Skip to content

Commit

Permalink
feat: add sourceCode property to the rule context (#17107)
Browse files Browse the repository at this point in the history
* feat: add `sourceCode` to the rule context

* docs: mark `context#getSourceCode()` as deprecated

* reafctor: prefer to use context.sourceCode and add tests for getSourceCode()

* docs: add deprecation note for context.getScope()

* docs: update docs/src/extend/custom-rules.md

Co-authored-by: Milos Djermanovic <milos.djermanovic@gmail.com>

---------

Co-authored-by: Milos Djermanovic <milos.djermanovic@gmail.com>
  • Loading branch information
snitin315 and mdjermanovic committed May 3, 2023
1 parent e980bf3 commit e52b98b
Show file tree
Hide file tree
Showing 222 changed files with 272 additions and 260 deletions.
2 changes: 1 addition & 1 deletion docs/src/extend/code-path-analysis.md
Expand Up @@ -259,7 +259,7 @@ Please use a map of information instead.
```js
function hasCb(node, context) {
if (node.type.indexOf("Function") !== -1) {
const sourceCode = context.getSourceCode();
const sourceCode = context.sourceCode;
return sourceCode.getDeclaredVariables(node).some(function(v) {
return v.type === "Parameter" && v.name === "cb";
});
Expand Down
11 changes: 7 additions & 4 deletions docs/src/extend/custom-rules.md
Expand Up @@ -128,6 +128,7 @@ The `context` object has the following properties:
* `physicalFilename`: (`string`) When linting a file, it provides the full path of the file on disk without any code block information. When linting text, it provides the value passed to `—stdin-filename` or `<text>` if not specified.
* `cwd`: (`string`) The `cwd` option passed to the [Linter](../integrate/nodejs-api#linter). It is a path to a directory that should be considered the current working directory.
* `options`: (`array`) An array of the [configured options](../use/configure/rules) for this rule. This array does not include the rule severity (see the [dedicated section](#accessing-options-passed-to-a-rule)).
* `sourceCode`: (`object`) A `SourceCode` object that you can use to work with the source that was passed to ESLint (see [Accessing the Source Code](#accessing-the-source-code)).
* `settings`: (`object`) The [shared settings](../use/configure/configuration-files#adding-shared-settings) from the configuration.
* `parserPath`: (`string`) The name of the `parser` from the configuration.
* `parserServices`: (`object`) Contains parser-provided services for rules. The default parser does not provide any services. However, if a rule is intended to be used with a custom parser, it could use `parserServices` to access anything provided by that parser. (For example, a TypeScript parser could provide the ability to get the computed type of a given node.)
Expand All @@ -150,7 +151,7 @@ Additionally, the `context` object has the following methods:
* `getFilename()`: (**Deprecated:** Use `context.filename` instead.) Returns the filename associated with the source.
* `getPhysicalFilename()`: (**Deprecated:** Use `context.physicalFilename` instead.) When linting a file, it returns the full path of the file on disk without any code block information. When linting text, it returns the value passed to `—stdin-filename` or `<text>` if not specified.
* `getScope()`: (**Deprecated:** Use `SourceCode#getScope(node)` instead.) Returns the [scope](./scope-manager-interface#scope-interface) of the currently-traversed node. This information can be used to track references to variables.
* `getSourceCode()`: Returns a `SourceCode` object that you can use to work with the source that was passed to ESLint (see [Accessing the Source Code](#accessing-the-source-code)).
* `getSourceCode()`: (**Deprecated:** Use `context.sourceCode` instead.) Returns a `SourceCode` object that you can use to work with the source that was passed to ESLint (see [Accessing the Source Code](#accessing-the-source-code)).
* `markVariableAsUsed(name)`: (**Deprecated:** Use `SourceCode#markVariableAsUsed(name, node)` instead.) Marks a variable with the given name in the current scope as used. This affects the [no-unused-vars](../rules/no-unused-vars) rule. Returns `true` if a variable with the given name was found and marked as used, otherwise `false`.
* `report(descriptor)`. Reports a problem in the code (see the [dedicated section](#reporting-problems)).

Expand Down Expand Up @@ -509,18 +510,20 @@ When using options, make sure that your rule has some logical defaults in case t

### Accessing the Source Code

The `SourceCode` object is the main object for getting more information about the source code being linted. You can retrieve the `SourceCode` object at any time by using the `context.getSourceCode()` method:
The `SourceCode` object is the main object for getting more information about the source code being linted. You can retrieve the `SourceCode` object at any time by using the `context.sourceCode` property:

```js
module.exports = {
create: function(context) {
var sourceCode = context.getSourceCode();
var sourceCode = context.sourceCode;

// ...
}
};
```

**Deprecated:** The `context.getSourceCode()` method is deprecated; make sure to use `context.sourceCode` property instead.

Once you have an instance of `SourceCode`, you can use the following methods on it to work with the code:

* `getText(node)`: Returns the source code for the given node. Omit `node` to get the whole source (see the [dedicated section](#accessing-the-source-text)).
Expand Down Expand Up @@ -712,7 +715,7 @@ To help with this, you can use the `sourceCode.markVariableAsUsed()` method. Thi
```js
module.exports = {
create: function(context) {
var sourceCode = context.getSourceCode();
var sourceCode = context.sourceCode;

return {
ReturnStatement(node) {
Expand Down
3 changes: 2 additions & 1 deletion lib/linter/linter.js
Expand Up @@ -902,7 +902,7 @@ const BASE_TRAVERSAL_CONTEXT = Object.freeze(
(contextInfo, methodName) =>
Object.assign(contextInfo, {
[methodName](...args) {
return this.getSourceCode()[DEPRECATED_SOURCECODE_PASSTHROUGHS[methodName]](...args);
return this.sourceCode[DEPRECATED_SOURCECODE_PASSTHROUGHS[methodName]](...args);
}
}),
{}
Expand Down Expand Up @@ -958,6 +958,7 @@ function runRules(sourceCode, configuredRules, ruleMapper, parserName, languageO
physicalFilename: physicalFilename || filename,
getScope: () => sourceCode.getScope(currentNode),
getSourceCode: () => sourceCode,
sourceCode,
markVariableAsUsed: name => sourceCode.markVariableAsUsed(name, currentNode),
parserOptions: {
...languageOptions.parserOptions
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/accessor-pairs.js
Expand Up @@ -178,7 +178,7 @@ module.exports = {
const checkGetWithoutSet = config.getWithoutSet === true;
const checkSetWithoutGet = config.setWithoutGet !== false;
const enforceForClassMembers = config.enforceForClassMembers !== false;
const sourceCode = context.getSourceCode();
const sourceCode = context.sourceCode;

/**
* Reports the given node.
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/array-bracket-newline.js
Expand Up @@ -56,7 +56,7 @@ module.exports = {
},

create(context) {
const sourceCode = context.getSourceCode();
const sourceCode = context.sourceCode;


//----------------------------------------------------------------------
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/array-bracket-spacing.js
Expand Up @@ -53,7 +53,7 @@ module.exports = {
},
create(context) {
const spaced = context.options[0] === "always",
sourceCode = context.getSourceCode();
sourceCode = context.sourceCode;

/**
* Determines whether an option is set, relative to the spacing option.
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/array-callback-return.js
Expand Up @@ -172,7 +172,7 @@ module.exports = {
create(context) {

const options = context.options[0] || { allowImplicit: false, checkForEach: false };
const sourceCode = context.getSourceCode();
const sourceCode = context.sourceCode;

let funcInfo = {
arrayMethodName: null,
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/array-element-newline.js
Expand Up @@ -79,7 +79,7 @@ module.exports = {
},

create(context) {
const sourceCode = context.getSourceCode();
const sourceCode = context.sourceCode;

//----------------------------------------------------------------------
// Helpers
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/arrow-body-style.js
Expand Up @@ -74,7 +74,7 @@ module.exports = {
const asNeeded = !options[0] || options[0] === "as-needed";
const never = options[0] === "never";
const requireReturnForObjectLiteral = options[1] && options[1].requireReturnForObjectLiteral;
const sourceCode = context.getSourceCode();
const sourceCode = context.sourceCode;
let funcInfo = null;

/**
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/arrow-parens.js
Expand Up @@ -69,7 +69,7 @@ module.exports = {
const asNeeded = context.options[0] === "as-needed";
const requireForBlockBody = asNeeded && context.options[1] && context.options[1].requireForBlockBody === true;

const sourceCode = context.getSourceCode();
const sourceCode = context.sourceCode;

/**
* Finds opening paren of parameters for the given arrow function, if it exists.
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/arrow-spacing.js
Expand Up @@ -61,7 +61,7 @@ module.exports = {
rule.before = rule.before !== false;
rule.after = rule.after !== false;

const sourceCode = context.getSourceCode();
const sourceCode = context.sourceCode;

/**
* Get tokens of arrow(`=>`) and before/after arrow.
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/block-scoped-var.js
Expand Up @@ -28,7 +28,7 @@ module.exports = {

create(context) {
let stack = [];
const sourceCode = context.getSourceCode();
const sourceCode = context.sourceCode;

/**
* Makes a block scope.
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/block-spacing.js
Expand Up @@ -37,7 +37,7 @@ module.exports = {
create(context) {
const always = (context.options[0] !== "never"),
messageId = always ? "missing" : "extra",
sourceCode = context.getSourceCode();
sourceCode = context.sourceCode;

/**
* Gets the open brace token from a given node.
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/brace-style.js
Expand Up @@ -53,7 +53,7 @@ module.exports = {
create(context) {
const style = context.options[0] || "1tbs",
params = context.options[1] || {},
sourceCode = context.getSourceCode();
sourceCode = context.sourceCode;

//--------------------------------------------------------------------------
// Helpers
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/callback-return.js
Expand Up @@ -37,7 +37,7 @@ module.exports = {
create(context) {

const callbacks = context.options[0] || ["callback", "cb", "next"],
sourceCode = context.getSourceCode();
sourceCode = context.sourceCode;

//--------------------------------------------------------------------------
// Helpers
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/camelcase.js
Expand Up @@ -73,7 +73,7 @@ module.exports = {
const ignoreImports = options.ignoreImports;
const ignoreGlobals = options.ignoreGlobals;
const allow = options.allow || [];
const sourceCode = context.getSourceCode();
const sourceCode = context.sourceCode;

//--------------------------------------------------------------------------
// Helpers
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/capitalized-comments.js
Expand Up @@ -139,7 +139,7 @@ module.exports = {

const capitalize = context.options[0] || "always",
normalizedOptions = getAllNormalizedOptions(context.options[1]),
sourceCode = context.getSourceCode();
sourceCode = context.sourceCode;

createRegExpForIgnorePatterns(normalizedOptions);

Expand Down
2 changes: 1 addition & 1 deletion lib/rules/class-methods-use-this.js
Expand Up @@ -133,7 +133,7 @@ module.exports = {
if (isIncludedInstanceMethod(node.parent) && !methodUsesThis) {
context.report({
node,
loc: astUtils.getFunctionHeadLoc(node, context.getSourceCode()),
loc: astUtils.getFunctionHeadLoc(node, context.sourceCode),
messageId: "missingThis",
data: {
name: astUtils.getFunctionNameWithKind(node)
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/comma-dangle.js
Expand Up @@ -136,7 +136,7 @@ module.exports = {
create(context) {
const options = normalizeOptions(context.options[0], context.languageOptions.ecmaVersion);

const sourceCode = context.getSourceCode();
const sourceCode = context.sourceCode;

/**
* Gets the last item of the given node.
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/comma-spacing.js
Expand Up @@ -48,7 +48,7 @@ module.exports = {

create(context) {

const sourceCode = context.getSourceCode();
const sourceCode = context.sourceCode;
const tokensAndComments = sourceCode.tokensAndComments;

const options = {
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/comma-style.js
Expand Up @@ -51,7 +51,7 @@ module.exports = {

create(context) {
const style = context.options[0] || "last",
sourceCode = context.getSourceCode();
sourceCode = context.sourceCode;
const exceptions = {
ArrayPattern: true,
ArrowFunctionExpression: true,
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/computed-property-spacing.js
Expand Up @@ -49,7 +49,7 @@ module.exports = {
},

create(context) {
const sourceCode = context.getSourceCode();
const sourceCode = context.sourceCode;
const propertyNameMustBeSpaced = context.options[0] === "always"; // default is "never"
const enforceForClassMembers = !context.options[1] || context.options[1].enforceForClassMembers;

Expand Down
4 changes: 2 additions & 2 deletions lib/rules/consistent-return.js
Expand Up @@ -104,7 +104,7 @@ module.exports = {
} else if (node.type === "ArrowFunctionExpression") {

// `=>` token
loc = context.getSourceCode().getTokenBefore(node.body, astUtils.isArrowToken).loc;
loc = context.sourceCode.getTokenBefore(node.body, astUtils.isArrowToken).loc;
} else if (
node.parent.type === "MethodDefinition" ||
(node.parent.type === "Property" && node.parent.method)
Expand All @@ -115,7 +115,7 @@ module.exports = {
} else {

// Function name or `function` keyword.
loc = (node.id || context.getSourceCode().getFirstToken(node)).loc;
loc = (node.id || context.sourceCode.getFirstToken(node)).loc;
}

if (!name) {
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/consistent-this.js
Expand Up @@ -36,7 +36,7 @@ module.exports = {

create(context) {
let aliases = [];
const sourceCode = context.getSourceCode();
const sourceCode = context.sourceCode;

if (context.options.length === 0) {
aliases.push("that");
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/curly.js
Expand Up @@ -70,7 +70,7 @@ module.exports = {
const multiOrNest = (context.options[0] === "multi-or-nest");
const consistent = (context.options[1] === "consistent");

const sourceCode = context.getSourceCode();
const sourceCode = context.sourceCode;

//--------------------------------------------------------------------------
// Helpers
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/default-case.js
Expand Up @@ -42,7 +42,7 @@ module.exports = {
? new RegExp(options.commentPattern, "u")
: DEFAULT_COMMENT_PATTERN;

const sourceCode = context.getSourceCode();
const sourceCode = context.sourceCode;

//--------------------------------------------------------------------------
// Helpers
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/dot-location.js
Expand Up @@ -43,7 +43,7 @@ module.exports = {
// default to onObject if no preference is passed
const onObject = config === "object" || !config;

const sourceCode = context.getSourceCode();
const sourceCode = context.sourceCode;

/**
* Reports if the dot between object and property is on the correct location.
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/dot-notation.js
Expand Up @@ -59,7 +59,7 @@ module.exports = {
create(context) {
const options = context.options[0] || {};
const allowKeywords = options.allowKeywords === void 0 || options.allowKeywords;
const sourceCode = context.getSourceCode();
const sourceCode = context.sourceCode;

let allowPattern;

Expand Down
2 changes: 1 addition & 1 deletion lib/rules/eol-last.js
Expand Up @@ -40,7 +40,7 @@ module.exports = {

return {
Program: function checkBadEOF(node) {
const sourceCode = context.getSourceCode(),
const sourceCode = context.sourceCode,
src = sourceCode.getText(),
lastLine = sourceCode.lines[sourceCode.lines.length - 1],
location = {
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/eqeqeq.js
Expand Up @@ -68,7 +68,7 @@ module.exports = {
create(context) {
const config = context.options[0] || "always";
const options = context.options[1] || {};
const sourceCode = context.getSourceCode();
const sourceCode = context.sourceCode;

const nullOption = (config === "always")
? options.null || "always"
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/func-call-spacing.js
Expand Up @@ -73,7 +73,7 @@ module.exports = {

const never = context.options[0] !== "always";
const allowNewlines = !never && context.options[1] && context.options[1].allowNewlines;
const sourceCode = context.getSourceCode();
const sourceCode = context.sourceCode;
const text = sourceCode.getText();

/**
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/func-names.js
Expand Up @@ -69,7 +69,7 @@ module.exports = {

create(context) {

const sourceCode = context.getSourceCode();
const sourceCode = context.sourceCode;

/**
* Returns the config option for the given node.
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/function-call-argument-newline.js
Expand Up @@ -35,7 +35,7 @@ module.exports = {
},

create(context) {
const sourceCode = context.getSourceCode();
const sourceCode = context.sourceCode;

const checkers = {
unexpected: {
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/function-paren-newline.js
Expand Up @@ -57,7 +57,7 @@ module.exports = {
},

create(context) {
const sourceCode = context.getSourceCode();
const sourceCode = context.sourceCode;
const rawOption = context.options[0] || "multiline";
const multilineOption = rawOption === "multiline";
const multilineArgumentsOption = rawOption === "multiline-arguments";
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/generator-star-spacing.js
Expand Up @@ -102,7 +102,7 @@ module.exports = {
};
}(context.options[0] || {}));

const sourceCode = context.getSourceCode();
const sourceCode = context.sourceCode;

/**
* Checks if the given token is a star token or not.
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/getter-return.js
Expand Up @@ -64,7 +64,7 @@ module.exports = {
create(context) {

const options = context.options[0] || { allowImplicit: false };
const sourceCode = context.getSourceCode();
const sourceCode = context.sourceCode;

let funcInfo = {
upper: null,
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/global-require.js
Expand Up @@ -71,7 +71,7 @@ module.exports = {
},

create(context) {
const sourceCode = context.getSourceCode();
const sourceCode = context.sourceCode;

return {
CallExpression(node) {
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/grouped-accessor-pairs.js
Expand Up @@ -115,7 +115,7 @@ module.exports = {

create(context) {
const order = context.options[0] || "anyOrder";
const sourceCode = context.getSourceCode();
const sourceCode = context.sourceCode;

/**
* Reports the given accessor pair.
Expand Down

0 comments on commit e52b98b

Please sign in to comment.