Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

eslint

Package Overview
Dependencies
Maintainers
4
Versions
372
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

eslint - npm Package Compare versions

Comparing version 9.0.0-alpha.1 to 9.0.0-alpha.2

lib/shared/serialization.js

7

lib/eslint/eslint.js

@@ -616,2 +616,9 @@ /**

// Check for the .eslintignore file, and warn if it's present.
if (existsSync(path.resolve(processedOptions.cwd, ".eslintignore"))) {
process.emitWarning(
"The \".eslintignore\" file is no longer supported. Switch to using the \"ignores\" property in \"eslint.config.js\": https://eslint.org/docs/latest/use/configure/migration-guide#ignoring-files",
"ESLintIgnoreWarning"
);
}
}

@@ -618,0 +625,0 @@

40

lib/linter/code-path-analysis/code-path.js

@@ -180,4 +180,4 @@ /**

// tracks the last skipped segment during traversal
let skippedSegment = null;
// segments that have been skipped during traversal
const skipped = new Set();

@@ -197,7 +197,3 @@ // indicates if we exited early from the traversal

skip() {
if (stack.length <= 1) {
broken = true;
} else {
skippedSegment = stack.at(-2)[0];
}
skipped.add(segment);
},

@@ -227,2 +223,14 @@

/**
* Checks if a given previous segment has been skipped.
* @param {CodePathSegment} prevSegment A previous segment to check.
* @returns {boolean} `true` if the segment has been skipped.
*/
function isSkipped(prevSegment) {
return (
skipped.has(prevSegment) ||
segment.isLoopedPrevSegment(prevSegment)
);
}
// the traversal

@@ -264,8 +272,12 @@ while (stack.length > 0) {

// Reset the skipping flag if all branches have been skipped.
if (skippedSegment && segment.prevSegments.includes(skippedSegment)) {
skippedSegment = null;
}
visited.add(segment);
// Skips the segment if all previous segments have been skipped.
const shouldSkip = (
skipped.size > 0 &&
segment.prevSegments.length > 0 &&
segment.prevSegments.every(isSkipped)
);
/*

@@ -275,3 +287,3 @@ * If the most recent segment hasn't been skipped, then we call

*/
if (!skippedSegment) {
if (!shouldSkip) {
resolvedCallback.call(this, segment, controller);

@@ -292,2 +304,6 @@

}
} else {
// If the most recent segment has been skipped, then mark it as skipped.
skipped.add(segment);
}

@@ -294,0 +310,0 @@ }

