tools: update ESLint to 8.3.0

PR-URL: https://github.com/nodejs/node/pull/40917
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Rich Trott <rtrott@gmail.com>
Reviewed-By: Mohammed Keyvanzadeh <mohammadkeyvanzade94@gmail.com>
Reviewed-By: Michaël Zasso <targos@protonmail.com>
This commit is contained in:
Luigi Pinca 2021-11-22 13:38:27 +01:00 committed by GitHub
parent 8ee4e672ec
commit 7ad052d2bd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
56 changed files with 1700 additions and 1287 deletions

View File

@ -206,6 +206,9 @@ This means:
These folks keep the project moving and are resources for help.
<!-- NOTE: This section is autogenerated. Do not manually edit.-->
<!--teamstart-->
### Technical Steering Committee (TSC)
@ -288,6 +291,9 @@ Nitin Kumar
<!--teamend-->
## <a name="sponsors"></a>Sponsors
The following companies, organizations, and individuals support ESLint's ongoing maintenance and development. [Become a Sponsor](https://opencollective.com/eslint) to get your logo on our README and website.

View File

@ -461,6 +461,10 @@ function processCodePathToEnter(analyzer, node) {
startCodePath("function");
break;
case "StaticBlock":
startCodePath("class-static-block");
break;
case "ChainExpression":
state.pushChainContext();
break;
@ -706,7 +710,8 @@ function postprocess(analyzer, node) {
case "Program":
case "FunctionDeclaration":
case "FunctionExpression":
case "ArrowFunctionExpression": {
case "ArrowFunctionExpression":
case "StaticBlock": {
endCodePath();
break;
}

View File

@ -40,7 +40,7 @@ class CodePath {
/**
* The reason that this code path was started. May be "program",
* "function", or "class-field-initializer".
* "function", "class-field-initializer", or "class-static-block".
* @type {string}
*/
this.origin = origin;

View File

@ -626,7 +626,7 @@ function analyzeScope(ast, parserOptions, visitorKeys) {
ignoreEval: true,
nodejsScope: ecmaFeatures.globalReturn,
impliedStrict: ecmaFeatures.impliedStrict,
ecmaVersion,
ecmaVersion: typeof ecmaVersion === "number" ? ecmaVersion : 6,
sourceType: parserOptions.sourceType || "script",
childVisitorKeys: visitorKeys || evk.KEYS,
fallback: Traverser.getKeys

View File

@ -112,6 +112,8 @@ module.exports = {
"SwitchStatement:exit": exitScope,
CatchClause: enterScope,
"CatchClause:exit": exitScope,
StaticBlock: enterScope,
"StaticBlock:exit": exitScope,
// Finds and reports references which are outside of valid scope.
VariableDeclaration: checkForVariables

View File

@ -40,7 +40,7 @@ module.exports = {
/**
* Gets the open brace token from a given node.
* @param {ASTNode} node A BlockStatement/SwitchStatement node to get.
* @param {ASTNode} node A BlockStatement/StaticBlock/SwitchStatement node to get.
* @returns {Token} The token of the open brace.
*/
function getOpenBrace(node) {
@ -50,6 +50,12 @@ module.exports = {
}
return sourceCode.getLastToken(node, 1);
}
if (node.type === "StaticBlock") {
return sourceCode.getFirstToken(node, { skip: 1 }); // skip the `static` token
}
// "BlockStatement"
return sourceCode.getFirstToken(node);
}
@ -72,8 +78,8 @@ module.exports = {
}
/**
* Reports invalid spacing style inside braces.
* @param {ASTNode} node A BlockStatement/SwitchStatement node to get.
* Checks and reports invalid spacing style inside braces.
* @param {ASTNode} node A BlockStatement/StaticBlock/SwitchStatement node to check.
* @returns {void}
*/
function checkSpacingInsideBraces(node) {
@ -157,6 +163,7 @@ module.exports = {
return {
BlockStatement: checkSpacingInsideBraces,
StaticBlock: checkSpacingInsideBraces,
SwitchStatement: checkSpacingInsideBraces
};
}

View File

@ -155,6 +155,12 @@ module.exports = {
validateCurlyPair(sourceCode.getFirstToken(node), sourceCode.getLastToken(node));
}
},
StaticBlock(node) {
validateCurlyPair(
sourceCode.getFirstToken(node, { skip: 1 }), // skip the `static` token
sourceCode.getLastToken(node)
);
},
ClassBody(node) {
validateCurlyPair(sourceCode.getFirstToken(node), sourceCode.getLastToken(node));
},

View File

@ -161,8 +161,17 @@ module.exports = {
/*
* Class field value are implicit functions.
*/
"PropertyDefinition:exit": popContext,
"PropertyDefinition > *.key:exit": pushContext,
"PropertyDefinition:exit": popContext,
/*
* Class static blocks are implicit functions. They aren't required to use `this`,
* but we have to push context so that it captures any use of `this` in the static block
* separately from enclosing contexts, because static blocks have their own `this` and it
* shouldn't count as used `this` in enclosing contexts.
*/
StaticBlock: pushContext,
"StaticBlock:exit": popContext,
ThisExpression: markThisUsed,
Super: markThisUsed,

View File

@ -124,20 +124,28 @@ module.exports = {
/*
* This rule only evaluates complexity of functions, so "program" is excluded.
* Class field initializers are implicit functions. Therefore, they shouldn't contribute
* to the enclosing function's complexity, but their own complexity should be evaluated.
* Class field initializers and class static blocks are implicit functions. Therefore,
* they shouldn't contribute to the enclosing function's complexity, but their
* own complexity should be evaluated.
*/
if (
codePath.origin !== "function" &&
codePath.origin !== "class-field-initializer"
codePath.origin !== "class-field-initializer" &&
codePath.origin !== "class-static-block"
) {
return;
}
if (complexity > THRESHOLD) {
const name = codePath.origin === "class-field-initializer"
? "class field initializer"
: astUtils.getFunctionNameWithKind(node);
let name;
if (codePath.origin === "class-field-initializer") {
name = "class field initializer";
} else if (codePath.origin === "class-static-block") {
name = "class static block";
} else {
name = astUtils.getFunctionNameWithKind(node);
}
context.report({
node,

View File

@ -68,6 +68,7 @@ const KNOWN_NODES = new Set([
"ReturnStatement",
"SequenceExpression",
"SpreadElement",
"StaticBlock",
"Super",
"SwitchCase",
"SwitchStatement",
@ -583,6 +584,16 @@ module.exports = {
},
additionalProperties: false
},
StaticBlock: {
type: "object",
properties: {
body: {
type: "integer",
minimum: 0
}
},
additionalProperties: false
},
CallExpression: {
type: "object",
properties: {
@ -646,6 +657,9 @@ module.exports = {
parameters: DEFAULT_PARAMETER_INDENT,
body: DEFAULT_FUNCTION_BODY_INDENT
},
StaticBlock: {
body: DEFAULT_FUNCTION_BODY_INDENT
},
CallExpression: {
arguments: DEFAULT_PARAMETER_INDENT
},
@ -1397,6 +1411,13 @@ module.exports = {
}
},
StaticBlock(node) {
const openingCurly = sourceCode.getFirstToken(node, { skip: 1 }); // skip the `static` token
const closingCurly = sourceCode.getLastToken(node);
addElementListIndent(node.body, openingCurly, closingCurly, options.StaticBlock.body);
},
SwitchStatement(node) {
const openingCurly = sourceCode.getTokenAfter(node.discriminant, astUtils.isOpeningBraceToken);
const closingCurly = sourceCode.getLastToken(node);

View File

@ -590,6 +590,7 @@ module.exports = {
ImportNamespaceSpecifier: checkSpacingForImportNamespaceSpecifier,
MethodDefinition: checkSpacingForProperty,
PropertyDefinition: checkSpacingForProperty,
StaticBlock: checkSpacingAroundFirstToken,
Property: checkSpacingForProperty,
// To avoid conflicts with `space-infix-ops`, e.g. `a > this.b`

View File

@ -185,10 +185,39 @@ module.exports = {
/**
* Returns the parent node that contains the given token.
* @param {token} token The token to check.
* @returns {ASTNode} The parent node that contains the given token.
* @returns {ASTNode|null} The parent node that contains the given token.
*/
function getParentNodeOfToken(token) {
return sourceCode.getNodeByRangeIndex(token.range[0]);
const node = sourceCode.getNodeByRangeIndex(token.range[0]);
/*
* For the purpose of this rule, the comment token is in a `StaticBlock` node only
* if it's inside the braces of that `StaticBlock` node.
*
* Example where this function returns `null`:
*
* static
* // comment
* {
* }
*
* Example where this function returns `StaticBlock` node:
*
* static
* {
* // comment
* }
*
*/
if (node && node.type === "StaticBlock") {
const openingBrace = sourceCode.getFirstToken(node, { skip: 1 }); // skip the `static` token
return token.range[0] >= openingBrace.range[0]
? node
: null;
}
return node;
}
/**
@ -200,8 +229,15 @@ module.exports = {
function isCommentAtParentStart(token, nodeType) {
const parent = getParentNodeOfToken(token);
return parent && isParentNodeType(parent, nodeType) &&
token.loc.start.line - parent.loc.start.line === 1;
if (parent && isParentNodeType(parent, nodeType)) {
const parentStartNodeOrToken = parent.type === "StaticBlock"
? sourceCode.getFirstToken(parent, { skip: 1 }) // opening brace of the static block
: parent;
return token.loc.start.line - parentStartNodeOrToken.loc.start.line === 1;
}
return false;
}
/**
@ -213,7 +249,7 @@ module.exports = {
function isCommentAtParentEnd(token, nodeType) {
const parent = getParentNodeOfToken(token);
return parent && isParentNodeType(parent, nodeType) &&
return !!parent && isParentNodeType(parent, nodeType) &&
parent.loc.end.line - token.loc.end.line === 1;
}
@ -223,7 +259,12 @@ module.exports = {
* @returns {boolean} True if the comment is at block start.
*/
function isCommentAtBlockStart(token) {
return isCommentAtParentStart(token, "ClassBody") || isCommentAtParentStart(token, "BlockStatement") || isCommentAtParentStart(token, "SwitchCase");
return (
isCommentAtParentStart(token, "ClassBody") ||
isCommentAtParentStart(token, "BlockStatement") ||
isCommentAtParentStart(token, "StaticBlock") ||
isCommentAtParentStart(token, "SwitchCase")
);
}
/**
@ -232,7 +273,13 @@ module.exports = {
* @returns {boolean} True if the comment is at block end.
*/
function isCommentAtBlockEnd(token) {
return isCommentAtParentEnd(token, "ClassBody") || isCommentAtParentEnd(token, "BlockStatement") || isCommentAtParentEnd(token, "SwitchCase") || isCommentAtParentEnd(token, "SwitchStatement");
return (
isCommentAtParentEnd(token, "ClassBody") ||
isCommentAtParentEnd(token, "BlockStatement") ||
isCommentAtParentEnd(token, "StaticBlock") ||
isCommentAtParentEnd(token, "SwitchCase") ||
isCommentAtParentEnd(token, "SwitchStatement")
);
}
/**

View File

@ -118,6 +118,7 @@ module.exports = {
FunctionDeclaration: startFunction,
FunctionExpression: startFunction,
ArrowFunctionExpression: startFunction,
StaticBlock: startFunction,
IfStatement(node) {
if (node.parent.type !== "IfStatement") {
@ -146,6 +147,7 @@ module.exports = {
"FunctionDeclaration:exit": endFunction,
"FunctionExpression:exit": endFunction,
"ArrowFunctionExpression:exit": endFunction,
"StaticBlock:exit": endFunction,
"Program:exit": endFunction
};

View File

@ -123,6 +123,14 @@ module.exports = {
function endFunction(node) {
const count = functionStack.pop();
/*
* This rule does not apply to class static blocks, but we have to track them so
* that stataments in them do not count as statements in the enclosing function.
*/
if (node.type === "StaticBlock") {
return;
}
if (ignoreTopLevelFunctions && functionStack.length === 0) {
topLevelFunctions.push({ node, count });
} else {
@ -148,12 +156,14 @@ module.exports = {
FunctionDeclaration: startFunction,
FunctionExpression: startFunction,
ArrowFunctionExpression: startFunction,
StaticBlock: startFunction,
BlockStatement: countStatements,
"FunctionDeclaration:exit": endFunction,
"FunctionExpression:exit": endFunction,
"ArrowFunctionExpression:exit": endFunction,
"StaticBlock:exit": endFunction,
"Program:exit"() {
if (topLevelFunctions.length === 1) {

View File

@ -248,6 +248,8 @@ module.exports = {
"ArrowFunctionExpression:exit": exitVarScope,
"PropertyDefinition > *.value": enterVarScope,
"PropertyDefinition > *.value:exit": exitVarScope,
StaticBlock: enterVarScope,
"StaticBlock:exit": exitVarScope,
ThisExpression(node) {
if (!isMember(node.parent, "eval")) {

View File

@ -116,7 +116,7 @@ module.exports = {
* @param {Node} node A MethodDefinition node of the start point.
* @returns {void}
*/
"MethodDefinition, PropertyDefinition"(node) {
"MethodDefinition, PropertyDefinition, StaticBlock"(node) {
checkForPartOfClassBody(sourceCode.getTokenAfter(node));
}
};

View File

@ -15,9 +15,33 @@ const astUtils = require("./utils/ast-utils");
// Rule Definition
//------------------------------------------------------------------------------
const validParent = new Set(["Program", "ExportNamedDeclaration", "ExportDefaultDeclaration"]);
const validParent = new Set(["Program", "StaticBlock", "ExportNamedDeclaration", "ExportDefaultDeclaration"]);
const validBlockStatementParent = new Set(["FunctionDeclaration", "FunctionExpression", "ArrowFunctionExpression"]);
/**
* Finds the nearest enclosing context where this rule allows declarations and returns its description.
* @param {ASTNode} node Node to search from.
* @returns {string} Description. One of "program", "function body", "class static block body".
*/
function getAllowedBodyDescription(node) {
let { parent } = node;
while (parent) {
if (parent.type === "StaticBlock") {
return "class static block body";
}
if (astUtils.isFunction(parent)) {
return "function body";
}
({ parent } = parent);
}
return "program";
}
module.exports = {
meta: {
type: "problem",
@ -59,14 +83,12 @@ module.exports = {
return;
}
const upperFunction = astUtils.getUpperFunction(parent);
context.report({
node,
messageId: "moveDeclToRoot",
data: {
type: (node.type === "FunctionDeclaration" ? "function" : "variable"),
body: (upperFunction === null ? "program" : "function body")
body: getAllowedBodyDescription(node)
}
});
}

View File

@ -132,6 +132,10 @@ module.exports = {
"PropertyDefinition > *.value": enterFunction,
"PropertyDefinition > *.value:exit": exitFunction,
// Class static blocks are implicit functions.
StaticBlock: enterFunction,
"StaticBlock:exit": exitFunction,
// Reports if `this` of the current context is invalid.
ThisExpression(node) {
const current = stack.getCurrent();

View File

@ -39,7 +39,9 @@ module.exports = {
* @returns {void}
*/
function report(node) {
const messageId = node.parent.type === "BlockStatement" ? "redundantNestedBlock" : "redundantBlock";
const messageId = node.parent.type === "BlockStatement" || node.parent.type === "StaticBlock"
? "redundantNestedBlock"
: "redundantBlock";
context.report({
node,
@ -54,6 +56,7 @@ module.exports = {
*/
function isLoneBlock(node) {
return node.parent.type === "BlockStatement" ||
node.parent.type === "StaticBlock" ||
node.parent.type === "Program" ||
// Don't report blocks in switch cases if the block is the only statement of the case.
@ -99,7 +102,10 @@ module.exports = {
loneBlocks.pop();
report(node);
} else if (
node.parent.type === "BlockStatement" &&
(
node.parent.type === "BlockStatement" ||
node.parent.type === "StaticBlock"
) &&
node.parent.body.length === 1
) {
report(node);

View File

@ -161,6 +161,8 @@ module.exports = {
FunctionExpression: checkForBlock,
ArrowFunctionExpression: checkForBlock,
StaticBlock: checkForBlock,
BlockStatement: checkForBlock,
ForStatement: checkForBlock,
ForInStatement: checkForBlock,

View File

@ -115,6 +115,12 @@ module.exports = {
const parent = ancestors[ancestors.length - 1],
grandparent = ancestors[ancestors.length - 2];
/**
* https://tc39.es/ecma262/#directive-prologue
*
* Only `FunctionBody`, `ScriptBody` and `ModuleBody` can have directive prologue.
* Class static blocks do not have directive prologue.
*/
return (parent.type === "Program" || parent.type === "BlockStatement" &&
(/Function/u.test(grandparent.type))) &&
directives(parent).indexOf(node) >= 0;

View File

@ -45,25 +45,37 @@ function isInRange(node, location) {
/**
* Checks whether or not a given location is inside of the range of a class static initializer.
* Static initializers are static blocks and initializers of static fields.
* @param {ASTNode} node `ClassBody` node to check static initializers.
* @param {number} location A location to check.
* @returns {boolean} `true` if the location is inside of a class static initializer.
*/
function isInClassStaticInitializerRange(node, location) {
return node.body.some(classMember => (
classMember.type === "PropertyDefinition" &&
classMember.static &&
classMember.value &&
isInRange(classMember.value, location)
(
classMember.type === "StaticBlock" &&
isInRange(classMember, location)
) ||
(
classMember.type === "PropertyDefinition" &&
classMember.static &&
classMember.value &&
isInRange(classMember.value, location)
)
));
}
/**
* Checks whether a given scope is the scope of a static class field initializer.
* Checks whether a given scope is the scope of a a class static initializer.
* Static initializers are static blocks and initializers of static fields.
* @param {eslint-scope.Scope} scope A scope to check.
* @returns {boolean} `true` if the scope is a class static initializer scope.
*/
function isClassStaticInitializerScope(scope) {
if (scope.type === "class-static-block") {
return true;
}
if (scope.type === "class-field-initializer") {
// `scope.block` is PropertyDefinition#value node
@ -82,7 +94,8 @@ function isClassStaticInitializerScope(scope) {
* - top-level
* - functions
* - class field initializers (implicit functions)
* Static class field initializers are automatically run during the class definition evaluation,
* - class static blocks (implicit functions)
* Static class field initializers and class static blocks are automatically run during the class definition evaluation,
* and therefore we'll consider them as a part of the parent execution context.
* Example:
*
@ -90,6 +103,7 @@ function isClassStaticInitializerScope(scope) {
*
* x; // returns `false`
* () => x; // returns `true`
*
* class C {
* field = x; // returns `true`
* static field = x; // returns `false`
@ -97,6 +111,14 @@ function isClassStaticInitializerScope(scope) {
* method() {
* x; // returns `true`
* }
*
* static method() {
* x; // returns `true`
* }
*
* static {
* x; // returns `false`
* }
* }
* @param {eslint-scope.Reference} reference A reference to check.
* @returns {boolean} `true` if the reference is from a separate execution context.
@ -127,8 +149,9 @@ function isFromSeparateExecutionContext(reference) {
* var {a = a} = obj
* for (var a in a) {}
* for (var a of a) {}
* var C = class { [C]; }
* var C = class { static foo = C; }
* var C = class { [C]; };
* var C = class { static foo = C; };
* var C = class { static { foo = C; } };
* class C extends C {}
* class C extends (class { static foo = C; }) {}
* class C { [C]; }
@ -158,7 +181,7 @@ function isEvaluatedDuringInitialization(reference) {
/*
* Class binding is initialized before running static initializers.
* For example, `class C { static foo = C; }` is valid.
* For example, `class C { static foo = C; static { bar = C; } }` is valid.
*/
!isInClassStaticInitializerRange(classDefinition.body, location)
);

View File

@ -541,6 +541,8 @@ module.exports = {
FunctionDeclaration: startFunction,
FunctionExpression: startFunction,
ArrowFunctionExpression: startFunction,
StaticBlock: startFunction, // StaticBlock creates a new scope for `var` variables
BlockStatement: startBlock,
ForStatement: startBlock,
ForInStatement: startBlock,
@ -552,10 +554,12 @@ module.exports = {
"ForInStatement:exit": endBlock,
"SwitchStatement:exit": endBlock,
"BlockStatement:exit": endBlock,
"Program:exit": endFunction,
"FunctionDeclaration:exit": endFunction,
"FunctionExpression:exit": endFunction,
"ArrowFunctionExpression:exit": endFunction
"ArrowFunctionExpression:exit": endFunction,
"StaticBlock:exit": endFunction
};
}

View File

@ -106,6 +106,12 @@ module.exports = {
if (node.type === "SwitchStatement") {
return sourceCode.getTokenBefore(node.cases[0]);
}
if (node.type === "StaticBlock") {
return sourceCode.getFirstToken(node, { skip: 1 }); // skip the `static` token
}
// `BlockStatement` or `ClassBody`
return sourceCode.getFirstToken(node);
}
@ -172,6 +178,7 @@ module.exports = {
function requirePaddingFor(node) {
switch (node.type) {
case "BlockStatement":
case "StaticBlock":
return options.blocks;
case "SwitchStatement":
return options.switches;
@ -282,6 +289,7 @@ module.exports = {
}
checkPadding(node);
};
rule.StaticBlock = rule.BlockStatement;
}
if (Object.prototype.hasOwnProperty.call(options, "classes")) {

View File

@ -618,9 +618,11 @@ module.exports = {
Program: enterScope,
BlockStatement: enterScope,
SwitchStatement: enterScope,
StaticBlock: enterScope,
"Program:exit": exitScope,
"BlockStatement:exit": exitScope,
"SwitchStatement:exit": exitScope,
"StaticBlock:exit": exitScope,
":statement": verify,

View File

@ -17,7 +17,7 @@ const astUtils = require("./utils/ast-utils");
//------------------------------------------------------------------------------
const PATTERN_TYPE = /^(?:.+?Pattern|RestElement|SpreadProperty|ExperimentalRestProperty|Property)$/u;
const DECLARATION_HOST_TYPE = /^(?:Program|BlockStatement|SwitchCase)$/u;
const DECLARATION_HOST_TYPE = /^(?:Program|BlockStatement|StaticBlock|SwitchCase)$/u;
const DESTRUCTURING_HOST_TYPE = /^(?:VariableDeclarator|AssignmentExpression)$/u;
/**

View File

@ -176,7 +176,17 @@ module.exports = {
},
fixable: null,
schema: [],
schema: [{
type: "object",
properties: {
allowProperties: {
type: "boolean",
default: false
}
},
additionalProperties: false
}],
messages: {
nonAtomicUpdate: "Possible race condition: `{{value}}` might be reassigned based on an outdated value of `{{value}}`.",
@ -185,6 +195,8 @@ module.exports = {
},
create(context) {
const allowProperties = !!context.options[0] && context.options[0].allowProperties;
const sourceCode = context.getSourceCode();
const assignmentReferences = new Map();
const segmentInfo = new SegmentInfo();
@ -284,7 +296,7 @@ module.exports = {
value: variable.name
}
});
} else {
} else if (!allowProperties) {
context.report({
node: node.parent,
messageId: "nonAtomicObjectUpdate",

View File

@ -25,7 +25,8 @@ const SELECTOR = [
/**
* Get the child node list of a given node.
* This returns `Program#body`, `BlockStatement#body`, or `SwitchCase#consequent`.
* This returns `BlockStatement#body`, `StaticBlock#body`, `Program#body`,
* `ClassBody#body`, or `SwitchCase#consequent`.
* This is used to check whether a node is the first/last child.
* @param {Node} node A node to get child node list.
* @returns {Node[]|null} The child node list.
@ -33,7 +34,12 @@ const SELECTOR = [
function getChildren(node) {
const t = node.type;
if (t === "BlockStatement" || t === "Program" || t === "ClassBody") {
if (
t === "BlockStatement" ||
t === "StaticBlock" ||
t === "Program" ||
t === "ClassBody"
) {
return node.body;
}
if (t === "SwitchCase") {

View File

@ -306,22 +306,31 @@ module.exports = {
}
/**
* Checks a node to see if it's in a one-liner block statement.
* Checks a node to see if it's the last item in a one-liner block.
* Block is any `BlockStatement` or `StaticBlock` node. Block is a one-liner if its
* braces (and consequently everything between them) are on the same line.
* @param {ASTNode} node The node to check.
* @returns {boolean} whether the node is in a one-liner block statement.
* @returns {boolean} whether the node is the last item in a one-liner block.
*/
function isOneLinerBlock(node) {
function isLastInOneLinerBlock(node) {
const parent = node.parent;
const nextToken = sourceCode.getTokenAfter(node);
if (!nextToken || nextToken.value !== "}") {
return false;
}
return (
!!parent &&
parent.type === "BlockStatement" &&
parent.loc.start.line === parent.loc.end.line
);
if (parent.type === "BlockStatement") {
return parent.loc.start.line === parent.loc.end.line;
}
if (parent.type === "StaticBlock") {
const openingBrace = sourceCode.getFirstToken(parent, { skip: 1 }); // skip the `static` token
return openingBrace.loc.start.line === parent.loc.end.line;
}
return false;
}
/**
@ -343,7 +352,7 @@ module.exports = {
report(node);
}
} else {
const oneLinerBlock = (exceptOneLine && isOneLinerBlock(node));
const oneLinerBlock = (exceptOneLine && isLastInOneLinerBlock(node));
if (isSemi && oneLinerBlock) {
report(node, true);

View File

@ -35,7 +35,7 @@ const COMMENTS_IGNORE_PATTERN = /^\s*(?:eslint|jshint\s+|jslint\s+|istanbul\s+|g
const LINEBREAKS = new Set(["\r\n", "\r", "\n", "\u2028", "\u2029"]);
// A set of node types that can contain a list of statements
const STATEMENT_LIST_PARENTS = new Set(["Program", "BlockStatement", "SwitchCase"]);
const STATEMENT_LIST_PARENTS = new Set(["Program", "BlockStatement", "StaticBlock", "SwitchCase"]);
const DECIMAL_INTEGER_PATTERN = /^(?:0|0[0-7]*[89]\d*|[1-9](?:_?\d)*)$/u;
@ -937,6 +937,8 @@ module.exports = {
*
* First, this checks the node:
*
* - The given node is not in `PropertyDefinition#value` position.
* - The given node is not `StaticBlock`.
* - The function name does not start with uppercase. It's a convention to capitalize the names
* of constructor functions. This check is not performed if `capIsConstructor` is set to `false`.
* - The function does not have a JSDoc comment that has a @this tag.
@ -951,7 +953,8 @@ module.exports = {
* - The location is not on an ES2015 class.
* - Its `bind`/`call`/`apply` method is not called directly.
* - The function is not a callback of array methods (such as `.forEach()`) if `thisArg` is given.
* @param {ASTNode} node A function node to check.
* @param {ASTNode} node A function node to check. It also can be an implicit function, like `StaticBlock`
* or any expression that is `PropertyDefinition#value` node.
* @param {SourceCode} sourceCode A SourceCode instance to get comments.
* @param {boolean} [capIsConstructor = true] `false` disables the assumption that functions which name starts
* with an uppercase or are assigned to a variable which name starts with an uppercase are constructors.
@ -964,7 +967,12 @@ module.exports = {
* Therefore, A expression node at `PropertyDefinition#value` is a function.
* In this case, `this` is always not default binding.
*/
if (node && node.parent && node.parent.type === "PropertyDefinition" && node.value === node) {
if (node.parent.type === "PropertyDefinition" && node.parent.value === node) {
return false;
}
// Class static blocks are implicit functions. In this case, `this` is always not default binding.
if (node.type === "StaticBlock") {
return false;
}
@ -1825,6 +1833,10 @@ module.exports = {
return true;
}
if (rightToken.type === "PrivateIdentifier") {
return true;
}
return false;
},

View File

@ -77,10 +77,12 @@ module.exports = {
const l = statements.length;
let i = 0;
// skip over directives
for (; i < l; ++i) {
if (!looksLikeDirective(statements[i]) && !looksLikeImport(statements[i])) {
break;
// Skip over directives and imports. Static blocks don't have either.
if (node.parent.type !== "StaticBlock") {
for (; i < l; ++i) {
if (!looksLikeDirective(statements[i]) && !looksLikeImport(statements[i])) {
break;
}
}
}
@ -111,16 +113,27 @@ module.exports = {
/**
* Checks whether variable is on top at functional block scope level
* @param {ASTNode} node The node to check
* @param {ASTNode} parent Parent of the node
* @param {ASTNode} grandParent Parent of the node's parent
* @returns {void}
*/
function blockScopeVarCheck(node, parent, grandParent) {
if (!(/Function/u.test(grandParent.type) &&
parent.type === "BlockStatement" &&
isVarOnTop(node, parent.body))) {
context.report({ node, messageId: "top" });
function blockScopeVarCheck(node) {
const { parent } = node;
if (
parent.type === "BlockStatement" &&
/Function/u.test(parent.parent.type) &&
isVarOnTop(node, parent.body)
) {
return;
}
if (
parent.type === "StaticBlock" &&
isVarOnTop(node, parent.body)
) {
return;
}
context.report({ node, messageId: "top" });
}
//--------------------------------------------------------------------------
@ -134,7 +147,7 @@ module.exports = {
} else if (node.parent.type === "Program") {
globalVarCheck(node, node.parent);
} else {
blockScopeVarCheck(node, node.parent, node.parent.parent);
blockScopeVarCheck(node);
}
}
};

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -4,6 +4,26 @@ var path = require('path');
var fs = require('fs');
var acorn = require('./acorn.js');
function _interopNamespace(e) {
if (e && e.__esModule) return e;
var n = Object.create(null);
if (e) {
Object.keys(e).forEach(function (k) {
if (k !== 'default') {
var d = Object.getOwnPropertyDescriptor(e, k);
Object.defineProperty(n, k, d.get ? d : {
enumerable: true,
get: function () { return e[k]; }
});
}
});
}
n["default"] = e;
return Object.freeze(n);
}
var acorn__namespace = /*#__PURE__*/_interopNamespace(acorn);
var inputFilePaths = [], forceFileName = false, fileMode = false, silent = false, compact = false, tokenize = false;
var options = {};
@ -44,14 +64,14 @@ function run(codeList) {
codeList.forEach(function (code, idx) {
fileIdx = idx;
if (!tokenize) {
result = acorn.parse(code, options);
result = acorn__namespace.parse(code, options);
options.program = result;
} else {
var tokenizer = acorn.tokenizer(code, options), token;
var tokenizer = acorn__namespace.tokenizer(code, options), token;
do {
token = tokenizer.getToken();
result.push(token);
} while (token.type !== acorn.tokTypes.eof)
} while (token.type !== acorn__namespace.tokTypes.eof)
}
});
} catch (e) {

View File

@ -16,7 +16,7 @@
],
"./package.json": "./package.json"
},
"version": "8.5.0",
"version": "8.6.0",
"engines": {"node": ">=0.4.0"},
"maintainers": [
{

View File

@ -366,7 +366,7 @@ class ParameterDefinition extends Definition {
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
const { Syntax: Syntax$2 } = estraverse__default['default'];
const { Syntax: Syntax$2 } = estraverse__default["default"];
/**
* Test if scope is struct
@ -491,7 +491,8 @@ class Scope {
constructor(scopeManager, type, upperScope, block, isMethodDefinition) {
/**
* One of 'module', 'block', 'switch', 'function', 'catch', 'with', 'function', 'class', 'global'.
* One of "global", "module", "function", "function-expression-name", "block", "switch", "catch", "with", "for",
* "class", "class-field-initializer", "class-static-block".
* @member {string} Scope#type
*/
this.type = type;
@ -559,7 +560,13 @@ class Scope {
* @member {Scope} Scope#variableScope
*/
this.variableScope =
(this.type === "global" || this.type === "function" || this.type === "module" || this.type === "class-field-initializer") ? this : upperScope.variableScope;
this.type === "global" ||
this.type === "module" ||
this.type === "function" ||
this.type === "class-field-initializer" ||
this.type === "class-static-block"
? this
: upperScope.variableScope;
/**
* Whether this scope is created by a FunctionExpression.
@ -803,8 +810,8 @@ class Scope {
resolve(ident) {
let ref, i, iz;
assert__default['default'](this.__isClosed(), "Scope should be closed.");
assert__default['default'](ident.type === Syntax$2.Identifier, "Target should be identifier.");
assert__default["default"](this.__isClosed(), "Scope should be closed.");
assert__default["default"](ident.type === Syntax$2.Identifier, "Target should be identifier.");
for (i = 0, iz = this.references.length; i < iz; ++i) {
ref = this.references[i];
if (ref.identifier === ident) {
@ -1008,7 +1015,7 @@ class FunctionScope extends Scope {
const variable = this.set.get("arguments");
assert__default['default'](variable, "Always have arguments variable.");
assert__default["default"](variable, "Always have arguments variable.");
return variable.tainted || variable.references.length !== 0;
}
@ -1072,6 +1079,12 @@ class ClassFieldInitializerScope extends Scope {
}
}
class ClassStaticBlockScope extends Scope {
constructor(scopeManager, upperScope, block) {
super(scopeManager, "class-static-block", upperScope, block, true);
}
}
/* vim: set sw=4 ts=4 et tw=80 : */
/*
@ -1124,7 +1137,7 @@ class ScopeManager {
}
__isNodejsScope() {
return this.__options.nodejsScope;
return this.__options.nodejsScope || this.__options.sourceType === "commonjs";
}
isModule() {
@ -1248,7 +1261,7 @@ class ScopeManager {
__nestScope(scope) {
if (scope instanceof GlobalScope) {
assert__default['default'](this.__currentScope === null);
assert__default["default"](this.__currentScope === null);
this.globalScope = scope;
}
this.__currentScope = scope;
@ -1287,6 +1300,10 @@ class ScopeManager {
return this.__nestScope(new ClassFieldInitializerScope(this, this.__currentScope, node));
}
__nestClassStaticBlockScope(node) {
return this.__nestScope(new ClassStaticBlockScope(this, this.__currentScope, node));
}
__nestSwitchScope(node) {
return this.__nestScope(new SwitchScope(this, this.__currentScope, node));
}
@ -1330,7 +1347,7 @@ class ScopeManager {
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
const { Syntax: Syntax$1 } = estraverse__default['default'];
const { Syntax: Syntax$1 } = estraverse__default["default"];
/**
* Get last array element
@ -1341,7 +1358,7 @@ function getLast(xs) {
return xs[xs.length - 1] || null;
}
class PatternVisitor extends esrecurse__default['default'].Visitor {
class PatternVisitor extends esrecurse__default["default"].Visitor {
static isPattern(node) {
const nodeType = node.type;
@ -1477,7 +1494,7 @@ class PatternVisitor extends esrecurse__default['default'].Visitor {
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
const { Syntax } = estraverse__default['default'];
const { Syntax } = estraverse__default["default"];
/**
* Traverse identifier in pattern
@ -1506,7 +1523,7 @@ function traverseIdentifierInPattern(options, rootPattern, referencer, callback)
// FIXME: Now, we don't create module environment, because the context is
// implementation dependent.
class Importer extends esrecurse__default['default'].Visitor {
class Importer extends esrecurse__default["default"].Visitor {
constructor(declaration, referencer) {
super(null, referencer.options);
this.declaration = declaration;
@ -1553,7 +1570,7 @@ class Importer extends esrecurse__default['default'].Visitor {
}
// Referencing variables and creating bindings.
class Referencer extends esrecurse__default['default'].Visitor {
class Referencer extends esrecurse__default["default"].Visitor {
constructor(options, scopeManager) {
super(null, options);
this.options = options;
@ -1914,6 +1931,14 @@ class Referencer extends esrecurse__default['default'].Visitor {
}
}
StaticBlock(node) {
this.scopeManager.__nestClassStaticBlockScope(node);
this.visitChildren(node);
this.close(node);
}
MethodDefinition(node) {
this.visitProperty(node);
}
@ -2035,7 +2060,7 @@ class Referencer extends esrecurse__default['default'].Visitor {
}
ImportDeclaration(node) {
assert__default['default'](this.scopeManager.__isES6() && this.scopeManager.isModule(), "ImportDeclaration should appear when the mode is ES6 and in the module context.");
assert__default["default"](this.scopeManager.__isES6() && this.scopeManager.isModule(), "ImportDeclaration should appear when the mode is ES6 and in the module context.");
const importer = new Importer(node, this);
@ -2087,7 +2112,7 @@ class Referencer extends esrecurse__default['default'].Visitor {
/* vim: set sw=4 ts=4 et tw=80 : */
const version = "6.0.0";
const version = "7.1.0";
/*
Copyright (C) 2012-2014 Yusuke Suzuki <utatane.tea@gmail.com>
@ -2125,7 +2150,7 @@ function defaultOptions() {
directive: false,
nodejsScope: false,
impliedStrict: false,
sourceType: "script", // one of ['script', 'module']
sourceType: "script", // one of ['script', 'module', 'commonjs']
ecmaVersion: 5,
childVisitorKeys: null,
fallback: "iteration"
@ -2181,7 +2206,7 @@ function updateDeeply(target, override) {
* a function scope immediately following the global scope.
* @param {boolean} [providedOptions.impliedStrict=false] implied strict mode
* (if ecmaVersion >= 5).
* @param {string} [providedOptions.sourceType='script'] the source type of the script. one of 'script' and 'module'
* @param {string} [providedOptions.sourceType='script'] the source type of the script. one of 'script', 'module', and 'commonjs'
* @param {number} [providedOptions.ecmaVersion=5] which ECMAScript version is considered
* @param {Object} [providedOptions.childVisitorKeys=null] Additional known visitor keys. See [esrecurse](https://github.com/estools/esrecurse)'s the `childVisitorKeys` option.
* @param {string} [providedOptions.fallback='iteration'] A kind of the fallback in order to encounter with unknown node. See [esrecurse](https://github.com/estools/esrecurse)'s the `fallback` option.
@ -2194,7 +2219,7 @@ function analyze(tree, providedOptions) {
referencer.visit(tree);
assert__default['default'](scopeManager.__currentScope === null, "currentScope should be null.");
assert__default["default"](scopeManager.__currentScope === null, "currentScope should be null.");
return scopeManager;
}

View File

@ -66,7 +66,7 @@ function defaultOptions() {
directive: false,
nodejsScope: false,
impliedStrict: false,
sourceType: "script", // one of ['script', 'module']
sourceType: "script", // one of ['script', 'module', 'commonjs']
ecmaVersion: 5,
childVisitorKeys: null,
fallback: "iteration"
@ -122,7 +122,7 @@ function updateDeeply(target, override) {
* a function scope immediately following the global scope.
* @param {boolean} [providedOptions.impliedStrict=false] implied strict mode
* (if ecmaVersion >= 5).
* @param {string} [providedOptions.sourceType='script'] the source type of the script. one of 'script' and 'module'
* @param {string} [providedOptions.sourceType='script'] the source type of the script. one of 'script', 'module', and 'commonjs'
* @param {number} [providedOptions.ecmaVersion=5] which ECMAScript version is considered
* @param {Object} [providedOptions.childVisitorKeys=null] Additional known visitor keys. See [esrecurse](https://github.com/estools/esrecurse)'s the `childVisitorKeys` option.
* @param {string} [providedOptions.fallback='iteration'] A kind of the fallback in order to encounter with unknown node. See [esrecurse](https://github.com/estools/esrecurse)'s the `fallback` option.

View File

@ -470,6 +470,14 @@ class Referencer extends esrecurse.Visitor {
}
}
StaticBlock(node) {
this.scopeManager.__nestClassStaticBlockScope(node);
this.visitChildren(node);
this.close(node);
}
MethodDefinition(node) {
this.visitProperty(node);
}

View File

@ -28,6 +28,7 @@ import {
BlockScope,
CatchScope,
ClassFieldInitializerScope,
ClassStaticBlockScope,
ClassScope,
ForScope,
FunctionExpressionNameScope,
@ -65,7 +66,7 @@ class ScopeManager {
}
__isNodejsScope() {
return this.__options.nodejsScope;
return this.__options.nodejsScope || this.__options.sourceType === "commonjs";
}
isModule() {
@ -228,6 +229,10 @@ class ScopeManager {
return this.__nestScope(new ClassFieldInitializerScope(this, this.__currentScope, node));
}
__nestClassStaticBlockScope(node) {
return this.__nestScope(new ClassStaticBlockScope(this, this.__currentScope, node));
}
__nestSwitchScope(node) {
return this.__nestScope(new SwitchScope(this, this.__currentScope, node));
}

View File

@ -157,7 +157,8 @@ class Scope {
constructor(scopeManager, type, upperScope, block, isMethodDefinition) {
/**
* One of 'module', 'block', 'switch', 'function', 'catch', 'with', 'function', 'class', 'global'.
* One of "global", "module", "function", "function-expression-name", "block", "switch", "catch", "with", "for",
* "class", "class-field-initializer", "class-static-block".
* @member {string} Scope#type
*/
this.type = type;
@ -225,7 +226,13 @@ class Scope {
* @member {Scope} Scope#variableScope
*/
this.variableScope =
(this.type === "global" || this.type === "function" || this.type === "module" || this.type === "class-field-initializer") ? this : upperScope.variableScope;
this.type === "global" ||
this.type === "module" ||
this.type === "function" ||
this.type === "class-field-initializer" ||
this.type === "class-static-block"
? this
: upperScope.variableScope;
/**
* Whether this scope is created by a FunctionExpression.
@ -738,6 +745,12 @@ class ClassFieldInitializerScope extends Scope {
}
}
class ClassStaticBlockScope extends Scope {
constructor(scopeManager, upperScope, block) {
super(scopeManager, "class-static-block", upperScope, block, true);
}
}
export {
Scope,
GlobalScope,
@ -750,7 +763,8 @@ export {
FunctionScope,
ForScope,
ClassScope,
ClassFieldInitializerScope
ClassFieldInitializerScope,
ClassStaticBlockScope
};
/* vim: set sw=4 ts=4 et tw=80 : */

View File

@ -1,3 +1,3 @@
const version = "6.0.0";
const version = "7.1.0";
export default version;

View File

@ -11,7 +11,7 @@
},
"./package.json": "./package.json"
},
"version": "6.0.0",
"version": "7.1.0",
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
@ -50,9 +50,9 @@
"eslint-config-eslint": "^7.0.0",
"eslint-plugin-jsdoc": "^35.4.1",
"eslint-plugin-node": "^11.1.0",
"eslint-release": "^3.1.2",
"eslint-visitor-keys": "^3.0.0",
"espree": "^8.0.0",
"eslint-release": "^3.2.0",
"eslint-visitor-keys": "^3.1.0",
"espree": "^9.0.0",
"mocha": "^9.0.1",
"npm-license": "^0.3.3",
"rollup": "^2.52.7",

View File

@ -17,7 +17,8 @@ $ npm install eslint-visitor-keys
### Requirements
- [Node.js] 10.0.0 or later.
- [Node.js] `^12.22.0`, `^14.17.0`, or `>=16.0.0`
## 📖 Usage
@ -102,5 +103,5 @@ Welcome. See [ESLint contribution guidelines](https://eslint.org/docs/developer-
[npm]: https://www.npmjs.com/
[Node.js]: https://nodejs.org/en/
[Node.js]: https://nodejs.org/
[ESTree]: https://github.com/estree/estree

View File

@ -239,6 +239,9 @@ const KEYS = {
SpreadElement: [
"argument"
],
StaticBlock: [
"body"
],
Super: [],
SwitchStatement: [
"discriminant",

View File

@ -235,6 +235,9 @@ const KEYS = {
SpreadElement: [
"argument"
],
StaticBlock: [
"body"
],
Super: [],
SwitchStatement: [
"discriminant",

View File

@ -1,6 +1,6 @@
{
"name": "eslint-visitor-keys",
"version": "3.0.0",
"version": "3.1.0",
"description": "Constants and utilities about visitor keys to traverse AST.",
"type": "module",
"main": "dist/eslint-visitor-keys.cjs",
@ -27,7 +27,7 @@
"eslint-config-eslint": "^7.0.0",
"eslint-plugin-jsdoc": "^35.4.0",
"eslint-plugin-node": "^11.1.0",
"eslint-release": "^3.1.2",
"eslint-release": "^3.2.0",
"mocha": "^9.0.1",
"opener": "^1.5.2",
"rollup": "^2.52.1"

View File

@ -145,7 +145,7 @@ const options = {
// You can also set "latest" to use the most recently supported version.
ecmaVersion: 5,
// specify which type of script you're parsing ("script" or "module")
// specify which type of script you're parsing ("script", "module", or "commonjs")
sourceType: "script",
// specify additional language features
@ -154,7 +154,7 @@ const options = {
// enable JSX parsing
jsx: false,
// enable return in global scope
// enable return in global scope (set to true automatically when sourceType is "commonjs")
globalReturn: false,
// enable implied strict mode (if ecmaVersion >= 5)
@ -238,6 +238,7 @@ Because ECMAScript 2022 is still under development, we are implementing features
* [Class static fields, static private methods and accessors](https://github.com/tc39/proposal-static-class-features)
* [RegExp match indices](https://github.com/tc39/proposal-regexp-match-indices)
* [Top-level await](https://github.com/tc39/proposal-top-level-await)
* [Class static initialization blocks](https://github.com/tc39/proposal-class-static-block)
See [finished-proposals.md](https://github.com/tc39/proposals/blob/master/finished-proposals.md) to know what features are finalized.

View File

@ -17,14 +17,12 @@ function _interopNamespace(e) {
var d = Object.getOwnPropertyDescriptor(e, k);
Object.defineProperty(n, k, d.get ? d : {
enumerable: true,
get: function () {
return e[k];
}
get: function () { return e[k]; }
});
}
});
}
n['default'] = e;
n["default"] = e;
return Object.freeze(n);
}
@ -462,6 +460,11 @@ function normalizeSourceType(sourceType = "script") {
if (sourceType === "script" || sourceType === "module") {
return sourceType;
}
if (sourceType === "commonjs") {
return "script";
}
throw new Error("Invalid sourceType.");
}
@ -477,16 +480,21 @@ function normalizeOptions(options) {
const ranges = options.range === true;
const locations = options.loc === true;
const allowReserved = ecmaVersion === 3 ? "never" : false;
const ecmaFeatures = options.ecmaFeatures || {};
const allowReturnOutsideFunction = options.sourceType === "commonjs" ||
Boolean(ecmaFeatures.globalReturn);
if (sourceType === "module" && ecmaVersion < 6) {
throw new Error("sourceType 'module' is not supported when ecmaVersion < 2015. Consider adding `{ ecmaVersion: 2015 }` to the parser options.");
}
return Object.assign({}, options, {
ecmaVersion,
sourceType,
ranges,
locations,
allowReserved
allowReserved,
allowReturnOutsideFunction
});
}
@ -546,6 +554,8 @@ var espree = () => Parser => {
code = String(code);
}
// save original source type in case of commonjs
const originalSourceType = opts.sourceType;
const options = normalizeOptions(opts);
const ecmaFeatures = options.ecmaFeatures || {};
const tokenTranslator =
@ -564,7 +574,7 @@ var espree = () => Parser => {
allowReserved: options.allowReserved,
// Truthy value is true for backward compatibility.
allowReturnOutsideFunction: Boolean(ecmaFeatures.globalReturn),
allowReturnOutsideFunction: options.allowReturnOutsideFunction,
// Collect tokens
onToken: token => {
@ -588,8 +598,13 @@ var espree = () => Parser => {
}
}, code);
// Initialize internal state.
/*
* Data that is unique to Espree and is not represented internally in
* Acorn. We put all of this data into a symbol property as a way to
* avoid potential naming conflicts with future versions of Acorn.
*/
this[STATE] = {
originalSourceType: originalSourceType || options.sourceType,
tokens: tokenTranslator ? [] : null,
comments: options.comment === true ? [] : null,
impliedStrict: ecmaFeatures.impliedStrict === true && this.options.ecmaVersion >= 5,
@ -634,7 +649,7 @@ var espree = () => Parser => {
const extra = this[STATE];
const program = super.parse();
program.sourceType = this.options.sourceType;
program.sourceType = extra.originalSourceType;
if (extra.comments) {
program.comments = extra.comments;
@ -810,7 +825,7 @@ var espree = () => Parser => {
};
};
const version$1 = "9.0.0";
const version$1 = "9.1.0";
/**
* @fileoverview Main Espree file that converts Acorn into Esprima output.
@ -884,7 +899,7 @@ const parsers = {
get jsx() {
if (this._jsx === null) {
this._jsx = acorn__namespace.Parser.extend(jsx__default['default'](), espree());
this._jsx = acorn__namespace.Parser.extend(jsx__default["default"](), espree());
}
return this._jsx;
},

View File

@ -56,6 +56,8 @@ export default () => Parser => {
code = String(code);
}
// save original source type in case of commonjs
const originalSourceType = opts.sourceType;
const options = normalizeOptions(opts);
const ecmaFeatures = options.ecmaFeatures || {};
const tokenTranslator =
@ -74,7 +76,7 @@ export default () => Parser => {
allowReserved: options.allowReserved,
// Truthy value is true for backward compatibility.
allowReturnOutsideFunction: Boolean(ecmaFeatures.globalReturn),
allowReturnOutsideFunction: options.allowReturnOutsideFunction,
// Collect tokens
onToken: token => {
@ -98,8 +100,13 @@ export default () => Parser => {
}
}, code);
// Initialize internal state.
/*
* Data that is unique to Espree and is not represented internally in
* Acorn. We put all of this data into a symbol property as a way to
* avoid potential naming conflicts with future versions of Acorn.
*/
this[STATE] = {
originalSourceType: originalSourceType || options.sourceType,
tokens: tokenTranslator ? [] : null,
comments: options.comment === true ? [] : null,
impliedStrict: ecmaFeatures.impliedStrict === true && this.options.ecmaVersion >= 5,
@ -144,7 +151,7 @@ export default () => Parser => {
const extra = this[STATE];
const program = super.parse();
program.sourceType = this.options.sourceType;
program.sourceType = extra.originalSourceType;
if (extra.comments) {
program.comments = extra.comments;

View File

@ -73,6 +73,11 @@ function normalizeSourceType(sourceType = "script") {
if (sourceType === "script" || sourceType === "module") {
return sourceType;
}
if (sourceType === "commonjs") {
return "script";
}
throw new Error("Invalid sourceType.");
}
@ -88,15 +93,20 @@ export function normalizeOptions(options) {
const ranges = options.range === true;
const locations = options.loc === true;
const allowReserved = ecmaVersion === 3 ? "never" : false;
const ecmaFeatures = options.ecmaFeatures || {};
const allowReturnOutsideFunction = options.sourceType === "commonjs" ||
Boolean(ecmaFeatures.globalReturn);
if (sourceType === "module" && ecmaVersion < 6) {
throw new Error("sourceType 'module' is not supported when ecmaVersion < 2015. Consider adding `{ ecmaVersion: 2015 }` to the parser options.");
}
return Object.assign({}, options, {
ecmaVersion,
sourceType,
ranges,
locations,
allowReserved
allowReserved,
allowReturnOutsideFunction
});
}

View File

@ -1,3 +1,3 @@
const version = "9.0.0";
const version = "9.1.0";
export default version;

View File

@ -16,7 +16,7 @@
],
"./package.json": "./package.json"
},
"version": "9.0.0",
"version": "9.1.0",
"files": [
"lib",
"dist/espree.cjs",
@ -31,9 +31,9 @@
},
"license": "BSD-2-Clause",
"dependencies": {
"acorn": "^8.5.0",
"acorn": "^8.6.0",
"acorn-jsx": "^5.3.1",
"eslint-visitor-keys": "^3.0.0"
"eslint-visitor-keys": "^3.1.0"
},
"devDependencies": {
"@rollup/plugin-commonjs": "^17.1.0",
@ -44,7 +44,7 @@
"eslint-config-eslint": "^7.0.0",
"eslint-plugin-jsdoc": "^32.2.0",
"eslint-plugin-node": "^11.1.0",
"eslint-release": "^3.1.2",
"eslint-release": "^3.2.0",
"esprima": "latest",
"esprima-fb": "^8001.2001.0-dev-harmony-fb",
"json-diff": "^0.5.4",

View File

@ -6,6 +6,18 @@
<sup>**Social Media Photo by [Matt Seymour](https://unsplash.com/@mattseymour) on [Unsplash](https://unsplash.com/)**</sup>
## Announcement 📣
There is a standard approach to recursion and more data-types than what JSON allow, and it's part of this [Structured Clone Module](https://github.com/ungap/structured-clone/#readme).
Beside acting as a polyfill, its `@ungap/structured-clone/json` export provides both `stringify` and `parse`, and it's been tested for being faster than *flatted*, but its produced output is also smaller than *flatted*.
The *@ungap/structured-clone* module is, in short, a drop in replacement for *flatted*, but it's not compatible with *flatted* specialized syntax.
However, if recursion, as well as more data-types, are what you are after, or interesting for your projects, consider switching to this new module whenever you can 👍
- - -
A super light (0.5K) and fast circular JSON parser, directly from the creator of [CircularJSON](https://github.com/WebReflection/circular-json/#circularjson).
Now available also for **[PHP](./php/flatted.php)**.

View File

@ -124,4 +124,4 @@ self.Flatted = (function (exports) {
return exports;
}({}));
})({});

View File

@ -1,6 +1,6 @@
{
"name": "flatted",
"version": "3.2.2",
"version": "3.2.4",
"description": "A super light and fast circular JSON parser.",
"unpkg": "min.js",
"types": "types.d.ts",
@ -12,9 +12,9 @@
"rollup:babel": "rollup --config rollup/babel.config.js && sed -i.bck 's/^var /self./' index.js && rm -rf index.js.bck && drop-babel-typeof index.js",
"min": "terser index.js -c -m -o min.js",
"size": "cat index.js | wc -c;cat min.js | wc -c;gzip -c9 min.js | wc -c;cat min.js | brotli | wc -c; cat es.js | brotli | wc -c",
"coveralls": "c8 report --reporter=text-lcov | coveralls",
"test": "c8 node test/index.js",
"test:php": "php php/test.php"
"test:php": "php php/test.php",
"coverage": "mkdir -p ./coverage; c8 report --reporter=text-lcov > ./coverage/lcov.info"
},
"repository": {
"type": "git",
@ -34,20 +34,20 @@
},
"homepage": "https://github.com/WebReflection/flatted#readme",
"devDependencies": {
"@babel/core": "^7.14.6",
"@babel/preset-env": "^7.14.7",
"@babel/core": "^7.16.0",
"@babel/preset-env": "^7.16.0",
"@ungap/structured-clone": "^0.3.4",
"ascjs": "^5.0.1",
"c8": "^7.7.3",
"c8": "^7.10.0",
"circular-json": "^0.5.9",
"circular-json-es6": "^2.0.2",
"coveralls": "^3.1.1",
"drop-babel-typeof": "^1.0.3",
"jsan": "^3.1.13",
"rollup": "^2.52.8",
"rollup": "^2.59.0",
"rollup-plugin-babel": "^4.4.0",
"rollup-plugin-node-resolve": "^5.2.0",
"rollup-plugin-terser": "^7.0.2",
"terser": "^5.7.1"
"terser": "^5.9.0"
},
"module": "./esm/index.js",
"type": "module",

View File

@ -1,6 +1,6 @@
{
"name": "eslint",
"version": "8.2.0",
"version": "8.3.0",
"author": "Nicholas C. Zakas <nicholas+npm@nczconsulting.com>",
"description": "An AST-based pattern checker for JavaScript.",
"bin": {
@ -56,10 +56,10 @@
"doctrine": "^3.0.0",
"enquirer": "^2.3.5",
"escape-string-regexp": "^4.0.0",
"eslint-scope": "^6.0.0",
"eslint-scope": "^7.1.0",
"eslint-utils": "^3.0.0",
"eslint-visitor-keys": "^3.0.0",
"espree": "^9.0.0",
"eslint-visitor-keys": "^3.1.0",
"espree": "^9.1.0",
"esquery": "^1.4.0",
"esutils": "^2.0.2",
"fast-deep-equal": "^3.1.3",