@dune2/cli 0.2.13 → 0.3.1

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.
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  normalizeConfig
3
- } from "./chunk-2Z2VUD6F.js";
3
+ } from "./chunk-T2XO6ALS.js";
4
4
 
5
5
  // src/shared/index.ts
6
6
  import cac from "cac";
@@ -248,4 +248,4 @@ export {
248
248
  configName,
249
249
  getConfig
250
250
  };
251
- //# sourceMappingURL=chunk-4B7QMN4G.js.map
251
+ //# sourceMappingURL=chunk-5FXMC2FS.js.map
@@ -36,6 +36,7 @@ function normalizeConfig(config) {
36
36
  return a.localeCompare(b);
37
37
  };
38
38
  item.enabled ??= true;
39
+ item.namespaceSeparator ??= ".";
39
40
  return item;
40
41
  });
41
42
  config.api ??= [];
@@ -63,4 +64,4 @@ export {
63
64
  normalizeConfig,
64
65
  apiConfigNormalizer
65
66
  };
66
- //# sourceMappingURL=chunk-2Z2VUD6F.js.map
67
+ //# sourceMappingURL=chunk-T2XO6ALS.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/shared/resolveSheetId.ts","../src/shared/config/normalizeConfig.ts"],"sourcesContent":["/**\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","import { ApiConfig, Config, I18nConfig } from \"./types\";\nimport { resolveSheetId } from \"../resolveSheetId\";\nimport path from \"path\";\nexport function normalizeConfig(config: Config): Config {\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 config.cwd ??= process.cwd();\n config.cacheDir ??= path.join(config.cwd, \"node_modules/.cache/dune-cli\");\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 item.enabled ??= true;\n\n //#region namespace\n item.namespaceSeparator ??= \".\";\n //#endregion\n return item;\n });\n //#endregion\n\n //#region api 配置标准化\n config.api ??= [];\n config.api = config.api.map(apiConfigNormalizer);\n //#endregion\n return config;\n}\nexport function apiConfigNormalizer(item: ApiConfig) {\n item.output ??= \"./src/apis\";\n // 没有配置 urlTransformer 时,给 requestFnImportPath 赋默认值\n // 优先使用 urlTransformer\n if (!item.urlTransformer) {\n item.requestFnImportPath ??= `import requestFn from '@/utils/request';`;\n }\n item.RequestBuilderImportPath ??= `import { RequestBuilder } from '@dune2/tools';`;\n item.enableTs ??= true;\n item.enabled ??= true;\n item.format ??= true;\n item.responseSchemaTransformer ??= (schema) =>\n schema.properties?.data ?? schema;\n return item;\n}\n"],"mappings":";AASA,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;;;AClBA,OAAO,UAAU;AACV,SAAS,gBAAgB,QAAwB;AAHxD;AAIE,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;AACA,SAAO,QAAQ,QAAQ,IAAI;AAC3B,SAAO,aAAa,KAAK,KAAK,OAAO,KAAK,8BAA8B;AAGxE,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,SAAK,YAAY;AAGjB,SAAK,uBAAuB;AAE5B,WAAO;AAAA,EACT,CAAC;AAID,SAAO,QAAQ,CAAC;AAChB,SAAO,MAAM,OAAO,IAAI,IAAI,mBAAmB;AAE/C,SAAO;AACT;AACO,SAAS,oBAAoB,MAAiB;AACnD,OAAK,WAAW;AAGhB,MAAI,CAAC,KAAK,gBAAgB;AACxB,SAAK,wBAAwB;AAAA,EAC/B;AACA,OAAK,6BAA6B;AAClC,OAAK,aAAa;AAClB,OAAK,YAAY;AACjB,OAAK,WAAW;AAChB,OAAK,8BAA8B,CAAC,WAAQ;AArD9C;AAsDI,yBAAO,eAAP,mBAAmB,SAAQ;AAAA;AAC7B,SAAO;AACT;","names":["item"]}
package/dist/cli.js CHANGED
@@ -6,8 +6,8 @@ import {
6
6
  getConfig,
7
7
  googleSheet,
8
8
  letterToNumber
9
- } from "./chunk-4B7QMN4G.js";
10
- import "./chunk-2Z2VUD6F.js";
9
+ } from "./chunk-5FXMC2FS.js";
10
+ import "./chunk-T2XO6ALS.js";
11
11
 
12
12
  // src/commands/extract.ts
13
13
  import fs2 from "fs-extra";
@@ -68,6 +68,7 @@ var I18nData = class {
68
68
  let newValue = oldData[key] || "";
69
69
  if (this.isDefaultLocale) {
70
70
  newValue = newValue || value.messages || key;
71
+ newValue = this.normalizeNamespacedDefaultLocaleData(newValue);
71
72
  }
72
73
  newData[key] = newValue;
73
74
  });
@@ -81,6 +82,17 @@ var I18nData = class {
81
82
  }
82
83
  });
83
84
  }
