@useinsider/eslint-config 1.13.0 → 1.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/README.md +366 -58
  2. package/dist/builders/configFiles.d.ts +12 -0
  3. package/dist/builders/jquery.d.ts +5 -0
  4. package/dist/builders/scopeBlocks.d.ts +49 -0
  5. package/dist/builders/spellChecker.d.ts +7 -0
  6. package/dist/builders/strict.d.ts +2 -0
  7. package/dist/builders/typescript.d.ts +6 -0
  8. package/dist/builders/vue.d.ts +8 -0
  9. package/dist/cli.cjs +4538 -0
  10. package/dist/cli.cjs.map +1 -0
  11. package/dist/configs/config/dependencies.d.ts +1 -0
  12. package/dist/configs/javascript/dependencies.d.ts +1 -0
  13. package/dist/configs/javascript-dom/dependencies.d.ts +1 -0
  14. package/dist/configs/javascript-node/dependencies.d.ts +1 -0
  15. package/dist/configs/jest/dependencies.d.ts +3 -0
  16. package/dist/configs/jsdoc-based-ts/dependencies.d.ts +6 -0
  17. package/dist/configs/strict/dependencies.d.ts +3 -0
  18. package/dist/configs/typescript/dependencies.d.ts +6 -0
  19. package/dist/configs/typescript-dom/dependencies.d.ts +6 -0
  20. package/dist/configs/typescript-node/dependencies.d.ts +6 -0
  21. package/dist/configs/vitest/dependencies.d.ts +3 -0
  22. package/dist/configs/vitest/index.d.ts +3 -0
  23. package/dist/configs/vue2/dependencies.d.ts +5 -0
  24. package/dist/configs/vue2-options-api/dependencies.d.ts +5 -0
  25. package/dist/configs/vue2-options-api/index.d.ts +1208 -0
  26. package/dist/configs/vue2-typescript/dependencies.d.ts +9 -0
  27. package/dist/configs/vue2-typescript-options-api/dependencies.d.ts +9 -0
  28. package/dist/configs/vue2-typescript-options-api/index.d.ts +3 -0
  29. package/dist/configs/vue3/dependencies.d.ts +5 -0
  30. package/dist/configs/vue3-options-api/dependencies.d.ts +5 -0
  31. package/dist/configs/vue3-options-api/index.d.ts +1208 -0
  32. package/dist/configs/vue3-typescript/dependencies.d.ts +9 -0
  33. package/dist/configs/vue3-typescript-options-api/dependencies.d.ts +9 -0
  34. package/dist/configs/vue3-typescript-options-api/index.d.ts +3 -0
  35. package/dist/{javascript-ZbGsFE17.cjs → javascript-CrNAuq8X.cjs} +2 -2
  36. package/dist/{javascript-ZbGsFE17.cjs.map → javascript-CrNAuq8X.cjs.map} +1 -1
  37. package/dist/{javascript-BXgxOHrE.js → javascript-DBh1tdoj.js} +2 -2
  38. package/dist/{javascript-BXgxOHrE.js.map → javascript-DBh1tdoj.js.map} +1 -1
  39. package/dist/{javascript-dom-D7RX0w0r.cjs → javascript-dom-qddIl6lD.cjs} +2 -2
  40. package/dist/{javascript-dom-D7RX0w0r.cjs.map → javascript-dom-qddIl6lD.cjs.map} +1 -1
  41. package/dist/{javascript-dom-DQiJS6LF.js → javascript-dom-vHj4V_jJ.js} +2 -2
  42. package/dist/{javascript-dom-DQiJS6LF.js.map → javascript-dom-vHj4V_jJ.js.map} +1 -1
  43. package/dist/{javascript-node-fII8MlI4.cjs → javascript-node-CymkpeIN.cjs} +2 -2
  44. package/dist/{javascript-node-fII8MlI4.cjs.map → javascript-node-CymkpeIN.cjs.map} +1 -1
  45. package/dist/{javascript-node-DDpIBysN.js → javascript-node-rbQ7OZX2.js} +2 -2
  46. package/dist/{javascript-node-DDpIBysN.js.map → javascript-node-rbQ7OZX2.js.map} +1 -1
  47. package/dist/main.cjs +530 -52
  48. package/dist/main.cjs.map +1 -1
  49. package/dist/main.d.ts +56 -21
  50. package/dist/main.js +531 -55
  51. package/dist/main.js.map +1 -1
  52. package/dist/rules/vue-options-api.d.ts +2 -0
  53. package/dist/{stylistic-Cca81A-Y.js → stylistic-C527N_5D.js} +22 -20
  54. package/dist/stylistic-C527N_5D.js.map +1 -0
  55. package/dist/{stylistic-BltudTa0.cjs → stylistic-_qagyIah.cjs} +22 -20
  56. package/dist/stylistic-_qagyIah.cjs.map +1 -0
  57. package/dist/{typescript-Z0gBgZeY.js → typescript-BkxC1Ebj.js} +3 -3
  58. package/dist/{typescript-Z0gBgZeY.js.map → typescript-BkxC1Ebj.js.map} +1 -1
  59. package/dist/{typescript-RDy5oH7o.cjs → typescript-Cm5y5BRu.cjs} +3 -3
  60. package/dist/{typescript-RDy5oH7o.cjs.map → typescript-Cm5y5BRu.cjs.map} +1 -1
  61. package/dist/{typescript-dom-DUh1spmb.cjs → typescript-dom-B5cwc97i.cjs} +2 -2
  62. package/dist/{typescript-dom-DUh1spmb.cjs.map → typescript-dom-B5cwc97i.cjs.map} +1 -1
  63. package/dist/{typescript-dom-BFinGO4G.js → typescript-dom-BMG-VaTV.js} +2 -2
  64. package/dist/{typescript-dom-BFinGO4G.js.map → typescript-dom-BMG-VaTV.js.map} +1 -1
  65. package/dist/{typescript-node-ClKSHtBn.cjs → typescript-node-BPHyiIve.cjs} +2 -2
  66. package/dist/{typescript-node-ClKSHtBn.cjs.map → typescript-node-BPHyiIve.cjs.map} +1 -1
  67. package/dist/{typescript-node-B3akGwfD.js → typescript-node-D_KHq9pf.js} +2 -2
  68. package/dist/{typescript-node-B3akGwfD.js.map → typescript-node-D_KHq9pf.js.map} +1 -1
  69. package/dist/utils/ensureConfigStructure.d.ts +17 -0
  70. package/dist/vitest-BgPQ6GrC.js +15 -0
  71. package/dist/vitest-BgPQ6GrC.js.map +1 -0
  72. package/dist/vitest-Cxe6To8m.cjs +17 -0
  73. package/dist/vitest-Cxe6To8m.cjs.map +1 -0
  74. package/dist/{vue-ABpPpVRF.cjs → vue-BSB1UZUR.cjs} +1 -1
  75. package/dist/{vue-ABpPpVRF.cjs.map → vue-BSB1UZUR.cjs.map} +1 -1
  76. package/dist/{vue-DN4l4tpE.js → vue-W9Dr0NU_.js} +1 -1
  77. package/dist/{vue-DN4l4tpE.js.map → vue-W9Dr0NU_.js.map} +1 -1
  78. package/dist/vue-options-api-DOwpLXkl.cjs +21 -0
  79. package/dist/vue-options-api-DOwpLXkl.cjs.map +1 -0
  80. package/dist/vue-options-api-Dx5bF7ak.js +16 -0
  81. package/dist/vue-options-api-Dx5bF7ak.js.map +1 -0
  82. package/dist/{vue2-DSL0XmaS.cjs → vue2-BO5tkjc4.cjs} +2 -2
  83. package/dist/{vue2-DSL0XmaS.cjs.map → vue2-BO5tkjc4.cjs.map} +1 -1
  84. package/dist/{vue2-BiP0fuu1.js → vue2-DkvfPqh_.js} +2 -2
  85. package/dist/{vue2-BiP0fuu1.js.map → vue2-DkvfPqh_.js.map} +1 -1
  86. package/dist/{vue2-Bh7W369C.cjs → vue2-XNhU8qvc.cjs} +3 -3
  87. package/dist/{vue2-Bh7W369C.cjs.map → vue2-XNhU8qvc.cjs.map} +1 -1
  88. package/dist/{vue2-DDKBhsLm.js → vue2-npomS1zY.js} +3 -3
  89. package/dist/{vue2-DDKBhsLm.js.map → vue2-npomS1zY.js.map} +1 -1
  90. package/dist/vue2-options-api-BPw5U0yK.js +25 -0
  91. package/dist/vue2-options-api-BPw5U0yK.js.map +1 -0
  92. package/dist/vue2-options-api-zm_Ppsnb.cjs +31 -0
  93. package/dist/vue2-options-api-zm_Ppsnb.cjs.map +1 -0
  94. package/dist/vue2-typescript-B2ubjEbm.cjs +18 -0
  95. package/dist/vue2-typescript-B2ubjEbm.cjs.map +1 -0
  96. package/dist/{vue2-typescript-CUqjxRHT.js → vue2-typescript-DV30OSCU.js} +4 -13
  97. package/dist/vue2-typescript-DV30OSCU.js.map +1 -0
  98. package/dist/vue2-typescript-DkeW8a4q.js +13 -0
  99. package/dist/vue2-typescript-DkeW8a4q.js.map +1 -0
  100. package/dist/vue2-typescript-options-api-Dxl4Cj_u.js +42 -0
  101. package/dist/vue2-typescript-options-api-Dxl4Cj_u.js.map +1 -0
  102. package/dist/vue2-typescript-options-api-Tj8_pTDc.cjs +50 -0
  103. package/dist/vue2-typescript-options-api-Tj8_pTDc.cjs.map +1 -0
  104. package/dist/{vue2-typescript-GmtjjCxx.cjs → vue2-typescript-qUvTF_0O.cjs} +5 -14
  105. package/dist/vue2-typescript-qUvTF_0O.cjs.map +1 -0
  106. package/dist/{vue3-CKwnKeS6.js → vue3-BnQYXB3K.js} +3 -3
  107. package/dist/{vue3-CKwnKeS6.js.map → vue3-BnQYXB3K.js.map} +1 -1
  108. package/dist/{vue3-BtNhSn_w.cjs → vue3-Dexa-ftV.cjs} +3 -3
  109. package/dist/{vue3-BtNhSn_w.cjs.map → vue3-Dexa-ftV.cjs.map} +1 -1
  110. package/dist/vue3-options-api-Fl27U2nN.cjs +31 -0
  111. package/dist/vue3-options-api-Fl27U2nN.cjs.map +1 -0
  112. package/dist/vue3-options-api-cejoqzVH.js +25 -0
  113. package/dist/vue3-options-api-cejoqzVH.js.map +1 -0
  114. package/dist/{vue3-typescript-CbM4dYzN.js → vue3-typescript-C65tDgFp.js} +3 -3
  115. package/dist/{vue3-typescript-CbM4dYzN.js.map → vue3-typescript-C65tDgFp.js.map} +1 -1
  116. package/dist/{vue3-typescript-P2UoKs0V.cjs → vue3-typescript-CzR7L5ep.cjs} +3 -3
  117. package/dist/{vue3-typescript-P2UoKs0V.cjs.map → vue3-typescript-CzR7L5ep.cjs.map} +1 -1
  118. package/dist/vue3-typescript-options-api-D56mHjp4.cjs +49 -0
  119. package/dist/vue3-typescript-options-api-D56mHjp4.cjs.map +1 -0
  120. package/dist/vue3-typescript-options-api-DL7JFqMJ.js +41 -0
  121. package/dist/vue3-typescript-options-api-DL7JFqMJ.js.map +1 -0
  122. package/package.json +29 -6
  123. package/dist/stylistic-BltudTa0.cjs.map +0 -1
  124. package/dist/stylistic-Cca81A-Y.js.map +0 -1
  125. package/dist/vue2-typescript-CUqjxRHT.js.map +0 -1
  126. package/dist/vue2-typescript-GmtjjCxx.cjs.map +0 -1
