@dittowords/cli 4.5.2 → 5.0.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (171) hide show
  1. package/README.md +6 -5
  2. package/bin/ditto.js +110 -285
  3. package/package.json +16 -10
  4. package/.github/actions/install-node-dependencies/action.yml +0 -24
  5. package/.github/workflows/required-checks.yml +0 -24
  6. package/.husky/pre-commit +0 -4
  7. package/.prettierignore +0 -0
  8. package/.prettierrc.json +0 -1
  9. package/__mocks__/fs.js +0 -2
  10. package/babel.config.js +0 -6
  11. package/bin/__mocks__/api.js +0 -48
  12. package/bin/__mocks__/api.js.map +0 -1
  13. package/bin/add-project.js +0 -104
  14. package/bin/add-project.js.map +0 -1
  15. package/bin/api.js +0 -54
  16. package/bin/api.js.map +0 -1
  17. package/bin/component-folders.js +0 -59
  18. package/bin/component-folders.js.map +0 -1
  19. package/bin/config.js +0 -242
  20. package/bin/config.js.map +0 -1
  21. package/bin/config.test.js +0 -93
  22. package/bin/config.test.js.map +0 -1
  23. package/bin/consts.js +0 -57
  24. package/bin/consts.js.map +0 -1
  25. package/bin/ditto.js.map +0 -1
  26. package/bin/generate-suggestions.js +0 -183
  27. package/bin/generate-suggestions.js.map +0 -1
  28. package/bin/generate-suggestions.test.js +0 -200
  29. package/bin/generate-suggestions.test.js.map +0 -1
  30. package/bin/http/__mocks__/fetchComponentFolders.js +0 -71
  31. package/bin/http/__mocks__/fetchComponentFolders.js.map +0 -1
  32. package/bin/http/__mocks__/fetchComponents.js +0 -73
  33. package/bin/http/__mocks__/fetchComponents.js.map +0 -1
  34. package/bin/http/__mocks__/fetchVariants.js +0 -71
  35. package/bin/http/__mocks__/fetchVariants.js.map +0 -1
  36. package/bin/http/fetchComponentFolders.js +0 -64
  37. package/bin/http/fetchComponentFolders.js.map +0 -1
  38. package/bin/http/fetchComponents.js +0 -78
  39. package/bin/http/fetchComponents.js.map +0 -1
  40. package/bin/http/fetchVariants.js +0 -87
  41. package/bin/http/fetchVariants.js.map +0 -1
  42. package/bin/http/http.test.js +0 -159
  43. package/bin/http/http.test.js.map +0 -1
  44. package/bin/http/importComponents.js +0 -114
  45. package/bin/http/importComponents.js.map +0 -1
  46. package/bin/importComponents.js +0 -65
  47. package/bin/importComponents.js.map +0 -1
  48. package/bin/init/init.js +0 -126
  49. package/bin/init/init.js.map +0 -1
  50. package/bin/init/project.js +0 -182
  51. package/bin/init/project.js.map +0 -1
  52. package/bin/init/project.test.js +0 -26
  53. package/bin/init/project.test.js.map +0 -1
  54. package/bin/init/token.js +0 -196
  55. package/bin/init/token.js.map +0 -1
  56. package/bin/init/token.test.js +0 -147
  57. package/bin/init/token.test.js.map +0 -1
  58. package/bin/output.js +0 -76
  59. package/bin/output.js.map +0 -1
  60. package/bin/pull-lib.test.js +0 -379
  61. package/bin/pull-lib.test.js.map +0 -1
  62. package/bin/pull.js +0 -562
  63. package/bin/pull.js.map +0 -1
  64. package/bin/pull.test.js +0 -151
  65. package/bin/pull.test.js.map +0 -1
  66. package/bin/remove-project.js +0 -99
  67. package/bin/remove-project.js.map +0 -1
  68. package/bin/replace.js +0 -171
  69. package/bin/replace.js.map +0 -1
  70. package/bin/replace.test.js +0 -197
  71. package/bin/replace.test.js.map +0 -1
  72. package/bin/types.js +0 -21
  73. package/bin/types.js.map +0 -1
  74. package/bin/utils/cleanFileName.js +0 -40
  75. package/bin/utils/cleanFileName.js.map +0 -1
  76. package/bin/utils/cleanFileName.test.js +0 -15
  77. package/bin/utils/cleanFileName.test.js.map +0 -1
  78. package/bin/utils/createSentryContext.js +0 -43
  79. package/bin/utils/createSentryContext.js.map +0 -1
  80. package/bin/utils/determineModuleType.js +0 -79
  81. package/bin/utils/determineModuleType.js.map +0 -1
  82. package/bin/utils/determineModuleType.test.js +0 -60
  83. package/bin/utils/determineModuleType.test.js.map +0 -1
  84. package/bin/utils/generateIOSBundles.js +0 -147
  85. package/bin/utils/generateIOSBundles.js.map +0 -1
  86. package/bin/utils/generateJsDriver.js +0 -178
  87. package/bin/utils/generateJsDriver.js.map +0 -1
  88. package/bin/utils/generateJsDriverTypeFile.js +0 -105
  89. package/bin/utils/generateJsDriverTypeFile.js.map +0 -1
  90. package/bin/utils/generateSwiftDriver.js +0 -93
  91. package/bin/utils/generateSwiftDriver.js.map +0 -1
  92. package/bin/utils/getSelectedProjects.js +0 -67
  93. package/bin/utils/getSelectedProjects.js.map +0 -1
  94. package/bin/utils/processMetaOption.js +0 -40
  95. package/bin/utils/processMetaOption.js.map +0 -1
  96. package/bin/utils/processMetaOption.test.js +0 -45
  97. package/bin/utils/processMetaOption.test.js.map +0 -1
  98. package/bin/utils/projectsToText.js +0 -58
  99. package/bin/utils/projectsToText.js.map +0 -1
  100. package/bin/utils/promptForProject.js +0 -96
  101. package/bin/utils/promptForProject.js.map +0 -1
  102. package/bin/utils/quit.js +0 -73
  103. package/bin/utils/quit.js.map +0 -1
  104. package/bin/utils/sourcesToText.js +0 -57
  105. package/bin/utils/sourcesToText.js.map +0 -1
  106. package/etsc.config.js +0 -13
  107. package/jest.config.ts +0 -16
  108. package/jsconfig.json +0 -5
  109. package/lib/__mocks__/api.ts +0 -12
  110. package/lib/add-project.ts +0 -48
  111. package/lib/api.ts +0 -16
  112. package/lib/component-folders.ts +0 -9
  113. package/lib/config.test.ts +0 -79
  114. package/lib/config.ts +0 -279
  115. package/lib/consts.ts +0 -22
  116. package/lib/ditto.ts +0 -285
  117. package/lib/generate-suggestions.test.ts +0 -169
  118. package/lib/generate-suggestions.ts +0 -166
  119. package/lib/http/__mocks__/fetchComponentFolders.ts +0 -23
  120. package/lib/http/__mocks__/fetchComponents.ts +0 -24
  121. package/lib/http/__mocks__/fetchVariants.ts +0 -21
  122. package/lib/http/fetchComponentFolders.ts +0 -23
  123. package/lib/http/fetchComponents.ts +0 -43
  124. package/lib/http/fetchVariants.ts +0 -42
  125. package/lib/http/http.test.ts +0 -122
  126. package/lib/http/importComponents.ts +0 -79
  127. package/lib/importComponents.ts +0 -24
  128. package/lib/init/init.ts +0 -79
  129. package/lib/init/project.test.ts +0 -26
  130. package/lib/init/project.ts +0 -136
  131. package/lib/init/token.test.ts +0 -99
  132. package/lib/init/token.ts +0 -156
  133. package/lib/output.ts +0 -21
  134. package/lib/pull-lib.test.ts +0 -367
  135. package/lib/pull.test.ts +0 -117
  136. package/lib/pull.ts +0 -629
  137. package/lib/remove-project.ts +0 -44
  138. package/lib/replace.test.ts +0 -157
  139. package/lib/replace.ts +0 -140
  140. package/lib/types.ts +0 -83
  141. package/lib/utils/cleanFileName.test.ts +0 -11
  142. package/lib/utils/cleanFileName.ts +0 -8
  143. package/lib/utils/createSentryContext.ts +0 -20
  144. package/lib/utils/determineModuleType.test.ts +0 -48
  145. package/lib/utils/determineModuleType.ts +0 -55
  146. package/lib/utils/generateIOSBundles.ts +0 -122
  147. package/lib/utils/generateJsDriver.ts +0 -207
  148. package/lib/utils/generateJsDriverTypeFile.ts +0 -75
  149. package/lib/utils/generateSwiftDriver.ts +0 -48
  150. package/lib/utils/getSelectedProjects.ts +0 -36
  151. package/lib/utils/processMetaOption.test.ts +0 -18
  152. package/lib/utils/processMetaOption.ts +0 -16
  153. package/lib/utils/projectsToText.ts +0 -29
  154. package/lib/utils/promptForProject.ts +0 -61
  155. package/lib/utils/quit.ts +0 -7
  156. package/lib/utils/sourcesToText.ts +0 -25
  157. package/pull_request_template.md +0 -20
  158. package/testfiles/en.json +0 -5
  159. package/testfiles/es.json +0 -5
  160. package/testfiles/fr.json +0 -5
  161. package/testfiles/test1.jsx +0 -18
  162. package/testfiles/test2.jsx +0 -9
  163. package/testing/.gitkeep +0 -0
  164. package/testing/fixtures/bad-yaml.yml +0 -6
  165. package/testing/fixtures/ditto-config-no-token +0 -2
  166. package/testing/fixtures/project-config-empty-projects.yml +0 -1
  167. package/testing/fixtures/project-config-no-id.yml +0 -2
  168. package/testing/fixtures/project-config-no-name.yml +0 -2
  169. package/testing/fixtures/project-config-pull.yml +0 -0
  170. package/testing/fixtures/project-config-working.yml +0 -3
  171. package/tsconfig.json +0 -16
