feima-shortcuts 0.3.0-beta.7 → 0.3.0-beta.9

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/bin/feima.js CHANGED
@@ -32,7 +32,9 @@ program
32
32
  .command('check-i18n-views')
33
33
  .description('检查已使用未创建的 key')
34
34
  .action(() => {
35
- checkI18nViews.run();
35
+ checkI18nViews.run({
36
+ scanDirs: ['src/views', 'src/components'],
37
+ })
36
38
  })
37
39
 
38
40
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "feima-shortcuts",
3
- "version": "0.3.0-beta.7",
3
+ "version": "0.3.0-beta.9",
4
4
  "description": "快捷指令",
5
5
  "main": "index.js",
6
6
  "directories": {
@@ -15,6 +15,9 @@
15
15
  "author": "1198810568@qq.com",
16
16
  "license": "ISC",
17
17
  "dependencies": {
18
+ "@babel/parser": "^7.28.5",
19
+ "@babel/traverse": "^7.28.5",
20
+ "@vue/compiler-sfc": "^3.5.26",
18
21
  "chalk": "^4.1.0",
19
22
  "commander": "^5.1.0",
20
23
  "download-git-repo": "^3.0.2",
@@ -9,7 +9,7 @@ const traverse = require('@babel/traverse').default
9
9
 
10
10
  const DEFAULT_OPTIONS = {
11
11
  cwd: process.cwd(),
12
- viewsDir: 'src/views',
12
+ scanDirs: ['src/views'],
13
13
  silent: false,
14
14
  }
15
15
 
@@ -42,35 +42,57 @@ function parseCode(code) {
42
42
  })
43
43
  }
44
44
 
45
+ /**
46
+ * 🔑 components 专用:
47
+ * 从当前文件目录开始,向上查找最近的 locale.ts
48
+ * 直到到达 src/components 为止
49
+ */
50
+ function findNearestLocale(fileDir, componentsRoot) {
51
+ let current = fileDir
52
+
53
+ while (current.startsWith(componentsRoot)) {
54
+ const localePath = path.join(current, 'locale.ts')
55
+ if (fs.existsSync(localePath)) {
56
+ return localePath
57
+ }
58
+ const parent = path.dirname(current)
59
+ if (parent === current) break
60
+ current = parent
61
+ }
62
+
63
+ return null
64
+ }
65
+
45
66
  /* ---------------- core ---------------- */
46
67
 