@@ -16,6 +16,8 @@ /**

util = require("util"),
path = require("path"),
equal = require("fast-deep-equal"),
Traverser = require("../shared/traverser"),
{ getRuleOptionsSchema } = require("../config/flat-config-helpers"),
{ Linter, SourceCodeFixer, interpolate } = require("../linter");
{ Linter, SourceCodeFixer, interpolate } = require("../linter"),
stringify = require("json-stable-stringify-without-jsonify");

@@ -30,2 +32,3 @@ const { FlatConfigArray } = require("../config/flat-config-array");

const { ConfigArraySymbol } = require("@humanwhocodes/config-array");
const { isSerializable } = require("../shared/serialization");

@@ -504,2 +507,5 @@ //------------------------------------------------------------------------------

const seenValidTestCases = new Set();
const seenInvalidTestCases = new Set();
if (!rule || typeof rule !== "object" || typeof rule.create !== "function") {

@@ -583,4 +589,12 @@ throw new TypeError("Rule must be an object with a `create` method");

function runRuleForItem(item) {
const configs = new FlatConfigArray(testerConfig, { baseConfig });
const flatConfigArrayOptions = {
baseConfig
};
if (item.filename) {
flatConfigArrayOptions.basePath = path.parse(item.filename).root;
}
const configs = new FlatConfigArray(testerConfig, flatConfigArrayOptions);
/*

@@ -802,2 +816,28 @@ * Modify the returned config so that the parser is wrapped to catch

/**
* Check if this test case is a duplicate of one we have seen before.
* @param {Object} item test case object
* @param {Set<string>} seenTestCases set of serialized test cases we have seen so far (managed by this function)
* @returns {void}
* @private
*/
function checkDuplicateTestCase(item, seenTestCases) {
if (!isSerializable(item)) {
/*
* If we can't serialize a test case (because it contains a function, RegExp, etc), skip the check.
* This might happen with properties like: options, plugins, settings, languageOptions.parser, languageOptions.parserOptions.
*/
return;
}
const serializedTestCase = stringify(item);
assert(
!seenTestCases.has(serializedTestCase),
"detected duplicate test case"
);
seenTestCases.add(serializedTestCase);
}
/**
* Check if the template is valid or not

@@ -817,2 +857,4 @@ * all valid cases go through this

checkDuplicateTestCase(item, seenValidTestCases);
const result = runRuleForItem(item);

@@ -869,2 +911,4 @@ const messages = result.messages;

checkDuplicateTestCase(item, seenInvalidTestCases);
const ruleHasMetaMessages = hasOwnProperty(rule, "meta") && hasOwnProperty(rule.meta, "messages");

@@ -871,0 +915,0 @@ const friendlyIDList = ruleHasMetaMessages ? `[${Object.keys(rule.meta.messages).map(key => `'${key}'`).join(", ")}]` : null;

@@ -191,2 +191,3 @@ /**

meta: {
hasSuggestions: true,
type: "suggestion",

@@ -233,3 +234,4 @@

messages: {
useRecommendation: "use `{{recommendation}}` instead."
implicitCoercion: "Unexpected implicit coercion encountered. Use `{{recommendation}}` instead.",
useRecommendation: "Use `{{recommendation}}` instead."
}

@@ -246,12 +248,30 @@ },

* @param {string} recommendation The recommended code for the issue
* @param {bool} shouldSuggest Whether this report should offer a suggestion
* @param {bool} shouldFix Whether this report should fix the node
* @returns {void}
*/
function report(node, recommendation, shouldFix) {
function report(node, recommendation, shouldSuggest, shouldFix) {
/**
* Fix function
* @param {RuleFixer} fixer The fixer to fix.
* @returns {Fix} The fix object.
*/
function fix(fixer) {
const tokenBefore = sourceCode.getTokenBefore(node);
if (
tokenBefore?.range[1] === node.range[0] &&
!astUtils.canTokensBeAdjacent(tokenBefore, recommendation)
) {
return fixer.replaceText(node, ` ${recommendation}`);
}
return fixer.replaceText(node, recommendation);
}
context.report({
node,
messageId: "useRecommendation",
data: {
recommendation
},
messageId: "implicitCoercion",
data: { recommendation },
fix(fixer) {

@@ -262,13 +282,17 @@ if (!shouldFix) {

const tokenBefore = sourceCode.getTokenBefore(node);
return fix(fixer);
},
suggest: [
{
messageId: "useRecommendation",
data: { recommendation },
fix(fixer) {
if (shouldFix || !shouldSuggest) {
return null;
}
if (
tokenBefore &&
tokenBefore.range[1] === node.range[0] &&
!astUtils.canTokensBeAdjacent(tokenBefore, recommendation)
) {
return fixer.replaceText(node, ` ${recommendation}`);
return fix(fixer);
}
}
return fixer.replaceText(node, recommendation);
}
]
});

@@ -285,4 +309,6 @@ }

const recommendation = `Boolean(${sourceCode.getText(node.argument.argument)})`;
const variable = astUtils.getVariableByName(sourceCode.getScope(node), "Boolean");
const booleanExists = variable?.identifiers.length === 0;
report(node, recommendation, true);
report(node, recommendation, true, booleanExists);
}

@@ -298,3 +324,3 @@

report(node, recommendation, false);
report(node, recommendation, false, false);
}

@@ -307,3 +333,3 @@

report(node, recommendation, true);
report(node, recommendation, true, false);
}

@@ -316,3 +342,3 @@

report(node, recommendation, false);
report(node, recommendation, true, false);
}

@@ -333,3 +359,3 @@ },

report(node, recommendation, true);
report(node, recommendation, true, false);
}

@@ -342,3 +368,3 @@

report(node, recommendation, true);
report(node, recommendation, true, false);
}

@@ -351,3 +377,3 @@

report(node, recommendation, true);
report(node, recommendation, true, false);
}

@@ -365,3 +391,3 @@ },

report(node, recommendation, true);
report(node, recommendation, true, false);
}

@@ -404,3 +430,3 @@ },

report(node, recommendation, true);
report(node, recommendation, true, false);
}

@@ -407,0 +433,0 @@ };

