Add components
This commit is contained in:
50
slider/node_modules/eslint/lib/api.js
generated
vendored
Normal file
50
slider/node_modules/eslint/lib/api.js
generated
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* @fileoverview Expose out ESLint and CLI to require.
|
||||
* @author Ian Christian Myers
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
const { ESLint, shouldUseFlatConfig } = require("./eslint/eslint");
|
||||
const { LegacyESLint } = require("./eslint/legacy-eslint");
|
||||
const { Linter } = require("./linter");
|
||||
const { RuleTester } = require("./rule-tester");
|
||||
const { SourceCode } = require("./languages/js/source-code");
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Functions
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Loads the correct ESLint constructor given the options.
|
||||
* @param {Object} [options] The options object
|
||||
* @param {boolean} [options.useFlatConfig] Whether or not to use a flat config
|
||||
* @returns {Promise<ESLint|LegacyESLint>} The ESLint constructor
|
||||
*/
|
||||
async function loadESLint({ useFlatConfig } = {}) {
|
||||
/*
|
||||
* Note: The v8.x version of this function also accepted a `cwd` option, but
|
||||
* it is not used in this implementation so we silently ignore it.
|
||||
*/
|
||||
|
||||
const shouldESLintUseFlatConfig =
|
||||
useFlatConfig ?? (await shouldUseFlatConfig());
|
||||
|
||||
return shouldESLintUseFlatConfig ? ESLint : LegacyESLint;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Exports
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
Linter,
|
||||
loadESLint,
|
||||
ESLint,
|
||||
RuleTester,
|
||||
SourceCode,
|
||||
};
|
||||
1109
slider/node_modules/eslint/lib/cli-engine/cli-engine.js
generated
vendored
Normal file
1109
slider/node_modules/eslint/lib/cli-engine/cli-engine.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
541
slider/node_modules/eslint/lib/cli-engine/file-enumerator.js
generated
vendored
Normal file
541
slider/node_modules/eslint/lib/cli-engine/file-enumerator.js
generated
vendored
Normal file
@@ -0,0 +1,541 @@
|
||||
/**
|
||||
* @fileoverview `FileEnumerator` class.
|
||||
*
|
||||
* `FileEnumerator` class has two responsibilities:
|
||||
*
|
||||
* 1. Find target files by processing glob patterns.
|
||||
* 2. Tie each target file and appropriate configuration.
|
||||
*
|
||||
* It provides a method:
|
||||
*
|
||||
* - `iterateFiles(patterns)`
|
||||
* Iterate files which are matched by given patterns together with the
|
||||
* corresponded configuration. This is for `CLIEngine#executeOnFiles()`.
|
||||
* While iterating files, it loads the configuration file of each directory
|
||||
* before iterate files on the directory, so we can use the configuration
|
||||
* files to determine target files.
|
||||
*
|
||||
* @example
|
||||
* const enumerator = new FileEnumerator();
|
||||
* const linter = new Linter();
|
||||
*
|
||||
* for (const { config, filePath } of enumerator.iterateFiles(["*.js"])) {
|
||||
* const code = fs.readFileSync(filePath, "utf8");
|
||||
* const messages = linter.verify(code, config, filePath);
|
||||
*
|
||||
* console.log(messages);
|
||||
* }
|
||||
*
|
||||
* @author Toru Nagashima <https://github.com/mysticatea>
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const fs = require("node:fs");
|
||||
const path = require("node:path");
|
||||
const getGlobParent = require("glob-parent");
|
||||
const isGlob = require("is-glob");
|
||||
const escapeRegExp = require("escape-string-regexp");
|
||||
const { Minimatch } = require("minimatch");
|
||||
|
||||
const {
|
||||
Legacy: { IgnorePattern, CascadingConfigArrayFactory },
|
||||
} = require("@eslint/eslintrc");
|
||||
const debug = require("debug")("eslint:file-enumerator");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const minimatchOpts = { dot: true, matchBase: true };
|
||||
const dotfilesPattern = /(?:^\.|[/\\]\.)[^/\\.].*/u;
|
||||
const NONE = 0;
|
||||
const IGNORED_SILENTLY = 1;
|
||||
const IGNORED = 2;
|
||||
|
||||
// For VSCode intellisense
|
||||
/** @typedef {ReturnType<CascadingConfigArrayFactory.getConfigArrayForFile>} ConfigArray */
|
||||
|
||||
/**
|
||||
* @typedef {Object} FileEnumeratorOptions
|
||||
* @property {CascadingConfigArrayFactory} [configArrayFactory] The factory for config arrays.
|
||||
* @property {string} [cwd] The base directory to start lookup.
|
||||
* @property {string[]} [extensions] The extensions to match files for directory patterns.
|
||||
* @property {boolean} [globInputPaths] Set to false to skip glob resolution of input file paths to lint (default: true). If false, each input file paths is assumed to be a non-glob path to an existing file.
|
||||
* @property {boolean} [ignore] The flag to check ignored files.
|
||||
* @property {string[]} [rulePaths] The value of `--rulesdir` option.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} FileAndConfig
|
||||
* @property {string} filePath The path to a target file.
|
||||
* @property {ConfigArray} config The config entries of that file.
|
||||
* @property {boolean} ignored If `true` then this file should be ignored and warned because it was directly specified.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} FileEntry
|
||||
* @property {string} filePath The path to a target file.
|
||||
* @property {ConfigArray} config The config entries of that file.
|
||||
* @property {NONE|IGNORED_SILENTLY|IGNORED} flag The flag.
|
||||
* - `NONE` means the file is a target file.
|
||||
* - `IGNORED_SILENTLY` means the file should be ignored silently.
|
||||
* - `IGNORED` means the file should be ignored and warned because it was directly specified.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} FileEnumeratorInternalSlots
|
||||
* @property {CascadingConfigArrayFactory} configArrayFactory The factory for config arrays.
|
||||
* @property {string} cwd The base directory to start lookup.
|
||||
* @property {RegExp|null} extensionRegExp The RegExp to test if a string ends with specific file extensions.
|
||||
* @property {boolean} globInputPaths Set to false to skip glob resolution of input file paths to lint (default: true). If false, each input file paths is assumed to be a non-glob path to an existing file.
|
||||
* @property {boolean} ignoreFlag The flag to check ignored files.
|
||||
* @property {(filePath:string, dot:boolean) => boolean} defaultIgnores The default predicate function to ignore files.
|
||||
*/
|
||||
|
||||
/** @type {WeakMap<FileEnumerator, FileEnumeratorInternalSlots>} */
|
||||
const internalSlotsMap = new WeakMap();
|
||||
|
||||
/**
|
||||
* Check if a string is a glob pattern or not.
|
||||
* @param {string} pattern A glob pattern.
|
||||
* @returns {boolean} `true` if the string is a glob pattern.
|
||||
*/
|
||||
function isGlobPattern(pattern) {
|
||||
return isGlob(path.sep === "\\" ? pattern.replace(/\\/gu, "/") : pattern);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get stats of a given path.
|
||||
* @param {string} filePath The path to target file.
|
||||
* @throws {Error} As may be thrown by `fs.statSync`.
|
||||
* @returns {fs.Stats|null} The stats.
|
||||
* @private
|
||||
*/
|
||||
function statSafeSync(filePath) {
|
||||
try {
|
||||
return fs.statSync(filePath);
|
||||
} catch (error) {
|
||||
/* c8 ignore next */
|
||||
if (error.code !== "ENOENT") {
|
||||
throw error;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get filenames in a given path to a directory.
|
||||
* @param {string} directoryPath The path to target directory.
|
||||
* @throws {Error} As may be thrown by `fs.readdirSync`.
|
||||
* @returns {import("fs").Dirent[]} The filenames.
|
||||
* @private
|
||||
*/
|
||||
function readdirSafeSync(directoryPath) {
|
||||
try {
|
||||
return fs.readdirSync(directoryPath, { withFileTypes: true });
|
||||
} catch (error) {
|
||||
/* c8 ignore next */
|
||||
if (error.code !== "ENOENT") {
|
||||
throw error;
|
||||
}
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a `RegExp` object to detect extensions.
|
||||
* @param {string[] | null} extensions The extensions to create.
|
||||
* @returns {RegExp | null} The created `RegExp` object or null.
|
||||
*/
|
||||
function createExtensionRegExp(extensions) {
|
||||
if (extensions) {
|
||||
const normalizedExts = extensions.map(ext =>
|
||||
escapeRegExp(ext.startsWith(".") ? ext.slice(1) : ext),
|
||||
);
|
||||
|
||||
return new RegExp(`.\\.(?:${normalizedExts.join("|")})$`, "u");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The error type when no files match a glob.
|
||||
*/
|
||||
class NoFilesFoundError extends Error {
|
||||
/**
|
||||
* @param {string} pattern The glob pattern which was not found.
|
||||
* @param {boolean} globDisabled If `true` then the pattern was a glob pattern, but glob was disabled.
|
||||
*/
|
||||
constructor(pattern, globDisabled) {
|
||||
super(
|
||||
`No files matching '${pattern}' were found${globDisabled ? " (glob was disabled)" : ""}.`,
|
||||
);
|
||||
this.messageTemplate = "file-not-found";
|
||||
this.messageData = { pattern, globDisabled };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The error type when there are files matched by a glob, but all of them have been ignored.
|
||||
*/
|
||||
class AllFilesIgnoredError extends Error {
|
||||
/**
|
||||
* @param {string} pattern The glob pattern which was not found.
|
||||
*/
|
||||
constructor(pattern) {
|
||||
super(`All files matched by '${pattern}' are ignored.`);
|
||||
this.messageTemplate = "all-files-ignored";
|
||||
this.messageData = { pattern };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This class provides the functionality that enumerates every file which is
|
||||
* matched by given glob patterns and that configuration.
|
||||
*/
|
||||
class FileEnumerator {
|
||||
/**
|
||||
* Initialize this enumerator.
|
||||
* @param {FileEnumeratorOptions} options The options.
|
||||
*/
|
||||
constructor({
|
||||
cwd = process.cwd(),
|
||||
configArrayFactory = new CascadingConfigArrayFactory({
|
||||
cwd,
|
||||
getEslintRecommendedConfig: () =>
|
||||
require("@eslint/js").configs.recommended,
|
||||
getEslintAllConfig: () => require("@eslint/js").configs.all,
|
||||
}),
|
||||
extensions = null,
|
||||
globInputPaths = true,
|
||||
errorOnUnmatchedPattern = true,
|
||||
ignore = true,
|
||||
} = {}) {
|
||||
internalSlotsMap.set(this, {
|
||||
configArrayFactory,
|
||||
cwd,
|
||||
defaultIgnores: IgnorePattern.createDefaultIgnore(cwd),
|
||||
extensionRegExp: createExtensionRegExp(extensions),
|
||||
globInputPaths,
|
||||
errorOnUnmatchedPattern,
|
||||
ignoreFlag: ignore,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given file is target or not.
|
||||
* @param {string} filePath The path to a candidate file.
|
||||
* @param {ConfigArray} [providedConfig] Optional. The configuration for the file.
|
||||
* @returns {boolean} `true` if the file is a target.
|
||||
*/
|
||||
isTargetPath(filePath, providedConfig) {
|
||||
const { configArrayFactory, extensionRegExp } =
|
||||
internalSlotsMap.get(this);
|
||||
|
||||
// If `--ext` option is present, use it.
|
||||
if (extensionRegExp) {
|
||||
return extensionRegExp.test(filePath);
|
||||
}
|
||||
|
||||
// `.js` file is target by default.
|
||||
if (filePath.endsWith(".js")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// use `overrides[].files` to check additional targets.
|
||||
const config =
|
||||
providedConfig ||
|
||||
configArrayFactory.getConfigArrayForFile(filePath, {
|
||||
ignoreNotFoundError: true,
|
||||
});
|
||||
|
||||
return config.isAdditionalTargetPath(filePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterate files which are matched by given glob patterns.
|
||||
* @param {string|string[]} patternOrPatterns The glob patterns to iterate files.
|
||||
* @throws {NoFilesFoundError|AllFilesIgnoredError} On an unmatched pattern.
|
||||
* @returns {IterableIterator<FileAndConfig>} The found files.
|
||||
*/
|
||||
*iterateFiles(patternOrPatterns) {
|
||||
const { globInputPaths, errorOnUnmatchedPattern } =
|
||||
internalSlotsMap.get(this);
|
||||
const patterns = Array.isArray(patternOrPatterns)
|
||||
? patternOrPatterns
|
||||
: [patternOrPatterns];
|
||||
|
||||
debug("Start to iterate files: %o", patterns);
|
||||
|
||||
// The set of paths to remove duplicate.
|
||||
const set = new Set();
|
||||
|
||||
for (const pattern of patterns) {
|
||||
let foundRegardlessOfIgnored = false;
|
||||
let found = false;
|
||||
|
||||
// Skip empty string.
|
||||
if (!pattern) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Iterate files of this pattern.
|
||||
for (const { config, filePath, flag } of this._iterateFiles(
|
||||
pattern,
|
||||
)) {
|
||||
foundRegardlessOfIgnored = true;
|
||||
if (flag === IGNORED_SILENTLY) {
|
||||
continue;
|
||||
}
|
||||
found = true;
|
||||
|
||||
// Remove duplicate paths while yielding paths.
|
||||
if (!set.has(filePath)) {
|
||||
set.add(filePath);
|
||||
yield {
|
||||
config,
|
||||
filePath,
|
||||
ignored: flag === IGNORED,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Raise an error if any files were not found.
|
||||
if (errorOnUnmatchedPattern) {
|
||||
if (!foundRegardlessOfIgnored) {
|
||||
throw new NoFilesFoundError(
|
||||
pattern,
|
||||
!globInputPaths && isGlob(pattern),
|
||||
);
|
||||
}
|
||||
if (!found) {
|
||||
throw new AllFilesIgnoredError(pattern);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
debug(`Complete iterating files: ${JSON.stringify(patterns)}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterate files which are matched by a given glob pattern.
|
||||
* @param {string} pattern The glob pattern to iterate files.
|
||||
* @returns {IterableIterator<FileEntry>} The found files.
|
||||
*/
|
||||
_iterateFiles(pattern) {
|
||||
const { cwd, globInputPaths } = internalSlotsMap.get(this);
|
||||
const absolutePath = path.resolve(cwd, pattern);
|
||||
const isDot = dotfilesPattern.test(pattern);
|
||||
const stat = statSafeSync(absolutePath);
|
||||
|
||||
if (stat && stat.isDirectory()) {
|
||||
return this._iterateFilesWithDirectory(absolutePath, isDot);
|
||||
}
|
||||
if (stat && stat.isFile()) {
|
||||
return this._iterateFilesWithFile(absolutePath);
|
||||
}
|
||||
if (globInputPaths && isGlobPattern(pattern)) {
|
||||
return this._iterateFilesWithGlob(pattern, isDot);
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterate a file which is matched by a given path.
|
||||
* @param {string} filePath The path to the target file.
|
||||
* @returns {IterableIterator<FileEntry>} The found files.
|
||||
* @private
|
||||
*/
|
||||
_iterateFilesWithFile(filePath) {
|
||||
debug(`File: ${filePath}`);
|
||||
|
||||
const { configArrayFactory } = internalSlotsMap.get(this);
|
||||
const config = configArrayFactory.getConfigArrayForFile(filePath);
|
||||
const ignored = this._isIgnoredFile(filePath, { config, direct: true });
|
||||
const flag = ignored ? IGNORED : NONE;
|
||||
|
||||
return [{ config, filePath, flag }];
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterate files in a given path.
|
||||
* @param {string} directoryPath The path to the target directory.
|
||||
* @param {boolean} dotfiles If `true` then it doesn't skip dot files by default.
|
||||
* @returns {IterableIterator<FileEntry>} The found files.
|
||||
* @private
|
||||
*/
|
||||
_iterateFilesWithDirectory(directoryPath, dotfiles) {
|
||||
debug(`Directory: ${directoryPath}`);
|
||||
|
||||
return this._iterateFilesRecursive(directoryPath, {
|
||||
dotfiles,
|
||||
recursive: true,
|
||||
selector: null,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterate files which are matched by a given glob pattern.
|
||||
* @param {string} pattern The glob pattern to iterate files.
|
||||
* @param {boolean} dotfiles If `true` then it doesn't skip dot files by default.
|
||||
* @returns {IterableIterator<FileEntry>} The found files.
|
||||
* @private
|
||||
*/
|
||||
_iterateFilesWithGlob(pattern, dotfiles) {
|
||||
debug(`Glob: ${pattern}`);
|
||||
|
||||
const { cwd } = internalSlotsMap.get(this);
|
||||
const directoryPath = path.resolve(cwd, getGlobParent(pattern));
|
||||
const absolutePath = path.resolve(cwd, pattern);
|
||||
const globPart = absolutePath.slice(directoryPath.length + 1);
|
||||
|
||||
/*
|
||||
* recursive if there are `**` or path separators in the glob part.
|
||||
* Otherwise, patterns such as `src/*.js`, it doesn't need recursive.
|
||||
*/
|
||||
const recursive = /\*\*|\/|\\/u.test(globPart);
|
||||
const selector = new Minimatch(absolutePath, minimatchOpts);
|
||||
|
||||
debug(`recursive? ${recursive}`);
|
||||
|
||||
return this._iterateFilesRecursive(directoryPath, {
|
||||
dotfiles,
|
||||
recursive,
|
||||
selector,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterate files in a given path.
|
||||
* @param {string} directoryPath The path to the target directory.
|
||||
* @param {Object} options The options to iterate files.
|
||||
* @param {boolean} [options.dotfiles] If `true` then it doesn't skip dot files by default.
|
||||
* @param {boolean} [options.recursive] If `true` then it dives into sub directories.
|
||||
* @param {InstanceType<Minimatch>} [options.selector] The matcher to choose files.
|
||||
* @returns {IterableIterator<FileEntry>} The found files.
|
||||
* @private
|
||||
*/
|
||||
*_iterateFilesRecursive(directoryPath, options) {
|
||||
debug(`Enter the directory: ${directoryPath}`);
|
||||
const { configArrayFactory } = internalSlotsMap.get(this);
|
||||
|
||||
/** @type {ConfigArray|null} */
|
||||
let config = null;
|
||||
|
||||
// Enumerate the files of this directory.
|
||||
for (const entry of readdirSafeSync(directoryPath)) {
|
||||
const filePath = path.join(directoryPath, entry.name);
|
||||
const fileInfo = entry.isSymbolicLink()
|
||||
? statSafeSync(filePath)
|
||||
: entry;
|
||||
|
||||
if (!fileInfo) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if the file is matched.
|
||||
if (fileInfo.isFile()) {
|
||||
if (!config) {
|
||||
config = configArrayFactory.getConfigArrayForFile(
|
||||
filePath,
|
||||
|
||||
/*
|
||||
* We must ignore `ConfigurationNotFoundError` at this
|
||||
* point because we don't know if target files exist in
|
||||
* this directory.
|
||||
*/
|
||||
{ ignoreNotFoundError: true },
|
||||
);
|
||||
}
|
||||
const matched = options.selector
|
||||
? // Started with a glob pattern; choose by the pattern.
|
||||
options.selector.match(filePath)
|
||||
: // Started with a directory path; choose by file extensions.
|
||||
this.isTargetPath(filePath, config);
|
||||
|
||||
if (matched) {
|
||||
const ignored = this._isIgnoredFile(filePath, {
|
||||
...options,
|
||||
config,
|
||||
});
|
||||
const flag = ignored ? IGNORED_SILENTLY : NONE;
|
||||
|
||||
debug(
|
||||
`Yield: ${entry.name}${ignored ? " but ignored" : ""}`,
|
||||
);
|
||||
yield {
|
||||
config: configArrayFactory.getConfigArrayForFile(
|
||||
filePath,
|
||||
),
|
||||
filePath,
|
||||
flag,
|
||||
};
|
||||
} else {
|
||||
debug(`Didn't match: ${entry.name}`);
|
||||
}
|
||||
|
||||
// Dive into the sub directory.
|
||||
} else if (options.recursive && fileInfo.isDirectory()) {
|
||||
if (!config) {
|
||||
config = configArrayFactory.getConfigArrayForFile(
|
||||
filePath,
|
||||
{ ignoreNotFoundError: true },
|
||||
);
|
||||
}
|
||||
const ignored = this._isIgnoredFile(filePath + path.sep, {
|
||||
...options,
|
||||
config,
|
||||
});
|
||||
|
||||
if (!ignored) {
|
||||
yield* this._iterateFilesRecursive(filePath, options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
debug(`Leave the directory: ${directoryPath}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given file should be ignored.
|
||||
* @param {string} filePath The path to a file to check.
|
||||
* @param {Object} options Options
|
||||
* @param {ConfigArray} [options.config] The config for this file.
|
||||
* @param {boolean} [options.dotfiles] If `true` then this is not ignore dot files by default.
|
||||
* @param {boolean} [options.direct] If `true` then this is a direct specified file.
|
||||
* @returns {boolean} `true` if the file should be ignored.
|
||||
* @private
|
||||
*/
|
||||
_isIgnoredFile(
|
||||
filePath,
|
||||
{ config: providedConfig, dotfiles = false, direct = false },
|
||||
) {
|
||||
const { configArrayFactory, defaultIgnores, ignoreFlag } =
|
||||
internalSlotsMap.get(this);
|
||||
|
||||
if (ignoreFlag) {
|
||||
const config =
|
||||
providedConfig ||
|
||||
configArrayFactory.getConfigArrayForFile(filePath, {
|
||||
ignoreNotFoundError: true,
|
||||
});
|
||||
const ignores =
|
||||
config.extractConfig(filePath).ignores || defaultIgnores;
|
||||
|
||||
return ignores(filePath, dotfiles);
|
||||
}
|
||||
|
||||
return !direct && defaultIgnores(filePath, dotfiles);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Public Interface
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
module.exports = { FileEnumerator };
|
||||
18
slider/node_modules/eslint/lib/cli-engine/formatters/formatters-meta.json
generated
vendored
Normal file
18
slider/node_modules/eslint/lib/cli-engine/formatters/formatters-meta.json
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
[
|
||||
{
|
||||
"name": "html",
|
||||
"description": "Outputs results to HTML. The `html` formatter is useful for visual presentation in the browser."
|
||||
},
|
||||
{
|
||||
"name": "json-with-metadata",
|
||||
"description": "Outputs JSON-serialized results. The `json-with-metadata` provides the same linting results as the [`json`](#json) formatter with additional metadata about the rules applied. The linting results are included in the `results` property and the rules metadata is included in the `metadata` property.\n\nAlternatively, you can use the [ESLint Node.js API](../../integrate/nodejs-api) to programmatically use ESLint."
|
||||
},
|
||||
{
|
||||
"name": "json",
|
||||
"description": "Outputs JSON-serialized results. The `json` formatter is useful when you want to programmatically work with the CLI's linting results.\n\nAlternatively, you can use the [ESLint Node.js API](../../integrate/nodejs-api) to programmatically use ESLint."
|
||||
},
|
||||
{
|
||||
"name": "stylish",
|
||||
"description": "Human-readable output format. This is the default formatter."
|
||||
}
|
||||
]
|
||||
359
slider/node_modules/eslint/lib/cli-engine/formatters/html.js
generated
vendored
Normal file
359
slider/node_modules/eslint/lib/cli-engine/formatters/html.js
generated
vendored
Normal file
@@ -0,0 +1,359 @@
|
||||
/**
|
||||
* @fileoverview HTML reporter
|
||||
* @author Julian Laval
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const encodeHTML = (function () {
|
||||
const encodeHTMLRules = {
|
||||
"&": "&",
|
||||
"<": "<",
|
||||
">": ">",
|
||||
'"': """,
|
||||
"'": "'",
|
||||
};
|
||||
const matchHTML = /[&<>"']/gu;
|
||||
|
||||
return function (code) {
|
||||
return code
|
||||
? code.toString().replace(matchHTML, m => encodeHTMLRules[m] || m)
|
||||
: "";
|
||||
};
|
||||
})();
|
||||
|
||||
/**
|
||||
* Get the final HTML document.
|
||||
* @param {Object} it data for the document.
|
||||
* @returns {string} HTML document.
|
||||
*/
|
||||
function pageTemplate(it) {
|
||||
const { reportColor, reportSummary, date, results } = it;
|
||||
|
||||
return `
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>ESLint Report</title>
|
||||
<link rel="icon" type="image/png" sizes="any" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAACXBIWXMAAAHaAAAB2gGFomX7AAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAABD1JREFUWMPFl11sk2UUx3/nbYtjxS1MF7MLMTECMgSTtSSyrQkLhAj7UBPnDSEGoxegGzMwojhXVpmTAA5iYpSoMQa8GBhFOrMFk03buei6yRAlcmOM0SEmU9d90b19jxcM1o5+sGnsc/e+z/l6ztf/HFFVMnns6QieeOCHBePGsHM+wrOtvLG2C4WRVDSSygNV7sCjlspxwDnPB44aols/DXk+mbMBmx/6OseITF1CuOtfevkPh2Uu+/jbdX8lujSScRlT5r7/QDlAfsRmfzmpnkQ/H3H13gf6bBrBn1uqK8WylgEnU8eZmk1repbfchJG1TyKyIKEwuBHFd3lD3naY3O1siiwXsVoBV2VgM1ht/QQUJk2ByqKghsQziYQ8ifKgexIXmuyzC4r67Y7R+xPAfuB/Nn3Cpva+0s7khpQVtZtd4bt51BWxtBYAiciprG7c7D4SixzU9PYalDL6110Ifb/w8W9eY7JqFeFHbO8fPGyLHwwFHJNJTSgwtVTB9oaw9BlQ+tO93vOxypoaQnfEYlI43SeCHDC4TDq9+51/h5fxr33q0ZfV9g04wat9Q943rjJgCp3952W2i8Bi6eDvdsfKj0cK/DYMRyXL4/sUJUmIHd2zYMezsvLaamp4WpcWN3BXSiHpuMwbGbZlnZ8tXY4rgosy+G7oRwQ0cAsd28YGgqfU5UjCZQDLALxDg+Hv/P5Rqvj4hwrS8izXzWb4spwc1GgENFnkpWRzxeuB+ssUHgLdb9UVdt8vpGdKQpze7n7y1U3DBChNRUuqOo9c+0+qpKKxyZqtAIYla7gY4JszAAQri93BSsMRZoyBcUC+w3Q3AyOA4sNhAOZ0q7Iq0b2vUNvK5zPgP+/H8+Zetdoa6uOikhdGurxebwvJY8Iz3V1rTMNAH+opEuQj5KTT/qA1yC+wyUjBm12OidaUtCcPNNX2h0Hx2JG69VulANZAJZJwfU7rzd/FHixuXniTdM0m4GtSQT7bTartqEh9yfImUEzkwKZmTwmo5a5JwkYBfcDL01/RkR5y8iWhtPBknB8ZxwtU9UjwOrrKCeizzc25nTGg1F/turEHoU9wMLpDvWKf8DTmNCAKnd/tqUTF4ElMXJ+A5rWDJS+41WsGWzALhJ+ErBWrLj9g+pqojHxlXJX8HGUg0BsR/x1yhxf3jm4cSzpQFLp6tmi6PEE7g1ZhtZ91ufpSZUAFa6gC+UoQslNaSmypT1U8mHKiUgEKS8KfgF4EpYunFI16tsHin+OG0LcgQK7yj7g6cSzpva2D3hKVNG0Y3mVO1BkqfSlmJrHBQ4uvM12gJHc6ETW8HZVfMRmXvyxxNC1Z/o839zyXlDuCr4nsC11J+MXueaVJWn6yPv+/pJtc9oLTNN4AeTvNGByd3rlhE2x9s5pLwDoHCy+grDzWmOZ95lUtLYj5Bma126Y8eX0/zj/ADxGyViSg4BXAAAAAElFTkSuQmCC">
|
||||
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PScwIDAgMjk0LjgyNSAyNTguOTgyJyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnPg0KPHBhdGggZmlsbD0nIzgwODBGMicgZD0nTTk3LjAyMSw5OS4wMTZsNDguNDMyLTI3Ljk2MmMxLjIxMi0wLjcsMi43MDYtMC43LDMuOTE4LDBsNDguNDMzLDI3Ljk2MiBjMS4yMTEsMC43LDEuOTU5LDEuOTkzLDEuOTU5LDMuMzkzdjU1LjkyNGMwLDEuMzk5LTAuNzQ4LDIuNjkzLTEuOTU5LDMuMzk0bC00OC40MzMsMjcuOTYyYy0xLjIxMiwwLjctMi43MDYsMC43LTMuOTE4LDAgbC00OC40MzItMjcuOTYyYy0xLjIxMi0wLjctMS45NTktMS45OTQtMS45NTktMy4zOTR2LTU1LjkyNEM5NS4wNjMsMTAxLjAwOSw5NS44MSw5OS43MTYsOTcuMDIxLDk5LjAxNicvPg0KPHBhdGggZmlsbD0nIzRCMzJDMycgZD0nTTI3My4zMzYsMTI0LjQ4OEwyMTUuNDY5LDIzLjgxNmMtMi4xMDItMy42NC01Ljk4NS02LjMyNS0xMC4xODgtNi4zMjVIODkuNTQ1IGMtNC4yMDQsMC04LjA4OCwyLjY4NS0xMC4xOSw2LjMyNWwtNTcuODY3LDEwMC40NWMtMi4xMDIsMy42NDEtMi4xMDIsOC4yMzYsMCwxMS44NzdsNTcuODY3LDk5Ljg0NyBjMi4xMDIsMy42NCw1Ljk4Niw1LjUwMSwxMC4xOSw1LjUwMWgxMTUuNzM1YzQuMjAzLDAsOC4wODctMS44MDUsMTAuMTg4LTUuNDQ2bDU3Ljg2Ny0xMDAuMDEgQzI3NS40MzksMTMyLjM5NiwyNzUuNDM5LDEyOC4xMjgsMjczLjMzNiwxMjQuNDg4IE0yMjUuNDE5LDE3Mi44OThjMCwxLjQ4LTAuODkxLDIuODQ5LTIuMTc0LDMuNTlsLTczLjcxLDQyLjUyNyBjLTEuMjgyLDAuNzQtMi44ODgsMC43NC00LjE3LDBsLTczLjc2Ny00Mi41MjdjLTEuMjgyLTAuNzQxLTIuMTc5LTIuMTA5LTIuMTc5LTMuNTlWODcuODQzYzAtMS40ODEsMC44ODQtMi44NDksMi4xNjctMy41OSBsNzMuNzA3LTQyLjUyN2MxLjI4Mi0wLjc0MSwyLjg4Ni0wLjc0MSw0LjE2OCwwbDczLjc3Miw0Mi41MjdjMS4yODMsMC43NDEsMi4xODYsMi4xMDksMi4xODYsMy41OVYxNzIuODk4eicvPg0KPC9zdmc+">
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, "Helvetica Neue", Helvetica, sans-serif;
|
||||
font-size: 16px;
|
||||
font-weight: normal;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
#overview {
|
||||
padding: 20px 30px;
|
||||
}
|
||||
|
||||
td,
|
||||
th {
|
||||
padding: 5px 10px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
table {
|
||||
margin: 30px;
|
||||
width: calc(100% - 60px);
|
||||
max-width: 1000px;
|
||||
border-radius: 5px;
|
||||
border: 1px solid #ddd;
|
||||
border-spacing: 0;
|
||||
}
|
||||
|
||||
th {
|
||||
font-weight: 400;
|
||||
font-size: medium;
|
||||
text-align: left;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
td.clr-1,
|
||||
td.clr-2,
|
||||
th span {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
th span {
|
||||
float: right;
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
th span::after {
|
||||
content: "";
|
||||
clear: both;
|
||||
display: block;
|
||||
}
|
||||
|
||||
tr:last-child td {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
tr td:first-child,
|
||||
tr td:last-child {
|
||||
color: #9da0a4;
|
||||
}
|
||||
|
||||
#overview.bg-0,
|
||||
tr.bg-0 th {
|
||||
color: #468847;
|
||||
background: #dff0d8;
|
||||
border-bottom: 1px solid #d6e9c6;
|
||||
}
|
||||
|
||||
#overview.bg-1,
|
||||
tr.bg-1 th {
|
||||
color: #f0ad4e;
|
||||
background: #fcf8e3;
|
||||
border-bottom: 1px solid #fbeed5;
|
||||
}
|
||||
|
||||
#overview.bg-2,
|
||||
tr.bg-2 th {
|
||||
color: #b94a48;
|
||||
background: #f2dede;
|
||||
border-bottom: 1px solid #eed3d7;
|
||||
}
|
||||
|
||||
td {
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
|
||||
td.clr-1 {
|
||||
color: #f0ad4e;
|
||||
}
|
||||
|
||||
td.clr-2 {
|
||||
color: #b94a48;
|
||||
}
|
||||
|
||||
td a {
|
||||
color: #3a33d1;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
td a:hover {
|
||||
color: #272296;
|
||||
text-decoration: underline;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="overview" class="bg-${reportColor}">
|
||||
<h1>ESLint Report</h1>
|
||||
<div>
|
||||
<span>${reportSummary}</span> - Generated on ${date}
|
||||
</div>
|
||||
</div>
|
||||
<table>
|
||||
<tbody>
|
||||
${results}
|
||||
</tbody>
|
||||
</table>
|
||||
<script type="text/javascript">
|
||||
var groups = document.querySelectorAll("tr[data-group]");
|
||||
for (i = 0; i < groups.length; i++) {
|
||||
groups[i].addEventListener("click", function() {
|
||||
var inGroup = document.getElementsByClassName(this.getAttribute("data-group"));
|
||||
this.innerHTML = (this.innerHTML.indexOf("+") > -1) ? this.innerHTML.replace("+", "-") : this.innerHTML.replace("-", "+");
|
||||
for (var j = 0; j < inGroup.length; j++) {
|
||||
inGroup[j].style.display = (inGroup[j].style.display !== "none") ? "none" : "table-row";
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
`.trimStart();
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a word and a count, append an s if count is not one.
|
||||
* @param {string} word A word in its singular form.
|
||||
* @param {number} count A number controlling whether word should be pluralized.
|
||||
* @returns {string} The original word with an s on the end if count is not one.
|
||||
*/
|
||||
function pluralize(word, count) {
|
||||
return count === 1 ? word : `${word}s`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders text along the template of x problems (x errors, x warnings)
|
||||
* @param {string} totalErrors Total errors
|
||||
* @param {string} totalWarnings Total warnings
|
||||
* @returns {string} The formatted string, pluralized where necessary
|
||||
*/
|
||||
function renderSummary(totalErrors, totalWarnings) {
|
||||
const totalProblems = totalErrors + totalWarnings;
|
||||
let renderedText = `${totalProblems} ${pluralize("problem", totalProblems)}`;
|
||||
|
||||
if (totalProblems !== 0) {
|
||||
renderedText += ` (${totalErrors} ${pluralize("error", totalErrors)}, ${totalWarnings} ${pluralize("warning", totalWarnings)})`;
|
||||
}
|
||||
return renderedText;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the color based on whether there are errors/warnings...
|
||||
* @param {string} totalErrors Total errors
|
||||
* @param {string} totalWarnings Total warnings
|
||||
* @returns {number} The color code (0 = green, 1 = yellow, 2 = red)
|
||||
*/
|
||||
function renderColor(totalErrors, totalWarnings) {
|
||||
if (totalErrors !== 0) {
|
||||
return 2;
|
||||
}
|
||||
if (totalWarnings !== 0) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get HTML (table row) describing a single message.
|
||||
* @param {Object} it data for the message.
|
||||
* @returns {string} HTML (table row) describing the message.
|
||||
*/
|
||||
function messageTemplate(it) {
|
||||
const {
|
||||
parentIndex,
|
||||
lineNumber,
|
||||
columnNumber,
|
||||
severityNumber,
|
||||
severityName,
|
||||
message,
|
||||
ruleUrl,
|
||||
ruleId,
|
||||
} = it;
|
||||
|
||||
return `
|
||||
<tr style="display: none;" class="f-${parentIndex}">
|
||||
<td>${lineNumber}:${columnNumber}</td>
|
||||
<td class="clr-${severityNumber}">${severityName}</td>
|
||||
<td>${encodeHTML(message)}</td>
|
||||
<td>
|
||||
<a href="${ruleUrl ? ruleUrl : ""}" target="_blank" rel="noopener noreferrer">${ruleId ? ruleId : ""}</a>
|
||||
</td>
|
||||
</tr>
|
||||
`.trimStart();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get HTML (table rows) describing the messages.
|
||||
* @param {Array} messages Messages.
|
||||
* @param {number} parentIndex Index of the parent HTML row.
|
||||
* @param {Object} rulesMeta Dictionary containing metadata for each rule executed by the analysis.
|
||||
* @returns {string} HTML (table rows) describing the messages.
|
||||
*/
|
||||
function renderMessages(messages, parentIndex, rulesMeta) {
|
||||
/**
|
||||
* Get HTML (table row) describing a message.
|
||||
* @param {Object} message Message.
|
||||
* @returns {string} HTML (table row) describing a message.
|
||||
*/
|
||||
return messages
|
||||
.map(message => {
|
||||
const lineNumber = message.line || 0;
|
||||
const columnNumber = message.column || 0;
|
||||
let ruleUrl;
|
||||
|
||||
if (rulesMeta) {
|
||||
const meta = rulesMeta[message.ruleId];
|
||||
|
||||
if (meta && meta.docs && meta.docs.url) {
|
||||
ruleUrl = meta.docs.url;
|
||||
}
|
||||
}
|
||||
|
||||
return messageTemplate({
|
||||
parentIndex,
|
||||
lineNumber,
|
||||
columnNumber,
|
||||
severityNumber: message.severity,
|
||||
severityName: message.severity === 1 ? "Warning" : "Error",
|
||||
message: message.message,
|
||||
ruleId: message.ruleId,
|
||||
ruleUrl,
|
||||
});
|
||||
})
|
||||
.join("\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get HTML (table row) describing the result for a single file.
|
||||
* @param {Object} it data for the file.
|
||||
* @returns {string} HTML (table row) describing the result for the file.
|
||||
*/
|
||||
function resultTemplate(it) {
|
||||
const { color, index, filePath, summary } = it;
|
||||
|
||||
return `
|
||||
<tr class="bg-${color}" data-group="f-${index}">
|
||||
<th colspan="4">
|
||||
[+] ${encodeHTML(filePath)}
|
||||
<span>${encodeHTML(summary)}</span>
|
||||
</th>
|
||||
</tr>
|
||||
`.trimStart();
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the results.
|
||||
* @param {Array} results Test results.
|
||||
* @param {Object} rulesMeta Dictionary containing metadata for each rule executed by the analysis.
|
||||
* @returns {string} HTML string describing the results.
|
||||
*/
|
||||
function renderResults(results, rulesMeta) {
|
||||
return results
|
||||
.map(
|
||||
(result, index) =>
|
||||
resultTemplate({
|
||||
index,
|
||||
color: renderColor(result.errorCount, result.warningCount),
|
||||
filePath: result.filePath,
|
||||
summary: renderSummary(
|
||||
result.errorCount,
|
||||
result.warningCount,
|
||||
),
|
||||
}) + renderMessages(result.messages, index, rulesMeta),
|
||||
)
|
||||
.join("\n");
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Public Interface
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
module.exports = function (results, data) {
|
||||
let totalErrors, totalWarnings;
|
||||
|
||||
const metaData = data ? data.rulesMeta : {};
|
||||
|
||||
totalErrors = 0;
|
||||
totalWarnings = 0;
|
||||
|
||||
// Iterate over results to get totals
|
||||
results.forEach(result => {
|
||||
totalErrors += result.errorCount;
|
||||
totalWarnings += result.warningCount;
|
||||
});
|
||||
|
||||
return pageTemplate({
|
||||
date: new Date(),
|
||||
reportColor: renderColor(totalErrors, totalWarnings),
|
||||
reportSummary: renderSummary(totalErrors, totalWarnings),
|
||||
results: renderResults(results, metaData),
|
||||
});
|
||||
};
|
||||
16
slider/node_modules/eslint/lib/cli-engine/formatters/json-with-metadata.js
generated
vendored
Normal file
16
slider/node_modules/eslint/lib/cli-engine/formatters/json-with-metadata.js
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* @fileoverview JSON reporter, including rules metadata
|
||||
* @author Chris Meyer
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Public Interface
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
module.exports = function (results, data) {
|
||||
return JSON.stringify({
|
||||
results,
|
||||
metadata: data,
|
||||
});
|
||||
};
|
||||
13
slider/node_modules/eslint/lib/cli-engine/formatters/json.js
generated
vendored
Normal file
13
slider/node_modules/eslint/lib/cli-engine/formatters/json.js
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* @fileoverview JSON reporter
|
||||
* @author Burak Yigit Kaya aka BYK
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Public Interface
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
module.exports = function (results) {
|
||||
return JSON.stringify(results);
|
||||
};
|
||||
122
slider/node_modules/eslint/lib/cli-engine/formatters/stylish.js
generated
vendored
Normal file
122
slider/node_modules/eslint/lib/cli-engine/formatters/stylish.js
generated
vendored
Normal file
@@ -0,0 +1,122 @@
|
||||
/**
|
||||
* @fileoverview Stylish reporter
|
||||
* @author Sindre Sorhus
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
const chalk = require("chalk"),
|
||||
util = require("node:util"),
|
||||
table = require("../../shared/text-table");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Given a word and a count, append an s if count is not one.
|
||||
* @param {string} word A word in its singular form.
|
||||
* @param {number} count A number controlling whether word should be pluralized.
|
||||
* @returns {string} The original word with an s on the end if count is not one.
|
||||
*/
|
||||
function pluralize(word, count) {
|
||||
return count === 1 ? word : `${word}s`;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Public Interface
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
module.exports = function (results) {
|
||||
let output = "\n",
|
||||
errorCount = 0,
|
||||
warningCount = 0,
|
||||
fixableErrorCount = 0,
|
||||
fixableWarningCount = 0,
|
||||
summaryColor = "yellow";
|
||||
|
||||
results.forEach(result => {
|
||||
const messages = result.messages;
|
||||
|
||||
if (messages.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
errorCount += result.errorCount;
|
||||
warningCount += result.warningCount;
|
||||
fixableErrorCount += result.fixableErrorCount;
|
||||
fixableWarningCount += result.fixableWarningCount;
|
||||
|
||||
output += `${chalk.underline(result.filePath)}\n`;
|
||||
|
||||
output += `${table(
|
||||
messages.map(message => {
|
||||
let messageType;
|
||||
|
||||
if (message.fatal || message.severity === 2) {
|
||||
messageType = chalk.red("error");
|
||||
summaryColor = "red";
|
||||
} else {
|
||||
messageType = chalk.yellow("warning");
|
||||
}
|
||||
|
||||
return [
|
||||
"",
|
||||
String(message.line || 0),
|
||||
String(message.column || 0),
|
||||
messageType,
|
||||
message.message.replace(/([^ ])\.$/u, "$1"),
|
||||
chalk.dim(message.ruleId || ""),
|
||||
];
|
||||
}),
|
||||
{
|
||||
align: ["", "r", "l"],
|
||||
stringLength(str) {
|
||||
return util.stripVTControlCharacters(str).length;
|
||||
},
|
||||
},
|
||||
)
|
||||
.split("\n")
|
||||
.map(el =>
|
||||
el.replace(/(\d+)\s+(\d+)/u, (m, p1, p2) =>
|
||||
chalk.dim(`${p1}:${p2}`),
|
||||
),
|
||||
)
|
||||
.join("\n")}\n\n`;
|
||||
});
|
||||
|
||||
const total = errorCount + warningCount;
|
||||
|
||||
if (total > 0) {
|
||||
output += chalk[summaryColor].bold(
|
||||
[
|
||||
"\u2716 ",
|
||||
total,
|
||||
pluralize(" problem", total),
|
||||
" (",
|
||||
errorCount,
|
||||
pluralize(" error", errorCount),
|
||||
", ",
|
||||
warningCount,
|
||||
pluralize(" warning", warningCount),
|
||||
")\n",
|
||||
].join(""),
|
||||
);
|
||||
|
||||
if (fixableErrorCount > 0 || fixableWarningCount > 0) {
|
||||
output += chalk[summaryColor].bold(
|
||||
[
|
||||
" ",
|
||||
fixableErrorCount,
|
||||
pluralize(" error", fixableErrorCount),
|
||||
" and ",
|
||||
fixableWarningCount,
|
||||
pluralize(" warning", fixableWarningCount),
|
||||
" potentially fixable with the `--fix` option.\n",
|
||||
].join(""),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Resets output color, for prevent change on top level
|
||||
return total > 0 ? chalk.reset(output) : "";
|
||||
};
|
||||
35
slider/node_modules/eslint/lib/cli-engine/hash.js
generated
vendored
Normal file
35
slider/node_modules/eslint/lib/cli-engine/hash.js
generated
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* @fileoverview Defining the hashing function in one place.
|
||||
* @author Michael Ficarra
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const murmur = require("imurmurhash");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Private
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* hash the given string
|
||||
* @param {string} str the string to hash
|
||||
* @returns {string} the hash
|
||||
*/
|
||||
function hash(str) {
|
||||
return murmur(str).result().toString(36);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Public Interface
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
module.exports = hash;
|
||||
7
slider/node_modules/eslint/lib/cli-engine/index.js
generated
vendored
Normal file
7
slider/node_modules/eslint/lib/cli-engine/index.js
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
"use strict";
|
||||
|
||||
const { CLIEngine } = require("./cli-engine");
|
||||
|
||||
module.exports = {
|
||||
CLIEngine,
|
||||
};
|
||||
202
slider/node_modules/eslint/lib/cli-engine/lint-result-cache.js
generated
vendored
Normal file
202
slider/node_modules/eslint/lib/cli-engine/lint-result-cache.js
generated
vendored
Normal file
@@ -0,0 +1,202 @@
|
||||
/**
|
||||
* @fileoverview Utility for caching lint results.
|
||||
* @author Kevin Partington
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
const fs = require("node:fs");
|
||||
const fileEntryCache = require("file-entry-cache");
|
||||
const stringify = require("json-stable-stringify-without-jsonify");
|
||||
const pkg = require("../../package.json");
|
||||
const assert = require("../shared/assert");
|
||||
const hash = require("./hash");
|
||||
|
||||
const debug = require("debug")("eslint:lint-result-cache");
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
const configHashCache = new WeakMap();
|
||||
const nodeVersion = process && process.version;
|
||||
|
||||
const validCacheStrategies = ["metadata", "content"];
|
||||
const invalidCacheStrategyErrorMessage = `Cache strategy must be one of: ${validCacheStrategies
|
||||
.map(strategy => `"${strategy}"`)
|
||||
.join(", ")}`;
|
||||
|
||||
/**
|
||||
* Tests whether a provided cacheStrategy is valid
|
||||
* @param {string} cacheStrategy The cache strategy to use
|
||||
* @returns {boolean} true if `cacheStrategy` is one of `validCacheStrategies`; false otherwise
|
||||
*/
|
||||
function isValidCacheStrategy(cacheStrategy) {
|
||||
return validCacheStrategies.includes(cacheStrategy);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the hash of the config
|
||||
* @param {ConfigArray} config The config.
|
||||
* @returns {string} The hash of the config
|
||||
*/
|
||||
function hashOfConfigFor(config) {
|
||||
if (!configHashCache.has(config)) {
|
||||
configHashCache.set(
|
||||
config,
|
||||
hash(`${pkg.version}_${nodeVersion}_${stringify(config)}`),
|
||||
);
|
||||
}
|
||||
|
||||
return configHashCache.get(config);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Public Interface
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Lint result cache. This wraps around the file-entry-cache module,
|
||||
* transparently removing properties that are difficult or expensive to
|
||||
* serialize and adding them back in on retrieval.
|
||||
*/
|
||||
class LintResultCache {
|
||||
/**
|
||||
* Creates a new LintResultCache instance.
|
||||
* @param {string} cacheFileLocation The cache file location.
|
||||
* @param {"metadata" | "content"} cacheStrategy The cache strategy to use.
|
||||
*/
|
||||
constructor(cacheFileLocation, cacheStrategy) {
|
||||
assert(cacheFileLocation, "Cache file location is required");
|
||||
assert(cacheStrategy, "Cache strategy is required");
|
||||
assert(
|
||||
isValidCacheStrategy(cacheStrategy),
|
||||
invalidCacheStrategyErrorMessage,
|
||||
);
|
||||
|
||||
debug(`Caching results to ${cacheFileLocation}`);
|
||||
|
||||
const useChecksum = cacheStrategy === "content";
|
||||
|
||||
debug(`Using "${cacheStrategy}" strategy to detect changes`);
|
||||
|
||||
this.fileEntryCache = fileEntryCache.create(
|
||||
cacheFileLocation,
|
||||
void 0,
|
||||
useChecksum,
|
||||
);
|
||||
this.cacheFileLocation = cacheFileLocation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve cached lint results for a given file path, if present in the
|
||||
* cache. If the file is present and has not been changed, rebuild any
|
||||
* missing result information.
|
||||
* @param {string} filePath The file for which to retrieve lint results.
|
||||
* @param {ConfigArray} config The config of the file.
|
||||
* @returns {Object|null} The rebuilt lint results, or null if the file is
|
||||
* changed or not in the filesystem.
|
||||
*/
|
||||
getCachedLintResults(filePath, config) {
|
||||
/*
|
||||
* Cached lint results are valid if and only if:
|
||||
* 1. The file is present in the filesystem
|
||||
* 2. The file has not changed since the time it was previously linted
|
||||
* 3. The ESLint configuration has not changed since the time the file
|
||||
* was previously linted
|
||||
* If any of these are not true, we will not reuse the lint results.
|
||||
*/
|
||||
const fileDescriptor = this.fileEntryCache.getFileDescriptor(filePath);
|
||||
const hashOfConfig = hashOfConfigFor(config);
|
||||
const changed =
|
||||
fileDescriptor.changed ||
|
||||
fileDescriptor.meta.hashOfConfig !== hashOfConfig;
|
||||
|
||||
if (fileDescriptor.notFound) {
|
||||
debug(`File not found on the file system: ${filePath}`);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
debug(`Cache entry not found or no longer valid: ${filePath}`);
|
||||
return null;
|
||||
}
|
||||
|
||||
const cachedResults = fileDescriptor.meta.results;
|
||||
|
||||
// Just in case, not sure if this can ever happen.
|
||||
if (!cachedResults) {
|
||||
return cachedResults;
|
||||
}
|
||||
|
||||
/*
|
||||
* Shallow clone the object to ensure that any properties added or modified afterwards
|
||||
* will not be accidentally stored in the cache file when `reconcile()` is called.
|
||||
* https://github.com/eslint/eslint/issues/13507
|
||||
* All intentional changes to the cache file must be done through `setCachedLintResults()`.
|
||||
*/
|
||||
const results = { ...cachedResults };
|
||||
|
||||
// If source is present but null, need to reread the file from the filesystem.
|
||||
if (results.source === null) {
|
||||
debug(
|
||||
`Rereading cached result source from filesystem: ${filePath}`,
|
||||
);
|
||||
results.source = fs.readFileSync(filePath, "utf-8");
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the cached lint results for a given file path, after removing any
|
||||
* information that will be both unnecessary and difficult to serialize.
|
||||
* Avoids caching results with an "output" property (meaning fixes were
|
||||
* applied), to prevent potentially incorrect results if fixes are not
|
||||
* written to disk.
|
||||
* @param {string} filePath The file for which to set lint results.
|
||||
* @param {ConfigArray} config The config of the file.
|
||||
* @param {Object} result The lint result to be set for the file.
|
||||
* @returns {void}
|
||||
*/
|
||||
setCachedLintResults(filePath, config, result) {
|
||||
if (result && Object.hasOwn(result, "output")) {
|
||||
return;
|
||||
}
|
||||
|
||||
const fileDescriptor = this.fileEntryCache.getFileDescriptor(filePath);
|
||||
|
||||
if (fileDescriptor && !fileDescriptor.notFound) {
|
||||
debug(`Updating cached result: ${filePath}`);
|
||||
|
||||
// Serialize the result, except that we want to remove the file source if present.
|
||||
const resultToSerialize = Object.assign({}, result);
|
||||
|
||||
/*
|
||||
* Set result.source to null.
|
||||
* In `getCachedLintResults`, if source is explicitly null, we will
|
||||
* read the file from the filesystem to set the value again.
|
||||
*/
|
||||
if (Object.hasOwn(resultToSerialize, "source")) {
|
||||
resultToSerialize.source = null;
|
||||
}
|
||||
|
||||
fileDescriptor.meta.results = resultToSerialize;
|
||||
fileDescriptor.meta.hashOfConfig = hashOfConfigFor(config);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Persists the in-memory cache to disk.
|
||||
* @returns {void}
|
||||
*/
|
||||
reconcile() {
|
||||
debug(`Persisting cached results: ${this.cacheFileLocation}`);
|
||||
this.fileEntryCache.reconcile();
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = LintResultCache;
|
||||
46
slider/node_modules/eslint/lib/cli-engine/load-rules.js
generated
vendored
Normal file
46
slider/node_modules/eslint/lib/cli-engine/load-rules.js
generated
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* @fileoverview Module for loading rules from files and directories.
|
||||
* @author Michael Ficarra
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const fs = require("node:fs"),
|
||||
path = require("node:path");
|
||||
|
||||
const rulesDirCache = {};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Public Interface
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Load all rule modules from specified directory.
|
||||
* @param {string} relativeRulesDir Path to rules directory, may be relative.
|
||||
* @param {string} cwd Current working directory
|
||||
* @returns {Object} Loaded rule modules.
|
||||
*/
|
||||
module.exports = function (relativeRulesDir, cwd) {
|
||||
const rulesDir = path.resolve(cwd, relativeRulesDir);
|
||||
|
||||
// cache will help performance as IO operation are expensive
|
||||
if (rulesDirCache[rulesDir]) {
|
||||
return rulesDirCache[rulesDir];
|
||||
}
|
||||
|
||||
const rules = Object.create(null);
|
||||
|
||||
fs.readdirSync(rulesDir).forEach(file => {
|
||||
if (path.extname(file) !== ".js") {
|
||||
return;
|
||||
}
|
||||
rules[file.slice(0, -3)] = require(path.join(rulesDir, file));
|
||||
});
|
||||
rulesDirCache[rulesDir] = rules;
|
||||
|
||||
return rules;
|
||||
};
|
||||
553
slider/node_modules/eslint/lib/cli.js
generated
vendored
Normal file
553
slider/node_modules/eslint/lib/cli.js
generated
vendored
Normal file
@@ -0,0 +1,553 @@
|
||||
/**
|
||||
* @fileoverview Main CLI object.
|
||||
* @author Nicholas C. Zakas
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
* NOTE: The CLI object should *not* call process.exit() directly. It should only return
|
||||
* exit codes. This allows other programs to use the CLI object and still control
|
||||
* when the program exits.
|
||||
*/
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const fs = require("node:fs"),
|
||||
{ mkdir, stat, writeFile } = require("node:fs/promises"),
|
||||
path = require("node:path"),
|
||||
{ pathToFileURL } = require("node:url"),
|
||||
{ LegacyESLint } = require("./eslint"),
|
||||
{
|
||||
ESLint,
|
||||
shouldUseFlatConfig,
|
||||
locateConfigFileToUse,
|
||||
} = require("./eslint/eslint"),
|
||||
createCLIOptions = require("./options"),
|
||||
log = require("./shared/logging"),
|
||||
RuntimeInfo = require("./shared/runtime-info"),
|
||||
translateOptions = require("./shared/translate-cli-options");
|
||||
const { getCacheFile } = require("./eslint/eslint-helpers");
|
||||
const { SuppressionsService } = require("./services/suppressions-service");
|
||||
const debug = require("debug")("eslint:cli");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Types
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @typedef {import("./options").ParsedCLIOptions} ParsedCLIOptions */
|
||||
/** @typedef {import("./types").ESLint.LintResult} LintResult */
|
||||
/** @typedef {import("./types").ESLint.ResultsMeta} ResultsMeta */
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Count error messages.
|
||||
* @param {LintResult[]} results The lint results.
|
||||
* @returns {{errorCount:number;fatalErrorCount:number,warningCount:number}} The number of error messages.
|
||||
*/
|
||||
function countErrors(results) {
|
||||
let errorCount = 0;
|
||||
let fatalErrorCount = 0;
|
||||
let warningCount = 0;
|
||||
|
||||
for (const result of results) {
|
||||
errorCount += result.errorCount;
|
||||
fatalErrorCount += result.fatalErrorCount;
|
||||
warningCount += result.warningCount;
|
||||
}
|
||||
|
||||
return { errorCount, fatalErrorCount, warningCount };
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an options module from the provided CLI options and encodes it as a data URL.
|
||||
* @param {ParsedCLIOptions} options The CLI options.
|
||||
* @returns {URL} The URL of the options module.
|
||||
*/
|
||||
function createOptionsModule(options) {
|
||||
const translateOptionsFileURL = new URL(
|
||||
"./shared/translate-cli-options.js",
|
||||
pathToFileURL(__filename),
|
||||
).href;
|
||||
const optionsSrc =
|
||||
`import translateOptions from ${JSON.stringify(translateOptionsFileURL)};\n` +
|
||||
`export default await translateOptions(${JSON.stringify(options)}, "flat");\n`;
|
||||
|
||||
// Base64 encoding is typically shorter than URL encoding
|
||||
return new URL(
|
||||
`data:text/javascript;base64,${Buffer.from(optionsSrc).toString("base64")}`,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given file path is a directory or not.
|
||||
* @param {string} filePath The path to a file to check.
|
||||
* @returns {Promise<boolean>} `true` if the given path is a directory.
|
||||
*/
|
||||
async function isDirectory(filePath) {
|
||||
try {
|
||||
return (await stat(filePath)).isDirectory();
|
||||
} catch (error) {
|
||||
if (error.code === "ENOENT" || error.code === "ENOTDIR") {
|
||||
return false;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs the results of the linting.
|
||||
* @param {ESLint} engine The ESLint instance to use.
|
||||
* @param {LintResult[]} results The results to print.
|
||||
* @param {string} format The name of the formatter to use or the path to the formatter.
|
||||
* @param {string} outputFile The path for the output file.
|
||||
* @param {ResultsMeta} resultsMeta Warning count and max threshold.
|
||||
* @returns {Promise<boolean>} True if the printing succeeds, false if not.
|
||||
* @private
|
||||
*/
|
||||
async function printResults(engine, results, format, outputFile, resultsMeta) {
|
||||
let formatter;
|
||||
|
||||
try {
|
||||
formatter = await engine.loadFormatter(format);
|
||||
} catch (e) {
|
||||
log.error(e.message);
|
||||
return false;
|
||||
}
|
||||
|
||||
const output = await formatter.format(results, resultsMeta);
|
||||
|
||||
if (outputFile) {
|
||||
const filePath = path.resolve(process.cwd(), outputFile);
|
||||
|
||||
if (await isDirectory(filePath)) {
|
||||
log.error(
|
||||
"Cannot write to output file path, it is a directory: %s",
|
||||
outputFile,
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
await mkdir(path.dirname(filePath), { recursive: true });
|
||||
await writeFile(filePath, output);
|
||||
} catch (ex) {
|
||||
log.error("There was a problem writing the output file:\n%s", ex);
|
||||
return false;
|
||||
}
|
||||
} else if (output) {
|
||||
log.info(output);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the `--concurrency` flag value.
|
||||
* @param {string} concurrency The `--concurrency` flag value to validate.
|
||||
* @returns {void}
|
||||
* @throws {Error} If the `--concurrency` flag value is invalid.
|
||||
*/
|
||||
function validateConcurrency(concurrency) {
|
||||
if (
|
||||
concurrency === void 0 ||
|
||||
concurrency === "auto" ||
|
||||
concurrency === "off"
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const concurrencyValue = Number(concurrency);
|
||||
|
||||
if (!Number.isInteger(concurrencyValue) || concurrencyValue < 1) {
|
||||
throw new Error(
|
||||
`Option concurrency: '${concurrency}' is not a positive integer, 'auto' or 'off'.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Public Interface
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Encapsulates all CLI behavior for eslint. Makes it easier to test as well as
|
||||
* for other Node.js programs to effectively run the CLI.
|
||||
*/
|
||||
const cli = {
|
||||
/**
|
||||
* Calculates the command string for the --inspect-config operation.
|
||||
* @param {string} configFile The path to the config file to inspect.
|
||||
* @returns {Promise<string>} The command string to execute.
|
||||
*/
|
||||
async calculateInspectConfigFlags(configFile) {
|
||||
// find the config file
|
||||
const { configFilePath, basePath } = await locateConfigFileToUse({
|
||||
cwd: process.cwd(),
|
||||
configFile,
|
||||
});
|
||||
|
||||
return ["--config", configFilePath, "--basePath", basePath];
|
||||
},
|
||||
|
||||
/**
|
||||
* Executes the CLI based on an array of arguments that is passed in.
|
||||
* @param {string|Array|Object} args The arguments to process.
|
||||
* @param {string} [text] The text to lint (used for TTY).
|
||||
* @param {boolean} [allowFlatConfig=true] Whether or not to allow flat config.
|
||||
* @returns {Promise<number>} The exit code for the operation.
|
||||
*/
|
||||
async execute(args, text, allowFlatConfig = true) {
|
||||
if (Array.isArray(args)) {
|
||||
debug("CLI args: %o", args.slice(2));
|
||||
}
|
||||
|
||||
/*
|
||||
* Before doing anything, we need to see if we are using a
|
||||
* flat config file. If so, then we need to change the way command
|
||||
* line args are parsed. This is temporary, and when we fully
|
||||
* switch to flat config we can remove this logic.
|
||||
*/
|
||||
|
||||
const usingFlatConfig =
|
||||
allowFlatConfig && (await shouldUseFlatConfig());
|
||||
|
||||
debug("Using flat config?", usingFlatConfig);
|
||||
|
||||
if (allowFlatConfig && !usingFlatConfig) {
|
||||
const { WarningService } = require("./services/warning-service");
|
||||
new WarningService().emitESLintRCWarning();
|
||||
}
|
||||
|
||||
const CLIOptions = createCLIOptions(usingFlatConfig);
|
||||
|
||||
/** @type {ParsedCLIOptions} */
|
||||
let options;
|
||||
|
||||
try {
|
||||
options = CLIOptions.parse(args);
|
||||
validateConcurrency(options.concurrency);
|
||||
} catch (error) {
|
||||
debug("Error parsing CLI options:", error.message);
|
||||
|
||||
let errorMessage = error.message;
|
||||
|
||||
if (usingFlatConfig) {
|
||||
errorMessage +=
|
||||
"\nYou're using eslint.config.js, some command line flags are no longer available. Please see https://eslint.org/docs/latest/use/command-line-interface for details.";
|
||||
}
|
||||
|
||||
log.error(errorMessage);
|
||||
return 2;
|
||||
}
|
||||
|
||||
const files = options._;
|
||||
const useStdin = typeof text === "string";
|
||||
|
||||
if (options.help) {
|
||||
log.info(CLIOptions.generateHelp());
|
||||
return 0;
|
||||
}
|
||||
if (options.version) {
|
||||
log.info(RuntimeInfo.version());
|
||||
return 0;
|
||||
}
|
||||
if (options.envInfo) {
|
||||
try {
|
||||
log.info(RuntimeInfo.environment());
|
||||
return 0;
|
||||
} catch (err) {
|
||||
debug("Error retrieving environment info");
|
||||
log.error(err.message);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (options.printConfig) {
|
||||
if (files.length) {
|
||||
log.error(
|
||||
"The --print-config option must be used with exactly one file name.",
|
||||
);
|
||||
return 2;
|
||||
}
|
||||
if (useStdin) {
|
||||
log.error(
|
||||
"The --print-config option is not available for piped-in code.",
|
||||
);
|
||||
return 2;
|
||||
}
|
||||
|
||||
const engine = usingFlatConfig
|
||||
? new ESLint(await translateOptions(options, "flat"))
|
||||
: new LegacyESLint(await translateOptions(options));
|
||||
const fileConfig = await engine.calculateConfigForFile(
|
||||
options.printConfig,
|
||||
);
|
||||
|
||||
log.info(JSON.stringify(fileConfig, null, " "));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (options.inspectConfig) {
|
||||
log.info(
|
||||
"You can also run this command directly using 'npx @eslint/config-inspector@latest' in the same directory as your configuration file.",
|
||||
);
|
||||
|
||||
try {
|
||||
const flatOptions = await translateOptions(options, "flat");
|
||||
const spawn = require("cross-spawn");
|
||||
const flags = await cli.calculateInspectConfigFlags(
|
||||
flatOptions.overrideConfigFile,
|
||||
);
|
||||
|
||||
spawn.sync(
|
||||
"npx",
|
||||
["@eslint/config-inspector@latest", ...flags],
|
||||
{ encoding: "utf8", stdio: "inherit" },
|
||||
);
|
||||
} catch (error) {
|
||||
log.error(error);
|
||||
return 2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
debug(`Running on ${useStdin ? "text" : "files"}`);
|
||||
|
||||
if (options.fix && options.fixDryRun) {
|
||||
log.error(
|
||||
"The --fix option and the --fix-dry-run option cannot be used together.",
|
||||
);
|
||||
return 2;
|
||||
}
|
||||
if (useStdin && options.fix) {
|
||||
log.error(
|
||||
"The --fix option is not available for piped-in code; use --fix-dry-run instead.",
|
||||
);
|
||||
return 2;
|
||||
}
|
||||
if (options.fixType && !options.fix && !options.fixDryRun) {
|
||||
log.error(
|
||||
"The --fix-type option requires either --fix or --fix-dry-run.",
|
||||
);
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (
|
||||
options.reportUnusedDisableDirectives &&
|
||||
options.reportUnusedDisableDirectivesSeverity !== void 0
|
||||
) {
|
||||
log.error(
|
||||
"The --report-unused-disable-directives option and the --report-unused-disable-directives-severity option cannot be used together.",
|
||||
);
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (usingFlatConfig && options.ext) {
|
||||
// Passing `--ext ""` results in `options.ext` being an empty array.
|
||||
if (options.ext.length === 0) {
|
||||
log.error("The --ext option value cannot be empty.");
|
||||
return 2;
|
||||
}
|
||||
|
||||
// Passing `--ext ,ts` results in an empty string at index 0. Passing `--ext ts,,tsx` results in an empty string at index 1.
|
||||
const emptyStringIndex = options.ext.indexOf("");
|
||||
|
||||
if (emptyStringIndex >= 0) {
|
||||
log.error(
|
||||
`The --ext option arguments cannot be empty strings. Found an empty string at index ${emptyStringIndex}.`,
|
||||
);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (options.suppressAll && options.suppressRule) {
|
||||
log.error(
|
||||
"The --suppress-all option and the --suppress-rule option cannot be used together.",
|
||||
);
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (options.suppressAll && options.pruneSuppressions) {
|
||||
log.error(
|
||||
"The --suppress-all option and the --prune-suppressions option cannot be used together.",
|
||||
);
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (options.suppressRule && options.pruneSuppressions) {
|
||||
log.error(
|
||||
"The --suppress-rule option and the --prune-suppressions option cannot be used together.",
|
||||
);
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (
|
||||
useStdin &&
|
||||
(options.suppressAll ||
|
||||
options.suppressRule ||
|
||||
options.pruneSuppressions)
|
||||
) {
|
||||
log.error(
|
||||
"The --suppress-all, --suppress-rule, and --prune-suppressions options cannot be used with piped-in code.",
|
||||
);
|
||||
return 2;
|
||||
}
|
||||
|
||||
const ActiveESLint = usingFlatConfig ? ESLint : LegacyESLint;
|
||||
|
||||
/** @type {ESLint|LegacyESLint} */
|
||||
let engine;
|
||||
|
||||
if (options.concurrency && options.concurrency !== "off") {
|
||||
const optionsURL = createOptionsModule(options);
|
||||
engine = await ESLint.fromOptionsModule(optionsURL);
|
||||
} else {
|
||||
const eslintOptions = await translateOptions(
|
||||
options,
|
||||
usingFlatConfig ? "flat" : "eslintrc",
|
||||
);
|
||||
engine = new ActiveESLint(eslintOptions);
|
||||
}
|
||||
let results;
|
||||
|
||||
if (useStdin) {
|
||||
results = await engine.lintText(text, {
|
||||
filePath: options.stdinFilename,
|
||||
|
||||
// flatConfig respects CLI flag and constructor warnIgnored, eslintrc forces true for backwards compatibility
|
||||
warnIgnored: usingFlatConfig ? void 0 : true,
|
||||
});
|
||||
} else {
|
||||
results = await engine.lintFiles(files);
|
||||
}
|
||||
|
||||
if (options.fix) {
|
||||
debug("Fix mode enabled - applying fixes");
|
||||
await ActiveESLint.outputFixes(results);
|
||||
}
|
||||
|
||||
let unusedSuppressions = {};
|
||||
|
||||
if (!useStdin) {
|
||||
const suppressionsFileLocation = getCacheFile(
|
||||
options.suppressionsLocation || "eslint-suppressions.json",
|
||||
process.cwd(),
|
||||
{
|
||||
prefix: "suppressions_",
|
||||
},
|
||||
);
|
||||
|
||||
if (
|
||||
options.suppressionsLocation &&
|
||||
!fs.existsSync(suppressionsFileLocation) &&
|
||||
!options.suppressAll &&
|
||||
!options.suppressRule
|
||||
) {
|
||||
log.error(
|
||||
"The suppressions file does not exist. Please run the command with `--suppress-all` or `--suppress-rule` to create it.",
|
||||
);
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (
|
||||
options.suppressAll ||
|
||||
options.suppressRule ||
|
||||
options.pruneSuppressions ||
|
||||
fs.existsSync(suppressionsFileLocation)
|
||||
) {
|
||||
const suppressions = new SuppressionsService({
|
||||
filePath: suppressionsFileLocation,
|
||||
cwd: process.cwd(),
|
||||
});
|
||||
|
||||
if (options.suppressAll || options.suppressRule) {
|
||||
await suppressions.suppress(results, options.suppressRule);
|
||||
}
|
||||
|
||||
if (options.pruneSuppressions) {
|
||||
await suppressions.prune(results);
|
||||
}
|
||||
|
||||
const suppressionResults = suppressions.applySuppressions(
|
||||
results,
|
||||
await suppressions.load(),
|
||||
);
|
||||
|
||||
results = suppressionResults.results;
|
||||
unusedSuppressions = suppressionResults.unused;
|
||||
}
|
||||
}
|
||||
|
||||
let resultsToPrint = results;
|
||||
|
||||
if (options.quiet) {
|
||||
debug("Quiet mode enabled - filtering out warnings");
|
||||
resultsToPrint = ActiveESLint.getErrorResults(resultsToPrint);
|
||||
}
|
||||
|
||||
const resultCounts = countErrors(results);
|
||||
const tooManyWarnings =
|
||||
options.maxWarnings >= 0 &&
|
||||
resultCounts.warningCount > options.maxWarnings;
|
||||
const resultsMeta = tooManyWarnings
|
||||
? {
|
||||
maxWarningsExceeded: {
|
||||
maxWarnings: options.maxWarnings,
|
||||
foundWarnings: resultCounts.warningCount,
|
||||
},
|
||||
}
|
||||
: {};
|
||||
|
||||
if (
|
||||
await printResults(
|
||||
engine,
|
||||
resultsToPrint,
|
||||
options.format,
|
||||
options.outputFile,
|
||||
resultsMeta,
|
||||
)
|
||||
) {
|
||||
// Errors and warnings from the original unfiltered results should determine the exit code
|
||||
const shouldExitForFatalErrors =
|
||||
options.exitOnFatalError && resultCounts.fatalErrorCount > 0;
|
||||
|
||||
if (!resultCounts.errorCount && tooManyWarnings) {
|
||||
log.error(
|
||||
"ESLint found too many warnings (maximum: %s).",
|
||||
options.maxWarnings,
|
||||
);
|
||||
}
|
||||
|
||||
if (!options.passOnUnprunedSuppressions) {
|
||||
const unusedSuppressionsCount =
|
||||
Object.keys(unusedSuppressions).length;
|
||||
|
||||
if (unusedSuppressionsCount > 0) {
|
||||
log.error(
|
||||
"There are suppressions left that do not occur anymore. Consider re-running the command with `--prune-suppressions`.",
|
||||
);
|
||||
debug(JSON.stringify(unusedSuppressions, null, 2));
|
||||
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldExitForFatalErrors) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
return resultCounts.errorCount || tooManyWarnings ? 1 : 0;
|
||||
}
|
||||
|
||||
return 2;
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = cli;
|
||||
12
slider/node_modules/eslint/lib/config-api.js
generated
vendored
Normal file
12
slider/node_modules/eslint/lib/config-api.js
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* @fileoverview exports for config helpers
|
||||
* @author Nicholas C. Zakas
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
const { defineConfig, globalIgnores } = require("@eslint/config-helpers");
|
||||
|
||||
module.exports = {
|
||||
defineConfig,
|
||||
globalIgnores,
|
||||
};
|
||||
816
slider/node_modules/eslint/lib/config/config-loader.js
generated
vendored
Normal file
816
slider/node_modules/eslint/lib/config/config-loader.js
generated
vendored
Normal file
@@ -0,0 +1,816 @@
|
||||
/**
|
||||
* @fileoverview Utility to load config files
|
||||
* @author Nicholas C. Zakas
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const path = require("node:path");
|
||||
const fs = require("node:fs/promises");
|
||||
const findUp = require("find-up");
|
||||
const { pathToFileURL } = require("node:url");
|
||||
const debug = require("debug")("eslint:config-loader");
|
||||
const { FlatConfigArray } = require("./flat-config-array");
|
||||
const { WarningService } = require("../services/warning-service");
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Types
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/** @typedef {import("../types").Linter.Config} Config */
|
||||
|
||||
/**
|
||||
* @typedef {Object} ConfigLoaderOptions
|
||||
* @property {string|false|undefined} configFile The path to the config file to use.
|
||||
* @property {string} cwd The current working directory.
|
||||
* @property {boolean} ignoreEnabled Indicates if ignore patterns should be honored.
|
||||
* @property {Config|Array<Config>} [baseConfig] The base config to use.
|
||||
* @property {Array<Config>} [defaultConfigs] The default configs to use.
|
||||
* @property {Array<string>} [ignorePatterns] The ignore patterns to use.
|
||||
* @property {Config|Array<Config>} [overrideConfig] The override config to use.
|
||||
* @property {boolean} [hasUnstableNativeNodeJsTSConfigFlag] The flag to indicate whether the `unstable_native_nodejs_ts_config` flag is enabled.
|
||||
* @property {WarningService} [warningService] The warning service to use.
|
||||
*/
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const FLAT_CONFIG_FILENAMES = [
|
||||
"eslint.config.js",
|
||||
"eslint.config.mjs",
|
||||
"eslint.config.cjs",
|
||||
"eslint.config.ts",
|
||||
"eslint.config.mts",
|
||||
"eslint.config.cts",
|
||||
];
|
||||
|
||||
const importedConfigFileModificationTime = new Map();
|
||||
|
||||
/**
|
||||
* Asserts that the given file path is valid.
|
||||
* @param {string} filePath The file path to check.
|
||||
* @returns {void}
|
||||
* @throws {Error} If `filePath` is not a non-empty string.
|
||||
*/
|
||||
function assertValidFilePath(filePath) {
|
||||
if (!filePath || typeof filePath !== "string") {
|
||||
throw new Error("'filePath' must be a non-empty string");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that a configuration exists. A configuration exists if any
|
||||
* of the following are true:
|
||||
* - `configFilePath` is defined.
|
||||
* - `useConfigFile` is `false`.
|
||||
* @param {string|undefined} configFilePath The path to the config file.
|
||||
* @param {ConfigLoaderOptions} loaderOptions The options to use when loading configuration files.
|
||||
* @returns {void}
|
||||
* @throws {Error} If no configuration exists.
|
||||
*/
|
||||
function assertConfigurationExists(configFilePath, loaderOptions) {
|
||||
const { configFile: useConfigFile } = loaderOptions;
|
||||
|
||||
if (!configFilePath && useConfigFile !== false) {
|
||||
const error = new Error("Could not find config file.");
|
||||
|
||||
error.messageTemplate = "config-file-missing";
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the file is a TypeScript file.
|
||||
* @param {string} filePath The file path to check.
|
||||
* @returns {boolean} `true` if the file is a TypeScript file, `false` if it's not.
|
||||
*/
|
||||
function isFileTS(filePath) {
|
||||
const fileExtension = path.extname(filePath);
|
||||
|
||||
return /^\.[mc]?ts$/u.test(fileExtension);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if ESLint is running in Bun.
|
||||
* @returns {boolean} `true` if the ESLint is running Bun, `false` if it's not.
|
||||
*/
|
||||
function isRunningInBun() {
|
||||
return !!globalThis.Bun;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if ESLint is running in Deno.
|
||||
* @returns {boolean} `true` if the ESLint is running in Deno, `false` if it's not.
|
||||
*/
|
||||
function isRunningInDeno() {
|
||||
return !!globalThis.Deno;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if native TypeScript support is
|
||||
* enabled in the current Node.js process.
|
||||
*
|
||||
* This function determines if the
|
||||
* {@linkcode NodeJS.ProcessFeatures.typescript | typescript}
|
||||
* feature is present in the
|
||||
* {@linkcode process.features} object
|
||||
* and if its value is either "strip" or "transform".
|
||||
* @returns {boolean} `true` if native TypeScript support is enabled, otherwise `false`.
|
||||
* @since 9.24.0
|
||||
*/
|
||||
function isNativeTypeScriptSupportEnabled() {
|
||||
return (
|
||||
// eslint-disable-next-line n/no-unsupported-features/node-builtins -- it's still an experimental feature.
|
||||
["strip", "transform"].includes(process.features.typescript)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the TypeScript configuration file.
|
||||
* @param {string} filePath The absolute file path to load.
|
||||
* @param {URL} fileURL The file URL to load.
|
||||
* @param {number} mtime The last modified timestamp of the file.
|
||||
* @returns {Promise<any>} The configuration loaded from the file.
|
||||
* @since 9.24.0
|
||||
*/
|
||||
async function loadTypeScriptConfigFileWithJiti(filePath, fileURL, mtime) {
|
||||
const { createJiti, version: jitiVersion } =
|
||||
// eslint-disable-next-line no-use-before-define -- `ConfigLoader.loadJiti` can be overwritten for testing
|
||||
await ConfigLoader.loadJiti().catch(() => {
|
||||
throw new Error(
|
||||
"The 'jiti' library is required for loading TypeScript configuration files. Make sure to install it.",
|
||||
);
|
||||
});
|
||||
|
||||
// `createJiti` was added in jiti v2.
|
||||
if (typeof createJiti !== "function") {
|
||||
throw new Error(
|
||||
"You are using an outdated version of the 'jiti' library. Please update to the latest version of 'jiti' to ensure compatibility and access to the latest features.",
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* Disabling `moduleCache` allows us to reload a
|
||||
* config file when the last modified timestamp changes.
|
||||
*/
|
||||
const jitiOptions = {
|
||||
moduleCache: false,
|
||||
};
|
||||
|
||||
if (jitiVersion.startsWith("2.1.")) {
|
||||
jitiOptions.interopDefault = false;
|
||||
}
|
||||
|
||||
const jiti = createJiti(__filename, jitiOptions);
|
||||
const config = await jiti.import(fileURL.href);
|
||||
|
||||
importedConfigFileModificationTime.set(filePath, mtime);
|
||||
|
||||
return config?.default ?? config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dynamically imports a module from the given file path.
|
||||
* @param {string} filePath The absolute file path of the module to import.
|
||||
* @param {URL} fileURL The file URL to load.
|
||||
* @param {number} mtime The last modified timestamp of the file.
|
||||
* @returns {Promise<any>} - A {@linkcode Promise | promise} that resolves to the imported ESLint config.
|
||||
* @since 9.24.0
|
||||
*/
|
||||
async function dynamicImportConfig(filePath, fileURL, mtime) {
|
||||
const module = await import(fileURL.href);
|
||||
|
||||
importedConfigFileModificationTime.set(filePath, mtime);
|
||||
|
||||
return module.default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the config array from the given filename.
|
||||
* @param {string} filePath The filename to load from.
|
||||
* @param {boolean} hasUnstableNativeNodeJsTSConfigFlag The flag to indicate whether the `unstable_native_nodejs_ts_config` flag is enabled.
|
||||
* @returns {Promise<any>} The config loaded from the config file.
|
||||
*/
|
||||
async function loadConfigFile(filePath, hasUnstableNativeNodeJsTSConfigFlag) {
|
||||
debug(`Loading config from ${filePath}`);
|
||||
|
||||
const fileURL = pathToFileURL(filePath);
|
||||
|
||||
debug(`Config file URL is ${fileURL}`);
|
||||
|
||||
const mtime = (await fs.stat(filePath)).mtime.getTime();
|
||||
|
||||
/*
|
||||
* Append a query with the config file's modification time (`mtime`) in order
|
||||
* to import the current version of the config file. Without the query, `import()` would
|
||||
* cache the config file module by the pathname only, and then always return
|
||||
* the same version (the one that was actual when the module was imported for the first time).
|
||||
*
|
||||
* This ensures that the config file module is loaded and executed again
|
||||
* if it has been changed since the last time it was imported.
|
||||
* If it hasn't been changed, `import()` will just return the cached version.
|
||||
*
|
||||
* Note that we should not overuse queries (e.g., by appending the current time
|
||||
* to always reload the config file module) as that could cause memory leaks
|
||||
* because entries are never removed from the import cache.
|
||||
*/
|
||||
fileURL.searchParams.append("mtime", mtime);
|
||||
|
||||
/*
|
||||
* With queries, we can bypass the import cache. However, when import-ing a CJS module,
|
||||
* Node.js uses the require infrastructure under the hood. That includes the require cache,
|
||||
* which caches the config file module by its file path (queries have no effect).
|
||||
* Therefore, we also need to clear the require cache before importing the config file module.
|
||||
* In order to get the same behavior with ESM and CJS config files, in particular - to reload
|
||||
* the config file only if it has been changed, we track file modification times and clear
|
||||
* the require cache only if the file has been changed.
|
||||
*/
|
||||
if (importedConfigFileModificationTime.get(filePath) !== mtime) {
|
||||
delete require.cache[filePath];
|
||||
}
|
||||
|
||||
const isTS = isFileTS(filePath);
|
||||
const isBun = isRunningInBun();
|
||||
const isDeno = isRunningInDeno();
|
||||
|
||||
/*
|
||||
* If we are dealing with a TypeScript file, then we need to use `jiti` to load it
|
||||
* in Node.js. Deno and Bun both allow native importing of TypeScript files.
|
||||
*
|
||||
* When Node.js supports native TypeScript imports, we can remove this check.
|
||||
*/
|
||||
|
||||
if (isTS) {
|
||||
if (hasUnstableNativeNodeJsTSConfigFlag) {
|
||||
if (isNativeTypeScriptSupportEnabled()) {
|
||||
return await dynamicImportConfig(filePath, fileURL, mtime);
|
||||
}
|
||||
|
||||
if (!("typescript" in process.features)) {
|
||||
throw new Error(
|
||||
"The unstable_native_nodejs_ts_config flag is not supported in older versions of Node.js.",
|
||||
);
|
||||
}
|
||||
|
||||
throw new Error(
|
||||
"The unstable_native_nodejs_ts_config flag is enabled, but native TypeScript support is not enabled in the current Node.js process. You need to either enable native TypeScript support by passing --experimental-strip-types or remove the unstable_native_nodejs_ts_config flag.",
|
||||
);
|
||||
}
|
||||
|
||||
if (!isDeno && !isBun) {
|
||||
return await loadTypeScriptConfigFileWithJiti(
|
||||
filePath,
|
||||
fileURL,
|
||||
mtime,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// fallback to normal runtime behavior
|
||||
|
||||
return await dynamicImportConfig(filePath, fileURL, mtime);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Exports
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Encapsulates the loading and caching of configuration files when looking up
|
||||
* from the file being linted.
|
||||
*/
|
||||
class ConfigLoader {
|
||||
/**
|
||||
* Map of config file paths to the config arrays for those directories.
|
||||
* @type {Map<string, FlatConfigArray|Promise<FlatConfigArray>>}
|
||||
*/
|
||||
#configArrays = new Map();
|
||||
|
||||
/**
|
||||
* Map of absolute directory names to the config file paths for those directories.
|
||||
* @type {Map<string, {configFilePath:string,basePath:string}|Promise<{configFilePath:string,basePath:string}>>}
|
||||
*/
|
||||
#configFilePaths = new Map();
|
||||
|
||||
/**
|
||||
* The options to use when loading configuration files.
|
||||
* @type {ConfigLoaderOptions}
|
||||
*/
|
||||
#options;
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
* @param {ConfigLoaderOptions} options The options to use when loading configuration files.
|
||||
*/
|
||||
constructor(options) {
|
||||
this.#options = options.warningService
|
||||
? options
|
||||
: { ...options, warningService: new WarningService() };
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines which config file to use. This is determined by seeing if an
|
||||
* override config file was specified, and if so, using it; otherwise, as long
|
||||
* as override config file is not explicitly set to `false`, it will search
|
||||
* upwards from `fromDirectory` for a file named `eslint.config.js`.
|
||||
* @param {string} fromDirectory The directory from which to start searching.
|
||||
* @returns {Promise<{configFilePath:string|undefined,basePath:string}>} Location information for
|
||||
* the config file.
|
||||
*/
|
||||
async #locateConfigFileToUse(fromDirectory) {
|
||||
// check cache first
|
||||
if (this.#configFilePaths.has(fromDirectory)) {
|
||||
return this.#configFilePaths.get(fromDirectory);
|
||||
}
|
||||
|
||||
const resultPromise = ConfigLoader.locateConfigFileToUse({
|
||||
useConfigFile: this.#options.configFile,
|
||||
cwd: this.#options.cwd,
|
||||
fromDirectory,
|
||||
});
|
||||
|
||||
// ensure `ConfigLoader.locateConfigFileToUse` is called only once for `fromDirectory`
|
||||
this.#configFilePaths.set(fromDirectory, resultPromise);
|
||||
|
||||
// Unwrap the promise. This is primarily for the sync `getCachedConfigArrayForPath` method.
|
||||
const result = await resultPromise;
|
||||
|
||||
this.#configFilePaths.set(fromDirectory, result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the config array for this run based on inputs.
|
||||
* @param {string} configFilePath The absolute path to the config file to use if not overridden.
|
||||
* @param {string} basePath The base path to use for relative paths in the config file.
|
||||
* @returns {Promise<FlatConfigArray>} The config array for `eslint`.
|
||||
*/
|
||||
async #calculateConfigArray(configFilePath, basePath) {
|
||||
// check for cached version first
|
||||
if (this.#configArrays.has(configFilePath)) {
|
||||
return this.#configArrays.get(configFilePath);
|
||||
}
|
||||
|
||||
const configsPromise = ConfigLoader.calculateConfigArray(
|
||||
configFilePath,
|
||||
basePath,
|
||||
this.#options,
|
||||
);
|
||||
|
||||
// ensure `ConfigLoader.calculateConfigArray` is called only once for `configFilePath`
|
||||
this.#configArrays.set(configFilePath, configsPromise);
|
||||
|
||||
// Unwrap the promise. This is primarily for the sync `getCachedConfigArrayForPath` method.
|
||||
const configs = await configsPromise;
|
||||
|
||||
this.#configArrays.set(configFilePath, configs);
|
||||
|
||||
return configs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the config file path for the given directory or file. This will either use
|
||||
* the override config file that was specified in the constructor options or
|
||||
* search for a config file from the directory.
|
||||
* @param {string} fileOrDirPath The file or directory path to get the config file path for.
|
||||
* @returns {Promise<string|undefined>} The config file path or `undefined` if not found.
|
||||
* @throws {Error} If `fileOrDirPath` is not a non-empty string.
|
||||
* @throws {Error} If `fileOrDirPath` is not an absolute path.
|
||||
*/
|
||||
async findConfigFileForPath(fileOrDirPath) {
|
||||
assertValidFilePath(fileOrDirPath);
|
||||
|
||||
const absoluteDirPath = path.resolve(
|
||||
this.#options.cwd,
|
||||
path.dirname(fileOrDirPath),
|
||||
);
|
||||
const { configFilePath } =
|
||||
await this.#locateConfigFileToUse(absoluteDirPath);
|
||||
|
||||
return configFilePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a configuration object for the given file based on the CLI options.
|
||||
* This is the same logic used by the ESLint CLI executable to determine
|
||||
* configuration for each file it processes.
|
||||
* @param {string} filePath The path of the file or directory to retrieve config for.
|
||||
* @returns {Promise<FlatConfigArray>} A configuration object for the file.
|
||||
* @throws {Error} If no configuration for `filePath` exists.
|
||||
*/
|
||||
async loadConfigArrayForFile(filePath) {
|
||||
assertValidFilePath(filePath);
|
||||
|
||||
debug(`Calculating config for file ${filePath}`);
|
||||
|
||||
const configFilePath = await this.findConfigFileForPath(filePath);
|
||||
|
||||
assertConfigurationExists(configFilePath, this.#options);
|
||||
|
||||
return this.loadConfigArrayForDirectory(filePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a configuration object for the given directory based on the CLI options.
|
||||
* This is the same logic used by the ESLint CLI executable to determine
|
||||
* configuration for each file it processes.
|
||||
* @param {string} dirPath The path of the directory to retrieve config for.
|
||||
* @returns {Promise<FlatConfigArray>} A configuration object for the directory.
|
||||
*/
|
||||
async loadConfigArrayForDirectory(dirPath) {
|
||||
assertValidFilePath(dirPath);
|
||||
|
||||
debug(`Calculating config for directory ${dirPath}`);
|
||||
|
||||
const absoluteDirPath = path.resolve(
|
||||
this.#options.cwd,
|
||||
path.dirname(dirPath),
|
||||
);
|
||||
const { configFilePath, basePath } =
|
||||
await this.#locateConfigFileToUse(absoluteDirPath);
|
||||
|
||||
debug(`Using config file ${configFilePath} and base path ${basePath}`);
|
||||
return this.#calculateConfigArray(configFilePath, basePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a configuration array for the given file based on the CLI options.
|
||||
* This is a synchronous operation and does not read any files from disk. It's
|
||||
* intended to be used in locations where we know the config file has already
|
||||
* been loaded and we just need to get the configuration for a file.
|
||||
* @param {string} filePath The path of the file to retrieve a config object for.
|
||||
* @returns {FlatConfigArray} A configuration object for the file.
|
||||
* @throws {Error} If `filePath` is not a non-empty string.
|
||||
* @throws {Error} If `filePath` is not an absolute path.
|
||||
* @throws {Error} If the config file was not already loaded.
|
||||
*/
|
||||
getCachedConfigArrayForFile(filePath) {
|
||||
assertValidFilePath(filePath);
|
||||
|
||||
debug(`Looking up cached config for ${filePath}`);
|
||||
|
||||
return this.getCachedConfigArrayForPath(path.dirname(filePath));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a configuration array for the given directory based on the CLI options.
|
||||
* This is a synchronous operation and does not read any files from disk. It's
|
||||
* intended to be used in locations where we know the config file has already
|
||||
* been loaded and we just need to get the configuration for a file.
|
||||
* @param {string} fileOrDirPath The path of the directory to retrieve a config object for.
|
||||
* @returns {FlatConfigArray} A configuration object for the directory.
|
||||
* @throws {Error} If `dirPath` is not a non-empty string.
|
||||
* @throws {Error} If `dirPath` is not an absolute path.
|
||||
* @throws {Error} If the config file was not already loaded.
|
||||
*/
|
||||
getCachedConfigArrayForPath(fileOrDirPath) {
|
||||
assertValidFilePath(fileOrDirPath);
|
||||
|
||||
debug(`Looking up cached config for ${fileOrDirPath}`);
|
||||
|
||||
const absoluteDirPath = path.resolve(this.#options.cwd, fileOrDirPath);
|
||||
|
||||
if (!this.#configFilePaths.has(absoluteDirPath)) {
|
||||
throw new Error(`Could not find config file for ${fileOrDirPath}`);
|
||||
}
|
||||
|
||||
const configFilePathInfo = this.#configFilePaths.get(absoluteDirPath);
|
||||
|
||||
if (typeof configFilePathInfo.then === "function") {
|
||||
throw new Error(
|
||||
`Config file path for ${fileOrDirPath} has not yet been calculated or an error occurred during the calculation`,
|
||||
);
|
||||
}
|
||||
|
||||
const { configFilePath } = configFilePathInfo;
|
||||
|
||||
const configArray = this.#configArrays.get(configFilePath);
|
||||
|
||||
if (!configArray || typeof configArray.then === "function") {
|
||||
throw new Error(
|
||||
`Config array for ${fileOrDirPath} has not yet been calculated or an error occurred during the calculation`,
|
||||
);
|
||||
}
|
||||
|
||||
return configArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to import the jiti dependency. This method is exposed internally for testing purposes.
|
||||
* @returns {Promise<{createJiti: Function|undefined, version: string;}>} A promise that fulfills with an object containing the jiti module's createJiti function and version.
|
||||
*/
|
||||
static async loadJiti() {
|
||||
const { createJiti } = await import("jiti");
|
||||
const version = require("jiti/package.json").version;
|
||||
return { createJiti, version };
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines which config file to use. This is determined by seeing if an
|
||||
* override config file was specified, and if so, using it; otherwise, as long
|
||||
* as override config file is not explicitly set to `false`, it will search
|
||||
* upwards from `fromDirectory` for a file named `eslint.config.js`.
|
||||
* This method is exposed internally for testing purposes.
|
||||
* @param {Object} [options] the options object
|
||||
* @param {string|false|undefined} options.useConfigFile The path to the config file to use.
|
||||
* @param {string} options.cwd Path to a directory that should be considered as the current working directory.
|
||||
* @param {string} [options.fromDirectory] The directory from which to start searching. Defaults to `cwd`.
|
||||
* @returns {Promise<{configFilePath:string|undefined,basePath:string}>} Location information for
|
||||
* the config file.
|
||||
*/
|
||||
static async locateConfigFileToUse({
|
||||
useConfigFile,
|
||||
cwd,
|
||||
fromDirectory = cwd,
|
||||
}) {
|
||||
// determine where to load config file from
|
||||
let configFilePath;
|
||||
let basePath = cwd;
|
||||
|
||||
if (typeof useConfigFile === "string") {
|
||||
debug(`Override config file path is ${useConfigFile}`);
|
||||
configFilePath = path.resolve(cwd, useConfigFile);
|
||||
basePath = cwd;
|
||||
} else if (useConfigFile !== false) {
|
||||
debug("Searching for eslint.config.js");
|
||||
configFilePath = await findUp(FLAT_CONFIG_FILENAMES, {
|
||||
cwd: fromDirectory,
|
||||
});
|
||||
|
||||
if (configFilePath) {
|
||||
basePath = path.dirname(configFilePath);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
configFilePath,
|
||||
basePath,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the config array for this run based on inputs.
|
||||
* This method is exposed internally for testing purposes.
|
||||
* @param {string} configFilePath The absolute path to the config file to use if not overridden.
|
||||
* @param {string} basePath The base path to use for relative paths in the config file.
|
||||
* @param {ConfigLoaderOptions} options The options to use when loading configuration files.
|
||||
* @returns {Promise<FlatConfigArray>} The config array for `eslint`.
|
||||
*/
|
||||
static async calculateConfigArray(configFilePath, basePath, options) {
|
||||
const {
|
||||
cwd,
|
||||
baseConfig,
|
||||
ignoreEnabled,
|
||||
ignorePatterns,
|
||||
overrideConfig,
|
||||
hasUnstableNativeNodeJsTSConfigFlag = false,
|
||||
defaultConfigs = [],
|
||||
warningService,
|
||||
} = options;
|
||||
|
||||
debug(
|
||||
`Calculating config array from config file ${configFilePath} and base path ${basePath}`,
|
||||
);
|
||||
|
||||
const configs = new FlatConfigArray(baseConfig || [], {
|
||||
basePath,
|
||||
shouldIgnore: ignoreEnabled,
|
||||
});
|
||||
|
||||
// load config file
|
||||
if (configFilePath) {
|
||||
debug(`Loading config file ${configFilePath}`);
|
||||
const fileConfig = await loadConfigFile(
|
||||
configFilePath,
|
||||
hasUnstableNativeNodeJsTSConfigFlag,
|
||||
);
|
||||
|
||||
/*
|
||||
* It's possible that a config file could be empty or else
|
||||
* have an empty object or array. In this case, we want to
|
||||
* warn the user that they have an empty config.
|
||||
*
|
||||
* An empty CommonJS file exports an empty object while
|
||||
* an empty ESM file exports undefined.
|
||||
*/
|
||||
|
||||
let emptyConfig = typeof fileConfig === "undefined";
|
||||
|
||||
debug(
|
||||
`Config file ${configFilePath} is ${emptyConfig ? "empty" : "not empty"}`,
|
||||
);
|
||||
|
||||
if (!emptyConfig) {
|
||||
if (Array.isArray(fileConfig)) {
|
||||
if (fileConfig.length === 0) {
|
||||
debug(
|
||||
`Config file ${configFilePath} is an empty array`,
|
||||
);
|
||||
emptyConfig = true;
|
||||
} else {
|
||||
configs.push(...fileConfig);
|
||||
}
|
||||
} else {
|
||||
if (
|
||||
typeof fileConfig === "object" &&
|
||||
fileConfig !== null &&
|
||||
Object.keys(fileConfig).length === 0
|
||||
) {
|
||||
debug(
|
||||
`Config file ${configFilePath} is an empty object`,
|
||||
);
|
||||
emptyConfig = true;
|
||||
} else {
|
||||
configs.push(fileConfig);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (emptyConfig) {
|
||||
warningService.emitEmptyConfigWarning(configFilePath);
|
||||
}
|
||||
}
|
||||
|
||||
// add in any configured defaults
|
||||
configs.push(...defaultConfigs);
|
||||
|
||||
// append command line ignore patterns
|
||||
if (ignorePatterns && ignorePatterns.length > 0) {
|
||||
/*
|
||||
* Ignore patterns are added to the end of the config array
|
||||
* so they can override default ignores.
|
||||
*/
|
||||
configs.push({
|
||||
basePath: cwd,
|
||||
ignores: ignorePatterns,
|
||||
});
|
||||
}
|
||||
|
||||
if (overrideConfig) {
|
||||
if (Array.isArray(overrideConfig)) {
|
||||
configs.push(...overrideConfig);
|
||||
} else {
|
||||
configs.push(overrideConfig);
|
||||
}
|
||||
}
|
||||
|
||||
await configs.normalize();
|
||||
|
||||
return configs;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encapsulates the loading and caching of configuration files when looking up
|
||||
* from the current working directory.
|
||||
*/
|
||||
class LegacyConfigLoader extends ConfigLoader {
|
||||
/**
|
||||
* The options to use when loading configuration files.
|
||||
* @type {ConfigLoaderOptions}
|
||||
*/
|
||||
#options;
|
||||
|
||||
/**
|
||||
* The cached config file path for this instance.
|
||||
* @type {Promise<{configFilePath:string,basePath:string}|undefined>}
|
||||
*/
|
||||
#configFilePath;
|
||||
|
||||
/**
|
||||
* The cached config array for this instance.
|
||||
* @type {FlatConfigArray|Promise<FlatConfigArray>}
|
||||
*/
|
||||
#configArray;
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
* @param {ConfigLoaderOptions} options The options to use when loading configuration files.
|
||||
*/
|
||||
constructor(options) {
|
||||
const normalizedOptions = options.warningService
|
||||
? options
|
||||
: { ...options, warningService: new WarningService() };
|
||||
super(normalizedOptions);
|
||||
this.#options = normalizedOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines which config file to use. This is determined by seeing if an
|
||||
* override config file was specified, and if so, using it; otherwise, as long
|
||||
* as override config file is not explicitly set to `false`, it will search
|
||||
* upwards from the cwd for a file named `eslint.config.js`.
|
||||
* @returns {Promise<{configFilePath:string|undefined,basePath:string}>} Location information for
|
||||
* the config file.
|
||||
*/
|
||||
#locateConfigFileToUse() {
|
||||
if (!this.#configFilePath) {
|
||||
this.#configFilePath = ConfigLoader.locateConfigFileToUse({
|
||||
useConfigFile: this.#options.configFile,
|
||||
cwd: this.#options.cwd,
|
||||
});
|
||||
}
|
||||
|
||||
return this.#configFilePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the config array for this run based on inputs.
|
||||
* @param {string} configFilePath The absolute path to the config file to use if not overridden.
|
||||
* @param {string} basePath The base path to use for relative paths in the config file.
|
||||
* @returns {Promise<FlatConfigArray>} The config array for `eslint`.
|
||||
*/
|
||||
async #calculateConfigArray(configFilePath, basePath) {
|
||||
// check for cached version first
|
||||
if (this.#configArray) {
|
||||
return this.#configArray;
|
||||
}
|
||||
|
||||
// ensure `ConfigLoader.calculateConfigArray` is called only once
|
||||
this.#configArray = ConfigLoader.calculateConfigArray(
|
||||
configFilePath,
|
||||
basePath,
|
||||
this.#options,
|
||||
);
|
||||
|
||||
// Unwrap the promise. This is primarily for the sync `getCachedConfigArrayForPath` method.
|
||||
this.#configArray = await this.#configArray;
|
||||
|
||||
return this.#configArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the config file path for the given directory. This will either use
|
||||
* the override config file that was specified in the constructor options or
|
||||
* search for a config file from the directory of the file being linted.
|
||||
* @param {string} dirPath The directory path to get the config file path for.
|
||||
* @returns {Promise<string|undefined>} The config file path or `undefined` if not found.
|
||||
* @throws {Error} If `fileOrDirPath` is not a non-empty string.
|
||||
* @throws {Error} If `fileOrDirPath` is not an absolute path.
|
||||
*/
|
||||
async findConfigFileForPath(dirPath) {
|
||||
assertValidFilePath(dirPath);
|
||||
|
||||
const { configFilePath } = await this.#locateConfigFileToUse();
|
||||
|
||||
return configFilePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a configuration object for the given file based on the CLI options.
|
||||
* This is the same logic used by the ESLint CLI executable to determine
|
||||
* configuration for each file it processes.
|
||||
* @param {string} dirPath The path of the directory to retrieve config for.
|
||||
* @returns {Promise<FlatConfigArray>} A configuration object for the file.
|
||||
*/
|
||||
async loadConfigArrayForDirectory(dirPath) {
|
||||
assertValidFilePath(dirPath);
|
||||
|
||||
debug(`[Legacy]: Calculating config for ${dirPath}`);
|
||||
|
||||
const { configFilePath, basePath } =
|
||||
await this.#locateConfigFileToUse();
|
||||
|
||||
debug(
|
||||
`[Legacy]: Using config file ${configFilePath} and base path ${basePath}`,
|
||||
);
|
||||
return this.#calculateConfigArray(configFilePath, basePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a configuration array for the given directory based on the CLI options.
|
||||
* This is a synchronous operation and does not read any files from disk. It's
|
||||
* intended to be used in locations where we know the config file has already
|
||||
* been loaded and we just need to get the configuration for a file.
|
||||
* @param {string} dirPath The path of the directory to retrieve a config object for.
|
||||
* @returns {FlatConfigArray} A configuration object for the file.
|
||||
* @throws {Error} If `dirPath` is not a non-empty string.
|
||||
* @throws {Error} If `dirPath` is not an absolute path.
|
||||
* @throws {Error} If the config file was not already loaded.
|
||||
*/
|
||||
getCachedConfigArrayForPath(dirPath) {
|
||||
assertValidFilePath(dirPath);
|
||||
|
||||
debug(`[Legacy]: Looking up cached config for ${dirPath}`);
|
||||
|
||||
if (!this.#configArray) {
|
||||
throw new Error(`Could not find config file for ${dirPath}`);
|
||||
}
|
||||
|
||||
if (typeof this.#configArray.then === "function") {
|
||||
throw new Error(
|
||||
`Config array for ${dirPath} has not yet been calculated or an error occurred during the calculation`,
|
||||
);
|
||||
}
|
||||
|
||||
return this.#configArray;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { ConfigLoader, LegacyConfigLoader };
|
||||
674
slider/node_modules/eslint/lib/config/config.js
generated
vendored
Normal file
674
slider/node_modules/eslint/lib/config/config.js
generated
vendored
Normal file
@@ -0,0 +1,674 @@
|
||||
/**
|
||||
* @fileoverview The `Config` class
|
||||
* @author Nicholas C. Zakas
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
const { deepMergeArrays } = require("../shared/deep-merge-arrays");
|
||||
const { flatConfigSchema, hasMethod } = require("./flat-config-schema");
|
||||
const { ObjectSchema } = require("@eslint/config-array");
|
||||
const ajvImport = require("../shared/ajv");
|
||||
const ajv = ajvImport();
|
||||
const ruleReplacements = require("../../conf/replacements.json");
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Typedefs
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @import { RuleDefinition } from "@eslint/core";
|
||||
* @import { Linter } from "eslint";
|
||||
*/
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Private Members
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// JSON schema that disallows passing any options
|
||||
const noOptionsSchema = Object.freeze({
|
||||
type: "array",
|
||||
minItems: 0,
|
||||
maxItems: 0,
|
||||
});
|
||||
|
||||
const severities = new Map([
|
||||
[0, 0],
|
||||
[1, 1],
|
||||
[2, 2],
|
||||
["off", 0],
|
||||
["warn", 1],
|
||||
["error", 2],
|
||||
]);
|
||||
|
||||
/**
|
||||
* A collection of compiled validators for rules that have already
|
||||
* been validated.
|
||||
* @type {WeakMap}
|
||||
*/
|
||||
const validators = new WeakMap();
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Throws a helpful error when a rule cannot be found.
|
||||
* @param {Object} ruleId The rule identifier.
|
||||
* @param {string} ruleId.pluginName The ID of the rule to find.
|
||||
* @param {string} ruleId.ruleName The ID of the rule to find.
|
||||
* @param {Object} config The config to search in.
|
||||
* @throws {TypeError} For missing plugin or rule.
|
||||
* @returns {void}
|
||||
*/
|
||||
function throwRuleNotFoundError({ pluginName, ruleName }, config) {
|
||||
const ruleId = pluginName === "@" ? ruleName : `${pluginName}/${ruleName}`;
|
||||
|
||||
const errorMessageHeader = `Key "rules": Key "${ruleId}"`;
|
||||
|
||||
let errorMessage = `${errorMessageHeader}: Could not find plugin "${pluginName}" in configuration.`;
|
||||
|
||||
const missingPluginErrorMessage = errorMessage;
|
||||
|
||||
// if the plugin exists then we need to check if the rule exists
|
||||
if (config.plugins && config.plugins[pluginName]) {
|
||||
const replacementRuleName = ruleReplacements.rules[ruleName];
|
||||
|
||||
if (pluginName === "@" && replacementRuleName) {
|
||||
errorMessage = `${errorMessageHeader}: Rule "${ruleName}" was removed and replaced by "${replacementRuleName}".`;
|
||||
} else {
|
||||
errorMessage = `${errorMessageHeader}: Could not find "${ruleName}" in plugin "${pluginName}".`;
|
||||
|
||||
// otherwise, let's see if we can find the rule name elsewhere
|
||||
for (const [otherPluginName, otherPlugin] of Object.entries(
|
||||
config.plugins,
|
||||
)) {
|
||||
if (otherPlugin.rules && otherPlugin.rules[ruleName]) {
|
||||
errorMessage += ` Did you mean "${otherPluginName}/${ruleName}"?`;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// falls through to throw error
|
||||
}
|
||||
|
||||
const error = new TypeError(errorMessage);
|
||||
|
||||
if (errorMessage === missingPluginErrorMessage) {
|
||||
error.messageTemplate = "config-plugin-missing";
|
||||
error.messageData = { pluginName, ruleId };
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
|
||||
/**
|
||||
* The error type when a rule has an invalid `meta.schema`.
|
||||
*/
|
||||
class InvalidRuleOptionsSchemaError extends Error {
|
||||
/**
|
||||
* Creates a new instance.
|
||||
* @param {string} ruleId Id of the rule that has an invalid `meta.schema`.
|
||||
* @param {Error} processingError Error caught while processing the `meta.schema`.
|
||||
*/
|
||||
constructor(ruleId, processingError) {
|
||||
super(
|
||||
`Error while processing options validation schema of rule '${ruleId}': ${processingError.message}`,
|
||||
{ cause: processingError },
|
||||
);
|
||||
this.code = "ESLINT_INVALID_RULE_OPTIONS_SCHEMA";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a ruleId into its plugin and rule parts.
|
||||
* @param {string} ruleId The rule ID to parse.
|
||||
* @returns {{pluginName:string,ruleName:string}} The plugin and rule
|
||||
* parts of the ruleId;
|
||||
*/
|
||||
function parseRuleId(ruleId) {
|
||||
let pluginName, ruleName;
|
||||
|
||||
// distinguish between core rules and plugin rules
|
||||
if (ruleId.includes("/")) {
|
||||
// mimic scoped npm packages
|
||||
if (ruleId.startsWith("@")) {
|
||||
pluginName = ruleId.slice(0, ruleId.lastIndexOf("/"));
|
||||
} else {
|
||||
pluginName = ruleId.slice(0, ruleId.indexOf("/"));
|
||||
}
|
||||
|
||||
ruleName = ruleId.slice(pluginName.length + 1);
|
||||
} else {
|
||||
pluginName = "@";
|
||||
ruleName = ruleId;
|
||||
}
|
||||
|
||||
return {
|
||||
pluginName,
|
||||
ruleName,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a rule instance from a given config based on the ruleId.
|
||||
* @param {string} ruleId The rule ID to look for.
|
||||
* @param {Linter.Config} config The config to search.
|
||||
* @returns {RuleDefinition|undefined} The rule if found
|
||||
* or undefined if not.
|
||||
*/
|
||||
function getRuleFromConfig(ruleId, config) {
|
||||
const { pluginName, ruleName } = parseRuleId(ruleId);
|
||||
|
||||
return config.plugins?.[pluginName]?.rules?.[ruleName];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a complete options schema for a rule.
|
||||
* @param {RuleDefinition} rule A rule object
|
||||
* @throws {TypeError} If `meta.schema` is specified but is not an array, object or `false`.
|
||||
* @returns {Object|null} JSON Schema for the rule's options. `null` if `meta.schema` is `false`.
|
||||
*/
|
||||
function getRuleOptionsSchema(rule) {
|
||||
if (!rule.meta) {
|
||||
return { ...noOptionsSchema }; // default if `meta.schema` is not specified
|
||||
}
|
||||
|
||||
const schema = rule.meta.schema;
|
||||
|
||||
if (typeof schema === "undefined") {
|
||||
return { ...noOptionsSchema }; // default if `meta.schema` is not specified
|
||||
}
|
||||
|
||||
// `schema:false` is an allowed explicit opt-out of options validation for the rule
|
||||
if (schema === false) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (typeof schema !== "object" || schema === null) {
|
||||
throw new TypeError("Rule's `meta.schema` must be an array or object");
|
||||
}
|
||||
|
||||
// ESLint-specific array form needs to be converted into a valid JSON Schema definition
|
||||
if (Array.isArray(schema)) {
|
||||
if (schema.length) {
|
||||
return {
|
||||
type: "array",
|
||||
items: schema,
|
||||
minItems: 0,
|
||||
maxItems: schema.length,
|
||||
};
|
||||
}
|
||||
|
||||
// `schema:[]` is an explicit way to specify that the rule does not accept any options
|
||||
return { ...noOptionsSchema };
|
||||
}
|
||||
|
||||
// `schema:<object>` is assumed to be a valid JSON Schema definition
|
||||
return schema;
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits a plugin identifier in the form a/b/c into two parts: a/b and c.
|
||||
* @param {string} identifier The identifier to parse.
|
||||
* @returns {{objectName: string, pluginName: string}} The parts of the plugin
|
||||
* name.
|
||||
*/
|
||||
function splitPluginIdentifier(identifier) {
|
||||
const parts = identifier.split("/");
|
||||
|
||||
return {
|
||||
objectName: parts.pop(),
|
||||
pluginName: parts.join("/"),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of an object in the config by reading its `meta` key.
|
||||
* @param {Object} object The object to check.
|
||||
* @returns {string?} The name of the object if found or `null` if there
|
||||
* is no name.
|
||||
*/
|
||||
function getObjectId(object) {
|
||||
// first check old-style name
|
||||
let name = object.name;
|
||||
|
||||
if (!name) {
|
||||
if (!object.meta) {
|
||||
return null;
|
||||
}
|
||||
|
||||
name = object.meta.name;
|
||||
|
||||
if (!name) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// now check for old-style version
|
||||
let version = object.version;
|
||||
|
||||
if (!version) {
|
||||
version = object.meta && object.meta.version;
|
||||
}
|
||||
|
||||
// if there's a version then append that
|
||||
if (version) {
|
||||
return `${name}@${version}`;
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that a value is not a function.
|
||||
* @param {any} value The value to check.
|
||||
* @param {string} key The key of the value in the object.
|
||||
* @param {string} objectKey The key of the object being checked.
|
||||
* @returns {void}
|
||||
* @throws {TypeError} If the value is a function.
|
||||
*/
|
||||
function assertNotFunction(value, key, objectKey) {
|
||||
if (typeof value === "function") {
|
||||
const error = new TypeError(
|
||||
`Cannot serialize key "${key}" in "${objectKey}": Function values are not supported.`,
|
||||
);
|
||||
|
||||
error.messageTemplate = "config-serialize-function";
|
||||
error.messageData = { key, objectKey };
|
||||
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a languageOptions object to a JSON representation.
|
||||
* @param {Record<string, any>} languageOptions The options to create a JSON
|
||||
* representation of.
|
||||
* @param {string} objectKey The key of the object being converted.
|
||||
* @returns {Record<string, any>} The JSON representation of the languageOptions.
|
||||
* @throws {TypeError} If a function is found in the languageOptions.
|
||||
*/
|
||||
function languageOptionsToJSON(languageOptions, objectKey = "languageOptions") {
|
||||
if (typeof languageOptions.toJSON === "function") {
|
||||
const result = languageOptions.toJSON();
|
||||
|
||||
assertNotFunction(result, "toJSON", objectKey);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
const result = {};
|
||||
|
||||
for (const [key, value] of Object.entries(languageOptions)) {
|
||||
if (value) {
|
||||
if (typeof value === "object") {
|
||||
const name = getObjectId(value);
|
||||
|
||||
if (typeof value.toJSON === "function") {
|
||||
result[key] = value.toJSON();
|
||||
assertNotFunction(result[key], key, objectKey);
|
||||
} else if (name && hasMethod(value)) {
|
||||
result[key] = name;
|
||||
} else {
|
||||
result[key] = languageOptionsToJSON(value, key);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
assertNotFunction(value, key, objectKey);
|
||||
}
|
||||
|
||||
result[key] = value;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets or creates a validator for a rule.
|
||||
* @param {Object} rule The rule to get a validator for.
|
||||
* @param {string} ruleId The ID of the rule (for error reporting).
|
||||
* @returns {Function|null} A validation function or null if no validation is needed.
|
||||
* @throws {InvalidRuleOptionsSchemaError} If a rule's `meta.schema` is invalid.
|
||||
*/
|
||||
function getOrCreateValidator(rule, ruleId) {
|
||||
if (!validators.has(rule)) {
|
||||
try {
|
||||
const schema = getRuleOptionsSchema(rule);
|
||||
|
||||
if (schema) {
|
||||
validators.set(rule, ajv.compile(schema));
|
||||
}
|
||||
} catch (err) {
|
||||
throw new InvalidRuleOptionsSchemaError(ruleId, err);
|
||||
}
|
||||
}
|
||||
|
||||
return validators.get(rule);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Exports
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Represents a normalized configuration object.
|
||||
*/
|
||||
class Config {
|
||||
/**
|
||||
* The name to use for the language when serializing to JSON.
|
||||
* @type {string|undefined}
|
||||
*/
|
||||
#languageName;
|
||||
|
||||
/**
|
||||
* The name to use for the processor when serializing to JSON.
|
||||
* @type {string|undefined}
|
||||
*/
|
||||
#processorName;
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
* @param {Object} config The configuration object.
|
||||
*/
|
||||
constructor(config) {
|
||||
const { plugins, language, languageOptions, processor, ...otherKeys } =
|
||||
config;
|
||||
|
||||
// Validate config object
|
||||
const schema = new ObjectSchema(flatConfigSchema);
|
||||
|
||||
schema.validate(config);
|
||||
|
||||
// first, copy all the other keys over
|
||||
Object.assign(this, otherKeys);
|
||||
|
||||
// ensure that a language is specified
|
||||
if (!language) {
|
||||
throw new TypeError("Key 'language' is required.");
|
||||
}
|
||||
|
||||
// copy the rest over
|
||||
this.plugins = plugins;
|
||||
this.language = language;
|
||||
|
||||
// Check language value
|
||||
const {
|
||||
pluginName: languagePluginName,
|
||||
objectName: localLanguageName,
|
||||
} = splitPluginIdentifier(language);
|
||||
|
||||
this.#languageName = language;
|
||||
|
||||
if (
|
||||
!plugins ||
|
||||
!plugins[languagePluginName] ||
|
||||
!plugins[languagePluginName].languages ||
|
||||
!plugins[languagePluginName].languages[localLanguageName]
|
||||
) {
|
||||
throw new TypeError(
|
||||
`Key "language": Could not find "${localLanguageName}" in plugin "${languagePluginName}".`,
|
||||
);
|
||||
}
|
||||
|
||||
this.language =
|
||||
plugins[languagePluginName].languages[localLanguageName];
|
||||
|
||||
if (this.language.defaultLanguageOptions ?? languageOptions) {
|
||||
this.languageOptions = flatConfigSchema.languageOptions.merge(
|
||||
this.language.defaultLanguageOptions,
|
||||
languageOptions,
|
||||
);
|
||||
} else {
|
||||
this.languageOptions = {};
|
||||
}
|
||||
|
||||
// Validate language options
|
||||
try {
|
||||
this.language.validateLanguageOptions(this.languageOptions);
|
||||
} catch (error) {
|
||||
throw new TypeError(`Key "languageOptions": ${error.message}`, {
|
||||
cause: error,
|
||||
});
|
||||
}
|
||||
|
||||
// Normalize language options if necessary
|
||||
if (this.language.normalizeLanguageOptions) {
|
||||
this.languageOptions = this.language.normalizeLanguageOptions(
|
||||
this.languageOptions,
|
||||
);
|
||||
}
|
||||
|
||||
// Check processor value
|
||||
if (processor) {
|
||||
this.processor = processor;
|
||||
|
||||
if (typeof processor === "string") {
|
||||
const { pluginName, objectName: localProcessorName } =
|
||||
splitPluginIdentifier(processor);
|
||||
|
||||
this.#processorName = processor;
|
||||
|
||||
if (
|
||||
!plugins ||
|
||||
!plugins[pluginName] ||
|
||||
!plugins[pluginName].processors ||
|
||||
!plugins[pluginName].processors[localProcessorName]
|
||||
) {
|
||||
throw new TypeError(
|
||||
`Key "processor": Could not find "${localProcessorName}" in plugin "${pluginName}".`,
|
||||
);
|
||||
}
|
||||
|
||||
this.processor =
|
||||
plugins[pluginName].processors[localProcessorName];
|
||||
} else if (typeof processor === "object") {
|
||||
this.#processorName = getObjectId(processor);
|
||||
this.processor = processor;
|
||||
} else {
|
||||
throw new TypeError(
|
||||
"Key 'processor' must be a string or an object.",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Process the rules
|
||||
if (this.rules) {
|
||||
this.#normalizeRulesConfig();
|
||||
this.validateRulesConfig(this.rules);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the configuration to a JSON representation.
|
||||
* @returns {Record<string, any>} The JSON representation of the configuration.
|
||||
* @throws {Error} If the configuration cannot be serialized.
|
||||
*/
|
||||
toJSON() {
|
||||
if (this.processor && !this.#processorName) {
|
||||
throw new Error(
|
||||
"Could not serialize processor object (missing 'meta' object).",
|
||||
);
|
||||
}
|
||||
|
||||
if (!this.#languageName) {
|
||||
throw new Error(
|
||||
"Could not serialize language object (missing 'meta' object).",
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
...this,
|
||||
plugins: Object.entries(this.plugins).map(([namespace, plugin]) => {
|
||||
const pluginId = getObjectId(plugin);
|
||||
|
||||
if (!pluginId) {
|
||||
return namespace;
|
||||
}
|
||||
|
||||
return `${namespace}:${pluginId}`;
|
||||
}),
|
||||
language: this.#languageName,
|
||||
languageOptions: languageOptionsToJSON(this.languageOptions),
|
||||
processor: this.#processorName,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a rule configuration by its ID.
|
||||
* @param {string} ruleId The ID of the rule to get.
|
||||
* @returns {RuleDefinition|undefined} The rule definition from the plugin, or `undefined` if the rule is not found.
|
||||
*/
|
||||
getRuleDefinition(ruleId) {
|
||||
return getRuleFromConfig(ruleId, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes the rules configuration. Ensures that each rule config is
|
||||
* an array and that the severity is a number. Applies meta.defaultOptions.
|
||||
* This function modifies `this.rules`.
|
||||
* @returns {void}
|
||||
*/
|
||||
#normalizeRulesConfig() {
|
||||
for (const [ruleId, originalConfig] of Object.entries(this.rules)) {
|
||||
// ensure rule config is an array
|
||||
let ruleConfig = Array.isArray(originalConfig)
|
||||
? originalConfig
|
||||
: [originalConfig];
|
||||
|
||||
// normalize severity
|
||||
ruleConfig[0] = severities.get(ruleConfig[0]);
|
||||
|
||||
const rule = getRuleFromConfig(ruleId, this);
|
||||
|
||||
// apply meta.defaultOptions
|
||||
const slicedOptions = ruleConfig.slice(1);
|
||||
const mergedOptions = deepMergeArrays(
|
||||
rule?.meta?.defaultOptions,
|
||||
slicedOptions,
|
||||
);
|
||||
|
||||
if (mergedOptions.length) {
|
||||
ruleConfig = [ruleConfig[0], ...mergedOptions];
|
||||
}
|
||||
|
||||
this.rules[ruleId] = ruleConfig;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates all of the rule configurations in the given rules config
|
||||
* against the plugins in this instance. This is used primarily to
|
||||
* validate inline configuration rules while inting.
|
||||
* @param {Object} rulesConfig The rules config to validate.
|
||||
* @returns {void}
|
||||
* @throws {Error} If a rule's configuration does not match its schema.
|
||||
* @throws {TypeError} If the rulesConfig is not provided or is invalid.
|
||||
* @throws {InvalidRuleOptionsSchemaError} If a rule's `meta.schema` is invalid.
|
||||
* @throws {TypeError} If a rule is not found in the plugins.
|
||||
*/
|
||||
validateRulesConfig(rulesConfig) {
|
||||
if (!rulesConfig) {
|
||||
throw new TypeError("Config is required for validation.");
|
||||
}
|
||||
|
||||
for (const [ruleId, ruleOptions] of Object.entries(rulesConfig)) {
|
||||
// check for edge case
|
||||
if (ruleId === "__proto__") {
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* If a rule is disabled, we don't do any validation. This allows
|
||||
* users to safely set any value to 0 or "off" without worrying
|
||||
* that it will cause a validation error.
|
||||
*
|
||||
* Note: ruleOptions is always an array at this point because
|
||||
* this validation occurs after FlatConfigArray has merged and
|
||||
* normalized values.
|
||||
*/
|
||||
if (ruleOptions[0] === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const rule = getRuleFromConfig(ruleId, this);
|
||||
|
||||
if (!rule) {
|
||||
throwRuleNotFoundError(parseRuleId(ruleId), this);
|
||||
}
|
||||
|
||||
const validateRule = getOrCreateValidator(rule, ruleId);
|
||||
|
||||
if (validateRule) {
|
||||
validateRule(ruleOptions.slice(1));
|
||||
|
||||
if (validateRule.errors) {
|
||||
throw new Error(
|
||||
`Key "rules": Key "${ruleId}":\n${validateRule.errors
|
||||
.map(error => {
|
||||
if (
|
||||
error.keyword === "additionalProperties" &&
|
||||
error.schema === false &&
|
||||
typeof error.parentSchema?.properties ===
|
||||
"object" &&
|
||||
typeof error.params?.additionalProperty ===
|
||||
"string"
|
||||
) {
|
||||
const expectedProperties = Object.keys(
|
||||
error.parentSchema.properties,
|
||||
).map(property => `"${property}"`);
|
||||
|
||||
return `\tValue ${JSON.stringify(error.data)} ${error.message}.\n\t\tUnexpected property "${error.params.additionalProperty}". Expected properties: ${expectedProperties.join(", ")}.\n`;
|
||||
}
|
||||
|
||||
return `\tValue ${JSON.stringify(error.data)} ${error.message}.\n`;
|
||||
})
|
||||
.join("")}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a complete options schema for a rule.
|
||||
* @param {RuleDefinition} ruleDefinition A rule definition object.
|
||||
* @throws {TypeError} If `meta.schema` is specified but is not an array, object or `false`.
|
||||
* @returns {Object|null} JSON Schema for the rule's options. `null` if `meta.schema` is `false`.
|
||||
*/
|
||||
static getRuleOptionsSchema(ruleDefinition) {
|
||||
return getRuleOptionsSchema(ruleDefinition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes the severity value of a rule's configuration to a number
|
||||
* @param {(number|string|[number, ...*]|[string, ...*])} ruleConfig A rule's configuration value, generally
|
||||
* received from the user. A valid config value is either 0, 1, 2, the string "off" (treated the same as 0),
|
||||
* the string "warn" (treated the same as 1), the string "error" (treated the same as 2), or an array
|
||||
* whose first element is one of the above values. Strings are matched case-insensitively.
|
||||
* @returns {(0|1|2)} The numeric severity value if the config value was valid, otherwise 0.
|
||||
*/
|
||||
static getRuleNumericSeverity(ruleConfig) {
|
||||
const severityValue = Array.isArray(ruleConfig)
|
||||
? ruleConfig[0]
|
||||
: ruleConfig;
|
||||
|
||||
if (severities.has(severityValue)) {
|
||||
return severities.get(severityValue);
|
||||
}
|
||||
|
||||
if (typeof severityValue === "string") {
|
||||
return severities.get(severityValue.toLowerCase()) ?? 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { Config };
|
||||
78
slider/node_modules/eslint/lib/config/default-config.js
generated
vendored
Normal file
78
slider/node_modules/eslint/lib/config/default-config.js
generated
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
* @fileoverview Default configuration
|
||||
* @author Nicholas C. Zakas
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
const Rules = require("../rules");
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
const sharedDefaultConfig = [
|
||||
// intentionally empty config to ensure these files are globbed by default
|
||||
{
|
||||
files: ["**/*.js", "**/*.mjs"],
|
||||
},
|
||||
{
|
||||
files: ["**/*.cjs"],
|
||||
languageOptions: {
|
||||
sourceType: "commonjs",
|
||||
ecmaVersion: "latest",
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
exports.defaultConfig = Object.freeze([
|
||||
{
|
||||
plugins: {
|
||||
"@": {
|
||||
languages: {
|
||||
js: require("../languages/js"),
|
||||
},
|
||||
|
||||
/*
|
||||
* Because we try to delay loading rules until absolutely
|
||||
* necessary, a proxy allows us to hook into the lazy-loading
|
||||
* aspect of the rules map while still keeping all of the
|
||||
* relevant configuration inside of the config array.
|
||||
*/
|
||||
rules: new Proxy(
|
||||
{},
|
||||
{
|
||||
get(target, property) {
|
||||
return Rules.get(property);
|
||||
},
|
||||
|
||||
has(target, property) {
|
||||
return Rules.has(property);
|
||||
},
|
||||
},
|
||||
),
|
||||
},
|
||||
},
|
||||
language: "@/js",
|
||||
linterOptions: {
|
||||
reportUnusedDisableDirectives: 1,
|
||||
},
|
||||
},
|
||||
|
||||
// default ignores are listed here
|
||||
{
|
||||
ignores: ["**/node_modules/", ".git/"],
|
||||
},
|
||||
|
||||
...sharedDefaultConfig,
|
||||
]);
|
||||
|
||||
exports.defaultRuleTesterConfig = Object.freeze([
|
||||
{ files: ["**"] }, // Make sure the default config matches for all files
|
||||
|
||||
...sharedDefaultConfig,
|
||||
]);
|
||||
217
slider/node_modules/eslint/lib/config/flat-config-array.js
generated
vendored
Normal file
217
slider/node_modules/eslint/lib/config/flat-config-array.js
generated
vendored
Normal file
@@ -0,0 +1,217 @@
|
||||
/**
|
||||
* @fileoverview Flat Config Array
|
||||
* @author Nicholas C. Zakas
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
const { ConfigArray, ConfigArraySymbol } = require("@eslint/config-array");
|
||||
const { flatConfigSchema } = require("./flat-config-schema");
|
||||
const { defaultConfig } = require("./default-config");
|
||||
const { Config } = require("./config");
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Fields that are considered metadata and not part of the config object.
|
||||
*/
|
||||
const META_FIELDS = new Set(["name", "basePath"]);
|
||||
|
||||
/**
|
||||
* Wraps a config error with details about where the error occurred.
|
||||
* @param {Error} error The original error.
|
||||
* @param {number} originalLength The original length of the config array.
|
||||
* @param {number} baseLength The length of the base config.
|
||||
* @returns {TypeError} The new error with details.
|
||||
*/
|
||||
function wrapConfigErrorWithDetails(error, originalLength, baseLength) {
|
||||
let location = "user-defined";
|
||||
let configIndex = error.index;
|
||||
|
||||
/*
|
||||
* A config array is set up in this order:
|
||||
* 1. Base config
|
||||
* 2. Original configs
|
||||
* 3. User-defined configs
|
||||
* 4. CLI-defined configs
|
||||
*
|
||||
* So we need to adjust the index to account for the base config.
|
||||
*
|
||||
* - If the index is less than the base length, it's in the base config
|
||||
* (as specified by `baseConfig` argument to `FlatConfigArray` constructor).
|
||||
* - If the index is greater than the base length but less than the original
|
||||
* length + base length, it's in the original config. The original config
|
||||
* is passed to the `FlatConfigArray` constructor as the first argument.
|
||||
* - Otherwise, it's in the user-defined config, which is loaded from the
|
||||
* config file and merged with any command-line options.
|
||||
*/
|
||||
if (error.index < baseLength) {
|
||||
location = "base";
|
||||
} else if (error.index < originalLength + baseLength) {
|
||||
location = "original";
|
||||
configIndex = error.index - baseLength;
|
||||
} else {
|
||||
configIndex = error.index - originalLength - baseLength;
|
||||
}
|
||||
|
||||
return new TypeError(
|
||||
`${error.message.slice(0, -1)} at ${location} index ${configIndex}.`,
|
||||
{ cause: error },
|
||||
);
|
||||
}
|
||||
|
||||
const originalBaseConfig = Symbol("originalBaseConfig");
|
||||
const originalLength = Symbol("originalLength");
|
||||
const baseLength = Symbol("baseLength");
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Exports
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Represents an array containing configuration information for ESLint.
|
||||
*/
|
||||
class FlatConfigArray extends ConfigArray {
|
||||
/**
|
||||
* Creates a new instance.
|
||||
* @param {*[]} configs An array of configuration information.
|
||||
* @param {{basePath: string, shouldIgnore: boolean, baseConfig: FlatConfig}} options The options
|
||||
* to use for the config array instance.
|
||||
*/
|
||||
constructor(
|
||||
configs,
|
||||
{ basePath, shouldIgnore = true, baseConfig = defaultConfig } = {},
|
||||
) {
|
||||
super(configs, {
|
||||
basePath,
|
||||
schema: flatConfigSchema,
|
||||
});
|
||||
|
||||
/**
|
||||
* The original length of the array before any modifications.
|
||||
* @type {number}
|
||||
*/
|
||||
this[originalLength] = this.length;
|
||||
|
||||
if (baseConfig[Symbol.iterator]) {
|
||||
this.unshift(...baseConfig);
|
||||
} else {
|
||||
this.unshift(baseConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* The length of the array after applying the base config.
|
||||
* @type {number}
|
||||
*/
|
||||
this[baseLength] = this.length - this[originalLength];
|
||||
|
||||
/**
|
||||
* The base config used to build the config array.
|
||||
* @type {Array<FlatConfig>}
|
||||
*/
|
||||
this[originalBaseConfig] = baseConfig;
|
||||
Object.defineProperty(this, originalBaseConfig, { writable: false });
|
||||
|
||||
/**
|
||||
* Determines if `ignores` fields should be honored.
|
||||
* If true, then all `ignores` fields are honored.
|
||||
* if false, then only `ignores` fields in the baseConfig are honored.
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.shouldIgnore = shouldIgnore;
|
||||
Object.defineProperty(this, "shouldIgnore", { writable: false });
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes the array by calling the superclass method and catching/rethrowing
|
||||
* any ConfigError exceptions with additional details.
|
||||
* @param {any} [context] The context to use to normalize the array.
|
||||
* @returns {Promise<FlatConfigArray>} A promise that resolves when the array is normalized.
|
||||
*/
|
||||
normalize(context) {
|
||||
return super.normalize(context).catch(error => {
|
||||
if (error.name === "ConfigError") {
|
||||
throw wrapConfigErrorWithDetails(
|
||||
error,
|
||||
this[originalLength],
|
||||
this[baseLength],
|
||||
);
|
||||
}
|
||||
|
||||
throw error;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes the array by calling the superclass method and catching/rethrowing
|
||||
* any ConfigError exceptions with additional details.
|
||||
* @param {any} [context] The context to use to normalize the array.
|
||||
* @returns {FlatConfigArray} The current instance.
|
||||
* @throws {TypeError} If the config is invalid.
|
||||
*/
|
||||
normalizeSync(context) {
|
||||
try {
|
||||
return super.normalizeSync(context);
|
||||
} catch (error) {
|
||||
if (error.name === "ConfigError") {
|
||||
throw wrapConfigErrorWithDetails(
|
||||
error,
|
||||
this[originalLength],
|
||||
this[baseLength],
|
||||
);
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/* eslint-disable class-methods-use-this -- Desired as instance method */
|
||||
/**
|
||||
* Replaces a config with another config to allow us to put strings
|
||||
* in the config array that will be replaced by objects before
|
||||
* normalization.
|
||||
* @param {Object} config The config to preprocess.
|
||||
* @returns {Object} The preprocessed config.
|
||||
*/
|
||||
[ConfigArraySymbol.preprocessConfig](config) {
|
||||
/*
|
||||
* If a config object has `ignores` and no other non-meta fields, then it's an object
|
||||
* for global ignores. If `shouldIgnore` is false, that object shouldn't apply,
|
||||
* so we'll remove its `ignores`.
|
||||
*/
|
||||
if (
|
||||
!this.shouldIgnore &&
|
||||
!this[originalBaseConfig].includes(config) &&
|
||||
config.ignores &&
|
||||
Object.keys(config).filter(key => !META_FIELDS.has(key)).length ===
|
||||
1
|
||||
) {
|
||||
/* eslint-disable-next-line no-unused-vars -- need to strip off other keys */
|
||||
const { ignores, ...otherKeys } = config;
|
||||
|
||||
return otherKeys;
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finalizes the config by replacing plugin references with their objects
|
||||
* and validating rule option schemas.
|
||||
* @param {Object} config The config to finalize.
|
||||
* @returns {Object} The finalized config.
|
||||
* @throws {TypeError} If the config is invalid.
|
||||
*/
|
||||
[ConfigArraySymbol.finalizeConfig](config) {
|
||||
return new Config(config);
|
||||
}
|
||||
/* eslint-enable class-methods-use-this -- Desired as instance method */
|
||||
}
|
||||
|
||||
exports.FlatConfigArray = FlatConfigArray;
|
||||
598
slider/node_modules/eslint/lib/config/flat-config-schema.js
generated
vendored
Normal file
598
slider/node_modules/eslint/lib/config/flat-config-schema.js
generated
vendored
Normal file
@@ -0,0 +1,598 @@
|
||||
/**
|
||||
* @fileoverview Flat config schema
|
||||
* @author Nicholas C. Zakas
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
const { normalizeSeverityToNumber } = require("../shared/severity");
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Type Definitions
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @typedef ObjectPropertySchema
|
||||
* @property {Function|string} merge The function or name of the function to call
|
||||
* to merge multiple objects with this property.
|
||||
* @property {Function|string} validate The function or name of the function to call
|
||||
* to validate the value of this property.
|
||||
*/
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
const ruleSeverities = new Map([
|
||||
[0, 0],
|
||||
["off", 0],
|
||||
[1, 1],
|
||||
["warn", 1],
|
||||
[2, 2],
|
||||
["error", 2],
|
||||
]);
|
||||
|
||||
/**
|
||||
* 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";
|
||||
}
|
||||
|
||||
/**
|
||||
* Deeply merges two non-array objects.
|
||||
* @param {Object} first The base object.
|
||||
* @param {Object} second The overrides object.
|
||||
* @param {Map<string, Map<string, Object>>} [mergeMap] Maps the combination of first and second arguments to a merged result.
|
||||
* @returns {Object} An object with properties from both first and second.
|
||||
*/
|
||||
function deepMerge(first, second, mergeMap = new Map()) {
|
||||
let secondMergeMap = mergeMap.get(first);
|
||||
|
||||
if (secondMergeMap) {
|
||||
const result = secondMergeMap.get(second);
|
||||
|
||||
if (result) {
|
||||
// If this combination of first and second arguments has been already visited, return the previously created result.
|
||||
return result;
|
||||
}
|
||||
} else {
|
||||
secondMergeMap = new Map();
|
||||
mergeMap.set(first, secondMergeMap);
|
||||
}
|
||||
|
||||
/*
|
||||
* First create a result object where properties from the second object
|
||||
* overwrite properties from the first. This sets up a baseline to use
|
||||
* later rather than needing to inspect and change every property
|
||||
* individually.
|
||||
*/
|
||||
const result = {
|
||||
...first,
|
||||
...second,
|
||||
};
|
||||
|
||||
delete result.__proto__; // eslint-disable-line no-proto -- don't merge own property "__proto__"
|
||||
|
||||
// Store the pending result for this combination of first and second arguments.
|
||||
secondMergeMap.set(second, result);
|
||||
|
||||
for (const key of Object.keys(second)) {
|
||||
// avoid hairy edge case
|
||||
if (
|
||||
key === "__proto__" ||
|
||||
!Object.prototype.propertyIsEnumerable.call(first, key)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const firstValue = first[key];
|
||||
const secondValue = second[key];
|
||||
|
||||
if (isNonArrayObject(firstValue) && isNonArrayObject(secondValue)) {
|
||||
result[key] = deepMerge(firstValue, secondValue, mergeMap);
|
||||
} else if (isUndefined(secondValue)) {
|
||||
result[key] = firstValue;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes the rule options config for a given rule by ensuring that
|
||||
* it is an array and that the first item is 0, 1, or 2.
|
||||
* @param {Array|string|number} ruleOptions The rule options config.
|
||||
* @returns {Array} An array of rule options.
|
||||
*/
|
||||
function normalizeRuleOptions(ruleOptions) {
|
||||
const finalOptions = Array.isArray(ruleOptions)
|
||||
? ruleOptions.slice(0)
|
||||
: [ruleOptions];
|
||||
|
||||
finalOptions[0] = ruleSeverities.get(finalOptions[0]);
|
||||
return structuredClone(finalOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if an object has any methods.
|
||||
* @param {Object} object The object to check.
|
||||
* @returns {boolean} `true` if the object has any methods.
|
||||
*/
|
||||
function hasMethod(object) {
|
||||
for (const key of Object.keys(object)) {
|
||||
if (typeof object[key] === "function") {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Assertions
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* The error type when a rule's options are configured with an invalid type.
|
||||
*/
|
||||
class InvalidRuleOptionsError extends Error {
|
||||
/**
|
||||
* @param {string} ruleId Rule name being configured.
|
||||
* @param {any} value The invalid value.
|
||||
*/
|
||||
constructor(ruleId, value) {
|
||||
super(
|
||||
`Key "${ruleId}": Expected severity of "off", 0, "warn", 1, "error", or 2.`,
|
||||
);
|
||||
this.messageTemplate = "invalid-rule-options";
|
||||
this.messageData = { ruleId, value };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates that a value is a valid rule options entry.
|
||||
* @param {string} ruleId Rule name being configured.
|
||||
* @param {any} value The value to check.
|
||||
* @returns {void}
|
||||
* @throws {InvalidRuleOptionsError} If the value isn't a valid rule options.
|
||||
*/
|
||||
function assertIsRuleOptions(ruleId, value) {
|
||||
if (
|
||||
typeof value !== "string" &&
|
||||
typeof value !== "number" &&
|
||||
!Array.isArray(value)
|
||||
) {
|
||||
throw new InvalidRuleOptionsError(ruleId, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The error type when a rule's severity is invalid.
|
||||
*/
|
||||
class InvalidRuleSeverityError extends Error {
|
||||
/**
|
||||
* @param {string} ruleId Rule name being configured.
|
||||
* @param {any} value The invalid value.
|
||||
*/
|
||||
constructor(ruleId, value) {
|
||||
super(
|
||||
`Key "${ruleId}": Expected severity of "off", 0, "warn", 1, "error", or 2.`,
|
||||
);
|
||||
this.messageTemplate = "invalid-rule-severity";
|
||||
this.messageData = { ruleId, value };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates that a value is valid rule severity.
|
||||
* @param {string} ruleId Rule name being configured.
|
||||
* @param {any} value The value to check.
|
||||
* @returns {void}
|
||||
* @throws {InvalidRuleSeverityError} If the value isn't a valid rule severity.
|
||||
*/
|
||||
function assertIsRuleSeverity(ruleId, value) {
|
||||
const severity = ruleSeverities.get(value);
|
||||
|
||||
if (typeof severity === "undefined") {
|
||||
throw new InvalidRuleSeverityError(ruleId, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates that a given string is the form pluginName/objectName.
|
||||
* @param {string} value The string to check.
|
||||
* @returns {void}
|
||||
* @throws {TypeError} If the string isn't in the correct format.
|
||||
*/
|
||||
function assertIsPluginMemberName(value) {
|
||||
if (!/[\w\-@$]+(?:\/[\w\-$]+)+$/iu.test(value)) {
|
||||
throw new TypeError(
|
||||
`Expected string in the form "pluginName/objectName" but found "${value}".`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates that a value is an object.
|
||||
* @param {any} value The value to check.
|
||||
* @returns {void}
|
||||
* @throws {TypeError} If the value isn't an object.
|
||||
*/
|
||||
function assertIsObject(value) {
|
||||
if (!isNonNullObject(value)) {
|
||||
throw new TypeError("Expected an object.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The error type when there's an eslintrc-style options in a flat config.
|
||||
*/
|
||||
class IncompatibleKeyError extends Error {
|
||||
/**
|
||||
* @param {string} key The invalid key.
|
||||
*/
|
||||
constructor(key) {
|
||||
super(
|
||||
"This appears to be in eslintrc format rather than flat config format.",
|
||||
);
|
||||
this.messageTemplate = "eslintrc-incompat";
|
||||
this.messageData = { key };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The error type when there's an eslintrc-style plugins array found.
|
||||
*/
|
||||
class IncompatiblePluginsError extends Error {
|
||||
/**
|
||||
* Creates a new instance.
|
||||
* @param {Array<string>} plugins The plugins array.
|
||||
*/
|
||||
constructor(plugins) {
|
||||
super(
|
||||
"This appears to be in eslintrc format (array of strings) rather than flat config format (object).",
|
||||
);
|
||||
this.messageTemplate = "eslintrc-plugins";
|
||||
this.messageData = { plugins };
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Low-Level Schemas
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/** @type {ObjectPropertySchema} */
|
||||
const booleanSchema = {
|
||||
merge: "replace",
|
||||
validate: "boolean",
|
||||
};
|
||||
|
||||
const ALLOWED_SEVERITIES = new Set(["error", "warn", "off", 2, 1, 0]);
|
||||
|
||||
/** @type {ObjectPropertySchema} */
|
||||
const disableDirectiveSeveritySchema = {
|
||||
merge(first, second) {
|
||||
const value = second === void 0 ? first : second;
|
||||
|
||||
if (typeof value === "boolean") {
|
||||
return value ? "warn" : "off";
|
||||
}
|
||||
|
||||
return normalizeSeverityToNumber(value);
|
||||
},
|
||||
validate(value) {
|
||||
if (!(ALLOWED_SEVERITIES.has(value) || typeof value === "boolean")) {
|
||||
throw new TypeError(
|
||||
'Expected one of: "error", "warn", "off", 0, 1, 2, or a boolean.',
|
||||
);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
/** @type {ObjectPropertySchema} */
|
||||
const unusedInlineConfigsSeveritySchema = {
|
||||
merge(first, second) {
|
||||
const value = second === void 0 ? first : second;
|
||||
|
||||
return normalizeSeverityToNumber(value);
|
||||
},
|
||||
validate(value) {
|
||||
if (!ALLOWED_SEVERITIES.has(value)) {
|
||||
throw new TypeError(
|
||||
'Expected one of: "error", "warn", "off", 0, 1, or 2.',
|
||||
);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
/** @type {ObjectPropertySchema} */
|
||||
const deepObjectAssignSchema = {
|
||||
merge(first = {}, second = {}) {
|
||||
return deepMerge(first, second);
|
||||
},
|
||||
validate: "object",
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// High-Level Schemas
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/** @type {ObjectPropertySchema} */
|
||||
const languageOptionsSchema = {
|
||||
merge(first = {}, second = {}) {
|
||||
const result = deepMerge(first, second);
|
||||
|
||||
for (const [key, value] of Object.entries(result)) {
|
||||
/*
|
||||
* Special case: Because the `parser` property is an object, it should
|
||||
* not be deep merged. Instead, it should be replaced if it exists in
|
||||
* the second object. To make this more generic, we just check for
|
||||
* objects with methods and replace them if they exist in the second
|
||||
* object.
|
||||
*/
|
||||
if (isNonArrayObject(value)) {
|
||||
if (hasMethod(value)) {
|
||||
result[key] = second[key] ?? first[key];
|
||||
continue;
|
||||
}
|
||||
|
||||
// for other objects, make sure we aren't reusing the same object
|
||||
result[key] = { ...result[key] };
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
validate: "object",
|
||||
};
|
||||
|
||||
/** @type {ObjectPropertySchema} */
|
||||
const languageSchema = {
|
||||
merge: "replace",
|
||||
validate: assertIsPluginMemberName,
|
||||
};
|
||||
|
||||
/** @type {ObjectPropertySchema} */
|
||||
const pluginsSchema = {
|
||||
merge(first = {}, second = {}) {
|
||||
const keys = new Set([...Object.keys(first), ...Object.keys(second)]);
|
||||
const result = {};
|
||||
|
||||
// manually validate that plugins are not redefined
|
||||
for (const key of keys) {
|
||||
// avoid hairy edge case
|
||||
if (key === "__proto__") {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (key in first && key in second && first[key] !== second[key]) {
|
||||
throw new TypeError(`Cannot redefine plugin "${key}".`);
|
||||
}
|
||||
|
||||
result[key] = second[key] || first[key];
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
validate(value) {
|
||||
// first check the value to be sure it's an object
|
||||
if (value === null || typeof value !== "object") {
|
||||
throw new TypeError("Expected an object.");
|
||||
}
|
||||
|
||||
// make sure it's not an array, which would mean eslintrc-style is used
|
||||
if (Array.isArray(value)) {
|
||||
throw new IncompatiblePluginsError(value);
|
||||
}
|
||||
|
||||
// second check the keys to make sure they are objects
|
||||
for (const key of Object.keys(value)) {
|
||||
// avoid hairy edge case
|
||||
if (key === "__proto__") {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (value[key] === null || typeof value[key] !== "object") {
|
||||
throw new TypeError(`Key "${key}": Expected an object.`);
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
/** @type {ObjectPropertySchema} */
|
||||
const processorSchema = {
|
||||
merge: "replace",
|
||||
validate(value) {
|
||||
if (typeof value === "string") {
|
||||
assertIsPluginMemberName(value);
|
||||
} else if (value && typeof value === "object") {
|
||||
if (
|
||||
typeof value.preprocess !== "function" ||
|
||||
typeof value.postprocess !== "function"
|
||||
) {
|
||||
throw new TypeError(
|
||||
"Object must have a preprocess() and a postprocess() method.",
|
||||
);
|
||||
}
|
||||
} else {
|
||||
throw new TypeError("Expected an object or a string.");
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
/** @type {ObjectPropertySchema} */
|
||||
const rulesSchema = {
|
||||
merge(first = {}, second = {}) {
|
||||
const result = {
|
||||
...first,
|
||||
...second,
|
||||
};
|
||||
|
||||
for (const ruleId of Object.keys(result)) {
|
||||
try {
|
||||
// avoid hairy edge case
|
||||
if (ruleId === "__proto__") {
|
||||
/* eslint-disable-next-line no-proto -- Though deprecated, may still be present */
|
||||
delete result.__proto__;
|
||||
continue;
|
||||
}
|
||||
|
||||
result[ruleId] = normalizeRuleOptions(result[ruleId]);
|
||||
|
||||
/*
|
||||
* If either rule config is missing, then the correct
|
||||
* config is already present and we just need to normalize
|
||||
* the severity.
|
||||
*/
|
||||
if (!(ruleId in first) || !(ruleId in second)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const firstRuleOptions = normalizeRuleOptions(first[ruleId]);
|
||||
const secondRuleOptions = normalizeRuleOptions(second[ruleId]);
|
||||
|
||||
/*
|
||||
* If the second rule config only has a severity (length of 1),
|
||||
* then use that severity and keep the rest of the options from
|
||||
* the first rule config.
|
||||
*/
|
||||
if (secondRuleOptions.length === 1) {
|
||||
result[ruleId] = [
|
||||
secondRuleOptions[0],
|
||||
...firstRuleOptions.slice(1),
|
||||
];
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* In any other situation, then the second rule config takes
|
||||
* precedence. That means the value at `result[ruleId]` is
|
||||
* already correct and no further work is necessary.
|
||||
*/
|
||||
} catch (ex) {
|
||||
throw new Error(`Key "${ruleId}": ${ex.message}`, {
|
||||
cause: ex,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
validate(value) {
|
||||
assertIsObject(value);
|
||||
|
||||
/*
|
||||
* We are not checking the rule schema here because there is no
|
||||
* guarantee that the rule definition is present at this point. Instead
|
||||
* we wait and check the rule schema during the finalization step
|
||||
* of calculating a config.
|
||||
*/
|
||||
for (const ruleId of Object.keys(value)) {
|
||||
// avoid hairy edge case
|
||||
if (ruleId === "__proto__") {
|
||||
continue;
|
||||
}
|
||||
|
||||
const ruleOptions = value[ruleId];
|
||||
|
||||
assertIsRuleOptions(ruleId, ruleOptions);
|
||||
|
||||
if (Array.isArray(ruleOptions)) {
|
||||
assertIsRuleSeverity(ruleId, ruleOptions[0]);
|
||||
} else {
|
||||
assertIsRuleSeverity(ruleId, ruleOptions);
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a schema that always throws an error. Useful for warning
|
||||
* about eslintrc-style keys.
|
||||
* @param {string} key The eslintrc key to create a schema for.
|
||||
* @returns {ObjectPropertySchema} The schema.
|
||||
*/
|
||||
function createEslintrcErrorSchema(key) {
|
||||
return {
|
||||
merge: "replace",
|
||||
validate() {
|
||||
throw new IncompatibleKeyError(key);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const eslintrcKeys = [
|
||||
"env",
|
||||
"extends",
|
||||
"globals",
|
||||
"ignorePatterns",
|
||||
"noInlineConfig",
|
||||
"overrides",
|
||||
"parser",
|
||||
"parserOptions",
|
||||
"reportUnusedDisableDirectives",
|
||||
"root",
|
||||
];
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Full schema
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
const flatConfigSchema = {
|
||||
// eslintrc-style keys that should always error
|
||||
...Object.fromEntries(
|
||||
eslintrcKeys.map(key => [key, createEslintrcErrorSchema(key)]),
|
||||
),
|
||||
|
||||
// flat config keys
|
||||
settings: deepObjectAssignSchema,
|
||||
linterOptions: {
|
||||
schema: {
|
||||
noInlineConfig: booleanSchema,
|
||||
reportUnusedDisableDirectives: disableDirectiveSeveritySchema,
|
||||
reportUnusedInlineConfigs: unusedInlineConfigsSeveritySchema,
|
||||
},
|
||||
},
|
||||
language: languageSchema,
|
||||
languageOptions: languageOptionsSchema,
|
||||
processor: processorSchema,
|
||||
plugins: pluginsSchema,
|
||||
rules: rulesSchema,
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Exports
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
flatConfigSchema,
|
||||
hasMethod,
|
||||
assertIsRuleSeverity,
|
||||
};
|
||||
1462
slider/node_modules/eslint/lib/eslint/eslint-helpers.js
generated
vendored
Normal file
1462
slider/node_modules/eslint/lib/eslint/eslint-helpers.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1232
slider/node_modules/eslint/lib/eslint/eslint.js
generated
vendored
Normal file
1232
slider/node_modules/eslint/lib/eslint/eslint.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
9
slider/node_modules/eslint/lib/eslint/index.js
generated
vendored
Normal file
9
slider/node_modules/eslint/lib/eslint/index.js
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
"use strict";
|
||||
|
||||
const { ESLint } = require("./eslint");
|
||||
const { LegacyESLint } = require("./legacy-eslint");
|
||||
|
||||
module.exports = {
|
||||
ESLint,
|
||||
LegacyESLint,
|
||||
};
|
||||
786
slider/node_modules/eslint/lib/eslint/legacy-eslint.js
generated
vendored
Normal file
786
slider/node_modules/eslint/lib/eslint/legacy-eslint.js
generated
vendored
Normal file
@@ -0,0 +1,786 @@
|
||||
/**
|
||||
* @fileoverview Main API Class
|
||||
* @author Kai Cataldo
|
||||
* @author Toru Nagashima
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const path = require("node:path");
|
||||
const fs = require("node:fs");
|
||||
const { promisify } = require("node:util");
|
||||
const {
|
||||
CLIEngine,
|
||||
getCLIEngineInternalSlots,
|
||||
} = require("../cli-engine/cli-engine");
|
||||
const BuiltinRules = require("../rules");
|
||||
const {
|
||||
Legacy: {
|
||||
ConfigOps: { getRuleSeverity },
|
||||
},
|
||||
} = require("@eslint/eslintrc");
|
||||
const { version } = require("../../package.json");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Typedefs
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @typedef {import("../cli-engine/cli-engine").LintReport} CLIEngineLintReport */
|
||||
/** @typedef {import("../types").ESLint.ConfigData} ConfigData */
|
||||
/** @typedef {import("../types").ESLint.DeprecatedRuleUse} DeprecatedRuleInfo */
|
||||
/** @typedef {import("../types").Linter.LintMessage} LintMessage */
|
||||
/** @typedef {import("../types").ESLint.LintResult} LintResult */
|
||||
/** @typedef {import("../types").ESLint.Plugin} Plugin */
|
||||
/** @typedef {import("../types").ESLint.ResultsMeta} ResultsMeta */
|
||||
/** @typedef {import("../types").Rule.RuleModule} Rule */
|
||||
/** @typedef {import("../types").Linter.SuppressedLintMessage} SuppressedLintMessage */
|
||||
|
||||
/**
|
||||
* The main formatter object.
|
||||
* @typedef LoadedFormatter
|
||||
* @property {(results: LintResult[], resultsMeta: ResultsMeta) => string | Promise<string>} format format function.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The options with which to configure the LegacyESLint instance.
|
||||
* @typedef {Object} LegacyESLintOptions
|
||||
* @property {boolean} [allowInlineConfig] Enable or disable inline configuration comments.
|
||||
* @property {ConfigData} [baseConfig] Base config object, extended by all configs used with this instance
|
||||
* @property {boolean} [cache] Enable result caching.
|
||||
* @property {string} [cacheLocation] The cache file to use instead of .eslintcache.
|
||||
* @property {"metadata" | "content"} [cacheStrategy] The strategy used to detect changed files.
|
||||
* @property {string} [cwd] The value to use for the current working directory.
|
||||
* @property {boolean} [errorOnUnmatchedPattern] If `false` then `ESLint#lintFiles()` doesn't throw even if no target files found. Defaults to `true`.
|
||||
* @property {string[]} [extensions] An array of file extensions to check.
|
||||
* @property {boolean|Function} [fix] Execute in autofix mode. If a function, should return a boolean.
|
||||
* @property {string[]} [fixTypes] Array of rule types to apply fixes for.
|
||||
* @property {boolean} [globInputPaths] Set to false to skip glob resolution of input file paths to lint (default: true). If false, each input file paths is assumed to be a non-glob path to an existing file.
|
||||
* @property {boolean} [ignore] False disables use of .eslintignore.
|
||||
* @property {string} [ignorePath] The ignore file to use instead of .eslintignore.
|
||||
* @property {ConfigData} [overrideConfig] Override config object, overrides all configs used with this instance
|
||||
* @property {string} [overrideConfigFile] The configuration file to use.
|
||||
* @property {Record<string,Plugin>|null} [plugins] Preloaded plugins. This is a map-like object, keys are plugin IDs and each value is implementation.
|
||||
* @property {"error" | "warn" | "off"} [reportUnusedDisableDirectives] the severity to report unused eslint-disable directives.
|
||||
* @property {string} [resolvePluginsRelativeTo] The folder where plugins should be resolved from, defaulting to the CWD.
|
||||
* @property {string[]} [rulePaths] An array of directories to load custom rules from.
|
||||
* @property {boolean} [useEslintrc] False disables looking for .eslintrc.* files.
|
||||
* @property {boolean} [passOnNoPatterns=false] When set to true, missing patterns cause
|
||||
* the linting operation to short circuit and not report any failures.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A rules metadata object.
|
||||
* @typedef {Object} RulesMeta
|
||||
* @property {string} id The plugin ID.
|
||||
* @property {Object} definition The plugin definition.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Private members for the `ESLint` instance.
|
||||
* @typedef {Object} ESLintPrivateMembers
|
||||
* @property {CLIEngine} cliEngine The wrapped CLIEngine instance.
|
||||
* @property {LegacyESLintOptions} options The options used to instantiate the ESLint instance.
|
||||
*/
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const writeFile = promisify(fs.writeFile);
|
||||
|
||||
/**
|
||||
* The map with which to store private class members.
|
||||
* @type {WeakMap<ESLint, ESLintPrivateMembers>}
|
||||
*/
|
||||
const privateMembersMap = new WeakMap();
|
||||
|
||||
/**
|
||||
* Check if a given value is a non-empty string or not.
|
||||
* @param {any} value The value to check.
|
||||
* @returns {boolean} `true` if `value` is a non-empty string.
|
||||
*/
|
||||
function isNonEmptyString(value) {
|
||||
return typeof value === "string" && value.trim() !== "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given value is an array of non-empty strings or not.
|
||||
* @param {any} value The value to check.
|
||||
* @returns {boolean} `true` if `value` is an array of non-empty strings.
|
||||
*/
|
||||
function isArrayOfNonEmptyString(value) {
|
||||
return (
|
||||
Array.isArray(value) && value.length && value.every(isNonEmptyString)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given value is an empty array or an array of non-empty strings.
|
||||
* @param {any} value The value to check.
|
||||
* @returns {boolean} `true` if `value` is an empty array or an array of non-empty
|
||||
* strings.
|
||||
*/
|
||||
function isEmptyArrayOrArrayOfNonEmptyString(value) {
|
||||
return Array.isArray(value) && value.every(isNonEmptyString);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given value is a valid fix type or not.
|
||||
* @param {any} value The value to check.
|
||||
* @returns {boolean} `true` if `value` is valid fix type.
|
||||
*/
|
||||
function isFixType(value) {
|
||||
return (
|
||||
value === "directive" ||
|
||||
value === "problem" ||
|
||||
value === "suggestion" ||
|
||||
value === "layout"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given value is an array of fix types or not.
|
||||
* @param {any} value The value to check.
|
||||
* @returns {boolean} `true` if `value` is an array of fix types.
|
||||
*/
|
||||
function isFixTypeArray(value) {
|
||||
return Array.isArray(value) && value.every(isFixType);
|
||||
}
|
||||
|
||||
/**
|
||||
* The error for invalid options.
|
||||
*/
|
||||
class ESLintInvalidOptionsError extends Error {
|
||||
constructor(messages) {
|
||||
super(`Invalid Options:\n- ${messages.join("\n- ")}`);
|
||||
this.code = "ESLINT_INVALID_OPTIONS";
|
||||
Error.captureStackTrace(this, ESLintInvalidOptionsError);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates and normalizes options for the wrapped CLIEngine instance.
|
||||
* @param {LegacyESLintOptions} options The options to process.
|
||||
* @throws {ESLintInvalidOptionsError} If of any of a variety of type errors.
|
||||
* @returns {LegacyESLintOptions} The normalized options.
|
||||
*/
|
||||
function processOptions({
|
||||
allowInlineConfig = true, // ← we cannot use `overrideConfig.noInlineConfig` instead because `allowInlineConfig` has side-effect that suppress warnings that show inline configs are ignored.
|
||||
baseConfig = null,
|
||||
cache = false,
|
||||
cacheLocation = ".eslintcache",
|
||||
cacheStrategy = "metadata",
|
||||
cwd = process.cwd(),
|
||||
errorOnUnmatchedPattern = true,
|
||||
extensions = null, // ← should be null by default because if it's an array then it suppresses RFC20 feature.
|
||||
fix = false,
|
||||
fixTypes = null, // ← should be null by default because if it's an array then it suppresses rules that don't have the `meta.type` property.
|
||||
flags /* eslint-disable-line no-unused-vars -- leaving for compatibility with ESLint#hasFlag */,
|
||||
globInputPaths = true,
|
||||
ignore = true,
|
||||
ignorePath = null, // ← should be null by default because if it's a string then it may throw ENOENT.
|
||||
overrideConfig = null,
|
||||
overrideConfigFile = null,
|
||||
plugins = {},
|
||||
reportUnusedDisableDirectives = null, // ← should be null by default because if it's a string then it overrides the 'reportUnusedDisableDirectives' setting in config files. And we cannot use `overrideConfig.reportUnusedDisableDirectives` instead because we cannot configure the `error` severity with that.
|
||||
resolvePluginsRelativeTo = null, // ← should be null by default because if it's a string then it suppresses RFC47 feature.
|
||||
rulePaths = [],
|
||||
useEslintrc = true,
|
||||
passOnNoPatterns = false,
|
||||
...unknownOptions
|
||||
}) {
|
||||
const errors = [];
|
||||
const unknownOptionKeys = Object.keys(unknownOptions);
|
||||
|
||||
if (unknownOptionKeys.length >= 1) {
|
||||
errors.push(`Unknown options: ${unknownOptionKeys.join(", ")}`);
|
||||
if (unknownOptionKeys.includes("cacheFile")) {
|
||||
errors.push(
|
||||
"'cacheFile' has been removed. Please use the 'cacheLocation' option instead.",
|
||||
);
|
||||
}
|
||||
if (unknownOptionKeys.includes("configFile")) {
|
||||
errors.push(
|
||||
"'configFile' has been removed. Please use the 'overrideConfigFile' option instead.",
|
||||
);
|
||||
}
|
||||
if (unknownOptionKeys.includes("envs")) {
|
||||
errors.push(
|
||||
"'envs' has been removed. Please use the 'overrideConfig.env' option instead.",
|
||||
);
|
||||
}
|
||||
if (unknownOptionKeys.includes("globals")) {
|
||||
errors.push(
|
||||
"'globals' has been removed. Please use the 'overrideConfig.globals' option instead.",
|
||||
);
|
||||
}
|
||||
if (unknownOptionKeys.includes("ignorePattern")) {
|
||||
errors.push(
|
||||
"'ignorePattern' has been removed. Please use the 'overrideConfig.ignorePatterns' option instead.",
|
||||
);
|
||||
}
|
||||
if (unknownOptionKeys.includes("parser")) {
|
||||
errors.push(
|
||||
"'parser' has been removed. Please use the 'overrideConfig.parser' option instead.",
|
||||
);
|
||||
}
|
||||
if (unknownOptionKeys.includes("parserOptions")) {
|
||||
errors.push(
|
||||
"'parserOptions' has been removed. Please use the 'overrideConfig.parserOptions' option instead.",
|
||||
);
|
||||
}
|
||||
if (unknownOptionKeys.includes("rules")) {
|
||||
errors.push(
|
||||
"'rules' has been removed. Please use the 'overrideConfig.rules' option instead.",
|
||||
);
|
||||
}
|
||||
}
|
||||
if (typeof allowInlineConfig !== "boolean") {
|
||||
errors.push("'allowInlineConfig' must be a boolean.");
|
||||
}
|
||||
if (typeof baseConfig !== "object") {
|
||||
errors.push("'baseConfig' must be an object or null.");
|
||||
}
|
||||
if (typeof cache !== "boolean") {
|
||||
errors.push("'cache' must be a boolean.");
|
||||
}
|
||||
if (!isNonEmptyString(cacheLocation)) {
|
||||
errors.push("'cacheLocation' must be a non-empty string.");
|
||||
}
|
||||
if (cacheStrategy !== "metadata" && cacheStrategy !== "content") {
|
||||
errors.push('\'cacheStrategy\' must be any of "metadata", "content".');
|
||||
}
|
||||
if (!isNonEmptyString(cwd) || !path.isAbsolute(cwd)) {
|
||||
errors.push("'cwd' must be an absolute path.");
|
||||
}
|
||||
if (typeof errorOnUnmatchedPattern !== "boolean") {
|
||||
errors.push("'errorOnUnmatchedPattern' must be a boolean.");
|
||||
}
|
||||
if (
|
||||
!isEmptyArrayOrArrayOfNonEmptyString(extensions) &&
|
||||
extensions !== null
|
||||
) {
|
||||
errors.push(
|
||||
"'extensions' must be an array of non-empty strings or null.",
|
||||
);
|
||||
}
|
||||
if (typeof fix !== "boolean" && typeof fix !== "function") {
|
||||
errors.push("'fix' must be a boolean or a function.");
|
||||
}
|
||||
if (fixTypes !== null && !isFixTypeArray(fixTypes)) {
|
||||
errors.push(
|
||||
'\'fixTypes\' must be an array of any of "directive", "problem", "suggestion", and "layout".',
|
||||
);
|
||||
}
|
||||
if (typeof globInputPaths !== "boolean") {
|
||||
errors.push("'globInputPaths' must be a boolean.");
|
||||
}
|
||||
if (typeof ignore !== "boolean") {
|
||||
errors.push("'ignore' must be a boolean.");
|
||||
}
|
||||
if (!isNonEmptyString(ignorePath) && ignorePath !== null) {
|
||||
errors.push("'ignorePath' must be a non-empty string or null.");
|
||||
}
|
||||
if (typeof overrideConfig !== "object") {
|
||||
errors.push("'overrideConfig' must be an object or null.");
|
||||
}
|
||||
if (!isNonEmptyString(overrideConfigFile) && overrideConfigFile !== null) {
|
||||
errors.push("'overrideConfigFile' must be a non-empty string or null.");
|
||||
}
|
||||
if (typeof plugins !== "object") {
|
||||
errors.push("'plugins' must be an object or null.");
|
||||
} else if (plugins !== null && Object.keys(plugins).includes("")) {
|
||||
errors.push("'plugins' must not include an empty string.");
|
||||
}
|
||||
if (Array.isArray(plugins)) {
|
||||
errors.push(
|
||||
"'plugins' doesn't add plugins to configuration to load. Please use the 'overrideConfig.plugins' option instead.",
|
||||
);
|
||||
}
|
||||
if (
|
||||
reportUnusedDisableDirectives !== "error" &&
|
||||
reportUnusedDisableDirectives !== "warn" &&
|
||||
reportUnusedDisableDirectives !== "off" &&
|
||||
reportUnusedDisableDirectives !== null
|
||||
) {
|
||||
errors.push(
|
||||
'\'reportUnusedDisableDirectives\' must be any of "error", "warn", "off", and null.',
|
||||
);
|
||||
}
|
||||
if (
|
||||
!isNonEmptyString(resolvePluginsRelativeTo) &&
|
||||
resolvePluginsRelativeTo !== null
|
||||
) {
|
||||
errors.push(
|
||||
"'resolvePluginsRelativeTo' must be a non-empty string or null.",
|
||||
);
|
||||
}
|
||||
if (!isEmptyArrayOrArrayOfNonEmptyString(rulePaths)) {
|
||||
errors.push("'rulePaths' must be an array of non-empty strings.");
|
||||
}
|
||||
if (typeof useEslintrc !== "boolean") {
|
||||
errors.push("'useEslintrc' must be a boolean.");
|
||||
}
|
||||
if (typeof passOnNoPatterns !== "boolean") {
|
||||
errors.push("'passOnNoPatterns' must be a boolean.");
|
||||
}
|
||||
|
||||
if (errors.length > 0) {
|
||||
throw new ESLintInvalidOptionsError(errors);
|
||||
}
|
||||
|
||||
return {
|
||||
allowInlineConfig,
|
||||
baseConfig,
|
||||
cache,
|
||||
cacheLocation,
|
||||
cacheStrategy,
|
||||
configFile: overrideConfigFile,
|
||||
cwd: path.normalize(cwd),
|
||||
errorOnUnmatchedPattern,
|
||||
extensions,
|
||||
fix,
|
||||
fixTypes,
|
||||
flags: [], // LegacyESLint does not support flags, so just ignore them.
|
||||
globInputPaths,
|
||||
ignore,
|
||||
ignorePath,
|
||||
reportUnusedDisableDirectives,
|
||||
resolvePluginsRelativeTo,
|
||||
rulePaths,
|
||||
useEslintrc,
|
||||
passOnNoPatterns,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a value has one or more properties and that value is not undefined.
|
||||
* @param {any} obj The value to check.
|
||||
* @returns {boolean} `true` if `obj` has one or more properties that value is not undefined.
|
||||
*/
|
||||
function hasDefinedProperty(obj) {
|
||||
if (typeof obj === "object" && obj !== null) {
|
||||
for (const key in obj) {
|
||||
if (typeof obj[key] !== "undefined") {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create rulesMeta object.
|
||||
* @param {Map<string,Rule>} rules a map of rules from which to generate the object.
|
||||
* @returns {Object} metadata for all enabled rules.
|
||||
*/
|
||||
function createRulesMeta(rules) {
|
||||
return Array.from(rules).reduce((retVal, [id, rule]) => {
|
||||
retVal[id] = rule.meta;
|
||||
return retVal;
|
||||
}, {});
|
||||
}
|
||||
|
||||
/** @type {WeakMap<ExtractedConfig, DeprecatedRuleInfo[]>} */
|
||||
const usedDeprecatedRulesCache = new WeakMap();
|
||||
|
||||
/**
|
||||
* Create used deprecated rule list.
|
||||
* @param {CLIEngine} cliEngine The CLIEngine instance.
|
||||
* @param {string} maybeFilePath The absolute path to a lint target file or `"<text>"`.
|
||||
* @returns {DeprecatedRuleInfo[]} The used deprecated rule list.
|
||||
*/
|
||||
function getOrFindUsedDeprecatedRules(cliEngine, maybeFilePath) {
|
||||
const {
|
||||
configArrayFactory,
|
||||
options: { cwd },
|
||||
} = getCLIEngineInternalSlots(cliEngine);
|
||||
const filePath = path.isAbsolute(maybeFilePath)
|
||||
? maybeFilePath
|
||||
: path.join(cwd, "__placeholder__.js");
|
||||
const configArray = configArrayFactory.getConfigArrayForFile(filePath);
|
||||
const config = configArray.extractConfig(filePath);
|
||||
|
||||
// Most files use the same config, so cache it.
|
||||
if (!usedDeprecatedRulesCache.has(config)) {
|
||||
const pluginRules = configArray.pluginRules;
|
||||
const retv = [];
|
||||
|
||||
for (const [ruleId, ruleConf] of Object.entries(config.rules)) {
|
||||
if (getRuleSeverity(ruleConf) === 0) {
|
||||
continue;
|
||||
}
|
||||
const rule = pluginRules.get(ruleId) || BuiltinRules.get(ruleId);
|
||||
const meta = rule && rule.meta;
|
||||
|
||||
if (meta && meta.deprecated) {
|
||||
retv.push({ ruleId, replacedBy: meta.replacedBy || [] });
|
||||
}
|
||||
}
|
||||
|
||||
usedDeprecatedRulesCache.set(config, Object.freeze(retv));
|
||||
}
|
||||
|
||||
return usedDeprecatedRulesCache.get(config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the linting results generated by a CLIEngine linting report to
|
||||
* match the ESLint class's API.
|
||||
* @param {CLIEngine} cliEngine The CLIEngine instance.
|
||||
* @param {CLIEngineLintReport} report The CLIEngine linting report to process.
|
||||
* @returns {LintResult[]} The processed linting results.
|
||||
*/
|
||||
function processCLIEngineLintReport(cliEngine, { results }) {
|
||||
const descriptor = {
|
||||
configurable: true,
|
||||
enumerable: true,
|
||||
get() {
|
||||
return getOrFindUsedDeprecatedRules(cliEngine, this.filePath);
|
||||
},
|
||||
};
|
||||
|
||||
for (const result of results) {
|
||||
Object.defineProperty(result, "usedDeprecatedRules", descriptor);
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* An Array.prototype.sort() compatible compare function to order results by their file path.
|
||||
* @param {LintResult} a The first lint result.
|
||||
* @param {LintResult} b The second lint result.
|
||||
* @returns {number} An integer representing the order in which the two results should occur.
|
||||
*/
|
||||
function compareResultsByFilePath(a, b) {
|
||||
if (a.filePath < b.filePath) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (a.filePath > b.filePath) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Main API.
|
||||
*/
|
||||
class LegacyESLint {
|
||||
/**
|
||||
* The type of configuration used by this class.
|
||||
* @type {string}
|
||||
*/
|
||||
static configType = "eslintrc";
|
||||
|
||||
/**
|
||||
* Creates a new instance of the main ESLint API.
|
||||
* @param {LegacyESLintOptions} options The options for this instance.
|
||||
*/
|
||||
constructor(options = {}) {
|
||||
const processedOptions = processOptions(options);
|
||||
const cliEngine = new CLIEngine(processedOptions, {
|
||||
preloadedPlugins: options.plugins,
|
||||
});
|
||||
const { configArrayFactory, lastConfigArrays } =
|
||||
getCLIEngineInternalSlots(cliEngine);
|
||||
let updated = false;
|
||||
|
||||
/*
|
||||
* Address `overrideConfig` to set override config.
|
||||
* Operate the `configArrayFactory` internal slot directly because this
|
||||
* functionality doesn't exist as the public API of CLIEngine.
|
||||
*/
|
||||
if (hasDefinedProperty(options.overrideConfig)) {
|
||||
configArrayFactory.setOverrideConfig(options.overrideConfig);
|
||||
updated = true;
|
||||
}
|
||||
|
||||
// Update caches.
|
||||
if (updated) {
|
||||
configArrayFactory.clearCache();
|
||||
lastConfigArrays[0] = configArrayFactory.getConfigArrayForFile();
|
||||
}
|
||||
|
||||
// Initialize private properties.
|
||||
privateMembersMap.set(this, {
|
||||
cliEngine,
|
||||
options: processedOptions,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* The version text.
|
||||
* @type {string}
|
||||
*/
|
||||
static get version() {
|
||||
return version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs fixes from the given results to files.
|
||||
* @param {LintResult[]} results The lint results.
|
||||
* @returns {Promise<void>} Returns a promise that is used to track side effects.
|
||||
*/
|
||||
static async outputFixes(results) {
|
||||
if (!Array.isArray(results)) {
|
||||
throw new Error("'results' must be an array");
|
||||
}
|
||||
|
||||
await Promise.all(
|
||||
results
|
||||
.filter(result => {
|
||||
if (typeof result !== "object" || result === null) {
|
||||
throw new Error("'results' must include only objects");
|
||||
}
|
||||
return (
|
||||
typeof result.output === "string" &&
|
||||
path.isAbsolute(result.filePath)
|
||||
);
|
||||
})
|
||||
.map(r => writeFile(r.filePath, r.output)),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns results that only contains errors.
|
||||
* @param {LintResult[]} results The results to filter.
|
||||
* @returns {LintResult[]} The filtered results.
|
||||
*/
|
||||
static getErrorResults(results) {
|
||||
return CLIEngine.getErrorResults(results);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns meta objects for each rule represented in the lint results.
|
||||
* @param {LintResult[]} results The results to fetch rules meta for.
|
||||
* @returns {Object} A mapping of ruleIds to rule meta objects.
|
||||
*/
|
||||
getRulesMetaForResults(results) {
|
||||
const resultRuleIds = new Set();
|
||||
|
||||
// first gather all ruleIds from all results
|
||||
|
||||
for (const result of results) {
|
||||
for (const { ruleId } of result.messages) {
|
||||
resultRuleIds.add(ruleId);
|
||||
}
|
||||
for (const { ruleId } of result.suppressedMessages) {
|
||||
resultRuleIds.add(ruleId);
|
||||
}
|
||||
}
|
||||
|
||||
// create a map of all rules in the results
|
||||
|
||||
const { cliEngine } = privateMembersMap.get(this);
|
||||
const rules = cliEngine.getRules();
|
||||
const resultRules = new Map();
|
||||
|
||||
for (const [ruleId, rule] of rules) {
|
||||
if (resultRuleIds.has(ruleId)) {
|
||||
resultRules.set(ruleId, rule);
|
||||
}
|
||||
}
|
||||
|
||||
return createRulesMeta(resultRules);
|
||||
}
|
||||
|
||||
/* eslint-disable no-unused-vars, class-methods-use-this -- leaving for compatibility with ESLint#hasFlag */
|
||||
/**
|
||||
* Indicates if the given feature flag is enabled for this instance. For this
|
||||
* class, this always returns `false` because it does not support feature flags.
|
||||
* @param {string} flag The feature flag to check.
|
||||
* @returns {boolean} Always false.
|
||||
*/
|
||||
hasFlag(flag) {
|
||||
return false;
|
||||
}
|
||||
/* eslint-enable no-unused-vars, class-methods-use-this -- reenable rules for the rest of the file */
|
||||
|
||||
/**
|
||||
* Executes the current configuration on an array of file and directory names.
|
||||
* @param {string[]} patterns An array of file and directory names.
|
||||
* @returns {Promise<LintResult[]>} The results of linting the file patterns given.
|
||||
*/
|
||||
async lintFiles(patterns) {
|
||||
const { cliEngine, options } = privateMembersMap.get(this);
|
||||
|
||||
if (
|
||||
options.passOnNoPatterns &&
|
||||
(patterns === "" ||
|
||||
(Array.isArray(patterns) && patterns.length === 0))
|
||||
) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (!isNonEmptyString(patterns) && !isArrayOfNonEmptyString(patterns)) {
|
||||
throw new Error(
|
||||
"'patterns' must be a non-empty string or an array of non-empty strings",
|
||||
);
|
||||
}
|
||||
|
||||
return processCLIEngineLintReport(
|
||||
cliEngine,
|
||||
cliEngine.executeOnFiles(patterns),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the current configuration on text.
|
||||
* @param {string} code A string of JavaScript code to lint.
|
||||
* @param {Object} [options] The options.
|
||||
* @param {string} [options.filePath] The path to the file of the source code.
|
||||
* @param {boolean} [options.warnIgnored] When set to true, warn if given filePath is an ignored path.
|
||||
* @returns {Promise<LintResult[]>} The results of linting the string of code given.
|
||||
*/
|
||||
async lintText(code, options = {}) {
|
||||
if (typeof code !== "string") {
|
||||
throw new Error("'code' must be a string");
|
||||
}
|
||||
if (typeof options !== "object") {
|
||||
throw new Error("'options' must be an object, null, or undefined");
|
||||
}
|
||||
const {
|
||||
filePath,
|
||||
warnIgnored = false,
|
||||
...unknownOptions
|
||||
} = options || {};
|
||||
|
||||
const unknownOptionKeys = Object.keys(unknownOptions);
|
||||
|
||||
if (unknownOptionKeys.length > 0) {
|
||||
throw new Error(
|
||||
`'options' must not include the unknown option(s): ${unknownOptionKeys.join(", ")}`,
|
||||
);
|
||||
}
|
||||
|
||||
if (filePath !== void 0 && !isNonEmptyString(filePath)) {
|
||||
throw new Error(
|
||||
"'options.filePath' must be a non-empty string or undefined",
|
||||
);
|
||||
}
|
||||
if (typeof warnIgnored !== "boolean") {
|
||||
throw new Error(
|
||||
"'options.warnIgnored' must be a boolean or undefined",
|
||||
);
|
||||
}
|
||||
|
||||
const { cliEngine } = privateMembersMap.get(this);
|
||||
|
||||
return processCLIEngineLintReport(
|
||||
cliEngine,
|
||||
cliEngine.executeOnText(code, filePath, warnIgnored),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the formatter representing the given formatter name.
|
||||
* @param {string} [name] The name of the formatter to load.
|
||||
* The following values are allowed:
|
||||
* - `undefined` ... Load `stylish` builtin formatter.
|
||||
* - A builtin formatter name ... Load the builtin formatter.
|
||||
* - A third-party formatter name:
|
||||
* - `foo` → `eslint-formatter-foo`
|
||||
* - `@foo` → `@foo/eslint-formatter`
|
||||
* - `@foo/bar` → `@foo/eslint-formatter-bar`
|
||||
* - A file path ... Load the file.
|
||||
* @returns {Promise<LoadedFormatter>} A promise resolving to the formatter object.
|
||||
* This promise will be rejected if the given formatter was not found or not
|
||||
* a function.
|
||||
*/
|
||||
async loadFormatter(name = "stylish") {
|
||||
if (typeof name !== "string") {
|
||||
throw new Error("'name' must be a string");
|
||||
}
|
||||
|
||||
const { cliEngine, options } = privateMembersMap.get(this);
|
||||
const formatter = cliEngine.getFormatter(name);
|
||||
|
||||
if (typeof formatter !== "function") {
|
||||
throw new Error(
|
||||
`Formatter must be a function, but got a ${typeof formatter}.`,
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
/**
|
||||
* The main formatter method.
|
||||
* @param {LintResult[]} results The lint results to format.
|
||||
* @param {ResultsMeta} resultsMeta Warning count and max threshold.
|
||||
* @returns {string | Promise<string>} The formatted lint results.
|
||||
*/
|
||||
format(results, resultsMeta) {
|
||||
let rulesMeta = null;
|
||||
|
||||
results.sort(compareResultsByFilePath);
|
||||
|
||||
return formatter(results, {
|
||||
...resultsMeta,
|
||||
get cwd() {
|
||||
return options.cwd;
|
||||
},
|
||||
get rulesMeta() {
|
||||
if (!rulesMeta) {
|
||||
rulesMeta = createRulesMeta(cliEngine.getRules());
|
||||
}
|
||||
|
||||
return rulesMeta;
|
||||
},
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a configuration object for the given file based on the CLI options.
|
||||
* This is the same logic used by the ESLint CLI executable to determine
|
||||
* configuration for each file it processes.
|
||||
* @param {string} filePath The path of the file to retrieve a config object for.
|
||||
* @returns {Promise<ConfigData>} A configuration object for the file.
|
||||
*/
|
||||
async calculateConfigForFile(filePath) {
|
||||
if (!isNonEmptyString(filePath)) {
|
||||
throw new Error("'filePath' must be a non-empty string");
|
||||
}
|
||||
const { cliEngine } = privateMembersMap.get(this);
|
||||
|
||||
return cliEngine.getConfigForFile(filePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a given path is ignored by ESLint.
|
||||
* @param {string} filePath The path of the file to check.
|
||||
* @returns {Promise<boolean>} Whether or not the given path is ignored.
|
||||
*/
|
||||
async isPathIgnored(filePath) {
|
||||
if (!isNonEmptyString(filePath)) {
|
||||
throw new Error("'filePath' must be a non-empty string");
|
||||
}
|
||||
const { cliEngine } = privateMembersMap.get(this);
|
||||
|
||||
return cliEngine.isPathIgnored(filePath);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Public Interface
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
LegacyESLint,
|
||||
|
||||
/**
|
||||
* Get the private class members of a given ESLint instance for tests.
|
||||
* @param {ESLint} instance The ESLint instance to get.
|
||||
* @returns {ESLintPrivateMembers} The instance's private class members.
|
||||
*/
|
||||
getESLintPrivateMembers(instance) {
|
||||
return privateMembersMap.get(instance);
|
||||
},
|
||||
};
|
||||
164
slider/node_modules/eslint/lib/eslint/worker.js
generated
vendored
Normal file
164
slider/node_modules/eslint/lib/eslint/worker.js
generated
vendored
Normal file
@@ -0,0 +1,164 @@
|
||||
/**
|
||||
* @fileoverview Worker thread for multithread linting.
|
||||
* @author Francesco Trotta
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
const hrtimeBigint = process.hrtime.bigint;
|
||||
|
||||
const startTime = hrtimeBigint();
|
||||
|
||||
// eslint-disable-next-line n/no-unsupported-features/node-builtins -- enable V8's code cache if supported
|
||||
require("node:module").enableCompileCache?.();
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const { parentPort, threadId, workerData } = require("node:worker_threads");
|
||||
const createDebug = require("debug");
|
||||
const {
|
||||
createConfigLoader,
|
||||
createDefaultConfigs,
|
||||
createLinter,
|
||||
createLintResultCache,
|
||||
getCacheFile,
|
||||
lintFile,
|
||||
loadOptionsFromModule,
|
||||
processOptions,
|
||||
} = require("./eslint-helpers");
|
||||
const { WarningService } = require("../services/warning-service");
|
||||
|
||||
const depsLoadedTime = hrtimeBigint();
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Typedefs
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @typedef {import("../types").ESLint.LintResult} LintResult */
|
||||
/** @typedef {import("../types").ESLint.Options} ESLintOptions */
|
||||
/** @typedef {LintResult & { index?: number; }} IndexedLintResult */
|
||||
/** @typedef {IndexedLintResult[] & { netLintingDuration: bigint; }} WorkerLintResults */
|
||||
/**
|
||||
* @typedef {Object} WorkerData - Data passed to the worker thread.
|
||||
* @property {ESLintOptions | string} eslintOptionsOrURL - The unprocessed ESLint options or the URL of the options module.
|
||||
* @property {Uint32Array<SharedArrayBuffer>} filePathIndexArray - Shared counter used to track the next file to lint.
|
||||
* @property {string[]} filePaths - File paths to lint.
|
||||
*/
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const debug = createDebug(`eslint:worker:thread-${threadId}`);
|
||||
createDebug.formatters.t = timeDiff =>
|
||||
`${(timeDiff + 500_000n) / 1_000_000n} ms`;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Main
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
debug("Dependencies loaded in %t", depsLoadedTime - startTime);
|
||||
|
||||
(async () => {
|
||||
/** @type {WorkerData} */
|
||||
const { eslintOptionsOrURL, filePathIndexArray, filePaths } = workerData;
|
||||
const eslintOptions =
|
||||
typeof eslintOptionsOrURL === "object"
|
||||
? eslintOptionsOrURL
|
||||
: await loadOptionsFromModule(eslintOptionsOrURL);
|
||||
const processedESLintOptions = processOptions(eslintOptions);
|
||||
|
||||
const warningService = new WarningService();
|
||||
|
||||
// These warnings are always emitted by the controlling thread.
|
||||
warningService.emitEmptyConfigWarning =
|
||||
warningService.emitInactiveFlagWarning = () => {};
|
||||
|
||||
const linter = createLinter(processedESLintOptions, warningService);
|
||||
|
||||
const cacheFilePath = getCacheFile(
|
||||
processedESLintOptions.cacheLocation,
|
||||
processedESLintOptions.cwd,
|
||||
);
|
||||
|
||||
const lintResultCache = createLintResultCache(
|
||||
processedESLintOptions,
|
||||
cacheFilePath,
|
||||
);
|
||||
const defaultConfigs = createDefaultConfigs(eslintOptions.plugins);
|
||||
|
||||
const configLoader = createConfigLoader(
|
||||
processedESLintOptions,
|
||||
defaultConfigs,
|
||||
linter,
|
||||
warningService,
|
||||
);
|
||||
|
||||
/** @type {WorkerLintResults} */
|
||||
const indexedResults = [];
|
||||
let loadConfigTotalDuration = 0n;
|
||||
const readFileCounter = { duration: 0n };
|
||||
|
||||
const lintingStartTime = hrtimeBigint();
|
||||
debug(
|
||||
"Linting started %t after dependencies loaded",
|
||||
lintingStartTime - depsLoadedTime,
|
||||
);
|
||||
|
||||
for (;;) {
|
||||
const fileLintingStartTime = hrtimeBigint();
|
||||
|
||||
// It seems hard to produce an arithmetic overflow under realistic conditions here.
|
||||
const index = Atomics.add(filePathIndexArray, 0, 1);
|
||||
|
||||
const filePath = filePaths[index];
|
||||
if (!filePath) {
|
||||
break;
|
||||
}
|
||||
|
||||
const loadConfigEnterTime = hrtimeBigint();
|
||||
const configs = await configLoader.loadConfigArrayForFile(filePath);
|
||||
const loadConfigExitTime = hrtimeBigint();
|
||||
const loadConfigDuration = loadConfigExitTime - loadConfigEnterTime;
|
||||
debug(
|
||||
'Config array for file "%s" loaded in %t',
|
||||
filePath,
|
||||
loadConfigDuration,
|
||||
);
|
||||
loadConfigTotalDuration += loadConfigDuration;
|
||||
|
||||
/** @type {IndexedLintResult} */
|
||||
const result = await lintFile(
|
||||
filePath,
|
||||
configs,
|
||||
processedESLintOptions,
|
||||
linter,
|
||||
lintResultCache,
|
||||
readFileCounter,
|
||||
);
|
||||
if (result) {
|
||||
result.index = index;
|
||||
indexedResults.push(result);
|
||||
}
|
||||
|
||||
const fileLintingEndTime = hrtimeBigint();
|
||||
debug(
|
||||
'File "%s" processed in %t',
|
||||
filePath,
|
||||
fileLintingEndTime - fileLintingStartTime,
|
||||
);
|
||||
}
|
||||
|
||||
const lintingDuration = hrtimeBigint() - lintingStartTime;
|
||||
|
||||
/*
|
||||
* The net linting duration is the total linting time minus the time spent loading configs and reading files.
|
||||
* It captures the processing time dedicated to computation-intensive tasks that are highly parallelizable and not repeated across threads.
|
||||
*/
|
||||
indexedResults.netLintingDuration =
|
||||
lintingDuration - loadConfigTotalDuration - readFileCounter.duration;
|
||||
|
||||
parentPort.postMessage(indexedResults);
|
||||
})();
|
||||
336
slider/node_modules/eslint/lib/languages/js/index.js
generated
vendored
Normal file
336
slider/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 */
|
||||
/** @typedef {import("../../types").Linter.LanguageOptions} JSLanguageOptions */
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// 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 {JSLanguageOptions} 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 {JSLanguageOptions} 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 {JSLanguageOptions} 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
slider/node_modules/eslint/lib/languages/js/source-code/index.js
generated
vendored
Normal file
7
slider/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,
|
||||
};
|
||||
1364
slider/node_modules/eslint/lib/languages/js/source-code/source-code.js
generated
vendored
Normal file
1364
slider/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
61
slider/node_modules/eslint/lib/languages/js/source-code/token-store/backward-token-comment-cursor.js
generated
vendored
Normal file
61
slider/node_modules/eslint/lib/languages/js/source-code/token-store/backward-token-comment-cursor.js
generated
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* @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)
|
||||
);
|
||||
}
|
||||
};
|
||||
57
slider/node_modules/eslint/lib/languages/js/source-code/token-store/backward-token-cursor.js
generated
vendored
Normal file
57
slider/node_modules/eslint/lib/languages/js/source-code/token-store/backward-token-cursor.js
generated
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* @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
slider/node_modules/eslint/lib/languages/js/source-code/token-store/cursor.js
generated
vendored
Normal file
76
slider/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 */
|
||||
// eslint-disable-next-line class-methods-use-this -- Unused
|
||||
moveNext() {
|
||||
throw new Error("Not implemented.");
|
||||
}
|
||||
};
|
||||
120
slider/node_modules/eslint/lib/languages/js/source-code/token-store/cursors.js
generated
vendored
Normal file
120
slider/node_modules/eslint/lib/languages/js/source-code/token-store/cursors.js
generated
vendored
Normal file
@@ -0,0 +1,120 @@
|
||||
/**
|
||||
* @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,
|
||||
),
|
||||
};
|
||||
38
slider/node_modules/eslint/lib/languages/js/source-code/token-store/decorative-cursor.js
generated
vendored
Normal file
38
slider/node_modules/eslint/lib/languages/js/source-code/token-store/decorative-cursor.js
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
};
|
||||
42
slider/node_modules/eslint/lib/languages/js/source-code/token-store/filter-cursor.js
generated
vendored
Normal file
42
slider/node_modules/eslint/lib/languages/js/source-code/token-store/filter-cursor.js
generated
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
};
|
||||
65
slider/node_modules/eslint/lib/languages/js/source-code/token-store/forward-token-comment-cursor.js
generated
vendored
Normal file
65
slider/node_modules/eslint/lib/languages/js/source-code/token-store/forward-token-comment-cursor.js
generated
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* @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)
|
||||
);
|
||||
}
|
||||
};
|
||||
62
slider/node_modules/eslint/lib/languages/js/source-code/token-store/forward-token-cursor.js
generated
vendored
Normal file
62
slider/node_modules/eslint/lib/languages/js/source-code/token-store/forward-token-cursor.js
generated
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* @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);
|
||||
}
|
||||
};
|
||||
721
slider/node_modules/eslint/lib/languages/js/source-code/token-store/index.js
generated
vendored
Normal file
721
slider/node_modules/eslint/lib/languages/js/source-code/token-store/index.js
generated
vendored
Normal file
@@ -0,0 +1,721 @@
|
||||
/**
|
||||
* @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 {number} [beforeCount=0] The number of tokens before the node to retrieve.
|
||||
* @param {number} [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 {number} [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,
|
||||
});
|
||||
}
|
||||
};
|
||||
39
slider/node_modules/eslint/lib/languages/js/source-code/token-store/limit-cursor.js
generated
vendored
Normal file
39
slider/node_modules/eslint/lib/languages/js/source-code/token-store/limit-cursor.js
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
};
|
||||
45
slider/node_modules/eslint/lib/languages/js/source-code/token-store/padded-token-cursor.js
generated
vendored
Normal file
45
slider/node_modules/eslint/lib/languages/js/source-code/token-store/padded-token-cursor.js
generated
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* @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);
|
||||
}
|
||||
};
|
||||
41
slider/node_modules/eslint/lib/languages/js/source-code/token-store/skip-cursor.js
generated
vendored
Normal file
41
slider/node_modules/eslint/lib/languages/js/source-code/token-store/skip-cursor.js
generated
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* @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();
|
||||
}
|
||||
};
|
||||
110
slider/node_modules/eslint/lib/languages/js/source-code/token-store/utils.js
generated
vendored
Normal file
110
slider/node_modules/eslint/lib/languages/js/source-code/token-store/utils.js
generated
vendored
Normal file
@@ -0,0 +1,110 @@
|
||||
/**
|
||||
* @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;
|
||||
};
|
||||
196
slider/node_modules/eslint/lib/languages/js/validate-language-options.js
generated
vendored
Normal file
196
slider/node_modules/eslint/lib/languages/js/validate-language-options.js
generated
vendored
Normal file
@@ -0,0 +1,196 @@
|
||||
/**
|
||||
* @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 };
|
||||
584
slider/node_modules/eslint/lib/linter/apply-disable-directives.js
generated
vendored
Normal file
584
slider/node_modules/eslint/lib/linter/apply-disable-directives.js
generated
vendored
Normal file
@@ -0,0 +1,584 @@
|
||||
/**
|
||||
* @fileoverview A module that filters reported problems based on `eslint-disable` and `eslint-enable` comments
|
||||
* @author Teddy Katz
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Typedefs
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @typedef {import("../types").Linter.LintMessage} LintMessage */
|
||||
/** @typedef {import("@eslint/core").Language} Language */
|
||||
/** @typedef {import("@eslint/core").Position} Position */
|
||||
/** @typedef {import("@eslint/core").RulesConfig} RulesConfig */
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Module Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const escapeRegExp = require("escape-string-regexp");
|
||||
const { Config } = require("../config/config.js");
|
||||
|
||||
/**
|
||||
* Compares the locations of two objects in a source file
|
||||
* @param {Position} itemA The first object
|
||||
* @param {Position} itemB The second object
|
||||
* @returns {number} A value less than 1 if itemA appears before itemB in the source file, greater than 1 if
|
||||
* itemA appears after itemB in the source file, or 0 if itemA and itemB have the same location.
|
||||
*/
|
||||
function compareLocations(itemA, itemB) {
|
||||
return itemA.line - itemB.line || itemA.column - itemB.column;
|
||||
}
|
||||
|
||||
/**
|
||||
* Groups a set of directives into sub-arrays by their parent comment.
|
||||
* @param {Iterable<Directive>} directives Unused directives to be removed.
|
||||
* @returns {Directive[][]} Directives grouped by their parent comment.
|
||||
*/
|
||||
function groupByParentDirective(directives) {
|
||||
const groups = new Map();
|
||||
|
||||
for (const directive of directives) {
|
||||
const {
|
||||
unprocessedDirective: { parentDirective },
|
||||
} = directive;
|
||||
|
||||
if (groups.has(parentDirective)) {
|
||||
groups.get(parentDirective).push(directive);
|
||||
} else {
|
||||
groups.set(parentDirective, [directive]);
|
||||
}
|
||||
}
|
||||
|
||||
return [...groups.values()];
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates removal details for a set of directives within the same comment.
|
||||
* @param {Directive[]} directives Unused directives to be removed.
|
||||
* @param {{node: Token, value: string}} parentDirective Data about the backing directive.
|
||||
* @param {SourceCode} sourceCode The source code object for the file being linted.
|
||||
* @returns {{ description, fix, unprocessedDirective }[]} Details for later creation of output Problems.
|
||||
*/
|
||||
function createIndividualDirectivesRemoval(
|
||||
directives,
|
||||
parentDirective,
|
||||
sourceCode,
|
||||
) {
|
||||
/*
|
||||
* Get the list of the rules text without any surrounding whitespace. In order to preserve the original
|
||||
* formatting, we don't want to change that whitespace.
|
||||
*
|
||||
* // eslint-disable-line rule-one , rule-two , rule-three -- comment
|
||||
* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
*/
|
||||
const listText = parentDirective.value.trim();
|
||||
|
||||
// Calculate where it starts in the source code text
|
||||
const listStart = sourceCode.text.indexOf(
|
||||
listText,
|
||||
sourceCode.getRange(parentDirective.node)[0],
|
||||
);
|
||||
|
||||
/*
|
||||
* We can assume that `listText` contains multiple elements.
|
||||
* Otherwise, this function wouldn't be called - if there is
|
||||
* only one rule in the list, then the whole comment must be removed.
|
||||
*/
|
||||
|
||||
return directives.map(directive => {
|
||||
const { ruleId } = directive;
|
||||
|
||||
const regex = new RegExp(
|
||||
String.raw`(?:^|\s*,\s*)(?<quote>['"]?)${escapeRegExp(ruleId)}\k<quote>(?:\s*,\s*|$)`,
|
||||
"u",
|
||||
);
|
||||
const match = regex.exec(listText);
|
||||
const matchedText = match[0];
|
||||
const matchStart = listStart + match.index;
|
||||
const matchEnd = matchStart + matchedText.length;
|
||||
|
||||
const firstIndexOfComma = matchedText.indexOf(",");
|
||||
const lastIndexOfComma = matchedText.lastIndexOf(",");
|
||||
|
||||
let removalStart, removalEnd;
|
||||
|
||||
if (firstIndexOfComma !== lastIndexOfComma) {
|
||||
/*
|
||||
* Since there are two commas, this must one of the elements in the middle of the list.
|
||||
* Matched range starts where the previous rule name ends, and ends where the next rule name starts.
|
||||
*
|
||||
* // eslint-disable-line rule-one , rule-two , rule-three -- comment
|
||||
* ^^^^^^^^^^^^^^
|
||||
*
|
||||
* We want to remove only the content between the two commas, and also one of the commas.
|
||||
*
|
||||
* // eslint-disable-line rule-one , rule-two , rule-three -- comment
|
||||
* ^^^^^^^^^^^
|
||||
*/
|
||||
removalStart = matchStart + firstIndexOfComma;
|
||||
removalEnd = matchStart + lastIndexOfComma;
|
||||
} else {
|
||||
/*
|
||||
* This is either the first element or the last element.
|
||||
*
|
||||
* If this is the first element, matched range starts where the first rule name starts
|
||||
* and ends where the second rule name starts. This is exactly the range we want
|
||||
* to remove so that the second rule name will start where the first one was starting
|
||||
* and thus preserve the original formatting.
|
||||
*
|
||||
* // eslint-disable-line rule-one , rule-two , rule-three -- comment
|
||||
* ^^^^^^^^^^^
|
||||
*
|
||||
* Similarly, if this is the last element, we've already matched the range we want to
|
||||
* remove. The previous rule name will end where the last one was ending, relative
|
||||
* to the content on the right side.
|
||||
*
|
||||
* // eslint-disable-line rule-one , rule-two , rule-three -- comment
|
||||
* ^^^^^^^^^^^^^
|
||||
*/
|
||||
removalStart = matchStart;
|
||||
removalEnd = matchEnd;
|
||||
}
|
||||
|
||||
return {
|
||||
description: `'${ruleId}'`,
|
||||
fix: {
|
||||
range: [removalStart, removalEnd],
|
||||
text: "",
|
||||
},
|
||||
unprocessedDirective: directive.unprocessedDirective,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a description of deleting an entire unused disable directive.
|
||||
* @param {Directive[]} directives Unused directives to be removed.
|
||||
* @param {Token} node The backing Comment token.
|
||||
* @param {SourceCode} sourceCode The source code object for the file being linted.
|
||||
* @returns {{ description, fix, unprocessedDirective }} Details for later creation of an output problem.
|
||||
*/
|
||||
function createDirectiveRemoval(directives, node, sourceCode) {
|
||||
const range = sourceCode.getRange(node);
|
||||
const ruleIds = directives
|
||||
.filter(directive => directive.ruleId)
|
||||
.map(directive => `'${directive.ruleId}'`);
|
||||
|
||||
return {
|
||||
description:
|
||||
ruleIds.length <= 2
|
||||
? ruleIds.join(" or ")
|
||||
: `${ruleIds.slice(0, ruleIds.length - 1).join(", ")}, or ${ruleIds.at(-1)}`,
|
||||
fix: {
|
||||
range,
|
||||
text: " ",
|
||||
},
|
||||
unprocessedDirective: directives[0].unprocessedDirective,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses details from directives to create output Problems.
|
||||
* @param {Iterable<Directive>} allDirectives Unused directives to be removed.
|
||||
* @param {SourceCode} sourceCode The source code object for the file being linted.
|
||||
* @returns {{ description, fix, unprocessedDirective }[]} Details for later creation of output Problems.
|
||||
*/
|
||||
function processUnusedDirectives(allDirectives, sourceCode) {
|
||||
const directiveGroups = groupByParentDirective(allDirectives);
|
||||
|
||||
return directiveGroups.flatMap(directives => {
|
||||
const { parentDirective } = directives[0].unprocessedDirective;
|
||||
const remainingRuleIds = new Set(parentDirective.ruleIds);
|
||||
|
||||
for (const directive of directives) {
|
||||
remainingRuleIds.delete(directive.ruleId);
|
||||
}
|
||||
|
||||
return remainingRuleIds.size
|
||||
? createIndividualDirectivesRemoval(
|
||||
directives,
|
||||
parentDirective,
|
||||
sourceCode,
|
||||
)
|
||||
: [
|
||||
createDirectiveRemoval(
|
||||
directives,
|
||||
parentDirective.node,
|
||||
sourceCode,
|
||||
),
|
||||
];
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect eslint-enable comments that are removing suppressions by eslint-disable comments.
|
||||
* @param {Directive[]} directives The directives to check.
|
||||
* @returns {Set<Directive>} The used eslint-enable comments
|
||||
*/
|
||||
function collectUsedEnableDirectives(directives) {
|
||||
/**
|
||||
* A Map of `eslint-enable` keyed by ruleIds that may be marked as used.
|
||||
* If `eslint-enable` does not have a ruleId, the key will be `null`.
|
||||
* @type {Map<string|null, Directive>}
|
||||
*/
|
||||
const enabledRules = new Map();
|
||||
|
||||
/**
|
||||
* A Set of `eslint-enable` marked as used.
|
||||
* It is also the return value of `collectUsedEnableDirectives` function.
|
||||
* @type {Set<Directive>}
|
||||
*/
|
||||
const usedEnableDirectives = new Set();
|
||||
|
||||
/*
|
||||
* Checks the directives backwards to see if the encountered `eslint-enable` is used by the previous `eslint-disable`,
|
||||
* and if so, stores the `eslint-enable` in `usedEnableDirectives`.
|
||||
*/
|
||||
for (let index = directives.length - 1; index >= 0; index--) {
|
||||
const directive = directives[index];
|
||||
|
||||
if (directive.type === "disable") {
|
||||
if (enabledRules.size === 0) {
|
||||
continue;
|
||||
}
|
||||
if (directive.ruleId === null) {
|
||||
// If encounter `eslint-disable` without ruleId,
|
||||
// mark all `eslint-enable` currently held in enabledRules as used.
|
||||
// e.g.
|
||||
// /* eslint-disable */ <- current directive
|
||||
// /* eslint-enable rule-id1 */ <- used
|
||||
// /* eslint-enable rule-id2 */ <- used
|
||||
// /* eslint-enable */ <- used
|
||||
for (const enableDirective of enabledRules.values()) {
|
||||
usedEnableDirectives.add(enableDirective);
|
||||
}
|
||||
enabledRules.clear();
|
||||
} else {
|
||||
const enableDirective = enabledRules.get(directive.ruleId);
|
||||
|
||||
if (enableDirective) {
|
||||
// If encounter `eslint-disable` with ruleId, and there is an `eslint-enable` with the same ruleId in enabledRules,
|
||||
// mark `eslint-enable` with ruleId as used.
|
||||
// e.g.
|
||||
// /* eslint-disable rule-id */ <- current directive
|
||||
// /* eslint-enable rule-id */ <- used
|
||||
usedEnableDirectives.add(enableDirective);
|
||||
} else {
|
||||
const enabledDirectiveWithoutRuleId =
|
||||
enabledRules.get(null);
|
||||
|
||||
if (enabledDirectiveWithoutRuleId) {
|
||||
// If encounter `eslint-disable` with ruleId, and there is no `eslint-enable` with the same ruleId in enabledRules,
|
||||
// mark `eslint-enable` without ruleId as used.
|
||||
// e.g.
|
||||
// /* eslint-disable rule-id */ <- current directive
|
||||
// /* eslint-enable */ <- used
|
||||
usedEnableDirectives.add(enabledDirectiveWithoutRuleId);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (directive.type === "enable") {
|
||||
if (directive.ruleId === null) {
|
||||
// If encounter `eslint-enable` without ruleId, the `eslint-enable` that follows it are unused.
|
||||
// So clear enabledRules.
|
||||
// e.g.
|
||||
// /* eslint-enable */ <- current directive
|
||||
// /* eslint-enable rule-id *// <- unused
|
||||
// /* eslint-enable */ <- unused
|
||||
enabledRules.clear();
|
||||
enabledRules.set(null, directive);
|
||||
} else {
|
||||
enabledRules.set(directive.ruleId, directive);
|
||||
}
|
||||
}
|
||||
}
|
||||
return usedEnableDirectives;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the same as the exported function, except that it
|
||||
* doesn't handle disable-line and disable-next-line directives, and it always reports unused
|
||||
* disable directives.
|
||||
* @param {Object} options options for applying directives. This is the same as the options
|
||||
* for the exported function, except that `reportUnusedDisableDirectives` is not supported
|
||||
* (this function always reports unused disable directives).
|
||||
* @returns {{problems: LintMessage[], unusedDirectives: LintMessage[]}} An object with a list
|
||||
* of problems (including suppressed ones) and unused eslint-disable directives
|
||||
*/
|
||||
function applyDirectives(options) {
|
||||
const problems = [];
|
||||
const usedDisableDirectives = new Set();
|
||||
const { sourceCode } = options;
|
||||
|
||||
for (const problem of options.problems) {
|
||||
let disableDirectivesForProblem = [];
|
||||
let nextDirectiveIndex = 0;
|
||||
|
||||
while (
|
||||
nextDirectiveIndex < options.directives.length &&
|
||||
compareLocations(options.directives[nextDirectiveIndex], problem) <=
|
||||
0
|
||||
) {
|
||||
const directive = options.directives[nextDirectiveIndex++];
|
||||
|
||||
if (
|
||||
directive.ruleId === null ||
|
||||
directive.ruleId === problem.ruleId
|
||||
) {
|
||||
switch (directive.type) {
|
||||
case "disable":
|
||||
disableDirectivesForProblem.push(directive);
|
||||
break;
|
||||
|
||||
case "enable":
|
||||
disableDirectivesForProblem = [];
|
||||
break;
|
||||
|
||||
// no default
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (disableDirectivesForProblem.length > 0) {
|
||||
const suppressions = disableDirectivesForProblem.map(directive => ({
|
||||
kind: "directive",
|
||||
justification: directive.unprocessedDirective.justification,
|
||||
}));
|
||||
|
||||
if (problem.suppressions) {
|
||||
problem.suppressions =
|
||||
problem.suppressions.concat(suppressions);
|
||||
} else {
|
||||
problem.suppressions = suppressions;
|
||||
usedDisableDirectives.add(disableDirectivesForProblem.at(-1));
|
||||
}
|
||||
}
|
||||
|
||||
problems.push(problem);
|
||||
}
|
||||
|
||||
const unusedDisableDirectivesToReport = options.directives.filter(
|
||||
directive =>
|
||||
directive.type === "disable" &&
|
||||
!usedDisableDirectives.has(directive) &&
|
||||
!options.rulesToIgnore.has(directive.ruleId),
|
||||
);
|
||||
|
||||
const unusedEnableDirectivesToReport = new Set(
|
||||
options.directives.filter(
|
||||
directive =>
|
||||
directive.unprocessedDirective.type === "enable" &&
|
||||
!options.rulesToIgnore.has(directive.ruleId),
|
||||
),
|
||||
);
|
||||
|
||||
/*
|
||||
* If directives has the eslint-enable directive,
|
||||
* check whether the eslint-enable comment is used.
|
||||
*/
|
||||
if (unusedEnableDirectivesToReport.size > 0) {
|
||||
for (const directive of collectUsedEnableDirectives(
|
||||
options.directives,
|
||||
)) {
|
||||
unusedEnableDirectivesToReport.delete(directive);
|
||||
}
|
||||
}
|
||||
|
||||
const processed = processUnusedDirectives(
|
||||
unusedDisableDirectivesToReport,
|
||||
sourceCode,
|
||||
).concat(
|
||||
processUnusedDirectives(unusedEnableDirectivesToReport, sourceCode),
|
||||
);
|
||||
const columnOffset = options.language.columnStart === 1 ? 0 : 1;
|
||||
const lineOffset = options.language.lineStart === 1 ? 0 : 1;
|
||||
|
||||
const unusedDirectives = processed.map(
|
||||
({ description, fix, unprocessedDirective }) => {
|
||||
const { parentDirective, type, line, column } =
|
||||
unprocessedDirective;
|
||||
|
||||
let message;
|
||||
|
||||
if (type === "enable") {
|
||||
message = description
|
||||
? `Unused eslint-enable directive (no matching eslint-disable directives were found for ${description}).`
|
||||
: "Unused eslint-enable directive (no matching eslint-disable directives were found).";
|
||||
} else {
|
||||
message = description
|
||||
? `Unused eslint-disable directive (no problems were reported from ${description}).`
|
||||
: "Unused eslint-disable directive (no problems were reported).";
|
||||
}
|
||||
|
||||
const loc = sourceCode.getLoc(parentDirective.node);
|
||||
|
||||
return {
|
||||
ruleId: null,
|
||||
message,
|
||||
line:
|
||||
type === "disable-next-line"
|
||||
? loc.start.line + lineOffset
|
||||
: line,
|
||||
column:
|
||||
type === "disable-next-line"
|
||||
? loc.start.column + columnOffset
|
||||
: column,
|
||||
severity:
|
||||
options.reportUnusedDisableDirectives === "warn" ? 1 : 2,
|
||||
nodeType: null,
|
||||
...(options.disableFixes ? {} : { fix }),
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
return { problems, unusedDirectives };
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a list of directive comments (i.e. metadata about eslint-disable and eslint-enable comments) and a list
|
||||
* of reported problems, adds the suppression information to the problems.
|
||||
* @param {Object} options Information about directives and problems
|
||||
* @param {Language} options.language The language being linted.
|
||||
* @param {SourceCode} options.sourceCode The source code object for the file being linted.
|
||||
* @param {{
|
||||
* type: ("disable"|"enable"|"disable-line"|"disable-next-line"),
|
||||
* ruleId: (string|null),
|
||||
* line: number,
|
||||
* column: number,
|
||||
* justification: string
|
||||
* }} options.directives Directive comments found in the file, with one-based columns.
|
||||
* Two directive comments can only have the same location if they also have the same type (e.g. a single eslint-disable
|
||||
* comment for two different rules is represented as two directives).
|
||||
* @param {{ruleId: (string|null), line: number, column: number}[]} options.problems
|
||||
* A list of problems reported by rules, sorted by increasing location in the file, with one-based columns.
|
||||
* @param {"off" | "warn" | "error"} options.reportUnusedDisableDirectives If `"warn"` or `"error"`, adds additional problems for unused directives
|
||||
* @param {RulesConfig} options.configuredRules The rules configuration.
|
||||
* @param {Function} options.ruleFilter A predicate function to filter which rules should be executed.
|
||||
* @param {boolean} options.disableFixes If true, it doesn't make `fix` properties.
|
||||
* @returns {{ruleId: (string|null), line: number, column: number, suppressions?: {kind: string, justification: string}}[]}
|
||||
* An object with a list of reported problems, the suppressed of which contain the suppression information.
|
||||
*/
|
||||
module.exports = ({
|
||||
language,
|
||||
sourceCode,
|
||||
directives,
|
||||
disableFixes,
|
||||
problems,
|
||||
configuredRules,
|
||||
ruleFilter,
|
||||
reportUnusedDisableDirectives = "off",
|
||||
}) => {
|
||||
const blockDirectives = directives
|
||||
.filter(
|
||||
directive =>
|
||||
directive.type === "disable" || directive.type === "enable",
|
||||
)
|
||||
.map(directive =>
|
||||
Object.assign({}, directive, { unprocessedDirective: directive }),
|
||||
)
|
||||
.sort(compareLocations);
|
||||
|
||||
const lineDirectives = directives
|
||||
.flatMap(directive => {
|
||||
switch (directive.type) {
|
||||
case "disable":
|
||||
case "enable":
|
||||
return [];
|
||||
|
||||
case "disable-line":
|
||||
return [
|
||||
{
|
||||
type: "disable",
|
||||
line: directive.line,
|
||||
column: 1,
|
||||
ruleId: directive.ruleId,
|
||||
unprocessedDirective: directive,
|
||||
},
|
||||
{
|
||||
type: "enable",
|
||||
line: directive.line + 1,
|
||||
column: 0,
|
||||
ruleId: directive.ruleId,
|
||||
unprocessedDirective: directive,
|
||||
},
|
||||
];
|
||||
|
||||
case "disable-next-line":
|
||||
return [
|
||||
{
|
||||
type: "disable",
|
||||
line: directive.line + 1,
|
||||
column: 1,
|
||||
ruleId: directive.ruleId,
|
||||
unprocessedDirective: directive,
|
||||
},
|
||||
{
|
||||
type: "enable",
|
||||
line: directive.line + 2,
|
||||
column: 0,
|
||||
ruleId: directive.ruleId,
|
||||
unprocessedDirective: directive,
|
||||
},
|
||||
];
|
||||
|
||||
default:
|
||||
throw new TypeError(
|
||||
`Unrecognized directive type '${directive.type}'`,
|
||||
);
|
||||
}
|
||||
})
|
||||
.sort(compareLocations);
|
||||
|
||||
// This determines a list of rules that are not being run by the given ruleFilter, if present.
|
||||
const rulesToIgnore =
|
||||
configuredRules && ruleFilter
|
||||
? new Set(
|
||||
Object.keys(configuredRules).filter(ruleId => {
|
||||
const severity = Config.getRuleNumericSeverity(
|
||||
configuredRules[ruleId],
|
||||
);
|
||||
|
||||
// Ignore for disabled rules.
|
||||
if (severity === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !ruleFilter({ severity, ruleId });
|
||||
}),
|
||||
)
|
||||
: new Set();
|
||||
|
||||
// If no ruleId is supplied that means this directive is applied to all rules, so we can't determine if it's unused if any rules are filtered out.
|
||||
if (rulesToIgnore.size > 0) {
|
||||
rulesToIgnore.add(null);
|
||||
}
|
||||
|
||||
const blockDirectivesResult = applyDirectives({
|
||||
language,
|
||||
sourceCode,
|
||||
problems,
|
||||
directives: blockDirectives,
|
||||
disableFixes,
|
||||
reportUnusedDisableDirectives,
|
||||
rulesToIgnore,
|
||||
});
|
||||
const lineDirectivesResult = applyDirectives({
|
||||
language,
|
||||
sourceCode,
|
||||
problems: blockDirectivesResult.problems,
|
||||
directives: lineDirectives,
|
||||
disableFixes,
|
||||
reportUnusedDisableDirectives,
|
||||
rulesToIgnore,
|
||||
});
|
||||
|
||||
return reportUnusedDisableDirectives !== "off"
|
||||
? lineDirectivesResult.problems
|
||||
.concat(blockDirectivesResult.unusedDirectives)
|
||||
.concat(lineDirectivesResult.unusedDirectives)
|
||||
.sort(compareLocations)
|
||||
: lineDirectivesResult.problems;
|
||||
};
|
||||
828
slider/node_modules/eslint/lib/linter/code-path-analysis/code-path-analyzer.js
generated
vendored
Normal file
828
slider/node_modules/eslint/lib/linter/code-path-analysis/code-path-analyzer.js
generated
vendored
Normal file
@@ -0,0 +1,828 @@
|
||||
/**
|
||||
* @fileoverview A class of the code path analyzer.
|
||||
* @author Toru Nagashima
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const assert = require("../../shared/assert"),
|
||||
{ breakableTypePattern } = require("../../shared/ast-utils"),
|
||||
CodePath = require("./code-path"),
|
||||
CodePathSegment = require("./code-path-segment"),
|
||||
IdGenerator = require("./id-generator"),
|
||||
debug = require("./debug-helpers");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Checks whether or not a given node is a `case` node (not `default` node).
|
||||
* @param {ASTNode} node A `SwitchCase` node to check.
|
||||
* @returns {boolean} `true` if the node is a `case` node (not `default` node).
|
||||
*/
|
||||
function isCaseNode(node) {
|
||||
return Boolean(node.test);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a given node appears as the value of a PropertyDefinition node.
|
||||
* @param {ASTNode} node THe node to check.
|
||||
* @returns {boolean} `true` if the node is a PropertyDefinition value,
|
||||
* false if not.
|
||||
*/
|
||||
function isPropertyDefinitionValue(node) {
|
||||
const parent = node.parent;
|
||||
|
||||
return (
|
||||
parent && parent.type === "PropertyDefinition" && parent.value === node
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given logical operator is taken into account for the code
|
||||
* path analysis.
|
||||
* @param {string} operator The operator found in the LogicalExpression node
|
||||
* @returns {boolean} `true` if the operator is "&&" or "||" or "??"
|
||||
*/
|
||||
function isHandledLogicalOperator(operator) {
|
||||
return operator === "&&" || operator === "||" || operator === "??";
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given assignment operator is a logical assignment operator.
|
||||
* Logical assignments are taken into account for the code path analysis
|
||||
* because of their short-circuiting semantics.
|
||||
* @param {string} operator The operator found in the AssignmentExpression node
|
||||
* @returns {boolean} `true` if the operator is "&&=" or "||=" or "??="
|
||||
*/
|
||||
function isLogicalAssignmentOperator(operator) {
|
||||
return operator === "&&=" || operator === "||=" || operator === "??=";
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the label if the parent node of a given node is a LabeledStatement.
|
||||
* @param {ASTNode} node A node to get.
|
||||
* @returns {string|null} The label or `null`.
|
||||
*/
|
||||
function getLabel(node) {
|
||||
if (node.parent.type === "LabeledStatement") {
|
||||
return node.parent.label.name;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether or not a given logical expression node goes different path
|
||||
* between the `true` case and the `false` case.
|
||||
* @param {ASTNode} node A node to check.
|
||||
* @returns {boolean} `true` if the node is a test of a choice statement.
|
||||
*/
|
||||
function isForkingByTrueOrFalse(node) {
|
||||
const parent = node.parent;
|
||||
|
||||
switch (parent.type) {
|
||||
case "ConditionalExpression":
|
||||
case "IfStatement":
|
||||
case "WhileStatement":
|
||||
case "DoWhileStatement":
|
||||
case "ForStatement":
|
||||
return parent.test === node;
|
||||
|
||||
case "LogicalExpression":
|
||||
return isHandledLogicalOperator(parent.operator);
|
||||
|
||||
case "AssignmentExpression":
|
||||
return isLogicalAssignmentOperator(parent.operator);
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the boolean value of a given literal node.
|
||||
*
|
||||
* This is used to detect infinity loops (e.g. `while (true) {}`).
|
||||
* Statements preceded by an infinity loop are unreachable if the loop didn't
|
||||
* have any `break` statement.
|
||||
* @param {ASTNode} node A node to get.
|
||||
* @returns {boolean|undefined} a boolean value if the node is a Literal node,
|
||||
* otherwise `undefined`.
|
||||
*/
|
||||
function getBooleanValueIfSimpleConstant(node) {
|
||||
if (node.type === "Literal") {
|
||||
return Boolean(node.value);
|
||||
}
|
||||
return void 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that a given identifier node is a reference or not.
|
||||
*
|
||||
* This is used to detect the first throwable node in a `try` block.
|
||||
* @param {ASTNode} node An Identifier node to check.
|
||||
* @returns {boolean} `true` if the node is a reference.
|
||||
*/
|
||||
function isIdentifierReference(node) {
|
||||
const parent = node.parent;
|
||||
|
||||
switch (parent.type) {
|
||||
case "LabeledStatement":
|
||||
case "BreakStatement":
|
||||
case "ContinueStatement":
|
||||
case "ArrayPattern":
|
||||
case "RestElement":
|
||||
case "ImportSpecifier":
|
||||
case "ImportDefaultSpecifier":
|
||||
case "ImportNamespaceSpecifier":
|
||||
case "CatchClause":
|
||||
return false;
|
||||
|
||||
case "FunctionDeclaration":
|
||||
case "FunctionExpression":
|
||||
case "ArrowFunctionExpression":
|
||||
case "ClassDeclaration":
|
||||
case "ClassExpression":
|
||||
case "VariableDeclarator":
|
||||
return parent.id !== node;
|
||||
|
||||
case "Property":
|
||||
case "PropertyDefinition":
|
||||
case "MethodDefinition":
|
||||
return parent.key !== node || parent.computed || parent.shorthand;
|
||||
|
||||
case "AssignmentPattern":
|
||||
return parent.key !== node;
|
||||
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the current segment with the head segment.
|
||||
* This is similar to local branches and tracking branches of git.
|
||||
*
|
||||
* To separate the current and the head is in order to not make useless segments.
|
||||
*
|
||||
* In this process, both "onCodePathSegmentStart" and "onCodePathSegmentEnd"
|
||||
* events are fired.
|
||||
* @param {CodePathAnalyzer} analyzer The instance.
|
||||
* @param {ASTNode} node The current AST node.
|
||||
* @returns {void}
|
||||
*/
|
||||
function forwardCurrentToHead(analyzer, node) {
|
||||
const codePath = analyzer.codePath;
|
||||
const state = CodePath.getState(codePath);
|
||||
const currentSegments = state.currentSegments;
|
||||
const headSegments = state.headSegments;
|
||||
const end = Math.max(currentSegments.length, headSegments.length);
|
||||
let i, currentSegment, headSegment;
|
||||
|
||||
// Fires leaving events.
|
||||
for (i = 0; i < end; ++i) {
|
||||
currentSegment = currentSegments[i];
|
||||
headSegment = headSegments[i];
|
||||
|
||||
if (currentSegment !== headSegment && currentSegment) {
|
||||
const eventName = currentSegment.reachable
|
||||
? "onCodePathSegmentEnd"
|
||||
: "onUnreachableCodePathSegmentEnd";
|
||||
|
||||
debug.dump(`${eventName} ${currentSegment.id}`);
|
||||
|
||||
analyzer.emit(eventName, [currentSegment, node]);
|
||||
}
|
||||
}
|
||||
|
||||
// Update state.
|
||||
state.currentSegments = headSegments;
|
||||
|
||||
// Fires entering events.
|
||||
for (i = 0; i < end; ++i) {
|
||||
currentSegment = currentSegments[i];
|
||||
headSegment = headSegments[i];
|
||||
|
||||
if (currentSegment !== headSegment && headSegment) {
|
||||
const eventName = headSegment.reachable
|
||||
? "onCodePathSegmentStart"
|
||||
: "onUnreachableCodePathSegmentStart";
|
||||
|
||||
debug.dump(`${eventName} ${headSegment.id}`);
|
||||
CodePathSegment.markUsed(headSegment);
|
||||
analyzer.emit(eventName, [headSegment, node]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the current segment with empty.
|
||||
* This is called at the last of functions or the program.
|
||||
* @param {CodePathAnalyzer} analyzer The instance.
|
||||
* @param {ASTNode} node The current AST node.
|
||||
* @returns {void}
|
||||
*/
|
||||
function leaveFromCurrentSegment(analyzer, node) {
|
||||
const state = CodePath.getState(analyzer.codePath);
|
||||
const currentSegments = state.currentSegments;
|
||||
|
||||
for (let i = 0; i < currentSegments.length; ++i) {
|
||||
const currentSegment = currentSegments[i];
|
||||
const eventName = currentSegment.reachable
|
||||
? "onCodePathSegmentEnd"
|
||||
: "onUnreachableCodePathSegmentEnd";
|
||||
|
||||
debug.dump(`${eventName} ${currentSegment.id}`);
|
||||
|
||||
analyzer.emit(eventName, [currentSegment, node]);
|
||||
}
|
||||
|
||||
state.currentSegments = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the code path due to the position of a given node in the parent node
|
||||
* thereof.
|
||||
*
|
||||
* For example, if the node is `parent.consequent`, this creates a fork from the
|
||||
* current path.
|
||||
* @param {CodePathAnalyzer} analyzer The instance.
|
||||
* @param {ASTNode} node The current AST node.
|
||||
* @returns {void}
|
||||
*/
|
||||
function preprocess(analyzer, node) {
|
||||
const codePath = analyzer.codePath;
|
||||
const state = CodePath.getState(codePath);
|
||||
const parent = node.parent;
|
||||
|
||||
switch (parent.type) {
|
||||
// The `arguments.length == 0` case is in `postprocess` function.
|
||||
case "CallExpression":
|
||||
if (
|
||||
parent.optional === true &&
|
||||
parent.arguments.length >= 1 &&
|
||||
parent.arguments[0] === node
|
||||
) {
|
||||
state.makeOptionalRight();
|
||||
}
|
||||
break;
|
||||
case "MemberExpression":
|
||||
if (parent.optional === true && parent.property === node) {
|
||||
state.makeOptionalRight();
|
||||
}
|
||||
break;
|
||||
|
||||
case "LogicalExpression":
|
||||
if (
|
||||
parent.right === node &&
|
||||
isHandledLogicalOperator(parent.operator)
|
||||
) {
|
||||
state.makeLogicalRight();
|
||||
}
|
||||
break;
|
||||
|
||||
case "AssignmentExpression":
|
||||
if (
|
||||
parent.right === node &&
|
||||
isLogicalAssignmentOperator(parent.operator)
|
||||
) {
|
||||
state.makeLogicalRight();
|
||||
}
|
||||
break;
|
||||
|
||||
case "ConditionalExpression":
|
||||
case "IfStatement":
|
||||
/*
|
||||
* Fork if this node is at `consequent`/`alternate`.
|
||||
* `popForkContext()` exists at `IfStatement:exit` and
|
||||
* `ConditionalExpression:exit`.
|
||||
*/
|
||||
if (parent.consequent === node) {
|
||||
state.makeIfConsequent();
|
||||
} else if (parent.alternate === node) {
|
||||
state.makeIfAlternate();
|
||||
}
|
||||
break;
|
||||
|
||||
case "SwitchCase":
|
||||
if (parent.consequent[0] === node) {
|
||||
state.makeSwitchCaseBody(false, !parent.test);
|
||||
}
|
||||
break;
|
||||
|
||||
case "TryStatement":
|
||||
if (parent.handler === node) {
|
||||
state.makeCatchBlock();
|
||||
} else if (parent.finalizer === node) {
|
||||
state.makeFinallyBlock();
|
||||
}
|
||||
break;
|
||||
|
||||
case "WhileStatement":
|
||||
if (parent.test === node) {
|
||||
state.makeWhileTest(getBooleanValueIfSimpleConstant(node));
|
||||
} else {
|
||||
assert(parent.body === node);
|
||||
state.makeWhileBody();
|
||||
}
|
||||
break;
|
||||
|
||||
case "DoWhileStatement":
|
||||
if (parent.body === node) {
|
||||
state.makeDoWhileBody();
|
||||
} else {
|
||||
assert(parent.test === node);
|
||||
state.makeDoWhileTest(getBooleanValueIfSimpleConstant(node));
|
||||
}
|
||||
break;
|
||||
|
||||
case "ForStatement":
|
||||
if (parent.test === node) {
|
||||
state.makeForTest(getBooleanValueIfSimpleConstant(node));
|
||||
} else if (parent.update === node) {
|
||||
state.makeForUpdate();
|
||||
} else if (parent.body === node) {
|
||||
state.makeForBody();
|
||||
}
|
||||
break;
|
||||
|
||||
case "ForInStatement":
|
||||
case "ForOfStatement":
|
||||
if (parent.left === node) {
|
||||
state.makeForInOfLeft();
|
||||
} else if (parent.right === node) {
|
||||
state.makeForInOfRight();
|
||||
} else {
|
||||
assert(parent.body === node);
|
||||
state.makeForInOfBody();
|
||||
}
|
||||
break;
|
||||
|
||||
case "AssignmentPattern":
|
||||
/*
|
||||
* Fork if this node is at `right`.
|
||||
* `left` is executed always, so it uses the current path.
|
||||
* `popForkContext()` exists at `AssignmentPattern:exit`.
|
||||
*/
|
||||
if (parent.right === node) {
|
||||
state.pushForkContext();
|
||||
state.forkBypassPath();
|
||||
state.forkPath();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the code path due to the type of a given node in entering.
|
||||
* @param {CodePathAnalyzer} analyzer The instance.
|
||||
* @param {ASTNode} node The current AST node.
|
||||
* @returns {void}
|
||||
*/
|
||||
function processCodePathToEnter(analyzer, node) {
|
||||
let codePath = analyzer.codePath;
|
||||
let state = codePath && CodePath.getState(codePath);
|
||||
const parent = node.parent;
|
||||
|
||||
/**
|
||||
* Creates a new code path and trigger the onCodePathStart event
|
||||
* based on the currently selected node.
|
||||
* @param {string} origin The reason the code path was started.
|
||||
* @returns {void}
|
||||
*/
|
||||
function startCodePath(origin) {
|
||||
if (codePath) {
|
||||
// Emits onCodePathSegmentStart events if updated.
|
||||
forwardCurrentToHead(analyzer, node);
|
||||
debug.dumpState(node, state, false);
|
||||
}
|
||||
|
||||
// Create the code path of this scope.
|
||||
codePath = analyzer.codePath = new CodePath({
|
||||
id: analyzer.idGenerator.next(),
|
||||
origin,
|
||||
upper: codePath,
|
||||
onLooped: analyzer.onLooped,
|
||||
});
|
||||
state = CodePath.getState(codePath);
|
||||
|
||||
// Emits onCodePathStart events.
|
||||
debug.dump(`onCodePathStart ${codePath.id}`);
|
||||
analyzer.emit("onCodePathStart", [codePath, node]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Special case: The right side of class field initializer is considered
|
||||
* to be its own function, so we need to start a new code path in this
|
||||
* case.
|
||||
*/
|
||||
if (isPropertyDefinitionValue(node)) {
|
||||
startCodePath("class-field-initializer");
|
||||
|
||||
/*
|
||||
* Intentional fall through because `node` needs to also be
|
||||
* processed by the code below. For example, if we have:
|
||||
*
|
||||
* class Foo {
|
||||
* a = () => {}
|
||||
* }
|
||||
*
|
||||
* In this case, we also need start a second code path.
|
||||
*/
|
||||
}
|
||||
|
||||
switch (node.type) {
|
||||
case "Program":
|
||||
startCodePath("program");
|
||||
break;
|
||||
|
||||
case "FunctionDeclaration":
|
||||
case "FunctionExpression":
|
||||
case "ArrowFunctionExpression":
|
||||
startCodePath("function");
|
||||
break;
|
||||
|
||||
case "StaticBlock":
|
||||
startCodePath("class-static-block");
|
||||
break;
|
||||
|
||||
case "ChainExpression":
|
||||
state.pushChainContext();
|
||||
break;
|
||||
case "CallExpression":
|
||||
if (node.optional === true) {
|
||||
state.makeOptionalNode();
|
||||
}
|
||||
break;
|
||||
case "MemberExpression":
|
||||
if (node.optional === true) {
|
||||
state.makeOptionalNode();
|
||||
}
|
||||
break;
|
||||
|
||||
case "LogicalExpression":
|
||||
if (isHandledLogicalOperator(node.operator)) {
|
||||
state.pushChoiceContext(
|
||||
node.operator,
|
||||
isForkingByTrueOrFalse(node),
|
||||
);
|
||||
}
|
||||
break;
|
||||
|
||||
case "AssignmentExpression":
|
||||
if (isLogicalAssignmentOperator(node.operator)) {
|
||||
state.pushChoiceContext(
|
||||
node.operator.slice(0, -1), // removes `=` from the end
|
||||
isForkingByTrueOrFalse(node),
|
||||
);
|
||||
}
|
||||
break;
|
||||
|
||||
case "ConditionalExpression":
|
||||
case "IfStatement":
|
||||
state.pushChoiceContext("test", false);
|
||||
break;
|
||||
|
||||
case "SwitchStatement":
|
||||
state.pushSwitchContext(
|
||||
node.cases.some(isCaseNode),
|
||||
getLabel(node),
|
||||
);
|
||||
break;
|
||||
|
||||
case "TryStatement":
|
||||
state.pushTryContext(Boolean(node.finalizer));
|
||||
break;
|
||||
|
||||
case "SwitchCase":
|
||||
/*
|
||||
* Fork if this node is after the 2st node in `cases`.
|
||||
* It's similar to `else` blocks.
|
||||
* The next `test` node is processed in this path.
|
||||
*/
|
||||
if (parent.discriminant !== node && parent.cases[0] !== node) {
|
||||
state.forkPath();
|
||||
}
|
||||
break;
|
||||
|
||||
case "WhileStatement":
|
||||
case "DoWhileStatement":
|
||||
case "ForStatement":
|
||||
case "ForInStatement":
|
||||
case "ForOfStatement":
|
||||
state.pushLoopContext(node.type, getLabel(node));
|
||||
break;
|
||||
|
||||
case "LabeledStatement":
|
||||
if (!breakableTypePattern.test(node.body.type)) {
|
||||
state.pushBreakContext(false, node.label.name);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Emits onCodePathSegmentStart events if updated.
|
||||
forwardCurrentToHead(analyzer, node);
|
||||
debug.dumpState(node, state, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the code path due to the type of a given node in leaving.
|
||||
* @param {CodePathAnalyzer} analyzer The instance.
|
||||
* @param {ASTNode} node The current AST node.
|
||||
* @returns {void}
|
||||
*/
|
||||
function processCodePathToExit(analyzer, node) {
|
||||
const codePath = analyzer.codePath;
|
||||
const state = CodePath.getState(codePath);
|
||||
let dontForward = false;
|
||||
|
||||
switch (node.type) {
|
||||
case "ChainExpression":
|
||||
state.popChainContext();
|
||||
break;
|
||||
|
||||
case "IfStatement":
|
||||
case "ConditionalExpression":
|
||||
state.popChoiceContext();
|
||||
break;
|
||||
|
||||
case "LogicalExpression":
|
||||
if (isHandledLogicalOperator(node.operator)) {
|
||||
state.popChoiceContext();
|
||||
}
|
||||
break;
|
||||
|
||||
case "AssignmentExpression":
|
||||
if (isLogicalAssignmentOperator(node.operator)) {
|
||||
state.popChoiceContext();
|
||||
}
|
||||
break;
|
||||
|
||||
case "SwitchStatement":
|
||||
state.popSwitchContext();
|
||||
break;
|
||||
|
||||
case "SwitchCase":
|
||||
/*
|
||||
* This is the same as the process at the 1st `consequent` node in
|
||||
* `preprocess` function.
|
||||
* Must do if this `consequent` is empty.
|
||||
*/
|
||||
if (node.consequent.length === 0) {
|
||||
state.makeSwitchCaseBody(true, !node.test);
|
||||
}
|
||||
if (state.forkContext.reachable) {
|
||||
dontForward = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case "TryStatement":
|
||||
state.popTryContext();
|
||||
break;
|
||||
|
||||
case "BreakStatement":
|
||||
forwardCurrentToHead(analyzer, node);
|
||||
state.makeBreak(node.label && node.label.name);
|
||||
dontForward = true;
|
||||
break;
|
||||
|
||||
case "ContinueStatement":
|
||||
forwardCurrentToHead(analyzer, node);
|
||||
state.makeContinue(node.label && node.label.name);
|
||||
dontForward = true;
|
||||
break;
|
||||
|
||||
case "ReturnStatement":
|
||||
forwardCurrentToHead(analyzer, node);
|
||||
state.makeReturn();
|
||||
dontForward = true;
|
||||
break;
|
||||
|
||||
case "ThrowStatement":
|
||||
forwardCurrentToHead(analyzer, node);
|
||||
state.makeThrow();
|
||||
dontForward = true;
|
||||
break;
|
||||
|
||||
case "Identifier":
|
||||
if (isIdentifierReference(node)) {
|
||||
state.makeFirstThrowablePathInTryBlock();
|
||||
dontForward = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case "CallExpression":
|
||||
case "ImportExpression":
|
||||
case "MemberExpression":
|
||||
case "NewExpression":
|
||||
case "YieldExpression":
|
||||
state.makeFirstThrowablePathInTryBlock();
|
||||
break;
|
||||
|
||||
case "WhileStatement":
|
||||
case "DoWhileStatement":
|
||||
case "ForStatement":
|
||||
case "ForInStatement":
|
||||
case "ForOfStatement":
|
||||
state.popLoopContext();
|
||||
break;
|
||||
|
||||
case "AssignmentPattern":
|
||||
state.popForkContext();
|
||||
break;
|
||||
|
||||
case "LabeledStatement":
|
||||
if (!breakableTypePattern.test(node.body.type)) {
|
||||
state.popBreakContext();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Emits onCodePathSegmentStart events if updated.
|
||||
if (!dontForward) {
|
||||
forwardCurrentToHead(analyzer, node);
|
||||
}
|
||||
debug.dumpState(node, state, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the code path to finalize the current code path.
|
||||
* @param {CodePathAnalyzer} analyzer The instance.
|
||||
* @param {ASTNode} node The current AST node.
|
||||
* @returns {void}
|
||||
*/
|
||||
function postprocess(analyzer, node) {
|
||||
/**
|
||||
* Ends the code path for the current node.
|
||||
* @returns {void}
|
||||
*/
|
||||
function endCodePath() {
|
||||
let codePath = analyzer.codePath;
|
||||
|
||||
// Mark the current path as the final node.
|
||||
CodePath.getState(codePath).makeFinal();
|
||||
|
||||
// Emits onCodePathSegmentEnd event of the current segments.
|
||||
leaveFromCurrentSegment(analyzer, node);
|
||||
|
||||
// Emits onCodePathEnd event of this code path.
|
||||
debug.dump(`onCodePathEnd ${codePath.id}`);
|
||||
analyzer.emit("onCodePathEnd", [codePath, node]);
|
||||
debug.dumpDot(codePath);
|
||||
|
||||
codePath = analyzer.codePath = analyzer.codePath.upper;
|
||||
if (codePath) {
|
||||
debug.dumpState(node, CodePath.getState(codePath), true);
|
||||
}
|
||||
}
|
||||
|
||||
switch (node.type) {
|
||||
case "Program":
|
||||
case "FunctionDeclaration":
|
||||
case "FunctionExpression":
|
||||
case "ArrowFunctionExpression":
|
||||
case "StaticBlock": {
|
||||
endCodePath();
|
||||
break;
|
||||
}
|
||||
|
||||
// The `arguments.length >= 1` case is in `preprocess` function.
|
||||
case "CallExpression":
|
||||
if (node.optional === true && node.arguments.length === 0) {
|
||||
CodePath.getState(analyzer.codePath).makeOptionalRight();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Special case: The right side of class field initializer is considered
|
||||
* to be its own function, so we need to end a code path in this
|
||||
* case.
|
||||
*
|
||||
* We need to check after the other checks in order to close the
|
||||
* code paths in the correct order for code like this:
|
||||
*
|
||||
*
|
||||
* class Foo {
|
||||
* a = () => {}
|
||||
* }
|
||||
*
|
||||
* In this case, The ArrowFunctionExpression code path is closed first
|
||||
* and then we need to close the code path for the PropertyDefinition
|
||||
* value.
|
||||
*/
|
||||
if (isPropertyDefinitionValue(node)) {
|
||||
endCodePath();
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Public Interface
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* The class to analyze code paths.
|
||||
* This class implements the EventGenerator interface.
|
||||
*/
|
||||
class CodePathAnalyzer {
|
||||
/**
|
||||
* @param {EventGenerator} eventGenerator An event generator to wrap.
|
||||
*/
|
||||
constructor(eventGenerator) {
|
||||
this.original = eventGenerator;
|
||||
this.emit = eventGenerator.emit;
|
||||
this.codePath = null;
|
||||
this.idGenerator = new IdGenerator("s");
|
||||
this.currentNode = null;
|
||||
this.onLooped = this.onLooped.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the process to enter a given AST node.
|
||||
* This updates state of analysis and calls `enterNode` of the wrapped.
|
||||
* @param {ASTNode} node A node which is entering.
|
||||
* @returns {void}
|
||||
*/
|
||||
enterNode(node) {
|
||||
this.currentNode = node;
|
||||
|
||||
// Updates the code path due to node's position in its parent node.
|
||||
if (node.parent) {
|
||||
preprocess(this, node);
|
||||
}
|
||||
|
||||
/*
|
||||
* Updates the code path.
|
||||
* And emits onCodePathStart/onCodePathSegmentStart events.
|
||||
*/
|
||||
processCodePathToEnter(this, node);
|
||||
|
||||
// Emits node events.
|
||||
this.original.enterNode(node);
|
||||
|
||||
this.currentNode = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the process to leave a given AST node.
|
||||
* This updates state of analysis and calls `leaveNode` of the wrapped.
|
||||
* @param {ASTNode} node A node which is leaving.
|
||||
* @returns {void}
|
||||
*/
|
||||
leaveNode(node) {
|
||||
this.currentNode = node;
|
||||
|
||||
/*
|
||||
* Updates the code path.
|
||||
* And emits onCodePathStart/onCodePathSegmentStart events.
|
||||
*/
|
||||
processCodePathToExit(this, node);
|
||||
|
||||
// Emits node events.
|
||||
this.original.leaveNode(node);
|
||||
|
||||
// Emits the last onCodePathStart/onCodePathSegmentStart events.
|
||||
postprocess(this, node);
|
||||
|
||||
this.currentNode = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is called on a code path looped.
|
||||
* Then this raises a looped event.
|
||||
* @param {CodePathSegment} fromSegment A segment of prev.
|
||||
* @param {CodePathSegment} toSegment A segment of next.
|
||||
* @returns {void}
|
||||
*/
|
||||
onLooped(fromSegment, toSegment) {
|
||||
if (fromSegment.reachable && toSegment.reachable) {
|
||||
debug.dump(
|
||||
`onCodePathSegmentLoop ${fromSegment.id} -> ${toSegment.id}`,
|
||||
);
|
||||
this.emit("onCodePathSegmentLoop", [
|
||||
fromSegment,
|
||||
toSegment,
|
||||
this.currentNode,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = CodePathAnalyzer;
|
||||
262
slider/node_modules/eslint/lib/linter/code-path-analysis/code-path-segment.js
generated
vendored
Normal file
262
slider/node_modules/eslint/lib/linter/code-path-analysis/code-path-segment.js
generated
vendored
Normal file
@@ -0,0 +1,262 @@
|
||||
/**
|
||||
* @fileoverview The CodePathSegment class.
|
||||
* @author Toru Nagashima
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const debug = require("./debug-helpers");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Checks whether or not a given segment is reachable.
|
||||
* @param {CodePathSegment} segment A segment to check.
|
||||
* @returns {boolean} `true` if the segment is reachable.
|
||||
*/
|
||||
function isReachable(segment) {
|
||||
return segment.reachable;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Public Interface
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* A code path segment.
|
||||
*
|
||||
* Each segment is arranged in a series of linked lists (implemented by arrays)
|
||||
* that keep track of the previous and next segments in a code path. In this way,
|
||||
* you can navigate between all segments in any code path so long as you have a
|
||||
* reference to any segment in that code path.
|
||||
*
|
||||
* When first created, the segment is in a detached state, meaning that it knows the
|
||||
* segments that came before it but those segments don't know that this new segment
|
||||
* follows it. Only when `CodePathSegment#markUsed()` is called on a segment does it
|
||||
* officially become part of the code path by updating the previous segments to know
|
||||
* that this new segment follows.
|
||||
*/
|
||||
class CodePathSegment {
|
||||
/**
|
||||
* Creates a new instance.
|
||||
* @param {string} id An identifier.
|
||||
* @param {CodePathSegment[]} allPrevSegments An array of the previous segments.
|
||||
* This array includes unreachable segments.
|
||||
* @param {boolean} reachable A flag which shows this is reachable.
|
||||
*/
|
||||
constructor(id, allPrevSegments, reachable) {
|
||||
/**
|
||||
* The identifier of this code path.
|
||||
* Rules use it to store additional information of each rule.
|
||||
* @type {string}
|
||||
*/
|
||||
this.id = id;
|
||||
|
||||
/**
|
||||
* An array of the next reachable segments.
|
||||
* @type {CodePathSegment[]}
|
||||
*/
|
||||
this.nextSegments = [];
|
||||
|
||||
/**
|
||||
* An array of the previous reachable segments.
|
||||
* @type {CodePathSegment[]}
|
||||
*/
|
||||
this.prevSegments = allPrevSegments.filter(isReachable);
|
||||
|
||||
/**
|
||||
* An array of all next segments including reachable and unreachable.
|
||||
* @type {CodePathSegment[]}
|
||||
*/
|
||||
this.allNextSegments = [];
|
||||
|
||||
/**
|
||||
* An array of all previous segments including reachable and unreachable.
|
||||
* @type {CodePathSegment[]}
|
||||
*/
|
||||
this.allPrevSegments = allPrevSegments;
|
||||
|
||||
/**
|
||||
* A flag which shows this is reachable.
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.reachable = reachable;
|
||||
|
||||
// Internal data.
|
||||
Object.defineProperty(this, "internal", {
|
||||
value: {
|
||||
// determines if the segment has been attached to the code path
|
||||
used: false,
|
||||
|
||||
// array of previous segments coming from the end of a loop
|
||||
loopedPrevSegments: [],
|
||||
},
|
||||
});
|
||||
|
||||
/* c8 ignore start */
|
||||
if (debug.enabled) {
|
||||
this.internal.nodes = [];
|
||||
} /* c8 ignore stop */
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks a given previous segment is coming from the end of a loop.
|
||||
* @param {CodePathSegment} segment A previous segment to check.
|
||||
* @returns {boolean} `true` if the segment is coming from the end of a loop.
|
||||
*/
|
||||
isLoopedPrevSegment(segment) {
|
||||
return this.internal.loopedPrevSegments.includes(segment);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the root segment.
|
||||
* @param {string} id An identifier.
|
||||
* @returns {CodePathSegment} The created segment.
|
||||
*/
|
||||
static newRoot(id) {
|
||||
return new CodePathSegment(id, [], true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new segment and appends it after the given segments.
|
||||
* @param {string} id An identifier.
|
||||
* @param {CodePathSegment[]} allPrevSegments An array of the previous segments
|
||||
* to append to.
|
||||
* @returns {CodePathSegment} The created segment.
|
||||
*/
|
||||
static newNext(id, allPrevSegments) {
|
||||
return new CodePathSegment(
|
||||
id,
|
||||
CodePathSegment.flattenUnusedSegments(allPrevSegments),
|
||||
allPrevSegments.some(isReachable),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an unreachable segment and appends it after the given segments.
|
||||
* @param {string} id An identifier.
|
||||
* @param {CodePathSegment[]} allPrevSegments An array of the previous segments.
|
||||
* @returns {CodePathSegment} The created segment.
|
||||
*/
|
||||
static newUnreachable(id, allPrevSegments) {
|
||||
const segment = new CodePathSegment(
|
||||
id,
|
||||
CodePathSegment.flattenUnusedSegments(allPrevSegments),
|
||||
false,
|
||||
);
|
||||
|
||||
/*
|
||||
* In `if (a) return a; foo();` case, the unreachable segment preceded by
|
||||
* the return statement is not used but must not be removed.
|
||||
*/
|
||||
CodePathSegment.markUsed(segment);
|
||||
|
||||
return segment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a segment that follows given segments.
|
||||
* This factory method does not connect with `allPrevSegments`.
|
||||
* But this inherits `reachable` flag.
|
||||
* @param {string} id An identifier.
|
||||
* @param {CodePathSegment[]} allPrevSegments An array of the previous segments.
|
||||
* @returns {CodePathSegment} The created segment.
|
||||
*/
|
||||
static newDisconnected(id, allPrevSegments) {
|
||||
return new CodePathSegment(id, [], allPrevSegments.some(isReachable));
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks a given segment as used.
|
||||
*
|
||||
* And this function registers the segment into the previous segments as a next.
|
||||
* @param {CodePathSegment} segment A segment to mark.
|
||||
* @returns {void}
|
||||
*/
|
||||
static markUsed(segment) {
|
||||
if (segment.internal.used) {
|
||||
return;
|
||||
}
|
||||
segment.internal.used = true;
|
||||
|
||||
let i;
|
||||
|
||||
if (segment.reachable) {
|
||||
/*
|
||||
* If the segment is reachable, then it's officially part of the
|
||||
* code path. This loops through all previous segments to update
|
||||
* their list of next segments. Because the segment is reachable,
|
||||
* it's added to both `nextSegments` and `allNextSegments`.
|
||||
*/
|
||||
for (i = 0; i < segment.allPrevSegments.length; ++i) {
|
||||
const prevSegment = segment.allPrevSegments[i];
|
||||
|
||||
prevSegment.allNextSegments.push(segment);
|
||||
prevSegment.nextSegments.push(segment);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* If the segment is not reachable, then it's not officially part of the
|
||||
* code path. This loops through all previous segments to update
|
||||
* their list of next segments. Because the segment is not reachable,
|
||||
* it's added only to `allNextSegments`.
|
||||
*/
|
||||
for (i = 0; i < segment.allPrevSegments.length; ++i) {
|
||||
segment.allPrevSegments[i].allNextSegments.push(segment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks a previous segment as looped.
|
||||
* @param {CodePathSegment} segment A segment.
|
||||
* @param {CodePathSegment} prevSegment A previous segment to mark.
|
||||
* @returns {void}
|
||||
*/
|
||||
static markPrevSegmentAsLooped(segment, prevSegment) {
|
||||
segment.internal.loopedPrevSegments.push(prevSegment);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new array based on an array of segments. If any segment in the
|
||||
* array is unused, then it is replaced by all of its previous segments.
|
||||
* All used segments are returned as-is without replacement.
|
||||
* @param {CodePathSegment[]} segments The array of segments to flatten.
|
||||
* @returns {CodePathSegment[]} The flattened array.
|
||||
*/
|
||||
static flattenUnusedSegments(segments) {
|
||||
const done = new Set();
|
||||
|
||||
for (let i = 0; i < segments.length; ++i) {
|
||||
const segment = segments[i];
|
||||
|
||||
// Ignores duplicated.
|
||||
if (done.has(segment)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Use previous segments if unused.
|
||||
if (!segment.internal.used) {
|
||||
for (let j = 0; j < segment.allPrevSegments.length; ++j) {
|
||||
const prevSegment = segment.allPrevSegments[j];
|
||||
|
||||
if (!done.has(prevSegment)) {
|
||||
done.add(prevSegment);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
done.add(segment);
|
||||
}
|
||||
}
|
||||
|
||||
return [...done];
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = CodePathSegment;
|
||||
2370
slider/node_modules/eslint/lib/linter/code-path-analysis/code-path-state.js
generated
vendored
Normal file
2370
slider/node_modules/eslint/lib/linter/code-path-analysis/code-path-state.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
332
slider/node_modules/eslint/lib/linter/code-path-analysis/code-path.js
generated
vendored
Normal file
332
slider/node_modules/eslint/lib/linter/code-path-analysis/code-path.js
generated
vendored
Normal file
@@ -0,0 +1,332 @@
|
||||
/**
|
||||
* @fileoverview A class of the code path.
|
||||
* @author Toru Nagashima
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const CodePathState = require("./code-path-state");
|
||||
const IdGenerator = require("./id-generator");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Public Interface
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* A code path.
|
||||
*/
|
||||
class CodePath {
|
||||
/**
|
||||
* Creates a new instance.
|
||||
* @param {Object} options Options for the function (see below).
|
||||
* @param {string} options.id An identifier.
|
||||
* @param {string} options.origin The type of code path origin.
|
||||
* @param {CodePath|null} options.upper The code path of the upper function scope.
|
||||
* @param {Function} options.onLooped A callback function to notify looping.
|
||||
*/
|
||||
constructor({ id, origin, upper, onLooped }) {
|
||||
/**
|
||||
* The identifier of this code path.
|
||||
* Rules use it to store additional information of each rule.
|
||||
* @type {string}
|
||||
*/
|
||||
this.id = id;
|
||||
|
||||
/**
|
||||
* The reason that this code path was started. May be "program",
|
||||
* "function", "class-field-initializer", or "class-static-block".
|
||||
* @type {string}
|
||||
*/
|
||||
this.origin = origin;
|
||||
|
||||
/**
|
||||
* The code path of the upper function scope.
|
||||
* @type {CodePath|null}
|
||||
*/
|
||||
this.upper = upper;
|
||||
|
||||
/**
|
||||
* The code paths of nested function scopes.
|
||||
* @type {CodePath[]}
|
||||
*/
|
||||
this.childCodePaths = [];
|
||||
|
||||
// Initializes internal state.
|
||||
Object.defineProperty(this, "internal", {
|
||||
value: new CodePathState(new IdGenerator(`${id}_`), onLooped),
|
||||
});
|
||||
|
||||
// Adds this into `childCodePaths` of `upper`.
|
||||
if (upper) {
|
||||
upper.childCodePaths.push(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the state of a given code path.
|
||||
* @param {CodePath} codePath A code path to get.
|
||||
* @returns {CodePathState} The state of the code path.
|
||||
*/
|
||||
static getState(codePath) {
|
||||
return codePath.internal;
|
||||
}
|
||||
|
||||
/**
|
||||
* The initial code path segment. This is the segment that is at the head
|
||||
* of the code path.
|
||||
* This is a passthrough to the underlying `CodePathState`.
|
||||
* @type {CodePathSegment}
|
||||
*/
|
||||
get initialSegment() {
|
||||
return this.internal.initialSegment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Final code path segments. These are the terminal (tail) segments in the
|
||||
* code path, which is the combination of `returnedSegments` and `thrownSegments`.
|
||||
* All segments in this array are reachable.
|
||||
* This is a passthrough to the underlying `CodePathState`.
|
||||
* @type {CodePathSegment[]}
|
||||
*/
|
||||
get finalSegments() {
|
||||
return this.internal.finalSegments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Final code path segments that represent normal completion of the code path.
|
||||
* For functions, this means both explicit `return` statements and implicit returns,
|
||||
* such as the last reachable segment in a function that does not have an
|
||||
* explicit `return` as this implicitly returns `undefined`. For scripts,
|
||||
* modules, class field initializers, and class static blocks, this means
|
||||
* all lines of code have been executed.
|
||||
* These segments are also present in `finalSegments`.
|
||||
* This is a passthrough to the underlying `CodePathState`.
|
||||
* @type {CodePathSegment[]}
|
||||
*/
|
||||
get returnedSegments() {
|
||||
return this.internal.returnedForkContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Final code path segments that represent `throw` statements.
|
||||
* This is a passthrough to the underlying `CodePathState`.
|
||||
* These segments are also present in `finalSegments`.
|
||||
* @type {CodePathSegment[]}
|
||||
*/
|
||||
get thrownSegments() {
|
||||
return this.internal.thrownForkContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Traverses all segments in this code path.
|
||||
*
|
||||
* codePath.traverseSegments((segment, controller) => {
|
||||
* // do something.
|
||||
* });
|
||||
*
|
||||
* This method enumerates segments in order from the head.
|
||||
*
|
||||
* The `controller` argument has two methods:
|
||||
*
|
||||
* - `skip()` - skips the following segments in this branch
|
||||
* - `break()` - skips all following segments in the traversal
|
||||
*
|
||||
* A note on the parameters: the `options` argument is optional. This means
|
||||
* the first argument might be an options object or the callback function.
|
||||
* @param {Object} [optionsOrCallback] Optional first and last segments to traverse.
|
||||
* @param {CodePathSegment} [optionsOrCallback.first] The first segment to traverse.
|
||||
* @param {CodePathSegment} [optionsOrCallback.last] The last segment to traverse.
|
||||
* @param {Function} callback A callback function.
|
||||
* @returns {void}
|
||||
*/
|
||||
traverseSegments(optionsOrCallback, callback) {
|
||||
// normalize the arguments into a callback and options
|
||||
let resolvedOptions;
|
||||
let resolvedCallback;
|
||||
|
||||
if (typeof optionsOrCallback === "function") {
|
||||
resolvedCallback = optionsOrCallback;
|
||||
resolvedOptions = {};
|
||||
} else {
|
||||
resolvedOptions = optionsOrCallback || {};
|
||||
resolvedCallback = callback;
|
||||
}
|
||||
|
||||
// determine where to start traversing from based on the options
|
||||
const startSegment =
|
||||
resolvedOptions.first || this.internal.initialSegment;
|
||||
const lastSegment = resolvedOptions.last;
|
||||
|
||||
// set up initial location information
|
||||
let record;
|
||||
let index;
|
||||
let end;
|
||||
let segment = null;
|
||||
|
||||
// segments that have already been visited during traversal
|
||||
const visited = new Set();
|
||||
|
||||
// tracks the traversal steps
|
||||
const stack = [[startSegment, 0]];
|
||||
|
||||
// segments that have been skipped during traversal
|
||||
const skipped = new Set();
|
||||
|
||||
// indicates if we exited early from the traversal
|
||||
let broken = false;
|
||||
|
||||
/**
|
||||
* Maintains traversal state.
|
||||
*/
|
||||
const controller = {
|
||||
/**
|
||||
* Skip the following segments in this branch.
|
||||
* @returns {void}
|
||||
*/
|
||||
skip() {
|
||||
skipped.add(segment);
|
||||
},
|
||||
|
||||
/**
|
||||
* Stop traversal completely - do not traverse to any
|
||||
* other segments.
|
||||
* @returns {void}
|
||||
*/
|
||||
break() {
|
||||
broken = true;
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks if a given previous segment has been visited.
|
||||
* @param {CodePathSegment} prevSegment A previous segment to check.
|
||||
* @returns {boolean} `true` if the segment has been visited.
|
||||
*/
|
||||
function isVisited(prevSegment) {
|
||||
return (
|
||||
visited.has(prevSegment) ||
|
||||
segment.isLoopedPrevSegment(prevSegment)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a given previous segment has been skipped.
|
||||
* @param {CodePathSegment} prevSegment A previous segment to check.
|
||||
* @returns {boolean} `true` if the segment has been skipped.
|
||||
*/
|
||||
function isSkipped(prevSegment) {
|
||||
return (
|
||||
skipped.has(prevSegment) ||
|
||||
segment.isLoopedPrevSegment(prevSegment)
|
||||
);
|
||||
}
|
||||
|
||||
// the traversal
|
||||
while (stack.length > 0) {
|
||||
/*
|
||||
* This isn't a pure stack. We use the top record all the time
|
||||
* but don't always pop it off. The record is popped only if
|
||||
* one of the following is true:
|
||||
*
|
||||
* 1) We have already visited the segment.
|
||||
* 2) We have not visited *all* of the previous segments.
|
||||
* 3) We have traversed past the available next segments.
|
||||
*
|
||||
* Otherwise, we just read the value and sometimes modify the
|
||||
* record as we traverse.
|
||||
*/
|
||||
record = stack.at(-1);
|
||||
segment = record[0];
|
||||
index = record[1];
|
||||
|
||||
if (index === 0) {
|
||||
// Skip if this segment has been visited already.
|
||||
if (visited.has(segment)) {
|
||||
stack.pop();
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip if all previous segments have not been visited.
|
||||
if (
|
||||
segment !== startSegment &&
|
||||
segment.prevSegments.length > 0 &&
|
||||
!segment.prevSegments.every(isVisited)
|
||||
) {
|
||||
stack.pop();
|
||||
continue;
|
||||
}
|
||||
|
||||
visited.add(segment);
|
||||
|
||||
// Skips the segment if all previous segments have been skipped.
|
||||
const shouldSkip =
|
||||
skipped.size > 0 &&
|
||||
segment.prevSegments.length > 0 &&
|
||||
segment.prevSegments.every(isSkipped);
|
||||
|
||||
/*
|
||||
* If the most recent segment hasn't been skipped, then we call
|
||||
* the callback, passing in the segment and the controller.
|
||||
*/
|
||||
if (!shouldSkip) {
|
||||
resolvedCallback.call(this, segment, controller);
|
||||
|
||||
// exit if we're at the last segment
|
||||
if (segment === lastSegment) {
|
||||
controller.skip();
|
||||
}
|
||||
|
||||
/*
|
||||
* If the previous statement was executed, or if the callback
|
||||
* called a method on the controller, we might need to exit the
|
||||
* loop, so check for that and break accordingly.
|
||||
*/
|
||||
if (broken) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// If the most recent segment has been skipped, then mark it as skipped.
|
||||
skipped.add(segment);
|
||||
}
|
||||
}
|
||||
|
||||
// Update the stack.
|
||||
end = segment.nextSegments.length - 1;
|
||||
if (index < end) {
|
||||
/*
|
||||
* If we haven't yet visited all of the next segments, update
|
||||
* the current top record on the stack to the next index to visit
|
||||
* and then push a record for the current segment on top.
|
||||
*
|
||||
* Setting the current top record's index lets us know how many
|
||||
* times we've been here and ensures that the segment won't be
|
||||
* reprocessed (because we only process segments with an index
|
||||
* of 0).
|
||||
*/
|
||||
record[1] += 1;
|
||||
stack.push([segment.nextSegments[index], 0]);
|
||||
} else if (index === end) {
|
||||
/*
|
||||
* If we are at the last next segment, then reset the top record
|
||||
* in the stack to next segment and set its index to 0 so it will
|
||||
* be processed next.
|
||||
*/
|
||||
record[0] = segment.nextSegments[index];
|
||||
record[1] = 0;
|
||||
} else {
|
||||
/*
|
||||
* If index > end, that means we have no more segments that need
|
||||
* processing. So, we pop that record off of the stack in order to
|
||||
* continue traversing at the next level up.
|
||||
*/
|
||||
stack.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = CodePath;
|
||||
223
slider/node_modules/eslint/lib/linter/code-path-analysis/debug-helpers.js
generated
vendored
Normal file
223
slider/node_modules/eslint/lib/linter/code-path-analysis/debug-helpers.js
generated
vendored
Normal file
@@ -0,0 +1,223 @@
|
||||
/**
|
||||
* @fileoverview Helpers to debug for code path analysis.
|
||||
* @author Toru Nagashima
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const debug = require("debug")("eslint:code-path");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Gets id of a given segment.
|
||||
* @param {CodePathSegment} segment A segment to get.
|
||||
* @returns {string} Id of the segment.
|
||||
*/
|
||||
/* c8 ignore next */
|
||||
// eslint-disable-next-line jsdoc/require-jsdoc -- Ignoring
|
||||
function getId(segment) {
|
||||
return segment.id + (segment.reachable ? "" : "!");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get string for the given node and operation.
|
||||
* @param {ASTNode} node The node to convert.
|
||||
* @param {"enter" | "exit" | undefined} label The operation label.
|
||||
* @returns {string} The string representation.
|
||||
*/
|
||||
function nodeToString(node, label) {
|
||||
const suffix = label ? `:${label}` : "";
|
||||
|
||||
switch (node.type) {
|
||||
case "Identifier":
|
||||
return `${node.type}${suffix} (${node.name})`;
|
||||
case "Literal":
|
||||
return `${node.type}${suffix} (${node.value})`;
|
||||
default:
|
||||
return `${node.type}${suffix}`;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Public Interface
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
/**
|
||||
* A flag that debug dumping is enabled or not.
|
||||
* @type {boolean}
|
||||
*/
|
||||
enabled: debug.enabled,
|
||||
|
||||
/**
|
||||
* Dumps given objects.
|
||||
* @param {...any} args objects to dump.
|
||||
* @returns {void}
|
||||
*/
|
||||
dump: debug,
|
||||
|
||||
/**
|
||||
* Dumps the current analyzing state.
|
||||
* @param {ASTNode} node A node to dump.
|
||||
* @param {CodePathState} state A state to dump.
|
||||
* @param {boolean} leaving A flag whether or not it's leaving
|
||||
* @returns {void}
|
||||
*/
|
||||
dumpState: !debug.enabled
|
||||
? debug
|
||||
: /* c8 ignore next */ function (node, state, leaving) {
|
||||
for (let i = 0; i < state.currentSegments.length; ++i) {
|
||||
const segInternal = state.currentSegments[i].internal;
|
||||
|
||||
if (leaving) {
|
||||
const last = segInternal.nodes.length - 1;
|
||||
|
||||
if (
|
||||
last >= 0 &&
|
||||
segInternal.nodes[last] ===
|
||||
nodeToString(node, "enter")
|
||||
) {
|
||||
segInternal.nodes[last] = nodeToString(
|
||||
node,
|
||||
void 0,
|
||||
);
|
||||
} else {
|
||||
segInternal.nodes.push(nodeToString(node, "exit"));
|
||||
}
|
||||
} else {
|
||||
segInternal.nodes.push(nodeToString(node, "enter"));
|
||||
}
|
||||
}
|
||||
|
||||
debug(
|
||||
[
|
||||
`${state.currentSegments.map(getId).join(",")})`,
|
||||
`${node.type}${leaving ? ":exit" : ""}`,
|
||||
].join(" "),
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Dumps a DOT code of a given code path.
|
||||
* The DOT code can be visualized with Graphvis.
|
||||
* @param {CodePath} codePath A code path to dump.
|
||||
* @returns {void}
|
||||
* @see http://www.graphviz.org
|
||||
* @see http://www.webgraphviz.com
|
||||
*/
|
||||
dumpDot: !debug.enabled
|
||||
? debug
|
||||
: /* c8 ignore next */ function (codePath) {
|
||||
let text =
|
||||
"\n" +
|
||||
"digraph {\n" +
|
||||
'node[shape=box,style="rounded,filled",fillcolor=white];\n' +
|
||||
'initial[label="",shape=circle,style=filled,fillcolor=black,width=0.25,height=0.25];\n';
|
||||
|
||||
if (codePath.returnedSegments.length > 0) {
|
||||
text +=
|
||||
'final[label="",shape=doublecircle,style=filled,fillcolor=black,width=0.25,height=0.25];\n';
|
||||
}
|
||||
if (codePath.thrownSegments.length > 0) {
|
||||
text +=
|
||||
'thrown[label="✘",shape=circle,width=0.3,height=0.3,fixedsize=true];\n';
|
||||
}
|
||||
|
||||
const traceMap = Object.create(null);
|
||||
const arrows = this.makeDotArrows(codePath, traceMap);
|
||||
|
||||
// eslint-disable-next-line guard-for-in -- Want ability to traverse prototype
|
||||
for (const id in traceMap) {
|
||||
const segment = traceMap[id];
|
||||
|
||||
text += `${id}[`;
|
||||
|
||||
if (segment.reachable) {
|
||||
text += 'label="';
|
||||
} else {
|
||||
text +=
|
||||
'style="rounded,dashed,filled",fillcolor="#FF9800",label="<<unreachable>>\\n';
|
||||
}
|
||||
|
||||
if (segment.internal.nodes.length > 0) {
|
||||
text += segment.internal.nodes.join("\\n");
|
||||
} else {
|
||||
text += "????";
|
||||
}
|
||||
|
||||
text += '"];\n';
|
||||
}
|
||||
|
||||
text += `${arrows}\n`;
|
||||
text += "}";
|
||||
debug("DOT", text);
|
||||
},
|
||||
|
||||
/**
|
||||
* Makes a DOT code of a given code path.
|
||||
* The DOT code can be visualized with Graphvis.
|
||||
* @param {CodePath} codePath A code path to make DOT.
|
||||
* @param {Object} traceMap Optional. A map to check whether or not segments had been done.
|
||||
* @returns {string} A DOT code of the code path.
|
||||
*/
|
||||
makeDotArrows(codePath, traceMap) {
|
||||
const stack = [[codePath.initialSegment, 0]];
|
||||
const done = traceMap || Object.create(null);
|
||||
let lastId = codePath.initialSegment.id;
|
||||
let text = `initial->${codePath.initialSegment.id}`;
|
||||
|
||||
while (stack.length > 0) {
|
||||
const item = stack.pop();
|
||||
const segment = item[0];
|
||||
const index = item[1];
|
||||
|
||||
if (done[segment.id] && index === 0) {
|
||||
continue;
|
||||
}
|
||||
done[segment.id] = segment;
|
||||
|
||||
const nextSegment = segment.allNextSegments[index];
|
||||
|
||||
if (!nextSegment) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (lastId === segment.id) {
|
||||
text += `->${nextSegment.id}`;
|
||||
} else {
|
||||
text += `;\n${segment.id}->${nextSegment.id}`;
|
||||
}
|
||||
lastId = nextSegment.id;
|
||||
|
||||
stack.unshift([segment, 1 + index]);
|
||||
stack.push([nextSegment, 0]);
|
||||
}
|
||||
|
||||
codePath.returnedSegments.forEach(finalSegment => {
|
||||
if (lastId === finalSegment.id) {
|
||||
text += "->final";
|
||||
} else {
|
||||
text += `;\n${finalSegment.id}->final`;
|
||||
}
|
||||
lastId = null;
|
||||
});
|
||||
|
||||
codePath.thrownSegments.forEach(finalSegment => {
|
||||
if (lastId === finalSegment.id) {
|
||||
text += "->thrown";
|
||||
} else {
|
||||
text += `;\n${finalSegment.id}->thrown`;
|
||||
}
|
||||
lastId = null;
|
||||
});
|
||||
|
||||
return `${text};`;
|
||||
},
|
||||
};
|
||||
374
slider/node_modules/eslint/lib/linter/code-path-analysis/fork-context.js
generated
vendored
Normal file
374
slider/node_modules/eslint/lib/linter/code-path-analysis/fork-context.js
generated
vendored
Normal file
@@ -0,0 +1,374 @@
|
||||
/**
|
||||
* @fileoverview A class to operate forking.
|
||||
*
|
||||
* This is state of forking.
|
||||
* This has a fork list and manages it.
|
||||
*
|
||||
* @author Toru Nagashima
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const assert = require("../../shared/assert"),
|
||||
CodePathSegment = require("./code-path-segment");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Determines whether or not a given segment is reachable.
|
||||
* @param {CodePathSegment} segment The segment to check.
|
||||
* @returns {boolean} `true` if the segment is reachable.
|
||||
*/
|
||||
function isReachable(segment) {
|
||||
return segment.reachable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new segment for each fork in the given context and appends it
|
||||
* to the end of the specified range of segments. Ultimately, this ends up calling
|
||||
* `new CodePathSegment()` for each of the forks using the `create` argument
|
||||
* as a wrapper around special behavior.
|
||||
*
|
||||
* The `startIndex` and `endIndex` arguments specify a range of segments in
|
||||
* `context` that should become `allPrevSegments` for the newly created
|
||||
* `CodePathSegment` objects.
|
||||
*
|
||||
* When `context.segmentsList` is `[[a, b], [c, d], [e, f]]`, `begin` is `0`, and
|
||||
* `end` is `-1`, this creates two new segments, `[g, h]`. This `g` is appended to
|
||||
* the end of the path from `a`, `c`, and `e`. This `h` is appended to the end of
|
||||
* `b`, `d`, and `f`.
|
||||
* @param {ForkContext} context An instance from which the previous segments
|
||||
* will be obtained.
|
||||
* @param {number} startIndex The index of the first segment in the context
|
||||
* that should be specified as previous segments for the newly created segments.
|
||||
* @param {number} endIndex The index of the last segment in the context
|
||||
* that should be specified as previous segments for the newly created segments.
|
||||
* @param {Function} create A function that creates new `CodePathSegment`
|
||||
* instances in a particular way. See the `CodePathSegment.new*` methods.
|
||||
* @returns {Array<CodePathSegment>} An array of the newly-created segments.
|
||||
*/
|
||||
function createSegments(context, startIndex, endIndex, create) {
|
||||
/** @type {Array<Array<CodePathSegment>>} */
|
||||
const list = context.segmentsList;
|
||||
|
||||
/*
|
||||
* Both `startIndex` and `endIndex` work the same way: if the number is zero
|
||||
* or more, then the number is used as-is. If the number is negative,
|
||||
* then that number is added to the length of the segments list to
|
||||
* determine the index to use. That means -1 for either argument
|
||||
* is the last element, -2 is the second to last, and so on.
|
||||
*
|
||||
* So if `startIndex` is 0, `endIndex` is -1, and `list.length` is 3, the
|
||||
* effective `startIndex` is 0 and the effective `endIndex` is 2, so this function
|
||||
* will include items at indices 0, 1, and 2.
|
||||
*
|
||||
* Therefore, if `startIndex` is -1 and `endIndex` is -1, that means we'll only
|
||||
* be using the last segment in `list`.
|
||||
*/
|
||||
const normalizedBegin =
|
||||
startIndex >= 0 ? startIndex : list.length + startIndex;
|
||||
const normalizedEnd = endIndex >= 0 ? endIndex : list.length + endIndex;
|
||||
|
||||
/** @type {Array<CodePathSegment>} */
|
||||
const segments = [];
|
||||
|
||||
for (let i = 0; i < context.count; ++i) {
|
||||
// this is passed into `new CodePathSegment` to add to code path.
|
||||
const allPrevSegments = [];
|
||||
|
||||
for (let j = normalizedBegin; j <= normalizedEnd; ++j) {
|
||||
allPrevSegments.push(list[j][i]);
|
||||
}
|
||||
|
||||
// note: `create` is just a wrapper that augments `new CodePathSegment`.
|
||||
segments.push(create(context.idGenerator.next(), allPrevSegments));
|
||||
}
|
||||
|
||||
return segments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inside of a `finally` block we end up with two parallel paths. If the code path
|
||||
* exits by a control statement (such as `break` or `continue`) from the `finally`
|
||||
* block, then we need to merge the remaining parallel paths back into one.
|
||||
* @param {ForkContext} context The fork context to work on.
|
||||
* @param {Array<CodePathSegment>} segments Segments to merge.
|
||||
* @returns {Array<CodePathSegment>} The merged segments.
|
||||
*/
|
||||
function mergeExtraSegments(context, segments) {
|
||||
let currentSegments = segments;
|
||||
|
||||
/*
|
||||
* We need to ensure that the array returned from this function contains no more
|
||||
* than the number of segments that the context allows. `context.count` indicates
|
||||
* how many items should be in the returned array to ensure that the new segment
|
||||
* entries will line up with the already existing segment entries.
|
||||
*/
|
||||
while (currentSegments.length > context.count) {
|
||||
const merged = [];
|
||||
|
||||
/*
|
||||
* Because `context.count` is a factor of 2 inside of a `finally` block,
|
||||
* we can divide the segment count by 2 to merge the paths together.
|
||||
* This loops through each segment in the list and creates a new `CodePathSegment`
|
||||
* that has the segment and the segment two slots away as previous segments.
|
||||
*
|
||||
* If `currentSegments` is [a,b,c,d], this will create new segments e and f, such
|
||||
* that:
|
||||
*
|
||||
* When `i` is 0:
|
||||
* a->e
|
||||
* c->e
|
||||
*
|
||||
* When `i` is 1:
|
||||
* b->f
|
||||
* d->f
|
||||
*/
|
||||
for (
|
||||
let i = 0, length = Math.floor(currentSegments.length / 2);
|
||||
i < length;
|
||||
++i
|
||||
) {
|
||||
merged.push(
|
||||
CodePathSegment.newNext(context.idGenerator.next(), [
|
||||
currentSegments[i],
|
||||
currentSegments[i + length],
|
||||
]),
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* Go through the loop condition one more time to see if we have the
|
||||
* number of segments for the context. If not, we'll keep merging paths
|
||||
* of the merged segments until we get there.
|
||||
*/
|
||||
currentSegments = merged;
|
||||
}
|
||||
|
||||
return currentSegments;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Public Interface
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Manages the forking of code paths.
|
||||
*/
|
||||
class ForkContext {
|
||||
/**
|
||||
* Creates a new instance.
|
||||
* @param {IdGenerator} idGenerator An identifier generator for segments.
|
||||
* @param {ForkContext|null} upper The preceding fork context.
|
||||
* @param {number} count The number of parallel segments in each element
|
||||
* of `segmentsList`.
|
||||
*/
|
||||
constructor(idGenerator, upper, count) {
|
||||
/**
|
||||
* The ID generator that will generate segment IDs for any new
|
||||
* segments that are created.
|
||||
* @type {IdGenerator}
|
||||
*/
|
||||
this.idGenerator = idGenerator;
|
||||
|
||||
/**
|
||||
* The preceding fork context.
|
||||
* @type {ForkContext|null}
|
||||
*/
|
||||
this.upper = upper;
|
||||
|
||||
/**
|
||||
* The number of elements in each element of `segmentsList`. In most
|
||||
* cases, this is 1 but can be 2 when there is a `finally` present,
|
||||
* which forks the code path outside of normal flow. In the case of nested
|
||||
* `finally` blocks, this can be a multiple of 2.
|
||||
* @type {number}
|
||||
*/
|
||||
this.count = count;
|
||||
|
||||
/**
|
||||
* The segments within this context. Each element in this array has
|
||||
* `count` elements that represent one step in each fork. For example,
|
||||
* when `segmentsList` is `[[a, b], [c, d], [e, f]]`, there is one path
|
||||
* a->c->e and one path b->d->f, and `count` is 2 because each element
|
||||
* is an array with two elements.
|
||||
* @type {Array<Array<CodePathSegment>>}
|
||||
*/
|
||||
this.segmentsList = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* The segments that begin this fork context.
|
||||
* @type {Array<CodePathSegment>}
|
||||
*/
|
||||
get head() {
|
||||
const list = this.segmentsList;
|
||||
|
||||
return list.length === 0 ? [] : list.at(-1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the context contains no segments.
|
||||
* @type {boolean}
|
||||
*/
|
||||
get empty() {
|
||||
return this.segmentsList.length === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if there are any segments that are reachable.
|
||||
* @type {boolean}
|
||||
*/
|
||||
get reachable() {
|
||||
const segments = this.head;
|
||||
|
||||
return segments.length > 0 && segments.some(isReachable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new segments in this context and appends them to the end of the
|
||||
* already existing `CodePathSegment`s specified by `startIndex` and
|
||||
* `endIndex`.
|
||||
* @param {number} startIndex The index of the first segment in the context
|
||||
* that should be specified as previous segments for the newly created segments.
|
||||
* @param {number} endIndex The index of the last segment in the context
|
||||
* that should be specified as previous segments for the newly created segments.
|
||||
* @returns {Array<CodePathSegment>} An array of the newly created segments.
|
||||
*/
|
||||
makeNext(startIndex, endIndex) {
|
||||
return createSegments(
|
||||
this,
|
||||
startIndex,
|
||||
endIndex,
|
||||
CodePathSegment.newNext,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new unreachable segments in this context and appends them to the end of the
|
||||
* already existing `CodePathSegment`s specified by `startIndex` and
|
||||
* `endIndex`.
|
||||
* @param {number} startIndex The index of the first segment in the context
|
||||
* that should be specified as previous segments for the newly created segments.
|
||||
* @param {number} endIndex The index of the last segment in the context
|
||||
* that should be specified as previous segments for the newly created segments.
|
||||
* @returns {Array<CodePathSegment>} An array of the newly created segments.
|
||||
*/
|
||||
makeUnreachable(startIndex, endIndex) {
|
||||
return createSegments(
|
||||
this,
|
||||
startIndex,
|
||||
endIndex,
|
||||
CodePathSegment.newUnreachable,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new segments in this context and does not append them to the end
|
||||
* of the already existing `CodePathSegment`s specified by `startIndex` and
|
||||
* `endIndex`. The `startIndex` and `endIndex` are only used to determine if
|
||||
* the new segments should be reachable. If any of the segments in this range
|
||||
* are reachable then the new segments are also reachable; otherwise, the new
|
||||
* segments are unreachable.
|
||||
* @param {number} startIndex The index of the first segment in the context
|
||||
* that should be considered for reachability.
|
||||
* @param {number} endIndex The index of the last segment in the context
|
||||
* that should be considered for reachability.
|
||||
* @returns {Array<CodePathSegment>} An array of the newly created segments.
|
||||
*/
|
||||
makeDisconnected(startIndex, endIndex) {
|
||||
return createSegments(
|
||||
this,
|
||||
startIndex,
|
||||
endIndex,
|
||||
CodePathSegment.newDisconnected,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds segments to the head of this context.
|
||||
* @param {Array<CodePathSegment>} segments The segments to add.
|
||||
* @returns {void}
|
||||
*/
|
||||
add(segments) {
|
||||
assert(
|
||||
segments.length >= this.count,
|
||||
`${segments.length} >= ${this.count}`,
|
||||
);
|
||||
this.segmentsList.push(mergeExtraSegments(this, segments));
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the head segments with the given segments.
|
||||
* The current head segments are removed.
|
||||
* @param {Array<CodePathSegment>} replacementHeadSegments The new head segments.
|
||||
* @returns {void}
|
||||
*/
|
||||
replaceHead(replacementHeadSegments) {
|
||||
assert(
|
||||
replacementHeadSegments.length >= this.count,
|
||||
`${replacementHeadSegments.length} >= ${this.count}`,
|
||||
);
|
||||
this.segmentsList.splice(
|
||||
-1,
|
||||
1,
|
||||
mergeExtraSegments(this, replacementHeadSegments),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds all segments of a given fork context into this context.
|
||||
* @param {ForkContext} otherForkContext The fork context to add from.
|
||||
* @returns {void}
|
||||
*/
|
||||
addAll(otherForkContext) {
|
||||
assert(otherForkContext.count === this.count);
|
||||
this.segmentsList.push(...otherForkContext.segmentsList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears all segments in this context.
|
||||
* @returns {void}
|
||||
*/
|
||||
clear() {
|
||||
this.segmentsList = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new root context, meaning that there are no parent
|
||||
* fork contexts.
|
||||
* @param {IdGenerator} idGenerator An identifier generator for segments.
|
||||
* @returns {ForkContext} New fork context.
|
||||
*/
|
||||
static newRoot(idGenerator) {
|
||||
const context = new ForkContext(idGenerator, null, 1);
|
||||
|
||||
context.add([CodePathSegment.newRoot(idGenerator.next())]);
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an empty fork context preceded by a given context.
|
||||
* @param {ForkContext} parentContext The parent fork context.
|
||||
* @param {boolean} shouldForkLeavingPath Indicates that we are inside of
|
||||
* a `finally` block and should therefore fork the path that leaves
|
||||
* `finally`.
|
||||
* @returns {ForkContext} New fork context.
|
||||
*/
|
||||
static newEmpty(parentContext, shouldForkLeavingPath) {
|
||||
return new ForkContext(
|
||||
parentContext.idGenerator,
|
||||
parentContext,
|
||||
(shouldForkLeavingPath ? 2 : 1) * parentContext.count,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ForkContext;
|
||||
44
slider/node_modules/eslint/lib/linter/code-path-analysis/id-generator.js
generated
vendored
Normal file
44
slider/node_modules/eslint/lib/linter/code-path-analysis/id-generator.js
generated
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* @fileoverview A class of identifiers generator for code path segments.
|
||||
*
|
||||
* Each rule uses the identifier of code path segments to store additional
|
||||
* information of the code path.
|
||||
*
|
||||
* @author Toru Nagashima
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Public Interface
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* A generator for unique ids.
|
||||
*/
|
||||
class IdGenerator {
|
||||
/**
|
||||
* @param {string} prefix Optional. A prefix of generated ids.
|
||||
*/
|
||||
constructor(prefix) {
|
||||
this.prefix = String(prefix);
|
||||
this.n = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates id.
|
||||
* @returns {string} A generated id.
|
||||
*/
|
||||
next() {
|
||||
this.n = (1 + this.n) | 0;
|
||||
|
||||
/* c8 ignore start */
|
||||
if (this.n < 0) {
|
||||
this.n = 1;
|
||||
} /* c8 ignore stop */
|
||||
|
||||
return this.prefix + this.n;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = IdGenerator;
|
||||
332
slider/node_modules/eslint/lib/linter/esquery.js
generated
vendored
Normal file
332
slider/node_modules/eslint/lib/linter/esquery.js
generated
vendored
Normal file
@@ -0,0 +1,332 @@
|
||||
/**
|
||||
* @fileoverview ESQuery wrapper for ESLint.
|
||||
* @author Nicholas C. Zakas
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const esquery = require("esquery");
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Typedefs
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @typedef {import("esquery").Selector} ESQuerySelector
|
||||
* @typedef {import("esquery").ESQueryOptions} ESQueryOptions
|
||||
*/
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Classes
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* The result of parsing and analyzing an ESQuery selector.
|
||||
*/
|
||||
class ESQueryParsedSelector {
|
||||
/**
|
||||
* The raw selector string that was parsed
|
||||
* @type {string}
|
||||
*/
|
||||
source;
|
||||
|
||||
/**
|
||||
* Whether this selector is an exit selector
|
||||
* @type {boolean}
|
||||
*/
|
||||
isExit;
|
||||
|
||||
/**
|
||||
* An object (from esquery) describing the matching behavior of the selector
|
||||
* @type {ESQuerySelector}
|
||||
*/
|
||||
root;
|
||||
|
||||
/**
|
||||
* The node types that could possibly trigger this selector, or `null` if all node types could trigger it
|
||||
* @type {string[]|null}
|
||||
*/
|
||||
nodeTypes;
|
||||
|
||||
/**
|
||||
* The number of class, pseudo-class, and attribute queries in this selector
|
||||
* @type {number}
|
||||
*/
|
||||
attributeCount;
|
||||
|
||||
/**
|
||||
* The number of identifier queries in this selector
|
||||
* @type {number}
|
||||
*/
|
||||
identifierCount;
|
||||
|
||||
/**
|
||||
* Creates a new parsed selector.
|
||||
* @param {string} source The raw selector string that was parsed
|
||||
* @param {boolean} isExit Whether this selector is an exit selector
|
||||
* @param {ESQuerySelector} root An object (from esquery) describing the matching behavior of the selector
|
||||
* @param {string[]|null} nodeTypes The node types that could possibly trigger this selector, or `null` if all node types could trigger it
|
||||
* @param {number} attributeCount The number of class, pseudo-class, and attribute queries in this selector
|
||||
* @param {number} identifierCount The number of identifier queries in this selector
|
||||
*/
|
||||
constructor(
|
||||
source,
|
||||
isExit,
|
||||
root,
|
||||
nodeTypes,
|
||||
attributeCount,
|
||||
identifierCount,
|
||||
) {
|
||||
this.source = source;
|
||||
this.isExit = isExit;
|
||||
this.root = root;
|
||||
this.nodeTypes = nodeTypes;
|
||||
this.attributeCount = attributeCount;
|
||||
this.identifierCount = identifierCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this selector's specifity to another selector for sorting purposes.
|
||||
* @param {ESQueryParsedSelector} otherSelector The selector to compare against
|
||||
* @returns {number}
|
||||
* a value less than 0 if this selector is less specific than otherSelector
|
||||
* a value greater than 0 if this selector is more specific than otherSelector
|
||||
* a value less than 0 if this selector and otherSelector have the same specificity, and this selector <= otherSelector alphabetically
|
||||
* a value greater than 0 if this selector and otherSelector have the same specificity, and this selector > otherSelector alphabetically
|
||||
*/
|
||||
compare(otherSelector) {
|
||||
return (
|
||||
this.attributeCount - otherSelector.attributeCount ||
|
||||
this.identifierCount - otherSelector.identifierCount ||
|
||||
(this.source <= otherSelector.source ? -1 : 1)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const selectorCache = new Map();
|
||||
|
||||
/**
|
||||
* Computes the union of one or more arrays
|
||||
* @param {...any[]} arrays One or more arrays to union
|
||||
* @returns {any[]} The union of the input arrays
|
||||
*/
|
||||
function union(...arrays) {
|
||||
return [...new Set(arrays.flat())];
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the intersection of one or more arrays
|
||||
* @param {...any[]} arrays One or more arrays to intersect
|
||||
* @returns {any[]} The intersection of the input arrays
|
||||
*/
|
||||
function intersection(...arrays) {
|
||||
if (arrays.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
let result = [...new Set(arrays[0])];
|
||||
|
||||
for (const array of arrays.slice(1)) {
|
||||
result = result.filter(x => array.includes(x));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Analyzes a parsed selector and returns combined data about it
|
||||
* @param {ESQuerySelector} parsedSelector An object (from esquery) describing the matching behavior of the selector
|
||||
* @returns {{nodeTypes:string[]|null, attributeCount:number, identifierCount:number}} Object containing selector data.
|
||||
*/
|
||||
function analyzeParsedSelector(parsedSelector) {
|
||||
let attributeCount = 0;
|
||||
let identifierCount = 0;
|
||||
|
||||
/**
|
||||
* Analyzes a selector and returns the node types that could possibly trigger it.
|
||||
* @param {ESQuerySelector} selector The selector to analyze.
|
||||
* @returns {string[]|null} The node types that could possibly trigger this selector, or `null` if all node types could trigger it
|
||||
*/
|
||||
function analyzeSelector(selector) {
|
||||
switch (selector.type) {
|
||||
case "identifier":
|
||||
identifierCount++;
|
||||
return [selector.value];
|
||||
|
||||
case "not":
|
||||
selector.selectors.map(analyzeSelector);
|
||||
return null;
|
||||
|
||||
case "matches": {
|
||||
const typesForComponents =
|
||||
selector.selectors.map(analyzeSelector);
|
||||
|
||||
if (typesForComponents.every(Boolean)) {
|
||||
return union(...typesForComponents);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
case "compound": {
|
||||
const typesForComponents = selector.selectors
|
||||
.map(analyzeSelector)
|
||||
.filter(typesForComponent => typesForComponent);
|
||||
|
||||
// If all of the components could match any type, then the compound could also match any type.
|
||||
if (!typesForComponents.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* If at least one of the components could only match a particular type, the compound could only match
|
||||
* the intersection of those types.
|
||||
*/
|
||||
return intersection(...typesForComponents);
|
||||
}
|
||||
|
||||
case "attribute":
|
||||
case "field":
|
||||
case "nth-child":
|
||||
case "nth-last-child":
|
||||
attributeCount++;
|
||||
return null;
|
||||
|
||||
case "child":
|
||||
case "descendant":
|
||||
case "sibling":
|
||||
case "adjacent":
|
||||
analyzeSelector(selector.left);
|
||||
return analyzeSelector(selector.right);
|
||||
|
||||
case "class":
|
||||
// TODO: abstract into JSLanguage somehow
|
||||
if (selector.name === "function") {
|
||||
return [
|
||||
"FunctionDeclaration",
|
||||
"FunctionExpression",
|
||||
"ArrowFunctionExpression",
|
||||
];
|
||||
}
|
||||
return null;
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
const nodeTypes = analyzeSelector(parsedSelector);
|
||||
|
||||
return {
|
||||
nodeTypes,
|
||||
attributeCount,
|
||||
identifierCount,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to parse a simple selector string, such as a single identifier or wildcard.
|
||||
* This saves time by avoiding the overhead of esquery parsing for simple cases.
|
||||
* @param {string} selector The selector string to parse.
|
||||
* @returns {Object|null} An object describing the selector if it is simple, or `null` if it is not.
|
||||
*/
|
||||
function trySimpleParseSelector(selector) {
|
||||
if (selector === "*") {
|
||||
return {
|
||||
type: "wildcard",
|
||||
value: "*",
|
||||
};
|
||||
}
|
||||
|
||||
if (/^[a-z]+$/iu.test(selector)) {
|
||||
return {
|
||||
type: "identifier",
|
||||
value: selector,
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a raw selector string, and throws a useful error if parsing fails.
|
||||
* @param {string} selector The selector string to parse.
|
||||
* @returns {Object} An object (from esquery) describing the matching behavior of this selector
|
||||
* @throws {Error} An error if the selector is invalid
|
||||
*/
|
||||
function tryParseSelector(selector) {
|
||||
try {
|
||||
return esquery.parse(selector);
|
||||
} catch (err) {
|
||||
if (
|
||||
err.location &&
|
||||
err.location.start &&
|
||||
typeof err.location.start.offset === "number"
|
||||
) {
|
||||
throw new SyntaxError(
|
||||
`Syntax error in selector "${selector}" at position ${err.location.start.offset}: ${err.message}`,
|
||||
{
|
||||
cause: err,
|
||||
},
|
||||
);
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a raw selector string, and returns the parsed selector along with specificity and type information.
|
||||
* @param {string} source A raw AST selector
|
||||
* @returns {ESQueryParsedSelector} A selector descriptor
|
||||
*/
|
||||
function parse(source) {
|
||||
if (selectorCache.has(source)) {
|
||||
return selectorCache.get(source);
|
||||
}
|
||||
|
||||
const cleanSource = source.replace(/:exit$/u, "");
|
||||
const parsedSelector =
|
||||
trySimpleParseSelector(cleanSource) ?? tryParseSelector(cleanSource);
|
||||
const { nodeTypes, attributeCount, identifierCount } =
|
||||
analyzeParsedSelector(parsedSelector);
|
||||
|
||||
const result = new ESQueryParsedSelector(
|
||||
source,
|
||||
source.endsWith(":exit"),
|
||||
parsedSelector,
|
||||
nodeTypes,
|
||||
attributeCount,
|
||||
identifierCount,
|
||||
);
|
||||
|
||||
selectorCache.set(source, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a node matches a given selector.
|
||||
* @param {Object} node The node to check against the selector.
|
||||
* @param {ESQuerySelector} root The root of the selector to match against.
|
||||
* @param {Object[]} ancestry The ancestry of the node being checked, which is an array of nodes from the current node to the root.
|
||||
* @param {ESQueryOptions} options The options to use for matching.
|
||||
* @returns {boolean} `true` if the node matches the selector, `false` otherwise.
|
||||
*/
|
||||
function matches(node, root, ancestry, options) {
|
||||
return esquery.matches(node, root, ancestry, options);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Exports
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
parse,
|
||||
matches,
|
||||
ESQueryParsedSelector,
|
||||
};
|
||||
144
slider/node_modules/eslint/lib/linter/file-context.js
generated
vendored
Normal file
144
slider/node_modules/eslint/lib/linter/file-context.js
generated
vendored
Normal file
@@ -0,0 +1,144 @@
|
||||
/**
|
||||
* @fileoverview The FileContext class.
|
||||
* @author Nicholas C. Zakas
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Represents a file context that the linter can use to lint a file.
|
||||
*/
|
||||
class FileContext {
|
||||
/**
|
||||
* The current working directory.
|
||||
* @type {string}
|
||||
*/
|
||||
cwd;
|
||||
|
||||
/**
|
||||
* The filename of the file being linted.
|
||||
* @type {string}
|
||||
*/
|
||||
filename;
|
||||
|
||||
/**
|
||||
* The physical filename of the file being linted.
|
||||
* @type {string}
|
||||
*/
|
||||
physicalFilename;
|
||||
|
||||
/**
|
||||
* The source code of the file being linted.
|
||||
* @type {SourceCode}
|
||||
*/
|
||||
sourceCode;
|
||||
|
||||
/**
|
||||
* The parser options for the file being linted.
|
||||
* @type {Record<string, unknown>}
|
||||
* @deprecated Use `languageOptions` instead.
|
||||
*/
|
||||
parserOptions;
|
||||
|
||||
/**
|
||||
* The path to the parser used to parse this file.
|
||||
* @type {string}
|
||||
* @deprecated No longer supported.
|
||||
*/
|
||||
parserPath;
|
||||
|
||||
/**
|
||||
* The language options used when parsing this file.
|
||||
* @type {Record<string, unknown>}
|
||||
*/
|
||||
languageOptions;
|
||||
|
||||
/**
|
||||
* The settings for the file being linted.
|
||||
* @type {Record<string, unknown>}
|
||||
*/
|
||||
settings;
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
* @param {Object} config The configuration object for the file context.
|
||||
* @param {string} config.cwd The current working directory.
|
||||
* @param {string} config.filename The filename of the file being linted.
|
||||
* @param {string} config.physicalFilename The physical filename of the file being linted.
|
||||
* @param {SourceCode} config.sourceCode The source code of the file being linted.
|
||||
* @param {Record<string, unknown>} config.parserOptions The parser options for the file being linted.
|
||||
* @param {string} config.parserPath The path to the parser used to parse this file.
|
||||
* @param {Record<string, unknown>} config.languageOptions The language options used when parsing this file.
|
||||
* @param {Record<string, unknown>} config.settings The settings for the file being linted.
|
||||
*/
|
||||
constructor({
|
||||
cwd,
|
||||
filename,
|
||||
physicalFilename,
|
||||
sourceCode,
|
||||
parserOptions,
|
||||
parserPath,
|
||||
languageOptions,
|
||||
settings,
|
||||
}) {
|
||||
this.cwd = cwd;
|
||||
this.filename = filename;
|
||||
this.physicalFilename = physicalFilename;
|
||||
this.sourceCode = sourceCode;
|
||||
this.parserOptions = parserOptions;
|
||||
this.parserPath = parserPath;
|
||||
this.languageOptions = languageOptions;
|
||||
this.settings = settings;
|
||||
|
||||
Object.freeze(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current working directory.
|
||||
* @returns {string} The current working directory.
|
||||
* @deprecated Use `cwd` instead.
|
||||
*/
|
||||
getCwd() {
|
||||
return this.cwd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the filename of the file being linted.
|
||||
* @returns {string} The filename of the file being linted.
|
||||
* @deprecated Use `filename` instead.
|
||||
*/
|
||||
getFilename() {
|
||||
return this.filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the physical filename of the file being linted.
|
||||
* @returns {string} The physical filename of the file being linted.
|
||||
* @deprecated Use `physicalFilename` instead.
|
||||
*/
|
||||
getPhysicalFilename() {
|
||||
return this.physicalFilename;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the source code of the file being linted.
|
||||
* @returns {SourceCode} The source code of the file being linted.
|
||||
* @deprecated Use `sourceCode` instead.
|
||||
*/
|
||||
getSourceCode() {
|
||||
return this.sourceCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new object with the current object as the prototype and
|
||||
* the specified properties as its own properties.
|
||||
* @param {Object} extension The properties to add to the new object.
|
||||
* @returns {FileContext} A new object with the current object as the prototype
|
||||
* and the specified properties as its own properties.
|
||||
*/
|
||||
extend(extension) {
|
||||
return Object.freeze(Object.assign(Object.create(this), extension));
|
||||
}
|
||||
}
|
||||
|
||||
exports.FileContext = FileContext;
|
||||
608
slider/node_modules/eslint/lib/linter/file-report.js
generated
vendored
Normal file
608
slider/node_modules/eslint/lib/linter/file-report.js
generated
vendored
Normal file
@@ -0,0 +1,608 @@
|
||||
/**
|
||||
* @fileoverview A class to track messages reported by the linter for a file.
|
||||
* @author Nicholas C. Zakas
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const assert = require("../shared/assert");
|
||||
const { RuleFixer } = require("./rule-fixer");
|
||||
const { interpolate } = require("./interpolate");
|
||||
const ruleReplacements = require("../../conf/replacements.json");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Typedefs
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @typedef {import("../types").Linter.LintMessage} LintMessage */
|
||||
/** @typedef {import("../types").Linter.LintSuggestion} SuggestionResult */
|
||||
/** @typedef {import("@eslint/core").Language} Language */
|
||||
/** @typedef {import("@eslint/core").SourceLocation} SourceLocation */
|
||||
|
||||
/**
|
||||
* An error message description
|
||||
* @typedef {Object} MessageDescriptor
|
||||
* @property {ASTNode} [node] The reported node
|
||||
* @property {Location} loc The location of the problem.
|
||||
* @property {string} message The problem message.
|
||||
* @property {Object} [data] Optional data to use to fill in placeholders in the
|
||||
* message.
|
||||
* @property {Function} [fix] The function to call that creates a fix command.
|
||||
* @property {Array<{desc?: string, messageId?: string, fix: Function}>} suggest Suggestion descriptions and functions to create a the associated fixes.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} LintProblem
|
||||
* @property {string} ruleId The rule ID that reported the problem.
|
||||
* @property {string} message The problem message.
|
||||
* @property {SourceLocation} loc The location of the problem.
|
||||
*/
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const DEFAULT_ERROR_LOC = {
|
||||
start: { line: 1, column: 0 },
|
||||
end: { line: 1, column: 1 },
|
||||
};
|
||||
|
||||
/**
|
||||
* Updates a given location based on the language offsets. This allows us to
|
||||
* change 0-based locations to 1-based locations. We always want ESLint
|
||||
* reporting lines and columns starting from 1.
|
||||
* @todo Potentially this should be moved into a shared utility file.
|
||||
* @param {Object} location The location to update.
|
||||
* @param {number} location.line The starting line number.
|
||||
* @param {number} location.column The starting column number.
|
||||
* @param {number} [location.endLine] The ending line number.
|
||||
* @param {number} [location.endColumn] The ending column number.
|
||||
* @param {Language} language The language to use to adjust the location information.
|
||||
* @returns {Object} The updated location.
|
||||
*/
|
||||
function updateLocationInformation(
|
||||
{ line, column, endLine, endColumn },
|
||||
language,
|
||||
) {
|
||||
const columnOffset = language.columnStart === 1 ? 0 : 1;
|
||||
const lineOffset = language.lineStart === 1 ? 0 : 1;
|
||||
|
||||
// calculate separately to account for undefined
|
||||
const finalEndLine = endLine === void 0 ? endLine : endLine + lineOffset;
|
||||
const finalEndColumn =
|
||||
endColumn === void 0 ? endColumn : endColumn + columnOffset;
|
||||
|
||||
return {
|
||||
line: line + lineOffset,
|
||||
column: column + columnOffset,
|
||||
endLine: finalEndLine,
|
||||
endColumn: finalEndColumn,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* creates a missing-rule message.
|
||||
* @param {string} ruleId the ruleId to create
|
||||
* @returns {string} created error message
|
||||
* @private
|
||||
*/
|
||||
function createMissingRuleMessage(ruleId) {
|
||||
return Object.hasOwn(ruleReplacements.rules, ruleId)
|
||||
? `Rule '${ruleId}' was removed and replaced by: ${ruleReplacements.rules[ruleId].join(", ")}`
|
||||
: `Definition for rule '${ruleId}' was not found.`;
|
||||
}
|
||||
|
||||
/**
|
||||
* creates a linting problem
|
||||
* @param {LintProblem} options to create linting error
|
||||
* @param {RuleSeverity} severity the error message to report
|
||||
* @param {Language} language the language to use to adjust the location information.
|
||||
* @returns {LintMessage} created problem, returns a missing-rule problem if only provided ruleId.
|
||||
* @private
|
||||
*/
|
||||
function createLintingProblem(options, severity, language) {
|
||||
const {
|
||||
ruleId = null,
|
||||
loc = DEFAULT_ERROR_LOC,
|
||||
message = createMissingRuleMessage(options.ruleId),
|
||||
} = options;
|
||||
|
||||
return {
|
||||
ruleId,
|
||||
message,
|
||||
...updateLocationInformation(
|
||||
{
|
||||
line: loc.start.line,
|
||||
column: loc.start.column,
|
||||
endLine: loc.end.line,
|
||||
endColumn: loc.end.column,
|
||||
},
|
||||
language,
|
||||
),
|
||||
severity,
|
||||
nodeType: null,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates a multi-argument context.report() call into a single object argument call
|
||||
* @param {...*} args A list of arguments passed to `context.report`
|
||||
* @returns {MessageDescriptor} A normalized object containing report information
|
||||
*/
|
||||
function normalizeMultiArgReportCall(...args) {
|
||||
// If there is one argument, it is considered to be a new-style call already.
|
||||
if (args.length === 1) {
|
||||
// Shallow clone the object to avoid surprises if reusing the descriptor
|
||||
return Object.assign({}, args[0]);
|
||||
}
|
||||
|
||||
// If the second argument is a string, the arguments are interpreted as [node, message, data, fix].
|
||||
if (typeof args[1] === "string") {
|
||||
return {
|
||||
node: args[0],
|
||||
message: args[1],
|
||||
data: args[2],
|
||||
fix: args[3],
|
||||
};
|
||||
}
|
||||
|
||||
// Otherwise, the arguments are interpreted as [node, loc, message, data, fix].
|
||||
return {
|
||||
node: args[0],
|
||||
loc: args[1],
|
||||
message: args[2],
|
||||
data: args[3],
|
||||
fix: args[4],
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that either a loc or a node was provided, and the node is valid if it was provided.
|
||||
* @param {MessageDescriptor} descriptor A descriptor to validate
|
||||
* @returns {void}
|
||||
* @throws AssertionError if neither a node nor a loc was provided, or if the node is not an object
|
||||
*/
|
||||
function assertValidNodeInfo(descriptor) {
|
||||
if (descriptor.node) {
|
||||
assert(typeof descriptor.node === "object", "Node must be an object");
|
||||
} else {
|
||||
assert(
|
||||
descriptor.loc,
|
||||
"Node must be provided when reporting error if location is not provided",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes a MessageDescriptor to always have a `loc` with `start` and `end` properties
|
||||
* @param {MessageDescriptor} descriptor A descriptor for the report from a rule.
|
||||
* @returns {{start: Location, end: (Location|null)}} An updated location that infers the `start` and `end` properties
|
||||
* from the `node` of the original descriptor, or infers the `start` from the `loc` of the original descriptor.
|
||||
*/
|
||||
function normalizeReportLoc(descriptor) {
|
||||
if (descriptor.loc.start) {
|
||||
return descriptor.loc;
|
||||
}
|
||||
return { start: descriptor.loc, end: null };
|
||||
}
|
||||
|
||||
/**
|
||||
* Clones the given fix object.
|
||||
* @param {Fix|null} fix The fix to clone.
|
||||
* @returns {Fix|null} Deep cloned fix object or `null` if `null` or `undefined` was passed in.
|
||||
*/
|
||||
function cloneFix(fix) {
|
||||
if (!fix) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
range: [fix.range[0], fix.range[1]],
|
||||
text: fix.text,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that a fix has a valid range.
|
||||
* @param {Fix|null} fix The fix to validate.
|
||||
* @returns {void}
|
||||
*/
|
||||
function assertValidFix(fix) {
|
||||
if (fix) {
|
||||
assert(
|
||||
fix.range &&
|
||||
typeof fix.range[0] === "number" &&
|
||||
typeof fix.range[1] === "number",
|
||||
`Fix has invalid range: ${JSON.stringify(fix, null, 2)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares items in a fixes array by range.
|
||||
* @param {Fix} a The first message.
|
||||
* @param {Fix} b The second message.
|
||||
* @returns {number} -1 if a comes before b, 1 if a comes after b, 0 if equal.
|
||||
* @private
|
||||
*/
|
||||
function compareFixesByRange(a, b) {
|
||||
return a.range[0] - b.range[0] || a.range[1] - b.range[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges the given fixes array into one.
|
||||
* @param {Fix[]} fixes The fixes to merge.
|
||||
* @param {SourceCode} sourceCode The source code object to get the text between fixes.
|
||||
* @returns {{text: string, range: number[]}} The merged fixes
|
||||
*/
|
||||
function mergeFixes(fixes, sourceCode) {
|
||||
for (const fix of fixes) {
|
||||
assertValidFix(fix);
|
||||
}
|
||||
|
||||
if (fixes.length === 0) {
|
||||
return null;
|
||||
}
|
||||
if (fixes.length === 1) {
|
||||
return cloneFix(fixes[0]);
|
||||
}
|
||||
|
||||
fixes.sort(compareFixesByRange);
|
||||
|
||||
const originalText = sourceCode.text;
|
||||
const start = fixes[0].range[0];
|
||||
const end = fixes.at(-1).range[1];
|
||||
let text = "";
|
||||
let lastPos = Number.MIN_SAFE_INTEGER;
|
||||
|
||||
for (const fix of fixes) {
|
||||
assert(
|
||||
fix.range[0] >= lastPos,
|
||||
"Fix objects must not be overlapped in a report.",
|
||||
);
|
||||
|
||||
if (fix.range[0] >= 0) {
|
||||
text += originalText.slice(
|
||||
Math.max(0, start, lastPos),
|
||||
fix.range[0],
|
||||
);
|
||||
}
|
||||
text += fix.text;
|
||||
lastPos = fix.range[1];
|
||||
}
|
||||
text += originalText.slice(Math.max(0, start, lastPos), end);
|
||||
|
||||
return { range: [start, end], text };
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets one fix object from the given descriptor.
|
||||
* If the descriptor retrieves multiple fixes, this merges those to one.
|
||||
* @param {MessageDescriptor} descriptor The report descriptor.
|
||||
* @param {SourceCode} sourceCode The source code object to get text between fixes.
|
||||
* @returns {({text: string, range: number[]}|null)} The fix for the descriptor
|
||||
*/
|
||||
function normalizeFixes(descriptor, sourceCode) {
|
||||
if (typeof descriptor.fix !== "function") {
|
||||
return null;
|
||||
}
|
||||
|
||||
const ruleFixer = new RuleFixer({ sourceCode });
|
||||
|
||||
// @type {null | Fix | Fix[] | IterableIterator<Fix>}
|
||||
const fix = descriptor.fix(ruleFixer);
|
||||
|
||||
// Merge to one.
|
||||
if (fix && Symbol.iterator in fix) {
|
||||
return mergeFixes(Array.from(fix), sourceCode);
|
||||
}
|
||||
|
||||
assertValidFix(fix);
|
||||
return cloneFix(fix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an array of suggestion objects from the given descriptor.
|
||||
* @param {MessageDescriptor} descriptor The report descriptor.
|
||||
* @param {SourceCode} sourceCode The source code object to get text between fixes.
|
||||
* @param {Object} messages Object of meta messages for the rule.
|
||||
* @returns {Array<SuggestionResult>} The suggestions for the descriptor
|
||||
*/
|
||||
function mapSuggestions(descriptor, sourceCode, messages) {
|
||||
if (!descriptor.suggest || !Array.isArray(descriptor.suggest)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return (
|
||||
descriptor.suggest
|
||||
.map(suggestInfo => {
|
||||
const computedDesc =
|
||||
suggestInfo.desc || messages[suggestInfo.messageId];
|
||||
|
||||
return {
|
||||
...suggestInfo,
|
||||
desc: interpolate(computedDesc, suggestInfo.data),
|
||||
fix: normalizeFixes(suggestInfo, sourceCode),
|
||||
};
|
||||
})
|
||||
|
||||
// Remove suggestions that didn't provide a fix
|
||||
.filter(({ fix }) => fix)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates information about the report from a descriptor
|
||||
* @param {Object} options Information about the problem
|
||||
* @param {string} options.ruleId Rule ID
|
||||
* @param {(0|1|2)} options.severity Rule severity
|
||||
* @param {(ASTNode|null)} options.node Node
|
||||
* @param {string} options.message Error message
|
||||
* @param {string} [options.messageId] The error message ID.
|
||||
* @param {{start: SourceLocation, end: (SourceLocation|null)}} options.loc Start and end location
|
||||
* @param {{text: string, range: (number[]|null)}} options.fix The fix object
|
||||
* @param {Array<{text: string, range: (number[]|null)}>} options.suggestions The array of suggestions objects
|
||||
* @param {Language} [options.language] The language to use to adjust line and column offsets.
|
||||
* @returns {LintMessage} Information about the report
|
||||
*/
|
||||
function createProblem(options) {
|
||||
const { language } = options;
|
||||
|
||||
// calculate offsets based on the language in use
|
||||
const columnOffset = language.columnStart === 1 ? 0 : 1;
|
||||
const lineOffset = language.lineStart === 1 ? 0 : 1;
|
||||
|
||||
const problem = {
|
||||
ruleId: options.ruleId,
|
||||
severity: options.severity,
|
||||
message: options.message,
|
||||
line: options.loc.start.line + lineOffset,
|
||||
column: options.loc.start.column + columnOffset,
|
||||
nodeType: (options.node && options.node.type) || null,
|
||||
};
|
||||
|
||||
/*
|
||||
* If this isn’t in the conditional, some of the tests fail
|
||||
* because `messageId` is present in the problem object
|
||||
*/
|
||||
if (options.messageId) {
|
||||
problem.messageId = options.messageId;
|
||||
}
|
||||
|
||||
if (options.loc.end) {
|
||||
problem.endLine = options.loc.end.line + lineOffset;
|
||||
problem.endColumn = options.loc.end.column + columnOffset;
|
||||
}
|
||||
|
||||
if (options.fix) {
|
||||
problem.fix = options.fix;
|
||||
}
|
||||
|
||||
if (options.suggestions && options.suggestions.length > 0) {
|
||||
problem.suggestions = options.suggestions;
|
||||
}
|
||||
|
||||
return problem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates that suggestions are properly defined. Throws if an error is detected.
|
||||
* @param {Array<{ desc?: string, messageId?: string }>} suggest The incoming suggest data.
|
||||
* @param {Object} messages Object of meta messages for the rule.
|
||||
* @returns {void}
|
||||
*/
|
||||
function validateSuggestions(suggest, messages) {
|
||||
if (suggest && Array.isArray(suggest)) {
|
||||
suggest.forEach(suggestion => {
|
||||
if (suggestion.messageId) {
|
||||
const { messageId } = suggestion;
|
||||
|
||||
if (!messages) {
|
||||
throw new TypeError(
|
||||
`context.report() called with a suggest option with a messageId '${messageId}', but no messages were present in the rule metadata.`,
|
||||
);
|
||||
}
|
||||
|
||||
if (!messages[messageId]) {
|
||||
throw new TypeError(
|
||||
`context.report() called with a suggest option with a messageId '${messageId}' which is not present in the 'messages' config: ${JSON.stringify(messages, null, 2)}`,
|
||||
);
|
||||
}
|
||||
|
||||
if (suggestion.desc) {
|
||||
throw new TypeError(
|
||||
"context.report() called with a suggest option that defines both a 'messageId' and an 'desc'. Please only pass one.",
|
||||
);
|
||||
}
|
||||
} else if (!suggestion.desc) {
|
||||
throw new TypeError(
|
||||
"context.report() called with a suggest option that doesn't have either a `desc` or `messageId`",
|
||||
);
|
||||
}
|
||||
|
||||
if (typeof suggestion.fix !== "function") {
|
||||
throw new TypeError(
|
||||
`context.report() called with a suggest option without a fix function. See: ${suggestion}`,
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the message from a report descriptor.
|
||||
* @param {MessageDescriptor} descriptor The report descriptor.
|
||||
* @param {Object} messages Object of meta messages for the rule.
|
||||
* @returns {string} The computed message.
|
||||
* @throws {TypeError} If messageId is not found or both message and messageId are provided.
|
||||
*/
|
||||
function computeMessageFromDescriptor(descriptor, messages) {
|
||||
if (descriptor.messageId) {
|
||||
if (!messages) {
|
||||
throw new TypeError(
|
||||
"context.report() called with a messageId, but no messages were present in the rule metadata.",
|
||||
);
|
||||
}
|
||||
const id = descriptor.messageId;
|
||||
|
||||
if (descriptor.message) {
|
||||
throw new TypeError(
|
||||
"context.report() called with a message and a messageId. Please only pass one.",
|
||||
);
|
||||
}
|
||||
if (!messages || !Object.hasOwn(messages, id)) {
|
||||
throw new TypeError(
|
||||
`context.report() called with a messageId of '${id}' which is not present in the 'messages' config: ${JSON.stringify(messages, null, 2)}`,
|
||||
);
|
||||
}
|
||||
return messages[id];
|
||||
}
|
||||
|
||||
if (descriptor.message) {
|
||||
return descriptor.message;
|
||||
}
|
||||
|
||||
throw new TypeError(
|
||||
"Missing `message` property in report() call; add a message that describes the linting problem.",
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* A report object that contains the messages reported the linter
|
||||
* for a file.
|
||||
*/
|
||||
class FileReport {
|
||||
/**
|
||||
* The messages reported by the linter for this file.
|
||||
* @type {LintMessage[]}
|
||||
*/
|
||||
messages = [];
|
||||
|
||||
/**
|
||||
* A rule mapper that maps rule IDs to their metadata.
|
||||
* @type {(string) => RuleDefinition}
|
||||
*/
|
||||
#ruleMapper;
|
||||
|
||||
/**
|
||||
* The source code object for the file.
|
||||
* @type {SourceCode}
|
||||
*/
|
||||
#sourceCode;
|
||||
|
||||
/**
|
||||
* The language to use to adjust line and column offsets.
|
||||
* @type {Language}
|
||||
*/
|
||||
#language;
|
||||
|
||||
/**
|
||||
* Whether to disable fixes for this report.
|
||||
* @type {boolean}
|
||||
*/
|
||||
#disableFixes;
|
||||
|
||||
/**
|
||||
* Creates a new FileReport instance.
|
||||
* @param {Object} options The options for the file report
|
||||
* @param {(string) => RuleDefinition} options.ruleMapper A rule mapper that maps rule IDs to their metadata.
|
||||
* @param {SourceCode} options.sourceCode The source code object for the file.
|
||||
* @param {Language} options.language The language to use to adjust line and column offsets.
|
||||
* @param {boolean} [options.disableFixes=false] Whether to disable fixes for this report.
|
||||
*/
|
||||
constructor({ ruleMapper, sourceCode, language, disableFixes = false }) {
|
||||
this.#ruleMapper = ruleMapper;
|
||||
this.#sourceCode = sourceCode;
|
||||
this.#language = language;
|
||||
this.#disableFixes = disableFixes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a rule-generated message to the report.
|
||||
* @param {string} ruleId The rule ID that reported the problem.
|
||||
* @param {0|1|2} severity The severity of the problem (0 = off, 1 = warning, 2 = error).
|
||||
* @param {...*} args The arguments passed to `context.report()`.
|
||||
* @returns {LintMessage} The created message object.
|
||||
* @throws {TypeError} If the messageId is not found or both message and messageId are provided.
|
||||
* @throws {AssertionError} If the node is not an object or neither a node nor a loc is provided.
|
||||
*/
|
||||
addRuleMessage(ruleId, severity, ...args) {
|
||||
const descriptor = normalizeMultiArgReportCall(...args);
|
||||
const ruleDefinition = this.#ruleMapper(ruleId);
|
||||
const messages = ruleDefinition?.meta?.messages;
|
||||
|
||||
assertValidNodeInfo(descriptor);
|
||||
|
||||
const computedMessage = computeMessageFromDescriptor(
|
||||
descriptor,
|
||||
messages,
|
||||
);
|
||||
|
||||
validateSuggestions(descriptor.suggest, messages);
|
||||
|
||||
this.messages.push(
|
||||
createProblem({
|
||||
ruleId,
|
||||
severity,
|
||||
node: descriptor.node,
|
||||
message: interpolate(computedMessage, descriptor.data),
|
||||
messageId: descriptor.messageId,
|
||||
loc: descriptor.loc
|
||||
? normalizeReportLoc(descriptor)
|
||||
: this.#sourceCode.getLoc(descriptor.node),
|
||||
fix: this.#disableFixes
|
||||
? null
|
||||
: normalizeFixes(descriptor, this.#sourceCode),
|
||||
suggestions: this.#disableFixes
|
||||
? []
|
||||
: mapSuggestions(descriptor, this.#sourceCode, messages),
|
||||
language: this.#language,
|
||||
}),
|
||||
);
|
||||
|
||||
return this.messages.at(-1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an error message to the report. Meant to be called outside of rules.
|
||||
* @param {LintProblem} descriptor The descriptor for the error message.
|
||||
* @returns {LintMessage} The created message object.
|
||||
*/
|
||||
addError(descriptor) {
|
||||
const message = createLintingProblem(descriptor, 2, this.#language);
|
||||
this.messages.push(message);
|
||||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a fatal error message to the report. Meant to be called outside of rules.
|
||||
* @param {LintProblem} descriptor The descriptor for the fatal error message.
|
||||
* @returns {LintMessage} The created message object.
|
||||
*/
|
||||
addFatal(descriptor) {
|
||||
const message = createLintingProblem(descriptor, 2, this.#language);
|
||||
message.fatal = true;
|
||||
this.messages.push(message);
|
||||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a warning message to the report. Meant to be called outside of rules.
|
||||
* @param {LintProblem} descriptor The descriptor for the warning message.
|
||||
* @returns {LintMessage} The created message object.
|
||||
*/
|
||||
addWarning(descriptor) {
|
||||
const message = createLintingProblem(descriptor, 1, this.#language);
|
||||
this.messages.push(message);
|
||||
return message;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
FileReport,
|
||||
updateLocationInformation,
|
||||
};
|
||||
11
slider/node_modules/eslint/lib/linter/index.js
generated
vendored
Normal file
11
slider/node_modules/eslint/lib/linter/index.js
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
"use strict";
|
||||
|
||||
const { Linter } = require("./linter");
|
||||
const SourceCodeFixer = require("./source-code-fixer");
|
||||
|
||||
module.exports = {
|
||||
Linter,
|
||||
|
||||
// For testers.
|
||||
SourceCodeFixer,
|
||||
};
|
||||
50
slider/node_modules/eslint/lib/linter/interpolate.js
generated
vendored
Normal file
50
slider/node_modules/eslint/lib/linter/interpolate.js
generated
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* @fileoverview Interpolate keys from an object into a string with {{ }} markers.
|
||||
* @author Jed Fox
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Public Interface
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns a global expression matching placeholders in messages.
|
||||
* @returns {RegExp} Global regular expression matching placeholders
|
||||
*/
|
||||
function getPlaceholderMatcher() {
|
||||
return /\{\{([^{}]+)\}\}/gu;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces {{ placeholders }} in the message with the provided data.
|
||||
* Does not replace placeholders not available in the data.
|
||||
* @param {string} text Original message with potential placeholders
|
||||
* @param {Record<string, string>} data Map of placeholder name to its value
|
||||
* @returns {string} Message with replaced placeholders
|
||||
*/
|
||||
function interpolate(text, data) {
|
||||
if (!data) {
|
||||
return text;
|
||||
}
|
||||
|
||||
const matcher = getPlaceholderMatcher();
|
||||
|
||||
// Substitution content for any {{ }} markers.
|
||||
return text.replace(matcher, (fullMatch, termWithWhitespace) => {
|
||||
const term = termWithWhitespace.trim();
|
||||
|
||||
if (term in data) {
|
||||
return data[term];
|
||||
}
|
||||
|
||||
// Preserve old behavior: If parameter name not provided, don't replace it.
|
||||
return fullMatch;
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getPlaceholderMatcher,
|
||||
interpolate,
|
||||
};
|
||||
2662
slider/node_modules/eslint/lib/linter/linter.js
generated
vendored
Normal file
2662
slider/node_modules/eslint/lib/linter/linter.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
169
slider/node_modules/eslint/lib/linter/rule-fixer.js
generated
vendored
Normal file
169
slider/node_modules/eslint/lib/linter/rule-fixer.js
generated
vendored
Normal file
@@ -0,0 +1,169 @@
|
||||
/**
|
||||
* @fileoverview An object that creates fix commands for rules.
|
||||
* @author Nicholas C. Zakas
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Typedefs
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @import { SourceRange } from "@eslint/core";
|
||||
*/
|
||||
|
||||
/* eslint class-methods-use-this: off -- Methods desired on instance */
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// none!
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Creates a fix command that inserts text at the specified index in the source text.
|
||||
* @param {number} index The 0-based index at which to insert the new text.
|
||||
* @param {string} text The text to insert.
|
||||
* @returns {Object} The fix command.
|
||||
* @private
|
||||
*/
|
||||
function insertTextAt(index, text) {
|
||||
return {
|
||||
range: [index, index],
|
||||
text,
|
||||
};
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Public Interface
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Creates code fixing commands for rules.
|
||||
*/
|
||||
class RuleFixer {
|
||||
/**
|
||||
* The source code object representing the text to be fixed.
|
||||
* @type {SourceCode}
|
||||
*/
|
||||
#sourceCode;
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
* @param {Object} options The options for the fixer.
|
||||
* @param {SourceCode} options.sourceCode The source code object representing the text to be fixed.
|
||||
*/
|
||||
constructor({ sourceCode }) {
|
||||
this.#sourceCode = sourceCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a fix command that inserts text after the given node or token.
|
||||
* The fix is not applied until applyFixes() is called.
|
||||
* @param {ASTNode|Token} nodeOrToken The node or token to insert after.
|
||||
* @param {string} text The text to insert.
|
||||
* @returns {Object} The fix command.
|
||||
*/
|
||||
insertTextAfter(nodeOrToken, text) {
|
||||
const range = this.#sourceCode.getRange(nodeOrToken);
|
||||
|
||||
return this.insertTextAfterRange(range, text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a fix command that inserts text after the specified range in the source text.
|
||||
* The fix is not applied until applyFixes() is called.
|
||||
* @param {SourceRange} range The range to replace, first item is start of range, second
|
||||
* is end of range.
|
||||
* @param {string} text The text to insert.
|
||||
* @returns {Object} The fix command.
|
||||
*/
|
||||
insertTextAfterRange(range, text) {
|
||||
return insertTextAt(range[1], text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a fix command that inserts text before the given node or token.
|
||||
* The fix is not applied until applyFixes() is called.
|
||||
* @param {ASTNode|Token} nodeOrToken The node or token to insert before.
|
||||
* @param {string} text The text to insert.
|
||||
* @returns {Object} The fix command.
|
||||
*/
|
||||
insertTextBefore(nodeOrToken, text) {
|
||||
const range = this.#sourceCode.getRange(nodeOrToken);
|
||||
|
||||
return this.insertTextBeforeRange(range, text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a fix command that inserts text before the specified range in the source text.
|
||||
* The fix is not applied until applyFixes() is called.
|
||||
* @param {SourceRange} range The range to replace, first item is start of range, second
|
||||
* is end of range.
|
||||
* @param {string} text The text to insert.
|
||||
* @returns {Object} The fix command.
|
||||
*/
|
||||
insertTextBeforeRange(range, text) {
|
||||
return insertTextAt(range[0], text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a fix command that replaces text at the node or token.
|
||||
* The fix is not applied until applyFixes() is called.
|
||||
* @param {ASTNode|Token} nodeOrToken The node or token to remove.
|
||||
* @param {string} text The text to insert.
|
||||
* @returns {Object} The fix command.
|
||||
*/
|
||||
replaceText(nodeOrToken, text) {
|
||||
const range = this.#sourceCode.getRange(nodeOrToken);
|
||||
|
||||
return this.replaceTextRange(range, text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a fix command that replaces text at the specified range in the source text.
|
||||
* The fix is not applied until applyFixes() is called.
|
||||
* @param {SourceRange} range The range to replace, first item is start of range, second
|
||||
* is end of range.
|
||||
* @param {string} text The text to insert.
|
||||
* @returns {Object} The fix command.
|
||||
*/
|
||||
replaceTextRange(range, text) {
|
||||
return {
|
||||
range,
|
||||
text,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a fix command that removes the node or token from the source.
|
||||
* The fix is not applied until applyFixes() is called.
|
||||
* @param {ASTNode|Token} nodeOrToken The node or token to remove.
|
||||
* @returns {Object} The fix command.
|
||||
*/
|
||||
remove(nodeOrToken) {
|
||||
const range = this.#sourceCode.getRange(nodeOrToken);
|
||||
|
||||
return this.removeRange(range);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a fix command that removes the specified range of text from the source.
|
||||
* The fix is not applied until applyFixes() is called.
|
||||
* @param {SourceRange} range The range to remove, first item is start of range, second
|
||||
* is end of range.
|
||||
* @returns {Object} The fix command.
|
||||
*/
|
||||
removeRange(range) {
|
||||
return {
|
||||
range,
|
||||
text: "",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { RuleFixer };
|
||||
71
slider/node_modules/eslint/lib/linter/rules.js
generated
vendored
Normal file
71
slider/node_modules/eslint/lib/linter/rules.js
generated
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* @fileoverview Defines a storage for rules.
|
||||
* @author Nicholas C. Zakas
|
||||
* @author aladdin-add
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const builtInRules = require("../rules");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Typedefs
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @typedef {import("../types").Rule.RuleModule} Rule */
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Public Interface
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* A storage for rules.
|
||||
*/
|
||||
class Rules {
|
||||
constructor() {
|
||||
this._rules = Object.create(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a rule module for rule id in storage.
|
||||
* @param {string} ruleId Rule id (file name).
|
||||
* @param {Rule} rule Rule object.
|
||||
* @returns {void}
|
||||
*/
|
||||
define(ruleId, rule) {
|
||||
this._rules[ruleId] = rule;
|
||||
}
|
||||
|
||||
/**
|
||||
* Access rule handler by id (file name).
|
||||
* @param {string} ruleId Rule id (file name).
|
||||
* @returns {Rule} Rule object.
|
||||
*/
|
||||
get(ruleId) {
|
||||
if (typeof this._rules[ruleId] === "string") {
|
||||
this.define(ruleId, require(this._rules[ruleId]));
|
||||
}
|
||||
if (this._rules[ruleId]) {
|
||||
return this._rules[ruleId];
|
||||
}
|
||||
if (builtInRules.has(ruleId)) {
|
||||
return builtInRules.get(ruleId);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
*[Symbol.iterator]() {
|
||||
yield* builtInRules;
|
||||
|
||||
for (const ruleId of Object.keys(this._rules)) {
|
||||
yield [ruleId, this.get(ruleId)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Rules;
|
||||
154
slider/node_modules/eslint/lib/linter/source-code-fixer.js
generated
vendored
Normal file
154
slider/node_modules/eslint/lib/linter/source-code-fixer.js
generated
vendored
Normal file
@@ -0,0 +1,154 @@
|
||||
/**
|
||||
* @fileoverview An object that caches and applies source code fixes.
|
||||
* @author Nicholas C. Zakas
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const debug = require("debug")("eslint:source-code-fixer");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const BOM = "\uFEFF";
|
||||
|
||||
/**
|
||||
* Compares items in a messages array by range.
|
||||
* @param {Message} a The first message.
|
||||
* @param {Message} b The second message.
|
||||
* @returns {number} -1 if a comes before b, 1 if a comes after b, 0 if equal.
|
||||
* @private
|
||||
*/
|
||||
function compareMessagesByFixRange(a, b) {
|
||||
return a.fix.range[0] - b.fix.range[0] || a.fix.range[1] - b.fix.range[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares items in a messages array by line and column.
|
||||
* @param {Message} a The first message.
|
||||
* @param {Message} b The second message.
|
||||
* @returns {number} -1 if a comes before b, 1 if a comes after b, 0 if equal.
|
||||
* @private
|
||||
*/
|
||||
function compareMessagesByLocation(a, b) {
|
||||
return a.line - b.line || a.column - b.column;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Public Interface
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Utility for apply fixes to source code.
|
||||
* @constructor
|
||||
*/
|
||||
function SourceCodeFixer() {
|
||||
Object.freeze(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the fixes specified by the messages to the given text. Tries to be
|
||||
* smart about the fixes and won't apply fixes over the same area in the text.
|
||||
* @param {string} sourceText The text to apply the changes to.
|
||||
* @param {Message[]} messages The array of messages reported by ESLint.
|
||||
* @param {boolean|Function} [shouldFix=true] Determines whether each message should be fixed
|
||||
* @returns {Object} An object containing the fixed text and any unfixed messages.
|
||||
*/
|
||||
SourceCodeFixer.applyFixes = function (sourceText, messages, shouldFix) {
|
||||
debug("Applying fixes");
|
||||
|
||||
if (shouldFix === false) {
|
||||
debug("shouldFix parameter was false, not attempting fixes");
|
||||
return {
|
||||
fixed: false,
|
||||
messages,
|
||||
output: sourceText,
|
||||
};
|
||||
}
|
||||
|
||||
// clone the array
|
||||
const remainingMessages = [],
|
||||
fixes = [],
|
||||
bom = sourceText.startsWith(BOM) ? BOM : "",
|
||||
text = bom ? sourceText.slice(1) : sourceText;
|
||||
let lastPos = Number.NEGATIVE_INFINITY,
|
||||
output = bom;
|
||||
|
||||
/**
|
||||
* Try to use the 'fix' from a problem.
|
||||
* @param {Message} problem The message object to apply fixes from
|
||||
* @returns {boolean} Whether fix was successfully applied
|
||||
*/
|
||||
function attemptFix(problem) {
|
||||
const fix = problem.fix;
|
||||
const start = fix.range[0];
|
||||
const end = fix.range[1];
|
||||
|
||||
// Remain it as a problem if it's overlapped or it's a negative range
|
||||
if (lastPos >= start || start > end) {
|
||||
remainingMessages.push(problem);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Remove BOM.
|
||||
if (
|
||||
(start < 0 && end >= 0) ||
|
||||
(start === 0 && fix.text.startsWith(BOM))
|
||||
) {
|
||||
output = "";
|
||||
}
|
||||
|
||||
// Make output to this fix.
|
||||
output += text.slice(Math.max(0, lastPos), Math.max(0, start));
|
||||
output += fix.text;
|
||||
lastPos = end;
|
||||
return true;
|
||||
}
|
||||
|
||||
messages.forEach(problem => {
|
||||
if (Object.hasOwn(problem, "fix") && problem.fix) {
|
||||
fixes.push(problem);
|
||||
} else {
|
||||
remainingMessages.push(problem);
|
||||
}
|
||||
});
|
||||
|
||||
if (fixes.length) {
|
||||
debug("Found fixes to apply");
|
||||
let fixesWereApplied = false;
|
||||
|
||||
for (const problem of fixes.sort(compareMessagesByFixRange)) {
|
||||
if (typeof shouldFix !== "function" || shouldFix(problem)) {
|
||||
attemptFix(problem);
|
||||
|
||||
/*
|
||||
* The only time attemptFix will fail is if a previous fix was
|
||||
* applied which conflicts with it. So we can mark this as true.
|
||||
*/
|
||||
fixesWereApplied = true;
|
||||
} else {
|
||||
remainingMessages.push(problem);
|
||||
}
|
||||
}
|
||||
output += text.slice(Math.max(0, lastPos));
|
||||
|
||||
return {
|
||||
fixed: fixesWereApplied,
|
||||
messages: remainingMessages.sort(compareMessagesByLocation),
|
||||
output,
|
||||
};
|
||||
}
|
||||
|
||||
debug("No fixes to apply");
|
||||
return {
|
||||
fixed: false,
|
||||
messages,
|
||||
output: bom + text,
|
||||
};
|
||||
};
|
||||
|
||||
module.exports = SourceCodeFixer;
|
||||
327
slider/node_modules/eslint/lib/linter/source-code-traverser.js
generated
vendored
Normal file
327
slider/node_modules/eslint/lib/linter/source-code-traverser.js
generated
vendored
Normal file
@@ -0,0 +1,327 @@
|
||||
/**
|
||||
* @fileoverview Traverser for SourceCode objects.
|
||||
* @author Nicholas C. Zakas
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const { parse, matches } = require("./esquery");
|
||||
const vk = require("eslint-visitor-keys");
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Typedefs
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @import { ESQueryParsedSelector } from "./esquery.js";
|
||||
* @import { Language, SourceCode } from "@eslint/core";
|
||||
* @import { SourceCodeVisitor } from "./source-code-visitor.js";
|
||||
*/
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
const STEP_KIND_VISIT = 1;
|
||||
const STEP_KIND_CALL = 2;
|
||||
|
||||
/**
|
||||
* Compares two ESQuery selectors by specificity.
|
||||
* @param {ESQueryParsedSelector} a The first selector to compare.
|
||||
* @param {ESQueryParsedSelector} b The second selector to compare.
|
||||
* @returns {number} A negative number if `a` is less specific than `b` or they are equally specific and `a` <= `b` alphabetically, a positive number if `a` is more specific than `b`.
|
||||
*/
|
||||
function compareSpecificity(a, b) {
|
||||
return a.compare(b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to wrap ESQuery operations.
|
||||
*/
|
||||
class ESQueryHelper {
|
||||
/**
|
||||
* Creates a new instance.
|
||||
* @param {SourceCodeVisitor} visitor The visitor containing the functions to call.
|
||||
* @param {ESQueryOptions} esqueryOptions `esquery` options for traversing custom nodes.
|
||||
* @returns {NodeEventGenerator} new instance
|
||||
*/
|
||||
constructor(visitor, esqueryOptions) {
|
||||
/**
|
||||
* The emitter to use during traversal.
|
||||
* @type {SourceCodeVisitor}
|
||||
*/
|
||||
this.visitor = visitor;
|
||||
|
||||
/**
|
||||
* The options for `esquery` to use during matching.
|
||||
* @type {ESQueryOptions}
|
||||
*/
|
||||
this.esqueryOptions = esqueryOptions;
|
||||
|
||||
/**
|
||||
* A map of node type to selectors targeting that node type on the
|
||||
* enter phase of traversal.
|
||||
* @type {Map<string, ESQueryParsedSelector[]>}
|
||||
*/
|
||||
this.enterSelectorsByNodeType = new Map();
|
||||
|
||||
/**
|
||||
* A map of node type to selectors targeting that node type on the
|
||||
* exit phase of traversal.
|
||||
* @type {Map<string, ESQueryParsedSelector[]>}
|
||||
*/
|
||||
this.exitSelectorsByNodeType = new Map();
|
||||
|
||||
/**
|
||||
* An array of selectors that match any node type on the
|
||||
* enter phase of traversal.
|
||||
* @type {ESQueryParsedSelector[]}
|
||||
*/
|
||||
this.anyTypeEnterSelectors = [];
|
||||
|
||||
/**
|
||||
* An array of selectors that match any node type on the
|
||||
* exit phase of traversal.
|
||||
* @type {ESQueryParsedSelector[]}
|
||||
*/
|
||||
this.anyTypeExitSelectors = [];
|
||||
|
||||
visitor.forEachName(rawSelector => {
|
||||
const selector = parse(rawSelector);
|
||||
|
||||
/*
|
||||
* If this selector has identified specific node types,
|
||||
* add it to the map for these node types for faster lookup.
|
||||
*/
|
||||
if (selector.nodeTypes) {
|
||||
const typeMap = selector.isExit
|
||||
? this.exitSelectorsByNodeType
|
||||
: this.enterSelectorsByNodeType;
|
||||
|
||||
selector.nodeTypes.forEach(nodeType => {
|
||||
if (!typeMap.has(nodeType)) {
|
||||
typeMap.set(nodeType, []);
|
||||
}
|
||||
typeMap.get(nodeType).push(selector);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remaining selectors are added to the "any type" selectors
|
||||
* list for the appropriate phase of traversal. This ensures
|
||||
* that all selectors will still be applied even if no
|
||||
* specific node type is matched.
|
||||
*/
|
||||
const selectors = selector.isExit
|
||||
? this.anyTypeExitSelectors
|
||||
: this.anyTypeEnterSelectors;
|
||||
|
||||
selectors.push(selector);
|
||||
});
|
||||
|
||||
// sort all selectors by specificity for prioritizing call order
|
||||
this.anyTypeEnterSelectors.sort(compareSpecificity);
|
||||
this.anyTypeExitSelectors.sort(compareSpecificity);
|
||||
this.enterSelectorsByNodeType.forEach(selectorList =>
|
||||
selectorList.sort(compareSpecificity),
|
||||
);
|
||||
this.exitSelectorsByNodeType.forEach(selectorList =>
|
||||
selectorList.sort(compareSpecificity),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a node matches a given selector.
|
||||
* @param {ASTNode} node The node to check
|
||||
* @param {ASTNode[]} ancestry The ancestry of the node being checked.
|
||||
* @param {ESQueryParsedSelector} selector An AST selector descriptor
|
||||
* @returns {boolean} `true` if the selector matches the node, `false` otherwise
|
||||
*/
|
||||
matches(node, ancestry, selector) {
|
||||
return matches(node, selector.root, ancestry, this.esqueryOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates all appropriate selectors to a node, in specificity order
|
||||
* @param {ASTNode} node The node to check
|
||||
* @param {ASTNode[]} ancestry The ancestry of the node being checked.
|
||||
* @param {boolean} isExit `false` if the node is currently being entered, `true` if it's currently being exited
|
||||
* @returns {string[]} An array of selectors that match the node.
|
||||
*/
|
||||
calculateSelectors(node, ancestry, isExit) {
|
||||
const nodeTypeKey = this.esqueryOptions?.nodeTypeKey || "type";
|
||||
const selectors = [];
|
||||
|
||||
/*
|
||||
* Get the selectors that may match this node. First, check
|
||||
* to see if the node type has specific selectors,
|
||||
* then gather the "any type" selectors.
|
||||
*/
|
||||
const selectorsByNodeType =
|
||||
(isExit
|
||||
? this.exitSelectorsByNodeType
|
||||
: this.enterSelectorsByNodeType
|
||||
).get(node[nodeTypeKey]) || [];
|
||||
const anyTypeSelectors = isExit
|
||||
? this.anyTypeExitSelectors
|
||||
: this.anyTypeEnterSelectors;
|
||||
|
||||
/*
|
||||
* selectorsByNodeType and anyTypeSelectors were already sorted by specificity in the constructor.
|
||||
* Iterate through each of them, applying selectors in the right order.
|
||||
*/
|
||||
let selectorsByNodeTypeIndex = 0;
|
||||
let anyTypeSelectorsIndex = 0;
|
||||
|
||||
while (
|
||||
selectorsByNodeTypeIndex < selectorsByNodeType.length ||
|
||||
anyTypeSelectorsIndex < anyTypeSelectors.length
|
||||
) {
|
||||
/*
|
||||
* If we've already exhausted the selectors for this node type,
|
||||
* or if the next any type selector is more specific than the
|
||||
* next selector for this node type, apply the any type selector.
|
||||
*/
|
||||
const hasMoreNodeTypeSelectors =
|
||||
selectorsByNodeTypeIndex < selectorsByNodeType.length;
|
||||
const hasMoreAnyTypeSelectors =
|
||||
anyTypeSelectorsIndex < anyTypeSelectors.length;
|
||||
const anyTypeSelector = anyTypeSelectors[anyTypeSelectorsIndex];
|
||||
const nodeTypeSelector =
|
||||
selectorsByNodeType[selectorsByNodeTypeIndex];
|
||||
|
||||
// Only compare specificity if both selectors exist
|
||||
const isAnyTypeSelectorLessSpecific =
|
||||
hasMoreAnyTypeSelectors &&
|
||||
hasMoreNodeTypeSelectors &&
|
||||
anyTypeSelector.compare(nodeTypeSelector) < 0;
|
||||
|
||||
if (!hasMoreNodeTypeSelectors || isAnyTypeSelectorLessSpecific) {
|
||||
anyTypeSelectorsIndex++;
|
||||
|
||||
if (this.matches(node, ancestry, anyTypeSelector)) {
|
||||
selectors.push(anyTypeSelector.source);
|
||||
}
|
||||
} else {
|
||||
selectorsByNodeTypeIndex++;
|
||||
|
||||
if (this.matches(node, ancestry, nodeTypeSelector)) {
|
||||
selectors.push(nodeTypeSelector.source);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return selectors;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Public Interface
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Traverses source code and ensures that visitor methods are called when
|
||||
* entering and leaving each node.
|
||||
*/
|
||||
class SourceCodeTraverser {
|
||||
/**
|
||||
* The language of the source code being traversed.
|
||||
* @type {Language}
|
||||
*/
|
||||
#language;
|
||||
|
||||
/**
|
||||
* Map of languages to instances of this class.
|
||||
* @type {WeakMap<Language, SourceCodeTraverser>}
|
||||
*/
|
||||
static instances = new WeakMap();
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
* @param {Language} language The language of the source code being traversed.
|
||||
*/
|
||||
constructor(language) {
|
||||
this.#language = language;
|
||||
}
|
||||
|
||||
static getInstance(language) {
|
||||
if (!this.instances.has(language)) {
|
||||
this.instances.set(language, new this(language));
|
||||
}
|
||||
|
||||
return this.instances.get(language);
|
||||
}
|
||||
|
||||
/**
|
||||
* Traverses the given source code synchronously.
|
||||
* @param {SourceCode} sourceCode The source code to traverse.
|
||||
* @param {SourceCodeVisitor} visitor The emitter to use for events.
|
||||
* @param {Object} options Options for traversal.
|
||||
* @param {ReturnType<SourceCode["traverse"]>} options.steps The steps to take during traversal.
|
||||
* @returns {void}
|
||||
* @throws {Error} If an error occurs during traversal.
|
||||
*/
|
||||
traverseSync(sourceCode, visitor, { steps } = {}) {
|
||||
const esquery = new ESQueryHelper(visitor, {
|
||||
visitorKeys: sourceCode.visitorKeys ?? this.#language.visitorKeys,
|
||||
fallback: vk.getKeys,
|
||||
matchClass: this.#language.matchesSelectorClass ?? (() => false),
|
||||
nodeTypeKey: this.#language.nodeTypeKey,
|
||||
});
|
||||
|
||||
const currentAncestry = [];
|
||||
|
||||
for (const step of steps ?? sourceCode.traverse()) {
|
||||
switch (step.kind) {
|
||||
case STEP_KIND_VISIT: {
|
||||
try {
|
||||
if (step.phase === 1) {
|
||||
esquery
|
||||
.calculateSelectors(
|
||||
step.target,
|
||||
currentAncestry,
|
||||
false,
|
||||
)
|
||||
.forEach(selector => {
|
||||
visitor.callSync(selector, step.target);
|
||||
});
|
||||
currentAncestry.unshift(step.target);
|
||||
} else {
|
||||
currentAncestry.shift();
|
||||
esquery
|
||||
.calculateSelectors(
|
||||
step.target,
|
||||
currentAncestry,
|
||||
true,
|
||||
)
|
||||
.forEach(selector => {
|
||||
visitor.callSync(selector, step.target);
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
err.currentNode = step.target;
|
||||
throw err;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case STEP_KIND_CALL: {
|
||||
visitor.callSync(step.target, ...step.args);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
throw new Error(
|
||||
`Invalid traversal step found: "${step.kind}".`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { SourceCodeTraverser };
|
||||
81
slider/node_modules/eslint/lib/linter/source-code-visitor.js
generated
vendored
Normal file
81
slider/node_modules/eslint/lib/linter/source-code-visitor.js
generated
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
/**
|
||||
* @fileoverview SourceCodeVisitor class
|
||||
* @author Nicholas C. Zakas
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
const emptyArray = Object.freeze([]);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Exports
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* A structure to hold a list of functions to call for a given name.
|
||||
* This is used to allow multiple rules to register functions for a given name
|
||||
* without having to know about each other.
|
||||
*/
|
||||
class SourceCodeVisitor {
|
||||
/**
|
||||
* The functions to call for a given name.
|
||||
* @type {Map<string, Function[]>}
|
||||
*/
|
||||
#functions = new Map();
|
||||
|
||||
/**
|
||||
* Adds a function to the list of functions to call for a given name.
|
||||
* @param {string} name The name of the function to call.
|
||||
* @param {Function} func The function to call.
|
||||
* @returns {void}
|
||||
*/
|
||||
add(name, func) {
|
||||
if (this.#functions.has(name)) {
|
||||
this.#functions.get(name).push(func);
|
||||
} else {
|
||||
this.#functions.set(name, [func]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the list of functions to call for a given name.
|
||||
* @param {string} name The name of the function to call.
|
||||
* @returns {Function[]} The list of functions to call.
|
||||
*/
|
||||
get(name) {
|
||||
if (this.#functions.has(name)) {
|
||||
return this.#functions.get(name);
|
||||
}
|
||||
|
||||
return emptyArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates over all names and calls the callback with the name.
|
||||
* @param {(name:string) => void} callback The callback to call for each name.
|
||||
* @returns {void}
|
||||
*/
|
||||
forEachName(callback) {
|
||||
this.#functions.forEach((funcs, name) => {
|
||||
callback(name);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the functions for a given name with the given arguments.
|
||||
* @param {string} name The name of the function to call.
|
||||
* @param {any[]} args The arguments to pass to the function.
|
||||
* @returns {void}
|
||||
*/
|
||||
callSync(name, ...args) {
|
||||
if (this.#functions.has(name)) {
|
||||
this.#functions.get(name).forEach(func => func(...args));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { SourceCodeVisitor };
|
||||
172
slider/node_modules/eslint/lib/linter/timing.js
generated
vendored
Normal file
172
slider/node_modules/eslint/lib/linter/timing.js
generated
vendored
Normal file
@@ -0,0 +1,172 @@
|
||||
/**
|
||||
* @fileoverview Tracks performance of individual rules.
|
||||
* @author Brandon Mills
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
const { startTime, endTime } = require("../shared/stats");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/* c8 ignore next */
|
||||
/**
|
||||
* Align the string to left
|
||||
* @param {string} str string to evaluate
|
||||
* @param {number} len length of the string
|
||||
* @param {string} ch delimiter character
|
||||
* @returns {string} modified string
|
||||
* @private
|
||||
*/
|
||||
function alignLeft(str, len, ch) {
|
||||
return str + new Array(len - str.length + 1).join(ch || " ");
|
||||
}
|
||||
|
||||
/* c8 ignore next */
|
||||
/**
|
||||
* Align the string to right
|
||||
* @param {string} str string to evaluate
|
||||
* @param {number} len length of the string
|
||||
* @param {string} ch delimiter character
|
||||
* @returns {string} modified string
|
||||
* @private
|
||||
*/
|
||||
function alignRight(str, len, ch) {
|
||||
return new Array(len - str.length + 1).join(ch || " ") + str;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Module definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const enabled = !!process.env.TIMING;
|
||||
|
||||
const HEADERS = ["Rule", "Time (ms)", "Relative"];
|
||||
const ALIGN = [alignLeft, alignRight, alignRight];
|
||||
|
||||
/**
|
||||
* Decide how many rules to show in the output list.
|
||||
* @returns {number} the number of rules to show
|
||||
*/
|
||||
function getListSize() {
|
||||
const MINIMUM_SIZE = 10;
|
||||
|
||||
if (typeof process.env.TIMING !== "string") {
|
||||
return MINIMUM_SIZE;
|
||||
}
|
||||
|
||||
if (process.env.TIMING.toLowerCase() === "all") {
|
||||
return Number.POSITIVE_INFINITY;
|
||||
}
|
||||
|
||||
const TIMING_ENV_VAR_AS_INTEGER = Number.parseInt(process.env.TIMING, 10);
|
||||
|
||||
return TIMING_ENV_VAR_AS_INTEGER > 10
|
||||
? TIMING_ENV_VAR_AS_INTEGER
|
||||
: MINIMUM_SIZE;
|
||||
}
|
||||
|
||||
/* c8 ignore next */
|
||||
/**
|
||||
* display the data
|
||||
* @param {Object} data Data object to be displayed
|
||||
* @returns {void} prints modified string with console.log
|
||||
* @private
|
||||
*/
|
||||
function display(data) {
|
||||
let total = 0;
|
||||
const rows = Object.keys(data)
|
||||
.map(key => {
|
||||
const time = data[key];
|
||||
|
||||
total += time;
|
||||
return [key, time];
|
||||
})
|
||||
.sort((a, b) => b[1] - a[1])
|
||||
.slice(0, getListSize());
|
||||
|
||||
rows.forEach(row => {
|
||||
row.push(`${((row[1] * 100) / total).toFixed(1)}%`);
|
||||
row[1] = row[1].toFixed(3);
|
||||
});
|
||||
|
||||
rows.unshift(HEADERS);
|
||||
|
||||
const widths = [];
|
||||
|
||||
rows.forEach(row => {
|
||||
const len = row.length;
|
||||
|
||||
for (let i = 0; i < len; i++) {
|
||||
const n = row[i].length;
|
||||
|
||||
if (!widths[i] || n > widths[i]) {
|
||||
widths[i] = n;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const table = rows.map(row =>
|
||||
row.map((cell, index) => ALIGN[index](cell, widths[index])).join(" | "),
|
||||
);
|
||||
|
||||
table.splice(
|
||||
1,
|
||||
0,
|
||||
widths
|
||||
.map((width, index) => {
|
||||
const extraAlignment =
|
||||
index !== 0 && index !== widths.length - 1 ? 2 : 1;
|
||||
|
||||
return ALIGN[index](":", width + extraAlignment, "-");
|
||||
})
|
||||
.join("|"),
|
||||
);
|
||||
|
||||
console.log(table.join("\n")); // eslint-disable-line no-console -- Debugging function
|
||||
}
|
||||
|
||||
/* c8 ignore next */
|
||||
module.exports = (function () {
|
||||
const data = Object.create(null);
|
||||
|
||||
/**
|
||||
* Time the run
|
||||
* @param {any} key key from the data object
|
||||
* @param {Function} fn function to be called
|
||||
* @param {boolean} stats if 'stats' is true, return the result and the time difference
|
||||
* @returns {Function} function to be executed
|
||||
* @private
|
||||
*/
|
||||
function time(key, fn, stats) {
|
||||
return function (...args) {
|
||||
const t = startTime();
|
||||
const result = fn(...args);
|
||||
const tdiff = endTime(t);
|
||||
|
||||
if (enabled) {
|
||||
if (typeof data[key] === "undefined") {
|
||||
data[key] = 0;
|
||||
}
|
||||
|
||||
data[key] += tdiff;
|
||||
}
|
||||
|
||||
return stats ? { result, tdiff } : result;
|
||||
};
|
||||
}
|
||||
|
||||
if (enabled) {
|
||||
process.on("exit", () => {
|
||||
display(data);
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
time,
|
||||
enabled,
|
||||
getListSize,
|
||||
};
|
||||
})();
|
||||
115
slider/node_modules/eslint/lib/linter/vfile.js
generated
vendored
Normal file
115
slider/node_modules/eslint/lib/linter/vfile.js
generated
vendored
Normal file
@@ -0,0 +1,115 @@
|
||||
/**
|
||||
* @fileoverview Virtual file
|
||||
* @author Nicholas C. Zakas
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Type Definitions
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/** @typedef {import("@eslint/core").File} File */
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Determines if a given value has a byte order mark (BOM).
|
||||
* @param {string|Uint8Array} value The value to check.
|
||||
* @returns {boolean} `true` if the value has a BOM, `false` otherwise.
|
||||
*/
|
||||
function hasUnicodeBOM(value) {
|
||||
return typeof value === "string"
|
||||
? value.charCodeAt(0) === 0xfeff
|
||||
: value[0] === 0xef && value[1] === 0xbb && value[2] === 0xbf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Strips Unicode BOM from the given value.
|
||||
* @param {string|Uint8Array} value The value to remove the BOM from.
|
||||
* @returns {string|Uint8Array} The stripped value.
|
||||
*/
|
||||
function stripUnicodeBOM(value) {
|
||||
if (!hasUnicodeBOM(value)) {
|
||||
return value;
|
||||
}
|
||||
|
||||
if (typeof value === "string") {
|
||||
/*
|
||||
* Check Unicode BOM.
|
||||
* In JavaScript, string data is stored as UTF-16, so BOM is 0xFEFF.
|
||||
* http://www.ecma-international.org/ecma-262/6.0/#sec-unicode-format-control-characters
|
||||
*/
|
||||
return value.slice(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* In a Uint8Array, the BOM is represented by three bytes: 0xEF, 0xBB, and 0xBF,
|
||||
* so we can just remove the first three bytes.
|
||||
*/
|
||||
return value.slice(3);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Exports
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Represents a virtual file inside of ESLint.
|
||||
* @implements {File}
|
||||
*/
|
||||
class VFile {
|
||||
/**
|
||||
* The file path including any processor-created virtual path.
|
||||
* @type {string}
|
||||
* @readonly
|
||||
*/
|
||||
path;
|
||||
|
||||
/**
|
||||
* The file path on disk.
|
||||
* @type {string}
|
||||
* @readonly
|
||||
*/
|
||||
physicalPath;
|
||||
|
||||
/**
|
||||
* The file contents.
|
||||
* @type {string|Uint8Array}
|
||||
* @readonly
|
||||
*/
|
||||
body;
|
||||
|
||||
/**
|
||||
* The raw body of the file, including a BOM if present.
|
||||
* @type {string|Uint8Array}
|
||||
* @readonly
|
||||
*/
|
||||
rawBody;
|
||||
|
||||
/**
|
||||
* Indicates whether the file has a byte order mark (BOM).
|
||||
* @type {boolean}
|
||||
* @readonly
|
||||
*/
|
||||
bom;
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
* @param {string} path The file path.
|
||||
* @param {string|Uint8Array} body The file contents.
|
||||
* @param {Object} [options] Additional options.
|
||||
* @param {string} [options.physicalPath] The file path on disk.
|
||||
*/
|
||||
constructor(path, body, { physicalPath } = {}) {
|
||||
this.path = path;
|
||||
this.physicalPath = physicalPath ?? path;
|
||||
this.bom = hasUnicodeBOM(body);
|
||||
this.body = stripUnicodeBOM(body);
|
||||
this.rawBody = body;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { VFile };
|
||||
536
slider/node_modules/eslint/lib/options.js
generated
vendored
Normal file
536
slider/node_modules/eslint/lib/options.js
generated
vendored
Normal file
@@ -0,0 +1,536 @@
|
||||
/**
|
||||
* @fileoverview Options configuration for optionator.
|
||||
* @author George Zahariev
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const optionator = require("optionator");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Typedefs
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* The options object parsed by Optionator.
|
||||
* @typedef {Object} ParsedCLIOptions
|
||||
* @property {boolean} cache Only check changed files
|
||||
* @property {string} cacheFile Path to the cache file. Deprecated: use --cache-location
|
||||
* @property {string} [cacheLocation] Path to the cache file or directory
|
||||
* @property {"metadata" | "content"} cacheStrategy Strategy to use for detecting changed files in the cache
|
||||
* @property {boolean} [color] Force enabling/disabling of color
|
||||
* @property {number | "auto" | "off"} [concurrency] Number of linting threads, "auto" to choose automatically, "off" for no multithreading
|
||||
* @property {string} [config] Use this configuration, overriding .eslintrc.* config options if present
|
||||
* @property {boolean} debug Output debugging information
|
||||
* @property {string[]} [env] Specify environments
|
||||
* @property {boolean} envInfo Output execution environment information
|
||||
* @property {boolean} errorOnUnmatchedPattern Prevent errors when pattern is unmatched
|
||||
* @property {boolean} eslintrc Disable use of configuration from .eslintrc.*
|
||||
* @property {string[]} [ext] Specify JavaScript file extensions
|
||||
* @property {string[]} [flag] Feature flags
|
||||
* @property {boolean} fix Automatically fix problems
|
||||
* @property {boolean} fixDryRun Automatically fix problems without saving the changes to the file system
|
||||
* @property {("directive" | "problem" | "suggestion" | "layout")[]} [fixType] Specify the types of fixes to apply (directive, problem, suggestion, layout)
|
||||
* @property {string} format Use a specific output format
|
||||
* @property {string[]} [global] Define global variables
|
||||
* @property {boolean} [help] Show help
|
||||
* @property {boolean} ignore Disable use of ignore files and patterns
|
||||
* @property {string} [ignorePath] Specify path of ignore file
|
||||
* @property {string[]} [ignorePattern] Patterns of files to ignore. In eslintrc mode, these are in addition to `.eslintignore`
|
||||
* @property {boolean} init Run config initialization wizard
|
||||
* @property {boolean} inlineConfig Prevent comments from changing config or rules
|
||||
* @property {number} maxWarnings Number of warnings to trigger nonzero exit code
|
||||
* @property {string} [outputFile] Specify file to write report to
|
||||
* @property {string} [parser] Specify the parser to be used
|
||||
* @property {Object} [parserOptions] Specify parser options
|
||||
* @property {boolean} [passOnNoPatterns=false] When set to true, missing patterns cause
|
||||
* the linting operation to short circuit and not report any failures.
|
||||
* @property {boolean} [passOnUnprunedSuppressions] Ignore unused suppressions
|
||||
* @property {string[]} [plugin] Specify plugins
|
||||
* @property {string} [printConfig] Print the configuration for the given file
|
||||
* @property {boolean} [pruneSuppressions] Prune unused suppressions
|
||||
* @property {boolean} quiet Report errors only
|
||||
* @property {boolean | undefined} reportUnusedDisableDirectives Adds reported errors for unused eslint-disable and eslint-enable directives
|
||||
* @property {string | undefined} reportUnusedDisableDirectivesSeverity A severity string indicating if and how unused disable and enable directives should be tracked and reported.
|
||||
* @property {string} [resolvePluginsRelativeTo] A folder where plugins should be resolved from, CWD by default
|
||||
* @property {Object} [rule] Specify rules
|
||||
* @property {string[]} [rulesdir] Load additional rules from this directory. Deprecated: Use rules from plugins
|
||||
* @property {boolean} [stats] Report additional statistics
|
||||
* @property {boolean} stdin Lint code provided on <STDIN>
|
||||
* @property {string} [stdinFilename] Specify filename to process STDIN as
|
||||
* @property {boolean} [suppressAll] Suppress all error violations
|
||||
* @property {string} [suppressionsLocation] Path to the suppressions file or directory
|
||||
* @property {string[]} [suppressRule] Suppress specific rules
|
||||
* @property {boolean} [version] Output the version number
|
||||
* @property {boolean} warnIgnored Show warnings when the file list includes ignored files
|
||||
* @property {string[]} _ Positional filenames or patterns
|
||||
*/
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Initialization and Public Interface
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// exports "parse(args)", "generateHelp()", and "generateHelpForOption(optionName)"
|
||||
|
||||
/**
|
||||
* Creates the CLI options for ESLint.
|
||||
* @param {boolean} usingFlatConfig Indicates if flat config is being used.
|
||||
* @returns {Object} The optionator instance.
|
||||
*/
|
||||
module.exports = function (usingFlatConfig) {
|
||||
let lookupFlag;
|
||||
|
||||
if (usingFlatConfig) {
|
||||
lookupFlag = {
|
||||
option: "config-lookup",
|
||||
type: "Boolean",
|
||||
default: "true",
|
||||
description: "Disable look up for eslint.config.js",
|
||||
};
|
||||
} else {
|
||||
lookupFlag = {
|
||||
option: "eslintrc",
|
||||
type: "Boolean",
|
||||
default: "true",
|
||||
description: "Disable use of configuration from .eslintrc.*",
|
||||
};
|
||||
}
|
||||
|
||||
let envFlag;
|
||||
|
||||
if (!usingFlatConfig) {
|
||||
envFlag = {
|
||||
option: "env",
|
||||
type: "[String]",
|
||||
description: "Specify environments",
|
||||
};
|
||||
}
|
||||
|
||||
let inspectConfigFlag;
|
||||
|
||||
if (usingFlatConfig) {
|
||||
inspectConfigFlag = {
|
||||
option: "inspect-config",
|
||||
type: "Boolean",
|
||||
description:
|
||||
"Open the config inspector with the current configuration",
|
||||
};
|
||||
}
|
||||
|
||||
let extFlag;
|
||||
|
||||
if (!usingFlatConfig) {
|
||||
extFlag = {
|
||||
option: "ext",
|
||||
type: "[String]",
|
||||
description: "Specify JavaScript file extensions",
|
||||
};
|
||||
} else {
|
||||
extFlag = {
|
||||
option: "ext",
|
||||
type: "[String]",
|
||||
description: "Specify additional file extensions to lint",
|
||||
};
|
||||
}
|
||||
|
||||
let resolvePluginsFlag;
|
||||
|
||||
if (!usingFlatConfig) {
|
||||
resolvePluginsFlag = {
|
||||
option: "resolve-plugins-relative-to",
|
||||
type: "path::String",
|
||||
description:
|
||||
"A folder where plugins should be resolved from, CWD by default",
|
||||
};
|
||||
}
|
||||
|
||||
let rulesDirFlag;
|
||||
|
||||
if (!usingFlatConfig) {
|
||||
rulesDirFlag = {
|
||||
option: "rulesdir",
|
||||
type: "[path::String]",
|
||||
description:
|
||||
"Load additional rules from this directory. Deprecated: Use rules from plugins",
|
||||
};
|
||||
}
|
||||
|
||||
let ignorePathFlag;
|
||||
|
||||
if (!usingFlatConfig) {
|
||||
ignorePathFlag = {
|
||||
option: "ignore-path",
|
||||
type: "path::String",
|
||||
description: "Specify path of ignore file",
|
||||
};
|
||||
}
|
||||
|
||||
let statsFlag;
|
||||
|
||||
if (usingFlatConfig) {
|
||||
statsFlag = {
|
||||
option: "stats",
|
||||
type: "Boolean",
|
||||
default: "false",
|
||||
description: "Add statistics to the lint report",
|
||||
};
|
||||
}
|
||||
|
||||
let warnIgnoredFlag;
|
||||
|
||||
if (usingFlatConfig) {
|
||||
warnIgnoredFlag = {
|
||||
option: "warn-ignored",
|
||||
type: "Boolean",
|
||||
default: "true",
|
||||
description:
|
||||
"Suppress warnings when the file list includes ignored files",
|
||||
};
|
||||
}
|
||||
|
||||
let flagFlag;
|
||||
|
||||
if (usingFlatConfig) {
|
||||
flagFlag = {
|
||||
option: "flag",
|
||||
type: "[String]",
|
||||
description: "Enable a feature flag",
|
||||
};
|
||||
}
|
||||
|
||||
let reportUnusedInlineConfigsFlag;
|
||||
|
||||
if (usingFlatConfig) {
|
||||
reportUnusedInlineConfigsFlag = {
|
||||
option: "report-unused-inline-configs",
|
||||
type: "String",
|
||||
default: void 0,
|
||||
description:
|
||||
"Adds reported errors for unused eslint inline config comments",
|
||||
enum: ["off", "warn", "error", "0", "1", "2"],
|
||||
};
|
||||
}
|
||||
|
||||
let mcpFlag;
|
||||
|
||||
if (usingFlatConfig) {
|
||||
mcpFlag = {
|
||||
option: "mcp",
|
||||
type: "Boolean",
|
||||
description: "Start the ESLint MCP server",
|
||||
};
|
||||
}
|
||||
|
||||
let concurrencyFlag;
|
||||
|
||||
if (usingFlatConfig) {
|
||||
concurrencyFlag = {
|
||||
option: "concurrency",
|
||||
type: "Int|String",
|
||||
default: "off",
|
||||
description:
|
||||
"Number of linting threads, auto to choose automatically, off for no multithreading",
|
||||
};
|
||||
}
|
||||
|
||||
return optionator({
|
||||
prepend: "eslint [options] file.js [file.js] [dir]",
|
||||
defaults: {
|
||||
concatRepeatedArrays: true,
|
||||
mergeRepeatedObjects: true,
|
||||
},
|
||||
options: [
|
||||
{
|
||||
heading: "Basic configuration",
|
||||
},
|
||||
lookupFlag,
|
||||
{
|
||||
option: "config",
|
||||
alias: "c",
|
||||
type: "path::String",
|
||||
description: usingFlatConfig
|
||||
? "Use this configuration instead of eslint.config.js, eslint.config.mjs, or eslint.config.cjs"
|
||||
: "Use this configuration, overriding .eslintrc.* config options if present",
|
||||
},
|
||||
inspectConfigFlag,
|
||||
envFlag,
|
||||
extFlag,
|
||||
{
|
||||
option: "global",
|
||||
type: "[String]",
|
||||
description: "Define global variables",
|
||||
},
|
||||
{
|
||||
option: "parser",
|
||||
type: "String",
|
||||
description: "Specify the parser to be used",
|
||||
},
|
||||
{
|
||||
option: "parser-options",
|
||||
type: "Object",
|
||||
description: "Specify parser options",
|
||||
},
|
||||
resolvePluginsFlag,
|
||||
{
|
||||
heading: "Specify Rules and Plugins",
|
||||
},
|
||||
{
|
||||
option: "plugin",
|
||||
type: "[String]",
|
||||
description: "Specify plugins",
|
||||
},
|
||||
{
|
||||
option: "rule",
|
||||
type: "Object",
|
||||
description: "Specify rules",
|
||||
},
|
||||
rulesDirFlag,
|
||||
{
|
||||
heading: "Fix Problems",
|
||||
},
|
||||
{
|
||||
option: "fix",
|
||||
type: "Boolean",
|
||||
default: false,
|
||||
description: "Automatically fix problems",
|
||||
},
|
||||
{
|
||||
option: "fix-dry-run",
|
||||
type: "Boolean",
|
||||
default: false,
|
||||
description:
|
||||
"Automatically fix problems without saving the changes to the file system",
|
||||
},
|
||||
{
|
||||
option: "fix-type",
|
||||
type: "Array",
|
||||
description:
|
||||
"Specify the types of fixes to apply (directive, problem, suggestion, layout)",
|
||||
},
|
||||
{
|
||||
heading: "Ignore Files",
|
||||
},
|
||||
ignorePathFlag,
|
||||
{
|
||||
option: "ignore",
|
||||
type: "Boolean",
|
||||
default: "true",
|
||||
description: "Disable use of ignore files and patterns",
|
||||
},
|
||||
{
|
||||
option: "ignore-pattern",
|
||||
type: "[String]",
|
||||
description: `Patterns of files to ignore${usingFlatConfig ? "" : " (in addition to those in .eslintignore)"}`,
|
||||
concatRepeatedArrays: [
|
||||
true,
|
||||
{
|
||||
oneValuePerFlag: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
heading: "Use stdin",
|
||||
},
|
||||
{
|
||||
option: "stdin",
|
||||
type: "Boolean",
|
||||
default: "false",
|
||||
description: "Lint code provided on <STDIN>",
|
||||
},
|
||||
{
|
||||
option: "stdin-filename",
|
||||
type: "String",
|
||||
description: "Specify filename to process STDIN as",
|
||||
},
|
||||
{
|
||||
heading: "Handle Warnings",
|
||||
},
|
||||
{
|
||||
option: "quiet",
|
||||
type: "Boolean",
|
||||
default: "false",
|
||||
description: "Report errors only",
|
||||
},
|
||||
{
|
||||
option: "max-warnings",
|
||||
type: "Int",
|
||||
default: "-1",
|
||||
description: "Number of warnings to trigger nonzero exit code",
|
||||
},
|
||||
{
|
||||
heading: "Output",
|
||||
},
|
||||
{
|
||||
option: "output-file",
|
||||
alias: "o",
|
||||
type: "path::String",
|
||||
description: "Specify file to write report to",
|
||||
},
|
||||
{
|
||||
option: "format",
|
||||
alias: "f",
|
||||
type: "String",
|
||||
default: "stylish",
|
||||
description: "Use a specific output format",
|
||||
},
|
||||
{
|
||||
option: "color",
|
||||
type: "Boolean",
|
||||
alias: "no-color",
|
||||
description: "Force enabling/disabling of color",
|
||||
},
|
||||
{
|
||||
heading: "Inline configuration comments",
|
||||
},
|
||||
{
|
||||
option: "inline-config",
|
||||
type: "Boolean",
|
||||
default: "true",
|
||||
description: "Prevent comments from changing config or rules",
|
||||
},
|
||||
{
|
||||
option: "report-unused-disable-directives",
|
||||
type: "Boolean",
|
||||
default: void 0,
|
||||
description:
|
||||
"Adds reported errors for unused eslint-disable and eslint-enable directives",
|
||||
},
|
||||
{
|
||||
option: "report-unused-disable-directives-severity",
|
||||
type: "String",
|
||||
default: void 0,
|
||||
description:
|
||||
"Chooses severity level for reporting unused eslint-disable and eslint-enable directives",
|
||||
enum: ["off", "warn", "error", "0", "1", "2"],
|
||||
},
|
||||
reportUnusedInlineConfigsFlag,
|
||||
{
|
||||
heading: "Caching",
|
||||
},
|
||||
{
|
||||
option: "cache",
|
||||
type: "Boolean",
|
||||
default: "false",
|
||||
description: "Only check changed files",
|
||||
},
|
||||
{
|
||||
option: "cache-file",
|
||||
type: "path::String",
|
||||
default: ".eslintcache",
|
||||
description:
|
||||
"Path to the cache file. Deprecated: use --cache-location",
|
||||
},
|
||||
{
|
||||
option: "cache-location",
|
||||
type: "path::String",
|
||||
description: "Path to the cache file or directory",
|
||||
},
|
||||
{
|
||||
option: "cache-strategy",
|
||||
dependsOn: ["cache"],
|
||||
type: "String",
|
||||
default: "metadata",
|
||||
enum: ["metadata", "content"],
|
||||
description:
|
||||
"Strategy to use for detecting changed files in the cache",
|
||||
},
|
||||
{
|
||||
heading: "Suppressing Violations",
|
||||
},
|
||||
{
|
||||
option: "suppress-all",
|
||||
type: "Boolean",
|
||||
default: "false",
|
||||
description: "Suppress all violations",
|
||||
},
|
||||
{
|
||||
option: "suppress-rule",
|
||||
type: "[String]",
|
||||
description: "Suppress specific rules",
|
||||
},
|
||||
{
|
||||
option: "suppressions-location",
|
||||
type: "path::String",
|
||||
description: "Specify the location of the suppressions file",
|
||||
},
|
||||
{
|
||||
option: "prune-suppressions",
|
||||
type: "Boolean",
|
||||
default: "false",
|
||||
description: "Prune unused suppressions",
|
||||
},
|
||||
{
|
||||
option: "pass-on-unpruned-suppressions",
|
||||
type: "Boolean",
|
||||
default: "false",
|
||||
description: "Ignore unused suppressions",
|
||||
},
|
||||
{
|
||||
heading: "Miscellaneous",
|
||||
},
|
||||
{
|
||||
option: "init",
|
||||
type: "Boolean",
|
||||
default: "false",
|
||||
description: "Run config initialization wizard",
|
||||
},
|
||||
{
|
||||
option: "env-info",
|
||||
type: "Boolean",
|
||||
default: "false",
|
||||
description: "Output execution environment information",
|
||||
},
|
||||
{
|
||||
option: "error-on-unmatched-pattern",
|
||||
type: "Boolean",
|
||||
default: "true",
|
||||
description: "Prevent errors when pattern is unmatched",
|
||||
},
|
||||
{
|
||||
option: "exit-on-fatal-error",
|
||||
type: "Boolean",
|
||||
default: "false",
|
||||
description: "Exit with exit code 2 in case of fatal error",
|
||||
},
|
||||
warnIgnoredFlag,
|
||||
{
|
||||
option: "pass-on-no-patterns",
|
||||
type: "Boolean",
|
||||
default: false,
|
||||
description:
|
||||
"Exit with exit code 0 in case no file patterns are passed",
|
||||
},
|
||||
{
|
||||
option: "debug",
|
||||
type: "Boolean",
|
||||
default: false,
|
||||
description: "Output debugging information",
|
||||
},
|
||||
{
|
||||
option: "help",
|
||||
alias: "h",
|
||||
type: "Boolean",
|
||||
description: "Show help",
|
||||
},
|
||||
{
|
||||
option: "version",
|
||||
alias: "v",
|
||||
type: "Boolean",
|
||||
description: "Output the version number",
|
||||
},
|
||||
{
|
||||
option: "print-config",
|
||||
type: "path::String",
|
||||
description: "Print the configuration for the given file",
|
||||
},
|
||||
statsFlag,
|
||||
flagFlag,
|
||||
mcpFlag,
|
||||
concurrencyFlag,
|
||||
].filter(value => !!value),
|
||||
});
|
||||
};
|
||||
7
slider/node_modules/eslint/lib/rule-tester/index.js
generated
vendored
Normal file
7
slider/node_modules/eslint/lib/rule-tester/index.js
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
"use strict";
|
||||
|
||||
const RuleTester = require("./rule-tester");
|
||||
|
||||
module.exports = {
|
||||
RuleTester,
|
||||
};
|
||||
1579
slider/node_modules/eslint/lib/rule-tester/rule-tester.js
generated
vendored
Normal file
1579
slider/node_modules/eslint/lib/rule-tester/rule-tester.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
420
slider/node_modules/eslint/lib/rules/accessor-pairs.js
generated
vendored
Normal file
420
slider/node_modules/eslint/lib/rules/accessor-pairs.js
generated
vendored
Normal file
@@ -0,0 +1,420 @@
|
||||
/**
|
||||
* @fileoverview Rule to enforce getter and setter pairs in objects and classes.
|
||||
* @author Gyandeep Singh
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const astUtils = require("./utils/ast-utils");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Typedefs
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Property name if it can be computed statically, otherwise the list of the tokens of the key node.
|
||||
* @typedef {string|Token[]} Key
|
||||
*/
|
||||
|
||||
/**
|
||||
* Accessor nodes with the same key.
|
||||
* @typedef {Object} AccessorData
|
||||
* @property {Key} key Accessor's key
|
||||
* @property {ASTNode[]} getters List of getter nodes.
|
||||
* @property {ASTNode[]} setters List of setter nodes.
|
||||
*/
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Checks whether or not the given lists represent the equal tokens in the same order.
|
||||
* Tokens are compared by their properties, not by instance.
|
||||
* @param {Token[]} left First list of tokens.
|
||||
* @param {Token[]} right Second list of tokens.
|
||||
* @returns {boolean} `true` if the lists have same tokens.
|
||||
*/
|
||||
function areEqualTokenLists(left, right) {
|
||||
if (left.length !== right.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (let i = 0; i < left.length; i++) {
|
||||
const leftToken = left[i],
|
||||
rightToken = right[i];
|
||||
|
||||
if (
|
||||
leftToken.type !== rightToken.type ||
|
||||
leftToken.value !== rightToken.value
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether or not the given keys are equal.
|
||||
* @param {Key} left First key.
|
||||
* @param {Key} right Second key.
|
||||
* @returns {boolean} `true` if the keys are equal.
|
||||
*/
|
||||
function areEqualKeys(left, right) {
|
||||
if (typeof left === "string" && typeof right === "string") {
|
||||
// Statically computed names.
|
||||
return left === right;
|
||||
}
|
||||
if (Array.isArray(left) && Array.isArray(right)) {
|
||||
// Token lists.
|
||||
return areEqualTokenLists(left, right);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether or not a given node is of an accessor kind ('get' or 'set').
|
||||
* @param {ASTNode} node A node to check.
|
||||
* @returns {boolean} `true` if the node is of an accessor kind.
|
||||
*/
|
||||
function isAccessorKind(node) {
|
||||
return node.kind === "get" || node.kind === "set";
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether or not a given node is an argument of a specified method call.
|
||||
* @param {ASTNode} node A node to check.
|
||||
* @param {number} index An expected index of the node in arguments.
|
||||
* @param {string} object An expected name of the object of the method.
|
||||
* @param {string} property An expected name of the method.
|
||||
* @returns {boolean} `true` if the node is an argument of the specified method call.
|
||||
*/
|
||||
function isArgumentOfMethodCall(node, index, object, property) {
|
||||
const parent = node.parent;
|
||||
|
||||
return (
|
||||
parent.type === "CallExpression" &&
|
||||
astUtils.isSpecificMemberAccess(parent.callee, object, property) &&
|
||||
parent.arguments[index] === node
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether or not a given node is a property descriptor.
|
||||
* @param {ASTNode} node A node to check.
|
||||
* @returns {boolean} `true` if the node is a property descriptor.
|
||||
*/
|
||||
function isPropertyDescriptor(node) {
|
||||
// Object.defineProperty(obj, "foo", {set: ...})
|
||||
if (
|
||||
isArgumentOfMethodCall(node, 2, "Object", "defineProperty") ||
|
||||
isArgumentOfMethodCall(node, 2, "Reflect", "defineProperty")
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Object.defineProperties(obj, {foo: {set: ...}})
|
||||
* Object.create(proto, {foo: {set: ...}})
|
||||
*/
|
||||
const grandparent = node.parent.parent;
|
||||
|
||||
return (
|
||||
grandparent.type === "ObjectExpression" &&
|
||||
(isArgumentOfMethodCall(grandparent, 1, "Object", "create") ||
|
||||
isArgumentOfMethodCall(
|
||||
grandparent,
|
||||
1,
|
||||
"Object",
|
||||
"defineProperties",
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../types').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
|
||||
defaultOptions: [
|
||||
{
|
||||
enforceForTSTypes: false,
|
||||
enforceForClassMembers: true,
|
||||
getWithoutSet: false,
|
||||
setWithoutGet: true,
|
||||
},
|
||||
],
|
||||
|
||||
docs: {
|
||||
description:
|
||||
"Enforce getter and setter pairs in objects and classes",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/latest/rules/accessor-pairs",
|
||||
},
|
||||
|
||||
schema: [
|
||||
{
|
||||
type: "object",
|
||||
properties: {
|
||||
getWithoutSet: {
|
||||
type: "boolean",
|
||||
},
|
||||
setWithoutGet: {
|
||||
type: "boolean",
|
||||
},
|
||||
enforceForClassMembers: {
|
||||
type: "boolean",
|
||||
},
|
||||
enforceForTSTypes: {
|
||||
type: "boolean",
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
},
|
||||
],
|
||||
|
||||
messages: {
|
||||
missingGetterInPropertyDescriptor:
|
||||
"Getter is not present in property descriptor.",
|
||||
missingSetterInPropertyDescriptor:
|
||||
"Setter is not present in property descriptor.",
|
||||
missingGetterInObjectLiteral:
|
||||
"Getter is not present for {{ name }}.",
|
||||
missingSetterInObjectLiteral:
|
||||
"Setter is not present for {{ name }}.",
|
||||
missingGetterInClass: "Getter is not present for class {{ name }}.",
|
||||
missingSetterInClass: "Setter is not present for class {{ name }}.",
|
||||
missingGetterInType: "Getter is not present for type {{ name }}.",
|
||||
missingSetterInType: "Setter is not present for type {{ name }}.",
|
||||
},
|
||||
},
|
||||
create(context) {
|
||||
const [
|
||||
{
|
||||
getWithoutSet: checkGetWithoutSet,
|
||||
setWithoutGet: checkSetWithoutGet,
|
||||
enforceForClassMembers,
|
||||
enforceForTSTypes,
|
||||
},
|
||||
] = context.options;
|
||||
const sourceCode = context.sourceCode;
|
||||
|
||||
/**
|
||||
* Reports the given node.
|
||||
* @param {ASTNode} node The node to report.
|
||||
* @param {string} messageKind "missingGetter" or "missingSetter".
|
||||
* @returns {void}
|
||||
* @private
|
||||
*/
|
||||
function report(node, messageKind) {
|
||||
if (node.type === "Property") {
|
||||
context.report({
|
||||
node,
|
||||
messageId: `${messageKind}InObjectLiteral`,
|
||||
loc: astUtils.getFunctionHeadLoc(node.value, sourceCode),
|
||||
data: {
|
||||
name: astUtils.getFunctionNameWithKind(node.value),
|
||||
},
|
||||
});
|
||||
} else if (node.type === "MethodDefinition") {
|
||||
context.report({
|
||||
node,
|
||||
messageId: `${messageKind}InClass`,
|
||||
loc: astUtils.getFunctionHeadLoc(node.value, sourceCode),
|
||||
data: {
|
||||
name: astUtils.getFunctionNameWithKind(node.value),
|
||||
},
|
||||
});
|
||||
} else if (node.type === "TSMethodSignature") {
|
||||
context.report({
|
||||
node,
|
||||
messageId: `${messageKind}InType`,
|
||||
loc: astUtils.getFunctionHeadLoc(node, sourceCode),
|
||||
data: {
|
||||
name: astUtils.getFunctionNameWithKind(node),
|
||||
},
|
||||
});
|
||||
} else {
|
||||
context.report({
|
||||
node,
|
||||
messageId: `${messageKind}InPropertyDescriptor`,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports each of the nodes in the given list using the same messageId.
|
||||
* @param {ASTNode[]} nodes Nodes to report.
|
||||
* @param {string} messageKind "missingGetter" or "missingSetter".
|
||||
* @returns {void}
|
||||
* @private
|
||||
*/
|
||||
function reportList(nodes, messageKind) {
|
||||
for (const node of nodes) {
|
||||
report(node, messageKind);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks accessor pairs in the given list of nodes.
|
||||
* @param {ASTNode[]} nodes The list to check.
|
||||
* @returns {void}
|
||||
* @private
|
||||
*/
|
||||
function checkList(nodes) {
|
||||
const accessors = [];
|
||||
let found = false;
|
||||
|
||||
for (let i = 0; i < nodes.length; i++) {
|
||||
const node = nodes[i];
|
||||
|
||||
if (isAccessorKind(node)) {
|
||||
// Creates a new `AccessorData` object for the given getter or setter node.
|
||||
const name = astUtils.getStaticPropertyName(node);
|
||||
const key =
|
||||
name !== null ? name : sourceCode.getTokens(node.key);
|
||||
|
||||
// Merges the given `AccessorData` object into the given accessors list.
|
||||
for (let j = 0; j < accessors.length; j++) {
|
||||
const accessor = accessors[j];
|
||||
|
||||
if (areEqualKeys(accessor.key, key)) {
|
||||
accessor.getters.push(
|
||||
...(node.kind === "get" ? [node] : []),
|
||||
);
|
||||
accessor.setters.push(
|
||||
...(node.kind === "set" ? [node] : []),
|
||||
);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
accessors.push({
|
||||
key,
|
||||
getters: node.kind === "get" ? [node] : [],
|
||||
setters: node.kind === "set" ? [node] : [],
|
||||
});
|
||||
}
|
||||
found = false;
|
||||
}
|
||||
}
|
||||
|
||||
for (const { getters, setters } of accessors) {
|
||||
if (checkSetWithoutGet && setters.length && !getters.length) {
|
||||
reportList(setters, "missingGetter");
|
||||
}
|
||||
if (checkGetWithoutSet && getters.length && !setters.length) {
|
||||
reportList(getters, "missingSetter");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks accessor pairs in an object literal.
|
||||
* @param {ASTNode} node `ObjectExpression` node to check.
|
||||
* @returns {void}
|
||||
* @private
|
||||
*/
|
||||
function checkObjectLiteral(node) {
|
||||
checkList(node.properties.filter(p => p.type === "Property"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks accessor pairs in a property descriptor.
|
||||
* @param {ASTNode} node Property descriptor `ObjectExpression` node to check.
|
||||
* @returns {void}
|
||||
* @private
|
||||
*/
|
||||
function checkPropertyDescriptor(node) {
|
||||
const namesToCheck = new Set(
|
||||
node.properties
|
||||
.filter(
|
||||
p =>
|
||||
p.type === "Property" &&
|
||||
p.kind === "init" &&
|
||||
!p.computed,
|
||||
)
|
||||
.map(({ key }) => key.name),
|
||||
);
|
||||
|
||||
const hasGetter = namesToCheck.has("get");
|
||||
const hasSetter = namesToCheck.has("set");
|
||||
|
||||
if (checkSetWithoutGet && hasSetter && !hasGetter) {
|
||||
report(node, "missingGetter");
|
||||
}
|
||||
if (checkGetWithoutSet && hasGetter && !hasSetter) {
|
||||
report(node, "missingSetter");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the given object expression as an object literal and as a possible property descriptor.
|
||||
* @param {ASTNode} node `ObjectExpression` node to check.
|
||||
* @returns {void}
|
||||
* @private
|
||||
*/
|
||||
function checkObjectExpression(node) {
|
||||
checkObjectLiteral(node);
|
||||
if (isPropertyDescriptor(node)) {
|
||||
checkPropertyDescriptor(node);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the given class body.
|
||||
* @param {ASTNode} node `ClassBody` node to check.
|
||||
* @returns {void}
|
||||
* @private
|
||||
*/
|
||||
function checkClassBody(node) {
|
||||
const methodDefinitions = node.body.filter(
|
||||
m => m.type === "MethodDefinition",
|
||||
);
|
||||
|
||||
checkList(methodDefinitions.filter(m => m.static));
|
||||
checkList(methodDefinitions.filter(m => !m.static));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the given type.
|
||||
* @param {ASTNode} node `TSTypeLiteral` or `TSInterfaceBody` node to check.
|
||||
* @returns {void}
|
||||
* @private
|
||||
*/
|
||||
function checkType(node) {
|
||||
const members =
|
||||
node.type === "TSTypeLiteral" ? node.members : node.body;
|
||||
const methodDefinitions = members.filter(
|
||||
m => m.type === "TSMethodSignature",
|
||||
);
|
||||
|
||||
checkList(methodDefinitions);
|
||||
}
|
||||
|
||||
const listeners = {};
|
||||
|
||||
if (checkSetWithoutGet || checkGetWithoutSet) {
|
||||
listeners.ObjectExpression = checkObjectExpression;
|
||||
if (enforceForClassMembers) {
|
||||
listeners.ClassBody = checkClassBody;
|
||||
}
|
||||
if (enforceForTSTypes) {
|
||||
listeners["TSTypeLiteral, TSInterfaceBody"] = checkType;
|
||||
}
|
||||
}
|
||||
|
||||
return listeners;
|
||||
},
|
||||
};
|
||||
291
slider/node_modules/eslint/lib/rules/array-bracket-newline.js
generated
vendored
Normal file
291
slider/node_modules/eslint/lib/rules/array-bracket-newline.js
generated
vendored
Normal file
@@ -0,0 +1,291 @@
|
||||
/**
|
||||
* @fileoverview Rule to enforce linebreaks after open and before close array brackets
|
||||
* @author Jan Peer Stöcklmair <https://github.com/JPeer264>
|
||||
* @deprecated in ESLint v8.53.0
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
const astUtils = require("./utils/ast-utils");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../types').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
deprecated: {
|
||||
message: "Formatting rules are being moved out of ESLint core.",
|
||||
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
|
||||
deprecatedSince: "8.53.0",
|
||||
availableUntil: "10.0.0",
|
||||
replacedBy: [
|
||||
{
|
||||
message:
|
||||
"ESLint Stylistic now maintains deprecated stylistic core rules.",
|
||||
url: "https://eslint.style/guide/migration",
|
||||
plugin: {
|
||||
name: "@stylistic/eslint-plugin",
|
||||
url: "https://eslint.style",
|
||||
},
|
||||
rule: {
|
||||
name: "array-bracket-newline",
|
||||
url: "https://eslint.style/rules/array-bracket-newline",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
type: "layout",
|
||||
|
||||
docs: {
|
||||
description:
|
||||
"Enforce linebreaks after opening and before closing array brackets",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/latest/rules/array-bracket-newline",
|
||||
},
|
||||
|
||||
fixable: "whitespace",
|
||||
|
||||
schema: [
|
||||
{
|
||||
oneOf: [
|
||||
{
|
||||
enum: ["always", "never", "consistent"],
|
||||
},
|
||||
{
|
||||
type: "object",
|
||||
properties: {
|
||||
multiline: {
|
||||
type: "boolean",
|
||||
},
|
||||
minItems: {
|
||||
type: ["integer", "null"],
|
||||
minimum: 0,
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
messages: {
|
||||
unexpectedOpeningLinebreak:
|
||||
"There should be no linebreak after '['.",
|
||||
unexpectedClosingLinebreak:
|
||||
"There should be no linebreak before ']'.",
|
||||
missingOpeningLinebreak: "A linebreak is required after '['.",
|
||||
missingClosingLinebreak: "A linebreak is required before ']'.",
|
||||
},
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const sourceCode = context.sourceCode;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Helpers
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Normalizes a given option value.
|
||||
* @param {string|Object|undefined} option An option value to parse.
|
||||
* @returns {{multiline: boolean, minItems: number}} Normalized option object.
|
||||
*/
|
||||
function normalizeOptionValue(option) {
|
||||
let consistent = false;
|
||||
let multiline = false;
|
||||
let minItems;
|
||||
|
||||
if (option) {
|
||||
if (option === "consistent") {
|
||||
consistent = true;
|
||||
minItems = Number.POSITIVE_INFINITY;
|
||||
} else if (option === "always" || option.minItems === 0) {
|
||||
minItems = 0;
|
||||
} else if (option === "never") {
|
||||
minItems = Number.POSITIVE_INFINITY;
|
||||
} else {
|
||||
multiline = Boolean(option.multiline);
|
||||
minItems = option.minItems || Number.POSITIVE_INFINITY;
|
||||
}
|
||||
} else {
|
||||
consistent = false;
|
||||
multiline = true;
|
||||
minItems = Number.POSITIVE_INFINITY;
|
||||
}
|
||||
|
||||
return { consistent, multiline, minItems };
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes a given option value.
|
||||
* @param {string|Object|undefined} options An option value to parse.
|
||||
* @returns {{ArrayExpression: {multiline: boolean, minItems: number}, ArrayPattern: {multiline: boolean, minItems: number}}} Normalized option object.
|
||||
*/
|
||||
function normalizeOptions(options) {
|
||||
const value = normalizeOptionValue(options);
|
||||
|
||||
return { ArrayExpression: value, ArrayPattern: value };
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports that there shouldn't be a linebreak after the first token
|
||||
* @param {ASTNode} node The node to report in the event of an error.
|
||||
* @param {Token} token The token to use for the report.
|
||||
* @returns {void}
|
||||
*/
|
||||
function reportNoBeginningLinebreak(node, token) {
|
||||
context.report({
|
||||
node,
|
||||
loc: token.loc,
|
||||
messageId: "unexpectedOpeningLinebreak",
|
||||
fix(fixer) {
|
||||
const nextToken = sourceCode.getTokenAfter(token, {
|
||||
includeComments: true,
|
||||
});
|
||||
|
||||
if (astUtils.isCommentToken(nextToken)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return fixer.removeRange([
|
||||
token.range[1],
|
||||
nextToken.range[0],
|
||||
]);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports that there shouldn't be a linebreak before the last token
|
||||
* @param {ASTNode} node The node to report in the event of an error.
|
||||
* @param {Token} token The token to use for the report.
|
||||
* @returns {void}
|
||||
*/
|
||||
function reportNoEndingLinebreak(node, token) {
|
||||
context.report({
|
||||
node,
|
||||
loc: token.loc,
|
||||
messageId: "unexpectedClosingLinebreak",
|
||||
fix(fixer) {
|
||||
const previousToken = sourceCode.getTokenBefore(token, {
|
||||
includeComments: true,
|
||||
});
|
||||
|
||||
if (astUtils.isCommentToken(previousToken)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return fixer.removeRange([
|
||||
previousToken.range[1],
|
||||
token.range[0],
|
||||
]);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports that there should be a linebreak after the first token
|
||||
* @param {ASTNode} node The node to report in the event of an error.
|
||||
* @param {Token} token The token to use for the report.
|
||||
* @returns {void}
|
||||
*/
|
||||
function reportRequiredBeginningLinebreak(node, token) {
|
||||
context.report({
|
||||
node,
|
||||
loc: token.loc,
|
||||
messageId: "missingOpeningLinebreak",
|
||||
fix(fixer) {
|
||||
return fixer.insertTextAfter(token, "\n");
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports that there should be a linebreak before the last token
|
||||
* @param {ASTNode} node The node to report in the event of an error.
|
||||
* @param {Token} token The token to use for the report.
|
||||
* @returns {void}
|
||||
*/
|
||||
function reportRequiredEndingLinebreak(node, token) {
|
||||
context.report({
|
||||
node,
|
||||
loc: token.loc,
|
||||
messageId: "missingClosingLinebreak",
|
||||
fix(fixer) {
|
||||
return fixer.insertTextBefore(token, "\n");
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports a given node if it violated this rule.
|
||||
* @param {ASTNode} node A node to check. This is an ArrayExpression node or an ArrayPattern node.
|
||||
* @returns {void}
|
||||
*/
|
||||
function check(node) {
|
||||
const elements = node.elements;
|
||||
const normalizedOptions = normalizeOptions(context.options[0]);
|
||||
const options = normalizedOptions[node.type];
|
||||
const openBracket = sourceCode.getFirstToken(node);
|
||||
const closeBracket = sourceCode.getLastToken(node);
|
||||
const firstIncComment = sourceCode.getTokenAfter(openBracket, {
|
||||
includeComments: true,
|
||||
});
|
||||
const lastIncComment = sourceCode.getTokenBefore(closeBracket, {
|
||||
includeComments: true,
|
||||
});
|
||||
const first = sourceCode.getTokenAfter(openBracket);
|
||||
const last = sourceCode.getTokenBefore(closeBracket);
|
||||
|
||||
const needsLinebreaks =
|
||||
elements.length >= options.minItems ||
|
||||
(options.multiline &&
|
||||
elements.length > 0 &&
|
||||
firstIncComment.loc.start.line !==
|
||||
lastIncComment.loc.end.line) ||
|
||||
(elements.length === 0 &&
|
||||
firstIncComment.type === "Block" &&
|
||||
firstIncComment.loc.start.line !==
|
||||
lastIncComment.loc.end.line &&
|
||||
firstIncComment === lastIncComment) ||
|
||||
(options.consistent &&
|
||||
openBracket.loc.end.line !== first.loc.start.line);
|
||||
|
||||
/*
|
||||
* Use tokens or comments to check multiline or not.
|
||||
* But use only tokens to check whether linebreaks are needed.
|
||||
* This allows:
|
||||
* var arr = [ // eslint-disable-line foo
|
||||
* 'a'
|
||||
* ]
|
||||
*/
|
||||
|
||||
if (needsLinebreaks) {
|
||||
if (astUtils.isTokenOnSameLine(openBracket, first)) {
|
||||
reportRequiredBeginningLinebreak(node, openBracket);
|
||||
}
|
||||
if (astUtils.isTokenOnSameLine(last, closeBracket)) {
|
||||
reportRequiredEndingLinebreak(node, closeBracket);
|
||||
}
|
||||
} else {
|
||||
if (!astUtils.isTokenOnSameLine(openBracket, first)) {
|
||||
reportNoBeginningLinebreak(node, openBracket);
|
||||
}
|
||||
if (!astUtils.isTokenOnSameLine(last, closeBracket)) {
|
||||
reportNoEndingLinebreak(node, closeBracket);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Public
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
return {
|
||||
ArrayPattern: check,
|
||||
ArrayExpression: check,
|
||||
};
|
||||
},
|
||||
};
|
||||
301
slider/node_modules/eslint/lib/rules/array-bracket-spacing.js
generated
vendored
Normal file
301
slider/node_modules/eslint/lib/rules/array-bracket-spacing.js
generated
vendored
Normal file
@@ -0,0 +1,301 @@
|
||||
/**
|
||||
* @fileoverview Disallows or enforces spaces inside of array brackets.
|
||||
* @author Jamund Ferguson
|
||||
* @deprecated in ESLint v8.53.0
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
const astUtils = require("./utils/ast-utils");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../types').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
deprecated: {
|
||||
message: "Formatting rules are being moved out of ESLint core.",
|
||||
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
|
||||
deprecatedSince: "8.53.0",
|
||||
availableUntil: "10.0.0",
|
||||
replacedBy: [
|
||||
{
|
||||
message:
|
||||
"ESLint Stylistic now maintains deprecated stylistic core rules.",
|
||||
url: "https://eslint.style/guide/migration",
|
||||
plugin: {
|
||||
name: "@stylistic/eslint-plugin",
|
||||
url: "https://eslint.style",
|
||||
},
|
||||
rule: {
|
||||
name: "array-bracket-spacing",
|
||||
url: "https://eslint.style/rules/array-bracket-spacing",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
type: "layout",
|
||||
|
||||
docs: {
|
||||
description: "Enforce consistent spacing inside array brackets",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/latest/rules/array-bracket-spacing",
|
||||
},
|
||||
|
||||
fixable: "whitespace",
|
||||
|
||||
schema: [
|
||||
{
|
||||
enum: ["always", "never"],
|
||||
},
|
||||
{
|
||||
type: "object",
|
||||
properties: {
|
||||
singleValue: {
|
||||
type: "boolean",
|
||||
},
|
||||
objectsInArrays: {
|
||||
type: "boolean",
|
||||
},
|
||||
arraysInArrays: {
|
||||
type: "boolean",
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
},
|
||||
],
|
||||
|
||||
messages: {
|
||||
unexpectedSpaceAfter:
|
||||
"There should be no space after '{{tokenValue}}'.",
|
||||
unexpectedSpaceBefore:
|
||||
"There should be no space before '{{tokenValue}}'.",
|
||||
missingSpaceAfter: "A space is required after '{{tokenValue}}'.",
|
||||
missingSpaceBefore: "A space is required before '{{tokenValue}}'.",
|
||||
},
|
||||
},
|
||||
create(context) {
|
||||
const spaced = context.options[0] === "always",
|
||||
sourceCode = context.sourceCode;
|
||||
|
||||
/**
|
||||
* Determines whether an option is set, relative to the spacing option.
|
||||
* If spaced is "always", then check whether option is set to false.
|
||||
* If spaced is "never", then check whether option is set to true.
|
||||
* @param {Object} option The option to exclude.
|
||||
* @returns {boolean} Whether or not the property is excluded.
|
||||
*/
|
||||
function isOptionSet(option) {
|
||||
return context.options[1]
|
||||
? context.options[1][option] === !spaced
|
||||
: false;
|
||||
}
|
||||
|
||||
const options = {
|
||||
spaced,
|
||||
singleElementException: isOptionSet("singleValue"),
|
||||
objectsInArraysException: isOptionSet("objectsInArrays"),
|
||||
arraysInArraysException: isOptionSet("arraysInArrays"),
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Reports that there shouldn't be a space after the first token
|
||||
* @param {ASTNode} node The node to report in the event of an error.
|
||||
* @param {Token} token The token to use for the report.
|
||||
* @returns {void}
|
||||
*/
|
||||
function reportNoBeginningSpace(node, token) {
|
||||
const nextToken = sourceCode.getTokenAfter(token);
|
||||
|
||||
context.report({
|
||||
node,
|
||||
loc: { start: token.loc.end, end: nextToken.loc.start },
|
||||
messageId: "unexpectedSpaceAfter",
|
||||
data: {
|
||||
tokenValue: token.value,
|
||||
},
|
||||
fix(fixer) {
|
||||
return fixer.removeRange([
|
||||
token.range[1],
|
||||
nextToken.range[0],
|
||||
]);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports that there shouldn't be a space before the last token
|
||||
* @param {ASTNode} node The node to report in the event of an error.
|
||||
* @param {Token} token The token to use for the report.
|
||||
* @returns {void}
|
||||
*/
|
||||
function reportNoEndingSpace(node, token) {
|
||||
const previousToken = sourceCode.getTokenBefore(token);
|
||||
|
||||
context.report({
|
||||
node,
|
||||
loc: { start: previousToken.loc.end, end: token.loc.start },
|
||||
messageId: "unexpectedSpaceBefore",
|
||||
data: {
|
||||
tokenValue: token.value,
|
||||
},
|
||||
fix(fixer) {
|
||||
return fixer.removeRange([
|
||||
previousToken.range[1],
|
||||
token.range[0],
|
||||
]);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports that there should be a space after the first token
|
||||
* @param {ASTNode} node The node to report in the event of an error.
|
||||
* @param {Token} token The token to use for the report.
|
||||
* @returns {void}
|
||||
*/
|
||||
function reportRequiredBeginningSpace(node, token) {
|
||||
context.report({
|
||||
node,
|
||||
loc: token.loc,
|
||||
messageId: "missingSpaceAfter",
|
||||
data: {
|
||||
tokenValue: token.value,
|
||||
},
|
||||
fix(fixer) {
|
||||
return fixer.insertTextAfter(token, " ");
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports that there should be a space before the last token
|
||||
* @param {ASTNode} node The node to report in the event of an error.
|
||||
* @param {Token} token The token to use for the report.
|
||||
* @returns {void}
|
||||
*/
|
||||
function reportRequiredEndingSpace(node, token) {
|
||||
context.report({
|
||||
node,
|
||||
loc: token.loc,
|
||||
messageId: "missingSpaceBefore",
|
||||
data: {
|
||||
tokenValue: token.value,
|
||||
},
|
||||
fix(fixer) {
|
||||
return fixer.insertTextBefore(token, " ");
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if a node is an object type
|
||||
* @param {ASTNode} node The node to check.
|
||||
* @returns {boolean} Whether or not the node is an object type.
|
||||
*/
|
||||
function isObjectType(node) {
|
||||
return (
|
||||
node &&
|
||||
(node.type === "ObjectExpression" ||
|
||||
node.type === "ObjectPattern")
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if a node is an array type
|
||||
* @param {ASTNode} node The node to check.
|
||||
* @returns {boolean} Whether or not the node is an array type.
|
||||
*/
|
||||
function isArrayType(node) {
|
||||
return (
|
||||
node &&
|
||||
(node.type === "ArrayExpression" ||
|
||||
node.type === "ArrayPattern")
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the spacing around array brackets
|
||||
* @param {ASTNode} node The node we're checking for spacing
|
||||
* @returns {void}
|
||||
*/
|
||||
function validateArraySpacing(node) {
|
||||
if (options.spaced && node.elements.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const first = sourceCode.getFirstToken(node),
|
||||
second = sourceCode.getFirstToken(node, 1),
|
||||
last = node.typeAnnotation
|
||||
? sourceCode.getTokenBefore(node.typeAnnotation)
|
||||
: sourceCode.getLastToken(node),
|
||||
penultimate = sourceCode.getTokenBefore(last),
|
||||
firstElement = node.elements[0],
|
||||
lastElement = node.elements.at(-1);
|
||||
|
||||
const openingBracketMustBeSpaced =
|
||||
(options.objectsInArraysException &&
|
||||
isObjectType(firstElement)) ||
|
||||
(options.arraysInArraysException &&
|
||||
isArrayType(firstElement)) ||
|
||||
(options.singleElementException && node.elements.length === 1)
|
||||
? !options.spaced
|
||||
: options.spaced;
|
||||
|
||||
const closingBracketMustBeSpaced =
|
||||
(options.objectsInArraysException &&
|
||||
isObjectType(lastElement)) ||
|
||||
(options.arraysInArraysException && isArrayType(lastElement)) ||
|
||||
(options.singleElementException && node.elements.length === 1)
|
||||
? !options.spaced
|
||||
: options.spaced;
|
||||
|
||||
if (astUtils.isTokenOnSameLine(first, second)) {
|
||||
if (
|
||||
openingBracketMustBeSpaced &&
|
||||
!sourceCode.isSpaceBetweenTokens(first, second)
|
||||
) {
|
||||
reportRequiredBeginningSpace(node, first);
|
||||
}
|
||||
if (
|
||||
!openingBracketMustBeSpaced &&
|
||||
sourceCode.isSpaceBetweenTokens(first, second)
|
||||
) {
|
||||
reportNoBeginningSpace(node, first);
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
first !== penultimate &&
|
||||
astUtils.isTokenOnSameLine(penultimate, last)
|
||||
) {
|
||||
if (
|
||||
closingBracketMustBeSpaced &&
|
||||
!sourceCode.isSpaceBetweenTokens(penultimate, last)
|
||||
) {
|
||||
reportRequiredEndingSpace(node, last);
|
||||
}
|
||||
if (
|
||||
!closingBracketMustBeSpaced &&
|
||||
sourceCode.isSpaceBetweenTokens(penultimate, last)
|
||||
) {
|
||||
reportNoEndingSpace(node, last);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Public
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
return {
|
||||
ArrayPattern: validateArraySpacing,
|
||||
ArrayExpression: validateArraySpacing,
|
||||
};
|
||||
},
|
||||
};
|
||||
493
slider/node_modules/eslint/lib/rules/array-callback-return.js
generated
vendored
Normal file
493
slider/node_modules/eslint/lib/rules/array-callback-return.js
generated
vendored
Normal file
@@ -0,0 +1,493 @@
|
||||
/**
|
||||
* @fileoverview Rule to enforce return statements in callbacks of array's methods
|
||||
* @author Toru Nagashima
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const astUtils = require("./utils/ast-utils");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const TARGET_NODE_TYPE = /^(?:Arrow)?FunctionExpression$/u;
|
||||
const TARGET_METHODS =
|
||||
/^(?:every|filter|find(?:Last)?(?:Index)?|flatMap|forEach|map|reduce(?:Right)?|some|sort|toSorted)$/u;
|
||||
|
||||
/**
|
||||
* Checks a given node is a member access which has the specified name's
|
||||
* property.
|
||||
* @param {ASTNode} node A node to check.
|
||||
* @returns {boolean} `true` if the node is a member access which has
|
||||
* the specified name's property. The node may be a `(Chain|Member)Expression` node.
|
||||
*/
|
||||
function isTargetMethod(node) {
|
||||
return astUtils.isSpecificMemberAccess(node, null, TARGET_METHODS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks all segments in a set and returns true if any are reachable.
|
||||
* @param {Set<CodePathSegment>} segments The segments to check.
|
||||
* @returns {boolean} True if any segment is reachable; false otherwise.
|
||||
*/
|
||||
function isAnySegmentReachable(segments) {
|
||||
for (const segment of segments) {
|
||||
if (segment.reachable) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a human-legible description of an array method
|
||||
* @param {string} arrayMethodName A method name to fully qualify
|
||||
* @returns {string} the method name prefixed with `Array.` if it is a class method,
|
||||
* or else `Array.prototype.` if it is an instance method.
|
||||
*/
|
||||
function fullMethodName(arrayMethodName) {
|
||||
if (["from", "of", "isArray"].includes(arrayMethodName)) {
|
||||
return "Array.".concat(arrayMethodName);
|
||||
}
|
||||
return "Array.prototype.".concat(arrayMethodName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether or not a given node is a function expression which is the
|
||||
* callback of an array method, returning the method name.
|
||||
* @param {ASTNode} node A node to check. This is one of
|
||||
* FunctionExpression or ArrowFunctionExpression.
|
||||
* @returns {string} The method name if the node is a callback method,
|
||||
* null otherwise.
|
||||
*/
|
||||
function getArrayMethodName(node) {
|
||||
let currentNode = node;
|
||||
|
||||
while (currentNode) {
|
||||
const parent = currentNode.parent;
|
||||
|
||||
switch (parent.type) {
|
||||
/*
|
||||
* Looks up the destination. e.g.,
|
||||
* foo.every(nativeFoo || function foo() { ... });
|
||||
*/
|
||||
case "LogicalExpression":
|
||||
case "ConditionalExpression":
|
||||
case "ChainExpression":
|
||||
currentNode = parent;
|
||||
break;
|
||||
|
||||
/*
|
||||
* If the upper function is IIFE, checks the destination of the return value.
|
||||
* e.g.
|
||||
* foo.every((function() {
|
||||
* // setup...
|
||||
* return function callback() { ... };
|
||||
* })());
|
||||
*/
|
||||
case "ReturnStatement": {
|
||||
const func = astUtils.getUpperFunction(parent);
|
||||
|
||||
if (func === null || !astUtils.isCallee(func)) {
|
||||
return null;
|
||||
}
|
||||
currentNode = func.parent;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* e.g.
|
||||
* Array.from([], function() {});
|
||||
* list.every(function() {});
|
||||
*/
|
||||
case "CallExpression":
|
||||
if (astUtils.isArrayFromMethod(parent.callee)) {
|
||||
if (
|
||||
parent.arguments.length >= 2 &&
|
||||
parent.arguments[1] === currentNode
|
||||
) {
|
||||
return "from";
|
||||
}
|
||||
}
|
||||
if (isTargetMethod(parent.callee)) {
|
||||
if (
|
||||
parent.arguments.length >= 1 &&
|
||||
parent.arguments[0] === currentNode
|
||||
) {
|
||||
return astUtils.getStaticPropertyName(parent.callee);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
// Otherwise this node is not target.
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/* c8 ignore next */
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given node is a void expression.
|
||||
* @param {ASTNode} node The node to check.
|
||||
* @returns {boolean} - `true` if the node is a void expression
|
||||
*/
|
||||
function isExpressionVoid(node) {
|
||||
return node.type === "UnaryExpression" && node.operator === "void";
|
||||
}
|
||||
|
||||
/**
|
||||
* Fixes the linting error by prepending "void " to the given node
|
||||
* @param {Object} sourceCode context given by context.sourceCode
|
||||
* @param {ASTNode} node The node to fix.
|
||||
* @param {Object} fixer The fixer object provided by ESLint.
|
||||
* @returns {Array<Object>} - An array of fix objects to apply to the node.
|
||||
*/
|
||||
function voidPrependFixer(sourceCode, node, fixer) {
|
||||
const requiresParens =
|
||||
// prepending `void ` will fail if the node has a lower precedence than void
|
||||
astUtils.getPrecedence(node) <
|
||||
astUtils.getPrecedence({
|
||||
type: "UnaryExpression",
|
||||
operator: "void",
|
||||
}) &&
|
||||
// check if there are parentheses around the node to avoid redundant parentheses
|
||||
!astUtils.isParenthesised(sourceCode, node);
|
||||
|
||||
// avoid parentheses issues
|
||||
const returnOrArrowToken = sourceCode.getTokenBefore(
|
||||
node,
|
||||
node.parent.type === "ArrowFunctionExpression"
|
||||
? astUtils.isArrowToken
|
||||
: // isReturnToken
|
||||
token => token.type === "Keyword" && token.value === "return",
|
||||
);
|
||||
|
||||
const firstToken = sourceCode.getTokenAfter(returnOrArrowToken);
|
||||
|
||||
const prependSpace =
|
||||
// is return token, as => allows void to be adjacent
|
||||
returnOrArrowToken.value === "return" &&
|
||||
// If two tokens (return and "(") are adjacent
|
||||
returnOrArrowToken.range[1] === firstToken.range[0];
|
||||
|
||||
return [
|
||||
fixer.insertTextBefore(
|
||||
firstToken,
|
||||
`${prependSpace ? " " : ""}void ${requiresParens ? "(" : ""}`,
|
||||
),
|
||||
fixer.insertTextAfter(node, requiresParens ? ")" : ""),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Fixes the linting error by `wrapping {}` around the given node's body.
|
||||
* @param {Object} sourceCode context given by context.sourceCode
|
||||
* @param {ASTNode} node The node to fix.
|
||||
* @param {Object} fixer The fixer object provided by ESLint.
|
||||
* @returns {Array<Object>} - An array of fix objects to apply to the node.
|
||||
*/
|
||||
function curlyWrapFixer(sourceCode, node, fixer) {
|
||||
const arrowToken = sourceCode.getTokenBefore(
|
||||
node.body,
|
||||
astUtils.isArrowToken,
|
||||
);
|
||||
const firstToken = sourceCode.getTokenAfter(arrowToken);
|
||||
const lastToken = sourceCode.getLastToken(node);
|
||||
|
||||
return [
|
||||
fixer.insertTextBefore(firstToken, "{"),
|
||||
fixer.insertTextAfter(lastToken, "}"),
|
||||
];
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../types').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "problem",
|
||||
|
||||
defaultOptions: [
|
||||
{
|
||||
allowImplicit: false,
|
||||
checkForEach: false,
|
||||
allowVoid: false,
|
||||
},
|
||||
],
|
||||
|
||||
docs: {
|
||||
description:
|
||||
"Enforce `return` statements in callbacks of array methods",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/latest/rules/array-callback-return",
|
||||
},
|
||||
|
||||
hasSuggestions: true,
|
||||
|
||||
schema: [
|
||||
{
|
||||
type: "object",
|
||||
properties: {
|
||||
allowImplicit: {
|
||||
type: "boolean",
|
||||
},
|
||||
checkForEach: {
|
||||
type: "boolean",
|
||||
},
|
||||
allowVoid: {
|
||||
type: "boolean",
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
},
|
||||
],
|
||||
|
||||
messages: {
|
||||
expectedAtEnd:
|
||||
"{{arrayMethodName}}() expects a value to be returned at the end of {{name}}.",
|
||||
expectedInside:
|
||||
"{{arrayMethodName}}() expects a return value from {{name}}.",
|
||||
expectedReturnValue:
|
||||
"{{arrayMethodName}}() expects a return value from {{name}}.",
|
||||
expectedNoReturnValue:
|
||||
"{{arrayMethodName}}() expects no useless return value from {{name}}.",
|
||||
wrapBraces: "Wrap the expression in `{}`.",
|
||||
prependVoid: "Prepend `void` to the expression.",
|
||||
},
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const [options] = context.options;
|
||||
const sourceCode = context.sourceCode;
|
||||
|
||||
let funcInfo = {
|
||||
arrayMethodName: null,
|
||||
upper: null,
|
||||
codePath: null,
|
||||
hasReturn: false,
|
||||
shouldCheck: false,
|
||||
node: null,
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks whether or not the last code path segment is reachable.
|
||||
* Then reports this function if the segment is reachable.
|
||||
*
|
||||
* If the last code path segment is reachable, there are paths which are not
|
||||
* returned or thrown.
|
||||
* @param {ASTNode} node A node to check.
|
||||
* @returns {void}
|
||||
*/
|
||||
function checkLastSegment(node) {
|
||||
if (!funcInfo.shouldCheck) {
|
||||
return;
|
||||
}
|
||||
|
||||
const messageAndSuggestions = { messageId: "", suggest: [] };
|
||||
|
||||
if (funcInfo.arrayMethodName === "forEach") {
|
||||
if (
|
||||
options.checkForEach &&
|
||||
node.type === "ArrowFunctionExpression" &&
|
||||
node.expression
|
||||
) {
|
||||
if (options.allowVoid) {
|
||||
if (isExpressionVoid(node.body)) {
|
||||
return;
|
||||
}
|
||||
|
||||
messageAndSuggestions.messageId =
|
||||
"expectedNoReturnValue";
|
||||
messageAndSuggestions.suggest = [
|
||||
{
|
||||
messageId: "wrapBraces",
|
||||
fix(fixer) {
|
||||
return curlyWrapFixer(
|
||||
sourceCode,
|
||||
node,
|
||||
fixer,
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
messageId: "prependVoid",
|
||||
fix(fixer) {
|
||||
return voidPrependFixer(
|
||||
sourceCode,
|
||||
node.body,
|
||||
fixer,
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
} else {
|
||||
messageAndSuggestions.messageId =
|
||||
"expectedNoReturnValue";
|
||||
messageAndSuggestions.suggest = [
|
||||
{
|
||||
messageId: "wrapBraces",
|
||||
fix(fixer) {
|
||||
return curlyWrapFixer(
|
||||
sourceCode,
|
||||
node,
|
||||
fixer,
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (
|
||||
node.body.type === "BlockStatement" &&
|
||||
isAnySegmentReachable(funcInfo.currentSegments)
|
||||
) {
|
||||
messageAndSuggestions.messageId = funcInfo.hasReturn
|
||||
? "expectedAtEnd"
|
||||
: "expectedInside";
|
||||
}
|
||||
}
|
||||
|
||||
if (messageAndSuggestions.messageId) {
|
||||
const name = astUtils.getFunctionNameWithKind(node);
|
||||
|
||||
context.report({
|
||||
node,
|
||||
loc: astUtils.getFunctionHeadLoc(node, sourceCode),
|
||||
messageId: messageAndSuggestions.messageId,
|
||||
data: {
|
||||
name,
|
||||
arrayMethodName: fullMethodName(
|
||||
funcInfo.arrayMethodName,
|
||||
),
|
||||
},
|
||||
suggest:
|
||||
messageAndSuggestions.suggest.length !== 0
|
||||
? messageAndSuggestions.suggest
|
||||
: null,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
// Stacks this function's information.
|
||||
onCodePathStart(codePath, node) {
|
||||
let methodName = null;
|
||||
|
||||
if (TARGET_NODE_TYPE.test(node.type)) {
|
||||
methodName = getArrayMethodName(node);
|
||||
}
|
||||
|
||||
funcInfo = {
|
||||
arrayMethodName: methodName,
|
||||
upper: funcInfo,
|
||||
codePath,
|
||||
hasReturn: false,
|
||||
shouldCheck: methodName && !node.async && !node.generator,
|
||||
node,
|
||||
currentSegments: new Set(),
|
||||
};
|
||||
},
|
||||
|
||||
// Pops this function's information.
|
||||
onCodePathEnd() {
|
||||
funcInfo = funcInfo.upper;
|
||||
},
|
||||
|
||||
onUnreachableCodePathSegmentStart(segment) {
|
||||
funcInfo.currentSegments.add(segment);
|
||||
},
|
||||
|
||||
onUnreachableCodePathSegmentEnd(segment) {
|
||||
funcInfo.currentSegments.delete(segment);
|
||||
},
|
||||
|
||||
onCodePathSegmentStart(segment) {
|
||||
funcInfo.currentSegments.add(segment);
|
||||
},
|
||||
|
||||
onCodePathSegmentEnd(segment) {
|
||||
funcInfo.currentSegments.delete(segment);
|
||||
},
|
||||
|
||||
// Checks the return statement is valid.
|
||||
ReturnStatement(node) {
|
||||
if (!funcInfo.shouldCheck) {
|
||||
return;
|
||||
}
|
||||
|
||||
funcInfo.hasReturn = true;
|
||||
|
||||
const messageAndSuggestions = { messageId: "", suggest: [] };
|
||||
|
||||
if (funcInfo.arrayMethodName === "forEach") {
|
||||
// if checkForEach: true, returning a value at any path inside a forEach is not allowed
|
||||
if (options.checkForEach && node.argument) {
|
||||
if (options.allowVoid) {
|
||||
if (isExpressionVoid(node.argument)) {
|
||||
return;
|
||||
}
|
||||
|
||||
messageAndSuggestions.messageId =
|
||||
"expectedNoReturnValue";
|
||||
messageAndSuggestions.suggest = [
|
||||
{
|
||||
messageId: "prependVoid",
|
||||
fix(fixer) {
|
||||
return voidPrependFixer(
|
||||
sourceCode,
|
||||
node.argument,
|
||||
fixer,
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
} else {
|
||||
messageAndSuggestions.messageId =
|
||||
"expectedNoReturnValue";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// if allowImplicit: false, should also check node.argument
|
||||
if (!options.allowImplicit && !node.argument) {
|
||||
messageAndSuggestions.messageId = "expectedReturnValue";
|
||||
}
|
||||
}
|
||||
|
||||
if (messageAndSuggestions.messageId) {
|
||||
context.report({
|
||||
node,
|
||||
messageId: messageAndSuggestions.messageId,
|
||||
data: {
|
||||
name: astUtils.getFunctionNameWithKind(
|
||||
funcInfo.node,
|
||||
),
|
||||
arrayMethodName: fullMethodName(
|
||||
funcInfo.arrayMethodName,
|
||||
),
|
||||
},
|
||||
suggest:
|
||||
messageAndSuggestions.suggest.length !== 0
|
||||
? messageAndSuggestions.suggest
|
||||
: null,
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// Reports a given function if the last path is reachable.
|
||||
"FunctionExpression:exit": checkLastSegment,
|
||||
"ArrowFunctionExpression:exit": checkLastSegment,
|
||||
};
|
||||
},
|
||||
};
|
||||
374
slider/node_modules/eslint/lib/rules/array-element-newline.js
generated
vendored
Normal file
374
slider/node_modules/eslint/lib/rules/array-element-newline.js
generated
vendored
Normal file
@@ -0,0 +1,374 @@
|
||||
/**
|
||||
* @fileoverview Rule to enforce line breaks after each array element
|
||||
* @author Jan Peer Stöcklmair <https://github.com/JPeer264>
|
||||
* @deprecated in ESLint v8.53.0
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
const astUtils = require("./utils/ast-utils");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../types').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
deprecated: {
|
||||
message: "Formatting rules are being moved out of ESLint core.",
|
||||
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
|
||||
deprecatedSince: "8.53.0",
|
||||
availableUntil: "10.0.0",
|
||||
replacedBy: [
|
||||
{
|
||||
message:
|
||||
"ESLint Stylistic now maintains deprecated stylistic core rules.",
|
||||
url: "https://eslint.style/guide/migration",
|
||||
plugin: {
|
||||
name: "@stylistic/eslint-plugin",
|
||||
url: "https://eslint.style",
|
||||
},
|
||||
rule: {
|
||||
name: "array-element-newline",
|
||||
url: "https://eslint.style/rules/array-element-newline",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
type: "layout",
|
||||
|
||||
docs: {
|
||||
description: "Enforce line breaks after each array element",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/latest/rules/array-element-newline",
|
||||
},
|
||||
|
||||
fixable: "whitespace",
|
||||
|
||||
schema: {
|
||||
definitions: {
|
||||
basicConfig: {
|
||||
oneOf: [
|
||||
{
|
||||
enum: ["always", "never", "consistent"],
|
||||
},
|
||||
{
|
||||
type: "object",
|
||||
properties: {
|
||||
multiline: {
|
||||
type: "boolean",
|
||||
},
|
||||
minItems: {
|
||||
type: ["integer", "null"],
|
||||
minimum: 0,
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
type: "array",
|
||||
items: [
|
||||
{
|
||||
oneOf: [
|
||||
{
|
||||
$ref: "#/definitions/basicConfig",
|
||||
},
|
||||
{
|
||||
type: "object",
|
||||
properties: {
|
||||
ArrayExpression: {
|
||||
$ref: "#/definitions/basicConfig",
|
||||
},
|
||||
ArrayPattern: {
|
||||
$ref: "#/definitions/basicConfig",
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
minProperties: 1,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
messages: {
|
||||
unexpectedLineBreak: "There should be no linebreak here.",
|
||||
missingLineBreak: "There should be a linebreak after this element.",
|
||||
},
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const sourceCode = context.sourceCode;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Helpers
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Normalizes a given option value.
|
||||
* @param {string|Object|undefined} providedOption An option value to parse.
|
||||
* @returns {{multiline: boolean, minItems: number}} Normalized option object.
|
||||
*/
|
||||
function normalizeOptionValue(providedOption) {
|
||||
let consistent = false;
|
||||
let multiline = false;
|
||||
let minItems;
|
||||
|
||||
const option = providedOption || "always";
|
||||
|
||||
if (!option || option === "always" || option.minItems === 0) {
|
||||
minItems = 0;
|
||||
} else if (option === "never") {
|
||||
minItems = Number.POSITIVE_INFINITY;
|
||||
} else if (option === "consistent") {
|
||||
consistent = true;
|
||||
minItems = Number.POSITIVE_INFINITY;
|
||||
} else {
|
||||
multiline = Boolean(option.multiline);
|
||||
minItems = option.minItems || Number.POSITIVE_INFINITY;
|
||||
}
|
||||
|
||||
return { consistent, multiline, minItems };
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes a given option value.
|
||||
* @param {string|Object|undefined} options An option value to parse.
|
||||
* @returns {{ArrayExpression: {multiline: boolean, minItems: number}, ArrayPattern: {multiline: boolean, minItems: number}}} Normalized option object.
|
||||
*/
|
||||
function normalizeOptions(options) {
|
||||
if (options && (options.ArrayExpression || options.ArrayPattern)) {
|
||||
let expressionOptions, patternOptions;
|
||||
|
||||
if (options.ArrayExpression) {
|
||||
expressionOptions = normalizeOptionValue(
|
||||
options.ArrayExpression,
|
||||
);
|
||||
}
|
||||
|
||||
if (options.ArrayPattern) {
|
||||
patternOptions = normalizeOptionValue(options.ArrayPattern);
|
||||
}
|
||||
|
||||
return {
|
||||
ArrayExpression: expressionOptions,
|
||||
ArrayPattern: patternOptions,
|
||||
};
|
||||
}
|
||||
|
||||
const value = normalizeOptionValue(options);
|
||||
|
||||
return { ArrayExpression: value, ArrayPattern: value };
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports that there shouldn't be a line break after the first token
|
||||
* @param {Token} token The token to use for the report.
|
||||
* @returns {void}
|
||||
*/
|
||||
function reportNoLineBreak(token) {
|
||||
const tokenBefore = sourceCode.getTokenBefore(token, {
|
||||
includeComments: true,
|
||||
});
|
||||
|
||||
context.report({
|
||||
loc: {
|
||||
start: tokenBefore.loc.end,
|
||||
end: token.loc.start,
|
||||
},
|
||||
messageId: "unexpectedLineBreak",
|
||||
fix(fixer) {
|
||||
if (astUtils.isCommentToken(tokenBefore)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!astUtils.isTokenOnSameLine(tokenBefore, token)) {
|
||||
return fixer.replaceTextRange(
|
||||
[tokenBefore.range[1], token.range[0]],
|
||||
" ",
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* This will check if the comma is on the same line as the next element
|
||||
* Following array:
|
||||
* [
|
||||
* 1
|
||||
* , 2
|
||||
* , 3
|
||||
* ]
|
||||
*
|
||||
* will be fixed to:
|
||||
* [
|
||||
* 1, 2, 3
|
||||
* ]
|
||||
*/
|
||||
const twoTokensBefore = sourceCode.getTokenBefore(
|
||||
tokenBefore,
|
||||
{ includeComments: true },
|
||||
);
|
||||
|
||||
if (astUtils.isCommentToken(twoTokensBefore)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return fixer.replaceTextRange(
|
||||
[twoTokensBefore.range[1], tokenBefore.range[0]],
|
||||
"",
|
||||
);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports that there should be a line break after the first token
|
||||
* @param {Token} token The token to use for the report.
|
||||
* @returns {void}
|
||||
*/
|
||||
function reportRequiredLineBreak(token) {
|
||||
const tokenBefore = sourceCode.getTokenBefore(token, {
|
||||
includeComments: true,
|
||||
});
|
||||
|
||||
context.report({
|
||||
loc: {
|
||||
start: tokenBefore.loc.end,
|
||||
end: token.loc.start,
|
||||
},
|
||||
messageId: "missingLineBreak",
|
||||
fix(fixer) {
|
||||
return fixer.replaceTextRange(
|
||||
[tokenBefore.range[1], token.range[0]],
|
||||
"\n",
|
||||
);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports a given node if it violated this rule.
|
||||
* @param {ASTNode} node A node to check. This is an ObjectExpression node or an ObjectPattern node.
|
||||
* @returns {void}
|
||||
*/
|
||||
function check(node) {
|
||||
const elements = node.elements;
|
||||
const normalizedOptions = normalizeOptions(context.options[0]);
|
||||
const options = normalizedOptions[node.type];
|
||||
|
||||
if (!options) {
|
||||
return;
|
||||
}
|
||||
|
||||
let elementBreak = false;
|
||||
|
||||
/*
|
||||
* MULTILINE: true
|
||||
* loop through every element and check
|
||||
* if at least one element has linebreaks inside
|
||||
* this ensures that following is not valid (due to elements are on the same line):
|
||||
*
|
||||
* [
|
||||
* 1,
|
||||
* 2,
|
||||
* 3
|
||||
* ]
|
||||
*/
|
||||
if (options.multiline) {
|
||||
elementBreak = elements
|
||||
.filter(element => element !== null)
|
||||
.some(
|
||||
element =>
|
||||
element.loc.start.line !== element.loc.end.line,
|
||||
);
|
||||
}
|
||||
|
||||
let linebreaksCount = 0;
|
||||
|
||||
for (let i = 0; i < node.elements.length; i++) {
|
||||
const element = node.elements[i];
|
||||
|
||||
const previousElement = elements[i - 1];
|
||||
|
||||
if (i === 0 || element === null || previousElement === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const commaToken = sourceCode.getFirstTokenBetween(
|
||||
previousElement,
|
||||
element,
|
||||
astUtils.isCommaToken,
|
||||
);
|
||||
const lastTokenOfPreviousElement =
|
||||
sourceCode.getTokenBefore(commaToken);
|
||||
const firstTokenOfCurrentElement =
|
||||
sourceCode.getTokenAfter(commaToken);
|
||||
|
||||
if (
|
||||
!astUtils.isTokenOnSameLine(
|
||||
lastTokenOfPreviousElement,
|
||||
firstTokenOfCurrentElement,
|
||||
)
|
||||
) {
|
||||
linebreaksCount++;
|
||||
}
|
||||
}
|
||||
|
||||
const needsLinebreaks =
|
||||
elements.length >= options.minItems ||
|
||||
(options.multiline && elementBreak) ||
|
||||
(options.consistent &&
|
||||
linebreaksCount > 0 &&
|
||||
linebreaksCount < node.elements.length);
|
||||
|
||||
elements.forEach((element, i) => {
|
||||
const previousElement = elements[i - 1];
|
||||
|
||||
if (i === 0 || element === null || previousElement === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
const commaToken = sourceCode.getFirstTokenBetween(
|
||||
previousElement,
|
||||
element,
|
||||
astUtils.isCommaToken,
|
||||
);
|
||||
const lastTokenOfPreviousElement =
|
||||
sourceCode.getTokenBefore(commaToken);
|
||||
const firstTokenOfCurrentElement =
|
||||
sourceCode.getTokenAfter(commaToken);
|
||||
|
||||
if (needsLinebreaks) {
|
||||
if (
|
||||
astUtils.isTokenOnSameLine(
|
||||
lastTokenOfPreviousElement,
|
||||
firstTokenOfCurrentElement,
|
||||
)
|
||||
) {
|
||||
reportRequiredLineBreak(firstTokenOfCurrentElement);
|
||||
}
|
||||
} else {
|
||||
if (
|
||||
!astUtils.isTokenOnSameLine(
|
||||
lastTokenOfPreviousElement,
|
||||
firstTokenOfCurrentElement,
|
||||
)
|
||||
) {
|
||||
reportNoLineBreak(firstTokenOfCurrentElement);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Public
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
return {
|
||||
ArrayPattern: check,
|
||||
ArrayExpression: check,
|
||||
};
|
||||
},
|
||||
};
|
||||
418
slider/node_modules/eslint/lib/rules/arrow-body-style.js
generated
vendored
Normal file
418
slider/node_modules/eslint/lib/rules/arrow-body-style.js
generated
vendored
Normal file
@@ -0,0 +1,418 @@
|
||||
/**
|
||||
* @fileoverview Rule to require braces in arrow function body.
|
||||
* @author Alberto Rodríguez
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const astUtils = require("./utils/ast-utils");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../types').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
|
||||
defaultOptions: ["as-needed"],
|
||||
|
||||
docs: {
|
||||
description: "Require braces around arrow function bodies",
|
||||
recommended: false,
|
||||
frozen: true,
|
||||
url: "https://eslint.org/docs/latest/rules/arrow-body-style",
|
||||
},
|
||||
|
||||
schema: {
|
||||
anyOf: [
|
||||
{
|
||||
type: "array",
|
||||
items: [
|
||||
{
|
||||
enum: ["always", "never"],
|
||||
},
|
||||
],
|
||||
minItems: 0,
|
||||
maxItems: 1,
|
||||
},
|
||||
{
|
||||
type: "array",
|
||||
items: [
|
||||
{
|
||||
enum: ["as-needed"],
|
||||
},
|
||||
{
|
||||
type: "object",
|
||||
properties: {
|
||||
requireReturnForObjectLiteral: {
|
||||
type: "boolean",
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
},
|
||||
],
|
||||
minItems: 0,
|
||||
maxItems: 2,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
fixable: "code",
|
||||
|
||||
messages: {
|
||||
unexpectedOtherBlock:
|
||||
"Unexpected block statement surrounding arrow body.",
|
||||
unexpectedEmptyBlock:
|
||||
"Unexpected block statement surrounding arrow body; put a value of `undefined` immediately after the `=>`.",
|
||||
unexpectedObjectBlock:
|
||||
"Unexpected block statement surrounding arrow body; parenthesize the returned value and move it immediately after the `=>`.",
|
||||
unexpectedSingleBlock:
|
||||
"Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`.",
|
||||
expectedBlock: "Expected block statement surrounding arrow body.",
|
||||
},
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const options = context.options;
|
||||
const always = options[0] === "always";
|
||||
const asNeeded = options[0] === "as-needed";
|
||||
const never = options[0] === "never";
|
||||
const requireReturnForObjectLiteral =
|
||||
options[1] && options[1].requireReturnForObjectLiteral;
|
||||
const sourceCode = context.sourceCode;
|
||||
let funcInfo = null;
|
||||
|
||||
/**
|
||||
* Checks whether the given node has ASI problem or not.
|
||||
* @param {Token} token The token to check.
|
||||
* @returns {boolean} `true` if it changes semantics if `;` or `}` followed by the token are removed.
|
||||
*/
|
||||
function hasASIProblem(token) {
|
||||
return (
|
||||
token &&
|
||||
token.type === "Punctuator" &&
|
||||
/^[([/`+-]/u.test(token.value)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the closing parenthesis by the given node.
|
||||
* @param {ASTNode} node first node after an opening parenthesis.
|
||||
* @returns {Token} The found closing parenthesis token.
|
||||
*/
|
||||
function findClosingParen(node) {
|
||||
let nodeToCheck = node;
|
||||
|
||||
while (!astUtils.isParenthesised(sourceCode, nodeToCheck)) {
|
||||
nodeToCheck = nodeToCheck.parent;
|
||||
}
|
||||
return sourceCode.getTokenAfter(nodeToCheck);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the node is inside of a for loop's init
|
||||
* @param {ASTNode} node node is inside for loop
|
||||
* @returns {boolean} `true` if the node is inside of a for loop, else `false`
|
||||
*/
|
||||
function isInsideForLoopInitializer(node) {
|
||||
if (node && node.parent) {
|
||||
if (
|
||||
node.parent.type === "ForStatement" &&
|
||||
node.parent.init === node
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return isInsideForLoopInitializer(node.parent);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether a arrow function body needs braces
|
||||
* @param {ASTNode} node The arrow function node.
|
||||
* @returns {void}
|
||||
*/
|
||||
function validate(node) {
|
||||
const arrowBody = node.body;
|
||||
|
||||
if (arrowBody.type === "BlockStatement") {
|
||||
const blockBody = arrowBody.body;
|
||||
|
||||
if (blockBody.length !== 1 && !never) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
asNeeded &&
|
||||
requireReturnForObjectLiteral &&
|
||||
blockBody[0].type === "ReturnStatement" &&
|
||||
blockBody[0].argument &&
|
||||
blockBody[0].argument.type === "ObjectExpression"
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
never ||
|
||||
(asNeeded && blockBody[0].type === "ReturnStatement")
|
||||
) {
|
||||
let messageId;
|
||||
|
||||
if (blockBody.length === 0) {
|
||||
messageId = "unexpectedEmptyBlock";
|
||||
} else if (
|
||||
blockBody.length > 1 ||
|
||||
blockBody[0].type !== "ReturnStatement"
|
||||
) {
|
||||
messageId = "unexpectedOtherBlock";
|
||||
} else if (blockBody[0].argument === null) {
|
||||
messageId = "unexpectedSingleBlock";
|
||||
} else if (
|
||||
astUtils.isOpeningBraceToken(
|
||||
sourceCode.getFirstToken(blockBody[0], { skip: 1 }),
|
||||
)
|
||||
) {
|
||||
messageId = "unexpectedObjectBlock";
|
||||
} else {
|
||||
messageId = "unexpectedSingleBlock";
|
||||
}
|
||||
|
||||
context.report({
|
||||
node,
|
||||
loc: arrowBody.loc,
|
||||
messageId,
|
||||
fix(fixer) {
|
||||
const fixes = [];
|
||||
|
||||
if (
|
||||
blockBody.length !== 1 ||
|
||||
blockBody[0].type !== "ReturnStatement" ||
|
||||
!blockBody[0].argument ||
|
||||
hasASIProblem(
|
||||
sourceCode.getTokenAfter(arrowBody),
|
||||
)
|
||||
) {
|
||||
return fixes;
|
||||
}
|
||||
|
||||
const openingBrace =
|
||||
sourceCode.getFirstToken(arrowBody);
|
||||
const closingBrace =
|
||||
sourceCode.getLastToken(arrowBody);
|
||||
const firstValueToken = sourceCode.getFirstToken(
|
||||
blockBody[0],
|
||||
1,
|
||||
);
|
||||
const lastValueToken = sourceCode.getLastToken(
|
||||
blockBody[0],
|
||||
);
|
||||
const commentsExist =
|
||||
sourceCode.commentsExistBetween(
|
||||
openingBrace,
|
||||
firstValueToken,
|
||||
) ||
|
||||
sourceCode.commentsExistBetween(
|
||||
lastValueToken,
|
||||
closingBrace,
|
||||
);
|
||||
|
||||
/*
|
||||
* Remove tokens around the return value.
|
||||
* If comments don't exist, remove extra spaces as well.
|
||||
*/
|
||||
if (commentsExist) {
|
||||
fixes.push(
|
||||
fixer.remove(openingBrace),
|
||||
fixer.remove(closingBrace),
|
||||
fixer.remove(
|
||||
sourceCode.getTokenAfter(openingBrace),
|
||||
), // return keyword
|
||||
);
|
||||
} else {
|
||||
fixes.push(
|
||||
fixer.removeRange([
|
||||
openingBrace.range[0],
|
||||
firstValueToken.range[0],
|
||||
]),
|
||||
fixer.removeRange([
|
||||
lastValueToken.range[1],
|
||||
closingBrace.range[1],
|
||||
]),
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* If the first token of the return value is `{` or the return value is a sequence expression,
|
||||
* enclose the return value by parentheses to avoid syntax error.
|
||||
*/
|
||||
if (
|
||||
astUtils.isOpeningBraceToken(firstValueToken) ||
|
||||
blockBody[0].argument.type ===
|
||||
"SequenceExpression" ||
|
||||
(funcInfo.hasInOperator &&
|
||||
isInsideForLoopInitializer(node))
|
||||
) {
|
||||
if (
|
||||
!astUtils.isParenthesised(
|
||||
sourceCode,
|
||||
blockBody[0].argument,
|
||||
)
|
||||
) {
|
||||
fixes.push(
|
||||
fixer.insertTextBefore(
|
||||
firstValueToken,
|
||||
"(",
|
||||
),
|
||||
fixer.insertTextAfter(
|
||||
lastValueToken,
|
||||
")",
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If the last token of the return statement is semicolon, remove it.
|
||||
* Non-block arrow body is an expression, not a statement.
|
||||
*/
|
||||
if (astUtils.isSemicolonToken(lastValueToken)) {
|
||||
fixes.push(fixer.remove(lastValueToken));
|
||||
}
|
||||
|
||||
return fixes;
|
||||
},
|
||||
});
|
||||
}
|
||||
} else {
|
||||
if (
|
||||
always ||
|
||||
(asNeeded &&
|
||||
requireReturnForObjectLiteral &&
|
||||
arrowBody.type === "ObjectExpression")
|
||||
) {
|
||||
context.report({
|
||||
node,
|
||||
loc: arrowBody.loc,
|
||||
messageId: "expectedBlock",
|
||||
fix(fixer) {
|
||||
const fixes = [];
|
||||
const arrowToken = sourceCode.getTokenBefore(
|
||||
arrowBody,
|
||||
astUtils.isArrowToken,
|
||||
);
|
||||
const [
|
||||
firstTokenAfterArrow,
|
||||
secondTokenAfterArrow,
|
||||
] = sourceCode.getTokensAfter(arrowToken, {
|
||||
count: 2,
|
||||
});
|
||||
const lastToken = sourceCode.getLastToken(node);
|
||||
|
||||
let parenthesisedObjectLiteral = null;
|
||||
|
||||
if (
|
||||
astUtils.isOpeningParenToken(
|
||||
firstTokenAfterArrow,
|
||||
) &&
|
||||
astUtils.isOpeningBraceToken(
|
||||
secondTokenAfterArrow,
|
||||
)
|
||||
) {
|
||||
const braceNode =
|
||||
sourceCode.getNodeByRangeIndex(
|
||||
secondTokenAfterArrow.range[0],
|
||||
);
|
||||
|
||||
if (braceNode.type === "ObjectExpression") {
|
||||
parenthesisedObjectLiteral = braceNode;
|
||||
}
|
||||
}
|
||||
|
||||
// If the value is object literal, remove parentheses which were forced by syntax.
|
||||
if (parenthesisedObjectLiteral) {
|
||||
const openingParenToken = firstTokenAfterArrow;
|
||||
const openingBraceToken = secondTokenAfterArrow;
|
||||
|
||||
if (
|
||||
astUtils.isTokenOnSameLine(
|
||||
openingParenToken,
|
||||
openingBraceToken,
|
||||
)
|
||||
) {
|
||||
fixes.push(
|
||||
fixer.replaceText(
|
||||
openingParenToken,
|
||||
"{return ",
|
||||
),
|
||||
);
|
||||
} else {
|
||||
// Avoid ASI
|
||||
fixes.push(
|
||||
fixer.replaceText(
|
||||
openingParenToken,
|
||||
"{",
|
||||
),
|
||||
fixer.insertTextBefore(
|
||||
openingBraceToken,
|
||||
"return ",
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Closing paren for the object doesn't have to be lastToken, e.g.: () => ({}).foo()
|
||||
fixes.push(
|
||||
fixer.remove(
|
||||
findClosingParen(
|
||||
parenthesisedObjectLiteral,
|
||||
),
|
||||
),
|
||||
);
|
||||
fixes.push(
|
||||
fixer.insertTextAfter(lastToken, "}"),
|
||||
);
|
||||
} else {
|
||||
fixes.push(
|
||||
fixer.insertTextBefore(
|
||||
firstTokenAfterArrow,
|
||||
"{return ",
|
||||
),
|
||||
);
|
||||
fixes.push(
|
||||
fixer.insertTextAfter(lastToken, "}"),
|
||||
);
|
||||
}
|
||||
|
||||
return fixes;
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
"BinaryExpression[operator='in']"() {
|
||||
let info = funcInfo;
|
||||
|
||||
while (info) {
|
||||
info.hasInOperator = true;
|
||||
info = info.upper;
|
||||
}
|
||||
},
|
||||
ArrowFunctionExpression() {
|
||||
funcInfo = {
|
||||
upper: funcInfo,
|
||||
hasInOperator: false,
|
||||
};
|
||||
},
|
||||
"ArrowFunctionExpression:exit"(node) {
|
||||
validate(node);
|
||||
funcInfo = funcInfo.upper;
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
237
slider/node_modules/eslint/lib/rules/arrow-parens.js
generated
vendored
Normal file
237
slider/node_modules/eslint/lib/rules/arrow-parens.js
generated
vendored
Normal file
@@ -0,0 +1,237 @@
|
||||
/**
|
||||
* @fileoverview Rule to require parens in arrow function arguments.
|
||||
* @author Jxck
|
||||
* @deprecated in ESLint v8.53.0
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const astUtils = require("./utils/ast-utils");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Determines if the given arrow function has block body.
|
||||
* @param {ASTNode} node `ArrowFunctionExpression` node.
|
||||
* @returns {boolean} `true` if the function has block body.
|
||||
*/
|
||||
function hasBlockBody(node) {
|
||||
return node.body.type === "BlockStatement";
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../types').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
deprecated: {
|
||||
message: "Formatting rules are being moved out of ESLint core.",
|
||||
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
|
||||
deprecatedSince: "8.53.0",
|
||||
availableUntil: "10.0.0",
|
||||
replacedBy: [
|
||||
{
|
||||
message:
|
||||
"ESLint Stylistic now maintains deprecated stylistic core rules.",
|
||||
url: "https://eslint.style/guide/migration",
|
||||
plugin: {
|
||||
name: "@stylistic/eslint-plugin",
|
||||
url: "https://eslint.style",
|
||||
},
|
||||
rule: {
|
||||
name: "arrow-parens",
|
||||
url: "https://eslint.style/rules/arrow-parens",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
type: "layout",
|
||||
|
||||
docs: {
|
||||
description: "Require parentheses around arrow function arguments",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/latest/rules/arrow-parens",
|
||||
},
|
||||
|
||||
fixable: "code",
|
||||
|
||||
schema: [
|
||||
{
|
||||
enum: ["always", "as-needed"],
|
||||
},
|
||||
{
|
||||
type: "object",
|
||||
properties: {
|
||||
requireForBlockBody: {
|
||||
type: "boolean",
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
},
|
||||
],
|
||||
|
||||
messages: {
|
||||
unexpectedParens:
|
||||
"Unexpected parentheses around single function argument.",
|
||||
expectedParens:
|
||||
"Expected parentheses around arrow function argument.",
|
||||
|
||||
unexpectedParensInline:
|
||||
"Unexpected parentheses around single function argument having a body with no curly braces.",
|
||||
expectedParensBlock:
|
||||
"Expected parentheses around arrow function argument having a body with curly braces.",
|
||||
},
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const asNeeded = context.options[0] === "as-needed";
|
||||
const requireForBlockBody =
|
||||
asNeeded &&
|
||||
context.options[1] &&
|
||||
context.options[1].requireForBlockBody === true;
|
||||
|
||||
const sourceCode = context.sourceCode;
|
||||
|
||||
/**
|
||||
* Finds opening paren of parameters for the given arrow function, if it exists.
|
||||
* It is assumed that the given arrow function has exactly one parameter.
|
||||
* @param {ASTNode} node `ArrowFunctionExpression` node.
|
||||
* @returns {Token|null} the opening paren, or `null` if the given arrow function doesn't have parens of parameters.
|
||||
*/
|
||||
function findOpeningParenOfParams(node) {
|
||||
const tokenBeforeParams = sourceCode.getTokenBefore(node.params[0]);
|
||||
|
||||
if (
|
||||
tokenBeforeParams &&
|
||||
astUtils.isOpeningParenToken(tokenBeforeParams) &&
|
||||
node.range[0] <= tokenBeforeParams.range[0]
|
||||
) {
|
||||
return tokenBeforeParams;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds closing paren of parameters for the given arrow function.
|
||||
* It is assumed that the given arrow function has parens of parameters and that it has exactly one parameter.
|
||||
* @param {ASTNode} node `ArrowFunctionExpression` node.
|
||||
* @returns {Token} the closing paren of parameters.
|
||||
*/
|
||||
function getClosingParenOfParams(node) {
|
||||
return sourceCode.getTokenAfter(
|
||||
node.params[0],
|
||||
astUtils.isClosingParenToken,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the given arrow function has comments inside parens of parameters.
|
||||
* It is assumed that the given arrow function has parens of parameters.
|
||||
* @param {ASTNode} node `ArrowFunctionExpression` node.
|
||||
* @param {Token} openingParen Opening paren of parameters.
|
||||
* @returns {boolean} `true` if the function has at least one comment inside of parens of parameters.
|
||||
*/
|
||||
function hasCommentsInParensOfParams(node, openingParen) {
|
||||
return sourceCode.commentsExistBetween(
|
||||
openingParen,
|
||||
getClosingParenOfParams(node),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the given arrow function has unexpected tokens before opening paren of parameters,
|
||||
* in which case it will be assumed that the existing parens of parameters are necessary.
|
||||
* Only tokens within the range of the arrow function (tokens that are part of the arrow function) are taken into account.
|
||||
* Example: <T>(a) => b
|
||||
* @param {ASTNode} node `ArrowFunctionExpression` node.
|
||||
* @param {Token} openingParen Opening paren of parameters.
|
||||
* @returns {boolean} `true` if the function has at least one unexpected token.
|
||||
*/
|
||||
function hasUnexpectedTokensBeforeOpeningParen(node, openingParen) {
|
||||
const expectedCount = node.async ? 1 : 0;
|
||||
|
||||
return (
|
||||
sourceCode.getFirstToken(node, { skip: expectedCount }) !==
|
||||
openingParen
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
"ArrowFunctionExpression[params.length=1]"(node) {
|
||||
const shouldHaveParens =
|
||||
!asNeeded || (requireForBlockBody && hasBlockBody(node));
|
||||
const openingParen = findOpeningParenOfParams(node);
|
||||
const hasParens = openingParen !== null;
|
||||
const [param] = node.params;
|
||||
|
||||
if (shouldHaveParens && !hasParens) {
|
||||
context.report({
|
||||
node,
|
||||
messageId: requireForBlockBody
|
||||
? "expectedParensBlock"
|
||||
: "expectedParens",
|
||||
loc: param.loc,
|
||||
*fix(fixer) {
|
||||
yield fixer.insertTextBefore(param, "(");
|
||||
yield fixer.insertTextAfter(param, ")");
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (
|
||||
!shouldHaveParens &&
|
||||
hasParens &&
|
||||
param.type === "Identifier" &&
|
||||
!param.typeAnnotation &&
|
||||
!node.returnType &&
|
||||
!hasCommentsInParensOfParams(node, openingParen) &&
|
||||
!hasUnexpectedTokensBeforeOpeningParen(node, openingParen)
|
||||
) {
|
||||
context.report({
|
||||
node,
|
||||
messageId: requireForBlockBody
|
||||
? "unexpectedParensInline"
|
||||
: "unexpectedParens",
|
||||
loc: param.loc,
|
||||
*fix(fixer) {
|
||||
const tokenBeforeOpeningParen =
|
||||
sourceCode.getTokenBefore(openingParen);
|
||||
const closingParen = getClosingParenOfParams(node);
|
||||
|
||||
if (
|
||||
tokenBeforeOpeningParen &&
|
||||
tokenBeforeOpeningParen.range[1] ===
|
||||
openingParen.range[0] &&
|
||||
!astUtils.canTokensBeAdjacent(
|
||||
tokenBeforeOpeningParen,
|
||||
sourceCode.getFirstToken(param),
|
||||
)
|
||||
) {
|
||||
yield fixer.insertTextBefore(openingParen, " ");
|
||||
}
|
||||
|
||||
// remove parens, whitespace inside parens, and possible trailing comma
|
||||
yield fixer.removeRange([
|
||||
openingParen.range[0],
|
||||
param.range[0],
|
||||
]);
|
||||
yield fixer.removeRange([
|
||||
param.range[1],
|
||||
closingParen.range[1],
|
||||
]);
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
188
slider/node_modules/eslint/lib/rules/arrow-spacing.js
generated
vendored
Normal file
188
slider/node_modules/eslint/lib/rules/arrow-spacing.js
generated
vendored
Normal file
@@ -0,0 +1,188 @@
|
||||
/**
|
||||
* @fileoverview Rule to define spacing before/after arrow function's arrow.
|
||||
* @author Jxck
|
||||
* @deprecated in ESLint v8.53.0
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const astUtils = require("./utils/ast-utils");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../types').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
deprecated: {
|
||||
message: "Formatting rules are being moved out of ESLint core.",
|
||||
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
|
||||
deprecatedSince: "8.53.0",
|
||||
availableUntil: "10.0.0",
|
||||
replacedBy: [
|
||||
{
|
||||
message:
|
||||
"ESLint Stylistic now maintains deprecated stylistic core rules.",
|
||||
url: "https://eslint.style/guide/migration",
|
||||
plugin: {
|
||||
name: "@stylistic/eslint-plugin",
|
||||
url: "https://eslint.style",
|
||||
},
|
||||
rule: {
|
||||
name: "arrow-spacing",
|
||||
url: "https://eslint.style/rules/arrow-spacing",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
type: "layout",
|
||||
|
||||
docs: {
|
||||
description:
|
||||
"Enforce consistent spacing before and after the arrow in arrow functions",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/latest/rules/arrow-spacing",
|
||||
},
|
||||
|
||||
fixable: "whitespace",
|
||||
|
||||
schema: [
|
||||
{
|
||||
type: "object",
|
||||
properties: {
|
||||
before: {
|
||||
type: "boolean",
|
||||
default: true,
|
||||
},
|
||||
after: {
|
||||
type: "boolean",
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
},
|
||||
],
|
||||
|
||||
messages: {
|
||||
expectedBefore: "Missing space before =>.",
|
||||
unexpectedBefore: "Unexpected space before =>.",
|
||||
|
||||
expectedAfter: "Missing space after =>.",
|
||||
unexpectedAfter: "Unexpected space after =>.",
|
||||
},
|
||||
},
|
||||
|
||||
create(context) {
|
||||
// merge rules with default
|
||||
const rule = Object.assign({}, context.options[0]);
|
||||
|
||||
rule.before = rule.before !== false;
|
||||
rule.after = rule.after !== false;
|
||||
|
||||
const sourceCode = context.sourceCode;
|
||||
|
||||
/**
|
||||
* Get tokens of arrow(`=>`) and before/after arrow.
|
||||
* @param {ASTNode} node The arrow function node.
|
||||
* @returns {Object} Tokens of arrow and before/after arrow.
|
||||
*/
|
||||
function getTokens(node) {
|
||||
const arrow = sourceCode.getTokenBefore(
|
||||
node.body,
|
||||
astUtils.isArrowToken,
|
||||
);
|
||||
|
||||
return {
|
||||
before: sourceCode.getTokenBefore(arrow),
|
||||
arrow,
|
||||
after: sourceCode.getTokenAfter(arrow),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Count spaces before/after arrow(`=>`) token.
|
||||
* @param {Object} tokens Tokens before/after arrow.
|
||||
* @returns {Object} count of space before/after arrow.
|
||||
*/
|
||||
function countSpaces(tokens) {
|
||||
const before = tokens.arrow.range[0] - tokens.before.range[1];
|
||||
const after = tokens.after.range[0] - tokens.arrow.range[1];
|
||||
|
||||
return { before, after };
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether space(s) before after arrow(`=>`) is satisfy rule.
|
||||
* if before/after value is `true`, there should be space(s).
|
||||
* if before/after value is `false`, there should be no space.
|
||||
* @param {ASTNode} node The arrow function node.
|
||||
* @returns {void}
|
||||
*/
|
||||
function spaces(node) {
|
||||
const tokens = getTokens(node);
|
||||
const countSpace = countSpaces(tokens);
|
||||
|
||||
if (rule.before) {
|
||||
// should be space(s) before arrow
|
||||
if (countSpace.before === 0) {
|
||||
context.report({
|
||||
node: tokens.before,
|
||||
messageId: "expectedBefore",
|
||||
fix(fixer) {
|
||||
return fixer.insertTextBefore(tokens.arrow, " ");
|
||||
},
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// should be no space before arrow
|
||||
if (countSpace.before > 0) {
|
||||
context.report({
|
||||
node: tokens.before,
|
||||
messageId: "unexpectedBefore",
|
||||
fix(fixer) {
|
||||
return fixer.removeRange([
|
||||
tokens.before.range[1],
|
||||
tokens.arrow.range[0],
|
||||
]);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (rule.after) {
|
||||
// should be space(s) after arrow
|
||||
if (countSpace.after === 0) {
|
||||
context.report({
|
||||
node: tokens.after,
|
||||
messageId: "expectedAfter",
|
||||
fix(fixer) {
|
||||
return fixer.insertTextAfter(tokens.arrow, " ");
|
||||
},
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// should be no space after arrow
|
||||
if (countSpace.after > 0) {
|
||||
context.report({
|
||||
node: tokens.after,
|
||||
messageId: "unexpectedAfter",
|
||||
fix(fixer) {
|
||||
return fixer.removeRange([
|
||||
tokens.arrow.range[1],
|
||||
tokens.after.range[0],
|
||||
]);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
ArrowFunctionExpression: spaces,
|
||||
};
|
||||
},
|
||||
};
|
||||
137
slider/node_modules/eslint/lib/rules/block-scoped-var.js
generated
vendored
Normal file
137
slider/node_modules/eslint/lib/rules/block-scoped-var.js
generated
vendored
Normal file
@@ -0,0 +1,137 @@
|
||||
/**
|
||||
* @fileoverview Rule to check for "block scoped" variables by binding context
|
||||
* @author Matt DuVall <http://www.mattduvall.com>
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../types').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
|
||||
docs: {
|
||||
description:
|
||||
"Enforce the use of variables within the scope they are defined",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/latest/rules/block-scoped-var",
|
||||
},
|
||||
|
||||
schema: [],
|
||||
|
||||
messages: {
|
||||
outOfScope:
|
||||
"'{{name}}' declared on line {{definitionLine}} column {{definitionColumn}} is used outside of binding context.",
|
||||
},
|
||||
},
|
||||
|
||||
create(context) {
|
||||
let stack = [];
|
||||
const sourceCode = context.sourceCode;
|
||||
|
||||
/**
|
||||
* Makes a block scope.
|
||||
* @param {ASTNode} node A node of a scope.
|
||||
* @returns {void}
|
||||
*/
|
||||
function enterScope(node) {
|
||||
stack.push(node.range);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pops the last block scope.
|
||||
* @returns {void}
|
||||
*/
|
||||
function exitScope() {
|
||||
stack.pop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports a given reference.
|
||||
* @param {eslint-scope.Reference} reference A reference to report.
|
||||
* @param {eslint-scope.Definition} definition A definition for which to report reference.
|
||||
* @returns {void}
|
||||
*/
|
||||
function report(reference, definition) {
|
||||
const identifier = reference.identifier;
|
||||
const definitionPosition = definition.name.loc.start;
|
||||
|
||||
context.report({
|
||||
node: identifier,
|
||||
messageId: "outOfScope",
|
||||
data: {
|
||||
name: identifier.name,
|
||||
definitionLine: definitionPosition.line,
|
||||
definitionColumn: definitionPosition.column + 1,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds and reports references which are outside of valid scopes.
|
||||
* @param {ASTNode} node A node to get variables.
|
||||
* @returns {void}
|
||||
*/
|
||||
function checkForVariables(node) {
|
||||
if (node.kind !== "var") {
|
||||
return;
|
||||
}
|
||||
|
||||
// Defines a predicate to check whether or not a given reference is outside of valid scope.
|
||||
const scopeRange = stack.at(-1);
|
||||
|
||||
/**
|
||||
* Check if a reference is out of scope
|
||||
* @param {ASTNode} reference node to examine
|
||||
* @returns {boolean} True is its outside the scope
|
||||
* @private
|
||||
*/
|
||||
function isOutsideOfScope(reference) {
|
||||
const idRange = reference.identifier.range;
|
||||
|
||||
return idRange[0] < scopeRange[0] || idRange[1] > scopeRange[1];
|
||||
}
|
||||
|
||||
// Gets declared variables, and checks its references.
|
||||
const variables = sourceCode.getDeclaredVariables(node);
|
||||
|
||||
for (let i = 0; i < variables.length; ++i) {
|
||||
// Reports.
|
||||
variables[i].references.filter(isOutsideOfScope).forEach(ref =>
|
||||
report(
|
||||
ref,
|
||||
variables[i].defs.find(def => def.parent === node),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
Program(node) {
|
||||
stack = [node.range];
|
||||
},
|
||||
|
||||
// Manages scopes.
|
||||
BlockStatement: enterScope,
|
||||
"BlockStatement:exit": exitScope,
|
||||
ForStatement: enterScope,
|
||||
"ForStatement:exit": exitScope,
|
||||
ForInStatement: enterScope,
|
||||
"ForInStatement:exit": exitScope,
|
||||
ForOfStatement: enterScope,
|
||||
"ForOfStatement:exit": exitScope,
|
||||
SwitchStatement: enterScope,
|
||||
"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,
|
||||
};
|
||||
},
|
||||
};
|
||||
202
slider/node_modules/eslint/lib/rules/block-spacing.js
generated
vendored
Normal file
202
slider/node_modules/eslint/lib/rules/block-spacing.js
generated
vendored
Normal file
@@ -0,0 +1,202 @@
|
||||
/**
|
||||
* @fileoverview A rule to disallow or enforce spaces inside of single line blocks.
|
||||
* @author Toru Nagashima
|
||||
* @deprecated in ESLint v8.53.0
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
const util = require("./utils/ast-utils");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../types').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
deprecated: {
|
||||
message: "Formatting rules are being moved out of ESLint core.",
|
||||
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
|
||||
deprecatedSince: "8.53.0",
|
||||
availableUntil: "10.0.0",
|
||||
replacedBy: [
|
||||
{
|
||||
message:
|
||||
"ESLint Stylistic now maintains deprecated stylistic core rules.",
|
||||
url: "https://eslint.style/guide/migration",
|
||||
plugin: {
|
||||
name: "@stylistic/eslint-plugin",
|
||||
url: "https://eslint.style",
|
||||
},
|
||||
rule: {
|
||||
name: "block-spacing",
|
||||
url: "https://eslint.style/rules/block-spacing",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
type: "layout",
|
||||
|
||||
docs: {
|
||||
description:
|
||||
"Disallow or enforce spaces inside of blocks after opening block and before closing block",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/latest/rules/block-spacing",
|
||||
},
|
||||
|
||||
fixable: "whitespace",
|
||||
|
||||
schema: [{ enum: ["always", "never"] }],
|
||||
|
||||
messages: {
|
||||
missing: "Requires a space {{location}} '{{token}}'.",
|
||||
extra: "Unexpected space(s) {{location}} '{{token}}'.",
|
||||
},
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const always = context.options[0] !== "never",
|
||||
messageId = always ? "missing" : "extra",
|
||||
sourceCode = context.sourceCode;
|
||||
|
||||
/**
|
||||
* Gets the open brace token from a given node.
|
||||
* @param {ASTNode} node A BlockStatement/StaticBlock/SwitchStatement node to get.
|
||||
* @returns {Token} The token of the open brace.
|
||||
*/
|
||||
function getOpenBrace(node) {
|
||||
if (node.type === "SwitchStatement") {
|
||||
if (node.cases.length > 0) {
|
||||
return sourceCode.getTokenBefore(node.cases[0]);
|
||||
}
|
||||
return sourceCode.getLastToken(node, 1);
|
||||
}
|
||||
|
||||
if (node.type === "StaticBlock") {
|
||||
return sourceCode.getFirstToken(node, { skip: 1 }); // skip the `static` token
|
||||
}
|
||||
|
||||
// "BlockStatement"
|
||||
return sourceCode.getFirstToken(node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether or not:
|
||||
* - given tokens are on same line.
|
||||
* - there is/isn't a space between given tokens.
|
||||
* @param {Token} left A token to check.
|
||||
* @param {Token} right The token which is next to `left`.
|
||||
* @returns {boolean}
|
||||
* When the option is `"always"`, `true` if there are one or more spaces between given tokens.
|
||||
* When the option is `"never"`, `true` if there are not any spaces between given tokens.
|
||||
* If given tokens are not on same line, it's always `true`.
|
||||
*/
|
||||
function isValid(left, right) {
|
||||
return (
|
||||
!util.isTokenOnSameLine(left, right) ||
|
||||
sourceCode.isSpaceBetweenTokens(left, right) === always
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks and reports invalid spacing style inside braces.
|
||||
* @param {ASTNode} node A BlockStatement/StaticBlock/SwitchStatement node to check.
|
||||
* @returns {void}
|
||||
*/
|
||||
function checkSpacingInsideBraces(node) {
|
||||
// Gets braces and the first/last token of content.
|
||||
const openBrace = getOpenBrace(node);
|
||||
const closeBrace = sourceCode.getLastToken(node);
|
||||
const firstToken = sourceCode.getTokenAfter(openBrace, {
|
||||
includeComments: true,
|
||||
});
|
||||
const lastToken = sourceCode.getTokenBefore(closeBrace, {
|
||||
includeComments: true,
|
||||
});
|
||||
|
||||
// Skip if the node is invalid or empty.
|
||||
if (
|
||||
openBrace.type !== "Punctuator" ||
|
||||
openBrace.value !== "{" ||
|
||||
closeBrace.type !== "Punctuator" ||
|
||||
closeBrace.value !== "}" ||
|
||||
firstToken === closeBrace
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Skip line comments for option never
|
||||
if (!always && firstToken.type === "Line") {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check.
|
||||
if (!isValid(openBrace, firstToken)) {
|
||||
let loc = openBrace.loc;
|
||||
|
||||
if (messageId === "extra") {
|
||||
loc = {
|
||||
start: openBrace.loc.end,
|
||||
end: firstToken.loc.start,
|
||||
};
|
||||
}
|
||||
|
||||
context.report({
|
||||
node,
|
||||
loc,
|
||||
messageId,
|
||||
data: {
|
||||
location: "after",
|
||||
token: openBrace.value,
|
||||
},
|
||||
fix(fixer) {
|
||||
if (always) {
|
||||
return fixer.insertTextBefore(firstToken, " ");
|
||||
}
|
||||
|
||||
return fixer.removeRange([
|
||||
openBrace.range[1],
|
||||
firstToken.range[0],
|
||||
]);
|
||||
},
|
||||
});
|
||||
}
|
||||
if (!isValid(lastToken, closeBrace)) {
|
||||
let loc = closeBrace.loc;
|
||||
|
||||
if (messageId === "extra") {
|
||||
loc = {
|
||||
start: lastToken.loc.end,
|
||||
end: closeBrace.loc.start,
|
||||
};
|
||||
}
|
||||
context.report({
|
||||
node,
|
||||
loc,
|
||||
messageId,
|
||||
data: {
|
||||
location: "before",
|
||||
token: closeBrace.value,
|
||||
},
|
||||
fix(fixer) {
|
||||
if (always) {
|
||||
return fixer.insertTextAfter(lastToken, " ");
|
||||
}
|
||||
|
||||
return fixer.removeRange([
|
||||
lastToken.range[1],
|
||||
closeBrace.range[0],
|
||||
]);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
BlockStatement: checkSpacingInsideBraces,
|
||||
StaticBlock: checkSpacingInsideBraces,
|
||||
SwitchStatement: checkSpacingInsideBraces,
|
||||
};
|
||||
},
|
||||
};
|
||||
278
slider/node_modules/eslint/lib/rules/brace-style.js
generated
vendored
Normal file
278
slider/node_modules/eslint/lib/rules/brace-style.js
generated
vendored
Normal file
@@ -0,0 +1,278 @@
|
||||
/**
|
||||
* @fileoverview Rule to flag block statements that do not use the one true brace style
|
||||
* @author Ian Christian Myers
|
||||
* @deprecated in ESLint v8.53.0
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
const astUtils = require("./utils/ast-utils");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../types').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
deprecated: {
|
||||
message: "Formatting rules are being moved out of ESLint core.",
|
||||
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
|
||||
deprecatedSince: "8.53.0",
|
||||
availableUntil: "10.0.0",
|
||||
replacedBy: [
|
||||
{
|
||||
message:
|
||||
"ESLint Stylistic now maintains deprecated stylistic core rules.",
|
||||
url: "https://eslint.style/guide/migration",
|
||||
plugin: {
|
||||
name: "@stylistic/eslint-plugin",
|
||||
url: "https://eslint.style",
|
||||
},
|
||||
rule: {
|
||||
name: "brace-style",
|
||||
url: "https://eslint.style/rules/brace-style",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
type: "layout",
|
||||
|
||||
docs: {
|
||||
description: "Enforce consistent brace style for blocks",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/latest/rules/brace-style",
|
||||
},
|
||||
|
||||
schema: [
|
||||
{
|
||||
enum: ["1tbs", "stroustrup", "allman"],
|
||||
},
|
||||
{
|
||||
type: "object",
|
||||
properties: {
|
||||
allowSingleLine: {
|
||||
type: "boolean",
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
},
|
||||
],
|
||||
|
||||
fixable: "whitespace",
|
||||
|
||||
messages: {
|
||||
nextLineOpen:
|
||||
"Opening curly brace does not appear on the same line as controlling statement.",
|
||||
sameLineOpen:
|
||||
"Opening curly brace appears on the same line as controlling statement.",
|
||||
blockSameLine:
|
||||
"Statement inside of curly braces should be on next line.",
|
||||
nextLineClose:
|
||||
"Closing curly brace does not appear on the same line as the subsequent block.",
|
||||
singleLineClose:
|
||||
"Closing curly brace should be on the same line as opening curly brace or on the line after the previous block.",
|
||||
sameLineClose:
|
||||
"Closing curly brace appears on the same line as the subsequent block.",
|
||||
},
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const style = context.options[0] || "1tbs",
|
||||
params = context.options[1] || {},
|
||||
sourceCode = context.sourceCode;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Fixes a place where a newline unexpectedly appears
|
||||
* @param {Token} firstToken The token before the unexpected newline
|
||||
* @param {Token} secondToken The token after the unexpected newline
|
||||
* @returns {Function} A fixer function to remove the newlines between the tokens
|
||||
*/
|
||||
function removeNewlineBetween(firstToken, secondToken) {
|
||||
const textRange = [firstToken.range[1], secondToken.range[0]];
|
||||
const textBetween = sourceCode.text.slice(
|
||||
textRange[0],
|
||||
textRange[1],
|
||||
);
|
||||
|
||||
// Don't do a fix if there is a comment between the tokens
|
||||
if (textBetween.trim()) {
|
||||
return null;
|
||||
}
|
||||
return fixer => fixer.replaceTextRange(textRange, " ");
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates a pair of curly brackets based on the user's config
|
||||
* @param {Token} openingCurly The opening curly bracket
|
||||
* @param {Token} closingCurly The closing curly bracket
|
||||
* @returns {void}
|
||||
*/
|
||||
function validateCurlyPair(openingCurly, closingCurly) {
|
||||
const tokenBeforeOpeningCurly =
|
||||
sourceCode.getTokenBefore(openingCurly);
|
||||
const tokenAfterOpeningCurly =
|
||||
sourceCode.getTokenAfter(openingCurly);
|
||||
const tokenBeforeClosingCurly =
|
||||
sourceCode.getTokenBefore(closingCurly);
|
||||
const singleLineException =
|
||||
params.allowSingleLine &&
|
||||
astUtils.isTokenOnSameLine(openingCurly, closingCurly);
|
||||
|
||||
if (
|
||||
style !== "allman" &&
|
||||
!astUtils.isTokenOnSameLine(
|
||||
tokenBeforeOpeningCurly,
|
||||
openingCurly,
|
||||
)
|
||||
) {
|
||||
context.report({
|
||||
node: openingCurly,
|
||||
messageId: "nextLineOpen",
|
||||
fix: removeNewlineBetween(
|
||||
tokenBeforeOpeningCurly,
|
||||
openingCurly,
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
if (
|
||||
style === "allman" &&
|
||||
astUtils.isTokenOnSameLine(
|
||||
tokenBeforeOpeningCurly,
|
||||
openingCurly,
|
||||
) &&
|
||||
!singleLineException
|
||||
) {
|
||||
context.report({
|
||||
node: openingCurly,
|
||||
messageId: "sameLineOpen",
|
||||
fix: fixer => fixer.insertTextBefore(openingCurly, "\n"),
|
||||
});
|
||||
}
|
||||
|
||||
if (
|
||||
astUtils.isTokenOnSameLine(
|
||||
openingCurly,
|
||||
tokenAfterOpeningCurly,
|
||||
) &&
|
||||
tokenAfterOpeningCurly !== closingCurly &&
|
||||
!singleLineException
|
||||
) {
|
||||
context.report({
|
||||
node: openingCurly,
|
||||
messageId: "blockSameLine",
|
||||
fix: fixer => fixer.insertTextAfter(openingCurly, "\n"),
|
||||
});
|
||||
}
|
||||
|
||||
if (
|
||||
tokenBeforeClosingCurly !== openingCurly &&
|
||||
!singleLineException &&
|
||||
astUtils.isTokenOnSameLine(
|
||||
tokenBeforeClosingCurly,
|
||||
closingCurly,
|
||||
)
|
||||
) {
|
||||
context.report({
|
||||
node: closingCurly,
|
||||
messageId: "singleLineClose",
|
||||
fix: fixer => fixer.insertTextBefore(closingCurly, "\n"),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the location of a token that appears before a keyword (e.g. a newline before `else`)
|
||||
* @param {Token} curlyToken The closing curly token. This is assumed to precede a keyword token (such as `else` or `finally`).
|
||||
* @returns {void}
|
||||
*/
|
||||
function validateCurlyBeforeKeyword(curlyToken) {
|
||||
const keywordToken = sourceCode.getTokenAfter(curlyToken);
|
||||
|
||||
if (
|
||||
style === "1tbs" &&
|
||||
!astUtils.isTokenOnSameLine(curlyToken, keywordToken)
|
||||
) {
|
||||
context.report({
|
||||
node: curlyToken,
|
||||
messageId: "nextLineClose",
|
||||
fix: removeNewlineBetween(curlyToken, keywordToken),
|
||||
});
|
||||
}
|
||||
|
||||
if (
|
||||
style !== "1tbs" &&
|
||||
astUtils.isTokenOnSameLine(curlyToken, keywordToken)
|
||||
) {
|
||||
context.report({
|
||||
node: curlyToken,
|
||||
messageId: "sameLineClose",
|
||||
fix: fixer => fixer.insertTextAfter(curlyToken, "\n"),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Public API
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
return {
|
||||
BlockStatement(node) {
|
||||
if (!astUtils.STATEMENT_LIST_PARENTS.has(node.parent.type)) {
|
||||
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),
|
||||
);
|
||||
},
|
||||
SwitchStatement(node) {
|
||||
const closingCurly = sourceCode.getLastToken(node);
|
||||
const openingCurly = sourceCode.getTokenBefore(
|
||||
node.cases.length ? node.cases[0] : closingCurly,
|
||||
);
|
||||
|
||||
validateCurlyPair(openingCurly, closingCurly);
|
||||
},
|
||||
IfStatement(node) {
|
||||
if (
|
||||
node.consequent.type === "BlockStatement" &&
|
||||
node.alternate
|
||||
) {
|
||||
// Handle the keyword after the `if` block (before `else`)
|
||||
validateCurlyBeforeKeyword(
|
||||
sourceCode.getLastToken(node.consequent),
|
||||
);
|
||||
}
|
||||
},
|
||||
TryStatement(node) {
|
||||
// Handle the keyword after the `try` block (before `catch` or `finally`)
|
||||
validateCurlyBeforeKeyword(sourceCode.getLastToken(node.block));
|
||||
|
||||
if (node.handler && node.finalizer) {
|
||||
// Handle the keyword after the `catch` block (before `finally`)
|
||||
validateCurlyBeforeKeyword(
|
||||
sourceCode.getLastToken(node.handler.body),
|
||||
);
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
216
slider/node_modules/eslint/lib/rules/callback-return.js
generated
vendored
Normal file
216
slider/node_modules/eslint/lib/rules/callback-return.js
generated
vendored
Normal file
@@ -0,0 +1,216 @@
|
||||
/**
|
||||
* @fileoverview Enforce return after a callback.
|
||||
* @author Jamund Ferguson
|
||||
* @deprecated in ESLint v7.0.0
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../types').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
deprecated: {
|
||||
message: "Node.js rules were moved out of ESLint core.",
|
||||
url: "https://eslint.org/docs/latest/use/migrating-to-7.0.0#deprecate-node-rules",
|
||||
deprecatedSince: "7.0.0",
|
||||
availableUntil: null,
|
||||
replacedBy: [
|
||||
{
|
||||
message:
|
||||
"eslint-plugin-n now maintains deprecated Node.js-related rules.",
|
||||
plugin: {
|
||||
name: "eslint-plugin-n",
|
||||
url: "https://github.com/eslint-community/eslint-plugin-n",
|
||||
},
|
||||
rule: {
|
||||
name: "callback-return",
|
||||
url: "https://github.com/eslint-community/eslint-plugin-n/tree/master/docs/rules/callback-return.md",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
type: "suggestion",
|
||||
|
||||
docs: {
|
||||
description: "Require `return` statements after callbacks",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/latest/rules/callback-return",
|
||||
},
|
||||
|
||||
schema: [
|
||||
{
|
||||
type: "array",
|
||||
items: { type: "string" },
|
||||
},
|
||||
],
|
||||
|
||||
messages: {
|
||||
missingReturn: "Expected return with your callback function.",
|
||||
},
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const callbacks = context.options[0] || ["callback", "cb", "next"],
|
||||
sourceCode = context.sourceCode;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Find the closest parent matching a list of types.
|
||||
* @param {ASTNode} node The node whose parents we are searching
|
||||
* @param {Array} types The node types to match
|
||||
* @returns {ASTNode} The matched node or undefined.
|
||||
*/
|
||||
function findClosestParentOfType(node, types) {
|
||||
if (!node.parent) {
|
||||
return null;
|
||||
}
|
||||
if (!types.includes(node.parent.type)) {
|
||||
return findClosestParentOfType(node.parent, types);
|
||||
}
|
||||
return node.parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if a node contains only identifiers
|
||||
* @param {ASTNode} node The node to check
|
||||
* @returns {boolean} Whether or not the node contains only identifiers
|
||||
*/
|
||||
function containsOnlyIdentifiers(node) {
|
||||
if (node.type === "Identifier") {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (node.type === "MemberExpression") {
|
||||
if (node.object.type === "Identifier") {
|
||||
return true;
|
||||
}
|
||||
if (node.object.type === "MemberExpression") {
|
||||
return containsOnlyIdentifiers(node.object);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if a CallExpression is in our callback list.
|
||||
* @param {ASTNode} node The node to check against our callback names list.
|
||||
* @returns {boolean} Whether or not this function matches our callback name.
|
||||
*/
|
||||
function isCallback(node) {
|
||||
return (
|
||||
containsOnlyIdentifiers(node.callee) &&
|
||||
callbacks.includes(sourceCode.getText(node.callee))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether or not the callback is part of a callback expression.
|
||||
* @param {ASTNode} node The callback node
|
||||
* @param {ASTNode} parentNode The expression node
|
||||
* @returns {boolean} Whether or not this is part of a callback expression
|
||||
*/
|
||||
function isCallbackExpression(node, parentNode) {
|
||||
// ensure the parent node exists and is an expression
|
||||
if (!parentNode || parentNode.type !== "ExpressionStatement") {
|
||||
return false;
|
||||
}
|
||||
|
||||
// cb()
|
||||
if (parentNode.expression === node) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// special case for cb && cb() and similar
|
||||
if (
|
||||
parentNode.expression.type === "BinaryExpression" ||
|
||||
parentNode.expression.type === "LogicalExpression"
|
||||
) {
|
||||
if (parentNode.expression.right === node) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Public
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
return {
|
||||
CallExpression(node) {
|
||||
// if we're not a callback we can return
|
||||
if (!isCallback(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// find the closest block, return or loop
|
||||
const closestBlock =
|
||||
findClosestParentOfType(node, [
|
||||
"BlockStatement",
|
||||
"ReturnStatement",
|
||||
"ArrowFunctionExpression",
|
||||
]) || {};
|
||||
|
||||
// if our parent is a return we know we're ok
|
||||
if (closestBlock.type === "ReturnStatement") {
|
||||
return;
|
||||
}
|
||||
|
||||
// arrow functions don't always have blocks and implicitly return
|
||||
if (closestBlock.type === "ArrowFunctionExpression") {
|
||||
return;
|
||||
}
|
||||
|
||||
// block statements are part of functions and most if statements
|
||||
if (closestBlock.type === "BlockStatement") {
|
||||
// find the last item in the block
|
||||
const lastItem = closestBlock.body.at(-1);
|
||||
|
||||
// if the callback is the last thing in a block that might be ok
|
||||
if (isCallbackExpression(node, lastItem)) {
|
||||
const parentType = closestBlock.parent.type;
|
||||
|
||||
// but only if the block is part of a function
|
||||
if (
|
||||
parentType === "FunctionExpression" ||
|
||||
parentType === "FunctionDeclaration" ||
|
||||
parentType === "ArrowFunctionExpression"
|
||||
) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// ending a block with a return is also ok
|
||||
if (lastItem.type === "ReturnStatement") {
|
||||
// but only if the callback is immediately before
|
||||
if (
|
||||
isCallbackExpression(node, closestBlock.body.at(-2))
|
||||
) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// as long as you're the child of a function at this point you should be asked to return
|
||||
if (
|
||||
findClosestParentOfType(node, [
|
||||
"FunctionDeclaration",
|
||||
"FunctionExpression",
|
||||
"ArrowFunctionExpression",
|
||||
])
|
||||
) {
|
||||
context.report({ node, messageId: "missingReturn" });
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
422
slider/node_modules/eslint/lib/rules/camelcase.js
generated
vendored
Normal file
422
slider/node_modules/eslint/lib/rules/camelcase.js
generated
vendored
Normal file
@@ -0,0 +1,422 @@
|
||||
/**
|
||||
* @fileoverview Rule to flag non-camelcased identifiers
|
||||
* @author Nicholas C. Zakas
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const astUtils = require("./utils/ast-utils");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../types').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
|
||||
defaultOptions: [
|
||||
{
|
||||
allow: [],
|
||||
ignoreDestructuring: false,
|
||||
ignoreGlobals: false,
|
||||
ignoreImports: false,
|
||||
properties: "always",
|
||||
},
|
||||
],
|
||||
|
||||
docs: {
|
||||
description: "Enforce camelcase naming convention",
|
||||
recommended: false,
|
||||
frozen: true,
|
||||
url: "https://eslint.org/docs/latest/rules/camelcase",
|
||||
},
|
||||
|
||||
schema: [
|
||||
{
|
||||
type: "object",
|
||||
properties: {
|
||||
ignoreDestructuring: {
|
||||
type: "boolean",
|
||||
},
|
||||
ignoreImports: {
|
||||
type: "boolean",
|
||||
},
|
||||
ignoreGlobals: {
|
||||
type: "boolean",
|
||||
},
|
||||
properties: {
|
||||
enum: ["always", "never"],
|
||||
},
|
||||
allow: {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "string",
|
||||
},
|
||||
minItems: 0,
|
||||
uniqueItems: true,
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
},
|
||||
],
|
||||
|
||||
messages: {
|
||||
notCamelCase: "Identifier '{{name}}' is not in camel case.",
|
||||
notCamelCasePrivate: "#{{name}} is not in camel case.",
|
||||
},
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const [
|
||||
{
|
||||
allow,
|
||||
ignoreDestructuring,
|
||||
ignoreGlobals,
|
||||
ignoreImports,
|
||||
properties,
|
||||
},
|
||||
] = context.options;
|
||||
const sourceCode = context.sourceCode;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
// contains reported nodes to avoid reporting twice on destructuring with shorthand notation
|
||||
const reported = new Set();
|
||||
|
||||
/**
|
||||
* Checks if a string contains an underscore and isn't all upper-case
|
||||
* @param {string} name The string to check.
|
||||
* @returns {boolean} if the string is underscored
|
||||
* @private
|
||||
*/
|
||||
function isUnderscored(name) {
|
||||
const nameBody = name.replace(/^_+|_+$/gu, "");
|
||||
|
||||
// if there's an underscore, it might be A_CONSTANT, which is okay
|
||||
return (
|
||||
nameBody.includes("_") && nameBody !== nameBody.toUpperCase()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a string match the ignore list
|
||||
* @param {string} name The string to check.
|
||||
* @returns {boolean} if the string is ignored
|
||||
* @private
|
||||
*/
|
||||
function isAllowed(name) {
|
||||
return allow.some(
|
||||
entry => name === entry || name.match(new RegExp(entry, "u")),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a given name is good or not.
|
||||
* @param {string} name The name to check.
|
||||
* @returns {boolean} `true` if the name is good.
|
||||
* @private
|
||||
*/
|
||||
function isGoodName(name) {
|
||||
return !isUnderscored(name) || isAllowed(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a given identifier reference or member expression is an assignment
|
||||
* target.
|
||||
* @param {ASTNode} node The node to check.
|
||||
* @returns {boolean} `true` if the node is an assignment target.
|
||||
*/
|
||||
function isAssignmentTarget(node) {
|
||||
const parent = node.parent;
|
||||
|
||||
switch (parent.type) {
|
||||
case "AssignmentExpression":
|
||||
case "AssignmentPattern":
|
||||
return parent.left === node;
|
||||
|
||||
case "Property":
|
||||
return (
|
||||
parent.parent.type === "ObjectPattern" &&
|
||||
parent.value === node
|
||||
);
|
||||
case "ArrayPattern":
|
||||
case "RestElement":
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a given binding identifier uses the original name as-is.
|
||||
* - If it's in object destructuring or object expression, the original name is its property name.
|
||||
* - If it's in import declaration, the original name is its exported name.
|
||||
* @param {ASTNode} node The `Identifier` node to check.
|
||||
* @returns {boolean} `true` if the identifier uses the original name as-is.
|
||||
*/
|
||||
function equalsToOriginalName(node) {
|
||||
const localName = node.name;
|
||||
const valueNode =
|
||||
node.parent.type === "AssignmentPattern" ? node.parent : node;
|
||||
const parent = valueNode.parent;
|
||||
|
||||
switch (parent.type) {
|
||||
case "Property":
|
||||
return (
|
||||
(parent.parent.type === "ObjectPattern" ||
|
||||
parent.parent.type === "ObjectExpression") &&
|
||||
parent.value === valueNode &&
|
||||
!parent.computed &&
|
||||
parent.key.type === "Identifier" &&
|
||||
parent.key.name === localName
|
||||
);
|
||||
|
||||
case "ImportSpecifier":
|
||||
return (
|
||||
parent.local === node &&
|
||||
astUtils.getModuleExportName(parent.imported) ===
|
||||
localName
|
||||
);
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports an AST node as a rule violation.
|
||||
* @param {ASTNode} node The node to report.
|
||||
* @returns {void}
|
||||
* @private
|
||||
*/
|
||||
function report(node) {
|
||||
if (reported.has(node.range[0])) {
|
||||
return;
|
||||
}
|
||||
reported.add(node.range[0]);
|
||||
|
||||
// Report it.
|
||||
context.report({
|
||||
node,
|
||||
messageId:
|
||||
node.type === "PrivateIdentifier"
|
||||
? "notCamelCasePrivate"
|
||||
: "notCamelCase",
|
||||
data: { name: node.name },
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports an identifier reference or a binding identifier.
|
||||
* @param {ASTNode} node The `Identifier` node to report.
|
||||
* @returns {void}
|
||||
*/
|
||||
function reportReferenceId(node) {
|
||||
/*
|
||||
* For backward compatibility, if it's in callings then ignore it.
|
||||
* Not sure why it is.
|
||||
*/
|
||||
if (
|
||||
node.parent.type === "CallExpression" ||
|
||||
node.parent.type === "NewExpression"
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* For backward compatibility, if it's a default value of
|
||||
* destructuring/parameters then ignore it.
|
||||
* Not sure why it is.
|
||||
*/
|
||||
if (
|
||||
node.parent.type === "AssignmentPattern" &&
|
||||
node.parent.right === node
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* The `ignoreDestructuring` flag skips the identifiers that uses
|
||||
* the property name as-is.
|
||||
*/
|
||||
if (ignoreDestructuring && equalsToOriginalName(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Import attribute keys are always ignored
|
||||
*/
|
||||
if (astUtils.isImportAttributeKey(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
report(node);
|
||||
}
|
||||
|
||||
return {
|
||||
// Report camelcase of global variable references ------------------
|
||||
Program(node) {
|
||||
const scope = sourceCode.getScope(node);
|
||||
|
||||
if (!ignoreGlobals) {
|
||||
// Defined globals in config files or directive comments.
|
||||
for (const variable of scope.variables) {
|
||||
if (
|
||||
variable.identifiers.length > 0 ||
|
||||
isGoodName(variable.name)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
for (const reference of variable.references) {
|
||||
/*
|
||||
* For backward compatibility, this rule reports read-only
|
||||
* references as well.
|
||||
*/
|
||||
reportReferenceId(reference.identifier);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Undefined globals.
|
||||
for (const reference of scope.through) {
|
||||
const id = reference.identifier;
|
||||
|
||||
if (
|
||||
isGoodName(id.name) ||
|
||||
astUtils.isImportAttributeKey(id)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* For backward compatibility, this rule reports read-only
|
||||
* references as well.
|
||||
*/
|
||||
reportReferenceId(id);
|
||||
}
|
||||
},
|
||||
|
||||
// Report camelcase of declared variables --------------------------
|
||||
[[
|
||||
"VariableDeclaration",
|
||||
"FunctionDeclaration",
|
||||
"FunctionExpression",
|
||||
"ArrowFunctionExpression",
|
||||
"ClassDeclaration",
|
||||
"ClassExpression",
|
||||
"CatchClause",
|
||||
]](node) {
|
||||
for (const variable of sourceCode.getDeclaredVariables(node)) {
|
||||
if (isGoodName(variable.name)) {
|
||||
continue;
|
||||
}
|
||||
const id = variable.identifiers[0];
|
||||
|
||||
// Report declaration.
|
||||
if (!(ignoreDestructuring && equalsToOriginalName(id))) {
|
||||
report(id);
|
||||
}
|
||||
|
||||
/*
|
||||
* For backward compatibility, report references as well.
|
||||
* It looks unnecessary because declarations are reported.
|
||||
*/
|
||||
for (const reference of variable.references) {
|
||||
if (reference.init) {
|
||||
continue; // Skip the write references of initializers.
|
||||
}
|
||||
reportReferenceId(reference.identifier);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// Report camelcase in properties ----------------------------------
|
||||
[[
|
||||
"ObjectExpression > Property[computed!=true] > Identifier.key",
|
||||
"MethodDefinition[computed!=true] > Identifier.key",
|
||||
"PropertyDefinition[computed!=true] > Identifier.key",
|
||||
"MethodDefinition > PrivateIdentifier.key",
|
||||
"PropertyDefinition > PrivateIdentifier.key",
|
||||
]](node) {
|
||||
if (
|
||||
properties === "never" ||
|
||||
astUtils.isImportAttributeKey(node) ||
|
||||
isGoodName(node.name)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
report(node);
|
||||
},
|
||||
"MemberExpression[computed!=true] > Identifier.property"(node) {
|
||||
if (
|
||||
properties === "never" ||
|
||||
!isAssignmentTarget(node.parent) || // ← ignore read-only references.
|
||||
isGoodName(node.name)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
report(node);
|
||||
},
|
||||
|
||||
// Report camelcase in import --------------------------------------
|
||||
ImportDeclaration(node) {
|
||||
for (const variable of sourceCode.getDeclaredVariables(node)) {
|
||||
if (isGoodName(variable.name)) {
|
||||
continue;
|
||||
}
|
||||
const id = variable.identifiers[0];
|
||||
|
||||
// Report declaration.
|
||||
if (!(ignoreImports && equalsToOriginalName(id))) {
|
||||
report(id);
|
||||
}
|
||||
|
||||
/*
|
||||
* For backward compatibility, report references as well.
|
||||
* It looks unnecessary because declarations are reported.
|
||||
*/
|
||||
for (const reference of variable.references) {
|
||||
reportReferenceId(reference.identifier);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// Report camelcase in re-export -----------------------------------
|
||||
[[
|
||||
"ExportAllDeclaration > Identifier.exported",
|
||||
"ExportSpecifier > Identifier.exported",
|
||||
]](node) {
|
||||
if (isGoodName(node.name)) {
|
||||
return;
|
||||
}
|
||||
report(node);
|
||||
},
|
||||
|
||||
// Report camelcase in labels --------------------------------------
|
||||
[[
|
||||
"LabeledStatement > Identifier.label",
|
||||
|
||||
/*
|
||||
* For backward compatibility, report references as well.
|
||||
* It looks unnecessary because declarations are reported.
|
||||
*/
|
||||
"BreakStatement > Identifier.label",
|
||||
"ContinueStatement > Identifier.label",
|
||||
]](node) {
|
||||
if (isGoodName(node.name)) {
|
||||
return;
|
||||
}
|
||||
report(node);
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
325
slider/node_modules/eslint/lib/rules/capitalized-comments.js
generated
vendored
Normal file
325
slider/node_modules/eslint/lib/rules/capitalized-comments.js
generated
vendored
Normal file
@@ -0,0 +1,325 @@
|
||||
/**
|
||||
* @fileoverview enforce or disallow capitalization of the first letter of a comment
|
||||
* @author Kevin Partington
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const astUtils = require("./utils/ast-utils");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const DEFAULT_IGNORE_PATTERN = astUtils.COMMENTS_IGNORE_PATTERN,
|
||||
WHITESPACE = /\s/gu,
|
||||
MAYBE_URL = /^\s*[^:/?#\s]+:\/\/[^?#]/u, // TODO: Combine w/ max-len pattern?
|
||||
LETTER_PATTERN = /\p{L}/u;
|
||||
|
||||
/*
|
||||
* Base schema body for defining the basic capitalization rule, ignorePattern,
|
||||
* and ignoreInlineComments values.
|
||||
* This can be used in a few different ways in the actual schema.
|
||||
*/
|
||||
const SCHEMA_BODY = {
|
||||
type: "object",
|
||||
properties: {
|
||||
ignorePattern: {
|
||||
type: "string",
|
||||
},
|
||||
ignoreInlineComments: {
|
||||
type: "boolean",
|
||||
},
|
||||
ignoreConsecutiveComments: {
|
||||
type: "boolean",
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
};
|
||||
const DEFAULTS = {
|
||||
ignorePattern: "",
|
||||
ignoreInlineComments: false,
|
||||
ignoreConsecutiveComments: false,
|
||||
};
|
||||
|
||||
/**
|
||||
* Get normalized options for either block or line comments from the given
|
||||
* user-provided options.
|
||||
* - If the user-provided options is just a string, returns a normalized
|
||||
* set of options using default values for all other options.
|
||||
* - If the user-provided options is an object, then a normalized option
|
||||
* set is returned. Options specified in overrides will take priority
|
||||
* over options specified in the main options object, which will in
|
||||
* turn take priority over the rule's defaults.
|
||||
* @param {Object|string} rawOptions The user-provided options.
|
||||
* @param {string} which Either "line" or "block".
|
||||
* @returns {Object} The normalized options.
|
||||
*/
|
||||
function getNormalizedOptions(rawOptions, which) {
|
||||
return Object.assign({}, DEFAULTS, rawOptions[which] || rawOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get normalized options for block and line comments.
|
||||
* @param {Object|string} rawOptions The user-provided options.
|
||||
* @returns {Object} An object with "Line" and "Block" keys and corresponding
|
||||
* normalized options objects.
|
||||
*/
|
||||
function getAllNormalizedOptions(rawOptions = {}) {
|
||||
return {
|
||||
Line: getNormalizedOptions(rawOptions, "line"),
|
||||
Block: getNormalizedOptions(rawOptions, "block"),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a regular expression for each ignorePattern defined in the rule
|
||||
* options.
|
||||
*
|
||||
* This is done in order to avoid invoking the RegExp constructor repeatedly.
|
||||
* @param {Object} normalizedOptions The normalized rule options.
|
||||
* @returns {void}
|
||||
*/
|
||||
function createRegExpForIgnorePatterns(normalizedOptions) {
|
||||
Object.keys(normalizedOptions).forEach(key => {
|
||||
const ignorePatternStr = normalizedOptions[key].ignorePattern;
|
||||
|
||||
if (ignorePatternStr) {
|
||||
const regExp = RegExp(`^\\s*(?:${ignorePatternStr})`, "u");
|
||||
|
||||
normalizedOptions[key].ignorePatternRegExp = regExp;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../types').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
|
||||
docs: {
|
||||
description:
|
||||
"Enforce or disallow capitalization of the first letter of a comment",
|
||||
recommended: false,
|
||||
frozen: true,
|
||||
url: "https://eslint.org/docs/latest/rules/capitalized-comments",
|
||||
},
|
||||
|
||||
fixable: "code",
|
||||
|
||||
schema: [
|
||||
{ enum: ["always", "never"] },
|
||||
{
|
||||
oneOf: [
|
||||
SCHEMA_BODY,
|
||||
{
|
||||
type: "object",
|
||||
properties: {
|
||||
line: SCHEMA_BODY,
|
||||
block: SCHEMA_BODY,
|
||||
},
|
||||
additionalProperties: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
messages: {
|
||||
unexpectedLowercaseComment:
|
||||
"Comments should not begin with a lowercase character.",
|
||||
unexpectedUppercaseComment:
|
||||
"Comments should not begin with an uppercase character.",
|
||||
},
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const capitalize = context.options[0] || "always",
|
||||
normalizedOptions = getAllNormalizedOptions(context.options[1]),
|
||||
sourceCode = context.sourceCode;
|
||||
|
||||
createRegExpForIgnorePatterns(normalizedOptions);
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Helpers
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Checks whether a comment is an inline comment.
|
||||
*
|
||||
* For the purpose of this rule, a comment is inline if:
|
||||
* 1. The comment is preceded by a token on the same line; and
|
||||
* 2. The command is followed by a token on the same line.
|
||||
*
|
||||
* Note that the comment itself need not be single-line!
|
||||
*
|
||||
* Also, it follows from this definition that only block comments can
|
||||
* be considered as possibly inline. This is because line comments
|
||||
* would consume any following tokens on the same line as the comment.
|
||||
* @param {ASTNode} comment The comment node to check.
|
||||
* @returns {boolean} True if the comment is an inline comment, false
|
||||
* otherwise.
|
||||
*/
|
||||
function isInlineComment(comment) {
|
||||
const previousToken = sourceCode.getTokenBefore(comment, {
|
||||
includeComments: true,
|
||||
}),
|
||||
nextToken = sourceCode.getTokenAfter(comment, {
|
||||
includeComments: true,
|
||||
});
|
||||
|
||||
return Boolean(
|
||||
previousToken &&
|
||||
nextToken &&
|
||||
comment.loc.start.line === previousToken.loc.end.line &&
|
||||
comment.loc.end.line === nextToken.loc.start.line,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a comment follows another comment.
|
||||
* @param {ASTNode} comment The comment to check.
|
||||
* @returns {boolean} True if the comment follows a valid comment.
|
||||
*/
|
||||
function isConsecutiveComment(comment) {
|
||||
const previousTokenOrComment = sourceCode.getTokenBefore(comment, {
|
||||
includeComments: true,
|
||||
});
|
||||
|
||||
return Boolean(
|
||||
previousTokenOrComment &&
|
||||
["Block", "Line"].includes(previousTokenOrComment.type),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check a comment to determine if it is valid for this rule.
|
||||
* @param {ASTNode} comment The comment node to process.
|
||||
* @param {Object} options The options for checking this comment.
|
||||
* @returns {boolean} True if the comment is valid, false otherwise.
|
||||
*/
|
||||
function isCommentValid(comment, options) {
|
||||
// 1. Check for default ignore pattern.
|
||||
if (DEFAULT_IGNORE_PATTERN.test(comment.value)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 2. Check for custom ignore pattern.
|
||||
const commentWithoutAsterisks = comment.value.replace(/\*/gu, "");
|
||||
|
||||
if (
|
||||
options.ignorePatternRegExp &&
|
||||
options.ignorePatternRegExp.test(commentWithoutAsterisks)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 3. Check for inline comments.
|
||||
if (options.ignoreInlineComments && isInlineComment(comment)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 4. Is this a consecutive comment (and are we tolerating those)?
|
||||
if (
|
||||
options.ignoreConsecutiveComments &&
|
||||
isConsecutiveComment(comment)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 5. Does the comment start with a possible URL?
|
||||
if (MAYBE_URL.test(commentWithoutAsterisks)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 6. Is the initial word character a letter?
|
||||
const commentWordCharsOnly = commentWithoutAsterisks.replace(
|
||||
WHITESPACE,
|
||||
"",
|
||||
);
|
||||
|
||||
if (commentWordCharsOnly.length === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Get the first Unicode character (1 or 2 code units).
|
||||
const [firstWordChar] = commentWordCharsOnly;
|
||||
|
||||
if (!LETTER_PATTERN.test(firstWordChar)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 7. Check the case of the initial word character.
|
||||
const isUppercase =
|
||||
firstWordChar !== firstWordChar.toLocaleLowerCase(),
|
||||
isLowercase =
|
||||
firstWordChar !== firstWordChar.toLocaleUpperCase();
|
||||
|
||||
if (capitalize === "always" && isLowercase) {
|
||||
return false;
|
||||
}
|
||||
if (capitalize === "never" && isUppercase) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a comment to determine if it needs to be reported.
|
||||
* @param {ASTNode} comment The comment node to process.
|
||||
* @returns {void}
|
||||
*/
|
||||
function processComment(comment) {
|
||||
const options = normalizedOptions[comment.type],
|
||||
commentValid = isCommentValid(comment, options);
|
||||
|
||||
if (!commentValid) {
|
||||
const messageId =
|
||||
capitalize === "always"
|
||||
? "unexpectedLowercaseComment"
|
||||
: "unexpectedUppercaseComment";
|
||||
|
||||
context.report({
|
||||
node: null, // Intentionally using loc instead
|
||||
loc: comment.loc,
|
||||
messageId,
|
||||
fix(fixer) {
|
||||
const match = comment.value.match(LETTER_PATTERN);
|
||||
const char = match[0];
|
||||
|
||||
// Offset match.index by 2 to account for the first 2 characters that start the comment (// or /*)
|
||||
const charIndex = comment.range[0] + match.index + 2;
|
||||
|
||||
return fixer.replaceTextRange(
|
||||
[charIndex, charIndex + char.length],
|
||||
capitalize === "always"
|
||||
? char.toLocaleUpperCase()
|
||||
: char.toLocaleLowerCase(),
|
||||
);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Public
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
return {
|
||||
Program() {
|
||||
const comments = sourceCode.getAllComments();
|
||||
|
||||
comments
|
||||
.filter(token => token.type !== "Shebang")
|
||||
.forEach(processComment);
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
250
slider/node_modules/eslint/lib/rules/class-methods-use-this.js
generated
vendored
Normal file
250
slider/node_modules/eslint/lib/rules/class-methods-use-this.js
generated
vendored
Normal file
@@ -0,0 +1,250 @@
|
||||
/**
|
||||
* @fileoverview Rule to enforce that all class methods use 'this'.
|
||||
* @author Patrick Williams
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const astUtils = require("./utils/ast-utils");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../types').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
dialects: ["javascript", "typescript"],
|
||||
language: "javascript",
|
||||
type: "suggestion",
|
||||
|
||||
defaultOptions: [
|
||||
{
|
||||
enforceForClassFields: true,
|
||||
exceptMethods: [],
|
||||
ignoreOverrideMethods: false,
|
||||
},
|
||||
],
|
||||
|
||||
docs: {
|
||||
description: "Enforce that class methods utilize `this`",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/latest/rules/class-methods-use-this",
|
||||
},
|
||||
|
||||
schema: [
|
||||
{
|
||||
type: "object",
|
||||
properties: {
|
||||
exceptMethods: {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "string",
|
||||
},
|
||||
},
|
||||
enforceForClassFields: {
|
||||
type: "boolean",
|
||||
},
|
||||
ignoreOverrideMethods: {
|
||||
type: "boolean",
|
||||
},
|
||||
ignoreClassesWithImplements: {
|
||||
enum: ["all", "public-fields"],
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
},
|
||||
],
|
||||
|
||||
messages: {
|
||||
missingThis: "Expected 'this' to be used by class {{name}}.",
|
||||
},
|
||||
},
|
||||
create(context) {
|
||||
const [options] = context.options;
|
||||
const {
|
||||
enforceForClassFields,
|
||||
ignoreOverrideMethods,
|
||||
ignoreClassesWithImplements,
|
||||
} = options;
|
||||
const exceptMethods = new Set(options.exceptMethods);
|
||||
|
||||
const stack = [];
|
||||
|
||||
/**
|
||||
* Push `this` used flag initialized with `false` onto the stack.
|
||||
* @returns {void}
|
||||
*/
|
||||
function pushContext() {
|
||||
stack.push(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pop `this` used flag from the stack.
|
||||
* @returns {boolean | undefined} `this` used flag
|
||||
*/
|
||||
function popContext() {
|
||||
return stack.pop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the current context to false and pushes it onto the stack.
|
||||
* These booleans represent whether 'this' has been used in the context.
|
||||
* @returns {void}
|
||||
* @private
|
||||
*/
|
||||
function enterFunction() {
|
||||
pushContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the node is an instance method
|
||||
* @param {ASTNode} node node to check
|
||||
* @returns {boolean} True if its an instance method
|
||||
* @private
|
||||
*/
|
||||
function isInstanceMethod(node) {
|
||||
switch (node.type) {
|
||||
case "MethodDefinition":
|
||||
return !node.static && node.kind !== "constructor";
|
||||
case "AccessorProperty":
|
||||
case "PropertyDefinition":
|
||||
return !node.static && enforceForClassFields;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the node's parent class implements any interfaces
|
||||
* @param {ASTNode} node node to check
|
||||
* @returns {boolean} True if parent class implements interfaces
|
||||
* @private
|
||||
*/
|
||||
function hasImplements(node) {
|
||||
const classNode = node.parent.parent;
|
||||
return (
|
||||
classNode?.type === "ClassDeclaration" &&
|
||||
classNode.implements?.length > 0
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the node is an instance method not excluded by config
|
||||
* @param {ASTNode} node node to check
|
||||
* @returns {boolean} True if it is an instance method, and not excluded by config
|
||||
* @private
|
||||
*/
|
||||
function isIncludedInstanceMethod(node) {
|
||||
if (isInstanceMethod(node)) {
|
||||
if (node.computed) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ignoreOverrideMethods && node.override) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ignoreClassesWithImplements) {
|
||||
const implementsInterfaces = hasImplements(node);
|
||||
if (implementsInterfaces) {
|
||||
if (
|
||||
ignoreClassesWithImplements === "all" ||
|
||||
(ignoreClassesWithImplements === "public-fields" &&
|
||||
node.key.type !== "PrivateIdentifier" &&
|
||||
(!node.accessibility ||
|
||||
node.accessibility === "public"))
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const hashIfNeeded =
|
||||
node.key.type === "PrivateIdentifier" ? "#" : "";
|
||||
const name =
|
||||
node.key.type === "Literal"
|
||||
? astUtils.getStaticStringValue(node.key)
|
||||
: node.key.name || "";
|
||||
|
||||
return !exceptMethods.has(hashIfNeeded + name);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if we are leaving a function that is a method, and reports if 'this' has not been used.
|
||||
* Static methods and the constructor are exempt.
|
||||
* Then pops the context off the stack.
|
||||
* @param {ASTNode} node A function node that was entered.
|
||||
* @returns {void}
|
||||
* @private
|
||||
*/
|
||||
function exitFunction(node) {
|
||||
const methodUsesThis = popContext();
|
||||
|
||||
if (isIncludedInstanceMethod(node.parent) && !methodUsesThis) {
|
||||
context.report({
|
||||
node,
|
||||
loc: astUtils.getFunctionHeadLoc(node, context.sourceCode),
|
||||
messageId: "missingThis",
|
||||
data: {
|
||||
name: astUtils.getFunctionNameWithKind(node),
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the current context as having used 'this'.
|
||||
* @returns {void}
|
||||
* @private
|
||||
*/
|
||||
function markThisUsed() {
|
||||
if (stack.length) {
|
||||
stack[stack.length - 1] = true;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
FunctionDeclaration: enterFunction,
|
||||
"FunctionDeclaration:exit": exitFunction,
|
||||
FunctionExpression: enterFunction,
|
||||
"FunctionExpression:exit": exitFunction,
|
||||
|
||||
/*
|
||||
* Class field value are implicit functions.
|
||||
*/
|
||||
"AccessorProperty > *.key:exit": pushContext,
|
||||
"AccessorProperty: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,
|
||||
...(enforceForClassFields && {
|
||||
"AccessorProperty > ArrowFunctionExpression.value":
|
||||
enterFunction,
|
||||
"AccessorProperty > ArrowFunctionExpression.value:exit":
|
||||
exitFunction,
|
||||
"PropertyDefinition > ArrowFunctionExpression.value":
|
||||
enterFunction,
|
||||
"PropertyDefinition > ArrowFunctionExpression.value:exit":
|
||||
exitFunction,
|
||||
}),
|
||||
};
|
||||
},
|
||||
};
|
||||
424
slider/node_modules/eslint/lib/rules/comma-dangle.js
generated
vendored
Normal file
424
slider/node_modules/eslint/lib/rules/comma-dangle.js
generated
vendored
Normal file
@@ -0,0 +1,424 @@
|
||||
/**
|
||||
* @fileoverview Rule to forbid or enforce dangling commas.
|
||||
* @author Ian Christian Myers
|
||||
* @deprecated in ESLint v8.53.0
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const astUtils = require("./utils/ast-utils");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const DEFAULT_OPTIONS = Object.freeze({
|
||||
arrays: "never",
|
||||
objects: "never",
|
||||
imports: "never",
|
||||
exports: "never",
|
||||
functions: "never",
|
||||
});
|
||||
|
||||
/**
|
||||
* Checks whether or not a trailing comma is allowed in a given node.
|
||||
* If the `lastItem` is `RestElement` or `RestProperty`, it disallows trailing commas.
|
||||
* @param {ASTNode} lastItem The node of the last element in the given node.
|
||||
* @returns {boolean} `true` if a trailing comma is allowed.
|
||||
*/
|
||||
function isTrailingCommaAllowed(lastItem) {
|
||||
return !(
|
||||
lastItem.type === "RestElement" ||
|
||||
lastItem.type === "RestProperty" ||
|
||||
lastItem.type === "ExperimentalRestProperty"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize option value.
|
||||
* @param {string|Object|undefined} optionValue The 1st option value to normalize.
|
||||
* @param {number} ecmaVersion The normalized ECMAScript version.
|
||||
* @returns {Object} The normalized option value.
|
||||
*/
|
||||
function normalizeOptions(optionValue, ecmaVersion) {
|
||||
if (typeof optionValue === "string") {
|
||||
return {
|
||||
arrays: optionValue,
|
||||
objects: optionValue,
|
||||
imports: optionValue,
|
||||
exports: optionValue,
|
||||
functions: ecmaVersion < 2017 ? "ignore" : optionValue,
|
||||
};
|
||||
}
|
||||
if (typeof optionValue === "object" && optionValue !== null) {
|
||||
return {
|
||||
arrays: optionValue.arrays || DEFAULT_OPTIONS.arrays,
|
||||
objects: optionValue.objects || DEFAULT_OPTIONS.objects,
|
||||
imports: optionValue.imports || DEFAULT_OPTIONS.imports,
|
||||
exports: optionValue.exports || DEFAULT_OPTIONS.exports,
|
||||
functions: optionValue.functions || DEFAULT_OPTIONS.functions,
|
||||
};
|
||||
}
|
||||
|
||||
return DEFAULT_OPTIONS;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../types').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
deprecated: {
|
||||
message: "Formatting rules are being moved out of ESLint core.",
|
||||
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
|
||||
deprecatedSince: "8.53.0",
|
||||
availableUntil: "10.0.0",
|
||||
replacedBy: [
|
||||
{
|
||||
message:
|
||||
"ESLint Stylistic now maintains deprecated stylistic core rules.",
|
||||
url: "https://eslint.style/guide/migration",
|
||||
plugin: {
|
||||
name: "@stylistic/eslint-plugin",
|
||||
url: "https://eslint.style",
|
||||
},
|
||||
rule: {
|
||||
name: "comma-dangle",
|
||||
url: "https://eslint.style/rules/comma-dangle",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
type: "layout",
|
||||
|
||||
docs: {
|
||||
description: "Require or disallow trailing commas",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/latest/rules/comma-dangle",
|
||||
},
|
||||
|
||||
fixable: "code",
|
||||
|
||||
schema: {
|
||||
definitions: {
|
||||
value: {
|
||||
enum: [
|
||||
"always-multiline",
|
||||
"always",
|
||||
"never",
|
||||
"only-multiline",
|
||||
],
|
||||
},
|
||||
valueWithIgnore: {
|
||||
enum: [
|
||||
"always-multiline",
|
||||
"always",
|
||||
"ignore",
|
||||
"never",
|
||||
"only-multiline",
|
||||
],
|
||||
},
|
||||
},
|
||||
type: "array",
|
||||
items: [
|
||||
{
|
||||
oneOf: [
|
||||
{
|
||||
$ref: "#/definitions/value",
|
||||
},
|
||||
{
|
||||
type: "object",
|
||||
properties: {
|
||||
arrays: {
|
||||
$ref: "#/definitions/valueWithIgnore",
|
||||
},
|
||||
objects: {
|
||||
$ref: "#/definitions/valueWithIgnore",
|
||||
},
|
||||
imports: {
|
||||
$ref: "#/definitions/valueWithIgnore",
|
||||
},
|
||||
exports: {
|
||||
$ref: "#/definitions/valueWithIgnore",
|
||||
},
|
||||
functions: {
|
||||
$ref: "#/definitions/valueWithIgnore",
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
additionalItems: false,
|
||||
},
|
||||
|
||||
messages: {
|
||||
unexpected: "Unexpected trailing comma.",
|
||||
missing: "Missing trailing comma.",
|
||||
},
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const options = normalizeOptions(
|
||||
context.options[0],
|
||||
context.languageOptions.ecmaVersion,
|
||||
);
|
||||
|
||||
const sourceCode = context.sourceCode;
|
||||
|
||||
/**
|
||||
* Gets the last item of the given node.
|
||||
* @param {ASTNode} node The node to get.
|
||||
* @returns {ASTNode|null} The last node or null.
|
||||
*/
|
||||
function getLastItem(node) {
|
||||
/**
|
||||
* Returns the last element of an array
|
||||
* @param {any[]} array The input array
|
||||
* @returns {any} The last element
|
||||
*/
|
||||
function last(array) {
|
||||
return array.at(-1);
|
||||
}
|
||||
|
||||
switch (node.type) {
|
||||
case "ObjectExpression":
|
||||
case "ObjectPattern":
|
||||
return last(node.properties);
|
||||
case "ArrayExpression":
|
||||
case "ArrayPattern":
|
||||
return last(node.elements);
|
||||
case "ImportDeclaration":
|
||||
case "ExportNamedDeclaration":
|
||||
return last(node.specifiers);
|
||||
case "FunctionDeclaration":
|
||||
case "FunctionExpression":
|
||||
case "ArrowFunctionExpression":
|
||||
return last(node.params);
|
||||
case "CallExpression":
|
||||
case "NewExpression":
|
||||
return last(node.arguments);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the trailing comma token of the given node.
|
||||
* If the trailing comma does not exist, this returns the token which is
|
||||
* the insertion point of the trailing comma token.
|
||||
* @param {ASTNode} node The node to get.
|
||||
* @param {ASTNode} lastItem The last item of the node.
|
||||
* @returns {Token} The trailing comma token or the insertion point.
|
||||
*/
|
||||
function getTrailingToken(node, lastItem) {
|
||||
switch (node.type) {
|
||||
case "ObjectExpression":
|
||||
case "ArrayExpression":
|
||||
case "CallExpression":
|
||||
case "NewExpression":
|
||||
return sourceCode.getLastToken(node, 1);
|
||||
default: {
|
||||
const nextToken = sourceCode.getTokenAfter(lastItem);
|
||||
|
||||
if (astUtils.isCommaToken(nextToken)) {
|
||||
return nextToken;
|
||||
}
|
||||
return sourceCode.getLastToken(lastItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether or not a given node is multiline.
|
||||
* This rule handles a given node as multiline when the closing parenthesis
|
||||
* and the last element are not on the same line.
|
||||
* @param {ASTNode} node A node to check.
|
||||
* @returns {boolean} `true` if the node is multiline.
|
||||
*/
|
||||
function isMultiline(node) {
|
||||
const lastItem = getLastItem(node);
|
||||
|
||||
if (!lastItem) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const penultimateToken = getTrailingToken(node, lastItem);
|
||||
const lastToken = sourceCode.getTokenAfter(penultimateToken);
|
||||
|
||||
return lastToken.loc.end.line !== penultimateToken.loc.end.line;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports a trailing comma if it exists.
|
||||
* @param {ASTNode} node A node to check. Its type is one of
|
||||
* ObjectExpression, ObjectPattern, ArrayExpression, ArrayPattern,
|
||||
* ImportDeclaration, and ExportNamedDeclaration.
|
||||
* @returns {void}
|
||||
*/
|
||||
function forbidTrailingComma(node) {
|
||||
const lastItem = getLastItem(node);
|
||||
|
||||
if (
|
||||
!lastItem ||
|
||||
(node.type === "ImportDeclaration" &&
|
||||
lastItem.type !== "ImportSpecifier")
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const trailingToken = getTrailingToken(node, lastItem);
|
||||
|
||||
if (astUtils.isCommaToken(trailingToken)) {
|
||||
context.report({
|
||||
node: lastItem,
|
||||
loc: trailingToken.loc,
|
||||
messageId: "unexpected",
|
||||
*fix(fixer) {
|
||||
yield fixer.remove(trailingToken);
|
||||
|
||||
/*
|
||||
* Extend the range of the fix to include surrounding tokens to ensure
|
||||
* that the element after which the comma is removed stays _last_.
|
||||
* This intentionally makes conflicts in fix ranges with rules that may be
|
||||
* adding or removing elements in the same autofix pass.
|
||||
* https://github.com/eslint/eslint/issues/15660
|
||||
*/
|
||||
yield fixer.insertTextBefore(
|
||||
sourceCode.getTokenBefore(trailingToken),
|
||||
"",
|
||||
);
|
||||
yield fixer.insertTextAfter(
|
||||
sourceCode.getTokenAfter(trailingToken),
|
||||
"",
|
||||
);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports the last element of a given node if it does not have a trailing
|
||||
* comma.
|
||||
*
|
||||
* If a given node is `ArrayPattern` which has `RestElement`, the trailing
|
||||
* comma is disallowed, so report if it exists.
|
||||
* @param {ASTNode} node A node to check. Its type is one of
|
||||
* ObjectExpression, ObjectPattern, ArrayExpression, ArrayPattern,
|
||||
* ImportDeclaration, and ExportNamedDeclaration.
|
||||
* @returns {void}
|
||||
*/
|
||||
function forceTrailingComma(node) {
|
||||
const lastItem = getLastItem(node);
|
||||
|
||||
if (
|
||||
!lastItem ||
|
||||
(node.type === "ImportDeclaration" &&
|
||||
lastItem.type !== "ImportSpecifier")
|
||||
) {
|
||||
return;
|
||||
}
|
||||
if (!isTrailingCommaAllowed(lastItem)) {
|
||||
forbidTrailingComma(node);
|
||||
return;
|
||||
}
|
||||
|
||||
const trailingToken = getTrailingToken(node, lastItem);
|
||||
|
||||
if (trailingToken.value !== ",") {
|
||||
context.report({
|
||||
node: lastItem,
|
||||
loc: {
|
||||
start: trailingToken.loc.end,
|
||||
end: astUtils.getNextLocation(
|
||||
sourceCode,
|
||||
trailingToken.loc.end,
|
||||
),
|
||||
},
|
||||
messageId: "missing",
|
||||
*fix(fixer) {
|
||||
yield fixer.insertTextAfter(trailingToken, ",");
|
||||
|
||||
/*
|
||||
* Extend the range of the fix to include surrounding tokens to ensure
|
||||
* that the element after which the comma is inserted stays _last_.
|
||||
* This intentionally makes conflicts in fix ranges with rules that may be
|
||||
* adding or removing elements in the same autofix pass.
|
||||
* https://github.com/eslint/eslint/issues/15660
|
||||
*/
|
||||
yield fixer.insertTextBefore(trailingToken, "");
|
||||
yield fixer.insertTextAfter(
|
||||
sourceCode.getTokenAfter(trailingToken),
|
||||
"",
|
||||
);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If a given node is multiline, reports the last element of a given node
|
||||
* when it does not have a trailing comma.
|
||||
* Otherwise, reports a trailing comma if it exists.
|
||||
* @param {ASTNode} node A node to check. Its type is one of
|
||||
* ObjectExpression, ObjectPattern, ArrayExpression, ArrayPattern,
|
||||
* ImportDeclaration, and ExportNamedDeclaration.
|
||||
* @returns {void}
|
||||
*/
|
||||
function forceTrailingCommaIfMultiline(node) {
|
||||
if (isMultiline(node)) {
|
||||
forceTrailingComma(node);
|
||||
} else {
|
||||
forbidTrailingComma(node);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Only if a given node is not multiline, reports the last element of a given node
|
||||
* when it does not have a trailing comma.
|
||||
* Otherwise, reports a trailing comma if it exists.
|
||||
* @param {ASTNode} node A node to check. Its type is one of
|
||||
* ObjectExpression, ObjectPattern, ArrayExpression, ArrayPattern,
|
||||
* ImportDeclaration, and ExportNamedDeclaration.
|
||||
* @returns {void}
|
||||
*/
|
||||
function allowTrailingCommaIfMultiline(node) {
|
||||
if (!isMultiline(node)) {
|
||||
forbidTrailingComma(node);
|
||||
}
|
||||
}
|
||||
|
||||
const predicate = {
|
||||
always: forceTrailingComma,
|
||||
"always-multiline": forceTrailingCommaIfMultiline,
|
||||
"only-multiline": allowTrailingCommaIfMultiline,
|
||||
never: forbidTrailingComma,
|
||||
ignore() {},
|
||||
};
|
||||
|
||||
return {
|
||||
ObjectExpression: predicate[options.objects],
|
||||
ObjectPattern: predicate[options.objects],
|
||||
|
||||
ArrayExpression: predicate[options.arrays],
|
||||
ArrayPattern: predicate[options.arrays],
|
||||
|
||||
ImportDeclaration: predicate[options.imports],
|
||||
|
||||
ExportNamedDeclaration: predicate[options.exports],
|
||||
|
||||
FunctionDeclaration: predicate[options.functions],
|
||||
FunctionExpression: predicate[options.functions],
|
||||
ArrowFunctionExpression: predicate[options.functions],
|
||||
CallExpression: predicate[options.functions],
|
||||
NewExpression: predicate[options.functions],
|
||||
};
|
||||
},
|
||||
};
|
||||
208
slider/node_modules/eslint/lib/rules/comma-spacing.js
generated
vendored
Normal file
208
slider/node_modules/eslint/lib/rules/comma-spacing.js
generated
vendored
Normal file
@@ -0,0 +1,208 @@
|
||||
/**
|
||||
* @fileoverview Comma spacing - validates spacing before and after comma
|
||||
* @author Vignesh Anand aka vegetableman.
|
||||
* @deprecated in ESLint v8.53.0
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
const astUtils = require("./utils/ast-utils");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../types').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
deprecated: {
|
||||
message: "Formatting rules are being moved out of ESLint core.",
|
||||
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
|
||||
deprecatedSince: "8.53.0",
|
||||
availableUntil: "10.0.0",
|
||||
replacedBy: [
|
||||
{
|
||||
message:
|
||||
"ESLint Stylistic now maintains deprecated stylistic core rules.",
|
||||
url: "https://eslint.style/guide/migration",
|
||||
plugin: {
|
||||
name: "@stylistic/eslint-plugin",
|
||||
url: "https://eslint.style",
|
||||
},
|
||||
rule: {
|
||||
name: "comma-spacing",
|
||||
url: "https://eslint.style/rules/comma-spacing",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
type: "layout",
|
||||
|
||||
docs: {
|
||||
description: "Enforce consistent spacing before and after commas",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/latest/rules/comma-spacing",
|
||||
},
|
||||
|
||||
fixable: "whitespace",
|
||||
|
||||
schema: [
|
||||
{
|
||||
type: "object",
|
||||
properties: {
|
||||
before: {
|
||||
type: "boolean",
|
||||
default: false,
|
||||
},
|
||||
after: {
|
||||
type: "boolean",
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
},
|
||||
],
|
||||
|
||||
messages: {
|
||||
missing: "A space is required {{loc}} ','.",
|
||||
unexpected: "There should be no space {{loc}} ','.",
|
||||
},
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const sourceCode = context.sourceCode;
|
||||
const tokensAndComments = sourceCode.tokensAndComments;
|
||||
|
||||
const options = {
|
||||
before: context.options[0] ? context.options[0].before : false,
|
||||
after: context.options[0] ? context.options[0].after : true,
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
// list of comma tokens to ignore for the check of leading whitespace
|
||||
const commaTokensToIgnore = [];
|
||||
|
||||
/**
|
||||
* Reports a spacing error with an appropriate message.
|
||||
* @param {ASTNode} node The binary expression node to report.
|
||||
* @param {string} loc Is the error "before" or "after" the comma?
|
||||
* @param {ASTNode} otherNode The node at the left or right of `node`
|
||||
* @returns {void}
|
||||
* @private
|
||||
*/
|
||||
function report(node, loc, otherNode) {
|
||||
context.report({
|
||||
node,
|
||||
fix(fixer) {
|
||||
if (options[loc]) {
|
||||
if (loc === "before") {
|
||||
return fixer.insertTextBefore(node, " ");
|
||||
}
|
||||
return fixer.insertTextAfter(node, " ");
|
||||
}
|
||||
let start, end;
|
||||
const newText = "";
|
||||
|
||||
if (loc === "before") {
|
||||
start = otherNode.range[1];
|
||||
end = node.range[0];
|
||||
} else {
|
||||
start = node.range[1];
|
||||
end = otherNode.range[0];
|
||||
}
|
||||
|
||||
return fixer.replaceTextRange([start, end], newText);
|
||||
},
|
||||
messageId: options[loc] ? "missing" : "unexpected",
|
||||
data: {
|
||||
loc,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds null elements of the given ArrayExpression or ArrayPattern node to the ignore list.
|
||||
* @param {ASTNode} node An ArrayExpression or ArrayPattern node.
|
||||
* @returns {void}
|
||||
*/
|
||||
function addNullElementsToIgnoreList(node) {
|
||||
let previousToken = sourceCode.getFirstToken(node);
|
||||
|
||||
node.elements.forEach(element => {
|
||||
let token;
|
||||
|
||||
if (element === null) {
|
||||
token = sourceCode.getTokenAfter(previousToken);
|
||||
|
||||
if (astUtils.isCommaToken(token)) {
|
||||
commaTokensToIgnore.push(token);
|
||||
}
|
||||
} else {
|
||||
token = sourceCode.getTokenAfter(element);
|
||||
}
|
||||
|
||||
previousToken = token;
|
||||
});
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Public
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
return {
|
||||
"Program:exit"() {
|
||||
tokensAndComments.forEach((token, i) => {
|
||||
if (!astUtils.isCommaToken(token)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const previousToken = tokensAndComments[i - 1];
|
||||
const nextToken = tokensAndComments[i + 1];
|
||||
|
||||
if (
|
||||
previousToken &&
|
||||
!astUtils.isCommaToken(previousToken) && // ignore spacing between two commas
|
||||
/*
|
||||
* `commaTokensToIgnore` are ending commas of `null` elements (array holes/elisions).
|
||||
* In addition to spacing between two commas, this can also ignore:
|
||||
*
|
||||
* - Spacing after `[` (controlled by array-bracket-spacing)
|
||||
* Example: [ , ]
|
||||
* ^
|
||||
* - Spacing after a comment (for backwards compatibility, this was possibly unintentional)
|
||||
* Example: [a, /* * / ,]
|
||||
* ^
|
||||
*/
|
||||
!commaTokensToIgnore.includes(token) &&
|
||||
astUtils.isTokenOnSameLine(previousToken, token) &&
|
||||
options.before !==
|
||||
sourceCode.isSpaceBetweenTokens(
|
||||
previousToken,
|
||||
token,
|
||||
)
|
||||
) {
|
||||
report(token, "before", previousToken);
|
||||
}
|
||||
|
||||
if (
|
||||
nextToken &&
|
||||
!astUtils.isCommaToken(nextToken) && // ignore spacing between two commas
|
||||
!astUtils.isClosingParenToken(nextToken) && // controlled by space-in-parens
|
||||
!astUtils.isClosingBracketToken(nextToken) && // controlled by array-bracket-spacing
|
||||
!astUtils.isClosingBraceToken(nextToken) && // controlled by object-curly-spacing
|
||||
!(!options.after && nextToken.type === "Line") && // special case, allow space before line comment
|
||||
astUtils.isTokenOnSameLine(token, nextToken) &&
|
||||
options.after !==
|
||||
sourceCode.isSpaceBetweenTokens(token, nextToken)
|
||||
) {
|
||||
report(token, "after", nextToken);
|
||||
}
|
||||
});
|
||||
},
|
||||
ArrayExpression: addNullElementsToIgnoreList,
|
||||
ArrayPattern: addNullElementsToIgnoreList,
|
||||
};
|
||||
},
|
||||
};
|
||||
391
slider/node_modules/eslint/lib/rules/comma-style.js
generated
vendored
Normal file
391
slider/node_modules/eslint/lib/rules/comma-style.js
generated
vendored
Normal file
@@ -0,0 +1,391 @@
|
||||
/**
|
||||
* @fileoverview Comma style - enforces comma styles of two types: last and first
|
||||
* @author Vignesh Anand aka vegetableman
|
||||
* @deprecated in ESLint v8.53.0
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
const astUtils = require("./utils/ast-utils");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../types').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
deprecated: {
|
||||
message: "Formatting rules are being moved out of ESLint core.",
|
||||
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
|
||||
deprecatedSince: "8.53.0",
|
||||
availableUntil: "10.0.0",
|
||||
replacedBy: [
|
||||
{
|
||||
message:
|
||||
"ESLint Stylistic now maintains deprecated stylistic core rules.",
|
||||
url: "https://eslint.style/guide/migration",
|
||||
plugin: {
|
||||
name: "@stylistic/eslint-plugin",
|
||||
url: "https://eslint.style",
|
||||
},
|
||||
rule: {
|
||||
name: "comma-style",
|
||||
url: "https://eslint.style/rules/comma-style",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
type: "layout",
|
||||
|
||||
docs: {
|
||||
description: "Enforce consistent comma style",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/latest/rules/comma-style",
|
||||
},
|
||||
|
||||
fixable: "code",
|
||||
|
||||
schema: [
|
||||
{
|
||||
enum: ["first", "last"],
|
||||
},
|
||||
{
|
||||
type: "object",
|
||||
properties: {
|
||||
exceptions: {
|
||||
type: "object",
|
||||
additionalProperties: {
|
||||
type: "boolean",
|
||||
},
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
},
|
||||
],
|
||||
|
||||
messages: {
|
||||
unexpectedLineBeforeAndAfterComma:
|
||||
"Bad line breaking before and after ','.",
|
||||
expectedCommaFirst: "',' should be placed first.",
|
||||
expectedCommaLast: "',' should be placed last.",
|
||||
},
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const style = context.options[0] || "last",
|
||||
sourceCode = context.sourceCode;
|
||||
const exceptions = {
|
||||
ArrayPattern: true,
|
||||
ArrowFunctionExpression: true,
|
||||
CallExpression: true,
|
||||
FunctionDeclaration: true,
|
||||
FunctionExpression: true,
|
||||
ImportDeclaration: true,
|
||||
ObjectPattern: true,
|
||||
NewExpression: true,
|
||||
};
|
||||
|
||||
if (
|
||||
context.options.length === 2 &&
|
||||
Object.hasOwn(context.options[1], "exceptions")
|
||||
) {
|
||||
const keys = Object.keys(context.options[1].exceptions);
|
||||
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
exceptions[keys[i]] = context.options[1].exceptions[keys[i]];
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Modified text based on the style
|
||||
* @param {string} styleType Style type
|
||||
* @param {string} text Source code text
|
||||
* @returns {string} modified text
|
||||
* @private
|
||||
*/
|
||||
function getReplacedText(styleType, text) {
|
||||
switch (styleType) {
|
||||
case "between":
|
||||
return `,${text.replace(astUtils.LINEBREAK_MATCHER, "")}`;
|
||||
|
||||
case "first":
|
||||
return `${text},`;
|
||||
|
||||
case "last":
|
||||
return `,${text}`;
|
||||
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the fixer function for a given style.
|
||||
* @param {string} styleType comma style
|
||||
* @param {ASTNode} previousItemToken The token to check.
|
||||
* @param {ASTNode} commaToken The token to check.
|
||||
* @param {ASTNode} currentItemToken The token to check.
|
||||
* @returns {Function} Fixer function
|
||||
* @private
|
||||
*/
|
||||
function getFixerFunction(
|
||||
styleType,
|
||||
previousItemToken,
|
||||
commaToken,
|
||||
currentItemToken,
|
||||
) {
|
||||
const text =
|
||||
sourceCode.text.slice(
|
||||
previousItemToken.range[1],
|
||||
commaToken.range[0],
|
||||
) +
|
||||
sourceCode.text.slice(
|
||||
commaToken.range[1],
|
||||
currentItemToken.range[0],
|
||||
);
|
||||
const range = [
|
||||
previousItemToken.range[1],
|
||||
currentItemToken.range[0],
|
||||
];
|
||||
|
||||
return function (fixer) {
|
||||
return fixer.replaceTextRange(
|
||||
range,
|
||||
getReplacedText(styleType, text),
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the spacing around single items in lists.
|
||||
* @param {Token} previousItemToken The last token from the previous item.
|
||||
* @param {Token} commaToken The token representing the comma.
|
||||
* @param {Token} currentItemToken The first token of the current item.
|
||||
* @param {Token} reportItem The item to use when reporting an error.
|
||||
* @returns {void}
|
||||
* @private
|
||||
*/
|
||||
function validateCommaItemSpacing(
|
||||
previousItemToken,
|
||||
commaToken,
|
||||
currentItemToken,
|
||||
reportItem,
|
||||
) {
|
||||
// if single line
|
||||
if (
|
||||
astUtils.isTokenOnSameLine(commaToken, currentItemToken) &&
|
||||
astUtils.isTokenOnSameLine(previousItemToken, commaToken)
|
||||
) {
|
||||
// do nothing.
|
||||
} else if (
|
||||
!astUtils.isTokenOnSameLine(commaToken, currentItemToken) &&
|
||||
!astUtils.isTokenOnSameLine(previousItemToken, commaToken)
|
||||
) {
|
||||
const comment = sourceCode.getCommentsAfter(commaToken)[0];
|
||||
const styleType =
|
||||
comment &&
|
||||
comment.type === "Block" &&
|
||||
astUtils.isTokenOnSameLine(commaToken, comment)
|
||||
? style
|
||||
: "between";
|
||||
|
||||
// lone comma
|
||||
context.report({
|
||||
node: reportItem,
|
||||
loc: commaToken.loc,
|
||||
messageId: "unexpectedLineBeforeAndAfterComma",
|
||||
fix: getFixerFunction(
|
||||
styleType,
|
||||
previousItemToken,
|
||||
commaToken,
|
||||
currentItemToken,
|
||||
),
|
||||
});
|
||||
} else if (
|
||||
style === "first" &&
|
||||
!astUtils.isTokenOnSameLine(commaToken, currentItemToken)
|
||||
) {
|
||||
context.report({
|
||||
node: reportItem,
|
||||
loc: commaToken.loc,
|
||||
messageId: "expectedCommaFirst",
|
||||
fix: getFixerFunction(
|
||||
style,
|
||||
previousItemToken,
|
||||
commaToken,
|
||||
currentItemToken,
|
||||
),
|
||||
});
|
||||
} else if (
|
||||
style === "last" &&
|
||||
astUtils.isTokenOnSameLine(commaToken, currentItemToken)
|
||||
) {
|
||||
context.report({
|
||||
node: reportItem,
|
||||
loc: commaToken.loc,
|
||||
messageId: "expectedCommaLast",
|
||||
fix: getFixerFunction(
|
||||
style,
|
||||
previousItemToken,
|
||||
commaToken,
|
||||
currentItemToken,
|
||||
),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the comma placement with regards to a declaration/property/element
|
||||
* @param {ASTNode} node The binary expression node to check
|
||||
* @param {string} property The property of the node containing child nodes.
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
function validateComma(node, property) {
|
||||
const items = node[property],
|
||||
arrayLiteral =
|
||||
node.type === "ArrayExpression" ||
|
||||
node.type === "ArrayPattern";
|
||||
|
||||
if (items.length > 1 || arrayLiteral) {
|
||||
// seed as opening [
|
||||
let previousItemToken = sourceCode.getFirstToken(node);
|
||||
|
||||
items.forEach(item => {
|
||||
const commaToken = item
|
||||
? sourceCode.getTokenBefore(item)
|
||||
: previousItemToken,
|
||||
currentItemToken = item
|
||||
? sourceCode.getFirstToken(item)
|
||||
: sourceCode.getTokenAfter(commaToken),
|
||||
reportItem = item || currentItemToken;
|
||||
|
||||
/*
|
||||
* This works by comparing three token locations:
|
||||
* - previousItemToken is the last token of the previous item
|
||||
* - commaToken is the location of the comma before the current item
|
||||
* - currentItemToken is the first token of the current item
|
||||
*
|
||||
* These values get switched around if item is undefined.
|
||||
* previousItemToken will refer to the last token not belonging
|
||||
* to the current item, which could be a comma or an opening
|
||||
* square bracket. currentItemToken could be a comma.
|
||||
*
|
||||
* All comparisons are done based on these tokens directly, so
|
||||
* they are always valid regardless of an undefined item.
|
||||
*/
|
||||
if (astUtils.isCommaToken(commaToken)) {
|
||||
validateCommaItemSpacing(
|
||||
previousItemToken,
|
||||
commaToken,
|
||||
currentItemToken,
|
||||
reportItem,
|
||||
);
|
||||
}
|
||||
|
||||
if (item) {
|
||||
const tokenAfterItem = sourceCode.getTokenAfter(
|
||||
item,
|
||||
astUtils.isNotClosingParenToken,
|
||||
);
|
||||
|
||||
previousItemToken = tokenAfterItem
|
||||
? sourceCode.getTokenBefore(tokenAfterItem)
|
||||
: sourceCode.ast.tokens.at(-1);
|
||||
} else {
|
||||
previousItemToken = currentItemToken;
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
* Special case for array literals that have empty last items, such
|
||||
* as [ 1, 2, ]. These arrays only have two items show up in the
|
||||
* AST, so we need to look at the token to verify that there's no
|
||||
* dangling comma.
|
||||
*/
|
||||
if (arrayLiteral) {
|
||||
const lastToken = sourceCode.getLastToken(node),
|
||||
nextToLastToken = sourceCode.getTokenBefore(lastToken);
|
||||
|
||||
if (astUtils.isCommaToken(nextToLastToken)) {
|
||||
validateCommaItemSpacing(
|
||||
sourceCode.getTokenBefore(nextToLastToken),
|
||||
nextToLastToken,
|
||||
lastToken,
|
||||
lastToken,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Public
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
const nodes = {};
|
||||
|
||||
if (!exceptions.VariableDeclaration) {
|
||||
nodes.VariableDeclaration = function (node) {
|
||||
validateComma(node, "declarations");
|
||||
};
|
||||
}
|
||||
if (!exceptions.ObjectExpression) {
|
||||
nodes.ObjectExpression = function (node) {
|
||||
validateComma(node, "properties");
|
||||
};
|
||||
}
|
||||
if (!exceptions.ObjectPattern) {
|
||||
nodes.ObjectPattern = function (node) {
|
||||
validateComma(node, "properties");
|
||||
};
|
||||
}
|
||||
if (!exceptions.ArrayExpression) {
|
||||
nodes.ArrayExpression = function (node) {
|
||||
validateComma(node, "elements");
|
||||
};
|
||||
}
|
||||
if (!exceptions.ArrayPattern) {
|
||||
nodes.ArrayPattern = function (node) {
|
||||
validateComma(node, "elements");
|
||||
};
|
||||
}
|
||||
if (!exceptions.FunctionDeclaration) {
|
||||
nodes.FunctionDeclaration = function (node) {
|
||||
validateComma(node, "params");
|
||||
};
|
||||
}
|
||||
if (!exceptions.FunctionExpression) {
|
||||
nodes.FunctionExpression = function (node) {
|
||||
validateComma(node, "params");
|
||||
};
|
||||
}
|
||||
if (!exceptions.ArrowFunctionExpression) {
|
||||
nodes.ArrowFunctionExpression = function (node) {
|
||||
validateComma(node, "params");
|
||||
};
|
||||
}
|
||||
if (!exceptions.CallExpression) {
|
||||
nodes.CallExpression = function (node) {
|
||||
validateComma(node, "arguments");
|
||||
};
|
||||
}
|
||||
if (!exceptions.ImportDeclaration) {
|
||||
nodes.ImportDeclaration = function (node) {
|
||||
validateComma(node, "specifiers");
|
||||
};
|
||||
}
|
||||
if (!exceptions.NewExpression) {
|
||||
nodes.NewExpression = function (node) {
|
||||
validateComma(node, "arguments");
|
||||
};
|
||||
}
|
||||
|
||||
return nodes;
|
||||
},
|
||||
};
|
||||
196
slider/node_modules/eslint/lib/rules/complexity.js
generated
vendored
Normal file
196
slider/node_modules/eslint/lib/rules/complexity.js
generated
vendored
Normal file
@@ -0,0 +1,196 @@
|
||||
/**
|
||||
* @fileoverview Counts the cyclomatic complexity of each function of the script. See http://en.wikipedia.org/wiki/Cyclomatic_complexity.
|
||||
* Counts the number of if, conditional, for, while, try, switch/case,
|
||||
* @author Patrick Brosset
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const astUtils = require("./utils/ast-utils");
|
||||
const { upperCaseFirst } = require("../shared/string-utils");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const THRESHOLD_DEFAULT = 20;
|
||||
|
||||
/** @type {import('../types').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
|
||||
defaultOptions: [THRESHOLD_DEFAULT],
|
||||
|
||||
docs: {
|
||||
description:
|
||||
"Enforce a maximum cyclomatic complexity allowed in a program",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/latest/rules/complexity",
|
||||
},
|
||||
|
||||
schema: [
|
||||
{
|
||||
oneOf: [
|
||||
{
|
||||
type: "integer",
|
||||
minimum: 0,
|
||||
},
|
||||
{
|
||||
type: "object",
|
||||
properties: {
|
||||
maximum: {
|
||||
type: "integer",
|
||||
minimum: 0,
|
||||
},
|
||||
max: {
|
||||
type: "integer",
|
||||
minimum: 0,
|
||||
},
|
||||
variant: {
|
||||
enum: ["classic", "modified"],
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
messages: {
|
||||
complex:
|
||||
"{{name}} has a complexity of {{complexity}}. Maximum allowed is {{max}}.",
|
||||
},
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const option = context.options[0];
|
||||
let threshold = THRESHOLD_DEFAULT;
|
||||
let VARIANT = "classic";
|
||||
|
||||
if (typeof option === "object") {
|
||||
if (
|
||||
Object.hasOwn(option, "maximum") ||
|
||||
Object.hasOwn(option, "max")
|
||||
) {
|
||||
threshold = option.maximum || option.max;
|
||||
}
|
||||
|
||||
if (Object.hasOwn(option, "variant")) {
|
||||
VARIANT = option.variant;
|
||||
}
|
||||
} else if (typeof option === "number") {
|
||||
threshold = option;
|
||||
}
|
||||
|
||||
const IS_MODIFIED_COMPLEXITY = VARIANT === "modified";
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
// Using a stack to store complexity per code path
|
||||
const complexities = [];
|
||||
|
||||
/**
|
||||
* Increase the complexity of the code path in context
|
||||
* @returns {void}
|
||||
* @private
|
||||
*/
|
||||
function increaseComplexity() {
|
||||
complexities[complexities.length - 1]++;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Public API
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
return {
|
||||
onCodePathStart() {
|
||||
// The initial complexity is 1, representing one execution path in the CodePath
|
||||
complexities.push(1);
|
||||
},
|
||||
|
||||
// Each branching in the code adds 1 to the complexity
|
||||
CatchClause: increaseComplexity,
|
||||
ConditionalExpression: increaseComplexity,
|
||||
LogicalExpression: increaseComplexity,
|
||||
ForStatement: increaseComplexity,
|
||||
ForInStatement: increaseComplexity,
|
||||
ForOfStatement: increaseComplexity,
|
||||
IfStatement: increaseComplexity,
|
||||
WhileStatement: increaseComplexity,
|
||||
DoWhileStatement: increaseComplexity,
|
||||
AssignmentPattern: increaseComplexity,
|
||||
|
||||
// Avoid `default`
|
||||
"SwitchCase[test]": () =>
|
||||
IS_MODIFIED_COMPLEXITY || increaseComplexity(),
|
||||
SwitchStatement: () =>
|
||||
IS_MODIFIED_COMPLEXITY && increaseComplexity(),
|
||||
|
||||
// Logical assignment operators have short-circuiting behavior
|
||||
AssignmentExpression(node) {
|
||||
if (astUtils.isLogicalAssignmentOperator(node.operator)) {
|
||||
increaseComplexity();
|
||||
}
|
||||
},
|
||||
|
||||
MemberExpression(node) {
|
||||
if (node.optional === true) {
|
||||
increaseComplexity();
|
||||
}
|
||||
},
|
||||
|
||||
CallExpression(node) {
|
||||
if (node.optional === true) {
|
||||
increaseComplexity();
|
||||
}
|
||||
},
|
||||
|
||||
onCodePathEnd(codePath, node) {
|
||||
const complexity = complexities.pop();
|
||||
|
||||
/*
|
||||
* This rule only evaluates complexity of functions, so "program" is excluded.
|
||||
* 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-static-block"
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (complexity > threshold) {
|
||||
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,
|
||||
messageId: "complex",
|
||||
data: {
|
||||
name: upperCaseFirst(name),
|
||||
complexity,
|
||||
max: threshold,
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
251
slider/node_modules/eslint/lib/rules/computed-property-spacing.js
generated
vendored
Normal file
251
slider/node_modules/eslint/lib/rules/computed-property-spacing.js
generated
vendored
Normal file
@@ -0,0 +1,251 @@
|
||||
/**
|
||||
* @fileoverview Disallows or enforces spaces inside computed properties.
|
||||
* @author Jamund Ferguson
|
||||
* @deprecated in ESLint v8.53.0
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
const astUtils = require("./utils/ast-utils");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../types').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
deprecated: {
|
||||
message: "Formatting rules are being moved out of ESLint core.",
|
||||
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
|
||||
deprecatedSince: "8.53.0",
|
||||
availableUntil: "10.0.0",
|
||||
replacedBy: [
|
||||
{
|
||||
message:
|
||||
"ESLint Stylistic now maintains deprecated stylistic core rules.",
|
||||
url: "https://eslint.style/guide/migration",
|
||||
plugin: {
|
||||
name: "@stylistic/eslint-plugin",
|
||||
url: "https://eslint.style",
|
||||
},
|
||||
rule: {
|
||||
name: "computed-property-spacing",
|
||||
url: "https://eslint.style/rules/computed-property-spacing",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
type: "layout",
|
||||
|
||||
docs: {
|
||||
description:
|
||||
"Enforce consistent spacing inside computed property brackets",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/latest/rules/computed-property-spacing",
|
||||
},
|
||||
|
||||
fixable: "whitespace",
|
||||
|
||||
schema: [
|
||||
{
|
||||
enum: ["always", "never"],
|
||||
},
|
||||
{
|
||||
type: "object",
|
||||
properties: {
|
||||
enforceForClassMembers: {
|
||||
type: "boolean",
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
},
|
||||
],
|
||||
|
||||
messages: {
|
||||
unexpectedSpaceBefore:
|
||||
"There should be no space before '{{tokenValue}}'.",
|
||||
unexpectedSpaceAfter:
|
||||
"There should be no space after '{{tokenValue}}'.",
|
||||
|
||||
missingSpaceBefore: "A space is required before '{{tokenValue}}'.",
|
||||
missingSpaceAfter: "A space is required after '{{tokenValue}}'.",
|
||||
},
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const sourceCode = context.sourceCode;
|
||||
const propertyNameMustBeSpaced = context.options[0] === "always"; // default is "never"
|
||||
const enforceForClassMembers =
|
||||
!context.options[1] || context.options[1].enforceForClassMembers;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Reports that there shouldn't be a space after the first token
|
||||
* @param {ASTNode} node The node to report in the event of an error.
|
||||
* @param {Token} token The token to use for the report.
|
||||
* @param {Token} tokenAfter The token after `token`.
|
||||
* @returns {void}
|
||||
*/
|
||||
function reportNoBeginningSpace(node, token, tokenAfter) {
|
||||
context.report({
|
||||
node,
|
||||
loc: { start: token.loc.end, end: tokenAfter.loc.start },
|
||||
messageId: "unexpectedSpaceAfter",
|
||||
data: {
|
||||
tokenValue: token.value,
|
||||
},
|
||||
fix(fixer) {
|
||||
return fixer.removeRange([
|
||||
token.range[1],
|
||||
tokenAfter.range[0],
|
||||
]);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports that there shouldn't be a space before the last token
|
||||
* @param {ASTNode} node The node to report in the event of an error.
|
||||
* @param {Token} token The token to use for the report.
|
||||
* @param {Token} tokenBefore The token before `token`.
|
||||
* @returns {void}
|
||||
*/
|
||||
function reportNoEndingSpace(node, token, tokenBefore) {
|
||||
context.report({
|
||||
node,
|
||||
loc: { start: tokenBefore.loc.end, end: token.loc.start },
|
||||
messageId: "unexpectedSpaceBefore",
|
||||
data: {
|
||||
tokenValue: token.value,
|
||||
},
|
||||
fix(fixer) {
|
||||
return fixer.removeRange([
|
||||
tokenBefore.range[1],
|
||||
token.range[0],
|
||||
]);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports that there should be a space after the first token
|
||||
* @param {ASTNode} node The node to report in the event of an error.
|
||||
* @param {Token} token The token to use for the report.
|
||||
* @returns {void}
|
||||
*/
|
||||
function reportRequiredBeginningSpace(node, token) {
|
||||
context.report({
|
||||
node,
|
||||
loc: token.loc,
|
||||
messageId: "missingSpaceAfter",
|
||||
data: {
|
||||
tokenValue: token.value,
|
||||
},
|
||||
fix(fixer) {
|
||||
return fixer.insertTextAfter(token, " ");
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports that there should be a space before the last token
|
||||
* @param {ASTNode} node The node to report in the event of an error.
|
||||
* @param {Token} token The token to use for the report.
|
||||
* @returns {void}
|
||||
*/
|
||||
function reportRequiredEndingSpace(node, token) {
|
||||
context.report({
|
||||
node,
|
||||
loc: token.loc,
|
||||
messageId: "missingSpaceBefore",
|
||||
data: {
|
||||
tokenValue: token.value,
|
||||
},
|
||||
fix(fixer) {
|
||||
return fixer.insertTextBefore(token, " ");
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a function that checks the spacing of a node on the property name
|
||||
* that was passed in.
|
||||
* @param {string} propertyName The property on the node to check for spacing
|
||||
* @returns {Function} A function that will check spacing on a node
|
||||
*/
|
||||
function checkSpacing(propertyName) {
|
||||
return function (node) {
|
||||
if (!node.computed) {
|
||||
return;
|
||||
}
|
||||
|
||||
const property = node[propertyName];
|
||||
|
||||
const before = sourceCode.getTokenBefore(
|
||||
property,
|
||||
astUtils.isOpeningBracketToken,
|
||||
),
|
||||
first = sourceCode.getTokenAfter(before, {
|
||||
includeComments: true,
|
||||
}),
|
||||
after = sourceCode.getTokenAfter(
|
||||
property,
|
||||
astUtils.isClosingBracketToken,
|
||||
),
|
||||
last = sourceCode.getTokenBefore(after, {
|
||||
includeComments: true,
|
||||
});
|
||||
|
||||
if (astUtils.isTokenOnSameLine(before, first)) {
|
||||
if (propertyNameMustBeSpaced) {
|
||||
if (
|
||||
!sourceCode.isSpaceBetweenTokens(before, first) &&
|
||||
astUtils.isTokenOnSameLine(before, first)
|
||||
) {
|
||||
reportRequiredBeginningSpace(node, before);
|
||||
}
|
||||
} else {
|
||||
if (sourceCode.isSpaceBetweenTokens(before, first)) {
|
||||
reportNoBeginningSpace(node, before, first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (astUtils.isTokenOnSameLine(last, after)) {
|
||||
if (propertyNameMustBeSpaced) {
|
||||
if (
|
||||
!sourceCode.isSpaceBetweenTokens(last, after) &&
|
||||
astUtils.isTokenOnSameLine(last, after)
|
||||
) {
|
||||
reportRequiredEndingSpace(node, after);
|
||||
}
|
||||
} else {
|
||||
if (sourceCode.isSpaceBetweenTokens(last, after)) {
|
||||
reportNoEndingSpace(node, after, last);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Public
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
const listeners = {
|
||||
Property: checkSpacing("key"),
|
||||
MemberExpression: checkSpacing("property"),
|
||||
};
|
||||
|
||||
if (enforceForClassMembers) {
|
||||
listeners.MethodDefinition = listeners.PropertyDefinition =
|
||||
listeners.Property;
|
||||
}
|
||||
|
||||
return listeners;
|
||||
},
|
||||
};
|
||||
221
slider/node_modules/eslint/lib/rules/consistent-return.js
generated
vendored
Normal file
221
slider/node_modules/eslint/lib/rules/consistent-return.js
generated
vendored
Normal file
@@ -0,0 +1,221 @@
|
||||
/**
|
||||
* @fileoverview Rule to flag consistent return values
|
||||
* @author Nicholas C. Zakas
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const astUtils = require("./utils/ast-utils");
|
||||
const { upperCaseFirst } = require("../shared/string-utils");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Checks all segments in a set and returns true if all are unreachable.
|
||||
* @param {Set<CodePathSegment>} segments The segments to check.
|
||||
* @returns {boolean} True if all segments are unreachable; false otherwise.
|
||||
*/
|
||||
function areAllSegmentsUnreachable(segments) {
|
||||
for (const segment of segments) {
|
||||
if (segment.reachable) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a given node is a `constructor` method in an ES6 class
|
||||
* @param {ASTNode} node A node to check
|
||||
* @returns {boolean} `true` if the node is a `constructor` method
|
||||
*/
|
||||
function isClassConstructor(node) {
|
||||
return (
|
||||
node.type === "FunctionExpression" &&
|
||||
node.parent &&
|
||||
node.parent.type === "MethodDefinition" &&
|
||||
node.parent.kind === "constructor"
|
||||
);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../types').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
|
||||
docs: {
|
||||
description:
|
||||
"Require `return` statements to either always or never specify values",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/latest/rules/consistent-return",
|
||||
},
|
||||
|
||||
schema: [
|
||||
{
|
||||
type: "object",
|
||||
properties: {
|
||||
treatUndefinedAsUnspecified: {
|
||||
type: "boolean",
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
},
|
||||
],
|
||||
|
||||
defaultOptions: [{ treatUndefinedAsUnspecified: false }],
|
||||
|
||||
messages: {
|
||||
missingReturn: "Expected to return a value at the end of {{name}}.",
|
||||
missingReturnValue: "{{name}} expected a return value.",
|
||||
unexpectedReturnValue: "{{name}} expected no return value.",
|
||||
},
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const [{ treatUndefinedAsUnspecified }] = context.options;
|
||||
let funcInfo = null;
|
||||
|
||||
/**
|
||||
* Checks whether of not the implicit returning is consistent if the last
|
||||
* code path segment is reachable.
|
||||
* @param {ASTNode} node A program/function node to check.
|
||||
* @returns {void}
|
||||
*/
|
||||
function checkLastSegment(node) {
|
||||
let loc, name;
|
||||
|
||||
/*
|
||||
* Skip if it expected no return value or unreachable.
|
||||
* When unreachable, all paths are returned or thrown.
|
||||
*/
|
||||
if (
|
||||
!funcInfo.hasReturnValue ||
|
||||
areAllSegmentsUnreachable(funcInfo.currentSegments) ||
|
||||
astUtils.isES5Constructor(node) ||
|
||||
isClassConstructor(node)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Adjust a location and a message.
|
||||
if (node.type === "Program") {
|
||||
// The head of program.
|
||||
loc = { line: 1, column: 0 };
|
||||
name = "program";
|
||||
} else if (node.type === "ArrowFunctionExpression") {
|
||||
// `=>` token
|
||||
loc = context.sourceCode.getTokenBefore(
|
||||
node.body,
|
||||
astUtils.isArrowToken,
|
||||
).loc;
|
||||
} else if (
|
||||
node.parent.type === "MethodDefinition" ||
|
||||
(node.parent.type === "Property" && node.parent.method)
|
||||
) {
|
||||
// Method name.
|
||||
loc = node.parent.key.loc;
|
||||
} else {
|
||||
// Function name or `function` keyword.
|
||||
loc = (node.id || context.sourceCode.getFirstToken(node)).loc;
|
||||
}
|
||||
|
||||
if (!name) {
|
||||
name = astUtils.getFunctionNameWithKind(node);
|
||||
}
|
||||
|
||||
// Reports.
|
||||
context.report({
|
||||
node,
|
||||
loc,
|
||||
messageId: "missingReturn",
|
||||
data: { name },
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
// Initializes/Disposes state of each code path.
|
||||
onCodePathStart(codePath, node) {
|
||||
funcInfo = {
|
||||
upper: funcInfo,
|
||||
codePath,
|
||||
hasReturn: false,
|
||||
hasReturnValue: false,
|
||||
messageId: "",
|
||||
node,
|
||||
currentSegments: new Set(),
|
||||
};
|
||||
},
|
||||
onCodePathEnd() {
|
||||
funcInfo = funcInfo.upper;
|
||||
},
|
||||
|
||||
onUnreachableCodePathSegmentStart(segment) {
|
||||
funcInfo.currentSegments.add(segment);
|
||||
},
|
||||
|
||||
onUnreachableCodePathSegmentEnd(segment) {
|
||||
funcInfo.currentSegments.delete(segment);
|
||||
},
|
||||
|
||||
onCodePathSegmentStart(segment) {
|
||||
funcInfo.currentSegments.add(segment);
|
||||
},
|
||||
|
||||
onCodePathSegmentEnd(segment) {
|
||||
funcInfo.currentSegments.delete(segment);
|
||||
},
|
||||
|
||||
// Reports a given return statement if it's inconsistent.
|
||||
ReturnStatement(node) {
|
||||
const argument = node.argument;
|
||||
let hasReturnValue = Boolean(argument);
|
||||
|
||||
if (treatUndefinedAsUnspecified && hasReturnValue) {
|
||||
hasReturnValue =
|
||||
!astUtils.isSpecificId(argument, "undefined") &&
|
||||
argument.operator !== "void";
|
||||
}
|
||||
|
||||
if (!funcInfo.hasReturn) {
|
||||
funcInfo.hasReturn = true;
|
||||
funcInfo.hasReturnValue = hasReturnValue;
|
||||
funcInfo.messageId = hasReturnValue
|
||||
? "missingReturnValue"
|
||||
: "unexpectedReturnValue";
|
||||
funcInfo.data = {
|
||||
name:
|
||||
funcInfo.node.type === "Program"
|
||||
? "Program"
|
||||
: upperCaseFirst(
|
||||
astUtils.getFunctionNameWithKind(
|
||||
funcInfo.node,
|
||||
),
|
||||
),
|
||||
};
|
||||
} else if (funcInfo.hasReturnValue !== hasReturnValue) {
|
||||
context.report({
|
||||
node,
|
||||
messageId: funcInfo.messageId,
|
||||
data: funcInfo.data,
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// Reports a given program/function if the implicit returning is not consistent.
|
||||
"Program:exit": checkLastSegment,
|
||||
"FunctionDeclaration:exit": checkLastSegment,
|
||||
"FunctionExpression:exit": checkLastSegment,
|
||||
"ArrowFunctionExpression:exit": checkLastSegment,
|
||||
};
|
||||
},
|
||||
};
|
||||
179
slider/node_modules/eslint/lib/rules/consistent-this.js
generated
vendored
Normal file
179
slider/node_modules/eslint/lib/rules/consistent-this.js
generated
vendored
Normal file
@@ -0,0 +1,179 @@
|
||||
/**
|
||||
* @fileoverview Rule to enforce consistent naming of "this" context variables
|
||||
* @author Raphael Pigulla
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../types').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
|
||||
docs: {
|
||||
description:
|
||||
"Enforce consistent naming when capturing the current execution context",
|
||||
recommended: false,
|
||||
frozen: true,
|
||||
url: "https://eslint.org/docs/latest/rules/consistent-this",
|
||||
},
|
||||
|
||||
schema: {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "string",
|
||||
minLength: 1,
|
||||
},
|
||||
uniqueItems: true,
|
||||
},
|
||||
|
||||
defaultOptions: ["that"],
|
||||
|
||||
messages: {
|
||||
aliasNotAssignedToThis:
|
||||
"Designated alias '{{name}}' is not assigned to 'this'.",
|
||||
unexpectedAlias: "Unexpected alias '{{name}}' for 'this'.",
|
||||
},
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const aliases = context.options;
|
||||
const sourceCode = context.sourceCode;
|
||||
|
||||
/**
|
||||
* Reports that a variable declarator or assignment expression is assigning
|
||||
* a non-'this' value to the specified alias.
|
||||
* @param {ASTNode} node The assigning node.
|
||||
* @param {string} name the name of the alias that was incorrectly used.
|
||||
* @returns {void}
|
||||
*/
|
||||
function reportBadAssignment(node, name) {
|
||||
context.report({
|
||||
node,
|
||||
messageId: "aliasNotAssignedToThis",
|
||||
data: { name },
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that an assignment to an identifier only assigns 'this' to the
|
||||
* appropriate alias, and the alias is only assigned to 'this'.
|
||||
* @param {ASTNode} node The assigning node.
|
||||
* @param {Identifier} name The name of the variable assigned to.
|
||||
* @param {Expression} value The value of the assignment.
|
||||
* @returns {void}
|
||||
*/
|
||||
function checkAssignment(node, name, value) {
|
||||
const isThis = value.type === "ThisExpression";
|
||||
|
||||
if (aliases.includes(name)) {
|
||||
if (!isThis || (node.operator && node.operator !== "=")) {
|
||||
reportBadAssignment(node, name);
|
||||
}
|
||||
} else if (isThis) {
|
||||
context.report({
|
||||
node,
|
||||
messageId: "unexpectedAlias",
|
||||
data: { name },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that a variable declaration of the alias in a program or function
|
||||
* is assigned to the correct value.
|
||||
* @param {string} alias alias the check the assignment of.
|
||||
* @param {Object} scope scope of the current code we are checking.
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
function checkWasAssigned(alias, scope) {
|
||||
const variable = scope.set.get(alias);
|
||||
|
||||
if (!variable) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
variable.defs.some(
|
||||
def =>
|
||||
def.node.type === "VariableDeclarator" &&
|
||||
def.node.init !== null,
|
||||
)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* The alias has been declared and not assigned: check it was
|
||||
* assigned later in the same scope.
|
||||
*/
|
||||
if (
|
||||
!variable.references.some(reference => {
|
||||
const write = reference.writeExpr;
|
||||
|
||||
return (
|
||||
reference.from === scope &&
|
||||
write &&
|
||||
write.type === "ThisExpression" &&
|
||||
write.parent.operator === "="
|
||||
);
|
||||
})
|
||||
) {
|
||||
variable.defs
|
||||
.map(def => def.node)
|
||||
.forEach(node => {
|
||||
reportBadAssignment(node, alias);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check each alias to ensure that is was assigned to the correct value.
|
||||
* @param {ASTNode} node The node that represents the scope to check.
|
||||
* @returns {void}
|
||||
*/
|
||||
function ensureWasAssigned(node) {
|
||||
const scope = sourceCode.getScope(node);
|
||||
|
||||
// if this is program scope we also need to check module scope
|
||||
const extraScope =
|
||||
node.type === "Program" && node.sourceType === "module"
|
||||
? scope.childScopes[0]
|
||||
: null;
|
||||
|
||||
aliases.forEach(alias => {
|
||||
checkWasAssigned(alias, scope);
|
||||
|
||||
if (extraScope) {
|
||||
checkWasAssigned(alias, extraScope);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
"Program:exit": ensureWasAssigned,
|
||||
"FunctionExpression:exit": ensureWasAssigned,
|
||||
"FunctionDeclaration:exit": ensureWasAssigned,
|
||||
|
||||
VariableDeclarator(node) {
|
||||
const id = node.id;
|
||||
const isDestructuring =
|
||||
id.type === "ArrayPattern" || id.type === "ObjectPattern";
|
||||
|
||||
if (node.init !== null && !isDestructuring) {
|
||||
checkAssignment(node, id.name, node.init);
|
||||
}
|
||||
},
|
||||
|
||||
AssignmentExpression(node) {
|
||||
if (node.left.type === "Identifier") {
|
||||
checkAssignment(node, node.left.name, node.right);
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
453
slider/node_modules/eslint/lib/rules/constructor-super.js
generated
vendored
Normal file
453
slider/node_modules/eslint/lib/rules/constructor-super.js
generated
vendored
Normal file
@@ -0,0 +1,453 @@
|
||||
/**
|
||||
* @fileoverview A rule to verify `super()` callings in constructor.
|
||||
* @author Toru Nagashima
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Checks whether or not a given node is a constructor.
|
||||
* @param {ASTNode} node A node to check. This node type is one of
|
||||
* `Program`, `FunctionDeclaration`, `FunctionExpression`, and
|
||||
* `ArrowFunctionExpression`.
|
||||
* @returns {boolean} `true` if the node is a constructor.
|
||||
*/
|
||||
function isConstructorFunction(node) {
|
||||
return (
|
||||
node.type === "FunctionExpression" &&
|
||||
node.parent.type === "MethodDefinition" &&
|
||||
node.parent.kind === "constructor"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a given node can be a constructor or not.
|
||||
* @param {ASTNode} node A node to check.
|
||||
* @returns {boolean} `true` if the node can be a constructor.
|
||||
*/
|
||||
function isPossibleConstructor(node) {
|
||||
if (!node) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (node.type) {
|
||||
case "ClassExpression":
|
||||
case "FunctionExpression":
|
||||
case "ThisExpression":
|
||||
case "MemberExpression":
|
||||
case "CallExpression":
|
||||
case "NewExpression":
|
||||
case "ChainExpression":
|
||||
case "YieldExpression":
|
||||
case "TaggedTemplateExpression":
|
||||
case "MetaProperty":
|
||||
return true;
|
||||
|
||||
case "Identifier":
|
||||
return node.name !== "undefined";
|
||||
|
||||
case "AssignmentExpression":
|
||||
if (["=", "&&="].includes(node.operator)) {
|
||||
return isPossibleConstructor(node.right);
|
||||
}
|
||||
|
||||
if (["||=", "??="].includes(node.operator)) {
|
||||
return (
|
||||
isPossibleConstructor(node.left) ||
|
||||
isPossibleConstructor(node.right)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* All other assignment operators are mathematical assignment operators (arithmetic or bitwise).
|
||||
* An assignment expression with a mathematical operator can either evaluate to a primitive value,
|
||||
* or throw, depending on the operands. Thus, it cannot evaluate to a constructor function.
|
||||
*/
|
||||
return false;
|
||||
|
||||
case "LogicalExpression":
|
||||
/*
|
||||
* If the && operator short-circuits, the left side was falsy and therefore not a constructor, and if
|
||||
* it doesn't short-circuit, it takes the value from the right side, so the right side must always be a
|
||||
* possible constructor. A future improvement could verify that the left side could be truthy by
|
||||
* excluding falsy literals.
|
||||
*/
|
||||
if (node.operator === "&&") {
|
||||
return isPossibleConstructor(node.right);
|
||||
}
|
||||
|
||||
return (
|
||||
isPossibleConstructor(node.left) ||
|
||||
isPossibleConstructor(node.right)
|
||||
);
|
||||
|
||||
case "ConditionalExpression":
|
||||
return (
|
||||
isPossibleConstructor(node.alternate) ||
|
||||
isPossibleConstructor(node.consequent)
|
||||
);
|
||||
|
||||
case "SequenceExpression": {
|
||||
const lastExpression = node.expressions.at(-1);
|
||||
|
||||
return isPossibleConstructor(lastExpression);
|
||||
}
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A class to store information about a code path segment.
|
||||
*/
|
||||
class SegmentInfo {
|
||||
/**
|
||||
* Indicates if super() is called in all code paths.
|
||||
* @type {boolean}
|
||||
*/
|
||||
calledInEveryPaths = false;
|
||||
|
||||
/**
|
||||
* Indicates if super() is called in any code paths.
|
||||
* @type {boolean}
|
||||
*/
|
||||
calledInSomePaths = false;
|
||||
|
||||
/**
|
||||
* The nodes which have been validated and don't need to be reconsidered.
|
||||
* @type {ASTNode[]}
|
||||
*/
|
||||
validNodes = [];
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../types').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "problem",
|
||||
|
||||
docs: {
|
||||
description: "Require `super()` calls in constructors",
|
||||
recommended: true,
|
||||
url: "https://eslint.org/docs/latest/rules/constructor-super",
|
||||
},
|
||||
|
||||
schema: [],
|
||||
|
||||
messages: {
|
||||
missingSome: "Lacked a call of 'super()' in some code paths.",
|
||||
missingAll: "Expected to call 'super()'.",
|
||||
|
||||
duplicate: "Unexpected duplicate 'super()'.",
|
||||
badSuper:
|
||||
"Unexpected 'super()' because 'super' is not a constructor.",
|
||||
},
|
||||
},
|
||||
|
||||
create(context) {
|
||||
/*
|
||||
* {{hasExtends: boolean, scope: Scope, codePath: CodePath}[]}
|
||||
* Information for each constructor.
|
||||
* - upper: Information of the upper constructor.
|
||||
* - hasExtends: A flag which shows whether own class has a valid `extends`
|
||||
* part.
|
||||
* - scope: The scope of own class.
|
||||
* - codePath: The code path object of the constructor.
|
||||
*/
|
||||
let funcInfo = null;
|
||||
|
||||
/**
|
||||
* @type {Record<string, SegmentInfo>}
|
||||
*/
|
||||
const segInfoMap = Object.create(null);
|
||||
|
||||
/**
|
||||
* Gets the flag which shows `super()` is called in some paths.
|
||||
* @param {CodePathSegment} segment A code path segment to get.
|
||||
* @returns {boolean} The flag which shows `super()` is called in some paths
|
||||
*/
|
||||
function isCalledInSomePath(segment) {
|
||||
return (
|
||||
segment.reachable && segInfoMap[segment.id].calledInSomePaths
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if a segment has been seen in the traversal.
|
||||
* @param {CodePathSegment} segment A code path segment to check.
|
||||
* @returns {boolean} `true` if the segment has been seen.
|
||||
*/
|
||||
function hasSegmentBeenSeen(segment) {
|
||||
return !!segInfoMap[segment.id];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the flag which shows `super()` is called in all paths.
|
||||
* @param {CodePathSegment} segment A code path segment to get.
|
||||
* @returns {boolean} The flag which shows `super()` is called in all paths.
|
||||
*/
|
||||
function isCalledInEveryPath(segment) {
|
||||
return (
|
||||
segment.reachable && segInfoMap[segment.id].calledInEveryPaths
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
/**
|
||||
* Stacks a constructor information.
|
||||
* @param {CodePath} codePath A code path which was started.
|
||||
* @param {ASTNode} node The current node.
|
||||
* @returns {void}
|
||||
*/
|
||||
onCodePathStart(codePath, node) {
|
||||
if (isConstructorFunction(node)) {
|
||||
// Class > ClassBody > MethodDefinition > FunctionExpression
|
||||
const classNode = node.parent.parent.parent;
|
||||
const superClass = classNode.superClass;
|
||||
|
||||
funcInfo = {
|
||||
upper: funcInfo,
|
||||
isConstructor: true,
|
||||
hasExtends: Boolean(superClass),
|
||||
superIsConstructor: isPossibleConstructor(superClass),
|
||||
codePath,
|
||||
currentSegments: new Set(),
|
||||
};
|
||||
} else {
|
||||
funcInfo = {
|
||||
upper: funcInfo,
|
||||
isConstructor: false,
|
||||
hasExtends: false,
|
||||
superIsConstructor: false,
|
||||
codePath,
|
||||
currentSegments: new Set(),
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Pops a constructor information.
|
||||
* And reports if `super()` lacked.
|
||||
* @param {CodePath} codePath A code path which was ended.
|
||||
* @param {ASTNode} node The current node.
|
||||
* @returns {void}
|
||||
*/
|
||||
onCodePathEnd(codePath, node) {
|
||||
const hasExtends = funcInfo.hasExtends;
|
||||
|
||||
// Pop.
|
||||
funcInfo = funcInfo.upper;
|
||||
|
||||
if (!hasExtends) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Reports if `super()` lacked.
|
||||
const returnedSegments = codePath.returnedSegments;
|
||||
const calledInEveryPaths =
|
||||
returnedSegments.every(isCalledInEveryPath);
|
||||
const calledInSomePaths =
|
||||
returnedSegments.some(isCalledInSomePath);
|
||||
|
||||
if (!calledInEveryPaths) {
|
||||
context.report({
|
||||
messageId: calledInSomePaths
|
||||
? "missingSome"
|
||||
: "missingAll",
|
||||
node: node.parent,
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Initialize information of a given code path segment.
|
||||
* @param {CodePathSegment} segment A code path segment to initialize.
|
||||
* @param {CodePathSegment} node Node that starts the segment.
|
||||
* @returns {void}
|
||||
*/
|
||||
onCodePathSegmentStart(segment, node) {
|
||||
funcInfo.currentSegments.add(segment);
|
||||
|
||||
if (!(funcInfo.isConstructor && funcInfo.hasExtends)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialize info.
|
||||
const info = (segInfoMap[segment.id] = new SegmentInfo());
|
||||
|
||||
const seenPrevSegments =
|
||||
segment.prevSegments.filter(hasSegmentBeenSeen);
|
||||
|
||||
// When there are previous segments, aggregates these.
|
||||
if (seenPrevSegments.length > 0) {
|
||||
info.calledInSomePaths =
|
||||
seenPrevSegments.some(isCalledInSomePath);
|
||||
info.calledInEveryPaths =
|
||||
seenPrevSegments.every(isCalledInEveryPath);
|
||||
}
|
||||
|
||||
/*
|
||||
* ForStatement > *.update segments are a special case as they are created in advance,
|
||||
* without seen previous segments. Since they logically don't affect `calledInEveryPaths`
|
||||
* calculations, and they can never be a lone previous segment of another one, we'll set
|
||||
* their `calledInEveryPaths` to `true` to effectively ignore them in those calculations.
|
||||
* .
|
||||
*/
|
||||
if (
|
||||
node.parent &&
|
||||
node.parent.type === "ForStatement" &&
|
||||
node.parent.update === node
|
||||
) {
|
||||
info.calledInEveryPaths = true;
|
||||
}
|
||||
},
|
||||
|
||||
onUnreachableCodePathSegmentStart(segment) {
|
||||
funcInfo.currentSegments.add(segment);
|
||||
},
|
||||
|
||||
onUnreachableCodePathSegmentEnd(segment) {
|
||||
funcInfo.currentSegments.delete(segment);
|
||||
},
|
||||
|
||||
onCodePathSegmentEnd(segment) {
|
||||
funcInfo.currentSegments.delete(segment);
|
||||
},
|
||||
|
||||
/**
|
||||
* Update information of the code path segment when a code path was
|
||||
* looped.
|
||||
* @param {CodePathSegment} fromSegment The code path segment of the
|
||||
* end of a loop.
|
||||
* @param {CodePathSegment} toSegment A code path segment of the head
|
||||
* of a loop.
|
||||
* @returns {void}
|
||||
*/
|
||||
onCodePathSegmentLoop(fromSegment, toSegment) {
|
||||
if (!(funcInfo.isConstructor && funcInfo.hasExtends)) {
|
||||
return;
|
||||
}
|
||||
|
||||
funcInfo.codePath.traverseSegments(
|
||||
{ first: toSegment, last: fromSegment },
|
||||
(segment, controller) => {
|
||||
const info = segInfoMap[segment.id];
|
||||
|
||||
// skip segments after the loop
|
||||
if (!info) {
|
||||
controller.skip();
|
||||
return;
|
||||
}
|
||||
|
||||
const seenPrevSegments =
|
||||
segment.prevSegments.filter(hasSegmentBeenSeen);
|
||||
const calledInSomePreviousPaths =
|
||||
seenPrevSegments.some(isCalledInSomePath);
|
||||
const calledInEveryPreviousPaths =
|
||||
seenPrevSegments.every(isCalledInEveryPath);
|
||||
|
||||
info.calledInSomePaths ||= calledInSomePreviousPaths;
|
||||
info.calledInEveryPaths ||= calledInEveryPreviousPaths;
|
||||
|
||||
// If flags become true anew, reports the valid nodes.
|
||||
if (calledInSomePreviousPaths) {
|
||||
const nodes = info.validNodes;
|
||||
|
||||
info.validNodes = [];
|
||||
|
||||
for (let i = 0; i < nodes.length; ++i) {
|
||||
const node = nodes[i];
|
||||
|
||||
context.report({
|
||||
messageId: "duplicate",
|
||||
node,
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Checks for a call of `super()`.
|
||||
* @param {ASTNode} node A CallExpression node to check.
|
||||
* @returns {void}
|
||||
*/
|
||||
"CallExpression:exit"(node) {
|
||||
if (!(funcInfo.isConstructor && funcInfo.hasExtends)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Skips except `super()`.
|
||||
if (node.callee.type !== "Super") {
|
||||
return;
|
||||
}
|
||||
|
||||
// Reports if needed.
|
||||
const segments = funcInfo.currentSegments;
|
||||
let duplicate = false;
|
||||
let info = null;
|
||||
|
||||
for (const segment of segments) {
|
||||
if (segment.reachable) {
|
||||
info = segInfoMap[segment.id];
|
||||
|
||||
duplicate = duplicate || info.calledInSomePaths;
|
||||
info.calledInSomePaths = info.calledInEveryPaths = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (info) {
|
||||
if (duplicate) {
|
||||
context.report({
|
||||
messageId: "duplicate",
|
||||
node,
|
||||
});
|
||||
} else if (!funcInfo.superIsConstructor) {
|
||||
context.report({
|
||||
messageId: "badSuper",
|
||||
node,
|
||||
});
|
||||
} else {
|
||||
info.validNodes.push(node);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Set the mark to the returned path as `super()` was called.
|
||||
* @param {ASTNode} node A ReturnStatement node to check.
|
||||
* @returns {void}
|
||||
*/
|
||||
ReturnStatement(node) {
|
||||
if (!(funcInfo.isConstructor && funcInfo.hasExtends)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Skips if no argument.
|
||||
if (!node.argument) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Returning argument is a substitute of 'super()'.
|
||||
const segments = funcInfo.currentSegments;
|
||||
|
||||
for (const segment of segments) {
|
||||
if (segment.reachable) {
|
||||
const info = segInfoMap[segment.id];
|
||||
|
||||
info.calledInSomePaths = info.calledInEveryPaths = true;
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
425
slider/node_modules/eslint/lib/rules/curly.js
generated
vendored
Normal file
425
slider/node_modules/eslint/lib/rules/curly.js
generated
vendored
Normal file
@@ -0,0 +1,425 @@
|
||||
/**
|
||||
* @fileoverview Rule to flag statements without curly braces
|
||||
* @author Nicholas C. Zakas
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const astUtils = require("./utils/ast-utils");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../types').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
|
||||
docs: {
|
||||
description:
|
||||
"Enforce consistent brace style for all control statements",
|
||||
recommended: false,
|
||||
frozen: true,
|
||||
url: "https://eslint.org/docs/latest/rules/curly",
|
||||
},
|
||||
|
||||
schema: {
|
||||
anyOf: [
|
||||
{
|
||||
type: "array",
|
||||
items: [
|
||||
{
|
||||
enum: ["all"],
|
||||
},
|
||||
],
|
||||
minItems: 0,
|
||||
maxItems: 1,
|
||||
},
|
||||
{
|
||||
type: "array",
|
||||
items: [
|
||||
{
|
||||
enum: ["multi", "multi-line", "multi-or-nest"],
|
||||
},
|
||||
{
|
||||
enum: ["consistent"],
|
||||
},
|
||||
],
|
||||
minItems: 0,
|
||||
maxItems: 2,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
defaultOptions: ["all"],
|
||||
|
||||
fixable: "code",
|
||||
|
||||
messages: {
|
||||
missingCurlyAfter: "Expected { after '{{name}}'.",
|
||||
missingCurlyAfterCondition:
|
||||
"Expected { after '{{name}}' condition.",
|
||||
unexpectedCurlyAfter: "Unnecessary { after '{{name}}'.",
|
||||
unexpectedCurlyAfterCondition:
|
||||
"Unnecessary { after '{{name}}' condition.",
|
||||
},
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const multiOnly = context.options[0] === "multi";
|
||||
const multiLine = context.options[0] === "multi-line";
|
||||
const multiOrNest = context.options[0] === "multi-or-nest";
|
||||
const consistent = context.options[1] === "consistent";
|
||||
|
||||
const sourceCode = context.sourceCode;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Determines if a given node is a one-liner that's on the same line as it's preceding code.
|
||||
* @param {ASTNode} node The node to check.
|
||||
* @returns {boolean} True if the node is a one-liner that's on the same line as it's preceding code.
|
||||
* @private
|
||||
*/
|
||||
function isCollapsedOneLiner(node) {
|
||||
const before = sourceCode.getTokenBefore(node);
|
||||
const last = sourceCode.getLastToken(node);
|
||||
const lastExcludingSemicolon = astUtils.isSemicolonToken(last)
|
||||
? sourceCode.getTokenBefore(last)
|
||||
: last;
|
||||
|
||||
return (
|
||||
before.loc.start.line === lastExcludingSemicolon.loc.end.line
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if a given node is a one-liner.
|
||||
* @param {ASTNode} node The node to check.
|
||||
* @returns {boolean} True if the node is a one-liner.
|
||||
* @private
|
||||
*/
|
||||
function isOneLiner(node) {
|
||||
if (node.type === "EmptyStatement") {
|
||||
return true;
|
||||
}
|
||||
|
||||
const first = sourceCode.getFirstToken(node);
|
||||
const last = sourceCode.getLastToken(node);
|
||||
const lastExcludingSemicolon = astUtils.isSemicolonToken(last)
|
||||
? sourceCode.getTokenBefore(last)
|
||||
: last;
|
||||
|
||||
return first.loc.start.line === lastExcludingSemicolon.loc.end.line;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if a semicolon needs to be inserted after removing a set of curly brackets, in order to avoid a SyntaxError.
|
||||
* @param {Token} closingBracket The } token
|
||||
* @returns {boolean} `true` if a semicolon needs to be inserted after the last statement in the block.
|
||||
*/
|
||||
function needsSemicolon(closingBracket) {
|
||||
const tokenBefore = sourceCode.getTokenBefore(closingBracket);
|
||||
const tokenAfter = sourceCode.getTokenAfter(closingBracket);
|
||||
const lastBlockNode = sourceCode.getNodeByRangeIndex(
|
||||
tokenBefore.range[0],
|
||||
);
|
||||
|
||||
if (astUtils.isSemicolonToken(tokenBefore)) {
|
||||
// If the last statement already has a semicolon, don't add another one.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!tokenAfter) {
|
||||
// If there are no statements after this block, there is no need to add a semicolon.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (
|
||||
lastBlockNode.type === "BlockStatement" &&
|
||||
lastBlockNode.parent.type !== "FunctionExpression" &&
|
||||
lastBlockNode.parent.type !== "ArrowFunctionExpression"
|
||||
) {
|
||||
/*
|
||||
* If the last node surrounded by curly brackets is a BlockStatement (other than a FunctionExpression or an ArrowFunctionExpression),
|
||||
* don't insert a semicolon. Otherwise, the semicolon would be parsed as a separate statement, which would cause
|
||||
* a SyntaxError if it was followed by `else`.
|
||||
*/
|
||||
return false;
|
||||
}
|
||||
|
||||
if (tokenBefore.loc.end.line === tokenAfter.loc.start.line) {
|
||||
// If the next token is on the same line, insert a semicolon.
|
||||
return true;
|
||||
}
|
||||
|
||||
if (/^[([/`+-]/u.test(tokenAfter.value)) {
|
||||
// If the next token starts with a character that would disrupt ASI, insert a semicolon.
|
||||
return true;
|
||||
}
|
||||
|
||||
if (
|
||||
tokenBefore.type === "Punctuator" &&
|
||||
(tokenBefore.value === "++" || tokenBefore.value === "--")
|
||||
) {
|
||||
// If the last token is ++ or --, insert a semicolon to avoid disrupting ASI.
|
||||
return true;
|
||||
}
|
||||
|
||||
// Otherwise, do not insert a semicolon.
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares to check the body of a node to see if it's a block statement.
|
||||
* @param {ASTNode} node The node to report if there's a problem.
|
||||
* @param {ASTNode} body The body node to check for blocks.
|
||||
* @param {string} name The name to report if there's a problem.
|
||||
* @param {{ condition: boolean }} opts Options to pass to the report functions
|
||||
* @returns {Object} a prepared check object, with "actual", "expected", "check" properties.
|
||||
* "actual" will be `true` or `false` whether the body is already a block statement.
|
||||
* "expected" will be `true` or `false` if the body should be a block statement or not, or
|
||||
* `null` if it doesn't matter, depending on the rule options. It can be modified to change
|
||||
* the final behavior of "check".
|
||||
* "check" will be a function reporting appropriate problems depending on the other
|
||||
* properties.
|
||||
*/
|
||||
function prepareCheck(node, body, name, opts) {
|
||||
const hasBlock = body.type === "BlockStatement";
|
||||
let expected = null;
|
||||
|
||||
if (
|
||||
hasBlock &&
|
||||
(body.body.length !== 1 ||
|
||||
astUtils.areBracesNecessary(body, sourceCode))
|
||||
) {
|
||||
expected = true;
|
||||
} else if (multiOnly) {
|
||||
expected = false;
|
||||
} else if (multiLine) {
|
||||
if (!isCollapsedOneLiner(body)) {
|
||||
expected = true;
|
||||
}
|
||||
|
||||
// otherwise, the body is allowed to have braces or not to have braces
|
||||
} else if (multiOrNest) {
|
||||
if (hasBlock) {
|
||||
const statement = body.body[0];
|
||||
const leadingCommentsInBlock =
|
||||
sourceCode.getCommentsBefore(statement);
|
||||
|
||||
expected =
|
||||
!isOneLiner(statement) ||
|
||||
leadingCommentsInBlock.length > 0;
|
||||
} else {
|
||||
expected = !isOneLiner(body);
|
||||
}
|
||||
} else {
|
||||
// default "all"
|
||||
expected = true;
|
||||
}
|
||||
|
||||
return {
|
||||
actual: hasBlock,
|
||||
expected,
|
||||
check() {
|
||||
if (
|
||||
this.expected !== null &&
|
||||
this.expected !== this.actual
|
||||
) {
|
||||
if (this.expected) {
|
||||
context.report({
|
||||
node,
|
||||
loc: body.loc,
|
||||
messageId:
|
||||
opts && opts.condition
|
||||
? "missingCurlyAfterCondition"
|
||||
: "missingCurlyAfter",
|
||||
data: {
|
||||
name,
|
||||
},
|
||||
fix: fixer =>
|
||||
fixer.replaceText(
|
||||
body,
|
||||
`{${sourceCode.getText(body)}}`,
|
||||
),
|
||||
});
|
||||
} else {
|
||||
context.report({
|
||||
node,
|
||||
loc: body.loc,
|
||||
messageId:
|
||||
opts && opts.condition
|
||||
? "unexpectedCurlyAfterCondition"
|
||||
: "unexpectedCurlyAfter",
|
||||
data: {
|
||||
name,
|
||||
},
|
||||
fix(fixer) {
|
||||
/*
|
||||
* `do while` expressions sometimes need a space to be inserted after `do`.
|
||||
* e.g. `do{foo()} while (bar)` should be corrected to `do foo() while (bar)`
|
||||
*/
|
||||
const needsPrecedingSpace =
|
||||
node.type === "DoWhileStatement" &&
|
||||
sourceCode.getTokenBefore(body)
|
||||
.range[1] === body.range[0] &&
|
||||
!astUtils.canTokensBeAdjacent(
|
||||
"do",
|
||||
sourceCode.getFirstToken(body, {
|
||||
skip: 1,
|
||||
}),
|
||||
);
|
||||
|
||||
const openingBracket =
|
||||
sourceCode.getFirstToken(body);
|
||||
const closingBracket =
|
||||
sourceCode.getLastToken(body);
|
||||
const lastTokenInBlock =
|
||||
sourceCode.getTokenBefore(
|
||||
closingBracket,
|
||||
);
|
||||
|
||||
if (needsSemicolon(closingBracket)) {
|
||||
/*
|
||||
* If removing braces would cause a SyntaxError due to multiple statements on the same line (or
|
||||
* change the semantics of the code due to ASI), don't perform a fix.
|
||||
*/
|
||||
return null;
|
||||
}
|
||||
|
||||
const resultingBodyText =
|
||||
sourceCode
|
||||
.getText()
|
||||
.slice(
|
||||
openingBracket.range[1],
|
||||
lastTokenInBlock.range[0],
|
||||
) +
|
||||
sourceCode.getText(lastTokenInBlock) +
|
||||
sourceCode
|
||||
.getText()
|
||||
.slice(
|
||||
lastTokenInBlock.range[1],
|
||||
closingBracket.range[0],
|
||||
);
|
||||
|
||||
return fixer.replaceText(
|
||||
body,
|
||||
(needsPrecedingSpace ? " " : "") +
|
||||
resultingBodyText,
|
||||
);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares to check the bodies of a "if", "else if" and "else" chain.
|
||||
* @param {ASTNode} node The first IfStatement node of the chain.
|
||||
* @returns {Object[]} prepared checks for each body of the chain. See `prepareCheck` for more
|
||||
* information.
|
||||
*/
|
||||
function prepareIfChecks(node) {
|
||||
const preparedChecks = [];
|
||||
|
||||
for (
|
||||
let currentNode = node;
|
||||
currentNode;
|
||||
currentNode = currentNode.alternate
|
||||
) {
|
||||
preparedChecks.push(
|
||||
prepareCheck(currentNode, currentNode.consequent, "if", {
|
||||
condition: true,
|
||||
}),
|
||||
);
|
||||
if (
|
||||
currentNode.alternate &&
|
||||
currentNode.alternate.type !== "IfStatement"
|
||||
) {
|
||||
preparedChecks.push(
|
||||
prepareCheck(
|
||||
currentNode,
|
||||
currentNode.alternate,
|
||||
"else",
|
||||
),
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (consistent) {
|
||||
/*
|
||||
* If any node should have or already have braces, make sure they
|
||||
* all have braces.
|
||||
* If all nodes shouldn't have braces, make sure they don't.
|
||||
*/
|
||||
const expected = preparedChecks.some(preparedCheck => {
|
||||
if (preparedCheck.expected !== null) {
|
||||
return preparedCheck.expected;
|
||||
}
|
||||
return preparedCheck.actual;
|
||||
});
|
||||
|
||||
preparedChecks.forEach(preparedCheck => {
|
||||
preparedCheck.expected = expected;
|
||||
});
|
||||
}
|
||||
|
||||
return preparedChecks;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Public
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
return {
|
||||
IfStatement(node) {
|
||||
const parent = node.parent;
|
||||
const isElseIf =
|
||||
parent.type === "IfStatement" && parent.alternate === node;
|
||||
|
||||
if (!isElseIf) {
|
||||
// This is a top `if`, check the whole `if-else-if` chain
|
||||
prepareIfChecks(node).forEach(preparedCheck => {
|
||||
preparedCheck.check();
|
||||
});
|
||||
}
|
||||
|
||||
// Skip `else if`, it's already checked (when the top `if` was visited)
|
||||
},
|
||||
|
||||
WhileStatement(node) {
|
||||
prepareCheck(node, node.body, "while", {
|
||||
condition: true,
|
||||
}).check();
|
||||
},
|
||||
|
||||
DoWhileStatement(node) {
|
||||
prepareCheck(node, node.body, "do").check();
|
||||
},
|
||||
|
||||
ForStatement(node) {
|
||||
prepareCheck(node, node.body, "for", {
|
||||
condition: true,
|
||||
}).check();
|
||||
},
|
||||
|
||||
ForInStatement(node) {
|
||||
prepareCheck(node, node.body, "for-in").check();
|
||||
},
|
||||
|
||||
ForOfStatement(node) {
|
||||
prepareCheck(node, node.body, "for-of").check();
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
51
slider/node_modules/eslint/lib/rules/default-case-last.js
generated
vendored
Normal file
51
slider/node_modules/eslint/lib/rules/default-case-last.js
generated
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* @fileoverview Rule to enforce `default` clauses in `switch` statements to be last
|
||||
* @author Milos Djermanovic
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../types').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
|
||||
docs: {
|
||||
description:
|
||||
"Enforce `default` clauses in `switch` statements to be last",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/latest/rules/default-case-last",
|
||||
},
|
||||
|
||||
schema: [],
|
||||
|
||||
messages: {
|
||||
notLast: "Default clause should be the last clause.",
|
||||
},
|
||||
},
|
||||
|
||||
create(context) {
|
||||
return {
|
||||
SwitchStatement(node) {
|
||||
const cases = node.cases,
|
||||
indexOfDefault = cases.findIndex(c => c.test === null);
|
||||
|
||||
if (
|
||||
indexOfDefault !== -1 &&
|
||||
indexOfDefault !== cases.length - 1
|
||||
) {
|
||||
const defaultClause = cases[indexOfDefault];
|
||||
|
||||
context.report({
|
||||
node: defaultClause,
|
||||
messageId: "notLast",
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
103
slider/node_modules/eslint/lib/rules/default-case.js
generated
vendored
Normal file
103
slider/node_modules/eslint/lib/rules/default-case.js
generated
vendored
Normal file
@@ -0,0 +1,103 @@
|
||||
/**
|
||||
* @fileoverview require default case in switch statements
|
||||
* @author Aliaksei Shytkin
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
const DEFAULT_COMMENT_PATTERN = /^no default$/iu;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../types').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
|
||||
defaultOptions: [{}],
|
||||
|
||||
docs: {
|
||||
description: "Require `default` cases in `switch` statements",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/latest/rules/default-case",
|
||||
},
|
||||
|
||||
schema: [
|
||||
{
|
||||
type: "object",
|
||||
properties: {
|
||||
commentPattern: {
|
||||
type: "string",
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
},
|
||||
],
|
||||
|
||||
messages: {
|
||||
missingDefaultCase: "Expected a default case.",
|
||||
},
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const [options] = context.options;
|
||||
const commentPattern = options.commentPattern
|
||||
? new RegExp(options.commentPattern, "u")
|
||||
: DEFAULT_COMMENT_PATTERN;
|
||||
|
||||
const sourceCode = context.sourceCode;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Shortcut to get last element of array
|
||||
* @param {*[]} collection Array
|
||||
* @returns {any} Last element
|
||||
*/
|
||||
function last(collection) {
|
||||
return collection.at(-1);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Public
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
return {
|
||||
SwitchStatement(node) {
|
||||
if (!node.cases.length) {
|
||||
/*
|
||||
* skip check of empty switch because there is no easy way
|
||||
* to extract comments inside it now
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
const hasDefault = node.cases.some(v => v.test === null);
|
||||
|
||||
if (!hasDefault) {
|
||||
let comment;
|
||||
|
||||
const lastCase = last(node.cases);
|
||||
const comments = sourceCode.getCommentsAfter(lastCase);
|
||||
|
||||
if (comments.length) {
|
||||
comment = last(comments);
|
||||
}
|
||||
|
||||
if (
|
||||
!comment ||
|
||||
!commentPattern.test(comment.value.trim())
|
||||
) {
|
||||
context.report({
|
||||
node,
|
||||
messageId: "missingDefaultCase",
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
78
slider/node_modules/eslint/lib/rules/default-param-last.js
generated
vendored
Normal file
78
slider/node_modules/eslint/lib/rules/default-param-last.js
generated
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
* @fileoverview enforce default parameters to be last
|
||||
* @author Chiawen Chen
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Checks if node is required: i.e. does not have a default value or ? optional indicator.
|
||||
* @param {ASTNode} node the node to be evaluated
|
||||
* @returns {boolean} true if the node is required, false if not.
|
||||
*/
|
||||
function isRequiredParameter(node) {
|
||||
return !(
|
||||
node.type === "AssignmentPattern" ||
|
||||
node.type === "RestElement" ||
|
||||
node.optional
|
||||
);
|
||||
}
|
||||
|
||||
/** @type {import('../types').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
dialects: ["javascript", "typescript"],
|
||||
language: "javascript",
|
||||
type: "suggestion",
|
||||
|
||||
docs: {
|
||||
description: "Enforce default parameters to be last",
|
||||
recommended: false,
|
||||
frozen: true,
|
||||
url: "https://eslint.org/docs/latest/rules/default-param-last",
|
||||
},
|
||||
|
||||
schema: [],
|
||||
|
||||
messages: {
|
||||
shouldBeLast: "Default parameters should be last.",
|
||||
},
|
||||
},
|
||||
|
||||
create(context) {
|
||||
/**
|
||||
* Handler for function contexts.
|
||||
* @param {ASTNode} node function node
|
||||
* @returns {void}
|
||||
*/
|
||||
function handleFunction(node) {
|
||||
let hasSeenRequiredParameter = false;
|
||||
|
||||
for (let i = node.params.length - 1; i >= 0; i -= 1) {
|
||||
const current = node.params[i];
|
||||
const param =
|
||||
current.type === "TSParameterProperty"
|
||||
? current.parameter
|
||||
: current;
|
||||
|
||||
if (isRequiredParameter(param)) {
|
||||
hasSeenRequiredParameter = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (hasSeenRequiredParameter) {
|
||||
context.report({
|
||||
node: current,
|
||||
messageId: "shouldBeLast",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
FunctionDeclaration: handleFunction,
|
||||
FunctionExpression: handleFunction,
|
||||
ArrowFunctionExpression: handleFunction,
|
||||
};
|
||||
},
|
||||
};
|
||||
138
slider/node_modules/eslint/lib/rules/dot-location.js
generated
vendored
Normal file
138
slider/node_modules/eslint/lib/rules/dot-location.js
generated
vendored
Normal file
@@ -0,0 +1,138 @@
|
||||
/**
|
||||
* @fileoverview Validates newlines before and after dots
|
||||
* @author Greg Cochard
|
||||
* @deprecated in ESLint v8.53.0
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
const astUtils = require("./utils/ast-utils");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../types').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
deprecated: {
|
||||
message: "Formatting rules are being moved out of ESLint core.",
|
||||
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
|
||||
deprecatedSince: "8.53.0",
|
||||
availableUntil: "10.0.0",
|
||||
replacedBy: [
|
||||
{
|
||||
message:
|
||||
"ESLint Stylistic now maintains deprecated stylistic core rules.",
|
||||
url: "https://eslint.style/guide/migration",
|
||||
plugin: {
|
||||
name: "@stylistic/eslint-plugin",
|
||||
url: "https://eslint.style",
|
||||
},
|
||||
rule: {
|
||||
name: "dot-location",
|
||||
url: "https://eslint.style/rules/dot-location",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
type: "layout",
|
||||
|
||||
docs: {
|
||||
description: "Enforce consistent newlines before and after dots",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/latest/rules/dot-location",
|
||||
},
|
||||
|
||||
schema: [
|
||||
{
|
||||
enum: ["object", "property"],
|
||||
},
|
||||
],
|
||||
|
||||
fixable: "code",
|
||||
|
||||
messages: {
|
||||
expectedDotAfterObject:
|
||||
"Expected dot to be on same line as object.",
|
||||
expectedDotBeforeProperty:
|
||||
"Expected dot to be on same line as property.",
|
||||
},
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const config = context.options[0];
|
||||
|
||||
// default to onObject if no preference is passed
|
||||
const onObject = config === "object" || !config;
|
||||
|
||||
const sourceCode = context.sourceCode;
|
||||
|
||||
/**
|
||||
* Reports if the dot between object and property is on the correct location.
|
||||
* @param {ASTNode} node The `MemberExpression` node.
|
||||
* @returns {void}
|
||||
*/
|
||||
function checkDotLocation(node) {
|
||||
const property = node.property;
|
||||
const dotToken = sourceCode.getTokenBefore(property);
|
||||
|
||||
if (onObject) {
|
||||
// `obj` expression can be parenthesized, but those paren tokens are not a part of the `obj` node.
|
||||
const tokenBeforeDot = sourceCode.getTokenBefore(dotToken);
|
||||
|
||||
if (!astUtils.isTokenOnSameLine(tokenBeforeDot, dotToken)) {
|
||||
context.report({
|
||||
node,
|
||||
loc: dotToken.loc,
|
||||
messageId: "expectedDotAfterObject",
|
||||
*fix(fixer) {
|
||||
if (
|
||||
dotToken.value.startsWith(".") &&
|
||||
astUtils.isDecimalIntegerNumericToken(
|
||||
tokenBeforeDot,
|
||||
)
|
||||
) {
|
||||
yield fixer.insertTextAfter(
|
||||
tokenBeforeDot,
|
||||
` ${dotToken.value}`,
|
||||
);
|
||||
} else {
|
||||
yield fixer.insertTextAfter(
|
||||
tokenBeforeDot,
|
||||
dotToken.value,
|
||||
);
|
||||
}
|
||||
yield fixer.remove(dotToken);
|
||||
},
|
||||
});
|
||||
}
|
||||
} else if (!astUtils.isTokenOnSameLine(dotToken, property)) {
|
||||
context.report({
|
||||
node,
|
||||
loc: dotToken.loc,
|
||||
messageId: "expectedDotBeforeProperty",
|
||||
*fix(fixer) {
|
||||
yield fixer.remove(dotToken);
|
||||
yield fixer.insertTextBefore(property, dotToken.value);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the spacing of the dot within a member expression.
|
||||
* @param {ASTNode} node The node to check.
|
||||
* @returns {void}
|
||||
*/
|
||||
function checkNode(node) {
|
||||
if (!node.computed) {
|
||||
checkDotLocation(node);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
MemberExpression: checkNode,
|
||||
};
|
||||
},
|
||||
};
|
||||
216
slider/node_modules/eslint/lib/rules/dot-notation.js
generated
vendored
Normal file
216
slider/node_modules/eslint/lib/rules/dot-notation.js
generated
vendored
Normal file
@@ -0,0 +1,216 @@
|
||||
/**
|
||||
* @fileoverview Rule to warn about using dot notation instead of square bracket notation when possible.
|
||||
* @author Josh Perez
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const astUtils = require("./utils/ast-utils");
|
||||
const keywords = require("./utils/keywords");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const validIdentifier = /^[a-zA-Z_$][\w$]*$/u;
|
||||
|
||||
// `null` literal must be handled separately.
|
||||
const literalTypesToCheck = new Set(["string", "boolean"]);
|
||||
|
||||
/** @type {import('../types').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
|
||||
defaultOptions: [
|
||||
{
|
||||
allowKeywords: true,
|
||||
allowPattern: "",
|
||||
},
|
||||
],
|
||||
|
||||
docs: {
|
||||
description: "Enforce dot notation whenever possible",
|
||||
recommended: false,
|
||||
frozen: true,
|
||||
url: "https://eslint.org/docs/latest/rules/dot-notation",
|
||||
},
|
||||
|
||||
schema: [
|
||||
{
|
||||
type: "object",
|
||||
properties: {
|
||||
allowKeywords: {
|
||||
type: "boolean",
|
||||
},
|
||||
allowPattern: {
|
||||
type: "string",
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
},
|
||||
],
|
||||
|
||||
fixable: "code",
|
||||
|
||||
messages: {
|
||||
useDot: "[{{key}}] is better written in dot notation.",
|
||||
useBrackets: ".{{key}} is a syntax error.",
|
||||
},
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const [options] = context.options;
|
||||
const allowKeywords = options.allowKeywords;
|
||||
const sourceCode = context.sourceCode;
|
||||
|
||||
let allowPattern;
|
||||
|
||||
if (options.allowPattern) {
|
||||
allowPattern = new RegExp(options.allowPattern, "u");
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the property is valid dot notation
|
||||
* @param {ASTNode} node The dot notation node
|
||||
* @param {string} value Value which is to be checked
|
||||
* @returns {void}
|
||||
*/
|
||||
function checkComputedProperty(node, value) {
|
||||
if (
|
||||
validIdentifier.test(value) &&
|
||||
(allowKeywords || !keywords.includes(String(value))) &&
|
||||
!(allowPattern && allowPattern.test(value))
|
||||
) {
|
||||
const formattedValue =
|
||||
node.property.type === "Literal"
|
||||
? JSON.stringify(value)
|
||||
: `\`${value}\``;
|
||||
|
||||
context.report({
|
||||
node: node.property,
|
||||
messageId: "useDot",
|
||||
data: {
|
||||
key: formattedValue,
|
||||
},
|
||||
*fix(fixer) {
|
||||
const leftBracket = sourceCode.getTokenAfter(
|
||||
node.object,
|
||||
astUtils.isOpeningBracketToken,
|
||||
);
|
||||
const rightBracket = sourceCode.getLastToken(node);
|
||||
const nextToken = sourceCode.getTokenAfter(node);
|
||||
|
||||
// Don't perform any fixes if there are comments inside the brackets.
|
||||
if (
|
||||
sourceCode.commentsExistBetween(
|
||||
leftBracket,
|
||||
rightBracket,
|
||||
)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Replace the brackets by an identifier.
|
||||
if (!node.optional) {
|
||||
yield fixer.insertTextBefore(
|
||||
leftBracket,
|
||||
astUtils.isDecimalInteger(node.object)
|
||||
? " ."
|
||||
: ".",
|
||||
);
|
||||
}
|
||||
yield fixer.replaceTextRange(
|
||||
[leftBracket.range[0], rightBracket.range[1]],
|
||||
value,
|
||||
);
|
||||
|
||||
// Insert a space after the property if it will be connected to the next token.
|
||||
if (
|
||||
nextToken &&
|
||||
rightBracket.range[1] === nextToken.range[0] &&
|
||||
!astUtils.canTokensBeAdjacent(
|
||||
String(value),
|
||||
nextToken,
|
||||
)
|
||||
) {
|
||||
yield fixer.insertTextAfter(node, " ");
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
MemberExpression(node) {
|
||||
if (
|
||||
node.computed &&
|
||||
node.property.type === "Literal" &&
|
||||
(literalTypesToCheck.has(typeof node.property.value) ||
|
||||
astUtils.isNullLiteral(node.property))
|
||||
) {
|
||||
checkComputedProperty(node, node.property.value);
|
||||
}
|
||||
if (
|
||||
node.computed &&
|
||||
astUtils.isStaticTemplateLiteral(node.property)
|
||||
) {
|
||||
checkComputedProperty(
|
||||
node,
|
||||
node.property.quasis[0].value.cooked,
|
||||
);
|
||||
}
|
||||
if (
|
||||
!allowKeywords &&
|
||||
!node.computed &&
|
||||
node.property.type === "Identifier" &&
|
||||
keywords.includes(String(node.property.name))
|
||||
) {
|
||||
context.report({
|
||||
node: node.property,
|
||||
messageId: "useBrackets",
|
||||
data: {
|
||||
key: node.property.name,
|
||||
},
|
||||
*fix(fixer) {
|
||||
const dotToken = sourceCode.getTokenBefore(
|
||||
node.property,
|
||||
);
|
||||
|
||||
// A statement that starts with `let[` is parsed as a destructuring variable declaration, not a MemberExpression.
|
||||
if (
|
||||
node.object.type === "Identifier" &&
|
||||
node.object.name === "let" &&
|
||||
!node.optional
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't perform any fixes if there are comments between the dot and the property name.
|
||||
if (
|
||||
sourceCode.commentsExistBetween(
|
||||
dotToken,
|
||||
node.property,
|
||||
)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Replace the identifier to brackets.
|
||||
if (!node.optional) {
|
||||
yield fixer.remove(dotToken);
|
||||
}
|
||||
yield fixer.replaceText(
|
||||
node.property,
|
||||
`["${node.property.name}"]`,
|
||||
);
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
135
slider/node_modules/eslint/lib/rules/eol-last.js
generated
vendored
Normal file
135
slider/node_modules/eslint/lib/rules/eol-last.js
generated
vendored
Normal file
@@ -0,0 +1,135 @@
|
||||
/**
|
||||
* @fileoverview Require or disallow newline at the end of files
|
||||
* @author Nodeca Team <https://github.com/nodeca>
|
||||
* @deprecated in ESLint v8.53.0
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../types').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
deprecated: {
|
||||
message: "Formatting rules are being moved out of ESLint core.",
|
||||
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
|
||||
deprecatedSince: "8.53.0",
|
||||
availableUntil: "10.0.0",
|
||||
replacedBy: [
|
||||
{
|
||||
message:
|
||||
"ESLint Stylistic now maintains deprecated stylistic core rules.",
|
||||
url: "https://eslint.style/guide/migration",
|
||||
plugin: {
|
||||
name: "@stylistic/eslint-plugin",
|
||||
url: "https://eslint.style",
|
||||
},
|
||||
rule: {
|
||||
name: "eol-last",
|
||||
url: "https://eslint.style/rules/eol-last",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
type: "layout",
|
||||
|
||||
docs: {
|
||||
description: "Require or disallow newline at the end of files",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/latest/rules/eol-last",
|
||||
},
|
||||
|
||||
fixable: "whitespace",
|
||||
|
||||
schema: [
|
||||
{
|
||||
enum: ["always", "never", "unix", "windows"],
|
||||
},
|
||||
],
|
||||
|
||||
messages: {
|
||||
missing: "Newline required at end of file but not found.",
|
||||
unexpected: "Newline not allowed at end of file.",
|
||||
},
|
||||
},
|
||||
create(context) {
|
||||
//--------------------------------------------------------------------------
|
||||
// Public
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
return {
|
||||
Program: function checkBadEOF(node) {
|
||||
const sourceCode = context.sourceCode,
|
||||
src = sourceCode.getText(),
|
||||
lastLine = sourceCode.lines.at(-1),
|
||||
location = {
|
||||
column: lastLine.length,
|
||||
line: sourceCode.lines.length,
|
||||
},
|
||||
LF = "\n",
|
||||
CRLF = `\r${LF}`,
|
||||
endsWithNewline = src.endsWith(LF);
|
||||
|
||||
/*
|
||||
* Empty source is always valid: No content in file so we don't
|
||||
* need to lint for a newline on the last line of content.
|
||||
*/
|
||||
if (!src.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
let mode = context.options[0] || "always",
|
||||
appendCRLF = false;
|
||||
|
||||
if (mode === "unix") {
|
||||
// `"unix"` should behave exactly as `"always"`
|
||||
mode = "always";
|
||||
}
|
||||
if (mode === "windows") {
|
||||
// `"windows"` should behave exactly as `"always"`, but append CRLF in the fixer for backwards compatibility
|
||||
mode = "always";
|
||||
appendCRLF = true;
|
||||
}
|
||||
if (mode === "always" && !endsWithNewline) {
|
||||
// File is not newline-terminated, but should be
|
||||
context.report({
|
||||
node,
|
||||
loc: location,
|
||||
messageId: "missing",
|
||||
fix(fixer) {
|
||||
return fixer.insertTextAfterRange(
|
||||
[0, src.length],
|
||||
appendCRLF ? CRLF : LF,
|
||||
);
|
||||
},
|
||||
});
|
||||
} else if (mode === "never" && endsWithNewline) {
|
||||
const secondLastLine = sourceCode.lines.at(-2);
|
||||
|
||||
// File is newline-terminated, but shouldn't be
|
||||
context.report({
|
||||
node,
|
||||
loc: {
|
||||
start: {
|
||||
line: sourceCode.lines.length - 1,
|
||||
column: secondLastLine.length,
|
||||
},
|
||||
end: { line: sourceCode.lines.length, column: 0 },
|
||||
},
|
||||
messageId: "unexpected",
|
||||
fix(fixer) {
|
||||
const finalEOLs = /(?:\r?\n)+$/u,
|
||||
match = finalEOLs.exec(sourceCode.text),
|
||||
start = match.index,
|
||||
end = sourceCode.text.length;
|
||||
|
||||
return fixer.replaceTextRange([start, end], "");
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
210
slider/node_modules/eslint/lib/rules/eqeqeq.js
generated
vendored
Normal file
210
slider/node_modules/eslint/lib/rules/eqeqeq.js
generated
vendored
Normal file
@@ -0,0 +1,210 @@
|
||||
/**
|
||||
* @fileoverview Rule to flag statements that use != and == instead of !== and ===
|
||||
* @author Nicholas C. Zakas
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const astUtils = require("./utils/ast-utils");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../types').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
hasSuggestions: true,
|
||||
|
||||
docs: {
|
||||
description: "Require the use of `===` and `!==`",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/latest/rules/eqeqeq",
|
||||
},
|
||||
|
||||
schema: {
|
||||
anyOf: [
|
||||
{
|
||||
type: "array",
|
||||
items: [
|
||||
{
|
||||
enum: ["always"],
|
||||
},
|
||||
{
|
||||
type: "object",
|
||||
properties: {
|
||||
null: {
|
||||
enum: ["always", "never", "ignore"],
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
},
|
||||
],
|
||||
additionalItems: false,
|
||||
},
|
||||
{
|
||||
type: "array",
|
||||
items: [
|
||||
{
|
||||
enum: ["smart", "allow-null"],
|
||||
},
|
||||
],
|
||||
additionalItems: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
fixable: "code",
|
||||
|
||||
messages: {
|
||||
unexpected:
|
||||
"Expected '{{expectedOperator}}' and instead saw '{{actualOperator}}'.",
|
||||
replaceOperator:
|
||||
"Use '{{expectedOperator}}' instead of '{{actualOperator}}'.",
|
||||
},
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const config = context.options[0] || "always";
|
||||
const options = context.options[1] || {};
|
||||
const sourceCode = context.sourceCode;
|
||||
|
||||
const nullOption =
|
||||
config === "always" ? options.null || "always" : "ignore";
|
||||
const enforceRuleForNull = nullOption === "always";
|
||||
const enforceInverseRuleForNull = nullOption === "never";
|
||||
|
||||
/**
|
||||
* Checks if an expression is a typeof expression
|
||||
* @param {ASTNode} node The node to check
|
||||
* @returns {boolean} if the node is a typeof expression
|
||||
*/
|
||||
function isTypeOf(node) {
|
||||
return (
|
||||
node.type === "UnaryExpression" && node.operator === "typeof"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if either operand of a binary expression is a typeof operation
|
||||
* @param {ASTNode} node The node to check
|
||||
* @returns {boolean} if one of the operands is typeof
|
||||
* @private
|
||||
*/
|
||||
function isTypeOfBinary(node) {
|
||||
return isTypeOf(node.left) || isTypeOf(node.right);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if operands are literals of the same type (via typeof)
|
||||
* @param {ASTNode} node The node to check
|
||||
* @returns {boolean} if operands are of same type
|
||||
* @private
|
||||
*/
|
||||
function areLiteralsAndSameType(node) {
|
||||
return (
|
||||
node.left.type === "Literal" &&
|
||||
node.right.type === "Literal" &&
|
||||
typeof node.left.value === typeof node.right.value
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if one of the operands is a literal null
|
||||
* @param {ASTNode} node The node to check
|
||||
* @returns {boolean} if operands are null
|
||||
* @private
|
||||
*/
|
||||
function isNullCheck(node) {
|
||||
return (
|
||||
astUtils.isNullLiteral(node.right) ||
|
||||
astUtils.isNullLiteral(node.left)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports a message for this rule.
|
||||
* @param {ASTNode} node The binary expression node that was checked
|
||||
* @param {string} expectedOperator The operator that was expected (either '==', '!=', '===', or '!==')
|
||||
* @returns {void}
|
||||
* @private
|
||||
*/
|
||||
function report(node, expectedOperator) {
|
||||
const operatorToken = sourceCode.getFirstTokenBetween(
|
||||
node.left,
|
||||
node.right,
|
||||
token => token.value === node.operator,
|
||||
);
|
||||
|
||||
const commonReportParams = {
|
||||
node,
|
||||
loc: operatorToken.loc,
|
||||
messageId: "unexpected",
|
||||
data: { expectedOperator, actualOperator: node.operator },
|
||||
};
|
||||
|
||||
if (isTypeOfBinary(node) || areLiteralsAndSameType(node)) {
|
||||
context.report({
|
||||
...commonReportParams,
|
||||
fix(fixer) {
|
||||
return fixer.replaceText(
|
||||
operatorToken,
|
||||
expectedOperator,
|
||||
);
|
||||
},
|
||||
});
|
||||
} else {
|
||||
context.report({
|
||||
...commonReportParams,
|
||||
suggest: [
|
||||
{
|
||||
messageId: "replaceOperator",
|
||||
data: {
|
||||
expectedOperator,
|
||||
actualOperator: node.operator,
|
||||
},
|
||||
fix: fixer =>
|
||||
fixer.replaceText(
|
||||
operatorToken,
|
||||
expectedOperator,
|
||||
),
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
BinaryExpression(node) {
|
||||
const isNull = isNullCheck(node);
|
||||
|
||||
if (node.operator !== "==" && node.operator !== "!=") {
|
||||
if (enforceInverseRuleForNull && isNull) {
|
||||
report(node, node.operator.slice(0, -1));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
config === "smart" &&
|
||||
(isTypeOfBinary(node) ||
|
||||
areLiteralsAndSameType(node) ||
|
||||
isNull)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!enforceRuleForNull && isNull) {
|
||||
return;
|
||||
}
|
||||
|
||||
report(node, `${node.operator}=`);
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
165
slider/node_modules/eslint/lib/rules/for-direction.js
generated
vendored
Normal file
165
slider/node_modules/eslint/lib/rules/for-direction.js
generated
vendored
Normal file
@@ -0,0 +1,165 @@
|
||||
/**
|
||||
* @fileoverview enforce `for` loop update clause moving the counter in the right direction.(for-direction)
|
||||
* @author Aladdin-ADD<hh_2013@foxmail.com>
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const { getStaticValue } = require("@eslint-community/eslint-utils");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../types').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "problem",
|
||||
|
||||
docs: {
|
||||
description:
|
||||
"Enforce `for` loop update clause moving the counter in the right direction",
|
||||
recommended: true,
|
||||
url: "https://eslint.org/docs/latest/rules/for-direction",
|
||||
},
|
||||
|
||||
fixable: null,
|
||||
schema: [],
|
||||
|
||||
messages: {
|
||||
incorrectDirection:
|
||||
"The update clause in this loop moves the variable in the wrong direction.",
|
||||
},
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const { sourceCode } = context;
|
||||
|
||||
/**
|
||||
* report an error.
|
||||
* @param {ASTNode} node the node to report.
|
||||
* @returns {void}
|
||||
*/
|
||||
function report(node) {
|
||||
context.report({
|
||||
node,
|
||||
messageId: "incorrectDirection",
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* check the right side of the assignment
|
||||
* @param {ASTNode} update UpdateExpression to check
|
||||
* @param {number} dir expected direction that could either be turned around or invalidated
|
||||
* @returns {number} return dir, the negated dir, or zero if the counter does not change or the direction is not clear
|
||||
*/
|
||||
function getRightDirection(update, dir) {
|
||||
const staticValue = getStaticValue(
|
||||
update.right,
|
||||
sourceCode.getScope(update),
|
||||
);
|
||||
|
||||
if (
|
||||
staticValue &&
|
||||
["bigint", "boolean", "number"].includes(
|
||||
typeof staticValue.value,
|
||||
)
|
||||
) {
|
||||
const sign = Math.sign(Number(staticValue.value)) || 0; // convert NaN to 0
|
||||
|
||||
return dir * sign;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* check UpdateExpression add/sub the counter
|
||||
* @param {ASTNode} update UpdateExpression to check
|
||||
* @param {string} counter variable name to check
|
||||
* @returns {number} if add return 1, if sub return -1, if nochange, return 0
|
||||
*/
|
||||
function getUpdateDirection(update, counter) {
|
||||
if (
|
||||
update.argument.type === "Identifier" &&
|
||||
update.argument.name === counter
|
||||
) {
|
||||
if (update.operator === "++") {
|
||||
return 1;
|
||||
}
|
||||
if (update.operator === "--") {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* check AssignmentExpression add/sub the counter
|
||||
* @param {ASTNode} update AssignmentExpression to check
|
||||
* @param {string} counter variable name to check
|
||||
* @returns {number} if add return 1, if sub return -1, if nochange, return 0
|
||||
*/
|
||||
function getAssignmentDirection(update, counter) {
|
||||
if (update.left.name === counter) {
|
||||
if (update.operator === "+=") {
|
||||
return getRightDirection(update, 1);
|
||||
}
|
||||
if (update.operator === "-=") {
|
||||
return getRightDirection(update, -1);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
return {
|
||||
ForStatement(node) {
|
||||
if (
|
||||
node.test &&
|
||||
node.test.type === "BinaryExpression" &&
|
||||
node.update
|
||||
) {
|
||||
for (const counterPosition of ["left", "right"]) {
|
||||
if (node.test[counterPosition].type !== "Identifier") {
|
||||
continue;
|
||||
}
|
||||
|
||||
const counter = node.test[counterPosition].name;
|
||||
const operator = node.test.operator;
|
||||
const update = node.update;
|
||||
|
||||
let wrongDirection;
|
||||
|
||||
if (operator === "<" || operator === "<=") {
|
||||
wrongDirection =
|
||||
counterPosition === "left" ? -1 : 1;
|
||||
} else if (operator === ">" || operator === ">=") {
|
||||
wrongDirection =
|
||||
counterPosition === "left" ? 1 : -1;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
if (update.type === "UpdateExpression") {
|
||||
if (
|
||||
getUpdateDirection(update, counter) ===
|
||||
wrongDirection
|
||||
) {
|
||||
report(node);
|
||||
}
|
||||
} else if (
|
||||
update.type === "AssignmentExpression" &&
|
||||
getAssignmentDirection(update, counter) ===
|
||||
wrongDirection
|
||||
) {
|
||||
report(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
281
slider/node_modules/eslint/lib/rules/func-call-spacing.js
generated
vendored
Normal file
281
slider/node_modules/eslint/lib/rules/func-call-spacing.js
generated
vendored
Normal file
@@ -0,0 +1,281 @@
|
||||
/**
|
||||
* @fileoverview Rule to control spacing within function calls
|
||||
* @author Matt DuVall <http://www.mattduvall.com>
|
||||
* @deprecated in ESLint v8.53.0
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const astUtils = require("./utils/ast-utils");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../types').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
deprecated: {
|
||||
message: "Formatting rules are being moved out of ESLint core.",
|
||||
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
|
||||
deprecatedSince: "8.53.0",
|
||||
availableUntil: "10.0.0",
|
||||
replacedBy: [
|
||||
{
|
||||
message:
|
||||
"ESLint Stylistic now maintains deprecated stylistic core rules.",
|
||||
url: "https://eslint.style/guide/migration",
|
||||
plugin: {
|
||||
name: "@stylistic/eslint-plugin",
|
||||
url: "https://eslint.style",
|
||||
},
|
||||
rule: {
|
||||
name: "function-call-spacing",
|
||||
url: "https://eslint.style/rules/function-call-spacing",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
type: "layout",
|
||||
|
||||
docs: {
|
||||
description:
|
||||
"Require or disallow spacing between function identifiers and their invocations",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/latest/rules/func-call-spacing",
|
||||
},
|
||||
|
||||
fixable: "whitespace",
|
||||
|
||||
schema: {
|
||||
anyOf: [
|
||||
{
|
||||
type: "array",
|
||||
items: [
|
||||
{
|
||||
enum: ["never"],
|
||||
},
|
||||
],
|
||||
minItems: 0,
|
||||
maxItems: 1,
|
||||
},
|
||||
{
|
||||
type: "array",
|
||||
items: [
|
||||
{
|
||||
enum: ["always"],
|
||||
},
|
||||
{
|
||||
type: "object",
|
||||
properties: {
|
||||
allowNewlines: {
|
||||
type: "boolean",
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
},
|
||||
],
|
||||
minItems: 0,
|
||||
maxItems: 2,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
messages: {
|
||||
unexpectedWhitespace:
|
||||
"Unexpected whitespace between function name and paren.",
|
||||
unexpectedNewline:
|
||||
"Unexpected newline between function name and paren.",
|
||||
missing: "Missing space between function name and paren.",
|
||||
},
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const never = context.options[0] !== "always";
|
||||
const allowNewlines =
|
||||
!never && context.options[1] && context.options[1].allowNewlines;
|
||||
const sourceCode = context.sourceCode;
|
||||
const text = sourceCode.getText();
|
||||
|
||||
/**
|
||||
* Check if open space is present in a function name
|
||||
* @param {ASTNode} node node to evaluate
|
||||
* @param {Token} leftToken The last token of the callee. This may be the closing parenthesis that encloses the callee.
|
||||
* @param {Token} rightToken Tha first token of the arguments. this is the opening parenthesis that encloses the arguments.
|
||||
* @returns {void}
|
||||
* @private
|
||||
*/
|
||||
function checkSpacing(node, leftToken, rightToken) {
|
||||
const textBetweenTokens = text
|
||||
.slice(leftToken.range[1], rightToken.range[0])
|
||||
.replace(/\/\*.*?\*\//gu, "");
|
||||
const hasWhitespace = /\s/u.test(textBetweenTokens);
|
||||
const hasNewline =
|
||||
hasWhitespace &&
|
||||
astUtils.LINEBREAK_MATCHER.test(textBetweenTokens);
|
||||
|
||||
/*
|
||||
* never allowNewlines hasWhitespace hasNewline message
|
||||
* F F F F Missing space between function name and paren.
|
||||
* F F F T (Invalid `!hasWhitespace && hasNewline`)
|
||||
* F F T T Unexpected newline between function name and paren.
|
||||
* F F T F (OK)
|
||||
* F T T F (OK)
|
||||
* F T T T (OK)
|
||||
* F T F T (Invalid `!hasWhitespace && hasNewline`)
|
||||
* F T F F Missing space between function name and paren.
|
||||
* T T F F (Invalid `never && allowNewlines`)
|
||||
* T T F T (Invalid `!hasWhitespace && hasNewline`)
|
||||
* T T T T (Invalid `never && allowNewlines`)
|
||||
* T T T F (Invalid `never && allowNewlines`)
|
||||
* T F T F Unexpected space between function name and paren.
|
||||
* T F T T Unexpected space between function name and paren.
|
||||
* T F F T (Invalid `!hasWhitespace && hasNewline`)
|
||||
* T F F F (OK)
|
||||
*
|
||||
* T T Unexpected space between function name and paren.
|
||||
* F F Missing space between function name and paren.
|
||||
* F F T Unexpected newline between function name and paren.
|
||||
*/
|
||||
|
||||
if (never && hasWhitespace) {
|
||||
context.report({
|
||||
node,
|
||||
loc: {
|
||||
start: leftToken.loc.end,
|
||||
end: {
|
||||
line: rightToken.loc.start.line,
|
||||
column: rightToken.loc.start.column - 1,
|
||||
},
|
||||
},
|
||||
messageId: "unexpectedWhitespace",
|
||||
fix(fixer) {
|
||||
// Don't remove comments.
|
||||
if (
|
||||
sourceCode.commentsExistBetween(
|
||||
leftToken,
|
||||
rightToken,
|
||||
)
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// If `?.` exists, it doesn't hide no-unexpected-multiline errors
|
||||
if (node.optional) {
|
||||
return fixer.replaceTextRange(
|
||||
[leftToken.range[1], rightToken.range[0]],
|
||||
"?.",
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* Only autofix if there is no newline
|
||||
* https://github.com/eslint/eslint/issues/7787
|
||||
*/
|
||||
if (hasNewline) {
|
||||
return null;
|
||||
}
|
||||
return fixer.removeRange([
|
||||
leftToken.range[1],
|
||||
rightToken.range[0],
|
||||
]);
|
||||
},
|
||||
});
|
||||
} else if (!never && !hasWhitespace) {
|
||||
context.report({
|
||||
node,
|
||||
loc: {
|
||||
start: {
|
||||
line: leftToken.loc.end.line,
|
||||
column: leftToken.loc.end.column - 1,
|
||||
},
|
||||
end: rightToken.loc.start,
|
||||
},
|
||||
messageId: "missing",
|
||||
fix(fixer) {
|
||||
if (node.optional) {
|
||||
return null; // Not sure if inserting a space to either before/after `?.` token.
|
||||
}
|
||||
return fixer.insertTextBefore(rightToken, " ");
|
||||
},
|
||||
});
|
||||
} else if (!never && !allowNewlines && hasNewline) {
|
||||
context.report({
|
||||
node,
|
||||
loc: {
|
||||
start: leftToken.loc.end,
|
||||
end: rightToken.loc.start,
|
||||
},
|
||||
messageId: "unexpectedNewline",
|
||||
fix(fixer) {
|
||||
/*
|
||||
* Only autofix if there is no newline
|
||||
* https://github.com/eslint/eslint/issues/7787
|
||||
* But if `?.` exists, it doesn't hide no-unexpected-multiline errors
|
||||
*/
|
||||
if (!node.optional) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Don't remove comments.
|
||||
if (
|
||||
sourceCode.commentsExistBetween(
|
||||
leftToken,
|
||||
rightToken,
|
||||
)
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const range = [leftToken.range[1], rightToken.range[0]];
|
||||
const qdToken = sourceCode.getTokenAfter(leftToken);
|
||||
|
||||
if (qdToken.range[0] === leftToken.range[1]) {
|
||||
return fixer.replaceTextRange(range, "?. ");
|
||||
}
|
||||
if (qdToken.range[1] === rightToken.range[0]) {
|
||||
return fixer.replaceTextRange(range, " ?.");
|
||||
}
|
||||
return fixer.replaceTextRange(range, " ?. ");
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
"CallExpression, NewExpression"(node) {
|
||||
const lastToken = sourceCode.getLastToken(node);
|
||||
const lastCalleeToken = sourceCode.getLastToken(node.callee);
|
||||
const parenToken = sourceCode.getFirstTokenBetween(
|
||||
lastCalleeToken,
|
||||
lastToken,
|
||||
astUtils.isOpeningParenToken,
|
||||
);
|
||||
const prevToken =
|
||||
parenToken &&
|
||||
sourceCode.getTokenBefore(
|
||||
parenToken,
|
||||
astUtils.isNotQuestionDotToken,
|
||||
);
|
||||
|
||||
// Parens in NewExpression are optional
|
||||
if (!(parenToken && parenToken.range[1] < node.range[1])) {
|
||||
return;
|
||||
}
|
||||
|
||||
checkSpacing(node, prevToken, parenToken);
|
||||
},
|
||||
|
||||
ImportExpression(node) {
|
||||
const leftToken = sourceCode.getFirstToken(node);
|
||||
const rightToken = sourceCode.getTokenAfter(leftToken);
|
||||
|
||||
checkSpacing(node, leftToken, rightToken);
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
338
slider/node_modules/eslint/lib/rules/func-name-matching.js
generated
vendored
Normal file
338
slider/node_modules/eslint/lib/rules/func-name-matching.js
generated
vendored
Normal file
@@ -0,0 +1,338 @@
|
||||
/**
|
||||
* @fileoverview Rule to require function names to match the name of the variable or property to which they are assigned.
|
||||
* @author Annie Zhang, Pavel Strashkin
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
const astUtils = require("./utils/ast-utils");
|
||||
const esutils = require("esutils");
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Determines if a pattern is `module.exports` or `module["exports"]`
|
||||
* @param {ASTNode} pattern The left side of the AssignmentExpression
|
||||
* @returns {boolean} True if the pattern is `module.exports` or `module["exports"]`
|
||||
*/
|
||||
function isModuleExports(pattern) {
|
||||
if (
|
||||
pattern.type === "MemberExpression" &&
|
||||
pattern.object.type === "Identifier" &&
|
||||
pattern.object.name === "module"
|
||||
) {
|
||||
// module.exports
|
||||
if (
|
||||
pattern.property.type === "Identifier" &&
|
||||
pattern.property.name === "exports"
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// module["exports"]
|
||||
if (
|
||||
pattern.property.type === "Literal" &&
|
||||
pattern.property.value === "exports"
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if a string name is a valid identifier
|
||||
* @param {string} name The string to be checked
|
||||
* @param {number} ecmaVersion The ECMAScript version if specified in the parserOptions config
|
||||
* @returns {boolean} True if the string is a valid identifier
|
||||
*/
|
||||
function isIdentifier(name, ecmaVersion) {
|
||||
if (ecmaVersion >= 2015) {
|
||||
return esutils.keyword.isIdentifierES6(name);
|
||||
}
|
||||
return esutils.keyword.isIdentifierES5(name);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const alwaysOrNever = { enum: ["always", "never"] };
|
||||
const optionsObject = {
|
||||
type: "object",
|
||||
properties: {
|
||||
considerPropertyDescriptor: {
|
||||
type: "boolean",
|
||||
},
|
||||
includeCommonJSModuleExports: {
|
||||
type: "boolean",
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
};
|
||||
|
||||
/** @type {import('../types').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
|
||||
docs: {
|
||||
description:
|
||||
"Require function names to match the name of the variable or property to which they are assigned",
|
||||
recommended: false,
|
||||
frozen: true,
|
||||
url: "https://eslint.org/docs/latest/rules/func-name-matching",
|
||||
},
|
||||
|
||||
schema: {
|
||||
anyOf: [
|
||||
{
|
||||
type: "array",
|
||||
additionalItems: false,
|
||||
items: [alwaysOrNever, optionsObject],
|
||||
},
|
||||
{
|
||||
type: "array",
|
||||
additionalItems: false,
|
||||
items: [optionsObject],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
messages: {
|
||||
matchProperty:
|
||||
"Function name `{{funcName}}` should match property name `{{name}}`.",
|
||||
matchVariable:
|
||||
"Function name `{{funcName}}` should match variable name `{{name}}`.",
|
||||
notMatchProperty:
|
||||
"Function name `{{funcName}}` should not match property name `{{name}}`.",
|
||||
notMatchVariable:
|
||||
"Function name `{{funcName}}` should not match variable name `{{name}}`.",
|
||||
},
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const options =
|
||||
(typeof context.options[0] === "object"
|
||||
? context.options[0]
|
||||
: context.options[1]) || {};
|
||||
const nameMatches =
|
||||
typeof context.options[0] === "string"
|
||||
? context.options[0]
|
||||
: "always";
|
||||
const considerPropertyDescriptor = options.considerPropertyDescriptor;
|
||||
const includeModuleExports = options.includeCommonJSModuleExports;
|
||||
const ecmaVersion = context.languageOptions.ecmaVersion;
|
||||
|
||||
/**
|
||||
* Check whether node is a certain CallExpression.
|
||||
* @param {string} objName object name
|
||||
* @param {string} funcName function name
|
||||
* @param {ASTNode} node The node to check
|
||||
* @returns {boolean} `true` if node matches CallExpression
|
||||
*/
|
||||
function isPropertyCall(objName, funcName, node) {
|
||||
if (!node) {
|
||||
return false;
|
||||
}
|
||||
return (
|
||||
node.type === "CallExpression" &&
|
||||
astUtils.isSpecificMemberAccess(node.callee, objName, funcName)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares identifiers based on the nameMatches option
|
||||
* @param {string} x the first identifier
|
||||
* @param {string} y the second identifier
|
||||
* @returns {boolean} whether the two identifiers should warn.
|
||||
*/
|
||||
function shouldWarn(x, y) {
|
||||
return (
|
||||
(nameMatches === "always" && x !== y) ||
|
||||
(nameMatches === "never" && x === y)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports
|
||||
* @param {ASTNode} node The node to report
|
||||
* @param {string} name The variable or property name
|
||||
* @param {string} funcName The function name
|
||||
* @param {boolean} isProp True if the reported node is a property assignment
|
||||
* @returns {void}
|
||||
*/
|
||||
function report(node, name, funcName, isProp) {
|
||||
let messageId;
|
||||
|
||||
if (nameMatches === "always" && isProp) {
|
||||
messageId = "matchProperty";
|
||||
} else if (nameMatches === "always") {
|
||||
messageId = "matchVariable";
|
||||
} else if (isProp) {
|
||||
messageId = "notMatchProperty";
|
||||
} else {
|
||||
messageId = "notMatchVariable";
|
||||
}
|
||||
context.report({
|
||||
node,
|
||||
messageId,
|
||||
data: {
|
||||
name,
|
||||
funcName,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether a given node is a string literal
|
||||
* @param {ASTNode} node The node to check
|
||||
* @returns {boolean} `true` if the node is a string literal
|
||||
*/
|
||||
function isStringLiteral(node) {
|
||||
return node.type === "Literal" && typeof node.value === "string";
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Public
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
return {
|
||||
VariableDeclarator(node) {
|
||||
if (
|
||||
!node.init ||
|
||||
node.init.type !== "FunctionExpression" ||
|
||||
node.id.type !== "Identifier"
|
||||
) {
|
||||
return;
|
||||
}
|
||||
if (
|
||||
node.init.id &&
|
||||
shouldWarn(node.id.name, node.init.id.name)
|
||||
) {
|
||||
report(node, node.id.name, node.init.id.name, false);
|
||||
}
|
||||
},
|
||||
|
||||
AssignmentExpression(node) {
|
||||
if (
|
||||
node.right.type !== "FunctionExpression" ||
|
||||
(node.left.computed &&
|
||||
node.left.property.type !== "Literal") ||
|
||||
(!includeModuleExports && isModuleExports(node.left)) ||
|
||||
(node.left.type !== "Identifier" &&
|
||||
node.left.type !== "MemberExpression")
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const isProp = node.left.type === "MemberExpression";
|
||||
const name = isProp
|
||||
? astUtils.getStaticPropertyName(node.left)
|
||||
: node.left.name;
|
||||
|
||||
if (
|
||||
node.right.id &&
|
||||
name &&
|
||||
isIdentifier(name) &&
|
||||
shouldWarn(name, node.right.id.name)
|
||||
) {
|
||||
report(node, name, node.right.id.name, isProp);
|
||||
}
|
||||
},
|
||||
|
||||
"Property, PropertyDefinition[value]"(node) {
|
||||
if (
|
||||
!(node.value.type === "FunctionExpression" && node.value.id)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (node.key.type === "Identifier" && !node.computed) {
|
||||
const functionName = node.value.id.name;
|
||||
let propertyName = node.key.name;
|
||||
|
||||
if (
|
||||
considerPropertyDescriptor &&
|
||||
propertyName === "value" &&
|
||||
node.parent.type === "ObjectExpression"
|
||||
) {
|
||||
if (
|
||||
isPropertyCall(
|
||||
"Object",
|
||||
"defineProperty",
|
||||
node.parent.parent,
|
||||
) ||
|
||||
isPropertyCall(
|
||||
"Reflect",
|
||||
"defineProperty",
|
||||
node.parent.parent,
|
||||
)
|
||||
) {
|
||||
const property = node.parent.parent.arguments[1];
|
||||
|
||||
if (
|
||||
isStringLiteral(property) &&
|
||||
shouldWarn(property.value, functionName)
|
||||
) {
|
||||
report(
|
||||
node,
|
||||
property.value,
|
||||
functionName,
|
||||
true,
|
||||
);
|
||||
}
|
||||
} else if (
|
||||
isPropertyCall(
|
||||
"Object",
|
||||
"defineProperties",
|
||||
node.parent.parent.parent.parent,
|
||||
)
|
||||
) {
|
||||
propertyName = node.parent.parent.key.name;
|
||||
if (
|
||||
!node.parent.parent.computed &&
|
||||
shouldWarn(propertyName, functionName)
|
||||
) {
|
||||
report(node, propertyName, functionName, true);
|
||||
}
|
||||
} else if (
|
||||
isPropertyCall(
|
||||
"Object",
|
||||
"create",
|
||||
node.parent.parent.parent.parent,
|
||||
)
|
||||
) {
|
||||
propertyName = node.parent.parent.key.name;
|
||||
if (
|
||||
!node.parent.parent.computed &&
|
||||
shouldWarn(propertyName, functionName)
|
||||
) {
|
||||
report(node, propertyName, functionName, true);
|
||||
}
|
||||
} else if (shouldWarn(propertyName, functionName)) {
|
||||
report(node, propertyName, functionName, true);
|
||||
}
|
||||
} else if (shouldWarn(propertyName, functionName)) {
|
||||
report(node, propertyName, functionName, true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
isStringLiteral(node.key) &&
|
||||
isIdentifier(node.key.value, ecmaVersion) &&
|
||||
shouldWarn(node.key.value, node.value.id.name)
|
||||
) {
|
||||
report(node, node.key.value, node.value.id.name, true);
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
192
slider/node_modules/eslint/lib/rules/func-names.js
generated
vendored
Normal file
192
slider/node_modules/eslint/lib/rules/func-names.js
generated
vendored
Normal file
@@ -0,0 +1,192 @@
|
||||
/**
|
||||
* @fileoverview Rule to warn when a function expression does not have a name.
|
||||
* @author Kyle T. Nunery
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const astUtils = require("./utils/ast-utils");
|
||||
|
||||
/**
|
||||
* Checks whether or not a given variable is a function name.
|
||||
* @param {eslint-scope.Variable} variable A variable to check.
|
||||
* @returns {boolean} `true` if the variable is a function name.
|
||||
*/
|
||||
function isFunctionName(variable) {
|
||||
return variable && variable.defs[0].type === "FunctionName";
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../types').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
|
||||
defaultOptions: ["always", {}],
|
||||
|
||||
docs: {
|
||||
description: "Require or disallow named `function` expressions",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/latest/rules/func-names",
|
||||
},
|
||||
|
||||
schema: {
|
||||
definitions: {
|
||||
value: {
|
||||
enum: ["always", "as-needed", "never"],
|
||||
},
|
||||
},
|
||||
items: [
|
||||
{
|
||||
$ref: "#/definitions/value",
|
||||
},
|
||||
{
|
||||
type: "object",
|
||||
properties: {
|
||||
generators: {
|
||||
$ref: "#/definitions/value",
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
messages: {
|
||||
unnamed: "Unexpected unnamed {{name}}.",
|
||||
named: "Unexpected named {{name}}.",
|
||||
},
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const sourceCode = context.sourceCode;
|
||||
|
||||
/**
|
||||
* Returns the config option for the given node.
|
||||
* @param {ASTNode} node A node to get the config for.
|
||||
* @returns {string} The config option.
|
||||
*/
|
||||
function getConfigForNode(node) {
|
||||
if (node.generator && context.options[1].generators) {
|
||||
return context.options[1].generators;
|
||||
}
|
||||
|
||||
return context.options[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the current FunctionExpression node is a get, set, or
|
||||
* shorthand method in an object literal or a class.
|
||||
* @param {ASTNode} node A node to check.
|
||||
* @returns {boolean} True if the node is a get, set, or shorthand method.
|
||||
*/
|
||||
function isObjectOrClassMethod(node) {
|
||||
const parent = node.parent;
|
||||
|
||||
return (
|
||||
parent.type === "MethodDefinition" ||
|
||||
(parent.type === "Property" &&
|
||||
(parent.method ||
|
||||
parent.kind === "get" ||
|
||||
parent.kind === "set"))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the current FunctionExpression node has a name that would be
|
||||
* inferred from context in a conforming ES6 environment.
|
||||
* @param {ASTNode} node A node to check.
|
||||
* @returns {boolean} True if the node would have a name assigned automatically.
|
||||
*/
|
||||
function hasInferredName(node) {
|
||||
const parent = node.parent;
|
||||
|
||||
return (
|
||||
isObjectOrClassMethod(node) ||
|
||||
(parent.type === "VariableDeclarator" &&
|
||||
parent.id.type === "Identifier" &&
|
||||
parent.init === node) ||
|
||||
(parent.type === "Property" && parent.value === node) ||
|
||||
(parent.type === "PropertyDefinition" &&
|
||||
parent.value === node) ||
|
||||
(parent.type === "AssignmentExpression" &&
|
||||
parent.left.type === "Identifier" &&
|
||||
parent.right === node) ||
|
||||
(parent.type === "AssignmentPattern" &&
|
||||
parent.left.type === "Identifier" &&
|
||||
parent.right === node)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports that an unnamed function should be named
|
||||
* @param {ASTNode} node The node to report in the event of an error.
|
||||
* @returns {void}
|
||||
*/
|
||||
function reportUnexpectedUnnamedFunction(node) {
|
||||
context.report({
|
||||
node,
|
||||
messageId: "unnamed",
|
||||
loc: astUtils.getFunctionHeadLoc(node, sourceCode),
|
||||
data: { name: astUtils.getFunctionNameWithKind(node) },
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports that a named function should be unnamed
|
||||
* @param {ASTNode} node The node to report in the event of an error.
|
||||
* @returns {void}
|
||||
*/
|
||||
function reportUnexpectedNamedFunction(node) {
|
||||
context.report({
|
||||
node,
|
||||
messageId: "named",
|
||||
loc: astUtils.getFunctionHeadLoc(node, sourceCode),
|
||||
data: { name: astUtils.getFunctionNameWithKind(node) },
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* The listener for function nodes.
|
||||
* @param {ASTNode} node function node
|
||||
* @returns {void}
|
||||
*/
|
||||
function handleFunction(node) {
|
||||
// Skip recursive functions.
|
||||
const nameVar = sourceCode.getDeclaredVariables(node)[0];
|
||||
|
||||
if (isFunctionName(nameVar) && nameVar.references.length > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const hasName = Boolean(node.id && node.id.name);
|
||||
const config = getConfigForNode(node);
|
||||
|
||||
if (config === "never") {
|
||||
if (hasName && node.type !== "FunctionDeclaration") {
|
||||
reportUnexpectedNamedFunction(node);
|
||||
}
|
||||
} else if (config === "as-needed") {
|
||||
if (!hasName && !hasInferredName(node)) {
|
||||
reportUnexpectedUnnamedFunction(node);
|
||||
}
|
||||
} else {
|
||||
if (!hasName && !isObjectOrClassMethod(node)) {
|
||||
reportUnexpectedUnnamedFunction(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
"FunctionExpression:exit": handleFunction,
|
||||
"ExportDefaultDeclaration > FunctionDeclaration": handleFunction,
|
||||
};
|
||||
},
|
||||
};
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user