feima-shortcuts 0.3.0-beta.10 → 0.3.0-beta.11

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "feima-shortcuts",
3
- "version": "0.3.0-beta.10",
3
+ "version": "0.3.0-beta.11",
4
4
  "description": "快捷指令",
5
5
  "main": "index.js",
6
6
  "directories": {
@@ -5,16 +5,12 @@ const { parse } = require('@vue/compiler-sfc')
5
5
  const babelParser = require('@babel/parser')
6
6
  const traverse = require('@babel/traverse').default
7
7
 
8
- /* ---------------- defaults ---------------- */
9
-
10
8
  const DEFAULT_OPTIONS = {
11
9
  cwd: process.cwd(),
12
10
  scanDirs: ['src/views', 'src/components'],
13
11
  silent: false,
14
12
  }
15
13
 
16
- /* ---------------- utils ---------------- */
17
-
18
14
  function flattenLocale(obj, prefix = '') {
19
15
  let res = []
20
16
  for (const k in obj) {
@@ -43,12 +39,12 @@ function parseCode(code) {
43
39
  }
44
40
 
45
41
  /**
46
- * 从当前文件目录开始,向上查找最近的 locale.ts
47
- * 直到到达 componentsRoot 为止
42
+ * components 目录专用:
43
+ * 向上查找最近含 locale.ts 的目录(包含自身目录)
44
+ * 到达 componentsRoot 停止
48
45
  */
49
46
  function findNearestLocale(fileDir, componentsRoot) {
50
47
  let current = fileDir
51
-
52
48
  while (current.startsWith(componentsRoot)) {
53
49
  const localePath = path.join(current, 'locale.ts')
54
50
  if (fs.existsSync(localePath)) {
@@ -58,11 +54,18 @@ function findNearestLocale(fileDir, componentsRoot) {
58
54
  if (parent === current) break
59
55
  current = parent
60
56
  }
61
-
62
57
  return null
63
58
  }
64
59
 
65
- /* ---------------- core ---------------- */
60
+ /**
61
+ * views 目录专用:
62
+ * 只查找当前文件同目录的 locale.ts
63
+ */
64
+ function findViewsLocale(fileDir) {
65
+ const localePath = path.join(fileDir, 'locale.ts')
66
+ if (fs.existsSync(localePath)) return localePath
67
+ return null
68
+ }
66
69
 
67
70
  function run(userOptions = {}) {
68
71
  const options = { ...DEFAULT_OPTIONS, ...userOptions }
@@ -73,12 +76,9 @@ function run(userOptions = {}) {
73
76
  for (const dir of scanDirs) {
74
77
  const absDir = path.join(cwd, dir)
75
78
  if (!fs.existsSync(absDir)) {
76
- if (!silent) {
77
- console.warn(`⚠️ 目录不存在:${dir}`)
78
- }
79
+ if (!silent) console.warn(`⚠️ 目录不存在:${dir}`)
79
80
  continue
80
81
  }
81
-
82
82
  files.push(
83
83
  ...glob.sync('**/*.{vue,ts,tsx}', {
84
84
  cwd: absDir,
@@ -116,7 +116,7 @@ function run(userOptions = {}) {
116
116
  }
117
117
 
118
118
  const usedKeys = []
119
- let importedLocale = false
119
+ let importedLocale = false // 只对 views 生效
120
120
 
121
121
  traverse(ast, {
122
122
  ImportDeclaration(p) {
@@ -124,22 +124,44 @@ function run(userOptions = {}) {
124
124
  importedLocale = true
125
125
  }
126
126
  },
127
-
128
127
  CallExpression(p) {
129
128
  const callee = p.node.callee
130
- if (
131
- (callee.type === 'Identifier' && (callee.name === 't' || callee.name === '$t'))
132
- ) {
133
- const keyArg = p.node.arguments[0]
134
- const defaultArg = p.node.arguments[1]
135
- if (keyArg && keyArg.type === 'StringLiteral') {
136
- usedKeys.push({
137
- key: keyArg.value,
138
- defaultValue:
139
- defaultArg && defaultArg.type === 'StringLiteral'
140
- ? defaultArg.value
141
- : null,
142
- })
129
+
130
+ if (file.startsWith(viewsRoot)) {
131
+ // src/views 目录:只检查 t()
132
+ if (
133
+ callee.type === 'Identifier' &&
134
+ callee.name === 't'
135
+ ) {
136
+ const keyArg = p.node.arguments[0]
137
+ const defaultArg = p.node.arguments[1]
138
+ if (keyArg && keyArg.type === 'StringLiteral') {
139
+ usedKeys.push({
140
+ key: keyArg.value,
141
+ defaultValue:
142
+ defaultArg && defaultArg.type === 'StringLiteral'
143
+ ? defaultArg.value
144
+ : null,
145
+ })
146
+ }
147
+ }
148
+ } else if (file.startsWith(componentsRoot)) {
149
+ // src/components 目录:只检查 $t()
150
+ if (
151
+ callee.type === 'Identifier' &&
152
+ callee.name === '$t'
153
+ ) {
154
+ const keyArg = p.node.arguments[0]
155
+ const defaultArg = p.node.arguments[1]
156
+ if (keyArg && keyArg.type === 'StringLiteral') {
157
+ usedKeys.push({
158
+ key: keyArg.value,
159
+ defaultValue:
160
+ defaultArg && defaultArg.type === 'StringLiteral'
161
+ ? defaultArg.value
162
+ : null,
163
+ })
164
+ }
143
165
  }
144
166
  }
145
167
  },
@@ -149,15 +171,25 @@ function run(userOptions = {}) {
149
171
 
150
172
  const fileDir = path.dirname(file)
151
173
 
152
- /* ---------- views 逻辑 ---------- */
153
174
  if (file.startsWith(viewsRoot)) {
154
- const localePath = path.join(fileDir, 'locale.ts')
155
- const localeKeys = loadLocaleKeys(localePath)
175
+ // views 逻辑:只查同目录 locale.ts,且 vue 文件必须导入 locale
176
+ const localePath = findViewsLocale(fileDir)
177
+ const localeKeys = localePath && loadLocaleKeys(localePath)
156
178
 
157
- if (!importedLocale || !localeKeys) {
179
+ if (file.endsWith('.vue') && !importedLocale) {
158
180
  noLocaleUsage.push({
159
181
  file: path.relative(cwd, file),
160
182
  keys: usedKeys.map(i => i.key),
183
+ reason: 'vue 文件未 import locale',
184
+ })
185
+ continue
186
+ }
187
+
188
+ if (!localeKeys) {
189
+ noLocaleUsage.push({
190
+ file: path.relative(cwd, file),
191
+ keys: usedKeys.map(i => i.key),
192
+ reason: '同目录无 locale.ts',
161
193
  })
162
194
  continue
163
195
  }
@@ -171,12 +203,11 @@ function run(userOptions = {}) {
171
203
  })
172
204
  }
173
205
  }
174
-
175
206
  continue
176
207
  }
177
208
 
178
- /* ---------- components 逻辑 ---------- */
179
209
  if (file.startsWith(componentsRoot)) {
210
+ // components 逻辑:向上找最近 locale.ts
180
211
  const localePath = findNearestLocale(fileDir, componentsRoot)
181
212
  const localeKeys = localePath && loadLocaleKeys(localePath)
182
213
 
@@ -184,6 +215,7 @@ function run(userOptions = {}) {
184
215
  noLocaleUsage.push({
185
216
  file: path.relative(cwd, file),
186
217
  keys: usedKeys.map(i => i.key),
218
+ reason: '未找到可用 locale.ts',
187
219
  })
188
220
  continue
189
221
  }
@@ -197,25 +229,28 @@ function run(userOptions = {}) {
197
229
  })
198
230
  }
199
231
  }
232
+ continue
200
233
  }
201
234
  }
202
235
 
203
- /* ---------------- output ---------------- */
204
-
205
236
  if (!silent) {
206
237
  if (missingKeys.length) {
207
238
  console.error('\n❌ 缺失的国际化 key:')
208
239
  missingKeys.forEach(i =>
209
240
  console.error(
210
- ` ${i.file} → ${i.key}${i.defaultValue ? ` (默认值: ${i.defaultValue})` : ''}`
241
+ ` ${i.file} → ${i.key}${
242
+ i.defaultValue ? ` (默认值: ${i.defaultValue})` : ''
243
+ }`
211
244
  )
212
245
  )
213
246
  }
214
247
 
215
248
  if (noLocaleUsage.length) {
216
- console.warn('\n⚠️ 使用了 $t / t 但未找到 locale.ts:')
249
+ console.warn('\n⚠️ 以下文件使用了 $t / t,但未正确使用 locale.ts:')
217
250
  noLocaleUsage.forEach(i =>
218
- console.warn(` ${i.file}`)
251
+ console.warn(
252
+ ` ${i.file} → 原因: ${i.reason},涉及 keys: ${i.keys.join(', ')}`
253
+ )
219
254
  )
220
255
  }
221
256
 
@@ -233,6 +268,4 @@ function run(userOptions = {}) {
233
268
  }
234
269
  }
235
270
 
236
- /* ---------------- exports ---------------- */
237
-
238
271
  exports.run = run