@@ -6,35 +6,42 @@ import { debugAssertIsNonNull } from "./utils/asserts.js";
66// are identical. Ditto `lintFile` and `lintFileWrapper`.
77let loadPlugin : typeof loadPluginWrapper | null = null ;
88let lintFile : typeof lintFileWrapper | null = null ;
9- let clearLoadedPlugin : typeof clearLoadedPluginWrapper | null = null ;
9+ let createWorkspace : typeof createWorkspaceWrapper | null = null ;
10+ let destroyWorkspace : typeof destroyWorkspaceWrapper | null = null ;
1011
1112/**
1213 * Load a plugin.
1314 *
1415 * Lazy-loads plugins code on first call, so that overhead is skipped if user doesn't use JS plugins.
1516 *
17+ * @param workspaceDir - Workspace root directory
1618 * @param path - Absolute path of plugin file
1719 * @param packageName - Optional package name from `package.json` (fallback if `plugin.meta.name` is not defined)
1820 * @returns Plugin details or error serialized to JSON string
1921 */
20- function loadPluginWrapper ( path : string , packageName : string | null ) : Promise < string > {
22+ function loadPluginWrapper (
23+ workspaceDir : string ,
24+ path : string ,
25+ packageName : string | null ,
26+ ) : Promise < string > {
2127 if ( loadPlugin === null ) {
2228 // Use promises here instead of making `loadPluginWrapper` an async function,
2329 // to avoid a micro-tick and extra wrapper `Promise` in all later calls to `loadPluginWrapper`
2430 return import ( "./plugins/index.js" ) . then ( ( mod ) => {
25- ( { loadPlugin, lintFile, clearLoadedPlugin } = mod ) ;
26- return loadPlugin ( path , packageName ) ;
31+ ( { loadPlugin, lintFile, createWorkspace , destroyWorkspace } = mod ) ;
32+ return loadPlugin ( workspaceDir , path , packageName ) ;
2733 } ) ;
2834 }
2935 debugAssertIsNonNull ( loadPlugin ) ;
30- return loadPlugin ( path , packageName ) ;
36+ return loadPlugin ( workspaceDir , path , packageName ) ;
3137}
3238
3339/**
3440 * Lint a file.
3541 *
3642 * Delegates to `lintFile`, which was lazy-loaded by `loadPluginWrapper`.
3743 *
44+ * @param workspaceDir - Directory of the workspace
3845 * @param filePath - Absolute path of file being linted
3946 * @param bufferId - ID of buffer containing file data
4047 * @param buffer - Buffer containing file data, or `null` if buffer with this ID was previously sent to JS
@@ -43,6 +50,7 @@ function loadPluginWrapper(path: string, packageName: string | null): Promise<st
4350 * @returns Diagnostics or error serialized to JSON string
4451 */
4552function lintFileWrapper (
53+ rootDir : string ,
4654 filePath : string ,
4755 bufferId : number ,
4856 buffer : Uint8Array | null ,
@@ -52,26 +60,54 @@ function lintFileWrapper(
5260 // `lintFileWrapper` is never called without `loadPluginWrapper` being called first,
5361 // so `lintFile` must be defined here
5462 debugAssertIsNonNull ( lintFile ) ;
55- return lintFile ( filePath , bufferId , buffer , ruleIds , settingsJSON ) ;
63+ return lintFile ( rootDir , filePath , bufferId , buffer , ruleIds , settingsJSON ) ;
5664}
5765
5866/**
59- * Clear loaded plugin state .
67+ * Create a new workspace .
6068 *
61- * Delegates to `clearLoadedPlugin`, which was lazy-loaded by `loadPluginWrapper`.
62- * If plugins haven't been loaded yet, this is a no-op.
69+ * Delegates to `createWorkspace`, which was lazy-loaded by `createWorkspaceWrapper`.
70+ *
71+ * @param rootDir - Root directory of the workspace
72+ * @returns Promise that resolves when workspace is created
6373 */
64- function clearLoadedPluginWrapper ( ) : void {
65- if ( clearLoadedPlugin !== null ) {
66- clearLoadedPlugin ( ) ;
74+ function createWorkspaceWrapper ( rootDir : string ) : Promise < undefined > {
75+ if ( createWorkspace === null ) {
76+ // Use promises here instead of making `createWorkspaceWrapper` an async function,
77+ // to avoid a micro-tick and extra wrapper `Promise` in all later calls to `createWorkspaceWrapper`
78+ return import ( "./plugins/index.js" ) . then ( ( mod ) => {
79+ ( { loadPlugin, lintFile, createWorkspace, destroyWorkspace } = mod ) ;
80+ return createWorkspace ( rootDir ) ;
81+ } ) ;
6782 }
83+
84+ debugAssertIsNonNull ( createWorkspace ) ;
85+ return Promise . resolve ( createWorkspace ( rootDir ) ) ;
86+ }
87+
88+ /**
89+ * Destroy a workspace.
90+ *
91+ * @param rootDir - Root directory of the workspace
92+ */
93+ function destroyWorkspaceWrapper ( rootDir : string ) : void {
94+ // `destroyWorkspaceWrapper` is never called without `createWorkspaceWrapper` being called first,
95+ // so `destroyWorkspace` must be defined here
96+ debugAssertIsNonNull ( destroyWorkspace ) ;
97+ destroyWorkspace ( rootDir ) ;
6898}
6999
70100// Get command line arguments, skipping first 2 (node binary and script path)
71101const args = process . argv . slice ( 2 ) ;
72102
73103// Call Rust, passing `loadPlugin`, `lintFile`, and `clearLoadedPlugin` as callbacks, and CLI arguments
74- const success = await lint ( args , loadPluginWrapper , lintFileWrapper , clearLoadedPluginWrapper ) ;
104+ const success = await lint (
105+ args ,
106+ loadPluginWrapper ,
107+ lintFileWrapper ,
108+ createWorkspaceWrapper ,
109+ destroyWorkspaceWrapper ,
110+ ) ;
75111
76112// Note: It's recommended to set `process.exitCode` instead of calling `process.exit()`.
77113// `process.exit()` kills the process immediately and `stdout` may not be flushed before process dies.
0 commit comments