diff --git a/package-lock.json b/package-lock.json index ac2e45298..caa69be0b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,13 +19,13 @@ "commander": "11.0.0", "enhanced-resolve": "5.15.0", "figures": "5.0.0", - "glob": "10.3.6", "ignore": "5.2.4", "indent-string": "5.0.0", "interpret": "^3.1.1", "is-installed-globally": "0.4.0", "json5": "2.2.3", "lodash": "4.17.21", + "picomatch": "2.3.1", "prompts": "2.4.2", "rechoir": "^0.8.0", "safe-regex": "2.1.1", @@ -803,44 +803,6 @@ "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", "dev": true }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "license": "ISC", - "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.0.1", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.1.0", - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, "node_modules/@istanbuljs/schema": { "version": "0.1.3", "dev": true, @@ -929,14 +891,6 @@ "node": ">= 8" } }, - "node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "license": "MIT", - "optional": true, - "engines": { - "node": ">=14" - } - }, "node_modules/@swc/core": { "version": "1.3.87", "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.87.tgz", @@ -1512,6 +1466,7 @@ }, "node_modules/ansi-regex": { "version": "5.0.1", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -1650,6 +1605,7 @@ }, "node_modules/balanced-match": { "version": "1.0.2", + "dev": true, "license": "MIT" }, "node_modules/better-path-resolve": { @@ -2180,6 +2136,7 @@ }, "node_modules/cross-spawn": { "version": "7.0.3", + "dev": true, "license": "MIT", "dependencies": { "path-key": "^3.1.0", @@ -3304,27 +3261,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/glob": { - "version": "10.3.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.6.tgz", - "integrity": "sha512-mEfImdc/fiYHEcF6pHFfD2b/KrdFB1qH9mRe5vI5HROF8G51SWxQJ2V56Ezl6ZL9y86gsxQ1Lgo2S746KGUPSQ==", - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^2.0.3", - "minimatch": "^9.0.1", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", - "path-scurry": "^1.10.1" - }, - "bin": { - "glob": "dist/cjs/src/bin.js" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/glob-parent": { "version": "6.0.2", "dev": true, @@ -3336,50 +3272,6 @@ "node": ">=10.13.0" } }, - "node_modules/glob/node_modules/brace-expansion": { - "version": "2.0.1", - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/glob/node_modules/foreground-child": { - "version": "3.1.1", - "license": "ISC", - "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob/node_modules/minimatch": { - "version": "9.0.3", - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob/node_modules/signal-exit": { - "version": "4.0.2", - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/global-dirs": { "version": "3.0.1", "license": "MIT", @@ -3981,6 +3873,7 @@ }, "node_modules/isexe": { "version": "2.0.0", + "dev": true, "license": "ISC" }, "node_modules/istanbul-lib-coverage": { @@ -4019,22 +3912,6 @@ "node": ">=8" } }, - "node_modules/jackspeak": { - "version": "2.2.1", - "license": "BlueOak-1.0.0", - "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" - } - }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -4570,13 +4447,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/minipass": { - "version": "7.0.1", - "license": "ISC", - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, "node_modules/mocha": { "version": "10.2.0", "dev": true, @@ -5112,6 +4982,7 @@ }, "node_modules/path-key": { "version": "3.1.1", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -5121,27 +4992,6 @@ "version": "1.0.7", "license": "MIT" }, - "node_modules/path-scurry": { - "version": "1.10.1", - "license": "BlueOak-1.0.0", - "dependencies": { - "lru-cache": "^9.1.1 || ^10.0.0", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/path-scurry/node_modules/lru-cache": { - "version": "10.0.0", - "license": "ISC", - "engines": { - "node": "14 || >=16.14" - } - }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -5158,8 +5008,8 @@ }, "node_modules/picomatch": { "version": "2.3.1", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "engines": { "node": ">=8.6" }, @@ -5785,6 +5635,7 @@ }, "node_modules/shebang-command": { "version": "2.0.0", + "dev": true, "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" @@ -5795,6 +5646,7 @@ }, "node_modules/shebang-regex": { "version": "3.0.0", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -5994,30 +5846,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/string-width-cjs": { - "name": "string-width", - "version": "4.2.3", - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string-width-cjs/node_modules/emoji-regex": { - "version": "8.0.0", - "license": "MIT" - }, - "node_modules/string-width-cjs/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/string-width/node_modules/ansi-regex": { "version": "6.0.1", "license": "MIT", @@ -6101,17 +5929,7 @@ }, "node_modules/strip-ansi": { "version": "6.0.1", - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi-cjs": { - "name": "strip-ansi", - "version": "6.0.1", + "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" @@ -6539,6 +6357,7 @@ }, "node_modules/which": { "version": "2.0.2", + "dev": true, "license": "ISC", "dependencies": { "isexe": "^2.0.0" @@ -6604,72 +6423,6 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/wrap-ansi-cjs": { - "name": "wrap-ansi", - "version": "7.0.0", - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { - "version": "4.3.0", - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/color-convert": { - "version": "2.0.1", - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/color-name": { - "version": "1.1.4", - "license": "MIT" - }, - "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { - "version": "8.0.0", - "license": "MIT" - }, - "node_modules/wrap-ansi-cjs/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/string-width": { - "version": "4.2.3", - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/wrap-ansi/node_modules/ansi-regex": { "version": "6.0.1", "license": "MIT", diff --git a/package.json b/package.json index 2a7889c7c..a6eb5a6b6 100644 --- a/package.json +++ b/package.json @@ -158,13 +158,13 @@ "commander": "11.0.0", "enhanced-resolve": "5.15.0", "figures": "5.0.0", - "glob": "10.3.6", "ignore": "5.2.4", "indent-string": "5.0.0", "interpret": "^3.1.1", "is-installed-globally": "0.4.0", "json5": "2.2.3", "lodash": "4.17.21", + "picomatch": "2.3.1", "prompts": "2.4.2", "rechoir": "^0.8.0", "safe-regex": "2.1.1", diff --git a/src/cli/index.mjs b/src/cli/index.mjs index 7ed9de2a3..e1533e04d 100644 --- a/src/cli/index.mjs +++ b/src/cli/index.mjs @@ -1,5 +1,5 @@ import { join } from "node:path"; -import { glob } from "glob"; +import picomatch from "picomatch"; import cloneDeep from "lodash/cloneDeep.js"; import set from "lodash/set.js"; import isInstalledGlobally from "is-installed-globally"; @@ -106,7 +106,7 @@ async function runCruise(pFileDirectoryArray, pCruiseOptions) { ); pFileDirectoryArray - .filter((pFileOrDirectory) => !glob.hasMagic(pFileOrDirectory)) + .filter((pFileOrDirectory) => !picomatch.scan(pFileOrDirectory).isGlob) .map((pFileOrDirectory) => lCruiseOptions?.ruleSet?.options?.baseDir ? join(lCruiseOptions.ruleSet.options.baseDir, pFileOrDirectory) diff --git a/src/extract/gather-initial-sources.mjs b/src/extract/gather-initial-sources.mjs index da49c1fac..1639ae0f5 100644 --- a/src/extract/gather-initial-sources.mjs +++ b/src/extract/gather-initial-sources.mjs @@ -1,6 +1,6 @@ import { readdirSync, statSync } from "node:fs"; -import { join } from "node:path"; -import { glob } from "glob"; +import { join, normalize } from "node:path"; +import picomatch from "picomatch"; import { filenameMatchesPattern } from "../graph-utl/match-facade.mjs"; import getExtension from "../utl/get-extension.mjs"; import pathToPosix from "../utl/path-to-posix.mjs"; @@ -45,7 +45,7 @@ function gatherScannableFilesFromDirectory(pDirectoryName, pOptions) { return readdirSync(join(pOptions.baseDir, pDirectoryName)) .map((pFileName) => join(pDirectoryName, pFileName)) .filter((pFullPathToFile) => - shouldNotBeExcluded(pathToPosix(pFullPathToFile), pOptions) + shouldNotBeExcluded(pathToPosix(pFullPathToFile), pOptions), ) .reduce((pSum, pFullPathToFile) => { let lStat = statSync(join(pOptions.baseDir, pFullPathToFile), { @@ -55,7 +55,7 @@ function gatherScannableFilesFromDirectory(pDirectoryName, pOptions) { if (lStat) { if (lStat.isDirectory()) { return pSum.concat( - gatherScannableFilesFromDirectory(pFullPathToFile, pOptions) + gatherScannableFilesFromDirectory(pFullPathToFile, pOptions), ); } if (fileIsScannable(pOptions, pFullPathToFile)) { @@ -68,6 +68,15 @@ function gatherScannableFilesFromDirectory(pDirectoryName, pOptions) { .filter((pFullPathToFile) => shouldBeIncluded(pFullPathToFile, pOptions)); } +function expandGlob(pBaseDirectory, pScannedGlob) { + const isMatch = picomatch(pathToPosix(pScannedGlob.glob)); + return readdirSync(join(pBaseDirectory, pScannedGlob.base), { + recursive: true, + }) + .filter((pFile) => isMatch(pFile)) + .map((pFile) => pathToPosix(join(pScannedGlob.base, pFile))); +} + /** * Returns an array of strings, representing paths to files to be gathered * @@ -78,7 +87,7 @@ function gatherScannableFilesFromDirectory(pDirectoryName, pOptions) { * Files and directories are assumed to be either absolute, or relative to the * current working directory. * - * @param {string[]} pFileAndDirectoryArray globs and/ or paths to files or + * @param {string[]} pFileDirectoryAndGlobArray globs and/ or paths to files or * directories to be gathered * @param {import('../../types/dependency-cruiser.js').IStrictCruiseOptions} pOptions options that * influence what needs to be gathered/ scanned @@ -87,31 +96,26 @@ function gatherScannableFilesFromDirectory(pDirectoryName, pOptions) { * - includeOnly - regexp what to include * @return {string[]} paths to files to be gathered. */ -export default function gatherInitialSources(pFileAndDirectoryArray, pOptions) { +export default function gatherInitialSources( + pFileDirectoryAndGlobArray, + pOptions, +) { const lOptions = { baseDir: process.cwd(), ...pOptions }; - // these are `.reduce`s and not `.map`s because they typically return larger - // arrays than the pFileAndDirectoryArray: - // - `glob` returns an array of strings - // - so does `gatherScannableFilesFromDirectory` - return pFileAndDirectoryArray - .reduce( - (pAll, pFileOrDirectory) => - pAll.concat( - glob.sync(pathToPosix(pFileOrDirectory), { - cwd: pathToPosix(lOptions.baseDir), - }) - ), - [] - ) - .reduce((pAll, pFileOrDirectory) => { + return pFileDirectoryAndGlobArray + .flatMap((pFileDirectoryOrGlob) => { + const lScannedGlob = picomatch.scan(pFileDirectoryOrGlob); + if (lScannedGlob.isGlob) { + return expandGlob(lOptions.baseDir, lScannedGlob); + } + return pathToPosix(normalize(pFileDirectoryOrGlob)); + }) + .flatMap((pFileOrDirectory) => { if (statSync(join(lOptions.baseDir, pFileOrDirectory)).isDirectory()) { - return pAll.concat( - gatherScannableFilesFromDirectory(pFileOrDirectory, lOptions) - ); - } else { - return pAll.concat(pathToPosix(pFileOrDirectory)); + return gatherScannableFilesFromDirectory(pFileOrDirectory, lOptions); } - }, []) + // Not a glob anymore, and not a directory => it's a file + return pathToPosix(pFileOrDirectory); + }) .sort(); } diff --git a/test/extract/gather-initial-sources.spec.mjs b/test/extract/gather-initial-sources.spec.mjs index cedfff32e..542f9c4ce 100644 --- a/test/extract/gather-initial-sources.spec.mjs +++ b/test/extract/gather-initial-sources.spec.mjs @@ -245,7 +245,33 @@ describe("[I] extract/gatherInitialSources", () => { ); }); - it("heeds the baseDir", () => { + it("heeds the baseDir for regular folder paths", () => { + deepEqual( + gatherInitialSources( + ["ly/"], + normalizeCruiseOptions({ + baseDir: + "test/extract/__mocks__/gather-globbing/packages/odin/src/deep", + }), + ).map(pathToPosix), + ["ly/index.js", "ly/nested.js"], + ); + }); + + it("heeds the baseDir for regular files", () => { + deepEqual( + gatherInitialSources( + ["ly.js", "ly.spec.js"], + normalizeCruiseOptions({ + baseDir: + "test/extract/__mocks__/gather-globbing/packages/odin/src/deep", + }), + ).map(pathToPosix), + ["ly.js", "ly.spec.js"], + ); + }); + + it("heeds the baseDir for globs", () => { deepEqual( gatherInitialSources( ["**/src/**/*.js"], diff --git a/test/main/main.cruise.cache.spec.mjs b/test/main/main.cruise.cache.spec.mjs index 526962bcf..a77c7b660 100644 --- a/test/main/main.cruise.cache.spec.mjs +++ b/test/main/main.cruise.cache.spec.mjs @@ -79,7 +79,7 @@ describe("[E] main.cruise - cache", () => { deepEqual(lResult.output, lOldCache); const lResultTwo = await cruise( - ["test/main/__mocks__/cache test/main/__mocks__/cache-too "], + ["test/main/__mocks__/cache", "test/main/__mocks__/cache-too"], { cache: CACHE_FOLDER, },