@dittowords/cli 2.8.0 → 3.2.0-alpha

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.
Files changed (61) hide show
  1. package/README.md +150 -141
  2. package/bin/add-project.js +5 -7
  3. package/bin/add-project.js.map +1 -1
  4. package/bin/config.js +37 -11
  5. package/bin/config.js.map +1 -1
  6. package/bin/ditto.js +82 -57
  7. package/bin/ditto.js.map +1 -1
  8. package/bin/generate-suggestions.js +71 -0
  9. package/bin/generate-suggestions.js.map +1 -0
  10. package/bin/http/fetchComponents.js +13 -0
  11. package/bin/http/fetchComponents.js.map +1 -0
  12. package/bin/http/fetchVariants.js +26 -0
  13. package/bin/http/fetchVariants.js.map +1 -0
  14. package/bin/init/init.js +17 -6
  15. package/bin/init/init.js.map +1 -1
  16. package/bin/init/project.js +38 -45
  17. package/bin/init/project.js.map +1 -1
  18. package/bin/init/token.js +22 -20
  19. package/bin/init/token.js.map +1 -1
  20. package/bin/pull.js +136 -193
  21. package/bin/pull.js.map +1 -1
  22. package/bin/remove-project.js +2 -7
  23. package/bin/remove-project.js.map +1 -1
  24. package/bin/replace.js +107 -0
  25. package/bin/replace.js.map +1 -0
  26. package/bin/utils/cleanFileName.js +11 -0
  27. package/bin/utils/cleanFileName.js.map +1 -0
  28. package/bin/utils/generateJsDriver.js +56 -0
  29. package/bin/utils/generateJsDriver.js.map +1 -0
  30. package/bin/utils/getSelectedProjects.js +3 -18
  31. package/bin/utils/getSelectedProjects.js.map +1 -1
  32. package/bin/utils/projectsToText.js +10 -1
  33. package/bin/utils/projectsToText.js.map +1 -1
  34. package/bin/utils/promptForProject.js +2 -3
  35. package/bin/utils/promptForProject.js.map +1 -1
  36. package/bin/utils/quit.js +10 -0
  37. package/bin/utils/quit.js.map +1 -0
  38. package/lib/add-project.ts +6 -9
  39. package/lib/config.ts +56 -19
  40. package/lib/ditto.ts +111 -60
  41. package/lib/generate-suggestions.test.ts +65 -0
  42. package/lib/generate-suggestions.ts +107 -0
  43. package/lib/http/fetchComponents.ts +14 -0
  44. package/lib/http/fetchVariants.ts +30 -0
  45. package/lib/init/init.ts +38 -6
  46. package/lib/init/project.test.ts +3 -3
  47. package/lib/init/project.ts +47 -58
  48. package/lib/init/token.ts +17 -16
  49. package/lib/pull.ts +199 -279
  50. package/lib/remove-project.ts +2 -8
  51. package/lib/replace.test.ts +101 -0
  52. package/lib/replace.ts +106 -0
  53. package/lib/types.ts +22 -3
  54. package/lib/utils/cleanFileName.ts +6 -0
  55. package/lib/utils/generateJsDriver.ts +68 -0
  56. package/lib/utils/getSelectedProjects.ts +5 -24
  57. package/lib/utils/projectsToText.ts +11 -1
  58. package/lib/utils/promptForProject.ts +2 -3
  59. package/lib/utils/quit.ts +5 -0
  60. package/package.json +9 -2
  61. package/tsconfig.json +2 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generateJsDriver.js","sourceRoot":"","sources":["../../lib/utils/generateJsDriver.ts"],"names":[],"mappings":";;;;;;AAAA,4CAAoB;AACpB,gDAAwB;AACxB,uDAA+B;AAC/B,uDAA+B;AAE/B,mDAAgD;AAEhD,6DAA6D;AAC7D,2CAA2C;AAC3C,MAAM,iBAAiB,GAAG,CAAC,SAAiB,EAAE,EAAE,CAC9C,SAAS,KAAK,yBAAyB,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,SAAS,EAAE,CAAC;AAE/E;;;;;;;;;;GAUG;AAEH,oBAAoB;AACpB,SAAgB,gBAAgB,CAAC,OAAiB;IAChD,MAAM,SAAS,GAAG,YAAE;SACjB,WAAW,CAAC,gBAAM,CAAC,QAAQ,CAAC;SAC5B,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;IAElD,MAAM,eAAe,GAA2B,OAAO,CAAC,MAAM,CAC5D,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE;QACd,IAAI,MAAM,CAAC,QAAQ,EAAE;YACnB,OAAO,EAAE,GAAG,GAAG,EAAE,CAAC,IAAA,6BAAa,EAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC;SAChE;QAED,OAAO,GAAG,CAAC;IACb,CAAC,EACD,EAAE,CACH,CAAC;IAEF,MAAM,IAAI,GAAG,SAAS,CAAC,MAAM,CAC3B,CAAC,GAA2C,EAAE,QAAQ,EAAE,EAAE;QACxD,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC9C,MAAM,CAAC,YAAY,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAEvC,MAAM,SAAS,GAAG,eAAe,CAAC,QAAQ,CAAC,CAAC;QAC5C,MAAM,YAAY,GAAG,iBAAiB,CAAC,SAAS,CAAC,CAAC;QAElD,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE;YACtB,GAAG,CAAC,YAAY,CAAC,GAAG,EAAE,CAAC;SACxB;QAED,GAAG,CAAC,YAAY,CAAC,CAAC,YAAY,CAAC,GAAG,cAAc,QAAQ,IAAI,CAAC;QAC7D,OAAO,GAAG,CAAC;IACb,CAAC,EACD,EAAE,CACH,CAAC;IAEF,IAAI,UAAU,GAAG,oBAAoB,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE;QAClE,0CAA0C;SACzC,OAAO,CAAC,oBAAoB,EAAE,aAAa,CAAC,CAAC;IAEhD,MAAM,QAAQ,GAAG,cAAI,CAAC,OAAO,CAAC,gBAAM,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;IAC3D,YAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,UAAU,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;IAE7D,OAAO,+BAA+B,gBAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;AAChE,CAAC;AA1CD,4CA0CC"}
