@rslint/core 0.6.5 → 0.7.0

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.
@@ -22572,9 +22572,11 @@ function scope_factory_analyze(ast, opts) {
22572
22572
  childVisitorKeys: VISITOR_KEYS
22573
22573
  });
22574
22574
  }
22575
+ const syntheticGlobals = new WeakSet();
22575
22576
  function ensureGlobal(gs, name, mode) {
22576
22577
  const existing = gs.set?.get(name);
22577
22578
  if (existing) {
22579
+ if (!syntheticGlobals.has(existing)) return existing;
22578
22580
  existing.writeable = 'writable' === mode;
22579
22581
  existing.eslintImplicitGlobalSetting = mode;
22580
22582
  return existing;
@@ -22588,6 +22590,7 @@ function ensureGlobal(gs, name, mode) {
22588
22590
  eslintImplicitGlobalSetting: mode,
22589
22591
  scope: gs
22590
22592
  };
22593
+ syntheticGlobals.add(v);
22591
22594
  gs.variables.push(v);
22592
22595
  gs.set?.set(name, v);
22593
22596
  return v;
@@ -22625,28 +22628,50 @@ function seedGlobals(scopeManager, globals) {
22625
22628
  const gs = sm.globalScope;
22626
22629
  if (!gs) return;
22627
22630
  if (!globals) return void resolveThroughReferences(gs);
22628
- for (const [name, mode] of Object.entries(globals)){
22629
- if ('off' === mode) {
22630
- if (gs.set?.has(name)) {
22631
- const v = gs.set.get(name);
22632
- if (Array.isArray(v.references) && v.references.length > 0) {
22633
- const through = gs.through ?? (gs.through = []);
22634
- for (const ref of v.references){
22635
- ref.resolved = null;
22636
- through.push(ref);
22631
+ for (const [name, access] of Object.entries(globals)){
22632
+ const mode = normalizeGlobalAccess(access);
22633
+ if (null != mode) {
22634
+ if ('off' === mode) {
22635
+ const v = gs.set?.get(name);
22636
+ if (v && syntheticGlobals.has(v)) {
22637
+ if (Array.isArray(v.references) && v.references.length > 0) {
22638
+ const through = gs.through ?? (gs.through = []);
22639
+ for (const ref of v.references){
22640
+ ref.resolved = null;
22641
+ through.push(ref);
22642
+ }
22643
+ v.references = [];
22637
22644
  }
22638
- v.references = [];
22645
+ const idx = gs.variables.indexOf(v);
22646
+ if (idx >= 0) gs.variables.splice(idx, 1);
22647
+ gs.set?.delete(name);
22639
22648
  }
22640
- const idx = gs.variables.indexOf(v);
22641
- if (idx >= 0) gs.variables.splice(idx, 1);
22642
- gs.set.delete(name);
22649
+ continue;
22643
22650
  }
22644
- continue;
22651
+ ensureGlobal(gs, name, mode);
22645
22652
  }
22646
- ensureGlobal(gs, name, mode);
22647
22653
  }
22648
22654
  resolveThroughReferences(gs);
22649
22655
  }
22656
+ function normalizeGlobalAccess(access) {
22657
+ switch(access){
22658
+ case true:
22659
+ case 'true':
22660
+ case 'writable':
22661
+ case 'writeable':
22662
+ return 'writable';
22663
+ case false:
22664
+ case null:
22665
+ case 'false':
22666
+ case 'readonly':
22667
+ case 'readable':
22668
+ return 'readonly';
22669
+ case 'off':
22670
+ return 'off';
22671
+ default:
22672
+ return;
22673
+ }
22674
+ }
22650
22675
  function esquery_esm_min_e(e, t) {
22651
22676
  (null == t || t > e.length) && (t = e.length);
22652
22677
  for(var r = 0, n = Array(t); r < t; r++)n[r] = e[r];
@@ -26084,7 +26109,6 @@ function unwrapPluginModule(mod) {
26084
26109
  }
26085
26110
  async function importConfigFile(configFilePath) {
26086
26111
  const ext = node_path.extname(configFilePath);
26087
- if ('.js' === ext || '.mjs' === ext || '.cjs' === ext) return import(pathToFileURL(configFilePath).href);
26088
26112
  if ('.ts' === ext || '.mts' === ext || '.cts' === ext) {
26089
26113
  const useNative = Boolean(process.features.typescript);
26090
26114
  if (useNative) return import(pathToFileURL(configFilePath).href);
@@ -26100,7 +26124,7 @@ async function importConfigFile(configFilePath) {
26100
26124
  const resolved = await jiti.import(configFilePath);
26101
26125
  return resolved;
26102
26126
  }
26103
- throw new Error(`Unsupported config file extension: ${ext}`);
26127
+ return import(pathToFileURL(configFilePath).href);
26104
26128
  }
26105
26129
  const MIN_NODE_MAJOR = 20;
26106
26130
  class PluginLoaderError extends Error {
@@ -26155,25 +26179,35 @@ async function loadPluginsFromConfigs(configs) {
26155
26179
  for(let i = 0; i < configs.length; i++){
26156
26180
  const dir = configs[i].configDirectory;
26157
26181
  const existing = out.get(dir);
26158
- out.set(dir, existing ? mergeLoadedPlugins(existing, loadedList[i], dir) : loadedList[i]);
26182
+ out.set(dir, existing ? mergeLoadedPlugins(existing, loadedList[i], dir, configs[i].configPath) : loadedList[i]);
26159
26183
  }
26160
26184
  return out;
26161
26185
  }
26162
- function mergeLoadedPlugins(a, b, dir) {
26186
+ function mergeLoadedPlugins(a, b, dir, configPath) {
26187
+ const plugins = [
26188
+ ...a.plugins
26189
+ ];
26190
+ const pluginsByPrefix = new Map(plugins.map((loaded)=>[
26191
+ loaded.prefix,
26192
+ loaded
26193
+ ]));
26194
+ for (const loaded of b.plugins){
26195
+ const existing = pluginsByPrefix.get(loaded.prefix);
26196
+ if (existing) {
26197
+ if (existing.plugin !== loaded.plugin) throw new PluginLoaderError(configPath, `Cannot redefine plugin "${loaded.prefix}" for routing key "${dir}".`);
26198
+ continue;
26199
+ }
26200
+ pluginsByPrefix.set(loaded.prefix, loaded);
26201
+ plugins.push(loaded);
26202
+ }
26163
26203
  const rules = new Map(a.rules);
26164
26204
  for (const [key, rule] of b.rules){
26165
26205
  const existing = rules.get(key);
26166
- if (void 0 !== existing && existing !== rule) {
26167
- process.stderr.write(`[rslint] plugin rule "${key}" is defined by more than one config in the same directory (${dir}); keeping the first. Deduplicate the rslint.config.* files for this directory.\n`);
26168
- continue;
26169
- }
26206
+ if (void 0 !== existing && existing !== rule) throw new PluginLoaderError(configPath, `[rslint] plugin rule "${key}" is defined by different plugin instances for the same config key (${dir})`);
26170
26207
  rules.set(key, rule);
26171
26208
  }
26172
26209
  return {
26173
- plugins: [
26174
- ...a.plugins,
26175
- ...b.plugins
26176
- ],
26210
+ plugins,
26177
26211
  rules
26178
26212
  };
26179
26213
  }
@@ -1,9 +1,3 @@
1
- /**
2
- * Types shared between the eslint-plugin host and its lint workers.
3
- *
4
- * Wire-format / IPC frame types (the Go↔Node frame contract) live in
5
- * `src/ipc/protocol.ts` — the single source the CLI host consumes.
6
- */
7
1
  /**
8
2
  * Per-config descriptor handed to the worker pool. Each worker imports
9
3
  * every descriptor's `configPath` once at init, then routes per-file
@@ -13,11 +7,27 @@
13
7
  * it as a Map key for per-file dispatch.
14
8
  */
15
9
  export declare interface ConfigDescriptor {
16
- /** Absolute filesystem path of the rslint config file (`rslint.config.{js,mjs,ts,mts}`). */
10
+ /** Absolute filesystem path of the selected JS/TS config file. */
17
11
  configPath: string;
18
- /** Absolute filesystem path of the directory holding the config file.
19
- * Matches the `ConfigKey` Go emits per file during plugin-lint dispatch. */
12
+ /** Go-authoritative absolute matching/routing directory. In explicit mode
13
+ * this can differ from the config file's parent and MUST byte-match the
14
+ * `ConfigKey` Go emits during plugin-lint dispatch. */
20
15
  configDirectory: string;
21
16
  }
22
17
 
18
+ /**
19
+ * Types shared between the eslint-plugin host and its lint workers.
20
+ *
21
+ * Wire-format / IPC frame types (the Go↔Node frame contract) live in
22
+ * `src/ipc/protocol.ts` — the single source the CLI host consumes.
23
+ */
24
+ /**
25
+ * ESLint-compatible access values carried to the plugin worker. This mirrors
26
+ * the public config authoring type without coupling the worker build project to
27
+ * the config-loader build project.
28
+ */
29
+ export declare type GlobalAccess = boolean | null | 'true' | 'false' | 'readonly' | 'readable' | 'writable' | 'writeable' | 'off';
30
+
31
+ export declare type GlobalsConfig = Record<string, GlobalAccess>;
32
+
23
33
  export { }
package/dist/index.d.ts CHANGED
@@ -21,6 +21,11 @@ export declare interface ESLintPlugin {
21
21
  [key: string]: unknown;
22
22
  }
23
23
 
24
+ /**
25
+ * Access level for a declared global variable.
26
+ */
27
+ declare type GlobalAccess = boolean | null | 'true' | 'false' | 'readonly' | 'readable' | 'writable' | 'writeable' | 'off';
28
+
24
29
  /**
25
30
  * Define a global-ignores config entry.
26
31
  *
@@ -37,6 +42,14 @@ export declare interface ESLintPlugin {
37
42
  */
38
43
  export declare function globalIgnores(ignorePatterns: string[]): RslintConfigEntry;
39
44
 
45
+ /**
46
+ * Map of global variable name to its access level.
47
+ *
48
+ * @example
49
+ * globals: { myGlobal: 'readonly' }
50
+ */
51
+ declare type GlobalsConfig = Record<string, GlobalAccess>;
52
+
40
53
  export declare const importPlugin: {
41
54
  configs: {
42
55
  recommended: RslintConfigEntry;
@@ -72,6 +85,16 @@ declare type KnownPlugin = (typeof NATIVE_PLUGINS)[number];
72
85
  */
73
86
  declare interface LanguageOptions {
74
87
  parserOptions?: ParserOptions;
88
+ /**
89
+ * Global variables available in this file's scope, e.g. from a browser
90
+ * or Node.js runtime. `'readonly'`, `false`, and `null` allow reading;
91
+ * `'writable'` and `true` allow reassignment. Only the string `'off'`
92
+ * un-declares a global inherited from an earlier entry.
93
+ *
94
+ * @example
95
+ * globals: { myGlobal: 'readonly' }
96
+ */
97
+ globals?: GlobalsConfig;
75
98
  }
76
99
 
77
100
  export declare interface LintMessage {
@@ -203,13 +226,17 @@ export declare type RslintConfig = RslintConfigEntry[];
203
226
  * different file globs and are merged at lint time.
204
227
  */
205
228
  export declare interface RslintConfigEntry {
229
+ /** Optional human-readable name for this config entry. */
230
+ name?: string;
206
231
  /**
207
- * Glob patterns for files this entry applies to.
232
+ * Glob selectors for files this entry applies to. Top-level selectors are
233
+ * ORed; strings inside one nested array are ANDed, matching ESLint flat
234
+ * config semantics.
208
235
  *
209
236
  * @example
210
237
  * files: ['src/**', 'tests/**']
211
238
  */
212
- files?: string[];
239
+ files?: Array<string | string[]>;
213
240
  /**
214
241
  * Glob patterns excluded from this entry.
215
242
  *
@@ -262,7 +289,7 @@ export declare interface RslintOptions {
262
289
  /** Extra config appended after the resolved/discovered config (ESLint's overrideConfig). */
263
290
  overrideConfig?: RslintConfigEntry | RslintConfigEntry[] | null;
264
291
  /**
265
- * `string` — use this config file (no discovery).
292
+ * `string` — use this JS/TS config module (no discovery).
266
293
  * `true` — use only `overrideConfig` (no file, no discovery).
267
294
  * `null`/absent — auto-discover the nearest config (ESLint v10 semantics; no `false`).
268
295
  */
@@ -270,15 +297,15 @@ export declare interface RslintOptions {
270
297
  /** Apply rule auto-fixes; results carry `output` (the JS side persists via outputFixes). */
271
298
  fix?: boolean;
272
299
  /**
273
- * In-memory file overlay (path → content) for fully in-memory linting (issue
274
- * #1106): put the `tsconfig.json` that `parserOptions.project` names plus any
300
+ * In-memory file overlay (path → content) for project inputs (issue #1106):
301
+ * put the `tsconfig.json` that `parserOptions.project` names plus any
275
302
  * dependency files here, then lint a buffer with `lintText`. Keys resolve
276
303
  * against `cwd` like a linted path (relative or absolute both work); a
277
304
  * same-path `lintText` code entry wins. Inside the tsconfig (`files`) and
278
305
  * `parserOptions.project`, use relative paths — the TS compiler resolves
279
306
  * those, and a bare POSIX-absolute path there has no drive letter on Windows,
280
- * so it won't match the overlay. rslint-only ESLint has no in-memory file
281
- * map.
307
+ * so it won't match the overlay. The overlay permits filesystem fallback and
308
+ * is not a sandbox. rslint-only — ESLint has no in-memory file map.
282
309
  *
283
310
  * Give the tsconfig explicit `files`, not a broad `include` glob: a glob is
284
311
  * expanded against the real filesystem and would scan `cwd` on disk.
@@ -287,29 +314,20 @@ export declare interface RslintOptions {
287
314
  }
288
315
 
289
316
  /**
290
- * Configuration value accepted for a single rule.
317
+ * Configuration value accepted for a single rule. Aligned with ESLint —
318
+ * rslint's own `{ level, options }` object form has been removed.
291
319
  *
292
320
  * - `RuleSeverity` — just toggle the rule.
293
321
  * - `[RuleSeverity, ...args]` — ESLint-style array form. Most rules take a
294
322
  * single options object (`[severity, { ... }]`); some accept positional
295
323
  * string/object args (`[severity, "always", { ... }]`).
296
- * - `{ level, options }` — object form supported by the loader.
297
- */
298
- declare type RuleEntry = RuleSeverity | readonly [RuleSeverity, ...any[]] | {
299
- level: RuleSeverity;
300
- options?: RuleOptions;
301
- };
302
-
303
- /**
304
- * Rule-specific options object. Each rule defines its own shape; until per-rule
305
- * types are generated, options are accepted as an open record.
306
324
  */
307
- declare type RuleOptions = Record<string, any>;
325
+ declare type RuleEntry = RuleSeverity | readonly [RuleSeverity, ...any[]];
308
326
 
309
327
  /**
310
328
  * Severity level for a rule.
311
329
  */
312
- declare type RuleSeverity = 'off' | 'warn' | 'error';
330
+ declare type RuleSeverity = 'off' | 'warn' | 'error' | 0 | 1 | 2;
313
331
 
314
332
  /**
315
333
  * Map of rule name → rule configuration. Rule names are `string` (no