function CLIEngine(options) {
options = Object.assign(
Object.create(null),
defaultOptions,
{ cwd: process.cwd() },
options
);
/**
* Stored options for this instance
* @type {Object}
*/
this.options = options;
const cacheFile = getCacheFile(this.options.cacheLocation || this.options.cacheFile, this.options.cwd);
/**
* Cache used to avoid operating on files that haven't changed since the
* last successful execution (e.g., file passed linting with no errors and
* no warnings).
* @type {Object}
*/
this._fileCache = fileEntryCache.create(cacheFile);
// load in additional rules
if (this.options.rulePaths) {
const cwd = this.options.cwd;
this.options.rulePaths.forEach(rulesdir => {
debug(`Loading rules from ${rulesdir}`);
rules.load(rulesdir, cwd);
});
}
Object.keys(this.options.rules || {}).forEach(name => {
validator.validateRuleOptions(name, this.options.rules[name], "CLI");
});
}
n/a
function RuleTester(testerConfig) {
/**
* The configuration to use for this tester. Combination of the tester
* configuration and the default configuration.
* @type {Object}
*/
this.testerConfig = lodash.merge(
// we have to clone because merge uses the first argument for recipient
lodash.cloneDeep(defaultConfig),
testerConfig
);
/**
* Rule definitions to define before tests.
* @type {Object}
*/
this.rules = {};
}
n/a
function SourceCode(text, ast) {
validate(ast);
/**
* The flag to indicate that the source code has Unicode BOM.
* @type boolean
*/
this.hasBOM = (text.charCodeAt(0) === 0xFEFF);
/**
* The original text source code.
* BOM was stripped from this text.
* @type string
*/
this.text = (this.hasBOM ? text.slice(1) : text);
/**
* The parsed AST for the source code.
* @type ASTNode
*/
this.ast = ast;
/**
* The source code split into lines according to ECMA-262 specification.
* This is done to avoid each rule needing to do so separately.
* @type string[]
*/
this.lines = [];
this.lineStartIndices = [0];
const lineEndingPattern = astUtils.createGlobalLinebreakMatcher();
let match;
/*
* Previously, this was implemented using a regex that
* matched a sequence of non-linebreak characters followed by a
* linebreak, then adding the lengths of the matches. However,
* this caused a catastrophic backtracking issue when the end
* of a file contained a large number of non-newline characters.
* To avoid this, the current implementation just matches newlines
* and uses match.index to get the correct line start indices.
*/
while ((match = lineEndingPattern.exec(this.text))) {
this.lines.push(this.text.slice(this.lineStartIndices[this.lineStartIndices.length - 1], match.index));
this.lineStartIndices.push(match.index + match[0].length);
}
this.lines.push(this.text.slice(this.lineStartIndices[this.lineStartIndices.length - 1]));
this.tokensAndComments = sortedMerge(ast.tokens, ast.comments);
// create token store methods
const tokenStore = new TokenStore(ast.tokens, ast.comments);
for (const methodName of TokenStore.PUBLIC_METHODS) {
this[methodName] = tokenStore[methodName].bind(tokenStore);
}
// don't allow modification of this object
Object.freeze(this);
Object.freeze(this.lines);
}
n/a
class RuleContext {
/**
* @param {string} ruleId The ID of the rule using this object.
* @param {eslint} eslint The eslint object.
* @param {number} severity The configured severity level of the rule.
* @param {Array} options The configuration information to be added to the rule.
* @param {Object} settings The configuration settings passed from the config file.
* @param {Object} parserOptions The parserOptions settings passed from the config file.
* @param {Object} parserPath The parser setting passed from the config file.
* @param {Object} meta The metadata of the rule
* @param {Object} parserServices The parser services for the rule.
*/
constructor(ruleId, eslint, severity, options, settings, parserOptions, parserPath, meta, parserServices) {
// public.
this.id = ruleId;
this.options = options;
this.settings = settings;
this.parserOptions = parserOptions;
this.parserPath = parserPath;
this.meta = meta;
// create a separate copy and freeze it (it's not nice to freeze other people's objects)
this.parserServices = Object.freeze(Object.assign({}, parserServices));
// private.
this.eslint = eslint;
this.severity = severity;
Object.freeze(this);
}
/**
* Passthrough to eslint.getSourceCode().
* @returns {SourceCode} The SourceCode object for the code.
*/
getSourceCode() {
return this.eslint.getSourceCode();
}
/**
* Passthrough to eslint.report() that automatically assigns the rule ID and severity.
* @param {ASTNode|MessageDescriptor} nodeOrDescriptor The AST node related to the message or a message
* descriptor.
* @param {Object=} location The location of the error.
* @param {string} message The message to display to the user.
* @param {Object} opts Optional template data which produces a formatted message
* with symbols being replaced by this object's values.
* @returns {void}
*/
report(nodeOrDescriptor, location, message, opts) {
// check to see if it's a new style call
if (arguments.length === 1) {
const descriptor = nodeOrDescriptor;
let fix = null;
// if there's a fix specified, get it
if (typeof descriptor.fix === "function") {
fix = descriptor.fix(ruleFixer);
}
this.eslint.report(
this.id,
this.severity,
descriptor.node,
descriptor.loc || descriptor.node.loc.start,
descriptor.message,
descriptor.data,
fix,
this.meta
);
return;
}
// old style call
this.eslint.report(
this.id,
this.severity,
nodeOrDescriptor,
location,
message,
opts,
this.meta
);
}
}
n/a
function CLIEngine(options) {
options = Object.assign(
Object.create(null),
defaultOptions,
{ cwd: process.cwd() },
options
);
/**
* Stored options for this instance
* @type {Object}
*/
this.options = options;
const cacheFile = getCacheFile(this.options.cacheLocation || this.options.cacheFile, this.options.cwd);
/**
* Cache used to avoid operating on files that haven't changed since the
* last successful execution (e.g., file passed linting with no errors and
* no warnings).
* @type {Object}
*/
this._fileCache = fileEntryCache.create(cacheFile);
// load in additional rules
if (this.options.rulePaths) {
const cwd = this.options.cwd;
this.options.rulePaths.forEach(rulesdir => {
debug(`Loading rules from ${rulesdir}`);
rules.load(rulesdir, cwd);
});
}
Object.keys(this.options.rules || {}).forEach(name => {
validator.validateRuleOptions(name, this.options.rules[name], "CLI");
});
}
n/a
getErrorResults = function (results) { const filtered = []; results.forEach(result => { const filteredMessages = result.messages.filter(isErrorMessage); if (filteredMessages.length > 0) { filtered.push( Object.assign(result, { messages: filteredMessages, errorCount: filteredMessages.length, warningCount: 0 }) ); } }); return filtered; }
n/a
getFormatter = function (format) { let formatterPath; // default is stylish format = format || "stylish"; // only strings are valid formatters if (typeof format === "string") { // replace \ with / for Windows compatibility format = format.replace(/\\/g, "/"); // if there's a slash, then it's a file if (format.indexOf("/") > -1) { const cwd = this.options ? this.options.cwd : process.cwd(); formatterPath = path.resolve(cwd, format); } else { formatterPath = `./formatters/${format}`; } try { return require(formatterPath); } catch (ex) { ex.message = `There was a problem loading formatter: ${formatterPath}\nError: ${ex.message}`; throw ex; } } else { return null; } }
n/a
outputFixes = function (report) { report.results.filter(result => result.hasOwnProperty("output")).forEach(result => { fs.writeFileSync(result.filePath, result.output); }); }
n/a
addPlugin(name, pluginobject) { Plugins.define(name, pluginobject); }
n/a
function CLIEngine(options) {
options = Object.assign(
Object.create(null),
defaultOptions,
{ cwd: process.cwd() },
options
);
/**
* Stored options for this instance
* @type {Object}
*/
this.options = options;
const cacheFile = getCacheFile(this.options.cacheLocation || this.options.cacheFile, this.options.cwd);
/**
* Cache used to avoid operating on files that haven't changed since the
* last successful execution (e.g., file passed linting with no errors and
* no warnings).
* @type {Object}
*/
this._fileCache = fileEntryCache.create(cacheFile);
// load in additional rules
if (this.options.rulePaths) {
const cwd = this.options.cwd;
this.options.rulePaths.forEach(rulesdir => {
debug(`Loading rules from ${rulesdir}`);
rules.load(rulesdir, cwd);
});
}
Object.keys(this.options.rules || {}).forEach(name => {
validator.validateRuleOptions(name, this.options.rules[name], "CLI");
});
}
n/a
executeOnFiles(patterns) {
const results = [],
options = this.options,
fileCache = this._fileCache,
configHelper = new Config(options);
let prevConfig; // the previous configuration used
/**
* Calculates the hash of the config file used to validate a given file
* @param {string} filename The path of the file to retrieve a config object for to calculate the hash
* @returns {string} the hash of the config
*/
function hashOfConfigFor(filename) {
const config = configHelper.getConfig(filename);
if (!prevConfig) {
prevConfig = {};
}
// reuse the previously hashed config if the config hasn't changed
if (prevConfig.config !== config) {
/*
* config changed so we need to calculate the hash of the config
* and the hash of the plugins being used
*/
prevConfig.config = config;
const eslintVersion = pkg.version;
prevConfig.hash = hash(`${eslintVersion}_${stringify(config)}`);
}
return prevConfig.hash;
}
/**
* Executes the linter on a file defined by the `filename`. Skips
* unsupported file extensions and any files that are already linted.
* @param {string} filename The resolved filename of the file to be linted
* @param {boolean} warnIgnored always warn when a file is ignored
* @returns {void}
*/
function executeOnFile(filename, warnIgnored) {
let hashOfConfig,
descriptor;
if (warnIgnored) {
results.push(createIgnoreResult(filename, options.cwd));
return;
}
if (options.cache) {
/*
* get the descriptor for this file
* with the metadata and the flag that determines if
* the file has changed
*/
descriptor = fileCache.getFileDescriptor(filename);
const meta = descriptor.meta || {};
hashOfConfig = hashOfConfigFor(filename);
const changed = descriptor.changed || meta.hashOfConfig !== hashOfConfig;
if (!changed) {
debug(`Skipping file since hasn't changed: ${filename}`);
/*
* Add the the cached results (always will be 0 error and
* 0 warnings). We should not cache results for files that
* failed, in order to guarantee that next execution will
* process those files as well.
*/
results.push(descriptor.meta.results);
// move to the next file
return;
}
} else {
fileCache.destroy();
}
debug(`Processing ${filename}`);
const res = processFile(filename, configHelper, options);
if (options.cache) {
/*
* if a file contains errors or warnings we don't want to
* store the file in the cache so we can guarantee that
* next execution will also operate on this file
*/
if (res.errorCount > 0 || res.warningCount > 0) {
debug(`File has problems, skipping it: ${filename}`);
// remove the entry from the cache
fileCache.removeEntry(filename);
} else {
/*
* since the file passed we store the result here
* TODO: check this as we might not need to store the
* successful runs as it will always should be 0 errors and
* 0 warnings.
*/
descriptor.meta.hashOfConfig = hashOfConfig;
descriptor.meta.results = res;
}
}
results.push(res);
}
const startTime = Date.now();
patterns = this.resolveFileGlobPatterns(patterns);
const fileList = globUtil.listFilesToProcess(patterns, options);
fileList.forEach(fileInfo => {
executeOnFile(fileInfo.filename, fileInfo ...
n/a
executeOnText(text, filename, warnIgnored) { const results = [], options = this.options, configHelper = new Config(options), ignoredPaths = new IgnoredPaths(options); // resolve filename based on options.cwd (for reporting, ignoredPaths also resolves) if (filename && !path.isAbsolute(filename)) { filename = path.resolve(options.cwd, filename); } if (filename && ignoredPaths.contains(filename)) { if (warnIgnored) { results.push(createIgnoreResult(filename, options.cwd)); } } else { results.push(processText(text, configHelper, filename, options.fix, options.allowInlineConfig)); } const stats = calculateStatsPerRun(results); return { results, errorCount: stats.errorCount, warningCount: stats.warningCount }; }
n/a
getConfigForFile(filePath) { const configHelper = new Config(this.options); return configHelper.getConfig(filePath); }
n/a
getFormatter = function (format) { let formatterPath; // default is stylish format = format || "stylish"; // only strings are valid formatters if (typeof format === "string") { // replace \ with / for Windows compatibility format = format.replace(/\\/g, "/"); // if there's a slash, then it's a file if (format.indexOf("/") > -1) { const cwd = this.options ? this.options.cwd : process.cwd(); formatterPath = path.resolve(cwd, format); } else { formatterPath = `./formatters/${format}`; } try { return require(formatterPath); } catch (ex) { ex.message = `There was a problem loading formatter: ${formatterPath}\nError: ${ex.message}`; throw ex; } } else { return null; } }
n/a
isPathIgnored(filePath) { const resolvedPath = path.resolve(this.options.cwd, filePath); const ignoredPaths = new IgnoredPaths(this.options); return ignoredPaths.contains(resolvedPath); }
n/a
resolveFileGlobPatterns(patterns) { return globUtil.resolveFileGlobPatterns(patterns, this.options); }
n/a
function RuleTester(testerConfig) {
/**
* The configuration to use for this tester. Combination of the tester
* configuration and the default configuration.
* @type {Object}
*/
this.testerConfig = lodash.merge(
// we have to clone because merge uses the first argument for recipient
lodash.cloneDeep(defaultConfig),
testerConfig
);
/**
* Rule definitions to define before tests.
* @type {Object}
*/
this.rules = {};
}
n/a
function defaultHandler(text, method) { return method.apply(this); }
n/a
getDefaultConfig = function () { return defaultConfig; }
n/a
function defaultHandler(text, method) { return method.apply(this); }
n/a
resetDefaultConfig = function () { defaultConfig = lodash.cloneDeep(testerDefaultConfig); }
n/a
setDefaultConfig = function (config) { if (typeof config !== "object") { throw new Error("RuleTester.setDefaultConfig: config must be an object"); } defaultConfig = config; // Make sure the rules object exists since it is assumed to exist later defaultConfig.rules = defaultConfig.rules || {}; }
n/a
defineRule(name, rule) { this.rules[name] = rule; }
n/a
run(ruleName, rule, test) {
const testerConfig = this.testerConfig,
requiredScenarios = ["valid", "invalid"],
scenarioErrors = [],
result = {};
if (lodash.isNil(test) || typeof test !== "object") {
throw new Error(`Test Scenarios for rule ${ruleName} : Could not find test scenario object`);
}
requiredScenarios.forEach(scenarioType => {
if (lodash.isNil(test[scenarioType])) {
scenarioErrors.push(`Could not find any ${scenarioType} test scenarios`);
}
});
if (scenarioErrors.length > 0) {
throw new Error([
`Test Scenarios for rule ${ruleName} is invalid:`
].concat(scenarioErrors).join("\n"));
}
/* eslint-disable no-shadow */
/**
* Run the rule for the given item
* @param {string} ruleName name of the rule
* @param {string|Object} item Item to run the rule against
* @returns {Object} Eslint run result
* @private
*/
function runRuleForItem(ruleName, item) {
let config = lodash.cloneDeep(testerConfig),
code, filename, beforeAST, afterAST;
if (typeof item === "string") {
code = item;
} else {
code = item.code;
// Assumes everything on the item is a config except for the
// parameters used by this tester
const itemConfig = lodash.omit(item, RuleTesterParameters);
// Create the config object from the tester config and this item
// specific configurations.
config = lodash.merge(
config,
itemConfig
);
}
if (item.filename) {
filename = item.filename;
}
if (item.options) {
const options = item.options.concat();
options.unshift(1);
config.rules[ruleName] = options;
} else {
config.rules[ruleName] = 1;
}
eslint.defineRule(ruleName, rule);
const schema = validator.getRuleOptionsSchema(ruleName);
if (schema) {
validateSchema(schema);
if (validateSchema.errors) {
throw new Error([
`Schema for rule ${ruleName} is invalid:`
].concat(validateSchema.errors.map(error => `\t${error.field}: ${error.message}`)).join("\n"));
}
}
validator.validate(config, "rule-tester");
/*
* Setup AST getters.
* The goal is to check whether or not AST was modified when
* running the rule under test.
*/
eslint.reset();
eslint.on("Program", node => {
beforeAST = cloneDeeplyExcludesParent(node);
});
eslint.on("Program:exit", node => {
afterAST = node;
});
// Freezes rule-context properties.
const originalGet = rules.get;
try {
rules.get = function(ruleId) {
const rule = originalGet(ruleId);
if (typeof rule === "function") {
return function(context) {
Object.freeze(context);
freezeDeeply(context.options);
freezeDeeply(context.settings);
freezeDeeply(context.parserOptions);
return rule(context);
};
}
return {
meta: rule.meta,
create(context) {
Object.freeze(context);
freezeDeeply(context.options);
freezeDeeply(context.settings);
freezeDeeply(context.parserOptions);
return rule.create(context);
}
};
};
return {
messages: eslint.verify(code, config, filename, true),
beforeAST,
afterAST: cloneDeeplyExcludesParent(afterAST)
};
} finally { ...
n/a
function SourceCode(text, ast) {
validate(ast);
/**
* The flag to indicate that the source code has Unicode BOM.
* @type boolean
*/
this.hasBOM = (text.charCodeAt(0) === 0xFEFF);
/**
* The original text source code.
* BOM was stripped from this text.
* @type string
*/
this.text = (this.hasBOM ? text.slice(1) : text);
/**
* The parsed AST for the source code.
* @type ASTNode
*/
this.ast = ast;
/**
* The source code split into lines according to ECMA-262 specification.
* This is done to avoid each rule needing to do so separately.
* @type string[]
*/
this.lines = [];
this.lineStartIndices = [0];
const lineEndingPattern = astUtils.createGlobalLinebreakMatcher();
let match;
/*
* Previously, this was implemented using a regex that
* matched a sequence of non-linebreak characters followed by a
* linebreak, then adding the lengths of the matches. However,
* this caused a catastrophic backtracking issue when the end
* of a file contained a large number of non-newline characters.
* To avoid this, the current implementation just matches newlines
* and uses match.index to get the correct line start indices.
*/
while ((match = lineEndingPattern.exec(this.text))) {
this.lines.push(this.text.slice(this.lineStartIndices[this.lineStartIndices.length - 1], match.index));
this.lineStartIndices.push(match.index + match[0].length);
}
this.lines.push(this.text.slice(this.lineStartIndices[this.lineStartIndices.length - 1]));
this.tokensAndComments = sortedMerge(ast.tokens, ast.comments);
// create token store methods
const tokenStore = new TokenStore(ast.tokens, ast.comments);
for (const methodName of TokenStore.PUBLIC_METHODS) {
this[methodName] = tokenStore[methodName].bind(tokenStore);
}
// don't allow modification of this object
Object.freeze(this);
Object.freeze(this.lines);
}
n/a
splitLines = function (text) { return text.split(astUtils.createGlobalLinebreakMatcher()); }
n/a
function SourceCode(text, ast) {
validate(ast);
/**
* The flag to indicate that the source code has Unicode BOM.
* @type boolean
*/
this.hasBOM = (text.charCodeAt(0) === 0xFEFF);
/**
* The original text source code.
* BOM was stripped from this text.
* @type string
*/
this.text = (this.hasBOM ? text.slice(1) : text);
/**
* The parsed AST for the source code.
* @type ASTNode
*/
this.ast = ast;
/**
* The source code split into lines according to ECMA-262 specification.
* This is done to avoid each rule needing to do so separately.
* @type string[]
*/
this.lines = [];
this.lineStartIndices = [0];
const lineEndingPattern = astUtils.createGlobalLinebreakMatcher();
let match;
/*
* Previously, this was implemented using a regex that
* matched a sequence of non-linebreak characters followed by a
* linebreak, then adding the lengths of the matches. However,
* this caused a catastrophic backtracking issue when the end
* of a file contained a large number of non-newline characters.
* To avoid this, the current implementation just matches newlines
* and uses match.index to get the correct line start indices.
*/
while ((match = lineEndingPattern.exec(this.text))) {
this.lines.push(this.text.slice(this.lineStartIndices[this.lineStartIndices.length - 1], match.index));
this.lineStartIndices.push(match.index + match[0].length);
}
this.lines.push(this.text.slice(this.lineStartIndices[this.lineStartIndices.length - 1]));
this.tokensAndComments = sortedMerge(ast.tokens, ast.comments);
// create token store methods
const tokenStore = new TokenStore(ast.tokens, ast.comments);
for (const methodName of TokenStore.PUBLIC_METHODS) {
this[methodName] = tokenStore[methodName].bind(tokenStore);
}
// don't allow modification of this object
Object.freeze(this);
Object.freeze(this.lines);
}
n/a
getAllComments() { return this.ast.comments; }
n/a
getComments(node) {
let leadingComments = node.leadingComments || [];
const trailingComments = node.trailingComments || [];
/*
* espree adds a "comments" array on Program nodes rather than
* leadingComments/trailingComments. Comments are only left in the
* Program node comments array if there is no executable code.
*/
if (node.type === "Program") {
if (node.body.length === 0) {
leadingComments = node.comments;
}
}
return {
leading: leadingComments,
trailing: trailingComments
};
}
...
return true;
}
// Checks `@this` in its leading comments for callbacks,
// because callbacks don't have its JSDoc comment.
// e.g.
// sinon.test(/* @this sinon.Sandbox */function() { this.spy(); });
return sourceCode.getComments(node).leading.some(comment => thisTagPattern.test
(comment.value));
}
/**
* Determines if a node is surrounded by parentheses.
* @param {SourceCode} sourceCode The ESLint source code object
* @param {ASTNode} node The node to be checked.
* @returns {boolean} True if the node is parenthesised.
...
getIndexFromLoc(loc) {
if (typeof loc !== "object" || typeof loc.line !== "number" || typeof loc.column !== "number") {
throw new TypeError("Expected `loc` to be an object with numeric `line` and `column` properties.");
}
if (loc.line <= 0) {
throw new RangeError(`Line number out of range (line ${loc.line} requested). Line numbers should be 1-based.`);
}
if (loc.line > this.lineStartIndices.length) {
throw new RangeError(`Line number out of range (line ${loc.line} requested, but only ${this.lineStartIndices.length} lines
present).`);
}
const lineStartIndex = this.lineStartIndices[loc.line - 1];
const lineEndIndex = loc.line === this.lineStartIndices.length ? this.text.length : this.lineStartIndices[loc.line];
const positionIndex = lineStartIndex + loc.column;
/*
* By design, getIndexFromLoc({ line: lineNum, column: 0 }) should return the start index of
* the given line, provided that the line number is valid element of this.lines. Since the
* last element of this.lines is an empty string for files with trailing newlines, add a
* special case where getting the index for the first location after the end of the file
* will return the length of the file, rather than throwing an error. This allows rules to
* use getIndexFromLoc consistently without worrying about edge cases at the end of a file.
*/
if (
loc.line === this.lineStartIndices.length && positionIndex > lineEndIndex ||
loc.line < this.lineStartIndices.length && positionIndex >= lineEndIndex
) {
throw new RangeError(`Column number out of range (column ${loc.column} requested, but the length of line ${loc.line} is ${
lineEndIndex - lineStartIndex}).`);
}
return positionIndex;
}
n/a
getJSDocComment(node) { let parent = node.parent; switch (node.type) { case "ClassDeclaration": case "FunctionDeclaration": if (looksLikeExport(parent)) { return findJSDocComment(parent.leadingComments, parent.loc.start.line); } return findJSDocComment(node.leadingComments, node.loc.start.line); case "ClassExpression": return findJSDocComment(parent.parent.leadingComments, parent.parent.loc.start.line); case "ArrowFunctionExpression": case "FunctionExpression": if (parent.type !== "CallExpression" && parent.type !== "NewExpression") { while (parent && !parent.leadingComments && !/Function/.test(parent.type) && parent.type !== "MethodDefinition" && parent.type !== "Property") { parent = parent.parent; } return parent && (parent.type !== "FunctionDeclaration") ? findJSDocComment(parent.leadingComments, parent.loc.start .line) : null; } else if (node.leadingComments) { return findJSDocComment(node.leadingComments, node.loc.start.line); } // falls through default: return null; } }
...
/**
* Checks whether or not a node has a `@this` tag in its comments.
* @param {ASTNode} node - A node to check.
* @param {SourceCode} sourceCode - A SourceCode instance to get comments.
* @returns {boolean} Whether or not the node has a `@this` tag in its comments.
*/
function hasJSDocThisTag(node, sourceCode) {
const jsdocComment = sourceCode.getJSDocComment(node);
if (jsdocComment && thisTagPattern.test(jsdocComment.value)) {
return true;
}
// Checks `@this` in its leading comments for callbacks,
// because callbacks don't have its JSDoc comment.
...
getLines() { return this.lines; }
n/a
getLocFromIndex(index) {
if (typeof index !== "number") {
throw new TypeError("Expected `index` to be a number.");
}
if (index < 0 || index > this.text.length) {
throw new RangeError(`Index out of range (requested index ${index}, but source text has length ${this.text.length}).`);
}
/*
* For an argument of this.text.length, return the location one "spot" past the last character
* of the file. If the last character is a linebreak, the location will be column 0 of the next
* line; otherwise, the location will be in the next column on the same line.
*
* See getIndexFromLoc for the motivation for this special case.
*/
if (index === this.text.length) {
return { line: this.lines.length, column: this.lines[this.lines.length - 1].length };
}
/*
* To figure out which line rangeIndex is on, determine the last index at which rangeIndex could
* be inserted into lineIndices to keep the list sorted.
*/
const lineNumber = lodash.sortedLastIndex(this.lineStartIndices, index);
return { line: lineNumber, column: index - this.lineStartIndices[lineNumber - 1] };
}
n/a
getNodeByRangeIndex(index) { let result = null, resultParent = null; const traverser = new Traverser(); traverser.traverse(this.ast, { enter(node, parent) { if (node.range[0] <= index && index < node.range[1]) { result = node; resultParent = parent; } else { this.skip(); } }, leave(node) { if (node === result) { this.break(); } } }); return result ? Object.assign({ parent: resultParent }, result) : null; }
n/a
getText(node, beforeCount, afterCount) { if (node) { return this.text.slice(Math.max(node.range[0] - (beforeCount || 0), 0), node.range[1] + (afterCount || 0)); } return this.text; }
...
return {
start: Object.assign({}, start),
end: Object.assign({}, end)
};
},
/**
* Gets the parenthesized text of a node. This is similar to sourceCode.getText(node),
but it also includes any parentheses
* surrounding the node.
* @param {SourceCode} sourceCode The source code object
* @param {ASTNode} node An expression node
* @returns {string} The text representing the node, with all surrounding parentheses included
*/
getParenthesisedText(sourceCode, node) {
let leftToken = sourceCode.getFirstToken(node);
...
isSpaceBetweenTokens(first, second) { const text = this.text.slice(first.range[1], second.range[0]); return /\s/.test(text.replace(/\/\*.*?\*\//g, "")); }
n/a
function CLIEngine(options) {
options = Object.assign(
Object.create(null),
defaultOptions,
{ cwd: process.cwd() },
options
);
/**
* Stored options for this instance
* @type {Object}
*/
this.options = options;
const cacheFile = getCacheFile(this.options.cacheLocation || this.options.cacheFile, this.options.cwd);
/**
* Cache used to avoid operating on files that haven't changed since the
* last successful execution (e.g., file passed linting with no errors and
* no warnings).
* @type {Object}
*/
this._fileCache = fileEntryCache.create(cacheFile);
// load in additional rules
if (this.options.rulePaths) {
const cwd = this.options.cwd;
this.options.rulePaths.forEach(rulesdir => {
debug(`Loading rules from ${rulesdir}`);
rules.load(rulesdir, cwd);
});
}
Object.keys(this.options.rules || {}).forEach(name => {
validator.validateRuleOptions(name, this.options.rules[name], "CLI");
});
}
n/a
function RuleTester(testerConfig) {
/**
* The configuration to use for this tester. Combination of the tester
* configuration and the default configuration.
* @type {Object}
*/
this.testerConfig = lodash.merge(
// we have to clone because merge uses the first argument for recipient
lodash.cloneDeep(defaultConfig),
testerConfig
);
/**
* Rule definitions to define before tests.
* @type {Object}
*/
this.rules = {};
}
n/a
function SourceCode(text, ast) {
validate(ast);
/**
* The flag to indicate that the source code has Unicode BOM.
* @type boolean
*/
this.hasBOM = (text.charCodeAt(0) === 0xFEFF);
/**
* The original text source code.
* BOM was stripped from this text.
* @type string
*/
this.text = (this.hasBOM ? text.slice(1) : text);
/**
* The parsed AST for the source code.
* @type ASTNode
*/
this.ast = ast;
/**
* The source code split into lines according to ECMA-262 specification.
* This is done to avoid each rule needing to do so separately.
* @type string[]
*/
this.lines = [];
this.lineStartIndices = [0];
const lineEndingPattern = astUtils.createGlobalLinebreakMatcher();
let match;
/*
* Previously, this was implemented using a regex that
* matched a sequence of non-linebreak characters followed by a
* linebreak, then adding the lengths of the matches. However,
* this caused a catastrophic backtracking issue when the end
* of a file contained a large number of non-newline characters.
* To avoid this, the current implementation just matches newlines
* and uses match.index to get the correct line start indices.
*/
while ((match = lineEndingPattern.exec(this.text))) {
this.lines.push(this.text.slice(this.lineStartIndices[this.lineStartIndices.length - 1], match.index));
this.lineStartIndices.push(match.index + match[0].length);
}
this.lines.push(this.text.slice(this.lineStartIndices[this.lineStartIndices.length - 1]));
this.tokensAndComments = sortedMerge(ast.tokens, ast.comments);
// create token store methods
const tokenStore = new TokenStore(ast.tokens, ast.comments);
for (const methodName of TokenStore.PUBLIC_METHODS) {
this[methodName] = tokenStore[methodName].bind(tokenStore);
}
// don't allow modification of this object
Object.freeze(this);
Object.freeze(this.lines);
}
n/a
couldBeError(node) { switch (node.type) { case "Identifier": case "CallExpression": case "NewExpression": case "MemberExpression": case "TaggedTemplateExpression": case "YieldExpression": case "AwaitExpression": return true; // possibly an error object. case "AssignmentExpression": return module.exports.couldBeError(node.right); case "SequenceExpression": { const exprs = node.expressions; return exprs.length !== 0 && module.exports.couldBeError(exprs[exprs.length - 1]); } case "LogicalExpression": return module.exports.couldBeError(node.left) || module.exports.couldBeError(node.right); case "ConditionalExpression": return module.exports.couldBeError(node.consequent) || module.exports.couldBeError(node.alternate); default: return false; } }
...
case "MemberExpression":
case "TaggedTemplateExpression":
case "YieldExpression":
case "AwaitExpression":
return true; // possibly an error object.
case "AssignmentExpression":
return module.exports.couldBeError(node.right);
case "SequenceExpression": {
const exprs = node.expressions;
return exprs.length !== 0 && module.exports.couldBeError(exprs[exprs.length - 1]);
}
...
function createGlobalLinebreakMatcher() { return new RegExp(LINEBREAK_MATCHER.source, "g"); }
n/a
getDirectivePrologue(node) { const directives = []; // Directive prologues only occur at the top of files or functions. if ( node.type === "Program" || node.type === "FunctionDeclaration" || node.type === "FunctionExpression" || // Do not check arrow functions with implicit return. // `() => "use strict";` returns the string `"use strict"`. (node.type === "ArrowFunctionExpression" && node.body.type === "BlockStatement") ) { const statements = node.type === "Program" ? node.body : node.body.body; for (const statement of statements) { if ( statement.type === "ExpressionStatement" && statement.expression.type === "Literal" ) { directives.push(statement); } else { break; } } } return directives; }
n/a
getFunctionHeadLoc(node, sourceCode) { const parent = node.parent; let start = null; let end = null; if (node.type === "ArrowFunctionExpression") { const arrowToken = sourceCode.getTokenBefore(node.body, isArrowToken); start = arrowToken.loc.start; end = arrowToken.loc.end; } else if (parent.type === "Property" || parent.type === "MethodDefinition") { start = parent.loc.start; end = getOpeningParenOfParams(node, sourceCode).loc.start; } else { start = node.loc.start; end = getOpeningParenOfParams(node, sourceCode).loc.start; } return { start: Object.assign({}, start), end: Object.assign({}, end) }; }
n/a
getFunctionNameWithKind(node) { const parent = node.parent; const tokens = []; if (parent.type === "MethodDefinition" && parent.static) { tokens.push("static"); } if (node.async) { tokens.push("async"); } if (node.generator) { tokens.push("generator"); } if (node.type === "ArrowFunctionExpression") { tokens.push("arrow", "function"); } else if (parent.type === "Property" || parent.type === "MethodDefinition") { if (parent.kind === "constructor") { return "constructor"; } else if (parent.kind === "get") { tokens.push("getter"); } else if (parent.kind === "set") { tokens.push("setter"); } else { tokens.push("method"); } } else { tokens.push("function"); } if (node.id) { tokens.push(`'${node.id.name}'`); } else { const name = module.exports.getStaticPropertyName(parent); if (name) { tokens.push(`'${name}'`); } } return tokens.join(" "); }
n/a
getLabel(node) { if (node.parent.type === "LabeledStatement") { return node.parent.label.name; } return null; }
n/a
getModifyingReferences(references) { return references.filter(isModifyingReference); }
n/a
getParenthesisedText(sourceCode, node) { let leftToken = sourceCode.getFirstToken(node); let rightToken = sourceCode.getLastToken(node); while ( sourceCode.getTokenBefore(leftToken) && sourceCode.getTokenBefore(leftToken).type === "Punctuator" && sourceCode.getTokenBefore(leftToken).value === "(" && sourceCode.getTokenAfter(rightToken) && sourceCode.getTokenAfter(rightToken).type === "Punctuator" && sourceCode.getTokenAfter(rightToken).value === ")" ) { leftToken = sourceCode.getTokenBefore(leftToken); rightToken = sourceCode.getTokenAfter(rightToken); } return sourceCode.getText().slice(leftToken.range[0], rightToken.range[1]); }
n/a
getPrecedence(node) {
switch (node.type) {
case "SequenceExpression":
return 0;
case "AssignmentExpression":
case "ArrowFunctionExpression":
case "YieldExpression":
return 1;
case "ConditionalExpression":
return 3;
case "LogicalExpression":
switch (node.operator) {
case "||":
return 4;
case "&&":
return 5;
// no default
}
/* falls through */
case "BinaryExpression":
switch (node.operator) {
case "|":
return 6;
case "^":
return 7;
case "&":
return 8;
case "==":
case "!=":
case "===":
case "!==":
return 9;
case "<":
case "<=":
case ">":
case ">=":
case "in":
case "instanceof":
return 10;
case "<<":
case ">>":
case ">>>":
return 11;
case "+":
case "-":
return 12;
case "*":
case "/":
case "%":
return 13;
case "**":
return 15;
// no default
}
/* falls through */
case "UnaryExpression":
case "AwaitExpression":
return 16;
case "UpdateExpression":
return 17;
case "CallExpression":
// IIFE is allowed to have parens in any position (#655)
if (node.callee.type === "FunctionExpression") {
return -1;
}
return 18;
case "NewExpression":
return 19;
// no default
}
return 20;
}
n/a
getStaticPropertyName(node) { let prop; switch (node && node.type) { case "Property": case "MethodDefinition": prop = node.key; break; case "MemberExpression": prop = node.property; break; // no default } switch (prop && prop.type) { case "Literal": return String(prop.value); case "TemplateLiteral": if (prop.expressions.length === 0 && prop.quasis.length === 1) { return prop.quasis[0].value.cooked; } break; case "Identifier": if (!node.computed) { return prop.name; } break; // no default } return null; }
...
} else {
tokens.push("function");
}
if (node.id) {
tokens.push(`'${node.id.name}'`);
} else {
const name = module.exports.getStaticPropertyName(parent);
if (name) {
tokens.push(`'${name}'`);
}
}
return tokens.join(" ");
...
function trailingStatement(node) { switch (node.type) { case 'IfStatement': if (node.alternate != null) { return node.alternate; } return node.consequent; case 'LabeledStatement': case 'ForStatement': case 'ForInStatement': case 'WhileStatement': case 'WithStatement': return node.body; } return null; }
n/a
function getUpperFunction(node) { while (node) { if (anyFunctionPattern.test(node.type)) { return node; } node = node.parent; } return null; }
n/a
getVariableByName(initScope, name) { let scope = initScope; while (scope) { const variable = scope.set.get(name); if (variable) { return variable; } scope = scope.upper; } return null; }
n/a
function isArrayFromMethod(node) { return ( node.type === "MemberExpression" && node.object.type === "Identifier" && arrayOrTypedArrayPattern.test(node.object.name) && node.property.type === "Identifier" && node.property.name === "from" && node.computed === false ); }
n/a
function isArrowToken(token) { return token.value === "=>" && token.type === "Punctuator"; }
n/a
isBreakableStatement(node) { return breakableTypePattern.test(node.type); }
n/a
function isCallee(node) { return node.parent.type === "CallExpression" && node.parent.callee === node; }
n/a
function isClosingBraceToken(token) { return token.value === "}" && token.type === "Punctuator"; }
n/a
function isClosingBracketToken(token) { return token.value === "]" && token.type === "Punctuator"; }
n/a
function isClosingParenToken(token) { return token.value === ")" && token.type === "Punctuator"; }
n/a
function isColonToken(token) { return token.value === ":" && token.type === "Punctuator"; }
n/a
function isCommaToken(token) { return token.value === "," && token.type === "Punctuator"; }
n/a
function isCommentToken(token) { return token.type === "Line" || token.type === "Block" || token.type === "Shebang"; }
n/a
isDecimalInteger(node) { return node.type === "Literal" && typeof node.value === "number" && /^(0|[1-9]\d*)$/.test(node.raw); }
n/a
isDefaultThisBinding(node, sourceCode) {
if (isES5Constructor(node) || hasJSDocThisTag(node, sourceCode)) {
return false;
}
const isAnonymous = node.id === null;
while (node) {
const parent = node.parent;
switch (parent.type) {
/*
* Looks up the destination.
* e.g., obj.foo = nativeFoo || function foo() { ... };
*/
case "LogicalExpression":
case "ConditionalExpression":
node = parent;
break;
// If the upper function is IIFE, checks the destination of the return value.
// e.g.
// obj.foo = (function() {
// // setup...
// return function foo() { ... };
// })();
case "ReturnStatement": {
const func = getUpperFunction(parent);
if (func === null || !isCallee(func)) {
return true;
}
node = func.parent;
break;
}
// e.g.
// var obj = { foo() { ... } };
// var obj = { foo: function() { ... } };
// class A { constructor() { ... } }
// class A { foo() { ... } }
// class A { get foo() { ... } }
// class A { set foo() { ... } }
// class A { static foo() { ... } }
case "Property":
case "MethodDefinition":
return parent.value !== node;
// e.g.
// obj.foo = function foo() { ... };
// Foo = function() { ... };
// [obj.foo = function foo() { ... }] = a;
// [Foo = function() { ... }] = a;
case "AssignmentExpression":
case "AssignmentPattern":
if (parent.right === node) {
if (parent.left.type === "MemberExpression") {
return false;
}
if (isAnonymous &&
parent.left.type === "Identifier" &&
startsWithUpperCase(parent.left.name)
) {
return false;
}
}
return true;
// e.g.
// var Foo = function() { ... };
case "VariableDeclarator":
return !(
isAnonymous &&
parent.init === node &&
parent.id.type === "Identifier" &&
startsWithUpperCase(parent.id.name)
);
// e.g.
// var foo = function foo() { ... }.bind(obj);
// (function foo() { ... }).call(obj);
// (function foo() { ... }).apply(obj, []);
case "MemberExpression":
return (
parent.object !== node ||
parent.property.type !== "Identifier" ||
!bindOrCallOrApplyPattern.test(parent.property.name) ||
!isCallee(parent) ||
parent.parent.arguments.length === 0 ||
isNullOrUndefined(parent.parent.arguments[0])
);
// e.g.
// Reflect.apply(function() {}, obj, []);
// Array.from([], function() {}, obj);
// list.forEach(function() {}, obj);
case "CallExpression":
if (isReflectApply(parent.callee)) {
return (
parent.arguments.length !== 3 ||
parent.arguments[0] !== node ||
isNullOrUndefined(parent.arguments[1])
);
}
if (isArrayFromMethod(parent.callee)) {
return (
parent.arguments.length !== 3 ||
parent.arguments[1] !== node ||
isNullOrUndefined(parent.arguments[2])
);
} ...
n/a
isDirectiveComment(node) { const comment = node.value.trim(); return ( node.type === "Line" && comment.indexOf("eslint-") === 0 || node.type === "Block" && ( comment.indexOf("global ") === 0 || comment.indexOf("eslint ") === 0 || comment.indexOf("eslint-") === 0 ) ); }
n/a
function isES5Constructor(node) { return (node.id && startsWithUpperCase(node.id.name)); }
n/a
isEmptyBlock(node) { return Boolean(node && node.type === "BlockStatement" && node.body.length === 0); }
...
/**
* Checks whether the given node is an empty function node or not.
*
* @param {ASTNode|null} node - The node to check.
* @returns {boolean} `true` if the node is an empty function.
*/
isEmptyFunction(node) {
return isFunction(node) && module.exports.isEmptyBlock(node.body);
},
/**
* Gets the property name of a given node.
* The node can be a MemberExpression, a Property, or a MethodDefinition.
*
* If the name is dynamic, this returns `null`.
...
isEmptyFunction(node) { return isFunction(node) && module.exports.isEmptyBlock(node.body); }
n/a
function isFunction(node) { return Boolean(node && anyFunctionPattern.test(node.type)); }
n/a
function isInLoop(node) { while (node && !isFunction(node)) { if (isLoop(node)) { return true; } node = node.parent; } return false; }
n/a
function isKeywordToken(token) { return token.type === "Keyword"; }
n/a
function isLoop(node) { return Boolean(node && anyLoopPattern.test(node.type)); }
n/a
token => !f(token)
n/a
token => !f(token)
n/a
token => !f(token)
n/a
token => !f(token)
n/a
token => !f(token)
n/a
token => !f(token)
n/a
token => !f(token)
n/a
token => !f(token)
n/a
token => !f(token)
n/a
isNullLiteral(node) {
/*
* Checking `node.value === null` does not guarantee that a literal is a null literal.
* When parsing values that cannot be represented in the current environment (e.g. unicode
* regexes in Node 4), `node.value` is set to `null` because it wouldn't be possible to
* set `node.value` to a unicode regex. To make sure a literal is actually `null`, check
* `node.regex` instead. Also see: https://github.com/eslint/eslint/issues/8020
*/
return node.type === "Literal" && node.value === null && !node.regex;
}
...
* Checks whether or not a node is `null` or `undefined`.
* @param {ASTNode} node - A node to check.
* @returns {boolean} Whether or not the node is a `null` or `undefined`.
* @public
*/
function isNullOrUndefined(node) {
return (
module.exports.isNullLiteral(node) ||
(node.type === "Identifier" && node.name === "undefined") ||
(node.type === "UnaryExpression" && node.operator === "void")
);
}
/**
* Checks whether or not a node is callee.
...
function isNullOrUndefined(node) { return ( module.exports.isNullLiteral(node) || (node.type === "Identifier" && node.name === "undefined") || (node.type === "UnaryExpression" && node.operator === "void") ); }
n/a
function isOpeningBraceToken(token) { return token.value === "{" && token.type === "Punctuator"; }
n/a
function isOpeningBracketToken(token) { return token.value === "[" && token.type === "Punctuator"; }
n/a
function isOpeningParenToken(token) { return token.value === "(" && token.type === "Punctuator"; }
n/a
function isParenthesised(sourceCode, node) { const previousToken = sourceCode.getTokenBefore(node), nextToken = sourceCode.getTokenAfter(node); return Boolean(previousToken && nextToken) && previousToken.value === "(" && previousToken.range[1] <= node.range[0] && nextToken.value === ")" && nextToken.range[0] >= node.range[1]; }
n/a
function isSemicolonToken(token) { return token.value === ";" && token.type === "Punctuator"; }
n/a
isStringLiteral(node) { return ( (node.type === "Literal" && typeof node.value === "string") || node.type === "TemplateLiteral" ); }
n/a
isSurroundedBy(val, character) { return val[0] === character && val[val.length - 1] === character; }
n/a
isTokenOnSameLine(left, right) { return left.loc.end.line === right.loc.start.line; }
n/a
defaults = function () { return require("../conf/eslint-recommended"); }
n/a
defineRule = function (ruleId, ruleModule) { rules.define(ruleId, ruleModule); }
n/a
defineRules = function (rulesToDefine) { Object.getOwnPropertyNames(rulesToDefine).forEach(ruleId => { defineRule(ruleId, rulesToDefine[ruleId]); }); }
n/a
getAllComments = function (a, b, c, d, e) { if (sourceCode) { return sourceCode[exMethodName](a, b, c, d, e); } return null; }
n/a
getAncestors = function () { return traverser.parents(); }
n/a
getComments = function (a, b, c, d, e) { if (sourceCode) { return sourceCode[exMethodName](a, b, c, d, e); } return null; }
...
return true;
}
// Checks `@this` in its leading comments for callbacks,
// because callbacks don't have its JSDoc comment.
// e.g.
// sinon.test(/* @this sinon.Sandbox */function() { this.spy(); });
return sourceCode.getComments(node).leading.some(comment => thisTagPattern.test
(comment.value));
}
/**
* Determines if a node is surrounded by parentheses.
* @param {SourceCode} sourceCode The ESLint source code object
* @param {ASTNode} node The node to be checked.
* @returns {boolean} True if the node is parenthesised.
...
getDeclaredVariables = function (node) { return (scopeManager && scopeManager.getDeclaredVariables(node)) || []; }
n/a
getFilename = function () { if (typeof currentFilename === "string") { return currentFilename; } return "<input>"; }
n/a
getFirstToken = function (a, b, c, d, e) { if (sourceCode) { return sourceCode[exMethodName](a, b, c, d, e); } return null; }
...
* @param {ASTNode} node - The function node to get.
* @param {SourceCode} sourceCode - The source code object to get tokens.
* @returns {Token} `(` token.
*/
function getOpeningParenOfParams(node, sourceCode) {
return node.id
? sourceCode.getTokenAfter(node.id, isOpeningParenToken)
: sourceCode.getFirstToken(node, isOpeningParenToken);
}
/**
* Creates a version of the LINEBREAK_MATCHER regex with the global flag.
* Global regexes are mutable, so this needs to be a function instead of a constant.
* @returns {RegExp} A global regular expression that matches line terminators
*/
...
getFirstTokens = function (a, b, c, d, e) { if (sourceCode) { return sourceCode[exMethodName](a, b, c, d, e); } return null; }
n/a
getJSDocComment = function (a, b, c, d, e) { if (sourceCode) { return sourceCode[exMethodName](a, b, c, d, e); } return null; }
...
/**
* Checks whether or not a node has a `@this` tag in its comments.
* @param {ASTNode} node - A node to check.
* @param {SourceCode} sourceCode - A SourceCode instance to get comments.
* @returns {boolean} Whether or not the node has a `@this` tag in its comments.
*/
function hasJSDocThisTag(node, sourceCode) {
const jsdocComment = sourceCode.getJSDocComment(node);
if (jsdocComment && thisTagPattern.test(jsdocComment.value)) {
return true;
}
// Checks `@this` in its leading comments for callbacks,
// because callbacks don't have its JSDoc comment.
...
getLastToken = function (a, b, c, d, e) { if (sourceCode) { return sourceCode[exMethodName](a, b, c, d, e); } return null; }
...
* surrounding the node.
* @param {SourceCode} sourceCode The source code object
* @param {ASTNode} node An expression node
* @returns {string} The text representing the node, with all surrounding parentheses included
*/
getParenthesisedText(sourceCode, node) {
let leftToken = sourceCode.getFirstToken(node);
let rightToken = sourceCode.getLastToken(node);
while (
sourceCode.getTokenBefore(leftToken) &&
sourceCode.getTokenBefore(leftToken).type === "Punctuator" &&
sourceCode.getTokenBefore(leftToken).value === "(" &&
sourceCode.getTokenAfter(rightToken) &&
sourceCode.getTokenAfter(rightToken).type === "Punctuator" &&
...
getLastTokens = function (a, b, c, d, e) { if (sourceCode) { return sourceCode[exMethodName](a, b, c, d, e); } return null; }
n/a
getNodeByRangeIndex = function (a, b, c, d, e) { if (sourceCode) { return sourceCode[exMethodName](a, b, c, d, e); } return null; }
n/a
getRules = function () { return rules.getAllLoadedRules(); }
n/a
getScope = function () { const parents = traverser.parents(); // Don't do this for Program nodes - they have no parents if (parents.length) { // if current node introduces a scope, add it to the list const current = traverser.current(); if (currentConfig.parserOptions.ecmaVersion >= 6) { if (["BlockStatement", "SwitchStatement", "CatchClause", "FunctionDeclaration", "FunctionExpression", "ArrowFunctionExpression "].indexOf(current.type) >= 0) { parents.push(current); } } else { if (["FunctionDeclaration", "FunctionExpression", "ArrowFunctionExpression"].indexOf(current.type) >= 0) { parents.push(current); } } // Ascend the current node's parents for (let i = parents.length - 1; i >= 0; --i) { // Get the innermost scope const scope = scopeManager.acquire(parents[i], true); if (scope) { if (scope.type === "function-expression-name") { return scope.childScopes[0]; } return scope; } } } return currentScopes[0]; }
n/a
getSource = function (a, b, c, d, e) { if (sourceCode) { return sourceCode[exMethodName](a, b, c, d, e); } return null; }
n/a
getSourceCode = function () { return sourceCode; }
...
this.eslint = eslint;
this.severity = severity;
Object.freeze(this);
}
/**
* Passthrough to eslint.getSourceCode().
* @returns {SourceCode} The SourceCode object for the code.
*/
getSourceCode() {
return this.eslint.getSourceCode();
}
/**
...
getSourceLines = function (a, b, c, d, e) { if (sourceCode) { return sourceCode[exMethodName](a, b, c, d, e); } return null; }
n/a
getTokenAfter = function (a, b, c, d, e) { if (sourceCode) { return sourceCode[exMethodName](a, b, c, d, e); } return null; }
...
* @param {SourceCode} sourceCode The ESLint source code object
* @param {ASTNode} node The node to be checked.
* @returns {boolean} True if the node is parenthesised.
* @private
*/
function isParenthesised(sourceCode, node) {
const previousToken = sourceCode.getTokenBefore(node),
nextToken = sourceCode.getTokenAfter(node);
return Boolean(previousToken && nextToken) &&
previousToken.value === "(" && previousToken.range[1] <= node.range[0] &&
nextToken.value === ")" && nextToken.range[0] >= node.range[1];
}
/**
...
getTokenBefore = function (a, b, c, d, e) { if (sourceCode) { return sourceCode[exMethodName](a, b, c, d, e); } return null; }
...
* Determines if a node is surrounded by parentheses.
* @param {SourceCode} sourceCode The ESLint source code object
* @param {ASTNode} node The node to be checked.
* @returns {boolean} True if the node is parenthesised.
* @private
*/
function isParenthesised(sourceCode, node) {
const previousToken = sourceCode.getTokenBefore(node),
nextToken = sourceCode.getTokenAfter(node);
return Boolean(previousToken && nextToken) &&
previousToken.value === "(" && previousToken.range[1] <= node.range[0] &&
nextToken.value === ")" && nextToken.range[0] >= node.range[1];
}
...
getTokenByRangeStart = function (a, b, c, d, e) { if (sourceCode) { return sourceCode[exMethodName](a, b, c, d, e); } return null; }
n/a
getTokens = function (a, b, c, d, e) { if (sourceCode) { return sourceCode[exMethodName](a, b, c, d, e); } return null; }
n/a
getTokensAfter = function (a, b, c, d, e) { if (sourceCode) { return sourceCode[exMethodName](a, b, c, d, e); } return null; }
n/a
getTokensBefore = function (a, b, c, d, e) { if (sourceCode) { return sourceCode[exMethodName](a, b, c, d, e); } return null; }
n/a
getTokensBetween = function (a, b, c, d, e) { if (sourceCode) { return sourceCode[exMethodName](a, b, c, d, e); } return null; }
n/a
markVariableAsUsed = function (name) { const hasGlobalReturn = currentConfig.parserOptions.ecmaFeatures && currentConfig.parserOptions.ecmaFeatures.globalReturn, specialScope = hasGlobalReturn || currentConfig.parserOptions.sourceType === "module"; let scope = this.getScope(), i, len; // Special Node.js scope means we need to start one level deeper if (scope.type === "global" && specialScope) { scope = scope.childScopes[0]; } do { const variables = scope.variables; for (i = 0, len = variables.length; i < len; i++) { if (variables[i].name === name) { variables[i].eslintUsed = true; return true; } } } while ((scope = scope.upper)); return false; }
n/a
report = function (ruleId, severity, node, location, message, opts, fix, meta) { if (node) { assert.strictEqual(typeof node, "object", "Node must be an object"); } if (typeof location === "string") { assert.ok(node, "Node must be provided when reporting error if location is not provided"); meta = fix; fix = opts; opts = message; message = location; location = node.loc.start; } // Store end location. const endLocation = location.end; location = location.start || location; if (isDisabledByReportingConfig(reportingConfig, ruleId, location)) { return; } if (opts) { message = message.replace(/\{\{\s*([^{}]+?)\s*\}\}/g, (fullMatch, term) => { if (term in opts) { return opts[term]; } // Preserve old behavior: If parameter name not provided, don't replace it. return fullMatch; }); } const problem = { ruleId, severity, message, line: location.line, column: location.column + 1, // switch to 1-base instead of 0-base nodeType: node && node.type, source: sourceCode.lines[location.line - 1] || "" }; // Define endLine and endColumn if exists. if (endLocation) { problem.endLine = endLocation.line; problem.endColumn = endLocation.column + 1; // switch to 1-base instead of 0-base } // ensure there's range and text properties, otherwise it's not a valid fix if (fix && Array.isArray(fix.range) && (typeof fix.text === "string")) { // If rule uses fix, has metadata, but has no metadata.fixable, we should throw if (meta && !meta.fixable) { throw new Error("Fixable rules should export a `meta.fixable` property."); } problem.fix = fix; } messages.push(problem); }
...
* @returns {SourceCode} The SourceCode object for the code.
*/
getSourceCode() {
return this.eslint.getSourceCode();
}
/**
* Passthrough to eslint.report() that automatically assigns the rule ID and severity
.
* @param {ASTNode|MessageDescriptor} nodeOrDescriptor The AST node related to the message or a message
* descriptor.
* @param {Object=} location The location of the error.
* @param {string} message The message to display to the user.
* @param {Object} opts Optional template data which produces a formatted message
* with symbols being replaced by this object's values.
* @returns {void}
...
reset = function () { this.removeAllListeners(); messages = []; currentConfig = null; currentScopes = null; scopeManager = null; traverser = null; reportingConfig = []; sourceCode = null; }
n/a
verify = function (textOrSourceCode, config, filenameOrOptions, saveState) { const text = (typeof textOrSourceCode === "string") ? textOrSourceCode : null; let ast, parseResult, shebang, allowInlineConfig; // evaluate arguments if (typeof filenameOrOptions === "object") { currentFilename = filenameOrOptions.filename; allowInlineConfig = filenameOrOptions.allowInlineConfig; saveState = filenameOrOptions.saveState; } else { currentFilename = filenameOrOptions; } if (!saveState) { this.reset(); } // search and apply "eslint-env *". const envInFile = findEslintEnv(text || textOrSourceCode.text); config = Object.assign({}, config); if (envInFile) { if (config.env) { config.env = Object.assign({}, config.env, envInFile); } else { config.env = envInFile; } } // process initial config to make it safe to extend config = prepareConfig(config); // only do this for text if (text !== null) { // there's no input, just exit here if (text.trim().length === 0) { sourceCode = new SourceCode(text, blankScriptAST); return messages; } parseResult = parse( stripUnicodeBOM(text).replace(/^#!([^\r\n]+)/, (match, captured) => { shebang = captured; return `//${captured}`; }), config, currentFilename ); // if this result is from a parseForESLint() method, normalize if (parseResult && parseResult.ast) { ast = parseResult.ast; } else { ast = parseResult; parseResult = null; } if (ast) { sourceCode = new SourceCode(text, ast); } } else { sourceCode = textOrSourceCode; ast = sourceCode.ast; } // if espree failed to parse the file, there's no sense in setting up rules if (ast) { // parse global comments and modify config if (allowInlineConfig !== false) { config = modifyConfigsFromComments(currentFilename, ast, config, reportingConfig, messages); } // ensure that severities are normalized in the config ConfigOps.normalize(config); // enable appropriate rules Object.keys(config.rules).filter(key => getRuleSeverity(config.rules[key]) > 0).forEach(key => { let ruleCreator; ruleCreator = rules.get(key); if (!ruleCreator) { const replacementMsg = getRuleReplacementMessage(key); if (replacementMsg) { ruleCreator = createStubRule(replacementMsg); } else { ruleCreator = createStubRule(`Definition for rule '${key}' was not found`); } rules.define(key, ruleCreator); } const severity = getRuleSeverity(config.rules[key]); const options = getRuleOptions(config.rules[key]); try { const ruleContext = new RuleContext( key, api, severity, options, config.settings, config.parserOptions, config.parser, ruleCreator.meta, (parseResult && parseResult.services ? parseResult.services : {}) ); const rule = ruleCreator.create ? ruleCreator.create(ruleContext) : ruleCreator(ruleContext); // add all the selectors from the rule as listeners Object.keys(rule).forEach(selector => { api.on(selector, timing.enabled ? timing.time(key, rule[selector]) : rule[selector] ); }); } catch (ex) { ex.message = `Error while loading rule '${key}': ${ex.message}`; throw ex; } }); // save config so rules can access as necess ...
n/a
error() { console.error.apply(console, Array.prototype.slice.call(arguments)); }
n/a
info() { console.log.apply(console, Array.prototype.slice.call(arguments)); }
n/a
generateHelp = function (arg$){ var ref$, showHidden, interpolate, maxWidth, output, out, data, optionCount, totalPreLen, preLens, i$, len$, item, that, pre, descParts, desc, preLen, sortedPreLens, maxPreLen, preLenMean, x, padAmount, descSepLen, fullWrapCount, partialWrapCount, descLen , totalLen, initialSpace, wrapAllFull, i, wrap; ref$ = arg$ != null ? arg$ : {}, showHidden = ref$.showHidden, interpolate = ref$.interpolate; maxWidth = stdout != null && stdout.isTTY ? stdout.columns - 1 : null; output = []; out = function(it){ return output.push(it != null ? it : ''); }; if (prepend) { out(interpolate ? interp(prepend, interpolate) : prepend); out(); } data = []; optionCount = 0; totalPreLen = 0; preLens = []; for (i$ = 0, len$ = (ref$ = options).length; i$ < len$; ++i$) { item = ref$[i$]; if (showHidden || !item.hidden) { if (that = item.heading) { data.push({ type: 'heading', value: that }); } else { pre = getPreText(item, helpStyle, maxWidth); descParts = []; if ((that = item.description) != null) { descParts.push(that); } if (that = item['enum']) { descParts.push("either: " + naturalJoin(that)); } if (item['default'] && !item.negateName) { descParts.push("default: " + item['default']); } desc = descParts.join(' - '); data.push({ type: 'option', pre: pre, desc: desc, descLen: desc.length }); preLen = pre.length; optionCount++; totalPreLen += preLen; preLens.push(preLen); } } } sortedPreLens = sort(preLens); maxPreLen = sortedPreLens[sortedPreLens.length - 1]; preLenMean = initialIndent + totalPreLen / optionCount; x = optionCount > 2 ? min(preLenMean * maxPadFactor, maxPreLen) : maxPreLen; for (i$ = sortedPreLens.length - 1; i$ >= 0; --i$) { preLen = sortedPreLens[i$]; if (preLen <= x) { padAmount = preLen; break; } } descSepLen = descriptionSeparator.length; if (maxWidth != null) { fullWrapCount = 0; partialWrapCount = 0; for (i$ = 0, len$ = data.length; i$ < len$; ++i$) { item = data[i$]; if (item.type === 'option') { pre = item.pre, desc = item.desc, descLen = item.descLen; if (descLen === 0) { item.wrap = 'none'; } else { preLen = max(padAmount, pre.length) + initialIndent + descSepLen; totalLen = preLen + descLen; if (totalLen > maxWidth) { if (descLen / 2.5 > maxWidth - preLen) { fullWrapCount++; item.wrap = 'full'; } else { partialWrapCount++; item.wrap = 'partial'; } } else { item.wrap = 'none'; } } } } } initialSpace = repeatString$(' ', initialIndent); wrapAllFull = optionCount > 1 && fullWrapCount + partialWrapCount * 0.5 > optionCount * 0.5; for (i$ = 0, len$ = data.length; i$ < len$; ++i$) { i = i$; item = data[i$]; if (item.type === 'heading') { if (i !== 0) { out(); } out(item.value + ":"); } else { pre = item.pre, desc = item.desc, descLen = item.descLen, wrap = item.wrap; if (maxWidth != null) { if (wrapAllFull || wrap === 'full') { wrap = wordwrap(initialIndent + secondaryIndent, maxWidth); out(initialSpace + "" + pre + "\n" + wrap(desc)); continue; } else if (wrap === 'partial') { wrap = wordwrap(initialIndent + descSepLen + max(padAmount, pre.length), maxWidth); out(initialSpace + "" + pad(pre, padAmount) + descriptionSeparator + wrap(desc).replace(/^\s+/, '')); continue; } } if (descLen === 0) { out(initialSpace + "" + pre); } else { out(initialSpace + "" + pad(pre, padAmount) + descriptionSeparator + desc); } } } if (append) { out(); out(interpola ...
n/a
generateHelpForOption = function (optionName){ var maxWidth, wrap, option, e, pre, defaultString, restPositionalString, description, fullDescription, that, preDescription, descriptionString , exampleString, examples, seperator; maxWidth = stdout != null && stdout.isTTY ? stdout.columns - 1 : null; wrap = maxWidth ? wordwrap(maxWidth) : id; try { option = getOption(dasherize(optionName)); } catch (e$) { e = e$; return e.message; } pre = getPreText(option, helpStyle); defaultString = option['default'] && !option.negateName ? "\ndefault: " + option['default'] : ''; restPositionalString = option.restPositional ? 'Everything after this option is considered a positional argument, even if it looks like an option.' : ''; description = option.longDescription || option.description && sentencize(option.description); fullDescription = description && restPositionalString ? description + " " + restPositionalString : (that = description || restPositionalString) ? that : ''; preDescription = 'description:'; descriptionString = !fullDescription ? '' : maxWidth && fullDescription.length - 1 - preDescription.length > maxWidth ? "\n" + preDescription + "\n" + wrap(fullDescription) : "\n" + preDescription + " " + fullDescription; exampleString = (that = option.example) ? (examples = [].concat(that), examples.length > 1 ? "\nexamples:\n" + unlines(examples) : "\nexample: " + examples[0]) : ''; seperator = defaultString || descriptionString || exampleString ? "\n" + repeatString$('=', pre.length) : ''; return pre + "" + seperator + defaultString + descriptionString + exampleString; }
n/a
parse = function (input, arg$){ var slice, obj, positional, restPositional, overrideRequired, prop, setValue, setDefaults, checkRequired, mutuallyExclusiveError , checkMutuallyExclusive, checkDependency, checkDependencies, checkProp, args, key, value, option, ref$, i$, len$, arg, that, result , short, argName, usingAssign, val, flags, len, j$, len1$, i, flag, opt, name, valPrime, negated, noedName; slice = (arg$ != null ? arg$ : {}).slice; obj = {}; positional = []; restPositional = false; overrideRequired = false; prop = null; setValue = function(name, value){ var opt, val, cra, e, currentType; opt = getOption(name); if (opt.boolean) { val = value; } else { try { cra = opt.concatRepeatedArrays; if (cra != null && cra[0] && cra[1].oneValuePerFlag && opt.parsedType.length === 1 && opt.parsedType[0].structure === 'array ') { val = [parseLevn(opt.parsedType[0].of, value)]; } else { val = parseLevn(opt.parsedType, value); } } catch (e$) { e = e$; throw new Error("Invalid value for option '" + name + "' - expected type " + opt.type + ", received value: " + value + "."); } if (opt['enum'] && !any(function(it){ return deepIs(it, val); }, opt.parsedPossibilities)) { throw new Error("Option " + name + ": '" + val + "' not one of " + naturalJoin(opt['enum']) + "."); } } currentType = toString$.call(obj[name]).slice(8, -1); if (obj[name] != null) { if (opt.concatRepeatedArrays != null && opt.concatRepeatedArrays[0] && currentType === 'Array') { obj[name] = obj[name].concat(val); } else if (opt.mergeRepeatedObjects && currentType === 'Object') { import$(obj[name], val); } else { obj[name] = val; } } else { obj[name] = val; } if (opt.restPositional) { restPositional = true; } if (opt.overrideRequired) { overrideRequired = true; } }; setDefaults = function(){ var name, ref$, value; for (name in ref$ = defaults) { value = ref$[name]; if (obj[name] == null) { obj[name] = value; } } }; checkRequired = function(){ var i$, ref$, len$, name; if (overrideRequired) { return; } for (i$ = 0, len$ = (ref$ = required).length; i$ < len$; ++i$) { name = ref$[i$]; if (!obj[name]) { throw new Error("Option " + nameToRaw(name) + " is required."); } } }; mutuallyExclusiveError = function(first, second){ throw new Error("The options " + nameToRaw(first) + " and " + nameToRaw(second) + " are mutually exclusive - you cannot use them at the same time."); }; checkMutuallyExclusive = function(){ var rules, i$, len$, rule, present, j$, len1$, element, k$, len2$, opt; rules = libOptions.mutuallyExclusive; if (!rules) { return; } for (i$ = 0, len$ = rules.length; i$ < len$; ++i$) { rule = rules[i$]; present = null; for (j$ = 0, len1$ = rule.length; j$ < len1$; ++j$) { element = rule[j$]; if (toString$.call(element).slice(8, -1) === 'Array') { for (k$ = 0, len2$ = element.length; k$ < len2$; ++k$) { opt = element[k$]; if (opt in obj) { if (present != null) { mutuallyExclusiveError(present, opt); } else { present = opt; break; } } } } else { if (element in obj) { if (present != null) { mutuallyExclusiveError(present, element); } else { present = element; } } } } } }; checkDependency = function(option){ var dependsOn, type, targetOptionNames, i$, len$, targetOptionName, targetOption; dependsOn = option.dependsOn; if (!dependsOn || option.dependenciesMet) { return true; } type = dependsOn[0], targetOptionNames = slice$.call(dependsOn, 1); for (i$ = 0, len$ = ...
n/a
parseArgv = function (it){ return parse(it, { slice: 2 }); }
n/a
class RuleContext {
/**
* @param {string} ruleId The ID of the rule using this object.
* @param {eslint} eslint The eslint object.
* @param {number} severity The configured severity level of the rule.
* @param {Array} options The configuration information to be added to the rule.
* @param {Object} settings The configuration settings passed from the config file.
* @param {Object} parserOptions The parserOptions settings passed from the config file.
* @param {Object} parserPath The parser setting passed from the config file.
* @param {Object} meta The metadata of the rule
* @param {Object} parserServices The parser services for the rule.
*/
constructor(ruleId, eslint, severity, options, settings, parserOptions, parserPath, meta, parserServices) {
// public.
this.id = ruleId;
this.options = options;
this.settings = settings;
this.parserOptions = parserOptions;
this.parserPath = parserPath;
this.meta = meta;
// create a separate copy and freeze it (it's not nice to freeze other people's objects)
this.parserServices = Object.freeze(Object.assign({}, parserServices));
// private.
this.eslint = eslint;
this.severity = severity;
Object.freeze(this);
}
/**
* Passthrough to eslint.getSourceCode().
* @returns {SourceCode} The SourceCode object for the code.
*/
getSourceCode() {
return this.eslint.getSourceCode();
}
/**
* Passthrough to eslint.report() that automatically assigns the rule ID and severity.
* @param {ASTNode|MessageDescriptor} nodeOrDescriptor The AST node related to the message or a message
* descriptor.
* @param {Object=} location The location of the error.
* @param {string} message The message to display to the user.
* @param {Object} opts Optional template data which produces a formatted message
* with symbols being replaced by this object's values.
* @returns {void}
*/
report(nodeOrDescriptor, location, message, opts) {
// check to see if it's a new style call
if (arguments.length === 1) {
const descriptor = nodeOrDescriptor;
let fix = null;
// if there's a fix specified, get it
if (typeof descriptor.fix === "function") {
fix = descriptor.fix(ruleFixer);
}
this.eslint.report(
this.id,
this.severity,
descriptor.node,
descriptor.loc || descriptor.node.loc.start,
descriptor.message,
descriptor.data,
fix,
this.meta
);
return;
}
// old style call
this.eslint.report(
this.id,
this.severity,
nodeOrDescriptor,
location,
message,
opts,
this.meta
);
}
}
n/a
getAllComments = function (a, b, c, d, e) { return this.eslint[name](a, b, c, d, e); }
n/a
getAncestors = function (a, b, c, d, e) { return this.eslint[name](a, b, c, d, e); }
n/a
getComments = function (a, b, c, d, e) { return this.eslint[name](a, b, c, d, e); }
...
return true;
}
// Checks `@this` in its leading comments for callbacks,
// because callbacks don't have its JSDoc comment.
// e.g.
// sinon.test(/* @this sinon.Sandbox */function() { this.spy(); });
return sourceCode.getComments(node).leading.some(comment => thisTagPattern.test
(comment.value));
}
/**
* Determines if a node is surrounded by parentheses.
* @param {SourceCode} sourceCode The ESLint source code object
* @param {ASTNode} node The node to be checked.
* @returns {boolean} True if the node is parenthesised.
...
getDeclaredVariables = function (a, b, c, d, e) { return this.eslint[name](a, b, c, d, e); }
n/a
getFilename = function (a, b, c, d, e) { return this.eslint[name](a, b, c, d, e); }
n/a
getFirstToken = function (a, b, c, d, e) { return this.eslint[name](a, b, c, d, e); }
...
* @param {ASTNode} node - The function node to get.
* @param {SourceCode} sourceCode - The source code object to get tokens.
* @returns {Token} `(` token.
*/
function getOpeningParenOfParams(node, sourceCode) {
return node.id
? sourceCode.getTokenAfter(node.id, isOpeningParenToken)
: sourceCode.getFirstToken(node, isOpeningParenToken);
}
/**
* Creates a version of the LINEBREAK_MATCHER regex with the global flag.
* Global regexes are mutable, so this needs to be a function instead of a constant.
* @returns {RegExp} A global regular expression that matches line terminators
*/
...
getFirstTokens = function (a, b, c, d, e) { return this.eslint[name](a, b, c, d, e); }
n/a
getJSDocComment = function (a, b, c, d, e) { return this.eslint[name](a, b, c, d, e); }
...
/**
* Checks whether or not a node has a `@this` tag in its comments.
* @param {ASTNode} node - A node to check.
* @param {SourceCode} sourceCode - A SourceCode instance to get comments.
* @returns {boolean} Whether or not the node has a `@this` tag in its comments.
*/
function hasJSDocThisTag(node, sourceCode) {
const jsdocComment = sourceCode.getJSDocComment(node);
if (jsdocComment && thisTagPattern.test(jsdocComment.value)) {
return true;
}
// Checks `@this` in its leading comments for callbacks,
// because callbacks don't have its JSDoc comment.
...
getLastToken = function (a, b, c, d, e) { return this.eslint[name](a, b, c, d, e); }
...
* surrounding the node.
* @param {SourceCode} sourceCode The source code object
* @param {ASTNode} node An expression node
* @returns {string} The text representing the node, with all surrounding parentheses included
*/
getParenthesisedText(sourceCode, node) {
let leftToken = sourceCode.getFirstToken(node);
let rightToken = sourceCode.getLastToken(node);
while (
sourceCode.getTokenBefore(leftToken) &&
sourceCode.getTokenBefore(leftToken).type === "Punctuator" &&
sourceCode.getTokenBefore(leftToken).value === "(" &&
sourceCode.getTokenAfter(rightToken) &&
sourceCode.getTokenAfter(rightToken).type === "Punctuator" &&
...
getLastTokens = function (a, b, c, d, e) { return this.eslint[name](a, b, c, d, e); }
n/a
getNodeByRangeIndex = function (a, b, c, d, e) { return this.eslint[name](a, b, c, d, e); }
n/a
getScope = function (a, b, c, d, e) { return this.eslint[name](a, b, c, d, e); }
n/a
getSource = function (a, b, c, d, e) { return this.eslint[name](a, b, c, d, e); }
n/a
getSourceLines = function (a, b, c, d, e) { return this.eslint[name](a, b, c, d, e); }
n/a
getTokenAfter = function (a, b, c, d, e) { return this.eslint[name](a, b, c, d, e); }
...
* @param {SourceCode} sourceCode The ESLint source code object
* @param {ASTNode} node The node to be checked.
* @returns {boolean} True if the node is parenthesised.
* @private
*/
function isParenthesised(sourceCode, node) {
const previousToken = sourceCode.getTokenBefore(node),
nextToken = sourceCode.getTokenAfter(node);
return Boolean(previousToken && nextToken) &&
previousToken.value === "(" && previousToken.range[1] <= node.range[0] &&
nextToken.value === ")" && nextToken.range[0] >= node.range[1];
}
/**
...
getTokenBefore = function (a, b, c, d, e) { return this.eslint[name](a, b, c, d, e); }
...
* Determines if a node is surrounded by parentheses.
* @param {SourceCode} sourceCode The ESLint source code object
* @param {ASTNode} node The node to be checked.
* @returns {boolean} True if the node is parenthesised.
* @private
*/
function isParenthesised(sourceCode, node) {
const previousToken = sourceCode.getTokenBefore(node),
nextToken = sourceCode.getTokenAfter(node);
return Boolean(previousToken && nextToken) &&
previousToken.value === "(" && previousToken.range[1] <= node.range[0] &&
nextToken.value === ")" && nextToken.range[0] >= node.range[1];
}
...
getTokenByRangeStart = function (a, b, c, d, e) { return this.eslint[name](a, b, c, d, e); }
n/a
getTokens = function (a, b, c, d, e) { return this.eslint[name](a, b, c, d, e); }
n/a
getTokensAfter = function (a, b, c, d, e) { return this.eslint[name](a, b, c, d, e); }
n/a
getTokensBefore = function (a, b, c, d, e) { return this.eslint[name](a, b, c, d, e); }
n/a
getTokensBetween = function (a, b, c, d, e) { return this.eslint[name](a, b, c, d, e); }
n/a
markVariableAsUsed = function (a, b, c, d, e) { return this.eslint[name](a, b, c, d, e); }
n/a
function define(ruleId, ruleModule) { rules[ruleId] = ruleModule; }
n/a
function getHandler(ruleId) { if (typeof rules[ruleId] === "string") { return require(rules[ruleId]); } return rules[ruleId]; }
...
rules = require("../lib/rules");
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
const enabledRules = Object.keys(load()).reduce((result, ruleId) => {
if (!rules.get(ruleId).meta.deprecated) {
result[ruleId] = "error";
}
return result;
}, {});
//------------------------------------------------------------------------------
// Public Interface
...
function getAllLoadedRules() { const allRules = new Map(); Object.keys(rules).forEach(name => { const rule = getHandler(name); allRules.set(name, rule); }); return allRules; }
n/a
function importPlugin(plugin, pluginName) { if (plugin.rules) { Object.keys(plugin.rules).forEach(ruleId => { const qualifiedRuleId = `${pluginName}/${ruleId}`, rule = plugin.rules[ruleId]; define(qualifiedRuleId, rule); }); } }
n/a
function load(rulesDir, cwd) { const newRules = loadRules(rulesDir, cwd); Object.keys(newRules).forEach(ruleId => { define(ruleId, newRules[ruleId]); }); }
...
config = configToLoad;
if (config.extends) {
config = ConfigFile.applyExtends(config, filePath);
}
} else {
filePath = configToLoad;
config = ConfigFile.load(filePath);
}
}
return config;
}
...
function testClear() { rules = Object.create(null); }
n/a
testReset() { testClear(); load(); }
n/a
function time(key, fn) { if (typeof data[key] === "undefined") { data[key] = 0; } return function() { let t = process.hrtime(); fn.apply(null, Array.prototype.slice.call(arguments)); t = process.hrtime(t); data[key] += t[0] * 1e3 + t[1] / 1e6; }; }
n/a