@@ -27,9 +27,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
27
27
  };
28
28
  Object.defineProperty(exports, "__esModule", { value: true });
29
29
  exports.getIsUsingComponents = exports.getSelectedProjects = void 0;
30
- const fs_1 = __importDefault(require("fs"));
31
30
  const js_yaml_1 = __importStar(require("js-yaml"));
32
31
  const consts_1 = require("../consts");
32
+ const config_1 = __importDefault(require("../config"));
33
33
  function jsonIsConfigYAML(json) {
34
34
  return typeof json === "object";
35
35
  }
@@ -54,23 +54,8 @@ function yamlToJson(_yaml) {
54
54
  * Returns an array containing all valid projects ({ id, name })
55
55
  * currently contained in the project config file.
56
56
  */
57
- const getSelectedProjects = (configFile = consts_1.PROJECT_CONFIG_FILE) => {
58
- if (!fs_1.default.existsSync(configFile))
59
- return [];
60
- const contentYaml = fs_1.default.readFileSync(configFile, "utf8");
61
- const contentJson = yamlToJson(contentYaml);
62
- if (!(contentJson && contentJson.projects)) {
63
- return [];
64
- }
65
- return contentJson.projects.filter(({ name, id }) => name && id);
66
- };
57
+ const getSelectedProjects = (configFile = consts_1.PROJECT_CONFIG_FILE) => config_1.default.parseSourceInformation(configFile).validProjects;
67
58
  exports.getSelectedProjects = getSelectedProjects;
68
- const getIsUsingComponents = (configFile = consts_1.PROJECT_CONFIG_FILE) => {
69
- if (!fs_1.default.existsSync(configFile))
70
- return false;
71
- const contentYaml = fs_1.default.readFileSync(configFile, "utf8");
72
- const contentJson = yamlToJson(contentYaml);
73
- return !!contentJson && !!contentJson.components;
74
- };
59
+ const getIsUsingComponents = (configFile = consts_1.PROJECT_CONFIG_FILE) => config_1.default.parseSourceInformation(configFile).shouldFetchComponentLibrary;
75
60
  exports.getIsUsingComponents = getIsUsingComponents;
76
61
  //# sourceMappingURL=getSelectedProjects.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"getSelectedProjects.js","sourceRoot":"","sources":["../../lib/utils/getSelectedProjects.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,4CAAoB;AACpB,mDAA8C;AAE9C,sCAAgD;AAGhD,SAAS,gBAAgB,CAAC,IAAa;IACrC,OAAO,OAAO,IAAI,KAAK,QAAQ,CAAC;AAClC,CAAC;AAED,SAAS,UAAU,CAAC,KAAa;IAC/B,IAAI;QACF,IAAI,UAAU,GAAG,iBAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAClC,IAAI,CAAC,gBAAgB,CAAC,UAAU,CAAC,EAAE;YACjC,OAAO,EAAE,CAAC;SACX;QACD,OAAO,UAAU,CAAC;KACnB;IAAC,OAAO,CAAC,EAAE;QACV,IAAI,CAAC,YAAY,uBAAa,EAAE;YAC9B,OAAO,IAAI,CAAC;SACb;aAAM;YACL,MAAM,CAAC,CAAC;SACT;KACF;AACH,CAAC;AAED;;;GAGG;AACI,MAAM,mBAAmB,GAAG,CACjC,UAAU,GAAG,4BAAmB,EACrB,EAAE;IACb,IAAI,CAAC,YAAE,CAAC,UAAU,CAAC,UAAU,CAAC;QAAE,OAAO,EAAE,CAAC;IAE1C,MAAM,WAAW,GAAG,YAAE,CAAC,YAAY,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;IACxD,MAAM,WAAW,GAAG,UAAU,CAAC,WAAW,CAAC,CAAC;IAE5C,IAAI,CAAC,CAAC,WAAW,IAAI,WAAW,CAAC,QAAQ,CAAC,EAAE;QAC1C,OAAO,EAAE,CAAC;KACX;IAED,OAAO,WAAW,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;AACnE,CAAC,CAAC;AAbW,QAAA,mBAAmB,uBAa9B;AAEK,MAAM,oBAAoB,GAAG,CAClC,UAAU,GAAG,4BAAmB,EACvB,EAAE;IACX,IAAI,CAAC,YAAE,CAAC,UAAU,CAAC,UAAU,CAAC;QAAE,OAAO,KAAK,CAAC;IAE7C,MAAM,WAAW,GAAG,YAAE,CAAC,YAAY,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;IACxD,MAAM,WAAW,GAAG,UAAU,CAAC,WAAW,CAAC,CAAC;IAE5C,OAAO,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,WAAW,CAAC,UAAU,CAAC;AACnD,CAAC,CAAC;AATW,QAAA,oBAAoB,wBAS/B"}
1
+ {"version":3,"file":"getSelectedProjects.js","sourceRoot":"","sources":["../../lib/utils/getSelectedProjects.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACA,mDAA8C;AAE9C,sCAAgD;AAEhD,uDAAwD;AAExD,SAAS,gBAAgB,CAAC,IAAa;IACrC,OAAO,OAAO,IAAI,KAAK,QAAQ,CAAC;AAClC,CAAC;AAED,SAAS,UAAU,CAAC,KAAa;IAC/B,IAAI;QACF,IAAI,UAAU,GAAG,iBAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAClC,IAAI,CAAC,gBAAgB,CAAC,UAAU,CAAC,EAAE;YACjC,OAAO,EAAE,CAAC;SACX;QACD,OAAO,UAAU,CAAC;KACnB;IAAC,OAAO,CAAC,EAAE;QACV,IAAI,CAAC,YAAY,uBAAa,EAAE;YAC9B,OAAO,IAAI,CAAC;SACb;aAAM;YACL,MAAM,CAAC,CAAC;SACT;KACF;AACH,CAAC;AAED;;;GAGG;AACI,MAAM,mBAAmB,GAAG,CAAC,UAAU,GAAG,4BAAmB,EAAE,EAAE,CACtE,gBAAM,CAAC,sBAAsB,CAAC,UAAU,CAAC,CAAC,aAAa,CAAC;AAD7C,QAAA,mBAAmB,uBAC0B;AAEnD,MAAM,oBAAoB,GAAG,CAAC,UAAU,GAAG,4BAAmB,EAAE,EAAE,CACvE,gBAAM,CAAC,sBAAsB,CAAC,UAAU,CAAC,CAAC,2BAA2B,CAAC;AAD3D,QAAA,oBAAoB,wBACuC"}
@@ -3,14 +3,23 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.getSourceUrl = void 0;
6
7
  const output_1 = __importDefault(require("../output"));
8
+ const getSourceUrl = (sourceId) => {
9
+ let base = "https://app.dittowords.com";
10
+ if (sourceId === "ditto_component_library") {
11
+ return `${base}/components`;
12
+ }
13
+ return `${base}/doc/${sourceId}`;
14
+ };
15
+ exports.getSourceUrl = getSourceUrl;
7
16
  const projectsToText = (projects) => {
8
17
  return ((projects || []).reduce((outputString, { name, id }) => outputString +
9
18
  ("\n" +
10
19
  "- " +
11
20
  output_1.default.info(name) +
12
21
  " " +
13
- output_1.default.subtle("https://app.dittowords.com/doc/" + id)), "") + "\n");
22
+ output_1.default.subtle((0, exports.getSourceUrl)(id))), "") + "\n");
14
23
  };