85
+ normalizeNamespacedDefaultLocaleData(v) {
86
+ if (!this.namespaceReg && this.config.namespace) {
87
+ const names = Object.keys(this.config.namespace).join("|");
88
+ const separator = this.config.namespaceSeparator;
89
+ this.namespaceReg = new RegExp(`^(${names})\\${separator}`);
90
+ }
91
+ if (this.namespaceReg) {
92
+ return v.replace(this.namespaceReg, "");
93
+ }
94
+ return v;
95
+ }
84
96
  async updateFromSheetData(sheetData) {
85
97
  await this.loadData();
86
98
  this.data = { ...this.data, ...sheetData };
@@ -474,7 +486,6 @@ async function download() {
474
486
  }
475
487
 
476
488
  // src/commands/generateApi/index.ts
477
- import * as child_process from "child_process";
478
489
  import _ from "lodash";
479
490
  import pMap4 from "p-map";
480
491
  import fs3 from "fs-extra";
@@ -482,21 +493,39 @@ import * as os2 from "os";
482
493
  import SwaggerParser from "@apidevtools/swagger-parser";
483
494
  import { compile } from "json-schema-to-typescript";
484
495
  import path3 from "path";
496
+
497
+ // src/shared/formatFile.ts
498
+ import * as child_process from "child_process";
485
499
  var log5 = createLogger("generateApi");
500
+ function formatFile(filename) {
501
+ log5.info(`\u5C1D\u8BD5\u683C\u5F0F\u5316\u4EE3\u7801: %s`, filename);
502
+ child_process.exec(`prettier --write '${filename}'`, (error) => {
503
+ if (error) {
504
+ log5.error(`\u683C\u5F0F\u5316\u4EE3\u7801\u5931\u8D25: ${error}`);
505
+ log5.error(`\u8BF7\u624B\u52A8\u6267\u884C: prettier --write ${filename}`);
506
+ log5.error(`\u6216\u8005\u5728\u914D\u7F6E\u6587\u4EF6\u4E2D\u5173\u95ED\u683C\u5F0F\u5316\u529F\u80FD`);
507
+ } else {
508
+ log5.info(`\u683C\u5F0F\u5316\u4EE3\u7801\u6210\u529F: %s`, filename);
509
+ }
510
+ });
511
+ }
512
+
513
+ // src/commands/generateApi/index.ts
514
+ var log6 = createLogger("generateApi");
486
515
  async function generateApi() {
487
516
  const config = await getConfig();
488
517
  const apiConfigs = await promptApiConfigEnable(config.api);
489
518
  for (const apiConfig of apiConfigs) {
490
- log5.info(`\u6E05\u9664\u65E7\u7684api\u6587\u4EF6: ${apiConfig.output}`);
519
+ log6.info(`\u6E05\u9664\u65E7\u7684api\u6587\u4EF6: ${apiConfig.output}`);
491
520
  await fs3.emptydir(apiConfig.output);
492
521
  }
493
522
  for (const apiConfig of apiConfigs) {
494
- log5.info("\u5F00\u59CB\u89E3\u6790 %s", apiConfig.swaggerJSONPath);
523
+ log6.info("\u5F00\u59CB\u89E3\u6790 %s", apiConfig.swaggerJSONPath);
495
524
  const parsed = await SwaggerParser.dereference(
496
525
  apiConfig.swaggerJSONPath
497
526
  );
498
527
  await pMap4(Object.entries(parsed.paths), async ([url, pathItemObject]) => {
499
- log5.info("\u5F00\u59CB\u751F\u6210 %s", url);
528
+ log6.info("\u5F00\u59CB\u751F\u6210 %s", url);
500
529
  if (pathItemObject) {
501
530
  await pMap4(
502
531
  ["get", "put", "post", "delete", "patch"],
@@ -522,19 +551,10 @@ async function generateApi() {
522
551
  }
523
552
  });
524
553
  if (apiConfig.format) {
525
- log5.info(`\u5C1D\u8BD5\u683C\u5F0F\u5316\u4EE3\u7801: %s`, apiConfig.output);
526
- child_process.exec(`prettier --write ${apiConfig.output}`, (error) => {
527
- if (error) {
528
- log5.error(`\u683C\u5F0F\u5316\u4EE3\u7801\u5931\u8D25: ${error}`);
529
- log5.error(`\u8BF7\u624B\u52A8\u6267\u884C: prettier --write ${apiConfig.output}`);
530
- log5.error(`\u6216\u8005\u5728\u914D\u7F6E\u6587\u4EF6\u4E2D\u5173\u95ED\u683C\u5F0F\u5316\u529F\u80FD`);
531
- } else {
532
- log5.info(`\u683C\u5F0F\u5316\u4EE3\u7801\u6210\u529F: %s`, apiConfig.output);
533
- }
534
- });
554
+ await formatFile(apiConfig.output);
535
555
  }
536
556
  }
537
- log5.info("generateApi Done");
557
+ log6.info("generateApi Done");
538
558
  }
539
559
  async function generateApiRequestCode(options) {
540
560
  var _a, _b;
@@ -648,7 +668,7 @@ async function compileRequestParams(operationObject) {
648
668
  additionalProperties: false
649
669
  });
650
670
  } catch (e) {
651
- log5.error("\u751F\u6210\u8BF7\u6C42\u53C2\u6570\u7C7B\u578B\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5 %o", {
671
+ log6.error("\u751F\u6210\u8BF7\u6C42\u53C2\u6570\u7C7B\u578B\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5 %o", {
652
672
  summary: operationObject.summary,
653
673
  message: e.message
654
674
  });
@@ -673,13 +693,13 @@ async function compileResponseParams(operationObject, apiConfig) {
673
693
  additionalProperties: false
674
694
  });
675
695
  } catch (e) {
676
- log5.error("\u8F6C\u6362\u54CD\u5E94\u53C2\u6570\u7C7B\u578B\u5931\u8D25, \u8BF7\u68C0\u67E5 %o", {
696
+ log6.error("\u8F6C\u6362\u54CD\u5E94\u53C2\u6570\u7C7B\u578B\u5931\u8D25, \u8BF7\u68C0\u67E5 %o", {
677
697
  summary: operationObject.summary,
678
698
  error: e.message
679
699
  });
680
700
  }
681
701
  } else {
682
- log5.error("responseSchemaTransformer \u8FD4\u56DE\u503C\u4E3A\u7A7A, \u8BF7\u68C0\u67E5");
702
+ log6.error("responseSchemaTransformer \u8FD4\u56DE\u503C\u4E3A\u7A7A, \u8BF7\u68C0\u67E5");
683
703
  }
684
704
  }
685
705
  return code ? code : "export type Res = any;";
@@ -704,7 +724,7 @@ function markCircularToRef(obj, parentMark = "#", map = /* @__PURE__ */ new Map(
704
724
  // src/commands/initConfig.ts
705
725
  import fs4 from "fs-extra";
706
726
  import path4 from "path";
707
- var log6 = createLogger("initConfig");
727
+ var log7 = createLogger("initConfig");
708
728
  var tpl = `/**
709
729
  * @param {import('@dune2/cli').Config} config
710
730
  */
@@ -716,18 +736,18 @@ module.exports = defineConfig({ i18n: [], api:[] });
716
736
  var initConfig = async () => {
717
737
  const config = await getConfig();
718
738
  const configPath = path4.join(config.cwd, configName);
719
- log6.info(`config file path: ${configPath}`);
739
+ log7.info(`config file path: ${configPath}`);
720
740
  if (await fs4.pathExists(configPath)) {
721
- log6.info(`config file already exists, skip`);
741
+ log7.info(`config file already exists, skip`);
722
742
  return;
723
743
  }
724
744
  await fs4.writeFile(configPath, tpl);
725
- log6.info(`config file created`);
745
+ log7.info(`config file created`);
726
746
  };
727
747
 
728
748
  // src/commands/upload.ts
729
749
  import pMap5 from "p-map";
730
- var log7 = createLogger("upload");
750
+ var log8 = createLogger("upload");
731
751
  async function batchUpdateKeys(config) {
732
752
  let sheetData = await resolveSheetData(config);
733
753
  const allKeys = [];
@@ -743,7 +763,7 @@ async function batchUpdateKeys(config) {
743
763
  });
744
764
  needSyncKeys = needSyncKeys.sort(config.keySorter);
745
765
  if (needSyncKeys.length) {
746
- log7.info(`\u5373\u5C06\u540C\u6B65\u672C\u5730\u65B0\u589E\u52A0 ${needSyncKeys.length} \u4E2A i18nKey \u5230\u4E91\u7AEF`);
766
+ log8.info(`\u5373\u5C06\u540C\u6B65\u672C\u5730\u65B0\u589E\u52A0 ${needSyncKeys.length} \u4E2A i18nKey \u5230\u4E91\u7AEF`);
747
767
  await googleSheet.updateColumn(
748
768
  config.sheetId,
749
769
  config.sheetRange,
@@ -751,7 +771,7 @@ async function batchUpdateKeys(config) {
751
771
  sheetData.nextAppendRowIndex,
752
772
  needSyncKeys
753
773
  );
754
- log7.info("\u540C\u6B65\u65B0\u589E\u52A0i18nKey\u6210\u529F");
774
+ log8.info("\u540C\u6B65\u65B0\u589E\u52A0i18nKey\u6210\u529F");
755
775
  for (const lang of config.locales) {
756
776
  const langFile = i18nDataMap.get(lang);
757
777
  const needSyncValues = [];
@@ -760,7 +780,7 @@ async function batchUpdateKeys(config) {
760
780
  needSyncValues.push(langFile.data[k]);
761
781
  }
762
782
  });
763
- log7.info(
783
+ log8.info(
764
784
  `\u5373\u5C06\u540C\u6B65\u672C\u5730 ${lang} \u65B0\u589E\u52A0 ${needSyncValues.length} \u4E2A\u503C\u5230\u4E91\u7AEF`
765
785
  );
766
786
  await googleSheet.updateColumn(
@@ -773,7 +793,7 @@ async function batchUpdateKeys(config) {
773
793
  }
774
794
  await sleep(1e3);
775
795
  sheetData = await resolveSheetData(config);
776
- log7.info(`\u5DF2\u91CD\u65B0\u83B7\u53D6 ${config.sheetRange} \u7684\u6570\u636E`);
796
+ log8.info(`\u5DF2\u91CD\u65B0\u83B7\u53D6 ${config.sheetRange} \u7684\u6570\u636E`);
777
797
  }
778
798
  return { sheetData, i18nDataMap };
779
799
  }
@@ -787,16 +807,16 @@ async function upload() {
787
807
  await i18nData.trySaveToGoogle(sheetData);
788
808
  });
789
809
  }
790
- log7.info("\u4E0A\u4F20\u6210\u529F");
810
+ log8.info("\u4E0A\u4F20\u6210\u529F");
791
811
  }
792
812
 
793
813
  // package.json
794
- var version = "0.2.10";
814
+ var version = "0.3.0";
795
815
 
796
816
  // src/commands/interactive.ts
797
817
  import enquirer2 from "enquirer";
798
818
  var { prompt: prompt2 } = enquirer2;
799
- var log8 = createLogger("interactive");
819
+ var log9 = createLogger("interactive");
800
820
  var interactive = async (args) => {
801
821
  var _a;
802
822
  const commands = cli.commands.filter((command2) => {
@@ -822,15 +842,104 @@ var interactive = async (args) => {
822
842
  });
823
843
  const command = commandMap.get(res.command);
824
844
  if (!command) {
825
- log8.error("\u672A\u627E\u5230\u547D\u4EE4 %s", res.command);
845
+ log9.error("\u672A\u627E\u5230\u547D\u4EE4 %s", res.command);
826
846
  return;
827
847
  }
828
848
  (_a = command.commandAction) == null ? void 0 : _a.apply(cli, args);
829
849
  };
830
850
 
851
+ // src/commands/namespace.ts
852
+ import enquirer3 from "enquirer";
853
+ import _2 from "lodash";
854
+ import { globby as globby2 } from "globby";
855
+ import fs5 from "fs-extra";
856
+ import pMap6 from "p-map";
857
+ import pc3 from "picocolors";
858
+ var { prompt: prompt3 } = enquirer3;
859
+ var log10 = createLogger("namespace");
860
+ async function namespace() {
861
+ var _a, _b;
862
+ const config = await getConfig();
863
+ let i18nConfigs = (_a = config.i18n) == null ? void 0 : _a.filter((item) => !item.disableExtract);
864
+ if (!i18nConfigs) {
865
+ log10.info("\u6CA1\u6709\u914D\u7F6E i18n");
866
+ return;
867
+ }
868
+ const { i18nDir } = await prompt3({
869
+ type: "select",
870
+ name: "i18nDir",
871
+ message: "\u9009\u62E9\u8981\u751F\u6548\u7684\u914D\u7F6E\u9879",
872
+ choices: i18nConfigs.map((item) => {
873
+ return {
874
+ name: item.i18nDir,
875
+ hint: `sheetRange: ${item.sheetRange}`
876
+ };
877
+ })
878
+ });
879
+ let i18nConfig = i18nConfigs.find((item) => item.i18nDir === i18nDir);
880
+ if (!i18nConfig) {
881
+ log10.info("\u6CA1\u6709\u627E\u5230\u5BF9\u5E94\u7684\u914D\u7F6E");
882
+ return;
883
+ }
884
+ const { namespaces } = await prompt3({
885
+ type: "multiselect",
886
+ message: "\u9009\u62E9\u8981\u751F\u6548\u7684\u914D\u7F6E\u9879",
887
+ hint: "(\u7A7A\u683C\u9009\u4E2D\uFF0C\u56DE\u8F66\u786E\u8BA4)",
888
+ name: "namespaces",
889
+ validate(value) {
890
+ return value.length === 0 ? `\u81F3\u5C11\u9009\u62E9\u4E00\u9879` : true;
891
+ },
892
+ choices: _2.map(i18nConfig.namespace, (v, k) => {
893
+ return {
894
+ name: k
895
+ };
896
+ })
897
+ });
898
+ for (const namespace2 of namespaces) {
899
+ const namespaceConfig = (_b = i18nConfig.namespace) == null ? void 0 : _b[namespace2];
900
+ const suffix = `**/**.{js,jsx,ts,tsx}`;
901
+ const combined = _2.map(_2.castArray(namespaceConfig), (v) => {
902
+ v = v.endsWith("/") ? v : v + "/";
903
+ return v + suffix;
904
+ });
905
+ log10.info("\u6B63\u5728\u5904\u7406 namespace: %s", pc3.green(namespace2));
906
+ log10.info("\u9884\u8BA1\u5904\u7406\u7684\u6587\u4EF6\u8DEF\u5F84: %s", pc3.green(combined.join("\n")));
907
+ const files = await globby2(
908
+ [
909
+ "!**/node_modules/**",
910
+ "!**.d.ts",
911
+ "!**/.next/**",
912
+ "!**/out/**"
913
+ ].concat(combined),
914
+ { cwd: i18nConfig.cwd }
915
+ );
916
+ log10.info("\u9884\u8BA1\u5171\u5904\u7406 %s \u4E2A\u6587\u4EF6", pc3.green(files.length));
917
+ const { autoNamespace } = await import("@dune2/wasm");
918
+ let transformedFileSet = /* @__PURE__ */ new Set();
919
+ await pMap6(files, async (file) => {
920
+ const content = await fs5.readFile(file, "utf-8");
921
+ const newContent = await autoNamespace(
922
+ content,
923
+ namespace2,
924
+ i18nConfig.namespaceSeparator
925
+ );
926
+ if (newContent) {
927
+ await fs5.writeFile(file, newContent);
928
+ await formatFile(file);
929
+ transformedFileSet.add(file);
930
+ }
931
+ });
932
+ log10.info(
933
+ "\u5DF2\u4E3A %s \u4E2A\u6587\u4EF6 \u81EA\u52A8\u6DFB\u52A0 namespace",
934
+ pc3.green(transformedFileSet.size)
935
+ );
936
+ }
937
+ }
938
+
831
939
  // src/cli.ts
832
940
  cli.command("download", "\u751F\u6210\u7FFB\u8BD1\u6587\u4EF6").example("dune download").action(download);
833
941
  cli.command("extract", "\u63D0\u53D6\u4EE3\u7801\u4E2D\u7684\u6587\u6848").option("--deleteUnused", "\u5220\u9664\u672A\u4F7F\u7528\u7684\u6587\u6848").example("dune extract").action(extract);
942
+ cli.command("namespace", "\u6DFB\u52A0namespace\u524D\u7F00").example("dune namespace").action(namespace);
834
943
  cli.command("upload", "\u4E0A\u4F20\u7FFB\u8BD1\u6587\u4EF6").example("dune upload").action(upload);
835
944
  cli.command("generateApi", "\u751F\u6210api\u6587\u4EF6").example("dune generateApi").action(generateApi);
836
945
  cli.command("init", "\u521D\u59CB\u5316\u914D\u7F6E\u6587\u4EF6").example("dune init").action(initConfig);
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/commands/extract.ts","../src/shared/i18nData.ts","../src/shared/sleep.ts","../src/shared/promptConfigEnable.ts","../src/commands/download.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, I18nConfig } from \"../shared/config\";\nimport { ExtractedMap, I18nData } from \"../shared/i18nData\";\nimport pc from \"picocolors\";\nimport os from \"os\";\nimport { promptI18nConfigEnable } from \"../shared/promptConfigEnable\";\nimport path from \"path\";\n\nconst log = createLogger(\"extract\");\n\n/**\n * 提取文案\n */\nexport async function extract(opts?: { deleteUnused: boolean }) {\n const config = await getConfig();\n const { extract } = await import(\"@dune2/wasm\");\n\n let i18nConfigs = await promptI18nConfigEnable(\n config.i18n?.filter((item) => !item.disableExtract)\n );\n\n // 这是使得任务串行,方便看日志\n for (const configItem of i18nConfigs) {\n const files = await globby(\n [\n `./src/**/**.{js,jsx,ts,tsx}`,\n \"!**/node_modules/**\",\n \"!**.d.ts\",\n \"!**/.next/**\",\n \"!**/out/**\",\n ].concat(configItem.include ?? []),\n { cwd: configItem.cwd }\n );\n log.info(\"预计共解析 %s 个文件\", pc.green(files.length));\n let errMsgs: string[] = [];\n const extractedI18nDataMap: ExtractedMap = new Map();\n\n await pMap(\n files,\n async (file) => {\n const content = await fs.readFile(file, \"utf-8\");\n const res = await extract(content, file);\n if (res.data.size) {\n log.info(\n \"从 %s 中提取到 %s 条文案\",\n pc.dim(file),\n pc.green(res.data.size)\n );\n res.data.forEach((value, key) => {\n let cur = extractedI18nDataMap.get(key)!;\n const hasCache = !!cur;\n if (!hasCache) {\n cur = { ...value, files: [] };\n }\n cur.files.push(\n path.resolve(file) + \":\" + value.line + \":\" + value.column\n );\n // 优先使用 提取出来的文案\n cur.messages = value.messages || cur.messages;\n\n if (!hasCache) {\n extractedI18nDataMap.set(key, cur);\n }\n });\n }\n if (res.errMsg) {\n errMsgs.push(res.errMsg);\n }\n },\n { concurrency: 20 }\n );\n\n await saveExtractedMetaData(configItem, extractedI18nDataMap);\n\n const i18nDataArr = await pMap(configItem.locales ?? [], async (locale) => {\n const i18nData = new I18nData(locale, configItem, opts?.deleteUnused);\n await i18nData.updateByExtractedData(extractedI18nDataMap);\n await i18nData.saveToDisk();\n return i18nData;\n });\n if (errMsgs.length) {\n console.log(pc.bold(\"以下未能成功提取的文案,请手动处理:\"));\n console.log(errMsgs.join(os.EOL));\n }\n I18nData.printStatistic(\"提取结果: \", i18nDataArr);\n }\n}\n\n/**\n * 保存相关的提取信息\n */\nasync function saveExtractedMetaData(\n config: I18nConfig,\n extractedI18nDataMap: ExtractedMap\n) {\n const { i18nDir } = config;\n // case:\n // input: \"./src/i18n\"\n // output: \"src_i18n.extractedLog.json\"\n const prefix = i18nDir!.replace(\"./\", \"\").replace(/\\//g, \"_\");\n const filename = `${prefix}.extractedLog.json`;\n\n const metaDataJsonPath = path.join(i18nDir!, filename);\n\n await fs.ensureFile(metaDataJsonPath);\n\n // extractedI18nDataMap 是个 Map 需要转成换json\n let data = Array.from(extractedI18nDataMap.entries()).map(\n ([key, value]) => value\n );\n // 按照 id 排序\n data = data.sort((a, b) => {\n return a.id.localeCompare(b.id);\n });\n\n await fs.writeJSON(\n metaDataJsonPath,\n\n data,\n {\n spaces: 2,\n }\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\";\nimport { sleep } from \"./sleep\";\n\nconst log = createLogger(\"i18nData\");\nexport type ExtractedMap = Map<\n string,\n { id: string; messages: string; files: string[] }\n>;\n\nexport class I18nData {\n data: Record<string, string> = {};\n\n filePath: string;\n\n /**\n * 是否是默认语言,默认语言需要使用提出来的文案作为value\n */\n isDefaultLocale: boolean;\n // 没有被使用到的翻译key\n unUsedKeys: Set<string> = new Set();\n constructor(\n public locale: string,\n public config: I18nConfig,\n // 是否需要删除未使用的文案\n public shouldDeleteUnused = false\n ) {\n this.isDefaultLocale = locale === config.defaultLocale;\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 /**\n * @param {ExtractedMap} extractedData 提取出来的内容\n */\n async updateByExtractedData(extractedData: ExtractedMap) {\n const oldData = await this.loadData();\n let newData = {};\n extractedData.forEach((value, key) => {\n let newValue = oldData[key] || \"\";\n if (this.isDefaultLocale) {\n // 默认语言需要回退到key作为value\n newValue = newValue || value.messages || key;\n }\n newData[key] = newValue;\n });\n if (!this.shouldDeleteUnused) {\n // 不删除未使用的文案,则需要合并旧数据\n newData = { ...oldData, ...newData };\n }\n this.data = newData;\n\n // 记录下来未被使用的key,后面需要打印出来提示用户\n Object.keys(oldData).forEach((key) => {\n if (!extractedData.has(key)) {\n this.unUsedKeys.add(key);\n }\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 trySaveToGoogle(sheetData: SheetData) {\n await pMap(\n Object.entries(this.data),\n async ([key, value]) => {\n if (sheetData.hasI18nItem(this.locale, key)) {\n // 更新已有的\n await sheetData.getI18nItem(this.locale, key)?.tryUpdate(value);\n // 避免频繁请求,Google sheet api 默认限制\n // • 每秒钟读操作数:100 请求/秒\n // • 每秒钟单元格写操作数:100 请求/秒\n await sleep(500);\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 { concurrency: 50 }\n );\n }\n private 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 static printStatistic(label: string, i18nDataArr: I18nData[]) {\n // 首先打印 unUsedKeys\n const unUsedKeys = i18nDataArr.reduce((keys, item) => {\n return new Set(item.unUsedKeys);\n }, new Set<string>());\n if (unUsedKeys.size) {\n console.log(\n pc.bold(\n `共有 ${pc.green(\n unUsedKeys.size\n )} 个 key 未在代码中使用,以下是具体的 key`\n )\n );\n console.log(\n pc.red(\n \"注意:这些key可能是已经删除的代码,也可能是通过 `t.ignoreExtract` 调用忽略了提取 并不一定是冗余的 key\"\n )\n );\n console.table(unUsedKeys);\n }\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\n i18nDataArr.forEach((i18nData) => {\n const statistic = i18nData.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","export function sleep(ms: number) {\n return new Promise((resolve) => {\n setTimeout(resolve, ms);\n });\n}\n","import enquirer from \"enquirer\";\nimport { ApiConfig, I18nConfig } from \"./config\";\nconst { prompt } = enquirer;\n\ninterface Opt<T> {\n configArr: (T & { enabled?: boolean })[];\n getChoiceItem: (item: T) => {\n name: string;\n message?: string;\n value?: string;\n hint?: string;\n };\n checkIsEnabled: (enabledArr: string[], item: T) => boolean;\n}\n\nasync function promptConfigEnable<T>(opt: Opt<T>) {\n const { configArr, getChoiceItem } = opt;\n // 只有一条配置的时候不用选择\n if (configArr.length <= 1) {\n return configArr;\n }\n\n const choices = [\n {\n name: \"全部\",\n message: \"全部\",\n choices: configArr.map((item) => {\n return getChoiceItem(item);\n }),\n },\n ];\n const res = await prompt<{ enabled: string[] }>({\n type: \"multiselect\",\n message: \"选择要生效的配置项\",\n hint: \"(空格选中,回车确认)\",\n name: \"enabled\",\n validate(value) {\n return value.length === 0 ? `至少选择一项` : true;\n },\n choices,\n });\n\n configArr.forEach((item) => {\n item.enabled = opt.checkIsEnabled(res.enabled, item);\n });\n\n return configArr.filter((c) => c.enabled);\n}\n\nexport function promptI18nConfigEnable(configArr: I18nConfig[] | undefined) {\n return promptConfigEnable({\n configArr: configArr ?? [],\n getChoiceItem: (item) => {\n return {\n name: item.i18nDir!,\n hint: `sheetRange: ${item.sheetRange}`,\n };\n },\n checkIsEnabled: (enabledArr, item) => {\n return enabledArr.includes(item.i18nDir!);\n },\n });\n}\n\nexport function promptApiConfigEnable(configArr: ApiConfig[] | undefined) {\n return promptConfigEnable({\n configArr: configArr ?? [],\n getChoiceItem: (item) => {\n return {\n name: item.output!,\n hint: `swaggerJSONPath: ${item.swaggerJSONPath}`,\n };\n },\n checkIsEnabled: (enabledArr, item) => {\n return enabledArr.includes(item.output!);\n },\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\";\nimport { promptI18nConfigEnable } from \"../shared/promptConfigEnable\";\n\nconst log = createLogger(\"generate\");\n\nexport async function download() {\n const config = await getConfig();\n\n let i18nConfigs = await promptI18nConfigEnable(config.i18n);\n\n let i = 0;\n for (const configItem of i18nConfigs) {\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 i18nData;\n }\n );\n I18nData.printStatistic(`${configItem.sheetRange} 生成结果: `, statistics);\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)];\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 * as child_process from \"child_process\";\nimport _ 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\";\nimport { promptApiConfigEnable } from \"../../shared/promptConfigEnable\";\n\nconst log = createLogger(\"generateApi\");\n\nexport async function generateApi() {\n const config = await getConfig();\n const apiConfigs = await promptApiConfigEnable(config.api);\n\n for (const apiConfig of apiConfigs) {\n log.info(`清除旧的api文件: ${apiConfig.output}`);\n await fs.emptydir(apiConfig.output!);\n }\n\n for (const apiConfig of apiConfigs) {\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\n .join(\n apiConfig.output!,\n url,\n apiConfig.enableTs ? `${method}.ts` : `${method}.js`\n )\n .replace(/:/g, \"_\");\n await fs.ensureFile(outputPath);\n await fs.writeFile(outputPath, code);\n }\n }\n );\n }\n });\n\n if (apiConfig.format) {\n // 格式化代码\n log.info(`尝试格式化代码: %s`, apiConfig.output);\n child_process.exec(`prettier --write ${apiConfig.output}`, (error) => {\n if (error) {\n log.error(`格式化代码失败: ${error}`);\n log.error(`请手动执行: prettier --write ${apiConfig.output}`);\n log.error(`或者在配置文件中关闭格式化功能`);\n } else {\n log.info(`格式化代码成功: %s`, apiConfig.output);\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 { method, operationObject, apiConfig } = options;\n\n const url = (() => {\n if (typeof apiConfig.urlTransformer === \"string\") {\n return `${apiConfig.urlTransformer}${options.url}`;\n }\n if (typeof apiConfig.urlTransformer === \"function\") {\n return apiConfig.urlTransformer(options.url);\n }\n return options.url;\n })();\n\n const seeUrl = apiConfig.swaggerUiUrl\n ? `${apiConfig.swaggerUiUrl}#/${operationObject.tags?.join(\"/\") ?? \"\"}/${\n operationObject.operationId\n }`\n : \"\";\n\n let requestBuilderName = _.camelCase(`${url}_${method}_api`);\n\n // 判断是否有效的js变量\n if (!/^[a-zA-Z_$][0-9a-zA-Z_$]*$/.test(requestBuilderName)) {\n // 不是有效的js变量,使用 _ + 数字\n requestBuilderName = `_${requestBuilderName}`;\n }\n\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 apiConfig.RequestBuilderImportPath!,\n apiConfig.requestFnImportPath!,\n apiConfig.queryClientImportPath!,\n\n \"/**\",\n ` * ${operationObject.summary}`,\n ` * @tags ${operationObject.tags?.join(\",\")}`,\n seeUrl && ` * @see ${seeUrl}`,\n ` */`,\n ].filter(Boolean);\n\n // builder 代码\n let builderCode = `\\\nexport const ${requestBuilderName} = new RequestBuilder({\n url: '${url}',\n method: '${method}',\n ${apiConfig.requestFnImportPath ? \"requestFn,\" : \"\"}\n ${urlPathParamsCode}\n ${apiConfig.queryClientImportPath ? \"queryClient,\" : \"\"}\n});`\n // 移除空行\n .replace(/,\\n\\s*}/, \",\" + os.EOL + \"}\");\n if (apiConfig.enableTs) {\n builderCode = builderCode.replace(\n \"new RequestBuilder(\",\n `new RequestBuilder<${requestBuilderName}.Req, ${requestBuilderName}.Res>(`\n );\n }\n code.push(builderCode);\n\n if (apiConfig.enableTs) {\n // 请求参数类型\n // 响应参数类型\n const [requestParamsTypeCode, responseParamsTypeCode] = await Promise.all([\n compileRequestParams(operationObject),\n compileResponseParams(operationObject, apiConfig),\n ]);\n\n code.push(`\nexport namespace ${requestBuilderName} {\n ${requestParamsTypeCode}\n \n ${responseParamsTypeCode}\n};`);\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.requestBody) {\n //TODO: 这里也需要处理其他类型\n schema = (operationObject.requestBody as OpenAPIV3.RequestBodyObject)\n .content[\"application/json\"].schema;\n } else if (operationObject.parameters) {\n const extraProperties = {};\n const parameters: OpenAPIV3.ParameterObject[] = [];\n (operationObject.parameters as OpenAPIV3.ParameterObject[]).forEach(\n (item) => {\n if (![\"query\", \"path\"].includes(item.in)) {\n return;\n }\n if (_.get(item.schema, \"type\") === \"object\") {\n // swagger get 请求上 有些参数是 object 类型 应该拍平\n _.assign(extraProperties, _.get(item.schema, \"properties\", {}));\n } else {\n parameters.push(item);\n }\n }\n );\n\n // 必填参数中忽略 分页相关的参数\n const required = parameters\n .filter(\n (p) => p.required && ![\"pageNum\", \"pageSize\", \"count\"].includes(p.name)\n )\n .map((p) => p.name);\n const properties = Object.fromEntries(\n parameters\n // 后端 swagger 可能出现没有 schema 的情况,这里过滤掉\n .filter((p) => !!p.schema)\n .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: { ...properties, ...extraProperties },\n };\n }\n\n let code = \"\";\n if (schema) {\n try {\n code = await compile(schema, \"Req\", {\n bannerComment: \"\",\n ignoreMinAndMaxItems: !!1,\n additionalProperties: false,\n // format: false,\n });\n } catch (e) {\n log.error(\"生成请求参数类型失败,请检查 %o\", {\n summary: operationObject.summary,\n message: e.message,\n });\n }\n }\n\n return code ? code : \"export type Req = any;\";\n}\n\nasync function compileResponseParams(\n operationObject: OpenAPIV3.OperationObject,\n apiConfig: ApiConfig\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 let data = apiConfig.responseSchemaTransformer!(schema);\n if (data) {\n // 这里需要深度clone的原因是:\n // 解析出来的scheme会尽可能的被复用,导致影响到下次解析\n data = _.cloneDeep(data);\n markCircularToRef(data);\n try {\n code = await compile(data, \"Res\", {\n bannerComment: \"\",\n ignoreMinAndMaxItems: !!1,\n additionalProperties: false,\n // format: false,\n });\n } catch (e) {\n log.error(\"转换响应参数类型失败, 请检查 %o\", {\n summary: operationObject.summary,\n error: e.message,\n });\n }\n } else {\n log.error(\"responseSchemaTransformer 返回值为空, 请检查\");\n }\n }\n\n return code ? code : \"export type Res = any;\";\n}\n\nexport function markCircularToRef(\n obj,\n parentMark = \"#\",\n map = new Map([[obj, parentMark]]),\n set = new Set([obj])\n) {\n Object.keys(obj).forEach((key) => {\n const value = obj[key];\n if (typeof value === \"object\" && !Array.isArray(value)) {\n if (set.has(value)) {\n obj[key] = { $ref: map.get(value) };\n return;\n }\n const tempMark = parentMark + \"/\" + key;\n set.add(value);\n map.set(value, tempMark);\n markCircularToRef(value, tempMark, map, set);\n }\n });\n return map;\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 * @param {import('@dune2/cli').Config} 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\";\nimport { promptI18nConfigEnable } from \"../shared/promptConfigEnable\";\nimport { sleep } from \"../shared/sleep\";\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}\n\nexport async function upload() {\n const config = await getConfig();\n let i18nConfigs = await promptI18nConfigEnable(config.i18n);\n\n for (const configItem of i18nConfigs) {\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 enquirer from \"enquirer\";\nconst { prompt } = enquirer;\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 prompt<{ command: string }>({\n type: \"autocomplete\",\n name: \"command\",\n message: \"选择要执行的命令:\",\n choices: commands.map((command) => {\n commandMap.set(command.name, command);\n return {\n name: command.name,\n value: command.name,\n message: command.description,\n hint: `等同命令 ${cli.name} ${command.name}`,\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 .option(\"--deleteUnused\", \"删除未使用的文案\")\n .example(\"dune extract\")\n .action(extract);\n\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","pc","path","log","extract","pc","pMap","fs","pMap","log","log","pMap","pMap","fs","os","path","log","fs","pMap","path","schema","fs","path","log","pMap","log","pMap","enquirer","prompt","log","command"]}
1
+ {"version":3,"sources":["../src/commands/extract.ts","../src/shared/i18nData.ts","../src/shared/sleep.ts","../src/shared/promptConfigEnable.ts","../src/commands/download.ts","../src/shared/resolveSheetData.ts","../src/commands/generateApi/index.ts","../src/shared/formatFile.ts","../src/commands/initConfig.ts","../src/commands/upload.ts","../src/commands/interactive.ts","../src/commands/namespace.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, I18nConfig } from \"../shared/config\";\nimport { ExtractedMap, I18nData } from \"../shared/i18nData\";\nimport pc from \"picocolors\";\nimport os from \"os\";\nimport { promptI18nConfigEnable } from \"../shared/promptConfigEnable\";\nimport path from \"path\";\n\nconst log = createLogger(\"extract\");\n\n/**\n * 提取文案\n */\nexport async function extract(opts?: { deleteUnused: boolean }) {\n const config = await getConfig();\n const { extract } = await import(\"@dune2/wasm\");\n\n let i18nConfigs = await promptI18nConfigEnable(\n config.i18n?.filter((item) => !item.disableExtract)\n );\n\n // 这是使得任务串行,方便看日志\n for (const configItem of i18nConfigs) {\n const files = await globby(\n [\n `./src/**/**.{js,jsx,ts,tsx}`,\n \"!**/node_modules/**\",\n \"!**.d.ts\",\n \"!**/.next/**\",\n \"!**/out/**\",\n ].concat(configItem.include ?? []),\n { cwd: configItem.cwd }\n );\n log.info(\"预计共解析 %s 个文件\", pc.green(files.length));\n let errMsgs: string[] = [];\n const extractedI18nDataMap: ExtractedMap = new Map();\n\n await pMap(\n files,\n async (file) => {\n const content = await fs.readFile(file, \"utf-8\");\n const res = await extract(content, file);\n if (res.data.size) {\n log.info(\n \"从 %s 中提取到 %s 条文案\",\n pc.dim(file),\n pc.green(res.data.size)\n );\n res.data.forEach((value, key) => {\n let cur = extractedI18nDataMap.get(key)!;\n const hasCache = !!cur;\n if (!hasCache) {\n cur = { ...value, files: [] };\n }\n cur.files.push(\n path.resolve(file) + \":\" + value.line + \":\" + value.column\n );\n // 优先使用 提取出来的文案\n cur.messages = value.messages || cur.messages;\n\n if (!hasCache) {\n extractedI18nDataMap.set(key, cur);\n }\n });\n }\n if (res.errMsg) {\n errMsgs.push(res.errMsg);\n }\n },\n { concurrency: 20 }\n );\n\n await saveExtractedMetaData(configItem, extractedI18nDataMap);\n\n const i18nDataArr = await pMap(configItem.locales ?? [], async (locale) => {\n const i18nData = new I18nData(locale, configItem, opts?.deleteUnused);\n await i18nData.updateByExtractedData(extractedI18nDataMap);\n await i18nData.saveToDisk();\n return i18nData;\n });\n if (errMsgs.length) {\n console.log(pc.bold(\"以下未能成功提取的文案,请手动处理:\"));\n console.log(errMsgs.join(os.EOL));\n }\n I18nData.printStatistic(\"提取结果: \", i18nDataArr);\n }\n}\n\n/**\n * 保存相关的提取信息\n */\nasync function saveExtractedMetaData(\n config: I18nConfig,\n extractedI18nDataMap: ExtractedMap\n) {\n const { i18nDir } = config;\n // case:\n // input: \"./src/i18n\"\n // output: \"src_i18n.extractedLog.json\"\n const prefix = i18nDir!.replace(\"./\", \"\").replace(/\\//g, \"_\");\n const filename = `${prefix}.extractedLog.json`;\n\n const metaDataJsonPath = path.join(i18nDir!, filename);\n\n await fs.ensureFile(metaDataJsonPath);\n\n // extractedI18nDataMap 是个 Map 需要转成换json\n let data = Array.from(extractedI18nDataMap.entries()).map(\n ([key, value]) => value\n );\n // 按照 id 排序\n data = data.sort((a, b) => {\n return a.id.localeCompare(b.id);\n });\n\n await fs.writeJSON(\n metaDataJsonPath,\n\n data,\n {\n spaces: 2,\n }\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\";\nimport { sleep } from \"./sleep\";\n\nconst log = createLogger(\"i18nData\");\nexport type ExtractedMap = Map<\n string,\n { id: string; messages: string; files: string[] }\n>;\n\nexport class I18nData {\n data: Record<string, string> = {};\n\n filePath: string;\n\n /**\n * 是否是默认语言,默认语言需要使用提出来的文案作为value\n */\n isDefaultLocale: boolean;\n // 没有被使用到的翻译key\n unUsedKeys: Set<string> = new Set();\n constructor(\n public locale: string,\n public config: I18nConfig,\n // 是否需要删除未使用的文案\n public shouldDeleteUnused = false\n ) {\n this.isDefaultLocale = locale === config.defaultLocale;\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 /**\n * @param {ExtractedMap} extractedData 提取出来的内容\n */\n async updateByExtractedData(extractedData: ExtractedMap) {\n const oldData = await this.loadData();\n let newData = {};\n extractedData.forEach((value, key) => {\n let newValue = oldData[key] || \"\";\n if (this.isDefaultLocale) {\n // 默认语言需要回退到key作为value\n newValue = newValue || value.messages || key;\n //#region 对namespace的支持\n newValue = this.normalizeNamespacedDefaultLocaleData(newValue);\n //#endregion\n }\n newData[key] = newValue;\n });\n if (!this.shouldDeleteUnused) {\n // 不删除未使用的文案,则需要合并旧数据\n newData = { ...oldData, ...newData };\n }\n this.data = newData;\n\n // 记录下来未被使用的key,后面需要打印出来提示用户\n Object.keys(oldData).forEach((key) => {\n if (!extractedData.has(key)) {\n this.unUsedKeys.add(key);\n }\n });\n }\n\n private namespaceReg: RegExp;\n /**\n * 如果是默认语言,开启了 namespace的话\n * 提取出来的 文案 是 `模块名.文案` 的形式\n * 在这里需要把 `模块名.` 去掉\n */\n private normalizeNamespacedDefaultLocaleData(v: string) {\n if (!this.namespaceReg && this.config.namespace) {\n const names = Object.keys(this.config.namespace).join(\"|\");\n const separator = this.config.namespaceSeparator;\n this.namespaceReg = new RegExp(`^(${names})\\\\${separator}`);\n }\n if (this.namespaceReg) {\n return v.replace(this.namespaceReg, \"\");\n }\n return v;\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 trySaveToGoogle(sheetData: SheetData) {\n await pMap(\n Object.entries(this.data),\n async ([key, value]) => {\n if (sheetData.hasI18nItem(this.locale, key)) {\n // 更新已有的\n await sheetData.getI18nItem(this.locale, key)?.tryUpdate(value);\n // 避免频繁请求,Google sheet api 默认限制\n // • 每秒钟读操作数:100 请求/秒\n // • 每秒钟单元格写操作数:100 请求/秒\n await sleep(500);\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 { concurrency: 50 }\n );\n }\n private 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 static printStatistic(label: string, i18nDataArr: I18nData[]) {\n // 首先打印 unUsedKeys\n const unUsedKeys = i18nDataArr.reduce((keys, item) => {\n return new Set(item.unUsedKeys);\n }, new Set<string>());\n if (unUsedKeys.size) {\n console.log(\n pc.bold(\n `共有 ${pc.green(\n unUsedKeys.size\n )} 个 key 未在代码中使用,以下是具体的 key`\n )\n );\n console.log(\n pc.red(\n \"注意:这些key可能是已经删除的代码,也可能是通过 `t.ignoreExtract` 调用忽略了提取 并不一定是冗余的 key\"\n )\n );\n console.table(unUsedKeys);\n }\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\n i18nDataArr.forEach((i18nData) => {\n const statistic = i18nData.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","export function sleep(ms: number) {\n return new Promise((resolve) => {\n setTimeout(resolve, ms);\n });\n}\n","import enquirer from \"enquirer\";\nimport { ApiConfig, I18nConfig } from \"./config\";\nconst { prompt } = enquirer;\n\ninterface Opt<T> {\n configArr: (T & { enabled?: boolean })[];\n getChoiceItem: (item: T) => {\n name: string;\n message?: string;\n value?: string;\n hint?: string;\n };\n checkIsEnabled: (enabledArr: string[], item: T) => boolean;\n}\n\nexport async function promptConfigEnable<T>(opt: Opt<T>) {\n const { configArr, getChoiceItem } = opt;\n // 只有一条配置的时候不用选择\n if (configArr.length <= 1) {\n return configArr;\n }\n\n const choices = [\n {\n name: \"全部\",\n message: \"全部\",\n choices: configArr.map((item) => {\n return getChoiceItem(item);\n }),\n },\n ];\n const res = await prompt<{ enabled: string[] }>({\n type: \"multiselect\",\n message: \"选择要生效的配置项\",\n hint: \"(空格选中,回车确认)\",\n name: \"enabled\",\n validate(value) {\n return value.length === 0 ? `至少选择一项` : true;\n },\n choices,\n });\n\n configArr.forEach((item) => {\n item.enabled = opt.checkIsEnabled(res.enabled, item);\n });\n\n return configArr.filter((c) => c.enabled);\n}\n\nexport function promptI18nConfigEnable(configArr: I18nConfig[] | undefined) {\n return promptConfigEnable({\n configArr: configArr ?? [],\n getChoiceItem: (item) => {\n return {\n name: item.i18nDir!,\n hint: `sheetRange: ${item.sheetRange}`,\n };\n },\n checkIsEnabled: (enabledArr, item) => {\n return enabledArr.includes(item.i18nDir!);\n },\n });\n}\n\nexport function promptApiConfigEnable(configArr: ApiConfig[] | undefined) {\n return promptConfigEnable({\n configArr: configArr ?? [],\n getChoiceItem: (item) => {\n return {\n name: item.output!,\n hint: `swaggerJSONPath: ${item.swaggerJSONPath}`,\n };\n },\n checkIsEnabled: (enabledArr, item) => {\n return enabledArr.includes(item.output!);\n },\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\";\nimport { promptI18nConfigEnable } from \"../shared/promptConfigEnable\";\n\nconst log = createLogger(\"generate\");\n\nexport async function download() {\n const config = await getConfig();\n\n let i18nConfigs = await promptI18nConfigEnable(config.i18n);\n\n let i = 0;\n for (const configItem of i18nConfigs) {\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 i18nData;\n }\n );\n I18nData.printStatistic(`${configItem.sheetRange} 生成结果: `, statistics);\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)];\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\";\nimport { promptApiConfigEnable } from \"../../shared/promptConfigEnable\";\nimport { formatFile } from \"../../shared/formatFile\";\n\nconst log = createLogger(\"generateApi\");\n\nexport async function generateApi() {\n const config = await getConfig();\n const apiConfigs = await promptApiConfigEnable(config.api);\n\n for (const apiConfig of apiConfigs) {\n log.info(`清除旧的api文件: ${apiConfig.output}`);\n await fs.emptydir(apiConfig.output!);\n }\n\n for (const apiConfig of apiConfigs) {\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\n .join(\n apiConfig.output!,\n url,\n apiConfig.enableTs ? `${method}.ts` : `${method}.js`\n )\n .replace(/:/g, \"_\");\n await fs.ensureFile(outputPath);\n await fs.writeFile(outputPath, code);\n }\n }\n );\n }\n });\n\n if (apiConfig.format) {\n await formatFile(apiConfig.output!);\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 { method, operationObject, apiConfig } = options;\n\n const url = (() => {\n if (typeof apiConfig.urlTransformer === \"string\") {\n return `${apiConfig.urlTransformer}${options.url}`;\n }\n if (typeof apiConfig.urlTransformer === \"function\") {\n return apiConfig.urlTransformer(options.url);\n }\n return options.url;\n })();\n\n const seeUrl = apiConfig.swaggerUiUrl\n ? `${apiConfig.swaggerUiUrl}#/${operationObject.tags?.join(\"/\") ?? \"\"}/${\n operationObject.operationId\n }`\n : \"\";\n\n let requestBuilderName = _.camelCase(`${url}_${method}_api`);\n\n // 判断是否有效的js变量\n if (!/^[a-zA-Z_$][0-9a-zA-Z_$]*$/.test(requestBuilderName)) {\n // 不是有效的js变量,使用 _ + 数字\n requestBuilderName = `_${requestBuilderName}`;\n }\n\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 apiConfig.RequestBuilderImportPath!,\n apiConfig.requestFnImportPath!,\n apiConfig.queryClientImportPath!,\n\n \"/**\",\n ` * ${operationObject.summary}`,\n ` * @tags ${operationObject.tags?.join(\",\")}`,\n seeUrl && ` * @see ${seeUrl}`,\n ` */`,\n ].filter(Boolean);\n\n // builder 代码\n let builderCode = `\\\nexport const ${requestBuilderName} = new RequestBuilder({\n url: '${url}',\n method: '${method}',\n ${apiConfig.requestFnImportPath ? \"requestFn,\" : \"\"}\n ${urlPathParamsCode}\n ${apiConfig.queryClientImportPath ? \"queryClient,\" : \"\"}\n});`\n // 移除空行\n .replace(/,\\n\\s*}/, \",\" + os.EOL + \"}\");\n if (apiConfig.enableTs) {\n builderCode = builderCode.replace(\n \"new RequestBuilder(\",\n `new RequestBuilder<${requestBuilderName}.Req, ${requestBuilderName}.Res>(`\n );\n }\n code.push(builderCode);\n\n if (apiConfig.enableTs) {\n // 请求参数类型\n // 响应参数类型\n const [requestParamsTypeCode, responseParamsTypeCode] = await Promise.all([\n compileRequestParams(operationObject),\n compileResponseParams(operationObject, apiConfig),\n ]);\n\n code.push(`\nexport namespace ${requestBuilderName} {\n ${requestParamsTypeCode}\n \n ${responseParamsTypeCode}\n};`);\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.requestBody) {\n //TODO: 这里也需要处理其他类型\n schema = (operationObject.requestBody as OpenAPIV3.RequestBodyObject)\n .content[\"application/json\"].schema;\n } else if (operationObject.parameters) {\n const extraProperties = {};\n const parameters: OpenAPIV3.ParameterObject[] = [];\n (operationObject.parameters as OpenAPIV3.ParameterObject[]).forEach(\n (item) => {\n if (![\"query\", \"path\"].includes(item.in)) {\n return;\n }\n if (_.get(item.schema, \"type\") === \"object\") {\n // swagger get 请求上 有些参数是 object 类型 应该拍平\n _.assign(extraProperties, _.get(item.schema, \"properties\", {}));\n } else {\n parameters.push(item);\n }\n }\n );\n\n // 必填参数中忽略 分页相关的参数\n const required = parameters\n .filter(\n (p) => p.required && ![\"pageNum\", \"pageSize\", \"count\"].includes(p.name)\n )\n .map((p) => p.name);\n const properties = Object.fromEntries(\n parameters\n // 后端 swagger 可能出现没有 schema 的情况,这里过滤掉\n .filter((p) => !!p.schema)\n .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: { ...properties, ...extraProperties },\n };\n }\n\n let code = \"\";\n if (schema) {\n try {\n code = await compile(schema, \"Req\", {\n bannerComment: \"\",\n ignoreMinAndMaxItems: !!1,\n additionalProperties: false,\n // format: false,\n });\n } catch (e) {\n log.error(\"生成请求参数类型失败,请检查 %o\", {\n summary: operationObject.summary,\n message: e.message,\n });\n }\n }\n\n return code ? code : \"export type Req = any;\";\n}\n\nasync function compileResponseParams(\n operationObject: OpenAPIV3.OperationObject,\n apiConfig: ApiConfig\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 let data = apiConfig.responseSchemaTransformer!(schema);\n if (data) {\n // 这里需要深度clone的原因是:\n // 解析出来的scheme会尽可能的被复用,导致影响到下次解析\n data = _.cloneDeep(data);\n markCircularToRef(data);\n try {\n code = await compile(data, \"Res\", {\n bannerComment: \"\",\n ignoreMinAndMaxItems: !!1,\n additionalProperties: false,\n // format: false,\n });\n } catch (e) {\n log.error(\"转换响应参数类型失败, 请检查 %o\", {\n summary: operationObject.summary,\n error: e.message,\n });\n }\n } else {\n log.error(\"responseSchemaTransformer 返回值为空, 请检查\");\n }\n }\n\n return code ? code : \"export type Res = any;\";\n}\n\nexport function markCircularToRef(\n obj,\n parentMark = \"#\",\n map = new Map([[obj, parentMark]]),\n set = new Set([obj])\n) {\n Object.keys(obj).forEach((key) => {\n const value = obj[key];\n if (typeof value === \"object\" && !Array.isArray(value)) {\n if (set.has(value)) {\n obj[key] = { $ref: map.get(value) };\n return;\n }\n const tempMark = parentMark + \"/\" + key;\n set.add(value);\n map.set(value, tempMark);\n markCircularToRef(value, tempMark, map, set);\n }\n });\n return map;\n}\n","import { createLogger } from \".\";\nimport * as child_process from \"child_process\";\n\nconst log = createLogger(\"generateApi\");\n\nexport function formatFile(filename: string) {\n // 格式化代码\n log.info(`尝试格式化代码: %s`, filename);\n child_process.exec(`prettier --write '${filename}'`, (error) => {\n if (error) {\n log.error(`格式化代码失败: ${error}`);\n log.error(`请手动执行: prettier --write ${filename}`);\n log.error(`或者在配置文件中关闭格式化功能`);\n } else {\n log.info(`格式化代码成功: %s`, filename);\n }\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 * @param {import('@dune2/cli').Config} 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\";\nimport { promptI18nConfigEnable } from \"../shared/promptConfigEnable\";\nimport { sleep } from \"../shared/sleep\";\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}\n\nexport async function upload() {\n const config = await getConfig();\n let i18nConfigs = await promptI18nConfigEnable(config.i18n);\n\n for (const configItem of i18nConfigs) {\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 enquirer from \"enquirer\";\nconst { prompt } = enquirer;\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 prompt<{ command: string }>({\n type: \"autocomplete\",\n name: \"command\",\n message: \"选择要执行的命令:\",\n choices: commands.map((command) => {\n commandMap.set(command.name, command);\n return {\n name: command.name,\n value: command.name,\n message: command.description,\n hint: `等同命令 ${cli.name} ${command.name}`,\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","import { createLogger } from \"../shared\";\nimport { getConfig } from \"../shared/config\";\nimport enquirer from \"enquirer\";\nimport _ from \"lodash\";\nimport { globby } from \"globby\";\nimport fs from \"fs-extra\";\nimport pMap from \"p-map\";\nimport pc from \"picocolors\";\nimport { formatFile } from \"../shared/formatFile\";\n\nconst { prompt } = enquirer;\n\nconst log = createLogger(\"namespace\");\n\nexport async function namespace() {\n const config = await getConfig();\n\n // 不允许提取的 配置 不需要选择\n let i18nConfigs = config.i18n?.filter((item) => !item.disableExtract);\n if (!i18nConfigs) {\n log.info(\"没有配置 i18n\");\n return;\n }\n\n // 选择 生效的 i18n 配置\n const { i18nDir } = await prompt<{ i18nDir: string }>({\n type: \"select\",\n name: \"i18nDir\",\n message: \"选择要生效的配置项\",\n choices: i18nConfigs.map((item) => {\n return {\n name: item.i18nDir!,\n hint: `sheetRange: ${item.sheetRange}`,\n };\n }),\n });\n let i18nConfig = i18nConfigs.find((item) => item.i18nDir === i18nDir);\n if (!i18nConfig) {\n log.info(\"没有找到对应的配置\");\n return;\n }\n\n // 选择 生效的 namespace\n const { namespaces } = await prompt<{ namespaces: string[] }>({\n type: \"multiselect\",\n message: \"选择要生效的配置项\",\n hint: \"(空格选中,回车确认)\",\n name: \"namespaces\",\n validate(value) {\n return value.length === 0 ? `至少选择一项` : true;\n },\n choices: _.map(i18nConfig.namespace, (v, k) => {\n return {\n name: k,\n };\n }),\n });\n\n for (const namespace of namespaces) {\n const namespaceConfig = i18nConfig.namespace?.[namespace];\n\n const suffix = `**/**.{js,jsx,ts,tsx}`;\n const combined = _.map(_.castArray(namespaceConfig), (v) => {\n v = v.endsWith(\"/\") ? v : v + \"/\";\n return v + suffix;\n });\n log.info(\"正在处理 namespace: %s\", pc.green(namespace));\n log.info(\"预计处理的文件路径: %s\", pc.green(combined.join(\"\\n\")));\n\n const files = await globby(\n [\n \"!**/node_modules/**\",\n \"!**.d.ts\",\n \"!**/.next/**\",\n \"!**/out/**\",\n //\n ].concat(combined),\n { cwd: i18nConfig.cwd }\n );\n\n log.info(\"预计共处理 %s 个文件\", pc.green(files.length));\n\n const { autoNamespace } = await import(\"@dune2/wasm\");\n\n let transformedFileSet = new Set<string>();\n\n await pMap(files, async (file) => {\n const content = await fs.readFile(file, \"utf-8\");\n\n const newContent = await autoNamespace(\n content,\n namespace,\n i18nConfig!.namespaceSeparator!\n );\n\n if (newContent) {\n await fs.writeFile(file, newContent);\n await formatFile(file);\n transformedFileSet.add(file);\n }\n });\n log.info(\n \"已为 %s 个文件 自动添加 namespace\",\n pc.green(transformedFileSet.size)\n );\n }\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\";\nimport { namespace } from \"./commands/namespace\";\n//#region 翻译相关\n\ncli\n .command(\"download\", \"生成翻译文件\")\n .example(\"dune download\")\n .action(download);\ncli\n .command(\"extract\", \"提取代码中的文案\")\n .option(\"--deleteUnused\", \"删除未使用的文案\")\n .example(\"dune extract\")\n .action(extract);\n\ncli\n .command(\"namespace\", \"添加namespace前缀\")\n .example(\"dune namespace\")\n .action(namespace);\n\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","pc","path","log","extract","pc","pMap","fs","pMap","log","log","pMap","pMap","fs","os","path","log","log","fs","pMap","path","schema","fs","path","log","pMap","log","pMap","enquirer","prompt","log","command","enquirer","_","globby","fs","pMap","pc","prompt","enquirer","log","_","namespace","pc","globby","pMap","fs"]}
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { GaxiosResponse } from 'gaxios';
2
2
  import { sheets_v4 } from 'googleapis';