package/dist/cli.cjs ADDED
@@ -0,0 +1,4538 @@
1
+ #!/usr/bin/env node
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const require_chunk = require("./chunk-CKQMccvm.cjs");
4
+ let globals = require("globals");
5
+ globals = require_chunk.__toESM(globals, 1);
6
+ let node_fs = require("node:fs");
7
+ let node_path = require("node:path");
8
+ let node_url = require("node:url");
9
+ let node_crypto = require("node:crypto");
10
+ let node_os = require("node:os");
11
+ let typescript = require("typescript");
12
+ typescript = require_chunk.__toESM(typescript, 1);
13
+ //#region src/cli/detect.ts
14
+ var flatConfigOrder = [
15
+ "eslint.config.mjs",
16
+ "eslint.config.js",
17
+ "eslint.config.cjs",
18
+ "eslint.config.ts",
19
+ "eslint.config.mts",
20
+ "eslint.config.cts"
21
+ ];
22
+ var legacyConfigOrder = [
23
+ ".eslintrc.cjs",
24
+ ".eslintrc.js",
25
+ ".eslintrc.mjs",
26
+ ".eslintrc.json",
27
+ ".eslintrc.yml",
28
+ ".eslintrc.yaml",
29
+ ".eslintrc"
30
+ ];
31
+ function detectExistingEslintConfig(cwd) {
32
+ const flatHit = flatConfigOrder.map((name) => (0, node_path.join)(cwd, name)).find((candidate) => (0, node_fs.existsSync)(candidate));
33
+ if (flatHit) return {
34
+ path: flatHit,
35
+ kind: "flat"
36
+ };
37
+ const legacyHit = legacyConfigOrder.map((name) => (0, node_path.join)(cwd, name)).find((candidate) => (0, node_fs.existsSync)(candidate));
38
+ if (legacyHit) return {
39
+ path: legacyHit,
40
+ kind: "legacy"
41
+ };
42
+ const pkgPath = (0, node_path.join)(cwd, "package.json");
43
+ if (!(0, node_fs.existsSync)(pkgPath)) return null;
44
+ try {
45
+ const raw = (0, node_fs.readFileSync)(pkgPath, "utf8");
46
+ const parsed = JSON.parse(raw);
47
+ if (parsed.eslintConfig && typeof parsed.eslintConfig === "object") return {
48
+ path: pkgPath,
49
+ kind: "legacy"
50
+ };
51
+ } catch {
52
+ return null;
53
+ }
54
+ return null;
55
+ }
56
+ var stringTokenPattern = /"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'/gu;
57
+ var lineCommentPattern = /\/\/[^\n]*/gu;
58
+ var blockCommentPattern = /\/\*[\s\S]*?\*\//gu;
59
+ var placeholderPattern = /__JSONC_TOKEN_(\d+)__/gu;
60
+ function stripJsonComments(source) {
61
+ const tokens = [];
62
+ return source.replace(stringTokenPattern, (match) => {
63
+ const index = tokens.length;
64
+ tokens.push(match);
65
+ return `__JSONC_TOKEN_${index}__`;
66
+ }).replace(blockCommentPattern, "").replace(lineCommentPattern, "").replace(placeholderPattern, (_match, indexValue) => tokens[Number(indexValue)]);
67
+ }
68
+ function stripTrailingCommas(source) {
69
+ return source.replace(/,(\s*[}\]])/g, "$1");
70
+ }
71
+ function readTsconfig(absPath) {
72
+ const stripped = stripTrailingCommas(stripJsonComments((0, node_fs.readFileSync)(absPath, "utf8")));
73
+ return JSON.parse(stripped);
74
+ }
75
+ function resolveTsconfigReferences(cwd) {
76
+ const rootPath = (0, node_path.join)(cwd, "tsconfig.json");
77
+ if (!(0, node_fs.existsSync)(rootPath)) return null;
78
+ const parsed = readTsconfig(rootPath);
79
+ const refs = parsed.references;
80
+ if (!refs || refs.length === 0) return null;
81
+ const hasFiles = Array.isArray(parsed.files) && parsed.files.length > 0;
82
+ const hasInclude = Array.isArray(parsed.include) && parsed.include.length > 0;
83
+ if (hasFiles || hasInclude) return null;
84
+ return {
85
+ rootPath,
86
+ refs: refs.map((ref) => ref.path)
87
+ };
88
+ }
89
+ //#endregion
90
+ //#region src/cli/detectVueApiPattern.ts
91
+ var SKIP_DIRS = new Set([
92
+ "node_modules",
93
+ ".git",
94
+ ".svn",
95
+ ".hg",
96
+ "dist",
97
+ "build",
98
+ "out",
99
+ "coverage",
100
+ ".next",
101
+ ".nuxt",
102
+ ".output",
103
+ ".cache",
104
+ ".turbo",
105
+ ".parcel-cache",
106
+ ".vite"
107
+ ]);
108
+ var MAX_FILES = 5e3;
109
+ var MATCH_THRESHOLD = .95;
110
+ var MIN_SAMPLES_PER_BUCKET = 2;
111
+ var SUFFIX_CANDIDATES = [
112
+ ".options",
113
+ ".classic",
114
+ ".legacy",
115
+ ".opts",
116
+ ".setup",
117
+ ".composition",
118
+ ".modern"
119
+ ];
120
+ var DIRECTORY_CANDIDATES = [
121
+ {
122
+ options: "options",
123
+ composition: "composition"
124
+ },
125
+ {
126
+ options: "Options",
127
+ composition: "Composition"
128
+ },
129
+ {
130
+ options: "options-api",
131
+ composition: "composition-api"
132
+ },
133
+ {
134
+ options: "classic",
135
+ composition: "modern"
136
+ },
137
+ {
138
+ options: "legacy",
139
+ composition: "next"
140
+ }
141
+ ];
142
+ function safeReaddir(path) {
143
+ try {
144
+ return (0, node_fs.readdirSync)(path, {
145
+ withFileTypes: true,
146
+ encoding: "utf8"
147
+ });
148
+ } catch {
149
+ return [];
150
+ }
151
+ }
152
+ function walkDir(dir, skipDirs, limit, accumulator) {
153
+ if (accumulator.truncated || accumulator.files.length >= limit) return;
154
+ safeReaddir(dir).forEach((entry) => {
155
+ if (accumulator.files.length >= limit) {
156
+ accumulator.truncated = true;
157
+ return;
158
+ }
159
+ const full = (0, node_path.join)(dir, entry.name);
160
+ if (entry.isDirectory()) {
161
+ if (!skipDirs.has(entry.name)) walkDir(full, skipDirs, limit, accumulator);
162
+ return;
163
+ }
164
+ if (entry.isFile() && entry.name.endsWith(".vue")) accumulator.files.push(full);
165
+ });
166
+ }
167
+ function scanVueFiles(options) {
168
+ const limit = options.maxFiles ?? MAX_FILES;
169
+ const skipDirs = options.skipDirs ?? SKIP_DIRS;
170
+ const accumulator = {
171
+ files: [],
172
+ truncated: false
173
+ };
174
+ walkDir(options.cwd, skipDirs, limit, accumulator);
175
+ return {
176
+ files: accumulator.files,
177
+ truncated: accumulator.truncated
178
+ };
179
+ }
180
+ function classifyVueContent(content) {
181
+ const hasSetupScript = /<script[^>]*\bsetup\b/i.test(content);
182
+ const hasPlainScript = /<script(?:(?!\bsetup\b)[^>])*>/i.test(content);
183
+ if (hasSetupScript && hasPlainScript) return "mixed";
184
+ if (hasSetupScript) return "composition";
185
+ return "options";
186
+ }
187
+ function classifyVueFiles(absolutePaths, cwd) {
188
+ return absolutePaths.reduce((classifications, absolutePath) => {
189
+ let content;
190
+ try {
191
+ if ((0, node_fs.statSync)(absolutePath).size > 2e6) return classifications;
192
+ content = (0, node_fs.readFileSync)(absolutePath, "utf8");
193
+ } catch {
194
+ return classifications;
195
+ }
196
+ const api = classifyVueContent(content);
197
+ const relativePath = (0, node_path.relative)(cwd, absolutePath);
198
+ classifications.push({
199
+ relativePath: relativePath.split(node_path.sep).join("/"),
200
+ api: api === "mixed" ? "composition" : api
201
+ });
202
+ return classifications;
203
+ }, []);
204
+ }
205
+ function basenameOf(relativePath) {
206
+ const lastSlash = relativePath.lastIndexOf("/");
207
+ return lastSlash === -1 ? relativePath : relativePath.slice(lastSlash + 1);
208
+ }
209
+ function ratio(matched, total) {
210
+ return total === 0 ? 0 : matched / total;
211
+ }
212
+ function suffixIsViable(targetMatches, otherMatches, targetTotal, otherTotal) {
213
+ const targetRatio = ratio(targetMatches.length, targetTotal);
214
+ const otherRatio = ratio(otherMatches.length, otherTotal);
215
+ if (targetRatio < MATCH_THRESHOLD || otherRatio < MATCH_THRESHOLD) return false;
216
+ return targetMatches.length >= MIN_SAMPLES_PER_BUCKET && otherMatches.length >= MIN_SAMPLES_PER_BUCKET;
217
+ }
218
+ function suffixMatchesTargetingApi(suffix, targetApi, optionsFiles, compositionFiles) {
219
+ const fullSuffix = `${suffix}.vue`;
220
+ const targetIsOptions = targetApi === "options";
221
+ const targetFiles = targetIsOptions ? optionsFiles : compositionFiles;
222
+ const otherFiles = targetIsOptions ? compositionFiles : optionsFiles;
223
+ const targetMatches = targetFiles.filter((path) => basenameOf(path).endsWith(fullSuffix));
224
+ const otherMatches = otherFiles.filter((path) => !basenameOf(path).endsWith(fullSuffix));
225
+ if (!suffixIsViable(targetMatches, otherMatches, targetFiles.length, otherFiles.length)) return null;
226
+ const optionsMatches = targetIsOptions ? targetMatches : otherMatches;
227
+ const compositionMatches = targetIsOptions ? otherMatches : targetMatches;
228
+ const optionsPattern = targetIsOptions ? `**/*${fullSuffix}` : "**/*.vue";
229
+ return {
230
+ kind: "suffix",
231
+ compositionPattern: targetIsOptions ? "**/*.vue" : `**/*${fullSuffix}`,
232
+ optionsPattern,
233
+ suffix: fullSuffix,
234
+ targetApi,
235
+ samples: {
236
+ composition: compositionMatches.slice(0, 5),
237
+ options: optionsMatches.slice(0, 5)
238
+ }
239
+ };
240
+ }
241
+ function suffixMatches(suffix, optionsFiles, compositionFiles) {
242
+ return suffixMatchesTargetingApi(suffix, "options", optionsFiles, compositionFiles) ?? suffixMatchesTargetingApi(suffix, "composition", optionsFiles, compositionFiles);
243
+ }
244
+ function detectSuffix(optionsFiles, compositionFiles) {
245
+ return SUFFIX_CANDIDATES.reduce((found, suffix) => {
246
+ if (found) return found;
247
+ return suffixMatches(suffix, optionsFiles, compositionFiles);
248
+ }, null);
249
+ }
250
+ function directoryMatches(options, composition, optionsFiles, compositionFiles) {
251
+ const optionsToken = `/${options}/`;
252
+ const optionsPrefix = `${options}/`;
253
+ const inOptionsDir = (path) => path.includes(optionsToken) || path.startsWith(optionsPrefix);
254
+ const optionsMatches = optionsFiles.filter(inOptionsDir);
255
+ const compositionMatches = compositionFiles.filter((path) => !inOptionsDir(path));
256
+ const optionsRatio = ratio(optionsMatches.length, optionsFiles.length);
257
+ const compositionRatio = ratio(compositionMatches.length, compositionFiles.length);
258
+ if (optionsRatio < MATCH_THRESHOLD || compositionRatio < MATCH_THRESHOLD) return null;
259
+ if (optionsMatches.length < MIN_SAMPLES_PER_BUCKET || compositionMatches.length < MIN_SAMPLES_PER_BUCKET) return null;
260
+ return {
261
+ kind: "directory",
262
+ compositionPattern: `**/${composition}/**/*.vue`,
263
+ optionsPattern: `**/${options}/**/*.vue`,
264
+ compositionDir: composition,
265
+ optionsDir: options,
266
+ samples: {
267
+ composition: compositionMatches.slice(0, 5),
268
+ options: optionsMatches.slice(0, 5)
269
+ }
270
+ };
271
+ }
272
+ function detectDirectory(optionsFiles, compositionFiles) {
273
+ return DIRECTORY_CANDIDATES.reduce((found, candidate) => {
274
+ if (found) return found;
275
+ return directoryMatches(candidate.options, candidate.composition, optionsFiles, compositionFiles);
276
+ }, null);
277
+ }
278
+ function detectVueApiPattern(input) {
279
+ const classifications = input.classifications ?? classifyVueFiles(scanVueFiles(input).files, input.cwd);
280
+ if (classifications.length === 0) return {
281
+ kind: "none",
282
+ compositionFiles: [],
283
+ optionsFiles: []
284
+ };
285
+ const optionsFiles = classifications.filter((item) => item.api === "options").map((item) => item.relativePath);
286
+ const compositionFiles = classifications.filter((item) => item.api === "composition").map((item) => item.relativePath);
287
+ if (optionsFiles.length === 0 || compositionFiles.length === 0) return {
288
+ kind: "none",
289
+ compositionFiles,
290
+ optionsFiles
291
+ };
292
+ const suffixHit = detectSuffix(optionsFiles, compositionFiles);
293
+ if (suffixHit) return suffixHit;
294
+ const directoryHit = detectDirectory(optionsFiles, compositionFiles);
295
+ if (directoryHit) return directoryHit;
296
+ return {
297
+ kind: "ambiguous",
298
+ reason: "Options and Composition files do not share a consistent suffix or directory split.",
299
+ compositionFiles: compositionFiles.slice(0, 5),
300
+ optionsFiles: optionsFiles.slice(0, 5)
301
+ };
302
+ }
303
+ //#endregion
304
+ //#region src/cli/dispatch.ts
305
+ var yesFlags = new Set(["--yes", "-y"]);
306
+ var noInstallFlags = new Set(["--no-install"]);
307
+ function isYesFlag(arg) {
308
+ return yesFlags.has(arg);
309
+ }
310
+ function isNoInstallFlag(arg) {
311
+ return noInstallFlags.has(arg);
312
+ }
313
+ function parseMigrateArgs(rest) {
314
+ const yes = rest.some(isYesFlag);
315
+ const noInstall = rest.some(isNoInstallFlag);
316
+ const positional = rest.filter((arg) => !isYesFlag(arg) && !isNoInstallFlag(arg));
317
+ return {
318
+ target: positional.length > 0 ? positional[positional.length - 1] : void 0,
319
+ yes,
320
+ noInstall
321
+ };
322
+ }
323
+ function parseScaffoldArgs(argv) {
324
+ return { yes: argv.some(isYesFlag) };
325
+ }
326
+ function printUsage(stderr, unknown) {
327
+ stderr(`[useinsider/eslint-config] Unknown subcommand: ${unknown}`);
328
+ stderr("Usage:");
329
+ stderr(" npx @useinsider/eslint-config [--yes|-y] Scaffold a new eslint.config.mjs");
330
+ stderr(" npx @useinsider/eslint-config migrate [path] [--yes|-y] [--no-install]");
331
+ stderr(" Migrate an existing v1 useInsider() config to v2");
332
+ }
333
+ function isScaffoldArgv(argv) {
334
+ return argv.length === 0 || argv.every((arg) => isYesFlag(arg));
335
+ }
336
+ async function dispatch(argv, cwd, deps) {
337
+ if (isScaffoldArgv(argv)) {
338
+ const { yes } = parseScaffoldArgs(argv);
339
+ return deps.scaffold({
340
+ cwd,
341
+ yes
342
+ });
343
+ }
344
+ const [subcommand, ...rest] = argv;
345
+ if (subcommand === "migrate") {
346
+ const { target, yes, noInstall } = parseMigrateArgs(rest);
347
+ return deps.migrate({
348
+ cwd,
349
+ target,
350
+ yes,
351
+ noInstall
352
+ });
353
+ }
354
+ printUsage(deps.stderr, subcommand);
355
+ return 1;
356
+ }
357
+ //#endregion
358
+ //#region src/configs/jest/dependencies.ts
359
+ var dependencies$14 = { "eslint-plugin-jest": true };
360
+ //#endregion
361
+ //#region src/configs/typescript/dependencies.ts
362
+ var dependencies$13 = {
363
+ typescript: false,
364
+ "typescript-eslint": false,
365
+ "@typescript-eslint/parser": false,
366
+ "@typescript-eslint/eslint-plugin": false
367
+ };
368
+ //#endregion
369
+ //#region src/configs/vitest/dependencies.ts
370
+ var dependencies$12 = { "@vitest/eslint-plugin": true };
371
+ //#endregion
372
+ //#region src/configs/vue2/dependencies.ts
373
+ var dependencies$11 = {
374
+ "eslint-plugin-vue": true,
375
+ "eslint-plugin-vue-scoped-css": true,
376
+ "vue-eslint-parser": true
377
+ };
378
+ //#endregion
379
+ //#region src/configs/vue2-typescript/dependencies.ts
380
+ var dependencies$10 = {
381
+ "eslint-plugin-vue": true,
382
+ "eslint-plugin-vue-scoped-css": true,
383
+ "vue-eslint-parser": true,
384
+ typescript: false,
385
+ "typescript-eslint": false,
386
+ "@typescript-eslint/parser": false,
387
+ "@typescript-eslint/eslint-plugin": false
388
+ };
389
+ //#endregion
390
+ //#region src/configs/vue3/dependencies.ts
391
+ var dependencies$9 = {
392
+ "eslint-plugin-vue": true,
393
+ "eslint-plugin-vue-scoped-css": true,
394
+ "vue-eslint-parser": true
395
+ };
396
+ //#endregion
397
+ //#region src/configs/vue3-typescript/dependencies.ts
398
+ var dependencies$8 = {
399
+ "eslint-plugin-vue": true,
400
+ "eslint-plugin-vue-scoped-css": true,
401
+ "vue-eslint-parser": true,
402
+ typescript: false,
403
+ "typescript-eslint": false,
404
+ "@typescript-eslint/parser": false,
405
+ "@typescript-eslint/eslint-plugin": false
406
+ };
407
+ //#endregion
408
+ //#region src/cli/resolveEslintConfigManifest.ts
409
+ function tryReadManifest(candidate) {
410
+ try {
411
+ const raw = (0, node_fs.readFileSync)(candidate, "utf8");
412
+ const parsed = JSON.parse(raw);
413
+ return parsed.name === "@useinsider/eslint-config" ? parsed : null;
414
+ } catch {
415
+ return null;
416
+ }
417
+ }
418
+ function resolveRuntimeDir() {
419
+ const { url } = {};
420
+ if (typeof url === "string" && url.startsWith("file:")) return (0, node_path.dirname)((0, node_url.fileURLToPath)(url));
421
+ if (typeof __dirname === "string") return __dirname;
422
+ return (0, node_path.resolve)(process.cwd(), "node_modules/@useinsider/eslint-config/dist");
423
+ }
424
+ function readOwnEslintConfigManifestFrom(runtimeDir) {
425
+ const found = [
426
+ (0, node_path.resolve)(runtimeDir, "../../package.json"),
427
+ (0, node_path.resolve)(runtimeDir, "../../../package.json"),
428
+ (0, node_path.resolve)(runtimeDir, "../package.json"),
429
+ (0, node_path.resolve)(process.cwd(), "node_modules/@useinsider/eslint-config/package.json")
430
+ ].map(tryReadManifest).find((manifest) => manifest !== null);
431
+ if (!found) throw new Error("Unable to locate @useinsider/eslint-config package.json from CLI runtime");
432
+ return found;
433
+ }
434
+ function readOwnEslintConfigManifest$1() {
435
+ return readOwnEslintConfigManifestFrom(resolveRuntimeDir());
436
+ }
437
+ //#endregion
438
+ //#region src/cli/install.ts
439
+ function toRequiredManifest(manifest) {
440
+ return {
441
+ version: manifest.version ?? "0.0.0",
442
+ dependencies: manifest.dependencies ?? {},
443
+ devDependencies: manifest.devDependencies ?? {},
444
+ peerDependencies: manifest.peerDependencies ?? {},
445
+ optionalDependencies: manifest.optionalDependencies ?? {}
446
+ };
447
+ }
448
+ function lookup(manifest, name) {
449
+ return manifest.dependencies[name] ?? manifest.devDependencies[name] ?? manifest.peerDependencies[name] ?? manifest.optionalDependencies[name];
450
+ }
451
+ function pinned(manifest, name) {
452
+ const version = lookup(manifest, name);
453
+ if (!version) throw new Error(`Unable to resolve pinned version for ${name} from @useinsider/eslint-config manifest`);
454
+ return `${name}@${version.replace(/^(?:\^|~|>=|<=|>|<|=)/u, "")}`;
455
+ }
456
+ function vueDepsFor(major, wantsTypescript) {
457
+ if (wantsTypescript) return major === 2 ? dependencies$10 : dependencies$8;
458
+ return major === 2 ? dependencies$11 : dependencies$9;
459
+ }
460
+ function applyRecord(deps, manifest, record) {
461
+ Object.entries(record).forEach(([name, install]) => {
462
+ if (install) deps.add(pinned(manifest, name));
463
+ });
464
+ }
465
+ function buildDependencyList(answers, rawManifest = readOwnEslintConfigManifest$1()) {
466
+ const manifest = toRequiredManifest(rawManifest);
467
+ const deps = /* @__PURE__ */ new Set();
468
+ deps.add(`@useinsider/eslint-config@${manifest.version}`);
469
+ deps.add(pinned(manifest, "eslint"));
470
+ deps.add(pinned(manifest, "globals"));
471
+ const wantsTypescript = answers.languages.includes("typescript");
472
+ if (answers.framework === "vue") applyRecord(deps, manifest, vueDepsFor(answers.vueMajor ?? 3, wantsTypescript));
473
+ else if (wantsTypescript) applyRecord(deps, manifest, dependencies$13);
474
+ if (answers.testFramework === "jest") applyRecord(deps, manifest, dependencies$14);
475
+ if (answers.testFramework === "vitest") applyRecord(deps, manifest, dependencies$12);
476
+ return [...deps];
477
+ }
478
+ async function installDependencies(deps) {
479
+ const { installPackage } = await import("@antfu/install-pkg");
480
+ await installPackage([...deps], {
481
+ dev: true,
482
+ additionalArgs: ["-E"]
483
+ });
484
+ }
485
+ //#endregion
486
+ //#region src/cli/installWithRetry.ts
487
+ var lockfileMap = [
488
+ {
489
+ file: "pnpm-lock.yaml",
490
+ manager: "pnpm"
491
+ },
492
+ {
493
+ file: "package-lock.json",
494
+ manager: "npm"
495
+ },
496
+ {
497
+ file: "yarn.lock",
498
+ manager: "yarn"
499
+ },
500
+ {
501
+ file: "bun.lockb",
502
+ manager: "bun"
503
+ }
504
+ ];
505
+ var knownErrorCodes = [
506
+ "ENOSPC",
507
+ "EACCES",
508
+ "EPERM",
509
+ "ENOTFOUND",
510
+ "ETIMEDOUT",
511
+ "ECONNREFUSED",
512
+ "ECONNRESET",
513
+ "EAI_AGAIN",
514
+ "E404",
515
+ "ERR_PNPM_FETCH_404",
516
+ "ERR_PNPM_NO_MATCHING_VERSION"
517
+ ];
518
+ function defaultWipeFs() {
519
+ return {
520
+ rmDir: (path) => {
521
+ (0, node_fs.rmSync)(path, {
522
+ recursive: true,
523
+ force: true
524
+ });
525
+ },
526
+ rmFile: (path) => {
527
+ (0, node_fs.unlinkSync)(path);
528
+ },
529
+ exists: (path) => (0, node_fs.existsSync)(path)
530
+ };
531
+ }
532
+ async function defaultInstaller(specs) {
533
+ const { installPackage } = await import("@antfu/install-pkg");
534
+ await installPackage([...specs], {
535
+ dev: true,
536
+ additionalArgs: ["-E"]
537
+ });
538
+ }
539
+ function detectLockfile(dir, exists) {
540
+ return lockfileMap.map((entry) => ({
541
+ manager: entry.manager,
542
+ lockfilePath: (0, node_path.join)(dir, entry.file)
543
+ })).find((candidate) => exists(candidate.lockfilePath)) ?? null;
544
+ }
545
+ var addCommandMap = {
546
+ pnpm: "pnpm add -D -E",
547
+ npm: "npm install -D -E",
548
+ yarn: "yarn add -D -E",
549
+ bun: "bun add -d -E"
550
+ };
551
+ var removeCommandMap = {
552
+ pnpm: "pnpm remove",
553
+ npm: "npm uninstall",
554
+ yarn: "yarn remove",
555
+ bun: "bun remove"
556
+ };
557
+ function detectPackageManager(dir, fsOps) {
558
+ return detectLockfile(dir, (fsOps ?? defaultWipeFs()).exists)?.manager ?? "pnpm";
559
+ }
560
+ function sortPackagesCaseInsensitive(packages) {
561
+ return [...packages].sort((left, right) => left.toLowerCase().localeCompare(right.toLowerCase()));
562
+ }
563
+ function formatMultilineCommand(header, packages, blockIndent, packageIndent) {
564
+ if (packages.length === 0) return "";
565
+ const sorted = sortPackagesCaseInsensitive(packages);
566
+ const lastIndex = sorted.length - 1;
567
+ const lines = [`${blockIndent}${header} \\`];
568
+ sorted.forEach((pkg, index) => {
569
+ const suffix = index === lastIndex ? "" : " \\";
570
+ lines.push(`${packageIndent}${pkg}${suffix}`);
571
+ });
572
+ return lines.join("\n");
573
+ }
574
+ function formatNextStepsAddCommand(manager, specs, blockIndent = " ", packageIndent = " ") {
575
+ return formatMultilineCommand(addCommandMap[manager], specs, blockIndent, packageIndent);
576
+ }
577
+ function formatNextStepsRemoveCommand(manager, names, blockIndent = " ", packageIndent = " ") {
578
+ return formatMultilineCommand(removeCommandMap[manager], names, blockIndent, packageIndent);
579
+ }
580
+ function manualRecoveryCommand(dir, detected) {
581
+ return `cd ${dir} && rm -rf node_modules ${detected ? (0, node_path.basename)(detected.lockfilePath) : "package-lock.json"} && ${detected?.manager ?? "npm"} install`;
582
+ }
583
+ function buildManualHint(specs, dir, detected) {
584
+ return `Manually add: ${specs.join(" ")}\nRecover with: ${manualRecoveryCommand(dir, detected)}`;
585
+ }
586
+ function isPeerDepFailure(reason) {
587
+ return reason.toLowerCase().includes("--legacy-peer-deps");
588
+ }
589
+ function firstNonEmptyLine(reason) {
590
+ return reason.split(/\r?\n/u).map((segment) => segment.trim()).find((segment) => segment.length > 0) ?? reason.trim();
591
+ }
592
+ function detectErrorCode(reason) {
593
+ return knownErrorCodes.find((code) => new RegExp(`\\b${code}\\b`, "u").test(reason)) ?? null;
594
+ }
595
+ function buildGenericSummary(reason) {
596
+ const code = detectErrorCode(reason);
597
+ const snippet = firstNonEmptyLine(reason);
598
+ if (code && !snippet.includes(code)) return `Dependency install failed (${code}): ${snippet}`;
599
+ return `Dependency install failed: ${snippet}`;
600
+ }
601
+ async function confirmPeerDepWipe(clack, autoConfirm) {
602
+ if (autoConfirm) return true;
603
+ const result = await clack.confirm({
604
+ message: "Install failed.\n\nThis usually means stale dependencies in node_modules conflict with the new ESLint plugin versions.\n\nWipe `node_modules` and the lockfile, then retry install?",
605
+ initialValue: false
606
+ });
607
+ return !clack.isCancel(result) && result === true;
608
+ }
609
+ async function confirmCleanReinstall(clack, autoConfirm, summary) {
610
+ if (autoConfirm) return true;
611
+ const message = `${summary}\n\nWould you like to try a clean reinstall? (removes \`node_modules\` and the lockfile, then re-runs install)`;
612
+ const result = await clack.confirm({
613
+ message,
614
+ initialValue: true
615
+ });
616
+ return !clack.isCancel(result) && result === true;
617
+ }
618
+ function noteWipeFailure(clack, label, path, reason) {
619
+ if (clack.note) clack.note(`Could not remove ${label} at ${path}: ${reason}`, "Warning");
620
+ }
621
+ function safeRemoveDir(clack, fs, path) {
622
+ if (!fs.exists(path)) return;
623
+ try {
624
+ fs.rmDir(path);
625
+ } catch (error) {
626
+ noteWipeFailure(clack, "node_modules", path, error instanceof Error ? error.message : String(error));
627
+ }
628
+ }
629
+ function safeRemoveFile(clack, fs, path) {
630
+ if (!fs.exists(path)) return;
631
+ try {
632
+ fs.rmFile(path);
633
+ } catch (error) {
634
+ noteWipeFailure(clack, "lockfile", path, error instanceof Error ? error.message : String(error));
635
+ }
636
+ }
637
+ function performFullWipe(clack, context) {
638
+ safeRemoveDir(clack, context.fs, (0, node_path.join)(context.dir, "node_modules"));
639
+ if (context.detected) safeRemoveFile(clack, context.fs, context.detected.lockfilePath);
640
+ }
641
+ function noteError(clack, prefix, reason, context, specs) {
642
+ if (!clack.note) return;
643
+ const hint = buildManualHint(specs, context.dir, context.detected);
644
+ clack.note(`${prefix}${reason}\n${hint}`, "Error");
645
+ }
646
+ function noteGenericError(clack, summary, context, specs) {
647
+ if (!clack.note) return;
648
+ const hint = buildManualHint(specs, context.dir, context.detected);
649
+ clack.note(`${summary}\n${hint}`, "Error");
650
+ }
651
+ async function tryRetryInstall(clack, installer, deps, context) {
652
+ try {
653
+ await installer(deps);
654
+ } catch (retryError) {
655
+ noteError(clack, "Retry install failed after wipe: ", retryError instanceof Error ? retryError.message : String(retryError), context, deps);
656
+ }
657
+ }
658
+ async function tryGenericRetryInstall(clack, installer, deps, context) {
659
+ try {
660
+ await installer(deps);
661
+ } catch (retryError) {
662
+ noteGenericError(clack, buildGenericSummary(`Clean reinstall failed: ${retryError instanceof Error ? retryError.message : String(retryError)}`), context, deps);
663
+ }
664
+ }
665
+ async function handlePeerDepFailure(clack, deps, autoConfirm, installer, reason, context) {
666
+ if (!await confirmPeerDepWipe(clack, autoConfirm)) {
667
+ noteError(clack, "Install failed: ", reason, context, deps);
668
+ return;
669
+ }
670
+ performFullWipe(clack, context);
671
+ await tryRetryInstall(clack, installer, deps, context);
672
+ }
673
+ async function handleGenericFailure(clack, deps, autoConfirm, installer, reason, context) {
674
+ const summary = buildGenericSummary(reason);
675
+ if (!await confirmCleanReinstall(clack, autoConfirm, summary)) {
676
+ if (clack.note) clack.note(`${summary}\nSkipping clean reinstall. Please resolve the issue manually and re-run.`, "Error");
677
+ return;
678
+ }
679
+ performFullWipe(clack, context);
680
+ await tryGenericRetryInstall(clack, installer, deps, context);
681
+ }
682
+ async function installWithRetry(opts) {
683
+ const installer = opts.installer ?? defaultInstaller;
684
+ const fs = opts.fsOps ?? defaultWipeFs();
685
+ try {
686
+ await installer(opts.deps);
687
+ } catch (error) {
688
+ const reason = error instanceof Error ? error.message : String(error);
689
+ const context = {
690
+ dir: opts.cwd,
691
+ fs,
692
+ detected: detectLockfile(opts.cwd, fs.exists)
693
+ };
694
+ if (isPeerDepFailure(reason)) {
695
+ await handlePeerDepFailure(opts.clack, opts.deps, opts.autoConfirm, installer, reason, context);
696
+ return;
697
+ }
698
+ await handleGenericFailure(opts.clack, opts.deps, opts.autoConfirm, installer, reason, context);
699
+ }
700
+ }
701
+ //#endregion
702
+ //#region src/cli/template.ts
703
+ var COMPOSITION_DEFAULT_SUFFIX_CHOICES = [
704
+ {
705
+ value: ".options.vue",
706
+ label: "*.options.vue"
707
+ },
708
+ {
709
+ value: ".classic.vue",
710
+ label: "*.classic.vue"
711
+ },
712
+ {
713
+ value: ".legacy.vue",
714
+ label: "*.legacy.vue"
715
+ }
716
+ ];
717
+ var OPTIONS_DEFAULT_SUFFIX_CHOICES = [
718
+ {
719
+ value: ".composition.vue",
720
+ label: "*.composition.vue"
721
+ },
722
+ {
723
+ value: ".setup.vue",
724
+ label: "*.setup.vue"
725
+ },
726
+ {
727
+ value: ".modern.vue",
728
+ label: "*.modern.vue"
729
+ }
730
+ ];
731
+ function getHybridSuffixChoices(defaultApi) {
732
+ return defaultApi === "composition" ? COMPOSITION_DEFAULT_SUFFIX_CHOICES : OPTIONS_DEFAULT_SUFFIX_CHOICES;
733
+ }
734
+ function getHybridDefaultSuffix(defaultApi) {
735
+ return getHybridSuffixChoices(defaultApi)[0].value;
736
+ }
737
+ var indent$1 = " ";
738
+ function hasJavascript(languages) {
739
+ return languages.includes("javascript");
740
+ }
741
+ function hasTypescript(languages) {
742
+ return languages.includes("typescript");
743
+ }
744
+ function isVueBrowserLike(answers) {
745
+ return answers.framework === "vue" && answers.projectType !== "backend";
746
+ }
747
+ function isVueOptionsApi(answers) {
748
+ return answers.vueApiStyle === "options";
749
+ }
750
+ function isVueHybridApi(answers) {
751
+ return answers.vueApiStyle === "hybrid";
752
+ }
753
+ function vueJsScope(major, api) {
754
+ if (major === 2) return api === "options" ? "vue2OptionsApi" : "vue2";
755
+ return api === "options" ? "vue3OptionsApi" : "vue3";
756
+ }
757
+ function vueTsScope(major, api) {
758
+ if (major === 2) return api === "options" ? "vue2TypescriptOptionsApi" : "vue2Typescript";
759
+ return api === "options" ? "vue3TypescriptOptionsApi" : "vue3Typescript";
760
+ }
761
+ function jsAppScopes(answers) {
762
+ if (isVueBrowserLike(answers) && !hasTypescript(answers.languages)) return [vueJsScope(answers.vueMajor ?? 3, isVueOptionsApi(answers) ? "options" : "composition")];
763
+ if (answers.projectType === "backend") return ["javascriptNode"];
764
+ if (answers.projectType === "hybrid") return ["javascriptNode", "javascriptDom"];
765
+ return ["javascriptDom"];
766
+ }
767
+ function tsAppScopes(answers) {
768
+ if (isVueBrowserLike(answers)) return [vueTsScope(answers.vueMajor ?? 3, isVueOptionsApi(answers) ? "options" : "composition")];
769
+ if (answers.projectType === "backend") return ["typescriptNode"];
770
+ if (answers.projectType === "hybrid") return ["typescriptNode", "typescriptDom"];
771
+ return ["typescriptDom"];
772
+ }
773
+ function jsAppFiles(answers) {
774
+ if (isVueBrowserLike(answers) && !hasTypescript(answers.languages)) return ["**/*.{js,jsx,cjs,mjs,vue}"];
775
+ return ["**/*.{js,jsx,cjs,mjs}"];
776
+ }
777
+ function normalizeHybridSuffix(raw) {
778
+ const trimmed = raw.trim();
779
+ const withDot = trimmed.startsWith(".") ? trimmed : `.${trimmed}`;
780
+ return withDot.endsWith(".vue") ? withDot : `${withDot}.vue`;
781
+ }
782
+ function tsAppFiles(answers, scoped) {
783
+ const vue = isVueBrowserLike(answers);
784
+ const prefix = scoped === "app" ? "src/**/*" : "**/*";
785
+ if (vue) return [`${prefix}.{ts,tsx,vue}`];
786
+ return [`${prefix}.{ts,tsx}`];
787
+ }
788
+ function testFilesGlob(languages) {
789
+ const ts = hasTypescript(languages);
790
+ const js = hasJavascript(languages);
791
+ if (ts && js) return ["**/*.{test,spec}.{ts,tsx,js,jsx}"];
792
+ if (ts) return ["**/*.{test,spec}.{ts,tsx}"];
793
+ return ["**/*.{test,spec}.{js,jsx}"];
794
+ }
795
+ function jqueryFilesGlob(answers) {
796
+ const vue = isVueBrowserLike(answers);
797
+ const ts = hasTypescript(answers.languages);
798
+ const js = hasJavascript(answers.languages);
799
+ if (vue) {
800
+ if (ts && js) return ["**/*.{ts,tsx,js,jsx,cjs,mjs,vue}"];
801
+ if (ts) return ["**/*.{ts,tsx,vue}"];
802
+ return ["**/*.{js,jsx,cjs,mjs,vue}"];
803
+ }
804
+ if (ts && js) return ["**/*.{ts,tsx,js,jsx,cjs,mjs}"];
805
+ if (ts) return ["**/*.{ts,tsx}"];
806
+ return ["**/*.{js,jsx,cjs,mjs}"];
807
+ }
808
+ function jsRootConfigFiles() {
809
+ return [
810
+ "*.js",
811
+ "*.cjs",
812
+ "*.mjs"
813
+ ];
814
+ }
815
+ function tsRootConfigFiles() {
816
+ return [
817
+ "*.ts",
818
+ "*.cts",
819
+ "*.mts"
820
+ ];
821
+ }
822
+ function findRole(plan, role) {
823
+ return plan.entries.find((entry) => entry.role === role);
824
+ }
825
+ function isHybridVueJsContext(answers) {
826
+ return isVueBrowserLike(answers) && isVueHybridApi(answers) && !hasTypescript(answers.languages) && Boolean(answers.vueHybridSuffix);
827
+ }
828
+ function isHybridVueTsContext(answers) {
829
+ return isVueBrowserLike(answers) && isVueHybridApi(answers) && hasTypescript(answers.languages) && Boolean(answers.vueHybridSuffix);
830
+ }
831
+ function buildHybridVueJsBlocks(answers) {
832
+ if (!isHybridVueJsContext(answers) || !answers.vueHybridSuffix) return null;
833
+ const major = answers.vueMajor ?? 3;
834
+ const { defaultApi, suffix: rawSuffix } = answers.vueHybridSuffix;
835
+ const targetGlob = `**/*${normalizeHybridSuffix(rawSuffix)}`;
836
+ const nonDefaultApi = defaultApi === "composition" ? "options" : "composition";
837
+ const defaultEntry = {
838
+ files: ["**/*.{js,jsx,cjs,mjs,vue}"],
839
+ ignores: [targetGlob]
840
+ };
841
+ return [{
842
+ scope: vueJsScope(major, defaultApi),
843
+ entry: defaultEntry
844
+ }, {
845
+ scope: vueJsScope(major, nonDefaultApi),
846
+ entry: { files: [targetGlob] }
847
+ }];
848
+ }
849
+ function makeHybridTsEntries(answers, suffix, appEntry) {
850
+ const targetGlob = `**/*${suffix}`;
851
+ const baseFiles = tsAppFiles(answers, answers.tsconfig?.referencesOnly === true && Boolean(appEntry) ? "app" : "all");
852
+ const tsconfigPaths = appEntry ? [appEntry.path] : void 0;
853
+ const defaultEntry = {
854
+ files: baseFiles,
855
+ ignores: [targetGlob]
856
+ };
857
+ const targetEntry = { files: [targetGlob] };
858
+ if (tsconfigPaths) {
859
+ defaultEntry.tsconfigPaths = tsconfigPaths;
860
+ targetEntry.tsconfigPaths = tsconfigPaths;
861
+ }
862
+ return {
863
+ defaultEntry,
864
+ targetEntry
865
+ };
866
+ }
867
+ function buildHybridVueTsBlocks(answers, appEntry) {
868
+ if (!isHybridVueTsContext(answers) || !answers.vueHybridSuffix) return null;
869
+ const major = answers.vueMajor ?? 3;
870
+ const { defaultApi, suffix: rawSuffix } = answers.vueHybridSuffix;
871
+ const suffix = normalizeHybridSuffix(rawSuffix);
872
+ const nonDefaultApi = defaultApi === "composition" ? "options" : "composition";
873
+ const { defaultEntry, targetEntry } = makeHybridTsEntries(answers, suffix, appEntry);
874
+ return [{
875
+ scope: vueTsScope(major, defaultApi),
876
+ entry: defaultEntry
877
+ }, {
878
+ scope: vueTsScope(major, nonDefaultApi),
879
+ entry: targetEntry
880
+ }];
881
+ }
882
+ function buildJsAppBlocks(answers) {
883
+ if (!hasJavascript(answers.languages)) return [];
884
+ const hybridBlocks = buildHybridVueJsBlocks(answers);
885
+ if (hybridBlocks) return hybridBlocks;
886
+ const files = jsAppFiles(answers);
887
+ return jsAppScopes(answers).map((scope) => ({
888
+ scope,
889
+ entry: { files }
890
+ }));
891
+ }
892
+ function buildTsAppBlocks(answers, appEntry) {
893
+ if (!hasTypescript(answers.languages)) return [];
894
+ const hybridBlocks = buildHybridVueTsBlocks(answers, appEntry);
895
+ if (hybridBlocks) return hybridBlocks;
896
+ const files = tsAppFiles(answers, answers.tsconfig?.referencesOnly === true && Boolean(appEntry) ? "app" : "all");
897
+ return tsAppScopes(answers).map((scope) => {
898
+ const entry = { files };
899
+ if (appEntry) entry.tsconfigPaths = [appEntry.path];
900
+ return {
901
+ scope,
902
+ entry
903
+ };
904
+ });
905
+ }
906
+ function tsConfigPathsForRoot(appEntry, configEntry) {
907
+ if (configEntry) return [configEntry.path];
908
+ if (appEntry) return [appEntry.path];
909
+ }
910
+ function configScopeFiles(answers) {
911
+ const files = [...jsRootConfigFiles()];
912
+ if (hasTypescript(answers.languages)) files.push(...tsRootConfigFiles());
913
+ return files;
914
+ }
915
+ function buildRootConfigBlocks(answers, appEntry, configEntry) {
916
+ const blocks = [{
917
+ scope: "config",
918
+ entry: { files: configScopeFiles(answers) }
919
+ }, {
920
+ scope: "javascriptNode",
921
+ entry: { files: jsRootConfigFiles() }
922
+ }];
923
+ if (hasTypescript(answers.languages)) {
924
+ const entry = { files: tsRootConfigFiles() };
925
+ const tsconfigPaths = tsConfigPathsForRoot(appEntry, configEntry);
926
+ if (tsconfigPaths) entry.tsconfigPaths = tsconfigPaths;
927
+ blocks.push({
928
+ scope: "typescriptNode",
929
+ entry
930
+ });
931
+ }
932
+ return blocks;
933
+ }
934
+ function buildTestBlock(answers, testEntry) {
935
+ if (answers.testFramework === "none") return null;
936
+ const entry = { files: testFilesGlob(answers.languages) };
937
+ if (hasTypescript(answers.languages) && testEntry) entry.tsconfigPaths = [testEntry.path];
938
+ return {
939
+ scope: answers.testFramework,
940
+ entry
941
+ };
942
+ }
943
+ function buildJqueryBlock(answers) {
944
+ if (!answers.extras.jquery) return null;
945
+ return {
946
+ scope: "jquery",
947
+ entry: { files: jqueryFilesGlob(answers) }
948
+ };
949
+ }
950
+ function buildScopedConfigs(answers) {
951
+ const plan = answers.tsconfig;
952
+ const referencesOnly = plan?.referencesOnly === true;
953
+ const appEntry = plan ? findRole(plan, "app") : void 0;
954
+ const configEntry = referencesOnly ? findRole(plan, "config") : void 0;
955
+ const tail = [buildTestBlock(answers, referencesOnly ? findRole(plan, "test") : appEntry), buildJqueryBlock(answers)];
956
+ return [
957
+ ...buildRootConfigBlocks(answers, appEntry, configEntry),
958
+ ...buildJsAppBlocks(answers),
959
+ ...buildTsAppBlocks(answers, appEntry),
960
+ ...tail.filter((block) => block !== null)
961
+ ];
962
+ }
963
+ function mergeByScope(blocks) {
964
+ return blocks.reduce((merged, { scope, entry }) => {
965
+ const existing = merged.get(scope);
966
+ if (existing) existing.push(entry);
967
+ else merged.set(scope, [entry]);
968
+ return merged;
969
+ }, /* @__PURE__ */ new Map());
970
+ }
971
+ function quote$1(value) {
972
+ return `'${value}'`;
973
+ }
974
+ function formatStringArray(values) {
975
+ return `[${values.map(quote$1).join(", ")}]`;
976
+ }
977
+ function formatEntry$1(entry, baseIndent) {
978
+ const filesLine = `files: ${formatStringArray(entry.files)}`;
979
+ const ignoresLine = entry.ignores ? `ignores: ${formatStringArray(entry.ignores)}` : null;
980
+ const tsconfigLine = entry.tsconfigPaths ? `tsconfigPaths: ${formatStringArray(entry.tsconfigPaths)}` : null;
981
+ if (!ignoresLine && !tsconfigLine) return `${baseIndent}{ ${filesLine} },`;
982
+ const childIndent = `${baseIndent}${indent$1}`;
983
+ const lines = [`${baseIndent}{`, `${childIndent}${filesLine},`];
984
+ if (ignoresLine) lines.push(`${childIndent}${ignoresLine},`);
985
+ if (tsconfigLine) lines.push(`${childIndent}${tsconfigLine},`);
986
+ lines.push(`${baseIndent}},`);
987
+ return lines.join("\n");
988
+ }
989
+ function formatScope$1(scope, entries, baseIndent) {
990
+ const childIndent = `${baseIndent}${indent$1}`;
991
+ const entryLines = entries.map((entry) => formatEntry$1(entry, childIndent));
992
+ return [
993
+ `${baseIndent}${scope}: [`,
994
+ ...entryLines,
995
+ `${baseIndent}],`
996
+ ].join("\n");
997
+ }
998
+ function renderUseInsiderBody(merged) {
999
+ return [...merged.entries()].map(([scope, entries]) => formatScope$1(scope, entries, indent$1)).join("\n");
1000
+ }
1001
+ function renderConfigFile(answers) {
1002
+ return [
1003
+ "import { useInsider } from '@useinsider/eslint-config';",
1004
+ "",
1005
+ "export default useInsider({",
1006
+ renderUseInsiderBody(mergeByScope(buildScopedConfigs(answers))),
1007
+ "});",
1008
+ ""
1009
+ ].join("\n");
1010
+ }
1011
+ //#endregion
1012
+ //#region src/cli/questions.ts
1013
+ var CliCancelledError = class extends Error {
1014
+ constructor(message) {
1015
+ super(message);
1016
+ this.name = "CliCancelledError";
1017
+ }
1018
+ };
1019
+ async function loadClack() {
1020
+ return await import("@clack/prompts");
1021
+ }
1022
+ function bail(clack, message) {
1023
+ clack.cancel(message);
1024
+ throw new CliCancelledError(message);
1025
+ }
1026
+ function ensure(clack, value) {
1027
+ if (clack.isCancel(value)) bail(clack, "Cancelled.");
1028
+ return value;
1029
+ }
1030
+ async function askProjectType(clack, initial = "backend") {
1031
+ return ensure(clack, await clack.select({
1032
+ message: "What kind of project are you setting up?",
1033
+ options: [
1034
+ {
1035
+ value: "backend",
1036
+ label: "Backend / Node.js"
1037
+ },
1038
+ {
1039
+ value: "browser",
1040
+ label: "Browser / frontend"
1041
+ },
1042
+ {
1043
+ value: "hybrid",
1044
+ label: "Hybrid",
1045
+ hint: "Node + browser (isomorphic, SSR, full-stack)"
1046
+ }
1047
+ ],
1048
+ initialValue: initial
1049
+ }));
1050
+ }
1051
+ async function askLanguages(clack, initial = ["typescript"]) {
1052
+ const picked = ensure(clack, await clack.multiselect({
1053
+ message: "Which languages will the project use? (press space to toggle, enter to confirm)",
1054
+ options: [{
1055
+ value: "javascript",
1056
+ label: "JavaScript"
1057
+ }, {
1058
+ value: "typescript",
1059
+ label: "TypeScript"
1060
+ }],
1061
+ required: true,
1062
+ initialValues: initial
1063
+ }));
1064
+ if (picked.length === 0) bail(clack, "At least one language must be selected.");
1065
+ return picked;
1066
+ }
1067
+ async function askFramework(clack, initial = "vanilla") {
1068
+ return ensure(clack, await clack.select({
1069
+ message: "Which frontend framework?",
1070
+ options: [{
1071
+ value: "vanilla",
1072
+ label: "None / Vanilla"
1073
+ }, {
1074
+ value: "vue",
1075
+ label: "Vue"
1076
+ }],
1077
+ initialValue: initial
1078
+ }));
1079
+ }
1080
+ async function askVueMajor(clack, initial = 3) {
1081
+ return ensure(clack, await clack.select({
1082
+ message: "Which Vue major version?",
1083
+ options: [{
1084
+ value: 3,
1085
+ label: "Vue 3"
1086
+ }, {
1087
+ value: 2,
1088
+ label: "Vue 2"
1089
+ }],
1090
+ initialValue: initial
1091
+ }));
1092
+ }
1093
+ async function askVueApiStyle(clack, initial = "composition") {
1094
+ return ensure(clack, await clack.select({
1095
+ message: "What API style does your Vue codebase use?",
1096
+ options: [
1097
+ {
1098
+ value: "composition",
1099
+ label: "Composition API (setup)"
1100
+ },
1101
+ {
1102
+ value: "options",
1103
+ label: "Options API"
1104
+ },
1105
+ {
1106
+ value: "hybrid",
1107
+ label: "Hybrid (both)"
1108
+ }
1109
+ ],
1110
+ initialValue: initial
1111
+ }));
1112
+ }
1113
+ async function askHybridProceedWithSuffix(clack, initial = true) {
1114
+ return ensure(clack, await clack.confirm({
1115
+ message: "Want me to scaffold both Options + Composition blocks using a filename suffix convention?",
1116
+ initialValue: initial
1117
+ }));
1118
+ }
1119
+ async function askVueHybridDefaultApi(clack, initial = "composition") {
1120
+ return ensure(clack, await clack.select({
1121
+ message: "Which API style is the default in your codebase?",
1122
+ options: [{
1123
+ value: "composition",
1124
+ label: "Composition API (setup)"
1125
+ }, {
1126
+ value: "options",
1127
+ label: "Options API"
1128
+ }],
1129
+ initialValue: initial
1130
+ }));
1131
+ }
1132
+ async function askHybridSuffix(clack, defaultApi, initial) {
1133
+ const choices = getHybridSuffixChoices(defaultApi);
1134
+ const message = defaultApi === "composition" ? "Pick a suffix for Options-API components:" : "Pick a suffix for Composition-API components:";
1135
+ const fallback = getHybridDefaultSuffix(defaultApi);
1136
+ const initialValue = initial && choices.some((choice) => choice.value === initial) ? initial : fallback;
1137
+ return ensure(clack, await clack.select({
1138
+ message,
1139
+ options: choices.map((choice) => ({
1140
+ value: choice.value,
1141
+ label: choice.label
1142
+ })),
1143
+ initialValue
1144
+ }));
1145
+ }
1146
+ async function askTestFramework(clack, initial = "vitest") {
1147
+ return ensure(clack, await clack.select({
1148
+ message: "Which testing framework?",
1149
+ options: [
1150
+ {
1151
+ value: "vitest",
1152
+ label: "Vitest"
1153
+ },
1154
+ {
1155
+ value: "jest",
1156
+ label: "Jest"
1157
+ },
1158
+ {
1159
+ value: "none",
1160
+ label: "None"
1161
+ }
1162
+ ],
1163
+ initialValue: initial
1164
+ }));
1165
+ }
1166
+ async function askExtras(clack, initial = { jquery: false }) {
1167
+ const initialValues = initial.jquery ? ["jquery"] : [];
1168
+ return { jquery: ensure(clack, await clack.multiselect({
1169
+ message: "Which extra libraries do you use?",
1170
+ options: [{
1171
+ value: "jquery",
1172
+ label: "jQuery (adds globals)"
1173
+ }],
1174
+ required: false,
1175
+ initialValues
1176
+ })).includes("jquery") };
1177
+ }
1178
+ async function askTsconfigRole(clack, refPath, initial = "app") {
1179
+ return ensure(clack, await clack.select({
1180
+ message: `Map ${refPath} to a role:`,
1181
+ options: [
1182
+ {
1183
+ value: "app",
1184
+ label: "App / source code"
1185
+ },
1186
+ {
1187
+ value: "test",
1188
+ label: "Test code"
1189
+ },
1190
+ {
1191
+ value: "config",
1192
+ label: "Config / root files"
1193
+ }
1194
+ ],
1195
+ initialValue: initial
1196
+ }));
1197
+ }
1198
+ async function collectRoleEntries(clack, refs, previous) {
1199
+ const previousByPath = new Map(previous?.map((entry) => [entry.path, entry.role]) ?? []);
1200
+ return refs.reduce(async (accumulator, ref) => {
1201
+ const entries = await accumulator;
1202
+ const role = await askTsconfigRole(clack, ref, previousByPath.get(ref));
1203
+ return [...entries, {
1204
+ path: ref,
1205
+ role
1206
+ }];
1207
+ }, Promise.resolve([]));
1208
+ }
1209
+ async function askTsconfigPlan(clack, input, previous) {
1210
+ if (!input.referencesOnly) return {
1211
+ referencesOnly: false,
1212
+ entries: [{
1213
+ path: "./tsconfig.json",
1214
+ role: "app"
1215
+ }]
1216
+ };
1217
+ return {
1218
+ referencesOnly: true,
1219
+ entries: await collectRoleEntries(clack, input.refs, previous?.entries)
1220
+ };
1221
+ }
1222
+ async function askExistingConfigDecision(clack, configPath, initial = "migrate") {
1223
+ return ensure(clack, await clack.select({
1224
+ message: `Found existing config at ${configPath}. How should we proceed?`,
1225
+ options: [
1226
+ {
1227
+ value: "migrate",
1228
+ label: "Migrate",
1229
+ hint: "preserve current base config, port them to the v2 shape"
1230
+ },
1231
+ {
1232
+ value: "override",
1233
+ label: "Override",
1234
+ hint: "discard the existing config and scaffold a new one"
1235
+ },
1236
+ {
1237
+ value: "exit",
1238
+ label: "Exit",
1239
+ hint: "leave the project untouched"
1240
+ }
1241
+ ],
1242
+ initialValue: initial
1243
+ }));
1244
+ }
1245
+ async function askBrowserBranch(clack, previous) {
1246
+ const framework = await askFramework(clack, previous?.framework);
1247
+ if (framework !== "vue") return {
1248
+ framework,
1249
+ vueMajor: void 0,
1250
+ vueApiStyle: void 0
1251
+ };
1252
+ return {
1253
+ framework,
1254
+ vueMajor: await askVueMajor(clack, previous?.vueMajor),
1255
+ vueApiStyle: await askVueApiStyle(clack, previous?.vueApiStyle)
1256
+ };
1257
+ }
1258
+ function noteResumed(clack, previous) {
1259
+ if (!previous || !clack.note) return;
1260
+ clack.note("Restored your previous choices. Press Enter on each prompt to confirm, or arrow keys to change.", "Resuming previous session");
1261
+ }
1262
+ function guardTsconfig(clack, wantsTypescript, context) {
1263
+ if (wantsTypescript && context.tsconfigMissing) bail(clack, "No tsconfig.json found in current directory. Create one and re-run.");
1264
+ }
1265
+ async function resolveBrowserBranch(clack, projectType, previous) {
1266
+ if (projectType !== "browser" && projectType !== "hybrid") return {
1267
+ framework: void 0,
1268
+ vueMajor: void 0,
1269
+ vueApiStyle: void 0
1270
+ };
1271
+ return askBrowserBranch(clack, previous);
1272
+ }
1273
+ async function resolveTsconfigPlan(clack, wantsTypescript, context, previous) {
1274
+ if (!wantsTypescript || !context.tsconfigInput) return;
1275
+ return askTsconfigPlan(clack, context.tsconfigInput, previous?.tsconfig);
1276
+ }
1277
+ async function runQuestions(context, clackOverride) {
1278
+ const clack = clackOverride ?? await loadClack();
1279
+ clack.intro("useinsider eslint-config setup");
1280
+ noteResumed(clack, context.previousAnswers);
1281
+ const previous = context.previousAnswers;
1282
+ const projectType = await askProjectType(clack, previous?.projectType);
1283
+ const languages = await askLanguages(clack, previous?.languages);
1284
+ const wantsTypescript = languages.includes("typescript");
1285
+ guardTsconfig(clack, wantsTypescript, context);
1286
+ const browserBranch = await resolveBrowserBranch(clack, projectType, previous);
1287
+ const testFramework = await askTestFramework(clack, previous?.testFramework);
1288
+ const extras = await askExtras(clack, previous?.extras);
1289
+ const tsconfig = await resolveTsconfigPlan(clack, wantsTypescript, context, previous);
1290
+ return {
1291
+ projectType,
1292
+ languages,
1293
+ framework: browserBranch.framework,
1294
+ vueMajor: browserBranch.vueMajor,
1295
+ vueApiStyle: browserBranch.vueApiStyle,
1296
+ testFramework,
1297
+ extras,
1298
+ tsconfig
1299
+ };
1300
+ }
1301
+ //#endregion
1302
+ //#region src/cli/sessionStore.ts
1303
+ var SCHEMA_VERSION = 4;
1304
+ var DEFAULT_TTL_MS = 3600 * 1e3;
1305
+ var FILE_PREFIX = "useinsider-eslint-config-session-";
1306
+ function hashCwd(cwd) {
1307
+ return (0, node_crypto.createHash)("sha1").update(cwd).digest("hex").slice(0, 16);
1308
+ }
1309
+ function getSessionFilePath(cwd, tmpDirOverride) {
1310
+ return (0, node_path.join)(tmpDirOverride ?? (0, node_os.tmpdir)(), `${FILE_PREFIX}${hashCwd(cwd)}.json`);
1311
+ }
1312
+ function safeUnlink$1(path) {
1313
+ try {
1314
+ (0, node_fs.unlinkSync)(path);
1315
+ } catch {}
1316
+ }
1317
+ function ensureDir(path) {
1318
+ if (!(0, node_fs.existsSync)(path)) (0, node_fs.mkdirSync)(path, { recursive: true });
1319
+ }
1320
+ function isSessionShape(value) {
1321
+ if (!value || typeof value !== "object") return false;
1322
+ const candidate = value;
1323
+ return candidate.v === SCHEMA_VERSION && typeof candidate.savedAt === "number" && typeof candidate.cwd === "string" && (candidate.command === "scaffold" || candidate.command === "migrate");
1324
+ }
1325
+ function saveSession(session, options) {
1326
+ const now = options.now ?? Date.now;
1327
+ const dir = options.tmpDir ?? (0, node_os.tmpdir)();
1328
+ ensureDir(dir);
1329
+ const path = getSessionFilePath(options.cwd, dir);
1330
+ const payload = {
1331
+ v: SCHEMA_VERSION,
1332
+ savedAt: now(),
1333
+ cwd: options.cwd,
1334
+ ...session
1335
+ };
1336
+ (0, node_fs.writeFileSync)(path, JSON.stringify(payload), {
1337
+ encoding: "utf8",
1338
+ mode: 384
1339
+ });
1340
+ try {
1341
+ (0, node_fs.chmodSync)(path, 384);
1342
+ } catch {}
1343
+ return path;
1344
+ }
1345
+ function loadSession(options) {
1346
+ const now = options.now ?? Date.now;
1347
+ const ttl = options.ttlMs ?? DEFAULT_TTL_MS;
1348
+ const path = getSessionFilePath(options.cwd, options.tmpDir);
1349
+ if (!(0, node_fs.existsSync)(path)) return null;
1350
+ let parsed;
1351
+ try {
1352
+ const raw = (0, node_fs.readFileSync)(path, "utf8");
1353
+ parsed = JSON.parse(raw);
1354
+ } catch {
1355
+ safeUnlink$1(path);
1356
+ return null;
1357
+ }
1358
+ if (!isSessionShape(parsed)) {
1359
+ safeUnlink$1(path);
1360
+ return null;
1361
+ }
1362
+ if (parsed.cwd !== options.cwd) {
1363
+ safeUnlink$1(path);
1364
+ return null;
1365
+ }
1366
+ if (now() - parsed.savedAt > ttl) {
1367
+ safeUnlink$1(path);
1368
+ return null;
1369
+ }
1370
+ return parsed;
1371
+ }
1372
+ function clearSession(options) {
1373
+ safeUnlink$1(getSessionFilePath(options.cwd, options.tmpDir));
1374
+ }
1375
+ /* v8 ignore stop */
1376
+ //#endregion
1377
+ //#region src/configs/config/dependencies.ts
1378
+ var dependencies$7 = {};
1379
+ //#endregion
1380
+ //#region src/configs/javascript/dependencies.ts
1381
+ var dependencies$6 = {};
1382
+ //#endregion
1383
+ //#region src/configs/javascript-dom/dependencies.ts
1384
+ var dependencies$5 = {};
1385
+ //#endregion
1386
+ //#region src/configs/javascript-node/dependencies.ts
1387
+ var dependencies$4 = {};
1388
+ //#endregion
1389
+ //#region src/configs/jsdoc-based-ts/dependencies.ts
1390
+ var dependencies$3 = {
1391
+ typescript: false,
1392
+ "typescript-eslint": false,
1393
+ "@typescript-eslint/parser": false,
1394
+ "@typescript-eslint/eslint-plugin": false
1395
+ };
1396
+ //#endregion
1397
+ //#region src/configs/strict/dependencies.ts
1398
+ var dependencies$2 = { "eslint-plugin-sonarjs": false };
1399
+ //#endregion
1400
+ //#region src/configs/typescript-dom/dependencies.ts
1401
+ var dependencies$1 = {
1402
+ typescript: false,
1403
+ "typescript-eslint": false,
1404
+ "@typescript-eslint/parser": false,
1405
+ "@typescript-eslint/eslint-plugin": false
1406
+ };
1407
+ //#endregion
1408
+ //#region src/configs/typescript-node/dependencies.ts
1409
+ var dependencies = {
1410
+ typescript: false,
1411
+ "typescript-eslint": false,
1412
+ "@typescript-eslint/parser": false,
1413
+ "@typescript-eslint/eslint-plugin": false
1414
+ };
1415
+ //#endregion
1416
+ //#region src/cli/migrate/dependencies.ts
1417
+ var EXACT_PATTERNS = new Set([
1418
+ "eslint",
1419
+ "@useinsider/eslint-config",
1420
+ "globals",
1421
+ "vue-eslint-parser",
1422
+ "typescript-eslint"
1423
+ ]);
1424
+ var PREFIX_PATTERNS = [
1425
+ "eslint-plugin-",
1426
+ "eslint-config-",
1427
+ "eslint-import-resolver-",
1428
+ "eslint-formatter-",
1429
+ "eslint-"
1430
+ ];
1431
+ var SCOPED_ESLINT_PATTERNS = [/^@[^/]+\/eslint-/u, /^@typescript-eslint\//u];
1432
+ var SAFELIST = new Set(["typescript", "@types/eslint"]);
1433
+ var SCOPE_TO_DEPS = {
1434
+ javascript: dependencies$6,
1435
+ javascriptDom: dependencies$5,
1436
+ javascriptNode: dependencies$4,
1437
+ typescript: dependencies$13,
1438
+ typescriptDom: dependencies$1,
1439
+ typescriptNode: dependencies,
1440
+ vue2: dependencies$11,
1441
+ vue3: dependencies$9,
1442
+ vue2Typescript: dependencies$10,
1443
+ vue3Typescript: dependencies$8,
1444
+ jest: dependencies$14,
1445
+ vitest: dependencies$12,
1446
+ jsdocBasedTs: dependencies$3
1447
+ };
1448
+ var ALL_PRESET_DEPS = [
1449
+ dependencies$7,
1450
+ dependencies$2,
1451
+ ...Object.values(SCOPE_TO_DEPS)
1452
+ ];
1453
+ var PRESET_DEPENDENCY_KEYS = new Set(ALL_PRESET_DEPS.flatMap((record) => Object.keys(record)));
1454
+ function isEslintRelatedDependency(name) {
1455
+ if (SAFELIST.has(name)) return false;
1456
+ if (EXACT_PATTERNS.has(name)) return true;
1457
+ if (PRESET_DEPENDENCY_KEYS.has(name)) return true;
1458
+ if (SCOPED_ESLINT_PATTERNS.some((pattern) => pattern.test(name))) return true;
1459
+ return PREFIX_PATTERNS.some((prefix) => name.startsWith(prefix));
1460
+ }
1461
+ function sortRecord(record) {
1462
+ return Object.keys(record).sort((left, right) => left.localeCompare(right)).reduce((accumulator, key) => {
1463
+ accumulator[key] = record[key];
1464
+ return accumulator;
1465
+ }, {});
1466
+ }
1467
+ function pruneSection(record, removed) {
1468
+ if (!record) return record;
1469
+ const kept = {};
1470
+ Object.entries(record).forEach(([name, version]) => {
1471
+ if (isEslintRelatedDependency(name)) {
1472
+ if (!removed.includes(name)) removed.push(name);
1473
+ return;
1474
+ }
1475
+ kept[name] = version;
1476
+ });
1477
+ return sortRecord(kept);
1478
+ }
1479
+ function parseOverrideKey(key) {
1480
+ if (key.length === 0) return { baseName: key };
1481
+ const searchFrom = key.startsWith("@") ? 1 : 0;
1482
+ const atIndex = key.indexOf("@", searchFrom);
1483
+ if (atIndex === -1) return { baseName: key };
1484
+ return { baseName: key.slice(0, atIndex) };
1485
+ }
1486
+ function sortOverrides(record) {
1487
+ return Object.keys(record).sort((left, right) => left.localeCompare(right)).reduce((accumulator, key) => {
1488
+ accumulator[key] = record[key];
1489
+ return accumulator;
1490
+ }, {});
1491
+ }
1492
+ function pruneOverridesSection(record, removed) {
1493
+ if (!record) return record;
1494
+ const kept = {};
1495
+ Object.entries(record).forEach(([key, value]) => {
1496
+ if (!(typeof value === "string")) {
1497
+ kept[key] = value;
1498
+ return;
1499
+ }
1500
+ const { baseName } = parseOverrideKey(key);
1501
+ if (isEslintRelatedDependency(baseName)) {
1502
+ if (!removed.includes(baseName)) removed.push(baseName);
1503
+ return;
1504
+ }
1505
+ kept[key] = value;
1506
+ });
1507
+ return sortOverrides(kept);
1508
+ }
1509
+ function pruneEslintDependencies(manifest) {
1510
+ const removed = [];
1511
+ const next = { ...manifest };
1512
+ if (manifest.dependencies) next.dependencies = pruneSection(manifest.dependencies, removed);
1513
+ if (manifest.devDependencies) next.devDependencies = pruneSection(manifest.devDependencies, removed);
1514
+ if (manifest.peerDependencies) next.peerDependencies = pruneSection(manifest.peerDependencies, removed);
1515
+ if (manifest.optionalDependencies) next.optionalDependencies = pruneSection(manifest.optionalDependencies, removed);
1516
+ if (manifest.overrides) next.overrides = pruneOverridesSection(manifest.overrides, removed);
1517
+ if (manifest.pnpm && typeof manifest.pnpm === "object") {
1518
+ const nextPnpm = { ...manifest.pnpm };
1519
+ if (manifest.pnpm.overrides) nextPnpm.overrides = pruneOverridesSection(manifest.pnpm.overrides, removed);
1520
+ next.pnpm = nextPnpm;
1521
+ }
1522
+ if (manifest.resolutions) next.resolutions = pruneSection(manifest.resolutions, removed);
1523
+ return {
1524
+ manifest: next,
1525
+ removed
1526
+ };
1527
+ }
1528
+ function lookupVersion(manifest, name) {
1529
+ return manifest.dependencies?.[name] ?? manifest.devDependencies?.[name] ?? manifest.peerDependencies?.[name] ?? manifest.optionalDependencies?.[name];
1530
+ }
1531
+ function stripRange(version) {
1532
+ return version.replace(/^(?:\^|~|>=|<=|>|<|=)/u, "");
1533
+ }
1534
+ function appendSpec(specs, spec) {
1535
+ if (!specs.includes(spec)) specs.push(spec);
1536
+ }
1537
+ function resolveSpec(name, manifest, fallbacks) {
1538
+ const version = lookupVersion(manifest, name);
1539
+ if (!version) {
1540
+ if (!fallbacks.includes(name)) fallbacks.push(name);
1541
+ return `${name}@latest`;
1542
+ }
1543
+ return `${name}@${stripRange(version)}`;
1544
+ }
1545
+ function buildInstallList(scopes, manifest) {
1546
+ const specs = [];
1547
+ const fallbacks = [];
1548
+ appendSpec(specs, "@useinsider/eslint-config@latest");
1549
+ appendSpec(specs, resolveSpec("eslint", manifest, fallbacks));
1550
+ [...scopes].forEach((scope) => {
1551
+ const record = SCOPE_TO_DEPS[scope];
1552
+ if (!record) return;
1553
+ Object.entries(record).forEach(([packageName, shouldInstall]) => {
1554
+ if (shouldInstall) appendSpec(specs, resolveSpec(packageName, manifest, fallbacks));
1555
+ });
1556
+ });
1557
+ return {
1558
+ specs,
1559
+ fallbacks
1560
+ };
1561
+ }
1562
+ var readOwnEslintConfigManifest = readOwnEslintConfigManifest$1;
1563
+ //#endregion
1564
+ //#region src/cli/prunePackageJson.ts
1565
+ function detectIndent(raw) {
1566
+ const match = /\n([ \t]+)"/u.exec(raw);
1567
+ if (!match) return " ";
1568
+ return match[1];
1569
+ }
1570
+ function serializeManifest(manifest, indent) {
1571
+ return `${JSON.stringify(manifest, null, indent)}\n`;
1572
+ }
1573
+ function tryReadConsumerManifest$1(path) {
1574
+ try {
1575
+ const raw = (0, node_fs.readFileSync)(path, "utf8");
1576
+ return {
1577
+ raw,
1578
+ manifest: JSON.parse(raw)
1579
+ };
1580
+ } catch {
1581
+ return null;
1582
+ }
1583
+ }
1584
+ function pruneConsumerPackageJson(cwd) {
1585
+ const packageJsonPath = (0, node_path.join)(cwd, "package.json");
1586
+ if (!(0, node_fs.existsSync)(packageJsonPath)) return {
1587
+ packageJsonPath: null,
1588
+ removed: []
1589
+ };
1590
+ const read = tryReadConsumerManifest$1(packageJsonPath);
1591
+ if (!read) return {
1592
+ packageJsonPath: null,
1593
+ removed: []
1594
+ };
1595
+ const { manifest, raw } = read;
1596
+ const outcome = pruneEslintDependencies(manifest);
1597
+ if (outcome.removed.length === 0) return {
1598
+ packageJsonPath,
1599
+ removed: []
1600
+ };
1601
+ const indent = detectIndent(raw);
1602
+ (0, node_fs.writeFileSync)(packageJsonPath, serializeManifest(outcome.manifest, indent), "utf8");
1603
+ return {
1604
+ packageJsonPath,
1605
+ removed: outcome.removed
1606
+ };
1607
+ }
1608
+ //#endregion
1609
+ //#region src/cli/migrate/stringEntry.ts
1610
+ function toEntries(values) {
1611
+ return values.map((value) => ({ value }));
1612
+ }
1613
+ function entryValues(entries) {
1614
+ return entries.map((entry) => entry.value);
1615
+ }
1616
+ function cloneEntry(entry) {
1617
+ return entry.leadingComment === void 0 ? { value: entry.value } : {
1618
+ value: entry.value,
1619
+ leadingComment: entry.leadingComment
1620
+ };
1621
+ }
1622
+ function cloneEntries(entries) {
1623
+ return entries.map(cloneEntry);
1624
+ }
1625
+ function hasValue(entries, value) {
1626
+ return entries.some((entry) => entry.value === value);
1627
+ }
1628
+ function leadingCommentTextFor(sourceFile, node) {
1629
+ const ranges = typescript.getLeadingCommentRanges(sourceFile.text, node.getFullStart());
1630
+ if (!ranges || ranges.length === 0) return;
1631
+ return ranges.map((range) => sourceFile.text.slice(range.pos, range.end)).join("\n");
1632
+ }
1633
+ //#endregion
1634
+ //#region src/cli/migrate/eslintrc/parse.ts
1635
+ function lineOf$1(sourceFile, node) {
1636
+ const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile));
1637
+ return line + 1;
1638
+ }
1639
+ function isStringLiteralLike(node) {
1640
+ return typescript.isStringLiteral(node) || typescript.isNoSubstitutionTemplateLiteral(node);
1641
+ }
1642
+ function propertyKeyName$1(property) {
1643
+ if (!typescript.isPropertyAssignment(property) && !typescript.isShorthandPropertyAssignment(property)) return null;
1644
+ const key = property.name;
1645
+ if (typescript.isIdentifier(key) || typescript.isStringLiteral(key)) return key.text;
1646
+ return null;
1647
+ }
1648
+ function findProperty$1(object, name) {
1649
+ return object.properties.filter((property) => typescript.isPropertyAssignment(property)).find((property) => propertyKeyName$1(property) === name);
1650
+ }
1651
+ function readStringArray(initializer) {
1652
+ if (!initializer || !typescript.isArrayLiteralExpression(initializer)) return [];
1653
+ return initializer.elements.map((element) => isStringLiteralLike(element) ? element.text : null).filter((value) => value !== null);
1654
+ }
1655
+ function readStringEntries(initializer, sourceFile) {
1656
+ if (!initializer || !typescript.isArrayLiteralExpression(initializer)) return [];
1657
+ return initializer.elements.map((element) => {
1658
+ if (!isStringLiteralLike(element)) return null;
1659
+ const leadingComment = leadingCommentTextFor(sourceFile, element);
1660
+ return leadingComment === void 0 ? { value: element.text } : {
1661
+ value: element.text,
1662
+ leadingComment
1663
+ };
1664
+ }).filter((entry) => entry !== null);
1665
+ }
1666
+ function readStringOrArray(initializer) {
1667
+ if (!initializer) return [];
1668
+ if (isStringLiteralLike(initializer)) return [initializer.text];
1669
+ return readStringArray(initializer);
1670
+ }
1671
+ function readStringOrEntries(initializer, sourceFile) {
1672
+ if (!initializer) return [];
1673
+ if (isStringLiteralLike(initializer)) return [{ value: initializer.text }];
1674
+ return readStringEntries(initializer, sourceFile);
1675
+ }
1676
+ function readGlobalValue$1(initializer) {
1677
+ if (isStringLiteralLike(initializer)) return { value: initializer.text };
1678
+ if (initializer.kind === typescript.SyntaxKind.TrueKeyword) return { value: true };
1679
+ if (initializer.kind === typescript.SyntaxKind.FalseKeyword) return { value: false };
1680
+ if (typescript.isNumericLiteral(initializer)) return { value: Number(initializer.text) };
1681
+ return null;
1682
+ }
1683
+ function readGlobalsObject$1(initializer) {
1684
+ if (!initializer || !typescript.isObjectLiteralExpression(initializer)) return;
1685
+ const entries = [];
1686
+ initializer.properties.forEach((property) => {
1687
+ if (!typescript.isPropertyAssignment(property)) return;
1688
+ const name = propertyKeyName$1(property);
1689
+ if (name === null) return;
1690
+ const wrapper = readGlobalValue$1(property.initializer);
1691
+ if (wrapper === null) return;
1692
+ entries.push([name, wrapper.value]);
1693
+ });
1694
+ if (entries.length === 0) return;
1695
+ return Object.fromEntries(entries);
1696
+ }
1697
+ function readGlobalsTokens$1(initializer, sourceFile) {
1698
+ if (!initializer || !typescript.isObjectLiteralExpression(initializer)) return;
1699
+ const tokens = [];
1700
+ initializer.properties.forEach((property) => {
1701
+ if (typescript.isSpreadAssignment(property)) {
1702
+ tokens.push({
1703
+ kind: "spread",
1704
+ raw: property.expression.getText(sourceFile)
1705
+ });
1706
+ return;
1707
+ }
1708
+ if (!typescript.isPropertyAssignment(property)) return;
1709
+ const name = propertyKeyName$1(property);
1710
+ if (name === null) return;
1711
+ const wrapper = readGlobalValue$1(property.initializer);
1712
+ if (wrapper === null) return;
1713
+ tokens.push({
1714
+ kind: "named",
1715
+ key: name,
1716
+ value: wrapper.value
1717
+ });
1718
+ });
1719
+ return tokens.length > 0 ? tokens : void 0;
1720
+ }
1721
+ function readPluginsArray(initializer) {
1722
+ if (!initializer) return [];
1723
+ if (typescript.isArrayLiteralExpression(initializer)) return readStringArray(initializer);
1724
+ if (typescript.isObjectLiteralExpression(initializer)) return initializer.properties.map(propertyKeyName$1).filter((name) => name !== null);
1725
+ return [];
1726
+ }
1727
+ function readEnvBoolean(value) {
1728
+ if (value.kind === typescript.SyntaxKind.TrueKeyword) return true;
1729
+ if (value.kind === typescript.SyntaxKind.FalseKeyword) return false;
1730
+ if (typescript.isNumericLiteral(value)) return Number(value.text) !== 0;
1731
+ if (isStringLiteralLike(value)) return value.text.length > 0;
1732
+ return false;
1733
+ }
1734
+ function readEnvFromInitializer(initializer) {
1735
+ const env = {
1736
+ browser: false,
1737
+ node: false,
1738
+ jest: false,
1739
+ jestGlobals: false
1740
+ };
1741
+ if (!initializer || !typescript.isObjectLiteralExpression(initializer)) return env;
1742
+ initializer.properties.forEach((property) => {
1743
+ if (!typescript.isPropertyAssignment(property)) return;
1744
+ const name = propertyKeyName$1(property);
1745
+ if (!readEnvBoolean(property.initializer)) return;
1746
+ if (name === "browser") env.browser = true;
1747
+ else if (name === "node") env.node = true;
1748
+ else if (name === "jest") env.jest = true;
1749
+ else if (name === "jest/globals") env.jestGlobals = true;
1750
+ });
1751
+ return env;
1752
+ }
1753
+ function classifyExtendValue(raw) {
1754
+ if (raw.startsWith("@useinsider/eslint-config")) {
1755
+ const slashIndex = raw.indexOf("/", 25);
1756
+ return {
1757
+ raw,
1758
+ kind: "insider",
1759
+ insiderPreset: slashIndex >= 0 ? raw.slice(slashIndex + 1) : ""
1760
+ };
1761
+ }
1762
+ if (raw.startsWith("plugin:vue/")) return {
1763
+ raw,
1764
+ kind: "vue",
1765
+ vueMajor: raw.slice(11).startsWith("vue2-") ? 2 : 3
1766
+ };
1767
+ if (raw.startsWith("plugin:jest/")) return {
1768
+ raw,
1769
+ kind: "jest"
1770
+ };
1771
+ if (raw.startsWith("plugin:jsdoc/")) return {
1772
+ raw,
1773
+ kind: "jsdoc"
1774
+ };
1775
+ if (raw === "airbnb" || raw === "airbnb-base" || raw.startsWith("airbnb-")) return {
1776
+ raw,
1777
+ kind: "airbnb"
1778
+ };
1779
+ return {
1780
+ raw,
1781
+ kind: "other"
1782
+ };
1783
+ }
1784
+ function readExtends(initializer) {
1785
+ if (!initializer) return [];
1786
+ if (isStringLiteralLike(initializer)) return [classifyExtendValue(initializer.text)];
1787
+ return readStringArray(initializer).map(classifyExtendValue);
1788
+ }
1789
+ function readParserMarker(initializer) {
1790
+ if (!initializer || !isStringLiteralLike(initializer)) return false;
1791
+ return initializer.text.includes("typescript-eslint");
1792
+ }
1793
+ function readParserOptions(initializer, env) {
1794
+ const options = {};
1795
+ let parserMarker = false;
1796
+ if (!initializer || !typescript.isObjectLiteralExpression(initializer)) return {
1797
+ options,
1798
+ parserMarker
1799
+ };
1800
+ const projectProperty = findProperty$1(initializer, "project");
1801
+ if (projectProperty) {
1802
+ const project = readStringOrArray(projectProperty.initializer);
1803
+ if (project.length > 0) options.project = project;
1804
+ }
1805
+ const parserProperty = findProperty$1(initializer, "parser");
1806
+ if (parserProperty && readParserMarker(parserProperty.initializer)) parserMarker = true;
1807
+ return {
1808
+ options,
1809
+ parserMarker
1810
+ };
1811
+ }
1812
+ function extractGlobalComponents$1(rulesNode, sourceFile) {
1813
+ const rule = findProperty$1(rulesNode, "vue/no-undef-components");
1814
+ if (!rule || !typescript.isArrayLiteralExpression(rule.initializer)) return;
1815
+ const [, optionsNode] = rule.initializer.elements;
1816
+ if (!optionsNode || !typescript.isObjectLiteralExpression(optionsNode)) return;
1817
+ const ignorePatterns = findProperty$1(optionsNode, "ignorePatterns");
1818
+ if (!ignorePatterns) return;
1819
+ const values = readStringEntries(ignorePatterns.initializer, sourceFile);
1820
+ return values.length > 0 ? values : void 0;
1821
+ }
1822
+ function detectSpellCheckerOff(rulesNode) {
1823
+ const rule = findProperty$1(rulesNode, "@cspell/spellchecker");
1824
+ if (!rule) return false;
1825
+ return isStringLiteralLike(rule.initializer) && rule.initializer.text === "off";
1826
+ }
1827
+ function resolveSpreadKeyCount(expression, context) {
1828
+ if (!typescript.isIdentifier(expression)) return null;
1829
+ const target = context.constantRulesObjects.get(expression.text);
1830
+ if (!target) return null;
1831
+ const keys = /* @__PURE__ */ new Set();
1832
+ target.properties.forEach((property) => {
1833
+ const name = propertyKeyName$1(property);
1834
+ if (name !== null && name !== "vue/no-undef-components" && name !== "@cspell/spellchecker") keys.add(name);
1835
+ });
1836
+ return keys.size;
1837
+ }
1838
+ function readRulesBlock$1(rulesPropertyInitializer, context) {
1839
+ const block = {
1840
+ customRuleCount: 0,
1841
+ spellCheckerOff: false,
1842
+ unresolvedSpreads: []
1843
+ };
1844
+ if (!rulesPropertyInitializer || !typescript.isObjectLiteralExpression(rulesPropertyInitializer)) return block;
1845
+ block.globalComponents = extractGlobalComponents$1(rulesPropertyInitializer, context.sourceFile);
1846
+ block.spellCheckerOff = detectSpellCheckerOff(rulesPropertyInitializer);
1847
+ rulesPropertyInitializer.properties.forEach((property) => {
1848
+ if (typescript.isPropertyAssignment(property)) {
1849
+ const name = propertyKeyName$1(property);
1850
+ if (name === null || name === "vue/no-undef-components" || name === "@cspell/spellchecker") return;
1851
+ block.customRuleCount += 1;
1852
+ return;
1853
+ }
1854
+ if (typescript.isSpreadAssignment(property)) {
1855
+ const resolved = resolveSpreadKeyCount(property.expression, context);
1856
+ if (resolved === null) {
1857
+ const identifierName = typescript.isIdentifier(property.expression) ? property.expression.text : "<expr>";
1858
+ block.unresolvedSpreads.push(identifierName);
1859
+ return;
1860
+ }
1861
+ block.customRuleCount += resolved;
1862
+ }
1863
+ });
1864
+ return block;
1865
+ }
1866
+ function collectConstantObjects(sourceFile) {
1867
+ const map = /* @__PURE__ */ new Map();
1868
+ sourceFile.statements.forEach((statement) => {
1869
+ if (!typescript.isVariableStatement(statement)) return;
1870
+ statement.declarationList.declarations.forEach((declaration) => {
1871
+ if (!typescript.isIdentifier(declaration.name) || !declaration.initializer) return;
1872
+ if (typescript.isObjectLiteralExpression(declaration.initializer)) map.set(declaration.name.text, declaration.initializer);
1873
+ });
1874
+ });
1875
+ return map;
1876
+ }
1877
+ function assignCommentIfPresent(target, key, comment) {
1878
+ if (comment !== void 0) target[key] = comment;
1879
+ }
1880
+ function collectBlockFieldComments(object, parserOptionsProperty, rulesProperty, rulesBlock, sourceFile) {
1881
+ const fieldComments = {};
1882
+ const filesProperty = findProperty$1(object, "files");
1883
+ if (filesProperty) assignCommentIfPresent(fieldComments, "files", leadingCommentTextFor(sourceFile, filesProperty));
1884
+ if (parserOptionsProperty && typescript.isObjectLiteralExpression(parserOptionsProperty.initializer)) {
1885
+ const projectProperty = findProperty$1(parserOptionsProperty.initializer, "project");
1886
+ if (projectProperty) assignCommentIfPresent(fieldComments, "project", leadingCommentTextFor(sourceFile, projectProperty));
1887
+ }
1888
+ const globalsProperty = findProperty$1(object, "globals");
1889
+ if (globalsProperty) assignCommentIfPresent(fieldComments, "globals", leadingCommentTextFor(sourceFile, globalsProperty));
1890
+ if (rulesProperty && rulesBlock.globalComponents) assignCommentIfPresent(fieldComments, "globalComponents", leadingCommentTextFor(sourceFile, rulesProperty));
1891
+ return Object.keys(fieldComments).length > 0 ? fieldComments : void 0;
1892
+ }
1893
+ function readSharedBlockFields(input) {
1894
+ const { object, line, context } = input;
1895
+ const extendsList = readExtends(findProperty$1(object, "extends")?.initializer);
1896
+ const env = readEnvFromInitializer(findProperty$1(object, "env")?.initializer);
1897
+ const parserOptionsProperty = findProperty$1(object, "parserOptions");
1898
+ const parserOptionsResult = readParserOptions(parserOptionsProperty?.initializer, env);
1899
+ const parserProperty = findProperty$1(object, "parser");
1900
+ const parserMarker = parserOptionsResult.parserMarker || readParserMarker(parserProperty?.initializer);
1901
+ const globalsInit = findProperty$1(object, "globals")?.initializer;
1902
+ const globalsTokens = readGlobalsTokens$1(globalsInit, context.sourceFile);
1903
+ const globals = readGlobalsObject$1(globalsInit);
1904
+ const rulesProperty = findProperty$1(object, "rules");
1905
+ const rulesBlock = readRulesBlock$1(rulesProperty?.initializer, context);
1906
+ const insiderPluginNames = new Set([
1907
+ "vue",
1908
+ "@typescript-eslint",
1909
+ "jsdoc",
1910
+ "import",
1911
+ "jest",
1912
+ "@cspell"
1913
+ ]);
1914
+ const customPluginNames = readPluginsArray(findProperty$1(object, "plugins")?.initializer).filter((name) => !insiderPluginNames.has(name));
1915
+ const fieldComments = collectBlockFieldComments(object, parserOptionsProperty, rulesProperty, rulesBlock, context.sourceFile);
1916
+ return {
1917
+ extendsList,
1918
+ env,
1919
+ parserOptions: parserOptionsResult.options,
1920
+ parserMarker,
1921
+ globals,
1922
+ globalsTokens,
1923
+ customPluginNames: customPluginNames.length > 0 ? customPluginNames : void 0,
1924
+ rulesBlock,
1925
+ fieldComments
1926
+ };
1927
+ }
1928
+ function readOverride(object, context, elementNode) {
1929
+ const line = lineOf$1(context.sourceFile, object);
1930
+ const filesProperty = findProperty$1(object, "files");
1931
+ const files = filesProperty ? readStringOrEntries(filesProperty.initializer, context.sourceFile) : [];
1932
+ if (files.length === 0) {
1933
+ context.warnings.push({
1934
+ kind: "unrecognized-block",
1935
+ line,
1936
+ message: "overrides[] entry missing `files`; skipping"
1937
+ });
1938
+ return null;
1939
+ }
1940
+ const shared = readSharedBlockFields({
1941
+ object,
1942
+ line,
1943
+ context
1944
+ });
1945
+ const leadingComment = leadingCommentTextFor(context.sourceFile, elementNode);
1946
+ const override = {
1947
+ line,
1948
+ files,
1949
+ extends: shared.extendsList,
1950
+ env: shared.env,
1951
+ parserMarker: shared.parserMarker,
1952
+ parserOptions: shared.parserOptions,
1953
+ globals: shared.globals,
1954
+ globalsTokens: shared.globalsTokens,
1955
+ customPluginNames: shared.customPluginNames,
1956
+ rulesBlock: shared.rulesBlock,
1957
+ fieldComments: shared.fieldComments
1958
+ };
1959
+ if (leadingComment !== void 0) override.leadingComment = leadingComment;
1960
+ return override;
1961
+ }
1962
+ function readOverrides(initializer, context) {
1963
+ if (!initializer || !typescript.isArrayLiteralExpression(initializer)) return [];
1964
+ return initializer.elements.map((element) => typescript.isObjectLiteralExpression(element) ? readOverride(element, context, element) : null).filter((value) => value !== null);
1965
+ }
1966
+ function matchesPropertyAccess(expression, owner, member) {
1967
+ if (!typescript.isPropertyAccessExpression(expression)) return false;
1968
+ return typescript.isIdentifier(expression.expression) && expression.expression.text === owner && expression.name.text === member;
1969
+ }
1970
+ function isExportsTarget(expression) {
1971
+ return matchesPropertyAccess(expression, "module", "exports") || matchesPropertyAccess(expression, "exports", "default");
1972
+ }
1973
+ function findExportObject(sourceFile) {
1974
+ let result = null;
1975
+ sourceFile.statements.forEach((statement) => {
1976
+ if (result !== null) return;
1977
+ if (!typescript.isExpressionStatement(statement)) return;
1978
+ const { expression } = statement;
1979
+ if (!typescript.isBinaryExpression(expression) || expression.operatorToken.kind !== typescript.SyntaxKind.EqualsToken) return;
1980
+ if (!isExportsTarget(expression.left)) return;
1981
+ if (typescript.isObjectLiteralExpression(expression.right)) result = expression.right;
1982
+ });
1983
+ return result;
1984
+ }
1985
+ function buildRoot(object, context) {
1986
+ const line = lineOf$1(context.sourceFile, object);
1987
+ const shared = readSharedBlockFields({
1988
+ object,
1989
+ line,
1990
+ context
1991
+ });
1992
+ const overrides = readOverrides(findProperty$1(object, "overrides")?.initializer, context);
1993
+ const ignorePatterns = readStringOrEntries(findProperty$1(object, "ignorePatterns")?.initializer, context.sourceFile);
1994
+ const settingsProperty = findProperty$1(object, "settings");
1995
+ return {
1996
+ line,
1997
+ extends: shared.extendsList,
1998
+ env: shared.env,
1999
+ parserMarker: shared.parserMarker,
2000
+ parserOptions: shared.parserOptions,
2001
+ globals: shared.globals,
2002
+ globalsTokens: shared.globalsTokens,
2003
+ customPluginNames: shared.customPluginNames,
2004
+ rulesBlock: shared.rulesBlock,
2005
+ overrides,
2006
+ ignorePatterns,
2007
+ hasSettings: Boolean(settingsProperty),
2008
+ fieldComments: shared.fieldComments
2009
+ };
2010
+ }
2011
+ function parseEslintrc(source, filePath) {
2012
+ const sourceFile = typescript.createSourceFile(filePath, source, typescript.ScriptTarget.Latest, true);
2013
+ const warnings = [];
2014
+ const context = {
2015
+ sourceFile,
2016
+ warnings,
2017
+ constantRulesObjects: collectConstantObjects(sourceFile)
2018
+ };
2019
+ const exportObject = findExportObject(sourceFile);
2020
+ if (!exportObject) return {
2021
+ found: false,
2022
+ root: null,
2023
+ warnings
2024
+ };
2025
+ return {
2026
+ found: true,
2027
+ root: buildRoot(exportObject, context),
2028
+ warnings
2029
+ };
2030
+ }
2031
+ //#endregion
2032
+ //#region src/cli/migrate/globalsFolding.ts
2033
+ var FOLDABLE_ENVS = [
2034
+ "jest",
2035
+ "vitest",
2036
+ "jquery",
2037
+ "serviceworker",
2038
+ "worker",
2039
+ "webextensions",
2040
+ "node",
2041
+ "browser"
2042
+ ];
2043
+ var HIGH_THRESHOLD_ENVS = new Set(["node", "browser"]);
2044
+ function normalizeGlobalValue(value) {
2045
+ if (value === true || value === "writable" || value === "writeable") return "writable";
2046
+ if (value === "off") return "off";
2047
+ return "readonly";
2048
+ }
2049
+ function envEntries(env) {
2050
+ return globals.default[env];
2051
+ }
2052
+ function envHasName(env, name) {
2053
+ return name in envEntries(env);
2054
+ }
2055
+ function envValueFor(env, name) {
2056
+ const entries = envEntries(env);
2057
+ if (!(name in entries)) return null;
2058
+ return normalizeGlobalValue(entries[name]);
2059
+ }
2060
+ var SPREAD_PATTERN = /^globals\.([A-Za-z_$][\w$]*)$/;
2061
+ function spreadEnvKey(raw) {
2062
+ const match = SPREAD_PATTERN.exec(raw.trim());
2063
+ if (!match) return null;
2064
+ const [, key] = match;
2065
+ return FOLDABLE_ENVS.includes(key) ? key : null;
2066
+ }
2067
+ function foldGlobalsTokens(input) {
2068
+ const preservedSpreads = [];
2069
+ const preservedSpreadEnvs = /* @__PURE__ */ new Set();
2070
+ const namedTokens = [];
2071
+ input.forEach((token) => {
2072
+ if (token.kind === "spread") {
2073
+ preservedSpreads.push({ ...token });
2074
+ const envKey = spreadEnvKey(token.raw);
2075
+ if (envKey) preservedSpreadEnvs.add(envKey);
2076
+ return;
2077
+ }
2078
+ namedTokens.push({ ...token });
2079
+ });
2080
+ const remaining = /* @__PURE__ */ new Map();
2081
+ const namedOrder = [];
2082
+ namedTokens.forEach((token) => {
2083
+ if (!remaining.has(token.key)) namedOrder.push(token.key);
2084
+ remaining.set(token.key, token);
2085
+ });
2086
+ const syntheticSpreads = [];
2087
+ const addedSpreadEnvs = [];
2088
+ FOLDABLE_ENVS.forEach((env) => {
2089
+ if (preservedSpreadEnvs.has(env)) {
2090
+ namedOrder.forEach((name) => {
2091
+ const named = remaining.get(name);
2092
+ if (!named) return;
2093
+ const envValue = envValueFor(env, name);
2094
+ if (envValue === null) return;
2095
+ if (envValue !== normalizeGlobalValue(named.value)) return;
2096
+ remaining.delete(name);
2097
+ });
2098
+ return;
2099
+ }
2100
+ const matches = [];
2101
+ namedOrder.forEach((name) => {
2102
+ const named = remaining.get(name);
2103
+ if (!named) return;
2104
+ if (!envHasName(env, name)) return;
2105
+ const envValue = envValueFor(env, name);
2106
+ if (envValue === null) return;
2107
+ if (envValue !== normalizeGlobalValue(named.value)) return;
2108
+ matches.push(name);
2109
+ });
2110
+ const threshold = HIGH_THRESHOLD_ENVS.has(env) ? 3 : 1;
2111
+ if (matches.length < threshold) return;
2112
+ matches.forEach((name) => remaining.delete(name));
2113
+ syntheticSpreads.push({
2114
+ kind: "spread",
2115
+ raw: `globals.${env}`
2116
+ });
2117
+ addedSpreadEnvs.push(env);
2118
+ });
2119
+ const finalNamed = namedOrder.map((name) => remaining.get(name)).filter((token) => token !== void 0).map((token) => ({ ...token }));
2120
+ return {
2121
+ tokens: [
2122
+ ...syntheticSpreads,
2123
+ ...preservedSpreads,
2124
+ ...finalNamed
2125
+ ],
2126
+ addedSpreadEnvs
2127
+ };
2128
+ }
2129
+ //#endregion
2130
+ //#region src/cli/migrate/eslintrc/transform.ts
2131
+ var presetToScope$1 = {
2132
+ javascript: "javascript",
2133
+ "javascript-dom": "javascriptDom",
2134
+ "javascript-node": "javascriptNode",
2135
+ typescript: "typescript",
2136
+ "typescript-dom": "typescriptDom",
2137
+ "typescript-node": "typescriptNode",
2138
+ vue2: "vue2",
2139
+ vue3: "vue3",
2140
+ "vue2-typescript": "vue2Typescript",
2141
+ "vue3-typescript": "vue3Typescript",
2142
+ jest: "jest",
2143
+ vitest: "vitest",
2144
+ "jsdoc-based-ts": "jsdocBasedTs"
2145
+ };
2146
+ var tsScopes$1 = new Set([
2147
+ "typescript",
2148
+ "typescriptDom",
2149
+ "typescriptNode",
2150
+ "vue2Typescript",
2151
+ "vue3Typescript",
2152
+ "jsdocBasedTs"
2153
+ ]);
2154
+ var vueScopes$1 = new Set([
2155
+ "vue2",
2156
+ "vue3",
2157
+ "vue2Typescript",
2158
+ "vue3Typescript"
2159
+ ]);
2160
+ var defaultJestGlob = "**/*.{test,spec}.{ts,tsx,js,jsx,vue}";
2161
+ function hasVueExtend(extendsList) {
2162
+ return extendsList.some((extend) => extend.kind === "vue");
2163
+ }
2164
+ function hasJestExtend(extendsList) {
2165
+ return extendsList.some((extend) => extend.kind === "jest");
2166
+ }
2167
+ function inferVueMajor(extendsList) {
2168
+ if (extendsList.find((extend) => extend.kind === "vue")?.vueMajor === 2) return 2;
2169
+ return 3;
2170
+ }
2171
+ function mapVueScope(vueMajor, tsMarker) {
2172
+ if (vueMajor === 2) return tsMarker ? "vue2Typescript" : "vue2";
2173
+ return tsMarker ? "vue3Typescript" : "vue3";
2174
+ }
2175
+ function warnEnvBothBrowserAndNode(env, line, warnings) {
2176
+ if (!(env.browser && env.node)) return;
2177
+ if (warnings.some((warning) => warning.kind === "env-both-browser-and-node")) return;
2178
+ warnings.push({
2179
+ kind: "env-both-browser-and-node",
2180
+ line,
2181
+ message: "env.browser and env.node both true — defaulting to Dom scope"
2182
+ });
2183
+ }
2184
+ function inferPrimaryScope(input) {
2185
+ const { env, extendsList, parserMarker, line, warnings } = input;
2186
+ const jestMarker = env.jest || env.jestGlobals || hasJestExtend(extendsList);
2187
+ warnEnvBothBrowserAndNode(env, line, warnings);
2188
+ if (hasVueExtend(extendsList)) {
2189
+ const vueMajor = inferVueMajor(extendsList);
2190
+ return {
2191
+ primary: mapVueScope(vueMajor, parserMarker),
2192
+ addJest: jestMarker,
2193
+ vueMajor
2194
+ };
2195
+ }
2196
+ if (env.browser) return {
2197
+ primary: parserMarker ? "typescriptDom" : "javascriptDom",
2198
+ addJest: jestMarker
2199
+ };
2200
+ if (env.node) return {
2201
+ primary: parserMarker ? "typescriptNode" : "javascriptNode",
2202
+ addJest: jestMarker
2203
+ };
2204
+ return {
2205
+ primary: null,
2206
+ addJest: jestMarker
2207
+ };
2208
+ }
2209
+ function freshConfig$1() {
2210
+ return {
2211
+ ignores: [],
2212
+ scopes: /* @__PURE__ */ new Map(),
2213
+ strictGlobs: [],
2214
+ strictWholeFile: false,
2215
+ spellChecker: { ignoredPaths: [] },
2216
+ configFiles: []
2217
+ };
2218
+ }
2219
+ function appendScope$1(config, scope, entry) {
2220
+ const existing = config.scopes.get(scope);
2221
+ if (existing) existing.push(entry);
2222
+ else config.scopes.set(scope, [entry]);
2223
+ }
2224
+ function mergeGlobals(base, extra) {
2225
+ if (!base && !extra) return;
2226
+ const merged = { ...base ?? {} };
2227
+ if (extra) Object.entries(extra).forEach(([key, value]) => {
2228
+ if (!(key in merged)) merged[key] = value;
2229
+ });
2230
+ return Object.keys(merged).length > 0 ? merged : void 0;
2231
+ }
2232
+ function applyTsconfig(entry, scope, perBlockProject, fallbackProject) {
2233
+ if (!tsScopes$1.has(scope)) return;
2234
+ const project = perBlockProject && perBlockProject.length > 0 ? perBlockProject : fallbackProject;
2235
+ if (project && project.length > 0) entry.tsconfigPaths = toEntries(project);
2236
+ }
2237
+ function applyGlobalComponents(entry, scope, globalComponents) {
2238
+ if (!vueScopes$1.has(scope) || !globalComponents || globalComponents.length === 0) return;
2239
+ entry.globalComponents = cloneEntries(globalComponents);
2240
+ }
2241
+ function mapEslintrcFieldComments(incoming, scope) {
2242
+ if (!incoming) return;
2243
+ const result = {};
2244
+ if (incoming.files !== void 0) result.files = incoming.files;
2245
+ if (incoming.globals !== void 0) result.globals = incoming.globals;
2246
+ if (incoming.project !== void 0 && tsScopes$1.has(scope)) result.tsconfigPaths = incoming.project;
2247
+ if (incoming.globalComponents !== void 0 && vueScopes$1.has(scope)) result.globalComponents = incoming.globalComponents;
2248
+ return Object.keys(result).length > 0 ? result : void 0;
2249
+ }
2250
+ function mergeGlobalsTokens(base, extra) {
2251
+ if (!base && !extra) return;
2252
+ const merged = [];
2253
+ const seenNamed = /* @__PURE__ */ new Map();
2254
+ const append = (tokens) => {
2255
+ tokens.forEach((token) => {
2256
+ if (token.kind === "spread") {
2257
+ merged.push({ ...token });
2258
+ return;
2259
+ }
2260
+ const seenIndex = seenNamed.get(token.key);
2261
+ if (seenIndex === void 0) {
2262
+ seenNamed.set(token.key, merged.length);
2263
+ merged.push({ ...token });
2264
+ return;
2265
+ }
2266
+ merged[seenIndex] = { ...token };
2267
+ });
2268
+ };
2269
+ if (base) append(base);
2270
+ if (extra) append(extra);
2271
+ return merged.length > 0 ? merged : void 0;
2272
+ }
2273
+ function buildEntry$1(input) {
2274
+ const entry = { files: cloneEntries(input.files) };
2275
+ applyTsconfig(entry, input.scope, input.perBlockProject, input.fallbackProject);
2276
+ applyGlobalComponents(entry, input.scope, input.globalComponents);
2277
+ const globalsTokens = mergeGlobalsTokens(input.blockGlobalsTokens, input.topLevelGlobalsTokens);
2278
+ if (globalsTokens) entry.globalsTokens = globalsTokens;
2279
+ const globals = mergeGlobals(input.blockGlobals, input.topLevelGlobals);
2280
+ if (globals) entry.globals = globals;
2281
+ const fieldComments = mapEslintrcFieldComments(input.fieldComments, input.scope);
2282
+ if (fieldComments) entry.fieldComments = fieldComments;
2283
+ return entry;
2284
+ }
2285
+ function collectInsiderPresets(extendsList) {
2286
+ return extendsList.filter((extend) => extend.kind === "insider" && extend.insiderPreset).map((extend) => extend.insiderPreset ?? "");
2287
+ }
2288
+ function mapInsiderPreset(preset) {
2289
+ if (preset === "config") return "config";
2290
+ return presetToScope$1[preset] ?? null;
2291
+ }
2292
+ function captureConfigPresetFiles$1(input, context) {
2293
+ input.files.forEach((file) => {
2294
+ if (!context.config.configFiles.some((existing) => existing.value === file.value)) context.config.configFiles.push({ ...file });
2295
+ });
2296
+ }
2297
+ function emitInsiderScopes(presets, input, context) {
2298
+ let firstEntry = null;
2299
+ presets.forEach((preset) => {
2300
+ const mapped = mapInsiderPreset(preset);
2301
+ if (mapped === null) {
2302
+ context.warnings.push({
2303
+ kind: "unknown-preset",
2304
+ line: input.line,
2305
+ message: `Unknown @useinsider preset '${preset}' — dropped`
2306
+ });
2307
+ return;
2308
+ }
2309
+ if (mapped === "config") {
2310
+ captureConfigPresetFiles$1(input, context);
2311
+ return;
2312
+ }
2313
+ const entry = buildEntry$1({
2314
+ files: input.files,
2315
+ scope: mapped,
2316
+ perBlockProject: input.perBlockProject,
2317
+ fallbackProject: context.topLevelProject,
2318
+ globalComponents: input.globalComponents,
2319
+ blockGlobals: input.blockGlobals,
2320
+ blockGlobalsTokens: input.blockGlobalsTokens,
2321
+ topLevelGlobals: context.topLevelGlobals,
2322
+ topLevelGlobalsTokens: context.topLevelGlobalsTokens,
2323
+ fieldComments: input.fieldComments
2324
+ });
2325
+ appendScope$1(context.config, mapped, entry);
2326
+ if (!firstEntry) firstEntry = entry;
2327
+ });
2328
+ return firstEntry;
2329
+ }
2330
+ function emitInferredScopes(input, context) {
2331
+ const inference = inferPrimaryScope({
2332
+ env: input.env,
2333
+ extendsList: input.extendsList,
2334
+ parserMarker: input.parserMarker,
2335
+ line: input.line,
2336
+ warnings: context.warnings
2337
+ });
2338
+ let firstEntry = null;
2339
+ if (inference.primary) {
2340
+ const entry = buildEntry$1({
2341
+ files: input.files,
2342
+ scope: inference.primary,
2343
+ perBlockProject: input.perBlockProject,
2344
+ fallbackProject: context.topLevelProject,
2345
+ globalComponents: input.globalComponents,
2346
+ blockGlobals: input.blockGlobals,
2347
+ blockGlobalsTokens: input.blockGlobalsTokens,
2348
+ topLevelGlobals: context.topLevelGlobals,
2349
+ topLevelGlobalsTokens: context.topLevelGlobalsTokens,
2350
+ fieldComments: input.fieldComments
2351
+ });
2352
+ appendScope$1(context.config, inference.primary, entry);
2353
+ firstEntry = entry;
2354
+ }
2355
+ if (inference.addJest) {
2356
+ const entry = buildEntry$1({
2357
+ files: [{ value: defaultJestGlob }],
2358
+ scope: "jest",
2359
+ blockGlobals: input.blockGlobals,
2360
+ blockGlobalsTokens: input.blockGlobalsTokens,
2361
+ topLevelGlobals: context.topLevelGlobals,
2362
+ topLevelGlobalsTokens: context.topLevelGlobalsTokens
2363
+ });
2364
+ appendScope$1(context.config, "jest", entry);
2365
+ if (!firstEntry) firstEntry = entry;
2366
+ }
2367
+ return firstEntry;
2368
+ }
2369
+ function recordDroppedRules(input, context) {
2370
+ if (input.rulesCount > 0) {
2371
+ context.droppedRules += input.rulesCount;
2372
+ context.droppedBlocks += 1;
2373
+ }
2374
+ input.unresolvedSpreads.forEach((name) => {
2375
+ context.warnings.push({
2376
+ kind: "unresolved-rules-spread",
2377
+ line: input.line,
2378
+ message: `Could not resolve identifier '${name}' inside rules; dropping`
2379
+ });
2380
+ });
2381
+ }
2382
+ function applySpellChecker(input, context) {
2383
+ if (!input.spellCheckerOff) return;
2384
+ input.files.forEach((file) => {
2385
+ if (!context.config.spellChecker.ignoredPaths.some((existing) => existing.value === file.value)) context.config.spellChecker.ignoredPaths.push({ ...file });
2386
+ });
2387
+ }
2388
+ function recordDroppedPlugins(input, context) {
2389
+ if (!input.customPluginNames || input.customPluginNames.length === 0) return;
2390
+ input.customPluginNames.forEach((name) => context.droppedPlugins.add(name));
2391
+ context.droppedPluginEntries += 1;
2392
+ }
2393
+ function processBlock(input, context) {
2394
+ recordDroppedRules(input, context);
2395
+ recordDroppedPlugins(input, context);
2396
+ applySpellChecker(input, context);
2397
+ const insiderPresets = collectInsiderPresets(input.extendsList);
2398
+ const firstEntry = insiderPresets.length > 0 ? emitInsiderScopes(insiderPresets, input, context) : emitInferredScopes(input, context);
2399
+ if (firstEntry && input.leadingComment !== void 0) firstEntry.leadingComment = input.leadingComment;
2400
+ return firstEntry !== null;
2401
+ }
2402
+ function blockInputFromRoot(root, defaultFiles) {
2403
+ return {
2404
+ line: root.line,
2405
+ files: defaultFiles,
2406
+ extendsList: root.extends,
2407
+ env: root.env,
2408
+ parserMarker: root.parserMarker,
2409
+ perBlockProject: root.parserOptions.project,
2410
+ globalComponents: root.rulesBlock.globalComponents,
2411
+ spellCheckerOff: root.rulesBlock.spellCheckerOff,
2412
+ blockGlobals: void 0,
2413
+ blockGlobalsTokens: void 0,
2414
+ customPluginNames: root.customPluginNames,
2415
+ rulesCount: root.rulesBlock.customRuleCount,
2416
+ unresolvedSpreads: root.rulesBlock.unresolvedSpreads,
2417
+ fieldComments: root.fieldComments
2418
+ };
2419
+ }
2420
+ function isBareOverride(override) {
2421
+ const noExtends = override.extends.length === 0;
2422
+ const noEnv = !override.env.browser && !override.env.node && !override.env.jest && !override.env.jestGlobals;
2423
+ const noParserMarker = !override.parserMarker;
2424
+ return noExtends && noEnv && noParserMarker;
2425
+ }
2426
+ function blockInputFromOverride(override, root) {
2427
+ const inherit = isBareOverride(override);
2428
+ return {
2429
+ line: override.line,
2430
+ files: override.files,
2431
+ extendsList: inherit ? root.extends : override.extends,
2432
+ env: inherit ? root.env : override.env,
2433
+ parserMarker: inherit ? root.parserMarker : override.parserMarker,
2434
+ perBlockProject: override.parserOptions.project,
2435
+ globalComponents: override.rulesBlock.globalComponents,
2436
+ spellCheckerOff: override.rulesBlock.spellCheckerOff,
2437
+ blockGlobals: override.globals,
2438
+ blockGlobalsTokens: override.globalsTokens,
2439
+ customPluginNames: override.customPluginNames,
2440
+ rulesCount: override.rulesBlock.customRuleCount,
2441
+ unresolvedSpreads: override.rulesBlock.unresolvedSpreads,
2442
+ leadingComment: override.leadingComment,
2443
+ fieldComments: override.fieldComments
2444
+ };
2445
+ }
2446
+ function defaultRootFiles(root) {
2447
+ if (root.env.browser && hasVueExtend(root.extends)) return toEntries(["**/*.{js,jsx,ts,tsx,vue}"]);
2448
+ if (root.parserMarker) return toEntries(["**/*.{ts,tsx}"]);
2449
+ return toEntries(["**/*.{js,jsx,cjs,mjs}"]);
2450
+ }
2451
+ function applyIgnorePatterns(root, config) {
2452
+ root.ignorePatterns.forEach((ignore) => {
2453
+ if (!config.ignores.some((existing) => existing.value === ignore.value)) config.ignores.push({ ...ignore });
2454
+ });
2455
+ }
2456
+ function recordSettingsWarning(root, warnings) {
2457
+ if (root.hasSettings) warnings.push({
2458
+ kind: "dropped-settings",
2459
+ line: root.line,
2460
+ message: "Dropped legacy `settings` block — flat config does not support this surface"
2461
+ });
2462
+ }
2463
+ function consolidateExtendsWarning(extendKinds, rawDropped, warnings) {
2464
+ if (rawDropped.size === 0) return;
2465
+ const list = [...rawDropped].sort((left, right) => left.localeCompare(right)).join(", ");
2466
+ warnings.push({
2467
+ kind: "dropped-extends",
2468
+ message: `Dropped non-@useinsider extends: ${list}`
2469
+ });
2470
+ }
2471
+ function recordNoInsiderWarning(hasInsiderExtend, warnings) {
2472
+ if (hasInsiderExtend) return;
2473
+ warnings.push({
2474
+ kind: "no-insider-extends",
2475
+ message: "Source did not extend any @useinsider/eslint-config preset — output is a best-effort inference. Custom rules were dropped; review the generated config and adjust scopes as needed."
2476
+ });
2477
+ }
2478
+ function collectExtendKinds(root) {
2479
+ const kinds = /* @__PURE__ */ new Set();
2480
+ const rawDropped = /* @__PURE__ */ new Set();
2481
+ let hasInsider = false;
2482
+ const visit = (list) => {
2483
+ list.forEach((extend) => {
2484
+ kinds.add(extend.kind);
2485
+ if (extend.kind === "insider") {
2486
+ hasInsider = true;
2487
+ return;
2488
+ }
2489
+ rawDropped.add(extend.raw);
2490
+ });
2491
+ };
2492
+ visit(root.extends);
2493
+ root.overrides.forEach((override) => visit(override.extends));
2494
+ return {
2495
+ kinds,
2496
+ rawDropped,
2497
+ hasInsider
2498
+ };
2499
+ }
2500
+ function formatDroppedRulesMessage$1(count, blocks) {
2501
+ return `Dropped ${count} custom ${count === 1 ? "rule override" : "rule overrides"} across ${blocks} ${blocks === 1 ? "block" : "blocks"}`;
2502
+ }
2503
+ function tokensFromRecord$2(globals) {
2504
+ return Object.entries(globals).map(([key, value]) => ({
2505
+ kind: "named",
2506
+ key,
2507
+ value
2508
+ }));
2509
+ }
2510
+ function resolveBaseTokens$1(entry) {
2511
+ if (entry.globalsTokens && entry.globalsTokens.length > 0) return entry.globalsTokens;
2512
+ if (entry.globals && Object.keys(entry.globals).length > 0) return tokensFromRecord$2(entry.globals);
2513
+ }
2514
+ function applyGlobalsFolding$1(config) {
2515
+ let anySyntheticEmitted = false;
2516
+ config.scopes.forEach((entries) => {
2517
+ entries.forEach((entry) => {
2518
+ const baseTokens = resolveBaseTokens$1(entry);
2519
+ if (!baseTokens) return;
2520
+ const { tokens, addedSpreadEnvs } = foldGlobalsTokens(baseTokens);
2521
+ if (addedSpreadEnvs.length > 0) anySyntheticEmitted = true;
2522
+ entry.globalsTokens = tokens;
2523
+ const namedRecord = {};
2524
+ tokens.forEach((token) => {
2525
+ if (token.kind === "named") namedRecord[token.key] = token.value;
2526
+ });
2527
+ entry.globals = Object.keys(namedRecord).length > 0 ? namedRecord : void 0;
2528
+ });
2529
+ });
2530
+ return anySyntheticEmitted;
2531
+ }
2532
+ function buildPreservedImports(emittedSyntheticSpread) {
2533
+ if (!emittedSyntheticSpread) return [];
2534
+ return [{
2535
+ raw: "import globals from 'globals';",
2536
+ moduleSpecifier: "globals"
2537
+ }];
2538
+ }
2539
+ function transformEslintrcToV2(parseResult) {
2540
+ const config = freshConfig$1();
2541
+ const warnings = [...parseResult.warnings];
2542
+ if (!parseResult.root) return {
2543
+ config,
2544
+ silenceRulesCalls: [],
2545
+ needsSilenceRulesImport: false,
2546
+ preservedImports: [],
2547
+ warnings,
2548
+ droppedRuleCount: 0,
2549
+ droppedRuleBlockCount: 0
2550
+ };
2551
+ const { root } = parseResult;
2552
+ const context = {
2553
+ config,
2554
+ warnings,
2555
+ topLevelGlobals: root.globals,
2556
+ topLevelGlobalsTokens: root.globalsTokens,
2557
+ topLevelProject: root.parserOptions.project,
2558
+ droppedRules: 0,
2559
+ droppedBlocks: 0,
2560
+ droppedPlugins: /* @__PURE__ */ new Set(),
2561
+ droppedPluginEntries: 0
2562
+ };
2563
+ applyIgnorePatterns(root, config);
2564
+ recordSettingsWarning(root, warnings);
2565
+ if (root.overrides.length > 0) {
2566
+ root.overrides.forEach((override) => {
2567
+ processBlock(blockInputFromOverride(override, root), context);
2568
+ });
2569
+ if (root.rulesBlock.customRuleCount > 0 || root.rulesBlock.unresolvedSpreads.length > 0) recordDroppedRules(blockInputFromRoot(root, defaultRootFiles(root)), context);
2570
+ } else processBlock(blockInputFromRoot(root, defaultRootFiles(root)), context);
2571
+ if (context.droppedRules > 0) warnings.push({
2572
+ kind: "dropped-rules",
2573
+ message: formatDroppedRulesMessage$1(context.droppedRules, context.droppedBlocks)
2574
+ });
2575
+ const { kinds, rawDropped, hasInsider } = collectExtendKinds(root);
2576
+ consolidateExtendsWarning(kinds, rawDropped, warnings);
2577
+ recordNoInsiderWarning(hasInsider, warnings);
2578
+ if (context.droppedPluginEntries > 0 && context.droppedPlugins.size > 0) {
2579
+ const sorted = [...context.droppedPlugins].sort((left, right) => left.localeCompare(right));
2580
+ warnings.push({
2581
+ kind: "dropped-plugins",
2582
+ message: `Dropped custom plugins on ${context.droppedPluginEntries} entries: ${sorted.join(", ")}`
2583
+ });
2584
+ }
2585
+ return {
2586
+ config,
2587
+ silenceRulesCalls: [],
2588
+ needsSilenceRulesImport: false,
2589
+ preservedImports: buildPreservedImports(applyGlobalsFolding$1(config)),
2590
+ warnings,
2591
+ droppedRuleCount: context.droppedRules,
2592
+ droppedRuleBlockCount: context.droppedBlocks
2593
+ };
2594
+ }
2595
+ //#endregion
2596
+ //#region src/cli/migrate/parse.ts
2597
+ var knownPresets = new Set([
2598
+ "config",
2599
+ "javascript",
2600
+ "javascript-dom",
2601
+ "javascript-node",
2602
+ "typescript",
2603
+ "typescript-dom",
2604
+ "typescript-node",
2605
+ "vue2",
2606
+ "vue2-typescript",
2607
+ "vue3",
2608
+ "vue3-typescript",
2609
+ "jest",
2610
+ "vitest",
2611
+ "jsdoc-based-ts",
2612
+ "strict",
2613
+ "dom",
2614
+ "node"
2615
+ ]);
2616
+ function lineOf(sourceFile, node) {
2617
+ const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile));
2618
+ return line + 1;
2619
+ }
2620
+ function unwrapTypeCasts(expression) {
2621
+ let current = expression;
2622
+ while (typescript.isParenthesizedExpression(current) || typescript.isAsExpression(current) || typescript.isTypeAssertionExpression(current) || typescript.isSatisfiesExpression(current)) current = current.expression;
2623
+ return current;
2624
+ }
2625
+ function unwrapAwait(expression) {
2626
+ const peeled = unwrapTypeCasts(expression);
2627
+ if (typescript.isAwaitExpression(peeled)) return unwrapTypeCasts(peeled.expression);
2628
+ return peeled;
2629
+ }
2630
+ function isStringLiteral(node) {
2631
+ return typescript.isStringLiteral(node) || typescript.isNoSubstitutionTemplateLiteral(node);
2632
+ }
2633
+ function readStringLiteralArray(node) {
2634
+ if (!node || !typescript.isArrayLiteralExpression(node)) return;
2635
+ const items = node.elements.map((element) => isStringLiteral(element) ? element.text : null);
2636
+ if (items.some((item) => item === null)) return;
2637
+ return items;
2638
+ }
2639
+ function readStringLiteralEntries(node, sourceFile) {
2640
+ if (!node || !typescript.isArrayLiteralExpression(node)) return;
2641
+ const entries = node.elements.map((element) => {
2642
+ if (!isStringLiteral(element)) return null;
2643
+ const leadingComment = leadingCommentTextFor(sourceFile, element);
2644
+ return leadingComment === void 0 ? { value: element.text } : {
2645
+ value: element.text,
2646
+ leadingComment
2647
+ };
2648
+ });
2649
+ if (entries.some((entry) => entry === null)) return;
2650
+ return entries;
2651
+ }
2652
+ function propertyKeyName(property) {
2653
+ if (!typescript.isPropertyAssignment(property)) return null;
2654
+ const key = property.name;
2655
+ if (typescript.isIdentifier(key) || typescript.isStringLiteral(key)) return key.text;
2656
+ return null;
2657
+ }
2658
+ function findProperty(object, name) {
2659
+ return object.properties.filter((property) => typescript.isPropertyAssignment(property)).find((property) => propertyKeyName(property) === name);
2660
+ }
2661
+ function readGlobalValue(initializer) {
2662
+ if (isStringLiteral(initializer)) return { value: initializer.text };
2663
+ if (initializer.kind === typescript.SyntaxKind.TrueKeyword) return { value: true };
2664
+ if (initializer.kind === typescript.SyntaxKind.FalseKeyword) return { value: false };
2665
+ if (typescript.isNumericLiteral(initializer)) return { value: Number(initializer.text) };
2666
+ return null;
2667
+ }
2668
+ function readGlobalsObject(node) {
2669
+ if (!node || !typescript.isObjectLiteralExpression(node)) return;
2670
+ const entries = node.properties.map((property) => {
2671
+ if (!typescript.isPropertyAssignment(property)) return null;
2672
+ const name = propertyKeyName(property);
2673
+ if (name === null) return null;
2674
+ const valueWrapper = readGlobalValue(property.initializer);
2675
+ if (valueWrapper === null) return null;
2676
+ return [name, valueWrapper.value];
2677
+ });
2678
+ if (entries.some((entry) => entry === null)) return;
2679
+ return Object.fromEntries(entries);
2680
+ }
2681
+ function readGlobalsTokens(node, sourceFile) {
2682
+ if (!node || !typescript.isObjectLiteralExpression(node)) return;
2683
+ const tokens = [];
2684
+ node.properties.forEach((property) => {
2685
+ if (typescript.isSpreadAssignment(property)) {
2686
+ tokens.push({
2687
+ kind: "spread",
2688
+ raw: property.expression.getText(sourceFile)
2689
+ });
2690
+ return;
2691
+ }
2692
+ if (!typescript.isPropertyAssignment(property)) return;
2693
+ const name = propertyKeyName(property);
2694
+ if (name === null) return;
2695
+ const valueWrapper = readGlobalValue(property.initializer);
2696
+ if (valueWrapper === null) return;
2697
+ tokens.push({
2698
+ kind: "named",
2699
+ key: name,
2700
+ value: valueWrapper.value
2701
+ });
2702
+ });
2703
+ return tokens.length > 0 ? tokens : void 0;
2704
+ }
2705
+ function namedTokensToRecord(tokens) {
2706
+ if (!tokens) return;
2707
+ const entries = tokens.filter((token) => token.kind === "named").map((token) => [token.key, token.value]);
2708
+ return entries.length > 0 ? Object.fromEntries(entries) : void 0;
2709
+ }
2710
+ function extractGlobalComponents(rulesNode, sourceFile) {
2711
+ const rule = findProperty(rulesNode, "vue/no-undef-components");
2712
+ if (!rule || !typescript.isArrayLiteralExpression(rule.initializer)) return;
2713
+ const [, optionsNode] = rule.initializer.elements;
2714
+ if (!optionsNode || !typescript.isObjectLiteralExpression(optionsNode)) return;
2715
+ const ignorePatterns = findProperty(optionsNode, "ignorePatterns");
2716
+ if (!ignorePatterns) return;
2717
+ return readStringLiteralEntries(ignorePatterns.initializer, sourceFile);
2718
+ }
2719
+ function assignFieldComment(data, field, comment) {
2720
+ if (comment === void 0) return;
2721
+ data.fieldComments = {
2722
+ ...data.fieldComments,
2723
+ [field]: comment
2724
+ };
2725
+ }
2726
+ function countExtraRules(rulesNode) {
2727
+ return rulesNode.properties.filter((property) => {
2728
+ const name = propertyKeyName(property);
2729
+ return name !== null && name !== "vue/no-undef-components";
2730
+ }).length;
2731
+ }
2732
+ function readParserProject(parserOptions, sourceFile) {
2733
+ const projectProperty = findProperty(parserOptions, "project");
2734
+ if (!projectProperty) return;
2735
+ const { initializer } = projectProperty;
2736
+ if (isStringLiteral(initializer)) return [{ value: initializer.text }];
2737
+ return readStringLiteralEntries(initializer, sourceFile);
2738
+ }
2739
+ function readParserProjectService(parserOptions) {
2740
+ if (findProperty(parserOptions, "projectService")?.initializer.kind === typescript.SyntaxKind.TrueKeyword) return true;
2741
+ }
2742
+ function expressionMentionsTsParser(expression, sourceFile) {
2743
+ return expression.getText(sourceFile).includes("@typescript-eslint/parser");
2744
+ }
2745
+ function readLanguageOptions(languageOptions, data, sourceFile) {
2746
+ const parserOptionsProperty = findProperty(languageOptions, "parserOptions");
2747
+ if (parserOptionsProperty && typescript.isObjectLiteralExpression(parserOptionsProperty.initializer)) {
2748
+ const parserOptions = parserOptionsProperty.initializer;
2749
+ data.parserProject = readParserProject(parserOptions, sourceFile);
2750
+ data.parserProjectService = readParserProjectService(parserOptions);
2751
+ }
2752
+ const parserProperty = findProperty(languageOptions, "parser");
2753
+ if (parserProperty && expressionMentionsTsParser(parserProperty.initializer, sourceFile)) data.parserIsTypescript = true;
2754
+ const globalsProperty = findProperty(languageOptions, "globals");
2755
+ if (globalsProperty) {
2756
+ data.globalsTokens = readGlobalsTokens(globalsProperty.initializer, sourceFile);
2757
+ data.globals = namedTokensToRecord(data.globalsTokens) ?? readGlobalsObject(globalsProperty.initializer);
2758
+ }
2759
+ }
2760
+ function readPluginNames(pluginsProperty) {
2761
+ if (!typescript.isObjectLiteralExpression(pluginsProperty.initializer)) return [];
2762
+ return pluginsProperty.initializer.properties.map(propertyKeyName).filter((name) => name !== null);
2763
+ }
2764
+ function readRulesBlock(rulesProperty, data, sourceFile) {
2765
+ if (!typescript.isObjectLiteralExpression(rulesProperty.initializer)) return;
2766
+ const rulesObject = rulesProperty.initializer;
2767
+ data.globalComponents = extractGlobalComponents(rulesObject, sourceFile);
2768
+ data.extraRuleCount = countExtraRules(rulesObject);
2769
+ }
2770
+ function captureLanguageOptionsComments(languageOptionsObject, data, sourceFile) {
2771
+ const parserOptionsProperty = findProperty(languageOptionsObject, "parserOptions");
2772
+ if (parserOptionsProperty && typescript.isObjectLiteralExpression(parserOptionsProperty.initializer)) {
2773
+ const projectProperty = findProperty(parserOptionsProperty.initializer, "project");
2774
+ if (projectProperty) assignFieldComment(data, "parserProject", leadingCommentTextFor(sourceFile, projectProperty));
2775
+ }
2776
+ const globalsProperty = findProperty(languageOptionsObject, "globals");
2777
+ if (globalsProperty) assignFieldComment(data, "globals", leadingCommentTextFor(sourceFile, globalsProperty));
2778
+ }
2779
+ function processFilesProperty(configNode, data, sourceFile) {
2780
+ const filesProperty = findProperty(configNode, "files");
2781
+ if (!filesProperty) return;
2782
+ data.files = readStringLiteralEntries(filesProperty.initializer, sourceFile);
2783
+ assignFieldComment(data, "files", leadingCommentTextFor(sourceFile, filesProperty));
2784
+ }
2785
+ function processIgnoresProperty(configNode, data, sourceFile) {
2786
+ const ignoresProperty = findProperty(configNode, "ignores");
2787
+ if (!ignoresProperty) return;
2788
+ data.ignores = readStringLiteralEntries(ignoresProperty.initializer, sourceFile);
2789
+ assignFieldComment(data, "ignores", leadingCommentTextFor(sourceFile, ignoresProperty));
2790
+ }
2791
+ function processPluginsProperty(configNode, data) {
2792
+ const pluginsProperty = findProperty(configNode, "plugins");
2793
+ if (!pluginsProperty) return;
2794
+ const pluginNames = readPluginNames(pluginsProperty);
2795
+ if (pluginNames.length > 0) data.customPluginNames = pluginNames;
2796
+ }
2797
+ function processRulesProperty(configNode, data, sourceFile) {
2798
+ const rulesProperty = findProperty(configNode, "rules");
2799
+ if (!rulesProperty) return;
2800
+ readRulesBlock(rulesProperty, data, sourceFile);
2801
+ if (data.globalComponents !== void 0) assignFieldComment(data, "globalComponents", leadingCommentTextFor(sourceFile, rulesProperty));
2802
+ }
2803
+ function parseConfigObject(configNode, sourceFile) {
2804
+ const data = { extraRuleCount: 0 };
2805
+ processFilesProperty(configNode, data, sourceFile);
2806
+ processIgnoresProperty(configNode, data, sourceFile);
2807
+ const languageOptionsProperty = findProperty(configNode, "languageOptions");
2808
+ if (languageOptionsProperty && typescript.isObjectLiteralExpression(languageOptionsProperty.initializer)) {
2809
+ readLanguageOptions(languageOptionsProperty.initializer, data, sourceFile);
2810
+ captureLanguageOptionsComments(languageOptionsProperty.initializer, data, sourceFile);
2811
+ }
2812
+ processPluginsProperty(configNode, data);
2813
+ processRulesProperty(configNode, data, sourceFile);
2814
+ return data;
2815
+ }
2816
+ function mergeRescuedGlobalsTokens(innerTokens, siblingTokens) {
2817
+ if (!innerTokens || innerTokens.length === 0) return siblingTokens.map((token) => ({ ...token }));
2818
+ const innerNamedKeys = /* @__PURE__ */ new Set();
2819
+ innerTokens.forEach((token) => {
2820
+ if (token.kind === "named") innerNamedKeys.add(token.key);
2821
+ });
2822
+ const merged = innerTokens.map((token) => ({ ...token }));
2823
+ siblingTokens.forEach((token) => {
2824
+ if (token.kind === "spread") {
2825
+ merged.push({ ...token });
2826
+ return;
2827
+ }
2828
+ if (innerNamedKeys.has(token.key)) return;
2829
+ merged.push({ ...token });
2830
+ innerNamedKeys.add(token.key);
2831
+ });
2832
+ return merged;
2833
+ }
2834
+ function applyRescuedGlobals(data, rescued) {
2835
+ if (rescued.globalsTokens && rescued.globalsTokens.length > 0) {
2836
+ data.globalsTokens = mergeRescuedGlobalsTokens(data.globalsTokens, rescued.globalsTokens);
2837
+ data.globals = namedTokensToRecord(data.globalsTokens) ?? data.globals;
2838
+ return true;
2839
+ }
2840
+ if (rescued.globals && Object.keys(rescued.globals).length > 0) {
2841
+ const existingGlobals = data.globals ?? {};
2842
+ data.globals = {
2843
+ ...rescued.globals,
2844
+ ...existingGlobals
2845
+ };
2846
+ return true;
2847
+ }
2848
+ return false;
2849
+ }
2850
+ function applyRescuedParserProject(data, rescued) {
2851
+ if (!rescued.parserProject || rescued.parserProject.length === 0) return false;
2852
+ if (data.parserProject && data.parserProject.length > 0) return false;
2853
+ data.parserProject = rescued.parserProject;
2854
+ return true;
2855
+ }
2856
+ function applyRescuedLanguageOptions(data, rescued) {
2857
+ let rescuedAny = applyRescuedGlobals(data, rescued);
2858
+ rescuedAny = applyRescuedParserProject(data, rescued) || rescuedAny;
2859
+ if (rescued.parserIsTypescript && !data.parserIsTypescript) {
2860
+ data.parserIsTypescript = true;
2861
+ rescuedAny = true;
2862
+ }
2863
+ if (rescued.parserProjectService && data.parserProjectService === void 0) {
2864
+ data.parserProjectService = true;
2865
+ rescuedAny = true;
2866
+ }
2867
+ return rescuedAny;
2868
+ }
2869
+ function parseSiblingLanguageOptions(callArgument, sourceFile) {
2870
+ const languageOptionsProperty = findProperty(callArgument, "languageOptions");
2871
+ if (!languageOptionsProperty || !typescript.isObjectLiteralExpression(languageOptionsProperty.initializer)) return null;
2872
+ const rescued = { extraRuleCount: 0 };
2873
+ readLanguageOptions(languageOptionsProperty.initializer, rescued, sourceFile);
2874
+ return rescued;
2875
+ }
2876
+ function mergeSiblingIgnoresIntoData(callArgument, data, sourceFile) {
2877
+ const ignoresProperty = findProperty(callArgument, "ignores");
2878
+ if (!ignoresProperty) return false;
2879
+ const rescuedIgnores = readStringLiteralEntries(ignoresProperty.initializer, sourceFile);
2880
+ if (!rescuedIgnores || rescuedIgnores.length === 0) return false;
2881
+ const existing = data.ignores ?? [];
2882
+ const seen = new Set(existing.map((entry) => entry.value));
2883
+ const additions = [];
2884
+ rescuedIgnores.forEach((entry) => {
2885
+ if (seen.has(entry.value)) return;
2886
+ seen.add(entry.value);
2887
+ additions.push(entry);
2888
+ });
2889
+ if (additions.length === 0) return false;
2890
+ data.ignores = [...existing, ...additions];
2891
+ return true;
2892
+ }
2893
+ function applySiblingRescues(callArgument, data, sourceFile) {
2894
+ const rescuedSibling = parseSiblingLanguageOptions(callArgument, sourceFile);
2895
+ const rescuedLanguageOptions = rescuedSibling ? applyRescuedLanguageOptions(data, rescuedSibling) : false;
2896
+ const rescuedIgnores = mergeSiblingIgnoresIntoData(callArgument, data, sourceFile);
2897
+ return rescuedLanguageOptions || rescuedIgnores;
2898
+ }
2899
+ function classifyPresets(presetList, line, warnings) {
2900
+ const presets = [];
2901
+ const unknownPresets = [];
2902
+ presetList.forEach((presetName) => {
2903
+ if (knownPresets.has(presetName)) presets.push(presetName);
2904
+ else {
2905
+ unknownPresets.push(presetName);
2906
+ warnings.push({
2907
+ kind: "unknown-preset",
2908
+ line,
2909
+ message: `Unknown v1 preset '${presetName}' — dropped`
2910
+ });
2911
+ }
2912
+ });
2913
+ return {
2914
+ presets,
2915
+ unknownPresets
2916
+ };
2917
+ }
2918
+ function parseUseInsiderCall(callExpression, sourceFile, warnings) {
2919
+ const line = lineOf(sourceFile, callExpression);
2920
+ const [firstArgument] = callExpression.arguments;
2921
+ if (!firstArgument || !typescript.isObjectLiteralExpression(firstArgument)) {
2922
+ warnings.push({
2923
+ kind: "unrecognized-block",
2924
+ line,
2925
+ message: "useInsider call without object literal argument; skipping"
2926
+ });
2927
+ return null;
2928
+ }
2929
+ const presetProperty = findProperty(firstArgument, "preset");
2930
+ const configProperty = findProperty(firstArgument, "config");
2931
+ if (!presetProperty) {
2932
+ warnings.push({
2933
+ kind: "unrecognized-block",
2934
+ line,
2935
+ message: "useInsider call missing preset; skipping"
2936
+ });
2937
+ return null;
2938
+ }
2939
+ const presetList = readStringLiteralArray(presetProperty.initializer);
2940
+ if (!presetList) {
2941
+ warnings.push({
2942
+ kind: "unrecognized-block",
2943
+ line,
2944
+ message: "useInsider preset is not a string-literal array; skipping"
2945
+ });
2946
+ return null;
2947
+ }
2948
+ const { presets, unknownPresets } = classifyPresets(presetList, line, warnings);
2949
+ const configData = configProperty && typescript.isObjectLiteralExpression(configProperty.initializer) ? parseConfigObject(configProperty.initializer, sourceFile) : { extraRuleCount: 0 };
2950
+ const rescuedAny = applySiblingRescues(firstArgument, configData, sourceFile);
2951
+ const call = {
2952
+ kind: "useInsiderCall",
2953
+ line,
2954
+ presets,
2955
+ unknownPresets,
2956
+ files: configData.files,
2957
+ ignores: configData.ignores,
2958
+ parserProject: configData.parserProject,
2959
+ parserProjectService: configData.parserProjectService,
2960
+ globals: configData.globals,
2961
+ globalsTokens: configData.globalsTokens,
2962
+ globalComponents: configData.globalComponents,
2963
+ parserIsTypescript: configData.parserIsTypescript,
2964
+ customPluginNames: configData.customPluginNames,
2965
+ extraRuleCount: configData.extraRuleCount,
2966
+ fieldComments: configData.fieldComments
2967
+ };
2968
+ if (rescuedAny) call.rescuedSiblingLanguageOptions = true;
2969
+ return call;
2970
+ }
2971
+ function tryClassifyIgnoresBlock(objectLiteral, keys, line, sourceFile) {
2972
+ if (keys.length !== 1 || keys[0] !== "ignores") return null;
2973
+ const ignoresProperty = findProperty(objectLiteral, "ignores");
2974
+ const ignores = ignoresProperty ? readStringLiteralEntries(ignoresProperty.initializer, sourceFile) : void 0;
2975
+ if (!ignores) return null;
2976
+ return {
2977
+ kind: "ignoresBlock",
2978
+ line,
2979
+ ignores
2980
+ };
2981
+ }
2982
+ function isSpellCheckerOffRule(rules) {
2983
+ if (rules.length !== 1) return false;
2984
+ const [onlyRule] = rules;
2985
+ if (!typescript.isPropertyAssignment(onlyRule) || propertyKeyName(onlyRule) !== "@cspell/spellchecker") return false;
2986
+ return isStringLiteral(onlyRule.initializer) && onlyRule.initializer.text === "off";
2987
+ }
2988
+ function tryClassifySpellCheckerOff(objectLiteral, keys, line, sourceFile) {
2989
+ if (keys.length !== 2 || !keys.includes("files") || !keys.includes("rules")) return null;
2990
+ const filesProperty = findProperty(objectLiteral, "files");
2991
+ const rulesProperty = findProperty(objectLiteral, "rules");
2992
+ const files = filesProperty ? readStringLiteralEntries(filesProperty.initializer, sourceFile) : void 0;
2993
+ if (!files || !rulesProperty || !typescript.isObjectLiteralExpression(rulesProperty.initializer)) return null;
2994
+ if (!isSpellCheckerOffRule(rulesProperty.initializer.properties)) return null;
2995
+ return {
2996
+ kind: "spellCheckerOff",
2997
+ line,
2998
+ files
2999
+ };
3000
+ }
3001
+ function tryClassifyStandaloneGlobals(objectLiteral, keys, line, sourceFile) {
3002
+ if (!keys.includes("files") || !keys.includes("languageOptions")) return null;
3003
+ const filesProperty = findProperty(objectLiteral, "files");
3004
+ const languageOptionsProperty = findProperty(objectLiteral, "languageOptions");
3005
+ const files = filesProperty ? readStringLiteralEntries(filesProperty.initializer, sourceFile) : void 0;
3006
+ if (!files || !languageOptionsProperty || !typescript.isObjectLiteralExpression(languageOptionsProperty.initializer)) return null;
3007
+ const globalsProperty = findProperty(languageOptionsProperty.initializer, "globals");
3008
+ if (!globalsProperty) return null;
3009
+ const tokens = readGlobalsTokens(globalsProperty.initializer, sourceFile);
3010
+ if (!tokens || tokens.length === 0) return null;
3011
+ return {
3012
+ kind: "standaloneGlobals",
3013
+ line,
3014
+ files,
3015
+ globalsTokens: tokens
3016
+ };
3017
+ }
3018
+ function classifyObjectElement(objectLiteral, sourceFile, warnings) {
3019
+ const line = lineOf(sourceFile, objectLiteral);
3020
+ const keys = objectLiteral.properties.map(propertyKeyName).filter((name) => name !== null);
3021
+ const ignoresBlock = tryClassifyIgnoresBlock(objectLiteral, keys, line, sourceFile);
3022
+ if (ignoresBlock) return ignoresBlock;
3023
+ const spellCheckerOff = tryClassifySpellCheckerOff(objectLiteral, keys, line, sourceFile);
3024
+ if (spellCheckerOff) return spellCheckerOff;
3025
+ const standaloneGlobals = tryClassifyStandaloneGlobals(objectLiteral, keys, line, sourceFile);
3026
+ if (standaloneGlobals) return standaloneGlobals;
3027
+ warnings.push({
3028
+ kind: "unrecognized-block",
3029
+ line,
3030
+ message: "Unrecognized array element; dropping"
3031
+ });
3032
+ return {
3033
+ kind: "unrecognized",
3034
+ line,
3035
+ snippet: objectLiteral.getText(sourceFile)
3036
+ };
3037
+ }
3038
+ function tryClassifyUseInsider(unwrapped, sourceFile, warnings, leadingComment) {
3039
+ if (!typescript.isCallExpression(unwrapped)) return;
3040
+ const callee = unwrapped.expression;
3041
+ if (!typescript.isIdentifier(callee) || callee.text !== "useInsider") return;
3042
+ const parsed = parseUseInsiderCall(unwrapped, sourceFile, warnings);
3043
+ if (parsed && leadingComment !== void 0) parsed.leadingComment = leadingComment;
3044
+ return parsed;
3045
+ }
3046
+ function classifyArrayElement(element, sourceFile, warnings) {
3047
+ const leadingComment = leadingCommentTextFor(sourceFile, element);
3048
+ const unwrapped = unwrapAwait(element);
3049
+ const useInsiderResult = tryClassifyUseInsider(unwrapped, sourceFile, warnings, leadingComment);
3050
+ if (useInsiderResult !== void 0) return useInsiderResult;
3051
+ if (typescript.isObjectLiteralExpression(unwrapped)) {
3052
+ const parsed = classifyObjectElement(unwrapped, sourceFile, warnings);
3053
+ if (leadingComment !== void 0) parsed.leadingComment = leadingComment;
3054
+ return parsed;
3055
+ }
3056
+ const line = lineOf(sourceFile, element);
3057
+ warnings.push({
3058
+ kind: "unrecognized-block",
3059
+ line,
3060
+ message: "Unrecognized array element; dropping"
3061
+ });
3062
+ const unrecognized = {
3063
+ kind: "unrecognized",
3064
+ line,
3065
+ snippet: element.getText(sourceFile)
3066
+ };
3067
+ if (leadingComment !== void 0) unrecognized.leadingComment = leadingComment;
3068
+ return unrecognized;
3069
+ }
3070
+ function isDefineConfigCall(expression) {
3071
+ return typescript.isCallExpression(expression) && typescript.isIdentifier(expression.expression) && expression.expression.text === "defineConfig";
3072
+ }
3073
+ function findDefaultExportArray(sourceFile) {
3074
+ const exportExpressions = sourceFile.statements.filter(typescript.isExportAssignment).map((statement) => unwrapTypeCasts(statement.expression));
3075
+ const directArray = exportExpressions.find(typescript.isArrayLiteralExpression);
3076
+ if (directArray) return directArray;
3077
+ const defineConfigCall = exportExpressions.find(isDefineConfigCall);
3078
+ if (!defineConfigCall) return null;
3079
+ const [first] = defineConfigCall.arguments;
3080
+ if (!first) return null;
3081
+ const unwrappedFirst = unwrapTypeCasts(first);
3082
+ if (typescript.isArrayLiteralExpression(unwrappedFirst)) return unwrappedFirst;
3083
+ return null;
3084
+ }
3085
+ function checkDefineConfigWrap(sourceFile) {
3086
+ return sourceFile.statements.some((statement) => {
3087
+ if (!typescript.isExportAssignment(statement)) return false;
3088
+ const expression = unwrapTypeCasts(statement.expression);
3089
+ return typescript.isCallExpression(expression) && typescript.isIdentifier(expression.expression) && expression.expression.text === "defineConfig";
3090
+ });
3091
+ }
3092
+ function getModuleSpecifierText(statement) {
3093
+ const { moduleSpecifier } = statement;
3094
+ if (!isStringLiteral(moduleSpecifier)) return null;
3095
+ return moduleSpecifier.text;
3096
+ }
3097
+ function collectNamedImports(importDeclaration) {
3098
+ const namedBindings = importDeclaration.importClause?.namedBindings;
3099
+ if (!namedBindings || !typescript.isNamedImports(namedBindings)) return [];
3100
+ return namedBindings.elements.map((specifier) => specifier.propertyName?.text ?? specifier.name.text);
3101
+ }
3102
+ function hasDefaultBinding(importDeclaration) {
3103
+ return Boolean(importDeclaration.importClause?.name);
3104
+ }
3105
+ var insiderDefaultRewriteTargets = new Set([
3106
+ "useInsider",
3107
+ "silenceRules",
3108
+ "silenceDependencyWarning"
3109
+ ]);
3110
+ function classifyInsiderImport(statement, sourceFile, flags) {
3111
+ collectNamedImports(statement).forEach((name) => {
3112
+ if (name === "useInsider") flags.hasUseInsider = true;
3113
+ if (name === "silenceRules") flags.hasSilenceRules = true;
3114
+ });
3115
+ if (hasDefaultBinding(statement)) {
3116
+ const defaultLocal = statement.importClause?.name?.text ?? "";
3117
+ if (insiderDefaultRewriteTargets.has(defaultLocal)) {
3118
+ if (defaultLocal === "useInsider") flags.hasUseInsider = true;
3119
+ if (defaultLocal === "silenceRules") flags.hasSilenceRules = true;
3120
+ return;
3121
+ }
3122
+ flags.hasUseInsider = true;
3123
+ const line = lineOf(sourceFile, statement);
3124
+ flags.preserved.push({
3125
+ raw: statement.getText(sourceFile),
3126
+ moduleSpecifier: "@useinsider/eslint-config"
3127
+ });
3128
+ flags.warnings.push({
3129
+ kind: "unrecognized-block",
3130
+ line,
3131
+ message: `Unexpected default import '${defaultLocal}' from '@useinsider/eslint-config'; kept literally — review before committing`
3132
+ });
3133
+ }
3134
+ }
3135
+ function inspectImports(sourceFile) {
3136
+ const flags = {
3137
+ hasUseInsider: false,
3138
+ hasSilenceRules: false,
3139
+ preserved: [],
3140
+ warnings: []
3141
+ };
3142
+ sourceFile.statements.forEach((statement) => {
3143
+ if (!typescript.isImportDeclaration(statement)) return;
3144
+ const moduleSpecifier = getModuleSpecifierText(statement);
3145
+ if (moduleSpecifier === null) return;
3146
+ if (moduleSpecifier === "@useinsider/eslint-config") {
3147
+ classifyInsiderImport(statement, sourceFile, flags);
3148
+ return;
3149
+ }
3150
+ if (moduleSpecifier === "eslint/config") return;
3151
+ flags.preserved.push({
3152
+ raw: statement.getText(sourceFile),
3153
+ moduleSpecifier
3154
+ });
3155
+ });
3156
+ return flags;
3157
+ }
3158
+ function collectSilenceRulesCalls(sourceFile) {
3159
+ return sourceFile.statements.filter(typescript.isExpressionStatement).map((statement) => {
3160
+ const { expression } = statement;
3161
+ if (!typescript.isCallExpression(expression) || !typescript.isIdentifier(expression.expression)) return null;
3162
+ if (expression.expression.text !== "silenceRules") return null;
3163
+ const [argument] = expression.arguments;
3164
+ const rules = readStringLiteralEntries(argument, sourceFile);
3165
+ if (!rules) return null;
3166
+ const leadingComment = leadingCommentTextFor(sourceFile, statement);
3167
+ const call = {
3168
+ line: lineOf(sourceFile, statement),
3169
+ rules
3170
+ };
3171
+ if (leadingComment !== void 0) call.leadingComment = leadingComment;
3172
+ return call;
3173
+ }).filter((call) => call !== null);
3174
+ }
3175
+ function parseV1Config(source, filePath) {
3176
+ const sourceFile = typescript.createSourceFile(filePath, source, typescript.ScriptTarget.Latest, true);
3177
+ const warnings = [];
3178
+ const imports = inspectImports(sourceFile);
3179
+ warnings.push(...imports.warnings);
3180
+ const silenceRulesCalls = collectSilenceRulesCalls(sourceFile);
3181
+ const arrayLiteral = findDefaultExportArray(sourceFile);
3182
+ const arrayElements = arrayLiteral ? arrayLiteral.elements.map((element) => classifyArrayElement(element, sourceFile, warnings)).filter((entry) => entry !== null) : [];
3183
+ return {
3184
+ hasUseInsiderImport: imports.hasUseInsider,
3185
+ hasSilenceRulesImport: imports.hasSilenceRules,
3186
+ hasDefineConfigWrap: checkDefineConfigWrap(sourceFile),
3187
+ silenceRulesCalls,
3188
+ arrayElements,
3189
+ preservedImports: imports.preserved,
3190
+ warnings
3191
+ };
3192
+ }
3193
+ //#endregion
3194
+ //#region src/cli/migrate/pruneUnusedImports.ts
3195
+ var INSIDER_MODULE_SPECIFIER = "@useinsider/eslint-config";
3196
+ function readModuleSpecifier(statement) {
3197
+ const { moduleSpecifier } = statement;
3198
+ if (!typescript.isStringLiteralLike(moduleSpecifier)) return null;
3199
+ return moduleSpecifier.text;
3200
+ }
3201
+ function readImportBindings(statement) {
3202
+ const moduleSpecifier = readModuleSpecifier(statement);
3203
+ if (moduleSpecifier === null) return null;
3204
+ const { importClause } = statement;
3205
+ if (!importClause) return {
3206
+ statement,
3207
+ moduleSpecifier,
3208
+ namedBindings: [],
3209
+ isSideEffect: true
3210
+ };
3211
+ const bindings = {
3212
+ statement,
3213
+ moduleSpecifier,
3214
+ namedBindings: [],
3215
+ isSideEffect: false
3216
+ };
3217
+ if (importClause.name) bindings.defaultBinding = importClause.name.text;
3218
+ const { namedBindings } = importClause;
3219
+ if (namedBindings) if (typescript.isNamespaceImport(namedBindings)) bindings.namespaceBinding = namedBindings.name.text;
3220
+ else namedBindings.elements.forEach((element) => {
3221
+ bindings.namedBindings.push({
3222
+ localName: element.name.text,
3223
+ importedName: element.propertyName?.text ?? element.name.text
3224
+ });
3225
+ });
3226
+ return bindings;
3227
+ }
3228
+ function isPropertyKeyPosition(node) {
3229
+ const { parent } = node;
3230
+ if (!parent) return false;
3231
+ if (typescript.isPropertyAssignment(parent) && parent.name === node) return true;
3232
+ if (typescript.isPropertyAccessExpression(parent) && parent.name === node) return true;
3233
+ if (typescript.isQualifiedName(parent) && parent.right === node) return true;
3234
+ return false;
3235
+ }
3236
+ function classifyIdentifier(node, referenced) {
3237
+ const { parent } = node;
3238
+ if (parent && typescript.isShorthandPropertyAssignment(parent) && parent.name === node) {
3239
+ referenced.add(node.text);
3240
+ return;
3241
+ }
3242
+ if (isPropertyKeyPosition(node)) return;
3243
+ referenced.add(node.text);
3244
+ }
3245
+ function collectReferencedIdentifiers(sourceFile) {
3246
+ const referenced = /* @__PURE__ */ new Set();
3247
+ function visit(node) {
3248
+ if (typescript.isImportDeclaration(node)) return;
3249
+ if (typescript.isIdentifier(node)) classifyIdentifier(node, referenced);
3250
+ typescript.forEachChild(node, visit);
3251
+ }
3252
+ sourceFile.statements.forEach((statement) => {
3253
+ if (typescript.isImportDeclaration(statement)) return;
3254
+ visit(statement);
3255
+ });
3256
+ return referenced;
3257
+ }
3258
+ function quoteModuleSpecifier(statement, sourceFile) {
3259
+ return statement.moduleSpecifier.getText(sourceFile);
3260
+ }
3261
+ function renderNamedSpecifier(binding) {
3262
+ if (binding.localName === binding.importedName) return binding.localName;
3263
+ return `${binding.importedName} as ${binding.localName}`;
3264
+ }
3265
+ function rebuildImportStatement(bindings, keptNamed, sourceFile) {
3266
+ const clauseParts = [];
3267
+ if (bindings.defaultBinding) clauseParts.push(bindings.defaultBinding);
3268
+ if (bindings.namespaceBinding) clauseParts.push(`* as ${bindings.namespaceBinding}`);
3269
+ else if (keptNamed.length > 0) {
3270
+ const list = keptNamed.map(renderNamedSpecifier).join(", ");
3271
+ clauseParts.push(`{ ${list} }`);
3272
+ }
3273
+ const moduleSpecifier = quoteModuleSpecifier(bindings.statement, sourceFile);
3274
+ if (clauseParts.length === 0) return `import ${moduleSpecifier};`;
3275
+ return `import ${clauseParts.join(", ")} from ${moduleSpecifier};`;
3276
+ }
3277
+ function summarizeUsage(bindings, referenced) {
3278
+ const defaultStays = bindings.defaultBinding ? referenced.has(bindings.defaultBinding) : false;
3279
+ const namespaceStays = bindings.namespaceBinding ? referenced.has(bindings.namespaceBinding) : false;
3280
+ const keptNamed = bindings.namedBindings.filter((named) => referenced.has(named.localName));
3281
+ return {
3282
+ hasDefault: Boolean(bindings.defaultBinding),
3283
+ hasNamespace: Boolean(bindings.namespaceBinding),
3284
+ hasNamed: bindings.namedBindings.length > 0,
3285
+ defaultStays,
3286
+ namespaceStays,
3287
+ keptNamed
3288
+ };
3289
+ }
3290
+ function isFullyUnchanged(bindings, usage) {
3291
+ if (usage.hasDefault && !usage.defaultStays) return false;
3292
+ if (usage.hasNamespace && !usage.namespaceStays) return false;
3293
+ if (usage.hasNamed && usage.keptNamed.length !== bindings.namedBindings.length) return false;
3294
+ return true;
3295
+ }
3296
+ function hasAnyBinding(usage) {
3297
+ return usage.hasDefault || usage.hasNamespace || usage.hasNamed;
3298
+ }
3299
+ function hasAnySurvivingBinding(usage) {
3300
+ const namedStays = usage.hasNamed && usage.keptNamed.length > 0;
3301
+ return usage.defaultStays || usage.namespaceStays || namedStays;
3302
+ }
3303
+ function buildRebuiltBindings(bindings, usage) {
3304
+ return {
3305
+ ...bindings,
3306
+ defaultBinding: usage.defaultStays ? bindings.defaultBinding : void 0,
3307
+ namespaceBinding: usage.namespaceStays ? bindings.namespaceBinding : void 0,
3308
+ namedBindings: usage.keptNamed
3309
+ };
3310
+ }
3311
+ function decideRewrite(bindings, referenced, sourceFile) {
3312
+ if (bindings.moduleSpecifier === INSIDER_MODULE_SPECIFIER || bindings.isSideEffect) return { keep: true };
3313
+ const usage = summarizeUsage(bindings, referenced);
3314
+ if (!hasAnyBinding(usage)) return { keep: true };
3315
+ if (!hasAnySurvivingBinding(usage)) return { keep: false };
3316
+ if (isFullyUnchanged(bindings, usage)) return { keep: true };
3317
+ return {
3318
+ keep: true,
3319
+ replacement: rebuildImportStatement(buildRebuiltBindings(bindings, usage), usage.keptNamed, sourceFile)
3320
+ };
3321
+ }
3322
+ function lineRangeForStatement(statement, sourceFile) {
3323
+ return {
3324
+ start: sourceFile.getLineAndCharacterOfPosition(statement.getStart(sourceFile)).line,
3325
+ end: sourceFile.getLineAndCharacterOfPosition(statement.getEnd()).line
3326
+ };
3327
+ }
3328
+ function applyReplacements(source, replacements) {
3329
+ if (replacements.length === 0) return source;
3330
+ const lines = source.split("\n");
3331
+ replacements.slice().sort((left, right) => right.startLine - left.startLine).forEach((replacement) => {
3332
+ const removeCount = replacement.endLine - replacement.startLine + 1;
3333
+ if (replacement.text === null) lines.splice(replacement.startLine, removeCount);
3334
+ else lines.splice(replacement.startLine, removeCount, replacement.text);
3335
+ });
3336
+ return lines.join("\n");
3337
+ }
3338
+ function pruneUnusedImports(source) {
3339
+ const sourceFile = typescript.createSourceFile("migrated.mjs", source, typescript.ScriptTarget.Latest, true);
3340
+ const importStatements = sourceFile.statements.filter(typescript.isImportDeclaration);
3341
+ if (importStatements.length === 0) return source;
3342
+ const referenced = collectReferencedIdentifiers(sourceFile);
3343
+ const replacements = [];
3344
+ importStatements.forEach((statement) => {
3345
+ const bindings = readImportBindings(statement);
3346
+ if (!bindings) return;
3347
+ const decision = decideRewrite(bindings, referenced, sourceFile);
3348
+ if (decision.keep && decision.replacement === void 0) return;
3349
+ const range = lineRangeForStatement(statement, sourceFile);
3350
+ if (!decision.keep) {
3351
+ replacements.push({
3352
+ startLine: range.start,
3353
+ endLine: range.end,
3354
+ text: null
3355
+ });
3356
+ return;
3357
+ }
3358
+ if (decision.replacement !== void 0) replacements.push({
3359
+ startLine: range.start,
3360
+ endLine: range.end,
3361
+ text: decision.replacement
3362
+ });
3363
+ });
3364
+ return applyReplacements(source, replacements);
3365
+ }
3366
+ /* v8 ignore stop */
3367
+ //#endregion
3368
+ //#region src/cli/migrate/render.ts
3369
+ var indent = " ";
3370
+ var MAX_LINE_LENGTH = 120;
3371
+ function quote(value) {
3372
+ return `'${value.replace(/'/g, "\\'")}'`;
3373
+ }
3374
+ function anyEntryHasComment(entries) {
3375
+ return entries.some((entry) => entry.leadingComment !== void 0);
3376
+ }
3377
+ function indentCommentBlock(raw, baseIndent) {
3378
+ return raw.split("\n").map((line) => `${baseIndent}${line}`).join("\n");
3379
+ }
3380
+ function formatStringArrayInline(entries) {
3381
+ return `[${entries.map((entry) => quote(entry.value)).join(", ")}]`;
3382
+ }
3383
+ function formatStringArrayMultiline(entries, baseIndent) {
3384
+ const childIndent = `${baseIndent}${indent}`;
3385
+ const lines = ["["];
3386
+ entries.forEach((entry) => {
3387
+ if (entry.leadingComment !== void 0) lines.push(indentCommentBlock(entry.leadingComment, childIndent));
3388
+ lines.push(`${childIndent}${quote(entry.value)},`);
3389
+ });
3390
+ lines.push(`${baseIndent}]`);
3391
+ return lines.join("\n");
3392
+ }
3393
+ function renderStringArrayField(label, entries, baseIndent) {
3394
+ if (!anyEntryHasComment(entries)) {
3395
+ const inline = `${baseIndent}${label}: ${formatStringArrayInline(entries)},`;
3396
+ if (inline.length <= MAX_LINE_LENGTH) return inline;
3397
+ }
3398
+ return `${baseIndent}${label}: ${formatStringArrayMultiline(entries, baseIndent)},`;
3399
+ }
3400
+ function formatGlobalValue(value) {
3401
+ if (typeof value === "string") return quote(value);
3402
+ return String(value);
3403
+ }
3404
+ function tokensFromRecord$1(globals) {
3405
+ return Object.entries(globals).map(([key, value]) => ({
3406
+ kind: "named",
3407
+ key,
3408
+ value
3409
+ }));
3410
+ }
3411
+ function formatGlobalTokenInline(token) {
3412
+ if (token.kind === "spread") return `...${token.raw}`;
3413
+ return `${token.key}: ${formatGlobalValue(token.value)}`;
3414
+ }
3415
+ function formatGlobalTokenLine(token, childIndent) {
3416
+ if (token.kind === "spread") return `${childIndent}...${token.raw},`;
3417
+ return `${childIndent}${token.key}: ${formatGlobalValue(token.value)},`;
3418
+ }
3419
+ function formatGlobalsTokensInline(tokens) {
3420
+ return `{ ${tokens.map(formatGlobalTokenInline).join(", ")} }`;
3421
+ }
3422
+ function formatGlobalsTokensMultiline(tokens, baseIndent) {
3423
+ const childIndent = `${baseIndent}${indent}`;
3424
+ return [
3425
+ "{",
3426
+ ...tokens.map((token) => formatGlobalTokenLine(token, childIndent)),
3427
+ `${baseIndent}}`
3428
+ ].join("\n");
3429
+ }
3430
+ function renderGlobalsField(tokens, baseIndent) {
3431
+ const inline = `${baseIndent}globals: ${formatGlobalsTokensInline(tokens)},`;
3432
+ if (inline.length <= MAX_LINE_LENGTH) return inline;
3433
+ return `${baseIndent}globals: ${formatGlobalsTokensMultiline(tokens, baseIndent)},`;
3434
+ }
3435
+ function resolveEntryGlobalsTokens(entry) {
3436
+ if (entry.globalsTokens && entry.globalsTokens.length > 0) return entry.globalsTokens;
3437
+ if (entry.globals && Object.keys(entry.globals).length > 0) return tokensFromRecord$1(entry.globals);
3438
+ }
3439
+ function pushFieldComment(lines, comment, fieldIndent) {
3440
+ if (comment === void 0) return;
3441
+ lines.push(indentCommentBlock(comment, fieldIndent));
3442
+ }
3443
+ function pushArrayField(lines, label, entries, fieldComment, fieldIndent) {
3444
+ if (!entries || entries.length === 0) return;
3445
+ pushFieldComment(lines, fieldComment, fieldIndent);
3446
+ lines.push(renderStringArrayField(label, entries, fieldIndent));
3447
+ }
3448
+ function formatEntry(entry, baseIndent) {
3449
+ const fieldIndent = `${baseIndent}${indent}`;
3450
+ const lines = [`${baseIndent}{`];
3451
+ pushFieldComment(lines, entry.fieldComments?.files, fieldIndent);
3452
+ lines.push(renderStringArrayField("files", entry.files, fieldIndent));
3453
+ pushArrayField(lines, "tsconfigPaths", entry.tsconfigPaths, entry.fieldComments?.tsconfigPaths, fieldIndent);
3454
+ pushArrayField(lines, "globalComponents", entry.globalComponents, entry.fieldComments?.globalComponents, fieldIndent);
3455
+ pushArrayField(lines, "ignores", entry.ignores, entry.fieldComments?.ignores, fieldIndent);
3456
+ const tokens = resolveEntryGlobalsTokens(entry);
3457
+ if (tokens) {
3458
+ pushFieldComment(lines, entry.fieldComments?.globals, fieldIndent);
3459
+ lines.push(renderGlobalsField(tokens, fieldIndent));
3460
+ }
3461
+ lines.push(`${baseIndent}},`);
3462
+ return lines.join("\n");
3463
+ }
3464
+ function formatScope(scope, entries, baseIndent) {
3465
+ const childIndent = `${baseIndent}${indent}`;
3466
+ const renderedEntries = [];
3467
+ entries.forEach((entry) => {
3468
+ if (entry.leadingComment !== void 0) renderedEntries.push(indentCommentBlock(entry.leadingComment, childIndent));
3469
+ renderedEntries.push(formatEntry(entry, childIndent));
3470
+ });
3471
+ return [
3472
+ `${baseIndent}${scope}: [`,
3473
+ ...renderedEntries,
3474
+ `${baseIndent}],`
3475
+ ].join("\n");
3476
+ }
3477
+ function renderInsiderImport(plan) {
3478
+ return `import { ${(plan.needsSilenceRulesImport ? ["silenceRules", "useInsider"] : ["useInsider"]).slice().sort((left, right) => left.localeCompare(right)).join(", ")} } from '@useinsider/eslint-config';`;
3479
+ }
3480
+ function renderPreservedImports(preserved) {
3481
+ return preserved.map((item) => item.raw);
3482
+ }
3483
+ function renderImports(plan) {
3484
+ return [...renderPreservedImports(plan.preservedImports ?? []), renderInsiderImport(plan)].join("\n");
3485
+ }
3486
+ function renderSilenceRulesCall(rules, leadingComment) {
3487
+ const hasComment = anyEntryHasComment(rules);
3488
+ const prefix = leadingComment === void 0 ? "" : `${leadingComment}\n`;
3489
+ if (!hasComment) {
3490
+ const inline = `${prefix}silenceRules(${formatStringArrayInline(rules)});`;
3491
+ if (inline.length - prefix.length <= MAX_LINE_LENGTH) return inline;
3492
+ }
3493
+ const lines = ["silenceRules(["];
3494
+ rules.forEach((rule) => {
3495
+ if (rule.leadingComment !== void 0) lines.push(indentCommentBlock(rule.leadingComment, indent));
3496
+ lines.push(`${indent}${quote(rule.value)},`);
3497
+ });
3498
+ lines.push("]);");
3499
+ return `${prefix}${lines.join("\n")}`;
3500
+ }
3501
+ function renderSilenceRulesCalls(plan) {
3502
+ if (plan.silenceRulesCalls.length === 0) return "";
3503
+ return plan.silenceRulesCalls.map((call) => renderSilenceRulesCall(call.rules, call.leadingComment)).join("\n\n");
3504
+ }
3505
+ function hasAnyContent(plan) {
3506
+ const { config } = plan;
3507
+ return config.scopes.size > 0 || config.ignores.length > 0 || config.strictGlobs.length > 0 || config.strictWholeFile || config.spellChecker.ignoredPaths.length > 0 || config.configFiles.length > 0;
3508
+ }
3509
+ function renderStrict(plan) {
3510
+ if (plan.config.strictWholeFile) return `${indent}strict: true,`;
3511
+ if (plan.config.strictGlobs.length > 0) return renderStringArrayField("strict", plan.config.strictGlobs, indent);
3512
+ return null;
3513
+ }
3514
+ function renderSpellChecker(plan) {
3515
+ if (plan.config.spellChecker.ignoredPaths.length === 0) return null;
3516
+ const innerIndent = `${indent}${indent}`;
3517
+ return [
3518
+ `${indent}spellChecker: {`,
3519
+ renderStringArrayField("ignoredPaths", plan.config.spellChecker.ignoredPaths, innerIndent),
3520
+ `${indent}},`
3521
+ ].join("\n");
3522
+ }
3523
+ function renderScopes(plan) {
3524
+ return [...plan.config.scopes.entries()].map(([scope, entries]) => formatScope(scope, entries, indent));
3525
+ }
3526
+ function renderConfigFiles(plan) {
3527
+ if (plan.config.configFiles.length === 0) return null;
3528
+ return renderStringArrayField("configFiles", plan.config.configFiles, indent);
3529
+ }
3530
+ function renderConfigBody(plan) {
3531
+ const lines = [];
3532
+ if (plan.config.ignores.length > 0) lines.push(renderStringArrayField("ignores", plan.config.ignores, indent));
3533
+ lines.push(...renderScopes(plan));
3534
+ const configFilesLine = renderConfigFiles(plan);
3535
+ if (configFilesLine) lines.push(configFilesLine);
3536
+ const strictLine = renderStrict(plan);
3537
+ if (strictLine) lines.push(strictLine);
3538
+ const spellCheckerSection = renderSpellChecker(plan);
3539
+ if (spellCheckerSection) lines.push(spellCheckerSection);
3540
+ return lines.join("\n");
3541
+ }
3542
+ function renderV2(plan) {
3543
+ const parts = [renderImports(plan)];
3544
+ const silenceRulesSection = renderSilenceRulesCalls(plan);
3545
+ if (silenceRulesSection) {
3546
+ parts.push("");
3547
+ parts.push(silenceRulesSection);
3548
+ }
3549
+ parts.push("");
3550
+ if (plan.useInsiderLeadingComment !== void 0) parts.push(plan.useInsiderLeadingComment);
3551
+ if (!hasAnyContent(plan)) {
3552
+ parts.push("export default useInsider({});");
3553
+ parts.push("");
3554
+ return pruneUnusedImports(parts.join("\n"));
3555
+ }
3556
+ parts.push("export default useInsider({");
3557
+ parts.push(renderConfigBody(plan));
3558
+ parts.push("});");
3559
+ parts.push("");
3560
+ return pruneUnusedImports(parts.join("\n"));
3561
+ }
3562
+ //#endregion
3563
+ //#region src/cli/migrate/transform.ts
3564
+ function appendUniqueEntry(target, incoming) {
3565
+ if (hasValue(target, incoming.value)) return;
3566
+ target.push(cloneEntry(incoming));
3567
+ }
3568
+ var presetToScope = {
3569
+ javascript: "javascript",
3570
+ "javascript-dom": "javascriptDom",
3571
+ "javascript-node": "javascriptNode",
3572
+ typescript: "typescript",
3573
+ "typescript-dom": "typescriptDom",
3574
+ "typescript-node": "typescriptNode",
3575
+ vue2: "vue2",
3576
+ vue3: "vue3",
3577
+ "vue2-typescript": "vue2Typescript",
3578
+ "vue3-typescript": "vue3Typescript",
3579
+ jest: "jest",
3580
+ vitest: "vitest",
3581
+ "jsdoc-based-ts": "jsdocBasedTs"
3582
+ };
3583
+ function isTypescriptContext(call) {
3584
+ if (call.parserIsTypescript) return true;
3585
+ return Boolean(call.parserProject && call.parserProject.length > 0);
3586
+ }
3587
+ function resolveAliasPreset(preset, call) {
3588
+ if (preset === "dom") return isTypescriptContext(call) ? "typescript-dom" : "javascript-dom";
3589
+ if (preset === "node") return isTypescriptContext(call) ? "typescript-node" : "javascript-node";
3590
+ return preset;
3591
+ }
3592
+ function promoteScopeForParser(scope, call) {
3593
+ if (!call.parserIsTypescript) return scope;
3594
+ if (scope === "javascript") return "typescript";
3595
+ if (scope === "javascriptDom") return "typescriptDom";
3596
+ if (scope === "javascriptNode") return "typescriptNode";
3597
+ if (scope === "vue2") return "vue2Typescript";
3598
+ if (scope === "vue3") return "vue3Typescript";
3599
+ return scope;
3600
+ }
3601
+ var tsScopes = new Set([
3602
+ "typescript",
3603
+ "typescriptDom",
3604
+ "typescriptNode",
3605
+ "vue2Typescript",
3606
+ "vue3Typescript",
3607
+ "jsdocBasedTs"
3608
+ ]);
3609
+ var vueScopes = new Set([
3610
+ "vue2",
3611
+ "vue3",
3612
+ "vue2Typescript",
3613
+ "vue3Typescript"
3614
+ ]);
3615
+ function freshConfig() {
3616
+ return {
3617
+ ignores: [],
3618
+ scopes: /* @__PURE__ */ new Map(),
3619
+ strictGlobs: [],
3620
+ strictWholeFile: false,
3621
+ spellChecker: { ignoredPaths: [] },
3622
+ configFiles: []
3623
+ };
3624
+ }
3625
+ function appendScope(config, scope, entry) {
3626
+ const existing = config.scopes.get(scope);
3627
+ if (existing) existing.push(entry);
3628
+ else config.scopes.set(scope, [entry]);
3629
+ }
3630
+ function applyTypescriptFields(entry, scope, call, warnings) {
3631
+ if (!tsScopes.has(scope)) return;
3632
+ if (call.parserProject && call.parserProject.length > 0) {
3633
+ entry.tsconfigPaths = cloneEntries(call.parserProject);
3634
+ return;
3635
+ }
3636
+ if (call.parserProjectService) warnings.push({
3637
+ kind: "project-service-dropped",
3638
+ line: call.line,
3639
+ message: "'projectService: true' is not supported in v2 — dropped"
3640
+ });
3641
+ }
3642
+ function applyVueFields(entry, scope, call) {
3643
+ if (vueScopes.has(scope) && call.globalComponents && call.globalComponents.length > 0) entry.globalComponents = cloneEntries(call.globalComponents);
3644
+ }
3645
+ function mapV1FieldComments(call, scope) {
3646
+ const incoming = call.fieldComments;
3647
+ if (!incoming) return;
3648
+ const result = {};
3649
+ if (incoming.files !== void 0) result.files = incoming.files;
3650
+ if (incoming.ignores !== void 0) result.ignores = incoming.ignores;
3651
+ if (incoming.globals !== void 0) result.globals = incoming.globals;
3652
+ if (incoming.parserProject !== void 0 && tsScopes.has(scope)) result.tsconfigPaths = incoming.parserProject;
3653
+ if (incoming.globalComponents !== void 0 && vueScopes.has(scope)) result.globalComponents = incoming.globalComponents;
3654
+ return Object.keys(result).length > 0 ? result : void 0;
3655
+ }
3656
+ function buildEntry(call, scope, warnings) {
3657
+ if (!call.files || call.files.length === 0) {
3658
+ warnings.push({
3659
+ kind: "unrecognized-block",
3660
+ line: call.line,
3661
+ message: `useInsider preset '${scope}' has no files glob; skipping`
3662
+ });
3663
+ return null;
3664
+ }
3665
+ const entry = { files: cloneEntries(call.files) };
3666
+ if (call.ignores && call.ignores.length > 0) entry.ignores = cloneEntries(call.ignores);
3667
+ applyTypescriptFields(entry, scope, call, warnings);
3668
+ applyVueFields(entry, scope, call);
3669
+ if (call.globalsTokens && call.globalsTokens.length > 0) entry.globalsTokens = call.globalsTokens.map((token) => ({ ...token }));
3670
+ if (call.globals && Object.keys(call.globals).length > 0) entry.globals = { ...call.globals };
3671
+ const fieldComments = mapV1FieldComments(call, scope);
3672
+ if (fieldComments) entry.fieldComments = fieldComments;
3673
+ return entry;
3674
+ }
3675
+ function handleStrictPreset(call, config) {
3676
+ if (!call.files || call.files.length === 0) {
3677
+ config.strictWholeFile = true;
3678
+ return;
3679
+ }
3680
+ call.files.forEach((file) => appendUniqueEntry(config.strictGlobs, file));
3681
+ }
3682
+ function handlePreset(preset, call, config, warnings) {
3683
+ if (preset === "strict") {
3684
+ handleStrictPreset(call, config);
3685
+ return null;
3686
+ }
3687
+ const baseScope = presetToScope[resolveAliasPreset(preset, call)];
3688
+ if (!baseScope) {
3689
+ warnings.push({
3690
+ kind: "unknown-preset",
3691
+ line: call.line,
3692
+ message: `Preset '${preset}' has no v2 mapping — dropped`
3693
+ });
3694
+ return null;
3695
+ }
3696
+ const scope = promoteScopeForParser(baseScope, call);
3697
+ const entry = buildEntry(call, scope, warnings);
3698
+ if (entry) {
3699
+ appendScope(config, scope, entry);
3700
+ return entry;
3701
+ }
3702
+ return null;
3703
+ }
3704
+ function emptyStats() {
3705
+ return {
3706
+ droppedRules: 0,
3707
+ droppedRuleBlocks: 0,
3708
+ droppedPlugins: /* @__PURE__ */ new Set(),
3709
+ droppedPluginEntries: 0
3710
+ };
3711
+ }
3712
+ function captureConfigPresetFiles(call, config) {
3713
+ if (!call.presets.includes("config") || !call.files) return;
3714
+ call.files.forEach((file) => appendUniqueEntry(config.configFiles, file));
3715
+ }
3716
+ function processUseInsiderCall(call, config, warnings) {
3717
+ captureConfigPresetFiles(call, config);
3718
+ const filteredPresets = call.presets.filter((preset) => preset !== "config");
3719
+ const stats = emptyStats();
3720
+ stats.droppedRules = call.extraRuleCount > 0 ? call.extraRuleCount : 0;
3721
+ stats.droppedRuleBlocks = call.extraRuleCount > 0 ? 1 : 0;
3722
+ if (call.customPluginNames && call.customPluginNames.length > 0) {
3723
+ call.customPluginNames.forEach((name) => stats.droppedPlugins.add(name));
3724
+ stats.droppedPluginEntries = 1;
3725
+ }
3726
+ let firstEmitted = null;
3727
+ filteredPresets.forEach((preset) => {
3728
+ const emitted = handlePreset(preset, call, config, warnings);
3729
+ if (emitted && !firstEmitted) firstEmitted = emitted;
3730
+ });
3731
+ if (firstEmitted && call.leadingComment !== void 0) firstEmitted.leadingComment = call.leadingComment;
3732
+ return stats;
3733
+ }
3734
+ function applyIgnoresBlock(element, config) {
3735
+ if (element.leadingComment !== void 0 && element.ignores.length > 0 && config.ignores.length === 0 && element.ignores[0].leadingComment === void 0) {
3736
+ const first = cloneEntry(element.ignores[0]);
3737
+ first.leadingComment = element.leadingComment;
3738
+ config.ignores.push(first);
3739
+ element.ignores.slice(1).forEach((ignore) => appendUniqueEntry(config.ignores, ignore));
3740
+ return;
3741
+ }
3742
+ element.ignores.forEach((ignore) => appendUniqueEntry(config.ignores, ignore));
3743
+ }
3744
+ function applySpellCheckerOff(element, config) {
3745
+ element.files.forEach((file) => appendUniqueEntry(config.spellChecker.ignoredPaths, file));
3746
+ }
3747
+ function filesOverlap(left, right) {
3748
+ const leftValues = entryValues(left);
3749
+ const rightValues = entryValues(right);
3750
+ if (leftValues.length === rightValues.length && leftValues.every((value, index) => value === rightValues[index])) return true;
3751
+ return leftValues.some((value) => rightValues.includes(value));
3752
+ }
3753
+ function findEntryForStandalone(config, files) {
3754
+ return [...config.scopes.values()].flat().find((entry) => filesOverlap(entry.files, files)) ?? null;
3755
+ }
3756
+ function mergeStandaloneTokensIntoEntry(entry, incoming) {
3757
+ const existing = entry.globalsTokens ?? [];
3758
+ const namedSeen = /* @__PURE__ */ new Map();
3759
+ existing.forEach((token, index) => {
3760
+ if (token.kind === "named") namedSeen.set(token.key, index);
3761
+ });
3762
+ const merged = existing.slice();
3763
+ incoming.forEach((token) => {
3764
+ if (token.kind === "spread") {
3765
+ merged.push({ ...token });
3766
+ return;
3767
+ }
3768
+ const seenIndex = namedSeen.get(token.key);
3769
+ if (seenIndex === void 0) {
3770
+ namedSeen.set(token.key, merged.length);
3771
+ merged.push({ ...token });
3772
+ return;
3773
+ }
3774
+ merged[seenIndex] = { ...token };
3775
+ });
3776
+ entry.globalsTokens = merged;
3777
+ const namedRecord = {};
3778
+ merged.forEach((token) => {
3779
+ if (token.kind === "named") namedRecord[token.key] = token.value;
3780
+ });
3781
+ entry.globals = Object.keys(namedRecord).length > 0 ? namedRecord : void 0;
3782
+ }
3783
+ function inferScopeForStandalone(files) {
3784
+ const values = entryValues(files);
3785
+ if (values.some((file) => file.includes(".vue"))) return "vue3";
3786
+ if (values.some((file) => file.includes(".ts") || file.includes(".tsx"))) return "typescript";
3787
+ return "javascript";
3788
+ }
3789
+ function applyStandaloneGlobals(element, config) {
3790
+ const existing = findEntryForStandalone(config, element.files);
3791
+ if (existing) {
3792
+ mergeStandaloneTokensIntoEntry(existing, element.globalsTokens);
3793
+ if (existing.leadingComment === void 0 && element.leadingComment !== void 0) existing.leadingComment = element.leadingComment;
3794
+ return;
3795
+ }
3796
+ const scope = inferScopeForStandalone(element.files);
3797
+ const entry = { files: cloneEntries(element.files) };
3798
+ mergeStandaloneTokensIntoEntry(entry, element.globalsTokens);
3799
+ if (element.leadingComment !== void 0) entry.leadingComment = element.leadingComment;
3800
+ appendScope(config, scope, entry);
3801
+ }
3802
+ function processElement(element, config, warnings) {
3803
+ if (element.kind === "ignoresBlock") {
3804
+ applyIgnoresBlock(element, config);
3805
+ return emptyStats();
3806
+ }
3807
+ if (element.kind === "spellCheckerOff") {
3808
+ applySpellCheckerOff(element, config);
3809
+ return emptyStats();
3810
+ }
3811
+ if (element.kind === "standaloneGlobals") {
3812
+ applyStandaloneGlobals(element, config);
3813
+ return emptyStats();
3814
+ }
3815
+ if (element.kind === "useInsiderCall") return processUseInsiderCall(element, config, warnings);
3816
+ return emptyStats();
3817
+ }
3818
+ function formatDroppedRulesMessage(count, blocks) {
3819
+ return `Dropped ${count} custom ${count === 1 ? "rule override" : "rule overrides"} across ${blocks} ${blocks === 1 ? "block" : "blocks"}`;
3820
+ }
3821
+ function formatDroppedPluginsMessage(pluginNames, entries) {
3822
+ return `Dropped custom plugins on ${entries} entries: ${pluginNames.slice().sort((left, right) => left.localeCompare(right)).join(", ")}`;
3823
+ }
3824
+ function mergeStats(left, right) {
3825
+ const merged = emptyStats();
3826
+ merged.droppedRules = left.droppedRules + right.droppedRules;
3827
+ merged.droppedRuleBlocks = left.droppedRuleBlocks + right.droppedRuleBlocks;
3828
+ merged.droppedPluginEntries = left.droppedPluginEntries + right.droppedPluginEntries;
3829
+ left.droppedPlugins.forEach((name) => merged.droppedPlugins.add(name));
3830
+ right.droppedPlugins.forEach((name) => merged.droppedPlugins.add(name));
3831
+ return merged;
3832
+ }
3833
+ function tokensFromRecord(globals) {
3834
+ return Object.entries(globals).map(([key, value]) => ({
3835
+ kind: "named",
3836
+ key,
3837
+ value
3838
+ }));
3839
+ }
3840
+ function resolveBaseTokens(entry) {
3841
+ if (entry.globalsTokens && entry.globalsTokens.length > 0) return entry.globalsTokens;
3842
+ if (entry.globals && Object.keys(entry.globals).length > 0) return tokensFromRecord(entry.globals);
3843
+ }
3844
+ function applyGlobalsFolding(config) {
3845
+ let anySyntheticEmitted = false;
3846
+ config.scopes.forEach((entries) => {
3847
+ entries.forEach((entry) => {
3848
+ const baseTokens = resolveBaseTokens(entry);
3849
+ if (!baseTokens) return;
3850
+ const { tokens, addedSpreadEnvs } = foldGlobalsTokens(baseTokens);
3851
+ if (addedSpreadEnvs.length > 0) anySyntheticEmitted = true;
3852
+ entry.globalsTokens = tokens;
3853
+ const namedRecord = {};
3854
+ tokens.forEach((token) => {
3855
+ if (token.kind === "named") namedRecord[token.key] = token.value;
3856
+ });
3857
+ entry.globals = Object.keys(namedRecord).length > 0 ? namedRecord : void 0;
3858
+ });
3859
+ });
3860
+ return anySyntheticEmitted;
3861
+ }
3862
+ function ensureGlobalsImport(preserved) {
3863
+ if (preserved.some((item) => item.moduleSpecifier === "globals")) return preserved;
3864
+ return [{
3865
+ raw: "import globals from 'globals';",
3866
+ moduleSpecifier: "globals"
3867
+ }, ...preserved];
3868
+ }
3869
+ function countRescuedSiblingCalls(parseResult) {
3870
+ return parseResult.arrayElements.reduce((accumulator, element) => {
3871
+ if (element.kind === "useInsiderCall" && element.rescuedSiblingLanguageOptions === true) return accumulator + 1;
3872
+ return accumulator;
3873
+ }, 0);
3874
+ }
3875
+ function formatRescuedSiblingMessage(count) {
3876
+ return `Rescued misplaced \`languageOptions\` from ${count} \`useInsider()\` ${count === 1 ? "call" : "calls"} — these were source-level mistakes that v1 ignored silently`;
3877
+ }
3878
+ function transformToV2(parseResult) {
3879
+ const config = freshConfig();
3880
+ const warnings = [...parseResult.warnings];
3881
+ const stats = parseResult.arrayElements.reduce((accumulator, element) => mergeStats(accumulator, processElement(element, config, warnings)), emptyStats());
3882
+ if (stats.droppedRules > 0) warnings.push({
3883
+ kind: "dropped-rules",
3884
+ message: formatDroppedRulesMessage(stats.droppedRules, stats.droppedRuleBlocks)
3885
+ });
3886
+ if (stats.droppedPluginEntries > 0 && stats.droppedPlugins.size > 0) warnings.push({
3887
+ kind: "dropped-plugins",
3888
+ message: formatDroppedPluginsMessage([...stats.droppedPlugins], stats.droppedPluginEntries)
3889
+ });
3890
+ const rescuedSiblingCount = countRescuedSiblingCalls(parseResult);
3891
+ if (rescuedSiblingCount > 0) warnings.push({
3892
+ kind: "rescued-sibling-language-options",
3893
+ message: formatRescuedSiblingMessage(rescuedSiblingCount)
3894
+ });
3895
+ const preservedImports = applyGlobalsFolding(config) ? ensureGlobalsImport(parseResult.preservedImports) : parseResult.preservedImports;
3896
+ return {
3897
+ config,
3898
+ silenceRulesCalls: parseResult.silenceRulesCalls,
3899
+ needsSilenceRulesImport: parseResult.silenceRulesCalls.length > 0,
3900
+ preservedImports,
3901
+ warnings,
3902
+ droppedRuleCount: stats.droppedRules,
3903
+ droppedRuleBlockCount: stats.droppedRuleBlocks
3904
+ };
3905
+ }
3906
+ //#endregion
3907
+ //#region src/cli/migrate/warnings.ts
3908
+ function formatWarnings(warnings) {
3909
+ if (warnings.length === 0) return "";
3910
+ return warnings.map((warning) => {
3911
+ return ` - ${warning.line === void 0 ? "" : `line ${warning.line}: `}${warning.message}`;
3912
+ }).join("\n");
3913
+ }
3914
+ //#endregion
3915
+ //#region src/cli/migrate/writer.ts
3916
+ function writeMigration(targetPath, newSource) {
3917
+ (0, node_fs.writeFileSync)(targetPath, newSource, "utf8");
3918
+ return { targetPath };
3919
+ }
3920
+ function writeMigrationLegacy(sourcePath, writePath, newSource) {
3921
+ (0, node_fs.writeFileSync)(writePath, newSource, "utf8");
3922
+ return {
3923
+ targetPath: writePath,
3924
+ deletedSourceCandidate: (0, node_path.basename)(sourcePath) === (0, node_path.basename)(writePath) ? void 0 : sourcePath
3925
+ };
3926
+ }
3927
+ //#endregion
3928
+ //#region src/cli/migrate/index.ts
3929
+ var flatConfigCandidates = [
3930
+ "eslint.config.mjs",
3931
+ "eslint.config.js",
3932
+ "eslint.config.cjs"
3933
+ ];
3934
+ var eslintrcCandidates = [
3935
+ ".eslintrc.cjs",
3936
+ ".eslintrc.js",
3937
+ ".eslintrc.mjs",
3938
+ ".eslintrc.json"
3939
+ ];
3940
+ var unsupportedEslintrcExtensions = [
3941
+ ".json",
3942
+ ".yml",
3943
+ ".yaml"
3944
+ ];
3945
+ function flatLooksLikeV1(filePath) {
3946
+ try {
3947
+ const source = (0, node_fs.readFileSync)(filePath, "utf8");
3948
+ return source.includes("useInsider") && /\b(import|require)\b/.test(source);
3949
+ } catch {
3950
+ return false;
3951
+ }
3952
+ }
3953
+ function resolveTargetPath(input) {
3954
+ if (input.target) {
3955
+ const absolute = (0, node_path.isAbsolute)(input.target) ? input.target : (0, node_path.resolve)(input.cwd, input.target);
3956
+ if ((0, node_fs.existsSync)(absolute)) return absolute;
3957
+ return null;
3958
+ }
3959
+ const flatFound = flatConfigCandidates.map((name) => (0, node_path.join)(input.cwd, name)).find((candidate) => (0, node_fs.existsSync)(candidate));
3960
+ const legacyFound = eslintrcCandidates.map((name) => (0, node_path.join)(input.cwd, name)).find((candidate) => (0, node_fs.existsSync)(candidate));
3961
+ if (flatFound && legacyFound) return flatLooksLikeV1(flatFound) ? flatFound : legacyFound;
3962
+ return flatFound ?? legacyFound ?? null;
3963
+ }
3964
+ function detectFormatByName(filePath) {
3965
+ const name = (0, node_path.basename)(filePath);
3966
+ if (name.startsWith("eslint.config.")) return "flat";
3967
+ if (!name.startsWith(".eslintrc")) return null;
3968
+ if (unsupportedEslintrcExtensions.find((extension) => name.endsWith(extension))) return "eslintrc-unsupported";
3969
+ return "eslintrc";
3970
+ }
3971
+ function detectFormatByContent(source) {
3972
+ if (source.includes("export default") && source.includes("useInsider")) return "flat";
3973
+ if (/\bmodule\.exports\s*=/.test(source)) return "eslintrc";
3974
+ return "flat";
3975
+ }
3976
+ function detectFormat(filePath, source) {
3977
+ const byName = detectFormatByName(filePath);
3978
+ if (byName) return byName;
3979
+ return detectFormatByContent(source);
3980
+ }
3981
+ function isV1Shape(parseResult) {
3982
+ if (!parseResult.hasUseInsiderImport) return false;
3983
+ return parseResult.arrayElements.some((element) => element.kind === "useInsiderCall");
3984
+ }
3985
+ function describeScopes(plan) {
3986
+ if (plan.config.scopes.size === 0) return "Scopes detected: (none)";
3987
+ return `Scopes detected: ${[...plan.config.scopes.entries()].map(([scope, entries]) => `${scope} (${entries.length})`).join(", ")}`;
3988
+ }
3989
+ function describeStrict(plan) {
3990
+ if (plan.config.strictWholeFile) return "Strict scopes: global (true)";
3991
+ if (plan.config.strictGlobs.length > 0) return `Strict scopes: 1 (${plan.config.strictGlobs.length} globs)`;
3992
+ return "Strict scopes: 0";
3993
+ }
3994
+ function summary(plan, format) {
3995
+ const lines = [];
3996
+ if (format === "eslintrc") lines.push("Source: legacy .eslintrc");
3997
+ else lines.push("Source: flat eslint.config.*");
3998
+ lines.push(describeScopes(plan));
3999
+ lines.push(describeStrict(plan));
4000
+ lines.push(`spellChecker.ignoredPaths: ${plan.config.spellChecker.ignoredPaths.length}`);
4001
+ const blocksLabel = plan.droppedRuleBlockCount === 1 ? "block" : "blocks";
4002
+ lines.push(`Dropped custom rules: ${plan.droppedRuleCount} across ${plan.droppedRuleBlockCount} ${blocksLabel}`);
4003
+ lines.push(`Warnings: ${plan.warnings.length}`);
4004
+ return lines.join("\n");
4005
+ }
4006
+ function planFromSource(source, filePath, format) {
4007
+ if (format === "flat") {
4008
+ const parseResult = parseV1Config(source, filePath);
4009
+ if (!isV1Shape(parseResult)) return null;
4010
+ const plan = transformToV2(parseResult);
4011
+ return {
4012
+ plan,
4013
+ rendered: renderV2(plan)
4014
+ };
4015
+ }
4016
+ const parseResult = parseEslintrc(source, filePath);
4017
+ if (!parseResult.found) return null;
4018
+ const plan = transformEslintrcToV2(parseResult);
4019
+ return {
4020
+ plan,
4021
+ rendered: renderV2(plan)
4022
+ };
4023
+ }
4024
+ function targetWritePath(cwd, sourcePath, format) {
4025
+ if (format !== "eslintrc") return sourcePath;
4026
+ const base = (0, node_path.basename)(sourcePath);
4027
+ const dir = sourcePath.slice(0, sourcePath.length - base.length);
4028
+ return (0, node_path.join)(dir.length > 0 ? dir : cwd, "eslint.config.mjs");
4029
+ }
4030
+ function parseEslintIgnoreContents(raw) {
4031
+ return raw.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
4032
+ }
4033
+ function findEslintIgnore(sourcePath) {
4034
+ const candidate = (0, node_path.join)((0, node_path.dirname)(sourcePath), ".eslintignore");
4035
+ if (!(0, node_fs.existsSync)(candidate)) return null;
4036
+ return {
4037
+ path: candidate,
4038
+ patterns: parseEslintIgnoreContents((0, node_fs.readFileSync)(candidate, "utf8"))
4039
+ };
4040
+ }
4041
+ function mergeIgnorePatterns(plan, extra) {
4042
+ extra.forEach((pattern) => {
4043
+ if (!plan.config.ignores.some((existing) => existing.value === pattern)) plan.config.ignores.push({ value: pattern });
4044
+ });
4045
+ }
4046
+ function safeUnlink(filePath, clack, label) {
4047
+ try {
4048
+ (0, node_fs.unlinkSync)(filePath);
4049
+ } catch (error) {
4050
+ const reason = error instanceof Error ? error.message : String(error);
4051
+ if (clack.note) clack.note(`Could not delete ${label} at ${filePath}: ${reason}`, "Warning");
4052
+ }
4053
+ }
4054
+ function describeDepChanges(depChanges) {
4055
+ if (!depChanges || !depChanges.packageJsonPath) return null;
4056
+ const lines = ["The following dependency changes will be applied to package.json:"];
4057
+ if (depChanges.removed.length > 0) lines.push(`- Remove (${depChanges.removed.length}): ${depChanges.removed.join(", ")}`);
4058
+ else lines.push("- Remove (0): (none)");
4059
+ lines.push(`- Install (${depChanges.install.specs.length}): ${depChanges.install.specs.join(", ")}`);
4060
+ return lines.join("\n");
4061
+ }
4062
+ async function confirmWrite(clack, writePath, initial = true) {
4063
+ const message = `Write migrated config to ${writePath}?`;
4064
+ const result = await clack.confirm({
4065
+ message,
4066
+ initialValue: initial
4067
+ });
4068
+ return !clack.isCancel(result) && result === true;
4069
+ }
4070
+ async function confirmInstall(clack, depSummary, initial = true) {
4071
+ const head = describeDepChanges(depSummary) ?? "";
4072
+ const message = head ? `${head}\nInstall dependencies now?` : "Install dependencies now?";
4073
+ const result = await clack.confirm({
4074
+ message,
4075
+ initialValue: initial
4076
+ });
4077
+ return !clack.isCancel(result) && result === true;
4078
+ }
4079
+ function renderNextStepsMessage(input) {
4080
+ const hasRemove = input.removed.length > 0;
4081
+ const hasInstall = input.installSpecs.length > 0;
4082
+ if (!hasRemove && !hasInstall) return null;
4083
+ const blocks = ["Skipped dependency installation. Run these to apply manually:"];
4084
+ if (hasRemove) blocks.push(formatNextStepsRemoveCommand(input.manager, input.removed));
4085
+ if (hasInstall) blocks.push(formatNextStepsAddCommand(input.manager, input.installSpecs));
4086
+ return blocks.join("\n\n");
4087
+ }
4088
+ function emitInstallNextSteps(clack, depSummary, cwd) {
4089
+ if (!clack.note) return;
4090
+ const message = renderNextStepsMessage({
4091
+ manager: detectPackageManager(cwd),
4092
+ removed: depSummary.removed,
4093
+ installSpecs: depSummary.install.specs
4094
+ });
4095
+ if (message === null) return;
4096
+ clack.note(message, "Next steps");
4097
+ }
4098
+ function emitSummary(clack, plan, format) {
4099
+ if (clack.note) clack.note(summary(plan, format), "Migration summary");
4100
+ if (plan.warnings.length > 0 && clack.note) clack.note(formatWarnings(plan.warnings), "Warnings");
4101
+ }
4102
+ function writeAndAnnounce(clack, targetPath, writePath, rendered, format) {
4103
+ if (format === "eslintrc") {
4104
+ const result = writeMigrationLegacy(targetPath, writePath, rendered);
4105
+ clack.outro(`Wrote ${writePath}`);
4106
+ return { deletedSourceCandidate: result.deletedSourceCandidate };
4107
+ }
4108
+ writeMigration(targetPath, rendered);
4109
+ clack.outro(`Wrote ${targetPath}`);
4110
+ return {};
4111
+ }
4112
+ async function confirmOverwriteExistingOutput(clack, writePath, sourcePath, initial = false) {
4113
+ const message = `An \`${(0, node_path.basename)(writePath)}\` already exists. Overwrite + delete \`${(0, node_path.basename)(sourcePath)}\`?`;
4114
+ const result = await clack.confirm({
4115
+ message,
4116
+ initialValue: initial
4117
+ });
4118
+ return !clack.isCancel(result) && result === true;
4119
+ }
4120
+ function resolveSource(input, clack) {
4121
+ const targetPath = resolveTargetPath(input);
4122
+ if (!targetPath) {
4123
+ clack.cancel("No eslint.config.{mjs,js,cjs} or .eslintrc.{cjs,js,mjs} found.");
4124
+ return {
4125
+ ok: false,
4126
+ exitCode: 1
4127
+ };
4128
+ }
4129
+ const source = (0, node_fs.readFileSync)(targetPath, "utf8");
4130
+ const format = detectFormat(targetPath, source);
4131
+ if (format === "eslintrc-unsupported") {
4132
+ const message = `Legacy ${(0, node_path.basename)(targetPath)} migration not supported in this release; convert manually first.`;
4133
+ clack.cancel(message);
4134
+ return {
4135
+ ok: false,
4136
+ exitCode: 1
4137
+ };
4138
+ }
4139
+ return {
4140
+ ok: true,
4141
+ resolved: {
4142
+ targetPath,
4143
+ source,
4144
+ format
4145
+ }
4146
+ };
4147
+ }
4148
+ function prepareMigration(resolved, input) {
4149
+ const planResult = planFromSource(resolved.source, resolved.targetPath, resolved.format);
4150
+ if (!planResult) return null;
4151
+ const { plan } = planResult;
4152
+ const writePath = targetWritePath(input.cwd, resolved.targetPath, resolved.format);
4153
+ const eslintIgnore = findEslintIgnore(resolved.targetPath);
4154
+ if (eslintIgnore && eslintIgnore.patterns.length > 0) mergeIgnorePatterns(plan, eslintIgnore.patterns);
4155
+ return {
4156
+ plan,
4157
+ rendered: renderV2(plan),
4158
+ writePath,
4159
+ eslintIgnore
4160
+ };
4161
+ }
4162
+ async function runConfirmations(clack, input, targetPath, writePath, previous) {
4163
+ if (writePath !== targetPath && (0, node_fs.existsSync)(writePath)) {
4164
+ if (!await confirmOverwriteExistingOutput(clack, writePath, targetPath, previous?.overwriteExisting ?? false)) {
4165
+ clack.outro("Aborted: existing output kept.");
4166
+ return false;
4167
+ }
4168
+ }
4169
+ if (!input.yes) {
4170
+ if (!await confirmWrite(clack, writePath, previous?.proceed ?? true)) {
4171
+ clack.outro("Aborted: original config kept.");
4172
+ return false;
4173
+ }
4174
+ }
4175
+ return true;
4176
+ }
4177
+ function consumerPackageJsonPath(writePath) {
4178
+ return (0, node_path.join)((0, node_path.dirname)(writePath), "package.json");
4179
+ }
4180
+ function tryReadConsumerManifest(path) {
4181
+ try {
4182
+ const raw = (0, node_fs.readFileSync)(path, "utf8");
4183
+ return JSON.parse(raw);
4184
+ } catch {
4185
+ return null;
4186
+ }
4187
+ }
4188
+ function computeDepSummary(plan, writePath, overrides) {
4189
+ const pkgPath = consumerPackageJsonPath(writePath);
4190
+ const manifest = tryReadConsumerManifest(pkgPath);
4191
+ if (!manifest) return {
4192
+ removed: [],
4193
+ install: {
4194
+ specs: [],
4195
+ fallbacks: []
4196
+ },
4197
+ packageJsonPath: null
4198
+ };
4199
+ const pruneOutcome = pruneEslintDependencies(manifest);
4200
+ const ownManifest = (overrides?.readEslintConfigManifest ?? readOwnEslintConfigManifest)();
4201
+ const install = buildInstallList(new Set(plan.config.scopes.keys()), ownManifest);
4202
+ return {
4203
+ removed: pruneOutcome.removed,
4204
+ install,
4205
+ packageJsonPath: pkgPath
4206
+ };
4207
+ }
4208
+ function persistPrunedManifest(depSummary) {
4209
+ if (!depSummary.packageJsonPath) return;
4210
+ pruneConsumerPackageJson((0, node_path.dirname)(depSummary.packageJsonPath));
4211
+ }
4212
+ function noteFallbacks(clack, depSummary) {
4213
+ if (depSummary.install.fallbacks.length === 0 || !clack.note) return;
4214
+ const list = depSummary.install.fallbacks.join(", ");
4215
+ clack.note(`Falling back to @latest for: ${list}`, "Warning");
4216
+ }
4217
+ function resolveInstallCwd(depSummary, input) {
4218
+ if (depSummary.packageJsonPath) return (0, node_path.dirname)(depSummary.packageJsonPath);
4219
+ return input.cwd;
4220
+ }
4221
+ async function runInstaller(clack, depSummary, input) {
4222
+ await installWithRetry({
4223
+ deps: depSummary.install.specs,
4224
+ cwd: resolveInstallCwd(depSummary, input),
4225
+ autoConfirm: Boolean(input.yes),
4226
+ clack,
4227
+ fsOps: input.overrides?.wipeFs,
4228
+ installer: input.overrides?.installer
4229
+ });
4230
+ }
4231
+ async function applyDepChanges(clack, depSummary, input) {
4232
+ if (!depSummary.packageJsonPath) {
4233
+ if (clack.note) clack.note("No package.json found alongside the migrated config — skipping dependency updates.", "Notice");
4234
+ return;
4235
+ }
4236
+ persistPrunedManifest(depSummary);
4237
+ if (input.noInstall) {
4238
+ emitInstallNextSteps(clack, depSummary, input.cwd);
4239
+ return;
4240
+ }
4241
+ if (!input.yes) {
4242
+ if (!await confirmInstall(clack, depSummary)) {
4243
+ emitInstallNextSteps(clack, depSummary, input.cwd);
4244
+ return;
4245
+ }
4246
+ }
4247
+ noteFallbacks(clack, depSummary);
4248
+ await runInstaller(clack, depSummary, input);
4249
+ }
4250
+ function performWriteAndCleanup(clack, resolved, prepared) {
4251
+ const outcome = writeAndAnnounce(clack, resolved.targetPath, prepared.writePath, prepared.rendered, resolved.format);
4252
+ if (prepared.eslintIgnore) safeUnlink(prepared.eslintIgnore.path, clack, ".eslintignore");
4253
+ if (outcome.deletedSourceCandidate) safeUnlink(outcome.deletedSourceCandidate, clack, "source config");
4254
+ }
4255
+ function loadPreviousMigrate(clack, cwd) {
4256
+ const restored = loadSession({ cwd });
4257
+ const previousMigrate = restored?.command === "migrate" ? restored.migrate : void 0;
4258
+ if (previousMigrate && clack.note) clack.note("Restored your previous choices. Press Enter on each prompt to confirm, or arrow keys to change.", "Resuming previous session");
4259
+ return previousMigrate;
4260
+ }
4261
+ function emitNothingToMigrate(clack, format) {
4262
+ clack.outro(format === "eslintrc" ? "No legacy `.eslintrc` shape found — nothing to migrate." : "No v1 useInsider patterns found — nothing to migrate.");
4263
+ }
4264
+ function persistMigrateSession(input, prepared, resolved) {
4265
+ const overwriteExisting = prepared.writePath !== resolved.targetPath && (0, node_fs.existsSync)(prepared.writePath);
4266
+ saveSession({
4267
+ command: "migrate",
4268
+ migrate: {
4269
+ target: input.target,
4270
+ yes: input.yes,
4271
+ noInstall: input.noInstall,
4272
+ overwriteExisting,
4273
+ proceed: true
4274
+ }
4275
+ }, { cwd: input.cwd });
4276
+ }
4277
+ async function runMigrate(input, clackOverride) {
4278
+ const clack = clackOverride ?? await loadClack();
4279
+ const sourceResult = resolveSource(input, clack);
4280
+ if (!sourceResult.ok) return sourceResult.exitCode;
4281
+ const { resolved } = sourceResult;
4282
+ clack.intro(`Migrating ${resolved.targetPath}`);
4283
+ const previousMigrate = loadPreviousMigrate(clack, input.cwd);
4284
+ const prepared = prepareMigration(resolved, input);
4285
+ if (!prepared) {
4286
+ emitNothingToMigrate(clack, resolved.format);
4287
+ return 0;
4288
+ }
4289
+ emitSummary(clack, prepared.plan, resolved.format);
4290
+ const depSummary = computeDepSummary(prepared.plan, prepared.writePath, input.overrides);
4291
+ if (!await runConfirmations(clack, input, resolved.targetPath, prepared.writePath, previousMigrate)) return 0;
4292
+ persistMigrateSession(input, prepared, resolved);
4293
+ performWriteAndCleanup(clack, resolved, prepared);
4294
+ if (depSummary) await applyDepChanges(clack, depSummary, input);
4295
+ clearSession({ cwd: input.cwd });
4296
+ return 0;
4297
+ }
4298
+ //#endregion
4299
+ //#region src/cli/index.ts
4300
+ function resolveTsconfigInput(cwd) {
4301
+ const referencesResult = resolveTsconfigReferences(cwd);
4302
+ if (referencesResult) return {
4303
+ input: {
4304
+ referencesOnly: true,
4305
+ rootPath: referencesResult.rootPath,
4306
+ refs: referencesResult.refs
4307
+ },
4308
+ missing: false
4309
+ };
4310
+ const rootPath = (0, node_path.join)(cwd, "tsconfig.json");
4311
+ if ((0, node_fs.existsSync)(rootPath)) return {
4312
+ input: {
4313
+ referencesOnly: false,
4314
+ rootPath,
4315
+ refs: []
4316
+ },
4317
+ missing: false
4318
+ };
4319
+ return {
4320
+ input: null,
4321
+ missing: true
4322
+ };
4323
+ }
4324
+ function decisionToChoice(decision) {
4325
+ return decision;
4326
+ }
4327
+ function isPackageJsonSource(existing) {
4328
+ return existing.path.endsWith("package.json");
4329
+ }
4330
+ async function handleExistingConfig(clack, input, existing, initial) {
4331
+ const decision = await askExistingConfigDecision(clack, existing.path, initial);
4332
+ saveSession({
4333
+ command: "scaffold",
4334
+ scaffold: { existingConfigChoice: decisionToChoice(decision) }
4335
+ }, { cwd: input.cwd });
4336
+ if (decision === "exit") {
4337
+ clearSession({ cwd: input.cwd });
4338
+ clack.outro("Exited: existing config kept.");
4339
+ return {
4340
+ continueScaffold: false,
4341
+ exitCode: 0
4342
+ };
4343
+ }
4344
+ if (decision === "migrate") {
4345
+ clearSession({ cwd: input.cwd });
4346
+ if (isPackageJsonSource(existing)) {
4347
+ clack.cancel("Migration from package.json `eslintConfig` is not supported; extract it to .eslintrc.cjs first, or pick Override.");
4348
+ return {
4349
+ continueScaffold: false,
4350
+ exitCode: 1
4351
+ };
4352
+ }
4353
+ return {
4354
+ continueScaffold: false,
4355
+ exitCode: await runMigrate({
4356
+ cwd: input.cwd,
4357
+ target: existing.path,
4358
+ yes: input.yes
4359
+ }, clack)
4360
+ };
4361
+ }
4362
+ return {
4363
+ continueScaffold: true,
4364
+ viaOverride: true
4365
+ };
4366
+ }
4367
+ function isScaffoldChoice(value) {
4368
+ return value === "override" || value === "migrate" || value === "exit";
4369
+ }
4370
+ function decisionInitial(persistedChoice) {
4371
+ if (persistedChoice && isScaffoldChoice(persistedChoice)) return persistedChoice;
4372
+ return "migrate";
4373
+ }
4374
+ function buildQuestionsContext(input, restoredAnswers) {
4375
+ const { input: tsconfigInput, missing } = resolveTsconfigInput(input.cwd);
4376
+ return {
4377
+ tsconfigInput,
4378
+ tsconfigMissing: missing,
4379
+ previousAnswers: restoredAnswers
4380
+ };
4381
+ }
4382
+ function noteOverridePrune(clack, removed) {
4383
+ if (removed.length === 0 || !clack.note) return;
4384
+ const list = removed.join(", ");
4385
+ clack.note(`Removed stale ESLint-related entries from package.json: ${list}`, "Override cleanup");
4386
+ }
4387
+ function describeHybridPattern(detection) {
4388
+ if (detection.kind === "suffix") return `Detected suffix convention: Options API files match \`${detection.optionsPattern}\`.`;
4389
+ if (detection.kind === "directory") return `Detected directory convention: \`${detection.optionsDir}/\` vs \`${detection.compositionDir}/\`.`;
4390
+ return "";
4391
+ }
4392
+ function noteHybridFound(clack, detection) {
4393
+ if (!clack.note) return;
4394
+ if (detection.kind !== "suffix" && detection.kind !== "directory") return;
4395
+ clack.note(describeHybridPattern(detection), "Hybrid Vue pattern detected");
4396
+ }
4397
+ function noteHybridMissing(clack) {
4398
+ if (!clack.note) return;
4399
+ clack.note("Hybrid Vue selected, but your `.vue` files do not follow a distinguishing naming pattern (e.g. `*.options.vue` vs `*.vue`). The generated config will treat every `.vue` file with one preset (composition by default). To get proper per-file linting, rename your Options-API components to `*.options.vue` (or similar) and re-run this CLI.", "No hybrid pattern detected");
4400
+ }
4401
+ function noteHybridSuffixScaffold(clack, suffix) {
4402
+ if (!clack.note) return;
4403
+ clack.note(`Rename your Options-API files to end with \`${suffix}\` and they will be picked up by the Options preset automatically. Composition components keep the plain \`.vue\` extension.`, "Suffix convention scaffolded");
4404
+ }
4405
+ async function resolveVueHybridPlan(clack, cwd, yes, previous) {
4406
+ const detection = detectVueApiPattern({ cwd });
4407
+ if (detection.kind === "suffix") {
4408
+ noteHybridFound(clack, detection);
4409
+ const detectedDefault = detection.targetApi === "options" ? "composition" : "options";
4410
+ return {
4411
+ suffix: detection.suffix,
4412
+ defaultApi: detectedDefault,
4413
+ fallbackToComposition: false
4414
+ };
4415
+ }
4416
+ if (detection.kind === "directory") {
4417
+ noteHybridFound(clack, detection);
4418
+ return {
4419
+ suffix: void 0,
4420
+ defaultApi: void 0,
4421
+ fallbackToComposition: false
4422
+ };
4423
+ }
4424
+ noteHybridMissing(clack);
4425
+ if (yes) return {
4426
+ suffix: void 0,
4427
+ defaultApi: void 0,
4428
+ fallbackToComposition: true
4429
+ };
4430
+ if (!await askHybridProceedWithSuffix(clack)) return {
4431
+ suffix: void 0,
4432
+ defaultApi: void 0,
4433
+ fallbackToComposition: true
4434
+ };
4435
+ const defaultApi = await askVueHybridDefaultApi(clack, previous?.defaultApi);
4436
+ const suffix = await askHybridSuffix(clack, defaultApi, previous?.suffix);
4437
+ noteHybridSuffixScaffold(clack, suffix);
4438
+ return {
4439
+ suffix,
4440
+ defaultApi,
4441
+ fallbackToComposition: false
4442
+ };
4443
+ }
4444
+ async function resolveHybridAnswers(clack, input, answers) {
4445
+ if (answers.framework !== "vue" || answers.vueApiStyle !== "hybrid") return answers;
4446
+ const plan = await resolveVueHybridPlan(clack, input.cwd, Boolean(input.yes), answers.vueHybridSuffix);
4447
+ if (plan.fallbackToComposition) return {
4448
+ ...answers,
4449
+ vueApiStyle: "composition",
4450
+ vueHybridSuffix: void 0
4451
+ };
4452
+ if (plan.suffix && plan.defaultApi) return {
4453
+ ...answers,
4454
+ vueHybridSuffix: {
4455
+ defaultApi: plan.defaultApi,
4456
+ suffix: plan.suffix
4457
+ }
4458
+ };
4459
+ return answers;
4460
+ }
4461
+ async function installAndWrite(clack, input, answers, options) {
4462
+ if (options.pruneBeforeInstall) noteOverridePrune(clack, pruneConsumerPackageJson(input.cwd).removed);
4463
+ const deps = buildDependencyList(answers);
4464
+ if (clack.note) clack.note(deps.map((dep) => ` - ${dep}`).join("\n"), "Installing dev dependencies");
4465
+ await installWithRetry({
4466
+ deps,
4467
+ cwd: input.cwd,
4468
+ autoConfirm: Boolean(input.yes),
4469
+ clack,
4470
+ installer: input.overrides?.installer ?? installDependencies,
4471
+ fsOps: input.overrides?.wipeFs
4472
+ });
4473
+ const targetPath = (0, node_path.join)(input.cwd, "eslint.config.mjs");
4474
+ (0, node_fs.writeFileSync)(targetPath, renderConfigFile(answers), "utf8");
4475
+ return targetPath;
4476
+ }
4477
+ async function runScaffold(input, clackOverride) {
4478
+ const clack = clackOverride ?? await loadClack();
4479
+ const existing = detectExistingEslintConfig(input.cwd);
4480
+ const restored = loadSession({ cwd: input.cwd });
4481
+ const restoredScaffold = restored?.command === "scaffold" ? restored.scaffold : void 0;
4482
+ let viaOverride = false;
4483
+ if (existing) {
4484
+ const outcome = await handleExistingConfig(clack, input, existing, decisionInitial(restoredScaffold?.existingConfigChoice));
4485
+ if (!outcome.continueScaffold) return outcome.exitCode;
4486
+ ({viaOverride} = outcome);
4487
+ }
4488
+ const resolvedAnswers = await resolveHybridAnswers(clack, input, await runQuestions(buildQuestionsContext(input, restoredScaffold?.answers), clack));
4489
+ saveSession({
4490
+ command: "scaffold",
4491
+ scaffold: {
4492
+ answers: resolvedAnswers,
4493
+ existingConfigChoice: "override"
4494
+ }
4495
+ }, { cwd: input.cwd });
4496
+ const targetPath = await installAndWrite(clack, input, resolvedAnswers, { pruneBeforeInstall: viaOverride });
4497
+ clearSession({ cwd: input.cwd });
4498
+ clack.outro(`Wrote ${targetPath}`);
4499
+ return 0;
4500
+ }
4501
+ async function runScaffoldSubcommand(scaffoldInput) {
4502
+ return runScaffold(scaffoldInput);
4503
+ }
4504
+ async function runMigrateSubcommand(input) {
4505
+ return runMigrate({
4506
+ cwd: input.cwd,
4507
+ target: input.target,
4508
+ yes: input.yes,
4509
+ noInstall: input.noInstall
4510
+ });
4511
+ }
4512
+ function writeStderr(line) {
4513
+ console.error(line);
4514
+ }
4515
+ async function main() {
4516
+ return dispatch(process.argv.slice(2), process.cwd(), {
4517
+ scaffold: runScaffoldSubcommand,
4518
+ migrate: runMigrateSubcommand,
4519
+ stderr: writeStderr
4520
+ });
4521
+ }
4522
+ function exitCleanly(code) {
4523
+ process.exit(code);
4524
+ }
4525
+ function isUnderTest() {
4526
+ return Boolean(process.env.VITEST) || process.env.NODE_ENV === "test";
4527
+ }
4528
+ if (!isUnderTest()) main().then(exitCleanly).catch((error) => {
4529
+ if (!(error instanceof CliCancelledError)) {
4530
+ const message = error instanceof Error ? error.message : String(error);
4531
+ console.error(`[useinsider/eslint-config] ${message}`);
4532
+ }
4533
+ exitCleanly(1);
4534
+ });
4535
+ //#endregion
4536
+ exports.runScaffold = runScaffold;
4537
+
4538
+ //# sourceMappingURL=cli.cjs.map