15
24
  exports.default = projectsToText;
16
25
  //# sourceMappingURL=projectsToText.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"projectsToText.js","sourceRoot":"","sources":["../../lib/utils/projectsToText.ts"],"names":[],"mappings":";;;;;AAAA,uDAA+B;AAG/B,MAAM,cAAc,GAAG,CAAC,QAAmB,EAAE,EAAE;IAC7C,OAAO,CACL,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,MAAM,CACrB,CAAC,YAAY,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,EAAE,CAC7B,YAAY;QACZ,CAAC,IAAI;YACH,IAAI;YACJ,gBAAM,CAAC,IAAI,CAAC,IAAI,CAAC;YACjB,GAAG;YACH,gBAAM,CAAC,MAAM,CAAC,iCAAiC,GAAG,EAAE,CAAC,CAAC,EAC1D,EAAE,CACH,GAAG,IAAI,CACT,CAAC;AACJ,CAAC,CAAC;AAEF,kBAAe,cAAc,CAAC"}
1
+ {"version":3,"file":"projectsToText.js","sourceRoot":"","sources":["../../lib/utils/projectsToText.ts"],"names":[],"mappings":";;;;;;AAAA,uDAA+B;AAGxB,MAAM,YAAY,GAAG,CAAC,QAAgB,EAAE,EAAE;IAC/C,IAAI,IAAI,GAAG,4BAA4B,CAAC;IAExC,IAAI,QAAQ,KAAK,yBAAyB,EAAE;QAC1C,OAAO,GAAG,IAAI,aAAa,CAAC;KAC7B;IAED,OAAO,GAAG,IAAI,QAAQ,QAAQ,EAAE,CAAC;AACnC,CAAC,CAAC;AARW,QAAA,YAAY,gBAQvB;AAEF,MAAM,cAAc,GAAG,CAAC,QAAmB,EAAE,EAAE;IAC7C,OAAO,CACL,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,MAAM,CACrB,CAAC,YAAY,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,EAAE,CAC7B,YAAY;QACZ,CAAC,IAAI;YACH,IAAI;YACJ,gBAAM,CAAC,IAAI,CAAC,IAAI,CAAC;YACjB,GAAG;YACH,gBAAM,CAAC,MAAM,CAAC,IAAA,oBAAY,EAAC,EAAE,CAAC,CAAC,CAAC,EACpC,EAAE,CACH,GAAG,IAAI,CACT,CAAC;AACJ,CAAC,CAAC;AAEF,kBAAe,cAAc,CAAC"}
@@ -5,10 +5,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const { AutoComplete } = require("enquirer");
7
7
  const output_1 = __importDefault(require("../output"));
