Skip to content

Commit cc403f5

Browse files
magic-akariCopilotoverlookmotel
authored
fix(linter/plugins): Return empty object for unimplemented parserServices (#15364)
## Summary - Changed `sourceCode.parserServices` from throwing an error to returning an empty object `{}` - Aligns with ESLint specification for parsers that don't implement parser services - Prevents crashes in ESLint plugins such as `eslint-plugin-better-tailwindcss`. ## Motivation According to the [ESLint custom parser documentation](https://eslint.org/docs/latest/extend/custom-parsers#parseforeslint-return-object): > services can contain any parser-dependent services (such as type checkers for nodes). The value of the services property is available to rules as context.sourceCode.parserServices. **Default is an empty object.** The current implementation throws an error when `parserServices` is accessed, which breaks plugins that use defensive checks like: ```typescript if(typeof ctx.sourceCode.parserServices?.defineTemplateBodyVisitor === "function"){ // ... } ``` Plugin authors defensively handle: - ✅ `parserServices` being undefined - ✅ `defineTemplateBodyVisitor` not existing - ❌ `parserServices` getter throwing an error (unexpected) ## Solution Return an empty object `{}` for unimplemented parser services, which: 1. Matches ESLint's documented default behavior 2. Allows plugins' defensive checks to work correctly 3. Provides correct semantics for "not implemented" ## Test Plan - Existing tests should continue to pass - Plugins using defensive checks like the example above will no longer crash ## Related Fixes the compatibility issue with plugins like [eslint-plugin-better-tailwindcss](https://github.com/schoero/eslint-plugin-better-tailwindcss/blob/a90cc3f547098a4293d7b0b7998bf6774f717cd2/src/utils/rule.ts#L140) --------- Signed-off-by: magic-akari <akari.ccino@gmail.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: overlookmotel <theoverlookmotel@gmail.com>
1 parent b1d3e00 commit cc403f5

File tree

6 files changed

+68
-1
lines changed

6 files changed

+68
-1
lines changed

apps/oxlint/src-js/plugins/source_code.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ export const SOURCE_CODE = Object.freeze({
127127

128128
// Get parser services for the file.
129129
get parserServices(): { [key: string]: unknown } {
130-
throw new Error('`sourceCode.parserServices` not implemented yet'); // TODO
130+
return {}; // TODO
131131
},
132132

133133
// Get source text as array of lines, split according to specification's definition of line breaks.

apps/oxlint/test/e2e.test.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,4 +254,8 @@ describe('oxlint CLI', () => {
254254
it('should support UTF16 characters in source code and comments with correct spans', async () => {
255255
await testFixture('unicode-comments');
256256
});
257+
258+
it('should return empty object for `parserServices` without throwing', async () => {
259+
await testFixture('parser_services');
260+
});
257261
});
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"jsPlugins": ["./plugin.ts"],
3+
"categories": {
4+
"correctness": "off"
5+
},
6+
"rules": {
7+
"parser-services-plugin/check-parser-services": "error"
8+
}
9+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// Simple file to test parserServices access
2+
console.log('testing parserServices');
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Exit code
2+
1
3+
4+
# stdout
5+
```
6+
x parser-services-plugin(check-parser-services): typeof context.sourceCode.parserServices: object
7+
,-[files/index.js:1:1]
8+
1 | // Simple file to test parserServices access
9+
: ^
10+
2 | console.log('testing parserServices');
11+
`----
12+
13+
Found 0 warnings and 1 error.
14+
Finished in Xms on 1 file using X threads.
15+
```
16+
17+
# stderr
18+
```
19+
WARNING: JS plugins are experimental and not subject to semver.
20+
Breaking changes are possible while JS plugins support is under development.
21+
```
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import type { Plugin, Node } from '../../../dist/index.js';
2+
3+
const SPAN: Node = {
4+
start: 0,
5+
end: 0,
6+
range: [0, 0],
7+
loc: {
8+
start: { line: 0, column: 0 },
9+
end: { line: 0, column: 0 },
10+
},
11+
};
12+
13+
const plugin: Plugin = {
14+
meta: {
15+
name: 'parser-services-plugin',
16+
},
17+
rules: {
18+
'check-parser-services': {
19+
create(context) {
20+
context.report({
21+
message: `typeof context.sourceCode.parserServices: ${typeof context.sourceCode.parserServices}`,
22+
node: SPAN,
23+
});
24+
25+
return {};
26+
},
27+
},
28+
},
29+
};
30+
31+
export default plugin;

0 commit comments

Comments
 (0)