@dune2/cli 0.0.4 → 0.0.6
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/{chunk-JA5TKWZF.js → chunk-UPESJ46X.js} +24 -21
- package/dist/chunk-UPESJ46X.js.map +1 -0
- package/dist/cli.js +208 -53
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +54 -3
- package/dist/index.js +1 -6
- package/package.json +8 -3
- package/readme.md +4 -2
- package/dist/chunk-JA5TKWZF.js.map +0 -1
|
@@ -17,39 +17,42 @@ function resolveSheetId(str) {
|
|
|
17
17
|
|
|
18
18
|
// src/shared/config.ts
|
|
19
19
|
var joycon = new JoyCon();
|
|
20
|
-
function defineConfig(config) {
|
|
21
|
-
return config;
|
|
22
|
-
}
|
|
23
20
|
var configName = "dune.config.js";
|
|
24
21
|
async function getConfig() {
|
|
22
|
+
var _a;
|
|
25
23
|
const res = await joycon.load([configName]);
|
|
26
|
-
const
|
|
24
|
+
const defaultI18nConfig = {
|
|
27
25
|
i18nDir: "./src/i18n",
|
|
28
26
|
i18nFileName: "{locale}.i18n.json",
|
|
29
|
-
cwd: process.cwd(),
|
|
30
27
|
position: { key: "B", zh: "C", en: "D", in: "E" },
|
|
31
28
|
parseStartIndex: 2
|
|
32
29
|
};
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
item.locales = Object.keys(item.position).filter(
|
|
38
|
-
(item2) => item2 !== "key"
|
|
39
|
-
);
|
|
40
|
-
item.sheetId = resolveSheetId(item.sheetId);
|
|
41
|
-
item.keySorter = (a, b) => {
|
|
42
|
-
return a.localeCompare(b);
|
|
43
|
-
};
|
|
44
|
-
return item;
|
|
45
|
-
});
|
|
30
|
+
let config = res.data ?? {};
|
|
31
|
+
config.cwd ??= process.cwd();
|
|
32
|
+
if (!config.i18n || !((_a = config.i18n) == null ? void 0 : _a.length)) {
|
|
33
|
+
config.i18n = [defaultI18nConfig];
|
|
46
34
|
}
|
|
47
|
-
|
|
35
|
+
config.i18n = config.i18n.map((item) => {
|
|
36
|
+
item = Object.assign({}, defaultI18nConfig, item);
|
|
37
|
+
item.cwd ??= config.cwd;
|
|
38
|
+
item.locales = Object.keys(item.position).filter((item2) => item2 !== "key");
|
|
39
|
+
item.sheetId = resolveSheetId(item.sheetId);
|
|
40
|
+
item.keySorter = (a, b) => {
|
|
41
|
+
return a.localeCompare(b);
|
|
42
|
+
};
|
|
43
|
+
return item;
|
|
44
|
+
});
|
|
45
|
+
config.api ??= [];
|
|
46
|
+
config.api = config.api.map((item) => {
|
|
47
|
+
item.output ??= "./src/apis";
|
|
48
|
+
item.requestFnImportPath ??= `import requestFn from '@/utils/request';`;
|
|
49
|
+
return item;
|
|
50
|
+
});
|
|
51
|
+
return config;
|
|
48
52
|
}
|
|
49
53
|
|
|
50
54
|
export {
|
|
51
|
-
defineConfig,
|
|
52
55
|
configName,
|
|
53
56
|
getConfig
|
|
54
57
|
};
|
|
55
|
-
//# sourceMappingURL=chunk-
|
|
58
|
+
//# sourceMappingURL=chunk-UPESJ46X.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/shared/config.ts","../src/shared/resolveSheetId.ts"],"sourcesContent":["import JoyCon from \"joycon\";\nimport { resolveSheetId } from \"./resolveSheetId\";\n\nconst joycon = new JoyCon();\n\nexport interface I18nConfig {\n // 语言文件存放目录,默认为项目根目录的 \"./src/i18n\"\n i18nDir?: string;\n // 语言文件名,默认为 \"{locale}.i18n.json\",其中 {locale} 会被替换为 locales 中的语言\n i18nFileName?: string;\n // 默认语言,默认为 \"zh\",影响到提出出来的文案的默认值\n defaultLocale?: string;\n /**\n * 可以是 id 或者 url,如果是 url 则会自动解析出 id\n * id: 1C9-Dol3oO20W9_FhiVlxNsDhOaaejJIgAZYRkonGmfk\n * url: https://docs.google.com/spreadsheets/d/1C9-Dol3oO20W9_FhiVlxNsDhOaaejJIgAZYRkonGmfk/edit#gid=1740568548\n */\n sheetId?: string;\n // google sheets 工作表名称\n sheetRange?: string;\n /**\n * 对应 语言、i18nKey 所在的列标识符 如(A,B,C...)\n * 传入时将忽略默认的配置\n * @default {key: \"B\", zh: \"C\", en: \"D\", in: \"E\",}\n */\n position?: {\n key: string;\n [key: string]: string;\n };\n\n /**\n * 从 Google Sheets 哪一行开始解析\n * 默认从第2行开始,模板文件第一行是表头\n * @default 2\n */\n parseStartIndex?: number;\n\n /**\n * 默认是 命令运行的目录,一般是项目根目录\n * @internal\n */\n cwd?: string;\n /**\n * 支持的语言列表,从 position 中解析出来\n * @internal\n */\n locales?: string[];\n\n /**\n * 翻译key的排序\n * @internal\n */\n keySorter?: (a: string, b: string) => number;\n}\n\nexport interface ApiConfig {\n /**\n * swagger JSON 的路径 可以是 本地 可以是远程\n */\n swaggerJSONPath: string;\n /**\n * 用在生成代码里快捷连接跳转到 swagger ui\n * 必须携带 urls.primaryName 参数\n * @example http://192.168.104.10:31082/swagger/?urls.primaryName=%E5%90%8E%E5%8F%B0%E7%AE%A1%E7%90%86%E7%9B%B8%E5%85%B3API\n */\n swaggerUiUrl?: string;\n /**\n * 输出的文件夹路径\n * @default \"./src/apis\"\n */\n output?: string;\n /**\n * 配置`requestFn` 方法引入的路径,生成的代码里会用到,生成代码如下\n * 引入的名称必须是`requestFn`\n * ```ts\n * // 需要命名为 requestFn\n * import requestFn from '@/utils/request'\n * import { foo as requestFn } from '@/utils/request'\n * ```\n * @default `import requestFn from '@/utils/request'`\n */\n requestFnImportPath?: string;\n}\n\nexport interface Config {\n i18n?: I18nConfig[];\n api?: ApiConfig[];\n /**\n * 默认是 命令运行的目录,一般是项目根目录\n * @internal\n */\n cwd?: string;\n}\nexport const configName = \"dune.config.js\";\n\nexport async function getConfig(): Promise<Config> {\n const res = await joycon.load([configName]);\n\n const defaultI18nConfig: I18nConfig = {\n i18nDir: \"./src/i18n\",\n i18nFileName: \"{locale}.i18n.json\",\n position: { key: \"B\", zh: \"C\", en: \"D\", in: \"E\" },\n parseStartIndex: 2,\n };\n\n let config = (res.data ?? {}) as Config;\n config.cwd ??= process.cwd();\n\n //#region i18n 配置标准化\n if (!config.i18n || !config.i18n?.length) {\n config.i18n = [defaultI18nConfig];\n }\n\n // 格式化 i18n 配置\n config.i18n = config.i18n.map((item) => {\n item = Object.assign({}, defaultI18nConfig, item);\n item.cwd ??= config.cwd;\n item.locales = Object.keys(item.position!).filter((item) => item !== \"key\");\n item.sheetId = resolveSheetId(item.sheetId);\n item.keySorter = (a, b) => {\n return a.localeCompare(b);\n };\n return item;\n });\n //#endregion\n\n //#region api 配置标准化\n config.api ??= [];\n config.api = config.api.map((item) => {\n item.output ??= \"./src/apis\";\n item.requestFnImportPath ??= `import requestFn from '@/utils/request';`;\n return item;\n });\n //#endregion\n\n return config;\n}\n","/**\n * input:\n * \"https://docs.google.com/spreadsheets/d/1C9-Dol3oO20W9_FhiVlxNsDhOaaejJIgAZYRkonGmfk/edit#gid=1740568548\"\n * output:\n * \"1C9-Dol3oO20W9_FhiVlxNsDhOaaejJIgAZYRkonGmfk\"\n * --\n * input: \"1C9-Dol3oO20W9_FhiVlxNsDhOaaejJIgAZYRkonGmfk\"\n * output: \"1C9-Dol3oO20W9_FhiVlxNsDhOaaejJIgAZYRkonGmfk\"\n */\nimport { match } from \"path-to-regexp\";\n\nexport function resolveSheetId(str?: string) {\n if (!str || !str?.startsWith(\"http\")) {\n return str;\n }\n const url = new URL(str);\n const matched = match<{ id: string[] }>(\"/spreadsheets/d/:id*\", {\n decode: decodeURIComponent,\n })(url.pathname);\n return matched ? matched.params.id?.[0] : str;\n}\n"],"mappings":";AAAA,OAAO,YAAY;;;ACSnB,SAAS,aAAa;AAEf,SAAS,eAAe,KAAc;AAX7C;AAYE,MAAI,CAAC,OAAO,EAAC,2BAAK,WAAW,UAAS;AACpC,WAAO;AAAA,EACT;AACA,QAAM,MAAM,IAAI,IAAI,GAAG;AACvB,QAAM,UAAU,MAAwB,wBAAwB;AAAA,IAC9D,QAAQ;AAAA,EACV,CAAC,EAAE,IAAI,QAAQ;AACf,SAAO,WAAU,aAAQ,OAAO,OAAf,mBAAoB,KAAK;AAC5C;;;ADjBA,IAAM,SAAS,IAAI,OAAO;AA0FnB,IAAM,aAAa;AAE1B,eAAsB,YAA6B;AA/FnD;AAgGE,QAAM,MAAM,MAAM,OAAO,KAAK,CAAC,UAAU,CAAC;AAE1C,QAAM,oBAAgC;AAAA,IACpC,SAAS;AAAA,IACT,cAAc;AAAA,IACd,UAAU,EAAE,KAAK,KAAK,IAAI,KAAK,IAAI,KAAK,IAAI,IAAI;AAAA,IAChD,iBAAiB;AAAA,EACnB;AAEA,MAAI,SAAU,IAAI,QAAQ,CAAC;AAC3B,SAAO,QAAQ,QAAQ,IAAI;AAG3B,MAAI,CAAC,OAAO,QAAQ,GAAC,YAAO,SAAP,mBAAa,SAAQ;AACxC,WAAO,OAAO,CAAC,iBAAiB;AAAA,EAClC;AAGA,SAAO,OAAO,OAAO,KAAK,IAAI,CAAC,SAAS;AACtC,WAAO,OAAO,OAAO,CAAC,GAAG,mBAAmB,IAAI;AAChD,SAAK,QAAQ,OAAO;AACpB,SAAK,UAAU,OAAO,KAAK,KAAK,QAAS,EAAE,OAAO,CAACA,UAASA,UAAS,KAAK;AAC1E,SAAK,UAAU,eAAe,KAAK,OAAO;AAC1C,SAAK,YAAY,CAAC,GAAG,MAAM;AACzB,aAAO,EAAE,cAAc,CAAC;AAAA,IAC1B;AACA,WAAO;AAAA,EACT,CAAC;AAID,SAAO,QAAQ,CAAC;AAChB,SAAO,MAAM,OAAO,IAAI,IAAI,CAAC,SAAS;AACpC,SAAK,WAAW;AAChB,SAAK,wBAAwB;AAC7B,WAAO;AAAA,EACT,CAAC;AAGD,SAAO;AACT;","names":["item"]}
|
package/dist/cli.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
configName,
|
|
4
4
|
getConfig
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-UPESJ46X.js";
|
|
6
6
|
|
|
7
7
|
// src/commands/extract.ts
|
|
8
8
|
import fs3 from "fs-extra";
|
|
@@ -78,7 +78,7 @@ var I18nData = class {
|
|
|
78
78
|
async updateByExtractedData(extractedData, shouldUseDefault = false) {
|
|
79
79
|
await this.loadData();
|
|
80
80
|
extractedData.forEach((value, key) => {
|
|
81
|
-
this.data[key] = shouldUseDefault ? value.
|
|
81
|
+
this.data[key] = shouldUseDefault ? value.messages || key : this.data[key] || "";
|
|
82
82
|
});
|
|
83
83
|
}
|
|
84
84
|
async updateFromSheetData(sheetData) {
|
|
@@ -128,8 +128,9 @@ var I18nData = class {
|
|
|
128
128
|
}
|
|
129
129
|
async trySaveToGoogle(sheetData) {
|
|
130
130
|
await pMap(Object.entries(this.data), async ([key, value]) => {
|
|
131
|
+
var _a;
|
|
131
132
|
if (sheetData.hasI18nItem(this.locale, key)) {
|
|
132
|
-
await sheetData.getI18nItem(this.locale, key).tryUpdate(value);
|
|
133
|
+
await ((_a = sheetData.getI18nItem(this.locale, key)) == null ? void 0 : _a.tryUpdate(value));
|
|
133
134
|
} else {
|
|
134
135
|
log.error(
|
|
135
136
|
"%s range %s not found key %s",
|
|
@@ -168,7 +169,7 @@ var log2 = createLogger("extract");
|
|
|
168
169
|
async function extract() {
|
|
169
170
|
const config = await getConfig();
|
|
170
171
|
const { extract: extract2 } = await import("@dune2/wasm");
|
|
171
|
-
for (const configItem of config) {
|
|
172
|
+
for (const configItem of config.i18n ?? []) {
|
|
172
173
|
const files = await globby(
|
|
173
174
|
[`**/**.{js,jsx,ts,tsx}`, "!**/node_modules/**", "!**.d.ts"],
|
|
174
175
|
{
|
|
@@ -189,7 +190,7 @@ async function extract() {
|
|
|
189
190
|
);
|
|
190
191
|
res.forEach((value, key) => {
|
|
191
192
|
const cur = extractedI18nDataMap.get(key);
|
|
192
|
-
if (!(cur == null ? void 0 : cur.
|
|
193
|
+
if (!(cur == null ? void 0 : cur.messages)) {
|
|
193
194
|
extractedI18nDataMap.set(key, value);
|
|
194
195
|
}
|
|
195
196
|
});
|
|
@@ -201,17 +202,20 @@ async function extract() {
|
|
|
201
202
|
pc2.green(extractedI18nDataMap.size),
|
|
202
203
|
extractedI18nDataMap
|
|
203
204
|
);
|
|
204
|
-
const statistics = await pMap2(
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
205
|
+
const statistics = await pMap2(
|
|
206
|
+
configItem.locales ?? [],
|
|
207
|
+
async (locale, index) => {
|
|
208
|
+
const i18nData = new I18nData(locale, configItem);
|
|
209
|
+
await i18nData.updateByExtractedData(extractedI18nDataMap, index === 0);
|
|
210
|
+
await i18nData.saveToDisk();
|
|
211
|
+
return await i18nData.statistic();
|
|
212
|
+
}
|
|
213
|
+
);
|
|
210
214
|
I18nData.printStatistic("\u63D0\u53D6\u7ED3\u679C: ", statistics);
|
|
211
215
|
}
|
|
212
216
|
}
|
|
213
217
|
|
|
214
|
-
// src/commands/
|
|
218
|
+
// src/commands/download.ts
|
|
215
219
|
import pMap3 from "p-map";
|
|
216
220
|
|
|
217
221
|
// src/shared/google/sheet.ts
|
|
@@ -447,7 +451,7 @@ async function resolveSheetData(config) {
|
|
|
447
451
|
}
|
|
448
452
|
const sheetData = new SheetData(config, res.data.values.length + 1);
|
|
449
453
|
res.data.values.forEach((row, rowIndex) => {
|
|
450
|
-
var _a;
|
|
454
|
+
var _a, _b;
|
|
451
455
|
const trulyRowIndex = rowIndex + 1;
|
|
452
456
|
if (parseStartIndex > trulyRowIndex) {
|
|
453
457
|
return;
|
|
@@ -461,7 +465,7 @@ async function resolveSheetData(config) {
|
|
|
461
465
|
} else {
|
|
462
466
|
sheetData.keySet.add(i18nKey);
|
|
463
467
|
}
|
|
464
|
-
config.locales.forEach((lang) => {
|
|
468
|
+
(_b = config.locales) == null ? void 0 : _b.forEach((lang) => {
|
|
465
469
|
sheetData.setI18nItem(
|
|
466
470
|
lang,
|
|
467
471
|
new SheetI18nItem(
|
|
@@ -507,63 +511,210 @@ var SheetData = class {
|
|
|
507
511
|
}
|
|
508
512
|
};
|
|
509
513
|
|
|
510
|
-
// src/commands/
|
|
514
|
+
// src/commands/download.ts
|
|
511
515
|
var log7 = createLogger("generate");
|
|
512
|
-
async function
|
|
516
|
+
async function download() {
|
|
513
517
|
const config = await getConfig();
|
|
514
518
|
let i = 0;
|
|
515
|
-
for (const configItem of config) {
|
|
519
|
+
for (const configItem of config.i18n ?? []) {
|
|
516
520
|
i++;
|
|
517
521
|
if (!configItem.sheetId || !configItem.sheetRange) {
|
|
518
522
|
log7.error(`config.${i} sheetId \u6216 sheetRange \u4E3A\u7A7A\uFF0C\u8BF7\u68C0\u67E5`);
|
|
519
523
|
continue;
|
|
520
524
|
}
|
|
521
525
|
const sheetData = await resolveSheetData(configItem);
|
|
522
|
-
const statistics = await pMap3(
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
526
|
+
const statistics = await pMap3(
|
|
527
|
+
configItem.locales ?? [],
|
|
528
|
+
async (locale, index) => {
|
|
529
|
+
const i18nData = new I18nData(locale, configItem);
|
|
530
|
+
await i18nData.updateFromSheetData(sheetData.getLangDataJSON(locale));
|
|
531
|
+
await i18nData.saveToDisk();
|
|
532
|
+
return await i18nData.statistic();
|
|
533
|
+
}
|
|
534
|
+
);
|
|
528
535
|
I18nData.printStatistic(`${configItem.sheetRange} \u751F\u6210\u7ED3\u679C: `, statistics);
|
|
529
536
|
}
|
|
530
537
|
}
|
|
531
538
|
|
|
532
|
-
// src/commands/
|
|
539
|
+
// src/commands/generateApi/index.ts
|
|
540
|
+
import _ from "lodash";
|
|
541
|
+
import pMap4 from "p-map";
|
|
533
542
|
import fs5 from "fs-extra";
|
|
543
|
+
import * as os from "os";
|
|
544
|
+
import SwaggerParser from "@apidevtools/swagger-parser";
|
|
545
|
+
import { compile } from "json-schema-to-typescript";
|
|
534
546
|
import path3 from "path";
|
|
535
|
-
var log8 = createLogger("
|
|
536
|
-
|
|
537
|
-
|
|
547
|
+
var log8 = createLogger("generateApi");
|
|
548
|
+
async function generateApi() {
|
|
549
|
+
const config = await getConfig();
|
|
550
|
+
for (const apiConfig of config.api ?? []) {
|
|
551
|
+
log8.info(`\u6E05\u9664\u65E7\u7684api\u6587\u4EF6: ${apiConfig.output}`);
|
|
552
|
+
await fs5.emptydir(apiConfig.output);
|
|
553
|
+
}
|
|
554
|
+
for (const apiConfig of config.api ?? []) {
|
|
555
|
+
log8.info("\u5F00\u59CB\u89E3\u6790 %s", apiConfig.swaggerJSONPath);
|
|
556
|
+
const parsed = await SwaggerParser.dereference(
|
|
557
|
+
apiConfig.swaggerJSONPath
|
|
558
|
+
);
|
|
559
|
+
await pMap4(Object.entries(parsed.paths), async ([url, pathItemObject]) => {
|
|
560
|
+
log8.info("\u5F00\u59CB\u751F\u6210 %s", url);
|
|
561
|
+
if (pathItemObject) {
|
|
562
|
+
await pMap4(
|
|
563
|
+
["get", "put", "post", "delete", "patch"],
|
|
564
|
+
async (method) => {
|
|
565
|
+
const operationObject = pathItemObject[method];
|
|
566
|
+
if (operationObject) {
|
|
567
|
+
const code = await generateApiRequestCode({
|
|
568
|
+
url,
|
|
569
|
+
method,
|
|
570
|
+
operationObject,
|
|
571
|
+
apiConfig
|
|
572
|
+
});
|
|
573
|
+
const outputPath = path3.join(
|
|
574
|
+
apiConfig.output,
|
|
575
|
+
url,
|
|
576
|
+
`${method}.ts`
|
|
577
|
+
);
|
|
578
|
+
await fs5.ensureFile(outputPath);
|
|
579
|
+
await fs5.writeFile(outputPath, code);
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
);
|
|
583
|
+
}
|
|
584
|
+
});
|
|
585
|
+
}
|
|
586
|
+
log8.info("generateApi Done");
|
|
587
|
+
}
|
|
588
|
+
async function generateApiRequestCode(options) {
|
|
589
|
+
var _a, _b;
|
|
590
|
+
const { url, method, operationObject, apiConfig } = options;
|
|
591
|
+
const seeUrl = apiConfig.swaggerUiUrl ? `${apiConfig.swaggerUiUrl}#/${encodeURIComponent(
|
|
592
|
+
((_a = operationObject.tags) == null ? void 0 : _a.join("/")) ?? ""
|
|
593
|
+
)}/${operationObject.operationId}` : "not found swagger ui url";
|
|
594
|
+
const requestBuilderName = _.camelCase(`${url}_${method}_api`);
|
|
595
|
+
const urlPathParams = getUrlPathParams(
|
|
596
|
+
operationObject.parameters ?? []
|
|
597
|
+
);
|
|
598
|
+
const urlPathParamsCode = urlPathParams.length ? `urlPathParams: ${JSON.stringify(urlPathParams)},` : "";
|
|
599
|
+
let code = [
|
|
600
|
+
"// \u8FD9\u4E2A\u6587\u4EF6\u7531 @dune2/cli \u81EA\u52A8\u751F\u6210\uFF0C\u4E0D\u8981\u624B\u52A8\u4FEE\u6539\uFF0C\u5426\u5219\u4F1A\u88AB\u8986\u76D6",
|
|
601
|
+
`import { RequestBuilder } from '@dune2/tools';`,
|
|
602
|
+
apiConfig.requestFnImportPath,
|
|
603
|
+
`/**
|
|
604
|
+
* ${operationObject.summary}
|
|
605
|
+
* @tags ${(_b = operationObject.tags) == null ? void 0 : _b.join(",")}
|
|
606
|
+
* @see ${seeUrl}
|
|
607
|
+
*/`
|
|
608
|
+
];
|
|
609
|
+
code.push(`export const ${requestBuilderName} = new RequestBuilder<${requestBuilderName}.Req, ${requestBuilderName}.Res>({
|
|
610
|
+
url: '${url}',
|
|
611
|
+
method: '${method}',
|
|
612
|
+
requestFn,
|
|
613
|
+
${urlPathParamsCode}
|
|
614
|
+
});`);
|
|
615
|
+
const [requestParamsTypeCode, responseParamsTypeCode] = await Promise.all([
|
|
616
|
+
compileRequestParams(operationObject),
|
|
617
|
+
compileResponseParams(operationObject)
|
|
618
|
+
]);
|
|
619
|
+
code.push(`
|
|
620
|
+
export namespace ${requestBuilderName} {
|
|
621
|
+
${requestParamsTypeCode}
|
|
622
|
+
|
|
623
|
+
${responseParamsTypeCode}
|
|
624
|
+
};`);
|
|
625
|
+
return code.join(os.EOL);
|
|
626
|
+
}
|
|
627
|
+
function getUrlPathParams(parameters) {
|
|
628
|
+
return parameters.filter((item) => item.in === "path").map((item) => item.name);
|
|
629
|
+
}
|
|
630
|
+
async function compileRequestParams(operationObject) {
|
|
631
|
+
let schema;
|
|
632
|
+
if (operationObject.parameters) {
|
|
633
|
+
const parameters = operationObject.parameters.filter(
|
|
634
|
+
(p) => p.in === "query" || p.in === "path"
|
|
635
|
+
) ?? [];
|
|
636
|
+
const required = parameters.filter((p) => p.required).map((p) => p.name);
|
|
637
|
+
const properties = Object.fromEntries(
|
|
638
|
+
parameters.map((p) => {
|
|
639
|
+
const schema2 = p.schema;
|
|
640
|
+
return [
|
|
641
|
+
p.name,
|
|
642
|
+
{
|
|
643
|
+
type: schema2.type,
|
|
644
|
+
description: p.description
|
|
645
|
+
}
|
|
646
|
+
];
|
|
647
|
+
})
|
|
648
|
+
);
|
|
649
|
+
schema = {
|
|
650
|
+
required,
|
|
651
|
+
type: "object",
|
|
652
|
+
properties
|
|
653
|
+
};
|
|
654
|
+
} else if (operationObject.requestBody) {
|
|
655
|
+
schema = operationObject.requestBody.content["application/json"].schema;
|
|
656
|
+
}
|
|
657
|
+
let code = "";
|
|
658
|
+
if (schema) {
|
|
659
|
+
code = await compile(schema, "Req", {
|
|
660
|
+
bannerComment: "",
|
|
661
|
+
ignoreMinAndMaxItems: true
|
|
662
|
+
});
|
|
663
|
+
}
|
|
664
|
+
return code ? code : "export type Req = any;";
|
|
665
|
+
}
|
|
666
|
+
async function compileResponseParams(operationObject) {
|
|
667
|
+
var _a;
|
|
668
|
+
const temp = operationObject.responses["200"];
|
|
669
|
+
let code = "";
|
|
670
|
+
if (temp == null ? void 0 : temp.content) {
|
|
671
|
+
const temp2 = temp.content["application/json"] || temp.content["*/*"];
|
|
672
|
+
const schema = temp2.schema;
|
|
673
|
+
const data = ((_a = schema.properties) == null ? void 0 : _a.data) ?? schema;
|
|
674
|
+
if (data) {
|
|
675
|
+
code = await compile(data, "Res", {
|
|
676
|
+
bannerComment: "",
|
|
677
|
+
ignoreMinAndMaxItems: true
|
|
678
|
+
});
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
return code ? code : "export type Res = any;";
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
// src/commands/initConfig.ts
|
|
685
|
+
import fs6 from "fs-extra";
|
|
686
|
+
import path4 from "path";
|
|
687
|
+
var log9 = createLogger("initConfig");
|
|
688
|
+
var tpl = `/**
|
|
538
689
|
* @template {import('@dune2/cli').Config} T
|
|
539
|
-
* @param {T
|
|
690
|
+
* @param {T} config - A generic parameter that flows through to the return type
|
|
540
691
|
* @constraint {{import('@dune2/cli').Config}}
|
|
541
692
|
*/
|
|
542
693
|
function defineConfig(config) {
|
|
543
694
|
return config;
|
|
544
695
|
}
|
|
545
|
-
module.exports = defineConfig([]);
|
|
696
|
+
module.exports = defineConfig({ i18n: [], api:[] });
|
|
546
697
|
`;
|
|
547
698
|
var initConfig = async () => {
|
|
548
699
|
const config = await getConfig();
|
|
549
|
-
const configPath =
|
|
550
|
-
|
|
551
|
-
if (await
|
|
552
|
-
|
|
700
|
+
const configPath = path4.join(config.cwd, configName);
|
|
701
|
+
log9.info(`config file path: ${configPath}`);
|
|
702
|
+
if (await fs6.pathExists(configPath)) {
|
|
703
|
+
log9.info(`config file already exists, skip`);
|
|
553
704
|
return;
|
|
554
705
|
}
|
|
555
|
-
await
|
|
556
|
-
|
|
706
|
+
await fs6.writeFile(configPath, tpl);
|
|
707
|
+
log9.info(`config file created`);
|
|
557
708
|
};
|
|
558
709
|
|
|
559
710
|
// src/commands/upload.ts
|
|
560
|
-
import
|
|
561
|
-
var
|
|
711
|
+
import pMap5 from "p-map";
|
|
712
|
+
var log10 = createLogger("upload");
|
|
562
713
|
async function batchUpdateKeys(config) {
|
|
563
714
|
let sheetData = await resolveSheetData(config);
|
|
564
715
|
const allKeys = [];
|
|
565
716
|
const i18nDataMap = /* @__PURE__ */ new Map();
|
|
566
|
-
await
|
|
717
|
+
await pMap5(config.locales ?? [], async (locale) => {
|
|
567
718
|
const i18nData = new I18nData(locale, config);
|
|
568
719
|
i18nDataMap.set(locale, i18nData);
|
|
569
720
|
const data = await i18nData.loadData();
|
|
@@ -574,7 +725,7 @@ async function batchUpdateKeys(config) {
|
|
|
574
725
|
});
|
|
575
726
|
needSyncKeys = needSyncKeys.sort(config.keySorter);
|
|
576
727
|
if (needSyncKeys.length) {
|
|
577
|
-
|
|
728
|
+
log10.info(`\u5373\u5C06\u540C\u6B65\u672C\u5730\u65B0\u589E\u52A0 ${needSyncKeys.length} \u4E2A i18nKey \u5230\u4E91\u7AEF`);
|
|
578
729
|
await googleSheet.updateColumn(
|
|
579
730
|
config.sheetId,
|
|
580
731
|
config.sheetRange,
|
|
@@ -582,14 +733,16 @@ async function batchUpdateKeys(config) {
|
|
|
582
733
|
sheetData.nextAppendRowIndex,
|
|
583
734
|
needSyncKeys
|
|
584
735
|
);
|
|
585
|
-
|
|
736
|
+
log10.info("\u540C\u6B65\u65B0\u589E\u52A0i18nKey\u6210\u529F");
|
|
586
737
|
for (const lang of config.locales) {
|
|
587
738
|
const langFile = i18nDataMap.get(lang);
|
|
588
739
|
const needSyncValues = [];
|
|
589
740
|
needSyncKeys.forEach((k) => {
|
|
590
|
-
|
|
741
|
+
if (langFile) {
|
|
742
|
+
needSyncValues.push(langFile.data[k]);
|
|
743
|
+
}
|
|
591
744
|
});
|
|
592
|
-
|
|
745
|
+
log10.info(
|
|
593
746
|
`\u5373\u5C06\u540C\u6B65\u672C\u5730 ${lang} \u65B0\u589E\u52A0 ${needSyncValues.length} \u4E2A\u503C\u5230\u4E91\u7AEF`
|
|
594
747
|
);
|
|
595
748
|
await googleSheet.updateColumn(
|
|
@@ -602,7 +755,7 @@ async function batchUpdateKeys(config) {
|
|
|
602
755
|
}
|
|
603
756
|
await sleep(1e3);
|
|
604
757
|
sheetData = await resolveSheetData(config);
|
|
605
|
-
|
|
758
|
+
log10.info(`\u5DF2\u91CD\u65B0\u83B7\u53D6 ${config.sheetRange} \u7684\u6570\u636E`);
|
|
606
759
|
}
|
|
607
760
|
return { sheetData, i18nDataMap };
|
|
608
761
|
}
|
|
@@ -613,23 +766,24 @@ function sleep(ms) {
|
|
|
613
766
|
}
|
|
614
767
|
async function upload() {
|
|
615
768
|
const config = await getConfig();
|
|
616
|
-
for (const configItem of config) {
|
|
769
|
+
for (const configItem of config.i18n ?? []) {
|
|
617
770
|
const { sheetData, i18nDataMap } = await batchUpdateKeys(configItem);
|
|
618
|
-
await
|
|
771
|
+
await pMap5(configItem.locales ?? [], async (locale) => {
|
|
619
772
|
const i18nData = i18nDataMap.get(locale);
|
|
620
773
|
await i18nData.trySaveToGoogle(sheetData);
|
|
621
774
|
});
|
|
622
775
|
}
|
|
623
|
-
|
|
776
|
+
log10.info("\u4E0A\u4F20\u6210\u529F");
|
|
624
777
|
}
|
|
625
778
|
|
|
626
779
|
// package.json
|
|
627
|
-
var version = "0.0.
|
|
780
|
+
var version = "0.0.5";
|
|
628
781
|
|
|
629
782
|
// src/commands/interactive.ts
|
|
630
783
|
import prompts from "prompts";
|
|
631
|
-
var
|
|
784
|
+
var log11 = createLogger("interactive");
|
|
632
785
|
var interactive = async (args) => {
|
|
786
|
+
var _a;
|
|
633
787
|
const commands = cli.commands.filter((command2) => {
|
|
634
788
|
if (command2.name) {
|
|
635
789
|
return !command2.name.startsWith("@@") && command2.name !== "interactive";
|
|
@@ -638,7 +792,7 @@ var interactive = async (args) => {
|
|
|
638
792
|
});
|
|
639
793
|
const commandMap = /* @__PURE__ */ new Map();
|
|
640
794
|
const res = await prompts({
|
|
641
|
-
type: "
|
|
795
|
+
type: "autocomplete",
|
|
642
796
|
name: "command",
|
|
643
797
|
message: "\u9009\u62E9\u8981\u6267\u884C\u7684\u547D\u4EE4\uFF1A",
|
|
644
798
|
choices: commands.map((command2) => {
|
|
@@ -652,16 +806,17 @@ var interactive = async (args) => {
|
|
|
652
806
|
});
|
|
653
807
|
const command = commandMap.get(res.command);
|
|
654
808
|
if (!command) {
|
|
655
|
-
|
|
809
|
+
log11.error("\u672A\u627E\u5230\u547D\u4EE4 %s", res.command);
|
|
656
810
|
return;
|
|
657
811
|
}
|
|
658
|
-
command.commandAction.apply(cli, args);
|
|
812
|
+
(_a = command.commandAction) == null ? void 0 : _a.apply(cli, args);
|
|
659
813
|
};
|
|
660
814
|
|
|
661
815
|
// src/cli.ts
|
|
662
|
-
cli.command("
|
|
663
|
-
cli.command("upload", "\u4E0A\u4F20\u7FFB\u8BD1\u6587\u4EF6").example("dune upload").action(upload);
|
|
816
|
+
cli.command("download", "\u751F\u6210\u7FFB\u8BD1\u6587\u4EF6").example("dune download").action(download);
|
|
664
817
|
cli.command("extract", "\u63D0\u53D6\u4EE3\u7801\u4E2D\u7684\u6587\u6848").example("dune extract").action(extract);
|
|
818
|
+
cli.command("upload", "\u4E0A\u4F20\u7FFB\u8BD1\u6587\u4EF6").example("dune upload").action(upload);
|
|
819
|
+
cli.command("generateApi", "\u751F\u6210api\u6587\u4EF6").example("dune generateApi").action(generateApi);
|
|
665
820
|
cli.command("init", "\u521D\u59CB\u5316\u914D\u7F6E\u6587\u4EF6").example("dune init").action(initConfig);
|
|
666
821
|
cli.command("interactive", "\u4EA4\u4E92\u5F0F\u64CD\u4F5C").example("dune interactive").alias("i").action(interactive);
|
|
667
822
|
cli.command("").action(interactive);
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/extract.ts","../src/shared/index.ts","../src/shared/i18nData.ts","../src/commands/generate.ts","../src/shared/google/sheet.ts","../src/shared/letters.ts","../src/shared/google/auth.ts","../src/shared/google/shared.ts","../src/shared/resolveSheetData.ts","../src/commands/initConfig.ts","../src/commands/upload.ts","../src/commands/interactive.ts","../src/cli.ts"],"sourcesContent":["import fs from \"fs-extra\";\nimport { globby } from \"globby\";\nimport pMap from \"p-map\";\nimport { createLogger } from \"../shared\";\nimport { getConfig } from \"../shared/config\";\nimport { I18nData, ExtractedMap } from \"../shared/i18nData\";\nimport pc from \"picocolors\";\n\nconst log = createLogger(\"extract\");\n\nexport async function extract() {\n const config = await getConfig();\n const { extract } = await import(\"@dune2/wasm\");\n\n // 这是使得任务串行,方便看日志\n for (const configItem of config) {\n const files = await globby(\n [`**/**.{js,jsx,ts,tsx}`, \"!**/node_modules/**\", \"!**.d.ts\"],\n {\n cwd: configItem.cwd,\n }\n );\n log.info(\"预计共解析 %s 个文件\", pc.green(files.length));\n const extractedI18nDataMap: ExtractedMap = new Map();\n await pMap(\n files,\n async (file) => {\n const content = await fs.readFile(file, \"utf-8\");\n const res: ExtractedMap = await extract(content);\n log.info(\n \"从 %s 中提取到 %s 条文案\",\n pc.dim(file),\n res.size ? pc.green(res.size) : res.size\n );\n res.forEach((value, key) => {\n const cur = extractedI18nDataMap.get(key);\n if (!cur?.defaults) {\n extractedI18nDataMap.set(key, value);\n }\n });\n },\n { concurrency: 20 }\n );\n log.info(\n \"总统提取到 %s 条文案 %O\",\n pc.green(extractedI18nDataMap.size),\n extractedI18nDataMap\n );\n\n const statistics = await pMap(configItem.locales, async (locale, index) => {\n const i18nData = new I18nData(locale, configItem);\n await i18nData.updateByExtractedData(extractedI18nDataMap, index === 0);\n await i18nData.saveToDisk();\n return await i18nData.statistic();\n });\n I18nData.printStatistic(\"提取结果: \", statistics);\n }\n}\n","import cac from \"cac\";\nimport debug from \"debug\";\nimport path from \"path\";\nimport fs from \"fs-extra\";\n\nexport const cli = cac(\"dune\");\n\nexport const createLogger = (name: string) => {\n const info = debug(`${cli.name}:${name}`);\n return {\n ...info,\n info,\n error: info.extend(\"error\"),\n };\n};\n\ndebug.enable(`${cli.name}:*`);\n\n/**\n * same with chacheDir\n * homeDir();\n * //=> '~/name'\n *\n * homeDir('bar.js')\n * //=> '~/name/bar.js'\n */\n// eslint-disable-next-line @typescript-eslint/explicit-function-return-type\nexport const homeConfigDir = (() => {\n const isWin = process.platform === \"win32\";\n const USER_HOME_DIR = isWin ? process.env.USERPROFILE : process.env.HOME;\n const configDir = path.join(USER_HOME_DIR, \".config\", cli.name);\n\n if (!fs.existsSync(configDir)) {\n fs.mkdirSync(configDir);\n }\n return homeConfigDir;\n\n function homeConfigDir(p?: string): string {\n if (!p) {\n return configDir;\n }\n return path.join(configDir, p);\n }\n})();\n","import pMap from \"p-map\";\nimport { InternalConfig } from \"./config\";\nimport { createLogger } from \"./index\";\nimport fs from \"fs-extra\";\nimport pc from \"picocolors\";\nimport path from \"path\";\nimport Table from \"cli-table3\";\nimport { SheetData } from \"./resolveSheetData\";\n\nconst log = createLogger(\"i18nData\");\nexport type ExtractedMap = Map<string, { id: string; defaults: string }>;\n\nexport class I18nData {\n data: Record<string, string> = {};\n\n filePath: string;\n\n constructor(public locale: string, public config: InternalConfig) {\n this.filePath = path.join(\n config.cwd,\n config.i18nDir,\n config.i18nFileName.replace(\"{locale}\", locale)\n );\n }\n\n async loadData() {\n try {\n if (await fs.pathExists(this.filePath)) {\n this.data = await fs.readJSON(this.filePath);\n } else {\n log.info(\"File '%s' does not exist\", pc.dim(this.filePath));\n }\n } catch (e) {\n log.error(\n \"Error loading i18n data for locale '%s' from file '%s'\",\n pc.yellow(this.locale),\n pc.yellow(this.filePath)\n );\n log.error(\"Error: %s\", e.message);\n }\n return this.data;\n }\n\n async updateByExtractedData(\n extractedData: ExtractedMap,\n shouldUseDefault = false\n ) {\n await this.loadData();\n extractedData.forEach((value, key) => {\n this.data[key] = shouldUseDefault\n ? value.defaults || key\n : this.data[key] || \"\";\n });\n }\n\n async updateFromSheetData(sheetData: Record<string, string>) {\n await this.loadData();\n this.data = { ...this.data, ...sheetData };\n }\n\n private sortData() {\n //region 语言key按一定规则排序\n const keys = Object.keys(this.data).sort(this.config.keySorter);\n const newData = {};\n keys.forEach((key) => {\n newData[key] = this.data[key];\n });\n this.data = newData;\n //endregion\n }\n\n async saveToDisk() {\n this.sortData();\n log.info(\n \"Saving i18n data for locale '%s' to file '%s'\",\n pc.green(this.locale),\n pc.dim(this.filePath)\n );\n try {\n await fs.ensureFile(this.filePath);\n await fs.writeJson(this.filePath, this.data, { spaces: 2 });\n log.info(\n \"Saved i18n data for locale '%s' to file '%s'\",\n pc.green(this.locale),\n pc.dim(this.filePath)\n );\n } catch (e) {\n log.error(\n \"Error saving i18n data for locale '%s' to file '%s'\",\n pc.green(this.locale),\n pc.dim(this.filePath)\n );\n log.error(\"Error: %s\", pc.red(e.message));\n }\n }\n\n async statistic() {\n const total = Object.keys(this.data).length;\n const missing = Object.values(this.data).filter((v) => !v).length;\n\n return {\n locale: this.locale,\n total,\n missing,\n };\n }\n\n async trySaveToGoogle(sheetData: SheetData) {\n await pMap(Object.entries(this.data), async ([key, value]) => {\n if (sheetData.hasI18nItem(this.locale, key)) {\n // 更新已有的\n await sheetData.getI18nItem(this.locale, key).tryUpdate(value);\n } else {\n log.error(\n \"%s range %s not found key %s\",\n pc.bold(this.config.sheetRange),\n pc.bold(this.locale),\n pc.bold(key)\n );\n }\n });\n }\n\n static printStatistic(\n label: string,\n statistics: { locale: string; total: number; missing: number }[]\n ) {\n const table = new Table({\n head: [\"Language\", \"Total count\", \"Missing\"],\n colAligns: [\"left\", \"center\", \"center\"],\n style: {\n head: [\"green\"],\n border: [],\n compact: true,\n },\n });\n statistics.forEach((statistic) => {\n table.push([\n statistic.locale,\n statistic.total,\n statistic.missing > 0 ? pc.red(statistic.missing) : statistic.missing,\n ]);\n });\n console.log(pc.bold(label));\n console.log(table.toString());\n }\n}\n","import pMap from \"p-map\";\nimport { createLogger } from \"../shared\";\nimport { getConfig } from \"../shared/config\";\nimport { I18nData } from \"../shared/i18nData\";\nimport { resolveSheetData } from \"../shared/resolveSheetData\";\n\nconst log = createLogger(\"generate\");\n\nexport async function generate() {\n const config = await getConfig();\n let i = 0;\n for (const configItem of config) {\n i++;\n if (!configItem.sheetId || !configItem.sheetRange) {\n log.error(`config.${i} sheetId 或 sheetRange 为空,请检查`);\n continue;\n }\n const sheetData = await resolveSheetData(configItem);\n\n const statistics = await pMap(configItem.locales, async (locale, index) => {\n const i18nData = new I18nData(locale, configItem);\n await i18nData.updateFromSheetData(sheetData.getLangDataJSON(locale));\n await i18nData.saveToDisk();\n return await i18nData.statistic();\n });\n I18nData.printStatistic(`${configItem.sheetRange} 生成结果: `, statistics);\n }\n}\n","import { GaxiosResponse } from \"gaxios\";\nimport type { sheets_v4 } from \"googleapis\";\nimport { google } from \"googleapis\";\nimport { createLogger } from \"../index\";\nimport { numberToLetter } from \"../letters\";\nimport { googleAuth } from \"./auth\";\n\nconst log = createLogger(\"google:sheets\");\n\nclass GoogleSheet {\n private sheets: sheets_v4.Sheets;\n\n private initPromise: Promise<void> | null = null;\n private async initImpl() {\n if (!this.sheets) {\n await googleAuth.initCredentials();\n this.sheets = google.sheets({\n version: \"v4\",\n auth: googleAuth.oauth2Client,\n });\n }\n }\n /**\n * 调用sheets其他方法的时候需要先初始化\n */\n async init() {\n if (!this.initPromise) {\n this.initPromise = this.initImpl();\n }\n await this.initPromise;\n }\n\n get = async (options: sheets_v4.Params$Resource$Spreadsheets$Values$Get) => {\n await this.init();\n return this.sheets.spreadsheets.values.get(options);\n };\n\n private async update(\n spreadsheetId: string,\n range: string,\n colIndex: number,\n rowIndex: number,\n values: string[][]\n ): Promise<GaxiosResponse<sheets_v4.Schema$UpdateValuesResponse>> {\n await this.init();\n\n const colLetter = numberToLetter(colIndex);\n const sheetNeedRange = `${range}!${colLetter}${rowIndex}`;\n\n const res = await this.sheets.spreadsheets.values.update({\n spreadsheetId,\n range: sheetNeedRange,\n valueInputOption: \"USER_ENTERED\",\n requestBody: { values },\n });\n\n if (res.status === 200) {\n log.info(`更新 ${sheetNeedRange} 的值成功`);\n } else {\n log.error(\"some thing wrong\", res);\n }\n return res;\n }\n\n /**\n * 更新某一个单元格\n */\n async updateCell(\n spreadsheetId: string,\n range: string,\n colIndex: number,\n rowIndex: number,\n values: string\n ) {\n return this.update(spreadsheetId, range, colIndex, rowIndex, [[values]]);\n }\n\n /**\n * 更新某一列\n */\n async updateColumn(\n spreadsheetId: string,\n range: string,\n colIndex: number,\n rowIndex: number,\n values: string[]\n ) {\n return this.update(spreadsheetId, range, colIndex, rowIndex, [\n ...values.map((v) => [v]),\n ]);\n }\n}\n\nexport const googleSheet = new GoogleSheet();\n","/**\n *\n * - input : A\n * output : 0\n * - input : Z\n * output : 25\n * - input : AA\n * output : 26\n * - input : a\n * output : 0\n */\nexport function letterToNumber(letters: string | number) {\n if (typeof letters === \"number\" || !Number.isNaN(+letters)) {\n return +letters;\n }\n\n let n = 0;\n letters = letters.toUpperCase();\n for (let p = 0; p < letters.length; p++) {\n n = letters[p].charCodeAt(0) - 64 + n * 26;\n }\n\n return Math.max(0, n - 1);\n}\n\n/**\n * fork from https://github.com/matthewmueller/number-to-letter\n */\nconst alphabet = \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\";\nconst base = alphabet.length;\n/**\n * numberToLetter(0) // A\n * numberToLetter(25) // Z\n * numberToLetter(26) // AA\n * numberToLetter(51) // AZ\n * numberToLetter(52) // BA\n * numberToLetter(676) // ZA\n * numberToLetter(701) // ZZ\n * numberToLetter(702) // AAA\n */\nexport function numberToLetter(n: number) {\n const digits = [];\n\n do {\n const v = n % base;\n digits.push(v);\n n = Math.floor(n / base);\n } while (n-- > 0);\n\n const chars = [];\n while (digits.length) {\n chars.push(alphabet[digits.pop()]);\n }\n\n return chars.join(\"\");\n}\n","import fs from \"fs-extra\";\nimport { OAuth2Client } from \"google-auth-library\";\nimport { google } from \"googleapis\";\nimport { homeConfigDir, createLogger } from \"../index\";\nimport { openAndWaitReturnQuery } from \"./shared\";\n\ninterface AuthOptions {\n client_id: string;\n client_secret: string;\n /**\n * @default ['spreadsheets']\n */\n scope?: string[];\n}\n\nconst log = createLogger(\"google:auth\");\n\nclass GoogleAuth {\n private tokens: any = null;\n\n private tokensCachePath = homeConfigDir(\"chromeAuthToken.json\");\n\n private readonly scope: string[];\n\n oauth2Client: OAuth2Client = new google.auth.OAuth2(\n this.options.client_id,\n this.options.client_secret,\n \"http://localhost:12345\"\n );\n\n constructor(private options: AuthOptions) {\n this.options.scope = this.options.scope ?? [\"spreadsheets\"];\n const scopePrefix = `https://www.googleapis.com/auth/`;\n this.scope = this.options.scope.map((item) => {\n if (item.startsWith(scopePrefix)) {\n return item;\n }\n return `${scopePrefix}${item}`;\n });\n\n try {\n this.tokens = fs.readJsonSync(this.tokensCachePath);\n } catch (e) {\n log.info(\"未获取到缓存的token\");\n this.tokens = null;\n }\n }\n\n private async saveTokens(tokens: any): Promise<void> {\n this.tokens = tokens;\n await fs.writeJSON(this.tokensCachePath, tokens);\n log.info(\"保存token成功\");\n }\n\n async getCode(): Promise<string> {\n log.info(\"将打开chrome浏览器进行授权\");\n const authUrl = this.oauth2Client.generateAuthUrl({\n access_type: \"offline\",\n scope: this.scope,\n });\n return await openAndWaitReturnQuery(authUrl, 12345, \"code\");\n }\n\n private async initCredentialsImpl(): Promise<void> {\n if (!this.tokens) {\n const code = await this.getCode();\n const { tokens } = await this.oauth2Client.getToken(code);\n await this.saveTokens(tokens);\n }\n this.oauth2Client.setCredentials(this.tokens);\n }\n private initCredentialsPromise: Promise<void> | null = null;\n async initCredentials() {\n if (!this.initCredentialsPromise) {\n this.initCredentialsPromise = this.initCredentialsImpl();\n }\n return await this.initCredentialsPromise;\n }\n}\n\n// see in https://console.cloud.google.com/apis/credentials?organizationId=286245507762&orgonly=true&project=dune-cli&supportedpurview=organizationId\nconst clientSecret = {\n client_id:\n \"728508473485-fgl11a3op1ucd0lef9hs49mkliuaipqa.apps.googleusercontent.com\",\n project_id: \"dune-cli\",\n auth_uri: \"https://accounts.google.com/o/oauth2/auth\",\n token_uri: \"https://oauth2.googleapis.com/token\",\n auth_provider_x509_cert_url: \"https://www.googleapis.com/oauth2/v1/certs\",\n client_secret: \"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\",\n redirect_uris: [\"http://localhost\"],\n};\nexport const googleAuth = new GoogleAuth(clientSecret);\n","import connect from \"connect\";\nimport open from \"open\";\nimport { URL } from \"url\";\nimport { createLogger } from \"../index\";\n\nconst log = createLogger(\"google:shared\");\n\nfunction openBrowser(url: string) {\n log.info(`如未自动打开浏览器,可访问以下地址:${url}`);\n open(url, { app: { name: open.apps.chrome } });\n}\n\nexport function openAndWaitReturnQuery(\n toOpenUrl: string,\n port: number,\n queryKey: string\n) {\n return new Promise<string>((resolve) => {\n openBrowser(toOpenUrl);\n\n const app = connect();\n app.use((req, res, next) => {\n const parsedUrl = new URL(req.url, `http://localhost:${port}`);\n const target = parsedUrl.searchParams.get(queryKey);\n if (target) {\n res.writeHead(200, {\n \"content-type\": \"text/html;charset=utf8\",\n });\n res.end(\n `<div>当前窗口可直接关闭</div>\n <script>\n window.open(\"\", \"_self\", \"\");\n window.close();\n </script>`\n );\n server.close();\n server.unref();\n resolve(target);\n }\n next();\n });\n\n const server = app.listen(port);\n });\n}\n","import { InternalConfig } from \"./config\";\nimport { googleSheet } from \"./google/sheet\";\nimport { createLogger } from \"./index\";\nimport { letterToNumber } from \"./letters\";\n\nconst log = createLogger(\"shared:resolveSheetData\");\n\nclass SheetI18nItem {\n value: string;\n\n colIndex: number;\n\n constructor(\n private spreadsheetId: string,\n private range: string,\n public key: string,\n colIndex: number | string,\n public row: string[],\n private rowIndex: number\n ) {\n this.colIndex = letterToNumber(colIndex);\n // TODO: 待确定 无值的key是否要生成\n // value = undefined 即不会生成\n this.value = this.row[this.colIndex] || \"\";\n }\n\n /**\n * 尝试更新 单元格的值\n * 如果一样则不更新\n */\n async tryUpdate(newValue: string) {\n if (newValue === this.value) {\n // 云端的值跟本地一样 不需要同步\n return;\n }\n\n await googleSheet.updateCell(\n this.spreadsheetId,\n this.range,\n this.colIndex,\n this.rowIndex,\n newValue\n );\n }\n}\n\nexport async function resolveSheetData(\n config: InternalConfig\n): Promise<SheetData> {\n const { position } = config;\n const parseStartIndex = config.parseStartIndex ?? 2;\n\n log.info(`读取 ${config.sheetRange} sheet数据`);\n\n const res = await googleSheet.get({\n spreadsheetId: config.sheetId,\n range: config.sheetRange,\n });\n if (!res.data.values) {\n log.error(\n `${config.sheetRange} sheet数据为空,请检查,应该最少有一行头部数据`\n );\n return new SheetData(config, 2);\n }\n\n const sheetData = new SheetData(config, res.data.values.length + 1);\n\n res.data.values.forEach((row: string[], rowIndex) => {\n // excel 的开始索引是1,所以要 +1\n const trulyRowIndex = rowIndex + 1;\n if (parseStartIndex > trulyRowIndex) {\n // 还未到可以开始解析的行数\n return;\n }\n\n const i18nKey = row[letterToNumber(position.key)]?.trim();\n\n if (i18nKey) {\n if (sheetData.keySet.has(i18nKey)) {\n log.error(\n `表格 ${config.sheetRange} 发现重复的i18nKey: ${i18nKey}, 将覆盖前面的值`\n );\n } else {\n sheetData.keySet.add(i18nKey);\n }\n\n config.locales.forEach((lang) => {\n sheetData.setI18nItem(\n lang,\n new SheetI18nItem(\n config.sheetId,\n config.sheetRange,\n i18nKey,\n position[lang],\n row,\n trulyRowIndex\n )\n );\n });\n }\n });\n\n return sheetData;\n}\n\nexport class SheetData {\n keySet = new Set<string>();\n\n constructor(\n private config: InternalConfig,\n // 当前有多少行 新增的时候往后面添加\n public nextAppendRowIndex: number\n ) {}\n\n private value = new Map(\n this.config.locales.map((lang) => {\n return [lang, new Map<string, SheetI18nItem>()];\n })\n );\n\n getI18nItem(lang: string, i18nKey: string) {\n return this.value.get(lang).get(i18nKey);\n }\n\n setI18nItem(lang: string, i18nItem: SheetI18nItem) {\n this.value.get(lang).set(i18nItem.key, i18nItem);\n }\n\n hasI18nItem(lang: string, i18nKey: string) {\n return this.value.get(lang).has(i18nKey);\n }\n\n getLangDataJSON(lang: string) {\n const res = {} as Record<string, string>;\n this.value.get(lang).forEach((i18nItem) => {\n res[i18nItem.key] = i18nItem.value;\n });\n return res;\n }\n}\n","import { createLogger } from \"../shared\";\nimport { getConfig, configName } from \"../shared/config\";\nimport fs from \"fs-extra\";\nimport path from \"path\";\n\nconst log = createLogger(\"initConfig\");\n\nconst tpl = `\n/**\n * @template {import('@dune2/cli').Config} T\n * @param {T | T[]} config - A generic parameter that flows through to the return type\n * @constraint {{import('@dune2/cli').Config}}\n */\nfunction defineConfig(config) {\n return config;\n}\nmodule.exports = defineConfig([]);\n`;\n\nexport const initConfig = async () => {\n const config = await getConfig();\n const configPath = path.join(config[0].cwd, configName);\n log.info(`config file path: ${configPath}`);\n if (await fs.pathExists(configPath)) {\n log.info(`config file already exists, skip`);\n return;\n }\n await fs.writeFile(configPath, tpl);\n log.info(`config file created`);\n};\n","import pMap from \"p-map\";\nimport { createLogger } from \"../shared\";\nimport { getConfig, InternalConfig } from \"../shared/config\";\nimport { googleSheet } from \"../shared/google/sheet\";\nimport { I18nData } from \"../shared/i18nData\";\nimport { letterToNumber } from \"../shared/letters\";\nimport { resolveSheetData } from \"../shared/resolveSheetData\";\n\nconst log = createLogger(\"upload\");\n\n/**\n * 检测有本地有新增的key 则将新增的key更新到云端\n * 无则跳过\n */\nasync function batchUpdateKeys(config: InternalConfig) {\n let sheetData = await resolveSheetData(config);\n\n const allKeys = [];\n const i18nDataMap = new Map<string, I18nData>();\n await pMap(config.locales, async (locale) => {\n const i18nData = new I18nData(locale, config);\n i18nDataMap.set(locale, i18nData);\n const data = await i18nData.loadData();\n allKeys.push(...Object.keys(data));\n });\n\n let needSyncKeys = Array.from(new Set(allKeys)).filter((key) => {\n // 本地有新的key 服务器没有\n return !sheetData.keySet.has(key);\n });\n needSyncKeys = needSyncKeys.sort(config.keySorter);\n\n if (needSyncKeys.length) {\n log.info(`即将同步本地新增加 ${needSyncKeys.length} 个 i18nKey 到云端`);\n await googleSheet.updateColumn(\n config.sheetId,\n config.sheetRange,\n letterToNumber(config.position.key),\n sheetData.nextAppendRowIndex,\n needSyncKeys\n );\n log.info(\"同步新增加i18nKey成功\");\n\n // 批量同步新增的key的values到云端\n for (const lang of config.locales) {\n const langFile = i18nDataMap.get(lang);\n const needSyncValues = [];\n needSyncKeys.forEach((k) => {\n needSyncValues.push(langFile.data[k]);\n });\n log.info(\n `即将同步本地 ${lang} 新增加 ${needSyncValues.length} 个值到云端`\n );\n await googleSheet.updateColumn(\n config.sheetId,\n config.sheetRange,\n letterToNumber(config.position[lang]),\n sheetData.nextAppendRowIndex,\n needSyncValues\n );\n }\n\n await sleep(1000);\n sheetData = await resolveSheetData(config);\n log.info(`已重新获取 ${config.sheetRange} 的数据`);\n }\n\n return { sheetData, i18nDataMap };\n}\nfunction sleep(ms: number) {\n return new Promise((resolve) => {\n setTimeout(resolve, ms);\n });\n}\n\nexport async function upload() {\n const config = await getConfig();\n\n for (const configItem of config) {\n const { sheetData, i18nDataMap } = await batchUpdateKeys(configItem);\n await pMap(configItem.locales, async (locale) => {\n const i18nData = i18nDataMap.get(locale);\n await i18nData.trySaveToGoogle(sheetData);\n });\n }\n\n log.info(\"上传成功\");\n}\n","import { cli, createLogger } from \"../shared\";\nimport prompts from \"prompts\";\n\nconst log = createLogger(\"interactive\");\n\nexport const interactive = async (args: any) => {\n const commands = cli.commands.filter((command) => {\n if (command.name) {\n return !command.name.startsWith(\"@@\") && command.name !== \"interactive\";\n }\n return false;\n });\n\n const commandMap = new Map<string, typeof commands[number]>();\n const res = await prompts({\n type: \"select\",\n name: \"command\",\n message: \"选择要执行的命令:\",\n choices: commands.map((command) => {\n commandMap.set(command.name, command);\n return {\n title: command.name,\n value: command.name,\n description: command.description,\n };\n }),\n });\n\n const command = commandMap.get(res.command);\n if (!command) {\n log.error(\"未找到命令 %s\", res.command);\n return;\n }\n command.commandAction.apply(cli, args);\n};\n","#!/usr/bin/env node\nimport { extract } from \"./commands/extract\";\nimport { generate } from \"./commands/generate\";\nimport { initConfig } from \"./commands/initConfig\";\nimport { upload } from \"./commands/upload\";\nimport { cli } from \"./shared\";\nimport { version } from \"../package.json\";\nimport { interactive } from \"./commands/interactive\";\n\ncli\n .command(\"generate\", \"生成翻译文件\")\n .alias(\"gen\")\n .example(\"dune generate\")\n .example(\"dune gen\")\n .action(generate);\n\ncli.command(\"upload\", \"上传翻译文件\").example(\"dune upload\").action(upload);\n\ncli\n .command(\"extract\", \"提取代码中的文案\")\n .example(\"dune extract\")\n .action(extract);\n\ncli.command(\"init\", \"初始化配置文件\").example(\"dune init\").action(initConfig);\n\ncli\n .command(\"interactive\", \"交互式操作\")\n .example(\"dune interactive\")\n .alias(\"i\")\n .action(interactive);\n// make default command run interactive\ncli.command(\"\").action(interactive);\n\ncli.version(version);\ncli.help();\n\n(async () => {\n try {\n // Parse CLI args without running the command\n cli.parse(process.argv, { run: false });\n // Run the command yourself\n // You only need `await` when your command action returns a Promise\n await cli.runMatchedCommand();\n } catch (error) {\n // Handle error here..\n // e.g.\n // console.error(error.stack)\n // process.exit(1)\n }\n})();\n"],"mappings":";;;;;;;AAAA,OAAOA,SAAQ;AACf,SAAS,cAAc;AACvB,OAAOC,WAAU;;;ACFjB,OAAO,SAAS;AAChB,OAAO,WAAW;AAClB,OAAO,UAAU;AACjB,OAAO,QAAQ;AAER,IAAM,MAAM,IAAI,MAAM;AAEtB,IAAM,eAAe,CAAC,SAAiB;AAC5C,QAAM,OAAO,MAAM,GAAG,IAAI,QAAQ,MAAM;AACxC,SAAO;AAAA,IACL,GAAG;AAAA,IACH;AAAA,IACA,OAAO,KAAK,OAAO,OAAO;AAAA,EAC5B;AACF;AAEA,MAAM,OAAO,GAAG,IAAI,QAAQ;AAWrB,IAAM,iBAAiB,MAAM;AAClC,QAAM,QAAQ,QAAQ,aAAa;AACnC,QAAM,gBAAgB,QAAQ,QAAQ,IAAI,cAAc,QAAQ,IAAI;AACpE,QAAM,YAAY,KAAK,KAAK,eAAe,WAAW,IAAI,IAAI;AAE9D,MAAI,CAAC,GAAG,WAAW,SAAS,GAAG;AAC7B,OAAG,UAAU,SAAS;AAAA,EACxB;AACA,SAAOC;AAEP,WAASA,eAAc,GAAoB;AACzC,QAAI,CAAC,GAAG;AACN,aAAO;AAAA,IACT;AACA,WAAO,KAAK,KAAK,WAAW,CAAC;AAAA,EAC/B;AACF,GAAG;;;AC3CH,OAAO,UAAU;AAGjB,OAAOC,SAAQ;AACf,OAAO,QAAQ;AACf,OAAOC,WAAU;AACjB,OAAO,WAAW;AAGlB,IAAM,MAAM,aAAa,UAAU;AAG5B,IAAM,WAAN,MAAe;AAAA,EAKpB,YAAmB,QAAuB,QAAwB;AAA/C;AAAuB;AAJ1C,gBAA+B,CAAC;AAK9B,SAAK,WAAWA,MAAK;AAAA,MACnB,OAAO;AAAA,MACP,OAAO;AAAA,MACP,OAAO,aAAa,QAAQ,YAAY,MAAM;AAAA,IAChD;AAAA,EACF;AAAA,EAEA,MAAM,WAAW;AACf,QAAI;AACF,UAAI,MAAMD,IAAG,WAAW,KAAK,QAAQ,GAAG;AACtC,aAAK,OAAO,MAAMA,IAAG,SAAS,KAAK,QAAQ;AAAA,MAC7C,OAAO;AACL,YAAI,KAAK,4BAA4B,GAAG,IAAI,KAAK,QAAQ,CAAC;AAAA,MAC5D;AAAA,IACF,SAAS,GAAP;AACA,UAAI;AAAA,QACF;AAAA,QACA,GAAG,OAAO,KAAK,MAAM;AAAA,QACrB,GAAG,OAAO,KAAK,QAAQ;AAAA,MACzB;AACA,UAAI,MAAM,aAAa,EAAE,OAAO;AAAA,IAClC;AACA,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAM,sBACJ,eACA,mBAAmB,OACnB;AACA,UAAM,KAAK,SAAS;AACpB,kBAAc,QAAQ,CAAC,OAAO,QAAQ;AACpC,WAAK,KAAK,OAAO,mBACb,MAAM,YAAY,MAClB,KAAK,KAAK,QAAQ;AAAA,IACxB,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,oBAAoB,WAAmC;AAC3D,UAAM,KAAK,SAAS;AACpB,SAAK,OAAO,EAAE,GAAG,KAAK,MAAM,GAAG,UAAU;AAAA,EAC3C;AAAA,EAEQ,WAAW;AAEjB,UAAM,OAAO,OAAO,KAAK,KAAK,IAAI,EAAE,KAAK,KAAK,OAAO,SAAS;AAC9D,UAAM,UAAU,CAAC;AACjB,SAAK,QAAQ,CAAC,QAAQ;AACpB,cAAQ,OAAO,KAAK,KAAK;AAAA,IAC3B,CAAC;AACD,SAAK,OAAO;AAAA,EAEd;AAAA,EAEA,MAAM,aAAa;AACjB,SAAK,SAAS;AACd,QAAI;AAAA,MACF;AAAA,MACA,GAAG,MAAM,KAAK,MAAM;AAAA,MACpB,GAAG,IAAI,KAAK,QAAQ;AAAA,IACtB;AACA,QAAI;AACF,YAAMA,IAAG,WAAW,KAAK,QAAQ;AACjC,YAAMA,IAAG,UAAU,KAAK,UAAU,KAAK,MAAM,EAAE,QAAQ,EAAE,CAAC;AAC1D,UAAI;AAAA,QACF;AAAA,QACA,GAAG,MAAM,KAAK,MAAM;AAAA,QACpB,GAAG,IAAI,KAAK,QAAQ;AAAA,MACtB;AAAA,IACF,SAAS,GAAP;AACA,UAAI;AAAA,QACF;AAAA,QACA,GAAG,MAAM,KAAK,MAAM;AAAA,QACpB,GAAG,IAAI,KAAK,QAAQ;AAAA,MACtB;AACA,UAAI,MAAM,aAAa,GAAG,IAAI,EAAE,OAAO,CAAC;AAAA,IAC1C;AAAA,EACF;AAAA,EAEA,MAAM,YAAY;AAChB,UAAM,QAAQ,OAAO,KAAK,KAAK,IAAI,EAAE;AACrC,UAAM,UAAU,OAAO,OAAO,KAAK,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE;AAE3D,WAAO;AAAA,MACL,QAAQ,KAAK;AAAA,MACb;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,gBAAgB,WAAsB;AAC1C,UAAM,KAAK,OAAO,QAAQ,KAAK,IAAI,GAAG,OAAO,CAAC,KAAK,KAAK,MAAM;AAC5D,UAAI,UAAU,YAAY,KAAK,QAAQ,GAAG,GAAG;AAE3C,cAAM,UAAU,YAAY,KAAK,QAAQ,GAAG,EAAE,UAAU,KAAK;AAAA,MAC/D,OAAO;AACL,YAAI;AAAA,UACF;AAAA,UACA,GAAG,KAAK,KAAK,OAAO,UAAU;AAAA,UAC9B,GAAG,KAAK,KAAK,MAAM;AAAA,UACnB,GAAG,KAAK,GAAG;AAAA,QACb;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,OAAO,eACL,OACA,YACA;AACA,UAAM,QAAQ,IAAI,MAAM;AAAA,MACtB,MAAM,CAAC,YAAY,eAAe,SAAS;AAAA,MAC3C,WAAW,CAAC,QAAQ,UAAU,QAAQ;AAAA,MACtC,OAAO;AAAA,QACL,MAAM,CAAC,OAAO;AAAA,QACd,QAAQ,CAAC;AAAA,QACT,SAAS;AAAA,MACX;AAAA,IACF,CAAC;AACD,eAAW,QAAQ,CAAC,cAAc;AAChC,YAAM,KAAK;AAAA,QACT,UAAU;AAAA,QACV,UAAU;AAAA,QACV,UAAU,UAAU,IAAI,GAAG,IAAI,UAAU,OAAO,IAAI,UAAU;AAAA,MAChE,CAAC;AAAA,IACH,CAAC;AACD,YAAQ,IAAI,GAAG,KAAK,KAAK,CAAC;AAC1B,YAAQ,IAAI,MAAM,SAAS,CAAC;AAAA,EAC9B;AACF;;;AF5IA,OAAOE,SAAQ;AAEf,IAAMC,OAAM,aAAa,SAAS;AAElC,eAAsB,UAAU;AAC9B,QAAM,SAAS,MAAM,UAAU;AAC/B,QAAM,EAAE,SAAAC,SAAQ,IAAI,MAAM,OAAO;AAGjC,aAAW,cAAc,QAAQ;AAC/B,UAAM,QAAQ,MAAM;AAAA,MAClB,CAAC,yBAAyB,uBAAuB,UAAU;AAAA,MAC3D;AAAA,QACE,KAAK,WAAW;AAAA,MAClB;AAAA,IACF;AACA,IAAAD,KAAI,KAAK,wDAAgBD,IAAG,MAAM,MAAM,MAAM,CAAC;AAC/C,UAAM,uBAAqC,oBAAI,IAAI;AACnD,UAAMG;AAAA,MACJ;AAAA,MACA,OAAO,SAAS;AACd,cAAM,UAAU,MAAMC,IAAG,SAAS,MAAM,OAAO;AAC/C,cAAM,MAAoB,MAAMF,SAAQ,OAAO;AAC/C,QAAAD,KAAI;AAAA,UACF;AAAA,UACAD,IAAG,IAAI,IAAI;AAAA,UACX,IAAI,OAAOA,IAAG,MAAM,IAAI,IAAI,IAAI,IAAI;AAAA,QACtC;AACA,YAAI,QAAQ,CAAC,OAAO,QAAQ;AAC1B,gBAAM,MAAM,qBAAqB,IAAI,GAAG;AACxC,cAAI,EAAC,2BAAK,WAAU;AAClB,iCAAqB,IAAI,KAAK,KAAK;AAAA,UACrC;AAAA,QACF,CAAC;AAAA,MACH;AAAA,MACA,EAAE,aAAa,GAAG;AAAA,IACpB;AACA,IAAAC,KAAI;AAAA,MACF;AAAA,MACAD,IAAG,MAAM,qBAAqB,IAAI;AAAA,MAClC;AAAA,IACF;AAEA,UAAM,aAAa,MAAMG,MAAK,WAAW,SAAS,OAAO,QAAQ,UAAU;AACzE,YAAM,WAAW,IAAI,SAAS,QAAQ,UAAU;AAChD,YAAM,SAAS,sBAAsB,sBAAsB,UAAU,CAAC;AACtE,YAAM,SAAS,WAAW;AAC1B,aAAO,MAAM,SAAS,UAAU;AAAA,IAClC,CAAC;AACD,aAAS,eAAe,8BAAU,UAAU;AAAA,EAC9C;AACF;;;AGzDA,OAAOE,WAAU;;;ACEjB,SAAS,UAAAC,eAAc;;;ACShB,SAAS,eAAe,SAA0B;AACvD,MAAI,OAAO,YAAY,YAAY,CAAC,OAAO,MAAM,CAAC,OAAO,GAAG;AAC1D,WAAO,CAAC;AAAA,EACV;AAEA,MAAI,IAAI;AACR,YAAU,QAAQ,YAAY;AAC9B,WAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AACvC,QAAI,QAAQ,GAAG,WAAW,CAAC,IAAI,KAAK,IAAI;AAAA,EAC1C;AAEA,SAAO,KAAK,IAAI,GAAG,IAAI,CAAC;AAC1B;AAKA,IAAM,WAAW;AACjB,IAAM,OAAO,SAAS;AAWf,SAAS,eAAe,GAAW;AACxC,QAAM,SAAS,CAAC;AAEhB,KAAG;AACD,UAAM,IAAI,IAAI;AACd,WAAO,KAAK,CAAC;AACb,QAAI,KAAK,MAAM,IAAI,IAAI;AAAA,EACzB,SAAS,MAAM;AAEf,QAAM,QAAQ,CAAC;AACf,SAAO,OAAO,QAAQ;AACpB,UAAM,KAAK,SAAS,OAAO,IAAI,EAAE;AAAA,EACnC;AAEA,SAAO,MAAM,KAAK,EAAE;AACtB;;;ACvDA,OAAOC,SAAQ;AAEf,SAAS,cAAc;;;ACFvB,OAAO,aAAa;AACpB,OAAO,UAAU;AACjB,SAAS,WAAW;AAGpB,IAAMC,OAAM,aAAa,eAAe;AAExC,SAAS,YAAY,KAAa;AAChC,EAAAA,KAAI,KAAK,+GAAqB,KAAK;AACnC,OAAK,KAAK,EAAE,KAAK,EAAE,MAAM,KAAK,KAAK,OAAO,EAAE,CAAC;AAC/C;AAEO,SAAS,uBACd,WACA,MACA,UACA;AACA,SAAO,IAAI,QAAgB,CAAC,YAAY;AACtC,gBAAY,SAAS;AAErB,UAAM,MAAM,QAAQ;AACpB,QAAI,IAAI,CAAC,KAAK,KAAK,SAAS;AAC1B,YAAM,YAAY,IAAI,IAAI,IAAI,KAAK,oBAAoB,MAAM;AAC7D,YAAM,SAAS,UAAU,aAAa,IAAI,QAAQ;AAClD,UAAI,QAAQ;AACV,YAAI,UAAU,KAAK;AAAA,UACjB,gBAAgB;AAAA,QAClB,CAAC;AACD,YAAI;AAAA,UACF;AAAA;AAAA;AAAA;AAAA;AAAA,QAKF;AACA,eAAO,MAAM;AACb,eAAO,MAAM;AACb,gBAAQ,MAAM;AAAA,MAChB;AACA,WAAK;AAAA,IACP,CAAC;AAED,UAAM,SAAS,IAAI,OAAO,IAAI;AAAA,EAChC,CAAC;AACH;;;AD7BA,IAAMC,OAAM,aAAa,aAAa;AAEtC,IAAM,aAAN,MAAiB;AAAA,EAaf,YAAoB,SAAsB;AAAtB;AAZpB,SAAQ,SAAc;AAEtB,SAAQ,kBAAkB,cAAc,sBAAsB;AAI9D,wBAA6B,IAAI,OAAO,KAAK;AAAA,MAC3C,KAAK,QAAQ;AAAA,MACb,KAAK,QAAQ;AAAA,MACb;AAAA,IACF;AA2CA,SAAQ,yBAA+C;AAxCrD,SAAK,QAAQ,QAAQ,KAAK,QAAQ,SAAS,CAAC,cAAc;AAC1D,UAAM,cAAc;AACpB,SAAK,QAAQ,KAAK,QAAQ,MAAM,IAAI,CAAC,SAAS;AAC5C,UAAI,KAAK,WAAW,WAAW,GAAG;AAChC,eAAO;AAAA,MACT;AACA,aAAO,GAAG,cAAc;AAAA,IAC1B,CAAC;AAED,QAAI;AACF,WAAK,SAASC,IAAG,aAAa,KAAK,eAAe;AAAA,IACpD,SAAS,GAAP;AACA,MAAAD,KAAI,KAAK,iDAAc;AACvB,WAAK,SAAS;AAAA,IAChB;AAAA,EACF;AAAA,EAEA,MAAc,WAAW,QAA4B;AACnD,SAAK,SAAS;AACd,UAAMC,IAAG,UAAU,KAAK,iBAAiB,MAAM;AAC/C,IAAAD,KAAI,KAAK,+BAAW;AAAA,EACtB;AAAA,EAEA,MAAM,UAA2B;AAC/B,IAAAA,KAAI,KAAK,oEAAkB;AAC3B,UAAM,UAAU,KAAK,aAAa,gBAAgB;AAAA,MAChD,aAAa;AAAA,MACb,OAAO,KAAK;AAAA,IACd,CAAC;AACD,WAAO,MAAM,uBAAuB,SAAS,OAAO,MAAM;AAAA,EAC5D;AAAA,EAEA,MAAc,sBAAqC;AACjD,QAAI,CAAC,KAAK,QAAQ;AAChB,YAAM,OAAO,MAAM,KAAK,QAAQ;AAChC,YAAM,EAAE,OAAO,IAAI,MAAM,KAAK,aAAa,SAAS,IAAI;AACxD,YAAM,KAAK,WAAW,MAAM;AAAA,IAC9B;AACA,SAAK,aAAa,eAAe,KAAK,MAAM;AAAA,EAC9C;AAAA,EAEA,MAAM,kBAAkB;AACtB,QAAI,CAAC,KAAK,wBAAwB;AAChC,WAAK,yBAAyB,KAAK,oBAAoB;AAAA,IACzD;AACA,WAAO,MAAM,KAAK;AAAA,EACpB;AACF;AAGA,IAAM,eAAe;AAAA,EACnB,WACE;AAAA,EACF,YAAY;AAAA,EACZ,UAAU;AAAA,EACV,WAAW;AAAA,EACX,6BAA6B;AAAA,EAC7B,eAAe;AAAA,EACf,eAAe,CAAC,kBAAkB;AACpC;AACO,IAAM,aAAa,IAAI,WAAW,YAAY;;;AFpFrD,IAAME,OAAM,aAAa,eAAe;AAExC,IAAM,cAAN,MAAkB;AAAA,EAAlB;AAGE,SAAQ,cAAoC;AAoB5C,eAAM,OAAO,YAA+D;AAC1E,YAAM,KAAK,KAAK;AAChB,aAAO,KAAK,OAAO,aAAa,OAAO,IAAI,OAAO;AAAA,IACpD;AAAA;AAAA,EAtBA,MAAc,WAAW;AACvB,QAAI,CAAC,KAAK,QAAQ;AAChB,YAAM,WAAW,gBAAgB;AACjC,WAAK,SAASC,QAAO,OAAO;AAAA,QAC1B,SAAS;AAAA,QACT,MAAM,WAAW;AAAA,MACnB,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAIA,MAAM,OAAO;AACX,QAAI,CAAC,KAAK,aAAa;AACrB,WAAK,cAAc,KAAK,SAAS;AAAA,IACnC;AACA,UAAM,KAAK;AAAA,EACb;AAAA,EAOA,MAAc,OACZ,eACA,OACA,UACA,UACA,QACgE;AAChE,UAAM,KAAK,KAAK;AAEhB,UAAM,YAAY,eAAe,QAAQ;AACzC,UAAM,iBAAiB,GAAG,SAAS,YAAY;AAE/C,UAAM,MAAM,MAAM,KAAK,OAAO,aAAa,OAAO,OAAO;AAAA,MACvD;AAAA,MACA,OAAO;AAAA,MACP,kBAAkB;AAAA,MAClB,aAAa,EAAE,OAAO;AAAA,IACxB,CAAC;AAED,QAAI,IAAI,WAAW,KAAK;AACtB,MAAAD,KAAI,KAAK,gBAAM,yCAAqB;AAAA,IACtC,OAAO;AACL,MAAAA,KAAI,MAAM,oBAAoB,GAAG;AAAA,IACnC;AACA,WAAO;AAAA,EACT;AAAA,EAKA,MAAM,WACJ,eACA,OACA,UACA,UACA,QACA;AACA,WAAO,KAAK,OAAO,eAAe,OAAO,UAAU,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC;AAAA,EACzE;AAAA,EAKA,MAAM,aACJ,eACA,OACA,UACA,UACA,QACA;AACA,WAAO,KAAK,OAAO,eAAe,OAAO,UAAU,UAAU;AAAA,MAC3D,GAAG,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;AAAA,IAC1B,CAAC;AAAA,EACH;AACF;AAEO,IAAM,cAAc,IAAI,YAAY;;;AIxF3C,IAAME,OAAM,aAAa,yBAAyB;AAElD,IAAM,gBAAN,MAAoB;AAAA,EAKlB,YACU,eACA,OACD,KACP,UACO,KACC,UACR;AANQ;AACA;AACD;AAEA;AACC;AAER,SAAK,WAAW,eAAe,QAAQ;AAGvC,SAAK,QAAQ,KAAK,IAAI,KAAK,aAAa;AAAA,EAC1C;AAAA,EAMA,MAAM,UAAU,UAAkB;AAChC,QAAI,aAAa,KAAK,OAAO;AAE3B;AAAA,IACF;AAEA,UAAM,YAAY;AAAA,MAChB,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL;AAAA,IACF;AAAA,EACF;AACF;AAEA,eAAsB,iBACpB,QACoB;AACpB,QAAM,EAAE,SAAS,IAAI;AACrB,QAAM,kBAAkB,OAAO,mBAAmB;AAElD,EAAAA,KAAI,KAAK,gBAAM,OAAO,8BAAoB;AAE1C,QAAM,MAAM,MAAM,YAAY,IAAI;AAAA,IAChC,eAAe,OAAO;AAAA,IACtB,OAAO,OAAO;AAAA,EAChB,CAAC;AACD,MAAI,CAAC,IAAI,KAAK,QAAQ;AACpB,IAAAA,KAAI;AAAA,MACF,GAAG,OAAO;AAAA,IACZ;AACA,WAAO,IAAI,UAAU,QAAQ,CAAC;AAAA,EAChC;AAEA,QAAM,YAAY,IAAI,UAAU,QAAQ,IAAI,KAAK,OAAO,SAAS,CAAC;AAElE,MAAI,KAAK,OAAO,QAAQ,CAAC,KAAe,aAAa;AAnEvD;AAqEI,UAAM,gBAAgB,WAAW;AACjC,QAAI,kBAAkB,eAAe;AAEnC;AAAA,IACF;AAEA,UAAM,WAAU,SAAI,eAAe,SAAS,GAAG,OAA/B,mBAAmC;AAEnD,QAAI,SAAS;AACX,UAAI,UAAU,OAAO,IAAI,OAAO,GAAG;AACjC,QAAAA,KAAI;AAAA,UACF,gBAAM,OAAO,qDAA4B;AAAA,QAC3C;AAAA,MACF,OAAO;AACL,kBAAU,OAAO,IAAI,OAAO;AAAA,MAC9B;AAEA,aAAO,QAAQ,QAAQ,CAAC,SAAS;AAC/B,kBAAU;AAAA,UACR;AAAA,UACA,IAAI;AAAA,YACF,OAAO;AAAA,YACP,OAAO;AAAA,YACP;AAAA,YACA,SAAS;AAAA,YACT;AAAA,YACA;AAAA,UACF;AAAA,QACF;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF,CAAC;AAED,SAAO;AACT;AAEO,IAAM,YAAN,MAAgB;AAAA,EAGrB,YACU,QAED,oBACP;AAHQ;AAED;AALT,kBAAS,oBAAI,IAAY;AAQzB,SAAQ,QAAQ,IAAI;AAAA,MAClB,KAAK,OAAO,QAAQ,IAAI,CAAC,SAAS;AAChC,eAAO,CAAC,MAAM,oBAAI,IAA2B,CAAC;AAAA,MAChD,CAAC;AAAA,IACH;AAAA,EANG;AAAA,EAQH,YAAY,MAAc,SAAiB;AACzC,WAAO,KAAK,MAAM,IAAI,IAAI,EAAE,IAAI,OAAO;AAAA,EACzC;AAAA,EAEA,YAAY,MAAc,UAAyB;AACjD,SAAK,MAAM,IAAI,IAAI,EAAE,IAAI,SAAS,KAAK,QAAQ;AAAA,EACjD;AAAA,EAEA,YAAY,MAAc,SAAiB;AACzC,WAAO,KAAK,MAAM,IAAI,IAAI,EAAE,IAAI,OAAO;AAAA,EACzC;AAAA,EAEA,gBAAgB,MAAc;AAC5B,UAAM,MAAM,CAAC;AACb,SAAK,MAAM,IAAI,IAAI,EAAE,QAAQ,CAAC,aAAa;AACzC,UAAI,SAAS,OAAO,SAAS;AAAA,IAC/B,CAAC;AACD,WAAO;AAAA,EACT;AACF;;;ALrIA,IAAMC,OAAM,aAAa,UAAU;AAEnC,eAAsB,WAAW;AAC/B,QAAM,SAAS,MAAM,UAAU;AAC/B,MAAI,IAAI;AACR,aAAW,cAAc,QAAQ;AAC/B;AACA,QAAI,CAAC,WAAW,WAAW,CAAC,WAAW,YAAY;AACjD,MAAAA,KAAI,MAAM,UAAU,kEAA+B;AACnD;AAAA,IACF;AACA,UAAM,YAAY,MAAM,iBAAiB,UAAU;AAEnD,UAAM,aAAa,MAAMC,MAAK,WAAW,SAAS,OAAO,QAAQ,UAAU;AACzE,YAAM,WAAW,IAAI,SAAS,QAAQ,UAAU;AAChD,YAAM,SAAS,oBAAoB,UAAU,gBAAgB,MAAM,CAAC;AACpE,YAAM,SAAS,WAAW;AAC1B,aAAO,MAAM,SAAS,UAAU;AAAA,IAClC,CAAC;AACD,aAAS,eAAe,GAAG,WAAW,yCAAqB,UAAU;AAAA,EACvE;AACF;;;AMzBA,OAAOC,SAAQ;AACf,OAAOC,WAAU;AAEjB,IAAMC,OAAM,aAAa,YAAY;AAErC,IAAM,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAYL,IAAM,aAAa,YAAY;AACpC,QAAM,SAAS,MAAM,UAAU;AAC/B,QAAM,aAAaD,MAAK,KAAK,OAAO,GAAG,KAAK,UAAU;AACtD,EAAAC,KAAI,KAAK,qBAAqB,YAAY;AAC1C,MAAI,MAAMF,IAAG,WAAW,UAAU,GAAG;AACnC,IAAAE,KAAI,KAAK,kCAAkC;AAC3C;AAAA,EACF;AACA,QAAMF,IAAG,UAAU,YAAY,GAAG;AAClC,EAAAE,KAAI,KAAK,qBAAqB;AAChC;;;AC7BA,OAAOC,WAAU;AAQjB,IAAMC,OAAM,aAAa,QAAQ;AAMjC,eAAe,gBAAgB,QAAwB;AACrD,MAAI,YAAY,MAAM,iBAAiB,MAAM;AAE7C,QAAM,UAAU,CAAC;AACjB,QAAM,cAAc,oBAAI,IAAsB;AAC9C,QAAMC,MAAK,OAAO,SAAS,OAAO,WAAW;AAC3C,UAAM,WAAW,IAAI,SAAS,QAAQ,MAAM;AAC5C,gBAAY,IAAI,QAAQ,QAAQ;AAChC,UAAM,OAAO,MAAM,SAAS,SAAS;AACrC,YAAQ,KAAK,GAAG,OAAO,KAAK,IAAI,CAAC;AAAA,EACnC,CAAC;AAED,MAAI,eAAe,MAAM,KAAK,IAAI,IAAI,OAAO,CAAC,EAAE,OAAO,CAAC,QAAQ;AAE9D,WAAO,CAAC,UAAU,OAAO,IAAI,GAAG;AAAA,EAClC,CAAC;AACD,iBAAe,aAAa,KAAK,OAAO,SAAS;AAEjD,MAAI,aAAa,QAAQ;AACvB,IAAAD,KAAI,KAAK,0DAAa,aAAa,0CAAsB;AACzD,UAAM,YAAY;AAAA,MAChB,OAAO;AAAA,MACP,OAAO;AAAA,MACP,eAAe,OAAO,SAAS,GAAG;AAAA,MAClC,UAAU;AAAA,MACV;AAAA,IACF;AACA,IAAAA,KAAI,KAAK,mDAAgB;AAGzB,eAAW,QAAQ,OAAO,SAAS;AACjC,YAAM,WAAW,YAAY,IAAI,IAAI;AACrC,YAAM,iBAAiB,CAAC;AACxB,mBAAa,QAAQ,CAAC,MAAM;AAC1B,uBAAe,KAAK,SAAS,KAAK,EAAE;AAAA,MACtC,CAAC;AACD,MAAAA,KAAI;AAAA,QACF,wCAAU,2BAAY,eAAe;AAAA,MACvC;AACA,YAAM,YAAY;AAAA,QAChB,OAAO;AAAA,QACP,OAAO;AAAA,QACP,eAAe,OAAO,SAAS,KAAK;AAAA,QACpC,UAAU;AAAA,QACV;AAAA,MACF;AAAA,IACF;AAEA,UAAM,MAAM,GAAI;AAChB,gBAAY,MAAM,iBAAiB,MAAM;AACzC,IAAAA,KAAI,KAAK,kCAAS,OAAO,+BAAgB;AAAA,EAC3C;AAEA,SAAO,EAAE,WAAW,YAAY;AAClC;AACA,SAAS,MAAM,IAAY;AACzB,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,eAAW,SAAS,EAAE;AAAA,EACxB,CAAC;AACH;AAEA,eAAsB,SAAS;AAC7B,QAAM,SAAS,MAAM,UAAU;AAE/B,aAAW,cAAc,QAAQ;AAC/B,UAAM,EAAE,WAAW,YAAY,IAAI,MAAM,gBAAgB,UAAU;AACnE,UAAMC,MAAK,WAAW,SAAS,OAAO,WAAW;AAC/C,YAAM,WAAW,YAAY,IAAI,MAAM;AACvC,YAAM,SAAS,gBAAgB,SAAS;AAAA,IAC1C,CAAC;AAAA,EACH;AAEA,EAAAD,KAAI,KAAK,0BAAM;AACjB;;;;;;ACtFA,OAAO,aAAa;AAEpB,IAAME,QAAM,aAAa,aAAa;AAE/B,IAAM,cAAc,OAAO,SAAc;AAC9C,QAAM,WAAW,IAAI,SAAS,OAAO,CAACC,aAAY;AAChD,QAAIA,SAAQ,MAAM;AAChB,aAAO,CAACA,SAAQ,KAAK,WAAW,IAAI,KAAKA,SAAQ,SAAS;AAAA,IAC5D;AACA,WAAO;AAAA,EACT,CAAC;AAED,QAAM,aAAa,oBAAI,IAAqC;AAC5D,QAAM,MAAM,MAAM,QAAQ;AAAA,IACxB,MAAM;AAAA,IACN,MAAM;AAAA,IACN,SAAS;AAAA,IACT,SAAS,SAAS,IAAI,CAACA,aAAY;AACjC,iBAAW,IAAIA,SAAQ,MAAMA,QAAO;AACpC,aAAO;AAAA,QACL,OAAOA,SAAQ;AAAA,QACf,OAAOA,SAAQ;AAAA,QACf,aAAaA,SAAQ;AAAA,MACvB;AAAA,IACF,CAAC;AAAA,EACH,CAAC;AAED,QAAM,UAAU,WAAW,IAAI,IAAI,OAAO;AAC1C,MAAI,CAAC,SAAS;AACZ,IAAAD,MAAI,MAAM,qCAAY,IAAI,OAAO;AACjC;AAAA,EACF;AACA,UAAQ,cAAc,MAAM,KAAK,IAAI;AACvC;;;ACzBA,IACG,QAAQ,YAAY,sCAAQ,EAC5B,MAAM,KAAK,EACX,QAAQ,eAAe,EACvB,QAAQ,UAAU,EAClB,OAAO,QAAQ;AAElB,IAAI,QAAQ,UAAU,sCAAQ,EAAE,QAAQ,aAAa,EAAE,OAAO,MAAM;AAEpE,IACG,QAAQ,WAAW,kDAAU,EAC7B,QAAQ,cAAc,EACtB,OAAO,OAAO;AAEjB,IAAI,QAAQ,QAAQ,4CAAS,EAAE,QAAQ,WAAW,EAAE,OAAO,UAAU;AAErE,IACG,QAAQ,eAAe,gCAAO,EAC9B,QAAQ,kBAAkB,EAC1B,MAAM,GAAG,EACT,OAAO,WAAW;AAErB,IAAI,QAAQ,EAAE,EAAE,OAAO,WAAW;AAElC,IAAI,QAAQ,OAAO;AACnB,IAAI,KAAK;AAAA,CAER,YAAY;AACX,MAAI;AAEF,QAAI,MAAM,QAAQ,MAAM,EAAE,KAAK,MAAM,CAAC;AAGtC,UAAM,IAAI,kBAAkB;AAAA,EAC9B,SAAS,OAAP;AAAA,EAKF;AACF,GAAG;","names":["fs","pMap","homeConfigDir","fs","path","pc","log","extract","pMap","fs","pMap","google","fs","log","log","fs","log","google","log","log","pMap","fs","path","log","pMap","log","pMap","log","command"]}
|
|
1
|
+
{"version":3,"sources":["../src/commands/extract.ts","../src/shared/index.ts","../src/shared/i18nData.ts","../src/commands/download.ts","../src/shared/google/sheet.ts","../src/shared/letters.ts","../src/shared/google/auth.ts","../src/shared/google/shared.ts","../src/shared/resolveSheetData.ts","../src/commands/generateApi/index.ts","../src/commands/initConfig.ts","../src/commands/upload.ts","../src/commands/interactive.ts","../src/cli.ts"],"sourcesContent":["import fs from \"fs-extra\";\nimport { globby } from \"globby\";\nimport pMap from \"p-map\";\nimport { createLogger } from \"../shared\";\nimport { getConfig } from \"../shared/config\";\nimport { I18nData, ExtractedMap } from \"../shared/i18nData\";\nimport pc from \"picocolors\";\n\nconst log = createLogger(\"extract\");\n\nexport async function extract() {\n const config = await getConfig();\n const { extract } = await import(\"@dune2/wasm\");\n\n // 这是使得任务串行,方便看日志\n for (const configItem of config.i18n ?? []) {\n const files = await globby(\n [`**/**.{js,jsx,ts,tsx}`, \"!**/node_modules/**\", \"!**.d.ts\"],\n {\n cwd: configItem.cwd,\n }\n );\n log.info(\"预计共解析 %s 个文件\", pc.green(files.length));\n const extractedI18nDataMap: ExtractedMap = new Map();\n await pMap(\n files,\n async (file) => {\n const content = await fs.readFile(file, \"utf-8\");\n const res: ExtractedMap = await extract(content);\n log.info(\n \"从 %s 中提取到 %s 条文案\",\n pc.dim(file),\n res.size ? pc.green(res.size) : res.size\n );\n res.forEach((value, key) => {\n const cur = extractedI18nDataMap.get(key);\n // 优先保留有 messages 的\n if (!cur?.messages) {\n extractedI18nDataMap.set(key, value);\n }\n });\n },\n { concurrency: 20 }\n );\n log.info(\n \"总统提取到 %s 条文案 %O\",\n pc.green(extractedI18nDataMap.size),\n extractedI18nDataMap\n );\n\n const statistics = await pMap(\n configItem.locales ?? [],\n async (locale, index) => {\n const i18nData = new I18nData(locale, configItem);\n await i18nData.updateByExtractedData(extractedI18nDataMap, index === 0);\n await i18nData.saveToDisk();\n return await i18nData.statistic();\n }\n );\n I18nData.printStatistic(\"提取结果: \", statistics);\n }\n}\n","import cac from \"cac\";\nimport debug from \"debug\";\nimport path from \"path\";\nimport fs from \"fs-extra\";\n\nexport const cli = cac(\"dune\");\n\nexport const createLogger = (name: string) => {\n const info = debug(`${cli.name}:${name}`);\n return {\n ...info,\n info,\n error: info.extend(\"error\"),\n };\n};\n\ndebug.enable(`${cli.name}:*`);\n\n/**\n * same with chacheDir\n * homeDir();\n * //=> '~/name'\n *\n * homeDir('bar.js')\n * //=> '~/name/bar.js'\n */\n// eslint-disable-next-line @typescript-eslint/explicit-function-return-type\nexport const homeConfigDir = (() => {\n const isWin = process.platform === \"win32\";\n const USER_HOME_DIR = isWin ? process.env.USERPROFILE : process.env.HOME;\n const configDir = path.join(USER_HOME_DIR!, \".config\", cli.name);\n\n if (!fs.existsSync(configDir)) {\n fs.mkdirSync(configDir);\n }\n return homeConfigDir;\n\n function homeConfigDir(p?: string): string {\n if (!p) {\n return configDir;\n }\n return path.join(configDir, p);\n }\n})();\n","import pMap from \"p-map\";\nimport { I18nConfig } from \"./config\";\nimport { createLogger } from \"./index\";\nimport fs from \"fs-extra\";\nimport pc from \"picocolors\";\nimport path from \"path\";\nimport Table from \"cli-table3\";\nimport { SheetData } from \"./resolveSheetData\";\n\nconst log = createLogger(\"i18nData\");\nexport type ExtractedMap = Map<string, { id: string; messages: string }>;\n\nexport class I18nData {\n data: Record<string, string> = {};\n\n filePath: string;\n\n constructor(public locale: string, public config: I18nConfig) {\n this.filePath = path.join(\n config.cwd!,\n config.i18nDir!,\n config.i18nFileName!.replace(\"{locale}\", locale)\n );\n }\n\n async loadData() {\n try {\n if (await fs.pathExists(this.filePath)) {\n this.data = await fs.readJSON(this.filePath);\n } else {\n log.info(\"File '%s' does not exist\", pc.dim(this.filePath));\n }\n } catch (e) {\n log.error(\n \"Error loading i18n data for locale '%s' from file '%s'\",\n pc.yellow(this.locale),\n pc.yellow(this.filePath)\n );\n log.error(\"Error: %s\", e.message);\n }\n return this.data;\n }\n\n async updateByExtractedData(\n extractedData: ExtractedMap,\n shouldUseDefault = false\n ) {\n await this.loadData();\n extractedData.forEach((value, key) => {\n this.data[key] = shouldUseDefault\n ? value.messages || key\n : this.data[key] || \"\";\n });\n }\n\n async updateFromSheetData(sheetData: Record<string, string>) {\n await this.loadData();\n this.data = { ...this.data, ...sheetData };\n }\n\n private sortData() {\n //region 语言key按一定规则排序\n const keys = Object.keys(this.data).sort(this.config.keySorter);\n const newData = {};\n keys.forEach((key) => {\n newData[key] = this.data[key];\n });\n this.data = newData;\n //endregion\n }\n\n async saveToDisk() {\n this.sortData();\n log.info(\n \"Saving i18n data for locale '%s' to file '%s'\",\n pc.green(this.locale),\n pc.dim(this.filePath)\n );\n try {\n await fs.ensureFile(this.filePath);\n await fs.writeJson(this.filePath, this.data, { spaces: 2 });\n log.info(\n \"Saved i18n data for locale '%s' to file '%s'\",\n pc.green(this.locale),\n pc.dim(this.filePath)\n );\n } catch (e) {\n log.error(\n \"Error saving i18n data for locale '%s' to file '%s'\",\n pc.green(this.locale),\n pc.dim(this.filePath)\n );\n log.error(\"Error: %s\", pc.red(e.message));\n }\n }\n\n async statistic() {\n const total = Object.keys(this.data).length;\n const missing = Object.values(this.data).filter((v) => !v).length;\n\n return {\n locale: this.locale,\n total,\n missing,\n };\n }\n\n async trySaveToGoogle(sheetData: SheetData) {\n await pMap(Object.entries(this.data), async ([key, value]) => {\n if (sheetData.hasI18nItem(this.locale, key)) {\n // 更新已有的\n await sheetData.getI18nItem(this.locale, key)?.tryUpdate(value);\n } else {\n log.error(\n \"%s range %s not found key %s\",\n pc.bold(this.config.sheetRange),\n pc.bold(this.locale),\n pc.bold(key)\n );\n }\n });\n }\n\n static printStatistic(\n label: string,\n statistics: { locale: string; total: number; missing: number }[]\n ) {\n const table = new Table({\n head: [\"Language\", \"Total count\", \"Missing\"],\n colAligns: [\"left\", \"center\", \"center\"],\n style: {\n head: [\"green\"],\n border: [],\n compact: true,\n },\n });\n statistics.forEach((statistic) => {\n table.push([\n statistic.locale,\n statistic.total,\n statistic.missing > 0 ? pc.red(statistic.missing) : statistic.missing,\n ]);\n });\n console.log(pc.bold(label));\n console.log(table.toString());\n }\n}\n","import pMap from \"p-map\";\nimport { createLogger } from \"../shared\";\nimport { getConfig } from \"../shared/config\";\nimport { I18nData } from \"../shared/i18nData\";\nimport { resolveSheetData } from \"../shared/resolveSheetData\";\n\nconst log = createLogger(\"generate\");\n\nexport async function download() {\n const config = await getConfig();\n let i = 0;\n for (const configItem of config.i18n ?? []) {\n i++;\n if (!configItem.sheetId || !configItem.sheetRange) {\n log.error(`config.${i} sheetId 或 sheetRange 为空,请检查`);\n continue;\n }\n const sheetData = await resolveSheetData(configItem);\n\n const statistics = await pMap(\n configItem.locales ?? [],\n async (locale, index) => {\n const i18nData = new I18nData(locale, configItem);\n await i18nData.updateFromSheetData(sheetData.getLangDataJSON(locale));\n await i18nData.saveToDisk();\n return await i18nData.statistic();\n }\n );\n I18nData.printStatistic(`${configItem.sheetRange} 生成结果: `, statistics);\n }\n}\n","import { GaxiosResponse } from \"gaxios\";\nimport type { sheets_v4 } from \"googleapis\";\nimport { google } from \"googleapis\";\nimport { createLogger } from \"../index\";\nimport { numberToLetter } from \"../letters\";\nimport { googleAuth } from \"./auth\";\n\nconst log = createLogger(\"google:sheets\");\n\nclass GoogleSheet {\n private sheets: sheets_v4.Sheets;\n\n private initPromise: Promise<void> | null = null;\n private async initImpl() {\n if (!this.sheets) {\n await googleAuth.initCredentials();\n this.sheets = google.sheets({\n version: \"v4\",\n auth: googleAuth.oauth2Client,\n });\n }\n }\n /**\n * 调用sheets其他方法的时候需要先初始化\n */\n async init() {\n if (!this.initPromise) {\n this.initPromise = this.initImpl();\n }\n await this.initPromise;\n }\n\n get = async (options: sheets_v4.Params$Resource$Spreadsheets$Values$Get) => {\n await this.init();\n return this.sheets.spreadsheets.values.get(options);\n };\n\n private async update(\n spreadsheetId: string,\n range: string,\n colIndex: number,\n rowIndex: number,\n values: string[][]\n ): Promise<GaxiosResponse<sheets_v4.Schema$UpdateValuesResponse>> {\n await this.init();\n\n const colLetter = numberToLetter(colIndex);\n const sheetNeedRange = `${range}!${colLetter}${rowIndex}`;\n\n const res = await this.sheets.spreadsheets.values.update({\n spreadsheetId,\n range: sheetNeedRange,\n valueInputOption: \"USER_ENTERED\",\n requestBody: { values },\n });\n\n if (res.status === 200) {\n log.info(`更新 ${sheetNeedRange} 的值成功`);\n } else {\n log.error(\"some thing wrong\", res);\n }\n return res;\n }\n\n /**\n * 更新某一个单元格\n */\n async updateCell(\n spreadsheetId: string,\n range: string,\n colIndex: number,\n rowIndex: number,\n values: string\n ) {\n return this.update(spreadsheetId, range, colIndex, rowIndex, [[values]]);\n }\n\n /**\n * 更新某一列\n */\n async updateColumn(\n spreadsheetId: string,\n range: string,\n colIndex: number,\n rowIndex: number,\n values: string[]\n ) {\n return this.update(spreadsheetId, range, colIndex, rowIndex, [\n ...values.map((v) => [v]),\n ]);\n }\n}\n\nexport const googleSheet = new GoogleSheet();\n","/**\n *\n * - input : A\n * output : 0\n * - input : Z\n * output : 25\n * - input : AA\n * output : 26\n * - input : a\n * output : 0\n */\nexport function letterToNumber(letters: string | number) {\n if (typeof letters === \"number\" || !Number.isNaN(+letters)) {\n return +letters;\n }\n\n let n = 0;\n letters = letters.toUpperCase();\n for (let p = 0; p < letters.length; p++) {\n n = letters[p].charCodeAt(0) - 64 + n * 26;\n }\n\n return Math.max(0, n - 1);\n}\n\n/**\n * fork from https://github.com/matthewmueller/number-to-letter\n */\nconst alphabet = \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\";\nconst base = alphabet.length;\n/**\n * numberToLetter(0) // A\n * numberToLetter(25) // Z\n * numberToLetter(26) // AA\n * numberToLetter(51) // AZ\n * numberToLetter(52) // BA\n * numberToLetter(676) // ZA\n * numberToLetter(701) // ZZ\n * numberToLetter(702) // AAA\n */\nexport function numberToLetter(n: number) {\n const digits: number[] = [];\n\n do {\n const v = n % base;\n digits.push(v);\n n = Math.floor(n / base);\n } while (n-- > 0);\n\n const chars: string[] = [];\n while (digits.length) {\n chars.push(alphabet[digits.pop()!]);\n }\n\n return chars.join(\"\");\n}\n","import fs from \"fs-extra\";\nimport { OAuth2Client } from \"google-auth-library\";\nimport { google } from \"googleapis\";\nimport { homeConfigDir, createLogger } from \"../index\";\nimport { openAndWaitReturnQuery } from \"./shared\";\n\ninterface AuthOptions {\n client_id: string;\n client_secret: string;\n /**\n * @default ['spreadsheets']\n */\n scope?: string[];\n}\n\nconst log = createLogger(\"google:auth\");\n\nclass GoogleAuth {\n private tokens: any = null;\n\n private tokensCachePath = homeConfigDir(\"chromeAuthToken.json\");\n\n private readonly scope: string[];\n\n oauth2Client: OAuth2Client = new google.auth.OAuth2(\n this.options.client_id,\n this.options.client_secret,\n \"http://localhost:12345\"\n );\n\n constructor(private options: AuthOptions) {\n this.options.scope = this.options.scope ?? [\"spreadsheets\"];\n const scopePrefix = `https://www.googleapis.com/auth/`;\n this.scope = this.options.scope.map((item) => {\n if (item.startsWith(scopePrefix)) {\n return item;\n }\n return `${scopePrefix}${item}`;\n });\n\n try {\n this.tokens = fs.readJsonSync(this.tokensCachePath);\n } catch (e) {\n log.info(\"未获取到缓存的token\");\n this.tokens = null;\n }\n }\n\n private async saveTokens(tokens: any): Promise<void> {\n this.tokens = tokens;\n await fs.writeJSON(this.tokensCachePath, tokens);\n log.info(\"保存token成功\");\n }\n\n async getCode(): Promise<string> {\n log.info(\"将打开chrome浏览器进行授权\");\n const authUrl = this.oauth2Client.generateAuthUrl({\n access_type: \"offline\",\n scope: this.scope,\n });\n return await openAndWaitReturnQuery(authUrl, 12345, \"code\");\n }\n\n private async initCredentialsImpl(): Promise<void> {\n if (!this.tokens) {\n const code = await this.getCode();\n const { tokens } = await this.oauth2Client.getToken(code);\n await this.saveTokens(tokens);\n }\n this.oauth2Client.setCredentials(this.tokens);\n }\n private initCredentialsPromise: Promise<void> | null = null;\n async initCredentials() {\n if (!this.initCredentialsPromise) {\n this.initCredentialsPromise = this.initCredentialsImpl();\n }\n return await this.initCredentialsPromise;\n }\n}\n\n// see in https://console.cloud.google.com/apis/credentials?organizationId=286245507762&orgonly=true&project=dune-cli&supportedpurview=organizationId\nconst clientSecret = {\n client_id:\n \"728508473485-fgl11a3op1ucd0lef9hs49mkliuaipqa.apps.googleusercontent.com\",\n project_id: \"dune-cli\",\n auth_uri: \"https://accounts.google.com/o/oauth2/auth\",\n token_uri: \"https://oauth2.googleapis.com/token\",\n auth_provider_x509_cert_url: \"https://www.googleapis.com/oauth2/v1/certs\",\n client_secret: \"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\",\n redirect_uris: [\"http://localhost\"],\n};\nexport const googleAuth = new GoogleAuth(clientSecret);\n","import connect from \"connect\";\nimport open from \"open\";\nimport { URL } from \"url\";\nimport { createLogger } from \"../index\";\n\nconst log = createLogger(\"google:shared\");\n\nfunction openBrowser(url: string) {\n log.info(`如未自动打开浏览器,可访问以下地址:${url}`);\n open(url, { app: { name: open.apps.chrome } });\n}\n\nexport function openAndWaitReturnQuery(\n toOpenUrl: string,\n port: number,\n queryKey: string\n) {\n return new Promise<string>((resolve) => {\n openBrowser(toOpenUrl);\n\n const app = connect();\n app.use((req, res, next) => {\n const parsedUrl = new URL(req.url, `http://localhost:${port}`);\n const target = parsedUrl.searchParams.get(queryKey);\n if (target) {\n res.writeHead(200, {\n \"content-type\": \"text/html;charset=utf8\",\n });\n res.end(\n `<div>当前窗口可直接关闭</div>\n <script>\n window.open(\"\", \"_self\", \"\");\n window.close();\n </script>`\n );\n server.close();\n server.unref();\n resolve(target);\n }\n next();\n });\n\n const server = app.listen(port);\n });\n}\n","import { I18nConfig } from \"./config\";\nimport { googleSheet } from \"./google/sheet\";\nimport { createLogger } from \"./index\";\nimport { letterToNumber } from \"./letters\";\n\nconst log = createLogger(\"shared:resolveSheetData\");\n\nclass SheetI18nItem {\n value: string;\n\n colIndex: number;\n\n constructor(\n private spreadsheetId: string,\n private range: string,\n public key: string,\n colIndex: number | string,\n public row: string[],\n private rowIndex: number\n ) {\n this.colIndex = letterToNumber(colIndex);\n // TODO: 待确定 无值的key是否要生成\n // value = undefined 即不会生成\n this.value = this.row[this.colIndex] || \"\";\n }\n\n /**\n * 尝试更新 单元格的值\n * 如果一样则不更新\n */\n async tryUpdate(newValue: string) {\n if (newValue === this.value) {\n // 云端的值跟本地一样 不需要同步\n return;\n }\n\n await googleSheet.updateCell(\n this.spreadsheetId,\n this.range,\n this.colIndex,\n this.rowIndex,\n newValue\n );\n }\n}\n\nexport async function resolveSheetData(config: I18nConfig): Promise<SheetData> {\n const { position } = config;\n const parseStartIndex = config.parseStartIndex ?? 2;\n\n log.info(`读取 ${config.sheetRange} sheet数据`);\n\n const res = await googleSheet.get({\n spreadsheetId: config.sheetId,\n range: config.sheetRange,\n });\n if (!res.data.values) {\n log.error(\n `${config.sheetRange} sheet数据为空,请检查,应该最少有一行头部数据`\n );\n return new SheetData(config, 2);\n }\n\n const sheetData = new SheetData(config, res.data.values.length + 1);\n\n res.data.values.forEach((row: string[], rowIndex) => {\n // excel 的开始索引是1,所以要 +1\n const trulyRowIndex = rowIndex + 1;\n if (parseStartIndex > trulyRowIndex) {\n // 还未到可以开始解析的行数\n return;\n }\n\n const i18nKey = row[letterToNumber(position!.key)]?.trim();\n\n if (i18nKey) {\n if (sheetData.keySet.has(i18nKey)) {\n log.error(\n `表格 ${config.sheetRange} 发现重复的i18nKey: ${i18nKey}, 将覆盖前面的值`\n );\n } else {\n sheetData.keySet.add(i18nKey);\n }\n\n config.locales?.forEach((lang) => {\n sheetData.setI18nItem(\n lang,\n new SheetI18nItem(\n config.sheetId!,\n config.sheetRange!,\n i18nKey,\n position![lang],\n row,\n trulyRowIndex\n )\n );\n });\n }\n });\n\n return sheetData;\n}\n\nexport class SheetData {\n keySet = new Set<string>();\n\n constructor(\n private config: I18nConfig,\n // 当前有多少行 新增的时候往后面添加\n public nextAppendRowIndex: number\n ) {}\n\n private value = new Map(\n this.config.locales!.map((lang) => {\n return [lang, new Map<string, SheetI18nItem>()];\n })\n );\n\n getI18nItem(lang: string, i18nKey: string) {\n return this.value.get(lang)!.get(i18nKey);\n }\n\n setI18nItem(lang: string, i18nItem: SheetI18nItem) {\n this.value.get(lang)!.set(i18nItem.key, i18nItem);\n }\n\n hasI18nItem(lang: string, i18nKey: string) {\n return this.value.get(lang)!.has(i18nKey);\n }\n\n getLangDataJSON(lang: string) {\n const res = {} as Record<string, string>;\n this.value.get(lang)!.forEach((i18nItem) => {\n res[i18nItem.key] = i18nItem.value;\n });\n return res;\n }\n}\n","import _ from \"lodash\";\nimport { OpenAPIV3 } from \"openapi-types\";\nimport pMap from \"p-map\";\nimport { createLogger } from \"../../shared\";\nimport { getConfig, ApiConfig } from \"../../shared/config\";\nimport fs from \"fs-extra\";\nimport * as os from \"os\";\nimport SwaggerParser from \"@apidevtools/swagger-parser\";\nimport { compile } from \"json-schema-to-typescript\";\nimport path from \"path\";\n\nconst log = createLogger(\"generateApi\");\n\nexport async function generateApi() {\n const config = await getConfig();\n\n for (const apiConfig of config.api ?? []) {\n log.info(`清除旧的api文件: ${apiConfig.output}`);\n await fs.emptydir(apiConfig.output!);\n }\n\n for (const apiConfig of config.api ?? []) {\n log.info(\"开始解析 %s\", apiConfig.swaggerJSONPath);\n const parsed = (await SwaggerParser.dereference(\n apiConfig.swaggerJSONPath\n )) as OpenAPIV3.Document;\n\n await pMap(Object.entries(parsed.paths), async ([url, pathItemObject]) => {\n log.info(\"开始生成 %s\", url);\n if (pathItemObject) {\n await pMap(\n [\"get\", \"put\", \"post\", \"delete\", \"patch\"],\n async (method) => {\n const operationObject = pathItemObject[method];\n if (operationObject) {\n const code = await generateApiRequestCode({\n url: url,\n method: method,\n operationObject: operationObject,\n apiConfig,\n });\n const outputPath = path.join(\n apiConfig.output!,\n url,\n `${method}.ts`\n );\n await fs.ensureFile(outputPath);\n await fs.writeFile(outputPath, code);\n }\n }\n );\n }\n });\n }\n\n log.info(\"generateApi Done\");\n}\n\n/**\n * 根据请求方法,生成请求代码\n */\nexport async function generateApiRequestCode(options: {\n url: string;\n method: string;\n operationObject: OpenAPIV3.OperationObject;\n apiConfig: ApiConfig;\n}): Promise<string> {\n const { url, method, operationObject, apiConfig } = options;\n\n const seeUrl = apiConfig.swaggerUiUrl\n ? `${apiConfig.swaggerUiUrl}#/${encodeURIComponent(\n operationObject.tags?.join(\"/\") ?? \"\"\n )}/${operationObject.operationId}`\n : \"not found swagger ui url\";\n\n const requestBuilderName = _.camelCase(`${url}_${method}_api`);\n //#region url上参数 例如 /api/v1/users/{userId}\n const urlPathParams = getUrlPathParams(\n (operationObject.parameters as never) ?? []\n );\n const urlPathParamsCode = urlPathParams.length\n ? `urlPathParams: ${JSON.stringify(urlPathParams)},`\n : \"\";\n //#endregion\n\n let code: string[] = [\n \"// 这个文件由 @dune2/cli 自动生成,不要手动修改,否则会被覆盖\",\n `import { RequestBuilder } from '@dune2/tools';`,\n apiConfig.requestFnImportPath!,\n `\\\n/**\n * ${operationObject.summary}\n * @tags ${operationObject.tags?.join(\",\")}\n * @see ${seeUrl}\n */`,\n ];\n\n // builder 代码\n code.push(`\\\nexport const ${requestBuilderName} = new RequestBuilder<${requestBuilderName}.Req, ${requestBuilderName}.Res>({\n url: '${url}',\n method: '${method}',\n requestFn,\n ${urlPathParamsCode}\n});`);\n\n // 请求参数类型\n // 响应参数类型\n const [requestParamsTypeCode, responseParamsTypeCode] = await Promise.all([\n compileRequestParams(operationObject),\n compileResponseParams(operationObject),\n ]);\n\n code.push(`\nexport namespace ${requestBuilderName} {\n ${requestParamsTypeCode}\n \n ${responseParamsTypeCode}\n};`);\n\n return code.join(os.EOL);\n}\n\nfunction getUrlPathParams(parameters: OpenAPIV3.ParameterObject[]) {\n return parameters\n .filter((item) => item.in === \"path\")\n .map((item) => item.name);\n}\n\n/**\n * 这个方法还不完善,只能处理简单的请求参数\n */\nasync function compileRequestParams(\n operationObject: OpenAPIV3.OperationObject\n) {\n let schema;\n if (operationObject.parameters) {\n // FIXME: 这里还需要处理 ref 类型\n const parameters =\n (operationObject.parameters as OpenAPIV3.ParameterObject[]).filter(\n (p) => p.in === \"query\" || p.in === \"path\"\n ) ?? [];\n\n const required = parameters.filter((p) => p.required).map((p) => p.name);\n const properties = Object.fromEntries(\n parameters.map((p) => {\n //TODO: 这里也要处理 ref 类型\n const schema = p.schema as OpenAPIV3.SchemaObject;\n return [\n p.name,\n {\n type: schema.type,\n description: p.description,\n // enum: schema.enum ?? [],\n },\n ];\n })\n );\n schema = {\n required,\n type: \"object\",\n properties,\n };\n } else if (operationObject.requestBody) {\n //TODO: 这里也需要处理其他类型\n schema = (operationObject.requestBody as OpenAPIV3.RequestBodyObject)\n .content[\"application/json\"].schema;\n }\n\n let code = \"\";\n if (schema) {\n code = await compile(schema, \"Req\", {\n bannerComment: \"\",\n ignoreMinAndMaxItems: !!1,\n // format: false,\n });\n }\n\n return code ? code : \"export type Req = any;\";\n}\n\nasync function compileResponseParams(\n operationObject: OpenAPIV3.OperationObject\n) {\n const temp = operationObject.responses[\"200\"] as OpenAPIV3.ResponseObject;\n let code = \"\";\n if (temp?.content) {\n // FIXME: 可能需要处理其他的content类型\n const temp2 = temp.content[\"application/json\"] || temp.content[\"*/*\"];\n const schema = temp2.schema as OpenAPIV3.SchemaObject;\n const data = schema.properties?.data ?? schema;\n if (data) {\n code = await compile(data, \"Res\", {\n bannerComment: \"\",\n ignoreMinAndMaxItems: !!1,\n // format: false,\n });\n }\n }\n\n return code ? code : \"export type Res = any;\";\n}\n","import { createLogger } from \"../shared\";\nimport { getConfig, configName } from \"../shared/config\";\nimport fs from \"fs-extra\";\nimport path from \"path\";\n\nconst log = createLogger(\"initConfig\");\n\nconst tpl = `\\\n/**\n * @template {import('@dune2/cli').Config} T\n * @param {T} config - A generic parameter that flows through to the return type\n * @constraint {{import('@dune2/cli').Config}}\n */\nfunction defineConfig(config) {\n return config;\n}\nmodule.exports = defineConfig({ i18n: [], api:[] });\n`;\n\nexport const initConfig = async () => {\n const config = await getConfig();\n const configPath = path.join(config.cwd!, configName);\n log.info(`config file path: ${configPath}`);\n if (await fs.pathExists(configPath)) {\n log.info(`config file already exists, skip`);\n return;\n }\n await fs.writeFile(configPath, tpl);\n log.info(`config file created`);\n};\n","import pMap from \"p-map\";\nimport { createLogger } from \"../shared\";\nimport { getConfig, I18nConfig } from \"../shared/config\";\nimport { googleSheet } from \"../shared/google/sheet\";\nimport { I18nData } from \"../shared/i18nData\";\nimport { letterToNumber } from \"../shared/letters\";\nimport { resolveSheetData } from \"../shared/resolveSheetData\";\n\nconst log = createLogger(\"upload\");\n\n/**\n * 检测有本地有新增的key 则将新增的key更新到云端\n * 无则跳过\n */\nasync function batchUpdateKeys(config: I18nConfig) {\n let sheetData = await resolveSheetData(config);\n\n const allKeys: string[] = [];\n const i18nDataMap = new Map<string, I18nData>();\n await pMap(config.locales ?? [], async (locale) => {\n const i18nData = new I18nData(locale, config);\n i18nDataMap.set(locale, i18nData);\n const data = await i18nData.loadData();\n allKeys.push(...Object.keys(data));\n });\n\n let needSyncKeys = Array.from(new Set(allKeys)).filter((key) => {\n // 本地有新的key 服务器没有\n return !sheetData.keySet.has(key);\n });\n needSyncKeys = needSyncKeys.sort(config.keySorter);\n\n if (needSyncKeys.length) {\n log.info(`即将同步本地新增加 ${needSyncKeys.length} 个 i18nKey 到云端`);\n await googleSheet.updateColumn(\n config.sheetId!,\n config.sheetRange!,\n letterToNumber(config.position!.key),\n sheetData.nextAppendRowIndex,\n needSyncKeys\n );\n log.info(\"同步新增加i18nKey成功\");\n\n // 批量同步新增的key的values到云端\n for (const lang of config.locales!) {\n const langFile = i18nDataMap.get(lang);\n const needSyncValues: string[] = [];\n needSyncKeys.forEach((k) => {\n if (langFile) {\n needSyncValues.push(langFile.data[k]);\n }\n });\n log.info(\n `即将同步本地 ${lang} 新增加 ${needSyncValues.length} 个值到云端`\n );\n await googleSheet.updateColumn(\n config.sheetId!,\n config.sheetRange!,\n letterToNumber(config.position![lang]),\n sheetData.nextAppendRowIndex,\n needSyncValues\n );\n }\n\n await sleep(1000);\n sheetData = await resolveSheetData(config);\n log.info(`已重新获取 ${config.sheetRange} 的数据`);\n }\n\n return { sheetData, i18nDataMap };\n}\nfunction sleep(ms: number) {\n return new Promise((resolve) => {\n setTimeout(resolve, ms);\n });\n}\n\nexport async function upload() {\n const config = await getConfig();\n\n for (const configItem of config.i18n ?? []) {\n const { sheetData, i18nDataMap } = await batchUpdateKeys(configItem);\n await pMap(configItem.locales ?? [], async (locale) => {\n const i18nData = i18nDataMap.get(locale)!;\n await i18nData.trySaveToGoogle(sheetData);\n });\n }\n\n log.info(\"上传成功\");\n}\n","import { cli, createLogger } from \"../shared\";\nimport prompts from \"prompts\";\n\nconst log = createLogger(\"interactive\");\n\nexport const interactive = async (args: any) => {\n const commands = cli.commands.filter((command) => {\n if (command.name) {\n return !command.name.startsWith(\"@@\") && command.name !== \"interactive\";\n }\n return false;\n });\n\n const commandMap = new Map<string, typeof commands[number]>();\n const res = await prompts({\n type: \"autocomplete\",\n name: \"command\",\n message: \"选择要执行的命令:\",\n choices: commands.map((command) => {\n commandMap.set(command.name, command);\n return {\n title: command.name,\n value: command.name,\n description: command.description,\n };\n }),\n });\n const command = commandMap.get(res.command);\n if (!command) {\n log.error(\"未找到命令 %s\", res.command);\n return;\n }\n command.commandAction?.apply(cli, args);\n};\n","#!/usr/bin/env node\nimport { extract } from \"./commands/extract\";\nimport { download } from \"./commands/download\";\nimport { generateApi } from \"./commands/generateApi\";\nimport { initConfig } from \"./commands/initConfig\";\nimport { upload } from \"./commands/upload\";\nimport { cli } from \"./shared\";\nimport { version } from \"../package.json\";\nimport { interactive } from \"./commands/interactive\";\n//#region 翻译相关\n\ncli\n .command(\"download\", \"生成翻译文件\")\n .example(\"dune download\")\n .action(download);\ncli\n .command(\"extract\", \"提取代码中的文案\")\n .example(\"dune extract\")\n .action(extract);\ncli.command(\"upload\", \"上传翻译文件\").example(\"dune upload\").action(upload);\n//#endregion\n\n//#region api 相关\ncli\n .command(\"generateApi\", \"生成api文件\")\n .example(\"dune generateApi\")\n .action(generateApi);\n//#endregion\n\ncli.command(\"init\", \"初始化配置文件\").example(\"dune init\").action(initConfig);\n\ncli\n .command(\"interactive\", \"交互式操作\")\n .example(\"dune interactive\")\n .alias(\"i\")\n .action(interactive);\n\n// make default command run interactive\ncli.command(\"\").action(interactive);\n\ncli.version(version);\ncli.help();\n\n(async () => {\n try {\n // Parse CLI args without running the command\n cli.parse(process.argv, { run: false });\n // Run the command yourself\n // You only need `await` when your command action returns a Promise\n await cli.runMatchedCommand();\n } catch (error) {\n // Handle error here..\n // e.g.\n // console.error(error.stack)\n // process.exit(1)\n }\n})();\n"],"mappings":"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","names":["fs","pMap","homeConfigDir","fs","path","pc","log","extract","pMap","fs","pMap","google","fs","log","log","fs","log","google","log","log","pMap","pMap","fs","path","log","pMap","schema","fs","path","log","pMap","log","pMap","log","command"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
interface
|
|
1
|
+
interface I18nConfig {
|
|
2
2
|
i18nDir?: string;
|
|
3
3
|
i18nFileName?: string;
|
|
4
4
|
defaultLocale?: string;
|
|
@@ -24,7 +24,58 @@ interface Config {
|
|
|
24
24
|
* @default 2
|
|
25
25
|
*/
|
|
26
26
|
parseStartIndex?: number;
|
|
27
|
+
/**
|
|
28
|
+
* 默认是 命令运行的目录,一般是项目根目录
|
|
29
|
+
* @internal
|
|
30
|
+
*/
|
|
31
|
+
cwd?: string;
|
|
32
|
+
/**
|
|
33
|
+
* 支持的语言列表,从 position 中解析出来
|
|
34
|
+
* @internal
|
|
35
|
+
*/
|
|
36
|
+
locales?: string[];
|
|
37
|
+
/**
|
|
38
|
+
* 翻译key的排序
|
|
39
|
+
* @internal
|
|
40
|
+
*/
|
|
41
|
+
keySorter?: (a: string, b: string) => number;
|
|
42
|
+
}
|
|
43
|
+
interface ApiConfig {
|
|
44
|
+
/**
|
|
45
|
+
* swagger JSON 的路径 可以是 本地 可以是远程
|
|
46
|
+
*/
|
|
47
|
+
swaggerJSONPath: string;
|
|
48
|
+
/**
|
|
49
|
+
* 用在生成代码里快捷连接跳转到 swagger ui
|
|
50
|
+
* 必须携带 urls.primaryName 参数
|
|
51
|
+
* @example http://192.168.104.10:31082/swagger/?urls.primaryName=%E5%90%8E%E5%8F%B0%E7%AE%A1%E7%90%86%E7%9B%B8%E5%85%B3API
|
|
52
|
+
*/
|
|
53
|
+
swaggerUiUrl?: string;
|
|
54
|
+
/**
|
|
55
|
+
* 输出的文件夹路径
|
|
56
|
+
* @default "./src/apis"
|
|
57
|
+
*/
|
|
58
|
+
output?: string;
|
|
59
|
+
/**
|
|
60
|
+
* 配置`requestFn` 方法引入的路径,生成的代码里会用到,生成代码如下
|
|
61
|
+
* 引入的名称必须是`requestFn`
|
|
62
|
+
* ```ts
|
|
63
|
+
* // 需要命名为 requestFn
|
|
64
|
+
* import requestFn from '@/utils/request'
|
|
65
|
+
* import { foo as requestFn } from '@/utils/request'
|
|
66
|
+
* ```
|
|
67
|
+
* @default `import requestFn from '@/utils/request'`
|
|
68
|
+
*/
|
|
69
|
+
requestFnImportPath?: string;
|
|
70
|
+
}
|
|
71
|
+
interface Config {
|
|
72
|
+
i18n?: I18nConfig[];
|
|
73
|
+
api?: ApiConfig[];
|
|
74
|
+
/**
|
|
75
|
+
* 默认是 命令运行的目录,一般是项目根目录
|
|
76
|
+
* @internal
|
|
77
|
+
*/
|
|
78
|
+
cwd?: string;
|
|
27
79
|
}
|
|
28
|
-
declare function defineConfig(config: Config | Config[]): Config | Config[];
|
|
29
80
|
|
|
30
|
-
export { Config
|
|
81
|
+
export { Config };
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dune2/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.6",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"dist"
|
|
20
20
|
],
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@dune2/wasm": "0.0.
|
|
22
|
+
"@dune2/wasm": "0.0.6",
|
|
23
23
|
"cac": "^6.7.14",
|
|
24
24
|
"cli-table3": "^0.6.3",
|
|
25
25
|
"connect": "^3.7.0",
|
|
@@ -32,10 +32,15 @@
|
|
|
32
32
|
"p-map": "^5.5.0",
|
|
33
33
|
"path-to-regexp": "^6.2.1",
|
|
34
34
|
"picocolors": "^1.0.0",
|
|
35
|
-
"prompts": "^2.4.2"
|
|
35
|
+
"prompts": "^2.4.2",
|
|
36
|
+
"json-schema-to-typescript": "^11.0.2",
|
|
37
|
+
"@apidevtools/swagger-parser": "^10.1.0",
|
|
38
|
+
"lodash": "^4.17.21"
|
|
36
39
|
},
|
|
37
40
|
"devDependencies": {
|
|
41
|
+
"openapi-types": "^12.0.2",
|
|
38
42
|
"@types/debug": "^4.1.7",
|
|
43
|
+
"@types/lodash": "^4.14.186",
|
|
39
44
|
"@types/prompts": "^2.4.0",
|
|
40
45
|
"gaxios": "*",
|
|
41
46
|
"google-auth-library": "*",
|
package/readme.md
CHANGED
|
@@ -3,15 +3,17 @@
|
|
|
3
3
|
- 提取翻译文案到`json`文件, 运行 `dune extract`
|
|
4
4
|
- 同步文件到`google sheet`(必须要有配置文件), 运行 `dune sync`
|
|
5
5
|
- 从`google sheet`生成文件(必须要有配置文件), 运行 `dune generate`
|
|
6
|
+
- 从`swagger` 生成`api`请求文件, 运行 `dune generateApi`
|
|
6
7
|
- 初始化配置文件, 运行 `dune init`
|
|
7
8
|
|
|
8
9
|
## 支持的命令
|
|
9
10
|
|
|
10
11
|
```shell
|
|
11
12
|
Commands:
|
|
12
|
-
|
|
13
|
-
upload 上传翻译文件
|
|
13
|
+
download 生成翻译文件
|
|
14
14
|
extract 提取代码中的文案
|
|
15
|
+
upload 上传翻译文件
|
|
16
|
+
generateApi 生成api文件
|
|
15
17
|
init 初始化配置文件
|
|
16
18
|
interactive 交互式操作
|
|
17
19
|
```
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/shared/config.ts","../src/shared/resolveSheetId.ts"],"sourcesContent":["import JoyCon from \"joycon\";\nimport { resolveSheetId } from \"./resolveSheetId\";\n\nconst joycon = new JoyCon();\n\nexport interface Config {\n // 语言文件存放目录,默认为项目根目录的 \"./src/i18n\"\n i18nDir?: string;\n // 语言文件名,默认为 \"{locale}.i18n.json\",其中 {locale} 会被替换为 locales 中的语言\n i18nFileName?: string;\n // 默认语言,默认为 \"zh\",影响到提出出来的文案的默认值\n defaultLocale?: string;\n /**\n * 可以是 id 或者 url,如果是 url 则会自动解析出 id\n * id: 1C9-Dol3oO20W9_FhiVlxNsDhOaaejJIgAZYRkonGmfk\n * url: https://docs.google.com/spreadsheets/d/1C9-Dol3oO20W9_FhiVlxNsDhOaaejJIgAZYRkonGmfk/edit#gid=1740568548\n */\n sheetId?: string;\n // google sheets 工作表名称\n sheetRange?: string;\n /**\n * 对应 语言、i18nKey 所在的列标识符 如(A,B,C...)\n * 传入时将忽略默认的配置\n * @default {key: \"B\", zh: \"C\", en: \"D\", in: \"E\",}\n */\n position?: {\n key: string;\n [key: string]: string;\n };\n\n /**\n * 从 Google Sheets 哪一行开始解析\n * 默认从第2行开始,模板文件第一行是表头\n * @default 2\n */\n parseStartIndex?: number;\n}\nexport interface InternalConfig extends Config {\n // 默认是 命令运行的目录,一般是项目根目录\n cwd?: string;\n // 支持的语言列表,从 position 中解析出来\n locales?: string[];\n\n keySorter?: (a: string, b: string) => number;\n}\n\nexport function defineConfig(config: Config | Config[]) {\n return config;\n}\n\nexport const configName = \"dune.config.js\";\n\nexport async function getConfig(): Promise<InternalConfig[]> {\n const res = await joycon.load([configName]);\n\n const defaultConfig = {\n i18nDir: \"./src/i18n\",\n i18nFileName: \"{locale}.i18n.json\",\n cwd: process.cwd(),\n position: { key: \"B\", zh: \"C\", en: \"D\", in: \"E\" },\n parseStartIndex: 2,\n };\n\n if (res.data) {\n const config: InternalConfig[] = Array.isArray(res.data)\n ? res.data\n : [res.data];\n return config.map((item) => {\n item = Object.assign({}, defaultConfig, item);\n item.locales = Object.keys(item.position).filter(\n (item) => item !== \"key\"\n );\n\n item.sheetId = resolveSheetId(item.sheetId);\n\n item.keySorter = (a, b) => {\n return a.localeCompare(b);\n };\n\n return item;\n });\n }\n\n return [defaultConfig];\n}\n","/**\n * input:\n * \"https://docs.google.com/spreadsheets/d/1C9-Dol3oO20W9_FhiVlxNsDhOaaejJIgAZYRkonGmfk/edit#gid=1740568548\"\n * output:\n * \"1C9-Dol3oO20W9_FhiVlxNsDhOaaejJIgAZYRkonGmfk\"\n * --\n * input: \"1C9-Dol3oO20W9_FhiVlxNsDhOaaejJIgAZYRkonGmfk\"\n * output: \"1C9-Dol3oO20W9_FhiVlxNsDhOaaejJIgAZYRkonGmfk\"\n */\nimport { match } from \"path-to-regexp\";\n\nexport function resolveSheetId(str?: string) {\n if (!str || !str?.startsWith(\"http\")) {\n return str;\n }\n const url = new URL(str);\n const matched = match<{ id: string[] }>(\"/spreadsheets/d/:id*\", {\n decode: decodeURIComponent,\n })(url.pathname);\n return matched ? matched.params.id?.[0] : str;\n}\n"],"mappings":";AAAA,OAAO,YAAY;;;ACSnB,SAAS,aAAa;AAEf,SAAS,eAAe,KAAc;AAX7C;AAYE,MAAI,CAAC,OAAO,EAAC,2BAAK,WAAW,UAAS;AACpC,WAAO;AAAA,EACT;AACA,QAAM,MAAM,IAAI,IAAI,GAAG;AACvB,QAAM,UAAU,MAAwB,wBAAwB;AAAA,IAC9D,QAAQ;AAAA,EACV,CAAC,EAAE,IAAI,QAAQ;AACf,SAAO,WAAU,aAAQ,OAAO,OAAf,mBAAoB,KAAK;AAC5C;;;ADjBA,IAAM,SAAS,IAAI,OAAO;AA2CnB,SAAS,aAAa,QAA2B;AACtD,SAAO;AACT;AAEO,IAAM,aAAa;AAE1B,eAAsB,YAAuC;AAC3D,QAAM,MAAM,MAAM,OAAO,KAAK,CAAC,UAAU,CAAC;AAE1C,QAAM,gBAAgB;AAAA,IACpB,SAAS;AAAA,IACT,cAAc;AAAA,IACd,KAAK,QAAQ,IAAI;AAAA,IACjB,UAAU,EAAE,KAAK,KAAK,IAAI,KAAK,IAAI,KAAK,IAAI,IAAI;AAAA,IAChD,iBAAiB;AAAA,EACnB;AAEA,MAAI,IAAI,MAAM;AACZ,UAAM,SAA2B,MAAM,QAAQ,IAAI,IAAI,IACnD,IAAI,OACJ,CAAC,IAAI,IAAI;AACb,WAAO,OAAO,IAAI,CAAC,SAAS;AAC1B,aAAO,OAAO,OAAO,CAAC,GAAG,eAAe,IAAI;AAC5C,WAAK,UAAU,OAAO,KAAK,KAAK,QAAQ,EAAE;AAAA,QACxC,CAACA,UAASA,UAAS;AAAA,MACrB;AAEA,WAAK,UAAU,eAAe,KAAK,OAAO;AAE1C,WAAK,YAAY,CAAC,GAAG,MAAM;AACzB,eAAO,EAAE,cAAc,CAAC;AAAA,MAC1B;AAEA,aAAO;AAAA,IACT,CAAC;AAAA,EACH;AAEA,SAAO,CAAC,aAAa;AACvB;","names":["item"]}
|