@@ -164,13 +164,21 @@ /**

const restrictedPaths = (isPathAndPatternsObject ? options[0].paths : context.options) || [];
const restrictedPathMessages = restrictedPaths.reduce((memo, importSource) => {
const groupedRestrictedPaths = restrictedPaths.reduce((memo, importSource) => {
const path = typeof importSource === "string"
? importSource
: importSource.name;
if (!memo[path]) {
memo[path] = [];
}
if (typeof importSource === "string") {
memo[importSource] = { message: null };
memo[path].push({});
} else {
memo[importSource.name] = {
memo[path].push({
message: importSource.message,
importNames: importSource.importNames
};
});
}
return memo;
}, {});
}, Object.create(null));

@@ -207,20 +215,50 @@ // Handle patterns too, either as strings or groups

function checkRestrictedPathAndReport(importSource, importNames, node) {
if (!Object.hasOwn(restrictedPathMessages, importSource)) {
if (!Object.hasOwn(groupedRestrictedPaths, importSource)) {
return;
}
const customMessage = restrictedPathMessages[importSource].message;
const restrictedImportNames = restrictedPathMessages[importSource].importNames;
groupedRestrictedPaths[importSource].forEach(restrictedPathEntry => {
const customMessage = restrictedPathEntry.message;
const restrictedImportNames = restrictedPathEntry.importNames;
if (restrictedImportNames) {
if (importNames.has("*")) {
const specifierData = importNames.get("*")[0];
if (restrictedImportNames) {
if (importNames.has("*")) {
const specifierData = importNames.get("*")[0];
context.report({
node,
messageId: customMessage ? "everythingWithCustomMessage" : "everything",
loc: specifierData.loc,
data: {
importSource,
importNames: restrictedImportNames,
customMessage
}
});
}
restrictedImportNames.forEach(importName => {
if (importNames.has(importName)) {
const specifiers = importNames.get(importName);
specifiers.forEach(specifier => {
context.report({
node,
messageId: customMessage ? "importNameWithCustomMessage" : "importName",
loc: specifier.loc,
data: {
importSource,
customMessage,
importName
}
});
});
}
});
} else {
context.report({
node,
messageId: customMessage ? "everythingWithCustomMessage" : "everything",
loc: specifierData.loc,
messageId: customMessage ? "pathWithCustomMessage" : "path",
data: {
importSource,
importNames: restrictedImportNames,
customMessage

@@ -230,31 +268,3 @@ }

}
restrictedImportNames.forEach(importName => {
if (importNames.has(importName)) {
const specifiers = importNames.get(importName);
specifiers.forEach(specifier => {
context.report({
node,
messageId: customMessage ? "importNameWithCustomMessage" : "importName",
loc: specifier.loc,
data: {
importSource,
customMessage,
importName
}
});
});
}
});
} else {
context.report({
node,
messageId: customMessage ? "pathWithCustomMessage" : "path",
data: {
importSource,
customMessage
}
});
}
});
}

@@ -261,0 +271,0 @@

@@ -200,8 +200,23 @@ /**

/**
* A collection of nodes to avoid duplicate reports.
* @type {Set<ASTNode>}
*/
const reported = new Set();
codePath.traverseSegments((segment, controller) => {
const info = segInfoMap[segment.id];
const invalidNodes = info.invalidNodes
.filter(
for (let i = 0; i < info.invalidNodes.length; ++i) {
const invalidNode = info.invalidNodes[i];
/*
* Avoid duplicate reports.
* When there is a `finally`, invalidNodes may contain already reported node.
*/
node => !reported.has(node)
);
for (const invalidNode of invalidNodes) {
reported.add(invalidNode);
context.report({

@@ -277,3 +292,2 @@ messageId: "noBeforeSuper",

if (info.superCalled) {
info.invalidNodes = [];
controller.skip();

@@ -285,3 +299,2 @@ } else if (

info.superCalled = true;
info.invalidNodes = [];
}

@@ -288,0 +301,0 @@ }

{
"name": "eslint",
"version": "9.0.0-alpha.1",
"version": "9.0.0-alpha.2",
"author": "Nicholas C. Zakas <nicholas+npm@nczconsulting.com>",

@@ -69,3 +69,3 @@ "description": "An AST-based pattern checker for JavaScript.",

"@eslint/eslintrc": "^3.0.0",
"@eslint/js": "9.0.0-alpha.0",
"@eslint/js": "9.0.0-alpha.2",
"@humanwhocodes/config-array": "^0.11.14",

@@ -81,3 +81,3 @@ "@humanwhocodes/module-importer": "^1.0.1",

"eslint-visitor-keys": "^3.4.3",
"espree": "^9.6.1",
"espree": "^10.0.0",
"esquery": "^1.4.2",

@@ -140,3 +140,3 @@ "esutils": "^2.0.2",

"markdown-it-container": "^3.0.0",
"markdownlint": "^0.32.0",
"markdownlint": "^0.33.0",
"markdownlint-cli": "^0.38.0",

@@ -143,0 +143,0 @@ "marked": "^4.0.8",

@@ -120,3 +120,3 @@ [![npm version](https://img.shields.io/npm/v/eslint.svg)](https://www.npmjs.com/package/eslint)

ESLint has full support for ECMAScript 3, 5 (default), 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, and 2023. You can set your desired ECMAScript syntax (and other settings, like global variables or your target environments) through [configuration](https://eslint.org/docs/latest/use/configure).
ESLint has full support for ECMAScript 3, 5, and every year from 2015 up until the most recent stage 4 specification (the default). You can set your desired ECMAScript syntax and other settings (like global variables) through [configuration](https://eslint.org/docs/latest/use/configure).

@@ -123,0 +123,0 @@ ### What about experimental features?

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc