@ai-i18n/eslint-plugin 1.0.0-alpha.6 → 1.0.0-alpha.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # @ai-i18n/eslint-plugin
2
2
 
3
3
  用于提前报告无法被 Vite/Yuku 静态提取、不符合推荐语法,或不会随语言切换刷新的 `t()`
4
- 用法。规则检查解析到 `virtual:ai-i18n` 的 `t` binding,以及 Vue/React 模式下
4
+ 用法。规则检查解析到 `virtual:ai-i18n` 的 `t` / Vue-only `tRef` binding,以及 Vue/React 模式下
5
5
  `useI18n()` 解构或对象成员得到的 `t`。其他库或局部同名函数不受影响。
6
6
 
7
7
  alpha 阶段请安装 `@ai-i18n/eslint-plugin@alpha`;peer 支持 ESLint 9 和 10。
@@ -73,6 +73,7 @@ Vue preset 同时覆盖 Vue JSX/TSX,但宿主仍需用 `@vitejs/plugin-vue-jsx
73
73
  ```ts
74
74
  export const label = t('保存'); // warning:只保存初始化时的译文
75
75
  export const getLabel = () => t('保存'); // 允许:每次调用重新读取当前语言
76
+ export const label = tRef('保存'); // Vue:允许,返回响应式 ComputedRef
76
77
  ```
77
78
 
78
79
  `recommended`、`vue`、`vue-auto-import` 与 `react-auto-import` 还启用
@@ -101,11 +102,16 @@ function SaveButton() {
101
102
 
102
103
  规则与 Vite 共用静态参数语义,包括从 `useI18n()` 获得的对象成员调用
103
104
  `i18n.t()`、`i18n['t']()`、省略式 `t('source', undefined)` 和 tagged template。
105
+ 整棵可静态求值的纯文案对象或数组可以直接传给 `t()` 或 Vue `tRef()`,不要求
106
+ `defineI18nMessages()` 或 `as const`;规则会按去重后的字符串叶子计算静态候选数。
104
107
  Vue 模板必须在 `<script setup>` 中绑定 `useI18n()` 返回的 `t`;自动导入只省略 import,
105
108
  不会自动合成 Hook。`vue-auto-import` 会把裸 template-only `t()` 作为 error;模板中已
106
109
  绑定到 Runtime 顶层 `t` 的调用则由 `no-unsubscribed-t` warning。
110
+ 在 template 或 JSX/TSX 渲染期间调用 `tRef()` 会重复创建 `computed`,同一规则会提示在
111
+ Vue setup 中只创建一次并使用返回的 Ref。
107
112
 
108
- 对象或数组成员只有在根集合由 `defineI18nMessages()` 标记后才属于推荐写法。字符串拼接、
113
+ 对象或数组的成员级引用只有在根集合由 `defineI18nMessages()` 标记后才属于推荐写法。
114
+ 动态生成的树、非普通对象以及带第二参数的整树调用会报错。字符串拼接、
109
115
  逻辑表达式、`let` 文案、普通集合成员、`const tr = t`、命名空间调用、二次 Hook 解构、
110
116
  `useI18n().t()` 与 `require()` 都会报错。
111
117
 
@@ -119,6 +125,7 @@ export default [
119
125
  languageOptions: {
120
126
  globals: {
121
127
  t: 'readonly',
128
+ tRef: 'readonly',
122
129
  useI18n: 'readonly',
123
130
  defineI18nMessages: 'readonly',
124
131
  },
@@ -128,21 +135,21 @@ export default [
128
135
  'ai-i18n/no-eager-translation': [
129
136
  'warn',
130
137
  {
131
- autoImport: ['t', 'useI18n'],
138
+ autoImport: ['t', 'tRef', 'useI18n'],
132
139
  tsconfigPath: './tsconfig.json',
133
140
  },
134
141
  ],
135
142
  'ai-i18n/no-unsubscribed-t': [
136
143
  'warn',
137
144
  {
138
- autoImport: ['t', 'useI18n'],
145
+ autoImport: ['t', 'tRef', 'useI18n'],
139
146
  tsconfigPath: './tsconfig.json',
140
147
  },
141
148
  ],
142
149
  'ai-i18n/static-candidate-limit': [
143
150
  'warn',
144
151
  {
145
- autoImport: ['t', 'useI18n'],
152
+ autoImport: ['t', 'tRef', 'useI18n'],
146
153
  tsconfigPath: './tsconfig.json',
147
154
  maxStaticCandidates: 2_000,
148
155
  },
@@ -150,7 +157,7 @@ export default [
150
157
  'ai-i18n/t-static-args': [
151
158
  'error',
152
159
  {
153
- autoImport: ['t', 'useI18n'],
160
+ autoImport: ['t', 'tRef', 'useI18n'],
154
161
  tsconfigPath: './tsconfig.json',
155
162
  },
156
163
  ],
@@ -159,8 +166,8 @@ export default [
159
166
  ];
160
167
  ```
161
168
 
162
- 上例匹配 Vue / React 模式;Vanilla 手工配置只使用 `autoImport: ['t']`,并声明对应的顶层
163
- Runtime globals。日常接入优先使用预设,避免 Vite 与 ESLint 的 API 集合不一致。
169
+ 上例匹配 Vue 模式;React 应移除 `tRef`,Vanilla 只使用 `autoImport: ['t']`,并声明对应的
170
+ 顶层 Runtime globals。日常接入优先使用预设,避免 Vite 与 ESLint 的 API 集合不一致。
164
171
 
165
172
  `ai-i18n/static-candidate-limit` 默认在单个 `t()` 的 source 与 options 组合超过 1000 个
166
173
  时警告。`maxStaticCandidates` 必须是正整数,只改变 ESLint 的提示阈值;Vite 提取不设
package/dist/index.js CHANGED
@@ -162,7 +162,7 @@ function stripJsonComments(source) {
162
162
  }
163
163
  //#endregion
164
164
  //#region src/analyze.ts
