@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.
- package/README.md +6 -5
- package/bin/ditto.js +110 -285
- package/package.json +16 -10
- package/.github/actions/install-node-dependencies/action.yml +0 -24
- package/.github/workflows/required-checks.yml +0 -24
- package/.husky/pre-commit +0 -4
- package/.prettierignore +0 -0
- package/.prettierrc.json +0 -1
- package/__mocks__/fs.js +0 -2
- package/babel.config.js +0 -6
- package/bin/__mocks__/api.js +0 -48
- package/bin/__mocks__/api.js.map +0 -1
- package/bin/add-project.js +0 -104
- package/bin/add-project.js.map +0 -1
- package/bin/api.js +0 -54
- package/bin/api.js.map +0 -1
- package/bin/component-folders.js +0 -59
- package/bin/component-folders.js.map +0 -1
- package/bin/config.js +0 -242
- package/bin/config.js.map +0 -1
- package/bin/config.test.js +0 -93
- package/bin/config.test.js.map +0 -1
- package/bin/consts.js +0 -57
- package/bin/consts.js.map +0 -1
- package/bin/ditto.js.map +0 -1
- package/bin/generate-suggestions.js +0 -183
- package/bin/generate-suggestions.js.map +0 -1
- package/bin/generate-suggestions.test.js +0 -200
- package/bin/generate-suggestions.test.js.map +0 -1
- package/bin/http/__mocks__/fetchComponentFolders.js +0 -71
- package/bin/http/__mocks__/fetchComponentFolders.js.map +0 -1
- package/bin/http/__mocks__/fetchComponents.js +0 -73
- package/bin/http/__mocks__/fetchComponents.js.map +0 -1
- package/bin/http/__mocks__/fetchVariants.js +0 -71
- package/bin/http/__mocks__/fetchVariants.js.map +0 -1
- package/bin/http/fetchComponentFolders.js +0 -64
- package/bin/http/fetchComponentFolders.js.map +0 -1
- package/bin/http/fetchComponents.js +0 -78
- package/bin/http/fetchComponents.js.map +0 -1
- package/bin/http/fetchVariants.js +0 -87
- package/bin/http/fetchVariants.js.map +0 -1
- package/bin/http/http.test.js +0 -159
- package/bin/http/http.test.js.map +0 -1
- package/bin/http/importComponents.js +0 -114
- package/bin/http/importComponents.js.map +0 -1
- package/bin/importComponents.js +0 -65
- package/bin/importComponents.js.map +0 -1
- package/bin/init/init.js +0 -126
- package/bin/init/init.js.map +0 -1
- package/bin/init/project.js +0 -182
- package/bin/init/project.js.map +0 -1
- package/bin/init/project.test.js +0 -26
- package/bin/init/project.test.js.map +0 -1
- package/bin/init/token.js +0 -196
- package/bin/init/token.js.map +0 -1
- package/bin/init/token.test.js +0 -147
- package/bin/init/token.test.js.map +0 -1
- package/bin/output.js +0 -76
- package/bin/output.js.map +0 -1
- package/bin/pull-lib.test.js +0 -379
- package/bin/pull-lib.test.js.map +0 -1
- package/bin/pull.js +0 -562
- package/bin/pull.js.map +0 -1
- package/bin/pull.test.js +0 -151
- package/bin/pull.test.js.map +0 -1
- package/bin/remove-project.js +0 -99
- package/bin/remove-project.js.map +0 -1
- package/bin/replace.js +0 -171
- package/bin/replace.js.map +0 -1
- package/bin/replace.test.js +0 -197
- package/bin/replace.test.js.map +0 -1
- package/bin/types.js +0 -21
- package/bin/types.js.map +0 -1
- package/bin/utils/cleanFileName.js +0 -40
- package/bin/utils/cleanFileName.js.map +0 -1
- package/bin/utils/cleanFileName.test.js +0 -15
- package/bin/utils/cleanFileName.test.js.map +0 -1
- package/bin/utils/createSentryContext.js +0 -43
- package/bin/utils/createSentryContext.js.map +0 -1
- package/bin/utils/determineModuleType.js +0 -79
- package/bin/utils/determineModuleType.js.map +0 -1
- package/bin/utils/determineModuleType.test.js +0 -60
- package/bin/utils/determineModuleType.test.js.map +0 -1
- package/bin/utils/generateIOSBundles.js +0 -147
- package/bin/utils/generateIOSBundles.js.map +0 -1
- package/bin/utils/generateJsDriver.js +0 -178
- package/bin/utils/generateJsDriver.js.map +0 -1
- package/bin/utils/generateJsDriverTypeFile.js +0 -105
- package/bin/utils/generateJsDriverTypeFile.js.map +0 -1
- package/bin/utils/generateSwiftDriver.js +0 -93
- package/bin/utils/generateSwiftDriver.js.map +0 -1
- package/bin/utils/getSelectedProjects.js +0 -67
- package/bin/utils/getSelectedProjects.js.map +0 -1
- package/bin/utils/processMetaOption.js +0 -40
- package/bin/utils/processMetaOption.js.map +0 -1
- package/bin/utils/processMetaOption.test.js +0 -45
- package/bin/utils/processMetaOption.test.js.map +0 -1
- package/bin/utils/projectsToText.js +0 -58
- package/bin/utils/projectsToText.js.map +0 -1
- package/bin/utils/promptForProject.js +0 -96
- package/bin/utils/promptForProject.js.map +0 -1
- package/bin/utils/quit.js +0 -73
- package/bin/utils/quit.js.map +0 -1
- package/bin/utils/sourcesToText.js +0 -57
- package/bin/utils/sourcesToText.js.map +0 -1
- package/etsc.config.js +0 -13
- package/jest.config.ts +0 -16
- package/jsconfig.json +0 -5
- package/lib/__mocks__/api.ts +0 -12
- package/lib/add-project.ts +0 -48
- package/lib/api.ts +0 -16
- package/lib/component-folders.ts +0 -9
- package/lib/config.test.ts +0 -79
- package/lib/config.ts +0 -279
- package/lib/consts.ts +0 -22
- package/lib/ditto.ts +0 -285
- package/lib/generate-suggestions.test.ts +0 -169
- package/lib/generate-suggestions.ts +0 -166
- package/lib/http/__mocks__/fetchComponentFolders.ts +0 -23
- package/lib/http/__mocks__/fetchComponents.ts +0 -24
- package/lib/http/__mocks__/fetchVariants.ts +0 -21
- package/lib/http/fetchComponentFolders.ts +0 -23
- package/lib/http/fetchComponents.ts +0 -43
- package/lib/http/fetchVariants.ts +0 -42
- package/lib/http/http.test.ts +0 -122
- package/lib/http/importComponents.ts +0 -79
- package/lib/importComponents.ts +0 -24
- package/lib/init/init.ts +0 -79
- package/lib/init/project.test.ts +0 -26
- package/lib/init/project.ts +0 -136
- package/lib/init/token.test.ts +0 -99
- package/lib/init/token.ts +0 -156
- package/lib/output.ts +0 -21
- package/lib/pull-lib.test.ts +0 -367
- package/lib/pull.test.ts +0 -117
- package/lib/pull.ts +0 -629
- package/lib/remove-project.ts +0 -44
- package/lib/replace.test.ts +0 -157
- package/lib/replace.ts +0 -140
- package/lib/types.ts +0 -83
- package/lib/utils/cleanFileName.test.ts +0 -11
- package/lib/utils/cleanFileName.ts +0 -8
- package/lib/utils/createSentryContext.ts +0 -20
- package/lib/utils/determineModuleType.test.ts +0 -48
- package/lib/utils/determineModuleType.ts +0 -55
- package/lib/utils/generateIOSBundles.ts +0 -122
- package/lib/utils/generateJsDriver.ts +0 -207
- package/lib/utils/generateJsDriverTypeFile.ts +0 -75
- package/lib/utils/generateSwiftDriver.ts +0 -48
- package/lib/utils/getSelectedProjects.ts +0 -36
- package/lib/utils/processMetaOption.test.ts +0 -18
- package/lib/utils/processMetaOption.ts +0 -16
- package/lib/utils/projectsToText.ts +0 -29
- package/lib/utils/promptForProject.ts +0 -61
- package/lib/utils/quit.ts +0 -7
- package/lib/utils/sourcesToText.ts +0 -25
- package/pull_request_template.md +0 -20
- package/testfiles/en.json +0 -5
- package/testfiles/es.json +0 -5
- package/testfiles/fr.json +0 -5
- package/testfiles/test1.jsx +0 -18
- package/testfiles/test2.jsx +0 -9
- package/testing/.gitkeep +0 -0
- package/testing/fixtures/bad-yaml.yml +0 -6
- package/testing/fixtures/ditto-config-no-token +0 -2
- package/testing/fixtures/project-config-empty-projects.yml +0 -1
- package/testing/fixtures/project-config-no-id.yml +0 -2
- package/testing/fixtures/project-config-no-name.yml +0 -2
- package/testing/fixtures/project-config-pull.yml +0 -0
- package/testing/fixtures/project-config-working.yml +0 -3
- 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();
|