@ai-i18n/eslint-plugin 1.0.0-alpha.6 → 1.0.0-alpha.7
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 +11 -7
- package/dist/index.js +74 -18
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
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` 还启用
|
|
@@ -104,6 +105,8 @@ function SaveButton() {
|
|
|
104
105
|
Vue 模板必须在 `<script setup>` 中绑定 `useI18n()` 返回的 `t`;自动导入只省略 import,
|
|
105
106
|
不会自动合成 Hook。`vue-auto-import` 会把裸 template-only `t()` 作为 error;模板中已
|
|
106
107
|
绑定到 Runtime 顶层 `t` 的调用则由 `no-unsubscribed-t` warning。
|
|
108
|
+
在 template 或 JSX/TSX 渲染期间调用 `tRef()` 会重复创建 `computed`,同一规则会提示在
|
|
109
|
+
Vue setup 中只创建一次并使用返回的 Ref。
|
|
107
110
|
|
|
108
111
|
对象或数组成员只有在根集合由 `defineI18nMessages()` 标记后才属于推荐写法。字符串拼接、
|
|
109
112
|
逻辑表达式、`let` 文案、普通集合成员、`const tr = t`、命名空间调用、二次 Hook 解构、
|
|
@@ -119,6 +122,7 @@ export default [
|
|
|
119
122
|
languageOptions: {
|
|
120
123
|
globals: {
|
|
121
124
|
t: 'readonly',
|
|
125
|
+
tRef: 'readonly',
|
|
122
126
|
useI18n: 'readonly',
|
|
123
127
|
defineI18nMessages: 'readonly',
|
|
124
128
|
},
|
|
@@ -128,21 +132,21 @@ export default [
|
|
|
128
132
|
'ai-i18n/no-eager-translation': [
|
|
129
133
|
'warn',
|
|
130
134
|
{
|
|
131
|
-
autoImport: ['t', 'useI18n'],
|
|
135
|
+
autoImport: ['t', 'tRef', 'useI18n'],
|
|
132
136
|
tsconfigPath: './tsconfig.json',
|
|
133
137
|
},
|
|
134
138
|
],
|
|
135
139
|
'ai-i18n/no-unsubscribed-t': [
|
|
136
140
|
'warn',
|
|
137
141
|
{
|
|
138
|
-
autoImport: ['t', 'useI18n'],
|
|
142
|
+
autoImport: ['t', 'tRef', 'useI18n'],
|
|
139
143
|
tsconfigPath: './tsconfig.json',
|
|
140
144
|
},
|
|
141
145
|
],
|
|
142
146
|
'ai-i18n/static-candidate-limit': [
|
|
143
147
|
'warn',
|
|
144
148
|
{
|
|
145
|
-
autoImport: ['t', 'useI18n'],
|
|
149
|
+
autoImport: ['t', 'tRef', 'useI18n'],
|
|
146
150
|
tsconfigPath: './tsconfig.json',
|
|
147
151
|
maxStaticCandidates: 2_000,
|
|
148
152
|
},
|
|
@@ -150,7 +154,7 @@ export default [
|
|
|
150
154
|
'ai-i18n/t-static-args': [
|
|
151
155
|
'error',
|
|
152
156
|
{
|
|
153
|
-
autoImport: ['t', 'useI18n'],
|
|
157
|
+
autoImport: ['t', 'tRef', 'useI18n'],
|
|
154
158
|
tsconfigPath: './tsconfig.json',
|
|
155
159
|
},
|
|
156
160
|
],
|
|
@@ -159,8 +163,8 @@ export default [
|
|
|
159
163
|
];
|
|
160
164
|
```
|
|
161
165
|
|
|
162
|
-
上例匹配 Vue
|
|
163
|
-
Runtime globals。日常接入优先使用预设,避免 Vite 与 ESLint 的 API 集合不一致。
|
|
166
|
+
上例匹配 Vue 模式;React 应移除 `tRef`,Vanilla 只使用 `autoImport: ['t']`,并声明对应的
|
|
167
|
+
顶层 Runtime globals。日常接入优先使用预设,避免 Vite 与 ESLint 的 API 集合不一致。
|
|
164
168
|
|
|
165
169
|
`ai-i18n/static-candidate-limit` 默认在单个 `t()` 的 source 与 options 组合超过 1000 个
|
|
166
170
|
时警告。`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: [
|
|
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()
|
|
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: "
|
|
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: [
|
|
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: {
|
|
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: [
|
|
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: [
|
|
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: [
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
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.
|
|
3
|
+
"version": "1.0.0-alpha.7",
|
|
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.
|
|
36
|
+
"@ai-i18n/analyzer": "^1.0.0-alpha.6"
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
39
|
"@vue/compiler-sfc": ">=3.2.0",
|