3
- import { C as Config } from './types-4aff0a8d.js';
4
- export { A as ApiConfig, C as Config, I as I18nConfig } from './types-4aff0a8d.js';
3
+ import { C as Config } from './types-26fc55c9.js';
4
+ export { A as ApiConfig, C as Config, I as I18nConfig } from './types-26fc55c9.js';
5
5
  import 'openapi-types';
6
6
 
7
7
  declare class GoogleSheet {
package/dist/index.js CHANGED
@@ -5,10 +5,10 @@ import {
5
5
  googleSheet,
6
6
  letterToNumber,
7
7
  numberToLetter
8
- } from "./chunk-4B7QMN4G.js";
8
+ } from "./chunk-5FXMC2FS.js";
9
9
  import {
10
10
  resolveSheetId
11
- } from "./chunk-2Z2VUD6F.js";
11
+ } from "./chunk-T2XO6ALS.js";
12
12
  export {
13
13
  configName,
14
14
  defineConfig,
@@ -1,4 +1,4 @@
1
- import { C as Config, A as ApiConfig } from './types-4aff0a8d.js';
1
+ import { C as Config, A as ApiConfig } from './types-26fc55c9.js';
2
2
  import 'openapi-types';
3
3
 
4
4
  declare function normalizeConfig(config: Config): Config;
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  apiConfigNormalizer,
3
3
  normalizeConfig
4
- } from "./chunk-2Z2VUD6F.js";
4
+ } from "./chunk-T2XO6ALS.js";
5
5
  export {
6
6
  apiConfigNormalizer,
7
7
  normalizeConfig
@@ -36,6 +36,18 @@ interface I18nConfig {
36
36
  * @default false
37
37
  */
38
38
  disableExtract?: boolean;
39
+ /**
40
+ * 翻译文案支持 namespace
41
+ * key 为 namespace
42
+ * value 为 对应的文件夹路径
43
+ * 使用场景:根据不同的业务模块,将翻译的key添加不同的前缀,并修改对应代码
44
+ */
45
+ namespace?: Record<string, string | string[]>;
46
+ /**
47
+ * namespace 分隔符
48
+ * @default "."
49
+ */
50
+ namespaceSeparator?: string;
39
51
  }
40
52
  interface ApiConfig {
41
53
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dune2/cli",
3
- "version": "0.2.13",
3
+ "version": "0.3.1",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {
@@ -23,7 +23,7 @@
23
23
  ],
24
24
  "dependencies": {
25
25
  "@apidevtools/swagger-parser": "^10.1.0",
26
- "@dune2/wasm": "0.2.2",
26
+ "@dune2/wasm": "0.3.1",
27
27
  "cac": "^6.7.14",
28
28
  "cli-table3": "^0.6.3",
29
29
  "connect": "^3.7.0",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/shared/resolveSheetId.ts","../src/shared/config/normalizeConfig.ts"],"sourcesContent":["/**\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","import { ApiConfig, Config, I18nConfig } from \"./types\";\nimport { resolveSheetId } from \"../resolveSheetId\";\nimport path from \"path\";\nexport function normalizeConfig(config: Config): Config {\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 config.cwd ??= process.cwd();\n config.cacheDir ??= path.join(config.cwd, \"node_modules/.cache/dune-cli\");\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 item.enabled ??= true;\n return item;\n });\n //#endregion\n\n //#region api 配置标准化\n config.api ??= [];\n config.api = config.api.map(apiConfigNormalizer);\n //#endregion\n return config;\n}\nexport function apiConfigNormalizer(item: ApiConfig) {\n item.output ??= \"./src/apis\";\n // 没有配置 urlTransformer 时,给 requestFnImportPath 赋默认值\n // 优先使用 urlTransformer\n if (!item.urlTransformer) {\n item.requestFnImportPath ??= `import requestFn from '@/utils/request';`;\n }\n item.RequestBuilderImportPath ??= `import { RequestBuilder } from '@dune2/tools';`;\n item.enableTs ??= true;\n item.enabled ??= true;\n item.format ??= true;\n item.responseSchemaTransformer ??= (schema) =>\n schema.properties?.data ?? schema;\n return item;\n}\n"],"mappings":";AASA,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;;;AClBA,OAAO,UAAU;AACV,SAAS,gBAAgB,QAAwB;AAHxD;AAIE,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;AACA,SAAO,QAAQ,QAAQ,IAAI;AAC3B,SAAO,aAAa,KAAK,KAAK,OAAO,KAAK,8BAA8B;AAGxE,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,SAAK,YAAY;AACjB,WAAO;AAAA,EACT,CAAC;AAID,SAAO,QAAQ,CAAC;AAChB,SAAO,MAAM,OAAO,IAAI,IAAI,mBAAmB;AAE/C,SAAO;AACT;AACO,SAAS,oBAAoB,MAAiB;AACnD,OAAK,WAAW;AAGhB,MAAI,CAAC,KAAK,gBAAgB;AACxB,SAAK,wBAAwB;AAAA,EAC/B;AACA,OAAK,6BAA6B;AAClC,OAAK,aAAa;AAClB,OAAK,YAAY;AACjB,OAAK,WAAW;AAChB,OAAK,8BAA8B,CAAC,WAAQ;AAjD9C;AAkDI,yBAAO,eAAP,mBAAmB,SAAQ;AAAA;AAC7B,SAAO;AACT;","names":["item"]}