forked from public/fvtt-cthulhu-eternal
Initial import with skill sheet working
This commit is contained in:
336
node_modules/eslint/lib/languages/js/index.js
generated
vendored
Normal file
336
node_modules/eslint/lib/languages/js/index.js
generated
vendored
Normal file
@ -0,0 +1,336 @@
|
||||
/**
|
||||
* @fileoverview JavaScript Language Object
|
||||
* @author Nicholas C. Zakas
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
const { SourceCode } = require("./source-code");
|
||||
const createDebug = require("debug");
|
||||
const astUtils = require("../../shared/ast-utils");
|
||||
const espree = require("espree");
|
||||
const eslintScope = require("eslint-scope");
|
||||
const evk = require("eslint-visitor-keys");
|
||||
const { validateLanguageOptions } = require("./validate-language-options");
|
||||
const { LATEST_ECMA_VERSION } = require("../../../conf/ecma-version");
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Type Definitions
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/** @typedef {import("@eslint/core").File} File */
|
||||
/** @typedef {import("@eslint/core").Language} Language */
|
||||
/** @typedef {import("@eslint/core").OkParseResult} OkParseResult */
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
const debug = createDebug("eslint:languages:js");
|
||||
const DEFAULT_ECMA_VERSION = 5;
|
||||
const parserSymbol = Symbol.for("eslint.RuleTester.parser");
|
||||
|
||||
/**
|
||||
* Analyze scope of the given AST.
|
||||
* @param {ASTNode} ast The `Program` node to analyze.
|
||||
* @param {LanguageOptions} languageOptions The parser options.
|
||||
* @param {Record<string, string[]>} visitorKeys The visitor keys.
|
||||
* @returns {ScopeManager} The analysis result.
|
||||
*/
|
||||
function analyzeScope(ast, languageOptions, visitorKeys) {
|
||||
const parserOptions = languageOptions.parserOptions;
|
||||
const ecmaFeatures = parserOptions.ecmaFeatures || {};
|
||||
const ecmaVersion = languageOptions.ecmaVersion || DEFAULT_ECMA_VERSION;
|
||||
|
||||
return eslintScope.analyze(ast, {
|
||||
ignoreEval: true,
|
||||
nodejsScope: ecmaFeatures.globalReturn,
|
||||
impliedStrict: ecmaFeatures.impliedStrict,
|
||||
ecmaVersion: typeof ecmaVersion === "number" ? ecmaVersion : 6,
|
||||
sourceType: languageOptions.sourceType || "script",
|
||||
childVisitorKeys: visitorKeys || evk.KEYS,
|
||||
fallback: evk.getKeys
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if a given object is Espree.
|
||||
* @param {Object} parser The parser to check.
|
||||
* @returns {boolean} True if the parser is Espree or false if not.
|
||||
*/
|
||||
function isEspree(parser) {
|
||||
return !!(parser === espree || parser[parserSymbol] === espree);
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize ECMAScript version from the initial config into languageOptions (year)
|
||||
* format.
|
||||
* @param {any} [ecmaVersion] ECMAScript version from the initial config
|
||||
* @returns {number} normalized ECMAScript version
|
||||
*/
|
||||
function normalizeEcmaVersionForLanguageOptions(ecmaVersion) {
|
||||
|
||||
switch (ecmaVersion) {
|
||||
case 3:
|
||||
return 3;
|
||||
|
||||
// void 0 = no ecmaVersion specified so use the default
|
||||
case 5:
|
||||
case void 0:
|
||||
return 5;
|
||||
|
||||
default:
|
||||
if (typeof ecmaVersion === "number") {
|
||||
return ecmaVersion >= 2015 ? ecmaVersion : ecmaVersion + 2009;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We default to the latest supported ecmaVersion for everything else.
|
||||
* Remember, this is for languageOptions.ecmaVersion, which sets the version
|
||||
* that is used for a number of processes inside of ESLint. It's normally
|
||||
* safe to assume people want the latest unless otherwise specified.
|
||||
*/
|
||||
return LATEST_ECMA_VERSION;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Exports
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @type {Language}
|
||||
*/
|
||||
module.exports = {
|
||||
|
||||
fileType: "text",
|
||||
lineStart: 1,
|
||||
columnStart: 0,
|
||||
nodeTypeKey: "type",
|
||||
visitorKeys: evk.KEYS,
|
||||
|
||||
defaultLanguageOptions: {
|
||||
sourceType: "module",
|
||||
ecmaVersion: "latest",
|
||||
parser: espree,
|
||||
parserOptions: {}
|
||||
},
|
||||
|
||||
validateLanguageOptions,
|
||||
|
||||
/**
|
||||
* Normalizes the language options.
|
||||
* @param {Object} languageOptions The language options to normalize.
|
||||
* @returns {Object} The normalized language options.
|
||||
*/
|
||||
normalizeLanguageOptions(languageOptions) {
|
||||
|
||||
languageOptions.ecmaVersion = normalizeEcmaVersionForLanguageOptions(
|
||||
languageOptions.ecmaVersion
|
||||
);
|
||||
|
||||
// Espree expects this information to be passed in
|
||||
if (isEspree(languageOptions.parser)) {
|
||||
const parserOptions = languageOptions.parserOptions;
|
||||
|
||||
if (languageOptions.sourceType) {
|
||||
|
||||
parserOptions.sourceType = languageOptions.sourceType;
|
||||
|
||||
if (
|
||||
parserOptions.sourceType === "module" &&
|
||||
parserOptions.ecmaFeatures &&
|
||||
parserOptions.ecmaFeatures.globalReturn
|
||||
) {
|
||||
parserOptions.ecmaFeatures.globalReturn = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return languageOptions;
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Determines if a given node matches a given selector class.
|
||||
* @param {string} className The class name to check.
|
||||
* @param {ASTNode} node The node to check.
|
||||
* @param {Array<ASTNode>} ancestry The ancestry of the node.
|
||||
* @returns {boolean} True if there's a match, false if not.
|
||||
* @throws {Error} When an unknown class name is passed.
|
||||
*/
|
||||
matchesSelectorClass(className, node, ancestry) {
|
||||
|
||||
/*
|
||||
* Copyright (c) 2013, Joel Feenstra
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the ESQuery nor the names of its contributors may
|
||||
* be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL JOEL FEENSTRA BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
switch (className.toLowerCase()) {
|
||||
|
||||
case "statement":
|
||||
if (node.type.slice(-9) === "Statement") {
|
||||
return true;
|
||||
}
|
||||
|
||||
// fallthrough: interface Declaration <: Statement { }
|
||||
|
||||
case "declaration":
|
||||
return node.type.slice(-11) === "Declaration";
|
||||
|
||||
case "pattern":
|
||||
if (node.type.slice(-7) === "Pattern") {
|
||||
return true;
|
||||
}
|
||||
|
||||
// fallthrough: interface Expression <: Node, Pattern { }
|
||||
|
||||
case "expression":
|
||||
return node.type.slice(-10) === "Expression" ||
|
||||
node.type.slice(-7) === "Literal" ||
|
||||
(
|
||||
node.type === "Identifier" &&
|
||||
(ancestry.length === 0 || ancestry[0].type !== "MetaProperty")
|
||||
) ||
|
||||
node.type === "MetaProperty";
|
||||
|
||||
case "function":
|
||||
return node.type === "FunctionDeclaration" ||
|
||||
node.type === "FunctionExpression" ||
|
||||
node.type === "ArrowFunctionExpression";
|
||||
|
||||
default:
|
||||
throw new Error(`Unknown class name: ${className}`);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Parses the given file into an AST.
|
||||
* @param {File} file The virtual file to parse.
|
||||
* @param {Object} options Additional options passed from ESLint.
|
||||
* @param {LanguageOptions} options.languageOptions The language options.
|
||||
* @returns {Object} The result of parsing.
|
||||
*/
|
||||
parse(file, { languageOptions }) {
|
||||
|
||||
// Note: BOM already removed
|
||||
const { body: text, path: filePath } = file;
|
||||
const textToParse = text.replace(astUtils.shebangPattern, (match, captured) => `//${captured}`);
|
||||
const { ecmaVersion, sourceType, parser } = languageOptions;
|
||||
const parserOptions = Object.assign(
|
||||
{ ecmaVersion, sourceType },
|
||||
languageOptions.parserOptions,
|
||||
{
|
||||
loc: true,
|
||||
range: true,
|
||||
raw: true,
|
||||
tokens: true,
|
||||
comment: true,
|
||||
eslintVisitorKeys: true,
|
||||
eslintScopeManager: true,
|
||||
filePath
|
||||
}
|
||||
);
|
||||
|
||||
/*
|
||||
* Check for parsing errors first. If there's a parsing error, nothing
|
||||
* else can happen. However, a parsing error does not throw an error
|
||||
* from this method - it's just considered a fatal error message, a
|
||||
* problem that ESLint identified just like any other.
|
||||
*/
|
||||
try {
|
||||
debug("Parsing:", filePath);
|
||||
const parseResult = (typeof parser.parseForESLint === "function")
|
||||
? parser.parseForESLint(textToParse, parserOptions)
|
||||
: { ast: parser.parse(textToParse, parserOptions) };
|
||||
|
||||
debug("Parsing successful:", filePath);
|
||||
|
||||
const {
|
||||
ast,
|
||||
services: parserServices = {},
|
||||
visitorKeys = evk.KEYS,
|
||||
scopeManager
|
||||
} = parseResult;
|
||||
|
||||
return {
|
||||
ok: true,
|
||||
ast,
|
||||
parserServices,
|
||||
visitorKeys,
|
||||
scopeManager
|
||||
};
|
||||
} catch (ex) {
|
||||
|
||||
// If the message includes a leading line number, strip it:
|
||||
const message = ex.message.replace(/^line \d+:/iu, "").trim();
|
||||
|
||||
debug("%s\n%s", message, ex.stack);
|
||||
|
||||
return {
|
||||
ok: false,
|
||||
errors: [{
|
||||
message,
|
||||
line: ex.lineNumber,
|
||||
column: ex.column
|
||||
}]
|
||||
};
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates a new `SourceCode` object from the given information.
|
||||
* @param {File} file The virtual file to create a `SourceCode` object from.
|
||||
* @param {OkParseResult} parseResult The result returned from `parse()`.
|
||||
* @param {Object} options Additional options passed from ESLint.
|
||||
* @param {LanguageOptions} options.languageOptions The language options.
|
||||
* @returns {SourceCode} The new `SourceCode` object.
|
||||
*/
|
||||
createSourceCode(file, parseResult, { languageOptions }) {
|
||||
|
||||
const { body: text, path: filePath, bom: hasBOM } = file;
|
||||
const { ast, parserServices, visitorKeys } = parseResult;
|
||||
|
||||
debug("Scope analysis:", filePath);
|
||||
const scopeManager = parseResult.scopeManager || analyzeScope(ast, languageOptions, visitorKeys);
|
||||
|
||||
debug("Scope analysis successful:", filePath);
|
||||
|
||||
return new SourceCode({
|
||||
text,
|
||||
ast,
|
||||
hasBOM,
|
||||
parserServices,
|
||||
scopeManager,
|
||||
visitorKeys
|
||||
});
|
||||
}
|
||||
|
||||
};
|
7
node_modules/eslint/lib/languages/js/source-code/index.js
generated
vendored
Normal file
7
node_modules/eslint/lib/languages/js/source-code/index.js
generated
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
"use strict";
|
||||
|
||||
const SourceCode = require("./source-code");
|
||||
|
||||
module.exports = {
|
||||
SourceCode
|
||||
};
|
1202
node_modules/eslint/lib/languages/js/source-code/source-code.js
generated
vendored
Normal file
1202
node_modules/eslint/lib/languages/js/source-code/source-code.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
57
node_modules/eslint/lib/languages/js/source-code/token-store/backward-token-comment-cursor.js
generated
vendored
Normal file
57
node_modules/eslint/lib/languages/js/source-code/token-store/backward-token-comment-cursor.js
generated
vendored
Normal file
@ -0,0 +1,57 @@
|
||||
/**
|
||||
* @fileoverview Define the cursor which iterates tokens and comments in reverse.
|
||||
* @author Toru Nagashima
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const Cursor = require("./cursor");
|
||||
const utils = require("./utils");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Exports
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* The cursor which iterates tokens and comments in reverse.
|
||||
*/
|
||||
module.exports = class BackwardTokenCommentCursor extends Cursor {
|
||||
|
||||
/**
|
||||
* Initializes this cursor.
|
||||
* @param {Token[]} tokens The array of tokens.
|
||||
* @param {Comment[]} comments The array of comments.
|
||||
* @param {Object} indexMap The map from locations to indices in `tokens`.
|
||||
* @param {number} startLoc The start location of the iteration range.
|
||||
* @param {number} endLoc The end location of the iteration range.
|
||||
*/
|
||||
constructor(tokens, comments, indexMap, startLoc, endLoc) {
|
||||
super();
|
||||
this.tokens = tokens;
|
||||
this.comments = comments;
|
||||
this.tokenIndex = utils.getLastIndex(tokens, indexMap, endLoc);
|
||||
this.commentIndex = utils.search(comments, endLoc) - 1;
|
||||
this.border = startLoc;
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
moveNext() {
|
||||
const token = (this.tokenIndex >= 0) ? this.tokens[this.tokenIndex] : null;
|
||||
const comment = (this.commentIndex >= 0) ? this.comments[this.commentIndex] : null;
|
||||
|
||||
if (token && (!comment || token.range[1] > comment.range[1])) {
|
||||
this.current = token;
|
||||
this.tokenIndex -= 1;
|
||||
} else if (comment) {
|
||||
this.current = comment;
|
||||
this.commentIndex -= 1;
|
||||
} else {
|
||||
this.current = null;
|
||||
}
|
||||
|
||||
return Boolean(this.current) && (this.border === -1 || this.current.range[0] >= this.border);
|
||||
}
|
||||
};
|
58
node_modules/eslint/lib/languages/js/source-code/token-store/backward-token-cursor.js
generated
vendored
Normal file
58
node_modules/eslint/lib/languages/js/source-code/token-store/backward-token-cursor.js
generated
vendored
Normal file
@ -0,0 +1,58 @@
|
||||
/**
|
||||
* @fileoverview Define the cursor which iterates tokens only in reverse.
|
||||
* @author Toru Nagashima
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const Cursor = require("./cursor");
|
||||
const { getLastIndex, getFirstIndex } = require("./utils");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Exports
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* The cursor which iterates tokens only in reverse.
|
||||
*/
|
||||
module.exports = class BackwardTokenCursor extends Cursor {
|
||||
|
||||
/**
|
||||
* Initializes this cursor.
|
||||
* @param {Token[]} tokens The array of tokens.
|
||||
* @param {Comment[]} comments The array of comments.
|
||||
* @param {Object} indexMap The map from locations to indices in `tokens`.
|
||||
* @param {number} startLoc The start location of the iteration range.
|
||||
* @param {number} endLoc The end location of the iteration range.
|
||||
*/
|
||||
constructor(tokens, comments, indexMap, startLoc, endLoc) {
|
||||
super();
|
||||
this.tokens = tokens;
|
||||
this.index = getLastIndex(tokens, indexMap, endLoc);
|
||||
this.indexEnd = getFirstIndex(tokens, indexMap, startLoc);
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
moveNext() {
|
||||
if (this.index >= this.indexEnd) {
|
||||
this.current = this.tokens[this.index];
|
||||
this.index -= 1;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* Shorthand for performance.
|
||||
*
|
||||
*/
|
||||
|
||||
/** @inheritdoc */
|
||||
getOneToken() {
|
||||
return (this.index >= this.indexEnd) ? this.tokens[this.index] : null;
|
||||
}
|
||||
};
|
76
node_modules/eslint/lib/languages/js/source-code/token-store/cursor.js
generated
vendored
Normal file
76
node_modules/eslint/lib/languages/js/source-code/token-store/cursor.js
generated
vendored
Normal file
@ -0,0 +1,76 @@
|
||||
/**
|
||||
* @fileoverview Define the abstract class about cursors which iterate tokens.
|
||||
* @author Toru Nagashima
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Exports
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* The abstract class about cursors which iterate tokens.
|
||||
*
|
||||
* This class has 2 abstract methods.
|
||||
*
|
||||
* - `current: Token | Comment | null` ... The current token.
|
||||
* - `moveNext(): boolean` ... Moves this cursor to the next token. If the next token didn't exist, it returns `false`.
|
||||
*
|
||||
* This is similar to ES2015 Iterators.
|
||||
* However, Iterators were slow (at 2017-01), so I created this class as similar to C# IEnumerable.
|
||||
*
|
||||
* There are the following known sub classes.
|
||||
*
|
||||
* - ForwardTokenCursor .......... The cursor which iterates tokens only.
|
||||
* - BackwardTokenCursor ......... The cursor which iterates tokens only in reverse.
|
||||
* - ForwardTokenCommentCursor ... The cursor which iterates tokens and comments.
|
||||
* - BackwardTokenCommentCursor .. The cursor which iterates tokens and comments in reverse.
|
||||
* - DecorativeCursor
|
||||
* - FilterCursor ............ The cursor which ignores the specified tokens.
|
||||
* - SkipCursor .............. The cursor which ignores the first few tokens.
|
||||
* - LimitCursor ............. The cursor which limits the count of tokens.
|
||||
*
|
||||
*/
|
||||
module.exports = class Cursor {
|
||||
|
||||
/**
|
||||
* Initializes this cursor.
|
||||
*/
|
||||
constructor() {
|
||||
this.current = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the first token.
|
||||
* This consumes this cursor.
|
||||
* @returns {Token|Comment} The first token or null.
|
||||
*/
|
||||
getOneToken() {
|
||||
return this.moveNext() ? this.current : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the first tokens.
|
||||
* This consumes this cursor.
|
||||
* @returns {(Token|Comment)[]} All tokens.
|
||||
*/
|
||||
getAllTokens() {
|
||||
const tokens = [];
|
||||
|
||||
while (this.moveNext()) {
|
||||
tokens.push(this.current);
|
||||
}
|
||||
|
||||
return tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves this cursor to the next token.
|
||||
* @returns {boolean} `true` if the next token exists.
|
||||
* @abstract
|
||||
*/
|
||||
/* c8 ignore next */
|
||||
moveNext() { // eslint-disable-line class-methods-use-this -- Unused
|
||||
throw new Error("Not implemented.");
|
||||
}
|
||||
};
|
92
node_modules/eslint/lib/languages/js/source-code/token-store/cursors.js
generated
vendored
Normal file
92
node_modules/eslint/lib/languages/js/source-code/token-store/cursors.js
generated
vendored
Normal file
@ -0,0 +1,92 @@
|
||||
/**
|
||||
* @fileoverview Define 2 token factories; forward and backward.
|
||||
* @author Toru Nagashima
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const BackwardTokenCommentCursor = require("./backward-token-comment-cursor");
|
||||
const BackwardTokenCursor = require("./backward-token-cursor");
|
||||
const FilterCursor = require("./filter-cursor");
|
||||
const ForwardTokenCommentCursor = require("./forward-token-comment-cursor");
|
||||
const ForwardTokenCursor = require("./forward-token-cursor");
|
||||
const LimitCursor = require("./limit-cursor");
|
||||
const SkipCursor = require("./skip-cursor");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* The cursor factory.
|
||||
* @private
|
||||
*/
|
||||
class CursorFactory {
|
||||
|
||||
/**
|
||||
* Initializes this cursor.
|
||||
* @param {Function} TokenCursor The class of the cursor which iterates tokens only.
|
||||
* @param {Function} TokenCommentCursor The class of the cursor which iterates the mix of tokens and comments.
|
||||
*/
|
||||
constructor(TokenCursor, TokenCommentCursor) {
|
||||
this.TokenCursor = TokenCursor;
|
||||
this.TokenCommentCursor = TokenCommentCursor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a base cursor instance that can be decorated by createCursor.
|
||||
* @param {Token[]} tokens The array of tokens.
|
||||
* @param {Comment[]} comments The array of comments.
|
||||
* @param {Object} indexMap The map from locations to indices in `tokens`.
|
||||
* @param {number} startLoc The start location of the iteration range.
|
||||
* @param {number} endLoc The end location of the iteration range.
|
||||
* @param {boolean} includeComments The flag to iterate comments as well.
|
||||
* @returns {Cursor} The created base cursor.
|
||||
*/
|
||||
createBaseCursor(tokens, comments, indexMap, startLoc, endLoc, includeComments) {
|
||||
const Cursor = includeComments ? this.TokenCommentCursor : this.TokenCursor;
|
||||
|
||||
return new Cursor(tokens, comments, indexMap, startLoc, endLoc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a cursor that iterates tokens with normalized options.
|
||||
* @param {Token[]} tokens The array of tokens.
|
||||
* @param {Comment[]} comments The array of comments.
|
||||
* @param {Object} indexMap The map from locations to indices in `tokens`.
|
||||
* @param {number} startLoc The start location of the iteration range.
|
||||
* @param {number} endLoc The end location of the iteration range.
|
||||
* @param {boolean} includeComments The flag to iterate comments as well.
|
||||
* @param {Function|null} filter The predicate function to choose tokens.
|
||||
* @param {number} skip The count of tokens the cursor skips.
|
||||
* @param {number} count The maximum count of tokens the cursor iterates. Zero is no iteration for backward compatibility.
|
||||
* @returns {Cursor} The created cursor.
|
||||
*/
|
||||
createCursor(tokens, comments, indexMap, startLoc, endLoc, includeComments, filter, skip, count) {
|
||||
let cursor = this.createBaseCursor(tokens, comments, indexMap, startLoc, endLoc, includeComments);
|
||||
|
||||
if (filter) {
|
||||
cursor = new FilterCursor(cursor, filter);
|
||||
}
|
||||
if (skip >= 1) {
|
||||
cursor = new SkipCursor(cursor, skip);
|
||||
}
|
||||
if (count >= 0) {
|
||||
cursor = new LimitCursor(cursor, count);
|
||||
}
|
||||
|
||||
return cursor;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Exports
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
forward: new CursorFactory(ForwardTokenCursor, ForwardTokenCommentCursor),
|
||||
backward: new CursorFactory(BackwardTokenCursor, BackwardTokenCommentCursor)
|
||||
};
|
39
node_modules/eslint/lib/languages/js/source-code/token-store/decorative-cursor.js
generated
vendored
Normal file
39
node_modules/eslint/lib/languages/js/source-code/token-store/decorative-cursor.js
generated
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
/**
|
||||
* @fileoverview Define the abstract class about cursors which manipulate another cursor.
|
||||
* @author Toru Nagashima
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const Cursor = require("./cursor");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Exports
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* The abstract class about cursors which manipulate another cursor.
|
||||
*/
|
||||
module.exports = class DecorativeCursor extends Cursor {
|
||||
|
||||
/**
|
||||
* Initializes this cursor.
|
||||
* @param {Cursor} cursor The cursor to be decorated.
|
||||
*/
|
||||
constructor(cursor) {
|
||||
super();
|
||||
this.cursor = cursor;
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
moveNext() {
|
||||
const retv = this.cursor.moveNext();
|
||||
|
||||
this.current = this.cursor.current;
|
||||
|
||||
return retv;
|
||||
}
|
||||
};
|
43
node_modules/eslint/lib/languages/js/source-code/token-store/filter-cursor.js
generated
vendored
Normal file
43
node_modules/eslint/lib/languages/js/source-code/token-store/filter-cursor.js
generated
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
/**
|
||||
* @fileoverview Define the cursor which ignores specified tokens.
|
||||
* @author Toru Nagashima
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const DecorativeCursor = require("./decorative-cursor");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Exports
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* The decorative cursor which ignores specified tokens.
|
||||
*/
|
||||
module.exports = class FilterCursor extends DecorativeCursor {
|
||||
|
||||
/**
|
||||
* Initializes this cursor.
|
||||
* @param {Cursor} cursor The cursor to be decorated.
|
||||
* @param {Function} predicate The predicate function to decide tokens this cursor iterates.
|
||||
*/
|
||||
constructor(cursor, predicate) {
|
||||
super(cursor);
|
||||
this.predicate = predicate;
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
moveNext() {
|
||||
const predicate = this.predicate;
|
||||
|
||||
while (super.moveNext()) {
|
||||
if (predicate(this.current)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
57
node_modules/eslint/lib/languages/js/source-code/token-store/forward-token-comment-cursor.js
generated
vendored
Normal file
57
node_modules/eslint/lib/languages/js/source-code/token-store/forward-token-comment-cursor.js
generated
vendored
Normal file
@ -0,0 +1,57 @@
|
||||
/**
|
||||
* @fileoverview Define the cursor which iterates tokens and comments.
|
||||
* @author Toru Nagashima
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const Cursor = require("./cursor");
|
||||
const { getFirstIndex, search } = require("./utils");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Exports
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* The cursor which iterates tokens and comments.
|
||||
*/
|
||||
module.exports = class ForwardTokenCommentCursor extends Cursor {
|
||||
|
||||
/**
|
||||
* Initializes this cursor.
|
||||
* @param {Token[]} tokens The array of tokens.
|
||||
* @param {Comment[]} comments The array of comments.
|
||||
* @param {Object} indexMap The map from locations to indices in `tokens`.
|
||||
* @param {number} startLoc The start location of the iteration range.
|
||||
* @param {number} endLoc The end location of the iteration range.
|
||||
*/
|
||||
constructor(tokens, comments, indexMap, startLoc, endLoc) {
|
||||
super();
|
||||
this.tokens = tokens;
|
||||
this.comments = comments;
|
||||
this.tokenIndex = getFirstIndex(tokens, indexMap, startLoc);
|
||||
this.commentIndex = search(comments, startLoc);
|
||||
this.border = endLoc;
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
moveNext() {
|
||||
const token = (this.tokenIndex < this.tokens.length) ? this.tokens[this.tokenIndex] : null;
|
||||
const comment = (this.commentIndex < this.comments.length) ? this.comments[this.commentIndex] : null;
|
||||
|
||||
if (token && (!comment || token.range[0] < comment.range[0])) {
|
||||
this.current = token;
|
||||
this.tokenIndex += 1;
|
||||
} else if (comment) {
|
||||
this.current = comment;
|
||||
this.commentIndex += 1;
|
||||
} else {
|
||||
this.current = null;
|
||||
}
|
||||
|
||||
return Boolean(this.current) && (this.border === -1 || this.current.range[1] <= this.border);
|
||||
}
|
||||
};
|
63
node_modules/eslint/lib/languages/js/source-code/token-store/forward-token-cursor.js
generated
vendored
Normal file
63
node_modules/eslint/lib/languages/js/source-code/token-store/forward-token-cursor.js
generated
vendored
Normal file
@ -0,0 +1,63 @@
|
||||
/**
|
||||
* @fileoverview Define the cursor which iterates tokens only.
|
||||
* @author Toru Nagashima
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const Cursor = require("./cursor");
|
||||
const { getFirstIndex, getLastIndex } = require("./utils");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Exports
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* The cursor which iterates tokens only.
|
||||
*/
|
||||
module.exports = class ForwardTokenCursor extends Cursor {
|
||||
|
||||
/**
|
||||
* Initializes this cursor.
|
||||
* @param {Token[]} tokens The array of tokens.
|
||||
* @param {Comment[]} comments The array of comments.
|
||||
* @param {Object} indexMap The map from locations to indices in `tokens`.
|
||||
* @param {number} startLoc The start location of the iteration range.
|
||||
* @param {number} endLoc The end location of the iteration range.
|
||||
*/
|
||||
constructor(tokens, comments, indexMap, startLoc, endLoc) {
|
||||
super();
|
||||
this.tokens = tokens;
|
||||
this.index = getFirstIndex(tokens, indexMap, startLoc);
|
||||
this.indexEnd = getLastIndex(tokens, indexMap, endLoc);
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
moveNext() {
|
||||
if (this.index <= this.indexEnd) {
|
||||
this.current = this.tokens[this.index];
|
||||
this.index += 1;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* Shorthand for performance.
|
||||
*
|
||||
*/
|
||||
|
||||
/** @inheritdoc */
|
||||
getOneToken() {
|
||||
return (this.index <= this.indexEnd) ? this.tokens[this.index] : null;
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
getAllTokens() {
|
||||
return this.tokens.slice(this.index, this.indexEnd + 1);
|
||||
}
|
||||
};
|
627
node_modules/eslint/lib/languages/js/source-code/token-store/index.js
generated
vendored
Normal file
627
node_modules/eslint/lib/languages/js/source-code/token-store/index.js
generated
vendored
Normal file
@ -0,0 +1,627 @@
|
||||
/**
|
||||
* @fileoverview Object to handle access and retrieval of tokens.
|
||||
* @author Brandon Mills
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const { isCommentToken } = require("@eslint-community/eslint-utils");
|
||||
const assert = require("../../../../shared/assert");
|
||||
const cursors = require("./cursors");
|
||||
const ForwardTokenCursor = require("./forward-token-cursor");
|
||||
const PaddedTokenCursor = require("./padded-token-cursor");
|
||||
const utils = require("./utils");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const TOKENS = Symbol("tokens");
|
||||
const COMMENTS = Symbol("comments");
|
||||
const INDEX_MAP = Symbol("indexMap");
|
||||
|
||||
/**
|
||||
* Creates the map from locations to indices in `tokens`.
|
||||
*
|
||||
* The first/last location of tokens is mapped to the index of the token.
|
||||
* The first/last location of comments is mapped to the index of the next token of each comment.
|
||||
* @param {Token[]} tokens The array of tokens.
|
||||
* @param {Comment[]} comments The array of comments.
|
||||
* @returns {Object} The map from locations to indices in `tokens`.
|
||||
* @private
|
||||
*/
|
||||
function createIndexMap(tokens, comments) {
|
||||
const map = Object.create(null);
|
||||
let tokenIndex = 0;
|
||||
let commentIndex = 0;
|
||||
let nextStart;
|
||||
let range;
|
||||
|
||||
while (tokenIndex < tokens.length || commentIndex < comments.length) {
|
||||
nextStart = (commentIndex < comments.length) ? comments[commentIndex].range[0] : Number.MAX_SAFE_INTEGER;
|
||||
while (tokenIndex < tokens.length && (range = tokens[tokenIndex].range)[0] < nextStart) {
|
||||
map[range[0]] = tokenIndex;
|
||||
map[range[1] - 1] = tokenIndex;
|
||||
tokenIndex += 1;
|
||||
}
|
||||
|
||||
nextStart = (tokenIndex < tokens.length) ? tokens[tokenIndex].range[0] : Number.MAX_SAFE_INTEGER;
|
||||
while (commentIndex < comments.length && (range = comments[commentIndex].range)[0] < nextStart) {
|
||||
map[range[0]] = tokenIndex;
|
||||
map[range[1] - 1] = tokenIndex;
|
||||
commentIndex += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the cursor iterates tokens with options.
|
||||
* @param {CursorFactory} factory The cursor factory to initialize cursor.
|
||||
* @param {Token[]} tokens The array of tokens.
|
||||
* @param {Comment[]} comments The array of comments.
|
||||
* @param {Object} indexMap The map from locations to indices in `tokens`.
|
||||
* @param {number} startLoc The start location of the iteration range.
|
||||
* @param {number} endLoc The end location of the iteration range.
|
||||
* @param {number|Function|Object} [opts=0] The option object. If this is a number then it's `opts.skip`. If this is a function then it's `opts.filter`.
|
||||
* @param {boolean} [opts.includeComments=false] The flag to iterate comments as well.
|
||||
* @param {Function|null} [opts.filter=null] The predicate function to choose tokens.
|
||||
* @param {number} [opts.skip=0] The count of tokens the cursor skips.
|
||||
* @returns {Cursor} The created cursor.
|
||||
* @private
|
||||
*/
|
||||
function createCursorWithSkip(factory, tokens, comments, indexMap, startLoc, endLoc, opts) {
|
||||
let includeComments = false;
|
||||
let skip = 0;
|
||||
let filter = null;
|
||||
|
||||
if (typeof opts === "number") {
|
||||
skip = opts | 0;
|
||||
} else if (typeof opts === "function") {
|
||||
filter = opts;
|
||||
} else if (opts) {
|
||||
includeComments = !!opts.includeComments;
|
||||
skip = opts.skip | 0;
|
||||
filter = opts.filter || null;
|
||||
}
|
||||
assert(skip >= 0, "options.skip should be zero or a positive integer.");
|
||||
assert(!filter || typeof filter === "function", "options.filter should be a function.");
|
||||
|
||||
return factory.createCursor(tokens, comments, indexMap, startLoc, endLoc, includeComments, filter, skip, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the cursor iterates tokens with options.
|
||||
* @param {CursorFactory} factory The cursor factory to initialize cursor.
|
||||
* @param {Token[]} tokens The array of tokens.
|
||||
* @param {Comment[]} comments The array of comments.
|
||||
* @param {Object} indexMap The map from locations to indices in `tokens`.
|
||||
* @param {number} startLoc The start location of the iteration range.
|
||||
* @param {number} endLoc The end location of the iteration range.
|
||||
* @param {number|Function|Object} [opts=0] The option object. If this is a number then it's `opts.count`. If this is a function then it's `opts.filter`.
|
||||
* @param {boolean} [opts.includeComments] The flag to iterate comments as well.
|
||||
* @param {Function|null} [opts.filter=null] The predicate function to choose tokens.
|
||||
* @param {number} [opts.count=0] The maximum count of tokens the cursor iterates. Zero is no iteration for backward compatibility.
|
||||
* @returns {Cursor} The created cursor.
|
||||
* @private
|
||||
*/
|
||||
function createCursorWithCount(factory, tokens, comments, indexMap, startLoc, endLoc, opts) {
|
||||
let includeComments = false;
|
||||
let count = 0;
|
||||
let countExists = false;
|
||||
let filter = null;
|
||||
|
||||
if (typeof opts === "number") {
|
||||
count = opts | 0;
|
||||
countExists = true;
|
||||
} else if (typeof opts === "function") {
|
||||
filter = opts;
|
||||
} else if (opts) {
|
||||
includeComments = !!opts.includeComments;
|
||||
count = opts.count | 0;
|
||||
countExists = typeof opts.count === "number";
|
||||
filter = opts.filter || null;
|
||||
}
|
||||
assert(count >= 0, "options.count should be zero or a positive integer.");
|
||||
assert(!filter || typeof filter === "function", "options.filter should be a function.");
|
||||
|
||||
return factory.createCursor(tokens, comments, indexMap, startLoc, endLoc, includeComments, filter, 0, countExists ? count : -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the cursor iterates tokens with options.
|
||||
* This is overload function of the below.
|
||||
* @param {Token[]} tokens The array of tokens.
|
||||
* @param {Comment[]} comments The array of comments.
|
||||
* @param {Object} indexMap The map from locations to indices in `tokens`.
|
||||
* @param {number} startLoc The start location of the iteration range.
|
||||
* @param {number} endLoc The end location of the iteration range.
|
||||
* @param {Function|Object} opts The option object. If this is a function then it's `opts.filter`.
|
||||
* @param {boolean} [opts.includeComments] The flag to iterate comments as well.
|
||||
* @param {Function|null} [opts.filter=null] The predicate function to choose tokens.
|
||||
* @param {number} [opts.count=0] The maximum count of tokens the cursor iterates. Zero is no iteration for backward compatibility.
|
||||
* @returns {Cursor} The created cursor.
|
||||
* @private
|
||||
*/
|
||||
/**
|
||||
* Creates the cursor iterates tokens with options.
|
||||
* @param {Token[]} tokens The array of tokens.
|
||||
* @param {Comment[]} comments The array of comments.
|
||||
* @param {Object} indexMap The map from locations to indices in `tokens`.
|
||||
* @param {number} startLoc The start location of the iteration range.
|
||||
* @param {number} endLoc The end location of the iteration range.
|
||||
* @param {number} [beforeCount=0] The number of tokens before the node to retrieve.
|
||||
* @param {boolean} [afterCount=0] The number of tokens after the node to retrieve.
|
||||
* @returns {Cursor} The created cursor.
|
||||
* @private
|
||||
*/
|
||||
function createCursorWithPadding(tokens, comments, indexMap, startLoc, endLoc, beforeCount, afterCount) {
|
||||
if (typeof beforeCount === "undefined" && typeof afterCount === "undefined") {
|
||||
return new ForwardTokenCursor(tokens, comments, indexMap, startLoc, endLoc);
|
||||
}
|
||||
if (typeof beforeCount === "number" || typeof beforeCount === "undefined") {
|
||||
return new PaddedTokenCursor(tokens, comments, indexMap, startLoc, endLoc, beforeCount | 0, afterCount | 0);
|
||||
}
|
||||
return createCursorWithCount(cursors.forward, tokens, comments, indexMap, startLoc, endLoc, beforeCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets comment tokens that are adjacent to the current cursor position.
|
||||
* @param {Cursor} cursor A cursor instance.
|
||||
* @returns {Array} An array of comment tokens adjacent to the current cursor position.
|
||||
* @private
|
||||
*/
|
||||
function getAdjacentCommentTokensFromCursor(cursor) {
|
||||
const tokens = [];
|
||||
let currentToken = cursor.getOneToken();
|
||||
|
||||
while (currentToken && isCommentToken(currentToken)) {
|
||||
tokens.push(currentToken);
|
||||
currentToken = cursor.getOneToken();
|
||||
}
|
||||
|
||||
return tokens;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Exports
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* The token store.
|
||||
*
|
||||
* This class provides methods to get tokens by locations as fast as possible.
|
||||
* The methods are a part of public API, so we should be careful if it changes this class.
|
||||
*
|
||||
* People can get tokens in O(1) by the hash map which is mapping from the location of tokens/comments to tokens.
|
||||
* Also people can get a mix of tokens and comments in O(log k), the k is the number of comments.
|
||||
* Assuming that comments to be much fewer than tokens, this does not make hash map from token's locations to comments to reduce memory cost.
|
||||
* This uses binary-searching instead for comments.
|
||||
*/
|
||||
module.exports = class TokenStore {
|
||||
|
||||
/**
|
||||
* Initializes this token store.
|
||||
* @param {Token[]} tokens The array of tokens.
|
||||
* @param {Comment[]} comments The array of comments.
|
||||
*/
|
||||
constructor(tokens, comments) {
|
||||
this[TOKENS] = tokens;
|
||||
this[COMMENTS] = comments;
|
||||
this[INDEX_MAP] = createIndexMap(tokens, comments);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Gets single token.
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Gets the token starting at the specified index.
|
||||
* @param {number} offset Index of the start of the token's range.
|
||||
* @param {Object} [options=0] The option object.
|
||||
* @param {boolean} [options.includeComments=false] The flag to iterate comments as well.
|
||||
* @returns {Token|null} The token starting at index, or null if no such token.
|
||||
*/
|
||||
getTokenByRangeStart(offset, options) {
|
||||
const includeComments = options && options.includeComments;
|
||||
const token = cursors.forward.createBaseCursor(
|
||||
this[TOKENS],
|
||||
this[COMMENTS],
|
||||
this[INDEX_MAP],
|
||||
offset,
|
||||
-1,
|
||||
includeComments
|
||||
).getOneToken();
|
||||
|
||||
if (token && token.range[0] === offset) {
|
||||
return token;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the first token of the given node.
|
||||
* @param {ASTNode} node The AST node.
|
||||
* @param {number|Function|Object} [options=0] The option object. If this is a number then it's `options.skip`. If this is a function then it's `options.filter`.
|
||||
* @param {boolean} [options.includeComments=false] The flag to iterate comments as well.
|
||||
* @param {Function|null} [options.filter=null] The predicate function to choose tokens.
|
||||
* @param {number} [options.skip=0] The count of tokens the cursor skips.
|
||||
* @returns {Token|null} An object representing the token.
|
||||
*/
|
||||
getFirstToken(node, options) {
|
||||
return createCursorWithSkip(
|
||||
cursors.forward,
|
||||
this[TOKENS],
|
||||
this[COMMENTS],
|
||||
this[INDEX_MAP],
|
||||
node.range[0],
|
||||
node.range[1],
|
||||
options
|
||||
).getOneToken();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the last token of the given node.
|
||||
* @param {ASTNode} node The AST node.
|
||||
* @param {number|Function|Object} [options=0] The option object. Same options as getFirstToken()
|
||||
* @returns {Token|null} An object representing the token.
|
||||
*/
|
||||
getLastToken(node, options) {
|
||||
return createCursorWithSkip(
|
||||
cursors.backward,
|
||||
this[TOKENS],
|
||||
this[COMMENTS],
|
||||
this[INDEX_MAP],
|
||||
node.range[0],
|
||||
node.range[1],
|
||||
options
|
||||
).getOneToken();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the token that precedes a given node or token.
|
||||
* @param {ASTNode|Token|Comment} node The AST node or token.
|
||||
* @param {number|Function|Object} [options=0] The option object. Same options as getFirstToken()
|
||||
* @returns {Token|null} An object representing the token.
|
||||
*/
|
||||
getTokenBefore(node, options) {
|
||||
return createCursorWithSkip(
|
||||
cursors.backward,
|
||||
this[TOKENS],
|
||||
this[COMMENTS],
|
||||
this[INDEX_MAP],
|
||||
-1,
|
||||
node.range[0],
|
||||
options
|
||||
).getOneToken();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the token that follows a given node or token.
|
||||
* @param {ASTNode|Token|Comment} node The AST node or token.
|
||||
* @param {number|Function|Object} [options=0] The option object. Same options as getFirstToken()
|
||||
* @returns {Token|null} An object representing the token.
|
||||
*/
|
||||
getTokenAfter(node, options) {
|
||||
return createCursorWithSkip(
|
||||
cursors.forward,
|
||||
this[TOKENS],
|
||||
this[COMMENTS],
|
||||
this[INDEX_MAP],
|
||||
node.range[1],
|
||||
-1,
|
||||
options
|
||||
).getOneToken();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the first token between two non-overlapping nodes.
|
||||
* @param {ASTNode|Token|Comment} left Node before the desired token range.
|
||||
* @param {ASTNode|Token|Comment} right Node after the desired token range.
|
||||
* @param {number|Function|Object} [options=0] The option object. Same options as getFirstToken()
|
||||
* @returns {Token|null} An object representing the token.
|
||||
*/
|
||||
getFirstTokenBetween(left, right, options) {
|
||||
return createCursorWithSkip(
|
||||
cursors.forward,
|
||||
this[TOKENS],
|
||||
this[COMMENTS],
|
||||
this[INDEX_MAP],
|
||||
left.range[1],
|
||||
right.range[0],
|
||||
options
|
||||
).getOneToken();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the last token between two non-overlapping nodes.
|
||||
* @param {ASTNode|Token|Comment} left Node before the desired token range.
|
||||
* @param {ASTNode|Token|Comment} right Node after the desired token range.
|
||||
* @param {number|Function|Object} [options=0] The option object. Same options as getFirstToken()
|
||||
* @returns {Token|null} An object representing the token.
|
||||
*/
|
||||
getLastTokenBetween(left, right, options) {
|
||||
return createCursorWithSkip(
|
||||
cursors.backward,
|
||||
this[TOKENS],
|
||||
this[COMMENTS],
|
||||
this[INDEX_MAP],
|
||||
left.range[1],
|
||||
right.range[0],
|
||||
options
|
||||
).getOneToken();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the token that precedes a given node or token in the token stream.
|
||||
* This is defined for backward compatibility. Use `includeComments` option instead.
|
||||
* TODO: We have a plan to remove this in a future major version.
|
||||
* @param {ASTNode|Token|Comment} node The AST node or token.
|
||||
* @param {number} [skip=0] A number of tokens to skip.
|
||||
* @returns {Token|null} An object representing the token.
|
||||
* @deprecated
|
||||
*/
|
||||
getTokenOrCommentBefore(node, skip) {
|
||||
return this.getTokenBefore(node, { includeComments: true, skip });
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the token that follows a given node or token in the token stream.
|
||||
* This is defined for backward compatibility. Use `includeComments` option instead.
|
||||
* TODO: We have a plan to remove this in a future major version.
|
||||
* @param {ASTNode|Token|Comment} node The AST node or token.
|
||||
* @param {number} [skip=0] A number of tokens to skip.
|
||||
* @returns {Token|null} An object representing the token.
|
||||
* @deprecated
|
||||
*/
|
||||
getTokenOrCommentAfter(node, skip) {
|
||||
return this.getTokenAfter(node, { includeComments: true, skip });
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Gets multiple tokens.
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Gets the first `count` tokens of the given node.
|
||||
* @param {ASTNode} node The AST node.
|
||||
* @param {number|Function|Object} [options=0] The option object. If this is a number then it's `options.count`. If this is a function then it's `options.filter`.
|
||||
* @param {boolean} [options.includeComments=false] The flag to iterate comments as well.
|
||||
* @param {Function|null} [options.filter=null] The predicate function to choose tokens.
|
||||
* @param {number} [options.count=0] The maximum count of tokens the cursor iterates.
|
||||
* @returns {Token[]} Tokens.
|
||||
*/
|
||||
getFirstTokens(node, options) {
|
||||
return createCursorWithCount(
|
||||
cursors.forward,
|
||||
this[TOKENS],
|
||||
this[COMMENTS],
|
||||
this[INDEX_MAP],
|
||||
node.range[0],
|
||||
node.range[1],
|
||||
options
|
||||
).getAllTokens();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the last `count` tokens of the given node.
|
||||
* @param {ASTNode} node The AST node.
|
||||
* @param {number|Function|Object} [options=0] The option object. Same options as getFirstTokens()
|
||||
* @returns {Token[]} Tokens.
|
||||
*/
|
||||
getLastTokens(node, options) {
|
||||
return createCursorWithCount(
|
||||
cursors.backward,
|
||||
this[TOKENS],
|
||||
this[COMMENTS],
|
||||
this[INDEX_MAP],
|
||||
node.range[0],
|
||||
node.range[1],
|
||||
options
|
||||
).getAllTokens().reverse();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `count` tokens that precedes a given node or token.
|
||||
* @param {ASTNode|Token|Comment} node The AST node or token.
|
||||
* @param {number|Function|Object} [options=0] The option object. Same options as getFirstTokens()
|
||||
* @returns {Token[]} Tokens.
|
||||
*/
|
||||
getTokensBefore(node, options) {
|
||||
return createCursorWithCount(
|
||||
cursors.backward,
|
||||
this[TOKENS],
|
||||
this[COMMENTS],
|
||||
this[INDEX_MAP],
|
||||
-1,
|
||||
node.range[0],
|
||||
options
|
||||
).getAllTokens().reverse();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `count` tokens that follows a given node or token.
|
||||
* @param {ASTNode|Token|Comment} node The AST node or token.
|
||||
* @param {number|Function|Object} [options=0] The option object. Same options as getFirstTokens()
|
||||
* @returns {Token[]} Tokens.
|
||||
*/
|
||||
getTokensAfter(node, options) {
|
||||
return createCursorWithCount(
|
||||
cursors.forward,
|
||||
this[TOKENS],
|
||||
this[COMMENTS],
|
||||
this[INDEX_MAP],
|
||||
node.range[1],
|
||||
-1,
|
||||
options
|
||||
).getAllTokens();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the first `count` tokens between two non-overlapping nodes.
|
||||
* @param {ASTNode|Token|Comment} left Node before the desired token range.
|
||||
* @param {ASTNode|Token|Comment} right Node after the desired token range.
|
||||
* @param {number|Function|Object} [options=0] The option object. Same options as getFirstTokens()
|
||||
* @returns {Token[]} Tokens between left and right.
|
||||
*/
|
||||
getFirstTokensBetween(left, right, options) {
|
||||
return createCursorWithCount(
|
||||
cursors.forward,
|
||||
this[TOKENS],
|
||||
this[COMMENTS],
|
||||
this[INDEX_MAP],
|
||||
left.range[1],
|
||||
right.range[0],
|
||||
options
|
||||
).getAllTokens();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the last `count` tokens between two non-overlapping nodes.
|
||||
* @param {ASTNode|Token|Comment} left Node before the desired token range.
|
||||
* @param {ASTNode|Token|Comment} right Node after the desired token range.
|
||||
* @param {number|Function|Object} [options=0] The option object. Same options as getFirstTokens()
|
||||
* @returns {Token[]} Tokens between left and right.
|
||||
*/
|
||||
getLastTokensBetween(left, right, options) {
|
||||
return createCursorWithCount(
|
||||
cursors.backward,
|
||||
this[TOKENS],
|
||||
this[COMMENTS],
|
||||
this[INDEX_MAP],
|
||||
left.range[1],
|
||||
right.range[0],
|
||||
options
|
||||
).getAllTokens().reverse();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all tokens that are related to the given node.
|
||||
* @param {ASTNode} node The AST node.
|
||||
* @param {Function|Object} options The option object. If this is a function then it's `options.filter`.
|
||||
* @param {boolean} [options.includeComments=false] The flag to iterate comments as well.
|
||||
* @param {Function|null} [options.filter=null] The predicate function to choose tokens.
|
||||
* @param {number} [options.count=0] The maximum count of tokens the cursor iterates.
|
||||
* @returns {Token[]} Array of objects representing tokens.
|
||||
*/
|
||||
/**
|
||||
* Gets all tokens that are related to the given node.
|
||||
* @param {ASTNode} node The AST node.
|
||||
* @param {int} [beforeCount=0] The number of tokens before the node to retrieve.
|
||||
* @param {int} [afterCount=0] The number of tokens after the node to retrieve.
|
||||
* @returns {Token[]} Array of objects representing tokens.
|
||||
*/
|
||||
getTokens(node, beforeCount, afterCount) {
|
||||
return createCursorWithPadding(
|
||||
this[TOKENS],
|
||||
this[COMMENTS],
|
||||
this[INDEX_MAP],
|
||||
node.range[0],
|
||||
node.range[1],
|
||||
beforeCount,
|
||||
afterCount
|
||||
).getAllTokens();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all of the tokens between two non-overlapping nodes.
|
||||
* @param {ASTNode|Token|Comment} left Node before the desired token range.
|
||||
* @param {ASTNode|Token|Comment} right Node after the desired token range.
|
||||
* @param {Function|Object} options The option object. If this is a function then it's `options.filter`.
|
||||
* @param {boolean} [options.includeComments=false] The flag to iterate comments as well.
|
||||
* @param {Function|null} [options.filter=null] The predicate function to choose tokens.
|
||||
* @param {number} [options.count=0] The maximum count of tokens the cursor iterates.
|
||||
* @returns {Token[]} Tokens between left and right.
|
||||
*/
|
||||
/**
|
||||
* Gets all of the tokens between two non-overlapping nodes.
|
||||
* @param {ASTNode|Token|Comment} left Node before the desired token range.
|
||||
* @param {ASTNode|Token|Comment} right Node after the desired token range.
|
||||
* @param {int} [padding=0] Number of extra tokens on either side of center.
|
||||
* @returns {Token[]} Tokens between left and right.
|
||||
*/
|
||||
getTokensBetween(left, right, padding) {
|
||||
return createCursorWithPadding(
|
||||
this[TOKENS],
|
||||
this[COMMENTS],
|
||||
this[INDEX_MAP],
|
||||
left.range[1],
|
||||
right.range[0],
|
||||
padding,
|
||||
padding
|
||||
).getAllTokens();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Others.
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Checks whether any comments exist or not between the given 2 nodes.
|
||||
* @param {ASTNode} left The node to check.
|
||||
* @param {ASTNode} right The node to check.
|
||||
* @returns {boolean} `true` if one or more comments exist.
|
||||
*/
|
||||
commentsExistBetween(left, right) {
|
||||
const index = utils.search(this[COMMENTS], left.range[1]);
|
||||
|
||||
return (
|
||||
index < this[COMMENTS].length &&
|
||||
this[COMMENTS][index].range[1] <= right.range[0]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all comment tokens directly before the given node or token.
|
||||
* @param {ASTNode|token} nodeOrToken The AST node or token to check for adjacent comment tokens.
|
||||
* @returns {Array} An array of comments in occurrence order.
|
||||
*/
|
||||
getCommentsBefore(nodeOrToken) {
|
||||
const cursor = createCursorWithCount(
|
||||
cursors.backward,
|
||||
this[TOKENS],
|
||||
this[COMMENTS],
|
||||
this[INDEX_MAP],
|
||||
-1,
|
||||
nodeOrToken.range[0],
|
||||
{ includeComments: true }
|
||||
);
|
||||
|
||||
return getAdjacentCommentTokensFromCursor(cursor).reverse();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all comment tokens directly after the given node or token.
|
||||
* @param {ASTNode|token} nodeOrToken The AST node or token to check for adjacent comment tokens.
|
||||
* @returns {Array} An array of comments in occurrence order.
|
||||
*/
|
||||
getCommentsAfter(nodeOrToken) {
|
||||
const cursor = createCursorWithCount(
|
||||
cursors.forward,
|
||||
this[TOKENS],
|
||||
this[COMMENTS],
|
||||
this[INDEX_MAP],
|
||||
nodeOrToken.range[1],
|
||||
-1,
|
||||
{ includeComments: true }
|
||||
);
|
||||
|
||||
return getAdjacentCommentTokensFromCursor(cursor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all comment tokens inside the given node.
|
||||
* @param {ASTNode} node The AST node to get the comments for.
|
||||
* @returns {Array} An array of comments in occurrence order.
|
||||
*/
|
||||
getCommentsInside(node) {
|
||||
return this.getTokens(node, {
|
||||
includeComments: true,
|
||||
filter: isCommentToken
|
||||
});
|
||||
}
|
||||
};
|
40
node_modules/eslint/lib/languages/js/source-code/token-store/limit-cursor.js
generated
vendored
Normal file
40
node_modules/eslint/lib/languages/js/source-code/token-store/limit-cursor.js
generated
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
/**
|
||||
* @fileoverview Define the cursor which limits the number of tokens.
|
||||
* @author Toru Nagashima
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const DecorativeCursor = require("./decorative-cursor");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Exports
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* The decorative cursor which limits the number of tokens.
|
||||
*/
|
||||
module.exports = class LimitCursor extends DecorativeCursor {
|
||||
|
||||
/**
|
||||
* Initializes this cursor.
|
||||
* @param {Cursor} cursor The cursor to be decorated.
|
||||
* @param {number} count The count of tokens this cursor iterates.
|
||||
*/
|
||||
constructor(cursor, count) {
|
||||
super(cursor);
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
moveNext() {
|
||||
if (this.count > 0) {
|
||||
this.count -= 1;
|
||||
return super.moveNext();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
38
node_modules/eslint/lib/languages/js/source-code/token-store/padded-token-cursor.js
generated
vendored
Normal file
38
node_modules/eslint/lib/languages/js/source-code/token-store/padded-token-cursor.js
generated
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
/**
|
||||
* @fileoverview Define the cursor which iterates tokens only, with inflated range.
|
||||
* @author Toru Nagashima
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const ForwardTokenCursor = require("./forward-token-cursor");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Exports
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* The cursor which iterates tokens only, with inflated range.
|
||||
* This is for the backward compatibility of padding options.
|
||||
*/
|
||||
module.exports = class PaddedTokenCursor extends ForwardTokenCursor {
|
||||
|
||||
/**
|
||||
* Initializes this cursor.
|
||||
* @param {Token[]} tokens The array of tokens.
|
||||
* @param {Comment[]} comments The array of comments.
|
||||
* @param {Object} indexMap The map from locations to indices in `tokens`.
|
||||
* @param {number} startLoc The start location of the iteration range.
|
||||
* @param {number} endLoc The end location of the iteration range.
|
||||
* @param {number} beforeCount The number of tokens this cursor iterates before start.
|
||||
* @param {number} afterCount The number of tokens this cursor iterates after end.
|
||||
*/
|
||||
constructor(tokens, comments, indexMap, startLoc, endLoc, beforeCount, afterCount) {
|
||||
super(tokens, comments, indexMap, startLoc, endLoc);
|
||||
this.index = Math.max(0, this.index - beforeCount);
|
||||
this.indexEnd = Math.min(tokens.length - 1, this.indexEnd + afterCount);
|
||||
}
|
||||
};
|
42
node_modules/eslint/lib/languages/js/source-code/token-store/skip-cursor.js
generated
vendored
Normal file
42
node_modules/eslint/lib/languages/js/source-code/token-store/skip-cursor.js
generated
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
/**
|
||||
* @fileoverview Define the cursor which ignores the first few tokens.
|
||||
* @author Toru Nagashima
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const DecorativeCursor = require("./decorative-cursor");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Exports
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* The decorative cursor which ignores the first few tokens.
|
||||
*/
|
||||
module.exports = class SkipCursor extends DecorativeCursor {
|
||||
|
||||
/**
|
||||
* Initializes this cursor.
|
||||
* @param {Cursor} cursor The cursor to be decorated.
|
||||
* @param {number} count The count of tokens this cursor skips.
|
||||
*/
|
||||
constructor(cursor, count) {
|
||||
super(cursor);
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
moveNext() {
|
||||
while (this.count > 0) {
|
||||
this.count -= 1;
|
||||
if (!super.moveNext()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return super.moveNext();
|
||||
}
|
||||
};
|
107
node_modules/eslint/lib/languages/js/source-code/token-store/utils.js
generated
vendored
Normal file
107
node_modules/eslint/lib/languages/js/source-code/token-store/utils.js
generated
vendored
Normal file
@ -0,0 +1,107 @@
|
||||
/**
|
||||
* @fileoverview Define utility functions for token store.
|
||||
* @author Toru Nagashima
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Exports
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Finds the index of the first token which is after the given location.
|
||||
* If it was not found, this returns `tokens.length`.
|
||||
* @param {(Token|Comment)[]} tokens It searches the token in this list.
|
||||
* @param {number} location The location to search.
|
||||
* @returns {number} The found index or `tokens.length`.
|
||||
*/
|
||||
exports.search = function search(tokens, location) {
|
||||
for (let minIndex = 0, maxIndex = tokens.length - 1; minIndex <= maxIndex;) {
|
||||
|
||||
/*
|
||||
* Calculate the index in the middle between minIndex and maxIndex.
|
||||
* `| 0` is used to round a fractional value down to the nearest integer: this is similar to
|
||||
* using `Math.trunc()` or `Math.floor()`, but performance tests have shown this method to
|
||||
* be faster.
|
||||
*/
|
||||
const index = (minIndex + maxIndex) / 2 | 0;
|
||||
const token = tokens[index];
|
||||
const tokenStartLocation = token.range[0];
|
||||
|
||||
if (location <= tokenStartLocation) {
|
||||
if (index === minIndex) {
|
||||
return index;
|
||||
}
|
||||
maxIndex = index;
|
||||
} else {
|
||||
minIndex = index + 1;
|
||||
}
|
||||
}
|
||||
return tokens.length;
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets the index of the `startLoc` in `tokens`.
|
||||
* `startLoc` can be the value of `node.range[1]`, so this checks about `startLoc - 1` as well.
|
||||
* @param {(Token|Comment)[]} tokens The tokens to find an index.
|
||||
* @param {Object} indexMap The map from locations to indices.
|
||||
* @param {number} startLoc The location to get an index.
|
||||
* @returns {number} The index.
|
||||
*/
|
||||
exports.getFirstIndex = function getFirstIndex(tokens, indexMap, startLoc) {
|
||||
if (startLoc in indexMap) {
|
||||
return indexMap[startLoc];
|
||||
}
|
||||
if ((startLoc - 1) in indexMap) {
|
||||
const index = indexMap[startLoc - 1];
|
||||
const token = tokens[index];
|
||||
|
||||
// If the mapped index is out of bounds, the returned cursor index will point after the end of the tokens array.
|
||||
if (!token) {
|
||||
return tokens.length;
|
||||
}
|
||||
|
||||
/*
|
||||
* For the map of "comment's location -> token's index", it points the next token of a comment.
|
||||
* In that case, +1 is unnecessary.
|
||||
*/
|
||||
if (token.range[0] >= startLoc) {
|
||||
return index;
|
||||
}
|
||||
return index + 1;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets the index of the `endLoc` in `tokens`.
|
||||
* The information of end locations are recorded at `endLoc - 1` in `indexMap`, so this checks about `endLoc - 1` as well.
|
||||
* @param {(Token|Comment)[]} tokens The tokens to find an index.
|
||||
* @param {Object} indexMap The map from locations to indices.
|
||||
* @param {number} endLoc The location to get an index.
|
||||
* @returns {number} The index.
|
||||
*/
|
||||
exports.getLastIndex = function getLastIndex(tokens, indexMap, endLoc) {
|
||||
if (endLoc in indexMap) {
|
||||
return indexMap[endLoc] - 1;
|
||||
}
|
||||
if ((endLoc - 1) in indexMap) {
|
||||
const index = indexMap[endLoc - 1];
|
||||
const token = tokens[index];
|
||||
|
||||
// If the mapped index is out of bounds, the returned cursor index will point before the end of the tokens array.
|
||||
if (!token) {
|
||||
return tokens.length - 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* For the map of "comment's location -> token's index", it points the next token of a comment.
|
||||
* In that case, -1 is necessary.
|
||||
*/
|
||||
if (token.range[1] > endLoc) {
|
||||
return index - 1;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
return tokens.length - 1;
|
||||
};
|
181
node_modules/eslint/lib/languages/js/validate-language-options.js
generated
vendored
Normal file
181
node_modules/eslint/lib/languages/js/validate-language-options.js
generated
vendored
Normal file
@ -0,0 +1,181 @@
|
||||
/**
|
||||
* @fileoverview The schema to validate language options
|
||||
* @author Nicholas C. Zakas
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Data
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
const globalVariablesValues = new Set([
|
||||
true, "true", "writable", "writeable",
|
||||
false, "false", "readonly", "readable", null,
|
||||
"off"
|
||||
]);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Check if a value is a non-null object.
|
||||
* @param {any} value The value to check.
|
||||
* @returns {boolean} `true` if the value is a non-null object.
|
||||
*/
|
||||
function isNonNullObject(value) {
|
||||
return typeof value === "object" && value !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a value is a non-null non-array object.
|
||||
* @param {any} value The value to check.
|
||||
* @returns {boolean} `true` if the value is a non-null non-array object.
|
||||
*/
|
||||
function isNonArrayObject(value) {
|
||||
return isNonNullObject(value) && !Array.isArray(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a value is undefined.
|
||||
* @param {any} value The value to check.
|
||||
* @returns {boolean} `true` if the value is undefined.
|
||||
*/
|
||||
function isUndefined(value) {
|
||||
return typeof value === "undefined";
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Schemas
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Validates the ecmaVersion property.
|
||||
* @param {string|number} ecmaVersion The value to check.
|
||||
* @returns {void}
|
||||
* @throws {TypeError} If the value is invalid.
|
||||
*/
|
||||
function validateEcmaVersion(ecmaVersion) {
|
||||
|
||||
if (isUndefined(ecmaVersion)) {
|
||||
throw new TypeError("Key \"ecmaVersion\": Expected an \"ecmaVersion\" property.");
|
||||
}
|
||||
|
||||
if (typeof ecmaVersion !== "number" && ecmaVersion !== "latest") {
|
||||
throw new TypeError("Key \"ecmaVersion\": Expected a number or \"latest\".");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the sourceType property.
|
||||
* @param {string} sourceType The value to check.
|
||||
* @returns {void}
|
||||
* @throws {TypeError} If the value is invalid.
|
||||
*/
|
||||
function validateSourceType(sourceType) {
|
||||
|
||||
if (typeof sourceType !== "string" || !/^(?:script|module|commonjs)$/u.test(sourceType)) {
|
||||
throw new TypeError("Key \"sourceType\": Expected \"script\", \"module\", or \"commonjs\".");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the globals property.
|
||||
* @param {Object} globals The value to check.
|
||||
* @returns {void}
|
||||
* @throws {TypeError} If the value is invalid.
|
||||
*/
|
||||
function validateGlobals(globals) {
|
||||
|
||||
if (!isNonArrayObject(globals)) {
|
||||
throw new TypeError("Key \"globals\": Expected an object.");
|
||||
}
|
||||
|
||||
for (const key of Object.keys(globals)) {
|
||||
|
||||
// avoid hairy edge case
|
||||
if (key === "__proto__") {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (key !== key.trim()) {
|
||||
throw new TypeError(`Key "globals": Global "${key}" has leading or trailing whitespace.`);
|
||||
}
|
||||
|
||||
if (!globalVariablesValues.has(globals[key])) {
|
||||
throw new TypeError(`Key "globals": Key "${key}": Expected "readonly", "writable", or "off".`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the parser property.
|
||||
* @param {Object} parser The value to check.
|
||||
* @returns {void}
|
||||
* @throws {TypeError} If the value is invalid.
|
||||
*/
|
||||
function validateParser(parser) {
|
||||
|
||||
if (!parser || typeof parser !== "object" ||
|
||||
(typeof parser.parse !== "function" && typeof parser.parseForESLint !== "function")
|
||||
) {
|
||||
throw new TypeError("Key \"parser\": Expected object with parse() or parseForESLint() method.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the language options.
|
||||
* @param {Object} languageOptions The language options to validate.
|
||||
* @returns {void}
|
||||
* @throws {TypeError} If the language options are invalid.
|
||||
*/
|
||||
function validateLanguageOptions(languageOptions) {
|
||||
|
||||
if (!isNonArrayObject(languageOptions)) {
|
||||
throw new TypeError("Expected an object.");
|
||||
}
|
||||
|
||||
const {
|
||||
ecmaVersion,
|
||||
sourceType,
|
||||
globals,
|
||||
parser,
|
||||
parserOptions,
|
||||
...otherOptions
|
||||
} = languageOptions;
|
||||
|
||||
if ("ecmaVersion" in languageOptions) {
|
||||
validateEcmaVersion(ecmaVersion);
|
||||
}
|
||||
|
||||
if ("sourceType" in languageOptions) {
|
||||
validateSourceType(sourceType);
|
||||
}
|
||||
|
||||
if ("globals" in languageOptions) {
|
||||
validateGlobals(globals);
|
||||
}
|
||||
|
||||
if ("parser" in languageOptions) {
|
||||
validateParser(parser);
|
||||
}
|
||||
|
||||
if ("parserOptions" in languageOptions) {
|
||||
if (!isNonArrayObject(parserOptions)) {
|
||||
throw new TypeError("Key \"parserOptions\": Expected an object.");
|
||||
}
|
||||
}
|
||||
|
||||
const otherOptionKeys = Object.keys(otherOptions);
|
||||
|
||||
if (otherOptionKeys.length > 0) {
|
||||
throw new TypeError(`Unexpected key "${otherOptionKeys[0]}" found.`);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = { validateLanguageOptions };
|
Reference in New Issue
Block a user