diff --git a/DEPENDENCIES.md b/DEPENDENCIES.md index 5fc3ac432104d..0223c09b8315a 100644 --- a/DEPENDENCIES.md +++ b/DEPENDENCIES.md @@ -35,6 +35,7 @@ graph LR; libnpmexec-->npmcli-arborist["@npmcli/arborist"]; libnpmexec-->npmcli-ci-detect["@npmcli/ci-detect"]; libnpmexec-->npmcli-eslint-config["@npmcli/eslint-config"]; + libnpmexec-->npmcli-fs["@npmcli/fs"]; libnpmexec-->npmcli-run-script["@npmcli/run-script"]; libnpmexec-->npmcli-template-oss["@npmcli/template-oss"]; libnpmexec-->npmlog; @@ -345,6 +346,7 @@ graph LR; libnpmexec-->npmcli-arborist["@npmcli/arborist"]; libnpmexec-->npmcli-ci-detect["@npmcli/ci-detect"]; libnpmexec-->npmcli-eslint-config["@npmcli/eslint-config"]; + libnpmexec-->npmcli-fs["@npmcli/fs"]; libnpmexec-->npmcli-run-script["@npmcli/run-script"]; libnpmexec-->npmcli-template-oss["@npmcli/template-oss"]; libnpmexec-->npmlog; diff --git a/node_modules/@npmcli/fs/lib/common/file-url-to-path/index.js b/node_modules/@npmcli/fs/lib/common/file-url-to-path/index.js deleted file mode 100644 index 7755d1c10e6d0..0000000000000 --- a/node_modules/@npmcli/fs/lib/common/file-url-to-path/index.js +++ /dev/null @@ -1,17 +0,0 @@ -const url = require('url') - -const node = require('../node.js') -const polyfill = require('./polyfill.js') - -const useNative = node.satisfies('>=10.12.0') - -const fileURLToPath = (path) => { - // the polyfill is tested separately from this module, no need to hack - // process.version to try to trigger it just for coverage - // istanbul ignore next - return useNative - ? url.fileURLToPath(path) - : polyfill(path) -} - -module.exports = fileURLToPath diff --git a/node_modules/@npmcli/fs/lib/common/file-url-to-path/polyfill.js b/node_modules/@npmcli/fs/lib/common/file-url-to-path/polyfill.js deleted file mode 100644 index 6cc90f0b07d79..0000000000000 --- a/node_modules/@npmcli/fs/lib/common/file-url-to-path/polyfill.js +++ /dev/null @@ -1,121 +0,0 @@ -const { URL, domainToUnicode } = require('url') - -const CHAR_LOWERCASE_A = 97 -const CHAR_LOWERCASE_Z = 122 - -const isWindows = process.platform === 'win32' - -class ERR_INVALID_FILE_URL_HOST extends TypeError { - constructor (platform) { - super(`File URL host must be "localhost" or empty on ${platform}`) - this.code = 'ERR_INVALID_FILE_URL_HOST' - } - - toString () { - return `${this.name} [${this.code}]: ${this.message}` - } -} - -class ERR_INVALID_FILE_URL_PATH extends TypeError { - constructor (msg) { - super(`File URL path ${msg}`) - this.code = 'ERR_INVALID_FILE_URL_PATH' - } - - toString () { - return `${this.name} [${this.code}]: ${this.message}` - } -} - -class ERR_INVALID_ARG_TYPE extends TypeError { - constructor (name, actual) { - super(`The "${name}" argument must be one of type string or an instance ` + - `of URL. Received type ${typeof actual} ${actual}`) - this.code = 'ERR_INVALID_ARG_TYPE' - } - - toString () { - return `${this.name} [${this.code}]: ${this.message}` - } -} - -class ERR_INVALID_URL_SCHEME extends TypeError { - constructor (expected) { - super(`The URL must be of scheme ${expected}`) - this.code = 'ERR_INVALID_URL_SCHEME' - } - - toString () { - return `${this.name} [${this.code}]: ${this.message}` - } -} - -const isURLInstance = (input) => { - return input != null && input.href && input.origin -} - -const getPathFromURLWin32 = (url) => { - const hostname = url.hostname - let pathname = url.pathname - for (let n = 0; n < pathname.length; n++) { - if (pathname[n] === '%') { - const third = pathname.codePointAt(n + 2) | 0x20 - if ((pathname[n + 1] === '2' && third === 102) || - (pathname[n + 1] === '5' && third === 99)) { - throw new ERR_INVALID_FILE_URL_PATH('must not include encoded \\ or / characters') - } - } - } - - pathname = pathname.replace(/\//g, '\\') - pathname = decodeURIComponent(pathname) - if (hostname !== '') { - return `\\\\${domainToUnicode(hostname)}${pathname}` - } - - const letter = pathname.codePointAt(1) | 0x20 - const sep = pathname[2] - if (letter < CHAR_LOWERCASE_A || letter > CHAR_LOWERCASE_Z || - (sep !== ':')) { - throw new ERR_INVALID_FILE_URL_PATH('must be absolute') - } - - return pathname.slice(1) -} - -const getPathFromURLPosix = (url) => { - if (url.hostname !== '') { - throw new ERR_INVALID_FILE_URL_HOST(process.platform) - } - - const pathname = url.pathname - - for (let n = 0; n < pathname.length; n++) { - if (pathname[n] === '%') { - const third = pathname.codePointAt(n + 2) | 0x20 - if (pathname[n + 1] === '2' && third === 102) { - throw new ERR_INVALID_FILE_URL_PATH('must not include encoded / characters') - } - } - } - - return decodeURIComponent(pathname) -} - -const fileURLToPath = (path) => { - if (typeof path === 'string') { - path = new URL(path) - } else if (!isURLInstance(path)) { - throw new ERR_INVALID_ARG_TYPE('path', ['string', 'URL'], path) - } - - if (path.protocol !== 'file:') { - throw new ERR_INVALID_URL_SCHEME('file') - } - - return isWindows - ? getPathFromURLWin32(path) - : getPathFromURLPosix(path) -} - -module.exports = fileURLToPath diff --git a/node_modules/@npmcli/fs/lib/common/owner-sync.js b/node_modules/@npmcli/fs/lib/common/owner-sync.js index 2055c4b21dec9..8fa18d5121eff 100644 --- a/node_modules/@npmcli/fs/lib/common/owner-sync.js +++ b/node_modules/@npmcli/fs/lib/common/owner-sync.js @@ -1,6 +1,6 @@ const { dirname, resolve } = require('path') +const url = require('url') -const fileURLToPath = require('./file-url-to-path/index.js') const fs = require('../fs.js') // given a path, find the owner of the nearest parent @@ -13,7 +13,7 @@ const find = (path) => { // fs methods accept URL objects with a scheme of file: so we need to unwrap // those into an actual path string before we can resolve it const resolved = path != null && path.href && path.origin - ? resolve(fileURLToPath(path)) + ? resolve(url.fileURLToPath(path)) : resolve(path) let stat diff --git a/node_modules/@npmcli/fs/lib/common/owner.js b/node_modules/@npmcli/fs/lib/common/owner.js index e3468b077d00e..3fe167cfc30aa 100644 --- a/node_modules/@npmcli/fs/lib/common/owner.js +++ b/node_modules/@npmcli/fs/lib/common/owner.js @@ -1,6 +1,6 @@ const { dirname, resolve } = require('path') +const url = require('url') -const fileURLToPath = require('./file-url-to-path/index.js') const fs = require('../fs.js') // given a path, find the owner of the nearest parent @@ -13,7 +13,7 @@ const find = async (path) => { // fs methods accept URL objects with a scheme of file: so we need to unwrap // those into an actual path string before we can resolve it const resolved = path != null && path.href && path.origin - ? resolve(fileURLToPath(path)) + ? resolve(url.fileURLToPath(path)) : resolve(path) let stat diff --git a/node_modules/@npmcli/fs/lib/index.js b/node_modules/@npmcli/fs/lib/index.js index 43892df5fee07..3a98648eca9a1 100644 --- a/node_modules/@npmcli/fs/lib/index.js +++ b/node_modules/@npmcli/fs/lib/index.js @@ -2,7 +2,7 @@ module.exports = { ...require('./fs.js'), copyFile: require('./copy-file.js'), cp: require('./cp/index.js'), - mkdir: require('./mkdir/index.js'), + mkdir: require('./mkdir.js'), mkdtemp: require('./mkdtemp.js'), rm: require('./rm/index.js'), withTempDir: require('./with-temp-dir.js'), diff --git a/node_modules/@npmcli/fs/lib/mkdir.js b/node_modules/@npmcli/fs/lib/mkdir.js new file mode 100644 index 0000000000000..098d8d0a09ae3 --- /dev/null +++ b/node_modules/@npmcli/fs/lib/mkdir.js @@ -0,0 +1,19 @@ +const fs = require('./fs.js') +const getOptions = require('./common/get-options.js') +const withOwner = require('./with-owner.js') + +// extends mkdir with the ability to specify an owner of the new dir +const mkdir = async (path, opts) => { + const options = getOptions(opts, { + copy: ['mode', 'recursive'], + wrap: 'mode', + }) + + return withOwner( + path, + () => fs.mkdir(path, options), + opts + ) +} + +module.exports = mkdir diff --git a/node_modules/@npmcli/fs/lib/mkdir/index.js b/node_modules/@npmcli/fs/lib/mkdir/index.js deleted file mode 100644 index e2691042daa26..0000000000000 --- a/node_modules/@npmcli/fs/lib/mkdir/index.js +++ /dev/null @@ -1,29 +0,0 @@ -const fs = require('../fs.js') -const getOptions = require('../common/get-options.js') -const node = require('../common/node.js') -const withOwner = require('../with-owner.js') - -const polyfill = require('./polyfill.js') - -// node 10.12.0 added the options parameter, which allows recursive and mode -// properties to be passed -const useNative = node.satisfies('>=10.12.0') - -// extends mkdir with the ability to specify an owner of the new dir -const mkdir = async (path, opts) => { - const options = getOptions(opts, { - copy: ['mode', 'recursive'], - wrap: 'mode', - }) - - // the polyfill is tested separately from this module, no need to hack - // process.version to try to trigger it just for coverage - // istanbul ignore next - return withOwner( - path, - () => useNative ? fs.mkdir(path, options) : polyfill(path, options), - opts - ) -} - -module.exports = mkdir diff --git a/node_modules/@npmcli/fs/lib/mkdir/polyfill.js b/node_modules/@npmcli/fs/lib/mkdir/polyfill.js deleted file mode 100644 index 4f8e6f006a30e..0000000000000 --- a/node_modules/@npmcli/fs/lib/mkdir/polyfill.js +++ /dev/null @@ -1,81 +0,0 @@ -const { dirname } = require('path') - -const fileURLToPath = require('../common/file-url-to-path/index.js') -const fs = require('../fs.js') - -const defaultOptions = { - mode: 0o777, - recursive: false, -} - -const mkdir = async (path, opts) => { - const options = { ...defaultOptions, ...opts } - - // if we're not in recursive mode, just call the real mkdir with the path and - // the mode option only - if (!options.recursive) { - return fs.mkdir(path, options.mode) - } - - const makeDirectory = async (dir, mode) => { - // we can't use dirname directly since these functions support URL - // objects with the file: protocol as the path input, so first we get a - // string path, then we can call dirname on that - const parent = dir != null && dir.href && dir.origin - ? dirname(fileURLToPath(dir)) - : dirname(dir) - - // if the parent is the dir itself, try to create it. anything but EISDIR - // should be rethrown - if (parent === dir) { - try { - await fs.mkdir(dir, opts) - } catch (err) { - if (err.code !== 'EISDIR') { - throw err - } - } - return undefined - } - - try { - await fs.mkdir(dir, mode) - return dir - } catch (err) { - // ENOENT means the parent wasn't there, so create that - if (err.code === 'ENOENT') { - const made = await makeDirectory(parent, mode) - await makeDirectory(dir, mode) - // return the shallowest path we created, i.e. the result of creating - // the parent - return made - } - - // an EEXIST means there's already something there - // an EROFS means we have a read-only filesystem and can't create a dir - // any other error is fatal and we should give up now - if (err.code !== 'EEXIST' && err.code !== 'EROFS') { - throw err - } - - // stat the directory, if the result is a directory, then we successfully - // created this one so return its path. otherwise, we reject with the - // original error by ignoring the error in the catch - try { - const stat = await fs.stat(dir) - if (stat.isDirectory()) { - // if it already existed, we didn't create anything so return - // undefined - return undefined - } - } catch (_) {} - - // if the thing that's there isn't a directory, then just re-throw - throw err - } - } - - return makeDirectory(path, options.mode) -} - -module.exports = mkdir diff --git a/node_modules/@npmcli/fs/lib/with-temp-dir.js b/node_modules/@npmcli/fs/lib/with-temp-dir.js index ac9ebb714b989..ad08e6ee6e6d6 100644 --- a/node_modules/@npmcli/fs/lib/with-temp-dir.js +++ b/node_modules/@npmcli/fs/lib/with-temp-dir.js @@ -1,7 +1,7 @@ const { join, sep } = require('path') const getOptions = require('./common/get-options.js') -const mkdir = require('./mkdir/index.js') +const mkdir = require('./mkdir.js') const mkdtemp = require('./mkdtemp.js') const rm = require('./rm/index.js') diff --git a/node_modules/@npmcli/fs/package.json b/node_modules/@npmcli/fs/package.json index 799bf514f200b..9e18028218d1a 100644 --- a/node_modules/@npmcli/fs/package.json +++ b/node_modules/@npmcli/fs/package.json @@ -1,6 +1,6 @@ { "name": "@npmcli/fs", - "version": "2.1.0", + "version": "2.1.1", "description": "filesystem utilities for the npm cli", "main": "lib/index.js", "files": [ @@ -33,8 +33,8 @@ "license": "ISC", "devDependencies": { "@npmcli/eslint-config": "^3.0.1", - "@npmcli/template-oss": "3.1.2", - "tap": "^15.1.6" + "@npmcli/template-oss": "3.5.0", + "tap": "^16.0.1" }, "dependencies": { "@gar/promisify": "^1.1.3", @@ -45,6 +45,6 @@ }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "3.1.2" + "version": "3.5.0" } } diff --git a/package-lock.json b/package-lock.json index f947eef55389a..baf220b12e6ea 100644 --- a/package-lock.json +++ b/package-lock.json @@ -916,9 +916,9 @@ } }, "node_modules/@npmcli/fs": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-2.1.0.tgz", - "integrity": "sha512-DmfBvNXGaetMxj9LTp8NAN9vEidXURrf5ZTslQzEAi/6GbW+4yjaLFQc6Tue5cpZ9Frlk4OBo/Snf1Bh/S7qTQ==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-2.1.1.tgz", + "integrity": "sha512-1Q0uzx6c/NVNGszePbr5Gc2riSU1zLpNlo/1YWntH+eaPmMgBssAW0qXofCVkpdj3ce4swZtlDYQu+NKiYcptg==", "inBundle": true, "dependencies": { "@gar/promisify": "^1.1.3", @@ -10136,6 +10136,7 @@ "dependencies": { "@npmcli/arborist": "^5.0.0", "@npmcli/ci-detect": "^2.0.0", + "@npmcli/fs": "^2.1.1", "@npmcli/run-script": "^4.1.3", "chalk": "^4.1.0", "mkdirp-infer-owner": "^2.0.0", diff --git a/workspaces/libnpmexec/package.json b/workspaces/libnpmexec/package.json index d163103ea2b0b..e0be916765593 100644 --- a/workspaces/libnpmexec/package.json +++ b/workspaces/libnpmexec/package.json @@ -57,6 +57,7 @@ "dependencies": { "@npmcli/arborist": "^5.0.0", "@npmcli/ci-detect": "^2.0.0", + "@npmcli/fs": "^2.1.1", "@npmcli/run-script": "^4.1.3", "chalk": "^4.1.0", "mkdirp-infer-owner": "^2.0.0",