165
- const POTENTIAL_TRANSLATION_RE = /virtual:ai-i18n|\b(?:t|useI18n|defineI18nMessages)\b/;
165
+ const POTENTIAL_TRANSLATION_RE = /virtual:ai-i18n|\b(?:t|tRef|useI18n|defineI18nMessages)\b/;
166
166
  function analyzeStaticSource(code, filename, tsconfigPath, lang, autoImport = false, maxStaticCandidates = Number.POSITIVE_INFINITY) {
167
167
  if (!hasPotentialTranslationCandidate(code)) return {
168
168
  warnings: [],
@@ -171,7 +171,7 @@ function analyzeStaticSource(code, filename, tsconfigPath, lang, autoImport = fa
171
171
  const autoImports = normalizeAutoImports(autoImport);
172
172
  const resolve = createImportResolver(tsconfigPath);
173
173
  const analyzer = new Analyzer({ resolve });
174
- analyzer.addFile(AI_I18N_VIRTUAL_MODULE_ID, "export function t(source) { return source }");
174
+ analyzer.addFile(AI_I18N_VIRTUAL_MODULE_ID, "export function t(source) { return source } export function tRef(source) { return source }");
175
175
  const entryPath = normalizeFilename(filename);
176
176
  const entry = analyzer.addFile(entryPath, code, lang ? { lang } : void 0);
177
177
  if (!hasTranslationCandidate(entry, autoImports)) return {
@@ -181,8 +181,8 @@ function analyzeStaticSource(code, filename, tsconfigPath, lang, autoImport = fa
181
181
  loadDependencies(analyzer, entry, resolve);
182
182
  analyzer.link();
183
183
  const hooks = translationHooks(autoImports);
184
- const extraction = extractMessages(entry, AI_I18N_VIRTUAL_MODULE_ID, hooks, autoImports.t, maxStaticCandidates).warnings;
185
- const recommended = validateRecommendedUsage(entry, AI_I18N_VIRTUAL_MODULE_ID, hooks, autoImports.t);
184
+ const extraction = extractMessages(entry, AI_I18N_VIRTUAL_MODULE_ID, hooks, autoImports.t || autoImports.tRef, maxStaticCandidates).warnings;
185
+ const recommended = validateRecommendedUsage(entry, AI_I18N_VIRTUAL_MODULE_ID, hooks, autoImports.t || autoImports.tRef);
186
186
  return {
187
187
  warnings: (recommended.length ? [
188
188
  ...extraction.filter((warning) => warning.code === "parse-error"),
@@ -194,7 +194,7 @@ function analyzeStaticSource(code, filename, tsconfigPath, lang, autoImport = fa
194
194
  column,
195
195
  message
196
196
  })),
197
- translationCalls: findTranslationCalls(entry, AI_I18N_VIRTUAL_MODULE_ID, hooks, autoImports.t)
197
+ translationCalls: findTranslationCalls(entry, AI_I18N_VIRTUAL_MODULE_ID, hooks, autoImports.t || autoImports.tRef)
198
198
  };
199
199
  }
200
200
  function hasPotentialTranslationCandidate(code) {
@@ -203,18 +203,21 @@ function hasPotentialTranslationCandidate(code) {
203
203
  function normalizeAutoImports(autoImport) {
204
204
  if (typeof autoImport === "boolean") return {
205
205
  t: autoImport,
206
+ tRef: false,
206
207
  useI18n: autoImport
207
208
  };
208
209
  return {
209
210
  t: autoImport?.includes("t") ?? false,
211
+ tRef: autoImport?.includes("tRef") ?? false,
210
212
  useI18n: autoImport?.includes("useI18n") ?? false
211
213
  };
212
214
  }
213
215
  function hasTranslationCandidate(module, autoImports) {
214
216
  const unbound = ["defineI18nMessages"];
215
217
  if (autoImports.t) unbound.push("t");
218
+ if (autoImports.tRef) unbound.push("tRef");
216
219
  if (autoImports.useI18n) unbound.push("useI18n");
217
- return module.imports.some((item) => !item.typeOnly && (item.specifier === AI_I18N_VIRTUAL_MODULE_ID || item.name === "t" || item.name === "useI18n")) || findInvalidDefineI18nMessagesReferences(module).length > 0 || findUnboundCalls(module, new Set(unbound)).length > 0;
220
+ return module.imports.some((item) => !item.typeOnly && (item.specifier === AI_I18N_VIRTUAL_MODULE_ID || item.name === "t" || item.name === "tRef" || item.name === "useI18n")) || findInvalidDefineI18nMessagesReferences(module).length > 0 || findUnboundCalls(module, new Set(unbound)).length > 0;
218
221
  }
219
222
  function translationHooks(autoImports) {
220
223
  return [{
@@ -319,6 +322,7 @@ function analyzeRuleContextResult(context, options, maxStaticCandidates) {
319
322
  const key = JSON.stringify([
320
323
  options.tsconfigPath ?? null,
321
324
  autoImports.t,
325
+ autoImports.tRef,
322
326
  autoImports.useI18n,
323
327
  limit
324
328
  ]);
@@ -383,13 +387,17 @@ const noEagerTranslation = {
383
387
  tsconfigPath: { type: "string" },
384
388
  autoImport: { anyOf: [{ type: "boolean" }, {
385
389
  type: "array",
386
- items: { enum: ["t", "useI18n"] },
390
+ items: { enum: [
391
+ "t",
392
+ "tRef",
393
+ "useI18n"
394
+ ] },
387
395
  uniqueItems: true
388
396
  }] }
389
397
  },
390
398
  additionalProperties: false
391
399
  }],
392
- messages: { eagerTranslation: diagnosticMessage("初始化期间保存的 t() 结果不会随语言切换更新。请改为函数或 Getter,在使用时调用 t();组件视图请使用 useI18n()。", "A t() result stored during initialization will not update when the language changes. Evaluate it lazily in a function or getter; use useI18n() in component views.") }
400
+ messages: { eagerTranslation: diagnosticMessage("初始化期间保存的 t() 结果不会随语言切换更新。请改为函数或 Getter,在使用时调用 t();Vue setup 中的响应式展示值可使用 tRef()。", "A t() result stored during initialization will not update when the language changes. Evaluate it lazily in a function or getter; reactive display values in Vue setup can use tRef().") }
393
401
  },
394
402
  create(context) {
395
403
  const options = context.options[0] ?? {};
@@ -416,7 +424,8 @@ const noEagerTranslation = {
416
424
  reportAnalysisFailureOnce(context, program, error);
417
425
  return;
418
426
  }
419
- for (const { node } of matches) {
427
+ for (const { call, node } of matches) {
428
+ if (call.origin === "vue-ref") continue;
420
429
  if (!storesOutsideFunction(node, context, isVueSfc)) continue;
421
430
  context.report({
422
431
  node,
@@ -509,20 +518,27 @@ const IMMEDIATE_CONSOLE_METHODS = /* @__PURE__ */ new Set([
509
518
  const noUnsubscribedT = {
510
519
  meta: {
511
520
  type: "problem",
512
- docs: { description: "警告组件渲染路径中未订阅语言状态的顶层 t" },
521
+ docs: { description: "检查组件渲染路径中的翻译 API 生命周期" },
513
522
  schema: [{
514
523
  type: "object",
515
524
  properties: {
516
525
  tsconfigPath: { type: "string" },
517
526
  autoImport: { anyOf: [{ type: "boolean" }, {
518
527
  type: "array",
519
- items: { enum: ["t", "useI18n"] },
528
+ items: { enum: [
529
+ "t",
530
+ "tRef",
531
+ "useI18n"
532
+ ] },
520
533
  uniqueItems: true
521
534
  }] }
522
535
  },
523
536
  additionalProperties: false
524
537
  }],
525
- messages: { unsubscribedT: diagnosticMessage("组件渲染期间使用顶层 t 不会订阅语言状态,语言切换不会主动刷新,缓存的渲染结果也可能继续使用旧译文。请使用 useI18n() 返回的 t。", "Top-level t does not subscribe the component to language updates, so language changes do not trigger a render and cached render results may remain stale. Use the t returned by useI18n().") }
538
+ messages: {
539
+ unsubscribedT: diagnosticMessage("组件渲染期间使用顶层 t 不会订阅语言状态,语言切换不会主动刷新,缓存的渲染结果也可能继续使用旧译文。请使用 useI18n() 返回的 t。", "Top-level t does not subscribe the component to language updates, so language changes do not trigger a render and cached render results may remain stale. Use the t returned by useI18n()."),
540
+ renderTRef: diagnosticMessage("不要在组件渲染或 template 中调用 tRef(),否则每次渲染都会创建新的 computed。请在 setup 中创建一次并使用返回的 Ref;渲染函数中请直接使用 useI18n() 返回的 t。", "Do not call tRef() during component rendering or in a template because each render creates a new computed. Create it once in setup and use the returned Ref; in render functions, call the t returned by useI18n() directly.")
541
+ }
526
542
  },
527
543
  create(context) {
528
544
  const options = context.options[0] ?? {};
@@ -557,6 +573,21 @@ const noUnsubscribedT = {
557
573
  return;
558
574
  }
559
575
  for (const { call, node } of matches) {
576
+ if (call.origin === "vue-ref") {
577
+ if (templateNodes.has(node)) {
578
+ if (!isVueTemplateEventHandler(node)) context.report({
579
+ node,
580
+ messageId: "renderTRef"
581
+ });
582
+ continue;
583
+ }
584
+ const owner = nearestFunction(node);
585
+ if (owner && jsxOwners.has(owner)) context.report({
586
+ node,
587
+ messageId: "renderTRef"
588
+ });
589
+ continue;
590
+ }
560
591
  if (call.origin !== "runtime") continue;
561
592
  if (templateNodes.has(node)) {
562
593
  if (!isVueTemplateEventHandler(node)) context.report({
@@ -629,7 +660,11 @@ const staticCandidateLimit = {
629
660
  tsconfigPath: { type: "string" },
630
661
  autoImport: { anyOf: [{ type: "boolean" }, {
631
662
  type: "array",
632
- items: { enum: ["t", "useI18n"] },
663
+ items: { enum: [
664
+ "t",
665
+ "tRef",
666
+ "useI18n"
667
+ ] },
633
668
  uniqueItems: true
634
669
  }] },
635
670
  maxStaticCandidates: {
@@ -680,7 +715,11 @@ const tStaticArgs = {
680
715
  tsconfigPath: { type: "string" },
681
716
  autoImport: { anyOf: [{ type: "boolean" }, {
682
717
  type: "array",
683
- items: { enum: ["t", "useI18n"] },
718
+ items: { enum: [
719
+ "t",
720
+ "tRef",
721
+ "useI18n"
722
+ ] },
684
723
  uniqueItems: true
685
724
  }] }
686
725
  },
@@ -846,14 +885,31 @@ plugin.configs["vue-auto-import"] = [{
846
885
  plugins: { "ai-i18n": plugin },
847
886
  languageOptions: { globals: {
848
887
  t: "readonly",
888
+ tRef: "readonly",
849
889
  useI18n: "readonly",
850
890
  defineI18nMessages: "readonly"
851
891
  } },
852
892
  rules: {
853
- "ai-i18n/t-static-args": ["error", { autoImport: ["t", "useI18n"] }],
854
- "ai-i18n/no-eager-translation": ["warn", { autoImport: ["t", "useI18n"] }],
855
- "ai-i18n/no-unsubscribed-t": ["warn", { autoImport: ["t", "useI18n"] }],
856
- "ai-i18n/static-candidate-limit": ["warn", { autoImport: ["t", "useI18n"] }]
893
+ "ai-i18n/t-static-args": ["error", { autoImport: [
894
+ "t",
895
+ "tRef",
896
+ "useI18n"
897
+ ] }],
898
+ "ai-i18n/no-eager-translation": ["warn", { autoImport: [
899
+ "t",
900
+ "tRef",
901
+ "useI18n"
902
+ ] }],
903
+ "ai-i18n/no-unsubscribed-t": ["warn", { autoImport: [
904
+ "t",
905
+ "tRef",
906
+ "useI18n"
907
+ ] }],
908
+ "ai-i18n/static-candidate-limit": ["warn", { autoImport: [
909
+ "t",
910
+ "tRef",
911
+ "useI18n"
912
+ ] }]
857
913
  }
858
914
  }];
859
915
  plugin.configs["react-auto-import"] = [{
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["FUNCTION_TYPES"],"sources":["../src/resolve-import.ts","../src/analyze.ts","../src/vue-sfc.ts","../src/rule-analysis.ts","../src/rules/translation-call.ts","../src/rules/no-eager-translation.ts","../src/rules/no-unsubscribed-t.ts","../src/rules/static-candidate-limit.ts","../src/rules/t-static-args.ts","../src/index.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\n\nconst SOURCE_EXTENSIONS = [\n '',\n '.ts',\n '.tsx',\n '.js',\n '.jsx',\n '.mts',\n '.cts',\n '.mjs',\n '.cjs',\n] as const;\nconst DIRECTORY_STAMP_TTL_MS = 250;\nconst MAX_PROBE_CACHE_ENTRIES = 10_000;\n\ninterface TsConfig {\n compilerOptions?: {\n baseUrl?: string;\n paths?: Record<string, string[]>;\n };\n}\n\ninterface Alias {\n prefix: string;\n suffix: string;\n targets: string[];\n}\n\ninterface CachedTsConfig {\n stamp: string | null;\n value: TsConfig;\n}\n\ninterface CachedDirectoryStamp {\n expiresAt: number;\n value: string | null;\n}\n\ninterface CachedProbe {\n candidateDirectory: string | null;\n parentDirectory: string | null;\n resolved: string | null;\n}\n\nconst tsconfigCache = new Map<string, CachedTsConfig>();\nconst directoryStampCache = new Map<string, CachedDirectoryStamp>();\nconst probeCache = new Map<string, CachedProbe>();\n\nexport function createImportResolver(tsconfigPath?: string) {\n const aliases: Alias[] = [];\n let baseUrl = process.cwd();\n if (tsconfigPath) {\n const absoluteConfig = path.resolve(tsconfigPath);\n const config = readTsConfig(absoluteConfig);\n baseUrl = path.resolve(\n path.dirname(absoluteConfig),\n config.compilerOptions?.baseUrl ?? '.',\n );\n for (const [pattern, targets] of Object.entries(\n config.compilerOptions?.paths ?? {},\n )) {\n const star = pattern.indexOf('*');\n aliases.push({\n prefix: star < 0 ? pattern : pattern.slice(0, star),\n suffix: star < 0 ? '' : pattern.slice(star + 1),\n targets,\n });\n }\n }\n\n return (specifier: string, importer: string): string | null => {\n if (specifier === 'virtual:ai-i18n') return specifier;\n if (specifier.startsWith('.')) {\n return probeSource(path.resolve(path.dirname(importer), specifier));\n }\n for (const alias of aliases) {\n if (\n !specifier.startsWith(alias.prefix) ||\n !specifier.endsWith(alias.suffix)\n ) {\n continue;\n }\n const value = specifier.slice(\n alias.prefix.length,\n specifier.length - alias.suffix.length || undefined,\n );\n for (const target of alias.targets) {\n const candidate = target.includes('*')\n ? target.replace('*', value)\n : target;\n const resolved = probeSource(path.resolve(baseUrl, candidate));\n if (resolved) return resolved;\n }\n }\n return null;\n };\n}\n\nfunction probeSource(candidate: string): string | null {\n candidate = path.normalize(candidate);\n const cached = probeCache.get(candidate);\n if (\n cached &&\n cached.parentDirectory === readDirectoryStamp(path.dirname(candidate)) &&\n cached.candidateDirectory === readDirectoryStamp(candidate)\n ) {\n return cached.resolved;\n }\n\n let resolved: string | null = null;\n for (const extension of SOURCE_EXTENSIONS) {\n const file = `${candidate}${extension}`;\n if (isFile(file)) {\n resolved = path.normalize(file);\n break;\n }\n }\n if (!resolved) {\n for (const extension of SOURCE_EXTENSIONS.slice(1)) {\n const file = path.join(candidate, `index${extension}`);\n if (isFile(file)) {\n resolved = path.normalize(file);\n break;\n }\n }\n }\n if (probeCache.size >= MAX_PROBE_CACHE_ENTRIES) probeCache.clear();\n probeCache.set(candidate, {\n parentDirectory: readDirectoryStamp(path.dirname(candidate)),\n candidateDirectory: readDirectoryStamp(candidate),\n resolved,\n });\n return resolved;\n}\n\nfunction isFile(file: string) {\n try {\n return fs.statSync(file).isFile();\n } catch {\n return false;\n }\n}\n\nfunction readTsConfig(filename: string): TsConfig {\n const stamp = readFileStamp(filename);\n const cached = tsconfigCache.get(filename);\n if (cached?.stamp === stamp) return cached.value;\n let value: TsConfig = {};\n try {\n value = JSON.parse(\n stripJsonComments(fs.readFileSync(filename, 'utf8')),\n ) as TsConfig;\n } catch {\n // 无效或不存在的 tsconfig 与未配置路径别名等价。\n }\n tsconfigCache.set(filename, { stamp, value });\n return value;\n}\n\nfunction readFileStamp(filename: string): string | null {\n try {\n const stat = fs.statSync(filename);\n return stat.isFile()\n ? `${stat.mtimeMs}:${stat.ctimeMs}:${stat.size}`\n : null;\n } catch {\n return null;\n }\n}\n\nfunction readDirectoryStamp(directory: string): string | null {\n const now = Date.now();\n const cached = directoryStampCache.get(directory);\n if (cached && cached.expiresAt > now) return cached.value;\n let value: string | null = null;\n try {\n const stat = fs.statSync(directory);\n if (stat.isDirectory()) {\n value = `${stat.mtimeMs}:${stat.ctimeMs}:${stat.size}`;\n }\n } catch {\n // 不存在的目录也要缓存,避免重复的失败探测。\n }\n if (directoryStampCache.size >= MAX_PROBE_CACHE_ENTRIES) {\n directoryStampCache.clear();\n }\n directoryStampCache.set(directory, {\n expiresAt: now + DIRECTORY_STAMP_TTL_MS,\n value,\n });\n return value;\n}\n\nfunction stripJsonComments(source: string): string {\n let result = '';\n let quote = '';\n let escaped = false;\n for (let index = 0; index < source.length; index += 1) {\n const current = source[index]!;\n const next = source[index + 1];\n if (quote) {\n result += current;\n if (escaped) escaped = false;\n else if (current === '\\\\') escaped = true;\n else if (current === quote) quote = '';\n continue;\n }\n if (current === '\"' || current === \"'\") {\n quote = current;\n result += current;\n continue;\n }\n if (current === '/' && next === '/') {\n while (index < source.length && source[index] !== '\\n') index += 1;\n result += '\\n';\n continue;\n }\n if (current === '/' && next === '*') {\n index += 2;\n while (\n index < source.length &&\n !(source[index] === '*' && source[index + 1] === '/')\n ) {\n if (source[index] === '\\n') result += '\\n';\n index += 1;\n }\n index += 1;\n continue;\n }\n result += current;\n }\n return result.replace(/,\\s*([}\\]])/g, '$1');\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport {\n AI_I18N_VIRTUAL_MODULE_ID,\n Analyzer,\n extractMessages,\n findInvalidDefineI18nMessagesReferences,\n findTranslationCalls,\n findUnboundCalls,\n validateRecommendedUsage,\n type Module,\n type ExtractWarningCode,\n type RecommendedUsageCode,\n type AnalysisLanguage,\n type TranslationCall,\n type TranslationHookBinding,\n} from '@ai-i18n/analyzer';\nimport { createImportResolver } from './resolve-import.js';\n\nexport interface StaticArgsWarning {\n code: ExtractWarningCode | RecommendedUsageCode;\n line: number;\n column: number;\n message: string;\n}\n\nexport interface StaticAnalysisResult {\n warnings: StaticArgsWarning[];\n translationCalls: TranslationCall[];\n}\n\nexport type AutoImportApi = 't' | 'useI18n';\nexport type AutoImportOption = boolean | readonly AutoImportApi[];\n\ninterface AutoImportBindings {\n t: boolean;\n useI18n: boolean;\n}\n\nconst POTENTIAL_TRANSLATION_RE =\n /virtual:ai-i18n|\\b(?:t|useI18n|defineI18nMessages)\\b/;\n\nexport function analyzeStaticArgs(\n code: string,\n filename: string,\n tsconfigPath?: string,\n lang?: AnalysisLanguage,\n autoImport: AutoImportOption = false,\n maxStaticCandidates = Number.POSITIVE_INFINITY,\n): StaticArgsWarning[] {\n return analyzeStaticSource(\n code,\n filename,\n tsconfigPath,\n lang,\n autoImport,\n maxStaticCandidates,\n ).warnings;\n}\n\nexport function analyzeStaticSource(\n code: string,\n filename: string,\n tsconfigPath?: string,\n lang?: AnalysisLanguage,\n autoImport: AutoImportOption = false,\n maxStaticCandidates = Number.POSITIVE_INFINITY,\n): StaticAnalysisResult {\n if (!hasPotentialTranslationCandidate(code)) {\n return { warnings: [], translationCalls: [] };\n }\n const autoImports = normalizeAutoImports(autoImport);\n const resolve = createImportResolver(tsconfigPath);\n const analyzer = new Analyzer({ resolve });\n analyzer.addFile(\n AI_I18N_VIRTUAL_MODULE_ID,\n 'export function t(source) { return source }',\n );\n const entryPath = normalizeFilename(filename);\n const entry = analyzer.addFile(entryPath, code, lang ? { lang } : undefined);\n if (!hasTranslationCandidate(entry, autoImports)) {\n return { warnings: [], translationCalls: [] };\n }\n loadDependencies(analyzer, entry, resolve);\n analyzer.link();\n const hooks = translationHooks(autoImports);\n const extraction = extractMessages(\n entry,\n AI_I18N_VIRTUAL_MODULE_ID,\n hooks,\n autoImports.t,\n maxStaticCandidates,\n ).warnings;\n const recommended = validateRecommendedUsage(\n entry,\n AI_I18N_VIRTUAL_MODULE_ID,\n hooks,\n autoImports.t,\n );\n const warnings = recommended.length\n ? [\n ...extraction.filter((warning) => warning.code === 'parse-error'),\n ...extraction.filter(\n (warning) => warning.code === 'static-candidate-limit',\n ),\n ...recommended,\n ]\n : extraction;\n return {\n warnings: warnings.map(({ code: warningCode, line, column, message }) => ({\n code: warningCode,\n line,\n column,\n message,\n })),\n translationCalls: findTranslationCalls(\n entry,\n AI_I18N_VIRTUAL_MODULE_ID,\n hooks,\n autoImports.t,\n ),\n };\n}\n\nexport function hasPotentialTranslationCandidate(code: string): boolean {\n return POTENTIAL_TRANSLATION_RE.test(code);\n}\n\nexport function normalizeAutoImports(\n autoImport: AutoImportOption | undefined,\n): AutoImportBindings {\n if (typeof autoImport === 'boolean') {\n return { t: autoImport, useI18n: autoImport };\n }\n return {\n t: autoImport?.includes('t') ?? false,\n useI18n: autoImport?.includes('useI18n') ?? false,\n };\n}\n\nfunction hasTranslationCandidate(\n module: Module,\n autoImports: AutoImportBindings,\n): boolean {\n const unbound = ['defineI18nMessages'];\n if (autoImports.t) unbound.push('t');\n if (autoImports.useI18n) unbound.push('useI18n');\n return (\n module.imports.some(\n (item) =>\n !item.typeOnly &&\n (item.specifier === AI_I18N_VIRTUAL_MODULE_ID ||\n item.name === 't' ||\n item.name === 'useI18n'),\n ) ||\n findInvalidDefineI18nMessagesReferences(module).length > 0 ||\n findUnboundCalls(module, new Set(unbound)).length > 0\n );\n}\n\nfunction translationHooks(\n autoImports: AutoImportBindings,\n): readonly TranslationHookBinding[] {\n return [\n {\n module: AI_I18N_VIRTUAL_MODULE_ID,\n hook: 'useI18n',\n property: 't',\n autoImport: autoImports.useI18n,\n },\n ];\n}\n\nfunction loadDependencies(\n analyzer: Analyzer,\n entry: Module,\n resolve: (specifier: string, importer: string) => string | null,\n) {\n const queue = [entry];\n const visited = new Set<string>();\n while (queue.length) {\n const module = queue.shift()!;\n if (visited.has(module.path)) continue;\n visited.add(module.path);\n for (const item of module.imports) {\n const resolved = resolve(item.specifier, module.path);\n if (!resolved || resolved === AI_I18N_VIRTUAL_MODULE_ID) continue;\n let dependency = analyzer.module(resolved);\n if (!dependency) {\n try {\n dependency = analyzer.addFile(\n resolved,\n fs.readFileSync(resolved, 'utf8'),\n );\n } catch {\n continue;\n }\n }\n queue.push(dependency);\n }\n }\n}\n\nfunction normalizeFilename(filename: string) {\n return filename.startsWith('<')\n ? path.resolve('eslint-input.ts')\n : path.resolve(filename);\n}\n","import { createRequire } from 'node:module';\nimport path from 'node:path';\nimport { diagnosticMessage } from '@ai-i18n/analyzer';\nimport {\n analyzeVueSource,\n type VueAnalysisSource,\n type VueCompiler,\n} from '@ai-i18n/analyzer/vue';\n\ninterface VueParserServices {\n getDocumentFragment?: () => unknown;\n}\n\ntype Require = ReturnType<typeof createRequire>;\ntype NodeVueCompiler = VueCompiler & {\n registerTS?: (loadTypeScript: () => unknown) => void;\n};\n\nconst packageRequire = createRequire(import.meta.url);\n\nexport function createVueAnalysisSource(\n source: string,\n filename: string,\n parserServices: VueParserServices,\n): VueAnalysisSource {\n if (!parserServices.getDocumentFragment?.()) {\n throw new Error(\n diagnosticMessage(\n '检查 .vue 文件需要配置 vue-eslint-parser。',\n 'Configure vue-eslint-parser to lint .vue files.',\n ),\n );\n }\n\n try {\n // Vue preset 真正处理 SFC 时才加载编译器,不影响 React/Vanilla 项目。\n const compiler = loadVueCompiler(filename);\n return analyzeVueSource(source, filename, compiler);\n } catch (error) {\n if (isMissingVueCompiler(error)) {\n throw new Error(\n diagnosticMessage(\n '检查 .vue 文件需要安装 @vue/compiler-sfc。',\n 'Install @vue/compiler-sfc to lint .vue files.',\n ),\n );\n }\n throw error;\n }\n}\n\nfunction loadVueCompiler(filename: string): VueCompiler {\n const hostRequire = createRequire(path.resolve(filename));\n // 优先复用宿主 Vue 的 Node wrapper,它会为 imported types 注册 TypeScript。\n const compiler = (tryRequire(hostRequire, 'vue/compiler-sfc') ??\n tryRequire(packageRequire, 'vue/compiler-sfc') ??\n tryRequire(hostRequire, '@vue/compiler-sfc') ??\n packageRequire('@vue/compiler-sfc')) as NodeVueCompiler;\n compiler.registerTS?.(() => {\n const typescript =\n tryResolve(hostRequire, 'typescript') ??\n tryResolve(packageRequire, 'typescript');\n return packageRequire(typescript ?? 'typescript');\n });\n return compiler;\n}\n\nfunction tryRequire(require: Require, id: string): unknown {\n const resolved = tryResolve(require, id);\n return resolved ? require(resolved) : null;\n}\n\nfunction tryResolve(require: Require, id: string): string | null {\n try {\n return require.resolve(id);\n } catch (error) {\n if (isMissingVueCompiler(error)) return null;\n throw error;\n }\n}\n\nfunction isMissingVueCompiler(error: unknown): boolean {\n return (\n error instanceof Error &&\n 'code' in error &&\n (error.code === 'MODULE_NOT_FOUND' ||\n error.code === 'ERR_PACKAGE_PATH_NOT_EXPORTED')\n );\n}\n","import type { Rule } from 'eslint';\nimport {\n analyzeStaticSource,\n hasPotentialTranslationCandidate,\n normalizeAutoImports,\n type AutoImportOption,\n type StaticAnalysisResult,\n type StaticArgsWarning,\n} from './analyze.js';\nimport { diagnosticMessage, type TranslationCall } from '@ai-i18n/analyzer';\nimport { createVueAnalysisSource } from './vue-sfc.js';\n\ninterface RuleAnalysisOptions {\n tsconfigPath?: string;\n autoImport?: AutoImportOption;\n}\n\ninterface CachedAnalysis {\n source: ReturnType<typeof createAnalysisSource>;\n analyses: Map<string, StaticAnalysisResult>;\n}\n\nconst DEFAULT_CANDIDATE_LIMIT = 1_000;\nconst cache = new WeakMap<object, CachedAnalysis>();\nconst reportedAnalysisFailures = new WeakSet<object>();\nconst EMPTY_ANALYSIS: StaticAnalysisResult = {\n warnings: [],\n translationCalls: [],\n};\n\nexport function analyzeRuleContext(\n context: Rule.RuleContext,\n options: RuleAnalysisOptions,\n maxStaticCandidates = Number.POSITIVE_INFINITY,\n): StaticArgsWarning[] {\n return analyzeRuleContextResult(context, options, maxStaticCandidates)\n .warnings;\n}\n\nexport function analyzeTranslationCalls(\n context: Rule.RuleContext,\n options: RuleAnalysisOptions,\n): TranslationCall[] {\n return analyzeRuleContextResult(context, options, DEFAULT_CANDIDATE_LIMIT)\n .translationCalls;\n}\n\nexport function reportAnalysisFailureOnce(\n context: Rule.RuleContext,\n node: Rule.Node,\n error: unknown,\n): void {\n if (reportedAnalysisFailures.has(context.sourceCode)) return;\n reportedAnalysisFailures.add(context.sourceCode);\n const detail = error instanceof Error ? error.message : String(error);\n context.report({\n node,\n message: diagnosticMessage(\n `静态分析失败:${detail}`,\n `Static analysis failed: ${detail}`,\n ),\n });\n}\n\nfunction analyzeRuleContextResult(\n context: Rule.RuleContext,\n options: RuleAnalysisOptions,\n maxStaticCandidates: number,\n): StaticAnalysisResult {\n if (!hasPotentialTranslationCandidate(context.sourceCode.text)) {\n return EMPTY_ANALYSIS;\n }\n const cached: CachedAnalysis = cache.get(context.sourceCode) ?? {\n source: createAnalysisSource(context),\n analyses: new Map<string, StaticAnalysisResult>(),\n };\n cache.set(context.sourceCode, cached);\n\n const analyze = (limit: number) => {\n const autoImports = normalizeAutoImports(options.autoImport);\n const key = JSON.stringify([\n options.tsconfigPath ?? null,\n autoImports.t,\n autoImports.useI18n,\n limit,\n ]);\n const existing = cached.analyses.get(key);\n if (existing) return existing;\n const result = analyzeStaticSource(\n cached.source.code,\n context.filename,\n options.tsconfigPath,\n cached.source.lang,\n options.autoImport,\n limit,\n );\n const analysis = {\n warnings: result.warnings.map((warning) => ({\n ...warning,\n ...cached.source.mapLocation(warning),\n })),\n translationCalls: result.translationCalls.map((call) => ({\n ...call,\n ...cached.source.mapLocation(call),\n })),\n };\n cached.analyses.set(key, analysis);\n return analysis;\n };\n\n if (Number.isFinite(maxStaticCandidates)) {\n return analyze(maxStaticCandidates);\n }\n const preflight = analyze(DEFAULT_CANDIDATE_LIMIT);\n return preflight.warnings.some(\n (warning) => warning.code === 'static-candidate-limit',\n )\n ? analyze(Number.POSITIVE_INFINITY)\n : preflight;\n}\n\nfunction createAnalysisSource(context: Rule.RuleContext) {\n return context.filename.endsWith('.vue')\n ? createVueAnalysisSource(\n context.sourceCode.text,\n context.filename,\n context.sourceCode.parserServices,\n )\n : {\n code: context.sourceCode.text,\n lang: undefined,\n mapLocation: (location: { line: number; column: number }) => location,\n };\n}\n","import type { TranslationCall } from '@ai-i18n/analyzer';\nimport type { Rule } from 'eslint';\nimport type { AutoImportOption } from '../analyze.js';\nimport { analyzeTranslationCalls } from '../rule-analysis.js';\n\nexport interface TranslationRuleOptions {\n tsconfigPath?: string;\n autoImport?: AutoImportOption;\n}\n\nexport interface TranslationCandidate {\n kind: TranslationCall['kind'];\n node: Rule.Node;\n}\n\nexport interface MatchedTranslationCall extends TranslationCandidate {\n call: TranslationCall;\n}\n\nexport function matchTranslationCalls(\n context: Rule.RuleContext,\n options: TranslationRuleOptions,\n candidates: readonly TranslationCandidate[],\n): MatchedTranslationCall[] {\n const calls = new Map(\n analyzeTranslationCalls(context, options).map((call) => [\n locationKey(call.line, call.column, call.kind),\n call,\n ]),\n );\n return candidates.flatMap((candidate) => {\n const location = candidate.node.loc?.start;\n if (!location) return [];\n const call = calls.get(\n locationKey(location.line, location.column, candidate.kind),\n );\n return call ? [{ ...candidate, call }] : [];\n });\n}\n\nfunction locationKey(\n line: number,\n column: number,\n kind: TranslationCall['kind'],\n): string {\n return `${kind}:${line}:${column}`;\n}\n","import { diagnosticMessage } from '@ai-i18n/analyzer';\nimport type { Rule } from 'eslint';\nimport { reportAnalysisFailureOnce } from '../rule-analysis.js';\nimport {\n matchTranslationCalls,\n type TranslationCandidate,\n type TranslationRuleOptions,\n} from './translation-call.js';\n\nconst FUNCTION_TYPES = new Set([\n 'ArrowFunctionExpression',\n 'FunctionDeclaration',\n 'FunctionExpression',\n]);\n\nexport const noEagerTranslation: Rule.RuleModule = {\n meta: {\n type: 'problem',\n docs: {\n description: '警告不会随语言切换更新的提前求值翻译结果',\n },\n schema: [\n {\n type: 'object',\n properties: {\n tsconfigPath: { type: 'string' },\n autoImport: {\n anyOf: [\n { type: 'boolean' },\n {\n type: 'array',\n items: { enum: ['t', 'useI18n'] },\n uniqueItems: true,\n },\n ],\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n eagerTranslation: diagnosticMessage(\n '初始化期间保存的 t() 结果不会随语言切换更新。请改为函数或 Getter,在使用时调用 t();组件视图请使用 useI18n()。',\n 'A t() result stored during initialization will not update when the language changes. Evaluate it lazily in a function or getter; use useI18n() in component views.',\n ),\n },\n },\n create(context) {\n const options = (context.options[0] ?? {}) as TranslationRuleOptions;\n const isVueSfc = context.filename.toLowerCase().endsWith('.vue');\n const candidates: TranslationCandidate[] = [];\n return {\n CallExpression(node) {\n candidates.push({ kind: 'call', node });\n },\n TaggedTemplateExpression(node) {\n candidates.push({ kind: 'tagged-template', node });\n },\n 'Program:exit'(program) {\n let matches;\n try {\n matches = matchTranslationCalls(context, options, candidates);\n } catch (error) {\n reportAnalysisFailureOnce(context, program as Rule.Node, error);\n return;\n }\n for (const { node } of matches) {\n if (!storesOutsideFunction(node, context, isVueSfc)) continue;\n context.report({ node, messageId: 'eagerTranslation' });\n }\n },\n };\n },\n};\n\nfunction storesOutsideFunction(\n node: Rule.Node,\n context: Rule.RuleContext,\n isVueSfc: boolean,\n): boolean {\n let current = node as ParentNode;\n let storesResult = false;\n while (current.parent) {\n const parent = current.parent;\n if (FUNCTION_TYPES.has(parent.type)) {\n // 普通 setup() 与 <script setup> 一样只执行一次;其他函数仍视为延迟求值。\n const returnsExpression =\n parent.type === 'ArrowFunctionExpression' && parent.body === current;\n return (\n isVueComponentSetup(parent, context, isVueSfc) &&\n (storesResult || returnsExpression)\n );\n }\n if (storesTranslationResult(parent, current)) storesResult = true;\n if (parent.type === 'Program') return storesResult;\n current = parent;\n }\n return storesResult;\n}\n\nfunction isVueComponentSetup(\n node: ParentNode,\n context: Rule.RuleContext,\n isVueSfc: boolean,\n): boolean {\n const directOwner = node.parent;\n if (\n directOwner?.type === 'CallExpression' &&\n directOwner.arguments?.[0] === node\n ) {\n return isImportedDefineComponent(directOwner.callee, context);\n }\n\n const property = node.parent;\n if (\n property?.type !== 'Property' ||\n property.value !== node ||\n property.computed ||\n propertyName(property.key) !== 'setup'\n ) {\n return false;\n }\n\n const options = property.parent;\n if (options?.type !== 'ObjectExpression') return false;\n const owner = options.parent;\n if (\n isVueSfc &&\n owner?.type === 'ExportDefaultDeclaration' &&\n owner.declaration === options\n ) {\n return true;\n }\n return (\n owner?.type === 'CallExpression' &&\n owner.arguments?.[0] === options &&\n isImportedDefineComponent(owner.callee, context)\n );\n}\n\nfunction propertyName(node: unknown): string | undefined {\n const key = node as { name?: string; type?: string; value?: unknown };\n if (key?.type === 'Identifier') return key.name;\n return key?.type === 'Literal' && typeof key.value === 'string'\n ? key.value\n : undefined;\n}\n\nfunction isImportedDefineComponent(\n node: unknown,\n context: Rule.RuleContext,\n): boolean {\n const callee = node as {\n computed?: boolean;\n name?: string;\n object?: unknown;\n property?: unknown;\n type?: string;\n };\n if (callee?.type === 'Identifier') {\n return isVueImport(callee, context, 'ImportSpecifier');\n }\n return (\n callee?.type === 'MemberExpression' &&\n !callee.computed &&\n propertyName(callee.property) === 'defineComponent' &&\n isVueImport(callee.object, context, 'ImportNamespaceSpecifier')\n );\n}\n\nfunction isVueImport(\n node: unknown,\n context: Rule.RuleContext,\n specifierType: 'ImportNamespaceSpecifier' | 'ImportSpecifier',\n): boolean {\n const identifier = node as Rule.Node & { name?: string };\n if (identifier?.type !== 'Identifier' || !identifier.name) return false;\n\n let scope = context.sourceCode.getScope(identifier);\n while (true) {\n const variable = scope.set.get(identifier.name);\n if (!variable) {\n if (!scope.upper) return false;\n scope = scope.upper;\n continue;\n }\n return variable.defs.some((definition) => {\n if (\n definition.type !== 'ImportBinding' ||\n definition.node.type !== specifierType ||\n definition.parent.source.value !== 'vue'\n ) {\n return false;\n }\n return (\n specifierType === 'ImportNamespaceSpecifier' ||\n propertyName((definition.node as { imported?: unknown }).imported) ===\n 'defineComponent'\n );\n });\n }\n}\n\nfunction storesTranslationResult(\n parent: ParentNode,\n child: ParentNode,\n): boolean {\n if (\n (parent as { type: string }).type === 'AccessorProperty' &&\n parent.value === child\n ) {\n return true;\n }\n switch (parent.type) {\n case 'VariableDeclarator':\n return parent.init === child;\n case 'AssignmentExpression':\n case 'AssignmentPattern':\n return parent.right === child;\n case 'PropertyDefinition':\n return parent.value === child;\n case 'ReturnStatement':\n return parent.argument === child;\n case 'ExportDefaultDeclaration':\n return parent.declaration === child;\n default:\n return false;\n }\n}\n\ntype ParentNode = Rule.Node & {\n arguments?: unknown[];\n argument?: unknown;\n body?: unknown;\n callee?: unknown;\n computed?: boolean;\n parent: ParentNode | null;\n declaration?: unknown;\n init?: unknown;\n key?: unknown;\n right?: unknown;\n value?: unknown;\n};\n","import { diagnosticMessage } from '@ai-i18n/analyzer';\nimport type { Rule } from 'eslint';\nimport { reportAnalysisFailureOnce } from '../rule-analysis.js';\nimport {\n matchTranslationCalls,\n type TranslationCandidate,\n type TranslationRuleOptions,\n} from './translation-call.js';\n\nconst FUNCTION_TYPES = new Set([\n 'ArrowFunctionExpression',\n 'FunctionDeclaration',\n 'FunctionExpression',\n]);\nconst IMMEDIATE_CONSOLE_METHODS = new Set([\n 'debug',\n 'error',\n 'info',\n 'log',\n 'warn',\n]);\n\nexport const noUnsubscribedT: Rule.RuleModule = {\n meta: {\n type: 'problem',\n docs: {\n description: '警告组件渲染路径中未订阅语言状态的顶层 t',\n },\n schema: [\n {\n type: 'object',\n properties: {\n tsconfigPath: { type: 'string' },\n autoImport: {\n anyOf: [\n { type: 'boolean' },\n {\n type: 'array',\n items: { enum: ['t', 'useI18n'] },\n uniqueItems: true,\n },\n ],\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n unsubscribedT: diagnosticMessage(\n '组件渲染期间使用顶层 t 不会订阅语言状态,语言切换不会主动刷新,缓存的渲染结果也可能继续使用旧译文。请使用 useI18n() 返回的 t。',\n 'Top-level t does not subscribe the component to language updates, so language changes do not trigger a render and cached render results may remain stale. Use the t returned by useI18n().',\n ),\n },\n },\n create(context) {\n const options = (context.options[0] ?? {}) as TranslationRuleOptions;\n const candidates: TranslationCandidate[] = [];\n const jsxOwners = new Set<ParentNode>();\n const templateNodes = new Set<Rule.Node>();\n const collectJsxOwner = (node: Rule.Node) => {\n const owner = nearestFunction(node);\n if (owner) jsxOwners.add(owner);\n };\n const scriptVisitor: Rule.RuleListener = {\n CallExpression(node) {\n candidates.push({ kind: 'call', node });\n },\n TaggedTemplateExpression(node) {\n candidates.push({ kind: 'tagged-template', node });\n },\n JSXElement: collectJsxOwner,\n JSXFragment: collectJsxOwner,\n 'Program:exit'(program) {\n let matches;\n try {\n matches = matchTranslationCalls(context, options, candidates);\n } catch (error) {\n reportAnalysisFailureOnce(context, program as Rule.Node, error);\n return;\n }\n for (const { call, node } of matches) {\n if (call.origin !== 'runtime') continue;\n if (templateNodes.has(node)) {\n if (!isVueTemplateEventHandler(node)) {\n context.report({ node, messageId: 'unsubscribedT' });\n }\n continue;\n }\n // ponytail: 先检查直接拥有 JSX 的最近函数;出现真实漏报后再引入调用图与框架数据流。\n const owner = nearestFunction(node);\n if (\n !owner ||\n !jsxOwners.has(owner) ||\n isImmediateConsoleEffect(node)\n ) {\n continue;\n }\n context.report({ node, messageId: 'unsubscribedT' });\n }\n },\n };\n const parserServices = context.sourceCode\n .parserServices as VueParserServices;\n if (!parserServices.defineTemplateBodyVisitor) return scriptVisitor;\n return parserServices.defineTemplateBodyVisitor(\n {\n CallExpression(node) {\n candidates.push({ kind: 'call', node });\n templateNodes.add(node);\n },\n TaggedTemplateExpression(node) {\n candidates.push({ kind: 'tagged-template', node });\n templateNodes.add(node);\n },\n },\n scriptVisitor,\n // 模板默认在 Program:exit 才遍历;提前到 Program,确保汇总前已收集候选。\n { templateBodyTriggerSelector: 'Program' },\n );\n },\n};\n\nfunction nearestFunction(node: Rule.Node): ParentNode | null {\n let current = node as ParentNode;\n while (current.parent) {\n current = current.parent;\n if (FUNCTION_TYPES.has(current.type)) return current;\n }\n return null;\n}\n\nfunction isImmediateConsoleEffect(node: Rule.Node): boolean {\n const call = (node as ParentNode).parent;\n if (\n call?.type !== 'CallExpression' ||\n call.parent?.type !== 'ExpressionStatement' ||\n !call.arguments.some((argument) => argument === node) ||\n call.callee.type !== 'MemberExpression' ||\n call.callee.object.type !== 'Identifier' ||\n call.callee.object.name !== 'console'\n ) {\n return false;\n }\n const property = call.callee.property;\n const method =\n !call.callee.computed && property.type === 'Identifier'\n ? property.name\n : call.callee.computed &&\n property.type === 'Literal' &&\n typeof property.value === 'string'\n ? property.value\n : null;\n return method !== null && IMMEDIATE_CONSOLE_METHODS.has(method);\n}\n\nfunction isVueTemplateEventHandler(node: Rule.Node): boolean {\n let current = node as unknown as TemplateParentNode;\n while (current.parent) {\n current = current.parent;\n if (current.type === 'VOnExpression') return true;\n }\n return false;\n}\n\ntype ParentNode = Rule.Node & {\n parent: ParentNode | null;\n};\n\ninterface TemplateParentNode {\n type: string;\n parent: TemplateParentNode | null;\n}\n\ninterface VueParserServices {\n defineTemplateBodyVisitor?(\n templateBodyVisitor: Record<string, (node: Rule.Node) => void>,\n scriptVisitor: Rule.RuleListener,\n options: { templateBodyTriggerSelector: 'Program' | 'Program:exit' },\n ): Rule.RuleListener;\n}\n","import type { Rule } from 'eslint';\nimport type { AutoImportOption } from '../analyze.js';\nimport {\n analyzeRuleContext,\n reportAnalysisFailureOnce,\n} from '../rule-analysis.js';\n\ninterface RuleOptions {\n tsconfigPath?: string;\n autoImport?: AutoImportOption;\n maxStaticCandidates?: number;\n}\n\nexport const staticCandidateLimit: Rule.RuleModule = {\n meta: {\n type: 'suggestion',\n docs: {\n description: '警告单个 t() 展开的静态候选数量过多',\n },\n schema: [\n {\n type: 'object',\n properties: {\n tsconfigPath: { type: 'string' },\n autoImport: {\n anyOf: [\n { type: 'boolean' },\n {\n type: 'array',\n items: { enum: ['t', 'useI18n'] },\n uniqueItems: true,\n },\n ],\n },\n maxStaticCandidates: {\n type: 'integer',\n minimum: 1,\n maximum: Number.MAX_SAFE_INTEGER,\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n candidateLimit: '{{reason}}',\n },\n },\n create(context) {\n const options = (context.options[0] ?? {}) as RuleOptions;\n return {\n 'Program:exit'(node) {\n try {\n const warnings = analyzeRuleContext(\n context,\n options,\n options.maxStaticCandidates ?? 1_000,\n );\n for (const warning of warnings) {\n if (warning.code !== 'static-candidate-limit') continue;\n context.report({\n node,\n loc: {\n start: warning,\n end: { line: warning.line, column: warning.column + 1 },\n },\n messageId: 'candidateLimit',\n data: { reason: warning.message },\n });\n }\n } catch (error) {\n reportAnalysisFailureOnce(context, node as Rule.Node, error);\n }\n },\n };\n },\n};\n","import type { Rule } from 'eslint';\nimport { diagnosticMessage } from '@ai-i18n/analyzer';\nimport { normalizeAutoImports, type AutoImportOption } from '../analyze.js';\nimport {\n analyzeRuleContext,\n reportAnalysisFailureOnce,\n} from '../rule-analysis.js';\n\ninterface RuleOptions {\n tsconfigPath?: string;\n autoImport?: AutoImportOption;\n}\n\ninterface AstNode {\n type: string;\n name?: string;\n importKind?: string;\n range?: [number, number];\n argument?: AstNode;\n left?: AstNode;\n elements?: Array<AstNode | null>;\n properties?: AstNode[];\n value?: AstNode;\n id?: AstNode;\n declarations?: AstNode[];\n specifiers?: AstNode[];\n local?: AstNode;\n declaration?: AstNode | null;\n body?: AstNode[];\n parent?: AstNode | null;\n}\n\ninterface VueElement extends AstNode {\n startTag?: {\n attributes?: Array<{\n directive?: boolean;\n key?: { name?: string };\n }>;\n };\n}\n\ninterface VueDocument {\n children?: AstNode[];\n}\n\ninterface VueParserServices {\n defineTemplateBodyVisitor?: (\n templateVisitor: Record<string, (node: AstNode) => void>,\n scriptVisitor: Rule.RuleListener,\n ) => Rule.RuleListener;\n getDocumentFragment?: () => VueDocument | null;\n}\n\ninterface VueReference {\n id?: AstNode;\n variable?: unknown;\n}\n\nexport const tStaticArgs: Rule.RuleModule = {\n meta: {\n type: 'problem',\n docs: {\n description: '要求 virtual:ai-i18n 的 t() 参数可被静态提取',\n },\n schema: [\n {\n type: 'object',\n properties: {\n tsconfigPath: { type: 'string' },\n autoImport: {\n anyOf: [\n { type: 'boolean' },\n {\n type: 'array',\n items: { enum: ['t', 'useI18n'] },\n uniqueItems: true,\n },\n ],\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n analysisFailed: '{{reason}}',\n dynamicArg: '{{reason}}',\n invalidUsage: '{{reason}}',\n templateNeedsI18n: '{{reason}}',\n },\n },\n create(context) {\n const options = (context.options[0] ?? {}) as RuleOptions;\n const scriptVisitor: Rule.RuleListener = {\n 'Program:exit'(node) {\n let warnings;\n try {\n warnings = analyzeRuleContext(context, options);\n } catch (error) {\n reportAnalysisFailureOnce(context, node as Rule.Node, error);\n return;\n }\n for (const warning of warnings) {\n const analysisFailed = warning.code === 'parse-error';\n const invalidUsage =\n warning.code !== 'dynamic-argument' &&\n warning.code !== 'unresolved-argument' &&\n !analysisFailed;\n context.report({\n node,\n loc: {\n start: warning,\n end: { line: warning.line, column: warning.column + 1 },\n },\n messageId: analysisFailed\n ? 'analysisFailed'\n : invalidUsage\n ? 'invalidUsage'\n : 'dynamicArg',\n data: {\n reason: analysisFailed\n ? diagnosticMessage(\n `静态分析失败:${warning.message}`,\n `Static analysis failed: ${warning.message}`,\n )\n : invalidUsage\n ? warning.message\n : diagnosticMessage(\n 't() 的参数无法静态提取。source 请使用静态字符串,options 请使用只包含 comment 的静态对象。',\n 'The t() arguments cannot be statically extracted. Use a static string for source and a static object containing only comment for options.',\n ),\n },\n });\n }\n },\n };\n\n if (\n !context.filename.toLowerCase().endsWith('.vue') ||\n !normalizeAutoImports(options.autoImport).t\n ) {\n return scriptVisitor;\n }\n const services = context.sourceCode\n .parserServices as unknown as VueParserServices;\n const document = services.getDocumentFragment?.();\n const scripts = document?.children?.filter(isScriptElement) ?? [];\n const setupScript = scripts.find(isScriptSetup);\n // 普通 Options API 的模板可从组件实例获得 t,无法仅凭 SFC 静态确认来源。\n if ((!setupScript && scripts.length > 0) || !document) {\n return scriptVisitor;\n }\n if (\n setupScript &&\n hasTopLevelBinding(\n context.sourceCode.ast as unknown as AstNode,\n setupScript,\n 't',\n )\n ) {\n return scriptVisitor;\n }\n if (!services.defineTemplateBodyVisitor) return scriptVisitor;\n\n const reportTemplateT = (node: AstNode) => {\n const target =\n node.type === 'CallExpression'\n ? (node as AstNode & { callee?: AstNode }).callee\n : (node as AstNode & { tag?: AstNode }).tag;\n if (\n target?.type !== 'Identifier' ||\n target.name !== 't' ||\n isTemplateLocal(target)\n ) {\n return;\n }\n context.report({\n node: target as Rule.Node,\n messageId: 'templateNeedsI18n',\n data: {\n reason: diagnosticMessage(\n '模板中的裸 t 无法绑定到 ai-i18n,也不会订阅语言变化。请在 <script setup> 中声明 const { t } = useI18n()。',\n 'A bare t in the template is not bound to ai-i18n and does not subscribe to language changes. Declare const { t } = useI18n() in <script setup>.',\n ),\n },\n });\n };\n return services.defineTemplateBodyVisitor(\n {\n CallExpression: reportTemplateT,\n TaggedTemplateExpression: reportTemplateT,\n },\n scriptVisitor,\n );\n },\n};\n\nfunction isScriptElement(node: AstNode): node is VueElement {\n return node.type === 'VElement' && node.name === 'script';\n}\n\nfunction isScriptSetup(node: VueElement): boolean {\n return (\n node.startTag?.attributes?.some(\n (attribute) => !attribute.directive && attribute.key?.name === 'setup',\n ) ?? false\n );\n}\n\nfunction hasTopLevelBinding(\n program: AstNode,\n script: VueElement,\n name: string,\n): boolean {\n return (\n program.body?.some(\n (statement) =>\n isInside(statement, script) && statementDeclares(statement, name),\n ) ?? false\n );\n}\n\nfunction isInside(node: AstNode, container: AstNode): boolean {\n return Boolean(\n node.range &&\n container.range &&\n node.range[0] >= container.range[0] &&\n node.range[1] <= container.range[1],\n );\n}\n\nfunction statementDeclares(node: AstNode, name: string): boolean {\n switch (node.type) {\n case 'ImportDeclaration':\n return (\n node.importKind !== 'type' &&\n (node.specifiers?.some(\n (item) => item.importKind !== 'type' && item.local?.name === name,\n ) ??\n false)\n );\n case 'VariableDeclaration':\n return (\n node.declarations?.some((item) => patternDeclares(item.id, name)) ??\n false\n );\n case 'FunctionDeclaration':\n case 'ClassDeclaration':\n case 'TSEnumDeclaration':\n case 'TSImportEqualsDeclaration':\n return node.id?.name === name;\n case 'ExportNamedDeclaration':\n case 'ExportDefaultDeclaration':\n return node.declaration\n ? statementDeclares(node.declaration, name)\n : false;\n default:\n return false;\n }\n}\n\nfunction patternDeclares(node: AstNode | undefined, name: string): boolean {\n if (!node) return false;\n switch (node.type) {\n case 'Identifier':\n return node.name === name;\n case 'RestElement':\n return patternDeclares(node.argument, name);\n case 'AssignmentPattern':\n return patternDeclares(node.left, name);\n case 'ArrayPattern':\n return (\n node.elements?.some((item) =>\n patternDeclares(item ?? undefined, name),\n ) ?? false\n );\n case 'ObjectPattern':\n return (\n node.properties?.some((item) =>\n patternDeclares(\n item.type === 'RestElement' ? item.argument : item.value,\n name,\n ),\n ) ?? false\n );\n default:\n return false;\n }\n}\n\nfunction isTemplateLocal(node: AstNode): boolean {\n let parent = node.parent;\n while (parent && parent.type !== 'VExpressionContainer') {\n parent = parent.parent;\n }\n const references = (\n parent as (AstNode & { references?: VueReference[] }) | null | undefined\n )?.references;\n return (\n references?.some(\n (reference) =>\n reference.variable &&\n (reference.id === node ||\n (reference.id?.range?.[0] === node.range?.[0] &&\n reference.id?.range?.[1] === node.range?.[1])),\n ) ?? false\n );\n}\n","import { createRequire } from 'node:module';\nimport type { ESLint } from 'eslint';\nimport { noEagerTranslation } from './rules/no-eager-translation.js';\nimport { noUnsubscribedT } from './rules/no-unsubscribed-t.js';\nimport { staticCandidateLimit } from './rules/static-candidate-limit.js';\nimport { tStaticArgs } from './rules/t-static-args.js';\n\nconst { version } = createRequire(import.meta.url)('../package.json') as {\n version: string;\n};\n\nconst plugin: ESLint.Plugin = {\n meta: {\n name: '@ai-i18n/eslint-plugin',\n version,\n namespace: 'ai-i18n',\n },\n rules: {\n 'no-eager-translation': noEagerTranslation,\n 'no-unsubscribed-t': noUnsubscribedT,\n 'static-candidate-limit': staticCandidateLimit,\n 't-static-args': tStaticArgs,\n },\n configs: {},\n};\n\n// 规则集必须由使用者显式引入,不会修改宿主项目的 ESLint 配置。\nplugin.configs!.recommended = [\n {\n ignores: ['**/*.vue'],\n plugins: { 'ai-i18n': plugin },\n languageOptions: {\n globals: { defineI18nMessages: 'readonly' },\n },\n rules: {\n 'ai-i18n/t-static-args': 'error',\n 'ai-i18n/no-eager-translation': 'warn',\n 'ai-i18n/no-unsubscribed-t': 'warn',\n 'ai-i18n/static-candidate-limit': 'warn',\n },\n },\n];\n\nplugin.configs!.vue = [\n {\n files: ['**/*.{js,mjs,cjs,ts,mts,cts,jsx,tsx,vue}'],\n plugins: { 'ai-i18n': plugin },\n languageOptions: {\n globals: { defineI18nMessages: 'readonly' },\n },\n rules: {\n 'ai-i18n/t-static-args': 'error',\n 'ai-i18n/no-eager-translation': 'warn',\n 'ai-i18n/no-unsubscribed-t': 'warn',\n 'ai-i18n/static-candidate-limit': 'warn',\n },\n },\n];\n\n// 自动导入 preset 必须与 Vite 各模式实际注入的 API 一一对应。\nplugin.configs!['vanilla-auto-import'] = [\n {\n files: ['**/*.{js,mjs,cjs,ts,mts,cts}'],\n plugins: { 'ai-i18n': plugin },\n languageOptions: {\n globals: {\n t: 'readonly',\n setLang: 'readonly',\n getLang: 'readonly',\n getLangs: 'readonly',\n getLangLoadState: 'readonly',\n subscribe: 'readonly',\n defineI18nMessages: 'readonly',\n },\n },\n rules: {\n 'ai-i18n/t-static-args': ['error', { autoImport: ['t'] }],\n 'ai-i18n/no-eager-translation': ['warn', { autoImport: ['t'] }],\n 'ai-i18n/static-candidate-limit': ['warn', { autoImport: ['t'] }],\n },\n },\n];\n\nplugin.configs!['vue-auto-import'] = [\n {\n files: ['**/*.{js,mjs,cjs,ts,mts,cts,jsx,tsx,vue}'],\n plugins: { 'ai-i18n': plugin },\n languageOptions: {\n globals: {\n t: 'readonly',\n useI18n: 'readonly',\n defineI18nMessages: 'readonly',\n },\n },\n rules: {\n 'ai-i18n/t-static-args': ['error', { autoImport: ['t', 'useI18n'] }],\n 'ai-i18n/no-eager-translation': [\n 'warn',\n { autoImport: ['t', 'useI18n'] },\n ],\n 'ai-i18n/no-unsubscribed-t': ['warn', { autoImport: ['t', 'useI18n'] }],\n 'ai-i18n/static-candidate-limit': [\n 'warn',\n { autoImport: ['t', 'useI18n'] },\n ],\n },\n },\n];\n\nplugin.configs!['react-auto-import'] = [\n {\n files: ['**/*.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],\n plugins: { 'ai-i18n': plugin },\n languageOptions: {\n globals: {\n t: 'readonly',\n useI18n: 'readonly',\n defineI18nMessages: 'readonly',\n },\n },\n rules: {\n 'ai-i18n/t-static-args': ['error', { autoImport: ['t', 'useI18n'] }],\n 'ai-i18n/no-eager-translation': [\n 'warn',\n { autoImport: ['t', 'useI18n'] },\n ],\n 'ai-i18n/no-unsubscribed-t': ['warn', { autoImport: ['t', 'useI18n'] }],\n 'ai-i18n/static-candidate-limit': [\n 'warn',\n { autoImport: ['t', 'useI18n'] },\n ],\n },\n },\n];\n\nexport {\n noEagerTranslation,\n noUnsubscribedT,\n staticCandidateLimit,\n tStaticArgs,\n};\nexport default plugin;\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["FUNCTION_TYPES"],"sources":["../src/resolve-import.ts","../src/analyze.ts","../src/vue-sfc.ts","../src/rule-analysis.ts","../src/rules/translation-call.ts","../src/rules/no-eager-translation.ts","../src/rules/no-unsubscribed-t.ts","../src/rules/static-candidate-limit.ts","../src/rules/t-static-args.ts","../src/index.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\n\nconst SOURCE_EXTENSIONS = [\n '',\n '.ts',\n '.tsx',\n '.js',\n '.jsx',\n '.mts',\n '.cts',\n '.mjs',\n '.cjs',\n] as const;\nconst DIRECTORY_STAMP_TTL_MS = 250;\nconst MAX_PROBE_CACHE_ENTRIES = 10_000;\n\ninterface TsConfig {\n compilerOptions?: {\n baseUrl?: string;\n paths?: Record<string, string[]>;\n };\n}\n\ninterface Alias {\n prefix: string;\n suffix: string;\n targets: string[];\n}\n\ninterface CachedTsConfig {\n stamp: string | null;\n value: TsConfig;\n}\n\ninterface CachedDirectoryStamp {\n expiresAt: number;\n value: string | null;\n}\n\ninterface CachedProbe {\n candidateDirectory: string | null;\n parentDirectory: string | null;\n resolved: string | null;\n}\n\nconst tsconfigCache = new Map<string, CachedTsConfig>();\nconst directoryStampCache = new Map<string, CachedDirectoryStamp>();\nconst probeCache = new Map<string, CachedProbe>();\n\nexport function createImportResolver(tsconfigPath?: string) {\n const aliases: Alias[] = [];\n let baseUrl = process.cwd();\n if (tsconfigPath) {\n const absoluteConfig = path.resolve(tsconfigPath);\n const config = readTsConfig(absoluteConfig);\n baseUrl = path.resolve(\n path.dirname(absoluteConfig),\n config.compilerOptions?.baseUrl ?? '.',\n );\n for (const [pattern, targets] of Object.entries(\n config.compilerOptions?.paths ?? {},\n )) {\n const star = pattern.indexOf('*');\n aliases.push({\n prefix: star < 0 ? pattern : pattern.slice(0, star),\n suffix: star < 0 ? '' : pattern.slice(star + 1),\n targets,\n });\n }\n }\n\n return (specifier: string, importer: string): string | null => {\n if (specifier === 'virtual:ai-i18n') return specifier;\n if (specifier.startsWith('.')) {\n return probeSource(path.resolve(path.dirname(importer), specifier));\n }\n for (const alias of aliases) {\n if (\n !specifier.startsWith(alias.prefix) ||\n !specifier.endsWith(alias.suffix)\n ) {\n continue;\n }\n const value = specifier.slice(\n alias.prefix.length,\n specifier.length - alias.suffix.length || undefined,\n );\n for (const target of alias.targets) {\n const candidate = target.includes('*')\n ? target.replace('*', value)\n : target;\n const resolved = probeSource(path.resolve(baseUrl, candidate));\n if (resolved) return resolved;\n }\n }\n return null;\n };\n}\n\nfunction probeSource(candidate: string): string | null {\n candidate = path.normalize(candidate);\n const cached = probeCache.get(candidate);\n if (\n cached &&\n cached.parentDirectory === readDirectoryStamp(path.dirname(candidate)) &&\n cached.candidateDirectory === readDirectoryStamp(candidate)\n ) {\n return cached.resolved;\n }\n\n let resolved: string | null = null;\n for (const extension of SOURCE_EXTENSIONS) {\n const file = `${candidate}${extension}`;\n if (isFile(file)) {\n resolved = path.normalize(file);\n break;\n }\n }\n if (!resolved) {\n for (const extension of SOURCE_EXTENSIONS.slice(1)) {\n const file = path.join(candidate, `index${extension}`);\n if (isFile(file)) {\n resolved = path.normalize(file);\n break;\n }\n }\n }\n if (probeCache.size >= MAX_PROBE_CACHE_ENTRIES) probeCache.clear();\n probeCache.set(candidate, {\n parentDirectory: readDirectoryStamp(path.dirname(candidate)),\n candidateDirectory: readDirectoryStamp(candidate),\n resolved,\n });\n return resolved;\n}\n\nfunction isFile(file: string) {\n try {\n return fs.statSync(file).isFile();\n } catch {\n return false;\n }\n}\n\nfunction readTsConfig(filename: string): TsConfig {\n const stamp = readFileStamp(filename);\n const cached = tsconfigCache.get(filename);\n if (cached?.stamp === stamp) return cached.value;\n let value: TsConfig = {};\n try {\n value = JSON.parse(\n stripJsonComments(fs.readFileSync(filename, 'utf8')),\n ) as TsConfig;\n } catch {\n // 无效或不存在的 tsconfig 与未配置路径别名等价。\n }\n tsconfigCache.set(filename, { stamp, value });\n return value;\n}\n\nfunction readFileStamp(filename: string): string | null {\n try {\n const stat = fs.statSync(filename);\n return stat.isFile()\n ? `${stat.mtimeMs}:${stat.ctimeMs}:${stat.size}`\n : null;\n } catch {\n return null;\n }\n}\n\nfunction readDirectoryStamp(directory: string): string | null {\n const now = Date.now();\n const cached = directoryStampCache.get(directory);\n if (cached && cached.expiresAt > now) return cached.value;\n let value: string | null = null;\n try {\n const stat = fs.statSync(directory);\n if (stat.isDirectory()) {\n value = `${stat.mtimeMs}:${stat.ctimeMs}:${stat.size}`;\n }\n } catch {\n // 不存在的目录也要缓存,避免重复的失败探测。\n }\n if (directoryStampCache.size >= MAX_PROBE_CACHE_ENTRIES) {\n directoryStampCache.clear();\n }\n directoryStampCache.set(directory, {\n expiresAt: now + DIRECTORY_STAMP_TTL_MS,\n value,\n });\n return value;\n}\n\nfunction stripJsonComments(source: string): string {\n let result = '';\n let quote = '';\n let escaped = false;\n for (let index = 0; index < source.length; index += 1) {\n const current = source[index]!;\n const next = source[index + 1];\n if (quote) {\n result += current;\n if (escaped) escaped = false;\n else if (current === '\\\\') escaped = true;\n else if (current === quote) quote = '';\n continue;\n }\n if (current === '\"' || current === \"'\") {\n quote = current;\n result += current;\n continue;\n }\n if (current === '/' && next === '/') {\n while (index < source.length && source[index] !== '\\n') index += 1;\n result += '\\n';\n continue;\n }\n if (current === '/' && next === '*') {\n index += 2;\n while (\n index < source.length &&\n !(source[index] === '*' && source[index + 1] === '/')\n ) {\n if (source[index] === '\\n') result += '\\n';\n index += 1;\n }\n index += 1;\n continue;\n }\n result += current;\n }\n return result.replace(/,\\s*([}\\]])/g, '$1');\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport {\n AI_I18N_VIRTUAL_MODULE_ID,\n Analyzer,\n extractMessages,\n findInvalidDefineI18nMessagesReferences,\n findTranslationCalls,\n findUnboundCalls,\n validateRecommendedUsage,\n type Module,\n type ExtractWarningCode,\n type RecommendedUsageCode,\n type AnalysisLanguage,\n type TranslationCall,\n type TranslationHookBinding,\n} from '@ai-i18n/analyzer';\nimport { createImportResolver } from './resolve-import.js';\n\nexport interface StaticArgsWarning {\n code: ExtractWarningCode | RecommendedUsageCode;\n line: number;\n column: number;\n message: string;\n}\n\nexport interface StaticAnalysisResult {\n warnings: StaticArgsWarning[];\n translationCalls: TranslationCall[];\n}\n\nexport type AutoImportApi = 't' | 'tRef' | 'useI18n';\nexport type AutoImportOption = boolean | readonly AutoImportApi[];\n\ninterface AutoImportBindings {\n t: boolean;\n tRef: boolean;\n useI18n: boolean;\n}\n\nconst POTENTIAL_TRANSLATION_RE =\n /virtual:ai-i18n|\\b(?:t|tRef|useI18n|defineI18nMessages)\\b/;\n\nexport function analyzeStaticArgs(\n code: string,\n filename: string,\n tsconfigPath?: string,\n lang?: AnalysisLanguage,\n autoImport: AutoImportOption = false,\n maxStaticCandidates = Number.POSITIVE_INFINITY,\n): StaticArgsWarning[] {\n return analyzeStaticSource(\n code,\n filename,\n tsconfigPath,\n lang,\n autoImport,\n maxStaticCandidates,\n ).warnings;\n}\n\nexport function analyzeStaticSource(\n code: string,\n filename: string,\n tsconfigPath?: string,\n lang?: AnalysisLanguage,\n autoImport: AutoImportOption = false,\n maxStaticCandidates = Number.POSITIVE_INFINITY,\n): StaticAnalysisResult {\n if (!hasPotentialTranslationCandidate(code)) {\n return { warnings: [], translationCalls: [] };\n }\n const autoImports = normalizeAutoImports(autoImport);\n const resolve = createImportResolver(tsconfigPath);\n const analyzer = new Analyzer({ resolve });\n analyzer.addFile(\n AI_I18N_VIRTUAL_MODULE_ID,\n 'export function t(source) { return source } export function tRef(source) { return source }',\n );\n const entryPath = normalizeFilename(filename);\n const entry = analyzer.addFile(entryPath, code, lang ? { lang } : undefined);\n if (!hasTranslationCandidate(entry, autoImports)) {\n return { warnings: [], translationCalls: [] };\n }\n loadDependencies(analyzer, entry, resolve);\n analyzer.link();\n const hooks = translationHooks(autoImports);\n const extraction = extractMessages(\n entry,\n AI_I18N_VIRTUAL_MODULE_ID,\n hooks,\n autoImports.t || autoImports.tRef,\n maxStaticCandidates,\n ).warnings;\n const recommended = validateRecommendedUsage(\n entry,\n AI_I18N_VIRTUAL_MODULE_ID,\n hooks,\n autoImports.t || autoImports.tRef,\n );\n const warnings = recommended.length\n ? [\n ...extraction.filter((warning) => warning.code === 'parse-error'),\n ...extraction.filter(\n (warning) => warning.code === 'static-candidate-limit',\n ),\n ...recommended,\n ]\n : extraction;\n return {\n warnings: warnings.map(({ code: warningCode, line, column, message }) => ({\n code: warningCode,\n line,\n column,\n message,\n })),\n translationCalls: findTranslationCalls(\n entry,\n AI_I18N_VIRTUAL_MODULE_ID,\n hooks,\n autoImports.t || autoImports.tRef,\n ),\n };\n}\n\nexport function hasPotentialTranslationCandidate(code: string): boolean {\n return POTENTIAL_TRANSLATION_RE.test(code);\n}\n\nexport function normalizeAutoImports(\n autoImport: AutoImportOption | undefined,\n): AutoImportBindings {\n if (typeof autoImport === 'boolean') {\n // boolean 保留跨框架的历史语义;Vue-only tRef 由 Vue preset 显式声明。\n return { t: autoImport, tRef: false, useI18n: autoImport };\n }\n return {\n t: autoImport?.includes('t') ?? false,\n tRef: autoImport?.includes('tRef') ?? false,\n useI18n: autoImport?.includes('useI18n') ?? false,\n };\n}\n\nfunction hasTranslationCandidate(\n module: Module,\n autoImports: AutoImportBindings,\n): boolean {\n const unbound = ['defineI18nMessages'];\n if (autoImports.t) unbound.push('t');\n if (autoImports.tRef) unbound.push('tRef');\n if (autoImports.useI18n) unbound.push('useI18n');\n return (\n module.imports.some(\n (item) =>\n !item.typeOnly &&\n (item.specifier === AI_I18N_VIRTUAL_MODULE_ID ||\n item.name === 't' ||\n item.name === 'tRef' ||\n item.name === 'useI18n'),\n ) ||\n findInvalidDefineI18nMessagesReferences(module).length > 0 ||\n findUnboundCalls(module, new Set(unbound)).length > 0\n );\n}\n\nfunction translationHooks(\n autoImports: AutoImportBindings,\n): readonly TranslationHookBinding[] {\n return [\n {\n module: AI_I18N_VIRTUAL_MODULE_ID,\n hook: 'useI18n',\n property: 't',\n autoImport: autoImports.useI18n,\n },\n ];\n}\n\nfunction loadDependencies(\n analyzer: Analyzer,\n entry: Module,\n resolve: (specifier: string, importer: string) => string | null,\n) {\n const queue = [entry];\n const visited = new Set<string>();\n while (queue.length) {\n const module = queue.shift()!;\n if (visited.has(module.path)) continue;\n visited.add(module.path);\n for (const item of module.imports) {\n const resolved = resolve(item.specifier, module.path);\n if (!resolved || resolved === AI_I18N_VIRTUAL_MODULE_ID) continue;\n let dependency = analyzer.module(resolved);\n if (!dependency) {\n try {\n dependency = analyzer.addFile(\n resolved,\n fs.readFileSync(resolved, 'utf8'),\n );\n } catch {\n continue;\n }\n }\n queue.push(dependency);\n }\n }\n}\n\nfunction normalizeFilename(filename: string) {\n return filename.startsWith('<')\n ? path.resolve('eslint-input.ts')\n : path.resolve(filename);\n}\n","import { createRequire } from 'node:module';\nimport path from 'node:path';\nimport { diagnosticMessage } from '@ai-i18n/analyzer';\nimport {\n analyzeVueSource,\n type VueAnalysisSource,\n type VueCompiler,\n} from '@ai-i18n/analyzer/vue';\n\ninterface VueParserServices {\n getDocumentFragment?: () => unknown;\n}\n\ntype Require = ReturnType<typeof createRequire>;\ntype NodeVueCompiler = VueCompiler & {\n registerTS?: (loadTypeScript: () => unknown) => void;\n};\n\nconst packageRequire = createRequire(import.meta.url);\n\nexport function createVueAnalysisSource(\n source: string,\n filename: string,\n parserServices: VueParserServices,\n): VueAnalysisSource {\n if (!parserServices.getDocumentFragment?.()) {\n throw new Error(\n diagnosticMessage(\n '检查 .vue 文件需要配置 vue-eslint-parser。',\n 'Configure vue-eslint-parser to lint .vue files.',\n ),\n );\n }\n\n try {\n // Vue preset 真正处理 SFC 时才加载编译器,不影响 React/Vanilla 项目。\n const compiler = loadVueCompiler(filename);\n return analyzeVueSource(source, filename, compiler);\n } catch (error) {\n if (isMissingVueCompiler(error)) {\n throw new Error(\n diagnosticMessage(\n '检查 .vue 文件需要安装 @vue/compiler-sfc。',\n 'Install @vue/compiler-sfc to lint .vue files.',\n ),\n );\n }\n throw error;\n }\n}\n\nfunction loadVueCompiler(filename: string): VueCompiler {\n const hostRequire = createRequire(path.resolve(filename));\n // 优先复用宿主 Vue 的 Node wrapper,它会为 imported types 注册 TypeScript。\n const compiler = (tryRequire(hostRequire, 'vue/compiler-sfc') ??\n tryRequire(packageRequire, 'vue/compiler-sfc') ??\n tryRequire(hostRequire, '@vue/compiler-sfc') ??\n packageRequire('@vue/compiler-sfc')) as NodeVueCompiler;\n compiler.registerTS?.(() => {\n const typescript =\n tryResolve(hostRequire, 'typescript') ??\n tryResolve(packageRequire, 'typescript');\n return packageRequire(typescript ?? 'typescript');\n });\n return compiler;\n}\n\nfunction tryRequire(require: Require, id: string): unknown {\n const resolved = tryResolve(require, id);\n return resolved ? require(resolved) : null;\n}\n\nfunction tryResolve(require: Require, id: string): string | null {\n try {\n return require.resolve(id);\n } catch (error) {\n if (isMissingVueCompiler(error)) return null;\n throw error;\n }\n}\n\nfunction isMissingVueCompiler(error: unknown): boolean {\n return (\n error instanceof Error &&\n 'code' in error &&\n (error.code === 'MODULE_NOT_FOUND' ||\n error.code === 'ERR_PACKAGE_PATH_NOT_EXPORTED')\n );\n}\n","import type { Rule } from 'eslint';\nimport {\n analyzeStaticSource,\n hasPotentialTranslationCandidate,\n normalizeAutoImports,\n type AutoImportOption,\n type StaticAnalysisResult,\n type StaticArgsWarning,\n} from './analyze.js';\nimport { diagnosticMessage, type TranslationCall } from '@ai-i18n/analyzer';\nimport { createVueAnalysisSource } from './vue-sfc.js';\n\ninterface RuleAnalysisOptions {\n tsconfigPath?: string;\n autoImport?: AutoImportOption;\n}\n\ninterface CachedAnalysis {\n source: ReturnType<typeof createAnalysisSource>;\n analyses: Map<string, StaticAnalysisResult>;\n}\n\nconst DEFAULT_CANDIDATE_LIMIT = 1_000;\nconst cache = new WeakMap<object, CachedAnalysis>();\nconst reportedAnalysisFailures = new WeakSet<object>();\nconst EMPTY_ANALYSIS: StaticAnalysisResult = {\n warnings: [],\n translationCalls: [],\n};\n\nexport function analyzeRuleContext(\n context: Rule.RuleContext,\n options: RuleAnalysisOptions,\n maxStaticCandidates = Number.POSITIVE_INFINITY,\n): StaticArgsWarning[] {\n return analyzeRuleContextResult(context, options, maxStaticCandidates)\n .warnings;\n}\n\nexport function analyzeTranslationCalls(\n context: Rule.RuleContext,\n options: RuleAnalysisOptions,\n): TranslationCall[] {\n return analyzeRuleContextResult(context, options, DEFAULT_CANDIDATE_LIMIT)\n .translationCalls;\n}\n\nexport function reportAnalysisFailureOnce(\n context: Rule.RuleContext,\n node: Rule.Node,\n error: unknown,\n): void {\n if (reportedAnalysisFailures.has(context.sourceCode)) return;\n reportedAnalysisFailures.add(context.sourceCode);\n const detail = error instanceof Error ? error.message : String(error);\n context.report({\n node,\n message: diagnosticMessage(\n `静态分析失败:${detail}`,\n `Static analysis failed: ${detail}`,\n ),\n });\n}\n\nfunction analyzeRuleContextResult(\n context: Rule.RuleContext,\n options: RuleAnalysisOptions,\n maxStaticCandidates: number,\n): StaticAnalysisResult {\n if (!hasPotentialTranslationCandidate(context.sourceCode.text)) {\n return EMPTY_ANALYSIS;\n }\n const cached: CachedAnalysis = cache.get(context.sourceCode) ?? {\n source: createAnalysisSource(context),\n analyses: new Map<string, StaticAnalysisResult>(),\n };\n cache.set(context.sourceCode, cached);\n\n const analyze = (limit: number) => {\n const autoImports = normalizeAutoImports(options.autoImport);\n const key = JSON.stringify([\n options.tsconfigPath ?? null,\n autoImports.t,\n autoImports.tRef,\n autoImports.useI18n,\n limit,\n ]);\n const existing = cached.analyses.get(key);\n if (existing) return existing;\n const result = analyzeStaticSource(\n cached.source.code,\n context.filename,\n options.tsconfigPath,\n cached.source.lang,\n options.autoImport,\n limit,\n );\n const analysis = {\n warnings: result.warnings.map((warning) => ({\n ...warning,\n ...cached.source.mapLocation(warning),\n })),\n translationCalls: result.translationCalls.map((call) => ({\n ...call,\n ...cached.source.mapLocation(call),\n })),\n };\n cached.analyses.set(key, analysis);\n return analysis;\n };\n\n if (Number.isFinite(maxStaticCandidates)) {\n return analyze(maxStaticCandidates);\n }\n const preflight = analyze(DEFAULT_CANDIDATE_LIMIT);\n return preflight.warnings.some(\n (warning) => warning.code === 'static-candidate-limit',\n )\n ? analyze(Number.POSITIVE_INFINITY)\n : preflight;\n}\n\nfunction createAnalysisSource(context: Rule.RuleContext) {\n return context.filename.endsWith('.vue')\n ? createVueAnalysisSource(\n context.sourceCode.text,\n context.filename,\n context.sourceCode.parserServices,\n )\n : {\n code: context.sourceCode.text,\n lang: undefined,\n mapLocation: (location: { line: number; column: number }) => location,\n };\n}\n","import type { TranslationCall } from '@ai-i18n/analyzer';\nimport type { Rule } from 'eslint';\nimport type { AutoImportOption } from '../analyze.js';\nimport { analyzeTranslationCalls } from '../rule-analysis.js';\n\nexport interface TranslationRuleOptions {\n tsconfigPath?: string;\n autoImport?: AutoImportOption;\n}\n\nexport interface TranslationCandidate {\n kind: TranslationCall['kind'];\n node: Rule.Node;\n}\n\nexport interface MatchedTranslationCall extends TranslationCandidate {\n call: TranslationCall;\n}\n\nexport function matchTranslationCalls(\n context: Rule.RuleContext,\n options: TranslationRuleOptions,\n candidates: readonly TranslationCandidate[],\n): MatchedTranslationCall[] {\n const calls = new Map(\n analyzeTranslationCalls(context, options).map((call) => [\n locationKey(call.line, call.column, call.kind),\n call,\n ]),\n );\n return candidates.flatMap((candidate) => {\n const location = candidate.node.loc?.start;\n if (!location) return [];\n const call = calls.get(\n locationKey(location.line, location.column, candidate.kind),\n );\n return call ? [{ ...candidate, call }] : [];\n });\n}\n\nfunction locationKey(\n line: number,\n column: number,\n kind: TranslationCall['kind'],\n): string {\n return `${kind}:${line}:${column}`;\n}\n","import { diagnosticMessage } from '@ai-i18n/analyzer';\nimport type { Rule } from 'eslint';\nimport { reportAnalysisFailureOnce } from '../rule-analysis.js';\nimport {\n matchTranslationCalls,\n type TranslationCandidate,\n type TranslationRuleOptions,\n} from './translation-call.js';\n\nconst FUNCTION_TYPES = new Set([\n 'ArrowFunctionExpression',\n 'FunctionDeclaration',\n 'FunctionExpression',\n]);\n\nexport const noEagerTranslation: Rule.RuleModule = {\n meta: {\n type: 'problem',\n docs: {\n description: '警告不会随语言切换更新的提前求值翻译结果',\n },\n schema: [\n {\n type: 'object',\n properties: {\n tsconfigPath: { type: 'string' },\n autoImport: {\n anyOf: [\n { type: 'boolean' },\n {\n type: 'array',\n items: { enum: ['t', 'tRef', 'useI18n'] },\n uniqueItems: true,\n },\n ],\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n eagerTranslation: diagnosticMessage(\n '初始化期间保存的 t() 结果不会随语言切换更新。请改为函数或 Getter,在使用时调用 t();Vue setup 中的响应式展示值可使用 tRef()。',\n 'A t() result stored during initialization will not update when the language changes. Evaluate it lazily in a function or getter; reactive display values in Vue setup can use tRef().',\n ),\n },\n },\n create(context) {\n const options = (context.options[0] ?? {}) as TranslationRuleOptions;\n const isVueSfc = context.filename.toLowerCase().endsWith('.vue');\n const candidates: TranslationCandidate[] = [];\n return {\n CallExpression(node) {\n candidates.push({ kind: 'call', node });\n },\n TaggedTemplateExpression(node) {\n candidates.push({ kind: 'tagged-template', node });\n },\n 'Program:exit'(program) {\n let matches;\n try {\n matches = matchTranslationCalls(context, options, candidates);\n } catch (error) {\n reportAnalysisFailureOnce(context, program as Rule.Node, error);\n return;\n }\n for (const { call, node } of matches) {\n if (call.origin === 'vue-ref') continue;\n if (!storesOutsideFunction(node, context, isVueSfc)) continue;\n context.report({ node, messageId: 'eagerTranslation' });\n }\n },\n };\n },\n};\n\nfunction storesOutsideFunction(\n node: Rule.Node,\n context: Rule.RuleContext,\n isVueSfc: boolean,\n): boolean {\n let current = node as ParentNode;\n let storesResult = false;\n while (current.parent) {\n const parent = current.parent;\n if (FUNCTION_TYPES.has(parent.type)) {\n // 普通 setup() 与 <script setup> 一样只执行一次;其他函数仍视为延迟求值。\n const returnsExpression =\n parent.type === 'ArrowFunctionExpression' && parent.body === current;\n return (\n isVueComponentSetup(parent, context, isVueSfc) &&\n (storesResult || returnsExpression)\n );\n }\n if (storesTranslationResult(parent, current)) storesResult = true;\n if (parent.type === 'Program') return storesResult;\n current = parent;\n }\n return storesResult;\n}\n\nfunction isVueComponentSetup(\n node: ParentNode,\n context: Rule.RuleContext,\n isVueSfc: boolean,\n): boolean {\n const directOwner = node.parent;\n if (\n directOwner?.type === 'CallExpression' &&\n directOwner.arguments?.[0] === node\n ) {\n return isImportedDefineComponent(directOwner.callee, context);\n }\n\n const property = node.parent;\n if (\n property?.type !== 'Property' ||\n property.value !== node ||\n property.computed ||\n propertyName(property.key) !== 'setup'\n ) {\n return false;\n }\n\n const options = property.parent;\n if (options?.type !== 'ObjectExpression') return false;\n const owner = options.parent;\n if (\n isVueSfc &&\n owner?.type === 'ExportDefaultDeclaration' &&\n owner.declaration === options\n ) {\n return true;\n }\n return (\n owner?.type === 'CallExpression' &&\n owner.arguments?.[0] === options &&\n isImportedDefineComponent(owner.callee, context)\n );\n}\n\nfunction propertyName(node: unknown): string | undefined {\n const key = node as { name?: string; type?: string; value?: unknown };\n if (key?.type === 'Identifier') return key.name;\n return key?.type === 'Literal' && typeof key.value === 'string'\n ? key.value\n : undefined;\n}\n\nfunction isImportedDefineComponent(\n node: unknown,\n context: Rule.RuleContext,\n): boolean {\n const callee = node as {\n computed?: boolean;\n name?: string;\n object?: unknown;\n property?: unknown;\n type?: string;\n };\n if (callee?.type === 'Identifier') {\n return isVueImport(callee, context, 'ImportSpecifier');\n }\n return (\n callee?.type === 'MemberExpression' &&\n !callee.computed &&\n propertyName(callee.property) === 'defineComponent' &&\n isVueImport(callee.object, context, 'ImportNamespaceSpecifier')\n );\n}\n\nfunction isVueImport(\n node: unknown,\n context: Rule.RuleContext,\n specifierType: 'ImportNamespaceSpecifier' | 'ImportSpecifier',\n): boolean {\n const identifier = node as Rule.Node & { name?: string };\n if (identifier?.type !== 'Identifier' || !identifier.name) return false;\n\n let scope = context.sourceCode.getScope(identifier);\n while (true) {\n const variable = scope.set.get(identifier.name);\n if (!variable) {\n if (!scope.upper) return false;\n scope = scope.upper;\n continue;\n }\n return variable.defs.some((definition) => {\n if (\n definition.type !== 'ImportBinding' ||\n definition.node.type !== specifierType ||\n definition.parent.source.value !== 'vue'\n ) {\n return false;\n }\n return (\n specifierType === 'ImportNamespaceSpecifier' ||\n propertyName((definition.node as { imported?: unknown }).imported) ===\n 'defineComponent'\n );\n });\n }\n}\n\nfunction storesTranslationResult(\n parent: ParentNode,\n child: ParentNode,\n): boolean {\n if (\n (parent as { type: string }).type === 'AccessorProperty' &&\n parent.value === child\n ) {\n return true;\n }\n switch (parent.type) {\n case 'VariableDeclarator':\n return parent.init === child;\n case 'AssignmentExpression':\n case 'AssignmentPattern':\n return parent.right === child;\n case 'PropertyDefinition':\n return parent.value === child;\n case 'ReturnStatement':\n return parent.argument === child;\n case 'ExportDefaultDeclaration':\n return parent.declaration === child;\n default:\n return false;\n }\n}\n\ntype ParentNode = Rule.Node & {\n arguments?: unknown[];\n argument?: unknown;\n body?: unknown;\n callee?: unknown;\n computed?: boolean;\n parent: ParentNode | null;\n declaration?: unknown;\n init?: unknown;\n key?: unknown;\n right?: unknown;\n value?: unknown;\n};\n","import { diagnosticMessage } from '@ai-i18n/analyzer';\nimport type { Rule } from 'eslint';\nimport { reportAnalysisFailureOnce } from '../rule-analysis.js';\nimport {\n matchTranslationCalls,\n type TranslationCandidate,\n type TranslationRuleOptions,\n} from './translation-call.js';\n\nconst FUNCTION_TYPES = new Set([\n 'ArrowFunctionExpression',\n 'FunctionDeclaration',\n 'FunctionExpression',\n]);\nconst IMMEDIATE_CONSOLE_METHODS = new Set([\n 'debug',\n 'error',\n 'info',\n 'log',\n 'warn',\n]);\n\nexport const noUnsubscribedT: Rule.RuleModule = {\n meta: {\n type: 'problem',\n docs: {\n description: '检查组件渲染路径中的翻译 API 生命周期',\n },\n schema: [\n {\n type: 'object',\n properties: {\n tsconfigPath: { type: 'string' },\n autoImport: {\n anyOf: [\n { type: 'boolean' },\n {\n type: 'array',\n items: { enum: ['t', 'tRef', 'useI18n'] },\n uniqueItems: true,\n },\n ],\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n unsubscribedT: diagnosticMessage(\n '组件渲染期间使用顶层 t 不会订阅语言状态,语言切换不会主动刷新,缓存的渲染结果也可能继续使用旧译文。请使用 useI18n() 返回的 t。',\n 'Top-level t does not subscribe the component to language updates, so language changes do not trigger a render and cached render results may remain stale. Use the t returned by useI18n().',\n ),\n renderTRef: diagnosticMessage(\n '不要在组件渲染或 template 中调用 tRef(),否则每次渲染都会创建新的 computed。请在 setup 中创建一次并使用返回的 Ref;渲染函数中请直接使用 useI18n() 返回的 t。',\n 'Do not call tRef() during component rendering or in a template because each render creates a new computed. Create it once in setup and use the returned Ref; in render functions, call the t returned by useI18n() directly.',\n ),\n },\n },\n create(context) {\n const options = (context.options[0] ?? {}) as TranslationRuleOptions;\n const candidates: TranslationCandidate[] = [];\n const jsxOwners = new Set<ParentNode>();\n const templateNodes = new Set<Rule.Node>();\n const collectJsxOwner = (node: Rule.Node) => {\n const owner = nearestFunction(node);\n if (owner) jsxOwners.add(owner);\n };\n const scriptVisitor: Rule.RuleListener = {\n CallExpression(node) {\n candidates.push({ kind: 'call', node });\n },\n TaggedTemplateExpression(node) {\n candidates.push({ kind: 'tagged-template', node });\n },\n JSXElement: collectJsxOwner,\n JSXFragment: collectJsxOwner,\n 'Program:exit'(program) {\n let matches;\n try {\n matches = matchTranslationCalls(context, options, candidates);\n } catch (error) {\n reportAnalysisFailureOnce(context, program as Rule.Node, error);\n return;\n }\n for (const { call, node } of matches) {\n if (call.origin === 'vue-ref') {\n if (templateNodes.has(node)) {\n if (!isVueTemplateEventHandler(node)) {\n context.report({ node, messageId: 'renderTRef' });\n }\n continue;\n }\n const owner = nearestFunction(node);\n if (owner && jsxOwners.has(owner)) {\n context.report({ node, messageId: 'renderTRef' });\n }\n continue;\n }\n if (call.origin !== 'runtime') continue;\n if (templateNodes.has(node)) {\n if (!isVueTemplateEventHandler(node)) {\n context.report({ node, messageId: 'unsubscribedT' });\n }\n continue;\n }\n // ponytail: 先检查直接拥有 JSX 的最近函数;出现真实漏报后再引入调用图与框架数据流。\n const owner = nearestFunction(node);\n if (\n !owner ||\n !jsxOwners.has(owner) ||\n isImmediateConsoleEffect(node)\n ) {\n continue;\n }\n context.report({ node, messageId: 'unsubscribedT' });\n }\n },\n };\n const parserServices = context.sourceCode\n .parserServices as VueParserServices;\n if (!parserServices.defineTemplateBodyVisitor) return scriptVisitor;\n return parserServices.defineTemplateBodyVisitor(\n {\n CallExpression(node) {\n candidates.push({ kind: 'call', node });\n templateNodes.add(node);\n },\n TaggedTemplateExpression(node) {\n candidates.push({ kind: 'tagged-template', node });\n templateNodes.add(node);\n },\n },\n scriptVisitor,\n // 模板默认在 Program:exit 才遍历;提前到 Program,确保汇总前已收集候选。\n { templateBodyTriggerSelector: 'Program' },\n );\n },\n};\n\nfunction nearestFunction(node: Rule.Node): ParentNode | null {\n let current = node as ParentNode;\n while (current.parent) {\n current = current.parent;\n if (FUNCTION_TYPES.has(current.type)) return current;\n }\n return null;\n}\n\nfunction isImmediateConsoleEffect(node: Rule.Node): boolean {\n const call = (node as ParentNode).parent;\n if (\n call?.type !== 'CallExpression' ||\n call.parent?.type !== 'ExpressionStatement' ||\n !call.arguments.some((argument) => argument === node) ||\n call.callee.type !== 'MemberExpression' ||\n call.callee.object.type !== 'Identifier' ||\n call.callee.object.name !== 'console'\n ) {\n return false;\n }\n const property = call.callee.property;\n const method =\n !call.callee.computed && property.type === 'Identifier'\n ? property.name\n : call.callee.computed &&\n property.type === 'Literal' &&\n typeof property.value === 'string'\n ? property.value\n : null;\n return method !== null && IMMEDIATE_CONSOLE_METHODS.has(method);\n}\n\nfunction isVueTemplateEventHandler(node: Rule.Node): boolean {\n let current = node as unknown as TemplateParentNode;\n while (current.parent) {\n current = current.parent;\n if (current.type === 'VOnExpression') return true;\n }\n return false;\n}\n\ntype ParentNode = Rule.Node & {\n parent: ParentNode | null;\n};\n\ninterface TemplateParentNode {\n type: string;\n parent: TemplateParentNode | null;\n}\n\ninterface VueParserServices {\n defineTemplateBodyVisitor?(\n templateBodyVisitor: Record<string, (node: Rule.Node) => void>,\n scriptVisitor: Rule.RuleListener,\n options: { templateBodyTriggerSelector: 'Program' | 'Program:exit' },\n ): Rule.RuleListener;\n}\n","import type { Rule } from 'eslint';\nimport type { AutoImportOption } from '../analyze.js';\nimport {\n analyzeRuleContext,\n reportAnalysisFailureOnce,\n} from '../rule-analysis.js';\n\ninterface RuleOptions {\n tsconfigPath?: string;\n autoImport?: AutoImportOption;\n maxStaticCandidates?: number;\n}\n\nexport const staticCandidateLimit: Rule.RuleModule = {\n meta: {\n type: 'suggestion',\n docs: {\n description: '警告单个 t() 展开的静态候选数量过多',\n },\n schema: [\n {\n type: 'object',\n properties: {\n tsconfigPath: { type: 'string' },\n autoImport: {\n anyOf: [\n { type: 'boolean' },\n {\n type: 'array',\n items: { enum: ['t', 'tRef', 'useI18n'] },\n uniqueItems: true,\n },\n ],\n },\n maxStaticCandidates: {\n type: 'integer',\n minimum: 1,\n maximum: Number.MAX_SAFE_INTEGER,\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n candidateLimit: '{{reason}}',\n },\n },\n create(context) {\n const options = (context.options[0] ?? {}) as RuleOptions;\n return {\n 'Program:exit'(node) {\n try {\n const warnings = analyzeRuleContext(\n context,\n options,\n options.maxStaticCandidates ?? 1_000,\n );\n for (const warning of warnings) {\n if (warning.code !== 'static-candidate-limit') continue;\n context.report({\n node,\n loc: {\n start: warning,\n end: { line: warning.line, column: warning.column + 1 },\n },\n messageId: 'candidateLimit',\n data: { reason: warning.message },\n });\n }\n } catch (error) {\n reportAnalysisFailureOnce(context, node as Rule.Node, error);\n }\n },\n };\n },\n};\n","import type { Rule } from 'eslint';\nimport { diagnosticMessage } from '@ai-i18n/analyzer';\nimport { normalizeAutoImports, type AutoImportOption } from '../analyze.js';\nimport {\n analyzeRuleContext,\n reportAnalysisFailureOnce,\n} from '../rule-analysis.js';\n\ninterface RuleOptions {\n tsconfigPath?: string;\n autoImport?: AutoImportOption;\n}\n\ninterface AstNode {\n type: string;\n name?: string;\n importKind?: string;\n range?: [number, number];\n argument?: AstNode;\n left?: AstNode;\n elements?: Array<AstNode | null>;\n properties?: AstNode[];\n value?: AstNode;\n id?: AstNode;\n declarations?: AstNode[];\n specifiers?: AstNode[];\n local?: AstNode;\n declaration?: AstNode | null;\n body?: AstNode[];\n parent?: AstNode | null;\n}\n\ninterface VueElement extends AstNode {\n startTag?: {\n attributes?: Array<{\n directive?: boolean;\n key?: { name?: string };\n }>;\n };\n}\n\ninterface VueDocument {\n children?: AstNode[];\n}\n\ninterface VueParserServices {\n defineTemplateBodyVisitor?: (\n templateVisitor: Record<string, (node: AstNode) => void>,\n scriptVisitor: Rule.RuleListener,\n ) => Rule.RuleListener;\n getDocumentFragment?: () => VueDocument | null;\n}\n\ninterface VueReference {\n id?: AstNode;\n variable?: unknown;\n}\n\nexport const tStaticArgs: Rule.RuleModule = {\n meta: {\n type: 'problem',\n docs: {\n description: '要求 virtual:ai-i18n 的 t() 参数可被静态提取',\n },\n schema: [\n {\n type: 'object',\n properties: {\n tsconfigPath: { type: 'string' },\n autoImport: {\n anyOf: [\n { type: 'boolean' },\n {\n type: 'array',\n items: { enum: ['t', 'tRef', 'useI18n'] },\n uniqueItems: true,\n },\n ],\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n analysisFailed: '{{reason}}',\n dynamicArg: '{{reason}}',\n invalidUsage: '{{reason}}',\n templateNeedsI18n: '{{reason}}',\n },\n },\n create(context) {\n const options = (context.options[0] ?? {}) as RuleOptions;\n const scriptVisitor: Rule.RuleListener = {\n 'Program:exit'(node) {\n let warnings;\n try {\n warnings = analyzeRuleContext(context, options);\n } catch (error) {\n reportAnalysisFailureOnce(context, node as Rule.Node, error);\n return;\n }\n for (const warning of warnings) {\n const analysisFailed = warning.code === 'parse-error';\n const invalidUsage =\n warning.code !== 'dynamic-argument' &&\n warning.code !== 'unresolved-argument' &&\n !analysisFailed;\n context.report({\n node,\n loc: {\n start: warning,\n end: { line: warning.line, column: warning.column + 1 },\n },\n messageId: analysisFailed\n ? 'analysisFailed'\n : invalidUsage\n ? 'invalidUsage'\n : 'dynamicArg',\n data: {\n reason: analysisFailed\n ? diagnosticMessage(\n `静态分析失败:${warning.message}`,\n `Static analysis failed: ${warning.message}`,\n )\n : invalidUsage\n ? warning.message\n : diagnosticMessage(\n 't() 的参数无法静态提取。source 请使用静态字符串,options 请使用只包含 comment 的静态对象。',\n 'The t() arguments cannot be statically extracted. Use a static string for source and a static object containing only comment for options.',\n ),\n },\n });\n }\n },\n };\n\n if (\n !context.filename.toLowerCase().endsWith('.vue') ||\n !normalizeAutoImports(options.autoImport).t\n ) {\n return scriptVisitor;\n }\n const services = context.sourceCode\n .parserServices as unknown as VueParserServices;\n const document = services.getDocumentFragment?.();\n const scripts = document?.children?.filter(isScriptElement) ?? [];\n const setupScript = scripts.find(isScriptSetup);\n // 普通 Options API 的模板可从组件实例获得 t,无法仅凭 SFC 静态确认来源。\n if ((!setupScript && scripts.length > 0) || !document) {\n return scriptVisitor;\n }\n if (\n setupScript &&\n hasTopLevelBinding(\n context.sourceCode.ast as unknown as AstNode,\n setupScript,\n 't',\n )\n ) {\n return scriptVisitor;\n }\n if (!services.defineTemplateBodyVisitor) return scriptVisitor;\n\n const reportTemplateT = (node: AstNode) => {\n const target =\n node.type === 'CallExpression'\n ? (node as AstNode & { callee?: AstNode }).callee\n : (node as AstNode & { tag?: AstNode }).tag;\n if (\n target?.type !== 'Identifier' ||\n target.name !== 't' ||\n isTemplateLocal(target)\n ) {\n return;\n }\n context.report({\n node: target as Rule.Node,\n messageId: 'templateNeedsI18n',\n data: {\n reason: diagnosticMessage(\n '模板中的裸 t 无法绑定到 ai-i18n,也不会订阅语言变化。请在 <script setup> 中声明 const { t } = useI18n()。',\n 'A bare t in the template is not bound to ai-i18n and does not subscribe to language changes. Declare const { t } = useI18n() in <script setup>.',\n ),\n },\n });\n };\n return services.defineTemplateBodyVisitor(\n {\n CallExpression: reportTemplateT,\n TaggedTemplateExpression: reportTemplateT,\n },\n scriptVisitor,\n );\n },\n};\n\nfunction isScriptElement(node: AstNode): node is VueElement {\n return node.type === 'VElement' && node.name === 'script';\n}\n\nfunction isScriptSetup(node: VueElement): boolean {\n return (\n node.startTag?.attributes?.some(\n (attribute) => !attribute.directive && attribute.key?.name === 'setup',\n ) ?? false\n );\n}\n\nfunction hasTopLevelBinding(\n program: AstNode,\n script: VueElement,\n name: string,\n): boolean {\n return (\n program.body?.some(\n (statement) =>\n isInside(statement, script) && statementDeclares(statement, name),\n ) ?? false\n );\n}\n\nfunction isInside(node: AstNode, container: AstNode): boolean {\n return Boolean(\n node.range &&\n container.range &&\n node.range[0] >= container.range[0] &&\n node.range[1] <= container.range[1],\n );\n}\n\nfunction statementDeclares(node: AstNode, name: string): boolean {\n switch (node.type) {\n case 'ImportDeclaration':\n return (\n node.importKind !== 'type' &&\n (node.specifiers?.some(\n (item) => item.importKind !== 'type' && item.local?.name === name,\n ) ??\n false)\n );\n case 'VariableDeclaration':\n return (\n node.declarations?.some((item) => patternDeclares(item.id, name)) ??\n false\n );\n case 'FunctionDeclaration':\n case 'ClassDeclaration':\n case 'TSEnumDeclaration':\n case 'TSImportEqualsDeclaration':\n return node.id?.name === name;\n case 'ExportNamedDeclaration':\n case 'ExportDefaultDeclaration':\n return node.declaration\n ? statementDeclares(node.declaration, name)\n : false;\n default:\n return false;\n }\n}\n\nfunction patternDeclares(node: AstNode | undefined, name: string): boolean {\n if (!node) return false;\n switch (node.type) {\n case 'Identifier':\n return node.name === name;\n case 'RestElement':\n return patternDeclares(node.argument, name);\n case 'AssignmentPattern':\n return patternDeclares(node.left, name);\n case 'ArrayPattern':\n return (\n node.elements?.some((item) =>\n patternDeclares(item ?? undefined, name),\n ) ?? false\n );\n case 'ObjectPattern':\n return (\n node.properties?.some((item) =>\n patternDeclares(\n item.type === 'RestElement' ? item.argument : item.value,\n name,\n ),\n ) ?? false\n );\n default:\n return false;\n }\n}\n\nfunction isTemplateLocal(node: AstNode): boolean {\n let parent = node.parent;\n while (parent && parent.type !== 'VExpressionContainer') {\n parent = parent.parent;\n }\n const references = (\n parent as (AstNode & { references?: VueReference[] }) | null | undefined\n )?.references;\n return (\n references?.some(\n (reference) =>\n reference.variable &&\n (reference.id === node ||\n (reference.id?.range?.[0] === node.range?.[0] &&\n reference.id?.range?.[1] === node.range?.[1])),\n ) ?? false\n );\n}\n","import { createRequire } from 'node:module';\nimport type { ESLint } from 'eslint';\nimport { noEagerTranslation } from './rules/no-eager-translation.js';\nimport { noUnsubscribedT } from './rules/no-unsubscribed-t.js';\nimport { staticCandidateLimit } from './rules/static-candidate-limit.js';\nimport { tStaticArgs } from './rules/t-static-args.js';\n\nconst { version } = createRequire(import.meta.url)('../package.json') as {\n version: string;\n};\n\nconst plugin: ESLint.Plugin = {\n meta: {\n name: '@ai-i18n/eslint-plugin',\n version,\n namespace: 'ai-i18n',\n },\n rules: {\n 'no-eager-translation': noEagerTranslation,\n 'no-unsubscribed-t': noUnsubscribedT,\n 'static-candidate-limit': staticCandidateLimit,\n 't-static-args': tStaticArgs,\n },\n configs: {},\n};\n\n// 规则集必须由使用者显式引入,不会修改宿主项目的 ESLint 配置。\nplugin.configs!.recommended = [\n {\n ignores: ['**/*.vue'],\n plugins: { 'ai-i18n': plugin },\n languageOptions: {\n globals: { defineI18nMessages: 'readonly' },\n },\n rules: {\n 'ai-i18n/t-static-args': 'error',\n 'ai-i18n/no-eager-translation': 'warn',\n 'ai-i18n/no-unsubscribed-t': 'warn',\n 'ai-i18n/static-candidate-limit': 'warn',\n },\n },\n];\n\nplugin.configs!.vue = [\n {\n files: ['**/*.{js,mjs,cjs,ts,mts,cts,jsx,tsx,vue}'],\n plugins: { 'ai-i18n': plugin },\n languageOptions: {\n globals: { defineI18nMessages: 'readonly' },\n },\n rules: {\n 'ai-i18n/t-static-args': 'error',\n 'ai-i18n/no-eager-translation': 'warn',\n 'ai-i18n/no-unsubscribed-t': 'warn',\n 'ai-i18n/static-candidate-limit': 'warn',\n },\n },\n];\n\n// 自动导入 preset 必须与 Vite 各模式实际注入的 API 一一对应。\nplugin.configs!['vanilla-auto-import'] = [\n {\n files: ['**/*.{js,mjs,cjs,ts,mts,cts}'],\n plugins: { 'ai-i18n': plugin },\n languageOptions: {\n globals: {\n t: 'readonly',\n setLang: 'readonly',\n getLang: 'readonly',\n getLangs: 'readonly',\n getLangLoadState: 'readonly',\n subscribe: 'readonly',\n defineI18nMessages: 'readonly',\n },\n },\n rules: {\n 'ai-i18n/t-static-args': ['error', { autoImport: ['t'] }],\n 'ai-i18n/no-eager-translation': ['warn', { autoImport: ['t'] }],\n 'ai-i18n/static-candidate-limit': ['warn', { autoImport: ['t'] }],\n },\n },\n];\n\nplugin.configs!['vue-auto-import'] = [\n {\n files: ['**/*.{js,mjs,cjs,ts,mts,cts,jsx,tsx,vue}'],\n plugins: { 'ai-i18n': plugin },\n languageOptions: {\n globals: {\n t: 'readonly',\n tRef: 'readonly',\n useI18n: 'readonly',\n defineI18nMessages: 'readonly',\n },\n },\n rules: {\n 'ai-i18n/t-static-args': [\n 'error',\n { autoImport: ['t', 'tRef', 'useI18n'] },\n ],\n 'ai-i18n/no-eager-translation': [\n 'warn',\n { autoImport: ['t', 'tRef', 'useI18n'] },\n ],\n 'ai-i18n/no-unsubscribed-t': [\n 'warn',\n { autoImport: ['t', 'tRef', 'useI18n'] },\n ],\n 'ai-i18n/static-candidate-limit': [\n 'warn',\n { autoImport: ['t', 'tRef', 'useI18n'] },\n ],\n },\n },\n];\n\nplugin.configs!['react-auto-import'] = [\n {\n files: ['**/*.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],\n plugins: { 'ai-i18n': plugin },\n languageOptions: {\n globals: {\n t: 'readonly',\n useI18n: 'readonly',\n defineI18nMessages: 'readonly',\n },\n },\n rules: {\n 'ai-i18n/t-static-args': ['error', { autoImport: ['t', 'useI18n'] }],\n 'ai-i18n/no-eager-translation': [\n 'warn',\n { autoImport: ['t', 'useI18n'] },\n ],\n 'ai-i18n/no-unsubscribed-t': ['warn', { autoImport: ['t', 'useI18n'] }],\n 'ai-i18n/static-candidate-limit': [\n 'warn',\n { autoImport: ['t', 'useI18n'] },\n ],\n },\n },\n];\n\nexport {\n noEagerTranslation,\n noUnsubscribedT,\n staticCandidateLimit,\n tStaticArgs,\n};\nexport default plugin;\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-i18n/eslint-plugin",
3
- "version": "1.0.0-alpha.6",
3
+ "version": "1.0.0-alpha.8",
4
4
  "description": "ESLint static-argument checks aligned with ai-i18n extraction semantics.",
5
5
  "keywords": [
6
6
  "eslint",
@@ -33,7 +33,7 @@
33
33
  }
34
34
  },
35
35
  "dependencies": {
36
- "@ai-i18n/analyzer": "^1.0.0-alpha.5"
36
+ "@ai-i18n/analyzer": "^1.0.0-alpha.7"
37
37
  },
38
38
  "peerDependencies": {
39
39
  "@vue/compiler-sfc": ">=3.2.0",