From b16210465f8ed8400ffd1d5ec4566fad068f6405 Mon Sep 17 00:00:00 2001 From: Nitin Kumar Date: Sun, 23 Apr 2023 09:25:33 +0530 Subject: [PATCH 1/6] feat: add `physicalFilename` property to the rule context --- lib/linter/linter.js | 1 + tests/lib/linter/linter.js | 52 +++++++++++++++++++++++++++++++------- 2 files changed, 44 insertions(+), 9 deletions(-) diff --git a/lib/linter/linter.js b/lib/linter/linter.js index 27345e771fc..c3ff7bbe455 100644 --- a/lib/linter/linter.js +++ b/lib/linter/linter.js @@ -955,6 +955,7 @@ function runRules(sourceCode, configuredRules, ruleMapper, parserName, languageO getFilename: () => filename, filename, getPhysicalFilename: () => physicalFilename || filename, + physicalFilename: physicalFilename || filename, getScope: () => sourceCode.getScope(currentNode), getSourceCode: () => sourceCode, markVariableAsUsed: name => sourceCode.markVariableAsUsed(name, currentNode), diff --git a/tests/lib/linter/linter.js b/tests/lib/linter/linter.js index a487eb23662..e1d011621e6 100644 --- a/tests/lib/linter/linter.js +++ b/tests/lib/linter/linter.js @@ -1847,7 +1847,7 @@ describe("Linter", () => { linter.defineRule(code, { create: context => ({ Literal(node) { - context.report(node, context.getPhysicalFilename()); + context.report(node, context.physicalFilename); } }) }); @@ -4868,7 +4868,7 @@ var a = "test2"; describe("physicalFilenames", () => { it("should be same as `filename` passed on options object, if no processors are used", () => { const physicalFilenameChecker = sinon.spy(context => { - assert.strictEqual(context.getPhysicalFilename(), "foo.js"); + assert.strictEqual(context.physicalFilename, "foo.js"); return {}; }); @@ -4879,7 +4879,7 @@ var a = "test2"; it("should default physicalFilename to when options object doesn't have filename", () => { const physicalFilenameChecker = sinon.spy(context => { - assert.strictEqual(context.getPhysicalFilename(), ""); + assert.strictEqual(context.physicalFilename, ""); return {}; }); @@ -4890,7 +4890,7 @@ var a = "test2"; it("should default physicalFilename to when only two arguments are passed", () => { const physicalFilenameChecker = sinon.spy(context => { - assert.strictEqual(context.getPhysicalFilename(), ""); + assert.strictEqual(context.physicalFilename, ""); return {}; }); @@ -6757,7 +6757,7 @@ var a = "test2"; create: context => ({ Program(ast) { receivedFilenames.push(context.filename); - receivedPhysicalFilenames.push(context.getPhysicalFilename()); + receivedPhysicalFilenames.push(context.physicalFilename); context.report({ node: ast, message: context.getSourceCode().text }); } }) @@ -9211,6 +9211,40 @@ describe("Linter with FlatConfigArray", () => { }); + describe("context.physicalFilename", () => { + + const ruleId = "filename-rule"; + + it("has access to the physicalFilename", () => { + + const config = { + plugins: { + test: { + rules: { + [ruleId]: { + create: context => ({ + Literal(node) { + context.report(node, context.physicalFilename); + } + }) + } + } + } + }, + rules: { + [`test/${ruleId}`]: 1 + } + }; + + const messages = linter.verify("0", config, filename); + const suppressedMessages = linter.getSuppressedMessages(); + + assert.strictEqual(messages[0].message, filename); + assert.strictEqual(suppressedMessages.length, 0); + }); + + }); + describe("context.getSourceLines()", () => { it("should get proper lines when using \\n as a line break", () => { @@ -11310,7 +11344,7 @@ describe("Linter with FlatConfigArray", () => { describe("physicalFilename", () => { it("should be same as `filename` passed on options object, if no processors are used", () => { const physicalFilenameChecker = sinon.spy(context => { - assert.strictEqual(context.getPhysicalFilename(), "foo.js"); + assert.strictEqual(context.physicalFilename, "foo.js"); return {}; }); @@ -11333,7 +11367,7 @@ describe("Linter with FlatConfigArray", () => { it("should default physicalFilename to when options object doesn't have filename", () => { const physicalFilenameChecker = sinon.spy(context => { - assert.strictEqual(context.getPhysicalFilename(), ""); + assert.strictEqual(context.physicalFilename, ""); return {}; }); @@ -11356,7 +11390,7 @@ describe("Linter with FlatConfigArray", () => { it("should default physicalFilename to when only two arguments are passed", () => { const physicalFilenameChecker = sinon.spy(context => { - assert.strictEqual(context.getPhysicalFilename(), ""); + assert.strictEqual(context.physicalFilename, ""); return {}; }); @@ -15523,7 +15557,7 @@ var a = "test2"; return { Program(ast) { receivedFilenames.push(context.filename); - receivedPhysicalFilenames.push(context.getPhysicalFilename()); + receivedPhysicalFilenames.push(context.physicalFilename); context.report({ node: ast, message: context.getSourceCode().text }); } }; From 2008de93a8fc16d7da7191b1c40f4aa1d3422c3b Mon Sep 17 00:00:00 2001 From: Nitin Kumar Date: Sun, 23 Apr 2023 09:29:00 +0530 Subject: [PATCH 2/6] docs: mark `context.getPhysicalFilename()` as deprecated --- docs/src/extend/custom-rules.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/src/extend/custom-rules.md b/docs/src/extend/custom-rules.md index d561651c0d3..afe5bead5e0 100644 --- a/docs/src/extend/custom-rules.md +++ b/docs/src/extend/custom-rules.md @@ -132,7 +132,7 @@ The `context` object has the following properties: * `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.) * `parserOptions`: The parser options configured for this run (more details [here](../use/configure/language-options#specifying-parser-options)). -Additionally, the `context` object has the following methods: +Additionally, the `context` object has the following methods & properties: * `getAncestors()`: (**Deprecated:** Use `SourceCode#getAncestors(node)` instead.) Returns an array of the ancestors of the currently-traversed node, starting at the root of the AST and continuing through the direct parent of the current node. This array does not include the currently-traversed node itself. * `getCwd()`: (**Deprecated:** Use `context.cwd` instead.) Returns 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. @@ -147,7 +147,8 @@ Additionally, the `context` object has the following methods: * If the node is an `ImportSpecifier`, `ImportDefaultSpecifier`, or `ImportNamespaceSpecifier`, the declared variable is returned. * Otherwise, if the node does not declare any variables, an empty array is returned. * `getFilename()`: (**Deprecated:** Use `context.filename` instead.) Returns the filename associated with the source. -* `getPhysicalFilename()`: 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 `` if not specified. +* `getFilename()`: 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 `` 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)). * `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`. From e566cc594f15e59194f81b473df7a92ade1de1a9 Mon Sep 17 00:00:00 2001 From: Nitin Kumar Date: Thu, 27 Apr 2023 19:13:18 +0530 Subject: [PATCH 3/6] tests: add asertions for context.getPhysicalFilename() --- docs/src/extend/custom-rules.md | 3 ++- tests/lib/linter/linter.js | 8 ++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/docs/src/extend/custom-rules.md b/docs/src/extend/custom-rules.md index afe5bead5e0..b6138bac9e2 100644 --- a/docs/src/extend/custom-rules.md +++ b/docs/src/extend/custom-rules.md @@ -125,6 +125,7 @@ The `context` object has the following properties: * `id`: (`string`) The rule ID. * `filename`: (`string`) The filename associated with the source. +* `physicalFilename`: (`string`) 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 `` 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)). * `settings`: (`object`) The [shared settings](../use/configure/configuration-files#adding-shared-settings) from the configuration. @@ -132,7 +133,7 @@ The `context` object has the following properties: * `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.) * `parserOptions`: The parser options configured for this run (more details [here](../use/configure/language-options#specifying-parser-options)). -Additionally, the `context` object has the following methods & properties: +Additionally, the `context` object has the following methods: * `getAncestors()`: (**Deprecated:** Use `SourceCode#getAncestors(node)` instead.) Returns an array of the ancestors of the currently-traversed node, starting at the root of the AST and continuing through the direct parent of the current node. This array does not include the currently-traversed node itself. * `getCwd()`: (**Deprecated:** Use `context.cwd` instead.) Returns 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. diff --git a/tests/lib/linter/linter.js b/tests/lib/linter/linter.js index e1d011621e6..c215f8a1168 100644 --- a/tests/lib/linter/linter.js +++ b/tests/lib/linter/linter.js @@ -1847,6 +1847,7 @@ describe("Linter", () => { linter.defineRule(code, { create: context => ({ Literal(node) { + assert.strictEqual(context.getPhysicalFilename(), context.physicalFilename); context.report(node, context.physicalFilename); } }) @@ -4868,6 +4869,7 @@ var a = "test2"; describe("physicalFilenames", () => { it("should be same as `filename` passed on options object, if no processors are used", () => { const physicalFilenameChecker = sinon.spy(context => { + assert.strictEqual(context.getPhysicalFilename(), context.physicalFilename); assert.strictEqual(context.physicalFilename, "foo.js"); return {}; }); @@ -4879,6 +4881,7 @@ var a = "test2"; it("should default physicalFilename to when options object doesn't have filename", () => { const physicalFilenameChecker = sinon.spy(context => { + assert.strictEqual(context.getPhysicalFilename(), context.physicalFilename); assert.strictEqual(context.physicalFilename, ""); return {}; }); @@ -4890,6 +4893,7 @@ var a = "test2"; it("should default physicalFilename to when only two arguments are passed", () => { const physicalFilenameChecker = sinon.spy(context => { + assert.strictEqual(context.getPhysicalFilename(), context.physicalFilename); assert.strictEqual(context.physicalFilename, ""); return {}; }); @@ -9224,6 +9228,7 @@ describe("Linter with FlatConfigArray", () => { [ruleId]: { create: context => ({ Literal(node) { + assert.strictEqual(context.getPhysicalFilename(), context.physicalFilename); context.report(node, context.physicalFilename); } }) @@ -11344,6 +11349,7 @@ describe("Linter with FlatConfigArray", () => { describe("physicalFilename", () => { it("should be same as `filename` passed on options object, if no processors are used", () => { const physicalFilenameChecker = sinon.spy(context => { + assert.strictEqual(context.getPhysicalFilename(), context.physicalFilename); assert.strictEqual(context.physicalFilename, "foo.js"); return {}; }); @@ -11367,6 +11373,7 @@ describe("Linter with FlatConfigArray", () => { it("should default physicalFilename to when options object doesn't have filename", () => { const physicalFilenameChecker = sinon.spy(context => { + assert.strictEqual(context.getPhysicalFilename(), context.physicalFilename); assert.strictEqual(context.physicalFilename, ""); return {}; }); @@ -11390,6 +11397,7 @@ describe("Linter with FlatConfigArray", () => { it("should default physicalFilename to when only two arguments are passed", () => { const physicalFilenameChecker = sinon.spy(context => { + assert.strictEqual(context.getPhysicalFilename(), context.physicalFilename); assert.strictEqual(context.physicalFilename, ""); return {}; }); From 0a8d71eb21bd1d3f6a27bf2aef504aa532d8c32e Mon Sep 17 00:00:00 2001 From: Nitin Kumar Date: Sat, 29 Apr 2023 15:13:42 +0530 Subject: [PATCH 4/6] docs: update context.physicalFilename description --- docs/src/extend/custom-rules.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/extend/custom-rules.md b/docs/src/extend/custom-rules.md index b6138bac9e2..af91c5352ea 100644 --- a/docs/src/extend/custom-rules.md +++ b/docs/src/extend/custom-rules.md @@ -125,7 +125,7 @@ The `context` object has the following properties: * `id`: (`string`) The rule ID. * `filename`: (`string`) The filename associated with the source. -* `physicalFilename`: (`string`) 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 `` if not specified. +* `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 `` 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)). * `settings`: (`object`) The [shared settings](../use/configure/configuration-files#adding-shared-settings) from the configuration. From ab439ffea7240dfa4371d575cd93df382dd88a93 Mon Sep 17 00:00:00 2001 From: Nitin Kumar Date: Sat, 29 Apr 2023 15:15:29 +0530 Subject: [PATCH 5/6] docs: remove duplicate changes --- docs/src/extend/custom-rules.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/src/extend/custom-rules.md b/docs/src/extend/custom-rules.md index af91c5352ea..6d69f1a4a67 100644 --- a/docs/src/extend/custom-rules.md +++ b/docs/src/extend/custom-rules.md @@ -148,7 +148,6 @@ Additionally, the `context` object has the following methods: * If the node is an `ImportSpecifier`, `ImportDefaultSpecifier`, or `ImportNamespaceSpecifier`, the declared variable is returned. * Otherwise, if the node does not declare any variables, an empty array is returned. * `getFilename()`: (**Deprecated:** Use `context.filename` instead.) Returns the filename associated with the source. -* `getFilename()`: 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 `` 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)). From 012acae6631a245ab1c7b5ff03edf623c6d3272d Mon Sep 17 00:00:00 2001 From: Nitin Kumar Date: Sat, 29 Apr 2023 16:25:18 +0530 Subject: [PATCH 6/6] tests: add more assertions for `getFilename()` and `getPhysicalFilename()` --- tests/lib/linter/linter.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/lib/linter/linter.js b/tests/lib/linter/linter.js index c215f8a1168..13824c9da49 100644 --- a/tests/lib/linter/linter.js +++ b/tests/lib/linter/linter.js @@ -6760,6 +6760,9 @@ var a = "test2"; linter.defineRule("report-original-text", { create: context => ({ Program(ast) { + assert.strictEqual(context.getFilename(), context.filename); + assert.strictEqual(context.getPhysicalFilename(), context.physicalFilename); + receivedFilenames.push(context.filename); receivedPhysicalFilenames.push(context.physicalFilename); context.report({ node: ast, message: context.getSourceCode().text }); @@ -15564,6 +15567,9 @@ var a = "test2"; create(context) { return { Program(ast) { + assert.strictEqual(context.getFilename(), context.filename); + assert.strictEqual(context.getPhysicalFilename(), context.physicalFilename); + receivedFilenames.push(context.filename); receivedPhysicalFilenames.push(context.physicalFilename); context.report({ node: ast, message: context.getSourceCode().text });