i18-fe-automator-beta 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commonjs/index.js +2334 -0
- package/dist/esm/index.mjs +2312 -0
- package/package.json +45 -0
|
@@ -0,0 +1,2334 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
var fs = require('fs');
|
|
5
|
+
var inquirer = require('inquirer');
|
|
6
|
+
var commander = require('commander');
|
|
7
|
+
var request = require('request');
|
|
8
|
+
var glob = require('glob');
|
|
9
|
+
var md5 = require('js-md5');
|
|
10
|
+
var CryptoJS = require('crypto-js');
|
|
11
|
+
var ora = require('ora');
|
|
12
|
+
var chalk = require('chalk');
|
|
13
|
+
var xlsx = require('node-xlsx');
|
|
14
|
+
var url = require('url');
|
|
15
|
+
var path = require('path');
|
|
16
|
+
var querystring = require('querystring');
|
|
17
|
+
var crypto = require('crypto');
|
|
18
|
+
var uuid = require('uuid');
|
|
19
|
+
var eslint = require('eslint');
|
|
20
|
+
var espree = require('espree');
|
|
21
|
+
var node_module = require('node:module');
|
|
22
|
+
var stripAnsi = require('strip-ansi');
|
|
23
|
+
require('shelljs');
|
|
24
|
+
var process$1 = require('child_process');
|
|
25
|
+
var _ = require('lodash');
|
|
26
|
+
var nanoid = require('nanoid');
|
|
27
|
+
var request$1 = require('request-promise');
|
|
28
|
+
require('os');
|
|
29
|
+
require('console');
|
|
30
|
+
|
|
31
|
+
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
32
|
+
function _interopNamespaceDefault(e) {
|
|
33
|
+
var n = Object.create(null);
|
|
34
|
+
if (e) {
|
|
35
|
+
Object.keys(e).forEach(function (k) {
|
|
36
|
+
if (k !== 'default') {
|
|
37
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
38
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
39
|
+
enumerable: true,
|
|
40
|
+
get: function () { return e[k]; }
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
n.default = e;
|
|
46
|
+
return Object.freeze(n);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
var espree__namespace = /*#__PURE__*/_interopNamespaceDefault(espree);
|
|
50
|
+
|
|
51
|
+
function Loading() {
|
|
52
|
+
this.spinner = ora();
|
|
53
|
+
}
|
|
54
|
+
var Loading$1 = new Loading().spinner;
|
|
55
|
+
|
|
56
|
+
//加密
|
|
57
|
+
function encrypt(word, keyStr) {
|
|
58
|
+
keyStr = keyStr ? keyStr : "abcdefgabcdefg12";
|
|
59
|
+
var key = CryptoJS.enc.Utf8.parse(keyStr); //Latin1 w8m31+Yy/Nw6thPsMpO5fg==
|
|
60
|
+
var srcs = CryptoJS.enc.Utf8.parse(word);
|
|
61
|
+
var encrypted = CryptoJS.AES.encrypt(srcs, key, {
|
|
62
|
+
mode: CryptoJS.mode.ECB,
|
|
63
|
+
padding: CryptoJS.pad.Pkcs7,
|
|
64
|
+
});
|
|
65
|
+
return encrypted.toString();
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function login(data) {
|
|
69
|
+
data.password = encrypt(md5(data.password));
|
|
70
|
+
const env=data.env;
|
|
71
|
+
Loading$1.start(`${env}: 登录中...`);
|
|
72
|
+
return new Promise((resolve, reject) => {
|
|
73
|
+
request(
|
|
74
|
+
{
|
|
75
|
+
url: `https://${
|
|
76
|
+
env === "pro" ? "" : `${env}-`
|
|
77
|
+
}hxjf.hongxinshop.com/sys/login`,
|
|
78
|
+
method: "POST",
|
|
79
|
+
json: true,
|
|
80
|
+
body: data,
|
|
81
|
+
},
|
|
82
|
+
function (error, response, body) {
|
|
83
|
+
const res = body;
|
|
84
|
+
if (!error && res.code == 200) {
|
|
85
|
+
Loading$1.succeed(`${env}: 登录成功`);
|
|
86
|
+
const access_token = res.data.access_token;
|
|
87
|
+
resolve(access_token);
|
|
88
|
+
} else {
|
|
89
|
+
Loading$1.fail(`${env}: 登录失败`);
|
|
90
|
+
console.log(chalk.red(error || res.msg));
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
);
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function importExcel({ uploadFilePath, token, env }) {
|
|
98
|
+
Loading$1.start(`${env}: 导入文件中...`);
|
|
99
|
+
const stream = fs.createReadStream(uploadFilePath);
|
|
100
|
+
return new Promise((resolve, reject) => {
|
|
101
|
+
request(
|
|
102
|
+
{
|
|
103
|
+
url: `https://${
|
|
104
|
+
env === "pro" ? "" : `${env}-`
|
|
105
|
+
}hxjf.hongxinshop.com/vue-api/api-globalization/api/i18n/importLangExcel`,
|
|
106
|
+
method: "POST",
|
|
107
|
+
headers: {
|
|
108
|
+
contentType: "multipart/form-data",
|
|
109
|
+
Authorization: `Bearer ${token}`,
|
|
110
|
+
"x-request-vaildate": "open",
|
|
111
|
+
},
|
|
112
|
+
formData: {
|
|
113
|
+
file: stream,
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
function (error, response, body) {
|
|
117
|
+
const res = JSON.parse(body);
|
|
118
|
+
if (!error && res.code == 200) {
|
|
119
|
+
Loading$1.succeed(`${env}: 导入文件成功`);
|
|
120
|
+
resolve(true);
|
|
121
|
+
} else {
|
|
122
|
+
Loading$1.fail(`${env}: 导入文件失败`);
|
|
123
|
+
console.log(chalk.red(error || JSON.stringify(res.data)));
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
);
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
function readExcel({ uploadFilePath }) {
|
|
130
|
+
return new Promise((resolve, reject) => {
|
|
131
|
+
// 读取文件
|
|
132
|
+
const workSheetsFromFile = xlsx.parse(uploadFilePath);
|
|
133
|
+
const data = workSheetsFromFile[0].data;
|
|
134
|
+
// 获取第一行
|
|
135
|
+
const titleList = data[0];
|
|
136
|
+
// 获取项目所在的列
|
|
137
|
+
const projectIndex = titleList.indexOf("项目");
|
|
138
|
+
if (projectIndex === -1) {
|
|
139
|
+
console.log(chalk.red("请检查文件是否包含项目列"));
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
// 获取数据
|
|
143
|
+
const list = data.slice(1);
|
|
144
|
+
const set = new Set();
|
|
145
|
+
list.forEach((item) => {
|
|
146
|
+
if (item[projectIndex]) {
|
|
147
|
+
set.add(item[projectIndex]);
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
// 判断set是否为空
|
|
151
|
+
if (set.size === 0) {
|
|
152
|
+
console.log(chalk.red("请检查文件是否包含项目数据"));
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
resolve([...set]);
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function uploadExcel({ data, token, env }) {
|
|
160
|
+
Loading$1.start(`${env}: 导入项目 ${data.projectList.join()}`);
|
|
161
|
+
return new Promise((resolve, reject) => {
|
|
162
|
+
request(
|
|
163
|
+
{
|
|
164
|
+
url: `https://${
|
|
165
|
+
env === "pro" ? "" : `${env}-`
|
|
166
|
+
}hxjf.hongxinshop.com/vue-api/api-globalization/api/i18n/uploadI18nLangForFront`,
|
|
167
|
+
method: "POST",
|
|
168
|
+
json: true,
|
|
169
|
+
headers: {
|
|
170
|
+
Authorization: `Bearer ${token}`,
|
|
171
|
+
"x-request-vaildate": "open",
|
|
172
|
+
},
|
|
173
|
+
body: data,
|
|
174
|
+
},
|
|
175
|
+
function (error, response, body) {
|
|
176
|
+
const res = body;
|
|
177
|
+
if (!error && res.code == 200) {
|
|
178
|
+
Loading$1.succeed(`${env}: 导入项目成功`);
|
|
179
|
+
resolve(true);
|
|
180
|
+
} else {
|
|
181
|
+
Loading$1.fail(`${env}: 导入项目失败`);
|
|
182
|
+
console.log(chalk.red(error || res.msg || res.message));
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
);
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// 获取命令行所在的目录
|
|
190
|
+
function getRunCliPath({ directory = false, root = false } = {}) {
|
|
191
|
+
const __filename = url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.src || new URL('index.js', document.baseURI).href)));
|
|
192
|
+
const __dirname = path.dirname(__filename);
|
|
193
|
+
if (root) {
|
|
194
|
+
return path.resolve(__dirname, "../");
|
|
195
|
+
}
|
|
196
|
+
return directory ? __dirname : __filename;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// 获取package.json
|
|
200
|
+
function getPackageJson() {
|
|
201
|
+
const packageJson = JSON.parse(
|
|
202
|
+
fs.readFileSync(path.resolve(getRunCliPath({ root: true }), "../package.json"))
|
|
203
|
+
);
|
|
204
|
+
return packageJson;
|
|
205
|
+
}
|
|
206
|
+
// 判断是否存在该路径
|
|
207
|
+
function isExistPath(path) {
|
|
208
|
+
return fs.existsSync(path);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// 写入缓存
|
|
212
|
+
function writeCache(key, value) {
|
|
213
|
+
fs.writeFileSync(getRunCliPath({ root: true }) + "/.cache/" + key, value);
|
|
214
|
+
}
|
|
215
|
+
// 读取缓存
|
|
216
|
+
function readCache(key) {
|
|
217
|
+
return fs.readFileSync(getRunCliPath({ root: true }) + "/.cache/" + key);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const sleep = (time) =>
|
|
221
|
+
new Promise((resolve = 2000) => {
|
|
222
|
+
setTimeout(() => resolve, time);
|
|
223
|
+
});
|
|
224
|
+
async function upload$1() {
|
|
225
|
+
const SECRET_NAME = "sass";
|
|
226
|
+
const SECRET_NAME_PRO = "sass_pro";
|
|
227
|
+
let cacheSecret = {};
|
|
228
|
+
let cacheSecretPro = {};
|
|
229
|
+
if (!isExistPath(getRunCliPath({ root: true }) + "/.cache")) {
|
|
230
|
+
fs.mkdirSync(getRunCliPath({ root: true }) + "/.cache");
|
|
231
|
+
}
|
|
232
|
+
const cacheFilePath =
|
|
233
|
+
getRunCliPath({ root: true }) + "/.cache/" + SECRET_NAME;
|
|
234
|
+
const cacheFilePathPro =
|
|
235
|
+
getRunCliPath({ root: true }) + "/.cache/" + SECRET_NAME_PRO;
|
|
236
|
+
if (isExistPath(cacheFilePath)) {
|
|
237
|
+
cacheSecret = JSON.parse(readCache(SECRET_NAME));
|
|
238
|
+
}
|
|
239
|
+
if (isExistPath(cacheFilePathPro)) {
|
|
240
|
+
cacheSecretPro = JSON.parse(readCache(SECRET_NAME_PRO));
|
|
241
|
+
}
|
|
242
|
+
// 是否上传
|
|
243
|
+
inquirer
|
|
244
|
+
.prompt([
|
|
245
|
+
{
|
|
246
|
+
message: "是否上传到sass平台",
|
|
247
|
+
name: "upload",
|
|
248
|
+
type: "confirm",
|
|
249
|
+
default: true,
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
// 选择环境
|
|
253
|
+
message: "请选择环境",
|
|
254
|
+
name: "env",
|
|
255
|
+
type: "rawlist",
|
|
256
|
+
choices: [
|
|
257
|
+
{
|
|
258
|
+
name: "mit",
|
|
259
|
+
value: "mit",
|
|
260
|
+
},
|
|
261
|
+
{
|
|
262
|
+
name: "sit",
|
|
263
|
+
value: "sit",
|
|
264
|
+
},
|
|
265
|
+
{
|
|
266
|
+
name: "uat",
|
|
267
|
+
value: "uat",
|
|
268
|
+
},
|
|
269
|
+
{
|
|
270
|
+
name: "pro",
|
|
271
|
+
value: "pro",
|
|
272
|
+
},
|
|
273
|
+
// {
|
|
274
|
+
// name: "一键发布pro(mit->sit->uat->pro)",
|
|
275
|
+
// value: "topro",
|
|
276
|
+
// },
|
|
277
|
+
{
|
|
278
|
+
name: "一键发布uat(mit->sit->uat)",
|
|
279
|
+
value: "to-mit,sit,uat",
|
|
280
|
+
},
|
|
281
|
+
{
|
|
282
|
+
name: "一键发布sit(mit->sit)",
|
|
283
|
+
value: "to-mit,sit",
|
|
284
|
+
},
|
|
285
|
+
],
|
|
286
|
+
when: function (res) {
|
|
287
|
+
return res.upload;
|
|
288
|
+
},
|
|
289
|
+
validate: function (val) {
|
|
290
|
+
if (val.length > 0) {
|
|
291
|
+
return true;
|
|
292
|
+
}
|
|
293
|
+
return "请选择环境";
|
|
294
|
+
},
|
|
295
|
+
},
|
|
296
|
+
{
|
|
297
|
+
message: "请输入域账号",
|
|
298
|
+
name: "username",
|
|
299
|
+
// 当upload为true时,展示
|
|
300
|
+
when: function (res) {
|
|
301
|
+
return res.upload && res.env !== "pro";
|
|
302
|
+
},
|
|
303
|
+
default: cacheSecret.username,
|
|
304
|
+
// 必填
|
|
305
|
+
validate: function (val) {
|
|
306
|
+
if (val) {
|
|
307
|
+
return true;
|
|
308
|
+
}
|
|
309
|
+
return "请输入域账号";
|
|
310
|
+
},
|
|
311
|
+
},
|
|
312
|
+
{
|
|
313
|
+
message: "请输入域密码",
|
|
314
|
+
name: "password",
|
|
315
|
+
default: cacheSecret.password,
|
|
316
|
+
when: function (res) {
|
|
317
|
+
return res.upload && res.env !== "pro";
|
|
318
|
+
},
|
|
319
|
+
// 必填
|
|
320
|
+
validate: function (val) {
|
|
321
|
+
if (val) {
|
|
322
|
+
return true;
|
|
323
|
+
}
|
|
324
|
+
return "请输入域密码";
|
|
325
|
+
},
|
|
326
|
+
},
|
|
327
|
+
{
|
|
328
|
+
message: "请输入生产域账号",
|
|
329
|
+
name: "username",
|
|
330
|
+
// 当upload为true时,展示
|
|
331
|
+
when: function (res) {
|
|
332
|
+
return res.upload && res.env === "pro";
|
|
333
|
+
},
|
|
334
|
+
default: cacheSecretPro.username,
|
|
335
|
+
// 必填
|
|
336
|
+
validate: function (val) {
|
|
337
|
+
if (val) {
|
|
338
|
+
return true;
|
|
339
|
+
}
|
|
340
|
+
return "请输入生产域账号";
|
|
341
|
+
},
|
|
342
|
+
},
|
|
343
|
+
{
|
|
344
|
+
message: "请输入生产域密码",
|
|
345
|
+
name: "password",
|
|
346
|
+
default: cacheSecretPro.password,
|
|
347
|
+
when: function (res) {
|
|
348
|
+
return res.upload && res.env === "pro";
|
|
349
|
+
},
|
|
350
|
+
// 必填
|
|
351
|
+
validate: function (val) {
|
|
352
|
+
if (val) {
|
|
353
|
+
return true;
|
|
354
|
+
}
|
|
355
|
+
return "请输入生产域密码";
|
|
356
|
+
},
|
|
357
|
+
},
|
|
358
|
+
])
|
|
359
|
+
.then(async (res) => {
|
|
360
|
+
const { upload, env, username, password } = res;
|
|
361
|
+
let envList = [];
|
|
362
|
+
if (env.indexOf("to") > -1) {
|
|
363
|
+
envList = env.replace("to-", "").split(",");
|
|
364
|
+
} else {
|
|
365
|
+
envList = [env];
|
|
366
|
+
}
|
|
367
|
+
if (upload) {
|
|
368
|
+
writeCache(
|
|
369
|
+
env === "pro" ? "sass_pro" : "sass",
|
|
370
|
+
JSON.stringify({
|
|
371
|
+
username,
|
|
372
|
+
password,
|
|
373
|
+
})
|
|
374
|
+
);
|
|
375
|
+
// 上传逻辑
|
|
376
|
+
// 1.获取上传文件路径
|
|
377
|
+
const choices = fs
|
|
378
|
+
.readdirSync("./")
|
|
379
|
+
.filter((item) => item.indexOf(".xlsx") > -1);
|
|
380
|
+
// 2. 选择上传文件
|
|
381
|
+
inquirer
|
|
382
|
+
.prompt([
|
|
383
|
+
{
|
|
384
|
+
type: "rawlist",
|
|
385
|
+
name: "excelFileName",
|
|
386
|
+
message: "请选择要上传的excel文件",
|
|
387
|
+
choices,
|
|
388
|
+
validate: function (val) {
|
|
389
|
+
if (val) {
|
|
390
|
+
return true;
|
|
391
|
+
}
|
|
392
|
+
return "请选择项目";
|
|
393
|
+
},
|
|
394
|
+
},
|
|
395
|
+
])
|
|
396
|
+
.then(async (res) => {
|
|
397
|
+
const { excelFileName } = res;
|
|
398
|
+
// 2.读取excel
|
|
399
|
+
const uploadFilePath = "./" + excelFileName;
|
|
400
|
+
const projectList = await readExcel({ uploadFilePath });
|
|
401
|
+
for (const env of envList) {
|
|
402
|
+
// 1.登录
|
|
403
|
+
const token = await login({
|
|
404
|
+
env,
|
|
405
|
+
username,
|
|
406
|
+
password,
|
|
407
|
+
});
|
|
408
|
+
// 2.导入excel
|
|
409
|
+
await importExcel({
|
|
410
|
+
uploadFilePath,
|
|
411
|
+
token,
|
|
412
|
+
env,
|
|
413
|
+
});
|
|
414
|
+
sleep(2000);
|
|
415
|
+
// 3.上传
|
|
416
|
+
await uploadExcel({
|
|
417
|
+
data: {
|
|
418
|
+
projectList,
|
|
419
|
+
},
|
|
420
|
+
token,
|
|
421
|
+
env,
|
|
422
|
+
});
|
|
423
|
+
console.log(`🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀${env}成功`);
|
|
424
|
+
}
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
});
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
// 获取应用list
|
|
431
|
+
function getApplicationList({ appName, env, token }) {
|
|
432
|
+
return new Promise((resolve, reject) => {
|
|
433
|
+
request(
|
|
434
|
+
{
|
|
435
|
+
url: `https://${
|
|
436
|
+
env === "pro" ? "" : `${env}-`
|
|
437
|
+
}hxjf.hongxinshop.com/api-u/api/saas/app/nameList`,
|
|
438
|
+
method: "POST",
|
|
439
|
+
json: true,
|
|
440
|
+
body: { name: appName, pageNo: 1, pageSize: 50 },
|
|
441
|
+
headers: {
|
|
442
|
+
Authorization: `Bearer ${token}`,
|
|
443
|
+
"x-request-vaildate": "open",
|
|
444
|
+
},
|
|
445
|
+
},
|
|
446
|
+
function (error, response, body) {
|
|
447
|
+
const res = body;
|
|
448
|
+
if (!error && res.code == 200) {
|
|
449
|
+
resolve(
|
|
450
|
+
res.data.map((item) => {
|
|
451
|
+
// return {
|
|
452
|
+
// name: item.name,
|
|
453
|
+
// value: item.id,
|
|
454
|
+
// };
|
|
455
|
+
return {
|
|
456
|
+
name: item.name,
|
|
457
|
+
value: item.name,
|
|
458
|
+
id: item.id,
|
|
459
|
+
code: item.code,
|
|
460
|
+
};
|
|
461
|
+
})
|
|
462
|
+
);
|
|
463
|
+
} else {
|
|
464
|
+
console.log(chalk.red(error || JSON.stringify(res.data)));
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
);
|
|
468
|
+
});
|
|
469
|
+
}
|
|
470
|
+
// 获取应用按钮权限配置
|
|
471
|
+
function getApplicationButtonConfig({ appId, env, token }) {
|
|
472
|
+
Loading$1.start(`获取按钮权限配置中...`);
|
|
473
|
+
return new Promise((resolve, reject) => {
|
|
474
|
+
request(
|
|
475
|
+
{
|
|
476
|
+
url: `https://${
|
|
477
|
+
env === "pro" ? "" : `${env}-`
|
|
478
|
+
}hxjf.hongxinshop.com/api-u/api/saas/permission/list`,
|
|
479
|
+
method: "POST",
|
|
480
|
+
json: true,
|
|
481
|
+
body: { id: appId },
|
|
482
|
+
headers: {
|
|
483
|
+
Authorization: `Bearer ${token}`,
|
|
484
|
+
"x-request-vaildate": "open",
|
|
485
|
+
},
|
|
486
|
+
},
|
|
487
|
+
function (error, response, body) {
|
|
488
|
+
const res = body;
|
|
489
|
+
if (!error && res.code == 200) {
|
|
490
|
+
Loading$1.succeed(`获取${env}环境按钮权限配置成功`);
|
|
491
|
+
resolve(res.data);
|
|
492
|
+
} else {
|
|
493
|
+
Loading$1.fail(`获取${env}环境按钮权限配置失败`);
|
|
494
|
+
console.log(chalk.red(error || JSON.stringify(res.data)));
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
);
|
|
498
|
+
});
|
|
499
|
+
}
|
|
500
|
+
// 删除应用按钮权限
|
|
501
|
+
function deleteApplicationButtonConfig({ data, env, token }) {
|
|
502
|
+
return new Promise((resolve, reject) => {
|
|
503
|
+
request(
|
|
504
|
+
{
|
|
505
|
+
url: `https://${
|
|
506
|
+
env === "pro" ? "" : `${env}-`
|
|
507
|
+
}hxjf.hongxinshop.com/api-u/api/saas/permission/del`,
|
|
508
|
+
method: "POST",
|
|
509
|
+
json: true,
|
|
510
|
+
body: data,
|
|
511
|
+
headers: {
|
|
512
|
+
Authorization: `Bearer ${token}`,
|
|
513
|
+
"x-request-vaildate": "open",
|
|
514
|
+
},
|
|
515
|
+
},
|
|
516
|
+
function (error, response, body) {
|
|
517
|
+
const res = body;
|
|
518
|
+
if (!error && res.code == 200) {
|
|
519
|
+
resolve(res.data);
|
|
520
|
+
} else {
|
|
521
|
+
const errorData = error || JSON.stringify(res.data);
|
|
522
|
+
console.log(chalk.red(errorData));
|
|
523
|
+
reject(errorData);
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
);
|
|
527
|
+
});
|
|
528
|
+
}
|
|
529
|
+
// 新增应用按钮权限
|
|
530
|
+
function addApplicationButtonConfig({ data, env, token }) {
|
|
531
|
+
Loading$1.start(`新增按钮权限 ${data.code} 中...`);
|
|
532
|
+
return new Promise((resolve, reject) => {
|
|
533
|
+
request(
|
|
534
|
+
{
|
|
535
|
+
url: `https://${
|
|
536
|
+
env === "pro" ? "" : `${env}-`
|
|
537
|
+
}hxjf.hongxinshop.com/api-u/api/saas/permission/add`,
|
|
538
|
+
method: "POST",
|
|
539
|
+
json: true,
|
|
540
|
+
body: data,
|
|
541
|
+
headers: {
|
|
542
|
+
Authorization: `Bearer ${token}`,
|
|
543
|
+
"x-request-vaildate": "open",
|
|
544
|
+
},
|
|
545
|
+
},
|
|
546
|
+
function (error, response, body) {
|
|
547
|
+
const res = body;
|
|
548
|
+
if (!error && res.code == 200) {
|
|
549
|
+
Loading$1.succeed(`${data.code}`);
|
|
550
|
+
resolve(true);
|
|
551
|
+
} else {
|
|
552
|
+
Loading$1.fail(`${data.code}`);
|
|
553
|
+
console.log(chalk.red(error || JSON.stringify(res.data)));
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
);
|
|
557
|
+
});
|
|
558
|
+
}
|
|
559
|
+
async function syncSassConfig() {
|
|
560
|
+
inquirer
|
|
561
|
+
.prompt([
|
|
562
|
+
{
|
|
563
|
+
message: `使用须知:
|
|
564
|
+
${chalk.green(`
|
|
565
|
+
1.此命令会${chalk.red('强制覆盖')}[from]->[to]环境配置,${chalk.red('不会合并')}!!! \n
|
|
566
|
+
2.请确保同步前已经在目标环境创建了应用 \n
|
|
567
|
+
3.从mit->sit/uat,建议先同步sit->mit以保证mit环境的配置是最新的
|
|
568
|
+
`)}
|
|
569
|
+
`,
|
|
570
|
+
name: "notice",
|
|
571
|
+
type: "confirm",
|
|
572
|
+
default: false,
|
|
573
|
+
},
|
|
574
|
+
{
|
|
575
|
+
message: "请选择从哪个环境同步配置",
|
|
576
|
+
name: "from",
|
|
577
|
+
type: "list",
|
|
578
|
+
choices: ["mit", "sit", "uat"],
|
|
579
|
+
when: (answers) => answers.notice,
|
|
580
|
+
},
|
|
581
|
+
{
|
|
582
|
+
message: "请选择同步至哪个环境",
|
|
583
|
+
name: "to",
|
|
584
|
+
type: "list",
|
|
585
|
+
when: (answers) => answers.notice,
|
|
586
|
+
choices: (answers) => {
|
|
587
|
+
const list = ["mit", "sit", "uat"];
|
|
588
|
+
return list.filter((item) => item !== answers.from);
|
|
589
|
+
},
|
|
590
|
+
},
|
|
591
|
+
])
|
|
592
|
+
.then(async (answers) => {
|
|
593
|
+
const { from, to,notice } = answers;
|
|
594
|
+
if(!notice){
|
|
595
|
+
return
|
|
596
|
+
}
|
|
597
|
+
const token = await login({
|
|
598
|
+
env: from,
|
|
599
|
+
username: "superAdmin",
|
|
600
|
+
password: "admin1",
|
|
601
|
+
});
|
|
602
|
+
const { inputAppName } = await inquirer.prompt([
|
|
603
|
+
{
|
|
604
|
+
message: "请输入应用名称关键字",
|
|
605
|
+
name: "inputAppName",
|
|
606
|
+
type: "input",
|
|
607
|
+
validate: function (value) {
|
|
608
|
+
if (value) {
|
|
609
|
+
return true;
|
|
610
|
+
}
|
|
611
|
+
return "请输入应用名称";
|
|
612
|
+
},
|
|
613
|
+
},
|
|
614
|
+
]);
|
|
615
|
+
const applicationList = await getApplicationList({
|
|
616
|
+
env: from,
|
|
617
|
+
token,
|
|
618
|
+
appName: inputAppName,
|
|
619
|
+
});
|
|
620
|
+
const { appName } = await inquirer.prompt([
|
|
621
|
+
{
|
|
622
|
+
message: "请选择应用名称",
|
|
623
|
+
name: "appName",
|
|
624
|
+
type: "rawlist",
|
|
625
|
+
choices: applicationList,
|
|
626
|
+
},
|
|
627
|
+
]);
|
|
628
|
+
const appId = applicationList.find((item) => item.name === appName).id;
|
|
629
|
+
// let appConfig = await getApplicationConfig({ appId, env: from, token });
|
|
630
|
+
const fromButtonList = await getApplicationButtonConfig({
|
|
631
|
+
appId,
|
|
632
|
+
env: from,
|
|
633
|
+
token,
|
|
634
|
+
});
|
|
635
|
+
if (!fromButtonList.length) {
|
|
636
|
+
return console.log(chalk.red("按钮权限配置为空,无法同步"));
|
|
637
|
+
}
|
|
638
|
+
console.log(`开始同步到${to}🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀`);
|
|
639
|
+
const toToken = await login({
|
|
640
|
+
env: to,
|
|
641
|
+
username: "superAdmin",
|
|
642
|
+
password: "admin1",
|
|
643
|
+
});
|
|
644
|
+
const toApplicationList = await getApplicationList({
|
|
645
|
+
env: to,
|
|
646
|
+
token: toToken,
|
|
647
|
+
appName,
|
|
648
|
+
});
|
|
649
|
+
if (!toApplicationList.length) {
|
|
650
|
+
return console.log(chalk.red(`${to}环境不存在该应用`));
|
|
651
|
+
}
|
|
652
|
+
const toAppId = toApplicationList[0].id;
|
|
653
|
+
const toButtonList = await getApplicationButtonConfig({
|
|
654
|
+
appId: toAppId,
|
|
655
|
+
env: to,
|
|
656
|
+
token: toToken,
|
|
657
|
+
});
|
|
658
|
+
try {
|
|
659
|
+
if (toButtonList.length) {
|
|
660
|
+
const deleteButtonPromiseList = toButtonList.map((item) => {
|
|
661
|
+
return deleteApplicationButtonConfig({
|
|
662
|
+
data: {
|
|
663
|
+
id: item.id,
|
|
664
|
+
ver: item.ver,
|
|
665
|
+
},
|
|
666
|
+
env: to,
|
|
667
|
+
token: toToken,
|
|
668
|
+
});
|
|
669
|
+
});
|
|
670
|
+
Loading$1.start(`删除${to}环境按钮权限配置中...`);
|
|
671
|
+
await Promise.all(deleteButtonPromiseList);
|
|
672
|
+
Loading$1.succeed(`删除${to}环境按钮权限配置成功`);
|
|
673
|
+
}
|
|
674
|
+
} catch (error) {
|
|
675
|
+
console.log(chalk.red(`删除${to}环境按钮权限配置失败`));
|
|
676
|
+
} finally {
|
|
677
|
+
for (const item of fromButtonList) {
|
|
678
|
+
const { code, name, visitConf } = item;
|
|
679
|
+
await addApplicationButtonConfig({
|
|
680
|
+
env: to,
|
|
681
|
+
token: toToken,
|
|
682
|
+
data: {
|
|
683
|
+
code1: code.split(":")[0],
|
|
684
|
+
code,
|
|
685
|
+
name,
|
|
686
|
+
visitConf,
|
|
687
|
+
ascriptionApp: toAppId,
|
|
688
|
+
},
|
|
689
|
+
});
|
|
690
|
+
}
|
|
691
|
+
console.log(chalk.green("同步成功"));
|
|
692
|
+
}
|
|
693
|
+
});
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
/**
|
|
697
|
+
* @fileoverview 不要单独中文
|
|
698
|
+
* @author ypf
|
|
699
|
+
*/
|
|
700
|
+
//------------------------------------------------------------------------------
|
|
701
|
+
// Rule Definition
|
|
702
|
+
//------------------------------------------------------------------------------
|
|
703
|
+
|
|
704
|
+
/** @type {import('eslint').Rule.RuleModule} */
|
|
705
|
+
|
|
706
|
+
// 判断字符串是否是中文
|
|
707
|
+
const isChinese = (str) => {
|
|
708
|
+
return /[\u4e00-\u9fa5]+/.test(str);
|
|
709
|
+
};
|
|
710
|
+
//去除特殊字符,包含空格
|
|
711
|
+
function trimSpecial(string = "", formatter) {
|
|
712
|
+
// const pattern =
|
|
713
|
+
// /[`~!@#$^\-&*()=|{}':;',\\\[\]\.<>\/?~!@#¥……&*()——|{}【】';:""'。,、?\s]/g;
|
|
714
|
+
// return string.replace(pattern, "");
|
|
715
|
+
// console.log(string);
|
|
716
|
+
// 获取开头空白符的位置
|
|
717
|
+
const startIdx = string.search(/\S/) - 1;
|
|
718
|
+
// 获取结尾空白符的位置
|
|
719
|
+
const endIdx = string.search(/\S\s*$/) + 1;
|
|
720
|
+
// 获取开头和结尾的字符串
|
|
721
|
+
const startStr = string.slice(0, startIdx + 1);
|
|
722
|
+
const endStr = string.slice(endIdx);
|
|
723
|
+
// 获取中间的字符串
|
|
724
|
+
const middle = string.slice(startIdx + 1, endIdx);
|
|
725
|
+
// 取出中间字符串的换行符
|
|
726
|
+
const middleStr = middle.replace(/\n/g, "");
|
|
727
|
+
return startStr + formatter(middleStr) + endStr;
|
|
728
|
+
}
|
|
729
|
+
// 判断当前节点是否已经翻译过
|
|
730
|
+
function isTranslate(node) {
|
|
731
|
+
if (
|
|
732
|
+
node.parent?.parent?.parent?.type === "CallExpression" &&
|
|
733
|
+
node.parent?.parent?.parent?.callee?.name === "$hxt"
|
|
734
|
+
) {
|
|
735
|
+
return true;
|
|
736
|
+
}
|
|
737
|
+
// console不翻译
|
|
738
|
+
if (
|
|
739
|
+
node.parent.type === "CallExpression" &&
|
|
740
|
+
node.parent.callee?.object?.name === "console"
|
|
741
|
+
) {
|
|
742
|
+
return true;
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
return false;
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
// 空key
|
|
749
|
+
const emptyKeyRules = (context) => {
|
|
750
|
+
return {
|
|
751
|
+
CallExpression(node) {
|
|
752
|
+
if (node.callee.name === "$hxt") {
|
|
753
|
+
const properties = node.arguments[0]?.properties || [];
|
|
754
|
+
// 如果属性是key且值为空
|
|
755
|
+
const result = properties.some((item) => {
|
|
756
|
+
// 去除key空格
|
|
757
|
+
const key = item.key.name.replace(/\s/g, "");
|
|
758
|
+
if (key === "key") {
|
|
759
|
+
// 去除value空格
|
|
760
|
+
// value是模版字符串
|
|
761
|
+
let value = "";
|
|
762
|
+
if (item.value.type === "TemplateLiteral") {
|
|
763
|
+
value = item.value.quasis[0].value.raw.replace(/\s/g, "");
|
|
764
|
+
} else if (item.value.type === "Literal") {
|
|
765
|
+
value = item.value.value.replace(/\s/g, "");
|
|
766
|
+
}
|
|
767
|
+
if (value === "") {
|
|
768
|
+
return true;
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
});
|
|
772
|
+
if (result) {
|
|
773
|
+
context.report({
|
|
774
|
+
node: node,
|
|
775
|
+
messageId: "noSingleChinese",
|
|
776
|
+
data: {
|
|
777
|
+
raw: chalk.green("key为空"),
|
|
778
|
+
},
|
|
779
|
+
fix: (fixer) => {},
|
|
780
|
+
});
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
},
|
|
784
|
+
};
|
|
785
|
+
};
|
|
786
|
+
var noSingleChineseRule = {
|
|
787
|
+
meta: {
|
|
788
|
+
type: "suggestion", // `problem`, `suggestion`, or `layout`
|
|
789
|
+
docs: {
|
|
790
|
+
description: "不要单独中文",
|
|
791
|
+
recommended: false,
|
|
792
|
+
url: null, // URL to the documentation page for this rule
|
|
793
|
+
},
|
|
794
|
+
fixable: "code", // Or `code` or `whitespace`
|
|
795
|
+
schema: [], // Add a schema if the rule has options
|
|
796
|
+
messages: {
|
|
797
|
+
noSingleChinese: "不要单独中文: {{raw}}",
|
|
798
|
+
}, // Add messageId and message
|
|
799
|
+
},
|
|
800
|
+
create(context) {
|
|
801
|
+
const sourceCode = context.sourceCode;
|
|
802
|
+
context.filename;
|
|
803
|
+
// console.log(filename,999999)
|
|
804
|
+
return context.parserServices.defineTemplateBodyVisitor(
|
|
805
|
+
// Event handlers for <template>.
|
|
806
|
+
{
|
|
807
|
+
// 纯字符串,如 测试
|
|
808
|
+
VText(node) {
|
|
809
|
+
// 如果是中文,替换为 {{ $hxt({key:'',desc:'中文'})}}
|
|
810
|
+
if (!isTranslate(node)) {
|
|
811
|
+
if (isChinese(node.value)) {
|
|
812
|
+
context.report({
|
|
813
|
+
node,
|
|
814
|
+
messageId: "noSingleChinese",
|
|
815
|
+
data: {
|
|
816
|
+
raw: chalk.green(node.value),
|
|
817
|
+
},
|
|
818
|
+
// message: `VText`,
|
|
819
|
+
fix: (fixer) => {
|
|
820
|
+
return fixer.replaceText(
|
|
821
|
+
node,
|
|
822
|
+
trimSpecial(node.value, (middle) => {
|
|
823
|
+
return "{{ $hxt({key:'',desc:'" + middle + "'})}}";
|
|
824
|
+
})
|
|
825
|
+
);
|
|
826
|
+
},
|
|
827
|
+
});
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
},
|
|
831
|
+
// 纯字符串,如 {{ mini ? '测试' : `开启` }}中的测试
|
|
832
|
+
// 纯字符串,如 {{test('测试')}}中的测试
|
|
833
|
+
Literal(node) {
|
|
834
|
+
if (!isTranslate(node)) {
|
|
835
|
+
if (isChinese(node.value)) {
|
|
836
|
+
context.report({
|
|
837
|
+
node,
|
|
838
|
+
messageId: "noSingleChinese",
|
|
839
|
+
data: {
|
|
840
|
+
raw: chalk.green(node.value),
|
|
841
|
+
},
|
|
842
|
+
// message: `Literal`,
|
|
843
|
+
fix: (fixer) => {
|
|
844
|
+
// console.log(1111, node);
|
|
845
|
+
return fixer.replaceText(
|
|
846
|
+
node,
|
|
847
|
+
trimSpecial(node.value, (middle) => {
|
|
848
|
+
return "$hxt({key:'',desc:'" + middle + "'})";
|
|
849
|
+
})
|
|
850
|
+
);
|
|
851
|
+
},
|
|
852
|
+
});
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
},
|
|
856
|
+
// 模版字符串,
|
|
857
|
+
// 如{{ mini ? '测试' : `开启` }}中的开启
|
|
858
|
+
// 如{{ mini ? `${a}测试` : "开启" }}中的${a}测试
|
|
859
|
+
// 如{{`111`}}
|
|
860
|
+
// 如<p :a="`${a}册书`">
|
|
861
|
+
TemplateLiteral(node) {
|
|
862
|
+
if (!isTranslate(node)) {
|
|
863
|
+
const textSource = sourceCode.getText(node);
|
|
864
|
+
let text = textSource;
|
|
865
|
+
// 删除$符号
|
|
866
|
+
text = text.replace(/\${/g, "{");
|
|
867
|
+
if (isChinese(text)) {
|
|
868
|
+
// 获取expressions的文本
|
|
869
|
+
const expressionsText = node.expressions.map((item) => {
|
|
870
|
+
return sourceCode.getText(item);
|
|
871
|
+
});
|
|
872
|
+
let expressionStr = "";
|
|
873
|
+
if (expressionsText.length) {
|
|
874
|
+
expressionsText.forEach((item, index) => {
|
|
875
|
+
const key = `slot${index + 1}`;
|
|
876
|
+
text = text.replace(item, `${key}`);
|
|
877
|
+
expressionStr += `${key}:${item},`;
|
|
878
|
+
});
|
|
879
|
+
// 删除最后一个逗号
|
|
880
|
+
expressionStr = `{${expressionStr.slice(0, -1)}}`;
|
|
881
|
+
}
|
|
882
|
+
if (!isChinese(text)) {
|
|
883
|
+
return;
|
|
884
|
+
}
|
|
885
|
+
context.report({
|
|
886
|
+
node,
|
|
887
|
+
data: {
|
|
888
|
+
raw: chalk.green(textSource),
|
|
889
|
+
},
|
|
890
|
+
messageId: "noSingleChinese",
|
|
891
|
+
// message: `TemplateLiteral`,
|
|
892
|
+
fix: (fixer) => {
|
|
893
|
+
return fixer.replaceText(
|
|
894
|
+
node,
|
|
895
|
+
trimSpecial(text, (middle) => {
|
|
896
|
+
return `$hxt({key:'',desc:${middle}}${
|
|
897
|
+
expressionStr ? `,${expressionStr}` : ""
|
|
898
|
+
})`;
|
|
899
|
+
})
|
|
900
|
+
);
|
|
901
|
+
},
|
|
902
|
+
});
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
},
|
|
906
|
+
// 如<p title="1">
|
|
907
|
+
VLiteral(node) {
|
|
908
|
+
if (!isTranslate(node)) {
|
|
909
|
+
if (isChinese(node.value)) {
|
|
910
|
+
context.report({
|
|
911
|
+
node,
|
|
912
|
+
messageId: "noSingleChinese",
|
|
913
|
+
// message: `VLiteral`,
|
|
914
|
+
data: {
|
|
915
|
+
raw: chalk.green(node.value),
|
|
916
|
+
},
|
|
917
|
+
|
|
918
|
+
fix: (fixer) => {
|
|
919
|
+
// 父节点需要改为冒号方式
|
|
920
|
+
const parentNode = node.parent;
|
|
921
|
+
if (parentNode.type === "VAttribute") {
|
|
922
|
+
const key = parentNode.key;
|
|
923
|
+
return fixer.replaceText(
|
|
924
|
+
parentNode,
|
|
925
|
+
":" +
|
|
926
|
+
key.name +
|
|
927
|
+
"=" +
|
|
928
|
+
'"' +
|
|
929
|
+
trimSpecial(node.value, (middle) => {
|
|
930
|
+
return "$hxt({key:'',desc:'" + middle + "'})";
|
|
931
|
+
}) +
|
|
932
|
+
'"'
|
|
933
|
+
);
|
|
934
|
+
}
|
|
935
|
+
},
|
|
936
|
+
});
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
},
|
|
940
|
+
// 如 <p v-permission="测试">中的测试
|
|
941
|
+
Identifier(node) {
|
|
942
|
+
if (
|
|
943
|
+
!isTranslate(node) &&
|
|
944
|
+
node.parent.type === "VExpressionContainer"
|
|
945
|
+
) {
|
|
946
|
+
if (isChinese(node.name)) {
|
|
947
|
+
context.report({
|
|
948
|
+
node,
|
|
949
|
+
messageId: "noSingleChinese",
|
|
950
|
+
// message: `Identifier`,
|
|
951
|
+
data: {
|
|
952
|
+
raw: chalk.green(node.name),
|
|
953
|
+
},
|
|
954
|
+
fix: (fixer) => {
|
|
955
|
+
return fixer.replaceText(
|
|
956
|
+
node,
|
|
957
|
+
trimSpecial(node.name, (middle) => {
|
|
958
|
+
return "$hxt({key:'',desc:'" + middle + "'})";
|
|
959
|
+
})
|
|
960
|
+
);
|
|
961
|
+
},
|
|
962
|
+
});
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
},
|
|
966
|
+
...emptyKeyRules(context),
|
|
967
|
+
},
|
|
968
|
+
// Event handlers for <script> or scripts. (optional)
|
|
969
|
+
{
|
|
970
|
+
JSXText(node) {
|
|
971
|
+
if (!isTranslate(node)) {
|
|
972
|
+
if (isChinese(node.value)) {
|
|
973
|
+
context.report({
|
|
974
|
+
node,
|
|
975
|
+
messageId: "noSingleChinese",
|
|
976
|
+
data: {
|
|
977
|
+
raw: chalk.green(node.value),
|
|
978
|
+
},
|
|
979
|
+
fix: (fixer) => {
|
|
980
|
+
return fixer.replaceText(
|
|
981
|
+
node,
|
|
982
|
+
trimSpecial(node.value, (middle) => {
|
|
983
|
+
return "{ $hxt({key:'',desc:'" + middle + "'})}";
|
|
984
|
+
})
|
|
985
|
+
);
|
|
986
|
+
},
|
|
987
|
+
});
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
},
|
|
991
|
+
TemplateLiteral(node) {
|
|
992
|
+
if (!isTranslate(node)) {
|
|
993
|
+
const textSource = sourceCode.getText(node);
|
|
994
|
+
let text = textSource;
|
|
995
|
+
// 删除$符号
|
|
996
|
+
text = text.replace(/\${/g, "{");
|
|
997
|
+
if (isChinese(text)) {
|
|
998
|
+
// 获取expressions的文本
|
|
999
|
+
const expressionsText = node.expressions.map((item) => {
|
|
1000
|
+
return sourceCode.getText(item);
|
|
1001
|
+
});
|
|
1002
|
+
// console.log(expressionsText,111)
|
|
1003
|
+
let expressionStr = "";
|
|
1004
|
+
if (expressionsText.length) {
|
|
1005
|
+
expressionsText.forEach((item, index) => {
|
|
1006
|
+
const key = `slot${index + 1}`;
|
|
1007
|
+
text = text.replace(item, `${key}`);
|
|
1008
|
+
expressionStr += `${key}:${item},`;
|
|
1009
|
+
});
|
|
1010
|
+
// 删除最后一个逗号
|
|
1011
|
+
expressionStr = `{${expressionStr.slice(0, -1)}}`;
|
|
1012
|
+
}
|
|
1013
|
+
if (!isChinese(text)) {
|
|
1014
|
+
return;
|
|
1015
|
+
}
|
|
1016
|
+
context.report({
|
|
1017
|
+
node,
|
|
1018
|
+
messageId: "noSingleChinese",
|
|
1019
|
+
data: {
|
|
1020
|
+
raw: chalk.green(textSource),
|
|
1021
|
+
},
|
|
1022
|
+
// message: `TemplateLiteral`,
|
|
1023
|
+
fix: (fixer) => {
|
|
1024
|
+
// return console.log(text,expressionStr)
|
|
1025
|
+
// trimSpecial(text, (middle) => {
|
|
1026
|
+
// return `$hxt({key:'',desc:${middle}}${
|
|
1027
|
+
// expressionStr ? `,${expressionStr}` : ""
|
|
1028
|
+
// })`;
|
|
1029
|
+
// })
|
|
1030
|
+
// return
|
|
1031
|
+
return fixer.replaceText(
|
|
1032
|
+
node,
|
|
1033
|
+
trimSpecial(text, (middle) => {
|
|
1034
|
+
return `$hxt({key:'',desc:${middle}}${
|
|
1035
|
+
expressionStr ? `,${expressionStr}` : ""
|
|
1036
|
+
})`;
|
|
1037
|
+
})
|
|
1038
|
+
);
|
|
1039
|
+
},
|
|
1040
|
+
});
|
|
1041
|
+
}
|
|
1042
|
+
}
|
|
1043
|
+
},
|
|
1044
|
+
Literal(node) {
|
|
1045
|
+
// 如果正则忽略
|
|
1046
|
+
if (node.regex) return;
|
|
1047
|
+
if (!isTranslate(node)) {
|
|
1048
|
+
if (isChinese(node.value)) {
|
|
1049
|
+
// 增加{}包裹 render(){return <p title={'测试'} title="测试" title={`${1}测试`}>内容 {`测试`}</p>} 中的内容
|
|
1050
|
+
if (node.parent.type === "JSXAttribute") {
|
|
1051
|
+
context.report({
|
|
1052
|
+
node,
|
|
1053
|
+
messageId: "noSingleChinese",
|
|
1054
|
+
data: {
|
|
1055
|
+
raw: chalk.green(node.value),
|
|
1056
|
+
},
|
|
1057
|
+
fix: (fixer) => {
|
|
1058
|
+
return fixer.replaceText(
|
|
1059
|
+
node,
|
|
1060
|
+
trimSpecial(node.value, (middle) => {
|
|
1061
|
+
return "{$hxt({key:'',desc:'" + middle + "'})}";
|
|
1062
|
+
})
|
|
1063
|
+
);
|
|
1064
|
+
},
|
|
1065
|
+
});
|
|
1066
|
+
} else {
|
|
1067
|
+
context.report({
|
|
1068
|
+
node,
|
|
1069
|
+
messageId: "noSingleChinese",
|
|
1070
|
+
data: {
|
|
1071
|
+
raw: chalk.green(node.value),
|
|
1072
|
+
},
|
|
1073
|
+
fix: (fixer) => {
|
|
1074
|
+
return fixer.replaceText(
|
|
1075
|
+
node,
|
|
1076
|
+
trimSpecial(node.value, (middle) => {
|
|
1077
|
+
return "$hxt({key:'',desc:'" + middle + "'})";
|
|
1078
|
+
})
|
|
1079
|
+
);
|
|
1080
|
+
},
|
|
1081
|
+
});
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1085
|
+
},
|
|
1086
|
+
...emptyKeyRules(context),
|
|
1087
|
+
}
|
|
1088
|
+
);
|
|
1089
|
+
},
|
|
1090
|
+
};
|
|
1091
|
+
|
|
1092
|
+
/**
|
|
1093
|
+
* @fileoverview 不能单独金额
|
|
1094
|
+
* @author ypf
|
|
1095
|
+
*/
|
|
1096
|
+
|
|
1097
|
+
//------------------------------------------------------------------------------
|
|
1098
|
+
// Rule Definition
|
|
1099
|
+
//------------------------------------------------------------------------------
|
|
1100
|
+
|
|
1101
|
+
/** @type {import('eslint').Rule.RuleModule} */
|
|
1102
|
+
const inputTagNameList = [
|
|
1103
|
+
"el-input",
|
|
1104
|
+
"ElInput",
|
|
1105
|
+
"hx-input",
|
|
1106
|
+
"HxInput",
|
|
1107
|
+
"van-field",
|
|
1108
|
+
"VanField",
|
|
1109
|
+
"hxmb-field",
|
|
1110
|
+
"HxmbField",
|
|
1111
|
+
]; // input标签
|
|
1112
|
+
const formTagNameList = ["hx-form", "HxForm", "HxmForm", "hxmb-form"]; // form标签
|
|
1113
|
+
// 匹配金额名
|
|
1114
|
+
const currencyList = [
|
|
1115
|
+
// "currency",
|
|
1116
|
+
"total",
|
|
1117
|
+
"price",
|
|
1118
|
+
"amount",
|
|
1119
|
+
];
|
|
1120
|
+
// 价格后缀过滤
|
|
1121
|
+
const notIncludeCurrencySuffixList = [
|
|
1122
|
+
"code",
|
|
1123
|
+
"type",
|
|
1124
|
+
"no",
|
|
1125
|
+
"status",
|
|
1126
|
+
"name",
|
|
1127
|
+
"sort",
|
|
1128
|
+
"source",
|
|
1129
|
+
"qty",
|
|
1130
|
+
];
|
|
1131
|
+
// 关键字属性
|
|
1132
|
+
const keyPropList = ["prop", "name", "id", "key"];
|
|
1133
|
+
const hasCurrencyName = (str) => {
|
|
1134
|
+
return currencyList.some((item) => {
|
|
1135
|
+
str = str.toLowerCase();
|
|
1136
|
+
const suffix = str.split(item)[1]?.toLowerCase();
|
|
1137
|
+
if (str.includes(item)) {
|
|
1138
|
+
if(suffix){
|
|
1139
|
+
return !notIncludeCurrencySuffixList.some((item) =>
|
|
1140
|
+
suffix.includes(item)
|
|
1141
|
+
);
|
|
1142
|
+
}
|
|
1143
|
+
return true
|
|
1144
|
+
}
|
|
1145
|
+
return false;
|
|
1146
|
+
});
|
|
1147
|
+
};
|
|
1148
|
+
var noSingleCurrencyRule = {
|
|
1149
|
+
meta: {
|
|
1150
|
+
type: "suggestion", // `problem`, `suggestion`, or `layout`
|
|
1151
|
+
docs: {
|
|
1152
|
+
description: "不能单独金额",
|
|
1153
|
+
recommended: false,
|
|
1154
|
+
url: null, // URL to the documentation page for this rule
|
|
1155
|
+
},
|
|
1156
|
+
fixable: null, // Or `code` or `whitespace`
|
|
1157
|
+
schema: [], // Add a schema if the rule has options
|
|
1158
|
+
messages: {
|
|
1159
|
+
noSingleCurrency: "不要单独币种: {{raw}}",
|
|
1160
|
+
}, // Add messageId and message
|
|
1161
|
+
},
|
|
1162
|
+
|
|
1163
|
+
create(context) {
|
|
1164
|
+
const sourceCode = context.sourceCode;
|
|
1165
|
+
// 获取路径
|
|
1166
|
+
const filename = context.filename;
|
|
1167
|
+
return context.parserServices.defineTemplateBodyVisitor(
|
|
1168
|
+
// Event handlers for <template>.
|
|
1169
|
+
{
|
|
1170
|
+
// 模版标签, 如<el-input >
|
|
1171
|
+
VElement(node) {
|
|
1172
|
+
const tagName = node.rawName;
|
|
1173
|
+
if (inputTagNameList.indexOf(tagName) > -1) {
|
|
1174
|
+
const attrs = node.startTag.attributes;
|
|
1175
|
+
// 遍历找到v-model 属性
|
|
1176
|
+
attrs.some((attr) => {
|
|
1177
|
+
const attrTextSource = sourceCode.getText(attr);
|
|
1178
|
+
if (attr.key?.name?.name === "model") {
|
|
1179
|
+
const textSource = sourceCode.getText(attr.value);
|
|
1180
|
+
// 如果包含currency、price、amount,则报错
|
|
1181
|
+
if (hasCurrencyName(textSource)) {
|
|
1182
|
+
context.report({
|
|
1183
|
+
node,
|
|
1184
|
+
data: {
|
|
1185
|
+
raw:
|
|
1186
|
+
chalk.red(`Template|<${tagName}> `) +
|
|
1187
|
+
chalk.green(attrTextSource),
|
|
1188
|
+
},
|
|
1189
|
+
messageId: "noSingleCurrency",
|
|
1190
|
+
// message: `TemplateLiteral`,
|
|
1191
|
+
fix: (fixer) => {},
|
|
1192
|
+
});
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
return false;
|
|
1196
|
+
});
|
|
1197
|
+
}
|
|
1198
|
+
},
|
|
1199
|
+
},
|
|
1200
|
+
// Event handlers for <script> or scripts. (optional)
|
|
1201
|
+
{
|
|
1202
|
+
// jsx 标签,如 render() { return <el-input /> } 中的<el-input />
|
|
1203
|
+
// <el-form formItemList=[]>中的formItemList
|
|
1204
|
+
JSXElement(node) {
|
|
1205
|
+
// console.log(node,'node')
|
|
1206
|
+
const tagName = node?.openingElement?.name?.name;
|
|
1207
|
+
// input
|
|
1208
|
+
if (inputTagNameList.indexOf(tagName) > -1) {
|
|
1209
|
+
// 遍历找到vModel 属性
|
|
1210
|
+
const attrs = node.openingElement.attributes;
|
|
1211
|
+
attrs.some((attr) => {
|
|
1212
|
+
const attrTextSource = sourceCode.getText(attr);
|
|
1213
|
+
// console.log(attrTextSource,'attrTextSource')
|
|
1214
|
+
if (attr.name.name === "vModel") {
|
|
1215
|
+
const textSource = sourceCode.getText(attr.value);
|
|
1216
|
+
// 如果包含币种
|
|
1217
|
+
if (hasCurrencyName(textSource)) {
|
|
1218
|
+
context.report({
|
|
1219
|
+
node,
|
|
1220
|
+
data: {
|
|
1221
|
+
raw:
|
|
1222
|
+
chalk.red(`JSX|<${tagName}> `) +
|
|
1223
|
+
chalk.green(attrTextSource),
|
|
1224
|
+
},
|
|
1225
|
+
messageId: "noSingleCurrency",
|
|
1226
|
+
// message: `TemplateLiteral`,
|
|
1227
|
+
fix: (fixer) => {},
|
|
1228
|
+
});
|
|
1229
|
+
}
|
|
1230
|
+
}
|
|
1231
|
+
});
|
|
1232
|
+
}
|
|
1233
|
+
// form
|
|
1234
|
+
if (formTagNameList.indexOf(tagName)) {
|
|
1235
|
+
const attrs = node.openingElement.attributes;
|
|
1236
|
+
// 遍历找到formItemList 属性
|
|
1237
|
+
attrs.some((attr) => {
|
|
1238
|
+
sourceCode.getText(attr);
|
|
1239
|
+
// 是formItemList
|
|
1240
|
+
if (attr?.name?.name === "formItemList") {
|
|
1241
|
+
// 且值是数组
|
|
1242
|
+
if (attr?.value?.expression?.type === "ArrayExpression") {
|
|
1243
|
+
// 遍历数组
|
|
1244
|
+
attr.value.expression.elements.forEach((item) => {
|
|
1245
|
+
(item.properties || []).some((item) => {
|
|
1246
|
+
const attrTextSource = sourceCode.getText(item);
|
|
1247
|
+
if (keyPropList.indexOf(item.key.name) > -1) {
|
|
1248
|
+
const textSource = sourceCode.getText(item.value);
|
|
1249
|
+
if (item?.value?.type === "CallExpression") return;
|
|
1250
|
+
// 如果包含币种
|
|
1251
|
+
if (hasCurrencyName(textSource)) {
|
|
1252
|
+
context.report({
|
|
1253
|
+
node,
|
|
1254
|
+
data: {
|
|
1255
|
+
raw:
|
|
1256
|
+
chalk.red(`JSX|${tagName}|${attr.name.name} `) +
|
|
1257
|
+
chalk.green(`${attrTextSource}`),
|
|
1258
|
+
},
|
|
1259
|
+
messageId: "noSingleCurrency",
|
|
1260
|
+
// message: `TemplateLiteral`,
|
|
1261
|
+
fix: (fixer) => {},
|
|
1262
|
+
});
|
|
1263
|
+
}
|
|
1264
|
+
}
|
|
1265
|
+
});
|
|
1266
|
+
});
|
|
1267
|
+
}
|
|
1268
|
+
}
|
|
1269
|
+
});
|
|
1270
|
+
}
|
|
1271
|
+
},
|
|
1272
|
+
// [{prop:'price'}]
|
|
1273
|
+
ArrayExpression(node) {
|
|
1274
|
+
// 不检测路由文件
|
|
1275
|
+
if (filename.includes("src/router")) return;
|
|
1276
|
+
// 是数组且不是jsx属性上的数组(上面已经检测过了,否则会出现2条错误)
|
|
1277
|
+
if (node.parent?.parent?.type === "JSXAttribute") return;
|
|
1278
|
+
(node.elements || []).forEach((item) => {
|
|
1279
|
+
// 数组里面是对象
|
|
1280
|
+
if (item?.type === "ObjectExpression") {
|
|
1281
|
+
(item.properties || []).forEach((item) => {
|
|
1282
|
+
const attrTextSource = sourceCode.getText(item);
|
|
1283
|
+
if (keyPropList.indexOf(item?.key?.name) > -1) {
|
|
1284
|
+
if (item?.value?.type === "CallExpression") return;
|
|
1285
|
+
const textSource = sourceCode.getText(item.value);
|
|
1286
|
+
// 如果包含币种
|
|
1287
|
+
if (hasCurrencyName(textSource)) {
|
|
1288
|
+
context.report({
|
|
1289
|
+
node,
|
|
1290
|
+
data: {
|
|
1291
|
+
raw:
|
|
1292
|
+
chalk.red(`JSX|[{}] `) +
|
|
1293
|
+
chalk.green(`${attrTextSource}`),
|
|
1294
|
+
},
|
|
1295
|
+
messageId: "noSingleCurrency",
|
|
1296
|
+
});
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1299
|
+
});
|
|
1300
|
+
}
|
|
1301
|
+
});
|
|
1302
|
+
},
|
|
1303
|
+
}
|
|
1304
|
+
);
|
|
1305
|
+
},
|
|
1306
|
+
};
|
|
1307
|
+
|
|
1308
|
+
/**
|
|
1309
|
+
* @fileoverview 不能单独金额
|
|
1310
|
+
* @author ypf
|
|
1311
|
+
*/
|
|
1312
|
+
|
|
1313
|
+
//------------------------------------------------------------------------------
|
|
1314
|
+
// Rule Definition
|
|
1315
|
+
//------------------------------------------------------------------------------
|
|
1316
|
+
|
|
1317
|
+
/** @type {import('eslint').Rule.RuleModule} */
|
|
1318
|
+
const tagNameList = ["hx-search-list-page", "HxSearchListPage"];
|
|
1319
|
+
const attrNameList = ["custom-column-module", "customColumnModule"];
|
|
1320
|
+
const moduleArr = new Set();
|
|
1321
|
+
const getModuleArr = () => [...moduleArr];
|
|
1322
|
+
|
|
1323
|
+
var noSingleCustomColumnModule = {
|
|
1324
|
+
meta: {
|
|
1325
|
+
type: "suggestion", // `problem`, `suggestion`, or `layout`
|
|
1326
|
+
docs: {
|
|
1327
|
+
description: "不能单独自定义列",
|
|
1328
|
+
recommended: false,
|
|
1329
|
+
url: null, // URL to the documentation page for this rule
|
|
1330
|
+
},
|
|
1331
|
+
fixable: null, // Or `code` or `whitespace`
|
|
1332
|
+
schema: [], // Add a schema if the rule has options
|
|
1333
|
+
messages: {}, // Add messageId and message
|
|
1334
|
+
},
|
|
1335
|
+
|
|
1336
|
+
create(context) {
|
|
1337
|
+
const sourceCode = context.sourceCode;
|
|
1338
|
+
// 获取路径
|
|
1339
|
+
const fullPathName = context.filename;
|
|
1340
|
+
const cwd = context.cwd;
|
|
1341
|
+
const getPath = (loc = {}) => {
|
|
1342
|
+
const location = `${loc.start?.line}:${loc.start?.column} `;
|
|
1343
|
+
return location + fullPathName.replace(cwd, "");
|
|
1344
|
+
};
|
|
1345
|
+
return context.parserServices.defineTemplateBodyVisitor(
|
|
1346
|
+
// Event handlers for <template>.
|
|
1347
|
+
{
|
|
1348
|
+
// 模版标签,
|
|
1349
|
+
VElement(node) {
|
|
1350
|
+
const tagName = node.rawName;
|
|
1351
|
+
if (tagNameList.indexOf(tagName) > -1) {
|
|
1352
|
+
const attrs = node.startTag.attributes;
|
|
1353
|
+
attrs.some((attr) => {
|
|
1354
|
+
sourceCode.getText(attr);
|
|
1355
|
+
if (
|
|
1356
|
+
attrNameList.includes(attr.key?.argument?.rawName) &&
|
|
1357
|
+
attr.value?.expression?.type === "Literal"
|
|
1358
|
+
) {
|
|
1359
|
+
const value = attr.value.expression.value;
|
|
1360
|
+
moduleArr.add({
|
|
1361
|
+
module: value,
|
|
1362
|
+
path: getPath(attr.loc),
|
|
1363
|
+
});
|
|
1364
|
+
} else if (
|
|
1365
|
+
attrNameList.includes(attr.key?.rawName) &&
|
|
1366
|
+
attr.value.type === "VLiteral"
|
|
1367
|
+
) {
|
|
1368
|
+
const value = attr.value.value;
|
|
1369
|
+
moduleArr.add({
|
|
1370
|
+
module: +value,
|
|
1371
|
+
path: getPath(attr.loc),
|
|
1372
|
+
});
|
|
1373
|
+
} else if (
|
|
1374
|
+
attrNameList.includes(attr.key?.argument?.rawName) ||
|
|
1375
|
+
attrNameList.includes(attr.key?.rawName)
|
|
1376
|
+
) {
|
|
1377
|
+
moduleArr.add({
|
|
1378
|
+
module: sourceCode.getText(attr.value.expression),
|
|
1379
|
+
path: getPath(attr.loc),
|
|
1380
|
+
isDynamics: true, // 变量
|
|
1381
|
+
});
|
|
1382
|
+
}
|
|
1383
|
+
return false;
|
|
1384
|
+
});
|
|
1385
|
+
}
|
|
1386
|
+
},
|
|
1387
|
+
},
|
|
1388
|
+
// Event handlers for <script> or scripts. (optional)
|
|
1389
|
+
{
|
|
1390
|
+
JSXElement(node) {
|
|
1391
|
+
const tagName = node?.openingElement?.name?.name;
|
|
1392
|
+
if (tagNameList.indexOf(tagName) > -1) {
|
|
1393
|
+
// 遍历找到customColumnModule 属性
|
|
1394
|
+
const attrs = node.openingElement.attributes;
|
|
1395
|
+
attrs.some((attr) => {
|
|
1396
|
+
sourceCode.getText(attr);
|
|
1397
|
+
if (attrNameList.includes(attr?.name?.name)) {
|
|
1398
|
+
if (attr.value?.expression?.type === "Literal") {
|
|
1399
|
+
const value = attr.value.expression.value;
|
|
1400
|
+
moduleArr.add({
|
|
1401
|
+
module: value,
|
|
1402
|
+
path: getPath(attr.loc),
|
|
1403
|
+
});
|
|
1404
|
+
} else {
|
|
1405
|
+
moduleArr.add({
|
|
1406
|
+
module: sourceCode.getText(attr.value.expression),
|
|
1407
|
+
path: getPath(attr.loc),
|
|
1408
|
+
isDynamics: true, // 变量
|
|
1409
|
+
});
|
|
1410
|
+
}
|
|
1411
|
+
}
|
|
1412
|
+
});
|
|
1413
|
+
}
|
|
1414
|
+
},
|
|
1415
|
+
}
|
|
1416
|
+
);
|
|
1417
|
+
},
|
|
1418
|
+
};
|
|
1419
|
+
|
|
1420
|
+
/**
|
|
1421
|
+
* @fileoverview 国际化
|
|
1422
|
+
* @author ypf
|
|
1423
|
+
*/
|
|
1424
|
+
const require$1 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.src || new URL('index.js', document.baseURI).href)));
|
|
1425
|
+
const VueESlintParserPath = require$1.resolve('vue-eslint-parser');
|
|
1426
|
+
const meta = {
|
|
1427
|
+
name: "eslint-plugin-i18n",
|
|
1428
|
+
version: "1.0.0",
|
|
1429
|
+
};
|
|
1430
|
+
var i18n = {
|
|
1431
|
+
rules: {
|
|
1432
|
+
"no-single-chinese": noSingleChineseRule,
|
|
1433
|
+
"no-single-currency": noSingleCurrencyRule,
|
|
1434
|
+
"no-single-customColumnModule": noSingleCustomColumnModule,
|
|
1435
|
+
},
|
|
1436
|
+
processors: {},
|
|
1437
|
+
configs: {
|
|
1438
|
+
recommended: {
|
|
1439
|
+
// 插件
|
|
1440
|
+
plugins: [
|
|
1441
|
+
"i18n", // 可以省略eslint-plugin-
|
|
1442
|
+
],
|
|
1443
|
+
rules: {
|
|
1444
|
+
"i18n/no-single-chinese": "warn",
|
|
1445
|
+
"i18n/no-single-currency": "warn",
|
|
1446
|
+
"i18n/no-single-customColumnModule": "warn",
|
|
1447
|
+
},
|
|
1448
|
+
// parser: "vue-eslint-parser",
|
|
1449
|
+
parser: VueESlintParserPath, // 文档中是只能字符串
|
|
1450
|
+
parserOptions: {
|
|
1451
|
+
ecmaVersion: "latest", // 指定你想要使用的 ECMAScript 版本
|
|
1452
|
+
sourceType: "module", // 支持脚本类型为模块,否则不支持import/export
|
|
1453
|
+
ecmaFeatures: {
|
|
1454
|
+
jsx: true,
|
|
1455
|
+
},
|
|
1456
|
+
parser: {
|
|
1457
|
+
js: espree__namespace,
|
|
1458
|
+
jsx: espree__namespace, // 支持jsx语法
|
|
1459
|
+
// ts: tsParser,
|
|
1460
|
+
// tsx: tsParser,
|
|
1461
|
+
},
|
|
1462
|
+
},
|
|
1463
|
+
},
|
|
1464
|
+
},
|
|
1465
|
+
};
|
|
1466
|
+
|
|
1467
|
+
// https://www.npmjs.com/package/text-table?activeTab=readme
|
|
1468
|
+
|
|
1469
|
+
function table (rows_, opts) {
|
|
1470
|
+
if (!opts) opts = {};
|
|
1471
|
+
var hsep = opts.hsep === undefined ? " " : opts.hsep;
|
|
1472
|
+
var align = opts.align || [];
|
|
1473
|
+
var stringLength =
|
|
1474
|
+
opts.stringLength ||
|
|
1475
|
+
function (s) {
|
|
1476
|
+
return String(s).length;
|
|
1477
|
+
};
|
|
1478
|
+
var dotsizes = reduce(
|
|
1479
|
+
rows_,
|
|
1480
|
+
function (acc, row) {
|
|
1481
|
+
forEach(row, function (c, ix) {
|
|
1482
|
+
var n = dotindex(c);
|
|
1483
|
+
if (!acc[ix] || n > acc[ix]) acc[ix] = n;
|
|
1484
|
+
});
|
|
1485
|
+
return acc;
|
|
1486
|
+
},
|
|
1487
|
+
[]
|
|
1488
|
+
);
|
|
1489
|
+
|
|
1490
|
+
var rows = map(rows_, function (row) {
|
|
1491
|
+
return map(row, function (c_, ix) {
|
|
1492
|
+
var c = String(c_);
|
|
1493
|
+
if (align[ix] === ".") {
|
|
1494
|
+
var index = dotindex(c);
|
|
1495
|
+
var size =
|
|
1496
|
+
dotsizes[ix] + (/\./.test(c) ? 1 : 2) - (stringLength(c) - index);
|
|
1497
|
+
return c + Array(size).join(" ");
|
|
1498
|
+
} else return c;
|
|
1499
|
+
});
|
|
1500
|
+
});
|
|
1501
|
+
|
|
1502
|
+
var sizes = reduce(
|
|
1503
|
+
rows,
|
|
1504
|
+
function (acc, row) {
|
|
1505
|
+
forEach(row, function (c, ix) {
|
|
1506
|
+
var n = stringLength(c);
|
|
1507
|
+
if (!acc[ix] || n > acc[ix]) acc[ix] = n;
|
|
1508
|
+
});
|
|
1509
|
+
return acc;
|
|
1510
|
+
},
|
|
1511
|
+
[]
|
|
1512
|
+
);
|
|
1513
|
+
|
|
1514
|
+
return map(rows, function (row) {
|
|
1515
|
+
return map(row, function (c, ix) {
|
|
1516
|
+
var n = sizes[ix] - stringLength(c) || 0;
|
|
1517
|
+
var s = Array(Math.max(n + 1, 1)).join(" ");
|
|
1518
|
+
if (align[ix] === "r" || align[ix] === ".") {
|
|
1519
|
+
return s + c;
|
|
1520
|
+
}
|
|
1521
|
+
if (align[ix] === "c") {
|
|
1522
|
+
return (
|
|
1523
|
+
Array(Math.ceil(n / 2 + 1)).join(" ") +
|
|
1524
|
+
c +
|
|
1525
|
+
Array(Math.floor(n / 2 + 1)).join(" ")
|
|
1526
|
+
);
|
|
1527
|
+
}
|
|
1528
|
+
|
|
1529
|
+
return c + s;
|
|
1530
|
+
})
|
|
1531
|
+
.join(hsep)
|
|
1532
|
+
.replace(/\s+$/, "");
|
|
1533
|
+
}).join("\n");
|
|
1534
|
+
}
|
|
1535
|
+
|
|
1536
|
+
function dotindex(c) {
|
|
1537
|
+
var m = /\.[^.]*$/.exec(c);
|
|
1538
|
+
return m ? m.index + 1 : c.length;
|
|
1539
|
+
}
|
|
1540
|
+
|
|
1541
|
+
function reduce(xs, f, init) {
|
|
1542
|
+
if (xs.reduce) return xs.reduce(f, init);
|
|
1543
|
+
var i = 0;
|
|
1544
|
+
var acc = arguments.length >= 3 ? init : xs[i++];
|
|
1545
|
+
for (; i < xs.length; i++) {
|
|
1546
|
+
f(acc, xs[i], i);
|
|
1547
|
+
}
|
|
1548
|
+
return acc;
|
|
1549
|
+
}
|
|
1550
|
+
|
|
1551
|
+
function forEach(xs, f) {
|
|
1552
|
+
if (xs.forEach) return xs.forEach(f);
|
|
1553
|
+
for (var i = 0; i < xs.length; i++) {
|
|
1554
|
+
f.call(xs, xs[i], i);
|
|
1555
|
+
}
|
|
1556
|
+
}
|
|
1557
|
+
|
|
1558
|
+
function map(xs, f) {
|
|
1559
|
+
if (xs.map) return xs.map(f);
|
|
1560
|
+
var res = [];
|
|
1561
|
+
for (var i = 0; i < xs.length; i++) {
|
|
1562
|
+
res.push(f.call(xs, xs[i], i));
|
|
1563
|
+
}
|
|
1564
|
+
return res;
|
|
1565
|
+
}
|
|
1566
|
+
|
|
1567
|
+
//------------------------------------------------------------------------------
|
|
1568
|
+
|
|
1569
|
+
/**
|
|
1570
|
+
* Given a word and a count, append an s if count is not one.
|
|
1571
|
+
* @param {string} word A word in its singular form.
|
|
1572
|
+
* @param {int} count A number controlling whether word should be pluralized.
|
|
1573
|
+
* @returns {string} The original word with an s on the end if count is not one.
|
|
1574
|
+
*/
|
|
1575
|
+
function pluralize(word, count) {
|
|
1576
|
+
return (count === 1 ? word : `${word}s`);
|
|
1577
|
+
}
|
|
1578
|
+
|
|
1579
|
+
//------------------------------------------------------------------------------
|
|
1580
|
+
// Public Interface
|
|
1581
|
+
//------------------------------------------------------------------------------
|
|
1582
|
+
|
|
1583
|
+
function stylish(results) {
|
|
1584
|
+
|
|
1585
|
+
let output = "\n",
|
|
1586
|
+
errorCount = 0,
|
|
1587
|
+
warningCount = 0,
|
|
1588
|
+
fixableErrorCount = 0,
|
|
1589
|
+
fixableWarningCount = 0,
|
|
1590
|
+
summaryColor = "yellow";
|
|
1591
|
+
results.forEach(result => {
|
|
1592
|
+
const messages = result.messages;
|
|
1593
|
+
|
|
1594
|
+
if (messages.length === 0) {
|
|
1595
|
+
return;
|
|
1596
|
+
}
|
|
1597
|
+
|
|
1598
|
+
errorCount += result.errorCount;
|
|
1599
|
+
warningCount += result.warningCount;
|
|
1600
|
+
fixableErrorCount += result.fixableErrorCount;
|
|
1601
|
+
fixableWarningCount += result.fixableWarningCount;
|
|
1602
|
+
|
|
1603
|
+
output += `${chalk.underline(result.filePath)}\n`;
|
|
1604
|
+
|
|
1605
|
+
output += `${table(
|
|
1606
|
+
messages.map(message => {
|
|
1607
|
+
let messageType;
|
|
1608
|
+
|
|
1609
|
+
if (message.fatal || message.severity === 2) {
|
|
1610
|
+
messageType = chalk.red("error");
|
|
1611
|
+
summaryColor = "red";
|
|
1612
|
+
} else {
|
|
1613
|
+
messageType = chalk.yellow("warning");
|
|
1614
|
+
}
|
|
1615
|
+
|
|
1616
|
+
return [
|
|
1617
|
+
"",
|
|
1618
|
+
message.line || 0,
|
|
1619
|
+
message.column || 0,
|
|
1620
|
+
messageType,
|
|
1621
|
+
message.message.replace(/([^ ])\.$/u, "$1"),
|
|
1622
|
+
chalk.dim(message.ruleId || "")
|
|
1623
|
+
];
|
|
1624
|
+
}),
|
|
1625
|
+
{
|
|
1626
|
+
align: ["", "r", "l"],
|
|
1627
|
+
stringLength(str) {
|
|
1628
|
+
return stripAnsi(str).length;
|
|
1629
|
+
}
|
|
1630
|
+
}
|
|
1631
|
+
).split("\n").map(el => el.replace(/(\d+)\s+(\d+)/u, (m, p1, p2) => chalk.dim(`${p1}:${p2}`))).join("\n")}\n\n`;
|
|
1632
|
+
});
|
|
1633
|
+
|
|
1634
|
+
const total = errorCount + warningCount;
|
|
1635
|
+
|
|
1636
|
+
if (total > 0) {
|
|
1637
|
+
output += chalk[summaryColor].bold([
|
|
1638
|
+
"\u2716 ", total, pluralize(" problem", total),
|
|
1639
|
+
" (", errorCount, pluralize(" error", errorCount), ", ",
|
|
1640
|
+
warningCount, pluralize(" warning", warningCount), ")\n"
|
|
1641
|
+
].join(""));
|
|
1642
|
+
|
|
1643
|
+
if (fixableErrorCount > 0 || fixableWarningCount > 0) {
|
|
1644
|
+
output += chalk[summaryColor].bold([
|
|
1645
|
+
" ", fixableErrorCount, pluralize(" error", fixableErrorCount), " and ",
|
|
1646
|
+
fixableWarningCount, pluralize(" warning", fixableWarningCount),
|
|
1647
|
+
" potentially fixable with the `--fix` option.\n"
|
|
1648
|
+
].join(""));
|
|
1649
|
+
}
|
|
1650
|
+
}
|
|
1651
|
+
|
|
1652
|
+
// Resets output color, for prevent change on top level
|
|
1653
|
+
return total > 0 ? chalk.reset(output) : "";
|
|
1654
|
+
}
|
|
1655
|
+
|
|
1656
|
+
async function lint$1(patterns, fix, rule, hook = {}) {
|
|
1657
|
+
const rules$1 = {
|
|
1658
|
+
"i18n/no-single-chinese": rule ? "off" : "warn",
|
|
1659
|
+
};
|
|
1660
|
+
rules[0].choices.forEach((item) => {
|
|
1661
|
+
rules$1[`i18n/no-single-${item.value}`] = "off";
|
|
1662
|
+
if (item.children) {
|
|
1663
|
+
item.children.forEach((child) => {
|
|
1664
|
+
child.choices.forEach((item) => {
|
|
1665
|
+
rules$1[`i18n/no-single-${item.value}`] = "off";
|
|
1666
|
+
});
|
|
1667
|
+
});
|
|
1668
|
+
}
|
|
1669
|
+
});
|
|
1670
|
+
if (rule) {
|
|
1671
|
+
rules$1[`i18n/no-single-${rule}`] = "warn";
|
|
1672
|
+
}
|
|
1673
|
+
const eslint$1 = new eslint.ESLint({
|
|
1674
|
+
useEslintrc: false, // 不检测其他规则,只检测i18n规则, 不设置为false,则会检测项目中的.eslintrc.js文件规则
|
|
1675
|
+
// 只检测js,jsx,vue文件
|
|
1676
|
+
extensions: [".js", ".jsx", ".vue"],
|
|
1677
|
+
fix: fix || false, // 是否自动修复
|
|
1678
|
+
overrideConfigFile: null,
|
|
1679
|
+
plugins: { [meta.name]: i18n }, // 必须写,下面的extends才能识别, 和配置文件那种不一样,配置文件那种只写extends就行,不用写plugins
|
|
1680
|
+
overrideConfig: {
|
|
1681
|
+
extends: [
|
|
1682
|
+
"plugin:i18n/recommended", // 表示使用test插件的推荐规则, plugin:后不能有空格,否则不生效
|
|
1683
|
+
],
|
|
1684
|
+
// 此处增加rules是为了动态判断覆盖extends中的rule级别
|
|
1685
|
+
rules: rules$1,
|
|
1686
|
+
},
|
|
1687
|
+
});
|
|
1688
|
+
Loading$1.start(`检测中...`);
|
|
1689
|
+
try {
|
|
1690
|
+
// 检查文件
|
|
1691
|
+
const results = await eslint$1.lintFiles(patterns);
|
|
1692
|
+
hook.lintFilesAfter && (await hook.lintFilesAfter(results,Loading$1));
|
|
1693
|
+
if (!fix) {
|
|
1694
|
+
// 判断是否有匹配到错误
|
|
1695
|
+
const hasErrors = results.some(
|
|
1696
|
+
(result) => result.messages && result.messages.length
|
|
1697
|
+
);
|
|
1698
|
+
if (!hasErrors) {
|
|
1699
|
+
return Loading$1.succeed(`没有要修复的错误`);
|
|
1700
|
+
}
|
|
1701
|
+
Loading$1.succeed(`检测完成`);
|
|
1702
|
+
// 如果没有fix,则直接输出错误
|
|
1703
|
+
return console.log(stylish(results));
|
|
1704
|
+
}
|
|
1705
|
+
// 判断是否有匹配到错误
|
|
1706
|
+
const hasErrors1 = results.some(
|
|
1707
|
+
(result) => result.output || result.warningCount
|
|
1708
|
+
);
|
|
1709
|
+
if (!hasErrors1) {
|
|
1710
|
+
return Loading$1.succeed(`没有要修复的错误`);
|
|
1711
|
+
}
|
|
1712
|
+
// 输出回原文件
|
|
1713
|
+
await eslint.ESLint.outputFixes(results);
|
|
1714
|
+
Loading$1.succeed(`替换空key完成`);
|
|
1715
|
+
inquirer
|
|
1716
|
+
.prompt([
|
|
1717
|
+
{
|
|
1718
|
+
message: `是否开始翻译key`,
|
|
1719
|
+
name: "isTransKey",
|
|
1720
|
+
type: "confirm",
|
|
1721
|
+
default: true,
|
|
1722
|
+
},
|
|
1723
|
+
])
|
|
1724
|
+
.then(({ isTransKey }) => {
|
|
1725
|
+
if (isTransKey) {
|
|
1726
|
+
console.log(chalk.green(`开始准备翻译...`));
|
|
1727
|
+
process$1.execSync(`fe-it-alpha --fix -i ${patterns} `, {
|
|
1728
|
+
stdio: "inherit", // 打印子进程的输出到父进程
|
|
1729
|
+
});
|
|
1730
|
+
}
|
|
1731
|
+
});
|
|
1732
|
+
} catch (error) {
|
|
1733
|
+
Loading$1.fail(`检测失败`);
|
|
1734
|
+
console.error(chalk.red(error));
|
|
1735
|
+
}
|
|
1736
|
+
}
|
|
1737
|
+
|
|
1738
|
+
const condition = {
|
|
1739
|
+
currency: hasCurrencyName,
|
|
1740
|
+
};
|
|
1741
|
+
async function customColumnModule (lintc, fix, rule, parentRule) {
|
|
1742
|
+
const { way } = await inquirer.prompt([
|
|
1743
|
+
{
|
|
1744
|
+
message: "请选择检测自定义列方式",
|
|
1745
|
+
name: "way",
|
|
1746
|
+
type: "list",
|
|
1747
|
+
choices: [
|
|
1748
|
+
{
|
|
1749
|
+
name: "自动检测HxSearchListPage的自定义列ID",
|
|
1750
|
+
value: "normal",
|
|
1751
|
+
},
|
|
1752
|
+
{
|
|
1753
|
+
name: "自定义输入",
|
|
1754
|
+
value: "input",
|
|
1755
|
+
},
|
|
1756
|
+
],
|
|
1757
|
+
},
|
|
1758
|
+
]);
|
|
1759
|
+
if (way === "normal") {
|
|
1760
|
+
lint$1(lintc, fix, "customColumnModule", {
|
|
1761
|
+
lintFilesAfter: (results, Loading) => {
|
|
1762
|
+
const arr = getModuleArr();
|
|
1763
|
+
const dynamicsArr = arr.filter((item) => item.isDynamics);
|
|
1764
|
+
const normalArr = arr.filter((item) => !item.isDynamics);
|
|
1765
|
+
|
|
1766
|
+
return new Promise((resolve) => {
|
|
1767
|
+
Loading.succeed(`检测完成,${arr.length?'':'未'}匹配到规则`);
|
|
1768
|
+
if (arr.length) {
|
|
1769
|
+
getColumn(normalArr, dynamicsArr, parentRule);
|
|
1770
|
+
}
|
|
1771
|
+
});
|
|
1772
|
+
},
|
|
1773
|
+
});
|
|
1774
|
+
} else if (way === "input") {
|
|
1775
|
+
const { customColumnId } = await inquirer.prompt([
|
|
1776
|
+
{
|
|
1777
|
+
message: "请输入自定义列ID,格式为xx,xx,xx",
|
|
1778
|
+
name: "customColumnId",
|
|
1779
|
+
type: "input",
|
|
1780
|
+
},
|
|
1781
|
+
]);
|
|
1782
|
+
const moduleArr = customColumnId.split(",").map((item) => {
|
|
1783
|
+
return {
|
|
1784
|
+
module: item,
|
|
1785
|
+
path: "NA",
|
|
1786
|
+
};
|
|
1787
|
+
});
|
|
1788
|
+
getColumn(moduleArr, [], parentRule);
|
|
1789
|
+
}
|
|
1790
|
+
}
|
|
1791
|
+
|
|
1792
|
+
async function getColumn(moduleArr = [], dynamicsArr = [],parentRule) {
|
|
1793
|
+
const token = await login({
|
|
1794
|
+
env: "sit",
|
|
1795
|
+
username: "superAdmin",
|
|
1796
|
+
password: "admin1",
|
|
1797
|
+
});
|
|
1798
|
+
const requestArr = moduleArr.map(({ module, path }) =>
|
|
1799
|
+
request$1({
|
|
1800
|
+
url: `http://sit-hxjf.hongxinshop.com/api-item/api/customizedColumns/find`,
|
|
1801
|
+
method: "POST",
|
|
1802
|
+
json: true,
|
|
1803
|
+
body: { module },
|
|
1804
|
+
headers: {
|
|
1805
|
+
Authorization: `Bearer ${token}`,
|
|
1806
|
+
"x-request-vaildate": "open",
|
|
1807
|
+
},
|
|
1808
|
+
})
|
|
1809
|
+
);
|
|
1810
|
+
Promise.allSettled(requestArr).then(async (res) => {
|
|
1811
|
+
const tableData = [];
|
|
1812
|
+
res.forEach(({ value, status }, index) => {
|
|
1813
|
+
const { path, module } = moduleArr[index];
|
|
1814
|
+
if (status === "fulfilled") {
|
|
1815
|
+
const { data } = value;
|
|
1816
|
+
const { showColumns, hiddenColumns } = data;
|
|
1817
|
+
let fieldArr = [];
|
|
1818
|
+
showColumns.concat(hiddenColumns).forEach((item) => {
|
|
1819
|
+
if (condition[parentRule](item.showField)) {
|
|
1820
|
+
fieldArr.push(`${item.showField} ${item.showName}`);
|
|
1821
|
+
}
|
|
1822
|
+
});
|
|
1823
|
+
if (fieldArr.length) {
|
|
1824
|
+
fieldArr.forEach((item, index) => {
|
|
1825
|
+
let obj = {
|
|
1826
|
+
module,
|
|
1827
|
+
field: item,
|
|
1828
|
+
path,
|
|
1829
|
+
};
|
|
1830
|
+
if (index !== 0) {
|
|
1831
|
+
// obj.module = module;
|
|
1832
|
+
// obj.path = path;
|
|
1833
|
+
delete obj.module;
|
|
1834
|
+
delete obj.path;
|
|
1835
|
+
}
|
|
1836
|
+
tableData.push(obj);
|
|
1837
|
+
});
|
|
1838
|
+
} else {
|
|
1839
|
+
tableData.push({
|
|
1840
|
+
module,
|
|
1841
|
+
field: "NA",
|
|
1842
|
+
path,
|
|
1843
|
+
});
|
|
1844
|
+
}
|
|
1845
|
+
} else {
|
|
1846
|
+
tableData.push({
|
|
1847
|
+
module,
|
|
1848
|
+
field: "error",
|
|
1849
|
+
path,
|
|
1850
|
+
});
|
|
1851
|
+
}
|
|
1852
|
+
});
|
|
1853
|
+
// 合并动态模块
|
|
1854
|
+
dynamicsArr.forEach((item) => {
|
|
1855
|
+
tableData.push({
|
|
1856
|
+
module: item.module,
|
|
1857
|
+
field: "error",
|
|
1858
|
+
path: item.path,
|
|
1859
|
+
});
|
|
1860
|
+
});
|
|
1861
|
+
// 排序, field为NA和error的排在后面
|
|
1862
|
+
tableData.sort((a, b) => {
|
|
1863
|
+
if (["NA", "error"].includes(b.field)) {
|
|
1864
|
+
return -1;
|
|
1865
|
+
} else {
|
|
1866
|
+
return 1;
|
|
1867
|
+
}
|
|
1868
|
+
});
|
|
1869
|
+
const successTableData = []; // 成功的数据
|
|
1870
|
+
const naTableData = [];
|
|
1871
|
+
const noNaTableData = [];
|
|
1872
|
+
const errorTableData = []; // 失败的数据
|
|
1873
|
+
tableData.forEach((item) => {
|
|
1874
|
+
if (item.field === "error") {
|
|
1875
|
+
errorTableData.push(item);
|
|
1876
|
+
} else {
|
|
1877
|
+
if (item.field === "NA") {
|
|
1878
|
+
naTableData.push(item);
|
|
1879
|
+
} else {
|
|
1880
|
+
noNaTableData.push(item);
|
|
1881
|
+
}
|
|
1882
|
+
successTableData.push(item);
|
|
1883
|
+
}
|
|
1884
|
+
});
|
|
1885
|
+
|
|
1886
|
+
console.log(
|
|
1887
|
+
chalk.green(
|
|
1888
|
+
`共${tableData.length}个moduleId, 成功${
|
|
1889
|
+
successTableData.length
|
|
1890
|
+
}个(规则命中${noNaTableData.length}个, ${chalk.yellow(
|
|
1891
|
+
`未命中${naTableData.length}个`
|
|
1892
|
+
)}),`
|
|
1893
|
+
) + chalk.red(`失败${errorTableData.length}个`)
|
|
1894
|
+
);
|
|
1895
|
+
if (noNaTableData.length) {
|
|
1896
|
+
console.log(chalk.green(`成功命中规则`));
|
|
1897
|
+
console.table(noNaTableData);
|
|
1898
|
+
}
|
|
1899
|
+
if (errorTableData.length) {
|
|
1900
|
+
console.log(chalk.red(`失败,需手动处理或重试`));
|
|
1901
|
+
console.table(errorTableData);
|
|
1902
|
+
}
|
|
1903
|
+
if (naTableData.length) {
|
|
1904
|
+
console.log(chalk.yellow(`成功但未命中规则,无需处理`));
|
|
1905
|
+
console.table(naTableData);
|
|
1906
|
+
}
|
|
1907
|
+
});
|
|
1908
|
+
}
|
|
1909
|
+
|
|
1910
|
+
// import packageJson from "../package.json" assert { type: "json" };
|
|
1911
|
+
const { version } = getPackageJson();
|
|
1912
|
+
// const spinner = ora();
|
|
1913
|
+
commander.program.version(version);
|
|
1914
|
+
commander.program.option("-i, --input <type>", "翻译空key");
|
|
1915
|
+
// command('merge')
|
|
1916
|
+
// .option("-i, --input <type>" , "翻译空key")
|
|
1917
|
+
// .option("-m, --merge" , "输出文件").action((options) => {
|
|
1918
|
+
// console.log('merge', options)
|
|
1919
|
+
// })
|
|
1920
|
+
// 上传翻译
|
|
1921
|
+
commander.program.option("-u, --upload", "上传翻译包");
|
|
1922
|
+
// 同步sass应用权限配置
|
|
1923
|
+
commander.program.option("-sass, --sass", "同步sass按钮权限配置");
|
|
1924
|
+
// 检测未$hxt中文
|
|
1925
|
+
commander.program.option("-lint, --lint <patterns>", "检测未$hxt的中文");
|
|
1926
|
+
// 检测配置项
|
|
1927
|
+
commander.program.option("-lintc, --lintc <patterns>", "检测指定配置规则");
|
|
1928
|
+
// 检测未$hxt中文自动修复
|
|
1929
|
+
commander.program.option("--fix", "修复lint检出的错误");
|
|
1930
|
+
commander.program.parse(process.argv);
|
|
1931
|
+
|
|
1932
|
+
// 判断命令参数
|
|
1933
|
+
const { input, sass, upload, lint, lintc, fix } = commander.program.opts();
|
|
1934
|
+
const rules = [
|
|
1935
|
+
{
|
|
1936
|
+
message: "请选择检查规则",
|
|
1937
|
+
name: "rule",
|
|
1938
|
+
type: "list",
|
|
1939
|
+
choices: [
|
|
1940
|
+
{
|
|
1941
|
+
name: "币种",
|
|
1942
|
+
value: "currency",
|
|
1943
|
+
children: [
|
|
1944
|
+
{
|
|
1945
|
+
message: "请选择场景",
|
|
1946
|
+
name: "scene",
|
|
1947
|
+
type: "list",
|
|
1948
|
+
choices: [
|
|
1949
|
+
{
|
|
1950
|
+
name: "匹配属性名含有price、total、amount金额字段",
|
|
1951
|
+
value: "currency",
|
|
1952
|
+
},
|
|
1953
|
+
{
|
|
1954
|
+
name: "自定义列",
|
|
1955
|
+
value: "customColumnModule",
|
|
1956
|
+
},
|
|
1957
|
+
],
|
|
1958
|
+
},
|
|
1959
|
+
],
|
|
1960
|
+
},
|
|
1961
|
+
],
|
|
1962
|
+
},
|
|
1963
|
+
];
|
|
1964
|
+
if (sass) {
|
|
1965
|
+
syncSassConfig();
|
|
1966
|
+
} else if (upload) {
|
|
1967
|
+
upload$1();
|
|
1968
|
+
} else if (lint) {
|
|
1969
|
+
lint$1(lint, fix);
|
|
1970
|
+
} else if (lintc) {
|
|
1971
|
+
inquirer.prompt(rules).then(async ({ rule }) => {
|
|
1972
|
+
const parentRule =rule;
|
|
1973
|
+
if (rule === "currency") {
|
|
1974
|
+
const ruleChoice = rules.find((item) => item.name === "rule");
|
|
1975
|
+
const currencySubChoice = ruleChoice.choices.find(
|
|
1976
|
+
(item) => item.value === "currency"
|
|
1977
|
+
).children;
|
|
1978
|
+
const { scene } = await inquirer.prompt(currencySubChoice);
|
|
1979
|
+
rule = scene;
|
|
1980
|
+
if(rule==='customColumnModule'){
|
|
1981
|
+
return customColumnModule(lintc,fix,rule,parentRule)
|
|
1982
|
+
}
|
|
1983
|
+
}
|
|
1984
|
+
lint$1(lintc, fix, rule);
|
|
1985
|
+
});
|
|
1986
|
+
} else {
|
|
1987
|
+
let projectName = "请在package.json中配置name字段(项目名称)";
|
|
1988
|
+
const projectPath = "./package.json";
|
|
1989
|
+
const isExist = isExistPath(projectPath);
|
|
1990
|
+
if (isExist) {
|
|
1991
|
+
const str = fs.readFileSync(projectPath, "utf-8").toString();
|
|
1992
|
+
projectName = JSON.parse(str).name;
|
|
1993
|
+
}
|
|
1994
|
+
inquirer
|
|
1995
|
+
.prompt([
|
|
1996
|
+
{
|
|
1997
|
+
message: `请确认package.json中项目名称是否是${projectName}`,
|
|
1998
|
+
name: "isProjectName",
|
|
1999
|
+
type: "confirm",
|
|
2000
|
+
default: true,
|
|
2001
|
+
},
|
|
2002
|
+
])
|
|
2003
|
+
.then((res) => {
|
|
2004
|
+
if (res.isProjectName) {
|
|
2005
|
+
inquirer
|
|
2006
|
+
.prompt([
|
|
2007
|
+
{
|
|
2008
|
+
message: "请选择翻译接口",
|
|
2009
|
+
name: "type",
|
|
2010
|
+
type: "list",
|
|
2011
|
+
choices: [
|
|
2012
|
+
{
|
|
2013
|
+
name: "百度翻译",
|
|
2014
|
+
value: "baidu",
|
|
2015
|
+
},
|
|
2016
|
+
],
|
|
2017
|
+
},
|
|
2018
|
+
])
|
|
2019
|
+
.then((res) => {
|
|
2020
|
+
const { type } = res;
|
|
2021
|
+
let cacheSecret = {};
|
|
2022
|
+
if (!isExistPath(getRunCliPath({ root: true }) + "/.cache")) {
|
|
2023
|
+
fs.mkdirSync(getRunCliPath({ root: true }) + "/.cache");
|
|
2024
|
+
}
|
|
2025
|
+
const cacheFilePath =
|
|
2026
|
+
getRunCliPath({ root: true }) + "/.cache/" + res.type;
|
|
2027
|
+
if (isExistPath(cacheFilePath)) {
|
|
2028
|
+
const cache = JSON.parse(readCache(res.type));
|
|
2029
|
+
cacheSecret = cache;
|
|
2030
|
+
}
|
|
2031
|
+
const question = [
|
|
2032
|
+
{
|
|
2033
|
+
message: "请输入百度翻译的appid",
|
|
2034
|
+
name: "appid",
|
|
2035
|
+
default: cacheSecret.appid,
|
|
2036
|
+
// 必填
|
|
2037
|
+
validate: function (val) {
|
|
2038
|
+
if (val) {
|
|
2039
|
+
return true;
|
|
2040
|
+
}
|
|
2041
|
+
return "请输入百度翻译的appid";
|
|
2042
|
+
},
|
|
2043
|
+
},
|
|
2044
|
+
{
|
|
2045
|
+
message: "请输入百度翻译的key",
|
|
2046
|
+
name: "key",
|
|
2047
|
+
default: cacheSecret.key,
|
|
2048
|
+
// 必填
|
|
2049
|
+
validate: function (val) {
|
|
2050
|
+
if (val) {
|
|
2051
|
+
return true;
|
|
2052
|
+
}
|
|
2053
|
+
return "请输入百度翻译的key";
|
|
2054
|
+
},
|
|
2055
|
+
},
|
|
2056
|
+
];
|
|
2057
|
+
inquirer.prompt(question).then((res) => {
|
|
2058
|
+
writeCache(
|
|
2059
|
+
type,
|
|
2060
|
+
JSON.stringify({
|
|
2061
|
+
type,
|
|
2062
|
+
...res,
|
|
2063
|
+
})
|
|
2064
|
+
);
|
|
2065
|
+
const { appid, key } = res;
|
|
2066
|
+
const isLintFix = fix;
|
|
2067
|
+
translateUtil(appid, key, projectName, isLintFix);
|
|
2068
|
+
});
|
|
2069
|
+
});
|
|
2070
|
+
} else {
|
|
2071
|
+
console.log(
|
|
2072
|
+
chalk.red("请在package.json中配置正确的name字段(项目名称)")
|
|
2073
|
+
);
|
|
2074
|
+
}
|
|
2075
|
+
});
|
|
2076
|
+
}
|
|
2077
|
+
|
|
2078
|
+
function translateUtil(appid, key, projectName, isLintFix) {
|
|
2079
|
+
const { input } = commander.program.opts();
|
|
2080
|
+
let src = [input];
|
|
2081
|
+
const isSrcDirectory = fs.statSync(input).isDirectory();
|
|
2082
|
+
if (isSrcDirectory) {
|
|
2083
|
+
const directory = input + "/**/*.{js,vue,jsx,ts,tsx}";
|
|
2084
|
+
src = glob.glob.sync(directory, {
|
|
2085
|
+
ignore: directory + `/**/node_modules/**`,
|
|
2086
|
+
});
|
|
2087
|
+
}
|
|
2088
|
+
let allArr = []; // 所有文本组成的数组
|
|
2089
|
+
let groupArr = []; // 分组后的数组
|
|
2090
|
+
let newAllArr = []; // 分组后的数组还原成所有数组
|
|
2091
|
+
// 循环遍历文件下的文件
|
|
2092
|
+
function readFolder(isOk) {
|
|
2093
|
+
// spinner.start();
|
|
2094
|
+
src.forEach((item, index) => {
|
|
2095
|
+
const fPath = item;
|
|
2096
|
+
let file = fs.readFileSync(fPath, "utf-8").toString();
|
|
2097
|
+
// 提取file里所有以$hxt({ key: '', desc:为开头 以')}结尾的字符串
|
|
2098
|
+
const reg =
|
|
2099
|
+
/\$hxt\([\r\n\s]*\{[\r\n\s]*key[\r\n\s]*:[\r\n\s]*['|"][\r\n\s]*['|"],[\r\n\s]*desc[\r\n\s]*:[\r\n\s]*['|"|`](.*?)['|"|`],*[\r\n\s]*\}(\)|,[\r\n\s]*\{)/g;
|
|
2100
|
+
file = file.replace(reg, function (match, p1, p2) {
|
|
2101
|
+
if (isOk) {
|
|
2102
|
+
const reg1 = /key[\r\n\s]*:[\r\n\s]*('|")[\r\n\s]*('|")/g;
|
|
2103
|
+
let key = newAllArr.find(
|
|
2104
|
+
(item) => item.path === fPath && item.ZH_CN === p1
|
|
2105
|
+
).key;
|
|
2106
|
+
// 去除{ slotxx }
|
|
2107
|
+
key = key.replace(/\{[\r\n\s]*slot\d[\r\n\s]*\}/g, "");
|
|
2108
|
+
// 去除空格
|
|
2109
|
+
key = key.replace(/\s/g, "");
|
|
2110
|
+
return match.replace(reg1, `key: '${key}'`);
|
|
2111
|
+
} else {
|
|
2112
|
+
allArr.push({
|
|
2113
|
+
path: fPath,
|
|
2114
|
+
ZH_CN: p1,
|
|
2115
|
+
EN: "",
|
|
2116
|
+
key: "",
|
|
2117
|
+
});
|
|
2118
|
+
}
|
|
2119
|
+
});
|
|
2120
|
+
if (isOk) {
|
|
2121
|
+
fs.writeFileSync(fPath, file, "utf-8");
|
|
2122
|
+
}
|
|
2123
|
+
});
|
|
2124
|
+
if (isOk) {
|
|
2125
|
+
// spinner.stop();
|
|
2126
|
+
return;
|
|
2127
|
+
}
|
|
2128
|
+
// 数组分割,如果str长度大于2000,就分割成多个数组
|
|
2129
|
+
let str = "";
|
|
2130
|
+
let cutArr = [];
|
|
2131
|
+
console.log(chalk.green(`共有${allArr.length}条数据需要翻译`));
|
|
2132
|
+
allArr.forEach((item, index) => {
|
|
2133
|
+
if (str.length > 2000) {
|
|
2134
|
+
groupArr.push(cutArr);
|
|
2135
|
+
str = "";
|
|
2136
|
+
cutArr = [];
|
|
2137
|
+
}
|
|
2138
|
+
str += item.ZH_CN + "\n";
|
|
2139
|
+
cutArr.push(item);
|
|
2140
|
+
});
|
|
2141
|
+
if (cutArr.length > 0) {
|
|
2142
|
+
Array.prototype.push.apply(groupArr, [cutArr]);
|
|
2143
|
+
} else {
|
|
2144
|
+
groupArr = allArr;
|
|
2145
|
+
}
|
|
2146
|
+
console.log(chalk.green(`共有${groupArr.length}组数据需要翻译`));
|
|
2147
|
+
if(!groupArr.length) return
|
|
2148
|
+
const task = groupArr.map(async (item, index) => {
|
|
2149
|
+
let str = "";
|
|
2150
|
+
item.forEach((item1, index1) => {
|
|
2151
|
+
// 去除换行空格
|
|
2152
|
+
const ZH_CN = item1.ZH_CN.replace(/\n/g, "");
|
|
2153
|
+
str += ZH_CN + "\n";
|
|
2154
|
+
});
|
|
2155
|
+
return translate(item, str, index + 1);
|
|
2156
|
+
});
|
|
2157
|
+
Promise.allSettled(task).then(async (res) => {
|
|
2158
|
+
console.log(chalk.green("任务执行完毕"));
|
|
2159
|
+
groupArr.forEach((item, index) => {
|
|
2160
|
+
Array.prototype.push.apply(newAllArr, item);
|
|
2161
|
+
});
|
|
2162
|
+
readFolder(true);
|
|
2163
|
+
|
|
2164
|
+
let exportData = [];
|
|
2165
|
+
// key中有debug排后面
|
|
2166
|
+
const sortNewAllArr = _.sortBy(newAllArr, function (item) {
|
|
2167
|
+
return item.key.indexOf("debug") > -1;
|
|
2168
|
+
});
|
|
2169
|
+
sortNewAllArr.forEach((item, index) => {
|
|
2170
|
+
const rowArr = [
|
|
2171
|
+
"GIT", // 系统
|
|
2172
|
+
projectName, // 项目
|
|
2173
|
+
"frontInit", // 模块(路由)
|
|
2174
|
+
"", // 编码
|
|
2175
|
+
1, // 所属(1:前端 2:后端)
|
|
2176
|
+
1, // 数据类型(1:static,2:enum,3:json)
|
|
2177
|
+
"", // 中文值
|
|
2178
|
+
"", // 英文
|
|
2179
|
+
"", // 泰文(TH)
|
|
2180
|
+
"", // 越南(VI)
|
|
2181
|
+
"", // 土耳其(TR)
|
|
2182
|
+
];
|
|
2183
|
+
const cacheIndex = {
|
|
2184
|
+
ZH_CN: 6,
|
|
2185
|
+
EN: 7,
|
|
2186
|
+
key: 3,
|
|
2187
|
+
};
|
|
2188
|
+
Object.entries(item).forEach(([key, value], index1) => {
|
|
2189
|
+
const insertIndex = cacheIndex[key];
|
|
2190
|
+
rowArr[insertIndex] = value;
|
|
2191
|
+
});
|
|
2192
|
+
exportData.push(rowArr);
|
|
2193
|
+
});
|
|
2194
|
+
const { isMerge } = await inquirer.prompt([
|
|
2195
|
+
{
|
|
2196
|
+
message: `是否合并至export.xlsx,默认${chalk.red("否,直接覆盖")}`,
|
|
2197
|
+
name: "isMerge",
|
|
2198
|
+
type: "confirm",
|
|
2199
|
+
default: false,
|
|
2200
|
+
},
|
|
2201
|
+
]);
|
|
2202
|
+
try {
|
|
2203
|
+
if (isMerge) {
|
|
2204
|
+
const str = xlsx.parse(fs.readFileSync("./export.xlsx"));
|
|
2205
|
+
if (str[0].data.length) {
|
|
2206
|
+
exportData = str[0].data.concat(exportData);
|
|
2207
|
+
} else {
|
|
2208
|
+
throw new Error();
|
|
2209
|
+
}
|
|
2210
|
+
} else {
|
|
2211
|
+
throw new Error();
|
|
2212
|
+
}
|
|
2213
|
+
} catch (error) {
|
|
2214
|
+
// 第一行插入标题
|
|
2215
|
+
exportData.unshift([
|
|
2216
|
+
"系统",
|
|
2217
|
+
"项目",
|
|
2218
|
+
"模块",
|
|
2219
|
+
"编码",
|
|
2220
|
+
"所属(1:前端 2:后端)",
|
|
2221
|
+
"数据类型(1:static,2:enum,3:json)",
|
|
2222
|
+
"中文值",
|
|
2223
|
+
"英文",
|
|
2224
|
+
"泰文(TH)",
|
|
2225
|
+
"越南(VI)",
|
|
2226
|
+
"土耳其(TR)",
|
|
2227
|
+
]);
|
|
2228
|
+
}
|
|
2229
|
+
const buffer = xlsx.build([{ data: exportData }]);
|
|
2230
|
+
fs.writeFileSync(`./export.xlsx`, buffer, "binary");
|
|
2231
|
+
console.log(chalk.green(`${isMerge?"合并":"覆盖"}文件成功`));
|
|
2232
|
+
});
|
|
2233
|
+
}
|
|
2234
|
+
|
|
2235
|
+
// 百度翻译接口
|
|
2236
|
+
async function translate(item, str, groupIndex) {
|
|
2237
|
+
const q = str;
|
|
2238
|
+
const salt = Math.random();
|
|
2239
|
+
const from = "zh";
|
|
2240
|
+
const to = "en";
|
|
2241
|
+
const sign = md5(appid + q + salt + key);
|
|
2242
|
+
const query = querystring.stringify({
|
|
2243
|
+
q,
|
|
2244
|
+
appid,
|
|
2245
|
+
salt,
|
|
2246
|
+
from,
|
|
2247
|
+
to,
|
|
2248
|
+
sign,
|
|
2249
|
+
});
|
|
2250
|
+
const url = "http://api.fanyi.baidu.com/api/trans/vip/translate?" + query;
|
|
2251
|
+
return new Promise((resolve, reject) => {
|
|
2252
|
+
// 自动翻译延时,必须大于 1000 ms,否则调用百度翻译 API 会失败
|
|
2253
|
+
throttle(() => {
|
|
2254
|
+
console.log(chalk.green(`正在翻译第${groupIndex}组数据`));
|
|
2255
|
+
return request(url, function (_error, response, body) {
|
|
2256
|
+
const resBody = JSON.parse(body);
|
|
2257
|
+
if (resBody.trans_result) {
|
|
2258
|
+
console.log(`ok`);
|
|
2259
|
+
let result = resBody.trans_result || [];
|
|
2260
|
+
item.forEach((item1, index1) => {
|
|
2261
|
+
const id = uuid.v5(item1.path, uuid.v5.URL).slice(0, 6);
|
|
2262
|
+
if (result[index1] && result[index1].src === item1.ZH_CN) {
|
|
2263
|
+
// 删除str中的单引号或双引号或斜杠或逗号
|
|
2264
|
+
let str = result[index1].dst
|
|
2265
|
+
.replace(/\'/g, "")
|
|
2266
|
+
.replace(/\"/g, "")
|
|
2267
|
+
.replace(/\//g, "")
|
|
2268
|
+
.replace(/\,/g, "");
|
|
2269
|
+
// 每个单词首首字母转换为大写
|
|
2270
|
+
const s = str.split(" ");
|
|
2271
|
+
let key = s
|
|
2272
|
+
.map((item, index) => {
|
|
2273
|
+
return item[0].toUpperCase() + item.slice(1);
|
|
2274
|
+
})
|
|
2275
|
+
.join("");
|
|
2276
|
+
// 去除key中的标点符号
|
|
2277
|
+
key = key.replace(/[^a-zA-Z0-9{}]/g, "").slice(0, 73);
|
|
2278
|
+
let EN = result[index1].dst;
|
|
2279
|
+
EN = EN[0].toUpperCase() + EN.slice(1);
|
|
2280
|
+
item1.EN = EN;
|
|
2281
|
+
if (isLintFix) {
|
|
2282
|
+
item1.key = nanoid.nanoid().replace("_", "a");
|
|
2283
|
+
// item1.key = id + "-" + key;
|
|
2284
|
+
} else {
|
|
2285
|
+
item1.key = id + "-" + key;
|
|
2286
|
+
}
|
|
2287
|
+
}
|
|
2288
|
+
});
|
|
2289
|
+
resolve(true);
|
|
2290
|
+
} else {
|
|
2291
|
+
item.forEach((item1, index1) => {
|
|
2292
|
+
const id = uuid.v5(item1.path, uuid.v5.URL).slice(0, 6);
|
|
2293
|
+
item1.key = id + "-" + "debug";
|
|
2294
|
+
});
|
|
2295
|
+
console.log(chalk.red(`error: ${body}`));
|
|
2296
|
+
resolve(true);
|
|
2297
|
+
}
|
|
2298
|
+
});
|
|
2299
|
+
});
|
|
2300
|
+
});
|
|
2301
|
+
}
|
|
2302
|
+
// md5加密
|
|
2303
|
+
function md5(str) {
|
|
2304
|
+
const md5 = crypto.createHash("md5");
|
|
2305
|
+
md5.update(str);
|
|
2306
|
+
return md5.digest("hex");
|
|
2307
|
+
}
|
|
2308
|
+
|
|
2309
|
+
// 节流函数
|
|
2310
|
+
const delay = 2000;
|
|
2311
|
+
const throttle = (function (delay = 1500) {
|
|
2312
|
+
const wait = [];
|
|
2313
|
+
let canCall = true;
|
|
2314
|
+
return function throttle(callback) {
|
|
2315
|
+
if (!canCall) {
|
|
2316
|
+
if (callback) wait.push(callback);
|
|
2317
|
+
return;
|
|
2318
|
+
}
|
|
2319
|
+
|
|
2320
|
+
callback();
|
|
2321
|
+
canCall = false;
|
|
2322
|
+
setTimeout(() => {
|
|
2323
|
+
canCall = true;
|
|
2324
|
+
if (wait.length) {
|
|
2325
|
+
throttle(wait.shift());
|
|
2326
|
+
}
|
|
2327
|
+
}, delay);
|
|
2328
|
+
};
|
|
2329
|
+
})(delay);
|
|
2330
|
+
// 开始方法
|
|
2331
|
+
readFolder();
|
|
2332
|
+
}
|
|
2333
|
+
|
|
2334
|
+
exports.rules = rules;
|