@useinsider/eslint-config 3.0.2-beta.1 → 4.0.0-beta.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.
Files changed (57) hide show
  1. package/README.md +285 -64
  2. package/dist/builders/configFiles.d.ts +13 -0
  3. package/dist/builders/oxlint.d.ts +51 -0
  4. package/dist/builders/oxlintOwnership.d.ts +43 -0
  5. package/dist/cli.cjs +584 -27
  6. package/dist/cli.cjs.map +1 -1
  7. package/dist/configs/dependencies.d.ts +3 -0
  8. package/dist/{javascript-VBXqjVi8.cjs → javascript-DH8-N38w.cjs} +5 -5
  9. package/dist/{javascript-VBXqjVi8.cjs.map → javascript-DH8-N38w.cjs.map} +1 -1
  10. package/dist/{javascript-dom-5jRL_yKP.cjs → javascript-dom-CvtQ6_9W.cjs} +4 -4
  11. package/dist/{javascript-dom-5jRL_yKP.cjs.map → javascript-dom-CvtQ6_9W.cjs.map} +1 -1
  12. package/dist/{javascript-node-C1AU_4X2.cjs → javascript-node-BNsy3loY.cjs} +4 -4
  13. package/dist/{javascript-node-C1AU_4X2.cjs.map → javascript-node-BNsy3loY.cjs.map} +1 -1
  14. package/dist/{jest-CHzjzBtf.cjs → jest-4Es9Ggaa.cjs} +3 -3
  15. package/dist/{jest-CHzjzBtf.cjs.map → jest-4Es9Ggaa.cjs.map} +1 -1
  16. package/dist/main.cjs +452 -73
  17. package/dist/main.cjs.map +1 -1
  18. package/dist/main.d.ts +9 -2
  19. package/dist/main.js +435 -56
  20. package/dist/main.js.map +1 -1
  21. package/dist/oxlintOwnership-7hpdB3d1.cjs +199 -0
  22. package/dist/oxlintOwnership-7hpdB3d1.cjs.map +1 -0
  23. package/dist/oxlintOwnership-Cx0hgA_J.js +127 -0
  24. package/dist/oxlintOwnership-Cx0hgA_J.js.map +1 -0
  25. package/dist/removePluginsFromConfigs-D0oSUj2C.cjs.map +1 -1
  26. package/dist/removePluginsFromConfigs-DzqX2Ju2.js.map +1 -1
  27. package/dist/{stylistic-Dio0AM2E.cjs → stylistic-CoP3MT1Y.cjs} +4 -4
  28. package/dist/{stylistic-Dio0AM2E.cjs.map → stylistic-CoP3MT1Y.cjs.map} +1 -1
  29. package/dist/{typescript-C1icmOxY.cjs → typescript-D3VeLnpn.cjs} +7 -7
  30. package/dist/{typescript-C1icmOxY.cjs.map → typescript-D3VeLnpn.cjs.map} +1 -1
  31. package/dist/{typescript-dom-RUJn2WCZ.cjs → typescript-dom-iB_xBTAD.cjs} +4 -4
  32. package/dist/{typescript-dom-RUJn2WCZ.cjs.map → typescript-dom-iB_xBTAD.cjs.map} +1 -1
  33. package/dist/{typescript-node-CBEzcc56.cjs → typescript-node-Cq6qhj53.cjs} +4 -4
  34. package/dist/{typescript-node-CBEzcc56.cjs.map → typescript-node-Cq6qhj53.cjs.map} +1 -1
  35. package/dist/utils/ensureConfigStructure.d.ts +9 -4
  36. package/dist/utils/ensureOxlintConfig.d.ts +9 -0
  37. package/dist/utils/silenceRules.d.ts +9 -0
  38. package/dist/{vitest-BomI8gtu.cjs → vitest-BlGQswK2.cjs} +3 -3
  39. package/dist/{vitest-BomI8gtu.cjs.map → vitest-BlGQswK2.cjs.map} +1 -1
  40. package/dist/{vue2-azKwRgaJ.cjs → vue2-Da1i_oVn.cjs} +8 -8
  41. package/dist/{vue2-azKwRgaJ.cjs.map → vue2-Da1i_oVn.cjs.map} +1 -1
  42. package/dist/{vue2-options-api-ma3J-bvM.cjs → vue2-options-api-BSdrUm8H.cjs} +8 -8
  43. package/dist/{vue2-options-api-ma3J-bvM.cjs.map → vue2-options-api-BSdrUm8H.cjs.map} +1 -1
  44. package/dist/{vue2-typescript-CZSHzp7I.cjs → vue2-typescript-dXLRSGNP.cjs} +10 -10
  45. package/dist/{vue2-typescript-CZSHzp7I.cjs.map → vue2-typescript-dXLRSGNP.cjs.map} +1 -1
  46. package/dist/{vue2-typescript-options-api-B8OzZlje.cjs → vue2-typescript-options-api-LM7U5dWq.cjs} +10 -10
  47. package/dist/{vue2-typescript-options-api-B8OzZlje.cjs.map → vue2-typescript-options-api-LM7U5dWq.cjs.map} +1 -1
  48. package/dist/{vue3-Df5UQ1Ys.cjs → vue3-621EM2Ii.cjs} +8 -8
  49. package/dist/{vue3-Df5UQ1Ys.cjs.map → vue3-621EM2Ii.cjs.map} +1 -1
  50. package/dist/{vue3-options-api-Bx7yYHza.cjs → vue3-options-api-CC9_fAiq.cjs} +8 -8
  51. package/dist/{vue3-options-api-Bx7yYHza.cjs.map → vue3-options-api-CC9_fAiq.cjs.map} +1 -1
  52. package/dist/{vue3-typescript-C0O1JZlk.cjs → vue3-typescript-DONe-IKz.cjs} +10 -10
  53. package/dist/{vue3-typescript-C0O1JZlk.cjs.map → vue3-typescript-DONe-IKz.cjs.map} +1 -1
  54. package/dist/{vue3-typescript-options-api-cPal4O-K.cjs → vue3-typescript-options-api-D4pqpDFs.cjs} +10 -10
  55. package/dist/{vue3-typescript-options-api-cPal4O-K.cjs.map → vue3-typescript-options-api-D4pqpDFs.cjs.map} +1 -1
  56. package/package.json +8 -5
  57. package/dist/rolldown-runtime-VH7oDXx4.cjs +0 -28