8
+ const projectsToText_1 = require("./projectsToText");
8
9
  function formatProjectChoice(project) {
9
- return (project.name +
10
- " " +
11
- output_1.default.subtle(project.url || `https://app.dittowords.com/doc/${project.id}`));
10
+ return (project.name + " " + output_1.default.subtle(project.url || (0, projectsToText_1.getSourceUrl)(project.id)));
12
11
  }
13
12
  function parseResponse(response) {
14
13
  if (!response) {
@@ -1 +1 @@
1
- {"version":3,"file":"promptForProject.js","sourceRoot":"","sources":["../../lib/utils/promptForProject.ts"],"names":[],"mappings":";;;;;AAAA,MAAM,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AAE7C,uDAA+B;AAG/B,SAAS,mBAAmB,CAAC,OAAgB;IAC3C,OAAO,CACL,OAAO,CAAC,IAAI;QACZ,GAAG;QACH,gBAAM,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,IAAI,kCAAkC,OAAO,CAAC,EAAE,EAAE,CAAC,CAC7E,CAAC;AACJ,CAAC;AAED,SAAS,aAAa,CAAC,QAAgB;IACrC,IAAI,CAAC,QAAQ,EAAE;QACb,OAAO,IAAI,CAAC;KACb;IAED,MAAM,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,2BAA2B,CAAC,CAAC;IAEjE,IAAI,EAAE,KAAK,KAAK,EAAE;QAChB,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,yBAAyB,EAAE,CAAC;KAChD;IAED,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;AACtB,CAAC;AAQD,MAAM,gBAAgB,GAAG,KAAK,EAAE,EAC9B,OAAO,EACP,QAAQ,EACR,KAAK,GAAG,EAAE,GACU,EAAE,EAAE;IACxB,gBAAM,CAAC,EAAE,EAAE,CAAC;IAEZ,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;IAClD,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC;QAC9B,IAAI,EAAE,SAAS;QACf,OAAO;QACP,KAAK;QACL,OAAO;KACR,CAAC,CAAC;IAEH,IAAI,QAAQ,CAAC;IAEb,IAAI;QACF,QAAQ,GAAG,MAAM,MAAM,CAAC,GAAG,EAAE,CAAC;KAC/B;IAAC,OAAO,CAAC,EAAE;QACV,oDAAoD;QACpD,4CAA4C;QAC5C,QAAQ,GAAG,IAAI,CAAC;KACjB;IAED,OAAO,aAAa,CAAC,QAAQ,CAAC,CAAC;AACjC,CAAC,CAAC;AAEF,kBAAe,gBAAgB,CAAC"}
1
+ {"version":3,"file":"promptForProject.js","sourceRoot":"","sources":["../../lib/utils/promptForProject.ts"],"names":[],"mappings":";;;;;AAAA,MAAM,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AAE7C,uDAA+B;AAE/B,qDAAgD;AAEhD,SAAS,mBAAmB,CAAC,OAAgB;IAC3C,OAAO,CACL,OAAO,CAAC,IAAI,GAAG,GAAG,GAAG,gBAAM,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,IAAI,IAAA,6BAAY,EAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAC5E,CAAC;AACJ,CAAC;AAED,SAAS,aAAa,CAAC,QAAgB;IACrC,IAAI,CAAC,QAAQ,EAAE;QACb,OAAO,IAAI,CAAC;KACb;IAED,MAAM,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,2BAA2B,CAAC,CAAC;IAEjE,IAAI,EAAE,KAAK,KAAK,EAAE;QAChB,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,yBAAyB,EAAE,CAAC;KAChD;IAED,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;AACtB,CAAC;AAQD,MAAM,gBAAgB,GAAG,KAAK,EAAE,EAC9B,OAAO,EACP,QAAQ,EACR,KAAK,GAAG,EAAE,GACU,EAAE,EAAE;IACxB,gBAAM,CAAC,EAAE,EAAE,CAAC;IAEZ,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;IAClD,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC;QAC9B,IAAI,EAAE,SAAS;QACf,OAAO;QACP,KAAK;QACL,OAAO;KACR,CAAC,CAAC;IAEH,IAAI,QAAQ,CAAC;IAEb,IAAI;QACF,QAAQ,GAAG,MAAM,MAAM,CAAC,GAAG,EAAE,CAAC;KAC/B;IAAC,OAAO,CAAC,EAAE;QACV,oDAAoD;QACpD,4CAA4C;QAC5C,QAAQ,GAAG,IAAI,CAAC;KACjB;IAED,OAAO,aAAa,CAAC,QAAQ,CAAC,CAAC;AACjC,CAAC,CAAC;AAEF,kBAAe,gBAAgB,CAAC"}
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.quit = void 0;
4
+ function quit(message, exitCode = 2) {
5
+ console.log(`\n${message}\n`);
6
+ process.exitCode = exitCode;
7
+ process.exit();
8
+ }
9
+ exports.quit = quit;
10
+ //# sourceMappingURL=quit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quit.js","sourceRoot":"","sources":["../../lib/utils/quit.ts"],"names":[],"mappings":";;;AAAA,SAAgB,IAAI,CAAC,OAAe,EAAE,QAAQ,GAAG,CAAC;IAChD,OAAO,CAAC,GAAG,CAAC,KAAK,OAAO,IAAI,CAAC,CAAC;IAC9B,OAAO,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC5B,OAAO,CAAC,IAAI,EAAE,CAAC;AACjB,CAAC;AAJD,oBAIC"}
@@ -1,16 +1,11 @@
1
- import { collectAndSaveProject } from "./init/project";
1
+ import { collectAndSaveSource } from "./init/project";
2
2
  import projectsToText from "./utils/projectsToText";
3
3
  import {
4
4
  getSelectedProjects,
5
5
  getIsUsingComponents,
6
6
  } from "./utils/getSelectedProjects";
7
7
  import output from "./output";
8
-
9
- function quit(exitCode = 2) {
10
- console.log("Project selection was not updated.");
11
- process.exitCode = exitCode;
12
- process.exit();
13
- }
8
+ import { quit } from "./utils/quit";
14
9
 
15
10
  const addProject = async () => {
16
11
  const projects = getSelectedProjects();
@@ -38,13 +33,15 @@ const addProject = async () => {
38
33
  )}`
39
34
  );
40
35
  }
41
- await collectAndSaveProject(false);
36
+ await collectAndSaveSource({
37
+ components: false,
38
+ });
42
39
  } catch (error) {
43
40
  console.log(
44
41
  `\nSorry, there was an error adding a project to your workspace: `,
45
42
  error
46
43
  );
47
- quit();
44
+ quit("Project selection was not updated.");
48
45
  }
49
46
  };
50
47
 
package/lib/config.ts CHANGED
@@ -3,16 +3,30 @@ import path from "path";
3
3
  import url from "url";
4
4
  import yaml from "js-yaml";
5
5
 
6
+ import output from "./output";
6
7
  import consts from "./consts";
7
8
  import { Project, ConfigYAML } from "./types";
8
9
 
9
- function createFileIfMissing(filename: string) {
10
+ export const DEFAULT_CONFIG_JSON: ConfigYAML = {
11
+ sources: {
12
+ components: { enabled: true },
13
+ },
14
+ variants: true,
15
+ format: "flat",
16
+ };
17
+
18
+ export const DEFAULT_CONFIG = yaml.dump(DEFAULT_CONFIG_JSON);
19
+
20
+ function createFileIfMissing(filename: string, defaultContents?: any) {
10
21
  const dir = path.dirname(filename);
11
22
 
23
+ // create the directory if it doesn't already exist
12
24
  if (!fs.existsSync(dir)) fs.mkdirSync(dir);
13
25
 
26
+ // create the file if it doesn't already exist
14
27
  if (!fs.existsSync(filename)) {
15
- fs.closeSync(fs.openSync(filename, "w"));
28
+ // create the file, writing the `defaultContents` if provided
29
+ fs.writeFileSync(filename, defaultContents || "", "utf-8");
16
30
  }
17
31
  }
18
32
 
@@ -26,11 +40,13 @@ function jsonIsGlobalYAML(
26
40
  return (
27
41
  !!json &&
28
42
  typeof json === "object" &&
29
- Object.values(json).every((arr) =>
30
- arr.every(
31
- (val: any) =>
32
- typeof val === "object" && Object.keys(val).includes("token")
33
- )
43
+ Object.values(json).every(
44
+ (arr) =>
45
+ (arr as any).every &&
46
+ arr.every(
47
+ (val: any) =>
48
+ typeof val === "object" && Object.keys(val).includes("token")
49
+ )
34
50
  )
35
51
  );
36
52
  }
@@ -45,7 +61,7 @@ function readProjectConfigData(
45
61
  file = consts.PROJECT_CONFIG_FILE,
46
62
  defaultData = {}
47
63
  ): ConfigYAML {
48
- createFileIfMissing(file);
64
+ createFileIfMissing(file, DEFAULT_CONFIG);
49
65
  const fileContents = fs.readFileSync(file, "utf8");
50
66
  const yamlData = yaml.load(fileContents);
51
67
  if (jsonIsConfigYAML(yamlData)) {
@@ -73,10 +89,20 @@ function readGlobalConfigData(
73
89
  return defaultData;
74
90
  }
75
91
 
76
- function writeProjectConfigData(file: string, data: object) {
77
- createFileIfMissing(file);
92
+ function writeProjectConfigData(file: string, data: Partial<ConfigYAML>) {
93
+ createFileIfMissing(file, DEFAULT_CONFIG);
78
94
  const existingData = readProjectConfigData(file);
79
- const yamlStr = yaml.dump({ ...existingData, ...data });
95
+
96
+ const configData: ConfigYAML = {
97
+ ...existingData,
98
+ ...data,
99
+ sources: {
100
+ ...existingData.sources,
101
+ ...data.sources,
102
+ },
103
+ };
104
+
105
+ const yamlStr = yaml.dump(configData);
80
106
  fs.writeFileSync(file, yamlStr, "utf8");
81
107
  }
82
108
 
@@ -160,14 +186,22 @@ function dedupeProjectName(projectNames: Set<string>, projectName: string) {
160
186
  * - an array of valid, deduped projects
161
187
  * - the `variants` and `format` config options
162
188
  */
163
- function parseSourceInformation() {
164
- const { projects, components, variants, format, status, richText } =
165
- readProjectConfigData();
189
+ function parseSourceInformation(file?: string) {
190
+ const {
191
+ sources,
192
+ variants,
193
+ format,
194
+ status,
195
+ richText,
196
+ projects: projectsRoot,
197
+ components: componentsRoot,
198
+ } = readProjectConfigData(file);
199
+
200
+ const projects = sources?.projects || [];
166
201
 
167
202
  const projectNames = new Set<string>();
168
203
  const validProjects: Project[] = [];
169
-
170
- let componentLibraryInProjects = false;
204
+ let hasComponentLibraryInProjects = false;
171
205
 
172
206
  (projects || []).forEach((project) => {
173
207
  const isValid = project.id && project.name;
@@ -176,7 +210,7 @@ function parseSourceInformation() {
176
210
  }
177
211
 
178
212
  if (project.id === "ditto_component_library") {
179
- componentLibraryInProjects = true;
213
+ hasComponentLibraryInProjects = true;
180
214
  return;
181
215
  }
182
216
 
@@ -186,8 +220,7 @@ function parseSourceInformation() {
186
220
  validProjects.push(project);
187
221
  });
188
222
 
189
- const shouldFetchComponentLibrary =
190
- !!components || componentLibraryInProjects;
223
+ const shouldFetchComponentLibrary = Boolean(sources?.components?.enabled);
191
224
 
192
225
  const hasSourceData = !!validProjects.length || shouldFetchComponentLibrary;
193
226
 
@@ -199,6 +232,10 @@ function parseSourceInformation() {
199
232
  format,
200
233
  status,
201
234
  richText,
235
+ hasTopLevelProjectsField: !!projectsRoot,
236
+ hasTopLevelComponentsField: !!componentsRoot,
237
+ hasComponentLibraryInProjects,
238
+ componentFolders: sources?.components?.folders || null,
202
239
  };
203
240
  }
204
241
 
package/lib/ditto.ts CHANGED
@@ -4,93 +4,144 @@ import { program } from "commander";
4
4
  // to use V8's code cache to speed up instantiation time
5
5
  import "v8-compile-cache";
6
6
 
7
- import { init, needsInit } from "./init/init";
8
- import { pull } from "./pull";
7
+ import packageJson from "../package.json";
9
8
 
9
+ import { init, needsTokenOrSource } from "./init/init";
10
+ import { pull } from "./pull";
11
+ import { quit } from "./utils/quit";
10
12
  import addProject from "./add-project";
11
13
  import removeProject from "./remove-project";
14
+ import { replace } from "./replace";
15
+ import { generateSuggestions } from "./generate-suggestions";
16
+
12
17
  import processMetaOption from "./utils/processMetaOption";
13
18
 
14
- /**
15
- * Catch and report unexpected error.
16
- * @param {any} error The thrown error object.
17
- * @returns {void}
18
- */
19
- function quit(exitCode = 2) {
20
- console.log("\nExiting Ditto CLI...\n");
21
- process.exitCode = exitCode;
22
- process.exit();
23
- }
19
+ const VERSION = packageJson.version;
20
+
21
+ type Command =
22
+ | "pull"
23
+ | "project"
24
+ | "project add"
25
+ | "project remove"
26
+ | "generate-suggestions"
27
+ | "replace";
28
+
29
+ const COMMANDS = [
30
+ {
31
+ name: "pull",
32
+ description: "Sync copy from Ditto into the current working directory",
33
+ },
34
+ {
35
+ name: "project",
36
+ description: "Add a Ditto project to sync copy from",
37
+ commands: [
38
+ {
39
+ name: "add",
40
+ description: "Add a Ditto project to sync copy from",
41
+ },
42
+ {
43
+ name: "remove",
44
+ description: "Stop syncing copy from a Ditto project",
45
+ },
46
+ ],
47
+ },
48
+ {
49
+ name: "generate-suggestions",
50
+ description: "Find text that can be potentially replaced with Ditto text",
51
+ },
52
+ {
53
+ name: "replace",
54
+ description: "Find and replace Ditto text with code",
55
+ },
56
+ ] as const;
24
57
 
25
58
  const setupCommands = () => {
26
59
  program.name("ditto-cli");
27
- program
28
- .command("pull")
29
- .description("Sync copy from Ditto into working directory")
30
- .action(() => checkInit("pull"));
31
-
32
- const projectDescription = "Add a Ditto project to sync copy from";
33
- const projectCommand = program
34
- .command("project")
35
- .description(projectDescription)
36
- .action(() => checkInit("project"));
37
-
38
- projectCommand
39
- .command("add")
40
- .description(projectDescription)
41
- .action(() => checkInit("project"));
42
-
43
- projectCommand
44
- .command("remove")
45
- .description("Stop syncing copy from a Ditto project")
46
- .action(() => checkInit("project remove"));
60
+
61
+ COMMANDS.forEach((commandConfig) => {
62
+ const cmd = program
63
+ .command(commandConfig.name)
64
+ .description(commandConfig.description)
65
+ .action((str, options) => executeCommand(commandConfig.name, options));
66
+
67
+ if ("commands" in commandConfig) {
68
+ commandConfig.commands.forEach((nestedCommand) => {
69
+ cmd
70
+ .command(nestedCommand.name)
71
+ .description(nestedCommand.description)
72
+ .action((str, options) =>
73
+ executeCommand(
74
+ `${commandConfig.name} ${nestedCommand.name}`,
75
+ options
76
+ )
77
+ );
78
+ });
79
+ }
80
+ });
47
81
  };
48
82
 
49
83
  const setupOptions = () => {
50
84
  program.option(
51
85
  "-m, --meta <data...>",
52
- "Optional metadata for this command to send arbitrary data to the backend. Ex: -m githubActionRequest:true trigger:manual"
86
+ "Include arbitrary data in requests to the Ditto API. Ex: -m githubActionRequest:true trigger:manual"
53
87
  );
88
+ program.version(VERSION, "-v, --version", "Output the current version");
54
89
  };
55
90
 
56
- const checkInit = async (command: string) => {
57
- if (needsInit() && command !== "project remove") {
91
+ const executeCommand = async (
92
+ command: Command | "none",
93
+ options: string[]
94
+ ): Promise<void> => {
95
+ const needsInitialization = needsTokenOrSource();
96
+ if (needsInitialization) {
58
97
  try {
59
98
  await init();
60
- if (command === "pull") main(); // re-run to actually pull text now that init is finished
61
99
  } catch (error) {
62
- quit();
100
+ quit("Exiting Ditto CLI...");
101
+ return;
102
+ }
103
+ }
104
+
105
+ const { meta } = program.opts();
106
+ switch (command) {
107
+ case "none":
108
+ case "pull": {
109
+ return pull({ meta: processMetaOption(meta) });
110
+ }
111
+ case "project":
112
+ case "project add": {
113
+ // initialization already includes the selection of a source,
114
+ // so if `project add` is called during initialization, don't
115
+ // prompt the user to select a source again
116
+ if (needsInitialization) return;
117
+
118
+ return addProject();
119
+ }
120
+ case "project remove": {
121
+ return removeProject();
63
122
  }
64
- } else {
65
- const { meta } = program.opts();
66
- switch (command) {
67
- case "pull":
68
- pull({ meta: processMetaOption(meta) });
69
- break;
70
- case "project":
71
- case "project add":
72
- addProject();
73
- break;
74
- case "project remove":
75
- removeProject();
76
- break;
77
- case "none":
78
- setupCommands();
79
- program.help();
80
- break;
81
- default:
82
- quit();
123
+ case "generate-suggestions": {
124
+ return generateSuggestions();
125
+ }
126
+ case "replace": {
127
+ return replace(options);
128
+ }
129
+ default: {
130
+ quit("Exiting Ditto CLI...");
131
+ return;
83
132
  }
84
133
  }
85
134
  };
86
135
 
87
136
  const main = async () => {
137
+ setupCommands();
138
+ setupOptions();
139
+
88
140
  if (process.argv.length <= 2 && process.argv[1].includes("ditto-cli")) {
89
- await checkInit("none");
90
- } else {
91
- setupCommands();
92
- setupOptions();
141
+ await executeCommand("none", []);
142
+ return;
93
143
  }
144
+
94
145
  program.parse(process.argv);
95
146
  };
96
147
 
@@ -0,0 +1,65 @@
1
+ import fs from "fs/promises";
2
+ import path from "path";
3
+ import { findTextInJSXFiles } from "./generate-suggestions";
4
+
5
+ describe("findTextInJSXFiles", () => {
6
+ async function createTempFile(filename, content) {
7
+ const filePath = path.join(".", filename);
8
+ await fs.writeFile(filePath, content);
9
+ return filePath;
10
+ }
11
+
12
+ async function deleteTempFile(filename) {
13
+ const filePath = path.join(".", filename);
14
+ await fs.unlink(filePath);
15
+ }
16
+
17
+ it("should return an empty array when no files are found", async () => {
18
+ const result = await findTextInJSXFiles(".", "searchString");
19
+
20
+ expect(result).toEqual([]);
21
+ });
22
+
23
+ it("should return an empty array when searchString is not found in any file", async () => {
24
+ const file1 = await createTempFile("file1.jsx", "<div>No match</div>");
25
+ const file2 = await createTempFile("file2.tsx", "<div>No match</div>");
26
+
27
+ const result = await findTextInJSXFiles(".", "searchString");
28
+
29
+ expect(result).toEqual([]);
30
+
31
+ await deleteTempFile(file1);
32
+ await deleteTempFile(file2);
33
+ });
34
+
35
+ it("should return an array with correct occurrences when searchString is found", async () => {
36
+ const file1 = await createTempFile(
37
+ "file1.jsx",
38
+ `<div>Test searchString and another searchString</div>`
39
+ );
40
+
41
+ const expectedResult = [
42
+ {
43
+ file: file1,
44
+ occurrences: [
45
+ {
46
+ lineNumber: 1,
47
+ preview:
48
+ "<div>Test {{searchString}} and another searchString</div>",
49
+ },
50
+ {
51
+ lineNumber: 1,
52
+ preview:
53
+ "<div>Test searchString and another {{searchString}}</div>",
54
+ },
55
+ ],
56
+ },
57
+ ];
58
+
59
+ const result = await findTextInJSXFiles(".", "searchString");
60
+
61
+ expect(result).toEqual(expectedResult);
62
+
63
+ await deleteTempFile(file1);
64
+ });
65
+ });