eslint
Advanced tools
Comparing version 8.25.0 to 8.26.0
@@ -146,8 +146,2 @@ /** | ||
if (ignorePattern) { | ||
overrideConfig.push({ | ||
ignores: ignorePattern | ||
}); | ||
} | ||
} else { | ||
@@ -191,3 +185,5 @@ overrideConfigFile = config; | ||
if (configType !== "flat") { | ||
if (configType === "flat") { | ||
options.ignorePatterns = ignorePattern; | ||
} else { | ||
options.resolvePluginsRelativeTo = resolvePluginsRelativeTo; | ||
@@ -284,2 +280,27 @@ options.rulePaths = rulesdir; | ||
/** | ||
* Returns whether flat config should be used. | ||
* @param {boolean} [allowFlatConfig] Whether or not to allow flat config. | ||
* @returns {Promise<boolean>} Where flat config should be used. | ||
*/ | ||
async function shouldUseFlatConfig(allowFlatConfig) { | ||
if (!allowFlatConfig) { | ||
return false; | ||
} | ||
switch (process.env.ESLINT_USE_FLAT_CONFIG) { | ||
case "true": | ||
return true; | ||
case "false": | ||
return false; | ||
default: | ||
/* | ||
* If neither explicitly enabled nor disabled, then use the presence | ||
* of a flat config file to determine enablement. | ||
*/ | ||
return !!(await findFlatConfigFile(process.cwd())); | ||
} | ||
} | ||
//------------------------------------------------------------------------------ | ||
@@ -314,3 +335,3 @@ // Public Interface | ||
const usingFlatConfig = allowFlatConfig && !!(await findFlatConfigFile(process.cwd())); | ||
const usingFlatConfig = await shouldUseFlatConfig(allowFlatConfig); | ||
@@ -317,0 +338,0 @@ debug("Using flat config?", usingFlatConfig); |
@@ -55,3 +55,3 @@ /** | ||
"**/node_modules/**", | ||
".git/**" | ||
".git/" | ||
] | ||
@@ -58,0 +58,0 @@ }, |
@@ -16,7 +16,17 @@ /** | ||
const isGlob = require("is-glob"); | ||
const globby = require("globby"); | ||
const hash = require("../cli-engine/hash"); | ||
const minimatch = require("minimatch"); | ||
const util = require("util"); | ||
const fswalk = require("@nodelib/fs.walk"); | ||
const globParent = require("glob-parent"); | ||
const isPathInside = require("is-path-inside"); | ||
//----------------------------------------------------------------------------- | ||
// Fixup references | ||
//----------------------------------------------------------------------------- | ||
const doFsWalk = util.promisify(fswalk.walk); | ||
const Minimatch = minimatch.Minimatch; | ||
//----------------------------------------------------------------------------- | ||
// Errors | ||
@@ -102,2 +112,137 @@ //----------------------------------------------------------------------------- | ||
/** | ||
* Searches a directory looking for matching glob patterns. This uses | ||
* the config array's logic to determine if a directory or file should | ||
* be ignored, so it is consistent with how ignoring works throughout | ||
* ESLint. | ||
* @param {Object} options The options for this function. | ||
* @param {string} options.basePath The directory to search. | ||
* @param {Array<string>} options.patterns An array of glob patterns | ||
* to match. | ||
* @param {FlatConfigArray} options.configs The config array to use for | ||
* determining what to ignore. | ||
* @returns {Promise<Array<string>>} An array of matching file paths | ||
* or an empty array if there are no matches. | ||
*/ | ||
async function globSearch({ basePath, patterns, configs }) { | ||
if (patterns.length === 0) { | ||
return []; | ||
} | ||
const matchers = patterns.map(pattern => { | ||
const patternToUse = path.isAbsolute(pattern) | ||
? normalizeToPosix(path.relative(basePath, pattern)) | ||
: pattern; | ||
return new minimatch.Minimatch(patternToUse); | ||
}); | ||
return (await doFsWalk(basePath, { | ||
deepFilter(entry) { | ||
const relativePath = normalizeToPosix(path.relative(basePath, entry.path)); | ||
const matchesPattern = matchers.some(matcher => matcher.match(relativePath, true)); | ||
return matchesPattern && !configs.isDirectoryIgnored(entry.path); | ||
}, | ||
entryFilter(entry) { | ||
const relativePath = normalizeToPosix(path.relative(basePath, entry.path)); | ||
// entries may be directories or files so filter out directories | ||
if (entry.dirent.isDirectory()) { | ||
return false; | ||
} | ||
const matchesPattern = matchers.some(matcher => matcher.match(relativePath)); | ||
return matchesPattern && !configs.isFileIgnored(entry.path); | ||
} | ||
})).map(entry => entry.path); | ||
} | ||
/** | ||
* Performs multiple glob searches in parallel. | ||
* @param {Object} options The options for this function. | ||
* @param {Array<{patterns:Array<string>,rawPatterns:Array<string>}>} options.searches | ||
* An array of glob patterns to match. | ||
* @param {FlatConfigArray} options.configs The config array to use for | ||
* determining what to ignore. | ||
* @returns {Promise<Array<string>>} An array of matching file paths | ||
* or an empty array if there are no matches. | ||
*/ | ||
async function globMultiSearch({ searches, configs }) { | ||
const results = await Promise.all( | ||
[...searches].map( | ||
([basePath, { patterns }]) => globSearch({ basePath, patterns, configs }) | ||
) | ||
); | ||
return [...new Set(results.flat())]; | ||
} | ||
/** | ||
* Determines if a given glob pattern will return any results. | ||
* Used primarily to help with useful error messages. | ||
* @param {Object} options The options for the function. | ||
* @param {string} options.basePath The directory to search. | ||
* @param {string} options.pattern A glob pattern to match. | ||
* @returns {Promise<boolean>} True if there is a glob match, false if not. | ||
*/ | ||
function globMatch({ basePath, pattern }) { | ||
let found = false; | ||
const patternToUse = path.isAbsolute(pattern) | ||
? normalizeToPosix(path.relative(basePath, pattern)) | ||
: pattern; | ||
const matcher = new Minimatch(patternToUse); | ||
const fsWalkSettings = { | ||
deepFilter(entry) { | ||
const relativePath = normalizeToPosix(path.relative(basePath, entry.path)); | ||
return !found && matcher.match(relativePath, true); | ||
}, | ||
entryFilter(entry) { | ||
if (found || entry.dirent.isDirectory()) { | ||
return false; | ||
} | ||
const relativePath = normalizeToPosix(path.relative(basePath, entry.path)); | ||
if (matcher.match(relativePath)) { | ||
found = true; | ||
return true; | ||
} | ||
return false; | ||
} | ||
}; | ||
return new Promise(resolve => { | ||
// using a stream so we can exit early because we just need one match | ||
const globStream = fswalk.walkStream(basePath, fsWalkSettings); | ||
globStream.on("data", () => { | ||
globStream.destroy(); | ||
resolve(true); | ||
}); | ||
// swallow errors as they're not important here | ||
globStream.on("error", () => {}); | ||
globStream.on("end", () => { | ||
resolve(false); | ||
}); | ||
globStream.read(); | ||
}); | ||
} | ||
/** | ||
* Finds all files matching the options specified. | ||
@@ -125,4 +270,6 @@ * @param {Object} args The arguments objects. | ||
const results = []; | ||
const globbyPatterns = []; | ||
const missingPatterns = []; | ||
let globbyPatterns = []; | ||
let rawPatterns = []; | ||
const searches = new Map([[cwd, { patterns: globbyPatterns, rawPatterns: [] }]]); | ||
@@ -148,3 +295,3 @@ // check to see if we have explicit files and directories | ||
filePath, | ||
ignored: configs.isIgnored(filePath) | ||
ignored: configs.isFileIgnored(filePath) | ||
}); | ||
@@ -156,65 +303,14 @@ } | ||
// filePatterns are all relative to cwd | ||
const filePatterns = configs.files | ||
.filter(filePattern => { | ||
// can only do this for strings, not functions | ||
if (typeof filePattern !== "string") { | ||
return false; | ||
} | ||
// patterns starting with ** always apply | ||
if (filePattern.startsWith("**")) { | ||
return true; | ||
} | ||
// patterns ending with * are not used for file search | ||
if (filePattern.endsWith("*")) { | ||
return false; | ||
} | ||
// not sure how to handle negated patterns yet | ||
if (filePattern.startsWith("!")) { | ||
return false; | ||
} | ||
// check if the pattern would be inside the config base path or not | ||
const fullFilePattern = path.join(cwd, filePattern); | ||
const patternRelativeToConfigBasePath = path.relative(configs.basePath, fullFilePattern); | ||
if (patternRelativeToConfigBasePath.startsWith("..")) { | ||
return false; | ||
} | ||
// check if the pattern matches | ||
if (minimatch(filePath, path.dirname(fullFilePattern), { partial: true })) { | ||
return true; | ||
} | ||
// check if the pattern is inside the directory or not | ||
const patternRelativeToFilePath = path.relative(filePath, fullFilePattern); | ||
if (patternRelativeToFilePath.startsWith("..")) { | ||
return false; | ||
} | ||
return true; | ||
}) | ||
.map(filePattern => { | ||
if (filePattern.startsWith("**")) { | ||
return path.join(pattern, filePattern); | ||
} | ||
// adjust the path to be relative to the cwd | ||
return path.relative( | ||
cwd, | ||
path.join(configs.basePath, filePattern) | ||
); | ||
}) | ||
.map(normalizeToPosix); | ||
if (filePatterns.length) { | ||
globbyPatterns.push(...filePatterns); | ||
// group everything in cwd together and split out others | ||
if (isPathInside(filePath, cwd)) { | ||
({ patterns: globbyPatterns, rawPatterns } = searches.get(cwd)); | ||
} else { | ||
if (!searches.has(filePath)) { | ||
searches.set(filePath, { patterns: [], rawPatterns: [] }); | ||
} | ||
({ patterns: globbyPatterns, rawPatterns } = searches.get(filePath)); | ||
} | ||
globbyPatterns.push(`${normalizeToPosix(filePath)}/**`); | ||
rawPatterns.push(pattern); | ||
} | ||
@@ -227,3 +323,17 @@ | ||
if (globInputPaths && isGlobPattern(filePath)) { | ||
globbyPatterns.push(pattern); | ||
const basePath = globParent(filePath); | ||
// group in cwd if possible and split out others | ||
if (isPathInside(basePath, cwd)) { | ||
({ patterns: globbyPatterns, rawPatterns } = searches.get(cwd)); | ||
} else { | ||
if (!searches.has(basePath)) { | ||
searches.set(basePath, { patterns: [], rawPatterns: [] }); | ||
} | ||
({ patterns: globbyPatterns, rawPatterns } = searches.get(basePath)); | ||
} | ||
globbyPatterns.push(filePath); | ||
rawPatterns.push(pattern); | ||
} else { | ||
@@ -234,8 +344,6 @@ missingPatterns.push(pattern); | ||
// note: globbyPatterns can be an empty array | ||
const globbyResults = (await globby(globbyPatterns, { | ||
cwd, | ||
absolute: true, | ||
ignore: configs.ignores.filter(matcher => typeof matcher === "string") | ||
})); | ||
const globbyResults = await globMultiSearch({ | ||
searches, | ||
configs | ||
}); | ||
@@ -245,19 +353,27 @@ // if there are no results, tell the user why | ||
// try globby without ignoring anything | ||
/* eslint-disable no-unreachable-loop -- We want to exit early. */ | ||
for (const globbyPattern of globbyPatterns) { | ||
for (const [basePath, { patterns: patternsToCheck, rawPatterns: patternsToReport }] of searches) { | ||
/* eslint-disable-next-line no-unused-vars -- Want to exit early. */ | ||
for await (const filePath of globby.stream(globbyPattern, { cwd, absolute: true })) { | ||
let index = 0; | ||
// files were found but ignored | ||
throw new AllFilesIgnoredError(globbyPattern); | ||
} | ||
// try globby without ignoring anything | ||
for (const patternToCheck of patternsToCheck) { | ||
// no files were found | ||
if (errorOnUnmatchedPattern) { | ||
throw new NoFilesFoundError(globbyPattern, globInputPaths); | ||
// check if there are any matches at all | ||
const patternHasMatch = await globMatch({ | ||
basePath, | ||
pattern: patternToCheck | ||
}); | ||
if (patternHasMatch) { | ||
throw new AllFilesIgnoredError(patternsToReport[index]); | ||
} | ||
// otherwise no files were found | ||
if (errorOnUnmatchedPattern) { | ||
throw new NoFilesFoundError(patternsToReport[index], globInputPaths); | ||
} | ||
index++; | ||
} | ||
} | ||
/* eslint-enable no-unreachable-loop -- Go back to normal. */ | ||
@@ -264,0 +380,0 @@ } |
@@ -265,8 +265,5 @@ /** | ||
* @param {string} filePath The filename to load from. | ||
* @param {Object} options Options to help load the config file. | ||
* @param {string} options.basePath The base path for the config array. | ||
* @param {boolean} options.shouldIgnore Whether to honor ignore patterns. | ||
* @returns {Promise<FlatConfigArray>} The config array loaded from the config file. | ||
* @returns {Promise<any>} The config loaded from the config file. | ||
*/ | ||
async function loadFlatConfigFile(filePath, { basePath, shouldIgnore }) { | ||
async function loadFlatConfigFile(filePath) { | ||
debug(`Loading config from ${filePath}`); | ||
@@ -278,8 +275,3 @@ | ||
const module = await import(fileURL); | ||
return new FlatConfigArray(module.default, { | ||
basePath, | ||
shouldIgnore | ||
}); | ||
return (await import(fileURL)).default; | ||
} | ||
@@ -295,2 +287,3 @@ | ||
cwd, | ||
baseConfig, | ||
overrideConfig, | ||
@@ -327,12 +320,14 @@ configFile, | ||
// load config array | ||
let configs; | ||
const configs = new FlatConfigArray(baseConfig || [], { basePath, shouldIgnore }); | ||
// load config file | ||
if (configFilePath) { | ||
configs = await loadFlatConfigFile(configFilePath, { | ||
basePath, | ||
shouldIgnore | ||
}); | ||
} else { | ||
configs = new FlatConfigArray([], { basePath, shouldIgnore }); | ||
const fileConfig = await loadFlatConfigFile(configFilePath); | ||
if (Array.isArray(fileConfig)) { | ||
configs.push(...fileConfig); | ||
} else { | ||
configs.push(fileConfig); | ||
} | ||
} | ||
@@ -369,13 +364,2 @@ | ||
/* | ||
* Ignore patterns are considered relative to a directory | ||
* when the pattern contains a slash in a position other | ||
* than the last character. If that's the case, we need to | ||
* add the relative ignore path to the current pattern to | ||
* get the correct behavior. Otherwise, no change is needed. | ||
*/ | ||
if (!basePattern.includes("/") || basePattern.endsWith("/")) { | ||
return pattern; | ||
} | ||
return (negated ? "!" : "") + | ||
@@ -673,9 +657,8 @@ path.posix.join(relativeIgnorePath, basePattern); | ||
const resultRules = new Map(); | ||
// short-circuit simple case | ||
if (results.length === 0) { | ||
return resultRules; | ||
return {}; | ||
} | ||
const resultRules = new Map(); | ||
const { configs } = privateMembers.get(this); | ||
@@ -709,2 +692,6 @@ | ||
for (const { ruleId } of allMessages) { | ||
if (!ruleId) { | ||
continue; | ||
} | ||
const rule = getRuleFromConfig(ruleId, config); | ||
@@ -711,0 +698,0 @@ |
@@ -115,14 +115,20 @@ /** | ||
// Object.defineProperty() | ||
if (parent.parent.parent.type === "CallExpression" && | ||
astUtils.getStaticPropertyName(parent.parent.parent.callee) === "defineProperty") { | ||
return true; | ||
// Object.defineProperty() or Reflect.defineProperty() | ||
if (parent.parent.parent.type === "CallExpression") { | ||
const callNode = parent.parent.parent.callee; | ||
if (astUtils.isSpecificMemberAccess(callNode, "Object", "defineProperty") || | ||
astUtils.isSpecificMemberAccess(callNode, "Reflect", "defineProperty")) { | ||
return true; | ||
} | ||
} | ||
// Object.defineProperties() | ||
// Object.defineProperties() or Object.create() | ||
if (parent.parent.parent.type === "Property" && | ||
parent.parent.parent.parent.type === "ObjectExpression" && | ||
parent.parent.parent.parent.parent.type === "CallExpression" && | ||
astUtils.getStaticPropertyName(parent.parent.parent.parent.parent.callee) === "defineProperties") { | ||
return true; | ||
parent.parent.parent.parent.parent.type === "CallExpression") { | ||
const callNode = parent.parent.parent.parent.parent.callee; | ||
return astUtils.isSpecificMemberAccess(callNode, "Object", "defineProperties") || | ||
astUtils.isSpecificMemberAccess(callNode, "Object", "create"); | ||
} | ||
@@ -129,0 +135,0 @@ } |
@@ -80,2 +80,7 @@ /** | ||
// Variables exported by "exported" block comments | ||
if (variable.eslintExported) { | ||
return; | ||
} | ||
variable.defs.forEach(def => { | ||
@@ -82,0 +87,0 @@ const defNode = def.node; |
{ | ||
"name": "eslint", | ||
"version": "8.25.0", | ||
"version": "8.26.0", | ||
"author": "Nicholas C. Zakas <nicholas+npm@nczconsulting.com>", | ||
@@ -59,4 +59,5 @@ "description": "An AST-based pattern checker for JavaScript.", | ||
"@eslint/eslintrc": "^1.3.3", | ||
"@humanwhocodes/config-array": "^0.10.5", | ||
"@humanwhocodes/config-array": "^0.11.6", | ||
"@humanwhocodes/module-importer": "^1.0.1", | ||
"@nodelib/fs.walk": "^1.2.8", | ||
"ajv": "^6.10.0", | ||
@@ -77,5 +78,4 @@ "chalk": "^4.0.0", | ||
"find-up": "^5.0.0", | ||
"glob-parent": "^6.0.1", | ||
"glob-parent": "^6.0.2", | ||
"globals": "^13.15.0", | ||
"globby": "^11.1.0", | ||
"grapheme-splitter": "^1.0.4", | ||
@@ -86,2 +86,3 @@ "ignore": "^5.2.0", | ||
"is-glob": "^4.0.0", | ||
"is-path-inside": "^3.0.3", | ||
"js-sdsl": "^4.1.4", | ||
@@ -88,0 +89,0 @@ "js-yaml": "^4.1.0", |
Sorry, the diff of this file is too big to display
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
2831587
67206
39
15
+ Added@nodelib/fs.walk@^1.2.8
+ Addedis-path-inside@^3.0.3
+ Added@humanwhocodes/config-array@0.11.14(transitive)
+ Added@humanwhocodes/object-schema@2.0.3(transitive)
+ Addedis-path-inside@3.0.3(transitive)
- Removedglobby@^11.1.0
- Removed@humanwhocodes/config-array@0.10.7(transitive)
- Removed@humanwhocodes/object-schema@1.2.1(transitive)
- Removedbraces@3.0.2(transitive)
- Removeddir-glob@3.0.1(transitive)
- Removedfast-glob@3.3.2(transitive)
- Removedfill-range@7.0.1(transitive)
- Removedglob-parent@5.1.2(transitive)
- Removedglobby@11.1.0(transitive)
- Removedis-number@7.0.0(transitive)
- Removedmerge2@1.4.1(transitive)
- Removedmicromatch@4.0.5(transitive)
- Removedpath-type@4.0.0(transitive)
- Removedpicomatch@2.3.1(transitive)
- Removedslash@3.0.0(transitive)
- Removedto-regex-range@5.0.1(transitive)
Updatedglob-parent@^6.0.2