-
Notifications
You must be signed in to change notification settings - Fork 4
FIX @W-21462752@ - Fix parser not configured when both JS and LWC base configs d… #431
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
aruntyagiTutu
merged 4 commits into
dev
from
bugfix/eslint-parser-when-both-base-configs-disabled
Mar 9, 2026
Merged
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
9a7e104
BUGFIX: Fix parser not configured when both JS and LWC base configs d…
aruntyagiTutu bb32d7f
BUGFIX: Add TypeScript parser config when disable_typescript_base_con…
aruntyagiTutu 3211f0f
TEST: Add comprehensive integration tests for parser configs with var…
aruntyagiTutu e2c9c54
DOCS: Improve documentation and test clarity for parser selection str…
aruntyagiTutu File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,6 +10,48 @@ import eslintPluginJsxA11y from "eslint-plugin-jsx-a11y"; | |
| import {ESLintEngineConfig} from "./config"; | ||
| import globals from "globals"; | ||
|
|
||
| /** | ||
| * BaseConfigFactory creates ESLint configurations based on user preferences and file types. | ||
| * | ||
| * Parser Selection Strategy: | ||
| * ========================== | ||
| * | ||
| * JavaScript Files (.js, .jsx, .mjs, .cjs): | ||
| * ----------------------------------------- | ||
| * 1. Both JS + LWC enabled → Full LWC config with Babel parser and all JS/LWC rules | ||
| * 2. Only JS enabled → JavaScript config with smart parser selection: | ||
| * - .js files: Babel (supports decorators + JSX) | ||
| * - .jsx/.mjs/.cjs: Espree (better performance) | ||
| * 3. Only LWC enabled → LWC config with Babel parser (no base JS rules) | ||
| * 4. Both JS + LWC disabled → Minimal parser config only (NO rules applied): | ||
| * - .js files: Babel for decorator support | ||
| * - .jsx/.mjs/.cjs: Espree with JSX support | ||
| * | ||
| * TypeScript Files (.ts, .tsx, .mts, .cts): | ||
| * ------------------------------------------ | ||
| * 1. TS enabled → Full TypeScript config with typescript-eslint parser, | ||
| * all TS rules, and projectService for type-aware linting | ||
| * 2. TS disabled → Minimal TypeScript parser config (NO rules applied): | ||
| * - Parser can handle TS syntax (decorators, types) | ||
| * - No projectService (allows files outside tsconfig.json) | ||
| * - Only non-type-aware rules can run | ||
| * | ||
| * React Files (JSX/TSX): | ||
| * ---------------------- | ||
| * 1. React enabled → All React rules + react-hooks rules | ||
| * 2. React disabled → No React rules, but JSX parsing still works via | ||
| * JS/TS parser configs above | ||
| * | ||
| * SLDS (CSS/HTML): | ||
| * ---------------- | ||
| * Separate concern - applies SLDS-specific linting to CSS/HTML files when enabled. | ||
| * | ||
| * Key Design Principle: | ||
| * --------------------- | ||
| * When users disable base configs (disable_javascript_base_config, disable_lwc_base_config, | ||
| * disable_typescript_base_config), they disable the BASE RULES but NOT parsing capability. | ||
| * We always configure parsers to ensure files can be analyzed, even with minimal rule sets. | ||
| */ | ||
| export class BaseConfigFactory { | ||
| private readonly engineConfig: ESLintEngineConfig; | ||
|
|
||
|
|
@@ -47,6 +89,10 @@ export class BaseConfigFactory { | |
| configArray.push(...this.createJavascriptConfigArray()); | ||
| } else if (this.useLwcBaseConfig()) { | ||
| configArray.push(...this.createLwcConfigArray()); | ||
| } else if (this.engineConfig.file_extensions.javascript.length > 0) { | ||
| // When both base configs are disabled, we still need to configure a parser for JavaScript files | ||
| // to avoid ESLint falling back to Espree which can't parse decorators | ||
| configArray.push(...this.createMinimalJavascriptParserConfig()); | ||
| } | ||
| if (this.useSldsCSSBaseConfig()) { | ||
| configArray.push(...this.createSldsCSSConfigArray()); | ||
|
|
@@ -56,6 +102,10 @@ export class BaseConfigFactory { | |
| } | ||
| if (this.useTsBaseConfig()) { | ||
| configArray.push(...this.createTypescriptConfigArray()); | ||
| } else if (this.engineConfig.file_extensions.typescript.length > 0) { | ||
| // When TS base config is disabled, we still need to configure a parser for TypeScript files | ||
| // to avoid ESLint falling back to a parser that can't handle TypeScript syntax | ||
| configArray.push(...this.createMinimalTypescriptParserConfig()); | ||
| } | ||
| // Add React plugin config for JSX files | ||
| if (this.useReactBaseConfig()) { | ||
|
|
@@ -195,6 +245,87 @@ export class BaseConfigFactory { | |
| } | ||
| } | ||
|
|
||
| private createMinimalJavascriptParserConfig(): Linter.Config[] { | ||
| // When both disable_javascript_base_config and disable_lwc_base_config are true, | ||
| // we still need to configure a parser for JavaScript files to avoid ESLint falling | ||
| // back to Espree which can't parse decorators. This method configures ONLY the parser, | ||
| // without applying any base JavaScript or LWC rules. | ||
| const hasJsExtension = this.engineConfig.file_extensions.javascript.includes('.js'); | ||
|
|
||
| if (hasJsExtension) { | ||
| // .js files might have LWC decorators - use Babel parser with decorator support | ||
| const lwcConfig = validateAndGetRawLwcConfigArray()[0]; | ||
| const babelParser = lwcConfig.languageOptions?.parser; | ||
| const originalParserOptions = lwcConfig.languageOptions?.parserOptions as Linter.ParserOptions; | ||
| const originalBabelOptions = originalParserOptions.babelOptions || {}; | ||
|
|
||
| // Add @babel/preset-react to support JSX in React files alongside LWC files | ||
| const enhancedParserOptions = { | ||
| ...originalParserOptions, | ||
| babelOptions: { | ||
| ...originalBabelOptions, | ||
| configFile: false, | ||
| // Add React preset for JSX support (.jsx files and React in .js files) | ||
| presets: [...(originalBabelOptions.presets || []), require.resolve('@babel/preset-react')] | ||
| } | ||
|
Comment on lines
+256
to
+270
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here can we use the createJavascriptPlusLwcConfigArray and useJsBaseConfig instead here. |
||
| }; | ||
|
|
||
| return [{ | ||
| files: this.engineConfig.file_extensions.javascript.map(ext => `**/*${ext}`), | ||
| languageOptions: { | ||
| parser: babelParser, | ||
| parserOptions: enhancedParserOptions | ||
| } | ||
| }]; | ||
| } else { | ||
| // Only .jsx, .mjs, .cjs (no .js) - use Espree for better performance | ||
| return [{ | ||
| files: this.engineConfig.file_extensions.javascript.map(ext => `**/*${ext}`), | ||
| languageOptions: { | ||
| parserOptions: { | ||
| ecmaFeatures: { | ||
| jsx: true // Enable JSX parsing for React/JSX files | ||
| } | ||
| } | ||
| } | ||
| }]; | ||
| } | ||
| } | ||
|
|
||
| private createMinimalTypescriptParserConfig(): Linter.Config[] { | ||
| // When disable_typescript_base_config is true, we still need to configure a parser | ||
| // for TypeScript files to avoid ESLint falling back to Espree which can't parse | ||
| // TypeScript syntax. This method configures ONLY the parser, without applying base rules. | ||
| // | ||
| // IMPORTANT LIMITATION - Type-Aware Rules: | ||
| // ========================================= | ||
| // We intentionally do NOT set projectService here. The projectService option | ||
| // is used for type-aware linting, but it requires files to be in a tsconfig.json project. | ||
| // Without projectService, the TypeScript parser can still parse TypeScript syntax | ||
| // (decorators, type annotations, etc.) but ONLY non-type-aware rules can run. | ||
| // | ||
| // Type-aware rules (e.g., @typescript-eslint/await-thenable) will NOT work with this | ||
| // minimal config. If users need type-aware rules, they should enable the TypeScript | ||
| // base config (disable_typescript_base_config: false). | ||
| // | ||
| // This trade-off allows users to: | ||
| // ✓ Parse TypeScript files without a tsconfig.json | ||
| // ✓ Run basic ESLint rules on TypeScript code | ||
| // ✗ Cannot use type-aware TypeScript rules | ||
|
|
||
| // Get the first TypeScript config which contains the parser setup | ||
| const tsConfig = (eslintTs.configs.all as Linter.Config[])[0]; | ||
|
|
||
| return [{ | ||
| files: this.engineConfig.file_extensions.typescript.map(ext => `**/*${ext}`), | ||
| languageOptions: { | ||
| ...(tsConfig.languageOptions ?? {}) | ||
| // Explicitly omit parserOptions.projectService to allow parsing files | ||
| // that aren't part of a TypeScript project | ||
| } | ||
| }]; | ||
| } | ||
|
|
||
| private createSldsHTMLConfigArray(): Linter.Config[] { | ||
| return sldsEslintPlugin.configs['flat/recommended-html'].map((htmlConfig: Linter.Config) => { | ||
| return { | ||
|
|
||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need to introduce new function here? Can we directly use useTsBaseConfig? Or maybe combine this.useTsBaseConfig() with or of this.engineConfig.file_extensions.typescript.length > 0.