@dittowords/cli 2.5.0 → 2.5.2
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 +14 -7
- package/babel.config.js +2 -8
- package/bin/add-project.js +38 -0
- package/bin/add-project.js.map +1 -0
- package/bin/api.js +20 -0
- package/bin/api.js.map +1 -0
- package/bin/config.js +174 -0
- package/bin/config.js.map +1 -0
- package/bin/consts.js +21 -0
- package/bin/consts.js.map +1 -0
- package/bin/ditto.js +71 -74
- package/bin/ditto.js.map +1 -0
- package/bin/init/init.js +39 -0
- package/bin/init/init.js.map +1 -0
- package/bin/init/project.js +115 -0
- package/bin/init/project.js.map +1 -0
- package/bin/init/token.js +89 -0
- package/bin/init/token.js.map +1 -0
- package/bin/output.js +34 -0
- package/bin/output.js.map +1 -0
- package/bin/pull.js +288 -0
- package/bin/pull.js.map +1 -0
- package/bin/remove-project.js +40 -0
- package/bin/remove-project.js.map +1 -0
- package/bin/types.js +3 -0
- package/bin/types.js.map +1 -0
- package/bin/utils/getSelectedProjects.js +76 -0
- package/bin/utils/getSelectedProjects.js.map +1 -0
- package/bin/utils/processMetaOption.js +15 -0
- package/bin/utils/processMetaOption.js.map +1 -0
- package/bin/utils/projectsToText.js +16 -0
- package/bin/utils/projectsToText.js.map +1 -0
- package/bin/utils/promptForProject.js +44 -0
- package/bin/utils/promptForProject.js.map +1 -0
- package/bin/utils/sourcesToText.js +25 -0
- package/bin/utils/sourcesToText.js.map +1 -0
- package/jest.config.js +1 -1
- package/lib/add-project.ts +51 -0
- package/lib/api.ts +15 -0
- package/lib/{config.test.js → config.test.ts} +14 -25
- package/lib/config.ts +214 -0
- package/lib/consts.ts +20 -0
- package/lib/ditto.ts +97 -0
- package/lib/init/{init.js → init.ts} +11 -12
- package/lib/init/project.test.ts +49 -0
- package/lib/init/{project.js → project.ts} +58 -32
- package/lib/init/{token.test.js → token.test.ts} +3 -3
- package/lib/init/{token.js → token.ts} +23 -19
- package/lib/output.ts +21 -0
- package/lib/pull.test.ts +142 -0
- package/lib/{pull.js → pull.ts} +119 -92
- package/lib/remove-project.ts +50 -0
- package/lib/types.ts +23 -0
- package/lib/utils/getSelectedProjects.ts +55 -0
- package/lib/utils/processMetaOption.test.ts +18 -0
- package/lib/utils/processMetaOption.ts +16 -0
- package/lib/utils/{projectsToText.js → projectsToText.ts} +5 -4
- package/lib/utils/{promptForProject.js → promptForProject.ts} +18 -9
- package/lib/utils/{sourcesToText.js → sourcesToText.ts} +6 -5
- package/package.json +20 -15
- package/testing/fixtures/project-config-pull.yml +0 -0
- package/tsconfig.json +12 -0
- package/lib/add-project.js +0 -30
- package/lib/api.js +0 -18
- package/lib/config.js +0 -169
- package/lib/consts.js +0 -14
- package/lib/init/project.test.js +0 -99
- package/lib/output.js +0 -21
- package/lib/pull.test.js +0 -173
- package/lib/remove-project.js +0 -39
- package/lib/utils/getSelectedProjects.js +0 -35
- package/lib/utils/processMetaOption.js +0 -16
- package/lib/utils/processMetaOption.test.js +0 -16
package/lib/add-project.js
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
const { collectAndSaveProject } = require("./init/project");
|
|
2
|
-
const projectsToText = require("./utils/projectsToText");
|
|
3
|
-
const getSelectedProjects = require("./utils/getSelectedProjects");
|
|
4
|
-
|
|
5
|
-
function quit(exitCode = 2) {
|
|
6
|
-
console.log("Project selection was not updated.");
|
|
7
|
-
process.exitCode = exitCode;
|
|
8
|
-
process.exit();
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
const addProject = async () => {
|
|
12
|
-
const projects = getSelectedProjects();
|
|
13
|
-
|
|
14
|
-
try {
|
|
15
|
-
console.log(
|
|
16
|
-
`\nYou're currently set up to sync text from the following projects: ${projectsToText(
|
|
17
|
-
projects
|
|
18
|
-
)}`
|
|
19
|
-
);
|
|
20
|
-
await collectAndSaveProject(false);
|
|
21
|
-
} catch (error) {
|
|
22
|
-
console.log(
|
|
23
|
-
`\nSorry, there was an error adding a project to your workspace: `,
|
|
24
|
-
error
|
|
25
|
-
);
|
|
26
|
-
quit();
|
|
27
|
-
}
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
module.exports = addProject;
|
package/lib/api.js
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
const axios = require("axios").default;
|
|
2
|
-
|
|
3
|
-
const config = require("./config");
|
|
4
|
-
const consts = require("./consts");
|
|
5
|
-
|
|
6
|
-
function create(token) {
|
|
7
|
-
return axios.create({
|
|
8
|
-
baseURL: consts.API_HOST,
|
|
9
|
-
headers: {
|
|
10
|
-
Authorization: `token ${token}`,
|
|
11
|
-
},
|
|
12
|
-
});
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
module.exports = { create };
|
|
16
|
-
module.exports.default = create(
|
|
17
|
-
config.getToken(consts.CONFIG_FILE, consts.API_HOST)
|
|
18
|
-
);
|
package/lib/config.js
DELETED
|
@@ -1,169 +0,0 @@
|
|
|
1
|
-
const fs = require("fs");
|
|
2
|
-
const path = require("path");
|
|
3
|
-
const url = require("url");
|
|
4
|
-
const yaml = require("js-yaml");
|
|
5
|
-
|
|
6
|
-
const consts = require("./consts");
|
|
7
|
-
|
|
8
|
-
function createFileIfMissing(filename) {
|
|
9
|
-
const dir = path.dirname(filename);
|
|
10
|
-
|
|
11
|
-
if (!fs.existsSync(dir)) fs.mkdirSync(dir);
|
|
12
|
-
|
|
13
|
-
if (!fs.existsSync(filename)) {
|
|
14
|
-
fs.closeSync(fs.openSync(filename, "w"));
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Read data from a file
|
|
20
|
-
* @param {string} file defaults to `PROJECT_CONFIG_FILE` defined in `constants.js`
|
|
21
|
-
* @param {*} defaultData defaults to `{}`
|
|
22
|
-
* @returns
|
|
23
|
-
*/
|
|
24
|
-
function readData(file = consts.PROJECT_CONFIG_FILE, defaultData = {}) {
|
|
25
|
-
createFileIfMissing(file);
|
|
26
|
-
const fileContents = fs.readFileSync(file, "utf8");
|
|
27
|
-
return yaml.safeLoad(fileContents) || defaultData;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function writeData(file, data) {
|
|
31
|
-
createFileIfMissing(file);
|
|
32
|
-
const existingData = readData(file);
|
|
33
|
-
const yamlStr = yaml.safeDump({ ...existingData, ...data });
|
|
34
|
-
fs.writeFileSync(file, yamlStr, "utf8");
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
function justTheHost(host) {
|
|
38
|
-
if (!host.includes("://")) return host;
|
|
39
|
-
return url.parse(host).hostname;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function deleteToken(file, host) {
|
|
43
|
-
const data = readData(file);
|
|
44
|
-
const hostParsed = justTheHost(host);
|
|
45
|
-
data[hostParsed] = [];
|
|
46
|
-
data[hostParsed][0] = {};
|
|
47
|
-
data[hostParsed][0].token = "";
|
|
48
|
-
writeData(file, data);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
function saveToken(file, host, token) {
|
|
52
|
-
const data = readData(file);
|
|
53
|
-
const hostParsed = justTheHost(host);
|
|
54
|
-
data[hostParsed] = []; // only allow one token per host
|
|
55
|
-
data[hostParsed][0] = {};
|
|
56
|
-
data[hostParsed][0].token = token;
|
|
57
|
-
writeData(file, data);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
function getTokenFromEnv() {
|
|
61
|
-
return process.env.DITTO_API_KEY;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
function getToken(file, host) {
|
|
65
|
-
const tokenFromEnv = getTokenFromEnv();
|
|
66
|
-
if (tokenFromEnv) {
|
|
67
|
-
return tokenFromEnv;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
const data = readData(file);
|
|
71
|
-
const hostEntry = data[justTheHost(host)];
|
|
72
|
-
if (!hostEntry) return undefined;
|
|
73
|
-
const { length } = hostEntry;
|
|
74
|
-
return hostEntry[length - 1].token;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
function save(file, key, value) {
|
|
78
|
-
const data = readData(file);
|
|
79
|
-
let current = data;
|
|
80
|
-
const parts = key.split(".");
|
|
81
|
-
parts.slice(0, -1).forEach((part) => {
|
|
82
|
-
if (!(part in current)) {
|
|
83
|
-
current[part] = {};
|
|
84
|
-
current = current[part];
|
|
85
|
-
}
|
|
86
|
-
});
|
|
87
|
-
current[parts.slice(-1)] = value;
|
|
88
|
-
writeData(file, data);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
const IS_DUPLICATE = /-(\d+$)/;
|
|
92
|
-
function dedupeProjectName(projectNames, projectName) {
|
|
93
|
-
let dedupedName = projectName;
|
|
94
|
-
|
|
95
|
-
if (projectNames.has(dedupedName)) {
|
|
96
|
-
while (projectNames.has(dedupedName)) {
|
|
97
|
-
const [_, numberStr] = dedupedName.match(IS_DUPLICATE) || [];
|
|
98
|
-
if (numberStr && !isNaN(parseInt(numberStr))) {
|
|
99
|
-
dedupedName = `${dedupedName.replace(IS_DUPLICATE, "")}-${
|
|
100
|
-
parseInt(numberStr) + 1
|
|
101
|
-
}`;
|
|
102
|
-
} else {
|
|
103
|
-
dedupedName = `${dedupedName}-1`;
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
return dedupedName;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Reads from the config file, filters out
|
|
113
|
-
* invalid projects, dedupes those remaining, and returns:
|
|
114
|
-
* - whether or not the data required to `pull` is present
|
|
115
|
-
* - whether or not the component library should be fetched
|
|
116
|
-
* - an array of valid, deduped projects
|
|
117
|
-
* - the `variants` and `format` config options
|
|
118
|
-
*/
|
|
119
|
-
function parseSourceInformation() {
|
|
120
|
-
const { projects, components, variants, format } = readData();
|
|
121
|
-
|
|
122
|
-
const projectNames = new Set();
|
|
123
|
-
const validProjects = [];
|
|
124
|
-
|
|
125
|
-
let componentLibraryInProjects = false;
|
|
126
|
-
|
|
127
|
-
(projects || []).forEach((project) => {
|
|
128
|
-
const isValid = project.id && project.name;
|
|
129
|
-
if (!isValid) {
|
|
130
|
-
return;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
if (project.id === "ditto_component_library") {
|
|
134
|
-
componentLibraryInProjects = true;
|
|
135
|
-
return;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
project.fileName = dedupeProjectName(projectNames, project.name);
|
|
139
|
-
projectNames.add(project.fileName);
|
|
140
|
-
|
|
141
|
-
validProjects.push(project);
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
const shouldFetchComponentLibrary =
|
|
145
|
-
!!components || componentLibraryInProjects;
|
|
146
|
-
|
|
147
|
-
const hasSourceData = validProjects.length || shouldFetchComponentLibrary;
|
|
148
|
-
|
|
149
|
-
return {
|
|
150
|
-
hasSourceData,
|
|
151
|
-
validProjects,
|
|
152
|
-
shouldFetchComponentLibrary,
|
|
153
|
-
variants,
|
|
154
|
-
format,
|
|
155
|
-
};
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
module.exports = {
|
|
159
|
-
createFileIfMissing,
|
|
160
|
-
readData,
|
|
161
|
-
writeData,
|
|
162
|
-
justTheHost,
|
|
163
|
-
saveToken,
|
|
164
|
-
deleteToken,
|
|
165
|
-
getToken,
|
|
166
|
-
getTokenFromEnv,
|
|
167
|
-
save,
|
|
168
|
-
parseSourceInformation,
|
|
169
|
-
};
|
package/lib/consts.js
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
const homedir = require("os").homedir();
|
|
2
|
-
const path = require("path");
|
|
3
|
-
|
|
4
|
-
const TEXT_DIR = process.env.DITTO_TEXT_DIR || "ditto"
|
|
5
|
-
|
|
6
|
-
module.exports.API_HOST =
|
|
7
|
-
process.env.DITTO_API_HOST || "https://api.dittowords.com";
|
|
8
|
-
module.exports.CONFIG_FILE =
|
|
9
|
-
process.env.DITTO_CONFIG_FILE || path.join(homedir, ".config", "ditto");
|
|
10
|
-
module.exports.PROJECT_CONFIG_FILE = path.normalize(
|
|
11
|
-
path.join("ditto", "config.yml")
|
|
12
|
-
);
|
|
13
|
-
module.exports.TEXT_DIR = TEXT_DIR
|
|
14
|
-
module.exports.TEXT_FILE = path.normalize(path.join(TEXT_DIR, "text.json"));
|
package/lib/init/project.test.js
DELETED
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
const fs = require("fs");
|
|
2
|
-
const path = require("path");
|
|
3
|
-
|
|
4
|
-
const rewire = require("rewire");
|
|
5
|
-
const yaml = require("js-yaml");
|
|
6
|
-
const { createFileIfMissing } = require("../config");
|
|
7
|
-
|
|
8
|
-
const project = rewire("./project");
|
|
9
|
-
|
|
10
|
-
const { needsProject } = project;
|
|
11
|
-
|
|
12
|
-
const saveProject = project.__get__("saveProject");
|
|
13
|
-
const parseResponse = project.__get__("parseResponse");
|
|
14
|
-
|
|
15
|
-
const fakeProjectDir = path.join(__dirname, "../../testing/tmp");
|
|
16
|
-
const badYaml = path.join(__dirname, "../../testing/fixtures/bad-yaml.yml");
|
|
17
|
-
const configEmptyProjects = path.join(
|
|
18
|
-
__dirname,
|
|
19
|
-
"../../testing/fixtures/bad-yaml.yml"
|
|
20
|
-
);
|
|
21
|
-
const configMissingName = path.join(
|
|
22
|
-
__dirname,
|
|
23
|
-
"../../testing/fixtures/project-config-no-name.yml"
|
|
24
|
-
);
|
|
25
|
-
const configMissingId = path.join(
|
|
26
|
-
__dirname,
|
|
27
|
-
"../../testing/fixtures/project-config-no-id.yml"
|
|
28
|
-
);
|
|
29
|
-
const configLegit = path.join(
|
|
30
|
-
__dirname,
|
|
31
|
-
"../../testing/fixtures/project-config-working.yml"
|
|
32
|
-
);
|
|
33
|
-
|
|
34
|
-
describe("saveProject", () => {
|
|
35
|
-
const configFile = path.join(fakeProjectDir, "ditto/config.yml");
|
|
36
|
-
const projectName = "My Amazing Project";
|
|
37
|
-
const projectId = "5f284259ce1d451b2eb2e23c";
|
|
38
|
-
|
|
39
|
-
beforeEach(() => {
|
|
40
|
-
if (!fs.existsSync(fakeProjectDir)) fs.mkdirSync(fakeProjectDir);
|
|
41
|
-
saveProject(configFile, projectName, projectId);
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
afterEach(() => {
|
|
45
|
-
fs.rmdirSync(fakeProjectDir, { recursive: true });
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
it("creates a config file with config data", () => {
|
|
49
|
-
const fileContents = fs.readFileSync(configFile, "utf8");
|
|
50
|
-
const data = yaml.safeLoad(fileContents);
|
|
51
|
-
expect(data.projects).toBeDefined();
|
|
52
|
-
expect(data.projects[0].name).toEqual(projectName);
|
|
53
|
-
expect(data.projects[0].id).toEqual(projectId);
|
|
54
|
-
});
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
describe("needsProject()", () => {
|
|
58
|
-
const configFile = path.join(fakeProjectDir, "ditto/config.yml");
|
|
59
|
-
it("is true if there is no existing config file", () => {
|
|
60
|
-
expect(needsProject(configFile)).toBeTruthy();
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
describe("with a file that exists", () => {
|
|
64
|
-
beforeEach(() => {
|
|
65
|
-
if (!fs.existsSync(fakeProjectDir)) fs.mkdirSync(fakeProjectDir);
|
|
66
|
-
createFileIfMissing(configFile);
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
it("is true if the file has no projects", () => {
|
|
70
|
-
expect(needsProject(configFile)).toBeTruthy();
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
it.each([
|
|
74
|
-
["the file is bad yaml", badYaml],
|
|
75
|
-
["no entries exist under projects", configEmptyProjects],
|
|
76
|
-
["an entry exists without a name", configMissingName],
|
|
77
|
-
["an entry exists without an id", configMissingId],
|
|
78
|
-
])("is true if %s", (_msg, file) => {
|
|
79
|
-
expect(fs.existsSync(file)).toBeTruthy();
|
|
80
|
-
expect(needsProject(file)).toBeTruthy();
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
it("is false if a file exists with a propper project", () => {
|
|
84
|
-
expect(fs.existsSync(configLegit)).toBeTruthy();
|
|
85
|
-
expect(needsProject(configLegit)).toBeFalsy();
|
|
86
|
-
});
|
|
87
|
-
});
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
describe("parseResponse", () => {
|
|
91
|
-
const result =
|
|
92
|
-
"Large file test [90mhttp://localhost:3000/doc/5ea120d8b56b315ffddb0ef8[39m";
|
|
93
|
-
it("returns the id, name for a project result", () => {
|
|
94
|
-
expect(parseResponse(result)).toEqual({
|
|
95
|
-
id: "5ea120d8b56b315ffddb0ef8",
|
|
96
|
-
name: "Large file test",
|
|
97
|
-
});
|
|
98
|
-
});
|
|
99
|
-
});
|
package/lib/output.js
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
const chalk = require("chalk");
|
|
2
|
-
|
|
3
|
-
const errorText = (msg) => chalk.magenta(msg);
|
|
4
|
-
const warnText = (msg) => chalk.yellow(msg);
|
|
5
|
-
const info = (msg) => chalk.blueBright(msg);
|
|
6
|
-
const success = (msg) => chalk.green(msg);
|
|
7
|
-
const url = (msg) => chalk.blueBright.underline(msg);
|
|
8
|
-
const subtle = (msg) => chalk.grey(msg);
|
|
9
|
-
const write = (msg) => chalk.white(msg);
|
|
10
|
-
const nl = () => console.log("\n");
|
|
11
|
-
|
|
12
|
-
module.exports = {
|
|
13
|
-
errorText,
|
|
14
|
-
warnText,
|
|
15
|
-
url,
|
|
16
|
-
info,
|
|
17
|
-
write,
|
|
18
|
-
subtle,
|
|
19
|
-
nl,
|
|
20
|
-
success,
|
|
21
|
-
};
|
package/lib/pull.test.js
DELETED
|
@@ -1,173 +0,0 @@
|
|
|
1
|
-
const fs = require("fs");
|
|
2
|
-
const yaml = require("js-yaml");
|
|
3
|
-
const path = require("path");
|
|
4
|
-
const api = require("./api");
|
|
5
|
-
|
|
6
|
-
const rewire = require("rewire");
|
|
7
|
-
const rewireConfig = rewire("./config");
|
|
8
|
-
rewireConfig.__set__("readData", () => {
|
|
9
|
-
const fileContents = fs.readFileSync(file, "utf8");
|
|
10
|
-
return yaml.safeLoad(fileContents) || defaultData;
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
jest.mock("./api");
|
|
14
|
-
api.default.get.mockResolvedValue({ data: [] });
|
|
15
|
-
|
|
16
|
-
jest.mock("./consts", () => ({
|
|
17
|
-
TEXT_DIR: ".testing",
|
|
18
|
-
API_HOST: "https://api.dittowords.com",
|
|
19
|
-
CONFIG_FILE: ".testing/ditto",
|
|
20
|
-
PROJECT_CONFIG_FILE: ".testing/config.yml",
|
|
21
|
-
TEXT_FILE: ".testing/text.json",
|
|
22
|
-
TEXT_DIR: ".testing",
|
|
23
|
-
}));
|
|
24
|
-
|
|
25
|
-
const consts = require("./consts");
|
|
26
|
-
const {
|
|
27
|
-
pull,
|
|
28
|
-
_testing: {
|
|
29
|
-
cleanOutputFiles,
|
|
30
|
-
getProjectsWithDedupedNames,
|
|
31
|
-
downloadAndSaveVariant,
|
|
32
|
-
downloadAndSaveBase,
|
|
33
|
-
},
|
|
34
|
-
} = require("./pull");
|
|
35
|
-
|
|
36
|
-
const testProjects = [
|
|
37
|
-
{
|
|
38
|
-
id: 1,
|
|
39
|
-
name: "Project 1",
|
|
40
|
-
},
|
|
41
|
-
{ id: 2, name: "Project 2" },
|
|
42
|
-
];
|
|
43
|
-
const variant = "english";
|
|
44
|
-
|
|
45
|
-
const cleanOutputDir = () => {
|
|
46
|
-
if (fs.existsSync(consts.TEXT_DIR))
|
|
47
|
-
fs.rmdirSync(consts.TEXT_DIR, { force: true, recursive: true });
|
|
48
|
-
|
|
49
|
-
fs.mkdirSync(consts.TEXT_DIR);
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
afterAll(() => {
|
|
53
|
-
fs.rmdirSync(consts.TEXT_DIR, { force: true, recursive: true });
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
describe("cleanOutputFiles", () => {
|
|
57
|
-
it("removes .js and .json files", () => {
|
|
58
|
-
cleanOutputDir();
|
|
59
|
-
|
|
60
|
-
fs.writeFileSync(path.resolve(consts.TEXT_DIR, "test.json"), "test");
|
|
61
|
-
fs.writeFileSync(path.resolve(consts.TEXT_DIR, "test.js"), "test");
|
|
62
|
-
// this file shouldn't be deleted
|
|
63
|
-
fs.writeFileSync(path.resolve(consts.TEXT_DIR, "test.txt"), "test");
|
|
64
|
-
|
|
65
|
-
expect(fs.readdirSync(consts.TEXT_DIR).length).toEqual(3);
|
|
66
|
-
|
|
67
|
-
cleanOutputFiles();
|
|
68
|
-
|
|
69
|
-
expect(fs.readdirSync(consts.TEXT_DIR).length).toEqual(1);
|
|
70
|
-
});
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
describe("getProjectsWithDedupedNames", () => {
|
|
74
|
-
it("dedupes projects with the same name", () => {
|
|
75
|
-
const projects = [
|
|
76
|
-
{ id: 1, name: "project" },
|
|
77
|
-
{ id: 2, name: "project" },
|
|
78
|
-
{ id: 3, name: "project" },
|
|
79
|
-
{ id: 4, name: "project-other" },
|
|
80
|
-
];
|
|
81
|
-
|
|
82
|
-
expect(getProjectsWithDedupedNames(projects)).toEqual([
|
|
83
|
-
{ id: 1, name: "project" },
|
|
84
|
-
{ id: 2, name: "project-1" },
|
|
85
|
-
{ id: 3, name: "project-2" },
|
|
86
|
-
{ id: 4, name: "project-other" },
|
|
87
|
-
]);
|
|
88
|
-
});
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
describe("downloadAndSaveVariant", () => {
|
|
92
|
-
beforeAll(() => {
|
|
93
|
-
if (!fs.existsSync(consts.TEXT_DIR)) {
|
|
94
|
-
fs.mkdirSync(consts.TEXT_DIR);
|
|
95
|
-
}
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
it("writes a single file for default format", async () => {
|
|
99
|
-
cleanOutputDir();
|
|
100
|
-
|
|
101
|
-
const output = await downloadAndSaveVariant(variant, testProjects);
|
|
102
|
-
|
|
103
|
-
expect(/saved to.*english\.json/.test(output)).toEqual(true);
|
|
104
|
-
expect(output.match(/saved to/g).length).toEqual(1);
|
|
105
|
-
expect(fs.readdirSync(consts.TEXT_DIR).length).toEqual(1);
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
it("writes multiple files for flat format", async () => {
|
|
109
|
-
cleanOutputDir();
|
|
110
|
-
|
|
111
|
-
const output = await downloadAndSaveVariant(variant, testProjects, "flat");
|
|
112
|
-
|
|
113
|
-
expect(/saved to.*Project 1__english\.json/.test(output)).toEqual(true);
|
|
114
|
-
expect(/saved to.*Project 2__english\.json/.test(output)).toEqual(true);
|
|
115
|
-
expect(output.match(/saved to/g).length).toEqual(2);
|
|
116
|
-
expect(fs.readdirSync(consts.TEXT_DIR).length).toEqual(2);
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
it("writes multiple files for structured format", async () => {
|
|
120
|
-
cleanOutputDir();
|
|
121
|
-
|
|
122
|
-
const output = await downloadAndSaveVariant(
|
|
123
|
-
variant,
|
|
124
|
-
testProjects,
|
|
125
|
-
"structured"
|
|
126
|
-
);
|
|
127
|
-
|
|
128
|
-
expect(/saved to.*Project 1__english\.json/.test(output)).toEqual(true);
|
|
129
|
-
expect(/saved to.*Project 2__english\.json/.test(output)).toEqual(true);
|
|
130
|
-
expect(output.match(/saved to/g).length).toEqual(2);
|
|
131
|
-
expect(fs.readdirSync(consts.TEXT_DIR).length).toEqual(2);
|
|
132
|
-
});
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
describe("downloadAndSaveBase", () => {
|
|
136
|
-
beforeAll(() => {
|
|
137
|
-
if (!fs.existsSync(consts.TEXT_DIR)) {
|
|
138
|
-
fs.mkdirSync(consts.TEXT_DIR);
|
|
139
|
-
}
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
it("writes to text.json for default format", async () => {
|
|
143
|
-
cleanOutputDir();
|
|
144
|
-
|
|
145
|
-
const output = await downloadAndSaveBase(testProjects);
|
|
146
|
-
|
|
147
|
-
expect(/saved to.*text\.json/.test(output)).toEqual(true);
|
|
148
|
-
expect(output.match(/saved to/g).length).toEqual(1);
|
|
149
|
-
expect(fs.readdirSync(consts.TEXT_DIR).length).toEqual(1);
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
it("writes multiple files for flat format", async () => {
|
|
153
|
-
cleanOutputDir();
|
|
154
|
-
|
|
155
|
-
const output = await downloadAndSaveBase(testProjects, "flat");
|
|
156
|
-
|
|
157
|
-
expect(/saved to.*Project 1\.json/.test(output)).toEqual(true);
|
|
158
|
-
expect(/saved to.*Project 2\.json/.test(output)).toEqual(true);
|
|
159
|
-
expect(output.match(/saved to/g).length).toEqual(2);
|
|
160
|
-
expect(fs.readdirSync(consts.TEXT_DIR).length).toEqual(2);
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
it("writes multiple files for structured format", async () => {
|
|
164
|
-
cleanOutputDir();
|
|
165
|
-
|
|
166
|
-
const output = await downloadAndSaveBase(testProjects, "structured");
|
|
167
|
-
|
|
168
|
-
expect(/saved to.*Project 1\.json/.test(output)).toEqual(true);
|
|
169
|
-
expect(/saved to.*Project 2\.json/.test(output)).toEqual(true);
|
|
170
|
-
expect(output.match(/saved to/g).length).toEqual(2);
|
|
171
|
-
expect(fs.readdirSync(consts.TEXT_DIR).length).toEqual(2);
|
|
172
|
-
});
|
|
173
|
-
});
|
package/lib/remove-project.js
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
const config = require("./config");
|
|
2
|
-
const consts = require("./consts");
|
|
3
|
-
const output = require("./output");
|
|
4
|
-
const getSelectedProjects = require("./utils/getSelectedProjects");
|
|
5
|
-
const promptForProject = require("./utils/promptForProject");
|
|
6
|
-
|
|
7
|
-
async function removeProject() {
|
|
8
|
-
const projects = getSelectedProjects();
|
|
9
|
-
if (!projects.length) {
|
|
10
|
-
console.log(
|
|
11
|
-
"\n" +
|
|
12
|
-
"No projects found in your workspace.\n" +
|
|
13
|
-
`Try adding one with: ${output.info("ditto-cli project add")}\n`
|
|
14
|
-
);
|
|
15
|
-
return;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const projectToRemove = await promptForProject({
|
|
19
|
-
projects,
|
|
20
|
-
message: "Select a project to remove",
|
|
21
|
-
});
|
|
22
|
-
if (!projectToRemove) return;
|
|
23
|
-
|
|
24
|
-
config.writeData(consts.PROJECT_CONFIG_FILE, {
|
|
25
|
-
projects: projects.filter(({ id }) => id !== projectToRemove.id),
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
console.log(
|
|
29
|
-
`\n${output.info(
|
|
30
|
-
projectToRemove.name
|
|
31
|
-
)} has been removed from your selected projects. ` +
|
|
32
|
-
`\nWe saved your updated configuration to: ${output.info(
|
|
33
|
-
consts.PROJECT_CONFIG_FILE
|
|
34
|
-
)}` +
|
|
35
|
-
"\n"
|
|
36
|
-
);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
module.exports = removeProject;
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
const fs = require("fs");
|
|
2
|
-
const yaml = require("js-yaml");
|
|
3
|
-
|
|
4
|
-
const { PROJECT_CONFIG_FILE } = require("../consts");
|
|
5
|
-
|
|
6
|
-
function yamlToJson(_yaml) {
|
|
7
|
-
try {
|
|
8
|
-
return yaml.safeLoad(_yaml);
|
|
9
|
-
} catch (e) {
|
|
10
|
-
if (e instanceof YAMLException) {
|
|
11
|
-
return "";
|
|
12
|
-
} else {
|
|
13
|
-
throw e;
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Returns an array containing all valid projects ({ id, name })
|
|
20
|
-
* currently contained in the project config file.
|
|
21
|
-
*/
|
|
22
|
-
function getSelectedProjects(configFile = PROJECT_CONFIG_FILE) {
|
|
23
|
-
if (!fs.existsSync(configFile)) return [];
|
|
24
|
-
|
|
25
|
-
const contentYaml = fs.readFileSync(configFile, "utf8");
|
|
26
|
-
const contentJson = yamlToJson(contentYaml);
|
|
27
|
-
|
|
28
|
-
if (!(contentJson && contentJson.projects)) {
|
|
29
|
-
return [];
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
return contentJson.projects.filter(({ name, id }) => name && id);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
module.exports = getSelectedProjects;
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
const processMetaOption = (inputArr) => {
|
|
2
|
-
const res = {};
|
|
3
|
-
|
|
4
|
-
if (!Array.isArray(inputArr)) {
|
|
5
|
-
return res;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
inputArr.forEach((element) => {
|
|
9
|
-
const [key, value] = element.split(':');
|
|
10
|
-
res[key] = value;
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
return res;
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
module.exports = processMetaOption;
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
const processMetaOption = require('./processMetaOption');
|
|
2
|
-
|
|
3
|
-
describe('processMetaOption tests', () => {
|
|
4
|
-
it('It parses correctly', () => {
|
|
5
|
-
expect(processMetaOption(['githubActionRequest:true', 'trigger:manual'])).toEqual({
|
|
6
|
-
githubActionRequest: 'true',
|
|
7
|
-
trigger: 'manual',
|
|
8
|
-
});
|
|
9
|
-
});
|
|
10
|
-
it('Malformed doesnt crash', () => {
|
|
11
|
-
expect(processMetaOption(['context:github-action', 'trigger'])).toEqual({
|
|
12
|
-
context: 'github-action',
|
|
13
|
-
trigger: undefined,
|
|
14
|
-
});
|
|
15
|
-
});
|
|
16
|
-
});
|