package/dist/main.cjs CHANGED
@@ -1,10 +1,10 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_rolldown_runtime = require("./rolldown-runtime-VH7oDXx4.cjs");
2
+ const require_oxlintOwnership = require("./oxlintOwnership-7hpdB3d1.cjs");
3
3
  const require_merge = require("./merge-DJQU2y2U.cjs");
4
4
  const require_mergeAllConfig = require("./mergeAllConfig-DjMWjBNg.cjs");
5
5
  let eslint_config = require("eslint/config");
6
6
  let globals = require("globals");
7
- globals = require_rolldown_runtime.__toESM(globals, 1);
7
+ globals = require_oxlintOwnership.__toESM(globals, 1);
8
8
  let node_fs = require("node:fs");
9
9
  let node_module = require("node:module");
10
10
  let node_path = require("node:path");
@@ -12,7 +12,7 @@ let node_url = require("node:url");
12
12
  let _typescript_eslint_types = require("@typescript-eslint/types");
13
13
  let _antfu_install_pkg = require("@antfu/install-pkg");
14
14
  let semver = require("semver");
15
- semver = require_rolldown_runtime.__toESM(semver, 1);
15
+ semver = require_oxlintOwnership.__toESM(semver, 1);
16
16
  let node_console = require("node:console");
17
17
  //#region src/builders/configFiles.ts
