Skip to content

NEW(esint): @W-18695515@ Manually resolve plugin conflicts …#304

Merged
stephen-carter-at-sf merged 2 commits into
devfrom
sc/eslintUpdates
Jun 5, 2025
Merged

NEW(esint): @W-18695515@ Manually resolve plugin conflicts …#304
stephen-carter-at-sf merged 2 commits into
devfrom
sc/eslintUpdates

Conversation

@stephen-carter-at-sf

Copy link
Copy Markdown
Contributor

… and forward events from background worker

// eslint-disable-next-line @typescript-eslint/no-explicit-any
async function dynamicallyImport(absJavaScriptFilePath: string): Promise<any> {
// To avoid issues with dynamically importing absolute paths on Windows, we need to convert to url with pathToFileURL.
const moduleUrl: string = pathToFileURL(absJavaScriptFilePath).href;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While working on this PR, I realized the more robust way to do dynamic imports is to use the pathToFileURL utility instead of manually replacing slashes for windows.

* Abstract class that provides the ability to emit engine events
*/
export abstract class Engine {
export abstract class EngineEventEmitter {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I split up the Engine class into 2 abstract classes so we can very easily reuse the event emitter methods for helper instances inside of an Engine. This made everything super clean instead of passing around function handles.

// Calculate configs for files
const calculatedConfigs: Linter.Config[] = await Promise.all(context.filesToScan.map(
f => eslint.calculateConfigForFile(f) as Linter.Config));
async calculateESLintContext(engineConfig: ESLintEngineConfig, eslintWorkspace: ESLintWorkspace, userConfigFile?: string): Promise<ESLintContext> {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The implementation details did not change at all... just moved the function inside of a class so that we could make it an event emitter and forward the events from the eslint factory.

Comment on lines +58 to +64
worker.on('message', (msg: Event | {type: "output", output: Output}) => {
if (msg.type === "output") {
resolve(msg.output);
} else {
this.emitEvent(msg);
}
});

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Super elegant in my opinion! We can can forward all events from background worker threads to the main thread very cleanly.

Comment on lines +93 to +97
` for (const eventType of Object.values(engineApi.EventType)) {\n` +
` task.onEvent(eventType, (evt) => {\n` +
` parentPort.postMessage(evt);\n` +
` });\n` +
` }\n` +

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where the magic happens. :-)

Comment thread packages/code-analyzer-eslint-engine/src/messages.ts Outdated
Co-authored-by: Juliet Shackell <63259011+jshackell-sfdc@users.noreply.github.com>
});

it('When workspace contains custom config that installs same plugin as one of our base plugins, we resolve plugins, describe and run rules properly', async () => {
if (os.platform().startsWith('win')) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm fine with us disabling the test on Windows for runtime reasons, but I do want to be sure that you actually ran it at least once on Windows to make sure it passes?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done manually just now - yes it passes.

}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
async function dynamicallyImport(absJavaScriptFilePath: string): Promise<any> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the explicit any here truly necessary? Could you use an as-cast in the return statement?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately no - the any is necessary. I tried even using unknown but we need to do post import validation that needs it to be any sadly.

@stephen-carter-at-sf stephen-carter-at-sf merged commit ef5b97a into dev Jun 5, 2025
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants