Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/code-analyzer-eslint-engine/package.json
Original file line number Diff line number Diff line change
@@ -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.43.0",
"version": "0.43.1-SNAPSHOT",
"author": "The Salesforce Code Analyzer Team",
"license": "BSD-3-Clause",
"homepage": "https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/overview",
Expand Down
6 changes: 6 additions & 0 deletions packages/code-analyzer-eslint-engine/src/base-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,11 @@ export class BaseConfigFactory {
}
};

// Add SSR processor to enable SSR-only linting for SSR-enabled components
// The processor checks -meta.xml files for SSR capabilities and only creates virtual .ssrjs files
// for components with lightning__ServerRenderable or lightning__ServerRenderableWithHydration
configs[0].processor = '@lwc/lwc/ssr';

// File patterns for different config types
const allJsExtensions = this.engineConfig.file_extensions.javascript;
const lwcExtensions = allJsExtensions.filter(ext => ext !== '.jsx');
Expand Down Expand Up @@ -194,6 +199,7 @@ export class BaseConfigFactory {
// we can work with the original index [4] instead of [3] to avoid confusion.
configs.splice(1, 1);

// The SSR processor is already configured in configs[0] by createJavascriptPlusLwcConfigArray()
return configs;
}

Expand Down
88 changes: 88 additions & 0 deletions packages/code-analyzer-eslint-engine/test/ssr-processor.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import {
ConfigObject,
Engine,
EngineRunResults,
RunOptions,
Workspace
} from "@salesforce/code-analyzer-engine-api";
import * as path from "node:path";
import {ESLintEnginePlugin} from "../src";
import {ESLintEngine} from "../src/engine";
import {createRunOptions} from "./test-helpers";

jest.setTimeout(60_000);

const testDataFolder: string = path.join(__dirname, 'test-data');
const workspaceWithNonSSRLwc: string = path.join(testDataFolder, 'workspaceWithNonSSRLwc');

async function createEngineFromPlugin(configObject: ConfigObject): Promise<Engine> {
const plugin: ESLintEnginePlugin = new ESLintEnginePlugin();
const engine: ESLintEngine = await plugin.createEngine('eslint', configObject);
engine._runESLintWorkerTask._runInCurrentThreadInsteadofNewThread = true;
return engine;
}

describe('SSR Processor Configuration', () => {
describe('Issue 2049: SSR rules should only apply to SSR-enabled components', () => {
it('should not report SSR rule violations on non-SSR LWC components', async () => {
// Setup: Default config with LWC enabled
const defaultConfig: ConfigObject = {
file_extensions: {
javascript: ['.js'],
typescript: ['.ts'],
html: ['.html'],
css: ['.css'],
other: []
},
config_root: __dirname
};

const engine: Engine = await createEngineFromPlugin(defaultConfig);
const workspace: Workspace = new Workspace('test', [workspaceWithNonSSRLwc],
[path.join(workspaceWithNonSSRLwc, 'helloWorld.js')]);

// Act: Run the engine - the SSR rules are automatically enabled by LWC recommended config
const runOptions: RunOptions = createRunOptions(workspace);
// Run all rules to trigger SSR rules from the LWC recommended config
// Use empty array to run all configured rules
const results: EngineRunResults = await engine.runRules([], runOptions);

// Assert: Non-SSR component should NOT have SSR rule violations
// The SSR processor should filter out SSR rules for non-SSR components
expect(results.violations).toBeDefined();
const ssrViolations = results.violations.filter(v =>
v.ruleName && v.ruleName.includes('ssr-')
);
// Without the processor configured, this will fail because SSR rules will fire
// With the processor configured, SSR rules only fire on SSR-enabled components
expect(ssrViolations.length).toBe(0);
});

it('should parse files without errors when SSR processor is configured', async () => {
const defaultConfig: ConfigObject = {
file_extensions: {
javascript: ['.js'],
typescript: ['.ts'],
html: ['.html'],
css: ['.css'],
other: []
},
config_root: __dirname
};

const engine: Engine = await createEngineFromPlugin(defaultConfig);
const workspace: Workspace = new Workspace('test', [workspaceWithNonSSRLwc],
[path.join(workspaceWithNonSSRLwc, 'helloWorld.js')]);

const runOptions: RunOptions = createRunOptions(workspace);
const results: EngineRunResults = await engine.runRules(['no-debugger'], runOptions);

// Assert: Should not have 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);
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { LightningElement } from 'lwc';

export default class HelloWorld extends LightningElement {
connectedCallback() {
// This code would violate SSR rules if SSR processor wasn't configured
console.log(window.location); // ssr-no-restricted-browser-globals
if (process.env.NODE_ENV === 'development') { // ssr-no-node-env
console.log('Development mode');
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>62.0</apiVersion>
<isExposed>true</isExposed>
<targets>
<target>lightning__AppPage</target>
</targets>
</LightningComponentBundle>
Loading