18
18
  /**
@@ -33,6 +33,33 @@ var configFileRules = {
33
33
  "import-x/no-extraneous-dependencies": "off",
34
34
  "import-x/prefer-default-export": "off"
35
35
  };
36
+ var LINT_TOPOLOGY_NAME = "insider/lint-topology";
37
+ /**
38
+ * The three files `useInsider()` requires a consumer to own. They are always linted with
39
+ * {@link buildLintTopologyBlocks}, independently of the `configFiles` option.
40
+ */
41
+ var LINT_TOPOLOGY_GLOBS = [
42
+ "**/insider.lint.{ts,mts,cts,js,mjs,cjs}",
43
+ "**/eslint.config.{ts,mts,cts,js,mjs,cjs}",
44
+ "**/oxlint.config.{ts,mts,cts,js,mjs,cjs}"
45
+ ];
46
+ var lintTopologyRules = {
47
+ ...configFileRules,
48
+ "import-x/extensions": "off"
49
+ };
50
+ /**
51
+ * Relaxations the mandated three-file layout needs in order to lint clean. Emitted unconditionally
52
+ * because the layout exists whether or not the consumer passes `configFiles`.
53
+ * @example
54
+ * buildLintTopologyBlocks()[0].rules['import-x/extensions']; // 'off'
55
+ */
56
+ function buildLintTopologyBlocks() {
57
+ return [{
58
+ name: LINT_TOPOLOGY_NAME,
59
+ files: [...LINT_TOPOLOGY_GLOBS],
60
+ rules: { ...lintTopologyRules }
61
+ }];
62
+ }
36
63
  function mergeGlobs(userGlobs) {
37
64
  const seen = /* @__PURE__ */ new Set();
38
65
  const merged = [];
@@ -62,17 +89,148 @@ function buildConfigFilesBlocks(value) {
62
89
  function buildJqueryBlocks(entries) {
63
90
  if (!entries || entries.length === 0) return [];
64
91
  return entries.map((entry) => ({
65
- files: entry.files,
92
+ files: [...entry.files],
66
93
  languageOptions: { globals: { ...globals.default.jquery } }
67
94
  }));
68
95
  }
69
96
  //#endregion
97
+ //#region src/builders/oxlint.ts
98
+ var OXLINT_SUPPRESSION_NAME = "insider/oxlint-suppression";
99
+ var OXLINT_SFC_EXCEPTION_NAME = "insider/oxlint-suppression-sfc-exception";
100
+ var UNUSED_DIRECTIVE_BLOCK_NAME = "insider/unused-disable-directives";
101
+ var UNUSED_DIRECTIVE_SEVERITY = "warn";
102
+ var OXLINT_DIRECTIVE_OPTIONS = {
103
+ respectEslintDisableDirectives: false,
104
+ reportUnusedDisableDirectives: UNUSED_DIRECTIVE_SEVERITY
105
+ };
106
+ /**
107
+ * The always-on ESLint block that makes a stale `eslint-disable` visible. ESLint 9 defaults this to
108
+ * `warn`, but the split relies on it, so it is pinned rather than inherited.
109
+ * @example
110
+ * buildUnusedDirectiveBlocks()[0].linterOptions; // { reportUnusedDisableDirectives: 'warn' }
111
+ */
112
+ function buildUnusedDirectiveBlocks() {
113
+ return [{
114
+ name: UNUSED_DIRECTIVE_BLOCK_NAME,
115
+ linterOptions: { reportUnusedDisableDirectives: UNUSED_DIRECTIVE_SEVERITY }
116
+ }];
117
+ }
118
+ function ownedRuleNames(rules) {
119
+ return Object.keys(rules).filter((name) => require_oxlintOwnership.isOxlintOwned(name) && !require_oxlintOwnership.isRuleDisabled(rules[name]));
120
+ }
121
+ function translatableRuleNames(rules) {
122
+ return Object.keys(rules).filter(require_oxlintOwnership.isOxlintOwned);
123
+ }
124
+ function toOffRecord(ruleNames) {
125
+ return Object.fromEntries(ruleNames.map((name) => [name, "off"]));
126
+ }
127
+ function suppressionFor(block) {
128
+ if (!block.rules) return [];
129
+ const owned = ownedRuleNames(block.rules);
130
+ if (owned.length === 0) return [];
131
+ const files = block.files ? { files: [...block.files] } : {};
132
+ const blockIgnores = block.ignores ? [...block.ignores] : [];
133
+ const vueSafe = owned.filter((name) => !require_oxlintOwnership.isVueUnsafeRule(name));
134
+ const vueUnsafe = owned.filter((name) => require_oxlintOwnership.isVueUnsafeRule(name));
135
+ const suppressions = [];
136
+ if (vueSafe.length > 0) suppressions.push({
137
+ name: OXLINT_SUPPRESSION_NAME,
138
+ ...files,
139
+ ...blockIgnores.length > 0 ? { ignores: blockIgnores } : {},
140
+ rules: toOffRecord(vueSafe)
141
+ });
142
+ if (vueUnsafe.length > 0) suppressions.push({
143
+ name: OXLINT_SFC_EXCEPTION_NAME,
144
+ ...files,
145
+ ignores: [...blockIgnores, ...require_oxlintOwnership.VUE_LIKE_GLOBS],
146
+ rules: toOffRecord(vueUnsafe)
147
+ });
148
+ return suppressions;
149
+ }
150
+ /**
151
+ * ESLint blocks that turn off every rule the emitted oxlint config takes over. Rules oxlint cannot
152
+ * check inside an SFC are suppressed everywhere except `.vue`/`.svelte`/`.astro`, so a Vue consumer
153
+ * keeps them.
154
+ * @example
155
+ * buildOxlintSuppressionBlocks([{ files: ['src/**\/*.ts'], rules: { 'no-var': 'error' } }]);
156
+ * // [{ files: ['src/**\/*.ts'], rules: { 'no-var': 'off' } }]
157
+ */
158
+ function buildOxlintSuppressionBlocks(blocks) {
159
+ return blocks.flatMap(suppressionFor);
160
+ }
161
+ function translateRules(rules, plugins) {
162
+ return translatableRuleNames(rules).reduce((accumulator, name) => {
163
+ plugins.add(require_oxlintOwnership.toOxlintPluginName(name));
164
+ accumulator[require_oxlintOwnership.toOxlintRuleName(name)] = rules[name];
165
+ return accumulator;
166
+ }, {});
167
+ }
168
+ function anchorOxlintGlob(glob) {
169
+ return glob.startsWith("**") || glob.startsWith("./") || glob.startsWith("/") ? glob : `./${glob}`;
170
+ }
171
+ function anchorGlobs(globs) {
172
+ return globs.map(anchorOxlintGlob);
173
+ }
174
+ function anchorOxlintIgnorePattern(pattern) {
175
+ const negated = pattern.startsWith("!");
176
+ const body = negated ? pattern.slice(1) : pattern;
177
+ const anchored = body.startsWith("/") || body.startsWith("**") ? body : `/${body}`;
178
+ return negated ? `!${anchored}` : anchored;
179
+ }
180
+ function overrideFor(block, plugins) {
181
+ if (!block.files || !block.rules) return [];
182
+ const translated = translateRules(block.rules, plugins);
183
+ if (Object.keys(translated).length === 0) return [];
184
+ return [{
185
+ files: anchorGlobs(block.files),
186
+ ...block.ignores && block.ignores.length > 0 ? { excludeFiles: anchorGlobs(block.ignores) } : {},
187
+ rules: translated
188
+ }];
189
+ }
190
+ /**
191
+ * The oxlint half of the split, derived from the same emitted ESLint blocks the suppression layer
192
+ * reads. Every oxlint category is pinned off so the config enables exactly the preset's own rules
193
+ * and nothing oxlint would otherwise turn on by default.
194
+ * @example
195
+ * buildOxlintConfig([{ files: ['src/**\/*.ts'], rules: { 'no-var': 'error' } }], ['dist']);
196
+ * // { plugins: ['eslint'], categories: { correctness: 'off', ... }, ignorePatterns: ['/dist'], ... }
197
+ */
198
+ function buildOxlintConfig(blocks, ignores) {
199
+ const plugins = /* @__PURE__ */ new Set(["eslint"]);
200
+ const overrides = blocks.flatMap((block) => overrideFor(block, plugins));
201
+ const globalRules = blocks.filter((block) => !block.files && block.rules).reduce((accumulator, block) => ({
202
+ ...accumulator,
203
+ ...translateRules(block.rules, plugins)
204
+ }), {});
205
+ return {
206
+ plugins: [...plugins].sort((left, right) => left.localeCompare(right)),
207
+ categories: Object.fromEntries(require_oxlintOwnership.OXLINT_CATEGORIES.map((name) => [name, "off"])),
208
+ ...ignores && ignores.length > 0 ? { ignorePatterns: ignores.map(anchorOxlintIgnorePattern) } : {},
209
+ options: { ...OXLINT_DIRECTIVE_OPTIONS },
210
+ rules: globalRules,
211
+ overrides
212
+ };
213
+ }
214
+ //#endregion
70
215
  //#region src/utils/ensureConfigStructure.ts
71
- var CONFIG_FILE_REGEX = /eslint\.config\.[mc]?[jt]s(?:$|\?)/;
72
- var OPT_OUT_ENV = "INSIDER_SKIP_CONFIG_VALIDATION";
216
+ var ANCHOR_FILE_REGEX = /(?:insider\.lint|eslint\.config)\.[mc]?[jt]s(?:$|\?)/;
217
+ var OPT_OUT_ENV$1 = "INSIDER_SKIP_CONFIG_VALIDATION";
73
218
  var FILE_URL_PREFIX = "file://";
74
219
  var TARGET_CALLEE_NAME = "useInsider";
220
+ var ESLINT_RENDERER_NAME = "useInsiderESLint";
221
+ var OXC_RENDERER_NAME = "useInsiderOXC";
75
222
  var INSIDER_IMPORT_SOURCE = "@useinsider/eslint-config";
223
+ var MODULE_EXTENSIONS = [
224
+ "ts",
225
+ "mts",
226
+ "cts",
227
+ "js",
228
+ "mjs",
229
+ "cjs"
230
+ ];
231
+ var RENDERER_EXPORT = `export const ${`{ ${ESLINT_RENDERER_NAME}, ${OXC_RENDERER_NAME} }`} = ${TARGET_CALLEE_NAME}({ ... })`;
232
+ var LINT_MODULE_FILENAMES = MODULE_EXTENSIONS.map((ext) => `insider.lint.${ext}`);
233
+ var ESLINT_CONFIG_FILENAMES = MODULE_EXTENSIONS.map((ext) => `eslint.config.${ext}`);
76
234
  var bypassWarnEmitted = false;
77
235
  function computeSelfModulePath() {
78
236
  const raw = (0, node_url.fileURLToPath)({}.url);
@@ -102,24 +260,24 @@ function locOf(node) {
102
260
  column: node.loc.start.column
103
261
  };
104
262
  }
105
- function validateCallExpression(callExpr) {
263
+ function validateCallExpression(callExpr, expectedCallee) {
106
264
  const { callee } = callExpr;
107
- if (callee.type !== _typescript_eslint_types.AST_NODE_TYPES.Identifier || callee.name !== TARGET_CALLEE_NAME) return [{
265
+ if (callee.type !== _typescript_eslint_types.AST_NODE_TYPES.Identifier || callee.name !== expectedCallee) return [{
108
266
  ...locOf(callExpr),
109
- reason: "Default export must call `useInsider(...)` directly."
267
+ reason: `Default export must call \`${expectedCallee}(...)\` directly.`
110
268
  }];
111
269
  return [];
112
270
  }
113
- function validateExportedCall(callee, fallbackLoc) {
271
+ function validateExportedCall(callee, fallbackLoc, expectedCallee) {
114
272
  let target = callee;
115
273
  if (target.type === _typescript_eslint_types.AST_NODE_TYPES.AwaitExpression) target = target.argument;
116
- if (target.type === _typescript_eslint_types.AST_NODE_TYPES.CallExpression) return validateCallExpression(target);
274
+ if (target.type === _typescript_eslint_types.AST_NODE_TYPES.CallExpression) return validateCallExpression(target, expectedCallee);
117
275
  if (target.type === _typescript_eslint_types.AST_NODE_TYPES.ArrayExpression) return [{
118
276
  ...locOf(target),
119
- reason: "Default export must not wrap `useInsider(...)` in an array. Use the typed options object instead."
277
+ reason: `Default export must not wrap \`${expectedCallee}(...)\` in an array.`
120
278
  }];
121
279
  if (target.type === _typescript_eslint_types.AST_NODE_TYPES.LogicalExpression || target.type === _typescript_eslint_types.AST_NODE_TYPES.ConditionalExpression) {
122
- const reason = ["Default export must not gate `useInsider(...)` behind a logical/conditional expression.", "Use the typed options object instead."].join(" ");
280
+ const reason = [`Default export must not gate \`${expectedCallee}(...)\` behind a logical/conditional expression.`, "Use the typed options object instead."].join(" ");
123
281
  return [{
124
282
  ...locOf(target),
125
283
  reason
@@ -127,7 +285,7 @@ function validateExportedCall(callee, fallbackLoc) {
127
285
  }
128
286
  return [{
129
287
  ...fallbackLoc,
130
- reason: "Default export must be a direct call to `useInsider(...)`."
288
+ reason: `Default export must be a direct call to \`${expectedCallee}(...)\`.`
131
289
  }];
132
290
  }
133
291
  function collectInsiderBindings(node, bindings, isInsiderSource) {
@@ -148,7 +306,7 @@ function classifyExpressionStatement(node, insiderBindings) {
148
306
  }
149
307
  };
150
308
  }
151
- function classifyStatement(node, exportSeen, insiderBindings) {
309
+ function classifyStatement(node, exportSeen, insiderBindings, expectedCallee) {
152
310
  if (node.type === _typescript_eslint_types.AST_NODE_TYPES.ImportDeclaration || node.type === _typescript_eslint_types.AST_NODE_TYPES.VariableDeclaration) return { type: "ignore" };
153
311
  if (node.type === _typescript_eslint_types.AST_NODE_TYPES.ExpressionStatement) return classifyExpressionStatement(node, insiderBindings);
154
312
  if (node.type === _typescript_eslint_types.AST_NODE_TYPES.ExportDefaultDeclaration) {
@@ -162,13 +320,13 @@ function classifyStatement(node, exportSeen, insiderBindings) {
162
320
  const declaration = node.declaration;
163
321
  return {
164
322
  type: "export",
165
- violations: validateExportedCall(declaration, locOf(node))
323
+ violations: validateExportedCall(declaration, locOf(node), expectedCallee)
166
324
  };
167
325
  }
168
326
  const reason = [
169
327
  `Disallowed top-level statement \`${node.type}\`.`,
170
328
  "Only imports, variable declarations, helper calls from `@useinsider/eslint-config`,",
171
- "and one `export default useInsider(...)` are allowed."
329
+ `and one \`export default ${expectedCallee}()\` are allowed.`
172
330
  ].join(" ");
173
331
  return {
174
332
  type: "disallowed",
@@ -183,18 +341,112 @@ function validateProgramStructure(program, configPath = "", options = {}) {
183
341
  const insiderBindings = /* @__PURE__ */ new Set();
184
342
  const resolver = options.isInsiderImportSource ?? defaultIsInsiderImportSource;
185
343
  const isInsiderSource = (source) => resolver(source, configPath);
344
+ const expectedCallee = options.expectedCallee ?? ESLINT_RENDERER_NAME;
186
345
  let exportSeen = false;
187
346
  program.body.forEach((node) => {
188
347
  if (node.type === _typescript_eslint_types.AST_NODE_TYPES.ImportDeclaration) collectInsiderBindings(node, insiderBindings, isInsiderSource);
189
- const result = classifyStatement(node, exportSeen, insiderBindings);
348
+ const result = classifyStatement(node, exportSeen, insiderBindings, expectedCallee);
190
349
  if (result.type === "ignore") return;
191
350
  if (result.type === "export") {
192
351
  exportSeen = true;
193
352
  violations.push(...result.violations);
194
353
  return;
195
354
  }
196
- if (result.type === "duplicateExport") {
197
- violations.push(result.violation);
355
+ violations.push(result.violation);
356
+ });
357
+ if (!exportSeen) violations.push({
358
+ line: 1,
359
+ column: 0,
360
+ reason: `Missing \`export default ${options.expectedCallee ?? ESLINT_RENDERER_NAME}()\`.`
361
+ });
362
+ return violations;
363
+ }
364
+ function validateRendererPattern(pattern) {
365
+ const bound = /* @__PURE__ */ new Set();
366
+ const violations = [];
367
+ pattern.properties.forEach((property) => {
368
+ if (property.type !== _typescript_eslint_types.AST_NODE_TYPES.Property || property.computed || !property.shorthand) {
369
+ violations.push({
370
+ ...locOf(property),
371
+ reason: `Destructure \`${ESLINT_RENDERER_NAME}\` and \`${OXC_RENDERER_NAME}\` by name, without renaming or spreading.`
372
+ });
373
+ return;
374
+ }
375
+ bound.add(property.key.name);
376
+ });
377
+ [ESLINT_RENDERER_NAME, OXC_RENDERER_NAME].forEach((name) => {
378
+ if (!bound.has(name)) violations.push({
379
+ ...locOf(pattern),
380
+ reason: `Missing \`${name}\` in the destructured \`${TARGET_CALLEE_NAME}(...)\` result.`
381
+ });
382
+ });
383
+ return violations;
384
+ }
385
+ function validateRendererExport(node) {
386
+ const { declaration } = node;
387
+ if (!declaration || declaration.type !== _typescript_eslint_types.AST_NODE_TYPES.VariableDeclaration || declaration.kind !== "const") return [{
388
+ ...locOf(node),
389
+ reason: `Renderer export must be \`${RENDERER_EXPORT};\`.`
390
+ }];
391
+ if (declaration.declarations.length !== 1) return [{
392
+ ...locOf(declaration),
393
+ reason: "Renderer export must declare exactly one binding."
394
+ }];
395
+ const [declarator] = declaration.declarations;
396
+ if (declarator.id.type !== _typescript_eslint_types.AST_NODE_TYPES.ObjectPattern) return [{
397
+ ...locOf(declarator.id),
398
+ reason: `Renderer export must destructure \`${ESLINT_RENDERER_NAME}\` and \`${OXC_RENDERER_NAME}\`.`
399
+ }];
400
+ const patternViolations = validateRendererPattern(declarator.id);
401
+ const { init } = declarator;
402
+ if (!init) return [...patternViolations, {
403
+ ...locOf(declarator),
404
+ reason: `Renderer export must be initialized by a direct \`${TARGET_CALLEE_NAME}(...)\` call.`
405
+ }];
406
+ return [...patternViolations, ...validateExportedCall(init, locOf(declarator), TARGET_CALLEE_NAME)];
407
+ }
408
+ function classifyLintModuleStatement(node, exportSeen, insiderBindings) {
409
+ if (node.type === _typescript_eslint_types.AST_NODE_TYPES.ImportDeclaration || node.type === _typescript_eslint_types.AST_NODE_TYPES.VariableDeclaration) return { type: "ignore" };
410
+ if (node.type === _typescript_eslint_types.AST_NODE_TYPES.ExpressionStatement) return classifyExpressionStatement(node, insiderBindings);
411
+ if (node.type === _typescript_eslint_types.AST_NODE_TYPES.ExportNamedDeclaration) {
412
+ if (exportSeen) return {
413
+ type: "duplicateExport",
414
+ violation: {
415
+ ...locOf(node),
416
+ reason: "Only one export is allowed."
417
+ }
418
+ };
419
+ return {
420
+ type: "export",
421
+ violations: validateRendererExport(node)
422
+ };
423
+ }
424
+ const reason = [
425
+ `Disallowed top-level statement \`${node.type}\`.`,
426
+ "Only imports, variable declarations, helper calls from `@useinsider/eslint-config`,",
427
+ `and one \`${RENDERER_EXPORT}\` are allowed.`
428
+ ].join(" ");
429
+ return {
430
+ type: "disallowed",
431
+ violation: {
432
+ ...locOf(node),
433
+ reason
434
+ }
435
+ };
436
+ }
437
+ function validateLintModuleStructure(program, configPath = "", options = {}) {
438
+ const violations = [];
439
+ const insiderBindings = /* @__PURE__ */ new Set();
440
+ const resolver = options.isInsiderImportSource ?? defaultIsInsiderImportSource;
441
+ const isInsiderSource = (source) => resolver(source, configPath);
442
+ let exportSeen = false;
443
+ program.body.forEach((node) => {
444
+ if (node.type === _typescript_eslint_types.AST_NODE_TYPES.ImportDeclaration) collectInsiderBindings(node, insiderBindings, isInsiderSource);
445
+ const result = classifyLintModuleStatement(node, exportSeen, insiderBindings);
446
+ if (result.type === "ignore") return;
447
+ if (result.type === "export") {
448
+ exportSeen = true;
449
+ violations.push(...result.violations);
198
450
  return;
199
451
  }
200
452
  violations.push(result.violation);
@@ -202,7 +454,7 @@ function validateProgramStructure(program, configPath = "", options = {}) {
202
454
  if (!exportSeen) violations.push({
203
455
  line: 1,
204
456
  column: 0,
205
- reason: "Missing `export default useInsider(...)`."
457
+ reason: `Missing \`${RENDERER_EXPORT};\`.`
206
458
  });
207
459
  return violations;
208
460
  }
@@ -226,7 +478,7 @@ function extractMatchesFromStack(frames) {
226
478
  const matches = /* @__PURE__ */ new Set();
227
479
  frames.forEach((frame) => {
228
480
  const name = normalizeFrameFilename(frame.getFileName());
229
- if (name && CONFIG_FILE_REGEX.test(name)) matches.add(name);
481
+ if (name && ANCHOR_FILE_REGEX.test(name)) matches.add(name);
230
482
  });
231
483
  return Array.from(matches);
232
484
  }
@@ -239,13 +491,16 @@ function argvCandidateAt(argv, index) {
239
491
  function extractConfigFromArgv(argv) {
240
492
  for (let i = 0; i < argv.length; i += 1) {
241
493
  const candidate = argvCandidateAt(argv, i);
242
- if (candidate && CONFIG_FILE_REGEX.test(candidate)) return candidate;
494
+ if (candidate && ANCHOR_FILE_REGEX.test(candidate)) return candidate;
243
495
  }
244
496
  return null;
245
497
  }
498
+ var LINT_MODULE_REGEX = /insider\.lint\.[mc]?[jt]s(?:$|\?)/;
246
499
  function getConsumerConfigPath(frames = readStackFrames(), argv = process.argv) {
247
500
  const stackMatches = extractMatchesFromStack(frames);
248
501
  if (stackMatches.length === 1) return stackMatches[0];
502
+ const lintModules = stackMatches.filter((match) => LINT_MODULE_REGEX.test(match));
503
+ if (lintModules.length === 1) return lintModules[0];
249
504
  const fromArgv = extractConfigFromArgv(argv);
250
505
  if (fromArgv) return fromArgv;
251
506
  return null;
@@ -255,27 +510,46 @@ function captureConsumerConfigDir(configPath) {
255
510
  consumerConfigDir = configPath === null ? null : (0, node_path.dirname)((0, node_path.resolve)(configPath));
256
511
  }
257
512
  /**
258
- * Directory holding the consumer's `eslint.config.*`, captured by {@link ensureConfigStructure}.
259
- * This is the anchor `tsconfigPaths` entries are written against; it falls back to `process.cwd()`
260
- * when the config file could not be located.
513
+ * Directory holding the consumer's `insider.lint.*` module and its sibling linter configs, captured
514
+ * by {@link ensureConfigStructure}. This is the anchor `tsconfigPaths` entries are written against,
515
+ * and where {@link import('./ensureOxlintConfig').ensureOxlintConfig} looks for the oxlint config;
516
+ * it falls back to `process.cwd()` when the module could not be located.
261
517
  * @example
262
- * // consumer config at /repo/eslint.config.mjs, `eslint` launched from /repo/app
518
+ * // consumer module at /repo/insider.lint.ts, `eslint` launched from /repo/app
263
519
  * getConsumerConfigDir(); // '/repo'
264
520
  */
265
521
  function getConsumerConfigDir() {
266
522
  return consumerConfigDir ?? process.cwd();
267
523
  }
524
+ var EXPECTED_LAYOUT = [
525
+ "Expected layout (three sibling files):",
526
+ "",
527
+ " // insider.lint.ts",
528
+ " import { useInsider } from '@useinsider/eslint-config';",
529
+ "",
530
+ ` ${RENDERER_EXPORT};`,
531
+ "",
532
+ " // eslint.config.ts",
533
+ ` import { ${ESLINT_RENDERER_NAME} } from './insider.lint.ts';`,
534
+ "",
535
+ ` export default ${ESLINT_RENDERER_NAME}();`,
536
+ "",
537
+ " // oxlint.config.ts",
538
+ ` import { ${OXC_RENDERER_NAME} } from './insider.lint.ts';`,
539
+ "",
540
+ ` export default await ${OXC_RENDERER_NAME}();`
541
+ ].join("\n");
268
542
  function formatReport(configPath, violations) {
269
543
  const header = ["@useinsider/eslint-config: protected configuration structure violated in:", ` ${configPath}`].join("\n");
270
544
  const lines = violations.map((violation) => ` - [${violation.line}:${violation.column}] ${violation.reason}`);
271
545
  const footer = [
272
546
  "",
273
- "Allowed structure:",
274
- " - import statements",
275
- " - const/let/var declarations",
276
- " - exactly one `export default useInsider({ ... })`",
547
+ "Alongside the export, only import statements, const/let/var declarations and helper calls",
548
+ "imported from `@useinsider/eslint-config` are allowed.",
277
549
  "",
278
- "Emergency bypass: set INSIDER_SKIP_CONFIG_VALIDATION=true (do not commit)."
550
+ EXPECTED_LAYOUT,
551
+ "",
552
+ `Emergency bypass: set ${OPT_OUT_ENV$1}=true (do not commit).`
279
553
  ].join("\n");
280
554
  return `${header}\n${lines.join("\n")}\n${footer}`;
281
555
  }
@@ -316,16 +590,50 @@ function parseConsumerSource(configPath, source) {
316
590
  return fail(`@useinsider/eslint-config: failed to parse consumer config at ${configPath}: ${message}`);
317
591
  }
318
592
  }
319
- function runValidation(configPath) {
320
- if (!configPath) fail(["@useinsider/eslint-config: unable to locate consumer `eslint.config.*` file for structure validation.", "If this is an unexpected environment, set INSIDER_SKIP_CONFIG_VALIDATION=true (do not commit)."].join("\n"));
321
- const violations = validateProgramStructure(parseConsumerSource(configPath, readConsumerSource(configPath)), configPath);
593
+ function resolveSibling(directory, filenames) {
594
+ const found = filenames.find((filename) => (0, node_fs.existsSync)((0, node_path.resolve)(directory, filename)));
595
+ return found ? (0, node_path.resolve)(directory, found) : null;
596
+ }
597
+ function validateFile(filePath, validator, options) {
598
+ const violations = validator(parseConsumerSource(filePath, readConsumerSource(filePath)), filePath, options);
322
599
  if (violations.length === 0) return;
323
- fail(formatReport(configPath, violations));
600
+ fail(formatReport(filePath, violations));
601
+ }
602
+ function runValidation(anchorPath) {
603
+ if (!anchorPath) fail([
604
+ "@useinsider/eslint-config: unable to locate the consumer `insider.lint.*` module for structure validation.",
605
+ "",
606
+ EXPECTED_LAYOUT,
607
+ "",
608
+ `If this is an unexpected environment, set ${OPT_OUT_ENV$1}=true (do not commit).`
609
+ ].join("\n"));
610
+ const directory = (0, node_path.dirname)((0, node_path.resolve)(anchorPath));
611
+ const lintModulePath = resolveSibling(directory, LINT_MODULE_FILENAMES);
612
+ if (!lintModulePath) fail([
613
+ `@useinsider/eslint-config: no \`insider.lint.*\` module found in ${directory}.`,
614
+ "",
615
+ `\`${TARGET_CALLEE_NAME}()\` now returns the two renderers instead of a flat-config array,`,
616
+ "so the config it is called from must be a module both linters can import.",
617
+ "",
618
+ EXPECTED_LAYOUT,
619
+ "",
620
+ `Emergency bypass: set ${OPT_OUT_ENV$1}=true (do not commit).`
621
+ ].join("\n"));
622
+ validateFile(lintModulePath, validateLintModuleStructure, {});
623
+ const eslintConfigPath = resolveSibling(directory, ESLINT_CONFIG_FILENAMES);
624
+ if (!eslintConfigPath) fail([
625
+ `@useinsider/eslint-config: no \`eslint.config.*\` file found in ${directory}.`,
626
+ "",
627
+ EXPECTED_LAYOUT,
628
+ "",
629
+ `Emergency bypass: set ${OPT_OUT_ENV$1}=true (do not commit).`
630
+ ].join("\n"));
631
+ validateFile(eslintConfigPath, validateProgramStructure, { expectedCallee: ESLINT_RENDERER_NAME });
324
632
  }
325
633
  function ensureConfigStructure(overridePath) {
326
634
  const configPath = overridePath === void 0 ? getConsumerConfigPath() : overridePath;
327
635
  captureConsumerConfigDir(configPath);
328
- if (process.env[OPT_OUT_ENV] === "true") {
636
+ if (process.env[OPT_OUT_ENV$1] === "true") {
329
637
  emitBypassWarning();
330
638
  return;
331
639
  }
@@ -366,52 +674,52 @@ function applyVueOverrides(block, input) {
366
674
  //#region src/builders/scopeBlocks.ts
367
675
  var scopeMap = {
368
676
  async javascript() {
369
- return Promise.resolve().then(() => require("./javascript-VBXqjVi8.cjs"));
677
+ return Promise.resolve().then(() => require("./javascript-DH8-N38w.cjs"));
370
678
  },
371
679
  async javascriptDom() {
372
- return Promise.resolve().then(() => require("./javascript-dom-5jRL_yKP.cjs"));
680
+ return Promise.resolve().then(() => require("./javascript-dom-CvtQ6_9W.cjs"));
373
681
  },
374
682
  async javascriptNode() {
375
- return Promise.resolve().then(() => require("./javascript-node-C1AU_4X2.cjs"));
683
+ return Promise.resolve().then(() => require("./javascript-node-BNsy3loY.cjs"));
376
684
  },
377
685
  async typescript() {
378
- return Promise.resolve().then(() => require("./typescript-C1icmOxY.cjs"));
686
+ return Promise.resolve().then(() => require("./typescript-D3VeLnpn.cjs"));
379
687
  },
380
688
  async typescriptDom() {
381
- return Promise.resolve().then(() => require("./typescript-dom-RUJn2WCZ.cjs"));
689
+ return Promise.resolve().then(() => require("./typescript-dom-iB_xBTAD.cjs"));
382
690
  },
383
691
  async typescriptNode() {
384
- return Promise.resolve().then(() => require("./typescript-node-CBEzcc56.cjs"));
692
+ return Promise.resolve().then(() => require("./typescript-node-Cq6qhj53.cjs"));
385
693
  },
386
694
  async vue2() {
387
- return Promise.resolve().then(() => require("./vue2-azKwRgaJ.cjs"));
695
+ return Promise.resolve().then(() => require("./vue2-Da1i_oVn.cjs"));
388
696
  },
389
697
  async vue3() {
390
- return Promise.resolve().then(() => require("./vue3-Df5UQ1Ys.cjs"));
698
+ return Promise.resolve().then(() => require("./vue3-621EM2Ii.cjs"));
391
699
  },
392
700
  async vue2Typescript() {
393
- return Promise.resolve().then(() => require("./vue2-typescript-CZSHzp7I.cjs"));
701
+ return Promise.resolve().then(() => require("./vue2-typescript-dXLRSGNP.cjs"));
394
702
  },
395
703
  async vue3Typescript() {
396
- return Promise.resolve().then(() => require("./vue3-typescript-C0O1JZlk.cjs"));
704
+ return Promise.resolve().then(() => require("./vue3-typescript-DONe-IKz.cjs"));
397
705
  },
398
706
  async vue2OptionsApi() {
399
- return Promise.resolve().then(() => require("./vue2-options-api-ma3J-bvM.cjs"));
707
+ return Promise.resolve().then(() => require("./vue2-options-api-BSdrUm8H.cjs"));
400
708
  },
401
709
  async vue3OptionsApi() {
402
- return Promise.resolve().then(() => require("./vue3-options-api-Bx7yYHza.cjs"));
710
+ return Promise.resolve().then(() => require("./vue3-options-api-CC9_fAiq.cjs"));
403
711
  },
404
712
  async vue2TypescriptOptionsApi() {
405
- return Promise.resolve().then(() => require("./vue2-typescript-options-api-B8OzZlje.cjs"));
713
+ return Promise.resolve().then(() => require("./vue2-typescript-options-api-LM7U5dWq.cjs"));
406
714
  },
407
715
  async vue3TypescriptOptionsApi() {
408
- return Promise.resolve().then(() => require("./vue3-typescript-options-api-cPal4O-K.cjs"));
716
+ return Promise.resolve().then(() => require("./vue3-typescript-options-api-D4pqpDFs.cjs"));
409
717
  },
410
718
  async jest() {
411
- return Promise.resolve().then(() => require("./jest-CHzjzBtf.cjs"));
719
+ return Promise.resolve().then(() => require("./jest-4Es9Ggaa.cjs"));
412
720
  },
413
721
  async vitest() {
414
- return Promise.resolve().then(() => require("./vitest-BomI8gtu.cjs"));
722
+ return Promise.resolve().then(() => require("./vitest-BlGQswK2.cjs"));
415
723
  },
416
724
  async jsdocBasedTs() {
417
725
  return Promise.resolve().then(() => require("./jsdoc-based-ts-Cfahz0nn.cjs"));
@@ -469,7 +777,7 @@ async function buildScopeBlocks(scope, entries) {
469
777
  const preset = (await scopeMap[scope]()).default;
470
778
  return entries.map((entry) => {
471
779
  const block = clonePreset(preset);
472
- block.files = entry.files;
780
+ block.files = [...entry.files];
473
781
  if (tsScopes.has(scope)) {
474
782
  const { tsconfigPaths } = entry;
475
783
  if (tsconfigPaths) applyTypescriptOverrides(block, { tsconfigPaths });
@@ -503,7 +811,7 @@ async function buildStrictBlocks(value) {
503
811
  const { default: strictConfig } = await Promise.resolve().then(() => require("./strict-DnJFBY_B.cjs"));
504
812
  const clone = { ...strictConfig };
505
813
  if (clone.rules) clone.rules = { ...clone.rules };
506
- if (isFileScoped) clone.files = value;
814
+ if (isFileScoped) clone.files = [...value];
507
815
  else delete clone.files;
508
816
  return [clone];
509
817
  }
@@ -512,7 +820,11 @@ async function buildStrictBlocks(value) {
512
820
  var turnOff = false;
513
821
  var scanned = false;
514
822
  var silencedDependencies = /* @__PURE__ */ new Set();
515
- var fixedDependencies = ["eslint", "globals"];
823
+ var fixedDependencies = [
824
+ "eslint",
825
+ "globals",
826
+ "oxlint"
827
+ ];
516
828
  var require$1 = (0, node_module.createRequire)({}.url);
517
829
  function getPackageJSONPath(currentDir) {
518
830
  const fileLocation = (0, node_path.resolve)(currentDir, "package.json");
@@ -568,6 +880,46 @@ function silenceDependencyWarning(input) {
568
880
  input.forEach((dependency) => silencedDependencies.add(String(dependency)));
569
881
  }
570
882
  //#endregion
883
+ //#region src/utils/ensureOxlintConfig.ts
884
+ var OPT_OUT_ENV = "INSIDER_SKIP_CONFIG_VALIDATION";
885
+ var OXLINT_CONFIG_FILENAMES = ["oxlint.config.ts", "oxlint.config.mts"];
886
+ function lintModuleSpecifier(directory) {
887
+ return `./${LINT_MODULE_FILENAMES.find((filename) => (0, node_fs.existsSync)((0, node_path.join)(directory, filename))) ?? "insider.lint.ts"}`;
888
+ }
889
+ function formatMessage(directory) {
890
+ return [
891
+ "@useinsider/eslint-config: no oxlint config found in",
892
+ ` ${directory}`,
893
+ "",
894
+ "useInsiderESLint() turns off every rule oxlint owns, so running ESLint alone would silently",
895
+ "drop those checks. Create the sibling oxlint config:",
896
+ "",
897
+ " // oxlint.config.ts",
898
+ ` import { useInsiderOXC } from '${lintModuleSpecifier(directory)}';`,
899
+ "",
900
+ " export default await useInsiderOXC();",
901
+ "",
902
+ "and run both linters:",
903
+ "",
904
+ " \"lint\": \"oxlint --disable-nested-config && eslint .\"",
905
+ "",
906
+ `Expected one of: ${OXLINT_CONFIG_FILENAMES.join(", ")}.`,
907
+ `Emergency bypass: set ${OPT_OUT_ENV}=true (do not commit).`
908
+ ].join("\n");
909
+ }
910
+ /**
911
+ * Fails when the consumer enabled the ESLint-side oxlint suppression without a sibling oxlint
912
+ * config to run the suppressed rules. Resolved against the directory
913
+ * {@link getConsumerConfigDir} captured during `useInsider()`.
914
+ * @example
915
+ * ensureOxlintConfig(); // throws unless oxlint.config.{ts,mts} sits beside insider.lint.*
916
+ */
917
+ function ensureOxlintConfig(directory = getConsumerConfigDir()) {
918
+ if (process.env[OPT_OUT_ENV] === "true") return;
919
+ if (OXLINT_CONFIG_FILENAMES.some((filename) => (0, node_fs.existsSync)((0, node_path.join)(directory, filename)))) return;
920
+ throw new Error(formatMessage(directory));
921
+ }
922
+ //#endregion
571
923
  //#region src/utils/silenceRules.ts
572
924
  var globallySilencedRules = /* @__PURE__ */ new Set();
573
925
  /**
@@ -587,14 +939,25 @@ function silenceRule(config) {
587
939
  const [, ...restConfig] = Array.isArray(config) ? config : [];
588
940
  return ["warn", ...restConfig];
589
941
  }
942
+ /**
943
+ * Reports a silenced rule name that no emitted block declares, which is how a typo in
944
+ * `silenceRules` stays visible. The caller passes the union of every block's rule keys: a single
945
+ * block is not evidence, because the emission is many narrow blocks and a correctly spelled rule is
946
+ * absent from nearly all of them.
947
+ * @example
948
+ * warnUnknownSilencedRules(['no-console'], ['no-unknown-rule']); // warns once
949
+ */
950
+ function warnUnknownSilencedRules(knownRules, silencedRules) {
951
+ const known = new Set(knownRules);
952
+ new Set(silencedRules).forEach((rule) => {
953
+ if (known.has(rule)) return;
954
+ (0, node_console.warn)(`Unknown rule "${rule}". Please remove it from the silenced rules list.`);
955
+ });
956
+ }
590
957
  function filterSilencedRules(rules, silencedRules) {
591
958
  let targetSilencedRules = silencedRules || globallySilencedRules;
592
959
  if (Array.isArray(targetSilencedRules)) targetSilencedRules = new Set(targetSilencedRules);
593
960
  if (!rules || !targetSilencedRules.size) return rules;
594
- if (silencedRules) targetSilencedRules.forEach((rule) => {
595
- if (rules[rule]) return;
596
- (0, node_console.warn)(`Unknown rule "${rule}". Please remove it from the silenced rules list.`);
597
- });
598
961
  return Object.entries(rules).reduce((newRules, [key, value]) => {
599
962
  if (value) newRules[key] = targetSilencedRules.has(key) && !isDisabled(value) ? silenceRule(value) : value;
600
963
  return newRules;
@@ -630,6 +993,7 @@ async function collectScopeBlocks(config) {
630
993
  }, Promise.resolve([]));
631
994
  }
632
995
  function applySilenceRules(blocks, perCallSilence) {
996
+ if (perCallSilence) warnUnknownSilencedRules(blocks.flatMap((block) => Object.keys(block.rules ?? {})), perCallSilence);
633
997
  blocks.forEach((block) => {
634
998
  if (!block.rules) return;
635
999
  block.rules = perCallSilence ? filterSilencedRules(block.rules, perCallSilence) : filterSilencedRules(block.rules);
@@ -639,29 +1003,44 @@ function buildIgnoresBlocks(ignores) {
639
1003
  if (!ignores || ignores.length === 0) return [];
640
1004
  return [{ ignores: [...ignores] }];
641
1005
  }
642
- async function useInsider(config) {
643
- assertNoRemovedKeys(config);
644
- ensureConfigStructure();
645
- await ensureDependencies();
646
- const ignoresBlocks = buildIgnoresBlocks(config.ignores);
1006
+ async function buildBaseBlocks(config) {
647
1007
  const scopeBlocks = await collectScopeBlocks(config);
648
- const jqueryBlocks = buildJqueryBlocks(config.jquery);
649
- const configFilesBlocks = buildConfigFilesBlocks(config.configFiles);
650
1008
  const strictBlocks = await buildStrictBlocks(config.strict);
651
- const spellCheckerBlocks = buildSpellCheckerBlocks(config.spellChecker);
652
- const blocks = [
653
- ...ignoresBlocks,
1009
+ return [
1010
+ ...buildIgnoresBlocks(config.ignores),
1011
+ ...buildUnusedDirectiveBlocks(),
654
1012
  ...scopeBlocks,
655
- ...jqueryBlocks,
656
- ...configFilesBlocks,
1013
+ ...buildJqueryBlocks(config.jquery),
1014
+ ...buildConfigFilesBlocks(config.configFiles),
657
1015
  ...strictBlocks,
658
- ...spellCheckerBlocks
1016
+ ...buildLintTopologyBlocks(),
1017
+ ...buildSpellCheckerBlocks(config.spellChecker)
659
1018
  ];
1019
+ }
1020
+ async function renderEslint(config) {
1021
+ await ensureDependencies();
1022
+ ensureOxlintConfig();
1023
+ const baseBlocks = await buildBaseBlocks(config);
1024
+ const blocks = [...baseBlocks, ...buildOxlintSuppressionBlocks(baseBlocks)];
660
1025
  applySilenceRules(blocks, config.silenceRules);
661
1026
  return (0, eslint_config.defineConfig)(blocks);
662
1027
  }
1028
+ async function renderOxlint(config) {
1029
+ const baseBlocks = await buildBaseBlocks(config);
1030
+ applySilenceRules(baseBlocks, config.silenceRules);
1031
+ return buildOxlintConfig(baseBlocks, config.ignores);
1032
+ }
1033
+ function useInsider(config) {
1034
+ assertNoRemovedKeys(config);
1035
+ ensureConfigStructure();
1036
+ return {
1037
+ useInsiderESLint: () => renderEslint(config),
1038
+ useInsiderOXC: () => renderOxlint(config)
1039
+ };
1040
+ }
663
1041
  //#endregion
664
1042
  exports.ensureConfigStructure = ensureConfigStructure;
1043
+ exports.ensureOxlintConfig = ensureOxlintConfig;
665
1044
  exports.merge = require_merge.merge;
666
1045
  exports.mergeAll = require_mergeAllConfig.mergeAll;
667
1046
  exports.silenceDependencyWarning = silenceDependencyWarning;