@rslint/core 0.6.5 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/0~engine.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { spawn } from "node:child_process";
2
+ import { ConfigModuleHost } from "./519.js";
2
3
  const RESPONSE_KIND = 'response';
3
4
  const ERROR_KIND = 'error';
4
5
  const HEADER_BYTES = 4;
@@ -251,6 +252,21 @@ async function runSafely(fn, tag) {
251
252
  process.stderr.write(`rslint: handler ${tag} threw: ${message}\n`);
252
253
  }
253
254
  }
255
+ function isRecord(value) {
256
+ return null !== value && 'object' == typeof value && !Array.isArray(value);
257
+ }
258
+ function isPluginHostFactoryModule(value) {
259
+ return isRecord(value) && 'function' == typeof value.createPluginLintHost;
260
+ }
261
+ function isConfigModuleCandidate(value) {
262
+ return isRecord(value) && 'string' == typeof value.id && 'string' == typeof value.configPath && 'string' == typeof value.configDirectory;
263
+ }
264
+ function isLoadConfigsRequest(value) {
265
+ return isRecord(value) && 1 === value.protocolVersion && 'string' == typeof value.transactionId && ('cached' === value.loadMode || 'fresh' === value.loadMode) && (void 0 === value.singleThreaded || 'boolean' == typeof value.singleThreaded) && Array.isArray(value.candidates) && value.candidates.every(isConfigModuleCandidate);
266
+ }
267
+ function isActivateConfigsRequest(value) {
268
+ return isRecord(value) && 1 === value.protocolVersion && 'string' == typeof value.transactionId && Array.isArray(value.effectiveConfigIds) && value.effectiveConfigIds.every((id)=>'string' == typeof id);
269
+ }
254
270
  const SIGNAL_EXIT_CODES = {
255
271
  SIGHUP: 129,
256
272
  SIGINT: 130,
@@ -304,22 +320,60 @@ async function runEngine(opts) {
304
320
  }
305
321
  const ipc = new IpcClient(child.stdout, child.stdin);
306
322
  let pluginHost = null;
307
- const pluginConfigs = opts.pluginConfigs ?? [];
308
- if (pluginConfigs.length > 0) {
309
- const pluginEntry = './eslint-plugin/index.js';
310
- try {
311
- const mod = await import(pluginEntry);
312
- pluginHost = await mod.createPluginLintHost(pluginConfigs, (rec)=>stderr.write(`[rslint:plugin] ${rec.text}\n`), opts.runtime?.singleThreaded);
313
- } catch (err) {
314
- const msg = err instanceof Error ? err.message : String(err);
315
- stderr.write(`rslint: failed to start ESLint-plugin worker: ${msg}\n`);
316
- safeKillGo(child);
317
- return 2;
323
+ const configModuleHost = opts.configModuleHost ?? new ConfigModuleHost();
324
+ const configTransactions = new Set();
325
+ let shuttingDown = false;
326
+ const pendingPluginHostBuilds = new Set();
327
+ const stagedPluginHosts = new Set();
328
+ const pluginHostShutdowns = new WeakMap();
329
+ const shutdownPluginHost = async (host)=>{
330
+ if (!host) return;
331
+ stagedPluginHosts.delete(host);
332
+ let shutdown = pluginHostShutdowns.get(host);
333
+ if (!shutdown) {
334
+ shutdown = host.shutdown();
335
+ pluginHostShutdowns.set(host, shutdown);
318
336
  }
319
- }
337
+ await shutdown;
338
+ };
339
+ const publishPluginHost = async (host)=>{
340
+ if (!host) return;
341
+ if (shuttingDown) return void await shutdownPluginHost(host).catch(()=>void 0);
342
+ stagedPluginHosts.delete(host);
343
+ pluginHost = host;
344
+ };
345
+ const buildPluginHost = async (pluginConfigs)=>{
346
+ const build = (async ()=>{
347
+ if (0 === pluginConfigs.length || shuttingDown) return null;
348
+ let createPluginLintHost = opts.createPluginLintHost;
349
+ if (!createPluginLintHost) {
350
+ const pluginEntry = './eslint-plugin/index.js';
351
+ const mod = await import(pluginEntry);
352
+ if (!isPluginHostFactoryModule(mod)) throw new Error('rslint ESLint-plugin entry does not export createPluginLintHost');
353
+ createPluginLintHost = mod.createPluginLintHost;
354
+ }
355
+ const host = await createPluginLintHost(pluginConfigs, (rec)=>stderr.write(`[rslint:plugin] ${rec.text}\n`), opts.runtime?.singleThreaded);
356
+ if (shuttingDown) {
357
+ await shutdownPluginHost(host).catch(()=>void 0);
358
+ return null;
359
+ }
360
+ stagedPluginHosts.add(host);
361
+ return host;
362
+ })();
363
+ pendingPluginHostBuilds.add(build);
364
+ build.then(()=>pendingPluginHostBuilds.delete(build), ()=>pendingPluginHostBuilds.delete(build));
365
+ const host = await build;
366
+ return host;
367
+ };
320
368
  const onSignal = ()=>{
369
+ shuttingDown = true;
321
370
  safeKillGo(child);
322
- pluginHost?.shutdown();
371
+ Promise.allSettled([
372
+ shutdownPluginHost(pluginHost),
373
+ ...[
374
+ ...stagedPluginHosts
375
+ ].map(shutdownPluginHost)
376
+ ]);
323
377
  };
324
378
  process.on('SIGINT', onSignal);
325
379
  process.on('SIGTERM', onSignal);
@@ -332,14 +386,42 @@ async function runEngine(opts) {
332
386
  try {
333
387
  ipc.setInboundHandler(async (msg)=>{
334
388
  switch(msg.kind){
389
+ case 'loadConfigs':
390
+ {
391
+ if (!isLoadConfigsRequest(msg.data)) throw new Error('engine: invalid loadConfigs request');
392
+ const request = msg.data;
393
+ const response = await configModuleHost.loadConfigs(request);
394
+ configTransactions.add(request.transactionId);
395
+ return response;
396
+ }
397
+ case 'activateConfigs':
398
+ {
399
+ if (!isActivateConfigsRequest(msg.data)) throw new Error('engine: invalid activateConfigs request');
400
+ const request = msg.data;
401
+ let stagedPluginHost = null;
402
+ try {
403
+ const response = await configModuleHost.activateConfigs(request, void 0, async (activation)=>{
404
+ if (pluginHost) return;
405
+ const createdHost = await buildPluginHost(activation.pluginConfigs);
406
+ if (shuttingDown) return void await shutdownPluginHost(createdHost).catch(()=>void 0);
407
+ stagedPluginHost = createdHost;
408
+ });
409
+ const preparedHost = stagedPluginHost;
410
+ await publishPluginHost(preparedHost);
411
+ stagedPluginHost = null;
412
+ return response;
413
+ } catch (error) {
414
+ await shutdownPluginHost(stagedPluginHost).catch(()=>void 0);
415
+ throw error;
416
+ }
417
+ }
335
418
  case 'shutdown':
336
419
  return {
337
420
  ok: true
338
421
  };
339
422
  case 'pluginLint':
340
- return pluginHost ? pluginHost.lint(msg.data) : {
341
- results: []
342
- };
423
+ if (!pluginHost) throw new Error('engine: pluginLint requested without an activated plugin host');
424
+ return pluginHost.lint(msg.data);
343
425
  default:
344
426
  throw new Error(`engine: unexpected inbound kind '${msg.kind}'`);
345
427
  }
@@ -354,8 +436,6 @@ async function runEngine(opts) {
354
436
  try {
355
437
  outcome = await raceWithExit(ipc.sendRequest('init', {
356
438
  ...opts.extraInit ?? {},
357
- configs: opts.configs,
358
- eslintPlugins: opts.eslintPluginEntries,
359
439
  runtime: {
360
440
  stdoutIsTTY,
361
441
  singleThreaded: opts.runtime?.singleThreaded
@@ -383,7 +463,17 @@ async function runEngine(opts) {
383
463
  return finalExit.code;
384
464
  } finally{
385
465
  removeSignalHandlers();
386
- await pluginHost?.shutdown();
466
+ shuttingDown = true;
467
+ await Promise.allSettled([
468
+ ...pendingPluginHostBuilds
469
+ ]);
470
+ await Promise.allSettled([
471
+ shutdownPluginHost(pluginHost),
472
+ ...[
473
+ ...stagedPluginHosts
474
+ ].map(shutdownPluginHost)
475
+ ]);
476
+ for (const transactionId of configTransactions)configModuleHost.deleteSession(transactionId);
387
477
  }
388
478
  }
389
479
  const KILL_GRACE_MS = 5000;