package/lib/config.ts DELETED
@@ -1,279 +0,0 @@
1
- import fs from "fs";
2
- import path from "path";
3
- import url from "url";
4
- import yaml from "js-yaml";
5
- import * as Sentry from "@sentry/node";
6
-
7
- import consts from "./consts";
8
- import { createSentryContext } from "./utils/createSentryContext";
9
- import { Project, ConfigYAML, SourceInformation, Source } from "./types";
10
-
11
- export const DEFAULT_CONFIG_JSON: ConfigYAML = {
12
- sources: {
13
- components: true,
14
- },
15
- variants: true,
16
- format: "flat",
17
- };
18
-
19
- export const DEFAULT_CONFIG = yaml.dump(DEFAULT_CONFIG_JSON);
20
-
21
- function createFileIfMissing(filename: string, defaultContents?: any) {
22
- const dir = path.dirname(filename);
23
-
24
- // create the directory if it doesn't already exist
25
- if (!fs.existsSync(dir)) fs.mkdirSync(dir);
26
-
27
- // create the file if it doesn't already exist
28
- if (!fs.existsSync(filename)) {
29
- // create the file, writing the `defaultContents` if provided
30
- fs.writeFileSync(filename, defaultContents || "", "utf-8");
31
- }
32
- }
33
-
34
- function jsonIsConfigYAML(json: unknown): json is ConfigYAML {
35
- return typeof json === "object";
36
- }
37
-
38
- function jsonIsGlobalYAML(
39
- json: unknown
40
- ): json is Record<string, { token: string }[]> {
41
- return (
42
- !!json &&
43
- typeof json === "object" &&
44
- Object.values(json).every(
45
- (arr) =>
46
- (arr as any).every &&
47
- arr.every(
48
- (val: any) =>
49
- typeof val === "object" && Object.keys(val).includes("token")
50
- )
51
- )
52
- );
53
- }
54
-
55
- /**
56
- * Read data from a project config file
57
- * @param {string} file defaults to `PROJECT_CONFIG_FILE` defined in `constants.js`
58
- * @param {*} defaultData defaults to `{}`
59
- * @returns { ConfigYAML }
60
- */
61
- function readProjectConfigData(
62
- file = consts.PROJECT_CONFIG_FILE,
63
- defaultData = {}
64
- ): ConfigYAML {
65
- createFileIfMissing(file, DEFAULT_CONFIG);
66
- const fileContents = fs.readFileSync(file, "utf8");
67
- const yamlData = yaml.load(fileContents);
68
- if (jsonIsConfigYAML(yamlData)) {
69
- return yamlData;
70
- }
71
- return defaultData;
72
- }
73
-
74
- /**
75
- * Read data from a global config file
76
- * @param {string} file defaults to `CONFIG_FILE` defined in `constants.js`
77
- * @param {*} defaultData defaults to `{}`
78
- * @returns { Record<string, { token: string }[]> }
79
- */
80
- function readGlobalConfigData(
81
- file = consts.CONFIG_FILE,
82
- defaultData = {}
83
- ): Record<string, { token: string }[]> {
84
- createFileIfMissing(file);
85
- const fileContents = fs.readFileSync(file, "utf8");
86
- const yamlData = yaml.load(fileContents);
87
- if (jsonIsGlobalYAML(yamlData)) {
88
- return yamlData;
89
- }
90
- return defaultData;
91
- }
92
-
93
- function writeProjectConfigData(file: string, data: Partial<ConfigYAML>) {
94
- createFileIfMissing(file, DEFAULT_CONFIG);
95
- const existingData = readProjectConfigData(file);
96
-
97
- const configData: ConfigYAML = {
98
- ...existingData,
99
- ...data,
100
- sources: {
101
- ...existingData.sources,
102
- ...data.sources,
103
- },
104
- };
105
-
106
- const yamlStr = yaml.dump(configData);
107
- fs.writeFileSync(file, yamlStr, "utf8");
108
- }
109
-
110
- function writeGlobalConfigData(file: string, data: object) {
111
- createFileIfMissing(file);
112
- const existingData = readGlobalConfigData(file);
113
- const yamlStr = yaml.dump({ ...existingData, ...data });
114
- fs.writeFileSync(file, yamlStr, "utf8");
115
- }
116
-
117
- function justTheHost(host: string) {
118
- if (!host.includes("://")) return host;
119
- return url.parse(host).hostname || "";
120
- }
121
-
122
- function deleteToken(file: string, host: string) {
123
- const data = readGlobalConfigData(file);
124
- const hostParsed = justTheHost(host);
125
- data[hostParsed] = [];
126
- data[hostParsed][0] = { token: "" };
127
- writeGlobalConfigData(file, data);
128
- }
129
-
130
- function saveToken(file: string, host: string, token: string) {
131
- const data = readGlobalConfigData(file);
132
- const hostParsed = justTheHost(host);
133
- data[hostParsed] = []; // only allow one token per host
134
- data[hostParsed][0] = { token };
135
- writeGlobalConfigData(file, data);
136
- }
137
-
138
- function getTokenFromEnv() {
139
- return process.env.DITTO_API_KEY;
140
- }
141
-
142
- /**
143
- *
144
- * @param {string} file
145
- * @param {string} host
146
- * @returns {Token}
147
- */
148
- function getToken(file: string, host: string) {
149
- const tokenFromEnv = getTokenFromEnv();
150
- if (tokenFromEnv) {
151
- return tokenFromEnv;
152
- }
153
-
154
- const data = readGlobalConfigData(file);
155
- const hostEntry = data[justTheHost(host)];
156
- if (!hostEntry) return undefined;
157
- const { length } = hostEntry;
158
-
159
- return hostEntry[length - 1].token;
160
- }
161
-
162
- const IS_DUPLICATE = /-(\d+$)/;
163
-
164
- function dedupeProjectName(projectNames: Set<string>, projectName: string) {
165
- let dedupedName = projectName;
166
-
167
- if (projectNames.has(dedupedName)) {
168
- while (projectNames.has(dedupedName)) {
169
- const [_, numberStr] = dedupedName.match(IS_DUPLICATE) || [];
170
- if (numberStr && !isNaN(parseInt(numberStr))) {
171
- dedupedName = `${dedupedName.replace(IS_DUPLICATE, "")}-${
172
- parseInt(numberStr) + 1
173
- }`;
174
- } else {
175
- dedupedName = `${dedupedName}-1`;
176
- }
177
- }
178
- }
179
-
180
- return dedupedName;
181
- }
182
-
183
- /**
184
- * Reads from the config file, filters out
185
- * invalid projects, dedupes those remaining, and returns:
186
- * - whether or not the data required to `pull` is present
187
- * - whether or not the component library should be fetched
188
- * - an array of valid, deduped projects
189
- * - the `variants` and `format` config options
190
- */
191
- function parseSourceInformation(file?: string): SourceInformation {
192
- const {
193
- sources,
194
- variants,
195
- format,
196
- status,
197
- richText,
198
- iosLocales,
199
- projects: projectsRoot,
200
- components: componentsRoot,
201
- disableJsDriver,
202
- } = readProjectConfigData(file);
203
-
204
- const projects = sources?.projects || [];
205
-
206
- const projectNames = new Set<string>();
207
- const validProjects: Project[] = [];
208
- let hasComponentLibraryInProjects = false;
209
-
210
- (projects || []).forEach((project) => {
211
- const isValid = project.id && project.name;
212
- if (!isValid) {
213
- return;
214
- }
215
-
216
- if (project.id === "ditto_component_library") {
217
- hasComponentLibraryInProjects = true;
218
- return;
219
- }
220
-
221
- project.fileName = dedupeProjectName(projectNames, project.name);
222
- projectNames.add(project.fileName);
223
-
224
- validProjects.push(project);
225
- });
226
-
227
- const shouldFetchComponentLibrary = Boolean(sources?.components);
228
- const componentRoot =
229
- typeof sources?.components === "object"
230
- ? sources.components.root
231
- : undefined;
232
- const componentFolders =
233
- typeof sources?.components === "object"
234
- ? sources.components.folders
235
- : undefined;
236
-
237
- /**
238
- * If it's not specified to fetch projects or the component library, then there
239
- * is no source data to pull.
240
- */
241
- const hasSourceData = !!validProjects.length || shouldFetchComponentLibrary;
242
-
243
- const result: SourceInformation = {
244
- hasSourceData,
245
- validProjects,
246
- shouldFetchComponentLibrary,
247
- variants: variants || false,
248
- format,
249
- status,
250
- richText,
251
- hasTopLevelProjectsField: !!projectsRoot,
252
- hasTopLevelComponentsField: !!componentsRoot,
253
- hasComponentLibraryInProjects,
254
- componentRoot,
255
- componentFolders,
256
- localeByVariantApiId: iosLocales
257
- ? iosLocales.reduce((acc, e) => ({ ...acc, ...e }), {} as any)
258
- : undefined,
259
- disableJsDriver,
260
- };
261
-
262
- Sentry.setContext("config", createSentryContext(result));
263
-
264
- return result;
265
- }
266
-
267
- export default {
268
- createFileIfMissing,
269
- readProjectConfigData,
270
- readGlobalConfigData,
271
- writeGlobalConfigData,
272
- writeProjectConfigData,
273
- justTheHost,
274
- saveToken,
275
- deleteToken,
276
- getToken,
277
- getTokenFromEnv,
278
- parseSourceInformation,
279
- };
package/lib/consts.ts DELETED
@@ -1,22 +0,0 @@
1
- import { homedir } from "os";
2
- import path from "path";
3
-
4
- export default new (class {
5
- get API_HOST() {
6
- return process.env.DITTO_API_HOST || "https://api.dittowords.com";
7
- }
8
- get CONFIG_FILE() {
9
- return (
10
- process.env.DITTO_CONFIG_FILE || path.join(homedir(), ".config", "ditto")
11
- );
12
- }
13
- get PROJECT_CONFIG_FILE() {
14
- return path.normalize(path.join("ditto", "config.yml"));
15
- }
16
- get TEXT_DIR() {
17
- return process.env.DITTO_TEXT_DIR || "ditto";
18
- }
19
- get TEXT_FILE() {
20
- return path.normalize(path.join(this.TEXT_DIR, "text.json"));
21
- }
22
- })();
package/lib/ditto.ts DELETED
@@ -1,285 +0,0 @@
1
- #!/usr/bin/env node
2
- // This is the main entry point for the ditto-cli command.
3
- import { program } from "commander";
4
- // to use V8's code cache to speed up instantiation time
5
- import "v8-compile-cache";
6
- import fs from "fs";
7
- import path from "path";
8
- import * as Sentry from "@sentry/node";
9
- import { version as release } from "../package.json";
10
- import { init, needsTokenOrSource } from "./init/init";
11
- import { pull } from "./pull";
12
- import { quit } from "./utils/quit";
13
- import addProject from "./add-project";
14
- import removeProject from "./remove-project";
15
- import { replace } from "./replace";
16
- import { generateSuggestions } from "./generate-suggestions";
17
- import processMetaOption from "./utils/processMetaOption";
18
- import { importComponents } from "./importComponents";
19
- import { showComponentFolders } from "./component-folders";
20
-
21
- const environment = process.env.ENV || "development";
22
- Sentry.init({ dsn: process.env.SENTRY_DSN, environment, release });
23
-
24
- function getVersion(): string {
25
- const packageJsonPath = path.join(__dirname, "..", "package.json");
26
- const packageJsonContent = fs.readFileSync(packageJsonPath, "utf8");
27
- const packageJson = JSON.parse(packageJsonContent) as { version: string };
28
- return packageJson.version;
29
- }
30
-
31
- const VERSION = getVersion();
32
-
33
- const CONFIG_FILE_RELIANT_COMMANDS = [
34
- "pull",
35
- "none",
36
- "project",
37
- "project add",
38
- "project remove",
39
- ];
40
-
41
- type Command =
42
- | "pull"
43
- | "project"
44
- | "project add"
45
- | "project remove"
46
- | "component-folders"
47
- | "generate-suggestions"
48
- | "replace"
49
- | "import-components";
50
-
51
- interface CommandConfig<T extends Command | "add" | "remove"> {
52
- name: T;
53
- description: string;
54
- commands?: CommandConfig<"add" | "remove">[];
55
- flags?: {
56
- [flag: string]: { description: string; processor?: (value: string) => any };
57
- };
58
- }
59
-
60
- const COMMANDS: CommandConfig<Command>[] = [
61
- {
62
- name: "pull",
63
- description: "Sync copy from Ditto into the current working directory",
64
- flags: {
65
- "--sample-data": {
66
- description: "Include sample data. Currently only supports variants.",
67
- },
68
- },
69
- },
70
- {
71
- name: "project",
72
- description: "Add a Ditto project to sync copy from",
73
- commands: [
74
- {
75
- name: "add",
76
- description: "Add a Ditto project to sync copy from",
77
- },
78
- {
79
- name: "remove",
80
- description: "Stop syncing copy from a Ditto project",
81
- },
82
- ],
83
- },
84
- {
85
- name: "component-folders",
86
- description:
87
- "List component folders in your workspace. More information about component folders can be found here: https://www.dittowords.com/docs/component-folders.",
88
- flags: {
89
- "-s, --sample-data": {
90
- description: "Includes the sample components folder in the output",
91
- },
92
- },
93
- },
94
- {
95
- name: "generate-suggestions",
96
- description: "Find text that can be potentially replaced with Ditto text",
97
- flags: {
98
- "-d, --directory [value]": {
99
- description: "Directory to search for text",
100
- },
101
- "-f, --files [value]": {
102
- description: "Files to search for text (will override -d)",
103
- processor: (value: string) => value.split(","),
104
- },
105
- "-cf, --component-folder [value]": {
106
- description: "Component folder to search for matches",
107
- },
108
- },
109
- },
110
- {
111
- name: "replace",
112
- description: "Find and replace Ditto text with code",
113
- flags: {
114
- "-ln, --line-numbers [value]": {
115
- description: "Only replace text on a specific line number",
116
- processor: (value: string) => value.split(",").map(Number),
117
- },
118
- },
119
- },
120
- {
121
- name: "import-components",
122
- description:
123
- "Import components via a file. For more information please see: https://www.dittowords.com/docs/importing-string-files.",
124
- flags: {
125
- "-t, --text [value]": {
126
- description: "Text column index (.csv format only)",
127
- },
128
- "-n, --component-name [value]": {
129
- description: "Name column indexes (comma separated) (.csv format only)",
130
- },
131
- "-no, --notes [value]": {
132
- description: "Notes column index (.csv format only)",
133
- },
134
- "-t, --tags [value]": {
135
- description: "Tags column index (.csv format only)",
136
- },
137
- "-s, --status [value]": {
138
- description: "Status column index (.csv format only)",
139
- },
140
- "-c, --component-id [value]": {
141
- description: "Component ID column index (.csv format only)",
142
- },
143
- },
144
- },
145
- ];
146
-
147
- const setupCommands = () => {
148
- program.name("ditto-cli");
149
-
150
- COMMANDS.forEach((commandConfig) => {
151
- const cmd = program
152
- .command(commandConfig.name)
153
- .description(commandConfig.description)
154
- .action((options) => {
155
- return executeCommand(commandConfig.name, options);
156
- });
157
-
158
- if (commandConfig.flags) {
159
- Object.entries(commandConfig.flags).forEach(
160
- ([flags, { description, processor }]) => {
161
- if (processor) {
162
- cmd.option(flags, description, processor);
163
- } else {
164
- cmd.option(flags, description);
165
- }
166
- }
167
- );
168
- }
169
-
170
- if ("commands" in commandConfig && commandConfig.commands) {
171
- commandConfig.commands.forEach((nestedCommand) => {
172
- cmd
173
- .command(nestedCommand.name)
174
- .description(nestedCommand.description)
175
- .action((str, options) => {
176
- if (commandConfig.name === "project") {
177
- const command =
178
- `${commandConfig.name} ${nestedCommand.name}` as Command;
179
-
180
- return executeCommand(command, options);
181
- }
182
- });
183
- });
184
- }
185
- });
186
- };
187
-
188
- const setupOptions = () => {
189
- program.option(
190
- "-m, --meta <data...>",
191
- "Include arbitrary data in requests to the Ditto API. Ex: -m githubActionRequest:true trigger:manual"
192
- );
193
- program.version(VERSION, "-v, --version", "Output the current version");
194
- };
195
-
196
- const executeCommand = async (
197
- command: Command | "none",
198
- options: any
199
- ): Promise<void> => {
200
- const needsInitialization =
201
- CONFIG_FILE_RELIANT_COMMANDS.includes(command) && needsTokenOrSource();
202
-
203
- if (needsInitialization) {
204
- try {
205
- await init();
206
- } catch (error) {
207
- await quit("Exiting Ditto CLI...");
208
- return;
209
- }
210
- }
211
-
212
- const { meta } = program.opts();
213
- switch (command) {
214
- case "none":
215
- case "pull": {
216
- return pull({
217
- meta: processMetaOption(meta),
218
- includeSampleData: options.sampleData || false,
219
- });
220
- }
221
- case "project":
222
- case "project add": {
223
- // initialization already includes the selection of a source,
224
- // so if `project add` is called during initialization, don't
225
- // prompt the user to select a source again
226
- if (needsInitialization) return;
227
-
228
- return addProject();
229
- }
230
- case "project remove": {
231
- return removeProject();
232
- }
233
- case "component-folders": {
234
- return showComponentFolders({
235
- showSampleData: options.sampleData,
236
- });
237
- }
238
- case "generate-suggestions": {
239
- return generateSuggestions({
240
- directory: options.directory,
241
- files: options.files,
242
- componentFolder: options.componentFolder,
243
- });
244
- }
245
- case "replace": {
246
- return replace(options.args, {
247
- ...(options?.lineNumbers ? { lineNumbers: options.lineNumbers } : {}),
248
- });
249
- }
250
- case "import-components": {
251
- if (options.args.length === 0) {
252
- console.info("Please provide a file path.");
253
- return;
254
- }
255
- return importComponents(options.args[0], {
256
- csvColumnMapping: {
257
- name: options.componentName,
258
- text: options.text,
259
- notes: options.notes,
260
- tags: options.tags,
261
- status: options.status,
262
- componentId: options.componentId,
263
- },
264
- });
265
- }
266
- default: {
267
- await quit("Exiting Ditto CLI...");
268
- return;
269
- }
270
- }
271
- };
272
-
273
- const main = async () => {
274
- setupCommands();
275
- setupOptions();
276
-
277
- if (process.argv.length <= 2 && process.argv[1].includes("ditto-cli")) {
278
- await executeCommand("none", []);
279
- return;
280
- }
281
-
282
- program.parse(process.argv);
283
- };
284
-
285
- main();