@useinsider/eslint-config 4.0.0-beta.3 → 4.0.0-beta.5

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 (49) hide show
  1. package/dist/cli.cjs +36 -10
  2. package/dist/cli.cjs.map +1 -1
  3. package/dist/configs/dependencies.d.ts +1 -0
  4. package/dist/{javascript-dom-CvtQ6_9W.cjs → javascript-dom-bySaQErv.cjs} +4 -4
  5. package/dist/{javascript-dom-CvtQ6_9W.cjs.map → javascript-dom-bySaQErv.cjs.map} +1 -1
  6. package/dist/{javascript-node-BNsy3loY.cjs → javascript-node-DZxexKer.cjs} +4 -4
  7. package/dist/{javascript-node-BNsy3loY.cjs.map → javascript-node-DZxexKer.cjs.map} +1 -1
  8. package/dist/{javascript-DH8-N38w.cjs → javascript-ycJ4W-e9.cjs} +5 -5
  9. package/dist/{javascript-DH8-N38w.cjs.map → javascript-ycJ4W-e9.cjs.map} +1 -1
  10. package/dist/{jest-4Es9Ggaa.cjs → jest-B2fpQmUB.cjs} +3 -3
  11. package/dist/{jest-4Es9Ggaa.cjs.map → jest-B2fpQmUB.cjs.map} +1 -1
  12. package/dist/main.cjs +30 -32
  13. package/dist/main.cjs.map +1 -1
  14. package/dist/main.js +4 -6
  15. package/dist/main.js.map +1 -1
  16. package/dist/{oxlintOwnership-7hpdB3d1.cjs → removedOptions-BYMW8w__.cjs} +29 -1
  17. package/dist/removedOptions-BYMW8w__.cjs.map +1 -0
  18. package/dist/{oxlintOwnership-Cx0hgA_J.js → removedOptions-Cb8SG8SI.js} +18 -2
  19. package/dist/removedOptions-Cb8SG8SI.js.map +1 -0
  20. package/dist/{stylistic-CoP3MT1Y.cjs → stylistic-B2hCwBRu.cjs} +4 -4
  21. package/dist/{stylistic-CoP3MT1Y.cjs.map → stylistic-B2hCwBRu.cjs.map} +1 -1
  22. package/dist/{typescript-D3VeLnpn.cjs → typescript-DdgbCNKI.cjs} +7 -7
  23. package/dist/{typescript-D3VeLnpn.cjs.map → typescript-DdgbCNKI.cjs.map} +1 -1
  24. package/dist/{typescript-dom-iB_xBTAD.cjs → typescript-dom-C0NNSGLd.cjs} +4 -4
  25. package/dist/{typescript-dom-iB_xBTAD.cjs.map → typescript-dom-C0NNSGLd.cjs.map} +1 -1
  26. package/dist/{typescript-node-Cq6qhj53.cjs → typescript-node-CjG8N83q.cjs} +4 -4
  27. package/dist/{typescript-node-Cq6qhj53.cjs.map → typescript-node-CjG8N83q.cjs.map} +1 -1
  28. package/dist/utils/removedOptions.d.ts +10 -0
  29. package/dist/{vitest-BlGQswK2.cjs → vitest-B3kOWOzo.cjs} +3 -3
  30. package/dist/{vitest-BlGQswK2.cjs.map → vitest-B3kOWOzo.cjs.map} +1 -1
  31. package/dist/{vue2-Da1i_oVn.cjs → vue2-DfL5FqeZ.cjs} +8 -8
  32. package/dist/{vue2-Da1i_oVn.cjs.map → vue2-DfL5FqeZ.cjs.map} +1 -1
  33. package/dist/{vue2-options-api-BSdrUm8H.cjs → vue2-options-api-sSrBV5Si.cjs} +8 -8
  34. package/dist/{vue2-options-api-BSdrUm8H.cjs.map → vue2-options-api-sSrBV5Si.cjs.map} +1 -1
  35. package/dist/{vue2-typescript-options-api-LM7U5dWq.cjs → vue2-typescript-options-api-CbRC2wf-.cjs} +10 -10
  36. package/dist/{vue2-typescript-options-api-LM7U5dWq.cjs.map → vue2-typescript-options-api-CbRC2wf-.cjs.map} +1 -1
  37. package/dist/{vue2-typescript-dXLRSGNP.cjs → vue2-typescript-rJIMzNUI.cjs} +10 -10
  38. package/dist/{vue2-typescript-dXLRSGNP.cjs.map → vue2-typescript-rJIMzNUI.cjs.map} +1 -1
  39. package/dist/{vue3-621EM2Ii.cjs → vue3-DmrGRHbo.cjs} +8 -8
  40. package/dist/{vue3-621EM2Ii.cjs.map → vue3-DmrGRHbo.cjs.map} +1 -1
  41. package/dist/{vue3-options-api-CC9_fAiq.cjs → vue3-options-api-DPEk8rBk.cjs} +8 -8
  42. package/dist/{vue3-options-api-CC9_fAiq.cjs.map → vue3-options-api-DPEk8rBk.cjs.map} +1 -1
  43. package/dist/{vue3-typescript-DONe-IKz.cjs → vue3-typescript-Dz5BM0LJ.cjs} +10 -10
  44. package/dist/{vue3-typescript-DONe-IKz.cjs.map → vue3-typescript-Dz5BM0LJ.cjs.map} +1 -1
  45. package/dist/{vue3-typescript-options-api-D4pqpDFs.cjs → vue3-typescript-options-api-DiYz_vVd.cjs} +10 -10
  46. package/dist/{vue3-typescript-options-api-D4pqpDFs.cjs.map → vue3-typescript-options-api-DiYz_vVd.cjs.map} +1 -1
  47. package/package.json +2 -1
  48. package/dist/oxlintOwnership-7hpdB3d1.cjs.map +0 -1
  49. package/dist/oxlintOwnership-Cx0hgA_J.js.map +0 -1
package/dist/main.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"main.cjs","names":[],"sources":["../src/builders/configFiles.ts","../src/builders/jquery.ts","../src/builders/oxlint.ts","../src/utils/layoutDiagnosis.ts","../src/utils/offerMigration.ts","../src/utils/ensureConfigStructure.ts","../src/builders/typescript.ts","../src/builders/vue.ts","../src/builders/scopeBlocks.ts","../src/builders/spellChecker.ts","../src/builders/strict.ts","../src/utils/ensureDependencies.ts","../src/utils/ensureOxlintConfig.ts","../src/utils/silenceRules.ts","../src/main.ts"],"sourcesContent":["import type { Linter } from 'eslint';\n\n/**\n * Default globs treated as \"configuration files\" — root-level `*.config.*`\n * variants plus the canonical `eslint.config.*` flat-config filenames.\n *\n * These are intentionally conservative: only the top-level matches that the\n * v1 `config` preset was overwhelmingly applied to. Project-specific paths\n * (subdirectories, custom names) must be opted into by passing them via the\n * `configFiles: string[]` knob.\n */\nexport const DEFAULT_CONFIG_FILE_GLOBS: readonly string[] = [\n '*.config.{ts,mts,cts,js,mjs,cjs}',\n '*.config.*.{ts,mts,cts,js,mjs,cjs}',\n 'eslint.config.{mjs,js,cjs,ts}',\n];\n\nconst configFileRules: Linter.RulesRecord = {\n 'import-x/no-extraneous-dependencies': 'off',\n 'import-x/prefer-default-export': 'off',\n};\n\nexport const LINT_TOPOLOGY_NAME = 'insider/lint-topology';\n\n/**\n * The three files `useInsider()` requires a consumer to own. They are always linted with\n * {@link buildLintTopologyBlocks}, independently of the `configFiles` option.\n */\nexport const LINT_TOPOLOGY_GLOBS: readonly string[] = [\n '**/insider.lint.{ts,mts,cts,js,mjs,cjs}',\n '**/eslint.config.{ts,mts,cts,js,mjs,cjs}',\n '**/oxlint.config.{ts,mts,cts,js,mjs,cjs}',\n];\n\n// Neither linter's loader applies TypeScript's `.js` → `.ts` specifier rewriting, so\n// `eslint.config.*` and `oxlint.config.*` have to import the lint module by its real extension —\n// exactly what `import-x/extensions` forbids.\nconst lintTopologyRules: Linter.RulesRecord = {\n ...configFileRules,\n 'import-x/extensions': 'off',\n};\n\n/**\n * Relaxations the mandated three-file layout needs in order to lint clean. Emitted unconditionally\n * because the layout exists whether or not the consumer passes `configFiles`.\n * @example\n * buildLintTopologyBlocks()[0].rules['import-x/extensions']; // 'off'\n */\nexport function buildLintTopologyBlocks (): Linter.Config[] {\n return [{\n name: LINT_TOPOLOGY_NAME,\n files: [...LINT_TOPOLOGY_GLOBS],\n rules: { ...lintTopologyRules },\n }];\n}\n\nfunction mergeGlobs (userGlobs: readonly string[]): string[] {\n const seen = new Set<string>();\n const merged: string[] = [];\n\n DEFAULT_CONFIG_FILE_GLOBS.forEach(glob => {\n if (!seen.has(glob)) {\n seen.add(glob);\n merged.push(glob);\n }\n });\n\n userGlobs.forEach(glob => {\n if (!seen.has(glob)) {\n seen.add(glob);\n merged.push(glob);\n }\n });\n\n return merged;\n}\n\nexport function buildConfigFilesBlocks (value: false | string[] | undefined): Linter.Config[] {\n if (value === false) {\n return [];\n }\n\n const files = value === undefined ? [...DEFAULT_CONFIG_FILE_GLOBS] : mergeGlobs(value);\n\n return [{\n files,\n rules: { ...configFileRules },\n }];\n}\n\n/* v8 ignore start */\nif (import.meta.vitest) {\n const { describe, test, expect } = import.meta.vitest;\n\n describe('buildConfigFilesBlocks', () => {\n test('returns one default-only block when value is undefined (defaults on by default)', () => {\n const blocks = buildConfigFilesBlocks(undefined);\n\n expect(blocks).toHaveLength(1);\n expect(blocks[0].files).toStrictEqual([...DEFAULT_CONFIG_FILE_GLOBS]);\n expect(blocks[0].rules).toStrictEqual({\n 'import-x/no-extraneous-dependencies': 'off',\n 'import-x/prefer-default-export': 'off',\n });\n });\n\n test('returns empty array when value is false (explicit opt-out)', () => {\n expect(buildConfigFilesBlocks(false)).toStrictEqual([]);\n });\n\n test('returns one block with merged globs when value is a string[]', () => {\n const blocks = buildConfigFilesBlocks(['my.special.ts']);\n\n expect(blocks).toHaveLength(1);\n expect(blocks[0].files).toStrictEqual([\n ...DEFAULT_CONFIG_FILE_GLOBS,\n 'my.special.ts',\n ]);\n });\n\n test('user globs append after defaults in given order', () => {\n const blocks = buildConfigFilesBlocks(['z.ts', 'a.ts']);\n\n expect(blocks[0].files).toStrictEqual([\n ...DEFAULT_CONFIG_FILE_GLOBS,\n 'z.ts',\n 'a.ts',\n ]);\n });\n\n test('dedupes user globs that overlap with defaults', () => {\n const blocks = buildConfigFilesBlocks([\n '*.config.{ts,mts,cts,js,mjs,cjs}',\n 'extra.ts',\n ]);\n\n expect(blocks[0].files).toStrictEqual([\n ...DEFAULT_CONFIG_FILE_GLOBS,\n 'extra.ts',\n ]);\n });\n\n test('empty user list still emits default-only block', () => {\n const blocks = buildConfigFilesBlocks([]);\n\n expect(blocks).toHaveLength(1);\n expect(blocks[0].files).toStrictEqual([...DEFAULT_CONFIG_FILE_GLOBS]);\n });\n\n test('block has no languageOptions / parserOptions — only files + rules', () => {\n const [block] = buildConfigFilesBlocks(undefined);\n\n expect(block.languageOptions).toBeUndefined();\n expect(Object.keys(block)).toStrictEqual(['files', 'rules']);\n });\n });\n\n describe('buildLintTopologyBlocks', () => {\n test('covers the lint module and both linter configs', () => {\n const [block] = buildLintTopologyBlocks();\n\n expect(block.files).toStrictEqual([...LINT_TOPOLOGY_GLOBS]);\n });\n\n test('turns off the extension rule the mandated import specifier violates', () => {\n const [block] = buildLintTopologyBlocks();\n\n expect(block.rules?.['import-x/extensions']).toBe('off');\n });\n\n test('keeps the configFiles relaxations so the layout works with configFiles: false', () => {\n const [block] = buildLintTopologyBlocks();\n\n expect(block.rules?.['import-x/no-extraneous-dependencies']).toBe('off');\n expect(block.rules?.['import-x/prefer-default-export']).toBe('off');\n });\n\n test('matches an insider.lint module in a nested workspace package', () => {\n const [block] = buildLintTopologyBlocks();\n\n expect(block.files).toContain('**/insider.lint.{ts,mts,cts,js,mjs,cjs}');\n });\n });\n}\n","import type { Linter } from 'eslint';\nimport globals from 'globals';\n\nexport interface JqueryEntry {\n files: string[];\n}\n\nexport function buildJqueryBlocks (entries: readonly JqueryEntry[] | undefined): Linter.Config[] {\n if (!entries || entries.length === 0) {\n return [];\n }\n\n return entries.map(entry => ({\n files: [...entry.files],\n languageOptions: {\n globals: { ...globals.jquery },\n },\n }));\n}\n\n/* v8 ignore start */\nif (import.meta.vitest) {\n const { describe, test, expect } = import.meta.vitest;\n\n describe('buildJqueryBlocks', () => {\n test('returns empty array when entries is undefined', () => {\n expect(buildJqueryBlocks(undefined)).toStrictEqual([]);\n });\n\n test('returns empty array when entries is empty', () => {\n expect(buildJqueryBlocks([])).toStrictEqual([]);\n });\n\n test('emits one block per entry with files set', () => {\n const blocks = buildJqueryBlocks([\n { files: ['a/**/*.js'] },\n { files: ['b/**/*.js'] },\n ]);\n\n expect(blocks).toHaveLength(2);\n expect(blocks[0].files).toStrictEqual(['a/**/*.js']);\n expect(blocks[1].files).toStrictEqual(['b/**/*.js']);\n });\n\n test('copies the files array (caller mutation does not leak into block)', () => {\n const files = ['legacy/**/*.js'];\n const [block] = buildJqueryBlocks([{ files }]);\n\n files.push('mutated/**');\n\n expect(block.files).toStrictEqual(['legacy/**/*.js']);\n });\n\n test('block exposes jquery globals ($, jQuery)', () => {\n const [block] = buildJqueryBlocks([{ files: ['legacy/**/*.js'] }]);\n const blockGlobals = block.languageOptions?.globals as Record<string, unknown>;\n\n expect(blockGlobals.$).toBeDefined();\n expect(blockGlobals.jQuery).toBeDefined();\n });\n });\n}\n","import type { Linter } from 'eslint';\nimport {\n OXLINT_CATEGORIES,\n VUE_LIKE_GLOBS,\n isOxlintOwned,\n isRuleDisabled,\n isVueUnsafeRule,\n toOxlintPluginName,\n toOxlintRuleName,\n} from './oxlintOwnership';\n\nexport const OXLINT_SUPPRESSION_NAME = 'insider/oxlint-suppression';\n\nexport const OXLINT_SFC_EXCEPTION_NAME = 'insider/oxlint-suppression-sfc-exception';\n\nexport const UNUSED_DIRECTIVE_BLOCK_NAME = 'insider/unused-disable-directives';\n\nexport const UNUSED_DIRECTIVE_SEVERITY = 'warn';\n\nexport function isOxlintSuppressionBlock (block: Linter.Config): boolean {\n return block.name === OXLINT_SUPPRESSION_NAME || block.name === OXLINT_SFC_EXCEPTION_NAME;\n}\n\nexport interface OxlintOverride {\n files: string[];\n excludeFiles?: string[];\n rules: Record<string, Linter.RuleEntry>;\n}\n\nexport interface OxlintRendererOptions {\n respectEslintDisableDirectives: boolean;\n reportUnusedDisableDirectives: typeof UNUSED_DIRECTIVE_SEVERITY;\n}\n\nexport interface OxlintRendererConfig {\n plugins: string[];\n categories: Record<string, 'off'>;\n ignorePatterns?: string[];\n options: OxlintRendererOptions;\n rules: Record<string, Linter.RuleEntry>;\n overrides: OxlintOverride[];\n}\n\n// oxlint judges an `eslint-disable` comment against the rules IT ran, so a directive naming\n// `@cspell/spellchecker`, `sonarjs/*` or `@stylistic/*` — everything the split deliberately keeps\n// on the ESLint side — reports as unused. Refusing the eslint spelling outright is what makes\n// unused-directive reporting sound: oxlint then judges only `oxlint-disable`, ESLint only\n// `eslint-disable`, and neither can flag a comment addressed to the other.\n//\n// oxlint accepts these keys only in the root config file, which is why every generated lint script\n// passes `--disable-nested-config`: a discovered nested config carrying them aborts the whole run.\nexport const OXLINT_DIRECTIVE_OPTIONS: OxlintRendererOptions = {\n respectEslintDisableDirectives: false,\n reportUnusedDisableDirectives: UNUSED_DIRECTIVE_SEVERITY,\n};\n\n/**\n * The always-on ESLint block that makes a stale `eslint-disable` visible. ESLint 9 defaults this to\n * `warn`, but the split relies on it, so it is pinned rather than inherited.\n * @example\n * buildUnusedDirectiveBlocks()[0].linterOptions; // { reportUnusedDisableDirectives: 'warn' }\n */\nexport function buildUnusedDirectiveBlocks (): Linter.Config[] {\n return [{\n name: UNUSED_DIRECTIVE_BLOCK_NAME,\n linterOptions: { reportUnusedDisableDirectives: UNUSED_DIRECTIVE_SEVERITY },\n }];\n}\n\nfunction ownedRuleNames (rules: Partial<Linter.RulesRecord>): string[] {\n return Object.keys(rules).filter(name => isOxlintOwned(name) && !isRuleDisabled(rules[name]));\n}\n\n// Unlike the suppression layer, the emitted oxlint config has to carry explicit `off` entries: a\n// later block that disables a rule an earlier block enabled only takes effect on the oxlint side\n// if the disable is translated too.\nfunction translatableRuleNames (rules: Partial<Linter.RulesRecord>): string[] {\n return Object.keys(rules).filter(isOxlintOwned);\n}\n\nfunction toOffRecord (ruleNames: readonly string[]): Linter.RulesRecord {\n return Object.fromEntries(ruleNames.map(name => [name, 'off']));\n}\n\nfunction suppressionFor (block: Linter.Config): Linter.Config[] {\n if (!block.rules) {\n return [];\n }\n\n const owned = ownedRuleNames(block.rules);\n\n if (owned.length === 0) {\n return [];\n }\n\n // A block without `files` applies everywhere, and so must its suppression.\n const files = block.files ? { files: [...block.files] as string[] } : {};\n const blockIgnores = block.ignores ? [...block.ignores] as string[] : [];\n const vueSafe = owned.filter(name => !isVueUnsafeRule(name));\n const vueUnsafe = owned.filter(name => isVueUnsafeRule(name));\n const suppressions: Linter.Config[] = [];\n\n if (vueSafe.length > 0) {\n suppressions.push({\n name: OXLINT_SUPPRESSION_NAME,\n ...files,\n ...blockIgnores.length > 0 ? { ignores: blockIgnores } : {},\n rules: toOffRecord(vueSafe),\n });\n }\n\n if (vueUnsafe.length > 0) {\n suppressions.push({\n name: OXLINT_SFC_EXCEPTION_NAME,\n ...files,\n ignores: [...blockIgnores, ...VUE_LIKE_GLOBS],\n rules: toOffRecord(vueUnsafe),\n });\n }\n\n return suppressions;\n}\n\n/**\n * ESLint blocks that turn off every rule the emitted oxlint config takes over. Rules oxlint cannot\n * check inside an SFC are suppressed everywhere except `.vue`/`.svelte`/`.astro`, so a Vue consumer\n * keeps them.\n * @example\n * buildOxlintSuppressionBlocks([{ files: ['src/**\\/*.ts'], rules: { 'no-var': 'error' } }]);\n * // [{ files: ['src/**\\/*.ts'], rules: { 'no-var': 'off' } }]\n */\nexport function buildOxlintSuppressionBlocks (blocks: readonly Linter.Config[]): Linter.Config[] {\n return blocks.flatMap(suppressionFor);\n}\n\nfunction translateRules (\n rules: Partial<Linter.RulesRecord>,\n plugins: Set<string>\n): Record<string, Linter.RuleEntry> {\n return translatableRuleNames(rules).reduce<Record<string, Linter.RuleEntry>>((accumulator, name) => {\n plugins.add(toOxlintPluginName(name));\n accumulator[toOxlintRuleName(name)] = rules[name] as Linter.RuleEntry;\n\n return accumulator;\n }, {});\n}\n\n// ESLint anchors a flat-config `files` glob at the config's own directory, while oxlint matches an\n// unanchored pattern at any depth — `*.mjs` would also claim `.husky/install.mjs`. A leading `./`\n// restores the anchor; patterns that already opt into any depth (`**/…`) keep their meaning.\nexport function anchorOxlintGlob (glob: string): string {\n const alreadyAnchored = glob.startsWith('**') || glob.startsWith('./') || glob.startsWith('/');\n\n return alreadyAnchored ? glob : `./${glob}`;\n}\n\nfunction anchorGlobs (globs: readonly unknown[]): string[] {\n return (globs as string[]).map(anchorOxlintGlob);\n}\n\n// `ignorePatterns` is read with gitignore semantics, not glob semantics, so it needs a different\n// anchor from `anchorOxlintGlob`: a leading `/`, which `./` does not stand in for — oxlint 1.83.0\n// matches nothing at all for `./dist`. Without it a slash-free pattern like `dist` is matched at\n// any depth, so oxlint would also skip `src/dist/**` that ESLint still lints — and since every\n// oxlint-owned rule is switched off on the ESLint side, those files would lose the rule entirely.\n// A pattern already carrying a slash is anchored by gitignore itself; `**`-leading and already\n// rooted patterns keep their meaning, and a negation is anchored inside the `!`.\nexport function anchorOxlintIgnorePattern (pattern: string): string {\n const negated = pattern.startsWith('!');\n const body = negated ? pattern.slice(1) : pattern;\n const anchored = body.startsWith('/') || body.startsWith('**') ? body : `/${body}`;\n\n return negated ? `!${anchored}` : anchored;\n}\n\nfunction overrideFor (block: Linter.Config, plugins: Set<string>): OxlintOverride[] {\n if (!block.files || !block.rules) {\n return [];\n }\n\n const translated = translateRules(block.rules, plugins);\n\n if (Object.keys(translated).length === 0) {\n return [];\n }\n\n return [{\n files: anchorGlobs(block.files),\n ...block.ignores && block.ignores.length > 0 ? { excludeFiles: anchorGlobs(block.ignores) } : {},\n rules: translated,\n }];\n}\n\n/**\n * The oxlint half of the split, derived from the same emitted ESLint blocks the suppression layer\n * reads. Every oxlint category is pinned off so the config enables exactly the preset's own rules\n * and nothing oxlint would otherwise turn on by default.\n * @example\n * buildOxlintConfig([{ files: ['src/**\\/*.ts'], rules: { 'no-var': 'error' } }], ['dist']);\n * // { plugins: ['eslint'], categories: { correctness: 'off', ... }, ignorePatterns: ['/dist'], ... }\n */\nexport function buildOxlintConfig (\n blocks: readonly Linter.Config[],\n ignores: readonly string[] | undefined\n): OxlintRendererConfig {\n const plugins = new Set<string>(['eslint']);\n const overrides = blocks.flatMap(block => overrideFor(block, plugins));\n const globalRules = blocks\n .filter(block => !block.files && block.rules)\n .reduce<Record<string, Linter.RuleEntry>>(\n (accumulator, block) => ({ ...accumulator, ...translateRules(block.rules!, plugins) }),\n {}\n );\n\n return {\n plugins: [...plugins].sort((left, right) => left.localeCompare(right)),\n categories: Object.fromEntries(OXLINT_CATEGORIES.map(name => [name, 'off'])),\n ...ignores && ignores.length > 0 ? { ignorePatterns: ignores.map(anchorOxlintIgnorePattern) } : {},\n options: { ...OXLINT_DIRECTIVE_OPTIONS },\n rules: globalRules,\n overrides,\n };\n}\n\n/* v8 ignore start */\nif (import.meta.vitest) {\n const { describe, test, expect } = import.meta.vitest;\n\n const tsBlock: Linter.Config = {\n files: ['src/**/*.ts'],\n rules: {\n 'no-var': 'error',\n 'import-x/first': 'error',\n '@typescript-eslint/no-unused-vars': 'error',\n 'sonarjs/no-identical-functions': 'error',\n '@stylistic/indent': ['error', 4],\n 'no-console': 'off',\n },\n };\n\n describe('buildOxlintSuppressionBlocks', () => {\n test('suppresses only the rules oxlint owns', () => {\n const [primary] = buildOxlintSuppressionBlocks([tsBlock]);\n\n expect(primary.rules).toStrictEqual({ 'no-var': 'off', 'import-x/first': 'off' });\n });\n\n test('keeps SFC-unsafe rules enforced for vue, svelte and astro files', () => {\n const [, exception] = buildOxlintSuppressionBlocks([tsBlock]);\n\n expect(exception.rules).toStrictEqual({ '@typescript-eslint/no-unused-vars': 'off' });\n expect(exception.ignores).toStrictEqual([...VUE_LIKE_GLOBS]);\n });\n\n test('never suppresses a rule the preset already turned off', () => {\n const blocks = buildOxlintSuppressionBlocks([tsBlock]);\n const suppressed = blocks.flatMap(block => Object.keys(block.rules ?? {}));\n\n expect(suppressed).not.toContain('no-console');\n });\n\n test('carries the source block ignores so the suppression matches the same files', () => {\n const [primary] = buildOxlintSuppressionBlocks([\n { ...tsBlock, ignores: ['src/legacy/**'] },\n ]);\n\n expect(primary.ignores).toStrictEqual(['src/legacy/**']);\n });\n\n test('appends the SFC globs to the source block ignores on the exception block', () => {\n const [, exception] = buildOxlintSuppressionBlocks([\n { ...tsBlock, ignores: ['src/legacy/**'] },\n ]);\n\n expect(exception.ignores).toStrictEqual(['src/legacy/**', ...VUE_LIKE_GLOBS]);\n });\n\n test('emits nothing for a block without files or rules', () => {\n expect(buildOxlintSuppressionBlocks([{ ignores: ['dist'] }])).toStrictEqual([]);\n expect(buildOxlintSuppressionBlocks([{ files: ['*.js'] }])).toStrictEqual([]);\n });\n });\n\n describe('buildUnusedDirectiveBlocks', () => {\n test('pins ESLint unused-directive reporting instead of inheriting the default', () => {\n expect(buildUnusedDirectiveBlocks()).toStrictEqual([{\n name: UNUSED_DIRECTIVE_BLOCK_NAME,\n linterOptions: { reportUnusedDisableDirectives: 'warn' },\n }]);\n });\n\n test('carries no files or rules, so it neither suppresses nor reaches the oxlint side', () => {\n const [block] = buildUnusedDirectiveBlocks();\n\n expect(buildOxlintSuppressionBlocks([block])).toStrictEqual([]);\n expect(buildOxlintConfig([block], undefined).overrides).toStrictEqual([]);\n });\n });\n\n describe('buildOxlintConfig', () => {\n test('translates owned rules into oxlint names, preserving severity and options', () => {\n const { overrides } = buildOxlintConfig([{\n files: ['src/**/*.ts'],\n rules: { 'no-bitwise': ['error', { allow: ['~'] }] },\n }], undefined);\n\n expect(overrides[0].rules).toStrictEqual({ 'eslint/no-bitwise': ['error', { allow: ['~'] }] });\n });\n\n test('derives the plugin list from the rules actually emitted', () => {\n const { plugins } = buildOxlintConfig([tsBlock], undefined);\n\n expect(plugins).toStrictEqual(['eslint', 'import', 'typescript']);\n });\n\n test('pins every oxlint category off so defaults cannot leak in', () => {\n const { categories } = buildOxlintConfig([], undefined);\n\n expect(Object.values(categories).every(value => value === 'off')).toBe(true);\n expect(Object.keys(categories)).toStrictEqual([...OXLINT_CATEGORIES]);\n });\n\n test('maps config ignores onto ignorePatterns', () => {\n expect(buildOxlintConfig([], ['dist', 'coverage']).ignorePatterns).toStrictEqual(['/dist', '/coverage']);\n expect(buildOxlintConfig([], []).ignorePatterns).toBeUndefined();\n });\n });\n\n describe('anchorOxlintIgnorePattern', () => {\n test('roots a slash-free pattern so it cannot swallow a nested directory of the same name', () => {\n expect(anchorOxlintIgnorePattern('dist')).toBe('/dist');\n expect(anchorOxlintIgnorePattern('dist/')).toBe('/dist/');\n });\n\n test('roots a pattern that already carries a slash, which gitignore anchors anyway', () => {\n expect(anchorOxlintIgnorePattern('scripts/legacy/**')).toBe('/scripts/legacy/**');\n });\n\n test('leaves an any-depth or already rooted pattern alone', () => {\n expect(anchorOxlintIgnorePattern('**/dist')).toBe('**/dist');\n expect(anchorOxlintIgnorePattern('/dist')).toBe('/dist');\n });\n\n test('anchors inside the negation so an un-ignore matches the same files as its ignore', () => {\n expect(anchorOxlintIgnorePattern('!dist/keep.js')).toBe('!/dist/keep.js');\n expect(anchorOxlintIgnorePattern('!**/dist')).toBe('!**/dist');\n });\n\n test('maps block ignores onto the override excludeFiles key', () => {\n const { overrides } = buildOxlintConfig([{ ...tsBlock, ignores: ['src/legacy/**'] }], undefined);\n\n expect(overrides[0].excludeFiles).toStrictEqual(['./src/legacy/**']);\n });\n\n test('anchors override globs so oxlint matches the same files ESLint does', () => {\n const { overrides } = buildOxlintConfig([{ files: ['*.mjs'], rules: { 'no-var': 'error' } }], undefined);\n\n expect(overrides[0].files).toStrictEqual(['./*.mjs']);\n });\n\n test('leaves any-depth globs alone', () => {\n const { overrides } = buildOxlintConfig([{\n files: ['**/*.mjs'],\n rules: { 'no-var': 'error' },\n }], undefined);\n\n expect(overrides[0].files).toStrictEqual(['**/*.mjs']);\n });\n\n test('carries an explicit off so a later block can release a rule an earlier one enabled', () => {\n const { overrides } = buildOxlintConfig([{\n files: ['*.mjs'],\n rules: { 'no-var': 'off' },\n }], undefined);\n\n expect(overrides[0].rules).toStrictEqual({ 'eslint/no-var': 'off' });\n });\n\n test('refuses the eslint-disable spelling and reports unused oxlint-disable directives', () => {\n expect(buildOxlintConfig([], undefined).options).toStrictEqual({\n respectEslintDisableDirectives: false,\n reportUnusedDisableDirectives: 'warn',\n });\n });\n\n test('emits no override for a block whose rules are all ESLint-owned', () => {\n const { overrides } = buildOxlintConfig([{\n files: ['src/**/*.ts'],\n rules: { 'sonarjs/no-identical-functions': 'error' },\n }], undefined);\n\n expect(overrides).toStrictEqual([]);\n });\n });\n}\n","import { existsSync, readFileSync } from 'node:fs';\nimport { createRequire } from 'node:module';\nimport { join } from 'node:path';\nimport { AST_NODE_TYPES, type TSESTree } from '@typescript-eslint/types';\n\nconst MODULE_EXTENSIONS: readonly string[] = ['ts', 'mts', 'cts', 'js', 'mjs', 'cjs'];\n\nexport const LINT_MODULE_FILENAMES: readonly string[] = MODULE_EXTENSIONS.map(ext => `insider.lint.${ext}`);\n\nexport const ESLINT_CONFIG_FILENAMES: readonly string[] = MODULE_EXTENSIONS.map(ext => `eslint.config.${ext}`);\n\n// oxlint discovers only these two. It ignores `oxlint.config.{cts,js,mjs,cjs}` without a word and\n// silently falls through to the nearest ancestor config, so accepting them here would let a\n// consumer believe a config is live when oxlint never reads it.\nexport const OXLINT_CONFIG_FILENAMES: readonly string[] = ['oxlint.config.ts', 'oxlint.config.mts'];\n\nexport const OPT_OUT_ENV = 'INSIDER_SKIP_CONFIG_VALIDATION';\n\nexport const MIGRATE_COMMAND = 'npx @useinsider/eslint-config migrate';\n\nexport const SCAFFOLD_COMMAND = 'npx @useinsider/eslint-config';\n\nexport const INSIDER_IMPORT_SOURCE = '@useinsider/eslint-config';\n\nexport const TARGET_CALLEE_NAME = 'useInsider';\n\nexport const ESLINT_RENDERER_NAME = 'useInsiderESLint';\n\nexport const OXC_RENDERER_NAME = 'useInsiderOXC';\n\nconst RENDERER_BINDINGS = `{ ${ESLINT_RENDERER_NAME}, ${OXC_RENDERER_NAME} }`;\n\nexport const RENDERER_EXPORT = `export const ${RENDERER_BINDINGS} = ${TARGET_CALLEE_NAME}({ ... })`;\n\n// The import specifier names the lint module's real extension: neither ESLint's jiti loader nor\n// oxlint's Node type stripping applies TypeScript's `.js` → `.ts` specifier rewriting.\nexport const EXPECTED_LAYOUT = [\n 'Expected layout (three sibling files):',\n '',\n ' // insider.lint.ts',\n ` import { ${TARGET_CALLEE_NAME} } from '${INSIDER_IMPORT_SOURCE}';`,\n '',\n ` ${RENDERER_EXPORT};`,\n '',\n ' // eslint.config.ts',\n ` import { ${ESLINT_RENDERER_NAME} } from './insider.lint.ts';`,\n '',\n ` export default ${ESLINT_RENDERER_NAME}();`,\n '',\n ' // oxlint.config.ts',\n ` import { ${OXC_RENDERER_NAME} } from './insider.lint.ts';`,\n '',\n ` export default await ${OXC_RENDERER_NAME}();`,\n].join('\\n');\n\nexport type LayoutCase = 'complete' | 'noConfig' | 'partial' | 'unmigratedV3';\n\nexport interface LayoutDiagnosis {\n kind: LayoutCase;\n directory: string;\n lintModule: string | null;\n eslintConfig: string | null;\n oxlintConfig: string | null;\n missing: string[];\n autoMigratable: boolean;\n}\n\nexport interface DiagnoseLayoutOptions {\n fileExists?: (path: string) => boolean;\n readSource?: (path: string) => string;\n}\n\nfunction findSibling (\n directory: string,\n filenames: readonly string[],\n fileExists: (path: string) => boolean\n): string | null {\n return filenames.find(filename => fileExists(join(directory, filename))) ?? null;\n}\n\nconst lazyRequire = createRequire(import.meta.url);\n\nfunction parseProgram (source: string): TSESTree.Program | null {\n try {\n const { parse } = lazyRequire('@typescript-eslint/parser') as typeof import('@typescript-eslint/parser');\n\n return parse(source, { sourceType: 'module', range: true, loc: true });\n } catch {\n return null;\n }\n}\n\nfunction collectUseInsiderAliases (program: TSESTree.Program): Set<string> {\n const aliases = new Set<string>();\n\n program.body.forEach(node => {\n if (node.type !== AST_NODE_TYPES.ImportDeclaration) {\n return;\n }\n\n node.specifiers.forEach(specifier => {\n const importsTheComposer = specifier.type === AST_NODE_TYPES.ImportSpecifier\n && specifier.imported.type === AST_NODE_TYPES.Identifier\n && specifier.imported.name === TARGET_CALLEE_NAME;\n\n if (importsTheComposer) {\n aliases.add(specifier.local.name);\n }\n });\n });\n\n return aliases;\n}\n\nfunction callsAny (node: unknown, aliases: ReadonlySet<string>): boolean {\n if (!node || typeof node !== 'object') {\n return false;\n }\n\n if (Array.isArray(node)) {\n return node.some(child => callsAny(child, aliases));\n }\n\n const candidate = node as TSESTree.Node;\n\n if (candidate.type === AST_NODE_TYPES.CallExpression) {\n const { callee } = candidate;\n\n if (callee.type === AST_NODE_TYPES.Identifier && aliases.has(callee.name)) {\n return true;\n }\n }\n\n return Object.entries(node).some(([key, value]) => key !== 'parent' && callsAny(value, aliases));\n}\n\n/**\n * Whether a flat-config source is still the removed v3 shape: it imports `useInsider` and calls it\n * itself, instead of importing a renderer from a sibling `insider.lint.*` module. Both the plain\n * `export default useInsider({...})` form and the spread form are recognized.\n * @example\n * isV3EslintConfigSource(\"import { useInsider } from '@useinsider/eslint-config';\\nexport default useInsider({});\");\n * // true\n */\nexport function isV3EslintConfigSource (source: string): boolean {\n const program = parseProgram(source);\n\n if (!program) {\n return false;\n }\n\n const aliases = collectUseInsiderAliases(program);\n\n if (aliases.size === 0) {\n return false;\n }\n\n return program.body.some(node => callsAny(node, aliases));\n}\n\nfunction classify (\n lintModule: string | null,\n eslintConfig: string | null,\n oxlintConfig: string | null,\n eslintConfigIsV3: boolean\n): LayoutCase {\n if (lintModule && eslintConfig && oxlintConfig) {\n return 'complete';\n }\n\n if (!lintModule && !eslintConfig && !oxlintConfig) {\n return 'noConfig';\n }\n\n if (!lintModule && eslintConfig && eslintConfigIsV3) {\n return 'unmigratedV3';\n }\n\n return 'partial';\n}\n\n/**\n * What of the three-file layout is on disk in a directory, and which of the four guidance branches\n * applies. `unmigratedV3` is the only branch the in-lint migration offer acts on, because it is the\n * only one {@link import('../cli/migrate').runMigrate} can actually rewrite.\n * @example\n * diagnoseLayout('/repo').kind; // 'unmigratedV3' when eslint.config.js still calls useInsider()\n */\nexport function diagnoseLayout (directory: string, options: DiagnoseLayoutOptions = {}): LayoutDiagnosis {\n const fileExists = options.fileExists ?? existsSync;\n const readSource = options.readSource ?? ((path: string) => readFileSync(path, 'utf8'));\n const lintModule = findSibling(directory, LINT_MODULE_FILENAMES, fileExists);\n const eslintConfig = findSibling(directory, ESLINT_CONFIG_FILENAMES, fileExists);\n const oxlintConfig = findSibling(directory, OXLINT_CONFIG_FILENAMES, fileExists);\n let eslintConfigIsV3 = false;\n\n if (eslintConfig && !lintModule) {\n try {\n eslintConfigIsV3 = isV3EslintConfigSource(readSource(join(directory, eslintConfig)));\n } catch {\n eslintConfigIsV3 = false;\n }\n }\n\n const kind = classify(lintModule, eslintConfig, oxlintConfig, eslintConfigIsV3);\n const missing = [\n lintModule ? null : 'insider.lint.ts',\n eslintConfig ? null : 'eslint.config.ts',\n oxlintConfig ? null : 'oxlint.config.ts',\n ].filter((name): name is string => name !== null);\n\n return {\n kind,\n directory,\n lintModule,\n eslintConfig,\n oxlintConfig,\n missing,\n autoMigratable: kind === 'unmigratedV3',\n };\n}\n\n/**\n * Import specifier for the consumer's lint module, naming the extension that is actually on disk so\n * the suggested snippet resolves as printed.\n * @example\n * lintModuleSpecifier('/repo'); // './insider.lint.mts' when that is the file present\n */\nexport function lintModuleSpecifier (directory: string, fileExists: (path: string) => boolean = existsSync): string {\n return `./${findSibling(directory, LINT_MODULE_FILENAMES, fileExists) ?? 'insider.lint.ts'}`;\n}\n\nfunction inventoryLines (diagnosis: LayoutDiagnosis): string[] {\n const v3Note = diagnosis.kind === 'unmigratedV3' ? ' (still calls `useInsider()` itself)' : '';\n\n return [\n diagnosis.lintModule\n ? ` present: ${diagnosis.lintModule}`\n : ' MISSING: insider.lint.{ts,mts}',\n diagnosis.eslintConfig\n ? ` present: ${diagnosis.eslintConfig}${v3Note}`\n : ' MISSING: eslint.config.{ts,mts}',\n diagnosis.oxlintConfig\n ? ` present: ${diagnosis.oxlintConfig}`\n : ` MISSING: ${OXLINT_CONFIG_FILENAMES.join(' or ')}`,\n ];\n}\n\nfunction guidanceBody (diagnosis: LayoutDiagnosis): string[] {\n if (diagnosis.kind === 'complete') {\n return [\n `All three files are already here, so there is nothing to migrate — ${TARGET_CALLEE_NAME}() was`,\n `reached from somewhere other than ${diagnosis.lintModule ?? LINT_MODULE_FILENAMES[0]}. Only the`,\n 'lint module may call it; the two configs import the renderers it exports.',\n ];\n }\n\n if (diagnosis.kind === 'unmigratedV3') {\n return [\n '`useInsider()` no longer returns a flat-config array, so the config it is called from has',\n 'to become a module both linters can import. The migration does that rewrite for you:',\n '',\n ` ${MIGRATE_COMMAND}`,\n ];\n }\n\n if (diagnosis.kind === 'noConfig') {\n return [\n 'There is no linter configuration here yet. Scaffold the three-file layout:',\n '',\n ` ${SCAFFOLD_COMMAND}`,\n ];\n }\n\n return [\n `The layout is incomplete — missing ${diagnosis.missing.join(', ')}.`,\n 'Add the missing file, or let the migration regenerate the whole layout:',\n '',\n ` ${MIGRATE_COMMAND}`,\n ];\n}\n\nfunction detailLines (detail: readonly string[] | undefined): string[] {\n if (!detail || detail.length === 0) {\n return [];\n }\n\n return ['', ...detail];\n}\n\nexport interface LayoutGuidanceInput {\n headline: string;\n diagnosis: LayoutDiagnosis;\n detail?: readonly string[];\n}\n\n/**\n * The consumer-facing failure text: a site-specific headline, then the branch that matches what is\n * on disk, then the layout dump, then the bypass. The command to run always comes before the dump,\n * because a consumer who reads only the first screen still has to be told about `migrate`.\n * @example\n * formatLayoutGuidance({ headline: 'no `insider.lint.*` module found in /repo.', diagnosis });\n */\nexport function formatLayoutGuidance (input: LayoutGuidanceInput): string {\n return [\n `@useinsider/eslint-config: ${input.headline}`,\n '',\n ...inventoryLines(input.diagnosis),\n '',\n ...guidanceBody(input.diagnosis),\n ...detailLines(input.detail),\n '',\n EXPECTED_LAYOUT,\n '',\n `Emergency bypass: set ${OPT_OUT_ENV}=true (do not commit).`,\n ].join('\\n');\n}\n\n/* v8 ignore start */\nif (import.meta.vitest) {\n const { describe, test, expect } = import.meta.vitest;\n const { mkdtempSync, writeFileSync } = await import('node:fs');\n const { tmpdir } = await import('node:os');\n\n const V3_SOURCE = [\n \"import { silenceRules, useInsider } from '@useinsider/eslint-config';\",\n \"silenceRules(['complexity']);\",\n 'export default useInsider({ typescriptNode: [{ files: [], tsconfigPaths: [] }] });',\n ].join('\\n');\n\n function makeDir (files: Record<string, string> = {}): string {\n const directory = mkdtempSync(join(tmpdir(), 'insider-diagnosis-'));\n\n Object.entries(files).forEach(([name, content]) => {\n writeFileSync(join(directory, name), content, 'utf8');\n });\n\n return directory;\n }\n\n describe('isV3EslintConfigSource', () => {\n test('recognizes the plain v3 default export', () => {\n expect(isV3EslintConfigSource(V3_SOURCE)).toBe(true);\n });\n\n test('recognizes the v3 spread shape', () => {\n const source = [\n \"import { useInsider } from '@useinsider/eslint-config';\",\n \"export default [{ ignores: ['dist'] }, ...await useInsider({}), { rules: {} }];\",\n ].join('\\n');\n\n expect(isV3EslintConfigSource(source)).toBe(true);\n });\n\n test('recognizes an aliased import', () => {\n const source = [\n \"import { useInsider as compose } from '@useinsider/eslint-config';\",\n 'export default compose({});',\n ].join('\\n');\n\n expect(isV3EslintConfigSource(source)).toBe(true);\n });\n\n test('rejects the migrated v4 config', () => {\n const source = [\n \"import { useInsiderESLint } from './insider.lint.ts';\",\n 'export default useInsiderESLint();',\n ].join('\\n');\n\n expect(isV3EslintConfigSource(source)).toBe(false);\n });\n\n test('rejects a config that imports useInsider without calling it', () => {\n const source = [\n \"import { useInsider } from '@useinsider/eslint-config';\",\n 'export default [];',\n ].join('\\n');\n\n expect(isV3EslintConfigSource(source)).toBe(false);\n });\n\n test('rejects an unparseable source instead of throwing', () => {\n expect(isV3EslintConfigSource('export default (((')).toBe(false);\n });\n });\n\n describe('diagnoseLayout', () => {\n test('reports a complete layout', () => {\n const directory = makeDir({\n 'insider.lint.ts': '',\n 'eslint.config.ts': '',\n 'oxlint.config.ts': '',\n });\n const diagnosis = diagnoseLayout(directory);\n\n expect(diagnosis.kind).toBe('complete');\n expect(diagnosis.missing).toStrictEqual([]);\n expect(diagnosis.autoMigratable).toBe(false);\n });\n\n test('reports an un-migrated v3 config', () => {\n const diagnosis = diagnoseLayout(makeDir({ 'eslint.config.js': V3_SOURCE }));\n\n expect(diagnosis.kind).toBe('unmigratedV3');\n expect(diagnosis.eslintConfig).toBe('eslint.config.js');\n expect(diagnosis.autoMigratable).toBe(true);\n expect(diagnosis.missing).toStrictEqual(['insider.lint.ts', 'oxlint.config.ts']);\n });\n\n test('reports an empty directory as noConfig', () => {\n const diagnosis = diagnoseLayout(makeDir());\n\n expect(diagnosis.kind).toBe('noConfig');\n expect(diagnosis.autoMigratable).toBe(false);\n });\n\n test('reports a v4 config missing its lint module as partial, not v3', () => {\n const diagnosis = diagnoseLayout(makeDir({\n 'eslint.config.ts': \"import { useInsiderESLint } from './insider.lint.ts';\\n\"\n + 'export default useInsiderESLint();',\n 'oxlint.config.ts': '',\n }));\n\n expect(diagnosis.kind).toBe('partial');\n expect(diagnosis.missing).toStrictEqual(['insider.lint.ts']);\n expect(diagnosis.autoMigratable).toBe(false);\n });\n\n test('reports a missing oxlint config as partial', () => {\n const diagnosis = diagnoseLayout(makeDir({\n 'insider.lint.ts': '',\n 'eslint.config.ts': '',\n }));\n\n expect(diagnosis.kind).toBe('partial');\n expect(diagnosis.missing).toStrictEqual(['oxlint.config.ts']);\n });\n\n test('ignores oxlint config extensions oxlint never discovers', () => {\n const diagnosis = diagnoseLayout(makeDir({\n 'insider.lint.ts': '',\n 'eslint.config.ts': '',\n 'oxlint.config.mjs': '',\n }));\n\n expect(diagnosis.oxlintConfig).toBeNull();\n expect(diagnosis.kind).toBe('partial');\n });\n\n test('survives an unreadable eslint config', () => {\n const diagnosis = diagnoseLayout('/does/not/exist', {\n fileExists: path => path.endsWith('eslint.config.js'),\n readSource: () => {\n throw new Error('EACCES');\n },\n });\n\n expect(diagnosis.kind).toBe('partial');\n });\n });\n\n describe('formatLayoutGuidance', () => {\n test('leads an un-migrated v3 config with the migrate command, before the layout dump', () => {\n const diagnosis = diagnoseLayout(makeDir({ 'eslint.config.js': V3_SOURCE }));\n const message = formatLayoutGuidance({ headline: 'headline.', diagnosis });\n\n expect(message.indexOf(MIGRATE_COMMAND)).toBeLessThan(message.indexOf('Expected layout'));\n expect(message.indexOf('Expected layout')).toBeLessThan(message.indexOf(OPT_OUT_ENV));\n expect(message).toContain('still calls `useInsider()` itself');\n });\n\n test('recommends scaffold when nothing is on disk', () => {\n const message = formatLayoutGuidance({\n headline: 'headline.',\n diagnosis: diagnoseLayout(makeDir()),\n });\n\n expect(message).toContain(SCAFFOLD_COMMAND);\n expect(message).not.toContain(MIGRATE_COMMAND);\n });\n\n test('names the missing file for a partial layout', () => {\n const message = formatLayoutGuidance({\n headline: 'headline.',\n diagnosis: diagnoseLayout(makeDir({ 'insider.lint.ts': '', 'eslint.config.ts': '' })),\n });\n\n expect(message).toContain('missing oxlint.config.ts');\n expect(message).toContain(MIGRATE_COMMAND);\n });\n\n test('places site-specific detail after the guidance and before the dump', () => {\n const message = formatLayoutGuidance({\n headline: 'headline.',\n diagnosis: diagnoseLayout(makeDir()),\n detail: ['site detail line'],\n });\n\n expect(message.indexOf(SCAFFOLD_COMMAND)).toBeLessThan(message.indexOf('site detail line'));\n expect(message.indexOf('site detail line')).toBeLessThan(message.indexOf('Expected layout'));\n });\n });\n\n describe('lintModuleSpecifier', () => {\n test('names the module that exists', () => {\n expect(lintModuleSpecifier(makeDir({ 'insider.lint.mts': '' }))).toBe('./insider.lint.mts');\n });\n\n test('falls back to the TypeScript filename', () => {\n expect(lintModuleSpecifier(makeDir())).toBe('./insider.lint.ts');\n });\n });\n}\n","import { spawnSync } from 'node:child_process';\nimport { existsSync, readFileSync } from 'node:fs';\nimport { basename, dirname, join, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { type LayoutDiagnosis, OPT_OUT_ENV } from './layoutDiagnosis';\n\nconst PACKAGE_NAME = '@useinsider/eslint-config';\nconst CLI_RELATIVE_PATH = 'dist/cli.cjs';\nconst NO_PROMPT_ENV = 'INSIDER_NO_PROMPT';\nconst IN_FLIGHT_ENV = 'INSIDER_MIGRATION_IN_PROGRESS';\nconst MIGRATE_FROM_LINT_ARGS: readonly string[] = ['migrate', '--from-lint'];\nconst BINARY_EXTENSIONS = /\\.[mc]?js$/u;\n\nexport type LintHost = 'eslint' | 'oxlint' | 'unknown';\n\nfunction binaryName (argument: string): string {\n return basename(argument).replace(BINARY_EXTENSIONS, '');\n}\n\n/**\n * Which linter is hosting the current process. oxlint evaluates `oxlint.config.ts` inside the Node\n * process that runs its own `bin/oxlint` wrapper, so `useInsider()` genuinely executes under both\n * binaries and the two have to be told apart before anything is written to stdout.\n * @example\n * detectLintHost(['node', '/app/node_modules/oxlint/bin/oxlint', '.']); // 'oxlint'\n */\nexport function detectLintHost (argv: readonly string[] = process.argv): LintHost {\n const names = argv.slice(1).map(binaryName);\n\n if (names.includes('oxlint')) {\n return 'oxlint';\n }\n\n if (names.includes('eslint')) {\n return 'eslint';\n }\n\n return 'unknown';\n}\n\nexport type OfferSkipReason = | 'already-offered'\n | 'cli-not-found'\n | 'host-is-oxlint'\n | 'no-tty'\n | 'running-in-ci'\n | 'running-under-test'\n | 'suppressed';\n\nexport interface MigrationOfferResult {\n offered: boolean;\n skipReason?: OfferSkipReason;\n accepted?: boolean;\n}\n\nexport interface MigrationOfferDeps {\n env?: NodeJS.ProcessEnv;\n argv?: readonly string[];\n interactive?: boolean;\n resolveCliEntry?: () => string | null;\n runCli?: (entry: string, args: readonly string[], cwd: string, env: NodeJS.ProcessEnv) => number;\n warn?: (message: string) => void;\n}\n\nfunction defaultInteractive (): boolean {\n return Boolean(process.stdin.isTTY) && Boolean(process.stdout.isTTY);\n}\n\nfunction skipReasonFor (\n env: NodeJS.ProcessEnv,\n argv: readonly string[],\n interactive: boolean\n): OfferSkipReason | null {\n if (env[IN_FLIGHT_ENV] === 'true') {\n return 'already-offered';\n }\n\n // A suite that happens to run in a terminal has a live TTY, and spawning the migrator from it\n // would rewrite the fixture tree under the runner. Specs inject `env` to exercise the real path.\n if (env.VITEST || env.NODE_ENV === 'test') {\n return 'running-under-test';\n }\n\n if (env[OPT_OUT_ENV] === 'true' || env[NO_PROMPT_ENV] === 'true') {\n return 'suppressed';\n }\n\n if (env.CI) {\n return 'running-in-ci';\n }\n\n if (detectLintHost(argv) === 'oxlint') {\n return 'host-is-oxlint';\n }\n\n if (!interactive) {\n return 'no-tty';\n }\n\n return null;\n}\n\nfunction manifestNameAt (directory: string): string | null {\n const manifestPath = join(directory, 'package.json');\n\n if (!existsSync(manifestPath)) {\n return null;\n }\n\n try {\n return (JSON.parse(readFileSync(manifestPath, 'utf8')) as { name?: string }).name ?? null;\n } catch {\n return null;\n }\n}\n\nfunction packageRootFrom (startDir: string): string | null {\n let current = startDir;\n\n for (let depth = 0; depth < 10; depth += 1) {\n if (manifestNameAt(current) === PACKAGE_NAME) {\n return current;\n }\n\n const parent = dirname(current);\n\n if (parent === current) {\n return null;\n }\n\n current = parent;\n }\n\n return null;\n}\n\n/**\n * Absolute path to this package's own built CLI, or `null` when it is not on disk. Resolved by\n * walking up from `startDir` — this module's own directory by default — rather than through\n * `require.resolve`, so it works from `dist/` and from `src/` alike.\n * @example\n * resolveCliEntry(); // '/app/node_modules/@useinsider/eslint-config/dist/cli.cjs'\n */\nexport function resolveCliEntry (startDir?: string): string | null {\n const root = packageRootFrom(startDir ?? dirname(fileURLToPath(import.meta.url)));\n\n if (!root) {\n return null;\n }\n\n const entry = resolve(root, CLI_RELATIVE_PATH);\n\n return existsSync(entry) ? entry : null;\n}\n\n// The migrator prompts, so it needs the terminal. `useInsider()` is synchronous — it is called\n// during ESLint's config evaluation and cannot await — so the only way to drive an interactive\n// migration from here is a synchronous child process that inherits this one's stdio.\nfunction defaultRunCli (\n entry: string,\n args: readonly string[],\n cwd: string,\n env: NodeJS.ProcessEnv\n): number {\n const result = spawnSync(process.execPath, [entry, ...args], { cwd, env, stdio: 'inherit' });\n\n if (result.error) {\n return 1;\n }\n\n return result.status ?? 1;\n}\n\nfunction defaultWarn (message: string): void {\n // oxlint-disable-next-line no-console -- diagnostic surface, mirrors ensureDependencies.ts.\n console.error(message);\n}\n\nfunction outdatedNotice (diagnosis: LayoutDiagnosis): string {\n const config = diagnosis.eslintConfig ?? 'eslint.config.*';\n\n return [\n `@useinsider/eslint-config: ${config} still uses the v3 single-file layout.`,\n ` ${join(diagnosis.directory, config)} calls \\`useInsider()\\` itself, and`,\n ` ${diagnosis.missing.join(' and ')} ${diagnosis.missing.length === 1 ? 'is' : 'are'} missing.`,\n '',\n 'Starting the guided migration. It shows every change before applying it.',\n `Skip it with ${NO_PROMPT_ENV}=true.`,\n '',\n ].join('\\n');\n}\n\nlet offerAttempted = false;\n\ntype ResolvedOfferDeps = Required<MigrationOfferDeps>;\n\nfunction withDefaults (deps: MigrationOfferDeps): ResolvedOfferDeps {\n return {\n env: deps.env ?? process.env,\n argv: deps.argv ?? process.argv,\n interactive: deps.interactive ?? defaultInteractive(),\n resolveCliEntry: deps.resolveCliEntry ?? resolveCliEntry,\n runCli: deps.runCli ?? defaultRunCli,\n warn: deps.warn ?? defaultWarn,\n };\n}\n\n/**\n * Offers the guided migration for an outdated layout and runs it when the consumer accepts. Declines\n * silently — returning a skip reason instead of prompting — whenever writing to stdout would be\n * wrong: under oxlint, in CI, without a TTY, or when already inside a migration.\n * @example\n * offerMigration(diagnoseLayout('/repo')).accepted; // true after the consumer confirmed\n */\nexport function offerMigration (\n diagnosis: LayoutDiagnosis,\n deps: MigrationOfferDeps = {}\n): MigrationOfferResult {\n const resolved = withDefaults(deps);\n\n if (offerAttempted) {\n return { offered: false, skipReason: 'already-offered' };\n }\n\n const skipReason = skipReasonFor(resolved.env, resolved.argv, resolved.interactive);\n\n if (skipReason) {\n return { offered: false, skipReason };\n }\n\n const entry = resolved.resolveCliEntry();\n\n if (!entry) {\n return { offered: false, skipReason: 'cli-not-found' };\n }\n\n offerAttempted = true;\n\n resolved.warn(outdatedNotice(diagnosis));\n\n const status = resolved.runCli(entry, MIGRATE_FROM_LINT_ARGS, diagnosis.directory, {\n ...resolved.env,\n [IN_FLIGHT_ENV]: 'true',\n });\n\n return { offered: true, accepted: status === 0 };\n}\n\n/** Clears the once-per-process latch {@link offerMigration} keeps, so a suite can exercise it twice. */\nexport function resetMigrationOffer (): void {\n offerAttempted = false;\n}\n\n/* v8 ignore start */\nif (import.meta.vitest) {\n const { afterEach, beforeEach, describe, test, expect, vi } = import.meta.vitest;\n const { mkdirSync, mkdtempSync, rmSync, writeFileSync } = await import('node:fs');\n const { tmpdir } = await import('node:os');\n\n const DIAGNOSIS: LayoutDiagnosis = {\n kind: 'unmigratedV3',\n directory: '/repo',\n lintModule: null,\n eslintConfig: 'eslint.config.js',\n oxlintConfig: null,\n missing: ['insider.lint.ts', 'oxlint.config.ts'],\n autoMigratable: true,\n };\n\n function harness (overrides: Partial<MigrationOfferDeps> = {}) {\n const runCli = vi.fn<(\n entry: string,\n args: readonly string[],\n cwd: string,\n env: NodeJS.ProcessEnv\n ) => number>().mockReturnValue(0);\n const warn = vi.fn<(message: string) => void>();\n const deps: MigrationOfferDeps = {\n env: {},\n argv: ['node', '/app/node_modules/.bin/eslint', '.'],\n interactive: true,\n resolveCliEntry: () => '/pkg/dist/cli.cjs',\n runCli,\n warn,\n ...overrides,\n };\n\n return { deps, runCli, warn };\n }\n\n beforeEach(() => {\n resetMigrationOffer();\n });\n\n afterEach(() => {\n resetMigrationOffer();\n vi.restoreAllMocks();\n });\n\n describe('detectLintHost', () => {\n test('recognizes the oxlint wrapper oxlint itself runs', () => {\n expect(detectLintHost([\n 'node',\n '/app/node_modules/oxlint/bin/oxlint',\n '--disable-nested-config',\n ])).toBe('oxlint');\n });\n\n test('recognizes the pnpm bin shim for oxlint', () => {\n expect(detectLintHost(['node', '/app/node_modules/.bin/oxlint'])).toBe('oxlint');\n });\n\n test('recognizes ESLint through its bin script', () => {\n expect(detectLintHost([\n 'node',\n '/app/node_modules/eslint/bin/eslint.js',\n '.',\n ])).toBe('eslint');\n });\n\n test('prefers oxlint when both binaries appear in argv', () => {\n expect(detectLintHost(['node', '/app/node_modules/oxlint/bin/oxlint', 'eslint'])).toBe('oxlint');\n });\n\n test('reports unknown for an unrelated host such as vitest', () => {\n expect(detectLintHost(['node', '/app/node_modules/.bin/vitest', 'run'])).toBe('unknown');\n });\n\n test('ignores argv[0], the node binary itself', () => {\n expect(detectLintHost(['/usr/bin/eslint'])).toBe('unknown');\n });\n });\n\n describe('offerMigration', () => {\n test('runs the migrator and reports acceptance', () => {\n const { deps, runCli, warn } = harness();\n const result = offerMigration(DIAGNOSIS, deps);\n\n expect(result).toStrictEqual({ offered: true, accepted: true });\n expect(runCli).toHaveBeenCalledWith(\n '/pkg/dist/cli.cjs',\n ['migrate', '--from-lint'],\n '/repo',\n { INSIDER_MIGRATION_IN_PROGRESS: 'true' }\n );\n expect(warn.mock.calls[0][0]).toContain('still uses the v3 single-file layout');\n });\n\n test('reports a declined migration as not accepted', () => {\n const { deps } = harness({ runCli: () => 1 });\n\n expect(offerMigration(DIAGNOSIS, deps)).toStrictEqual({ offered: true, accepted: false });\n });\n\n test('never prompts from the oxlint side, even on a TTY', () => {\n const { deps, runCli, warn } = harness({\n argv: ['node', '/app/node_modules/oxlint/bin/oxlint', '--disable-nested-config'],\n });\n\n expect(offerMigration(DIAGNOSIS, deps)).toStrictEqual({\n offered: false,\n skipReason: 'host-is-oxlint',\n });\n expect(runCli).not.toHaveBeenCalled();\n expect(warn).not.toHaveBeenCalled();\n });\n\n test('does not prompt in CI', () => {\n const { deps } = harness({ env: { CI: 'true' } });\n\n expect(offerMigration(DIAGNOSIS, deps).skipReason).toBe('running-in-ci');\n });\n\n test.each([{ VITEST: 'true' }, { NODE_ENV: 'test' }])('does not prompt under a test runner (%j)', env => {\n const { deps } = harness({ env });\n\n expect(offerMigration(DIAGNOSIS, deps).skipReason).toBe('running-under-test');\n });\n\n test('falls back to the real process env, which a suite run always marks as under test', () => {\n const { deps } = harness({ env: undefined });\n\n expect(offerMigration(DIAGNOSIS, deps).skipReason).toBe('running-under-test');\n });\n\n test('does not prompt without a TTY', () => {\n const { deps } = harness({ interactive: false });\n\n expect(offerMigration(DIAGNOSIS, deps).skipReason).toBe('no-tty');\n });\n\n test.each([OPT_OUT_ENV, NO_PROMPT_ENV])('does not prompt when %s is set', name => {\n const { deps } = harness({ env: { [name]: 'true' } });\n\n expect(offerMigration(DIAGNOSIS, deps).skipReason).toBe('suppressed');\n });\n\n test('does not prompt from inside a migration it started itself', () => {\n const { deps } = harness({ env: { [IN_FLIGHT_ENV]: 'true' } });\n\n expect(offerMigration(DIAGNOSIS, deps).skipReason).toBe('already-offered');\n });\n\n test('offers at most once per process', () => {\n const { deps, runCli } = harness();\n\n offerMigration(DIAGNOSIS, deps);\n\n expect(offerMigration(DIAGNOSIS, deps).skipReason).toBe('already-offered');\n expect(runCli).toHaveBeenCalledTimes(1);\n });\n\n test('skips without warning when the built CLI is absent', () => {\n const { deps, warn } = harness({ resolveCliEntry: () => null });\n\n expect(offerMigration(DIAGNOSIS, deps).skipReason).toBe('cli-not-found');\n expect(warn).not.toHaveBeenCalled();\n });\n\n test('leaves the latch free when it skipped, so a later promptable call still offers', () => {\n const oxlint = harness({ argv: ['node', '/app/node_modules/oxlint/bin/oxlint'] });\n\n offerMigration(DIAGNOSIS, oxlint.deps);\n\n const eslint = harness();\n\n expect(offerMigration(DIAGNOSIS, eslint.deps).offered).toBe(true);\n });\n\n test('falls back to the flat-config glob when the diagnosis named no config', () => {\n const { deps, warn } = harness();\n\n offerMigration({ ...DIAGNOSIS, eslintConfig: null }, deps);\n\n expect(warn.mock.calls[0][0])\n .toContain('eslint.config.* still uses the v3 single-file layout');\n expect(warn.mock.calls[0][0]).toContain(join(DIAGNOSIS.directory, 'eslint.config.*'));\n });\n\n test('names a single missing file in the singular', () => {\n const { deps, warn } = harness();\n\n offerMigration({ ...DIAGNOSIS, missing: ['insider.lint.ts'] }, deps);\n\n expect(warn.mock.calls[0][0]).toContain('insider.lint.ts is missing');\n });\n });\n\n describe('resolveCliEntry', () => {\n function makePackageTree (manifest: string | null, withCli: boolean): { root: string; start: string } {\n const root = mkdtempSync(join(tmpdir(), 'insider-offer-root-'));\n const start = join(root, 'src', 'utils');\n\n mkdirSync(start, { recursive: true });\n\n if (manifest !== null) {\n writeFileSync(join(root, 'package.json'), manifest, 'utf8');\n }\n\n if (withCli) {\n mkdirSync(join(root, 'dist'), { recursive: true });\n writeFileSync(join(root, 'dist', 'cli.cjs'), '', 'utf8');\n }\n\n return { root, start };\n }\n\n test('resolves the built CLI against the package root it walks up to', () => {\n const { root, start } = makePackageTree(`{\"name\":\"${PACKAGE_NAME}\"}`, true);\n\n expect(resolveCliEntry(start)).toBe(join(root, 'dist', 'cli.cjs'));\n });\n\n test('returns null when the package root carries no built CLI', () => {\n const { start } = makePackageTree(`{\"name\":\"${PACKAGE_NAME}\"}`, false);\n\n expect(resolveCliEntry(start)).toBeNull();\n });\n\n test('returns null when no manifest on the way up names this package', () => {\n const { start } = makePackageTree('{\"name\":\"some-consumer\"}', true);\n\n expect(resolveCliEntry(start)).toBeNull();\n });\n\n test('walks past an unparseable package.json instead of throwing', () => {\n const { start } = makePackageTree('{ not json', true);\n\n expect(resolveCliEntry(start)).toBeNull();\n });\n\n test('gives up after ten levels instead of walking all the way to the filesystem root', () => {\n const { root } = makePackageTree(`{\"name\":\"${PACKAGE_NAME}\"}`, true);\n const deepStart = join(root, ...Array.from({ length: 11 }, (_, index) => `level-${index}`));\n\n mkdirSync(deepStart, { recursive: true });\n\n expect(resolveCliEntry(deepStart)).toBeNull();\n });\n\n test('walks past a package.json that parses but declares no name', () => {\n const { root, start } = makePackageTree('{}', true);\n\n expect(existsSync(join(root, 'dist', 'cli.cjs'))).toBe(true);\n expect(resolveCliEntry(start)).toBeNull();\n });\n\n test('starts from this module\\'s own directory, not from the working directory', () => {\n const { root, start } = makePackageTree(`{\"name\":\"${PACKAGE_NAME}\"}`, true);\n\n vi.spyOn(process, 'cwd').mockReturnValue(start);\n\n expect(resolveCliEntry(start)).toBe(join(root, 'dist', 'cli.cjs'));\n expect(resolveCliEntry()).not.toBe(join(root, 'dist', 'cli.cjs'));\n });\n });\n\n describe('the dependencies offerMigration falls back to when none are injected', () => {\n function fakeCli (exitCode: number): string {\n const directory = mkdtempSync(join(tmpdir(), 'insider-offer-cli-'));\n const entry = join(directory, 'cli.cjs');\n\n writeFileSync(entry, `process.exit(${exitCode});\\n`, 'utf8');\n\n return entry;\n }\n\n function withTty<Result> (stdin: boolean, stdout: boolean, run: () => Result): Result {\n const original = { stdin: process.stdin.isTTY, stdout: process.stdout.isTTY };\n\n process.stdin.isTTY = stdin;\n process.stdout.isTTY = stdout;\n\n try {\n return run();\n } finally {\n process.stdin.isTTY = original.stdin;\n process.stdout.isTTY = original.stdout;\n }\n }\n\n test.each([\n { stdin: false, stdout: true },\n { stdin: true, stdout: false },\n ])('skips with no-tty when stdin is $stdin and stdout is $stdout', ({ stdin, stdout }) => {\n const { deps } = harness();\n const result = withTty(\n stdin,\n stdout,\n () => offerMigration(DIAGNOSIS, { ...deps, interactive: undefined })\n );\n\n expect(result.skipReason).toBe('no-tty');\n });\n\n test('offers when both of the real streams are a terminal', () => {\n const { deps } = harness();\n const result = withTty(\n true,\n true,\n () => offerMigration(DIAGNOSIS, { ...deps, interactive: undefined })\n );\n\n expect(result).toStrictEqual({ offered: true, accepted: true });\n });\n\n function withArgv<Result> (argv: readonly string[], run: () => Result): Result {\n const original = process.argv;\n\n process.argv = [...argv];\n\n try {\n return run();\n } finally {\n process.argv = original;\n }\n }\n\n test('skips with host-is-oxlint when the real process argv is the oxlint wrapper', () => {\n const { deps, runCli } = harness();\n const result = withArgv(\n ['node', '/app/node_modules/oxlint/bin/oxlint', '--disable-nested-config'],\n () => offerMigration(DIAGNOSIS, { ...deps, argv: undefined })\n );\n\n expect(result).toStrictEqual({ offered: false, skipReason: 'host-is-oxlint' });\n expect(runCli).not.toHaveBeenCalled();\n });\n\n test.each([\n { exitCode: 0, accepted: true },\n { exitCode: 3, accepted: false },\n ])('maps a real child exit of $exitCode to accepted=$accepted', ({ exitCode, accepted }) => {\n const entry = fakeCli(exitCode);\n const { deps } = harness({ runCli: undefined, resolveCliEntry: () => entry });\n const result = offerMigration({ ...DIAGNOSIS, directory: dirname(entry) }, deps);\n\n expect(result).toStrictEqual({ offered: true, accepted });\n });\n\n // A consumer who hits Ctrl-C mid-migration leaves `spawnSync` a `status` of null and a\n // `signal`, which is neither an exit code nor a spawn error.\n test('reports a migrator killed by a signal as not accepted', () => {\n const directory = mkdtempSync(join(tmpdir(), 'insider-offer-signal-'));\n const entry = join(directory, 'cli.cjs');\n const started = join(directory, 'started');\n const sentinel = join(directory, 'ran-past-the-signal');\n\n writeFileSync(entry, [\n 'const { writeFileSync } = require(\\'node:fs\\');',\n `writeFileSync(${JSON.stringify(started)}, 'started', 'utf8');`,\n 'process.kill(process.pid, \\'SIGKILL\\');',\n `writeFileSync(${JSON.stringify(sentinel)}, 'reached', 'utf8');`,\n '',\n ].join('\\n'), 'utf8');\n\n const { deps } = harness({ runCli: undefined, resolveCliEntry: () => entry });\n const result = offerMigration({ ...DIAGNOSIS, directory }, deps);\n\n expect(existsSync(started), 'the migrator never ran at all').toBe(true);\n expect(existsSync(sentinel), 'the child exited normally instead of dying by signal')\n .toBe(false);\n expect(result).toStrictEqual({ offered: true, accepted: false });\n });\n\n test('reports a child process that never started as not accepted', () => {\n const entry = fakeCli(0);\n const gone = mkdtempSync(join(tmpdir(), 'insider-offer-gone-'));\n\n rmSync(gone, { recursive: true, force: true });\n\n const { deps } = harness({ runCli: undefined, resolveCliEntry: () => entry });\n\n expect(offerMigration({ ...DIAGNOSIS, directory: gone }, deps))\n .toStrictEqual({ offered: true, accepted: false });\n });\n\n test('writes the notice to console.error when no warn sink is injected', () => {\n const spy = vi.spyOn(console, 'error').mockImplementation(() => undefined);\n const { deps } = harness();\n\n offerMigration(DIAGNOSIS, { ...deps, warn: undefined });\n\n expect(spy.mock.calls[0][0]).toContain('still uses the v3 single-file layout');\n });\n\n test('falls back to this module\\'s own resolveCliEntry when none is injected', () => {\n const builtCli = fileURLToPath(new URL('../../dist/cli.cjs', import.meta.url));\n const { deps, runCli } = harness({ resolveCliEntry: undefined });\n const result = offerMigration(DIAGNOSIS, deps);\n\n expect(result, `the default resolver must find ${builtCli}; build the package first`)\n .toStrictEqual({ offered: true, accepted: true });\n expect(runCli).toHaveBeenCalledWith(\n builtCli,\n ['migrate', '--from-lint'],\n '/repo',\n { INSIDER_MIGRATION_IN_PROGRESS: 'true' }\n );\n });\n });\n}\n","import { existsSync, readFileSync, realpathSync } from 'node:fs';\nimport { createRequire } from 'node:module';\nimport { dirname, resolve as resolvePath } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { AST_NODE_TYPES, type TSESTree } from '@typescript-eslint/types';\nimport {\n diagnoseLayout,\n ESLINT_CONFIG_FILENAMES,\n ESLINT_RENDERER_NAME,\n EXPECTED_LAYOUT,\n formatLayoutGuidance,\n INSIDER_IMPORT_SOURCE,\n type LayoutDiagnosis,\n LINT_MODULE_FILENAMES,\n OPT_OUT_ENV,\n OXC_RENDERER_NAME,\n RENDERER_EXPORT,\n TARGET_CALLEE_NAME,\n} from './layoutDiagnosis';\nimport { offerMigration } from './offerMigration';\n\nexport interface ConfigStructureViolation {\n line: number;\n column: number;\n reason: string;\n}\n\nexport interface ValidateProgramStructureOptions {\n isInsiderImportSource?: (source: string, configPath: string) => boolean;\n expectedCallee?: string;\n}\n\nconst ANCHOR_FILE_REGEX = /(?:insider\\.lint|eslint\\.config)\\.[mc]?[jt]s(?:$|\\?)/;\nconst FILE_URL_PREFIX = 'file://';\n\nexport { ESLINT_CONFIG_FILENAMES, LINT_MODULE_FILENAMES };\n\nlet bypassWarnEmitted = false;\n\nfunction computeSelfModulePath (): string {\n const raw = fileURLToPath(import.meta.url);\n\n try {\n return realpathSync(raw);\n } catch {\n return raw;\n }\n}\n\nconst SELF_MODULE_PATH = computeSelfModulePath();\n\nfunction isPathSpecifier (source: string): boolean {\n return source.startsWith('.') || source.startsWith('/');\n}\n\nexport function defaultIsInsiderImportSource (source: string, configPath: string): boolean {\n if (source === INSIDER_IMPORT_SOURCE) {\n return true;\n }\n\n if (!configPath || !isPathSpecifier(source)) {\n return false;\n }\n\n try {\n const absolute = resolvePath(dirname(configPath), source);\n const canonical = realpathSync(absolute);\n\n return canonical === SELF_MODULE_PATH;\n } catch {\n return false;\n }\n}\n\nfunction locOf (node: TSESTree.Node): { line: number; column: number } {\n return { line: node.loc.start.line, column: node.loc.start.column };\n}\n\nfunction validateCallExpression (\n callExpr: TSESTree.CallExpression,\n expectedCallee: string\n): ConfigStructureViolation[] {\n const { callee } = callExpr;\n\n if (callee.type !== AST_NODE_TYPES.Identifier || callee.name !== expectedCallee) {\n return [{\n ...locOf(callExpr),\n reason: `Default export must call \\`${expectedCallee}(...)\\` directly.`,\n }];\n }\n\n return [];\n}\n\nfunction validateExportedCall (\n callee: TSESTree.Expression,\n fallbackLoc: { line: number; column: number },\n expectedCallee: string\n): ConfigStructureViolation[] {\n let target: TSESTree.Expression = callee;\n\n if (target.type === AST_NODE_TYPES.AwaitExpression) {\n target = target.argument;\n }\n\n if (target.type === AST_NODE_TYPES.CallExpression) {\n return validateCallExpression(target, expectedCallee);\n }\n\n if (target.type === AST_NODE_TYPES.ArrayExpression) {\n return [{\n ...locOf(target),\n reason: `Default export must not wrap \\`${expectedCallee}(...)\\` in an array.`,\n }];\n }\n\n const isGated = target.type === AST_NODE_TYPES.LogicalExpression\n || target.type === AST_NODE_TYPES.ConditionalExpression;\n\n if (isGated) {\n const reason = [\n `Default export must not gate \\`${expectedCallee}(...)\\` behind a logical/conditional expression.`,\n 'Use the typed options object instead.',\n ].join(' ');\n\n return [{ ...locOf(target), reason }];\n }\n\n return [{\n ...fallbackLoc,\n reason: `Default export must be a direct call to \\`${expectedCallee}(...)\\`.`,\n }];\n}\n\ninterface IgnoreClassification {\n type: 'ignore';\n}\n\ninterface ExportClassification {\n type: 'export';\n violations: ConfigStructureViolation[];\n}\n\ninterface DuplicateExportClassification {\n type: 'duplicateExport';\n violation: ConfigStructureViolation;\n}\n\ninterface DisallowedClassification {\n type: 'disallowed';\n violation: ConfigStructureViolation;\n}\n\ntype StatementClassification = DisallowedClassification | DuplicateExportClassification | ExportClassification | IgnoreClassification; // eslint-disable-line @stylistic/max-len -- type alias union; splitting hits operator-linebreak rule.\n\nfunction collectInsiderBindings (\n node: TSESTree.ImportDeclaration,\n bindings: Set<string>,\n isInsiderSource: (source: string) => boolean\n): void {\n if (!isInsiderSource(node.source.value)) {\n return;\n }\n\n node.specifiers.forEach(specifier => {\n bindings.add(specifier.local.name);\n });\n}\n\nfunction classifyExpressionStatement (\n node: TSESTree.ExpressionStatement,\n insiderBindings: ReadonlySet<string>\n): StatementClassification {\n const { expression } = node;\n const isInsiderCall = expression.type === AST_NODE_TYPES.CallExpression\n && expression.callee.type === AST_NODE_TYPES.Identifier\n && insiderBindings.has(expression.callee.name);\n\n if (isInsiderCall) {\n return { type: 'ignore' };\n }\n\n const reason = [\n 'Disallowed top-level statement `ExpressionStatement`.',\n `Only call expressions whose callee was imported from \\`${INSIDER_IMPORT_SOURCE}\\` are allowed at top level.`,\n ].join(' ');\n\n return {\n type: 'disallowed',\n violation: { ...locOf(node), reason },\n };\n}\n\nfunction classifyStatement (\n node: TSESTree.ProgramStatement,\n exportSeen: boolean,\n insiderBindings: ReadonlySet<string>,\n expectedCallee: string\n): StatementClassification {\n if (node.type === AST_NODE_TYPES.ImportDeclaration || node.type === AST_NODE_TYPES.VariableDeclaration) {\n return { type: 'ignore' };\n }\n\n if (node.type === AST_NODE_TYPES.ExpressionStatement) {\n return classifyExpressionStatement(node, insiderBindings);\n }\n\n if (node.type === AST_NODE_TYPES.ExportDefaultDeclaration) {\n if (exportSeen) {\n return {\n type: 'duplicateExport',\n violation: { ...locOf(node), reason: 'Only one default export is allowed.' },\n };\n }\n\n const declaration = node.declaration as TSESTree.Expression;\n\n return { type: 'export', violations: validateExportedCall(declaration, locOf(node), expectedCallee) };\n }\n\n const reason = [\n `Disallowed top-level statement \\`${node.type}\\`.`,\n 'Only imports, variable declarations, helper calls from `@useinsider/eslint-config`,',\n `and one \\`export default ${expectedCallee}()\\` are allowed.`,\n ].join(' ');\n\n return {\n type: 'disallowed',\n violation: { ...locOf(node), reason },\n };\n}\n\nexport function validateProgramStructure (\n program: TSESTree.Program,\n configPath = '',\n options: ValidateProgramStructureOptions = {}\n): ConfigStructureViolation[] {\n const violations: ConfigStructureViolation[] = [];\n const insiderBindings = new Set<string>();\n const resolver = options.isInsiderImportSource ?? defaultIsInsiderImportSource;\n const isInsiderSource = (source: string): boolean => resolver(source, configPath);\n const expectedCallee = options.expectedCallee ?? ESLINT_RENDERER_NAME;\n let exportSeen = false;\n\n program.body.forEach(node => {\n if (node.type === AST_NODE_TYPES.ImportDeclaration) {\n collectInsiderBindings(node, insiderBindings, isInsiderSource);\n }\n\n const result = classifyStatement(node, exportSeen, insiderBindings, expectedCallee);\n\n if (result.type === 'ignore') {\n return;\n }\n\n if (result.type === 'export') {\n exportSeen = true;\n violations.push(...result.violations);\n\n return;\n }\n\n violations.push(result.violation);\n });\n\n if (!exportSeen) {\n violations.push({\n line: 1,\n column: 0,\n reason: `Missing \\`export default ${options.expectedCallee ?? ESLINT_RENDERER_NAME}()\\`.`,\n });\n }\n\n return violations;\n}\n\nfunction validateRendererPattern (pattern: TSESTree.ObjectPattern): ConfigStructureViolation[] {\n const bound = new Set<string>();\n const violations: ConfigStructureViolation[] = [];\n\n pattern.properties.forEach(property => {\n if (property.type !== AST_NODE_TYPES.Property || property.computed || !property.shorthand) {\n violations.push({\n ...locOf(property),\n reason: `Destructure \\`${ESLINT_RENDERER_NAME}\\` and \\`${OXC_RENDERER_NAME}\\` by name,`\n + ' without renaming or spreading.',\n });\n\n return;\n }\n\n bound.add((property.key as TSESTree.Identifier).name);\n });\n\n [ESLINT_RENDERER_NAME, OXC_RENDERER_NAME].forEach(name => {\n if (!bound.has(name)) {\n violations.push({\n ...locOf(pattern),\n reason: `Missing \\`${name}\\` in the destructured \\`${TARGET_CALLEE_NAME}(...)\\` result.`,\n });\n }\n });\n\n return violations;\n}\n\nfunction validateRendererExport (node: TSESTree.ExportNamedDeclaration): ConfigStructureViolation[] {\n const { declaration } = node;\n\n if (!declaration || declaration.type !== AST_NODE_TYPES.VariableDeclaration || declaration.kind !== 'const') {\n return [{\n ...locOf(node),\n reason: `Renderer export must be \\`${RENDERER_EXPORT};\\`.`,\n }];\n }\n\n if (declaration.declarations.length !== 1) {\n return [{\n ...locOf(declaration),\n reason: 'Renderer export must declare exactly one binding.',\n }];\n }\n\n const [declarator] = declaration.declarations;\n\n if (declarator.id.type !== AST_NODE_TYPES.ObjectPattern) {\n return [{\n ...locOf(declarator.id),\n reason: `Renderer export must destructure \\`${ESLINT_RENDERER_NAME}\\` and \\`${OXC_RENDERER_NAME}\\`.`,\n }];\n }\n\n const patternViolations = validateRendererPattern(declarator.id);\n const { init } = declarator;\n\n if (!init) {\n return [...patternViolations, {\n ...locOf(declarator),\n reason: `Renderer export must be initialized by a direct \\`${TARGET_CALLEE_NAME}(...)\\` call.`,\n }];\n }\n\n return [...patternViolations, ...validateExportedCall(init, locOf(declarator), TARGET_CALLEE_NAME)];\n}\n\nfunction classifyLintModuleStatement (\n node: TSESTree.ProgramStatement,\n exportSeen: boolean,\n insiderBindings: ReadonlySet<string>\n): StatementClassification {\n if (node.type === AST_NODE_TYPES.ImportDeclaration || node.type === AST_NODE_TYPES.VariableDeclaration) {\n return { type: 'ignore' };\n }\n\n if (node.type === AST_NODE_TYPES.ExpressionStatement) {\n return classifyExpressionStatement(node, insiderBindings);\n }\n\n if (node.type === AST_NODE_TYPES.ExportNamedDeclaration) {\n if (exportSeen) {\n return {\n type: 'duplicateExport',\n violation: { ...locOf(node), reason: 'Only one export is allowed.' },\n };\n }\n\n return { type: 'export', violations: validateRendererExport(node) };\n }\n\n const reason = [\n `Disallowed top-level statement \\`${node.type}\\`.`,\n 'Only imports, variable declarations, helper calls from `@useinsider/eslint-config`,',\n `and one \\`${RENDERER_EXPORT}\\` are allowed.`,\n ].join(' ');\n\n return {\n type: 'disallowed',\n violation: { ...locOf(node), reason },\n };\n}\n\nexport function validateLintModuleStructure (\n program: TSESTree.Program,\n configPath = '',\n options: ValidateProgramStructureOptions = {}\n): ConfigStructureViolation[] {\n const violations: ConfigStructureViolation[] = [];\n const insiderBindings = new Set<string>();\n const resolver = options.isInsiderImportSource ?? defaultIsInsiderImportSource;\n const isInsiderSource = (source: string): boolean => resolver(source, configPath);\n let exportSeen = false;\n\n program.body.forEach(node => {\n if (node.type === AST_NODE_TYPES.ImportDeclaration) {\n collectInsiderBindings(node, insiderBindings, isInsiderSource);\n }\n\n const result = classifyLintModuleStatement(node, exportSeen, insiderBindings);\n\n if (result.type === 'ignore') {\n return;\n }\n\n if (result.type === 'export') {\n exportSeen = true;\n violations.push(...result.violations);\n\n return;\n }\n\n violations.push(result.violation);\n });\n\n if (!exportSeen) {\n violations.push({\n line: 1,\n column: 0,\n reason: `Missing \\`${RENDERER_EXPORT};\\`.`,\n });\n }\n\n return violations;\n}\n\ninterface CallSiteLike {\n getFileName: (this: void) => string | null;\n}\n\nfunction readStackFrames (): readonly CallSiteLike[] {\n // eslint-disable-next-line @typescript-eslint/unbound-method -- Error.prepareStackTrace is a value slot, not a method call.\n const original = Error.prepareStackTrace;\n\n Error.prepareStackTrace = (_, frames) => frames;\n\n const holder: { stack?: unknown } = {};\n\n Error.captureStackTrace(holder, readStackFrames);\n\n const { stack } = holder;\n\n Error.prepareStackTrace = original;\n\n if (!Array.isArray(stack)) {\n return [];\n }\n\n return stack as readonly CallSiteLike[];\n}\n\nfunction normalizeFrameFilename (raw: string | null): string | null {\n if (!raw) {\n return null;\n }\n\n const withoutPrefix = raw.startsWith(FILE_URL_PREFIX) ? raw.slice(FILE_URL_PREFIX.length) : raw;\n const queryIndex = withoutPrefix.indexOf('?');\n\n return queryIndex === -1 ? withoutPrefix : withoutPrefix.slice(0, queryIndex);\n}\n\nfunction extractMatchesFromStack (frames: readonly CallSiteLike[]): string[] {\n const matches = new Set<string>();\n\n frames.forEach(frame => {\n const name = normalizeFrameFilename(frame.getFileName());\n\n if (name && ANCHOR_FILE_REGEX.test(name)) {\n matches.add(name);\n }\n });\n\n return Array.from(matches);\n}\n\nfunction argvCandidateAt (argv: readonly string[], index: number): string | null {\n const arg = argv[index];\n\n if (arg === '--config' || arg === '-c') {\n return argv[index + 1] ?? null;\n }\n\n if (arg.startsWith('--config=')) {\n return arg.slice('--config='.length);\n }\n\n return null;\n}\n\nfunction extractConfigFromArgv (argv: readonly string[]): string | null {\n for (let i = 0; i < argv.length; i += 1) {\n const candidate = argvCandidateAt(argv, i);\n\n if (candidate && ANCHOR_FILE_REGEX.test(candidate)) {\n return candidate;\n }\n }\n\n return null;\n}\n\nconst LINT_MODULE_REGEX = /insider\\.lint\\.[mc]?[jt]s(?:$|\\?)/;\n\nexport function getConsumerConfigPath (\n frames: readonly CallSiteLike[] = readStackFrames(),\n argv: readonly string[] = process.argv\n): string | null {\n const stackMatches = extractMatchesFromStack(frames);\n\n if (stackMatches.length === 1) {\n return stackMatches[0];\n }\n\n // `insider.lint.*` is the module that calls useInsider(), so when both it and the ESLint config\n // are on the stack it is the more precise anchor.\n const lintModules = stackMatches.filter(match => LINT_MODULE_REGEX.test(match));\n\n if (lintModules.length === 1) {\n return lintModules[0];\n }\n\n const fromArgv = extractConfigFromArgv(argv);\n\n if (fromArgv) {\n return fromArgv;\n }\n\n return null;\n}\n\nlet consumerConfigDir: string | null = null;\n\n// getConsumerConfigPath() reads the live stack, so the consumer's config frame is only visible\n// while useInsider() is still synchronous. Capture the directory here and let later async work\n// read it back instead of resolving again.\nexport function captureConsumerConfigDir (configPath: string | null): void {\n consumerConfigDir = configPath === null ? null : dirname(resolvePath(configPath));\n}\n\n/**\n * Directory holding the consumer's `insider.lint.*` module and its sibling linter configs, captured\n * by {@link ensureConfigStructure}. This is the anchor `tsconfigPaths` entries are written against,\n * and where {@link import('./ensureOxlintConfig').ensureOxlintConfig} looks for the oxlint config;\n * it falls back to `process.cwd()` when the module could not be located.\n * @example\n * // consumer module at /repo/insider.lint.ts, `eslint` launched from /repo/app\n * getConsumerConfigDir(); // '/repo'\n */\nexport function getConsumerConfigDir (): string {\n return consumerConfigDir ?? process.cwd();\n}\n\nfunction formatReport (configPath: string, violations: readonly ConfigStructureViolation[]): string {\n const header = [\n '@useinsider/eslint-config: protected configuration structure violated in:',\n ` ${configPath}`,\n ].join('\\n');\n const lines = violations.map(violation => ` - [${violation.line}:${violation.column}] ${violation.reason}`);\n const footer = [\n '',\n 'Alongside the export, only import statements, const/let/var declarations and helper calls',\n 'imported from `@useinsider/eslint-config` are allowed.',\n '',\n EXPECTED_LAYOUT,\n '',\n `Emergency bypass: set ${OPT_OUT_ENV}=true (do not commit).`,\n ].join('\\n');\n\n return `${header}\\n${lines.join('\\n')}\\n${footer}`;\n}\n\nfunction emitBypassWarning (): void {\n if (bypassWarnEmitted) {\n return;\n }\n\n bypassWarnEmitted = true;\n\n const message = [\n '@useinsider/eslint-config: structure validation BYPASSED',\n 'via INSIDER_SKIP_CONFIG_VALIDATION — emergency use only.',\n ].join(' ');\n\n // oxlint-disable-next-line no-console -- diagnostic surface, mirrors ensureDependencies.ts.\n console.warn(message);\n}\n\nclass ConfigStructureExit extends Error {}\n\nfunction fail (message: string): never {\n // oxlint-disable-next-line no-console -- diagnostic surface, mirrors ensureDependencies.ts.\n console.error(message);\n\n const exit: (code: number) => void = process.exit.bind(process);\n\n exit(1);\n\n throw new ConfigStructureExit(message);\n}\n\nfunction readConsumerSource (configPath: string): string {\n try {\n return readFileSync(configPath, 'utf8');\n } catch (readError) {\n const { message } = readError as Error;\n\n return fail(`@useinsider/eslint-config: failed to read consumer config at ${configPath}: ${message}`);\n }\n}\n\nconst lazyRequire = createRequire(import.meta.url);\n\nfunction loadParser (): typeof import('@typescript-eslint/parser').parse {\n const mod = lazyRequire('@typescript-eslint/parser') as typeof import('@typescript-eslint/parser');\n\n return mod.parse;\n}\n\nfunction parseConsumerSource (configPath: string, source: string): TSESTree.Program {\n const parse = loadParser();\n\n try {\n return parse(source, { sourceType: 'module', range: true, loc: true });\n } catch (parseError) {\n const { message } = parseError as Error;\n\n return fail(`@useinsider/eslint-config: failed to parse consumer config at ${configPath}: ${message}`);\n }\n}\n\ntype Validator = (\n program: TSESTree.Program,\n configPath: string,\n options: ValidateProgramStructureOptions\n) => ConfigStructureViolation[];\n\nfunction resolveSibling (directory: string, filenames: readonly string[]): string | null {\n const found = filenames.find(filename => existsSync(resolvePath(directory, filename)));\n\n return found ? resolvePath(directory, found) : null;\n}\n\nfunction validateFile (\n filePath: string,\n validator: Validator,\n options: ValidateProgramStructureOptions\n): void {\n const source = readConsumerSource(filePath);\n const program = parseConsumerSource(filePath, source);\n const violations = validator(program, filePath, options);\n\n if (violations.length === 0) {\n return;\n }\n\n fail(formatReport(filePath, violations));\n}\n\nconst MIGRATED_EXIT_NOTICE = [\n '@useinsider/eslint-config: migration finished.',\n '',\n 'Re-run your lint command. This process already loaded the old configuration, so continuing now',\n 'would lint against a config that no longer exists on disk.',\n].join('\\n');\n\nconst DECLINED_DETAIL: readonly string[] = [\n 'The guided migration was not completed, so nothing was written.',\n];\n\nexport interface RunValidationDeps {\n diagnose?: (directory: string) => LayoutDiagnosis;\n offer?: typeof offerMigration;\n}\n\nfunction failWithGuidance (\n headline: string,\n diagnosis: LayoutDiagnosis,\n detail?: readonly string[]\n): never {\n return fail(formatLayoutGuidance({ headline, diagnosis, detail }));\n}\n\n// The offer runs the migrator in a child process that rewrites the very files this process already\n// imported, so there is no continuing after it: exit non-zero either way and let the consumer re-run.\nfunction handleOutdatedLayout (\n headline: string,\n diagnosis: LayoutDiagnosis,\n offer: typeof offerMigration\n): never {\n if (!diagnosis.autoMigratable) {\n return failWithGuidance(headline, diagnosis);\n }\n\n const outcome = offer(diagnosis);\n\n if (!outcome.offered) {\n return failWithGuidance(headline, diagnosis);\n }\n\n if (!outcome.accepted) {\n return failWithGuidance(headline, diagnosis, DECLINED_DETAIL);\n }\n\n return fail(MIGRATED_EXIT_NOTICE);\n}\n\nfunction runValidation (anchorPath: string | null, deps: RunValidationDeps = {}): void {\n const diagnose = deps.diagnose ?? ((directory: string) => diagnoseLayout(directory));\n const offer = deps.offer ?? offerMigration;\n\n if (!anchorPath) {\n handleOutdatedLayout(\n 'unable to locate the consumer `insider.lint.*` module for structure validation.',\n diagnose(process.cwd()),\n offer\n );\n }\n\n const directory = dirname(resolvePath(anchorPath));\n const lintModulePath = resolveSibling(directory, LINT_MODULE_FILENAMES);\n\n if (!lintModulePath) {\n handleOutdatedLayout(\n `no \\`insider.lint.*\\` module found in ${directory}.`,\n diagnose(directory),\n offer\n );\n }\n\n validateFile(lintModulePath, validateLintModuleStructure, {});\n\n const eslintConfigPath = resolveSibling(directory, ESLINT_CONFIG_FILENAMES);\n\n if (!eslintConfigPath) {\n failWithGuidance(\n `no \\`eslint.config.*\\` file found in ${directory}.`,\n diagnose(directory),\n [\n `\\`${TARGET_CALLEE_NAME}()\\` returns renderers, not a flat-config array, so ESLint still`,\n `needs a config file whose default export is \\`${ESLINT_RENDERER_NAME}()\\`.`,\n ]\n );\n }\n\n validateFile(eslintConfigPath, validateProgramStructure, { expectedCallee: ESLINT_RENDERER_NAME });\n}\n\nexport function ensureConfigStructure (\n overridePath?: string | null,\n deps: RunValidationDeps = {}\n): void {\n const configPath = overridePath === undefined ? getConsumerConfigPath() : overridePath;\n\n captureConsumerConfigDir(configPath);\n\n if (process.env[OPT_OUT_ENV] === 'true') {\n emitBypassWarning();\n\n return;\n }\n\n try {\n runValidation(configPath, deps);\n } catch (error) {\n if (error instanceof ConfigStructureExit) {\n return;\n }\n\n throw error;\n }\n}\n\n/* v8 ignore start */\nif (import.meta.vitest) {\n const { afterEach, describe, test, expect, vi } = import.meta.vitest;\n\n function parseSource (source: string): TSESTree.Program {\n return loadParser()(source, { sourceType: 'module', range: true, loc: true });\n }\n\n const LINT_MODULE_IMPORT = \"import { useInsider } from '@useinsider/eslint-config';\";\n const RENDERER_EXPORT_SOURCE = 'export const { useInsiderESLint, useInsiderOXC } = useInsider({});';\n const ESLINT_CONFIG_IMPORT = \"import { useInsiderESLint } from './insider.lint.js';\";\n\n describe('validateLintModuleStructure', () => {\n test('accepts the canonical renderer export', () => {\n const program = parseSource([LINT_MODULE_IMPORT, RENDERER_EXPORT_SOURCE].join('\\n'));\n\n expect(validateLintModuleStructure(program)).toStrictEqual([]);\n });\n\n test('accepts declarations and insider helper calls alongside the export', () => {\n const program = parseSource([\n \"import { silenceDependencyWarning, useInsider } from '@useinsider/eslint-config';\",\n \"const files = ['**/*.ts'];\",\n 'silenceDependencyWarning(true);',\n 'export const { useInsiderESLint, useInsiderOXC } = useInsider({ typescript: [{ files }] });',\n ].join('\\n'));\n\n expect(validateLintModuleStructure(program)).toStrictEqual([]);\n });\n\n test('rejects a wrapped useInsider call', () => {\n const program = parseSource([\n LINT_MODULE_IMPORT,\n 'export const { useInsiderESLint, useInsiderOXC } = wrap(useInsider({}));',\n ].join('\\n'));\n const violations = validateLintModuleStructure(program);\n\n expect(violations).toHaveLength(1);\n expect(violations[0].reason).toMatch(/must call `useInsider\\(\\.\\.\\.\\)` directly/);\n });\n\n test('rejects an array-wrapped useInsider call', () => {\n const program = parseSource([\n LINT_MODULE_IMPORT,\n 'export const { useInsiderESLint, useInsiderOXC } = [useInsider({})];',\n ].join('\\n'));\n const violations = validateLintModuleStructure(program);\n\n expect(violations).toHaveLength(1);\n expect(violations[0].reason).toMatch(/must not wrap `useInsider\\(\\.\\.\\.\\)` in an array/);\n });\n\n test('rejects gating the call behind a conditional', () => {\n const program = parseSource([\n LINT_MODULE_IMPORT,\n 'export const { useInsiderESLint, useInsiderOXC } = flag ? useInsider({}) : useInsider({});',\n ].join('\\n'));\n const violations = validateLintModuleStructure(program);\n\n expect(violations).toHaveLength(1);\n expect(violations[0].reason).toMatch(/must not gate `useInsider\\(\\.\\.\\.\\)`/);\n });\n\n test('rejects renaming a renderer in the destructuring pattern', () => {\n const program = parseSource([\n LINT_MODULE_IMPORT,\n 'export const { useInsiderESLint: renderer, useInsiderOXC } = useInsider({});',\n ].join('\\n'));\n const reasons = validateLintModuleStructure(program).map(violation => violation.reason);\n\n expect(reasons).toContain(\n 'Destructure `useInsiderESLint` and `useInsiderOXC` by name, without renaming or spreading.'\n );\n expect(reasons.some(reason => /Missing `useInsiderESLint`/.test(reason))).toBe(true);\n });\n\n test('rejects a rest element in the destructuring pattern', () => {\n const program = parseSource([\n LINT_MODULE_IMPORT,\n 'export const { useInsiderESLint, ...rest } = useInsider({});',\n ].join('\\n'));\n const reasons = validateLintModuleStructure(program).map(violation => violation.reason);\n\n expect(reasons.some(reason => /without renaming or spreading/.test(reason))).toBe(true);\n });\n\n test('rejects an export that omits useInsiderOXC', () => {\n const program = parseSource([\n LINT_MODULE_IMPORT,\n 'export const { useInsiderESLint } = useInsider({});',\n ].join('\\n'));\n const violations = validateLintModuleStructure(program);\n\n expect(violations).toHaveLength(1);\n expect(violations[0].reason).toMatch(/Missing `useInsiderOXC`/);\n });\n\n test('rejects a non-destructured binding', () => {\n const program = parseSource([\n LINT_MODULE_IMPORT,\n 'export const renderers = useInsider({});',\n ].join('\\n'));\n const violations = validateLintModuleStructure(program);\n\n expect(violations).toHaveLength(1);\n expect(violations[0].reason).toMatch(/must destructure `useInsiderESLint` and `useInsiderOXC`/);\n });\n\n test('rejects `let` and `var` renderer exports', () => {\n ['let', 'var'].forEach(kind => {\n const program = parseSource([\n LINT_MODULE_IMPORT,\n `export ${kind} { useInsiderESLint, useInsiderOXC } = useInsider({});`,\n ].join('\\n'));\n const violations = validateLintModuleStructure(program);\n\n expect(violations[0].reason).toMatch(/Renderer export must be `export const/);\n });\n });\n\n test('rejects a sole export that declares nothing, such as a bare binding list', () => {\n const program = parseSource([\n LINT_MODULE_IMPORT,\n 'const useInsiderESLint = 1;',\n 'const useInsiderOXC = 2;',\n 'export { useInsiderESLint, useInsiderOXC };',\n ].join('\\n'));\n const violations = validateLintModuleStructure(program);\n\n expect(violations).toHaveLength(1);\n expect(violations[0].reason).toMatch(/Renderer export must be `export const/);\n });\n\n test('rejects an export declaring more than one binding', () => {\n const program = parseSource([\n LINT_MODULE_IMPORT,\n 'export const { useInsiderESLint, useInsiderOXC } = useInsider({}), extra = 1;',\n ].join('\\n'));\n const violations = validateLintModuleStructure(program);\n\n expect(violations).toHaveLength(1);\n expect(violations[0].reason).toMatch(/exactly one binding/);\n });\n\n test('rejects a re-export with no declaration', () => {\n const program = parseSource([\n LINT_MODULE_IMPORT,\n RENDERER_EXPORT_SOURCE,\n \"export { something } from './elsewhere.js';\",\n ].join('\\n'));\n const reasons = validateLintModuleStructure(program).map(violation => violation.reason);\n\n expect(reasons).toContain('Only one export is allowed.');\n });\n\n test('rejects a default export', () => {\n const program = parseSource([LINT_MODULE_IMPORT, 'export default useInsider({});'].join('\\n'));\n const reasons = validateLintModuleStructure(program).map(violation => violation.reason);\n\n expect(reasons.some(reason => /Disallowed top-level statement `ExportDefaultDeclaration`/.test(reason)))\n .toBe(true);\n });\n\n test('rejects a top-level call that did not come from the package', () => {\n const program = parseSource([\n LINT_MODULE_IMPORT,\n \"console.log('boot');\",\n RENDERER_EXPORT_SOURCE,\n ].join('\\n'));\n const reasons = validateLintModuleStructure(program).map(violation => violation.reason);\n\n expect(reasons.some(reason => /Disallowed top-level statement `ExpressionStatement`/.test(reason)))\n .toBe(true);\n });\n\n test('reports a missing renderer export', () => {\n const program = parseSource([LINT_MODULE_IMPORT, \"const files = ['a'];\"].join('\\n'));\n const violations = validateLintModuleStructure(program);\n\n expect(violations).toHaveLength(1);\n expect(violations[0].reason)\n .toBe('Missing `export const { useInsiderESLint, useInsiderOXC } = useInsider({ ... });`.');\n });\n\n test('rejects an uninitialized renderer export', () => {\n const program = parseSource([\n LINT_MODULE_IMPORT,\n 'export const { useInsiderESLint, useInsiderOXC };',\n ].join('\\n'));\n const reasons = validateLintModuleStructure(program).map(violation => violation.reason);\n\n expect(reasons).toStrictEqual([\n 'Renderer export must be initialized by a direct `useInsider(...)` call.',\n ]);\n });\n\n test('resolves insider bindings through a self-relative import', () => {\n const acceptSelfRelative = (source: string, configPath: string): boolean => source === INSIDER_IMPORT_SOURCE\n || (configPath === '/repo/insider.lint.ts' && source === './dist/main.js');\n const program = parseSource([\n \"import { useInsider, silenceDependencyWarning } from './dist/main.js';\",\n 'silenceDependencyWarning(true);',\n RENDERER_EXPORT_SOURCE,\n ].join('\\n'));\n\n expect(validateLintModuleStructure(program, '/repo/insider.lint.ts', {\n isInsiderImportSource: acceptSelfRelative,\n })).toStrictEqual([]);\n });\n });\n\n describe('validateProgramStructure', () => {\n test('accepts `export default useInsiderESLint()`', () => {\n const program = parseSource([ESLINT_CONFIG_IMPORT, 'export default useInsiderESLint();'].join('\\n'));\n\n expect(validateProgramStructure(program)).toStrictEqual([]);\n });\n\n test('accepts `export default await useInsiderESLint()`', () => {\n const program = parseSource([\n ESLINT_CONFIG_IMPORT,\n 'export default await useInsiderESLint();',\n ].join('\\n'));\n\n expect(validateProgramStructure(program)).toStrictEqual([]);\n });\n\n test('accepts let / var declarations alongside const', () => {\n const program = parseSource([\n ESLINT_CONFIG_IMPORT,\n 'let a = 1;',\n 'var b = 2;',\n 'const c = 3;',\n 'export default useInsiderESLint();',\n ].join('\\n'));\n\n expect(validateProgramStructure(program)).toStrictEqual([]);\n });\n\n test('rejects the removed v3 shape where the config itself calls useInsider', () => {\n const program = parseSource([\n \"import { useInsider } from '@useinsider/eslint-config';\",\n 'export default useInsider({});',\n ].join('\\n'));\n const violations = validateProgramStructure(program);\n\n expect(violations).toHaveLength(1);\n expect(violations[0].reason).toBe('Default export must call `useInsiderESLint(...)` directly.');\n });\n\n test('rejects a spread sibling around the renderer call', () => {\n const program = parseSource([\n ESLINT_CONFIG_IMPORT,\n 'export default [...useInsiderESLint(), { rules: {} }];',\n ].join('\\n'));\n const violations = validateProgramStructure(program);\n\n expect(violations).toHaveLength(1);\n expect(violations[0].reason).toMatch(/must not wrap `useInsiderESLint\\(\\.\\.\\.\\)` in an array/);\n });\n\n test('rejects array wrapping', () => {\n const program = parseSource([\n ESLINT_CONFIG_IMPORT,\n 'export default [useInsiderESLint()];',\n ].join('\\n'));\n\n expect(validateProgramStructure(program)).toHaveLength(1);\n });\n\n test('rejects logical and conditional gating', () => {\n ['export default flag && useInsiderESLint();', 'export default flag ? useInsiderESLint() : [];']\n .forEach(line => {\n const program = parseSource([ESLINT_CONFIG_IMPORT, line].join('\\n'));\n const violations = validateProgramStructure(program);\n\n expect(violations).toHaveLength(1);\n expect(violations[0].reason).toMatch(/must not gate `useInsiderESLint\\(\\.\\.\\.\\)`/);\n });\n });\n\n test('rejects an extra top-level statement when the callee is not from the package', () => {\n const program = parseSource([\n ESLINT_CONFIG_IMPORT,\n \"console.log('boot');\",\n 'export default useInsiderESLint();',\n ].join('\\n'));\n const violations = validateProgramStructure(program);\n\n expect(violations).toHaveLength(1);\n expect(violations[0].reason).toMatch(/Disallowed top-level statement `ExpressionStatement`/);\n });\n\n test('accepts top-level insider helper calls', () => {\n ['silenceDependencyWarning(true);', \"silenceRules(['no-console']);\"].forEach(line => {\n const program = parseSource([\n \"import { silenceDependencyWarning, silenceRules } from '@useinsider/eslint-config';\",\n ESLINT_CONFIG_IMPORT,\n line,\n 'export default useInsiderESLint();',\n ].join('\\n'));\n\n expect(validateProgramStructure(program)).toStrictEqual([]);\n });\n });\n\n test('accepts a renamed import binding via `as` alias when calling the alias at top level', () => {\n const program = parseSource([\n \"import { silenceDependencyWarning as quiet } from '@useinsider/eslint-config';\",\n ESLINT_CONFIG_IMPORT,\n 'quiet(true);',\n 'export default useInsiderESLint();',\n ].join('\\n'));\n\n expect(validateProgramStructure(program)).toStrictEqual([]);\n });\n\n test('rejects a top-level call whose callee comes from a different module', () => {\n const program = parseSource([\n \"import { silenceDependencyWarning } from 'some-other-package';\",\n ESLINT_CONFIG_IMPORT,\n 'silenceDependencyWarning(true);',\n 'export default useInsiderESLint();',\n ].join('\\n'));\n\n expect(validateProgramStructure(program)).toHaveLength(1);\n });\n\n test('rejects multiple exports (named export alongside default)', () => {\n const program = parseSource([\n ESLINT_CONFIG_IMPORT,\n 'export const foo = 1;',\n 'export default useInsiderESLint();',\n ].join('\\n'));\n const violations = validateProgramStructure(program);\n\n expect(violations).toHaveLength(1);\n expect(violations[0].reason).toMatch(/Disallowed top-level statement `ExportNamedDeclaration`/);\n });\n\n test('rejects two default exports — second one flagged as duplicate', () => {\n const program = parseSource([\n ESLINT_CONFIG_IMPORT,\n 'export default useInsiderESLint();',\n 'export default useInsiderESLint();',\n ].join('\\n'));\n const violations = validateProgramStructure(program);\n\n expect(violations).toHaveLength(1);\n expect(violations[0].reason).toBe('Only one default export is allowed.');\n });\n\n test('rejects missing default export', () => {\n const program = parseSource([ESLINT_CONFIG_IMPORT, 'const a = 1;'].join('\\n'));\n const violations = validateProgramStructure(program);\n\n expect(violations).toHaveLength(1);\n expect(violations[0].reason).toBe('Missing `export default useInsiderESLint()`.');\n });\n\n test('rejects export default of a plain object literal', () => {\n const program = parseSource('export default { rules: {} };');\n const violations = validateProgramStructure(program);\n\n expect(violations).toHaveLength(1);\n expect(violations[0].reason).toMatch(/direct call to `useInsiderESLint/);\n });\n\n test('honors an explicit expectedCallee override', () => {\n const program = parseSource('export default somethingElse();');\n\n expect(validateProgramStructure(program, '', { expectedCallee: 'somethingElse' }))\n .toStrictEqual([]);\n });\n });\n\n describe('defaultIsInsiderImportSource', () => {\n test('returns true for the canonical package source', () => {\n expect(defaultIsInsiderImportSource(INSIDER_IMPORT_SOURCE, '')).toBe(true);\n expect(defaultIsInsiderImportSource(INSIDER_IMPORT_SOURCE, '/any/insider.lint.ts')).toBe(true);\n });\n\n test('returns false for unrelated package sources', () => {\n expect(defaultIsInsiderImportSource('other-package', '/any/insider.lint.ts')).toBe(false);\n });\n\n test('returns false for a relative path that cannot be realpath-resolved', () => {\n expect(defaultIsInsiderImportSource('./missing.js', '/does/not/exist/insider.lint.ts')).toBe(false);\n });\n\n test('returns false for a relative source when configPath is empty', () => {\n expect(defaultIsInsiderImportSource('./dist/main.js', '')).toBe(false);\n });\n });\n\n describe('getConsumerConfigPath', () => {\n test('returns a single matching stack frame', () => {\n const frames: CallSiteLike[] = [\n { getFileName: () => '/repo/node_modules/@useinsider/eslint-config/dist/main.js' },\n { getFileName: () => '/repo/insider.lint.ts' },\n { getFileName: () => 'node:internal/process' },\n ];\n\n expect(getConsumerConfigPath(frames, [])).toBe('/repo/insider.lint.ts');\n });\n\n test('prefers the lint module when the ESLint config is also on the stack', () => {\n const frames: CallSiteLike[] = [\n { getFileName: () => '/repo/eslint.config.mjs' },\n { getFileName: () => '/repo/insider.lint.ts' },\n ];\n\n expect(getConsumerConfigPath(frames, [])).toBe('/repo/insider.lint.ts');\n });\n\n test('falls back to argv when two lint modules are on the stack', () => {\n const frames: CallSiteLike[] = [\n { getFileName: () => '/repo/a/insider.lint.ts' },\n { getFileName: () => '/repo/b/insider.lint.ts' },\n ];\n const argv = ['node', 'eslint', '-c', '/cli/eslint.config.cts', 'src'];\n\n expect(getConsumerConfigPath(frames, argv)).toBe('/cli/eslint.config.cts');\n });\n\n test('strips ESM cache-buster query string (`?mtime=...`) from stack frame', () => {\n const frames: CallSiteLike[] = [\n { getFileName: () => 'file:///repo/insider.lint.ts?mtime=1779282184336' },\n ];\n\n expect(getConsumerConfigPath(frames, [])).toBe('/repo/insider.lint.ts');\n });\n\n test('strips file:// prefix from stack frame', () => {\n const frames: CallSiteLike[] = [{ getFileName: () => 'file:///repo/insider.lint.ts' }];\n\n expect(getConsumerConfigPath(frames, [])).toBe('/repo/insider.lint.ts');\n });\n\n test('falls back to argv when the stack has no match', () => {\n const frames: CallSiteLike[] = [{ getFileName: () => 'node:internal/process' }];\n const argv = ['node', 'eslint', '--config', '/abs/eslint.config.mjs', 'src'];\n\n expect(getConsumerConfigPath(frames, argv)).toBe('/abs/eslint.config.mjs');\n });\n\n test('supports --config=<path> argv form', () => {\n expect(getConsumerConfigPath([], ['node', 'eslint', '--config=/cli/eslint.config.mts']))\n .toBe('/cli/eslint.config.mts');\n });\n\n test('returns null when nothing matches in stack or argv', () => {\n const frames: CallSiteLike[] = [\n { getFileName: () => 'node:internal/process' },\n { getFileName: () => null },\n ];\n\n expect(getConsumerConfigPath(frames, ['node', 'eslint', 'src'])).toBeNull();\n });\n\n test('default arguments: stack walk + process.argv probe runs without throwing', () => {\n const result = getConsumerConfigPath();\n\n expect(result === null || typeof result === 'string').toBe(true);\n });\n\n test('detection covers every lint-module and ESLint-config extension', () => {\n [...LINT_MODULE_FILENAMES, ...ESLINT_CONFIG_FILENAMES].forEach(name => {\n const frames: CallSiteLike[] = [{ getFileName: () => `/repo/${name}` }];\n\n expect(getConsumerConfigPath(frames, [])).toBe(`/repo/${name}`);\n });\n });\n });\n\n describe('getConsumerConfigDir', () => {\n afterEach(() => {\n captureConsumerConfigDir(null);\n vi.restoreAllMocks();\n });\n\n test('returns the directory holding the captured lint module', () => {\n captureConsumerConfigDir('/repo/insider.lint.ts');\n\n expect(getConsumerConfigDir()).toBe('/repo');\n });\n\n test('resolves a relative captured path against the working directory', () => {\n vi.spyOn(process, 'cwd').mockReturnValue('/repo');\n\n captureConsumerConfigDir('./packages/foo/insider.lint.ts');\n\n expect(getConsumerConfigDir()).toBe('/repo/packages/foo');\n });\n\n test('falls back to the working directory when nothing was located', () => {\n vi.spyOn(process, 'cwd').mockReturnValue('/repo/app');\n\n captureConsumerConfigDir(null);\n\n expect(getConsumerConfigDir()).toBe('/repo/app');\n });\n\n test('a later capture replaces the previous one', () => {\n captureConsumerConfigDir('/repo-a/insider.lint.ts');\n captureConsumerConfigDir('/repo-b/packages/app/insider.lint.ts');\n\n expect(getConsumerConfigDir()).toBe('/repo-b/packages/app');\n });\n });\n}\n","import type { Linter } from 'eslint';\nimport { captureConsumerConfigDir, getConsumerConfigDir } from '../utils/ensureConfigStructure';\n\ninterface TypescriptOverrideInput {\n tsconfigPaths: string[];\n}\n\ninterface ParserOptionsLike {\n project?: string[];\n tsconfigRootDir?: string;\n [key: string]: unknown;\n}\n\nexport function applyTypescriptOverrides<BlockType extends Linter.Config> (\n block: BlockType,\n input: TypescriptOverrideInput\n): BlockType {\n const languageOptions = block.languageOptions ?? {};\n const parserOptions = (languageOptions.parserOptions ?? {}) as ParserOptionsLike;\n\n parserOptions.project = input.tsconfigPaths;\n parserOptions.tsconfigRootDir = getConsumerConfigDir();\n languageOptions.parserOptions = parserOptions;\n block.languageOptions = languageOptions;\n\n return block;\n}\n\n/* v8 ignore start */\nif (import.meta.vitest) {\n const { afterEach, describe, test, expect, vi } = import.meta.vitest;\n\n describe('applyTypescriptOverrides', () => {\n test('sets parserOptions.project and tsconfigRootDir on a bare block', () => {\n const block: Linter.Config = {};\n\n applyTypescriptOverrides(block, { tsconfigPaths: ['tsconfig.lib.json'] });\n\n expect(block.languageOptions?.parserOptions).toMatchObject({\n project: ['tsconfig.lib.json'],\n tsconfigRootDir: process.cwd(),\n });\n });\n\n test('preserves existing parserOptions keys', () => {\n const block: Linter.Config = {\n languageOptions: {\n parserOptions: {\n sourceType: 'module',\n ecmaFeatures: { jsx: true },\n },\n },\n };\n\n applyTypescriptOverrides(block, { tsconfigPaths: ['tsconfig.json'] });\n\n expect(block.languageOptions?.parserOptions).toMatchObject({\n sourceType: 'module',\n ecmaFeatures: { jsx: true },\n project: ['tsconfig.json'],\n tsconfigRootDir: process.cwd(),\n });\n });\n\n test('overwrites any pre-existing project array', () => {\n const block: Linter.Config = {\n languageOptions: {\n parserOptions: {\n project: ['old.json'],\n },\n },\n };\n\n applyTypescriptOverrides(block, { tsconfigPaths: ['new.json'] });\n\n const parserOptions = block.languageOptions?.parserOptions as ParserOptionsLike;\n\n expect(parserOptions.project).toStrictEqual(['new.json']);\n });\n });\n\n describe('applyTypescriptOverrides — tsconfigRootDir anchoring', () => {\n function overridesFor (tsconfigPaths: string[]): ParserOptionsLike {\n const block: Linter.Config = {};\n\n applyTypescriptOverrides(block, { tsconfigPaths });\n\n return block.languageOptions?.parserOptions as ParserOptionsLike;\n }\n\n afterEach(() => {\n captureConsumerConfigDir(null);\n vi.restoreAllMocks();\n });\n\n test('anchors to the config directory, not the working directory', () => {\n vi.spyOn(process, 'cwd').mockReturnValue('/repo/app');\n captureConsumerConfigDir('/repo/eslint.config.mjs');\n\n expect(overridesFor(['app/tsconfig.json']).tsconfigRootDir).toBe('/repo');\n });\n\n test('a tsconfig path no longer doubles when eslint runs from a subdirectory', () => {\n vi.spyOn(process, 'cwd').mockReturnValue('/repo/app');\n captureConsumerConfigDir('/repo/eslint.config.mjs');\n\n const { tsconfigRootDir, project } = overridesFor(['app/tsconfig.json']);\n\n expect(`${tsconfigRootDir}/${project?.[0]}`).toBe('/repo/app/tsconfig.json');\n });\n\n test('config at the repo root with eslint launched there matches the working directory', () => {\n vi.spyOn(process, 'cwd').mockReturnValue('/repo');\n captureConsumerConfigDir('/repo/eslint.config.mjs');\n\n expect(overridesFor(['tsconfig.json']).tsconfigRootDir).toBe(process.cwd());\n });\n\n test('falls back to the working directory when the config file was not located', () => {\n vi.spyOn(process, 'cwd').mockReturnValue('/repo/app');\n captureConsumerConfigDir(null);\n\n expect(overridesFor(['tsconfig.json']).tsconfigRootDir).toBe('/repo/app');\n });\n });\n}\n","import type { Linter } from 'eslint';\n\ninterface VueOverrideInput {\n globalComponents?: string[];\n}\n\nexport function escapeRegex (input: string): string {\n return input.replace(/[\\\\^$.*+?()[\\]{}|]/g, '\\\\$&');\n}\n\nexport function anchoredEscapeRegex (input: string): string {\n return `^${escapeRegex(input)}$`;\n}\n\nexport function applyVueOverrides<BlockType extends Linter.Config> (\n block: BlockType,\n input: VueOverrideInput\n): BlockType {\n if (!input.globalComponents || input.globalComponents.length === 0) {\n return block;\n }\n\n const rules = block.rules ?? {};\n\n rules['vue/no-undef-components'] = ['error', {\n ignorePatterns: input.globalComponents.map(anchoredEscapeRegex),\n }];\n block.rules = rules;\n\n return block;\n}\n\n/* v8 ignore start */\nif (import.meta.vitest) {\n const { describe, test, expect } = import.meta.vitest;\n\n describe('escapeRegex', () => {\n test.each([\n ['plain', 'plain'],\n ['a.b', 'a\\\\.b'],\n ['$Foo', '\\\\$Foo'],\n ['a+b', 'a\\\\+b'],\n ['(x)', '\\\\(x\\\\)'],\n ['[a]', '\\\\[a\\\\]'],\n ['{a}', '\\\\{a\\\\}'],\n ['a|b', 'a\\\\|b'],\n ['a^b', 'a\\\\^b'],\n ['a*b', 'a\\\\*b'],\n ['a?b', 'a\\\\?b'],\n ['a\\\\b', 'a\\\\\\\\b'],\n ])('escapes %s → %s', (input, expected) => {\n expect(escapeRegex(input)).toBe(expected);\n });\n });\n\n describe('anchoredEscapeRegex', () => {\n test('wraps escaped output with ^…$', () => {\n expect(anchoredEscapeRegex('RouterLink')).toBe('^RouterLink$');\n expect(anchoredEscapeRegex('My.Component')).toBe('^My\\\\.Component$');\n });\n });\n\n describe('applyVueOverrides', () => {\n test('is a no-op when globalComponents is missing', () => {\n const block: Linter.Config = { rules: { 'vue/no-undef-components': ['error'] } };\n\n applyVueOverrides(block, {});\n\n expect(block.rules?.['vue/no-undef-components']).toStrictEqual(['error']);\n });\n\n test('is a no-op when globalComponents is empty', () => {\n const block: Linter.Config = { rules: { 'vue/no-undef-components': ['error'] } };\n\n applyVueOverrides(block, { globalComponents: [] });\n\n expect(block.rules?.['vue/no-undef-components']).toStrictEqual(['error']);\n });\n\n test('overrides rule with anchored escaped patterns', () => {\n const block: Linter.Config = {};\n\n applyVueOverrides(block, { globalComponents: ['RouterLink', 'NuxtLink'] });\n\n expect(block.rules?.['vue/no-undef-components']).toStrictEqual([\n 'error',\n { ignorePatterns: ['^RouterLink$', '^NuxtLink$'] },\n ]);\n });\n });\n}\n","import type { Linter } from 'eslint';\nimport { applyTypescriptOverrides } from './typescript';\nimport { applyVueOverrides } from './vue';\n\nexport interface CommonEntryFields {\n ignores?: string[];\n globals?: Linter.Globals;\n}\n\nexport interface JsEntry extends CommonEntryFields {\n files: string[];\n}\n\nexport interface TsEntry extends CommonEntryFields {\n files: string[];\n tsconfigPaths: string[];\n}\n\nexport interface VueEntry extends CommonEntryFields {\n files: string[];\n globalComponents?: string[];\n}\n\nexport interface VueTsEntry extends CommonEntryFields {\n files: string[];\n globalComponents?: string[];\n tsconfigPaths: string[];\n}\n\nexport interface TestEntry extends CommonEntryFields {\n files: string[];\n}\n\nexport type ScopeEntry = JsEntry | TsEntry | VueEntry | VueTsEntry | TestEntry;\n\nconst scopeMap = {\n async javascript () {\n return import('../configs/javascript');\n },\n async javascriptDom () {\n return import('../configs/javascript-dom');\n },\n async javascriptNode () {\n return import('../configs/javascript-node');\n },\n async typescript () {\n return import('../configs/typescript');\n },\n async typescriptDom () {\n return import('../configs/typescript-dom');\n },\n async typescriptNode () {\n return import('../configs/typescript-node');\n },\n async vue2 () {\n return import('../configs/vue2');\n },\n async vue3 () {\n return import('../configs/vue3');\n },\n async vue2Typescript () {\n return import('../configs/vue2-typescript');\n },\n async vue3Typescript () {\n return import('../configs/vue3-typescript');\n },\n async vue2OptionsApi () {\n return import('../configs/vue2-options-api');\n },\n async vue3OptionsApi () {\n return import('../configs/vue3-options-api');\n },\n async vue2TypescriptOptionsApi () {\n return import('../configs/vue2-typescript-options-api');\n },\n async vue3TypescriptOptionsApi () {\n return import('../configs/vue3-typescript-options-api');\n },\n async jest () {\n return import('../configs/jest');\n },\n async vitest () {\n return import('../configs/vitest');\n },\n async jsdocBasedTs () {\n return import('../configs/jsdoc-based-ts');\n },\n} satisfies Record<string, () => Promise<{ default: Linter.Config }>>;\n\nexport type ScopeName = keyof typeof scopeMap;\n\nconst tsScopes = new Set<ScopeName>([\n 'typescript',\n 'typescriptDom',\n 'typescriptNode',\n 'vue2Typescript',\n 'vue3Typescript',\n 'vue2TypescriptOptionsApi',\n 'vue3TypescriptOptionsApi',\n 'jsdocBasedTs',\n]);\n\nconst vueScopes = new Set<ScopeName>([\n 'vue2',\n 'vue3',\n 'vue2Typescript',\n 'vue3Typescript',\n 'vue2OptionsApi',\n 'vue3OptionsApi',\n 'vue2TypescriptOptionsApi',\n 'vue3TypescriptOptionsApi',\n]);\n\ntype LanguageOptions = NonNullable<Linter.Config['languageOptions']>;\n\nfunction cloneLanguageOptions (languageOptions: LanguageOptions): LanguageOptions {\n const clone: LanguageOptions = { ...languageOptions };\n\n if (languageOptions.parserOptions) {\n clone.parserOptions = { ...languageOptions.parserOptions };\n }\n\n if (languageOptions.globals) {\n clone.globals = { ...languageOptions.globals };\n }\n\n return clone;\n}\n\n// ESLint's flat-config schema validates every OWN key, so `languageOptions: undefined`\n// fails with `Key \"languageOptions\": Expected an object.` — absent keys must stay absent.\nfunction clonePreset (preset: Linter.Config): Linter.Config {\n const { languageOptions, rules, settings, ...rest } = preset;\n const clone: Linter.Config = { ...rest };\n\n if (languageOptions) {\n clone.languageOptions = cloneLanguageOptions(languageOptions);\n }\n\n if (rules) {\n clone.rules = { ...rules };\n }\n\n if (settings) {\n clone.settings = { ...settings };\n }\n\n return clone;\n}\n\nexport function isScopeName (key: string): key is ScopeName {\n return Object.keys(scopeMap).includes(key);\n}\n\n/**\n * Every scope name `useInsider()` accepts, for error messages that have to spell the options out.\n * @example\n * scopeNames().includes('typescriptNode'); // true\n */\nexport function scopeNames (): ScopeName[] {\n return Object.keys(scopeMap) as ScopeName[];\n}\n\nfunction applyCommonEntryFields (block: Linter.Config, entry: CommonEntryFields): void {\n if (entry.ignores && entry.ignores.length > 0) {\n block.ignores = [...entry.ignores];\n }\n\n if (entry.globals) {\n const languageOptions = block.languageOptions ?? {};\n const existingGlobals = languageOptions.globals ?? {};\n\n languageOptions.globals = { ...existingGlobals, ...entry.globals };\n block.languageOptions = languageOptions;\n }\n}\n\nexport async function buildScopeBlocks (\n scope: ScopeName,\n entries: readonly ScopeEntry[]\n): Promise<Linter.Config[]> {\n const preset = (await scopeMap[scope]()).default;\n\n return entries.map(entry => {\n const block = clonePreset(preset);\n\n block.files = [...entry.files];\n\n if (tsScopes.has(scope)) {\n const { tsconfigPaths } = entry as TsEntry;\n\n if (tsconfigPaths) {\n applyTypescriptOverrides(block, { tsconfigPaths });\n }\n }\n\n if (vueScopes.has(scope)) {\n const { globalComponents } = entry as VueEntry;\n\n applyVueOverrides(block, { globalComponents });\n }\n\n applyCommonEntryFields(block, entry);\n\n return block;\n });\n}\n\n/* v8 ignore start */\nif (import.meta.vitest) {\n const { describe, test, expect } = import.meta.vitest;\n\n interface ParserOptionsShape {\n project?: string[];\n tsconfigRootDir?: string;\n [key: string]: unknown;\n }\n\n describe('buildScopeBlocks — ignores', () => {\n test('sets block.ignores when entry.ignores is non-empty', async () => {\n const [block] = await buildScopeBlocks('javascriptNode', [\n {\n files: ['scripts/**/*.js'],\n ignores: ['scripts/legacy/**'],\n },\n ]);\n\n expect(block.ignores).toStrictEqual(['scripts/legacy/**']);\n });\n\n test('omits block.ignores when entry.ignores is missing', async () => {\n const [block] = await buildScopeBlocks('javascriptNode', [\n { files: ['scripts/**/*.js'] },\n ]);\n\n expect(block.ignores).toBeUndefined();\n });\n\n test('omits block.ignores when entry.ignores is an empty array', async () => {\n const [block] = await buildScopeBlocks('javascriptNode', [\n {\n files: ['scripts/**/*.js'],\n ignores: [],\n },\n ]);\n\n expect(block.ignores).toBeUndefined();\n });\n\n test('copies the ignores array (caller mutation does not leak into block)', async () => {\n const ignores = ['scripts/legacy/**'];\n const [block] = await buildScopeBlocks('javascriptNode', [\n {\n files: ['scripts/**/*.js'],\n ignores,\n },\n ]);\n\n ignores.push('mutated/**');\n\n expect(block.ignores).toStrictEqual(['scripts/legacy/**']);\n });\n });\n\n describe('buildScopeBlocks — files', () => {\n test('copies the files array (caller mutation does not leak into block)', async () => {\n const files = ['scripts/**/*.js'];\n const [block] = await buildScopeBlocks('javascriptNode', [{ files }]);\n\n files.push('mutated/**');\n\n expect(block.files).toStrictEqual(['scripts/**/*.js']);\n });\n });\n\n describe('buildScopeBlocks — globals', () => {\n test('merges user globals on top of preset globals (user wins on conflict)', async () => {\n const [block] = await buildScopeBlocks('javascriptNode', [\n {\n files: ['**/*.js'],\n globals: { MyCustomGlobal: 'readonly' },\n },\n ]);\n\n const blockGlobals = block.languageOptions?.globals as Record<string, unknown>;\n\n expect(blockGlobals.MyCustomGlobal).toBe('readonly');\n });\n\n test('preserves preset globals when entry.globals is absent', async () => {\n const [withUserGlobals] = await buildScopeBlocks('javascriptNode', [\n {\n files: ['**/*.js'],\n globals: { MyCustomGlobal: 'readonly' },\n },\n ]);\n const [withoutUserGlobals] = await buildScopeBlocks('javascriptNode', [\n { files: ['**/*.js'] },\n ]);\n\n const presetGlobals = withoutUserGlobals.languageOptions?.globals as Record<string, unknown>;\n const mergedGlobals = withUserGlobals.languageOptions?.globals as Record<string, unknown>;\n\n Object.keys(presetGlobals).forEach(key => {\n expect(mergedGlobals[key]).toBe(presetGlobals[key]);\n });\n });\n\n test('user globals override preset globals on key conflict', async () => {\n const [presetBlock] = await buildScopeBlocks('javascriptNode', [\n { files: ['**/*.js'] },\n ]);\n const presetGlobals = presetBlock.languageOptions?.globals as Record<string, unknown>;\n const [sharedKey] = Object.keys(presetGlobals);\n\n const [overrideBlock] = await buildScopeBlocks('javascriptNode', [\n {\n files: ['**/*.js'],\n globals: { [sharedKey]: 'writable' },\n },\n ]);\n const overrideGlobals = overrideBlock.languageOptions?.globals as Record<string, unknown>;\n\n expect(overrideGlobals[sharedKey]).toBe('writable');\n });\n });\n\n describe('buildScopeBlocks — ignores + typescript override interaction', () => {\n test('TS scope: ignores and tsconfigPaths both applied, ignores not overwritten', async () => {\n const [block] = await buildScopeBlocks('typescriptNode', [\n {\n files: ['*.ts', 'scripts/**/*.ts', 'e2e/**/*.ts'],\n tsconfigPaths: ['./tsconfig.node.json'],\n ignores: ['e2e/**/*.test.ts', 'scripts/design-system.d.ts'],\n },\n ]);\n\n const parserOptions = block.languageOptions?.parserOptions as ParserOptionsShape;\n\n expect(parserOptions.project).toStrictEqual(['./tsconfig.node.json']);\n expect(block.ignores).toStrictEqual([\n 'e2e/**/*.test.ts',\n 'scripts/design-system.d.ts',\n ]);\n });\n });\n\n describe('buildScopeBlocks — ignores + vue override interaction', () => {\n test('Vue scope: ignores and globalComponents both applied', async () => {\n const [block] = await buildScopeBlocks('vue3', [\n {\n files: ['src/**/*.vue'],\n globalComponents: ['RouterLink'],\n ignores: ['src/legacy/**/*.vue'],\n },\n ]);\n\n expect(block.ignores).toStrictEqual(['src/legacy/**/*.vue']);\n expect(block.rules?.['vue/no-undef-components']).toStrictEqual([\n 'error',\n { ignorePatterns: ['^RouterLink$'] },\n ]);\n });\n });\n\n describe('buildScopeBlocks — no undefined-valued own keys', () => {\n test.each(scopeNames())('%s block exposes no own key set to undefined', async scope => {\n const entry = {\n files: ['src/**/*'],\n tsconfigPaths: ['./tsconfig.json'],\n };\n const [block] = await buildScopeBlocks(scope, [entry]);\n\n const undefinedKeys = Object.entries(block)\n .filter(([, value]) => value === undefined)\n .map(([key]) => key);\n\n expect(undefinedKeys).toStrictEqual([]);\n });\n\n test('a preset declaring neither key keeps both absent instead of undefined', async () => {\n const [block] = await buildScopeBlocks('vitest', [{ files: ['**/*.spec.js'] }]);\n\n expect('languageOptions' in block).toBe(false);\n expect('settings' in block).toBe(false);\n });\n\n test('every preset that declares languageOptions leaves no undefined key inside it', async () => {\n const inspected: string[] = [];\n\n await Promise.all(scopeNames().map(async scope => {\n const [block] = await buildScopeBlocks(scope, [{\n files: ['src/**/*'],\n tsconfigPaths: ['./tsconfig.json'],\n }]);\n\n if (!block.languageOptions) {\n return;\n }\n\n inspected.push(scope);\n\n const undefinedKeys = Object.entries(block.languageOptions)\n .filter(([, value]) => value === undefined)\n .map(([key]) => key);\n\n expect(undefinedKeys).toStrictEqual([]);\n }));\n\n expect(inspected.length).toBeGreaterThan(0);\n });\n });\n\n describe('buildScopeBlocks — real-world repro (MB-2937 / mindbehind-fe)', () => {\n test('typescriptNode entry with design-system.d.ts in ignores emits matching block.ignores', async () => {\n const [, secondBlock] = await buildScopeBlocks('typescriptNode', [\n {\n files: ['e2e/**/*.test.ts'],\n tsconfigPaths: ['./tsconfig.node.json'],\n },\n {\n files: ['*.ts', 'scripts/**/*.ts', 'e2e/**/*.ts'],\n tsconfigPaths: ['./tsconfig.node.json'],\n ignores: ['e2e/**/*.test.ts', 'scripts/design-system.d.ts'],\n },\n ]);\n\n expect(secondBlock.files).toStrictEqual(['*.ts', 'scripts/**/*.ts', 'e2e/**/*.ts']);\n expect(secondBlock.ignores).toContain('scripts/design-system.d.ts');\n expect(secondBlock.ignores).toContain('e2e/**/*.test.ts');\n });\n });\n}\n","import type { Linter } from 'eslint';\n\ninterface SpellCheckerInput {\n ignoredPaths?: string[];\n customWordListFile?: string;\n}\n\nexport function buildSpellCheckerBlocks (input: SpellCheckerInput | undefined): Linter.Config[] {\n if (!input) {\n return [];\n }\n\n const blocks: Linter.Config[] = [];\n\n if (input.customWordListFile) {\n blocks.push({\n rules: {\n '@cspell/spellchecker': ['error', { customWordListFile: input.customWordListFile }],\n },\n });\n }\n\n if (input.ignoredPaths && input.ignoredPaths.length > 0) {\n blocks.push({\n files: input.ignoredPaths,\n rules: {\n '@cspell/spellchecker': 'off',\n },\n });\n }\n\n return blocks;\n}\n\n/* v8 ignore start */\nif (import.meta.vitest) {\n const { describe, test, expect } = import.meta.vitest;\n\n describe('buildSpellCheckerBlocks', () => {\n test('returns empty array when input is undefined', () => {\n expect(buildSpellCheckerBlocks(undefined)).toStrictEqual([]);\n });\n\n test('returns empty array when input has neither option', () => {\n expect(buildSpellCheckerBlocks({})).toStrictEqual([]);\n });\n\n test('returns customWordListFile block alone', () => {\n const blocks = buildSpellCheckerBlocks({ customWordListFile: './words.json' });\n\n expect(blocks).toStrictEqual([\n {\n rules: {\n '@cspell/spellchecker': ['error', { customWordListFile: './words.json' }],\n },\n },\n ]);\n });\n\n test('returns ignoredPaths off block alone', () => {\n const blocks = buildSpellCheckerBlocks({ ignoredPaths: ['vendor/**'] });\n\n expect(blocks).toStrictEqual([\n {\n files: ['vendor/**'],\n rules: { '@cspell/spellchecker': 'off' },\n },\n ]);\n });\n\n test('emits customWordListFile first then ignoredPaths so ignore wins on overlap', () => {\n const blocks = buildSpellCheckerBlocks({\n customWordListFile: './cspell.json',\n ignoredPaths: ['vendor/**', 'dist/**'],\n });\n\n expect(blocks).toHaveLength(2);\n expect(blocks[0].rules?.['@cspell/spellchecker']).toStrictEqual([\n 'error',\n { customWordListFile: './cspell.json' },\n ]);\n expect(blocks[1].files).toStrictEqual(['vendor/**', 'dist/**']);\n expect(blocks[1].rules?.['@cspell/spellchecker']).toBe('off');\n });\n\n test('ignores empty ignoredPaths array', () => {\n const blocks = buildSpellCheckerBlocks({ ignoredPaths: [] });\n\n expect(blocks).toStrictEqual([]);\n });\n });\n}\n","import type { Linter } from 'eslint';\n\nexport async function buildStrictBlocks (value: boolean | string[] | undefined): Promise<Linter.Config[]> {\n if (!value) {\n return [];\n }\n\n const isFileScoped = Array.isArray(value);\n\n if (isFileScoped && value.length === 0) {\n return [];\n }\n\n const { default: strictConfig } = await import('../configs/strict');\n const clone: Linter.Config = { ...strictConfig };\n\n if (clone.rules) {\n clone.rules = { ...clone.rules };\n }\n\n if (isFileScoped) {\n clone.files = [...value];\n } else {\n delete clone.files;\n }\n\n return [clone];\n}\n\n/* v8 ignore start */\nif (import.meta.vitest) {\n const { describe, test, expect } = import.meta.vitest;\n\n describe('buildStrictBlocks', () => {\n test('emits nothing for a falsy or empty value', async () => {\n expect(await buildStrictBlocks(undefined)).toStrictEqual([]);\n expect(await buildStrictBlocks(false)).toStrictEqual([]);\n expect(await buildStrictBlocks([])).toStrictEqual([]);\n });\n\n test('drops files when strict is enabled for every file', async () => {\n const [block] = await buildStrictBlocks(true);\n\n expect(block.files).toBeUndefined();\n });\n\n test('copies the files array (caller mutation does not leak into block)', async () => {\n const files = ['src/**/*.ts'];\n const [block] = await buildStrictBlocks(files);\n\n files.push('mutated/**');\n\n expect(block.files).toStrictEqual(['src/**/*.ts']);\n });\n });\n}\n","import { existsSync, readFileSync } from 'node:fs';\nimport { createRequire } from 'node:module';\nimport { resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { installPackage } from '@antfu/install-pkg';\nimport semver from 'semver';\n\nlet turnOff = false;\nlet scanned = false;\nconst silencedDependencies = new Set<string>();\n// oxlint is tracked alongside the two ESLint-side pins because the split makes it load-bearing: the\n// ESLint config turns off every rule oxlint owns, so a consumer on an older oxlint silently loses\n// whatever rules that release did not yet implement.\nconst fixedDependencies = [\n 'eslint',\n 'globals',\n 'oxlint',\n];\nconst require = createRequire(import.meta.url);\n\nfunction getPackageJSONPath (currentDir: string) {\n const fileLocation = resolve(currentDir, 'package.json');\n\n if (existsSync(fileLocation)) {\n return fileLocation;\n }\n\n if (currentDir === process.cwd()) {\n throw new Error(`Unable to locate package.json in ${currentDir}`);\n }\n\n const parentDir = resolve(currentDir, '..');\n\n return getPackageJSONPath(parentDir);\n}\n\nfunction getPackageJSON (fileLocation: string) {\n const packageJsonContent = readFileSync(fileLocation, 'utf8');\n\n return JSON.parse(packageJsonContent) as Record<string, Record<string, string>>;\n}\n\nfunction getExpectedDependencies (): Record<string, string> {\n const path = getPackageJSONPath(fileURLToPath(new URL(/* @vite-ignore */ import.meta.url)));\n const packageJson = getPackageJSON(path);\n\n return packageJson.dependencies;\n}\n\nfunction getDependencyVersionFromConsumer (depName: string, baseDir: string = process.cwd()): string | undefined {\n try {\n const pkgJsonPath = require.resolve(`${depName}/package.json`, { paths: [baseDir] });\n const pkgContent = readFileSync(pkgJsonPath, 'utf8');\n const pkg: { version?: string } = JSON.parse(pkgContent) as Record<string, Record<string, string>>;\n\n return pkg.version;\n } catch {\n return undefined;\n }\n}\n\nexport async function ensureDependencies () {\n if (turnOff || scanned) {\n return;\n }\n\n scanned = true;\n\n const expectedDependencies = Object.entries(getExpectedDependencies());\n const missingDependencyEntries = expectedDependencies.filter(\n ([expectedDependency, expectedVersion]) => {\n if (!fixedDependencies.includes(expectedDependency) || silencedDependencies.has(expectedDependency)) {\n return false;\n }\n\n const installedVersion = getDependencyVersionFromConsumer(expectedDependency);\n\n if (!installedVersion) {\n return true;\n }\n\n return semver.lt(installedVersion, expectedVersion);\n }\n );\n\n if (!missingDependencyEntries.length) {\n return;\n }\n\n const missingDependencies = missingDependencyEntries.map(([dependency, version]) => `${dependency}@${version.replace(/^\\W+/, '')}`);\n\n // oxlint-disable-next-line no-console\n console.info('Missing dependencies detected:');\n // oxlint-disable-next-line no-console\n console.info(missingDependencies.map(dependency => ` - ${dependency}`).join('\\n'));\n // oxlint-disable-next-line no-console\n console.info('\\nInstalling dependencies:');\n\n await installPackage(missingDependencies, { dev: true, additionalArgs: ['-E'] });\n\n // eslint-disable-next-line no-process-exit\n process.exit(1);\n}\n\nexport function silenceDependencyWarning (\n /**\n * Pass `true` to silence all dependency warnings.\n */\n all: boolean\n): void;\n\nexport function silenceDependencyWarning (dependencies: string[]): void;\n\nexport function silenceDependencyWarning (input: boolean | string[]) {\n if (typeof input === 'boolean') {\n turnOff = input;\n\n return;\n }\n\n silencedDependencies.clear();\n input.forEach(dependency => silencedDependencies.add(String(dependency)));\n}\n","import { existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { getConsumerConfigDir } from './ensureConfigStructure';\nimport {\n diagnoseLayout,\n formatLayoutGuidance,\n lintModuleSpecifier,\n OPT_OUT_ENV,\n OXLINT_CONFIG_FILENAMES,\n} from './layoutDiagnosis';\n\nexport { OXLINT_CONFIG_FILENAMES };\n\nfunction formatMessage (directory: string): string {\n return formatLayoutGuidance({\n headline: `no oxlint config found in ${directory}.`,\n diagnosis: diagnoseLayout(directory),\n detail: [\n 'useInsiderESLint() turns off every rule oxlint owns, so running ESLint alone would silently',\n 'drop those checks. Create the sibling oxlint config:',\n '',\n ' // oxlint.config.ts',\n ` import { useInsiderOXC } from '${lintModuleSpecifier(directory)}';`,\n '',\n ' export default await useInsiderOXC();',\n '',\n 'and run both linters:',\n '',\n ' \"lint\": \"oxlint --disable-nested-config && eslint .\"',\n '',\n `oxlint discovers only ${OXLINT_CONFIG_FILENAMES.join(' and ')} — any other extension is`,\n 'ignored without a word.',\n ],\n });\n}\n\n/**\n * Fails when the consumer enabled the ESLint-side oxlint suppression without a sibling oxlint\n * config to run the suppressed rules. Resolved against the directory\n * {@link getConsumerConfigDir} captured during `useInsider()`.\n * @example\n * ensureOxlintConfig(); // throws unless oxlint.config.{ts,mts} sits beside insider.lint.*\n */\nexport function ensureOxlintConfig (directory: string = getConsumerConfigDir()): void {\n if (process.env[OPT_OUT_ENV] === 'true') {\n return;\n }\n\n if (OXLINT_CONFIG_FILENAMES.some(filename => existsSync(join(directory, filename)))) {\n return;\n }\n\n throw new Error(formatMessage(directory));\n}\n\n/* v8 ignore start */\nif (import.meta.vitest) {\n const { afterEach, describe, test, expect, vi } = import.meta.vitest;\n const { mkdtempSync, writeFileSync } = await import('node:fs');\n const { tmpdir } = await import('node:os');\n\n function makeDir (): string {\n return mkdtempSync(join(tmpdir(), 'insider-oxlint-'));\n }\n\n afterEach(() => {\n vi.unstubAllEnvs();\n });\n\n describe('ensureOxlintConfig', () => {\n test('throws with an actionable message when no oxlint config sits beside the lint module', () => {\n vi.stubEnv(OPT_OUT_ENV, '');\n\n const directory = makeDir();\n\n expect(() => ensureOxlintConfig(directory)).toThrow(/no oxlint config found in/);\n expect(() => ensureOxlintConfig(directory)).toThrow(/useInsiderOXC/);\n expect(() => ensureOxlintConfig(directory)).toThrow(/oxlint --disable-nested-config && eslint/);\n });\n\n test.each(OXLINT_CONFIG_FILENAMES)('accepts %s', filename => {\n vi.stubEnv(OPT_OUT_ENV, '');\n\n const directory = makeDir();\n\n writeFileSync(join(directory, filename), 'export default {};\\n');\n\n expect(() => ensureOxlintConfig(directory)).not.toThrow();\n });\n\n test.each(['oxlint.config.js', 'oxlint.config.mjs', 'oxlint.config.cjs', 'oxlint.config.cts'])(\n 'rejects %s, which oxlint never discovers',\n filename => {\n vi.stubEnv(OPT_OUT_ENV, '');\n\n const directory = makeDir();\n\n writeFileSync(join(directory, filename), 'export default {};\\n');\n\n expect(() => ensureOxlintConfig(directory)).toThrow(/no oxlint config found in/);\n }\n );\n\n test('rejects a hand-written .oxlintrc.json, which cannot carry the preset rules', () => {\n vi.stubEnv(OPT_OUT_ENV, '');\n\n const directory = makeDir();\n\n writeFileSync(join(directory, '.oxlintrc.json'), '{}\\n');\n\n expect(() => ensureOxlintConfig(directory)).toThrow(/no oxlint config found in/);\n });\n\n test('names the lint module that actually exists, so the suggested import resolves', () => {\n vi.stubEnv(OPT_OUT_ENV, '');\n\n const directory = makeDir();\n\n writeFileSync(join(directory, 'insider.lint.mjs'), 'export const a = 1;\\n');\n\n expect(() => ensureOxlintConfig(directory)).toThrow(/from '\\.\\/insider\\.lint\\.mjs'/);\n });\n\n test('falls back to the TypeScript filename when no lint module is on disk yet', () => {\n vi.stubEnv(OPT_OUT_ENV, '');\n\n expect(() => ensureOxlintConfig(makeDir())).toThrow(/from '\\.\\/insider\\.lint\\.ts'/);\n });\n\n test('honors the INSIDER_SKIP_CONFIG_VALIDATION escape hatch', () => {\n vi.stubEnv(OPT_OUT_ENV, 'true');\n\n expect(() => ensureOxlintConfig(makeDir())).not.toThrow();\n });\n });\n}\n","import { warn } from 'node:console';\nimport type { Linter } from 'eslint';\n\nconst globallySilencedRules = new Set<string>();\n\n/**\n * Silence rules globally.\n * This will affect all configs scopes.\n */\nexport function silenceRules (rules: string[]) {\n rules.forEach(rule => {\n globallySilencedRules.add(rule);\n });\n}\n\nfunction isDisabled (config: Linter.RuleEntry): boolean {\n const [severity] = Array.isArray(config) ? config : [config];\n\n return severity === 'off' || severity === 0;\n}\n\nfunction silenceRule (config: Linter.RuleEntry) {\n const [, ...restConfig] = Array.isArray(config) ? config : [];\n\n return ['warn', ...restConfig as Record<string, unknown>[]] as Linter.RuleSeverityAndOptions;\n}\n\n/**\n * Reports a silenced rule name that no emitted block declares, which is how a typo in\n * `silenceRules` stays visible. The caller passes the union of every block's rule keys: a single\n * block is not evidence, because the emission is many narrow blocks and a correctly spelled rule is\n * absent from nearly all of them.\n * @example\n * warnUnknownSilencedRules(['no-console'], ['no-unknown-rule']); // warns once\n */\nexport function warnUnknownSilencedRules (\n knownRules: Iterable<string>,\n silencedRules: readonly string[]\n): void {\n const known = new Set(knownRules);\n\n new Set(silencedRules).forEach(rule => {\n if (known.has(rule)) {\n return;\n }\n\n warn(`Unknown rule \"${rule}\". Please remove it from the silenced rules list.`);\n });\n}\n\nexport function filterSilencedRules (\n rules: Partial<Linter.RulesRecord> | Readonly<Linter.RulesRecord> | undefined,\n silencedRules?: string[] | Set<string>\n) {\n let targetSilencedRules = silencedRules || globallySilencedRules;\n\n if (Array.isArray(targetSilencedRules)) {\n targetSilencedRules = new Set(targetSilencedRules);\n }\n\n if (!rules || !targetSilencedRules.size) {\n return rules;\n }\n\n return Object.entries(rules).reduce((newRules, [key, value]) => {\n if (value) {\n // Silencing must never make a rule louder, so a rule the config\n // deliberately turned off is left alone rather than demoted to a warning.\n const shouldSilence = targetSilencedRules.has(key) && !isDisabled(value);\n\n newRules[key] = shouldSilence ? silenceRule(value) : value;\n }\n\n return newRules;\n }, {} as Linter.RulesRecord);\n}\n\n/* v8 ignore start */\nif (import.meta.vitest) {\n const { describe, test, expect, beforeEach, afterEach } = import.meta.vitest;\n // `warn` is a static binding taken from `node:console`, and a `vi.mock` of that module is\n // hoisted out of this guard — it would stub the real `warn` for every spec that merely imports\n // this file, silently. Swapping the stream the binding writes to keeps the effect in here.\n const warnings: string[] = [];\n const writeToStderr = process.stderr.write.bind(process.stderr);\n\n beforeEach(() => {\n warnings.length = 0;\n\n process.stderr.write = (chunk: unknown) => {\n warnings.push(String(chunk));\n\n return true;\n };\n });\n\n afterEach(() => {\n process.stderr.write = writeToStderr;\n globallySilencedRules.clear();\n });\n\n describe('silenceRules', () => {\n test('should register given rule keys as silenced', () => {\n const rule = '@stylistic/type-generic-spacing';\n\n expect(globallySilencedRules.has(rule)).toBe(false);\n silenceRules([rule]);\n expect(globallySilencedRules.has(rule)).toBe(true);\n });\n });\n\n describe('filterSilencedRules', () => {\n test('should return the same rules object if no rules are silenced', () => {\n const rules = {\n 'no-console': 'warn',\n 'no-debugger': 'warn',\n } as Linter.RulesRecord;\n\n expect(filterSilencedRules(rules)).toBe(rules);\n });\n\n test('should return a new rules object with silenced rules silenced and other rules unchanged', () => {\n silenceRules(['no-console']);\n\n const rules = {\n 'no-console': 'error',\n 'no-debugger': 'warn',\n 'no-alert': 'error',\n } as Linter.RulesRecord;\n\n expect(filterSilencedRules(rules)).toStrictEqual({\n 'no-console': ['warn'],\n 'no-debugger': 'warn',\n 'no-alert': 'error',\n });\n });\n\n test('should return a new rules object with silenced rules silenced and other rules unchanged', () => {\n silenceRules(['no-bitwise', 'new-cap']);\n\n const rules = {\n 'max-len': 'off',\n 'new-cap': ['error'],\n 'no-alert': ['error'],\n 'no-bitwise': ['error', {\n allow: ['~'],\n }],\n } as Linter.RulesRecord;\n\n expect(filterSilencedRules(rules)).toStrictEqual({\n 'max-len': 'off',\n 'new-cap': ['warn'],\n 'no-alert': ['error'],\n 'no-bitwise': ['warn', {\n allow: ['~'],\n }],\n });\n });\n\n test.each([\n ['off' as Linter.RuleEntry],\n [['off'] as Linter.RuleEntry],\n [[0] as unknown as Linter.RuleEntry],\n ])('should leave a disabled rule (%j) disabled instead of promoting it to warn', entry => {\n const rules = { 'no-console': entry } as Linter.RulesRecord;\n\n expect(filterSilencedRules(rules, ['no-console'])).toStrictEqual({ 'no-console': entry });\n });\n\n test('never warns, so a block that simply lacks the rule cannot report a false typo', () => {\n const rules = {\n 'no-console': 'error',\n 'no-debugger': 'warn',\n } as Linter.RulesRecord;\n\n filterSilencedRules(rules, ['no-console', 'no-bitwise']);\n filterSilencedRules(rules);\n\n expect(warnings).toStrictEqual([]);\n });\n\n test.each([\n [['@typescript-eslint/no-unsafe-call'], ['warn']],\n [new Set(['@typescript-eslint/no-unsafe-call']), ['warn']],\n [[], 'error'],\n ])(\n '#%# should filter scope-related rules and ignore globally silenced rules',\n (silencedRules, expectation) => {\n silenceRules(['@typescript-eslint/no-unsafe-assignment']);\n\n const rules = {\n '@typescript-eslint/no-unsafe-assignment': 'error',\n '@typescript-eslint/no-unsafe-member-access': 'error',\n '@typescript-eslint/no-unsafe-call': 'error',\n } as Linter.RulesRecord;\n\n expect(filterSilencedRules(rules, silencedRules)).toStrictEqual({\n '@typescript-eslint/no-unsafe-assignment': 'error',\n '@typescript-eslint/no-unsafe-member-access': 'error',\n '@typescript-eslint/no-unsafe-call': expectation,\n });\n }\n );\n });\n\n describe('warnUnknownSilencedRules', () => {\n test('stays silent for a name the union of blocks declares, however few blocks carry it', () => {\n warnUnknownSilencedRules(['no-console', '@stylistic/indent'], ['no-console']);\n\n expect(warnings).toStrictEqual([]);\n });\n\n test('warns once per misspelled name, not once per block', () => {\n warnUnknownSilencedRules(['no-console'], ['no-unknown-rule', 'no-unknown-rule']);\n\n expect(warnings).toStrictEqual([\n 'Unknown rule \"no-unknown-rule\". Please remove it from the silenced rules list.\\n',\n ]);\n });\n });\n}\n","import type { Linter } from 'eslint';\nimport { defineConfig } from 'eslint/config';\nimport { buildConfigFilesBlocks, buildLintTopologyBlocks } from './builders/configFiles';\nimport { buildJqueryBlocks, type JqueryEntry } from './builders/jquery';\nimport {\n buildOxlintConfig,\n buildOxlintSuppressionBlocks,\n buildUnusedDirectiveBlocks,\n type OxlintRendererConfig,\n} from './builders/oxlint';\nimport { buildScopeBlocks, isScopeName, type ScopeEntry, scopeNames } from './builders/scopeBlocks';\nimport { buildSpellCheckerBlocks } from './builders/spellChecker';\nimport { buildStrictBlocks } from './builders/strict';\nimport { ensureConfigStructure } from './utils/ensureConfigStructure';\nimport { ensureDependencies } from './utils/ensureDependencies';\nimport { ensureOxlintConfig } from './utils/ensureOxlintConfig';\nimport { filterSilencedRules, warnUnknownSilencedRules } from './utils/silenceRules';\n\ninterface CommonEntryFields {\n ignores?: string[];\n globals?: Linter.Globals;\n}\n\ninterface JsEntry extends CommonEntryFields {\n files: string[];\n}\n\ninterface TsEntry extends CommonEntryFields {\n files: string[];\n tsconfigPaths: string[];\n}\n\ninterface VueEntry extends CommonEntryFields {\n files: string[];\n globalComponents?: string[];\n}\n\ninterface VueTsEntry extends CommonEntryFields {\n files: string[];\n globalComponents?: string[];\n tsconfigPaths: string[];\n}\n\ninterface TestEntry extends CommonEntryFields {\n files: string[];\n}\n\ninterface SpellCheckerOptions {\n ignoredPaths?: string[];\n customWordListFile?: string;\n}\n\nexport interface Config {\n ignores?: string[];\n\n javascript?: JsEntry[];\n javascriptDom?: JsEntry[];\n javascriptNode?: JsEntry[];\n typescript?: TsEntry[];\n typescriptDom?: TsEntry[];\n typescriptNode?: TsEntry[];\n vue2?: VueEntry[];\n vue3?: VueEntry[];\n vue2Typescript?: VueTsEntry[];\n vue3Typescript?: VueTsEntry[];\n vue2OptionsApi?: VueEntry[];\n vue3OptionsApi?: VueEntry[];\n vue2TypescriptOptionsApi?: VueTsEntry[];\n vue3TypescriptOptionsApi?: VueTsEntry[];\n jest?: TestEntry[];\n vitest?: TestEntry[];\n jsdocBasedTs?: TsEntry[];\n\n jquery?: JqueryEntry[];\n strict?: boolean | string[];\n spellChecker?: SpellCheckerOptions;\n silenceRules?: string[];\n configFiles?: false | string[];\n}\n\nconst reservedKeys = new Set([\n 'ignores',\n 'jquery',\n 'strict',\n 'spellChecker',\n 'silenceRules',\n 'configFiles',\n]);\n\nconst removedKeys = new Map<string, string>([\n [\n 'config',\n 'use `configFiles: string[]` instead. Its block is emitted after every scope block, so'\n + ' the overrides actually win; the `config` scope was emitted before them and was silently'\n + ' overridden for any file a language scope also matched.',\n ],\n]);\n\nfunction assertNoRemovedKeys (config: Config): void {\n const used = Object.keys(config).filter(key => removedKeys.has(key));\n\n if (used.length === 0) {\n return;\n }\n\n const details = used.map(key => ` - \\`${key}\\`: ${removedKeys.get(key)}`).join('\\n');\n\n throw new Error(`@useinsider/eslint-config: removed option(s) passed to useInsider():\\n${details}`);\n}\n\n// A key that is neither reserved nor a scope used to be dropped without a word, so a misspelled\n// scope name silently disabled that scope. The layout supports `insider.lint.{js,mjs,cjs}`, so there\n// is no type check standing behind this for every consumer.\nfunction assertNoUnknownKeys (config: Config): void {\n const unknown = Object.keys(config)\n .filter(key => !reservedKeys.has(key) && !removedKeys.has(key) && !isScopeName(key));\n\n if (unknown.length === 0) {\n return;\n }\n\n throw new Error(\n `@useinsider/eslint-config: unknown option(s) passed to useInsider(): ${unknown.join(', ')}.\\n`\n + ` Scopes: ${scopeNames().join(', ')}\\n`\n + ` Other options: ${[...reservedKeys].join(', ')}`\n );\n}\n\nfunction isProcessableScopeKey (key: string): boolean {\n return !reservedKeys.has(key) && isScopeName(key);\n}\n\nasync function collectScopeBlocks (config: Config): Promise<Linter.Config[]> {\n const scopeKeys = Object.keys(config).filter(isProcessableScopeKey);\n\n return scopeKeys.reduce<Promise<Linter.Config[]>>(async (accumulator, key) => {\n const blocks = await accumulator;\n const entries = config[key as keyof Config] as ScopeEntry[] | undefined;\n\n if (!entries || entries.length === 0) {\n return blocks;\n }\n\n const scopeBlocks = await buildScopeBlocks(key as Parameters<typeof buildScopeBlocks>[0], entries);\n\n return [...blocks, ...scopeBlocks];\n }, Promise.resolve([]));\n}\n\nfunction applySilenceRules (blocks: Linter.Config[], perCallSilence: string[] | undefined): void {\n if (perCallSilence) {\n warnUnknownSilencedRules(\n blocks.flatMap(block => Object.keys(block.rules ?? {})),\n perCallSilence\n );\n }\n\n blocks.forEach(block => {\n if (!block.rules) {\n return;\n }\n\n block.rules = perCallSilence\n ? filterSilencedRules(block.rules, perCallSilence)\n : filterSilencedRules(block.rules);\n });\n}\n\n/** Resolved return type of {@link Renderers.useInsiderESLint}: a Promise of an ESLint flat-config array. */\nexport type UseInsiderResult = Promise<Linter.Config[]>;\n\nexport interface Renderers {\n useInsiderESLint: () => UseInsiderResult;\n useInsiderOXC: () => Promise<OxlintRendererConfig>;\n}\n\nfunction buildIgnoresBlocks (ignores: string[] | undefined): Linter.Config[] {\n if (!ignores || ignores.length === 0) {\n return [];\n }\n\n return [{ ignores: [...ignores] }];\n}\n\n// Emission order is the precedence contract: later blocks win. `configFiles` and `strict` must be\n// able to override the language scopes, and `spellChecker` must survive all of them.\nasync function buildBaseBlocks (config: Config): Promise<Linter.Config[]> {\n const scopeBlocks = await collectScopeBlocks(config);\n const strictBlocks = await buildStrictBlocks(config.strict);\n\n return [\n ...buildIgnoresBlocks(config.ignores),\n ...buildUnusedDirectiveBlocks(),\n ...scopeBlocks,\n ...buildJqueryBlocks(config.jquery),\n ...buildConfigFilesBlocks(config.configFiles),\n ...strictBlocks,\n ...buildLintTopologyBlocks(),\n ...buildSpellCheckerBlocks(config.spellChecker),\n ];\n}\n\nasync function renderEslint (config: Config): UseInsiderResult {\n await ensureDependencies();\n ensureOxlintConfig();\n\n const baseBlocks = await buildBaseBlocks(config);\n const blocks = [...baseBlocks, ...buildOxlintSuppressionBlocks(baseBlocks)];\n\n applySilenceRules(blocks, config.silenceRules);\n\n return defineConfig(blocks);\n}\n\nasync function renderOxlint (config: Config): Promise<OxlintRendererConfig> {\n const baseBlocks = await buildBaseBlocks(config);\n\n applySilenceRules(baseBlocks, config.silenceRules);\n\n return buildOxlintConfig(baseBlocks, config.ignores);\n}\n\nexport function useInsider (config: Config): Renderers {\n assertNoRemovedKeys(config);\n assertNoUnknownKeys(config);\n ensureConfigStructure();\n\n return {\n useInsiderESLint: () => renderEslint(config),\n useInsiderOXC: () => renderOxlint(config),\n };\n}\n\nexport { merge } from './utils/merge';\n\nexport { mergeAll } from './utils/mergeAllConfig';\n\nexport { silenceDependencyWarning } from './utils/ensureDependencies';\n\nexport { ensureConfigStructure } from './utils/ensureConfigStructure';\n\nexport { ensureOxlintConfig } from './utils/ensureOxlintConfig';\n\nexport { silenceRules } from './utils/silenceRules';\n\nexport type { OxlintRendererConfig } from './builders/oxlint';\n"],"mappings":"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"}
1
+ {"version":3,"file":"main.cjs","names":[],"sources":["../src/builders/configFiles.ts","../src/builders/jquery.ts","../src/builders/oxlint.ts","../src/utils/layoutDiagnosis.ts","../src/utils/offerMigration.ts","../src/utils/ensureConfigStructure.ts","../src/builders/typescript.ts","../src/builders/vue.ts","../src/builders/scopeBlocks.ts","../src/builders/spellChecker.ts","../src/builders/strict.ts","../src/utils/ensureDependencies.ts","../src/utils/ensureOxlintConfig.ts","../src/utils/silenceRules.ts","../src/main.ts"],"sourcesContent":["import type { Linter } from 'eslint';\n\n/**\n * Default globs treated as \"configuration files\" — root-level `*.config.*`\n * variants plus the canonical `eslint.config.*` flat-config filenames.\n *\n * These are intentionally conservative: only the top-level matches that the\n * v1 `config` preset was overwhelmingly applied to. Project-specific paths\n * (subdirectories, custom names) must be opted into by passing them via the\n * `configFiles: string[]` knob.\n */\nexport const DEFAULT_CONFIG_FILE_GLOBS: readonly string[] = [\n '*.config.{ts,mts,cts,js,mjs,cjs}',\n '*.config.*.{ts,mts,cts,js,mjs,cjs}',\n 'eslint.config.{mjs,js,cjs,ts}',\n];\n\nconst configFileRules: Linter.RulesRecord = {\n 'import-x/no-extraneous-dependencies': 'off',\n 'import-x/prefer-default-export': 'off',\n};\n\nexport const LINT_TOPOLOGY_NAME = 'insider/lint-topology';\n\n/**\n * The three files `useInsider()` requires a consumer to own. They are always linted with\n * {@link buildLintTopologyBlocks}, independently of the `configFiles` option.\n */\nexport const LINT_TOPOLOGY_GLOBS: readonly string[] = [\n '**/insider.lint.{ts,mts,cts,js,mjs,cjs}',\n '**/eslint.config.{ts,mts,cts,js,mjs,cjs}',\n '**/oxlint.config.{ts,mts,cts,js,mjs,cjs}',\n];\n\n// Neither linter's loader applies TypeScript's `.js` → `.ts` specifier rewriting, so\n// `eslint.config.*` and `oxlint.config.*` have to import the lint module by its real extension —\n// exactly what `import-x/extensions` forbids.\nconst lintTopologyRules: Linter.RulesRecord = {\n ...configFileRules,\n 'import-x/extensions': 'off',\n};\n\n/**\n * Relaxations the mandated three-file layout needs in order to lint clean. Emitted unconditionally\n * because the layout exists whether or not the consumer passes `configFiles`.\n * @example\n * buildLintTopologyBlocks()[0].rules['import-x/extensions']; // 'off'\n */\nexport function buildLintTopologyBlocks (): Linter.Config[] {\n return [{\n name: LINT_TOPOLOGY_NAME,\n files: [...LINT_TOPOLOGY_GLOBS],\n rules: { ...lintTopologyRules },\n }];\n}\n\nfunction mergeGlobs (userGlobs: readonly string[]): string[] {\n const seen = new Set<string>();\n const merged: string[] = [];\n\n DEFAULT_CONFIG_FILE_GLOBS.forEach(glob => {\n if (!seen.has(glob)) {\n seen.add(glob);\n merged.push(glob);\n }\n });\n\n userGlobs.forEach(glob => {\n if (!seen.has(glob)) {\n seen.add(glob);\n merged.push(glob);\n }\n });\n\n return merged;\n}\n\nexport function buildConfigFilesBlocks (value: false | string[] | undefined): Linter.Config[] {\n if (value === false) {\n return [];\n }\n\n const files = value === undefined ? [...DEFAULT_CONFIG_FILE_GLOBS] : mergeGlobs(value);\n\n return [{\n files,\n rules: { ...configFileRules },\n }];\n}\n\n/* v8 ignore start */\nif (import.meta.vitest) {\n const { describe, test, expect } = import.meta.vitest;\n\n describe('buildConfigFilesBlocks', () => {\n test('returns one default-only block when value is undefined (defaults on by default)', () => {\n const blocks = buildConfigFilesBlocks(undefined);\n\n expect(blocks).toHaveLength(1);\n expect(blocks[0].files).toStrictEqual([...DEFAULT_CONFIG_FILE_GLOBS]);\n expect(blocks[0].rules).toStrictEqual({\n 'import-x/no-extraneous-dependencies': 'off',\n 'import-x/prefer-default-export': 'off',\n });\n });\n\n test('returns empty array when value is false (explicit opt-out)', () => {\n expect(buildConfigFilesBlocks(false)).toStrictEqual([]);\n });\n\n test('returns one block with merged globs when value is a string[]', () => {\n const blocks = buildConfigFilesBlocks(['my.special.ts']);\n\n expect(blocks).toHaveLength(1);\n expect(blocks[0].files).toStrictEqual([\n ...DEFAULT_CONFIG_FILE_GLOBS,\n 'my.special.ts',\n ]);\n });\n\n test('user globs append after defaults in given order', () => {\n const blocks = buildConfigFilesBlocks(['z.ts', 'a.ts']);\n\n expect(blocks[0].files).toStrictEqual([\n ...DEFAULT_CONFIG_FILE_GLOBS,\n 'z.ts',\n 'a.ts',\n ]);\n });\n\n test('dedupes user globs that overlap with defaults', () => {\n const blocks = buildConfigFilesBlocks([\n '*.config.{ts,mts,cts,js,mjs,cjs}',\n 'extra.ts',\n ]);\n\n expect(blocks[0].files).toStrictEqual([\n ...DEFAULT_CONFIG_FILE_GLOBS,\n 'extra.ts',\n ]);\n });\n\n test('empty user list still emits default-only block', () => {\n const blocks = buildConfigFilesBlocks([]);\n\n expect(blocks).toHaveLength(1);\n expect(blocks[0].files).toStrictEqual([...DEFAULT_CONFIG_FILE_GLOBS]);\n });\n\n test('block has no languageOptions / parserOptions — only files + rules', () => {\n const [block] = buildConfigFilesBlocks(undefined);\n\n expect(block.languageOptions).toBeUndefined();\n expect(Object.keys(block)).toStrictEqual(['files', 'rules']);\n });\n });\n\n describe('buildLintTopologyBlocks', () => {\n test('covers the lint module and both linter configs', () => {\n const [block] = buildLintTopologyBlocks();\n\n expect(block.files).toStrictEqual([...LINT_TOPOLOGY_GLOBS]);\n });\n\n test('turns off the extension rule the mandated import specifier violates', () => {\n const [block] = buildLintTopologyBlocks();\n\n expect(block.rules?.['import-x/extensions']).toBe('off');\n });\n\n test('keeps the configFiles relaxations so the layout works with configFiles: false', () => {\n const [block] = buildLintTopologyBlocks();\n\n expect(block.rules?.['import-x/no-extraneous-dependencies']).toBe('off');\n expect(block.rules?.['import-x/prefer-default-export']).toBe('off');\n });\n\n test('matches an insider.lint module in a nested workspace package', () => {\n const [block] = buildLintTopologyBlocks();\n\n expect(block.files).toContain('**/insider.lint.{ts,mts,cts,js,mjs,cjs}');\n });\n });\n}\n","import type { Linter } from 'eslint';\nimport globals from 'globals';\n\nexport interface JqueryEntry {\n files: string[];\n}\n\nexport function buildJqueryBlocks (entries: readonly JqueryEntry[] | undefined): Linter.Config[] {\n if (!entries || entries.length === 0) {\n return [];\n }\n\n return entries.map(entry => ({\n files: [...entry.files],\n languageOptions: {\n globals: { ...globals.jquery },\n },\n }));\n}\n\n/* v8 ignore start */\nif (import.meta.vitest) {\n const { describe, test, expect } = import.meta.vitest;\n\n describe('buildJqueryBlocks', () => {\n test('returns empty array when entries is undefined', () => {\n expect(buildJqueryBlocks(undefined)).toStrictEqual([]);\n });\n\n test('returns empty array when entries is empty', () => {\n expect(buildJqueryBlocks([])).toStrictEqual([]);\n });\n\n test('emits one block per entry with files set', () => {\n const blocks = buildJqueryBlocks([\n { files: ['a/**/*.js'] },\n { files: ['b/**/*.js'] },\n ]);\n\n expect(blocks).toHaveLength(2);\n expect(blocks[0].files).toStrictEqual(['a/**/*.js']);\n expect(blocks[1].files).toStrictEqual(['b/**/*.js']);\n });\n\n test('copies the files array (caller mutation does not leak into block)', () => {\n const files = ['legacy/**/*.js'];\n const [block] = buildJqueryBlocks([{ files }]);\n\n files.push('mutated/**');\n\n expect(block.files).toStrictEqual(['legacy/**/*.js']);\n });\n\n test('block exposes jquery globals ($, jQuery)', () => {\n const [block] = buildJqueryBlocks([{ files: ['legacy/**/*.js'] }]);\n const blockGlobals = block.languageOptions?.globals as Record<string, unknown>;\n\n expect(blockGlobals.$).toBeDefined();\n expect(blockGlobals.jQuery).toBeDefined();\n });\n });\n}\n","import type { Linter } from 'eslint';\nimport {\n OXLINT_CATEGORIES,\n VUE_LIKE_GLOBS,\n isOxlintOwned,\n isRuleDisabled,\n isVueUnsafeRule,\n toOxlintPluginName,\n toOxlintRuleName,\n} from './oxlintOwnership';\n\nexport const OXLINT_SUPPRESSION_NAME = 'insider/oxlint-suppression';\n\nexport const OXLINT_SFC_EXCEPTION_NAME = 'insider/oxlint-suppression-sfc-exception';\n\nexport const UNUSED_DIRECTIVE_BLOCK_NAME = 'insider/unused-disable-directives';\n\nexport const UNUSED_DIRECTIVE_SEVERITY = 'warn';\n\nexport function isOxlintSuppressionBlock (block: Linter.Config): boolean {\n return block.name === OXLINT_SUPPRESSION_NAME || block.name === OXLINT_SFC_EXCEPTION_NAME;\n}\n\nexport interface OxlintOverride {\n files: string[];\n excludeFiles?: string[];\n rules: Record<string, Linter.RuleEntry>;\n}\n\nexport interface OxlintRendererOptions {\n respectEslintDisableDirectives: boolean;\n reportUnusedDisableDirectives: typeof UNUSED_DIRECTIVE_SEVERITY;\n}\n\nexport interface OxlintRendererConfig {\n plugins: string[];\n categories: Record<string, 'off'>;\n ignorePatterns?: string[];\n options: OxlintRendererOptions;\n rules: Record<string, Linter.RuleEntry>;\n overrides: OxlintOverride[];\n}\n\n// oxlint judges an `eslint-disable` comment against the rules IT ran, so a directive naming\n// `@cspell/spellchecker`, `sonarjs/*` or `@stylistic/*` — everything the split deliberately keeps\n// on the ESLint side — reports as unused. Refusing the eslint spelling outright is what makes\n// unused-directive reporting sound: oxlint then judges only `oxlint-disable`, ESLint only\n// `eslint-disable`, and neither can flag a comment addressed to the other.\n//\n// oxlint accepts these keys only in the root config file, which is why every generated lint script\n// passes `--disable-nested-config`: a discovered nested config carrying them aborts the whole run.\nexport const OXLINT_DIRECTIVE_OPTIONS: OxlintRendererOptions = {\n respectEslintDisableDirectives: false,\n reportUnusedDisableDirectives: UNUSED_DIRECTIVE_SEVERITY,\n};\n\n/**\n * The always-on ESLint block that makes a stale `eslint-disable` visible. ESLint 9 defaults this to\n * `warn`, but the split relies on it, so it is pinned rather than inherited.\n * @example\n * buildUnusedDirectiveBlocks()[0].linterOptions; // { reportUnusedDisableDirectives: 'warn' }\n */\nexport function buildUnusedDirectiveBlocks (): Linter.Config[] {\n return [{\n name: UNUSED_DIRECTIVE_BLOCK_NAME,\n linterOptions: { reportUnusedDisableDirectives: UNUSED_DIRECTIVE_SEVERITY },\n }];\n}\n\nfunction ownedRuleNames (rules: Partial<Linter.RulesRecord>): string[] {\n return Object.keys(rules).filter(name => isOxlintOwned(name) && !isRuleDisabled(rules[name]));\n}\n\n// Unlike the suppression layer, the emitted oxlint config has to carry explicit `off` entries: a\n// later block that disables a rule an earlier block enabled only takes effect on the oxlint side\n// if the disable is translated too.\nfunction translatableRuleNames (rules: Partial<Linter.RulesRecord>): string[] {\n return Object.keys(rules).filter(isOxlintOwned);\n}\n\nfunction toOffRecord (ruleNames: readonly string[]): Linter.RulesRecord {\n return Object.fromEntries(ruleNames.map(name => [name, 'off']));\n}\n\nfunction suppressionFor (block: Linter.Config): Linter.Config[] {\n if (!block.rules) {\n return [];\n }\n\n const owned = ownedRuleNames(block.rules);\n\n if (owned.length === 0) {\n return [];\n }\n\n // A block without `files` applies everywhere, and so must its suppression.\n const files = block.files ? { files: [...block.files] as string[] } : {};\n const blockIgnores = block.ignores ? [...block.ignores] as string[] : [];\n const vueSafe = owned.filter(name => !isVueUnsafeRule(name));\n const vueUnsafe = owned.filter(name => isVueUnsafeRule(name));\n const suppressions: Linter.Config[] = [];\n\n if (vueSafe.length > 0) {\n suppressions.push({\n name: OXLINT_SUPPRESSION_NAME,\n ...files,\n ...blockIgnores.length > 0 ? { ignores: blockIgnores } : {},\n rules: toOffRecord(vueSafe),\n });\n }\n\n if (vueUnsafe.length > 0) {\n suppressions.push({\n name: OXLINT_SFC_EXCEPTION_NAME,\n ...files,\n ignores: [...blockIgnores, ...VUE_LIKE_GLOBS],\n rules: toOffRecord(vueUnsafe),\n });\n }\n\n return suppressions;\n}\n\n/**\n * ESLint blocks that turn off every rule the emitted oxlint config takes over. Rules oxlint cannot\n * check inside an SFC are suppressed everywhere except `.vue`/`.svelte`/`.astro`, so a Vue consumer\n * keeps them.\n * @example\n * buildOxlintSuppressionBlocks([{ files: ['src/**\\/*.ts'], rules: { 'no-var': 'error' } }]);\n * // [{ files: ['src/**\\/*.ts'], rules: { 'no-var': 'off' } }]\n */\nexport function buildOxlintSuppressionBlocks (blocks: readonly Linter.Config[]): Linter.Config[] {\n return blocks.flatMap(suppressionFor);\n}\n\nfunction translateRules (\n rules: Partial<Linter.RulesRecord>,\n plugins: Set<string>\n): Record<string, Linter.RuleEntry> {\n return translatableRuleNames(rules).reduce<Record<string, Linter.RuleEntry>>((accumulator, name) => {\n plugins.add(toOxlintPluginName(name));\n accumulator[toOxlintRuleName(name)] = rules[name] as Linter.RuleEntry;\n\n return accumulator;\n }, {});\n}\n\n// ESLint anchors a flat-config `files` glob at the config's own directory, while oxlint matches an\n// unanchored pattern at any depth — `*.mjs` would also claim `.husky/install.mjs`. A leading `./`\n// restores the anchor; patterns that already opt into any depth (`**/…`) keep their meaning.\nexport function anchorOxlintGlob (glob: string): string {\n const alreadyAnchored = glob.startsWith('**') || glob.startsWith('./') || glob.startsWith('/');\n\n return alreadyAnchored ? glob : `./${glob}`;\n}\n\nfunction anchorGlobs (globs: readonly unknown[]): string[] {\n return (globs as string[]).map(anchorOxlintGlob);\n}\n\n// `ignorePatterns` is read with gitignore semantics, not glob semantics, so it needs a different\n// anchor from `anchorOxlintGlob`: a leading `/`, which `./` does not stand in for — oxlint 1.83.0\n// matches nothing at all for `./dist`. Without it a slash-free pattern like `dist` is matched at\n// any depth, so oxlint would also skip `src/dist/**` that ESLint still lints — and since every\n// oxlint-owned rule is switched off on the ESLint side, those files would lose the rule entirely.\n// A pattern already carrying a slash is anchored by gitignore itself; `**`-leading and already\n// rooted patterns keep their meaning, and a negation is anchored inside the `!`.\nexport function anchorOxlintIgnorePattern (pattern: string): string {\n const negated = pattern.startsWith('!');\n const body = negated ? pattern.slice(1) : pattern;\n const anchored = body.startsWith('/') || body.startsWith('**') ? body : `/${body}`;\n\n return negated ? `!${anchored}` : anchored;\n}\n\nfunction overrideFor (block: Linter.Config, plugins: Set<string>): OxlintOverride[] {\n if (!block.files || !block.rules) {\n return [];\n }\n\n const translated = translateRules(block.rules, plugins);\n\n if (Object.keys(translated).length === 0) {\n return [];\n }\n\n return [{\n files: anchorGlobs(block.files),\n ...block.ignores && block.ignores.length > 0 ? { excludeFiles: anchorGlobs(block.ignores) } : {},\n rules: translated,\n }];\n}\n\n/**\n * The oxlint half of the split, derived from the same emitted ESLint blocks the suppression layer\n * reads. Every oxlint category is pinned off so the config enables exactly the preset's own rules\n * and nothing oxlint would otherwise turn on by default.\n * @example\n * buildOxlintConfig([{ files: ['src/**\\/*.ts'], rules: { 'no-var': 'error' } }], ['dist']);\n * // { plugins: ['eslint'], categories: { correctness: 'off', ... }, ignorePatterns: ['/dist'], ... }\n */\nexport function buildOxlintConfig (\n blocks: readonly Linter.Config[],\n ignores: readonly string[] | undefined\n): OxlintRendererConfig {\n const plugins = new Set<string>(['eslint']);\n const overrides = blocks.flatMap(block => overrideFor(block, plugins));\n const globalRules = blocks\n .filter(block => !block.files && block.rules)\n .reduce<Record<string, Linter.RuleEntry>>(\n (accumulator, block) => ({ ...accumulator, ...translateRules(block.rules!, plugins) }),\n {}\n );\n\n return {\n plugins: [...plugins].sort((left, right) => left.localeCompare(right)),\n categories: Object.fromEntries(OXLINT_CATEGORIES.map(name => [name, 'off'])),\n ...ignores && ignores.length > 0 ? { ignorePatterns: ignores.map(anchorOxlintIgnorePattern) } : {},\n options: { ...OXLINT_DIRECTIVE_OPTIONS },\n rules: globalRules,\n overrides,\n };\n}\n\n/* v8 ignore start */\nif (import.meta.vitest) {\n const { describe, test, expect } = import.meta.vitest;\n\n const tsBlock: Linter.Config = {\n files: ['src/**/*.ts'],\n rules: {\n 'no-var': 'error',\n 'import-x/first': 'error',\n '@typescript-eslint/no-unused-vars': 'error',\n 'sonarjs/no-identical-functions': 'error',\n '@stylistic/indent': ['error', 4],\n 'no-console': 'off',\n },\n };\n\n describe('buildOxlintSuppressionBlocks', () => {\n test('suppresses only the rules oxlint owns', () => {\n const [primary] = buildOxlintSuppressionBlocks([tsBlock]);\n\n expect(primary.rules).toStrictEqual({ 'no-var': 'off', 'import-x/first': 'off' });\n });\n\n test('keeps SFC-unsafe rules enforced for vue, svelte and astro files', () => {\n const [, exception] = buildOxlintSuppressionBlocks([tsBlock]);\n\n expect(exception.rules).toStrictEqual({ '@typescript-eslint/no-unused-vars': 'off' });\n expect(exception.ignores).toStrictEqual([...VUE_LIKE_GLOBS]);\n });\n\n test('never suppresses a rule the preset already turned off', () => {\n const blocks = buildOxlintSuppressionBlocks([tsBlock]);\n const suppressed = blocks.flatMap(block => Object.keys(block.rules ?? {}));\n\n expect(suppressed).not.toContain('no-console');\n });\n\n test('carries the source block ignores so the suppression matches the same files', () => {\n const [primary] = buildOxlintSuppressionBlocks([\n { ...tsBlock, ignores: ['src/legacy/**'] },\n ]);\n\n expect(primary.ignores).toStrictEqual(['src/legacy/**']);\n });\n\n test('appends the SFC globs to the source block ignores on the exception block', () => {\n const [, exception] = buildOxlintSuppressionBlocks([\n { ...tsBlock, ignores: ['src/legacy/**'] },\n ]);\n\n expect(exception.ignores).toStrictEqual(['src/legacy/**', ...VUE_LIKE_GLOBS]);\n });\n\n test('emits nothing for a block without files or rules', () => {\n expect(buildOxlintSuppressionBlocks([{ ignores: ['dist'] }])).toStrictEqual([]);\n expect(buildOxlintSuppressionBlocks([{ files: ['*.js'] }])).toStrictEqual([]);\n });\n });\n\n describe('buildUnusedDirectiveBlocks', () => {\n test('pins ESLint unused-directive reporting instead of inheriting the default', () => {\n expect(buildUnusedDirectiveBlocks()).toStrictEqual([{\n name: UNUSED_DIRECTIVE_BLOCK_NAME,\n linterOptions: { reportUnusedDisableDirectives: 'warn' },\n }]);\n });\n\n test('carries no files or rules, so it neither suppresses nor reaches the oxlint side', () => {\n const [block] = buildUnusedDirectiveBlocks();\n\n expect(buildOxlintSuppressionBlocks([block])).toStrictEqual([]);\n expect(buildOxlintConfig([block], undefined).overrides).toStrictEqual([]);\n });\n });\n\n describe('buildOxlintConfig', () => {\n test('translates owned rules into oxlint names, preserving severity and options', () => {\n const { overrides } = buildOxlintConfig([{\n files: ['src/**/*.ts'],\n rules: { 'no-bitwise': ['error', { allow: ['~'] }] },\n }], undefined);\n\n expect(overrides[0].rules).toStrictEqual({ 'eslint/no-bitwise': ['error', { allow: ['~'] }] });\n });\n\n test('derives the plugin list from the rules actually emitted', () => {\n const { plugins } = buildOxlintConfig([tsBlock], undefined);\n\n expect(plugins).toStrictEqual(['eslint', 'import', 'typescript']);\n });\n\n test('pins every oxlint category off so defaults cannot leak in', () => {\n const { categories } = buildOxlintConfig([], undefined);\n\n expect(Object.values(categories).every(value => value === 'off')).toBe(true);\n expect(Object.keys(categories)).toStrictEqual([...OXLINT_CATEGORIES]);\n });\n\n test('maps config ignores onto ignorePatterns', () => {\n expect(buildOxlintConfig([], ['dist', 'coverage']).ignorePatterns).toStrictEqual(['/dist', '/coverage']);\n expect(buildOxlintConfig([], []).ignorePatterns).toBeUndefined();\n });\n });\n\n describe('anchorOxlintIgnorePattern', () => {\n test('roots a slash-free pattern so it cannot swallow a nested directory of the same name', () => {\n expect(anchorOxlintIgnorePattern('dist')).toBe('/dist');\n expect(anchorOxlintIgnorePattern('dist/')).toBe('/dist/');\n });\n\n test('roots a pattern that already carries a slash, which gitignore anchors anyway', () => {\n expect(anchorOxlintIgnorePattern('scripts/legacy/**')).toBe('/scripts/legacy/**');\n });\n\n test('leaves an any-depth or already rooted pattern alone', () => {\n expect(anchorOxlintIgnorePattern('**/dist')).toBe('**/dist');\n expect(anchorOxlintIgnorePattern('/dist')).toBe('/dist');\n });\n\n test('anchors inside the negation so an un-ignore matches the same files as its ignore', () => {\n expect(anchorOxlintIgnorePattern('!dist/keep.js')).toBe('!/dist/keep.js');\n expect(anchorOxlintIgnorePattern('!**/dist')).toBe('!**/dist');\n });\n\n test('maps block ignores onto the override excludeFiles key', () => {\n const { overrides } = buildOxlintConfig([{ ...tsBlock, ignores: ['src/legacy/**'] }], undefined);\n\n expect(overrides[0].excludeFiles).toStrictEqual(['./src/legacy/**']);\n });\n\n test('anchors override globs so oxlint matches the same files ESLint does', () => {\n const { overrides } = buildOxlintConfig([{ files: ['*.mjs'], rules: { 'no-var': 'error' } }], undefined);\n\n expect(overrides[0].files).toStrictEqual(['./*.mjs']);\n });\n\n test('leaves any-depth globs alone', () => {\n const { overrides } = buildOxlintConfig([{\n files: ['**/*.mjs'],\n rules: { 'no-var': 'error' },\n }], undefined);\n\n expect(overrides[0].files).toStrictEqual(['**/*.mjs']);\n });\n\n test('carries an explicit off so a later block can release a rule an earlier one enabled', () => {\n const { overrides } = buildOxlintConfig([{\n files: ['*.mjs'],\n rules: { 'no-var': 'off' },\n }], undefined);\n\n expect(overrides[0].rules).toStrictEqual({ 'eslint/no-var': 'off' });\n });\n\n test('refuses the eslint-disable spelling and reports unused oxlint-disable directives', () => {\n expect(buildOxlintConfig([], undefined).options).toStrictEqual({\n respectEslintDisableDirectives: false,\n reportUnusedDisableDirectives: 'warn',\n });\n });\n\n test('emits no override for a block whose rules are all ESLint-owned', () => {\n const { overrides } = buildOxlintConfig([{\n files: ['src/**/*.ts'],\n rules: { 'sonarjs/no-identical-functions': 'error' },\n }], undefined);\n\n expect(overrides).toStrictEqual([]);\n });\n });\n}\n","import { existsSync, readFileSync } from 'node:fs';\nimport { createRequire } from 'node:module';\nimport { join } from 'node:path';\nimport { AST_NODE_TYPES, type TSESTree } from '@typescript-eslint/types';\n\nconst MODULE_EXTENSIONS: readonly string[] = ['ts', 'mts', 'cts', 'js', 'mjs', 'cjs'];\n\nexport const LINT_MODULE_FILENAMES: readonly string[] = MODULE_EXTENSIONS.map(ext => `insider.lint.${ext}`);\n\nexport const ESLINT_CONFIG_FILENAMES: readonly string[] = MODULE_EXTENSIONS.map(ext => `eslint.config.${ext}`);\n\n// oxlint discovers only these two. It ignores `oxlint.config.{cts,js,mjs,cjs}` without a word and\n// silently falls through to the nearest ancestor config, so accepting them here would let a\n// consumer believe a config is live when oxlint never reads it.\nexport const OXLINT_CONFIG_FILENAMES: readonly string[] = ['oxlint.config.ts', 'oxlint.config.mts'];\n\nexport const OPT_OUT_ENV = 'INSIDER_SKIP_CONFIG_VALIDATION';\n\nexport const MIGRATE_COMMAND = 'npx @useinsider/eslint-config migrate';\n\nexport const SCAFFOLD_COMMAND = 'npx @useinsider/eslint-config';\n\nexport const INSIDER_IMPORT_SOURCE = '@useinsider/eslint-config';\n\nexport const TARGET_CALLEE_NAME = 'useInsider';\n\nexport const ESLINT_RENDERER_NAME = 'useInsiderESLint';\n\nexport const OXC_RENDERER_NAME = 'useInsiderOXC';\n\nconst RENDERER_BINDINGS = `{ ${ESLINT_RENDERER_NAME}, ${OXC_RENDERER_NAME} }`;\n\nexport const RENDERER_EXPORT = `export const ${RENDERER_BINDINGS} = ${TARGET_CALLEE_NAME}({ ... })`;\n\n// The import specifier names the lint module's real extension: neither ESLint's jiti loader nor\n// oxlint's Node type stripping applies TypeScript's `.js` → `.ts` specifier rewriting.\nexport const EXPECTED_LAYOUT = [\n 'Expected layout (three sibling files):',\n '',\n ' // insider.lint.ts',\n ` import { ${TARGET_CALLEE_NAME} } from '${INSIDER_IMPORT_SOURCE}';`,\n '',\n ` ${RENDERER_EXPORT};`,\n '',\n ' // eslint.config.ts',\n ` import { ${ESLINT_RENDERER_NAME} } from './insider.lint.ts';`,\n '',\n ` export default ${ESLINT_RENDERER_NAME}();`,\n '',\n ' // oxlint.config.ts',\n ` import { ${OXC_RENDERER_NAME} } from './insider.lint.ts';`,\n '',\n ` export default await ${OXC_RENDERER_NAME}();`,\n].join('\\n');\n\nexport type LayoutCase = 'complete' | 'noConfig' | 'partial' | 'unmigratedV3';\n\nexport interface LayoutDiagnosis {\n kind: LayoutCase;\n directory: string;\n lintModule: string | null;\n eslintConfig: string | null;\n oxlintConfig: string | null;\n missing: string[];\n autoMigratable: boolean;\n}\n\nexport interface DiagnoseLayoutOptions {\n fileExists?: (path: string) => boolean;\n readSource?: (path: string) => string;\n}\n\nfunction findSibling (\n directory: string,\n filenames: readonly string[],\n fileExists: (path: string) => boolean\n): string | null {\n return filenames.find(filename => fileExists(join(directory, filename))) ?? null;\n}\n\nconst lazyRequire = createRequire(import.meta.url);\n\nfunction parseProgram (source: string): TSESTree.Program | null {\n try {\n const { parse } = lazyRequire('@typescript-eslint/parser') as typeof import('@typescript-eslint/parser');\n\n return parse(source, { sourceType: 'module', range: true, loc: true });\n } catch {\n return null;\n }\n}\n\nfunction collectUseInsiderAliases (program: TSESTree.Program): Set<string> {\n const aliases = new Set<string>();\n\n program.body.forEach(node => {\n if (node.type !== AST_NODE_TYPES.ImportDeclaration) {\n return;\n }\n\n node.specifiers.forEach(specifier => {\n const importsTheComposer = specifier.type === AST_NODE_TYPES.ImportSpecifier\n && specifier.imported.type === AST_NODE_TYPES.Identifier\n && specifier.imported.name === TARGET_CALLEE_NAME;\n\n if (importsTheComposer) {\n aliases.add(specifier.local.name);\n }\n });\n });\n\n return aliases;\n}\n\nfunction callsAny (node: unknown, aliases: ReadonlySet<string>): boolean {\n if (!node || typeof node !== 'object') {\n return false;\n }\n\n if (Array.isArray(node)) {\n return node.some(child => callsAny(child, aliases));\n }\n\n const candidate = node as TSESTree.Node;\n\n if (candidate.type === AST_NODE_TYPES.CallExpression) {\n const { callee } = candidate;\n\n if (callee.type === AST_NODE_TYPES.Identifier && aliases.has(callee.name)) {\n return true;\n }\n }\n\n return Object.entries(node).some(([key, value]) => key !== 'parent' && callsAny(value, aliases));\n}\n\n/**\n * Whether a flat-config source is still the removed v3 shape: it imports `useInsider` and calls it\n * itself, instead of importing a renderer from a sibling `insider.lint.*` module. Both the plain\n * `export default useInsider({...})` form and the spread form are recognized.\n * @example\n * isV3EslintConfigSource(\"import { useInsider } from '@useinsider/eslint-config';\\nexport default useInsider({});\");\n * // true\n */\nexport function isV3EslintConfigSource (source: string): boolean {\n const program = parseProgram(source);\n\n if (!program) {\n return false;\n }\n\n const aliases = collectUseInsiderAliases(program);\n\n if (aliases.size === 0) {\n return false;\n }\n\n return program.body.some(node => callsAny(node, aliases));\n}\n\nfunction classify (\n lintModule: string | null,\n eslintConfig: string | null,\n oxlintConfig: string | null,\n eslintConfigIsV3: boolean\n): LayoutCase {\n if (lintModule && eslintConfig && oxlintConfig) {\n return 'complete';\n }\n\n if (!lintModule && !eslintConfig && !oxlintConfig) {\n return 'noConfig';\n }\n\n if (!lintModule && eslintConfig && eslintConfigIsV3) {\n return 'unmigratedV3';\n }\n\n return 'partial';\n}\n\n/**\n * What of the three-file layout is on disk in a directory, and which of the four guidance branches\n * applies. `unmigratedV3` is the only branch the in-lint migration offer acts on, because it is the\n * only one {@link import('../cli/migrate').runMigrate} can actually rewrite.\n * @example\n * diagnoseLayout('/repo').kind; // 'unmigratedV3' when eslint.config.js still calls useInsider()\n */\nexport function diagnoseLayout (directory: string, options: DiagnoseLayoutOptions = {}): LayoutDiagnosis {\n const fileExists = options.fileExists ?? existsSync;\n const readSource = options.readSource ?? ((path: string) => readFileSync(path, 'utf8'));\n const lintModule = findSibling(directory, LINT_MODULE_FILENAMES, fileExists);\n const eslintConfig = findSibling(directory, ESLINT_CONFIG_FILENAMES, fileExists);\n const oxlintConfig = findSibling(directory, OXLINT_CONFIG_FILENAMES, fileExists);\n let eslintConfigIsV3 = false;\n\n if (eslintConfig && !lintModule) {\n try {\n eslintConfigIsV3 = isV3EslintConfigSource(readSource(join(directory, eslintConfig)));\n } catch {\n eslintConfigIsV3 = false;\n }\n }\n\n const kind = classify(lintModule, eslintConfig, oxlintConfig, eslintConfigIsV3);\n const missing = [\n lintModule ? null : 'insider.lint.ts',\n eslintConfig ? null : 'eslint.config.ts',\n oxlintConfig ? null : 'oxlint.config.ts',\n ].filter((name): name is string => name !== null);\n\n return {\n kind,\n directory,\n lintModule,\n eslintConfig,\n oxlintConfig,\n missing,\n autoMigratable: kind === 'unmigratedV3',\n };\n}\n\n/**\n * Import specifier for the consumer's lint module, naming the extension that is actually on disk so\n * the suggested snippet resolves as printed.\n * @example\n * lintModuleSpecifier('/repo'); // './insider.lint.mts' when that is the file present\n */\nexport function lintModuleSpecifier (directory: string, fileExists: (path: string) => boolean = existsSync): string {\n return `./${findSibling(directory, LINT_MODULE_FILENAMES, fileExists) ?? 'insider.lint.ts'}`;\n}\n\nfunction inventoryLines (diagnosis: LayoutDiagnosis): string[] {\n const v3Note = diagnosis.kind === 'unmigratedV3' ? ' (still calls `useInsider()` itself)' : '';\n\n return [\n diagnosis.lintModule\n ? ` present: ${diagnosis.lintModule}`\n : ' MISSING: insider.lint.{ts,mts}',\n diagnosis.eslintConfig\n ? ` present: ${diagnosis.eslintConfig}${v3Note}`\n : ' MISSING: eslint.config.{ts,mts}',\n diagnosis.oxlintConfig\n ? ` present: ${diagnosis.oxlintConfig}`\n : ` MISSING: ${OXLINT_CONFIG_FILENAMES.join(' or ')}`,\n ];\n}\n\nfunction guidanceBody (diagnosis: LayoutDiagnosis): string[] {\n if (diagnosis.kind === 'complete') {\n return [\n `All three files are already here, so there is nothing to migrate — ${TARGET_CALLEE_NAME}() was`,\n `reached from somewhere other than ${diagnosis.lintModule ?? LINT_MODULE_FILENAMES[0]}. Only the`,\n 'lint module may call it; the two configs import the renderers it exports.',\n ];\n }\n\n if (diagnosis.kind === 'unmigratedV3') {\n return [\n '`useInsider()` no longer returns a flat-config array, so the config it is called from has',\n 'to become a module both linters can import. The migration does that rewrite for you:',\n '',\n ` ${MIGRATE_COMMAND}`,\n ];\n }\n\n if (diagnosis.kind === 'noConfig') {\n return [\n 'There is no linter configuration here yet. Scaffold the three-file layout:',\n '',\n ` ${SCAFFOLD_COMMAND}`,\n ];\n }\n\n return [\n `The layout is incomplete — missing ${diagnosis.missing.join(', ')}.`,\n 'Add the missing file, or let the migration regenerate the whole layout:',\n '',\n ` ${MIGRATE_COMMAND}`,\n ];\n}\n\nfunction detailLines (detail: readonly string[] | undefined): string[] {\n if (!detail || detail.length === 0) {\n return [];\n }\n\n return ['', ...detail];\n}\n\nexport interface LayoutGuidanceInput {\n headline: string;\n diagnosis: LayoutDiagnosis;\n detail?: readonly string[];\n}\n\n/**\n * The consumer-facing failure text: a site-specific headline, then the branch that matches what is\n * on disk, then the layout dump, then the bypass. The command to run always comes before the dump,\n * because a consumer who reads only the first screen still has to be told about `migrate`.\n * @example\n * formatLayoutGuidance({ headline: 'no `insider.lint.*` module found in /repo.', diagnosis });\n */\nexport function formatLayoutGuidance (input: LayoutGuidanceInput): string {\n return [\n `@useinsider/eslint-config: ${input.headline}`,\n '',\n ...inventoryLines(input.diagnosis),\n '',\n ...guidanceBody(input.diagnosis),\n ...detailLines(input.detail),\n '',\n EXPECTED_LAYOUT,\n '',\n `Emergency bypass: set ${OPT_OUT_ENV}=true (do not commit).`,\n ].join('\\n');\n}\n\n/* v8 ignore start */\nif (import.meta.vitest) {\n const { describe, test, expect } = import.meta.vitest;\n const { mkdtempSync, writeFileSync } = await import('node:fs');\n const { tmpdir } = await import('node:os');\n\n const V3_SOURCE = [\n \"import { silenceRules, useInsider } from '@useinsider/eslint-config';\",\n \"silenceRules(['complexity']);\",\n 'export default useInsider({ typescriptNode: [{ files: [], tsconfigPaths: [] }] });',\n ].join('\\n');\n\n function makeDir (files: Record<string, string> = {}): string {\n const directory = mkdtempSync(join(tmpdir(), 'insider-diagnosis-'));\n\n Object.entries(files).forEach(([name, content]) => {\n writeFileSync(join(directory, name), content, 'utf8');\n });\n\n return directory;\n }\n\n describe('isV3EslintConfigSource', () => {\n test('recognizes the plain v3 default export', () => {\n expect(isV3EslintConfigSource(V3_SOURCE)).toBe(true);\n });\n\n test('recognizes the v3 spread shape', () => {\n const source = [\n \"import { useInsider } from '@useinsider/eslint-config';\",\n \"export default [{ ignores: ['dist'] }, ...await useInsider({}), { rules: {} }];\",\n ].join('\\n');\n\n expect(isV3EslintConfigSource(source)).toBe(true);\n });\n\n test('recognizes an aliased import', () => {\n const source = [\n \"import { useInsider as compose } from '@useinsider/eslint-config';\",\n 'export default compose({});',\n ].join('\\n');\n\n expect(isV3EslintConfigSource(source)).toBe(true);\n });\n\n test('rejects the migrated v4 config', () => {\n const source = [\n \"import { useInsiderESLint } from './insider.lint.ts';\",\n 'export default useInsiderESLint();',\n ].join('\\n');\n\n expect(isV3EslintConfigSource(source)).toBe(false);\n });\n\n test('rejects a config that imports useInsider without calling it', () => {\n const source = [\n \"import { useInsider } from '@useinsider/eslint-config';\",\n 'export default [];',\n ].join('\\n');\n\n expect(isV3EslintConfigSource(source)).toBe(false);\n });\n\n test('rejects an unparseable source instead of throwing', () => {\n expect(isV3EslintConfigSource('export default (((')).toBe(false);\n });\n });\n\n describe('diagnoseLayout', () => {\n test('reports a complete layout', () => {\n const directory = makeDir({\n 'insider.lint.ts': '',\n 'eslint.config.ts': '',\n 'oxlint.config.ts': '',\n });\n const diagnosis = diagnoseLayout(directory);\n\n expect(diagnosis.kind).toBe('complete');\n expect(diagnosis.missing).toStrictEqual([]);\n expect(diagnosis.autoMigratable).toBe(false);\n });\n\n test('reports an un-migrated v3 config', () => {\n const diagnosis = diagnoseLayout(makeDir({ 'eslint.config.js': V3_SOURCE }));\n\n expect(diagnosis.kind).toBe('unmigratedV3');\n expect(diagnosis.eslintConfig).toBe('eslint.config.js');\n expect(diagnosis.autoMigratable).toBe(true);\n expect(diagnosis.missing).toStrictEqual(['insider.lint.ts', 'oxlint.config.ts']);\n });\n\n test('reports an empty directory as noConfig', () => {\n const diagnosis = diagnoseLayout(makeDir());\n\n expect(diagnosis.kind).toBe('noConfig');\n expect(diagnosis.autoMigratable).toBe(false);\n });\n\n test('reports a v4 config missing its lint module as partial, not v3', () => {\n const diagnosis = diagnoseLayout(makeDir({\n 'eslint.config.ts': \"import { useInsiderESLint } from './insider.lint.ts';\\n\"\n + 'export default useInsiderESLint();',\n 'oxlint.config.ts': '',\n }));\n\n expect(diagnosis.kind).toBe('partial');\n expect(diagnosis.missing).toStrictEqual(['insider.lint.ts']);\n expect(diagnosis.autoMigratable).toBe(false);\n });\n\n test('reports a missing oxlint config as partial', () => {\n const diagnosis = diagnoseLayout(makeDir({\n 'insider.lint.ts': '',\n 'eslint.config.ts': '',\n }));\n\n expect(diagnosis.kind).toBe('partial');\n expect(diagnosis.missing).toStrictEqual(['oxlint.config.ts']);\n });\n\n test('ignores oxlint config extensions oxlint never discovers', () => {\n const diagnosis = diagnoseLayout(makeDir({\n 'insider.lint.ts': '',\n 'eslint.config.ts': '',\n 'oxlint.config.mjs': '',\n }));\n\n expect(diagnosis.oxlintConfig).toBeNull();\n expect(diagnosis.kind).toBe('partial');\n });\n\n test('survives an unreadable eslint config', () => {\n const diagnosis = diagnoseLayout('/does/not/exist', {\n fileExists: path => path.endsWith('eslint.config.js'),\n readSource: () => {\n throw new Error('EACCES');\n },\n });\n\n expect(diagnosis.kind).toBe('partial');\n });\n });\n\n describe('formatLayoutGuidance', () => {\n test('leads an un-migrated v3 config with the migrate command, before the layout dump', () => {\n const diagnosis = diagnoseLayout(makeDir({ 'eslint.config.js': V3_SOURCE }));\n const message = formatLayoutGuidance({ headline: 'headline.', diagnosis });\n\n expect(message.indexOf(MIGRATE_COMMAND)).toBeLessThan(message.indexOf('Expected layout'));\n expect(message.indexOf('Expected layout')).toBeLessThan(message.indexOf(OPT_OUT_ENV));\n expect(message).toContain('still calls `useInsider()` itself');\n });\n\n test('recommends scaffold when nothing is on disk', () => {\n const message = formatLayoutGuidance({\n headline: 'headline.',\n diagnosis: diagnoseLayout(makeDir()),\n });\n\n expect(message).toContain(SCAFFOLD_COMMAND);\n expect(message).not.toContain(MIGRATE_COMMAND);\n });\n\n test('names the missing file for a partial layout', () => {\n const message = formatLayoutGuidance({\n headline: 'headline.',\n diagnosis: diagnoseLayout(makeDir({ 'insider.lint.ts': '', 'eslint.config.ts': '' })),\n });\n\n expect(message).toContain('missing oxlint.config.ts');\n expect(message).toContain(MIGRATE_COMMAND);\n });\n\n test('places site-specific detail after the guidance and before the dump', () => {\n const message = formatLayoutGuidance({\n headline: 'headline.',\n diagnosis: diagnoseLayout(makeDir()),\n detail: ['site detail line'],\n });\n\n expect(message.indexOf(SCAFFOLD_COMMAND)).toBeLessThan(message.indexOf('site detail line'));\n expect(message.indexOf('site detail line')).toBeLessThan(message.indexOf('Expected layout'));\n });\n });\n\n describe('lintModuleSpecifier', () => {\n test('names the module that exists', () => {\n expect(lintModuleSpecifier(makeDir({ 'insider.lint.mts': '' }))).toBe('./insider.lint.mts');\n });\n\n test('falls back to the TypeScript filename', () => {\n expect(lintModuleSpecifier(makeDir())).toBe('./insider.lint.ts');\n });\n });\n}\n","import { spawnSync } from 'node:child_process';\nimport { existsSync, readFileSync } from 'node:fs';\nimport { basename, dirname, join, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { type LayoutDiagnosis, OPT_OUT_ENV } from './layoutDiagnosis';\n\nconst PACKAGE_NAME = '@useinsider/eslint-config';\nconst CLI_RELATIVE_PATH = 'dist/cli.cjs';\nconst NO_PROMPT_ENV = 'INSIDER_NO_PROMPT';\nconst IN_FLIGHT_ENV = 'INSIDER_MIGRATION_IN_PROGRESS';\nconst MIGRATE_FROM_LINT_ARGS: readonly string[] = ['migrate', '--from-lint'];\nconst BINARY_EXTENSIONS = /\\.[mc]?js$/u;\n\nexport type LintHost = 'eslint' | 'oxlint' | 'unknown';\n\nfunction binaryName (argument: string): string {\n return basename(argument).replace(BINARY_EXTENSIONS, '');\n}\n\n/**\n * Which linter is hosting the current process. oxlint evaluates `oxlint.config.ts` inside the Node\n * process that runs its own `bin/oxlint` wrapper, so `useInsider()` genuinely executes under both\n * binaries and the two have to be told apart before anything is written to stdout.\n * @example\n * detectLintHost(['node', '/app/node_modules/oxlint/bin/oxlint', '.']); // 'oxlint'\n */\nexport function detectLintHost (argv: readonly string[] = process.argv): LintHost {\n const names = argv.slice(1).map(binaryName);\n\n if (names.includes('oxlint')) {\n return 'oxlint';\n }\n\n if (names.includes('eslint')) {\n return 'eslint';\n }\n\n return 'unknown';\n}\n\nexport type OfferSkipReason = | 'already-offered'\n | 'cli-not-found'\n | 'host-is-oxlint'\n | 'no-tty'\n | 'running-in-ci'\n | 'running-under-test'\n | 'suppressed';\n\nexport interface MigrationOfferResult {\n offered: boolean;\n skipReason?: OfferSkipReason;\n accepted?: boolean;\n}\n\nexport interface MigrationOfferDeps {\n env?: NodeJS.ProcessEnv;\n argv?: readonly string[];\n interactive?: boolean;\n resolveCliEntry?: () => string | null;\n runCli?: (entry: string, args: readonly string[], cwd: string, env: NodeJS.ProcessEnv) => number;\n warn?: (message: string) => void;\n}\n\nfunction defaultInteractive (): boolean {\n return Boolean(process.stdin.isTTY) && Boolean(process.stdout.isTTY);\n}\n\nfunction skipReasonFor (\n env: NodeJS.ProcessEnv,\n argv: readonly string[],\n interactive: boolean\n): OfferSkipReason | null {\n if (env[IN_FLIGHT_ENV] === 'true') {\n return 'already-offered';\n }\n\n // A suite that happens to run in a terminal has a live TTY, and spawning the migrator from it\n // would rewrite the fixture tree under the runner. Specs inject `env` to exercise the real path.\n if (env.VITEST || env.NODE_ENV === 'test') {\n return 'running-under-test';\n }\n\n if (env[OPT_OUT_ENV] === 'true' || env[NO_PROMPT_ENV] === 'true') {\n return 'suppressed';\n }\n\n if (env.CI) {\n return 'running-in-ci';\n }\n\n if (detectLintHost(argv) === 'oxlint') {\n return 'host-is-oxlint';\n }\n\n if (!interactive) {\n return 'no-tty';\n }\n\n return null;\n}\n\nfunction manifestNameAt (directory: string): string | null {\n const manifestPath = join(directory, 'package.json');\n\n if (!existsSync(manifestPath)) {\n return null;\n }\n\n try {\n return (JSON.parse(readFileSync(manifestPath, 'utf8')) as { name?: string }).name ?? null;\n } catch {\n return null;\n }\n}\n\nfunction packageRootFrom (startDir: string): string | null {\n let current = startDir;\n\n for (let depth = 0; depth < 10; depth += 1) {\n if (manifestNameAt(current) === PACKAGE_NAME) {\n return current;\n }\n\n const parent = dirname(current);\n\n if (parent === current) {\n return null;\n }\n\n current = parent;\n }\n\n return null;\n}\n\n/**\n * Absolute path to this package's own built CLI, or `null` when it is not on disk. Resolved by\n * walking up from `startDir` — this module's own directory by default — rather than through\n * `require.resolve`, so it works from `dist/` and from `src/` alike.\n * @example\n * resolveCliEntry(); // '/app/node_modules/@useinsider/eslint-config/dist/cli.cjs'\n */\nexport function resolveCliEntry (startDir?: string): string | null {\n const root = packageRootFrom(startDir ?? dirname(fileURLToPath(import.meta.url)));\n\n if (!root) {\n return null;\n }\n\n const entry = resolve(root, CLI_RELATIVE_PATH);\n\n return existsSync(entry) ? entry : null;\n}\n\n// The migrator prompts, so it needs the terminal. `useInsider()` is synchronous — it is called\n// during ESLint's config evaluation and cannot await — so the only way to drive an interactive\n// migration from here is a synchronous child process that inherits this one's stdio.\nfunction defaultRunCli (\n entry: string,\n args: readonly string[],\n cwd: string,\n env: NodeJS.ProcessEnv\n): number {\n const result = spawnSync(process.execPath, [entry, ...args], { cwd, env, stdio: 'inherit' });\n\n if (result.error) {\n return 1;\n }\n\n return result.status ?? 1;\n}\n\nfunction defaultWarn (message: string): void {\n // oxlint-disable-next-line no-console -- diagnostic surface, mirrors ensureDependencies.ts.\n console.error(message);\n}\n\nfunction outdatedNotice (diagnosis: LayoutDiagnosis): string {\n const config = diagnosis.eslintConfig ?? 'eslint.config.*';\n\n return [\n `@useinsider/eslint-config: ${config} still uses the v3 single-file layout.`,\n ` ${join(diagnosis.directory, config)} calls \\`useInsider()\\` itself, and`,\n ` ${diagnosis.missing.join(' and ')} ${diagnosis.missing.length === 1 ? 'is' : 'are'} missing.`,\n '',\n 'Starting the guided migration. It shows every change before applying it.',\n `Skip it with ${NO_PROMPT_ENV}=true.`,\n '',\n ].join('\\n');\n}\n\nlet offerAttempted = false;\n\ntype ResolvedOfferDeps = Required<MigrationOfferDeps>;\n\nfunction withDefaults (deps: MigrationOfferDeps): ResolvedOfferDeps {\n return {\n env: deps.env ?? process.env,\n argv: deps.argv ?? process.argv,\n interactive: deps.interactive ?? defaultInteractive(),\n resolveCliEntry: deps.resolveCliEntry ?? resolveCliEntry,\n runCli: deps.runCli ?? defaultRunCli,\n warn: deps.warn ?? defaultWarn,\n };\n}\n\n/**\n * Offers the guided migration for an outdated layout and runs it when the consumer accepts. Declines\n * silently — returning a skip reason instead of prompting — whenever writing to stdout would be\n * wrong: under oxlint, in CI, without a TTY, or when already inside a migration.\n * @example\n * offerMigration(diagnoseLayout('/repo')).accepted; // true after the consumer confirmed\n */\nexport function offerMigration (\n diagnosis: LayoutDiagnosis,\n deps: MigrationOfferDeps = {}\n): MigrationOfferResult {\n const resolved = withDefaults(deps);\n\n if (offerAttempted) {\n return { offered: false, skipReason: 'already-offered' };\n }\n\n const skipReason = skipReasonFor(resolved.env, resolved.argv, resolved.interactive);\n\n if (skipReason) {\n return { offered: false, skipReason };\n }\n\n const entry = resolved.resolveCliEntry();\n\n if (!entry) {\n return { offered: false, skipReason: 'cli-not-found' };\n }\n\n offerAttempted = true;\n\n resolved.warn(outdatedNotice(diagnosis));\n\n const status = resolved.runCli(entry, MIGRATE_FROM_LINT_ARGS, diagnosis.directory, {\n ...resolved.env,\n [IN_FLIGHT_ENV]: 'true',\n });\n\n return { offered: true, accepted: status === 0 };\n}\n\n/** Clears the once-per-process latch {@link offerMigration} keeps, so a suite can exercise it twice. */\nexport function resetMigrationOffer (): void {\n offerAttempted = false;\n}\n\n/* v8 ignore start */\nif (import.meta.vitest) {\n const { afterEach, beforeEach, describe, test, expect, vi } = import.meta.vitest;\n const { mkdirSync, mkdtempSync, rmSync, writeFileSync } = await import('node:fs');\n const { tmpdir } = await import('node:os');\n\n const DIAGNOSIS: LayoutDiagnosis = {\n kind: 'unmigratedV3',\n directory: '/repo',\n lintModule: null,\n eslintConfig: 'eslint.config.js',\n oxlintConfig: null,\n missing: ['insider.lint.ts', 'oxlint.config.ts'],\n autoMigratable: true,\n };\n\n function harness (overrides: Partial<MigrationOfferDeps> = {}) {\n const runCli = vi.fn<(\n entry: string,\n args: readonly string[],\n cwd: string,\n env: NodeJS.ProcessEnv\n ) => number>().mockReturnValue(0);\n const warn = vi.fn<(message: string) => void>();\n const deps: MigrationOfferDeps = {\n env: {},\n argv: ['node', '/app/node_modules/.bin/eslint', '.'],\n interactive: true,\n resolveCliEntry: () => '/pkg/dist/cli.cjs',\n runCli,\n warn,\n ...overrides,\n };\n\n return { deps, runCli, warn };\n }\n\n beforeEach(() => {\n resetMigrationOffer();\n });\n\n afterEach(() => {\n resetMigrationOffer();\n vi.restoreAllMocks();\n });\n\n describe('detectLintHost', () => {\n test('recognizes the oxlint wrapper oxlint itself runs', () => {\n expect(detectLintHost([\n 'node',\n '/app/node_modules/oxlint/bin/oxlint',\n '--disable-nested-config',\n ])).toBe('oxlint');\n });\n\n test('recognizes the pnpm bin shim for oxlint', () => {\n expect(detectLintHost(['node', '/app/node_modules/.bin/oxlint'])).toBe('oxlint');\n });\n\n test('recognizes ESLint through its bin script', () => {\n expect(detectLintHost([\n 'node',\n '/app/node_modules/eslint/bin/eslint.js',\n '.',\n ])).toBe('eslint');\n });\n\n test('prefers oxlint when both binaries appear in argv', () => {\n expect(detectLintHost(['node', '/app/node_modules/oxlint/bin/oxlint', 'eslint'])).toBe('oxlint');\n });\n\n test('reports unknown for an unrelated host such as vitest', () => {\n expect(detectLintHost(['node', '/app/node_modules/.bin/vitest', 'run'])).toBe('unknown');\n });\n\n test('ignores argv[0], the node binary itself', () => {\n expect(detectLintHost(['/usr/bin/eslint'])).toBe('unknown');\n });\n });\n\n describe('offerMigration', () => {\n test('runs the migrator and reports acceptance', () => {\n const { deps, runCli, warn } = harness();\n const result = offerMigration(DIAGNOSIS, deps);\n\n expect(result).toStrictEqual({ offered: true, accepted: true });\n expect(runCli).toHaveBeenCalledWith(\n '/pkg/dist/cli.cjs',\n ['migrate', '--from-lint'],\n '/repo',\n { INSIDER_MIGRATION_IN_PROGRESS: 'true' }\n );\n expect(warn.mock.calls[0][0]).toContain('still uses the v3 single-file layout');\n });\n\n test('reports a declined migration as not accepted', () => {\n const { deps } = harness({ runCli: () => 1 });\n\n expect(offerMigration(DIAGNOSIS, deps)).toStrictEqual({ offered: true, accepted: false });\n });\n\n test('never prompts from the oxlint side, even on a TTY', () => {\n const { deps, runCli, warn } = harness({\n argv: ['node', '/app/node_modules/oxlint/bin/oxlint', '--disable-nested-config'],\n });\n\n expect(offerMigration(DIAGNOSIS, deps)).toStrictEqual({\n offered: false,\n skipReason: 'host-is-oxlint',\n });\n expect(runCli).not.toHaveBeenCalled();\n expect(warn).not.toHaveBeenCalled();\n });\n\n test('does not prompt in CI', () => {\n const { deps } = harness({ env: { CI: 'true' } });\n\n expect(offerMigration(DIAGNOSIS, deps).skipReason).toBe('running-in-ci');\n });\n\n test.each([{ VITEST: 'true' }, { NODE_ENV: 'test' }])('does not prompt under a test runner (%j)', env => {\n const { deps } = harness({ env });\n\n expect(offerMigration(DIAGNOSIS, deps).skipReason).toBe('running-under-test');\n });\n\n test('falls back to the real process env, which a suite run always marks as under test', () => {\n const { deps } = harness({ env: undefined });\n\n expect(offerMigration(DIAGNOSIS, deps).skipReason).toBe('running-under-test');\n });\n\n test('does not prompt without a TTY', () => {\n const { deps } = harness({ interactive: false });\n\n expect(offerMigration(DIAGNOSIS, deps).skipReason).toBe('no-tty');\n });\n\n test.each([OPT_OUT_ENV, NO_PROMPT_ENV])('does not prompt when %s is set', name => {\n const { deps } = harness({ env: { [name]: 'true' } });\n\n expect(offerMigration(DIAGNOSIS, deps).skipReason).toBe('suppressed');\n });\n\n test('does not prompt from inside a migration it started itself', () => {\n const { deps } = harness({ env: { [IN_FLIGHT_ENV]: 'true' } });\n\n expect(offerMigration(DIAGNOSIS, deps).skipReason).toBe('already-offered');\n });\n\n test('offers at most once per process', () => {\n const { deps, runCli } = harness();\n\n offerMigration(DIAGNOSIS, deps);\n\n expect(offerMigration(DIAGNOSIS, deps).skipReason).toBe('already-offered');\n expect(runCli).toHaveBeenCalledTimes(1);\n });\n\n test('skips without warning when the built CLI is absent', () => {\n const { deps, warn } = harness({ resolveCliEntry: () => null });\n\n expect(offerMigration(DIAGNOSIS, deps).skipReason).toBe('cli-not-found');\n expect(warn).not.toHaveBeenCalled();\n });\n\n test('leaves the latch free when it skipped, so a later promptable call still offers', () => {\n const oxlint = harness({ argv: ['node', '/app/node_modules/oxlint/bin/oxlint'] });\n\n offerMigration(DIAGNOSIS, oxlint.deps);\n\n const eslint = harness();\n\n expect(offerMigration(DIAGNOSIS, eslint.deps).offered).toBe(true);\n });\n\n test('falls back to the flat-config glob when the diagnosis named no config', () => {\n const { deps, warn } = harness();\n\n offerMigration({ ...DIAGNOSIS, eslintConfig: null }, deps);\n\n expect(warn.mock.calls[0][0])\n .toContain('eslint.config.* still uses the v3 single-file layout');\n expect(warn.mock.calls[0][0]).toContain(join(DIAGNOSIS.directory, 'eslint.config.*'));\n });\n\n test('names a single missing file in the singular', () => {\n const { deps, warn } = harness();\n\n offerMigration({ ...DIAGNOSIS, missing: ['insider.lint.ts'] }, deps);\n\n expect(warn.mock.calls[0][0]).toContain('insider.lint.ts is missing');\n });\n });\n\n describe('resolveCliEntry', () => {\n function makePackageTree (manifest: string | null, withCli: boolean): { root: string; start: string } {\n const root = mkdtempSync(join(tmpdir(), 'insider-offer-root-'));\n const start = join(root, 'src', 'utils');\n\n mkdirSync(start, { recursive: true });\n\n if (manifest !== null) {\n writeFileSync(join(root, 'package.json'), manifest, 'utf8');\n }\n\n if (withCli) {\n mkdirSync(join(root, 'dist'), { recursive: true });\n writeFileSync(join(root, 'dist', 'cli.cjs'), '', 'utf8');\n }\n\n return { root, start };\n }\n\n test('resolves the built CLI against the package root it walks up to', () => {\n const { root, start } = makePackageTree(`{\"name\":\"${PACKAGE_NAME}\"}`, true);\n\n expect(resolveCliEntry(start)).toBe(join(root, 'dist', 'cli.cjs'));\n });\n\n test('returns null when the package root carries no built CLI', () => {\n const { start } = makePackageTree(`{\"name\":\"${PACKAGE_NAME}\"}`, false);\n\n expect(resolveCliEntry(start)).toBeNull();\n });\n\n test('returns null when no manifest on the way up names this package', () => {\n const { start } = makePackageTree('{\"name\":\"some-consumer\"}', true);\n\n expect(resolveCliEntry(start)).toBeNull();\n });\n\n test('walks past an unparseable package.json instead of throwing', () => {\n const { start } = makePackageTree('{ not json', true);\n\n expect(resolveCliEntry(start)).toBeNull();\n });\n\n test('gives up after ten levels instead of walking all the way to the filesystem root', () => {\n const { root } = makePackageTree(`{\"name\":\"${PACKAGE_NAME}\"}`, true);\n const deepStart = join(root, ...Array.from({ length: 11 }, (_, index) => `level-${index}`));\n\n mkdirSync(deepStart, { recursive: true });\n\n expect(resolveCliEntry(deepStart)).toBeNull();\n });\n\n test('walks past a package.json that parses but declares no name', () => {\n const { root, start } = makePackageTree('{}', true);\n\n expect(existsSync(join(root, 'dist', 'cli.cjs'))).toBe(true);\n expect(resolveCliEntry(start)).toBeNull();\n });\n\n test('starts from this module\\'s own directory, not from the working directory', () => {\n const { root, start } = makePackageTree(`{\"name\":\"${PACKAGE_NAME}\"}`, true);\n\n vi.spyOn(process, 'cwd').mockReturnValue(start);\n\n expect(resolveCliEntry(start)).toBe(join(root, 'dist', 'cli.cjs'));\n expect(resolveCliEntry()).not.toBe(join(root, 'dist', 'cli.cjs'));\n });\n });\n\n describe('the dependencies offerMigration falls back to when none are injected', () => {\n function fakeCli (exitCode: number): string {\n const directory = mkdtempSync(join(tmpdir(), 'insider-offer-cli-'));\n const entry = join(directory, 'cli.cjs');\n\n writeFileSync(entry, `process.exit(${exitCode});\\n`, 'utf8');\n\n return entry;\n }\n\n function withTty<Result> (stdin: boolean, stdout: boolean, run: () => Result): Result {\n const original = { stdin: process.stdin.isTTY, stdout: process.stdout.isTTY };\n\n process.stdin.isTTY = stdin;\n process.stdout.isTTY = stdout;\n\n try {\n return run();\n } finally {\n process.stdin.isTTY = original.stdin;\n process.stdout.isTTY = original.stdout;\n }\n }\n\n test.each([\n { stdin: false, stdout: true },\n { stdin: true, stdout: false },\n ])('skips with no-tty when stdin is $stdin and stdout is $stdout', ({ stdin, stdout }) => {\n const { deps } = harness();\n const result = withTty(\n stdin,\n stdout,\n () => offerMigration(DIAGNOSIS, { ...deps, interactive: undefined })\n );\n\n expect(result.skipReason).toBe('no-tty');\n });\n\n test('offers when both of the real streams are a terminal', () => {\n const { deps } = harness();\n const result = withTty(\n true,\n true,\n () => offerMigration(DIAGNOSIS, { ...deps, interactive: undefined })\n );\n\n expect(result).toStrictEqual({ offered: true, accepted: true });\n });\n\n function withArgv<Result> (argv: readonly string[], run: () => Result): Result {\n const original = process.argv;\n\n process.argv = [...argv];\n\n try {\n return run();\n } finally {\n process.argv = original;\n }\n }\n\n test('skips with host-is-oxlint when the real process argv is the oxlint wrapper', () => {\n const { deps, runCli } = harness();\n const result = withArgv(\n ['node', '/app/node_modules/oxlint/bin/oxlint', '--disable-nested-config'],\n () => offerMigration(DIAGNOSIS, { ...deps, argv: undefined })\n );\n\n expect(result).toStrictEqual({ offered: false, skipReason: 'host-is-oxlint' });\n expect(runCli).not.toHaveBeenCalled();\n });\n\n test.each([\n { exitCode: 0, accepted: true },\n { exitCode: 3, accepted: false },\n ])('maps a real child exit of $exitCode to accepted=$accepted', ({ exitCode, accepted }) => {\n const entry = fakeCli(exitCode);\n const { deps } = harness({ runCli: undefined, resolveCliEntry: () => entry });\n const result = offerMigration({ ...DIAGNOSIS, directory: dirname(entry) }, deps);\n\n expect(result).toStrictEqual({ offered: true, accepted });\n });\n\n // A consumer who hits Ctrl-C mid-migration leaves `spawnSync` a `status` of null and a\n // `signal`, which is neither an exit code nor a spawn error.\n test('reports a migrator killed by a signal as not accepted', () => {\n const directory = mkdtempSync(join(tmpdir(), 'insider-offer-signal-'));\n const entry = join(directory, 'cli.cjs');\n const started = join(directory, 'started');\n const sentinel = join(directory, 'ran-past-the-signal');\n\n writeFileSync(entry, [\n 'const { writeFileSync } = require(\\'node:fs\\');',\n `writeFileSync(${JSON.stringify(started)}, 'started', 'utf8');`,\n 'process.kill(process.pid, \\'SIGKILL\\');',\n `writeFileSync(${JSON.stringify(sentinel)}, 'reached', 'utf8');`,\n '',\n ].join('\\n'), 'utf8');\n\n const { deps } = harness({ runCli: undefined, resolveCliEntry: () => entry });\n const result = offerMigration({ ...DIAGNOSIS, directory }, deps);\n\n expect(existsSync(started), 'the migrator never ran at all').toBe(true);\n expect(existsSync(sentinel), 'the child exited normally instead of dying by signal')\n .toBe(false);\n expect(result).toStrictEqual({ offered: true, accepted: false });\n });\n\n test('reports a child process that never started as not accepted', () => {\n const entry = fakeCli(0);\n const gone = mkdtempSync(join(tmpdir(), 'insider-offer-gone-'));\n\n rmSync(gone, { recursive: true, force: true });\n\n const { deps } = harness({ runCli: undefined, resolveCliEntry: () => entry });\n\n expect(offerMigration({ ...DIAGNOSIS, directory: gone }, deps))\n .toStrictEqual({ offered: true, accepted: false });\n });\n\n test('writes the notice to console.error when no warn sink is injected', () => {\n const spy = vi.spyOn(console, 'error').mockImplementation(() => undefined);\n const { deps } = harness();\n\n offerMigration(DIAGNOSIS, { ...deps, warn: undefined });\n\n expect(spy.mock.calls[0][0]).toContain('still uses the v3 single-file layout');\n });\n\n test('falls back to this module\\'s own resolveCliEntry when none is injected', () => {\n const builtCli = fileURLToPath(new URL('../../dist/cli.cjs', import.meta.url));\n const { deps, runCli } = harness({ resolveCliEntry: undefined });\n const result = offerMigration(DIAGNOSIS, deps);\n\n expect(result, `the default resolver must find ${builtCli}; build the package first`)\n .toStrictEqual({ offered: true, accepted: true });\n expect(runCli).toHaveBeenCalledWith(\n builtCli,\n ['migrate', '--from-lint'],\n '/repo',\n { INSIDER_MIGRATION_IN_PROGRESS: 'true' }\n );\n });\n });\n}\n","import { existsSync, readFileSync, realpathSync } from 'node:fs';\nimport { createRequire } from 'node:module';\nimport { dirname, resolve as resolvePath } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { AST_NODE_TYPES, type TSESTree } from '@typescript-eslint/types';\nimport {\n diagnoseLayout,\n ESLINT_CONFIG_FILENAMES,\n ESLINT_RENDERER_NAME,\n EXPECTED_LAYOUT,\n formatLayoutGuidance,\n INSIDER_IMPORT_SOURCE,\n type LayoutDiagnosis,\n LINT_MODULE_FILENAMES,\n OPT_OUT_ENV,\n OXC_RENDERER_NAME,\n RENDERER_EXPORT,\n TARGET_CALLEE_NAME,\n} from './layoutDiagnosis';\nimport { offerMigration } from './offerMigration';\n\nexport interface ConfigStructureViolation {\n line: number;\n column: number;\n reason: string;\n}\n\nexport interface ValidateProgramStructureOptions {\n isInsiderImportSource?: (source: string, configPath: string) => boolean;\n expectedCallee?: string;\n}\n\nconst ANCHOR_FILE_REGEX = /(?:insider\\.lint|eslint\\.config)\\.[mc]?[jt]s(?:$|\\?)/;\nconst FILE_URL_PREFIX = 'file://';\n\nexport { ESLINT_CONFIG_FILENAMES, LINT_MODULE_FILENAMES };\n\nlet bypassWarnEmitted = false;\n\nfunction computeSelfModulePath (): string {\n const raw = fileURLToPath(import.meta.url);\n\n try {\n return realpathSync(raw);\n } catch {\n return raw;\n }\n}\n\nconst SELF_MODULE_PATH = computeSelfModulePath();\n\nfunction isPathSpecifier (source: string): boolean {\n return source.startsWith('.') || source.startsWith('/');\n}\n\nexport function defaultIsInsiderImportSource (source: string, configPath: string): boolean {\n if (source === INSIDER_IMPORT_SOURCE) {\n return true;\n }\n\n if (!configPath || !isPathSpecifier(source)) {\n return false;\n }\n\n try {\n const absolute = resolvePath(dirname(configPath), source);\n const canonical = realpathSync(absolute);\n\n return canonical === SELF_MODULE_PATH;\n } catch {\n return false;\n }\n}\n\nfunction locOf (node: TSESTree.Node): { line: number; column: number } {\n return { line: node.loc.start.line, column: node.loc.start.column };\n}\n\nfunction validateCallExpression (\n callExpr: TSESTree.CallExpression,\n expectedCallee: string\n): ConfigStructureViolation[] {\n const { callee } = callExpr;\n\n if (callee.type !== AST_NODE_TYPES.Identifier || callee.name !== expectedCallee) {\n return [{\n ...locOf(callExpr),\n reason: `Default export must call \\`${expectedCallee}(...)\\` directly.`,\n }];\n }\n\n return [];\n}\n\nfunction validateExportedCall (\n callee: TSESTree.Expression,\n fallbackLoc: { line: number; column: number },\n expectedCallee: string\n): ConfigStructureViolation[] {\n let target: TSESTree.Expression = callee;\n\n if (target.type === AST_NODE_TYPES.AwaitExpression) {\n target = target.argument;\n }\n\n if (target.type === AST_NODE_TYPES.CallExpression) {\n return validateCallExpression(target, expectedCallee);\n }\n\n if (target.type === AST_NODE_TYPES.ArrayExpression) {\n return [{\n ...locOf(target),\n reason: `Default export must not wrap \\`${expectedCallee}(...)\\` in an array.`,\n }];\n }\n\n const isGated = target.type === AST_NODE_TYPES.LogicalExpression\n || target.type === AST_NODE_TYPES.ConditionalExpression;\n\n if (isGated) {\n const reason = [\n `Default export must not gate \\`${expectedCallee}(...)\\` behind a logical/conditional expression.`,\n 'Use the typed options object instead.',\n ].join(' ');\n\n return [{ ...locOf(target), reason }];\n }\n\n return [{\n ...fallbackLoc,\n reason: `Default export must be a direct call to \\`${expectedCallee}(...)\\`.`,\n }];\n}\n\ninterface IgnoreClassification {\n type: 'ignore';\n}\n\ninterface ExportClassification {\n type: 'export';\n violations: ConfigStructureViolation[];\n}\n\ninterface DuplicateExportClassification {\n type: 'duplicateExport';\n violation: ConfigStructureViolation;\n}\n\ninterface DisallowedClassification {\n type: 'disallowed';\n violation: ConfigStructureViolation;\n}\n\ntype StatementClassification = DisallowedClassification | DuplicateExportClassification | ExportClassification | IgnoreClassification; // eslint-disable-line @stylistic/max-len -- type alias union; splitting hits operator-linebreak rule.\n\nfunction collectInsiderBindings (\n node: TSESTree.ImportDeclaration,\n bindings: Set<string>,\n isInsiderSource: (source: string) => boolean\n): void {\n if (!isInsiderSource(node.source.value)) {\n return;\n }\n\n node.specifiers.forEach(specifier => {\n bindings.add(specifier.local.name);\n });\n}\n\nfunction classifyExpressionStatement (\n node: TSESTree.ExpressionStatement,\n insiderBindings: ReadonlySet<string>\n): StatementClassification {\n const { expression } = node;\n const isInsiderCall = expression.type === AST_NODE_TYPES.CallExpression\n && expression.callee.type === AST_NODE_TYPES.Identifier\n && insiderBindings.has(expression.callee.name);\n\n if (isInsiderCall) {\n return { type: 'ignore' };\n }\n\n const reason = [\n 'Disallowed top-level statement `ExpressionStatement`.',\n `Only call expressions whose callee was imported from \\`${INSIDER_IMPORT_SOURCE}\\` are allowed at top level.`,\n ].join(' ');\n\n return {\n type: 'disallowed',\n violation: { ...locOf(node), reason },\n };\n}\n\nfunction classifyStatement (\n node: TSESTree.ProgramStatement,\n exportSeen: boolean,\n insiderBindings: ReadonlySet<string>,\n expectedCallee: string\n): StatementClassification {\n if (node.type === AST_NODE_TYPES.ImportDeclaration || node.type === AST_NODE_TYPES.VariableDeclaration) {\n return { type: 'ignore' };\n }\n\n if (node.type === AST_NODE_TYPES.ExpressionStatement) {\n return classifyExpressionStatement(node, insiderBindings);\n }\n\n if (node.type === AST_NODE_TYPES.ExportDefaultDeclaration) {\n if (exportSeen) {\n return {\n type: 'duplicateExport',\n violation: { ...locOf(node), reason: 'Only one default export is allowed.' },\n };\n }\n\n const declaration = node.declaration as TSESTree.Expression;\n\n return { type: 'export', violations: validateExportedCall(declaration, locOf(node), expectedCallee) };\n }\n\n const reason = [\n `Disallowed top-level statement \\`${node.type}\\`.`,\n 'Only imports, variable declarations, helper calls from `@useinsider/eslint-config`,',\n `and one \\`export default ${expectedCallee}()\\` are allowed.`,\n ].join(' ');\n\n return {\n type: 'disallowed',\n violation: { ...locOf(node), reason },\n };\n}\n\nexport function validateProgramStructure (\n program: TSESTree.Program,\n configPath = '',\n options: ValidateProgramStructureOptions = {}\n): ConfigStructureViolation[] {\n const violations: ConfigStructureViolation[] = [];\n const insiderBindings = new Set<string>();\n const resolver = options.isInsiderImportSource ?? defaultIsInsiderImportSource;\n const isInsiderSource = (source: string): boolean => resolver(source, configPath);\n const expectedCallee = options.expectedCallee ?? ESLINT_RENDERER_NAME;\n let exportSeen = false;\n\n program.body.forEach(node => {\n if (node.type === AST_NODE_TYPES.ImportDeclaration) {\n collectInsiderBindings(node, insiderBindings, isInsiderSource);\n }\n\n const result = classifyStatement(node, exportSeen, insiderBindings, expectedCallee);\n\n if (result.type === 'ignore') {\n return;\n }\n\n if (result.type === 'export') {\n exportSeen = true;\n violations.push(...result.violations);\n\n return;\n }\n\n violations.push(result.violation);\n });\n\n if (!exportSeen) {\n violations.push({\n line: 1,\n column: 0,\n reason: `Missing \\`export default ${options.expectedCallee ?? ESLINT_RENDERER_NAME}()\\`.`,\n });\n }\n\n return violations;\n}\n\nfunction validateRendererPattern (pattern: TSESTree.ObjectPattern): ConfigStructureViolation[] {\n const bound = new Set<string>();\n const violations: ConfigStructureViolation[] = [];\n\n pattern.properties.forEach(property => {\n if (property.type !== AST_NODE_TYPES.Property || property.computed || !property.shorthand) {\n violations.push({\n ...locOf(property),\n reason: `Destructure \\`${ESLINT_RENDERER_NAME}\\` and \\`${OXC_RENDERER_NAME}\\` by name,`\n + ' without renaming or spreading.',\n });\n\n return;\n }\n\n bound.add((property.key as TSESTree.Identifier).name);\n });\n\n [ESLINT_RENDERER_NAME, OXC_RENDERER_NAME].forEach(name => {\n if (!bound.has(name)) {\n violations.push({\n ...locOf(pattern),\n reason: `Missing \\`${name}\\` in the destructured \\`${TARGET_CALLEE_NAME}(...)\\` result.`,\n });\n }\n });\n\n return violations;\n}\n\nfunction validateRendererExport (node: TSESTree.ExportNamedDeclaration): ConfigStructureViolation[] {\n const { declaration } = node;\n\n if (!declaration || declaration.type !== AST_NODE_TYPES.VariableDeclaration || declaration.kind !== 'const') {\n return [{\n ...locOf(node),\n reason: `Renderer export must be \\`${RENDERER_EXPORT};\\`.`,\n }];\n }\n\n if (declaration.declarations.length !== 1) {\n return [{\n ...locOf(declaration),\n reason: 'Renderer export must declare exactly one binding.',\n }];\n }\n\n const [declarator] = declaration.declarations;\n\n if (declarator.id.type !== AST_NODE_TYPES.ObjectPattern) {\n return [{\n ...locOf(declarator.id),\n reason: `Renderer export must destructure \\`${ESLINT_RENDERER_NAME}\\` and \\`${OXC_RENDERER_NAME}\\`.`,\n }];\n }\n\n const patternViolations = validateRendererPattern(declarator.id);\n const { init } = declarator;\n\n if (!init) {\n return [...patternViolations, {\n ...locOf(declarator),\n reason: `Renderer export must be initialized by a direct \\`${TARGET_CALLEE_NAME}(...)\\` call.`,\n }];\n }\n\n return [...patternViolations, ...validateExportedCall(init, locOf(declarator), TARGET_CALLEE_NAME)];\n}\n\nfunction classifyLintModuleStatement (\n node: TSESTree.ProgramStatement,\n exportSeen: boolean,\n insiderBindings: ReadonlySet<string>\n): StatementClassification {\n if (node.type === AST_NODE_TYPES.ImportDeclaration || node.type === AST_NODE_TYPES.VariableDeclaration) {\n return { type: 'ignore' };\n }\n\n if (node.type === AST_NODE_TYPES.ExpressionStatement) {\n return classifyExpressionStatement(node, insiderBindings);\n }\n\n if (node.type === AST_NODE_TYPES.ExportNamedDeclaration) {\n if (exportSeen) {\n return {\n type: 'duplicateExport',\n violation: { ...locOf(node), reason: 'Only one export is allowed.' },\n };\n }\n\n return { type: 'export', violations: validateRendererExport(node) };\n }\n\n const reason = [\n `Disallowed top-level statement \\`${node.type}\\`.`,\n 'Only imports, variable declarations, helper calls from `@useinsider/eslint-config`,',\n `and one \\`${RENDERER_EXPORT}\\` are allowed.`,\n ].join(' ');\n\n return {\n type: 'disallowed',\n violation: { ...locOf(node), reason },\n };\n}\n\nexport function validateLintModuleStructure (\n program: TSESTree.Program,\n configPath = '',\n options: ValidateProgramStructureOptions = {}\n): ConfigStructureViolation[] {\n const violations: ConfigStructureViolation[] = [];\n const insiderBindings = new Set<string>();\n const resolver = options.isInsiderImportSource ?? defaultIsInsiderImportSource;\n const isInsiderSource = (source: string): boolean => resolver(source, configPath);\n let exportSeen = false;\n\n program.body.forEach(node => {\n if (node.type === AST_NODE_TYPES.ImportDeclaration) {\n collectInsiderBindings(node, insiderBindings, isInsiderSource);\n }\n\n const result = classifyLintModuleStatement(node, exportSeen, insiderBindings);\n\n if (result.type === 'ignore') {\n return;\n }\n\n if (result.type === 'export') {\n exportSeen = true;\n violations.push(...result.violations);\n\n return;\n }\n\n violations.push(result.violation);\n });\n\n if (!exportSeen) {\n violations.push({\n line: 1,\n column: 0,\n reason: `Missing \\`${RENDERER_EXPORT};\\`.`,\n });\n }\n\n return violations;\n}\n\ninterface CallSiteLike {\n getFileName: (this: void) => string | null;\n}\n\nfunction readStackFrames (): readonly CallSiteLike[] {\n // eslint-disable-next-line @typescript-eslint/unbound-method -- Error.prepareStackTrace is a value slot, not a method call.\n const original = Error.prepareStackTrace;\n\n Error.prepareStackTrace = (_, frames) => frames;\n\n const holder: { stack?: unknown } = {};\n\n Error.captureStackTrace(holder, readStackFrames);\n\n const { stack } = holder;\n\n Error.prepareStackTrace = original;\n\n if (!Array.isArray(stack)) {\n return [];\n }\n\n return stack as readonly CallSiteLike[];\n}\n\nfunction normalizeFrameFilename (raw: string | null): string | null {\n if (!raw) {\n return null;\n }\n\n const withoutPrefix = raw.startsWith(FILE_URL_PREFIX) ? raw.slice(FILE_URL_PREFIX.length) : raw;\n const queryIndex = withoutPrefix.indexOf('?');\n\n return queryIndex === -1 ? withoutPrefix : withoutPrefix.slice(0, queryIndex);\n}\n\nfunction extractMatchesFromStack (frames: readonly CallSiteLike[]): string[] {\n const matches = new Set<string>();\n\n frames.forEach(frame => {\n const name = normalizeFrameFilename(frame.getFileName());\n\n if (name && ANCHOR_FILE_REGEX.test(name)) {\n matches.add(name);\n }\n });\n\n return Array.from(matches);\n}\n\nfunction argvCandidateAt (argv: readonly string[], index: number): string | null {\n const arg = argv[index];\n\n if (arg === '--config' || arg === '-c') {\n return argv[index + 1] ?? null;\n }\n\n if (arg.startsWith('--config=')) {\n return arg.slice('--config='.length);\n }\n\n return null;\n}\n\nfunction extractConfigFromArgv (argv: readonly string[]): string | null {\n for (let i = 0; i < argv.length; i += 1) {\n const candidate = argvCandidateAt(argv, i);\n\n if (candidate && ANCHOR_FILE_REGEX.test(candidate)) {\n return candidate;\n }\n }\n\n return null;\n}\n\nconst LINT_MODULE_REGEX = /insider\\.lint\\.[mc]?[jt]s(?:$|\\?)/;\n\nexport function getConsumerConfigPath (\n frames: readonly CallSiteLike[] = readStackFrames(),\n argv: readonly string[] = process.argv\n): string | null {\n const stackMatches = extractMatchesFromStack(frames);\n\n if (stackMatches.length === 1) {\n return stackMatches[0];\n }\n\n // `insider.lint.*` is the module that calls useInsider(), so when both it and the ESLint config\n // are on the stack it is the more precise anchor.\n const lintModules = stackMatches.filter(match => LINT_MODULE_REGEX.test(match));\n\n if (lintModules.length === 1) {\n return lintModules[0];\n }\n\n const fromArgv = extractConfigFromArgv(argv);\n\n if (fromArgv) {\n return fromArgv;\n }\n\n return null;\n}\n\nlet consumerConfigDir: string | null = null;\n\n// getConsumerConfigPath() reads the live stack, so the consumer's config frame is only visible\n// while useInsider() is still synchronous. Capture the directory here and let later async work\n// read it back instead of resolving again.\nexport function captureConsumerConfigDir (configPath: string | null): void {\n consumerConfigDir = configPath === null ? null : dirname(resolvePath(configPath));\n}\n\n/**\n * Directory holding the consumer's `insider.lint.*` module and its sibling linter configs, captured\n * by {@link ensureConfigStructure}. This is the anchor `tsconfigPaths` entries are written against,\n * and where {@link import('./ensureOxlintConfig').ensureOxlintConfig} looks for the oxlint config;\n * it falls back to `process.cwd()` when the module could not be located.\n * @example\n * // consumer module at /repo/insider.lint.ts, `eslint` launched from /repo/app\n * getConsumerConfigDir(); // '/repo'\n */\nexport function getConsumerConfigDir (): string {\n return consumerConfigDir ?? process.cwd();\n}\n\nfunction formatReport (configPath: string, violations: readonly ConfigStructureViolation[]): string {\n const header = [\n '@useinsider/eslint-config: protected configuration structure violated in:',\n ` ${configPath}`,\n ].join('\\n');\n const lines = violations.map(violation => ` - [${violation.line}:${violation.column}] ${violation.reason}`);\n const footer = [\n '',\n 'Alongside the export, only import statements, const/let/var declarations and helper calls',\n 'imported from `@useinsider/eslint-config` are allowed.',\n '',\n EXPECTED_LAYOUT,\n '',\n `Emergency bypass: set ${OPT_OUT_ENV}=true (do not commit).`,\n ].join('\\n');\n\n return `${header}\\n${lines.join('\\n')}\\n${footer}`;\n}\n\nfunction emitBypassWarning (): void {\n if (bypassWarnEmitted) {\n return;\n }\n\n bypassWarnEmitted = true;\n\n const message = [\n '@useinsider/eslint-config: structure validation BYPASSED',\n 'via INSIDER_SKIP_CONFIG_VALIDATION — emergency use only.',\n ].join(' ');\n\n // oxlint-disable-next-line no-console -- diagnostic surface, mirrors ensureDependencies.ts.\n console.warn(message);\n}\n\nclass ConfigStructureExit extends Error {}\n\nfunction fail (message: string): never {\n // oxlint-disable-next-line no-console -- diagnostic surface, mirrors ensureDependencies.ts.\n console.error(message);\n\n const exit: (code: number) => void = process.exit.bind(process);\n\n exit(1);\n\n throw new ConfigStructureExit(message);\n}\n\nfunction readConsumerSource (configPath: string): string {\n try {\n return readFileSync(configPath, 'utf8');\n } catch (readError) {\n const { message } = readError as Error;\n\n return fail(`@useinsider/eslint-config: failed to read consumer config at ${configPath}: ${message}`);\n }\n}\n\nconst lazyRequire = createRequire(import.meta.url);\n\nfunction loadParser (): typeof import('@typescript-eslint/parser').parse {\n const mod = lazyRequire('@typescript-eslint/parser') as typeof import('@typescript-eslint/parser');\n\n return mod.parse;\n}\n\nfunction parseConsumerSource (configPath: string, source: string): TSESTree.Program {\n const parse = loadParser();\n\n try {\n return parse(source, { sourceType: 'module', range: true, loc: true });\n } catch (parseError) {\n const { message } = parseError as Error;\n\n return fail(`@useinsider/eslint-config: failed to parse consumer config at ${configPath}: ${message}`);\n }\n}\n\ntype Validator = (\n program: TSESTree.Program,\n configPath: string,\n options: ValidateProgramStructureOptions\n) => ConfigStructureViolation[];\n\nfunction resolveSibling (directory: string, filenames: readonly string[]): string | null {\n const found = filenames.find(filename => existsSync(resolvePath(directory, filename)));\n\n return found ? resolvePath(directory, found) : null;\n}\n\nfunction validateFile (\n filePath: string,\n validator: Validator,\n options: ValidateProgramStructureOptions\n): void {\n const source = readConsumerSource(filePath);\n const program = parseConsumerSource(filePath, source);\n const violations = validator(program, filePath, options);\n\n if (violations.length === 0) {\n return;\n }\n\n fail(formatReport(filePath, violations));\n}\n\nconst MIGRATED_EXIT_NOTICE = [\n '@useinsider/eslint-config: migration finished.',\n '',\n 'Re-run your lint command. This process already loaded the old configuration, so continuing now',\n 'would lint against a config that no longer exists on disk.',\n].join('\\n');\n\nconst DECLINED_DETAIL: readonly string[] = [\n 'The guided migration was not completed, so nothing was written.',\n];\n\nexport interface RunValidationDeps {\n diagnose?: (directory: string) => LayoutDiagnosis;\n offer?: typeof offerMigration;\n}\n\nfunction failWithGuidance (\n headline: string,\n diagnosis: LayoutDiagnosis,\n detail?: readonly string[]\n): never {\n return fail(formatLayoutGuidance({ headline, diagnosis, detail }));\n}\n\n// The offer runs the migrator in a child process that rewrites the very files this process already\n// imported, so there is no continuing after it: exit non-zero either way and let the consumer re-run.\nfunction handleOutdatedLayout (\n headline: string,\n diagnosis: LayoutDiagnosis,\n offer: typeof offerMigration\n): never {\n if (!diagnosis.autoMigratable) {\n return failWithGuidance(headline, diagnosis);\n }\n\n const outcome = offer(diagnosis);\n\n if (!outcome.offered) {\n return failWithGuidance(headline, diagnosis);\n }\n\n if (!outcome.accepted) {\n return failWithGuidance(headline, diagnosis, DECLINED_DETAIL);\n }\n\n return fail(MIGRATED_EXIT_NOTICE);\n}\n\nfunction runValidation (anchorPath: string | null, deps: RunValidationDeps = {}): void {\n const diagnose = deps.diagnose ?? ((directory: string) => diagnoseLayout(directory));\n const offer = deps.offer ?? offerMigration;\n\n if (!anchorPath) {\n handleOutdatedLayout(\n 'unable to locate the consumer `insider.lint.*` module for structure validation.',\n diagnose(process.cwd()),\n offer\n );\n }\n\n const directory = dirname(resolvePath(anchorPath));\n const lintModulePath = resolveSibling(directory, LINT_MODULE_FILENAMES);\n\n if (!lintModulePath) {\n handleOutdatedLayout(\n `no \\`insider.lint.*\\` module found in ${directory}.`,\n diagnose(directory),\n offer\n );\n }\n\n validateFile(lintModulePath, validateLintModuleStructure, {});\n\n const eslintConfigPath = resolveSibling(directory, ESLINT_CONFIG_FILENAMES);\n\n if (!eslintConfigPath) {\n failWithGuidance(\n `no \\`eslint.config.*\\` file found in ${directory}.`,\n diagnose(directory),\n [\n `\\`${TARGET_CALLEE_NAME}()\\` returns renderers, not a flat-config array, so ESLint still`,\n `needs a config file whose default export is \\`${ESLINT_RENDERER_NAME}()\\`.`,\n ]\n );\n }\n\n validateFile(eslintConfigPath, validateProgramStructure, { expectedCallee: ESLINT_RENDERER_NAME });\n}\n\nexport function ensureConfigStructure (\n overridePath?: string | null,\n deps: RunValidationDeps = {}\n): void {\n const configPath = overridePath === undefined ? getConsumerConfigPath() : overridePath;\n\n captureConsumerConfigDir(configPath);\n\n if (process.env[OPT_OUT_ENV] === 'true') {\n emitBypassWarning();\n\n return;\n }\n\n try {\n runValidation(configPath, deps);\n } catch (error) {\n if (error instanceof ConfigStructureExit) {\n return;\n }\n\n throw error;\n }\n}\n\n/* v8 ignore start */\nif (import.meta.vitest) {\n const { afterEach, describe, test, expect, vi } = import.meta.vitest;\n\n function parseSource (source: string): TSESTree.Program {\n return loadParser()(source, { sourceType: 'module', range: true, loc: true });\n }\n\n const LINT_MODULE_IMPORT = \"import { useInsider } from '@useinsider/eslint-config';\";\n const RENDERER_EXPORT_SOURCE = 'export const { useInsiderESLint, useInsiderOXC } = useInsider({});';\n const ESLINT_CONFIG_IMPORT = \"import { useInsiderESLint } from './insider.lint.js';\";\n\n describe('validateLintModuleStructure', () => {\n test('accepts the canonical renderer export', () => {\n const program = parseSource([LINT_MODULE_IMPORT, RENDERER_EXPORT_SOURCE].join('\\n'));\n\n expect(validateLintModuleStructure(program)).toStrictEqual([]);\n });\n\n test('accepts declarations and insider helper calls alongside the export', () => {\n const program = parseSource([\n \"import { silenceDependencyWarning, useInsider } from '@useinsider/eslint-config';\",\n \"const files = ['**/*.ts'];\",\n 'silenceDependencyWarning(true);',\n 'export const { useInsiderESLint, useInsiderOXC } = useInsider({ typescript: [{ files }] });',\n ].join('\\n'));\n\n expect(validateLintModuleStructure(program)).toStrictEqual([]);\n });\n\n test('rejects a wrapped useInsider call', () => {\n const program = parseSource([\n LINT_MODULE_IMPORT,\n 'export const { useInsiderESLint, useInsiderOXC } = wrap(useInsider({}));',\n ].join('\\n'));\n const violations = validateLintModuleStructure(program);\n\n expect(violations).toHaveLength(1);\n expect(violations[0].reason).toMatch(/must call `useInsider\\(\\.\\.\\.\\)` directly/);\n });\n\n test('rejects an array-wrapped useInsider call', () => {\n const program = parseSource([\n LINT_MODULE_IMPORT,\n 'export const { useInsiderESLint, useInsiderOXC } = [useInsider({})];',\n ].join('\\n'));\n const violations = validateLintModuleStructure(program);\n\n expect(violations).toHaveLength(1);\n expect(violations[0].reason).toMatch(/must not wrap `useInsider\\(\\.\\.\\.\\)` in an array/);\n });\n\n test('rejects gating the call behind a conditional', () => {\n const program = parseSource([\n LINT_MODULE_IMPORT,\n 'export const { useInsiderESLint, useInsiderOXC } = flag ? useInsider({}) : useInsider({});',\n ].join('\\n'));\n const violations = validateLintModuleStructure(program);\n\n expect(violations).toHaveLength(1);\n expect(violations[0].reason).toMatch(/must not gate `useInsider\\(\\.\\.\\.\\)`/);\n });\n\n test('rejects renaming a renderer in the destructuring pattern', () => {\n const program = parseSource([\n LINT_MODULE_IMPORT,\n 'export const { useInsiderESLint: renderer, useInsiderOXC } = useInsider({});',\n ].join('\\n'));\n const reasons = validateLintModuleStructure(program).map(violation => violation.reason);\n\n expect(reasons).toContain(\n 'Destructure `useInsiderESLint` and `useInsiderOXC` by name, without renaming or spreading.'\n );\n expect(reasons.some(reason => /Missing `useInsiderESLint`/.test(reason))).toBe(true);\n });\n\n test('rejects a rest element in the destructuring pattern', () => {\n const program = parseSource([\n LINT_MODULE_IMPORT,\n 'export const { useInsiderESLint, ...rest } = useInsider({});',\n ].join('\\n'));\n const reasons = validateLintModuleStructure(program).map(violation => violation.reason);\n\n expect(reasons.some(reason => /without renaming or spreading/.test(reason))).toBe(true);\n });\n\n test('rejects an export that omits useInsiderOXC', () => {\n const program = parseSource([\n LINT_MODULE_IMPORT,\n 'export const { useInsiderESLint } = useInsider({});',\n ].join('\\n'));\n const violations = validateLintModuleStructure(program);\n\n expect(violations).toHaveLength(1);\n expect(violations[0].reason).toMatch(/Missing `useInsiderOXC`/);\n });\n\n test('rejects a non-destructured binding', () => {\n const program = parseSource([\n LINT_MODULE_IMPORT,\n 'export const renderers = useInsider({});',\n ].join('\\n'));\n const violations = validateLintModuleStructure(program);\n\n expect(violations).toHaveLength(1);\n expect(violations[0].reason).toMatch(/must destructure `useInsiderESLint` and `useInsiderOXC`/);\n });\n\n test('rejects `let` and `var` renderer exports', () => {\n ['let', 'var'].forEach(kind => {\n const program = parseSource([\n LINT_MODULE_IMPORT,\n `export ${kind} { useInsiderESLint, useInsiderOXC } = useInsider({});`,\n ].join('\\n'));\n const violations = validateLintModuleStructure(program);\n\n expect(violations[0].reason).toMatch(/Renderer export must be `export const/);\n });\n });\n\n test('rejects a sole export that declares nothing, such as a bare binding list', () => {\n const program = parseSource([\n LINT_MODULE_IMPORT,\n 'const useInsiderESLint = 1;',\n 'const useInsiderOXC = 2;',\n 'export { useInsiderESLint, useInsiderOXC };',\n ].join('\\n'));\n const violations = validateLintModuleStructure(program);\n\n expect(violations).toHaveLength(1);\n expect(violations[0].reason).toMatch(/Renderer export must be `export const/);\n });\n\n test('rejects an export declaring more than one binding', () => {\n const program = parseSource([\n LINT_MODULE_IMPORT,\n 'export const { useInsiderESLint, useInsiderOXC } = useInsider({}), extra = 1;',\n ].join('\\n'));\n const violations = validateLintModuleStructure(program);\n\n expect(violations).toHaveLength(1);\n expect(violations[0].reason).toMatch(/exactly one binding/);\n });\n\n test('rejects a re-export with no declaration', () => {\n const program = parseSource([\n LINT_MODULE_IMPORT,\n RENDERER_EXPORT_SOURCE,\n \"export { something } from './elsewhere.js';\",\n ].join('\\n'));\n const reasons = validateLintModuleStructure(program).map(violation => violation.reason);\n\n expect(reasons).toContain('Only one export is allowed.');\n });\n\n test('rejects a default export', () => {\n const program = parseSource([LINT_MODULE_IMPORT, 'export default useInsider({});'].join('\\n'));\n const reasons = validateLintModuleStructure(program).map(violation => violation.reason);\n\n expect(reasons.some(reason => /Disallowed top-level statement `ExportDefaultDeclaration`/.test(reason)))\n .toBe(true);\n });\n\n test('rejects a top-level call that did not come from the package', () => {\n const program = parseSource([\n LINT_MODULE_IMPORT,\n \"console.log('boot');\",\n RENDERER_EXPORT_SOURCE,\n ].join('\\n'));\n const reasons = validateLintModuleStructure(program).map(violation => violation.reason);\n\n expect(reasons.some(reason => /Disallowed top-level statement `ExpressionStatement`/.test(reason)))\n .toBe(true);\n });\n\n test('reports a missing renderer export', () => {\n const program = parseSource([LINT_MODULE_IMPORT, \"const files = ['a'];\"].join('\\n'));\n const violations = validateLintModuleStructure(program);\n\n expect(violations).toHaveLength(1);\n expect(violations[0].reason)\n .toBe('Missing `export const { useInsiderESLint, useInsiderOXC } = useInsider({ ... });`.');\n });\n\n test('rejects an uninitialized renderer export', () => {\n const program = parseSource([\n LINT_MODULE_IMPORT,\n 'export const { useInsiderESLint, useInsiderOXC };',\n ].join('\\n'));\n const reasons = validateLintModuleStructure(program).map(violation => violation.reason);\n\n expect(reasons).toStrictEqual([\n 'Renderer export must be initialized by a direct `useInsider(...)` call.',\n ]);\n });\n\n test('resolves insider bindings through a self-relative import', () => {\n const acceptSelfRelative = (source: string, configPath: string): boolean => source === INSIDER_IMPORT_SOURCE\n || (configPath === '/repo/insider.lint.ts' && source === './dist/main.js');\n const program = parseSource([\n \"import { useInsider, silenceDependencyWarning } from './dist/main.js';\",\n 'silenceDependencyWarning(true);',\n RENDERER_EXPORT_SOURCE,\n ].join('\\n'));\n\n expect(validateLintModuleStructure(program, '/repo/insider.lint.ts', {\n isInsiderImportSource: acceptSelfRelative,\n })).toStrictEqual([]);\n });\n });\n\n describe('validateProgramStructure', () => {\n test('accepts `export default useInsiderESLint()`', () => {\n const program = parseSource([ESLINT_CONFIG_IMPORT, 'export default useInsiderESLint();'].join('\\n'));\n\n expect(validateProgramStructure(program)).toStrictEqual([]);\n });\n\n test('accepts `export default await useInsiderESLint()`', () => {\n const program = parseSource([\n ESLINT_CONFIG_IMPORT,\n 'export default await useInsiderESLint();',\n ].join('\\n'));\n\n expect(validateProgramStructure(program)).toStrictEqual([]);\n });\n\n test('accepts let / var declarations alongside const', () => {\n const program = parseSource([\n ESLINT_CONFIG_IMPORT,\n 'let a = 1;',\n 'var b = 2;',\n 'const c = 3;',\n 'export default useInsiderESLint();',\n ].join('\\n'));\n\n expect(validateProgramStructure(program)).toStrictEqual([]);\n });\n\n test('rejects the removed v3 shape where the config itself calls useInsider', () => {\n const program = parseSource([\n \"import { useInsider } from '@useinsider/eslint-config';\",\n 'export default useInsider({});',\n ].join('\\n'));\n const violations = validateProgramStructure(program);\n\n expect(violations).toHaveLength(1);\n expect(violations[0].reason).toBe('Default export must call `useInsiderESLint(...)` directly.');\n });\n\n test('rejects a spread sibling around the renderer call', () => {\n const program = parseSource([\n ESLINT_CONFIG_IMPORT,\n 'export default [...useInsiderESLint(), { rules: {} }];',\n ].join('\\n'));\n const violations = validateProgramStructure(program);\n\n expect(violations).toHaveLength(1);\n expect(violations[0].reason).toMatch(/must not wrap `useInsiderESLint\\(\\.\\.\\.\\)` in an array/);\n });\n\n test('rejects array wrapping', () => {\n const program = parseSource([\n ESLINT_CONFIG_IMPORT,\n 'export default [useInsiderESLint()];',\n ].join('\\n'));\n\n expect(validateProgramStructure(program)).toHaveLength(1);\n });\n\n test('rejects logical and conditional gating', () => {\n ['export default flag && useInsiderESLint();', 'export default flag ? useInsiderESLint() : [];']\n .forEach(line => {\n const program = parseSource([ESLINT_CONFIG_IMPORT, line].join('\\n'));\n const violations = validateProgramStructure(program);\n\n expect(violations).toHaveLength(1);\n expect(violations[0].reason).toMatch(/must not gate `useInsiderESLint\\(\\.\\.\\.\\)`/);\n });\n });\n\n test('rejects an extra top-level statement when the callee is not from the package', () => {\n const program = parseSource([\n ESLINT_CONFIG_IMPORT,\n \"console.log('boot');\",\n 'export default useInsiderESLint();',\n ].join('\\n'));\n const violations = validateProgramStructure(program);\n\n expect(violations).toHaveLength(1);\n expect(violations[0].reason).toMatch(/Disallowed top-level statement `ExpressionStatement`/);\n });\n\n test('accepts top-level insider helper calls', () => {\n ['silenceDependencyWarning(true);', \"silenceRules(['no-console']);\"].forEach(line => {\n const program = parseSource([\n \"import { silenceDependencyWarning, silenceRules } from '@useinsider/eslint-config';\",\n ESLINT_CONFIG_IMPORT,\n line,\n 'export default useInsiderESLint();',\n ].join('\\n'));\n\n expect(validateProgramStructure(program)).toStrictEqual([]);\n });\n });\n\n test('accepts a renamed import binding via `as` alias when calling the alias at top level', () => {\n const program = parseSource([\n \"import { silenceDependencyWarning as quiet } from '@useinsider/eslint-config';\",\n ESLINT_CONFIG_IMPORT,\n 'quiet(true);',\n 'export default useInsiderESLint();',\n ].join('\\n'));\n\n expect(validateProgramStructure(program)).toStrictEqual([]);\n });\n\n test('rejects a top-level call whose callee comes from a different module', () => {\n const program = parseSource([\n \"import { silenceDependencyWarning } from 'some-other-package';\",\n ESLINT_CONFIG_IMPORT,\n 'silenceDependencyWarning(true);',\n 'export default useInsiderESLint();',\n ].join('\\n'));\n\n expect(validateProgramStructure(program)).toHaveLength(1);\n });\n\n test('rejects multiple exports (named export alongside default)', () => {\n const program = parseSource([\n ESLINT_CONFIG_IMPORT,\n 'export const foo = 1;',\n 'export default useInsiderESLint();',\n ].join('\\n'));\n const violations = validateProgramStructure(program);\n\n expect(violations).toHaveLength(1);\n expect(violations[0].reason).toMatch(/Disallowed top-level statement `ExportNamedDeclaration`/);\n });\n\n test('rejects two default exports — second one flagged as duplicate', () => {\n const program = parseSource([\n ESLINT_CONFIG_IMPORT,\n 'export default useInsiderESLint();',\n 'export default useInsiderESLint();',\n ].join('\\n'));\n const violations = validateProgramStructure(program);\n\n expect(violations).toHaveLength(1);\n expect(violations[0].reason).toBe('Only one default export is allowed.');\n });\n\n test('rejects missing default export', () => {\n const program = parseSource([ESLINT_CONFIG_IMPORT, 'const a = 1;'].join('\\n'));\n const violations = validateProgramStructure(program);\n\n expect(violations).toHaveLength(1);\n expect(violations[0].reason).toBe('Missing `export default useInsiderESLint()`.');\n });\n\n test('rejects export default of a plain object literal', () => {\n const program = parseSource('export default { rules: {} };');\n const violations = validateProgramStructure(program);\n\n expect(violations).toHaveLength(1);\n expect(violations[0].reason).toMatch(/direct call to `useInsiderESLint/);\n });\n\n test('honors an explicit expectedCallee override', () => {\n const program = parseSource('export default somethingElse();');\n\n expect(validateProgramStructure(program, '', { expectedCallee: 'somethingElse' }))\n .toStrictEqual([]);\n });\n });\n\n describe('defaultIsInsiderImportSource', () => {\n test('returns true for the canonical package source', () => {\n expect(defaultIsInsiderImportSource(INSIDER_IMPORT_SOURCE, '')).toBe(true);\n expect(defaultIsInsiderImportSource(INSIDER_IMPORT_SOURCE, '/any/insider.lint.ts')).toBe(true);\n });\n\n test('returns false for unrelated package sources', () => {\n expect(defaultIsInsiderImportSource('other-package', '/any/insider.lint.ts')).toBe(false);\n });\n\n test('returns false for a relative path that cannot be realpath-resolved', () => {\n expect(defaultIsInsiderImportSource('./missing.js', '/does/not/exist/insider.lint.ts')).toBe(false);\n });\n\n test('returns false for a relative source when configPath is empty', () => {\n expect(defaultIsInsiderImportSource('./dist/main.js', '')).toBe(false);\n });\n });\n\n describe('getConsumerConfigPath', () => {\n test('returns a single matching stack frame', () => {\n const frames: CallSiteLike[] = [\n { getFileName: () => '/repo/node_modules/@useinsider/eslint-config/dist/main.js' },\n { getFileName: () => '/repo/insider.lint.ts' },\n { getFileName: () => 'node:internal/process' },\n ];\n\n expect(getConsumerConfigPath(frames, [])).toBe('/repo/insider.lint.ts');\n });\n\n test('prefers the lint module when the ESLint config is also on the stack', () => {\n const frames: CallSiteLike[] = [\n { getFileName: () => '/repo/eslint.config.mjs' },\n { getFileName: () => '/repo/insider.lint.ts' },\n ];\n\n expect(getConsumerConfigPath(frames, [])).toBe('/repo/insider.lint.ts');\n });\n\n test('falls back to argv when two lint modules are on the stack', () => {\n const frames: CallSiteLike[] = [\n { getFileName: () => '/repo/a/insider.lint.ts' },\n { getFileName: () => '/repo/b/insider.lint.ts' },\n ];\n const argv = ['node', 'eslint', '-c', '/cli/eslint.config.cts', 'src'];\n\n expect(getConsumerConfigPath(frames, argv)).toBe('/cli/eslint.config.cts');\n });\n\n test('strips ESM cache-buster query string (`?mtime=...`) from stack frame', () => {\n const frames: CallSiteLike[] = [\n { getFileName: () => 'file:///repo/insider.lint.ts?mtime=1779282184336' },\n ];\n\n expect(getConsumerConfigPath(frames, [])).toBe('/repo/insider.lint.ts');\n });\n\n test('strips file:// prefix from stack frame', () => {\n const frames: CallSiteLike[] = [{ getFileName: () => 'file:///repo/insider.lint.ts' }];\n\n expect(getConsumerConfigPath(frames, [])).toBe('/repo/insider.lint.ts');\n });\n\n test('falls back to argv when the stack has no match', () => {\n const frames: CallSiteLike[] = [{ getFileName: () => 'node:internal/process' }];\n const argv = ['node', 'eslint', '--config', '/abs/eslint.config.mjs', 'src'];\n\n expect(getConsumerConfigPath(frames, argv)).toBe('/abs/eslint.config.mjs');\n });\n\n test('supports --config=<path> argv form', () => {\n expect(getConsumerConfigPath([], ['node', 'eslint', '--config=/cli/eslint.config.mts']))\n .toBe('/cli/eslint.config.mts');\n });\n\n test('returns null when nothing matches in stack or argv', () => {\n const frames: CallSiteLike[] = [\n { getFileName: () => 'node:internal/process' },\n { getFileName: () => null },\n ];\n\n expect(getConsumerConfigPath(frames, ['node', 'eslint', 'src'])).toBeNull();\n });\n\n test('default arguments: stack walk + process.argv probe runs without throwing', () => {\n const result = getConsumerConfigPath();\n\n expect(result === null || typeof result === 'string').toBe(true);\n });\n\n test('detection covers every lint-module and ESLint-config extension', () => {\n [...LINT_MODULE_FILENAMES, ...ESLINT_CONFIG_FILENAMES].forEach(name => {\n const frames: CallSiteLike[] = [{ getFileName: () => `/repo/${name}` }];\n\n expect(getConsumerConfigPath(frames, [])).toBe(`/repo/${name}`);\n });\n });\n });\n\n describe('getConsumerConfigDir', () => {\n afterEach(() => {\n captureConsumerConfigDir(null);\n vi.restoreAllMocks();\n });\n\n test('returns the directory holding the captured lint module', () => {\n captureConsumerConfigDir('/repo/insider.lint.ts');\n\n expect(getConsumerConfigDir()).toBe('/repo');\n });\n\n test('resolves a relative captured path against the working directory', () => {\n vi.spyOn(process, 'cwd').mockReturnValue('/repo');\n\n captureConsumerConfigDir('./packages/foo/insider.lint.ts');\n\n expect(getConsumerConfigDir()).toBe('/repo/packages/foo');\n });\n\n test('falls back to the working directory when nothing was located', () => {\n vi.spyOn(process, 'cwd').mockReturnValue('/repo/app');\n\n captureConsumerConfigDir(null);\n\n expect(getConsumerConfigDir()).toBe('/repo/app');\n });\n\n test('a later capture replaces the previous one', () => {\n captureConsumerConfigDir('/repo-a/insider.lint.ts');\n captureConsumerConfigDir('/repo-b/packages/app/insider.lint.ts');\n\n expect(getConsumerConfigDir()).toBe('/repo-b/packages/app');\n });\n });\n}\n","import type { Linter } from 'eslint';\nimport { captureConsumerConfigDir, getConsumerConfigDir } from '../utils/ensureConfigStructure';\n\ninterface TypescriptOverrideInput {\n tsconfigPaths: string[];\n}\n\ninterface ParserOptionsLike {\n project?: string[];\n tsconfigRootDir?: string;\n [key: string]: unknown;\n}\n\nexport function applyTypescriptOverrides<BlockType extends Linter.Config> (\n block: BlockType,\n input: TypescriptOverrideInput\n): BlockType {\n const languageOptions = block.languageOptions ?? {};\n const parserOptions = (languageOptions.parserOptions ?? {}) as ParserOptionsLike;\n\n parserOptions.project = input.tsconfigPaths;\n parserOptions.tsconfigRootDir = getConsumerConfigDir();\n languageOptions.parserOptions = parserOptions;\n block.languageOptions = languageOptions;\n\n return block;\n}\n\n/* v8 ignore start */\nif (import.meta.vitest) {\n const { afterEach, describe, test, expect, vi } = import.meta.vitest;\n\n describe('applyTypescriptOverrides', () => {\n test('sets parserOptions.project and tsconfigRootDir on a bare block', () => {\n const block: Linter.Config = {};\n\n applyTypescriptOverrides(block, { tsconfigPaths: ['tsconfig.lib.json'] });\n\n expect(block.languageOptions?.parserOptions).toMatchObject({\n project: ['tsconfig.lib.json'],\n tsconfigRootDir: process.cwd(),\n });\n });\n\n test('preserves existing parserOptions keys', () => {\n const block: Linter.Config = {\n languageOptions: {\n parserOptions: {\n sourceType: 'module',\n ecmaFeatures: { jsx: true },\n },\n },\n };\n\n applyTypescriptOverrides(block, { tsconfigPaths: ['tsconfig.json'] });\n\n expect(block.languageOptions?.parserOptions).toMatchObject({\n sourceType: 'module',\n ecmaFeatures: { jsx: true },\n project: ['tsconfig.json'],\n tsconfigRootDir: process.cwd(),\n });\n });\n\n test('overwrites any pre-existing project array', () => {\n const block: Linter.Config = {\n languageOptions: {\n parserOptions: {\n project: ['old.json'],\n },\n },\n };\n\n applyTypescriptOverrides(block, { tsconfigPaths: ['new.json'] });\n\n const parserOptions = block.languageOptions?.parserOptions as ParserOptionsLike;\n\n expect(parserOptions.project).toStrictEqual(['new.json']);\n });\n });\n\n describe('applyTypescriptOverrides — tsconfigRootDir anchoring', () => {\n function overridesFor (tsconfigPaths: string[]): ParserOptionsLike {\n const block: Linter.Config = {};\n\n applyTypescriptOverrides(block, { tsconfigPaths });\n\n return block.languageOptions?.parserOptions as ParserOptionsLike;\n }\n\n afterEach(() => {\n captureConsumerConfigDir(null);\n vi.restoreAllMocks();\n });\n\n test('anchors to the config directory, not the working directory', () => {\n vi.spyOn(process, 'cwd').mockReturnValue('/repo/app');\n captureConsumerConfigDir('/repo/eslint.config.mjs');\n\n expect(overridesFor(['app/tsconfig.json']).tsconfigRootDir).toBe('/repo');\n });\n\n test('a tsconfig path no longer doubles when eslint runs from a subdirectory', () => {\n vi.spyOn(process, 'cwd').mockReturnValue('/repo/app');\n captureConsumerConfigDir('/repo/eslint.config.mjs');\n\n const { tsconfigRootDir, project } = overridesFor(['app/tsconfig.json']);\n\n expect(`${tsconfigRootDir}/${project?.[0]}`).toBe('/repo/app/tsconfig.json');\n });\n\n test('config at the repo root with eslint launched there matches the working directory', () => {\n vi.spyOn(process, 'cwd').mockReturnValue('/repo');\n captureConsumerConfigDir('/repo/eslint.config.mjs');\n\n expect(overridesFor(['tsconfig.json']).tsconfigRootDir).toBe(process.cwd());\n });\n\n test('falls back to the working directory when the config file was not located', () => {\n vi.spyOn(process, 'cwd').mockReturnValue('/repo/app');\n captureConsumerConfigDir(null);\n\n expect(overridesFor(['tsconfig.json']).tsconfigRootDir).toBe('/repo/app');\n });\n });\n}\n","import type { Linter } from 'eslint';\n\ninterface VueOverrideInput {\n globalComponents?: string[];\n}\n\nexport function escapeRegex (input: string): string {\n return input.replace(/[\\\\^$.*+?()[\\]{}|]/g, '\\\\$&');\n}\n\nexport function anchoredEscapeRegex (input: string): string {\n return `^${escapeRegex(input)}$`;\n}\n\nexport function applyVueOverrides<BlockType extends Linter.Config> (\n block: BlockType,\n input: VueOverrideInput\n): BlockType {\n if (!input.globalComponents || input.globalComponents.length === 0) {\n return block;\n }\n\n const rules = block.rules ?? {};\n\n rules['vue/no-undef-components'] = ['error', {\n ignorePatterns: input.globalComponents.map(anchoredEscapeRegex),\n }];\n block.rules = rules;\n\n return block;\n}\n\n/* v8 ignore start */\nif (import.meta.vitest) {\n const { describe, test, expect } = import.meta.vitest;\n\n describe('escapeRegex', () => {\n test.each([\n ['plain', 'plain'],\n ['a.b', 'a\\\\.b'],\n ['$Foo', '\\\\$Foo'],\n ['a+b', 'a\\\\+b'],\n ['(x)', '\\\\(x\\\\)'],\n ['[a]', '\\\\[a\\\\]'],\n ['{a}', '\\\\{a\\\\}'],\n ['a|b', 'a\\\\|b'],\n ['a^b', 'a\\\\^b'],\n ['a*b', 'a\\\\*b'],\n ['a?b', 'a\\\\?b'],\n ['a\\\\b', 'a\\\\\\\\b'],\n ])('escapes %s → %s', (input, expected) => {\n expect(escapeRegex(input)).toBe(expected);\n });\n });\n\n describe('anchoredEscapeRegex', () => {\n test('wraps escaped output with ^…$', () => {\n expect(anchoredEscapeRegex('RouterLink')).toBe('^RouterLink$');\n expect(anchoredEscapeRegex('My.Component')).toBe('^My\\\\.Component$');\n });\n });\n\n describe('applyVueOverrides', () => {\n test('is a no-op when globalComponents is missing', () => {\n const block: Linter.Config = { rules: { 'vue/no-undef-components': ['error'] } };\n\n applyVueOverrides(block, {});\n\n expect(block.rules?.['vue/no-undef-components']).toStrictEqual(['error']);\n });\n\n test('is a no-op when globalComponents is empty', () => {\n const block: Linter.Config = { rules: { 'vue/no-undef-components': ['error'] } };\n\n applyVueOverrides(block, { globalComponents: [] });\n\n expect(block.rules?.['vue/no-undef-components']).toStrictEqual(['error']);\n });\n\n test('overrides rule with anchored escaped patterns', () => {\n const block: Linter.Config = {};\n\n applyVueOverrides(block, { globalComponents: ['RouterLink', 'NuxtLink'] });\n\n expect(block.rules?.['vue/no-undef-components']).toStrictEqual([\n 'error',\n { ignorePatterns: ['^RouterLink$', '^NuxtLink$'] },\n ]);\n });\n });\n}\n","import type { Linter } from 'eslint';\nimport { applyTypescriptOverrides } from './typescript';\nimport { applyVueOverrides } from './vue';\n\nexport interface CommonEntryFields {\n ignores?: string[];\n globals?: Linter.Globals;\n}\n\nexport interface JsEntry extends CommonEntryFields {\n files: string[];\n}\n\nexport interface TsEntry extends CommonEntryFields {\n files: string[];\n tsconfigPaths: string[];\n}\n\nexport interface VueEntry extends CommonEntryFields {\n files: string[];\n globalComponents?: string[];\n}\n\nexport interface VueTsEntry extends CommonEntryFields {\n files: string[];\n globalComponents?: string[];\n tsconfigPaths: string[];\n}\n\nexport interface TestEntry extends CommonEntryFields {\n files: string[];\n}\n\nexport type ScopeEntry = JsEntry | TsEntry | VueEntry | VueTsEntry | TestEntry;\n\nconst scopeMap = {\n async javascript () {\n return import('../configs/javascript');\n },\n async javascriptDom () {\n return import('../configs/javascript-dom');\n },\n async javascriptNode () {\n return import('../configs/javascript-node');\n },\n async typescript () {\n return import('../configs/typescript');\n },\n async typescriptDom () {\n return import('../configs/typescript-dom');\n },\n async typescriptNode () {\n return import('../configs/typescript-node');\n },\n async vue2 () {\n return import('../configs/vue2');\n },\n async vue3 () {\n return import('../configs/vue3');\n },\n async vue2Typescript () {\n return import('../configs/vue2-typescript');\n },\n async vue3Typescript () {\n return import('../configs/vue3-typescript');\n },\n async vue2OptionsApi () {\n return import('../configs/vue2-options-api');\n },\n async vue3OptionsApi () {\n return import('../configs/vue3-options-api');\n },\n async vue2TypescriptOptionsApi () {\n return import('../configs/vue2-typescript-options-api');\n },\n async vue3TypescriptOptionsApi () {\n return import('../configs/vue3-typescript-options-api');\n },\n async jest () {\n return import('../configs/jest');\n },\n async vitest () {\n return import('../configs/vitest');\n },\n async jsdocBasedTs () {\n return import('../configs/jsdoc-based-ts');\n },\n} satisfies Record<string, () => Promise<{ default: Linter.Config }>>;\n\nexport type ScopeName = keyof typeof scopeMap;\n\nconst tsScopes = new Set<ScopeName>([\n 'typescript',\n 'typescriptDom',\n 'typescriptNode',\n 'vue2Typescript',\n 'vue3Typescript',\n 'vue2TypescriptOptionsApi',\n 'vue3TypescriptOptionsApi',\n 'jsdocBasedTs',\n]);\n\nconst vueScopes = new Set<ScopeName>([\n 'vue2',\n 'vue3',\n 'vue2Typescript',\n 'vue3Typescript',\n 'vue2OptionsApi',\n 'vue3OptionsApi',\n 'vue2TypescriptOptionsApi',\n 'vue3TypescriptOptionsApi',\n]);\n\ntype LanguageOptions = NonNullable<Linter.Config['languageOptions']>;\n\nfunction cloneLanguageOptions (languageOptions: LanguageOptions): LanguageOptions {\n const clone: LanguageOptions = { ...languageOptions };\n\n if (languageOptions.parserOptions) {\n clone.parserOptions = { ...languageOptions.parserOptions };\n }\n\n if (languageOptions.globals) {\n clone.globals = { ...languageOptions.globals };\n }\n\n return clone;\n}\n\n// ESLint's flat-config schema validates every OWN key, so `languageOptions: undefined`\n// fails with `Key \"languageOptions\": Expected an object.` — absent keys must stay absent.\nfunction clonePreset (preset: Linter.Config): Linter.Config {\n const { languageOptions, rules, settings, ...rest } = preset;\n const clone: Linter.Config = { ...rest };\n\n if (languageOptions) {\n clone.languageOptions = cloneLanguageOptions(languageOptions);\n }\n\n if (rules) {\n clone.rules = { ...rules };\n }\n\n if (settings) {\n clone.settings = { ...settings };\n }\n\n return clone;\n}\n\nexport function isScopeName (key: string): key is ScopeName {\n return Object.keys(scopeMap).includes(key);\n}\n\n/**\n * Every scope name `useInsider()` accepts, for error messages that have to spell the options out.\n * @example\n * scopeNames().includes('typescriptNode'); // true\n */\nexport function scopeNames (): ScopeName[] {\n return Object.keys(scopeMap) as ScopeName[];\n}\n\nfunction applyCommonEntryFields (block: Linter.Config, entry: CommonEntryFields): void {\n if (entry.ignores && entry.ignores.length > 0) {\n block.ignores = [...entry.ignores];\n }\n\n if (entry.globals) {\n const languageOptions = block.languageOptions ?? {};\n const existingGlobals = languageOptions.globals ?? {};\n\n languageOptions.globals = { ...existingGlobals, ...entry.globals };\n block.languageOptions = languageOptions;\n }\n}\n\nexport async function buildScopeBlocks (\n scope: ScopeName,\n entries: readonly ScopeEntry[]\n): Promise<Linter.Config[]> {\n const preset = (await scopeMap[scope]()).default;\n\n return entries.map(entry => {\n const block = clonePreset(preset);\n\n block.files = [...entry.files];\n\n if (tsScopes.has(scope)) {\n const { tsconfigPaths } = entry as TsEntry;\n\n if (tsconfigPaths) {\n applyTypescriptOverrides(block, { tsconfigPaths });\n }\n }\n\n if (vueScopes.has(scope)) {\n const { globalComponents } = entry as VueEntry;\n\n applyVueOverrides(block, { globalComponents });\n }\n\n applyCommonEntryFields(block, entry);\n\n return block;\n });\n}\n\n/* v8 ignore start */\nif (import.meta.vitest) {\n const { describe, test, expect } = import.meta.vitest;\n\n interface ParserOptionsShape {\n project?: string[];\n tsconfigRootDir?: string;\n [key: string]: unknown;\n }\n\n describe('buildScopeBlocks — ignores', () => {\n test('sets block.ignores when entry.ignores is non-empty', async () => {\n const [block] = await buildScopeBlocks('javascriptNode', [\n {\n files: ['scripts/**/*.js'],\n ignores: ['scripts/legacy/**'],\n },\n ]);\n\n expect(block.ignores).toStrictEqual(['scripts/legacy/**']);\n });\n\n test('omits block.ignores when entry.ignores is missing', async () => {\n const [block] = await buildScopeBlocks('javascriptNode', [\n { files: ['scripts/**/*.js'] },\n ]);\n\n expect(block.ignores).toBeUndefined();\n });\n\n test('omits block.ignores when entry.ignores is an empty array', async () => {\n const [block] = await buildScopeBlocks('javascriptNode', [\n {\n files: ['scripts/**/*.js'],\n ignores: [],\n },\n ]);\n\n expect(block.ignores).toBeUndefined();\n });\n\n test('copies the ignores array (caller mutation does not leak into block)', async () => {\n const ignores = ['scripts/legacy/**'];\n const [block] = await buildScopeBlocks('javascriptNode', [\n {\n files: ['scripts/**/*.js'],\n ignores,\n },\n ]);\n\n ignores.push('mutated/**');\n\n expect(block.ignores).toStrictEqual(['scripts/legacy/**']);\n });\n });\n\n describe('buildScopeBlocks — files', () => {\n test('copies the files array (caller mutation does not leak into block)', async () => {\n const files = ['scripts/**/*.js'];\n const [block] = await buildScopeBlocks('javascriptNode', [{ files }]);\n\n files.push('mutated/**');\n\n expect(block.files).toStrictEqual(['scripts/**/*.js']);\n });\n });\n\n describe('buildScopeBlocks — globals', () => {\n test('merges user globals on top of preset globals (user wins on conflict)', async () => {\n const [block] = await buildScopeBlocks('javascriptNode', [\n {\n files: ['**/*.js'],\n globals: { MyCustomGlobal: 'readonly' },\n },\n ]);\n\n const blockGlobals = block.languageOptions?.globals as Record<string, unknown>;\n\n expect(blockGlobals.MyCustomGlobal).toBe('readonly');\n });\n\n test('preserves preset globals when entry.globals is absent', async () => {\n const [withUserGlobals] = await buildScopeBlocks('javascriptNode', [\n {\n files: ['**/*.js'],\n globals: { MyCustomGlobal: 'readonly' },\n },\n ]);\n const [withoutUserGlobals] = await buildScopeBlocks('javascriptNode', [\n { files: ['**/*.js'] },\n ]);\n\n const presetGlobals = withoutUserGlobals.languageOptions?.globals as Record<string, unknown>;\n const mergedGlobals = withUserGlobals.languageOptions?.globals as Record<string, unknown>;\n\n Object.keys(presetGlobals).forEach(key => {\n expect(mergedGlobals[key]).toBe(presetGlobals[key]);\n });\n });\n\n test('user globals override preset globals on key conflict', async () => {\n const [presetBlock] = await buildScopeBlocks('javascriptNode', [\n { files: ['**/*.js'] },\n ]);\n const presetGlobals = presetBlock.languageOptions?.globals as Record<string, unknown>;\n const [sharedKey] = Object.keys(presetGlobals);\n\n const [overrideBlock] = await buildScopeBlocks('javascriptNode', [\n {\n files: ['**/*.js'],\n globals: { [sharedKey]: 'writable' },\n },\n ]);\n const overrideGlobals = overrideBlock.languageOptions?.globals as Record<string, unknown>;\n\n expect(overrideGlobals[sharedKey]).toBe('writable');\n });\n });\n\n describe('buildScopeBlocks — ignores + typescript override interaction', () => {\n test('TS scope: ignores and tsconfigPaths both applied, ignores not overwritten', async () => {\n const [block] = await buildScopeBlocks('typescriptNode', [\n {\n files: ['*.ts', 'scripts/**/*.ts', 'e2e/**/*.ts'],\n tsconfigPaths: ['./tsconfig.node.json'],\n ignores: ['e2e/**/*.test.ts', 'scripts/design-system.d.ts'],\n },\n ]);\n\n const parserOptions = block.languageOptions?.parserOptions as ParserOptionsShape;\n\n expect(parserOptions.project).toStrictEqual(['./tsconfig.node.json']);\n expect(block.ignores).toStrictEqual([\n 'e2e/**/*.test.ts',\n 'scripts/design-system.d.ts',\n ]);\n });\n });\n\n describe('buildScopeBlocks — ignores + vue override interaction', () => {\n test('Vue scope: ignores and globalComponents both applied', async () => {\n const [block] = await buildScopeBlocks('vue3', [\n {\n files: ['src/**/*.vue'],\n globalComponents: ['RouterLink'],\n ignores: ['src/legacy/**/*.vue'],\n },\n ]);\n\n expect(block.ignores).toStrictEqual(['src/legacy/**/*.vue']);\n expect(block.rules?.['vue/no-undef-components']).toStrictEqual([\n 'error',\n { ignorePatterns: ['^RouterLink$'] },\n ]);\n });\n });\n\n describe('buildScopeBlocks — no undefined-valued own keys', () => {\n test.each(scopeNames())('%s block exposes no own key set to undefined', async scope => {\n const entry = {\n files: ['src/**/*'],\n tsconfigPaths: ['./tsconfig.json'],\n };\n const [block] = await buildScopeBlocks(scope, [entry]);\n\n const undefinedKeys = Object.entries(block)\n .filter(([, value]) => value === undefined)\n .map(([key]) => key);\n\n expect(undefinedKeys).toStrictEqual([]);\n });\n\n test('a preset declaring neither key keeps both absent instead of undefined', async () => {\n const [block] = await buildScopeBlocks('vitest', [{ files: ['**/*.spec.js'] }]);\n\n expect('languageOptions' in block).toBe(false);\n expect('settings' in block).toBe(false);\n });\n\n test('every preset that declares languageOptions leaves no undefined key inside it', async () => {\n const inspected: string[] = [];\n\n await Promise.all(scopeNames().map(async scope => {\n const [block] = await buildScopeBlocks(scope, [{\n files: ['src/**/*'],\n tsconfigPaths: ['./tsconfig.json'],\n }]);\n\n if (!block.languageOptions) {\n return;\n }\n\n inspected.push(scope);\n\n const undefinedKeys = Object.entries(block.languageOptions)\n .filter(([, value]) => value === undefined)\n .map(([key]) => key);\n\n expect(undefinedKeys).toStrictEqual([]);\n }));\n\n expect(inspected.length).toBeGreaterThan(0);\n });\n });\n\n describe('buildScopeBlocks — real-world repro (MB-2937 / mindbehind-fe)', () => {\n test('typescriptNode entry with design-system.d.ts in ignores emits matching block.ignores', async () => {\n const [, secondBlock] = await buildScopeBlocks('typescriptNode', [\n {\n files: ['e2e/**/*.test.ts'],\n tsconfigPaths: ['./tsconfig.node.json'],\n },\n {\n files: ['*.ts', 'scripts/**/*.ts', 'e2e/**/*.ts'],\n tsconfigPaths: ['./tsconfig.node.json'],\n ignores: ['e2e/**/*.test.ts', 'scripts/design-system.d.ts'],\n },\n ]);\n\n expect(secondBlock.files).toStrictEqual(['*.ts', 'scripts/**/*.ts', 'e2e/**/*.ts']);\n expect(secondBlock.ignores).toContain('scripts/design-system.d.ts');\n expect(secondBlock.ignores).toContain('e2e/**/*.test.ts');\n });\n });\n}\n","import type { Linter } from 'eslint';\n\ninterface SpellCheckerInput {\n ignoredPaths?: string[];\n customWordListFile?: string;\n}\n\nexport function buildSpellCheckerBlocks (input: SpellCheckerInput | undefined): Linter.Config[] {\n if (!input) {\n return [];\n }\n\n const blocks: Linter.Config[] = [];\n\n if (input.customWordListFile) {\n blocks.push({\n rules: {\n '@cspell/spellchecker': ['error', { customWordListFile: input.customWordListFile }],\n },\n });\n }\n\n if (input.ignoredPaths && input.ignoredPaths.length > 0) {\n blocks.push({\n files: input.ignoredPaths,\n rules: {\n '@cspell/spellchecker': 'off',\n },\n });\n }\n\n return blocks;\n}\n\n/* v8 ignore start */\nif (import.meta.vitest) {\n const { describe, test, expect } = import.meta.vitest;\n\n describe('buildSpellCheckerBlocks', () => {\n test('returns empty array when input is undefined', () => {\n expect(buildSpellCheckerBlocks(undefined)).toStrictEqual([]);\n });\n\n test('returns empty array when input has neither option', () => {\n expect(buildSpellCheckerBlocks({})).toStrictEqual([]);\n });\n\n test('returns customWordListFile block alone', () => {\n const blocks = buildSpellCheckerBlocks({ customWordListFile: './words.json' });\n\n expect(blocks).toStrictEqual([\n {\n rules: {\n '@cspell/spellchecker': ['error', { customWordListFile: './words.json' }],\n },\n },\n ]);\n });\n\n test('returns ignoredPaths off block alone', () => {\n const blocks = buildSpellCheckerBlocks({ ignoredPaths: ['vendor/**'] });\n\n expect(blocks).toStrictEqual([\n {\n files: ['vendor/**'],\n rules: { '@cspell/spellchecker': 'off' },\n },\n ]);\n });\n\n test('emits customWordListFile first then ignoredPaths so ignore wins on overlap', () => {\n const blocks = buildSpellCheckerBlocks({\n customWordListFile: './cspell.json',\n ignoredPaths: ['vendor/**', 'dist/**'],\n });\n\n expect(blocks).toHaveLength(2);\n expect(blocks[0].rules?.['@cspell/spellchecker']).toStrictEqual([\n 'error',\n { customWordListFile: './cspell.json' },\n ]);\n expect(blocks[1].files).toStrictEqual(['vendor/**', 'dist/**']);\n expect(blocks[1].rules?.['@cspell/spellchecker']).toBe('off');\n });\n\n test('ignores empty ignoredPaths array', () => {\n const blocks = buildSpellCheckerBlocks({ ignoredPaths: [] });\n\n expect(blocks).toStrictEqual([]);\n });\n });\n}\n","import type { Linter } from 'eslint';\n\nexport async function buildStrictBlocks (value: boolean | string[] | undefined): Promise<Linter.Config[]> {\n if (!value) {\n return [];\n }\n\n const isFileScoped = Array.isArray(value);\n\n if (isFileScoped && value.length === 0) {\n return [];\n }\n\n const { default: strictConfig } = await import('../configs/strict');\n const clone: Linter.Config = { ...strictConfig };\n\n if (clone.rules) {\n clone.rules = { ...clone.rules };\n }\n\n if (isFileScoped) {\n clone.files = [...value];\n } else {\n delete clone.files;\n }\n\n return [clone];\n}\n\n/* v8 ignore start */\nif (import.meta.vitest) {\n const { describe, test, expect } = import.meta.vitest;\n\n describe('buildStrictBlocks', () => {\n test('emits nothing for a falsy or empty value', async () => {\n expect(await buildStrictBlocks(undefined)).toStrictEqual([]);\n expect(await buildStrictBlocks(false)).toStrictEqual([]);\n expect(await buildStrictBlocks([])).toStrictEqual([]);\n });\n\n test('drops files when strict is enabled for every file', async () => {\n const [block] = await buildStrictBlocks(true);\n\n expect(block.files).toBeUndefined();\n });\n\n test('copies the files array (caller mutation does not leak into block)', async () => {\n const files = ['src/**/*.ts'];\n const [block] = await buildStrictBlocks(files);\n\n files.push('mutated/**');\n\n expect(block.files).toStrictEqual(['src/**/*.ts']);\n });\n });\n}\n","import { existsSync, readFileSync } from 'node:fs';\nimport { createRequire } from 'node:module';\nimport { resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { installPackage } from '@antfu/install-pkg';\nimport semver from 'semver';\n\nlet turnOff = false;\nlet scanned = false;\nconst silencedDependencies = new Set<string>();\n// oxlint is tracked alongside the two ESLint-side pins because the split makes it load-bearing: the\n// ESLint config turns off every rule oxlint owns, so a consumer on an older oxlint silently loses\n// whatever rules that release did not yet implement.\nconst fixedDependencies = [\n 'eslint',\n 'globals',\n 'oxlint',\n];\nconst require = createRequire(import.meta.url);\n\nfunction getPackageJSONPath (currentDir: string) {\n const fileLocation = resolve(currentDir, 'package.json');\n\n if (existsSync(fileLocation)) {\n return fileLocation;\n }\n\n if (currentDir === process.cwd()) {\n throw new Error(`Unable to locate package.json in ${currentDir}`);\n }\n\n const parentDir = resolve(currentDir, '..');\n\n return getPackageJSONPath(parentDir);\n}\n\nfunction getPackageJSON (fileLocation: string) {\n const packageJsonContent = readFileSync(fileLocation, 'utf8');\n\n return JSON.parse(packageJsonContent) as Record<string, Record<string, string>>;\n}\n\nfunction getExpectedDependencies (): Record<string, string> {\n const path = getPackageJSONPath(fileURLToPath(new URL(/* @vite-ignore */ import.meta.url)));\n const packageJson = getPackageJSON(path);\n\n return packageJson.dependencies;\n}\n\nfunction getDependencyVersionFromConsumer (depName: string, baseDir: string = process.cwd()): string | undefined {\n try {\n const pkgJsonPath = require.resolve(`${depName}/package.json`, { paths: [baseDir] });\n const pkgContent = readFileSync(pkgJsonPath, 'utf8');\n const pkg: { version?: string } = JSON.parse(pkgContent) as Record<string, Record<string, string>>;\n\n return pkg.version;\n } catch {\n return undefined;\n }\n}\n\nexport async function ensureDependencies () {\n if (turnOff || scanned) {\n return;\n }\n\n scanned = true;\n\n const expectedDependencies = Object.entries(getExpectedDependencies());\n const missingDependencyEntries = expectedDependencies.filter(\n ([expectedDependency, expectedVersion]) => {\n if (!fixedDependencies.includes(expectedDependency) || silencedDependencies.has(expectedDependency)) {\n return false;\n }\n\n const installedVersion = getDependencyVersionFromConsumer(expectedDependency);\n\n if (!installedVersion) {\n return true;\n }\n\n return semver.lt(installedVersion, expectedVersion);\n }\n );\n\n if (!missingDependencyEntries.length) {\n return;\n }\n\n const missingDependencies = missingDependencyEntries.map(([dependency, version]) => `${dependency}@${version.replace(/^\\W+/, '')}`);\n\n // oxlint-disable-next-line no-console\n console.info('Missing dependencies detected:');\n // oxlint-disable-next-line no-console\n console.info(missingDependencies.map(dependency => ` - ${dependency}`).join('\\n'));\n // oxlint-disable-next-line no-console\n console.info('\\nInstalling dependencies:');\n\n await installPackage(missingDependencies, { dev: true, additionalArgs: ['-E'] });\n\n // eslint-disable-next-line no-process-exit\n process.exit(1);\n}\n\nexport function silenceDependencyWarning (\n /**\n * Pass `true` to silence all dependency warnings.\n */\n all: boolean\n): void;\n\nexport function silenceDependencyWarning (dependencies: string[]): void;\n\nexport function silenceDependencyWarning (input: boolean | string[]) {\n if (typeof input === 'boolean') {\n turnOff = input;\n\n return;\n }\n\n silencedDependencies.clear();\n input.forEach(dependency => silencedDependencies.add(String(dependency)));\n}\n","import { existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { getConsumerConfigDir } from './ensureConfigStructure';\nimport {\n diagnoseLayout,\n formatLayoutGuidance,\n lintModuleSpecifier,\n OPT_OUT_ENV,\n OXLINT_CONFIG_FILENAMES,\n} from './layoutDiagnosis';\n\nexport { OXLINT_CONFIG_FILENAMES };\n\nfunction formatMessage (directory: string): string {\n return formatLayoutGuidance({\n headline: `no oxlint config found in ${directory}.`,\n diagnosis: diagnoseLayout(directory),\n detail: [\n 'useInsiderESLint() turns off every rule oxlint owns, so running ESLint alone would silently',\n 'drop those checks. Create the sibling oxlint config:',\n '',\n ' // oxlint.config.ts',\n ` import { useInsiderOXC } from '${lintModuleSpecifier(directory)}';`,\n '',\n ' export default await useInsiderOXC();',\n '',\n 'and run both linters:',\n '',\n ' \"lint\": \"oxlint --disable-nested-config && eslint .\"',\n '',\n `oxlint discovers only ${OXLINT_CONFIG_FILENAMES.join(' and ')} — any other extension is`,\n 'ignored without a word.',\n ],\n });\n}\n\n/**\n * Fails when the consumer enabled the ESLint-side oxlint suppression without a sibling oxlint\n * config to run the suppressed rules. Resolved against the directory\n * {@link getConsumerConfigDir} captured during `useInsider()`.\n * @example\n * ensureOxlintConfig(); // throws unless oxlint.config.{ts,mts} sits beside insider.lint.*\n */\nexport function ensureOxlintConfig (directory: string = getConsumerConfigDir()): void {\n if (process.env[OPT_OUT_ENV] === 'true') {\n return;\n }\n\n if (OXLINT_CONFIG_FILENAMES.some(filename => existsSync(join(directory, filename)))) {\n return;\n }\n\n throw new Error(formatMessage(directory));\n}\n\n/* v8 ignore start */\nif (import.meta.vitest) {\n const { afterEach, describe, test, expect, vi } = import.meta.vitest;\n const { mkdtempSync, writeFileSync } = await import('node:fs');\n const { tmpdir } = await import('node:os');\n\n function makeDir (): string {\n return mkdtempSync(join(tmpdir(), 'insider-oxlint-'));\n }\n\n afterEach(() => {\n vi.unstubAllEnvs();\n });\n\n describe('ensureOxlintConfig', () => {\n test('throws with an actionable message when no oxlint config sits beside the lint module', () => {\n vi.stubEnv(OPT_OUT_ENV, '');\n\n const directory = makeDir();\n\n expect(() => ensureOxlintConfig(directory)).toThrow(/no oxlint config found in/);\n expect(() => ensureOxlintConfig(directory)).toThrow(/useInsiderOXC/);\n expect(() => ensureOxlintConfig(directory)).toThrow(/oxlint --disable-nested-config && eslint/);\n });\n\n test.each(OXLINT_CONFIG_FILENAMES)('accepts %s', filename => {\n vi.stubEnv(OPT_OUT_ENV, '');\n\n const directory = makeDir();\n\n writeFileSync(join(directory, filename), 'export default {};\\n');\n\n expect(() => ensureOxlintConfig(directory)).not.toThrow();\n });\n\n test.each(['oxlint.config.js', 'oxlint.config.mjs', 'oxlint.config.cjs', 'oxlint.config.cts'])(\n 'rejects %s, which oxlint never discovers',\n filename => {\n vi.stubEnv(OPT_OUT_ENV, '');\n\n const directory = makeDir();\n\n writeFileSync(join(directory, filename), 'export default {};\\n');\n\n expect(() => ensureOxlintConfig(directory)).toThrow(/no oxlint config found in/);\n }\n );\n\n test('rejects a hand-written .oxlintrc.json, which cannot carry the preset rules', () => {\n vi.stubEnv(OPT_OUT_ENV, '');\n\n const directory = makeDir();\n\n writeFileSync(join(directory, '.oxlintrc.json'), '{}\\n');\n\n expect(() => ensureOxlintConfig(directory)).toThrow(/no oxlint config found in/);\n });\n\n test('names the lint module that actually exists, so the suggested import resolves', () => {\n vi.stubEnv(OPT_OUT_ENV, '');\n\n const directory = makeDir();\n\n writeFileSync(join(directory, 'insider.lint.mjs'), 'export const a = 1;\\n');\n\n expect(() => ensureOxlintConfig(directory)).toThrow(/from '\\.\\/insider\\.lint\\.mjs'/);\n });\n\n test('falls back to the TypeScript filename when no lint module is on disk yet', () => {\n vi.stubEnv(OPT_OUT_ENV, '');\n\n expect(() => ensureOxlintConfig(makeDir())).toThrow(/from '\\.\\/insider\\.lint\\.ts'/);\n });\n\n test('honors the INSIDER_SKIP_CONFIG_VALIDATION escape hatch', () => {\n vi.stubEnv(OPT_OUT_ENV, 'true');\n\n expect(() => ensureOxlintConfig(makeDir())).not.toThrow();\n });\n });\n}\n","import { warn } from 'node:console';\nimport type { Linter } from 'eslint';\n\nconst globallySilencedRules = new Set<string>();\n\n/**\n * Silence rules globally.\n * This will affect all configs scopes.\n */\nexport function silenceRules (rules: string[]) {\n rules.forEach(rule => {\n globallySilencedRules.add(rule);\n });\n}\n\nfunction isDisabled (config: Linter.RuleEntry): boolean {\n const [severity] = Array.isArray(config) ? config : [config];\n\n return severity === 'off' || severity === 0;\n}\n\nfunction silenceRule (config: Linter.RuleEntry) {\n const [, ...restConfig] = Array.isArray(config) ? config : [];\n\n return ['warn', ...restConfig as Record<string, unknown>[]] as Linter.RuleSeverityAndOptions;\n}\n\n/**\n * Reports a silenced rule name that no emitted block declares, which is how a typo in\n * `silenceRules` stays visible. The caller passes the union of every block's rule keys: a single\n * block is not evidence, because the emission is many narrow blocks and a correctly spelled rule is\n * absent from nearly all of them.\n * @example\n * warnUnknownSilencedRules(['no-console'], ['no-unknown-rule']); // warns once\n */\nexport function warnUnknownSilencedRules (\n knownRules: Iterable<string>,\n silencedRules: readonly string[]\n): void {\n const known = new Set(knownRules);\n\n new Set(silencedRules).forEach(rule => {\n if (known.has(rule)) {\n return;\n }\n\n warn(`Unknown rule \"${rule}\". Please remove it from the silenced rules list.`);\n });\n}\n\nexport function filterSilencedRules (\n rules: Partial<Linter.RulesRecord> | Readonly<Linter.RulesRecord> | undefined,\n silencedRules?: string[] | Set<string>\n) {\n let targetSilencedRules = silencedRules || globallySilencedRules;\n\n if (Array.isArray(targetSilencedRules)) {\n targetSilencedRules = new Set(targetSilencedRules);\n }\n\n if (!rules || !targetSilencedRules.size) {\n return rules;\n }\n\n return Object.entries(rules).reduce((newRules, [key, value]) => {\n if (value) {\n // Silencing must never make a rule louder, so a rule the config\n // deliberately turned off is left alone rather than demoted to a warning.\n const shouldSilence = targetSilencedRules.has(key) && !isDisabled(value);\n\n newRules[key] = shouldSilence ? silenceRule(value) : value;\n }\n\n return newRules;\n }, {} as Linter.RulesRecord);\n}\n\n/* v8 ignore start */\nif (import.meta.vitest) {\n const { describe, test, expect, beforeEach, afterEach } = import.meta.vitest;\n // `warn` is a static binding taken from `node:console`, and a `vi.mock` of that module is\n // hoisted out of this guard — it would stub the real `warn` for every spec that merely imports\n // this file, silently. Swapping the stream the binding writes to keeps the effect in here.\n const warnings: string[] = [];\n const writeToStderr = process.stderr.write.bind(process.stderr);\n\n beforeEach(() => {\n warnings.length = 0;\n\n process.stderr.write = (chunk: unknown) => {\n warnings.push(String(chunk));\n\n return true;\n };\n });\n\n afterEach(() => {\n process.stderr.write = writeToStderr;\n globallySilencedRules.clear();\n });\n\n describe('silenceRules', () => {\n test('should register given rule keys as silenced', () => {\n const rule = '@stylistic/type-generic-spacing';\n\n expect(globallySilencedRules.has(rule)).toBe(false);\n silenceRules([rule]);\n expect(globallySilencedRules.has(rule)).toBe(true);\n });\n });\n\n describe('filterSilencedRules', () => {\n test('should return the same rules object if no rules are silenced', () => {\n const rules = {\n 'no-console': 'warn',\n 'no-debugger': 'warn',\n } as Linter.RulesRecord;\n\n expect(filterSilencedRules(rules)).toBe(rules);\n });\n\n test('should return a new rules object with silenced rules silenced and other rules unchanged', () => {\n silenceRules(['no-console']);\n\n const rules = {\n 'no-console': 'error',\n 'no-debugger': 'warn',\n 'no-alert': 'error',\n } as Linter.RulesRecord;\n\n expect(filterSilencedRules(rules)).toStrictEqual({\n 'no-console': ['warn'],\n 'no-debugger': 'warn',\n 'no-alert': 'error',\n });\n });\n\n test('should return a new rules object with silenced rules silenced and other rules unchanged', () => {\n silenceRules(['no-bitwise', 'new-cap']);\n\n const rules = {\n 'max-len': 'off',\n 'new-cap': ['error'],\n 'no-alert': ['error'],\n 'no-bitwise': ['error', {\n allow: ['~'],\n }],\n } as Linter.RulesRecord;\n\n expect(filterSilencedRules(rules)).toStrictEqual({\n 'max-len': 'off',\n 'new-cap': ['warn'],\n 'no-alert': ['error'],\n 'no-bitwise': ['warn', {\n allow: ['~'],\n }],\n });\n });\n\n test.each([\n ['off' as Linter.RuleEntry],\n [['off'] as Linter.RuleEntry],\n [[0] as unknown as Linter.RuleEntry],\n ])('should leave a disabled rule (%j) disabled instead of promoting it to warn', entry => {\n const rules = { 'no-console': entry } as Linter.RulesRecord;\n\n expect(filterSilencedRules(rules, ['no-console'])).toStrictEqual({ 'no-console': entry });\n });\n\n test('never warns, so a block that simply lacks the rule cannot report a false typo', () => {\n const rules = {\n 'no-console': 'error',\n 'no-debugger': 'warn',\n } as Linter.RulesRecord;\n\n filterSilencedRules(rules, ['no-console', 'no-bitwise']);\n filterSilencedRules(rules);\n\n expect(warnings).toStrictEqual([]);\n });\n\n test.each([\n [['@typescript-eslint/no-unsafe-call'], ['warn']],\n [new Set(['@typescript-eslint/no-unsafe-call']), ['warn']],\n [[], 'error'],\n ])(\n '#%# should filter scope-related rules and ignore globally silenced rules',\n (silencedRules, expectation) => {\n silenceRules(['@typescript-eslint/no-unsafe-assignment']);\n\n const rules = {\n '@typescript-eslint/no-unsafe-assignment': 'error',\n '@typescript-eslint/no-unsafe-member-access': 'error',\n '@typescript-eslint/no-unsafe-call': 'error',\n } as Linter.RulesRecord;\n\n expect(filterSilencedRules(rules, silencedRules)).toStrictEqual({\n '@typescript-eslint/no-unsafe-assignment': 'error',\n '@typescript-eslint/no-unsafe-member-access': 'error',\n '@typescript-eslint/no-unsafe-call': expectation,\n });\n }\n );\n });\n\n describe('warnUnknownSilencedRules', () => {\n test('stays silent for a name the union of blocks declares, however few blocks carry it', () => {\n warnUnknownSilencedRules(['no-console', '@stylistic/indent'], ['no-console']);\n\n expect(warnings).toStrictEqual([]);\n });\n\n test('warns once per misspelled name, not once per block', () => {\n warnUnknownSilencedRules(['no-console'], ['no-unknown-rule', 'no-unknown-rule']);\n\n expect(warnings).toStrictEqual([\n 'Unknown rule \"no-unknown-rule\". Please remove it from the silenced rules list.\\n',\n ]);\n });\n });\n}\n","import type { Linter } from 'eslint';\nimport { defineConfig } from 'eslint/config';\nimport { buildConfigFilesBlocks, buildLintTopologyBlocks } from './builders/configFiles';\nimport { buildJqueryBlocks, type JqueryEntry } from './builders/jquery';\nimport {\n buildOxlintConfig,\n buildOxlintSuppressionBlocks,\n buildUnusedDirectiveBlocks,\n type OxlintRendererConfig,\n} from './builders/oxlint';\nimport { buildScopeBlocks, isScopeName, type ScopeEntry, scopeNames } from './builders/scopeBlocks';\nimport { buildSpellCheckerBlocks } from './builders/spellChecker';\nimport { buildStrictBlocks } from './builders/strict';\nimport { ensureConfigStructure } from './utils/ensureConfigStructure';\nimport { ensureDependencies } from './utils/ensureDependencies';\nimport { ensureOxlintConfig } from './utils/ensureOxlintConfig';\nimport { describeRemovedOptions, removedOptions } from './utils/removedOptions';\nimport { filterSilencedRules, warnUnknownSilencedRules } from './utils/silenceRules';\n\ninterface CommonEntryFields {\n ignores?: string[];\n globals?: Linter.Globals;\n}\n\ninterface JsEntry extends CommonEntryFields {\n files: string[];\n}\n\ninterface TsEntry extends CommonEntryFields {\n files: string[];\n tsconfigPaths: string[];\n}\n\ninterface VueEntry extends CommonEntryFields {\n files: string[];\n globalComponents?: string[];\n}\n\ninterface VueTsEntry extends CommonEntryFields {\n files: string[];\n globalComponents?: string[];\n tsconfigPaths: string[];\n}\n\ninterface TestEntry extends CommonEntryFields {\n files: string[];\n}\n\ninterface SpellCheckerOptions {\n ignoredPaths?: string[];\n customWordListFile?: string;\n}\n\nexport interface Config {\n ignores?: string[];\n\n javascript?: JsEntry[];\n javascriptDom?: JsEntry[];\n javascriptNode?: JsEntry[];\n typescript?: TsEntry[];\n typescriptDom?: TsEntry[];\n typescriptNode?: TsEntry[];\n vue2?: VueEntry[];\n vue3?: VueEntry[];\n vue2Typescript?: VueTsEntry[];\n vue3Typescript?: VueTsEntry[];\n vue2OptionsApi?: VueEntry[];\n vue3OptionsApi?: VueEntry[];\n vue2TypescriptOptionsApi?: VueTsEntry[];\n vue3TypescriptOptionsApi?: VueTsEntry[];\n jest?: TestEntry[];\n vitest?: TestEntry[];\n jsdocBasedTs?: TsEntry[];\n\n jquery?: JqueryEntry[];\n strict?: boolean | string[];\n spellChecker?: SpellCheckerOptions;\n silenceRules?: string[];\n configFiles?: false | string[];\n}\n\nconst reservedKeys = new Set([\n 'ignores',\n 'jquery',\n 'strict',\n 'spellChecker',\n 'silenceRules',\n 'configFiles',\n]);\n\nfunction assertNoRemovedKeys (config: Config): void {\n const details = describeRemovedOptions(Object.keys(config));\n\n if (details === null) {\n return;\n }\n\n throw new Error(`@useinsider/eslint-config: removed option(s) passed to useInsider():\\n${details}`);\n}\n\n// A key that is neither reserved nor a scope used to be dropped without a word, so a misspelled\n// scope name silently disabled that scope. The layout supports `insider.lint.{js,mjs,cjs}`, so there\n// is no type check standing behind this for every consumer.\nfunction assertNoUnknownKeys (config: Config): void {\n const unknown = Object.keys(config)\n .filter(key => !reservedKeys.has(key) && !removedOptions.has(key) && !isScopeName(key));\n\n if (unknown.length === 0) {\n return;\n }\n\n throw new Error(\n `@useinsider/eslint-config: unknown option(s) passed to useInsider(): ${unknown.join(', ')}.\\n`\n + ` Scopes: ${scopeNames().join(', ')}\\n`\n + ` Other options: ${[...reservedKeys].join(', ')}`\n );\n}\n\nfunction isProcessableScopeKey (key: string): boolean {\n return !reservedKeys.has(key) && isScopeName(key);\n}\n\nasync function collectScopeBlocks (config: Config): Promise<Linter.Config[]> {\n const scopeKeys = Object.keys(config).filter(isProcessableScopeKey);\n\n return scopeKeys.reduce<Promise<Linter.Config[]>>(async (accumulator, key) => {\n const blocks = await accumulator;\n const entries = config[key as keyof Config] as ScopeEntry[] | undefined;\n\n if (!entries || entries.length === 0) {\n return blocks;\n }\n\n const scopeBlocks = await buildScopeBlocks(key as Parameters<typeof buildScopeBlocks>[0], entries);\n\n return [...blocks, ...scopeBlocks];\n }, Promise.resolve([]));\n}\n\nfunction applySilenceRules (blocks: Linter.Config[], perCallSilence: string[] | undefined): void {\n if (perCallSilence) {\n warnUnknownSilencedRules(\n blocks.flatMap(block => Object.keys(block.rules ?? {})),\n perCallSilence\n );\n }\n\n blocks.forEach(block => {\n if (!block.rules) {\n return;\n }\n\n block.rules = perCallSilence\n ? filterSilencedRules(block.rules, perCallSilence)\n : filterSilencedRules(block.rules);\n });\n}\n\n/** Resolved return type of {@link Renderers.useInsiderESLint}: a Promise of an ESLint flat-config array. */\nexport type UseInsiderResult = Promise<Linter.Config[]>;\n\nexport interface Renderers {\n useInsiderESLint: () => UseInsiderResult;\n useInsiderOXC: () => Promise<OxlintRendererConfig>;\n}\n\nfunction buildIgnoresBlocks (ignores: string[] | undefined): Linter.Config[] {\n if (!ignores || ignores.length === 0) {\n return [];\n }\n\n return [{ ignores: [...ignores] }];\n}\n\n// Emission order is the precedence contract: later blocks win. `configFiles` and `strict` must be\n// able to override the language scopes, and `spellChecker` must survive all of them.\nasync function buildBaseBlocks (config: Config): Promise<Linter.Config[]> {\n const scopeBlocks = await collectScopeBlocks(config);\n const strictBlocks = await buildStrictBlocks(config.strict);\n\n return [\n ...buildIgnoresBlocks(config.ignores),\n ...buildUnusedDirectiveBlocks(),\n ...scopeBlocks,\n ...buildJqueryBlocks(config.jquery),\n ...buildConfigFilesBlocks(config.configFiles),\n ...strictBlocks,\n ...buildLintTopologyBlocks(),\n ...buildSpellCheckerBlocks(config.spellChecker),\n ];\n}\n\nasync function renderEslint (config: Config): UseInsiderResult {\n await ensureDependencies();\n ensureOxlintConfig();\n\n const baseBlocks = await buildBaseBlocks(config);\n const blocks = [...baseBlocks, ...buildOxlintSuppressionBlocks(baseBlocks)];\n\n applySilenceRules(blocks, config.silenceRules);\n\n return defineConfig(blocks);\n}\n\nasync function renderOxlint (config: Config): Promise<OxlintRendererConfig> {\n const baseBlocks = await buildBaseBlocks(config);\n\n applySilenceRules(baseBlocks, config.silenceRules);\n\n return buildOxlintConfig(baseBlocks, config.ignores);\n}\n\nexport function useInsider (config: Config): Renderers {\n assertNoRemovedKeys(config);\n assertNoUnknownKeys(config);\n ensureConfigStructure();\n\n return {\n useInsiderESLint: () => renderEslint(config),\n useInsiderOXC: () => renderOxlint(config),\n };\n}\n\nexport { merge } from './utils/merge';\n\nexport { mergeAll } from './utils/mergeAllConfig';\n\nexport { silenceDependencyWarning } from './utils/ensureDependencies';\n\nexport { ensureConfigStructure } from './utils/ensureConfigStructure';\n\nexport { ensureOxlintConfig } from './utils/ensureOxlintConfig';\n\nexport { silenceRules } from './utils/silenceRules';\n\nexport type { OxlintRendererConfig } from './builders/oxlint';\n"],"mappings":"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"}