47
68
  function run(userOptions = {}) {
48
- // ✅ 保证 options 永远有值
49
69
  const options = { ...DEFAULT_OPTIONS, ...userOptions }
50
- const { cwd, viewsDir, silent } = options
70
+ const { cwd, scanDirs, silent } = options
51
71
 
52
- const absViewsDir = path.join(cwd, viewsDir)
72
+ let files = []
53
73
 
54
- if (!fs.existsSync(absViewsDir)) {
55
- if (!silent) {
56
- console.warn(`⚠️ views 目录不存在:${viewsDir}`)
57
- }
58
- return {
59
- success: true,
60
- missingKeys: [],
61
- noLocaleUsage: [],
62
- scannedFiles: 0,
74
+ for (const dir of scanDirs) {
75
+ const absDir = path.join(cwd, dir)
76
+ if (!fs.existsSync(absDir)) {
77
+ if (!silent) {
78
+ console.warn(`⚠️ 目录不存在:${dir}`)
79
+ }
80
+ continue
63
81
  }
64
- }
65
82
 
66
- const files = glob.sync('**/*.{vue,ts,tsx}', {
67
- cwd: absViewsDir,
68
- absolute: true,
69
- })
83
+ files.push(
84
+ ...glob.sync('**/*.{vue,ts,tsx}', {
85
+ cwd: absDir,
86
+ absolute: true,
87
+ })
88
+ )
89
+ }
70
90
 
71
91
  const missingKeys = []
72
92
  const noLocaleUsage = []
73
93
 
94
+ const componentsRoot = path.join(cwd, 'src/components')
95
+
74
96
  for (const file of files) {
75
97
  const content = fs.readFileSync(file, 'utf-8')
76
98
 
@@ -86,15 +108,21 @@ function run(userOptions = {}) {
86
108
 
87
109
  if (!scriptCode) continue
88
110
 
89
- const ast = parseCode(scriptCode)
111
+ let ast
112
+ try {
113
+ ast = parseCode(scriptCode)
114
+ } catch {
115
+ continue
116
+ }
90
117
 
91
- let usedLocale = false
92
118
  const usedKeys = []
119
+ let usedT = false
120
+ let importedLocale = false
93
121
 
94
122
  traverse(ast, {
95
123
  ImportDeclaration(p) {
96
124
  if (p.node.source.value === './locale') {
97
- usedLocale = true
125
+ importedLocale = true
98
126
  }
99
127
  },
100
128
 
@@ -104,6 +132,7 @@ function run(userOptions = {}) {
104
132
  (callee.type === 'Identifier' && callee.name === 't') ||
105
133
  (callee.type === 'Identifier' && callee.name === '$t')
106
134
  ) {
135
+ usedT = true
107
136
  const arg = p.node.arguments[0]
108
137
  if (arg && arg.type === 'StringLiteral') {
109
138
  usedKeys.push(arg.value)
@@ -114,23 +143,53 @@ function run(userOptions = {}) {
114
143
 
115
144
  if (!usedKeys.length) continue
116
145
 
117
- const localePath = path.join(path.dirname(file), 'locale.ts')
118
- const localeKeys = loadLocaleKeys(localePath)
146
+ const fileDir = path.dirname(file)
147
+
148
+ /* ---------- views 逻辑 ---------- */
149
+ if (file.startsWith(path.join(cwd, 'src/views'))) {
150
+ const localePath = path.join(fileDir, 'locale.ts')
151
+ const localeKeys = loadLocaleKeys(localePath)
152
+
153
+ if (!importedLocale || !localeKeys) {
154
+ noLocaleUsage.push({
155
+ file: path.relative(cwd, file),
156
+ keys: usedKeys,
157
+ })
158
+ continue
159
+ }
160
+
161
+ for (const key of usedKeys) {
162
+ if (!localeKeys.includes(key)) {
163
+ missingKeys.push({
164
+ file: path.relative(cwd, file),
165
+ key,
166
+ })
167
+ }
168
+ }
119
169
 
120
- if (!usedLocale || !localeKeys) {
121
- noLocaleUsage.push({
122
- file: path.relative(cwd, file),
123
- keys: usedKeys,
124
- })
125
170
  continue
126
171
  }
127
172
 
128
- for (const key of usedKeys) {
129
- if (!localeKeys.includes(key)) {
130
- missingKeys.push({
173
+ /* ---------- components 逻辑 ---------- */
174
+ if (file.startsWith(componentsRoot)) {
175
+ const localePath = findNearestLocale(fileDir, componentsRoot)
176
+ const localeKeys = localePath && loadLocaleKeys(localePath)
177
+
178
+ if (!localeKeys) {
179
+ noLocaleUsage.push({
131
180
  file: path.relative(cwd, file),
132
- key,
181
+ keys: usedKeys,
133
182
  })
183
+ continue
184
+ }
185
+
186
+ for (const key of usedKeys) {
187
+ if (!localeKeys.includes(key)) {
188
+ missingKeys.push({
189
+ file: path.relative(cwd, file),
190
+ key,
191
+ })
192
+ }
134
193
  }
135
194
  }
136
195
  }
@@ -146,14 +205,14 @@ function run(userOptions = {}) {
146
205
  }
147
206
 
148
207
  if (noLocaleUsage.length) {
149
- console.warn('\n⚠️ 使用了 t/$t 但未使用 ./locale:')
208
+ console.warn('\n⚠️ 使用了 $t / t 但未找到 locale.ts:')
150
209
  noLocaleUsage.forEach(i =>
151
210
  console.warn(` ${i.file}`)
152
211
  )
153
212
  }
154
213
 
155
214
  if (!missingKeys.length && !noLocaleUsage.length) {
156
- console.log('✅ views 国际化检查通过')
215
+ console.log('✅ 国际化检查通过(views + components)')
157
216
  }
158
217
  }
159
218
 
@@ -162,7 +221,7 @@ function run(userOptions = {}) {
162
221
  missingKeys,
163
222
  noLocaleUsage,
164
223
  scannedFiles: files.length,
165
- options, // 🔍 调试/日志时很有用
224
+ options,
166
225
  }
167
226
  }
168
227