diff --git a/packages/code-analyzer-eslint-engine/package.json b/packages/code-analyzer-eslint-engine/package.json index 7aa4129a..65cc6a90 100644 --- a/packages/code-analyzer-eslint-engine/package.json +++ b/packages/code-analyzer-eslint-engine/package.json @@ -1,7 +1,7 @@ { "name": "@salesforce/code-analyzer-eslint-engine", "description": "Plugin package that adds 'eslint' as an engine into Salesforce Code Analyzer", - "version": "0.40.1-SNAPSHOT", + "version": "0.40.2-SNAPSHOT", "author": "The Salesforce Code Analyzer Team", "license": "BSD-3-Clause", "homepage": "https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/overview", diff --git a/packages/code-analyzer-eslint-engine/src/base-config.ts b/packages/code-analyzer-eslint-engine/src/base-config.ts index f2bbcc79..bb5baf2c 100644 --- a/packages/code-analyzer-eslint-engine/src/base-config.ts +++ b/packages/code-analyzer-eslint-engine/src/base-config.ts @@ -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')] + } + }; + + 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 { diff --git a/packages/code-analyzer-eslint-engine/test/parser-selection.test.ts b/packages/code-analyzer-eslint-engine/test/parser-selection.test.ts index 80dffd2b..acb77589 100644 --- a/packages/code-analyzer-eslint-engine/test/parser-selection.test.ts +++ b/packages/code-analyzer-eslint-engine/test/parser-selection.test.ts @@ -524,4 +524,412 @@ describe('Parser Selection for Decorator Support', () => { expect(parsingErrors.length).toBe(0); }); }); + + describe('Critical Bug Fix: Both disable_javascript_base_config and disable_lwc_base_config set to true', () => { + it('should parse .js files with decorators when both JS and LWC base configs are disabled', async () => { + // This was the bug: when BOTH disable_javascript_base_config AND disable_lwc_base_config + // were true, no parser was configured, causing Espree fallback which can't parse decorators + const configWithBothJsAndLwcDisabled: ConfigObject = { + disable_javascript_base_config: true, + disable_lwc_base_config: true, + file_extensions: { + javascript: ['.js'], + typescript: ['.ts'], + html: ['.html'], + css: ['.css'], + other: [] + }, + config_root: __dirname + }; + + const engine: Engine = await createEngineFromPlugin(configWithBothJsAndLwcDisabled); + const workspace: Workspace = new Workspace('test', [workspaceWithLwcDecorators], + [path.join(workspaceWithLwcDecorators, 'lwcComponent.js')]); + + const runOptions: RunOptions = createRunOptions(workspace); + const results: EngineRunResults = await engine.runRules(['no-debugger'], runOptions); + + // Assert: Should parse decorators successfully (minimal parser config with Babel) + expect(results.violations).toBeDefined(); + const parsingErrors = results.violations.filter(v => + v.message.includes('Parsing error') || v.message.includes('Unexpected character') + ); + expect(parsingErrors.length).toBe(0); + }); + + it('should parse .jsx files when both JS and LWC base configs are disabled with only .jsx extension', async () => { + const configWithBothDisabledJsxOnly: ConfigObject = { + disable_javascript_base_config: true, + disable_lwc_base_config: true, + file_extensions: { + javascript: ['.jsx'], // Only .jsx, no .js + typescript: ['.ts'], + html: ['.html'], + css: ['.css'], + other: [] + }, + config_root: __dirname + }; + + const engine: Engine = await createEngineFromPlugin(configWithBothDisabledJsxOnly); + const workspace: Workspace = new Workspace('test', [workspaceWithJsxOnly], + [path.join(workspaceWithJsxOnly, 'ReactComponent.jsx')]); + + const runOptions: RunOptions = createRunOptions(workspace); + const results: EngineRunResults = await engine.runRules(['no-debugger'], runOptions); + + // Assert: Should parse JSX successfully with Espree + expect(results.violations).toBeDefined(); + const parsingErrors = results.violations.filter(v => + v.message.includes('Parsing error') + ); + expect(parsingErrors.length).toBe(0); + }); + + it('should parse .mjs and .cjs files when both JS and LWC base configs are disabled', async () => { + const workspaceWithModuleFiles: string = path.join(testDataFolder, 'workspaceWithModuleFiles'); + const configWithBothDisabledModules: ConfigObject = { + disable_javascript_base_config: true, + disable_lwc_base_config: true, + file_extensions: { + javascript: ['.mjs', '.cjs'], + typescript: ['.ts'], + html: ['.html'], + css: ['.css'], + other: [] + }, + config_root: __dirname + }; + + const engine: Engine = await createEngineFromPlugin(configWithBothDisabledModules); + const workspace: Workspace = new Workspace('test', [workspaceWithModuleFiles], + [path.join(workspaceWithModuleFiles, 'module.mjs')]); + + const runOptions: RunOptions = createRunOptions(workspace); + const results: EngineRunResults = await engine.runRules(['no-debugger'], runOptions); + + // Assert: Should parse module files successfully with Espree + expect(results.violations).toBeDefined(); + const parsingErrors = results.violations.filter(v => + v.message.includes('Parsing error') + ); + expect(parsingErrors.length).toBe(0); + }); + + it('should parse mixed .js and .jsx files when both JS and LWC base configs are disabled', async () => { + const configWithBothDisabledMixed: ConfigObject = { + disable_javascript_base_config: true, + disable_lwc_base_config: true, + file_extensions: { + javascript: ['.js', '.jsx'], + typescript: ['.ts'], + html: ['.html'], + css: ['.css'], + other: [] + }, + config_root: __dirname + }; + + const engine: Engine = await createEngineFromPlugin(configWithBothDisabledMixed); + const workspace: Workspace = new Workspace('test', [workspaceWithMixedJsJsx], + [ + path.join(workspaceWithMixedJsJsx, 'lwcFile.js'), + path.join(workspaceWithMixedJsJsx, 'reactFile.jsx') + ]); + + const runOptions: RunOptions = createRunOptions(workspace); + const results: EngineRunResults = await engine.runRules(['no-debugger'], runOptions); + + // Assert: Both .js (with decorators) and .jsx (React) should parse successfully + expect(results.violations).toBeDefined(); + const parsingErrors = results.violations.filter(v => + v.message.includes('Parsing error') || v.message.includes('Unexpected character') + ); + expect(parsingErrors.length).toBe(0); + }); + + it('should work when all three base configs (JS, LWC, React) are disabled', async () => { + const configWithAllThreeDisabled: ConfigObject = { + disable_javascript_base_config: true, + disable_lwc_base_config: true, + disable_react_base_config: true, + file_extensions: { + javascript: ['.js'], + typescript: ['.ts'], + html: ['.html'], + css: ['.css'], + other: [] + }, + config_root: __dirname + }; + + const engine: Engine = await createEngineFromPlugin(configWithAllThreeDisabled); + const workspace: Workspace = new Workspace('test', [workspaceWithLwcDecorators], + [path.join(workspaceWithLwcDecorators, 'lwcComponent.js')]); + + const runOptions: RunOptions = createRunOptions(workspace); + const results: EngineRunResults = await engine.runRules(['no-debugger'], runOptions); + + // Assert: Should still parse with minimal parser config + expect(results.violations).toBeDefined(); + const parsingErrors = results.violations.filter(v => + v.message.includes('Parsing error') || v.message.includes('Unexpected character') + ); + expect(parsingErrors.length).toBe(0); + }); + + it('should not configure parser when no JavaScript extensions are present', async () => { + const configWithNoJsExtensions: ConfigObject = { + disable_javascript_base_config: true, + disable_lwc_base_config: true, + file_extensions: { + javascript: [], // No JavaScript extensions + typescript: ['.ts'], + html: ['.html'], + css: ['.css'], + other: [] + }, + config_root: __dirname + }; + + const engine: Engine = await createEngineFromPlugin(configWithNoJsExtensions); + + // Just verify engine creation succeeds without JavaScript config + expect(engine).toBeDefined(); + }); + }); + + describe('TypeScript with disable_typescript_base_config: Bug Check', () => { + const workspaceWithTsDecorators: string = path.join(testDataFolder, 'workspaceWithTsDecorators'); + + it('should parse .ts files with decorators when disable_typescript_base_config is true', async () => { + // This test checks if we have the same bug with TypeScript as we had with JavaScript + // When disable_typescript_base_config: true, is a TypeScript parser still configured? + const configWithTsDisabled: ConfigObject = { + disable_typescript_base_config: true, + file_extensions: { + javascript: ['.js'], + typescript: ['.ts'], + html: ['.html'], + css: ['.css'], + other: [] + }, + config_root: __dirname + }; + + const engine: Engine = await createEngineFromPlugin(configWithTsDisabled); + const workspace: Workspace = new Workspace('test', [workspaceWithTsDecorators], + [path.join(workspaceWithTsDecorators, 'tsComponent.ts')]); + + const runOptions: RunOptions = createRunOptions(workspace); + const results: EngineRunResults = await engine.runRules(['no-debugger'], runOptions); + + // Assert: Should parse TypeScript decorators successfully + expect(results.violations).toBeDefined(); + const parsingErrors = results.violations.filter(v => + v.message.includes('Parsing error') || v.message.includes('Unexpected character') + ); + expect(parsingErrors.length).toBe(0); + }); + + it('should parse .tsx files with JSX when disable_typescript_base_config is true', async () => { + const workspaceWithTsx: string = path.join(testDataFolder, 'workspaceWithTsx'); + const configWithTsDisabled: ConfigObject = { + disable_typescript_base_config: true, + file_extensions: { + javascript: ['.js'], + typescript: ['.tsx'], + html: ['.html'], + css: ['.css'], + other: [] + }, + config_root: __dirname + }; + + const engine: Engine = await createEngineFromPlugin(configWithTsDisabled); + const workspace: Workspace = new Workspace('test', [workspaceWithTsx], + [path.join(workspaceWithTsx, 'ReactTsComponent.tsx')]); + + const runOptions: RunOptions = createRunOptions(workspace); + const results: EngineRunResults = await engine.runRules(['no-debugger'], runOptions); + + // Assert: Should parse TSX (TypeScript + JSX) successfully + expect(results.violations).toBeDefined(); + const parsingErrors = results.violations.filter(v => + v.message.includes('Parsing error') + ); + expect(parsingErrors.length).toBe(0); + }); + }); + + describe('Integration Tests: Verify Analysis Capabilities with Different Flag Combinations', () => { + const workspaceWithReactViolations: string = path.join(testDataFolder, 'workspaceWithReactViolations'); + const workspaceWithLwcViolations: string = path.join(testDataFolder, 'workspaceWithLwcViolations'); + + it('should parse React JSX files using minimal parser fallback when all base configs disabled', async () => { + // When all base configs are disabled, the minimal parser fallback activates + // JSX should still parse correctly (uses Espree with JSX support) + const configWithReactDisabled: ConfigObject = { + disable_javascript_base_config: true, // Disable JS base, will use minimal parser + disable_lwc_base_config: true, // Disable LWC base (not needed for React) + disable_react_base_config: true, // Disable React rules + file_extensions: { + javascript: ['.jsx'], + typescript: ['.ts'], + html: ['.html'], + css: ['.css'], + other: [] + }, + config_root: __dirname + }; + + const engine: Engine = await createEngineFromPlugin(configWithReactDisabled); + const workspace: Workspace = new Workspace('test', [workspaceWithReactViolations], + [path.join(workspaceWithReactViolations, 'ComponentWithViolations.jsx')]); + + const runOptions: RunOptions = createRunOptions(workspace); + // Just verify parsing works - we don't need to check for specific violations + const results: EngineRunResults = await engine.runRules(['no-debugger'], runOptions); + + // Assert: Should parse successfully without parsing errors + expect(results.violations).toBeDefined(); + const parsingErrors = results.violations.filter(v => + v.message.includes('Parsing error') + ); + expect(parsingErrors.length).toBe(0); + }); + + it('should parse LWC files using LWC parser (not minimal fallback) when only JS base disabled', async () => { + // When JS base config is disabled but LWC enabled, LWC decorators should still parse + // This uses the LWC parser config, not the minimal fallback + const configWithJsDisabled: ConfigObject = { + disable_javascript_base_config: true, + disable_lwc_base_config: false, // LWC enabled for parsing + file_extensions: { + javascript: ['.js'], + typescript: ['.ts'], + html: ['.html'], + css: ['.css'], + other: [] + }, + config_root: __dirname + }; + + const engine: Engine = await createEngineFromPlugin(configWithJsDisabled); + const workspace: Workspace = new Workspace('test', [workspaceWithLwcViolations], + [path.join(workspaceWithLwcViolations, 'lwcComponentWithViolations.js')]); + + const runOptions: RunOptions = createRunOptions(workspace); + // Just verify parsing works + const results: EngineRunResults = await engine.runRules(['no-debugger'], runOptions); + + // Assert: Should parse decorators successfully without parsing errors + expect(results.violations).toBeDefined(); + const parsingErrors = results.violations.filter(v => + v.message.includes('Parsing error') || v.message.includes('Unexpected character') + ); + expect(parsingErrors.length).toBe(0); + }); + + it('should parse mixed React and LWC files using LWC parser + minimal fallback for JSX', async () => { + // Verify that both React (JSX) and LWC (decorators) work when JS base disabled + // LWC uses LWC parser, JSX uses minimal fallback + const configMixed: ConfigObject = { + disable_javascript_base_config: true, + disable_lwc_base_config: false, + disable_react_base_config: true, // Disable React rules to avoid config issues + file_extensions: { + javascript: ['.js', '.jsx'], + typescript: ['.ts'], + html: ['.html'], + css: ['.css'], + other: [] + }, + config_root: __dirname + }; + + const engine: Engine = await createEngineFromPlugin(configMixed); + const workspace: Workspace = new Workspace('test', + [workspaceWithLwcViolations, workspaceWithReactViolations], + [ + path.join(workspaceWithLwcViolations, 'lwcComponentWithViolations.js'), + path.join(workspaceWithReactViolations, 'ComponentWithViolations.jsx') + ]); + + const runOptions: RunOptions = createRunOptions(workspace); + const results: EngineRunResults = await engine.runRules(['no-debugger'], runOptions); + + // Assert: Both files should parse without errors + expect(results.violations).toBeDefined(); + const parsingErrors = results.violations.filter(v => + v.message.includes('Parsing error') || v.message.includes('Unexpected character') + ); + expect(parsingErrors.length).toBe(0); + }); + + it('should parse using minimal parser fallback when all base configs disabled', async () => { + // All base configs disabled - only minimal parsers configured + // Verifies the minimal parser fallback mechanism works + const configAllDisabled: ConfigObject = { + disable_javascript_base_config: true, + disable_lwc_base_config: true, + disable_typescript_base_config: true, + file_extensions: { + javascript: ['.jsx'], + typescript: ['.ts'], + html: ['.html'], + css: ['.css'], + other: [] + }, + config_root: __dirname + }; + + const engine: Engine = await createEngineFromPlugin(configAllDisabled); + const workspace: Workspace = new Workspace('test', [workspaceWithReactViolations], + [path.join(workspaceWithReactViolations, 'ComponentWithViolations.jsx')]); + + const runOptions: RunOptions = createRunOptions(workspace); + // Run a simple rule that doesn't depend on base config + const results: EngineRunResults = await engine.runRules(['no-debugger'], runOptions); + + // Assert: Should parse and run rules even with all base configs disabled + expect(results.violations).toBeDefined(); + const parsingErrors = results.violations.filter(v => + v.message.includes('Parsing error') + ); + expect(parsingErrors.length).toBe(0); + }); + + it('should parse TypeScript files using minimal parser fallback when TS base config disabled', async () => { + // When TS base config is disabled, minimal TS parser fallback activates + // The minimal TS parser config allows parsing TS syntax without type-aware rules + const configTsDisabled: ConfigObject = { + disable_typescript_base_config: true, + file_extensions: { + javascript: ['.js'], + typescript: ['.ts'], + html: ['.html'], + css: ['.css'], + other: [] + }, + config_root: __dirname + }; + + const engine: Engine = await createEngineFromPlugin(configTsDisabled); + const workspaceWithTsViolations: string = path.join(testDataFolder, 'workspaceWithTsViolations'); + const workspace: Workspace = new Workspace('test', [workspaceWithTsViolations], + [path.join(workspaceWithTsViolations, 'tsFileWithViolations.ts')]); + + const runOptions: RunOptions = createRunOptions(workspace); + // Just verify parsing works - don't check for specific violations + const results: EngineRunResults = await engine.runRules(['no-debugger'], runOptions); + + // Assert: Should parse TypeScript syntax (type annotations, decorators) without parsing errors + expect(results.violations).toBeDefined(); + const parsingErrors = results.violations.filter(v => + v.message.includes('Parsing error') || v.message.includes('Unexpected token') + ); + expect(parsingErrors.length).toBe(0); + }); + }); }); diff --git a/packages/code-analyzer-eslint-engine/test/test-data/workspaceWithLwcViolations/lwcComponentWithViolations.js b/packages/code-analyzer-eslint-engine/test/test-data/workspaceWithLwcViolations/lwcComponentWithViolations.js new file mode 100644 index 00000000..0c7a67c3 --- /dev/null +++ b/packages/code-analyzer-eslint-engine/test/test-data/workspaceWithLwcViolations/lwcComponentWithViolations.js @@ -0,0 +1,11 @@ +import { LightningElement, api } from 'lwc'; + +// This file intentionally has LWC violations for testing +export default class LwcComponentWithViolations extends LightningElement { + @api recordId; + + connectedCallback() { + // Violation: Reassigning @api property (no-api-reassignments) + this.recordId = 'newValue'; + } +} diff --git a/packages/code-analyzer-eslint-engine/test/test-data/workspaceWithModuleFiles/module.mjs b/packages/code-analyzer-eslint-engine/test/test-data/workspaceWithModuleFiles/module.mjs new file mode 100644 index 00000000..6dccf4e3 --- /dev/null +++ b/packages/code-analyzer-eslint-engine/test/test-data/workspaceWithModuleFiles/module.mjs @@ -0,0 +1,6 @@ +// Simple ES module file +export function greet(name) { + return `Hello, ${name}!`; +} + +export const version = '1.0.0'; diff --git a/packages/code-analyzer-eslint-engine/test/test-data/workspaceWithReactViolations/ComponentWithViolations.jsx b/packages/code-analyzer-eslint-engine/test/test-data/workspaceWithReactViolations/ComponentWithViolations.jsx new file mode 100644 index 00000000..87403605 --- /dev/null +++ b/packages/code-analyzer-eslint-engine/test/test-data/workspaceWithReactViolations/ComponentWithViolations.jsx @@ -0,0 +1,15 @@ +import React from 'react'; + +// This file intentionally has violations for testing +const ComponentWithViolations = () => { + const unusedVariable = 'This variable is never used'; // no-unused-vars violation + const name = 'Test'; + + return ( +
+

Hello, {name}!

+
+ ); +}; + +export default ComponentWithViolations; diff --git a/packages/code-analyzer-eslint-engine/test/test-data/workspaceWithTsDecorators/tsComponent.ts b/packages/code-analyzer-eslint-engine/test/test-data/workspaceWithTsDecorators/tsComponent.ts new file mode 100644 index 00000000..af2f34ca --- /dev/null +++ b/packages/code-analyzer-eslint-engine/test/test-data/workspaceWithTsDecorators/tsComponent.ts @@ -0,0 +1,25 @@ +// TypeScript component with decorators - for testing ESLint parsing +// @ts-nocheck +function Component(target: any) { + return target; +} + +function Property(target: any, propertyKey: string) { + // Property decorator +} + +@Component +class MyComponent { + @Property + public name: string; + + constructor() { + this.name = "Test Component"; + } + + public greet(): string { + return `Hello from ${this.name}`; + } +} + +export default MyComponent; diff --git a/packages/code-analyzer-eslint-engine/test/test-data/workspaceWithTsViolations/tsFileWithViolations.ts b/packages/code-analyzer-eslint-engine/test/test-data/workspaceWithTsViolations/tsFileWithViolations.ts new file mode 100644 index 00000000..37c3051a --- /dev/null +++ b/packages/code-analyzer-eslint-engine/test/test-data/workspaceWithTsViolations/tsFileWithViolations.ts @@ -0,0 +1,10 @@ +// @ts-nocheck +// This file intentionally has violations for testing + +function processData(data: string): string { + debugger; // no-debugger violation + const unusedVariable: number = 42; // no-unused-vars violation + return data.toUpperCase(); +} + +export { processData }; diff --git a/packages/code-analyzer-eslint-engine/test/test-data/workspaceWithTsx/ReactTsComponent.tsx b/packages/code-analyzer-eslint-engine/test/test-data/workspaceWithTsx/ReactTsComponent.tsx new file mode 100644 index 00000000..3d1db308 --- /dev/null +++ b/packages/code-analyzer-eslint-engine/test/test-data/workspaceWithTsx/ReactTsComponent.tsx @@ -0,0 +1,16 @@ +// @ts-nocheck +interface Props { + name: string; + age?: number; +} + +const ReactTsComponent = ({ name, age }: Props) => { + return ( +
+

Hello, {name}!

+ {age &&

Age: {age}

} +
+ ); +}; + +export default ReactTsComponent;