@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.
- package/README.md +150 -141
- package/bin/add-project.js +5 -7
- package/bin/add-project.js.map +1 -1
- package/bin/config.js +37 -11
- package/bin/config.js.map +1 -1
- package/bin/ditto.js +82 -57
- package/bin/ditto.js.map +1 -1
- package/bin/generate-suggestions.js +71 -0
- package/bin/generate-suggestions.js.map +1 -0
- package/bin/http/fetchComponents.js +13 -0
- package/bin/http/fetchComponents.js.map +1 -0
- package/bin/http/fetchVariants.js +26 -0
- package/bin/http/fetchVariants.js.map +1 -0
- package/bin/init/init.js +17 -6
- package/bin/init/init.js.map +1 -1
- package/bin/init/project.js +38 -45
- package/bin/init/project.js.map +1 -1
- package/bin/init/token.js +22 -20
- package/bin/init/token.js.map +1 -1
- package/bin/pull.js +136 -193
- package/bin/pull.js.map +1 -1
- package/bin/remove-project.js +2 -7
- package/bin/remove-project.js.map +1 -1
- package/bin/replace.js +107 -0
- package/bin/replace.js.map +1 -0
- package/bin/utils/cleanFileName.js +11 -0
- package/bin/utils/cleanFileName.js.map +1 -0
- package/bin/utils/generateJsDriver.js +56 -0
- package/bin/utils/generateJsDriver.js.map +1 -0
- package/bin/utils/getSelectedProjects.js +3 -18
- package/bin/utils/getSelectedProjects.js.map +1 -1
- package/bin/utils/projectsToText.js +10 -1
- package/bin/utils/projectsToText.js.map +1 -1
- package/bin/utils/promptForProject.js +2 -3
- package/bin/utils/promptForProject.js.map +1 -1
- package/bin/utils/quit.js +10 -0
- package/bin/utils/quit.js.map +1 -0
- package/lib/add-project.ts +6 -9
- package/lib/config.ts +56 -19
- package/lib/ditto.ts +111 -60
- package/lib/generate-suggestions.test.ts +65 -0
- package/lib/generate-suggestions.ts +107 -0
- package/lib/http/fetchComponents.ts +14 -0
- package/lib/http/fetchVariants.ts +30 -0
- package/lib/init/init.ts +38 -6
- package/lib/init/project.test.ts +3 -3
- package/lib/init/project.ts +47 -58
- package/lib/init/token.ts +17 -16
- package/lib/pull.ts +199 -279
- package/lib/remove-project.ts +2 -8
- package/lib/replace.test.ts +101 -0
- package/lib/replace.ts +106 -0
- package/lib/types.ts +22 -3
- package/lib/utils/cleanFileName.ts +6 -0
- package/lib/utils/generateJsDriver.ts +68 -0
- package/lib/utils/getSelectedProjects.ts +5 -24
- package/lib/utils/projectsToText.ts +11 -1
- package/lib/utils/promptForProject.ts +2 -3
- package/lib/utils/quit.ts +5 -0
- package/package.json +9 -2
- 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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
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(
|
|
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":"
|
|
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;
|
|
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"}
|
package/lib/add-project.ts
CHANGED
|
@@ -1,16 +1,11 @@
|
|
|
1
|
-
import {
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
30
|
-
arr
|
|
31
|
-
(
|
|
32
|
-
|
|
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:
|
|
77
|
-
createFileIfMissing(file);
|
|
92
|
+
function writeProjectConfigData(file: string, data: Partial<ConfigYAML>) {
|
|
93
|
+
createFileIfMissing(file, DEFAULT_CONFIG);
|
|
78
94
|
const existingData = readProjectConfigData(file);
|
|
79
|
-
|
|
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 {
|
|
165
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
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
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
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
|
-
"
|
|
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
|
|
57
|
-
|
|
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
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
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
|
|
90
|
-
|
|
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
|
+
});
|