@dittowords/cli 1.2.7-beta → 2.1.1
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 +87 -9
- package/lib/config.js +77 -2
- package/lib/init/init.js +19 -11
- package/lib/init/project.js +12 -5
- package/lib/pull.js +41 -96
- package/lib/utils/getSelectedProjects.js +1 -1
- package/lib/utils/projectsToText.js +1 -1
- package/lib/utils/sourcesToText.js +24 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -16,9 +16,39 @@ npm install --global @dittowords/cli
|
|
|
16
16
|
|
|
17
17
|
The installed binary is named `ditto-cli`. You can execute it directly in `node_modules/.bin/ditto-cli` or using [npx](https://www.npmjs.com/package/npx) (with or without installation) like `npx @dittowords/cli`.
|
|
18
18
|
|
|
19
|
-
The first time you run the CLI, you'll be asked to provide an API key (found at [https://beta.dittowords.com/account/user](https://beta.dittowords.com/account/user) under **API Keys**)
|
|
19
|
+
The first time you run the CLI, you'll be asked to provide an API key (found at [https://beta.dittowords.com/account/user](https://beta.dittowords.com/account/user) under **API Keys**):
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
```
|
|
22
|
+
$ npx @dittowords/cli
|
|
23
|
+
|
|
24
|
+
┌──────────────────────────────────┐
|
|
25
|
+
│ │
|
|
26
|
+
│ Welcome to the Ditto CLI. │
|
|
27
|
+
│ │
|
|
28
|
+
│ We're glad to have you here. │
|
|
29
|
+
│ │
|
|
30
|
+
└──────────────────────────────────┘
|
|
31
|
+
|
|
32
|
+
What is your API key? > xxx-xxx-xxx
|
|
33
|
+
|
|
34
|
+
Thanks for authenticating.
|
|
35
|
+
We'll save the key to: /Users/{username}/.config/ditto
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Once you've successfully authenticated, you'll be asked to configure the CLI with an initial project from your workspace:
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
Looks like there are no Ditto projects selected for your current directory.
|
|
42
|
+
|
|
43
|
+
? Choose the project you'd like to sync text from:
|
|
44
|
+
- Ditto Component Library https://beta.dittowords.com/components/all
|
|
45
|
+
- NUX Onboarding Flow https://beta.dittowords.com/doc/609e9981c313f8018d0c346a
|
|
46
|
+
...
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
After selecting a project, a configuration file will automatically be created at the path `./ditto/config.yml`, relative to your current working directory. The CLI will attempt to read from this file every time a command is executed. See the [documentation on config.yml](#files) further down in this README for a full reference of how the CLI can be configured.
|
|
50
|
+
|
|
51
|
+
Once you've successfully authenticated and a config file has been created, you’re ready to start fetching copy! You can set up the CLI in multiple directories by running `ditto-cli` and choosing an initial project to sync from.
|
|
22
52
|
|
|
23
53
|
## Commands
|
|
24
54
|
|
|
@@ -52,7 +82,7 @@ This folder houses the configuration file (`ditto/config.yml`) used by the CLI a
|
|
|
52
82
|
|
|
53
83
|
If you run the CLI in a directory that does not contain a `ditto/` folder, the folder and a `config.yml` file will be automatically created.
|
|
54
84
|
|
|
55
|
-
- ####
|
|
85
|
+
- #### config.yml
|
|
56
86
|
|
|
57
87
|
This is the source of truth for a given directory about how the CLI should fetch and store data from Ditto. It includes information about which Ditto projects the CLI should pull text from and in what format the text should be stored.
|
|
58
88
|
|
|
@@ -60,16 +90,62 @@ If you run the CLI in a directory that does not contain a `ditto/` folder, the f
|
|
|
60
90
|
|
|
61
91
|
**Supported properties**
|
|
62
92
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
93
|
+
##### `projects`
|
|
94
|
+
|
|
95
|
+
A list of project names and ids to pull text from. R
|
|
96
|
+
|
|
97
|
+
equired if `components: true` is not specified.
|
|
66
98
|
|
|
67
|
-
**
|
|
99
|
+
**Note**: the `name` property is used for display purposes when referencing a project in the CLI, but does not have to be an
|
|
100
|
+
exact match with the project name in Ditto.
|
|
68
101
|
|
|
102
|
+
```yml
|
|
103
|
+
projects:
|
|
104
|
+
- name: Landing Page Copy
|
|
105
|
+
id: 61b8d26105f8f400e97fdd14
|
|
106
|
+
- name: User Settings
|
|
107
|
+
id: 606cb89ac55041013d552f8b
|
|
69
108
|
```
|
|
109
|
+
|
|
110
|
+
##### `components`
|
|
111
|
+
|
|
112
|
+
If included with a value of `true`, data from the component library will be fetched and included in the CLI's output.
|
|
113
|
+
|
|
114
|
+
Required if `projects` is not specified with a valid list of projects.
|
|
115
|
+
|
|
116
|
+
```yml
|
|
117
|
+
components: true
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
##### `variants`
|
|
121
|
+
|
|
122
|
+
If included with a value of `true`, variant data will be pulled for the specified projects and/or the component library.
|
|
123
|
+
|
|
124
|
+
Defaults to `false`.
|
|
125
|
+
|
|
126
|
+
```yml
|
|
127
|
+
variants: true
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
##### `format`
|
|
131
|
+
|
|
132
|
+
The format the specified projects should be stored in. Acceptable values are `structured` or `flat`.
|
|
133
|
+
|
|
134
|
+
If not specified, the default format containing block and frame data will be used.
|
|
135
|
+
|
|
136
|
+
```yml
|
|
137
|
+
format: flat
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
**Full Example**
|
|
141
|
+
|
|
142
|
+
```yml
|
|
70
143
|
projects:
|
|
71
|
-
- name:
|
|
72
|
-
id:
|
|
144
|
+
- name: Landing Page Copy
|
|
145
|
+
id: 61b8d26105f8f400e97fdd14
|
|
146
|
+
- name: User Settings
|
|
147
|
+
id: 606cb89ac55041013d552f8b
|
|
148
|
+
components: true
|
|
73
149
|
variants: true
|
|
74
150
|
format: flat
|
|
75
151
|
```
|
|
@@ -89,6 +165,8 @@ If you run the CLI in a directory that does not contain a `ditto/` folder, the f
|
|
|
89
165
|
|
|
90
166
|
An automatically generated driver file that simplifies the process of passing text data to Ditto JavaScript SDKs. This file has a standardized format that is always the same independent of the CLI configuration used to generate it.
|
|
91
167
|
|
|
168
|
+
**Since this file is designed to be consumed by other internal Ditto libraries, it is not recommended that you depend on it - its format may change between major releases.**
|
|
169
|
+
|
|
92
170
|
```ts
|
|
93
171
|
interface DriverFile {
|
|
94
172
|
[projectId: string]: {
|
package/lib/config.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
const fs = require("fs");
|
|
2
2
|
const path = require("path");
|
|
3
3
|
const url = require("url");
|
|
4
|
-
|
|
5
4
|
const yaml = require("js-yaml");
|
|
6
5
|
|
|
6
|
+
const consts = require("./consts");
|
|
7
|
+
|
|
7
8
|
function createFileIfMissing(filename) {
|
|
8
9
|
const dir = path.dirname(filename);
|
|
9
10
|
|
|
@@ -14,7 +15,13 @@ function createFileIfMissing(filename) {
|
|
|
14
15
|
}
|
|
15
16
|
}
|
|
16
17
|
|
|
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 = {}) {
|
|
18
25
|
createFileIfMissing(file);
|
|
19
26
|
const fileContents = fs.readFileSync(file, "utf8");
|
|
20
27
|
return yaml.safeLoad(fileContents) || defaultData;
|
|
@@ -72,6 +79,73 @@ function save(file, key, value) {
|
|
|
72
79
|
writeData(file, data);
|
|
73
80
|
}
|
|
74
81
|
|
|
82
|
+
const IS_DUPLICATE = /-(\d+$)/;
|
|
83
|
+
function dedupeProjectName(projectNames, projectName) {
|
|
84
|
+
let dedupedName = projectName;
|
|
85
|
+
|
|
86
|
+
if (projectNames.has(dedupedName)) {
|
|
87
|
+
while (projectNames.has(dedupedName)) {
|
|
88
|
+
const [_, numberStr] = dedupedName.match(IS_DUPLICATE) || [];
|
|
89
|
+
if (numberStr && !isNaN(parseInt(numberStr))) {
|
|
90
|
+
dedupedName = `${dedupedName.replace(IS_DUPLICATE, "")}-${
|
|
91
|
+
parseInt(numberStr) + 1
|
|
92
|
+
}`;
|
|
93
|
+
} else {
|
|
94
|
+
dedupedName = `${dedupedName}-1`;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return dedupedName;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Reads from the config file, filters out
|
|
104
|
+
* invalid projects, dedupes those remaining, and returns:
|
|
105
|
+
* - whether or not the data required to `pull` is present
|
|
106
|
+
* - whether or not the component library should be fetched
|
|
107
|
+
* - an array of valid, deduped projects
|
|
108
|
+
* - the `variants` and `format` config options
|
|
109
|
+
*/
|
|
110
|
+
function parseSourceInformation() {
|
|
111
|
+
const { projects, components, variants, format } = readData();
|
|
112
|
+
|
|
113
|
+
const projectNames = {};
|
|
114
|
+
const validProjects = [];
|
|
115
|
+
|
|
116
|
+
let componentLibraryInProjects = false;
|
|
117
|
+
|
|
118
|
+
(projects || []).forEach((project) => {
|
|
119
|
+
const isValid = project.id && project.name;
|
|
120
|
+
if (!isValid) {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (project.id === "ditto_component_library") {
|
|
125
|
+
componentLibraryInProjects = true;
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
project.fileName = dedupeProjectName(projectNames, project.name);
|
|
130
|
+
projectNames.add(project.fileName);
|
|
131
|
+
|
|
132
|
+
validProjects.push(project);
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
const shouldFetchComponentLibrary =
|
|
136
|
+
!!components || componentLibraryInProjects;
|
|
137
|
+
|
|
138
|
+
const hasSourceData = validProjects.length || shouldFetchComponentLibrary;
|
|
139
|
+
|
|
140
|
+
return {
|
|
141
|
+
hasSourceData,
|
|
142
|
+
validProjects,
|
|
143
|
+
shouldFetchComponentLibrary,
|
|
144
|
+
variants,
|
|
145
|
+
format,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
|
|
75
149
|
module.exports = {
|
|
76
150
|
createFileIfMissing,
|
|
77
151
|
readData,
|
|
@@ -81,4 +155,5 @@ module.exports = {
|
|
|
81
155
|
deleteToken,
|
|
82
156
|
getToken,
|
|
83
157
|
save,
|
|
158
|
+
parseSourceInformation,
|
|
84
159
|
};
|
package/lib/init/init.js
CHANGED
|
@@ -2,13 +2,16 @@
|
|
|
2
2
|
// expected to be run once per project.
|
|
3
3
|
const boxen = require("boxen");
|
|
4
4
|
const chalk = require("chalk");
|
|
5
|
-
const getSelectedProjects = require("../utils/getSelectedProjects");
|
|
6
5
|
const projectsToText = require("../utils/projectsToText");
|
|
7
6
|
|
|
8
|
-
const {
|
|
7
|
+
const { needsSource, collectAndSaveProject } = require("./project");
|
|
9
8
|
const { needsToken, collectAndSaveToken } = require("./token");
|
|
10
9
|
|
|
11
|
-
const
|
|
10
|
+
const config = require("../config");
|
|
11
|
+
const output = require("../output");
|
|
12
|
+
const sourcesToText = require("../utils/sourcesToText");
|
|
13
|
+
|
|
14
|
+
const needsInit = () => needsToken() || needsSource();
|
|
12
15
|
|
|
13
16
|
function welcome() {
|
|
14
17
|
const msg = chalk.white(`${chalk.bold(
|
|
@@ -22,19 +25,24 @@ We're glad to have you here.`);
|
|
|
22
25
|
|
|
23
26
|
async function init() {
|
|
24
27
|
welcome();
|
|
28
|
+
|
|
25
29
|
if (needsToken()) {
|
|
26
30
|
await collectAndSaveToken();
|
|
27
31
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
)}\n`
|
|
34
|
-
);
|
|
35
|
-
} else {
|
|
32
|
+
|
|
33
|
+
const { hasSourceData, validProjects, shouldFetchComponentLibrary } =
|
|
34
|
+
config.parseSourceInformation();
|
|
35
|
+
|
|
36
|
+
if (!hasSourceData) {
|
|
36
37
|
await collectAndSaveProject(true);
|
|
38
|
+
return;
|
|
37
39
|
}
|
|
40
|
+
|
|
41
|
+
const message =
|
|
42
|
+
"You're currently set up to sync text from " +
|
|
43
|
+
sourcesToText(validProjects, shouldFetchComponentLibrary);
|
|
44
|
+
|
|
45
|
+
console.log(message);
|
|
38
46
|
}
|
|
39
47
|
|
|
40
48
|
module.exports = { needsInit, init };
|
package/lib/init/project.js
CHANGED
|
@@ -15,14 +15,21 @@ function quit(exitCode = 2) {
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
function saveProject(file, name, id) {
|
|
18
|
+
// old functionality included "ditto_component_library" in the `projects`
|
|
19
|
+
// array, but we want to always treat the component library as a separate
|
|
20
|
+
// entity and use the new notation of a top-level `components` key
|
|
21
|
+
if (id === "ditto_component_library") {
|
|
22
|
+
config.writeData(file, { components: true });
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
|
|
18
26
|
const projects = [...getSelectedProjects(), { name, id }];
|
|
19
27
|
|
|
20
28
|
config.writeData(file, { projects });
|
|
21
29
|
}
|
|
22
30
|
|
|
23
|
-
function
|
|
24
|
-
|
|
25
|
-
return !(projects && projects.length);
|
|
31
|
+
function needsSource() {
|
|
32
|
+
return !config.parseSourceInformation().hasSourceData;
|
|
26
33
|
}
|
|
27
34
|
|
|
28
35
|
async function askForAnotherToken() {
|
|
@@ -60,7 +67,7 @@ async function collectProject(token, initialize) {
|
|
|
60
67
|
const path = process.cwd();
|
|
61
68
|
if (initialize) {
|
|
62
69
|
console.log(
|
|
63
|
-
`Looks like are no Ditto projects selected for your current directory: ${output.info(
|
|
70
|
+
`Looks like there are no Ditto projects selected for your current directory: ${output.info(
|
|
64
71
|
path
|
|
65
72
|
)}.`
|
|
66
73
|
);
|
|
@@ -113,4 +120,4 @@ async function collectAndSaveProject(initialize = false) {
|
|
|
113
120
|
}
|
|
114
121
|
}
|
|
115
122
|
|
|
116
|
-
module.exports = {
|
|
123
|
+
module.exports = { needsSource, collectAndSaveProject };
|
package/lib/pull.js
CHANGED
|
@@ -9,6 +9,7 @@ const consts = require("./consts");
|
|
|
9
9
|
const output = require("./output");
|
|
10
10
|
const { collectAndSaveToken } = require("./init/token");
|
|
11
11
|
const projectsToText = require("./utils/projectsToText");
|
|
12
|
+
const sourcesToText = require("./utils/sourcesToText");
|
|
12
13
|
|
|
13
14
|
const NON_DEFAULT_FORMATS = ["flat", "structured"];
|
|
14
15
|
|
|
@@ -30,54 +31,6 @@ async function askForAnotherToken() {
|
|
|
30
31
|
await collectAndSaveToken(message);
|
|
31
32
|
}
|
|
32
33
|
|
|
33
|
-
function cleanProjectName(projectName) {
|
|
34
|
-
return (
|
|
35
|
-
projectName
|
|
36
|
-
.replace(/\s/g, "-")
|
|
37
|
-
// replace double underscore since this is what we use
|
|
38
|
-
// to separate project names and API IDs
|
|
39
|
-
.replace(/__/g, "_")
|
|
40
|
-
.toLowerCase()
|
|
41
|
-
.trim()
|
|
42
|
-
);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Return the passed array of projects with `project.name` modified
|
|
47
|
-
* to be `${project.name}-${duplicate_number}` for each project
|
|
48
|
-
* that has the same name as another project in the original array.
|
|
49
|
-
*/
|
|
50
|
-
const IS_DUPLICATE = /-(\d+$)/;
|
|
51
|
-
function getProjectsWithDedupedNames(projects) {
|
|
52
|
-
const projectsWithDedupedNames = [];
|
|
53
|
-
const projectNames = {};
|
|
54
|
-
|
|
55
|
-
projects.forEach(({ id, name }) => {
|
|
56
|
-
let dedupedName = name;
|
|
57
|
-
|
|
58
|
-
if (projectNames[dedupedName]) {
|
|
59
|
-
while (projectNames[dedupedName]) {
|
|
60
|
-
const [_, numberStr] = dedupedName.match(IS_DUPLICATE) || [];
|
|
61
|
-
if (numberStr && !isNaN(parseInt(numberStr))) {
|
|
62
|
-
dedupedName = `${dedupedName.replace(IS_DUPLICATE, "")}-${
|
|
63
|
-
parseInt(numberStr) + 1
|
|
64
|
-
}`;
|
|
65
|
-
} else {
|
|
66
|
-
dedupedName = `${dedupedName}-1`;
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
projectNames[dedupedName] = true;
|
|
72
|
-
projectsWithDedupedNames.push({
|
|
73
|
-
id,
|
|
74
|
-
name: cleanProjectName(dedupedName),
|
|
75
|
-
});
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
return projectsWithDedupedNames;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
34
|
/**
|
|
82
35
|
* For a given variant:
|
|
83
36
|
* - if format is unspecified, fetch data for all projects from `/projects` and
|
|
@@ -93,7 +46,7 @@ async function downloadAndSaveVariant(variantApiId, projects, format, token) {
|
|
|
93
46
|
|
|
94
47
|
if (NON_DEFAULT_FORMATS.includes(format)) {
|
|
95
48
|
const savedMessages = await Promise.all(
|
|
96
|
-
projects.map(async ({ id,
|
|
49
|
+
projects.map(async ({ id, fileName }) => {
|
|
97
50
|
const { data } = await api.get(`/projects/${id}`, {
|
|
98
51
|
params,
|
|
99
52
|
headers: { Authorization: `token ${token}` },
|
|
@@ -103,7 +56,7 @@ async function downloadAndSaveVariant(variantApiId, projects, format, token) {
|
|
|
103
56
|
return "";
|
|
104
57
|
}
|
|
105
58
|
|
|
106
|
-
const filename =
|
|
59
|
+
const filename = fileName + ("__" + (variantApiId || "base")) + ".json";
|
|
107
60
|
const filepath = path.join(consts.TEXT_DIR, filename);
|
|
108
61
|
|
|
109
62
|
const dataString = JSON.stringify(data, null, 2);
|
|
@@ -162,13 +115,13 @@ async function downloadAndSaveBase(projects, format, token) {
|
|
|
162
115
|
|
|
163
116
|
if (NON_DEFAULT_FORMATS.includes(format)) {
|
|
164
117
|
const savedMessages = await Promise.all(
|
|
165
|
-
projects.map(async ({ id,
|
|
118
|
+
projects.map(async ({ id, fileName }) => {
|
|
166
119
|
const { data } = await api.get(`/projects/${id}`, {
|
|
167
120
|
params,
|
|
168
121
|
headers: { Authorization: `token ${token}` },
|
|
169
122
|
});
|
|
170
123
|
|
|
171
|
-
const filename = `${
|
|
124
|
+
const filename = `${fileName}.json`;
|
|
172
125
|
const filepath = path.join(consts.TEXT_DIR, filename);
|
|
173
126
|
|
|
174
127
|
const dataString = JSON.stringify(data, null, 2);
|
|
@@ -195,36 +148,20 @@ async function downloadAndSaveBase(projects, format, token) {
|
|
|
195
148
|
}
|
|
196
149
|
|
|
197
150
|
function getSavedMessage(file) {
|
|
198
|
-
return `Successfully saved to ${output.info(file)}
|
|
151
|
+
return `Successfully saved to ${output.info(file)}\n`;
|
|
199
152
|
}
|
|
200
153
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
fs.
|
|
204
|
-
});
|
|
205
|
-
|
|
206
|
-
if (!exists) {
|
|
207
|
-
await new Promise((resolve) => fs.mkdir(consts.TEXT_DIR, () => resolve()));
|
|
154
|
+
function cleanOutputFiles() {
|
|
155
|
+
if (!fs.existsSync(consts.TEXT_DIR)) {
|
|
156
|
+
fs.mkdirSync(consts.TEXT_DIR);
|
|
208
157
|
}
|
|
209
158
|
|
|
210
|
-
const fileNames =
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
resolve(
|
|
214
|
-
}
|
|
215
|
-
);
|
|
216
|
-
|
|
217
|
-
await Promise.all(
|
|
218
|
-
fileNames.map((fileName) => {
|
|
219
|
-
if (/\.js(on)?$/.test(fileName)) {
|
|
220
|
-
return new Promise((resolve) => {
|
|
221
|
-
fs.unlink(path.resolve(consts.TEXT_DIR, fileName), () => resolve());
|
|
222
|
-
});
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
return Promise.resolve();
|
|
226
|
-
})
|
|
227
|
-
);
|
|
159
|
+
const fileNames = fs.readdirSync(consts.TEXT_DIR);
|
|
160
|
+
fileNames.forEach((fileName) => {
|
|
161
|
+
if (/\.js(on)?$/.test(fileName)) {
|
|
162
|
+
fs.unlinkSync(path.resolve(consts.TEXT_DIR, fileName));
|
|
163
|
+
}
|
|
164
|
+
});
|
|
228
165
|
|
|
229
166
|
return "Cleaning old output files..\n";
|
|
230
167
|
}
|
|
@@ -251,7 +188,7 @@ function generateJsDriver(projects, variants, format) {
|
|
|
251
188
|
.filter((fileName) => /\.json$/.test(fileName));
|
|
252
189
|
|
|
253
190
|
const projectIdsByName = projects.reduce(
|
|
254
|
-
(agg, project) => ({ ...agg, [project.
|
|
191
|
+
(agg, project) => ({ ...agg, [project.fileName]: project.id }),
|
|
255
192
|
{}
|
|
256
193
|
);
|
|
257
194
|
|
|
@@ -321,32 +258,40 @@ function generateJsDriver(projects, variants, format) {
|
|
|
321
258
|
const filePath = path.resolve(consts.TEXT_DIR, "index.js");
|
|
322
259
|
fs.writeFileSync(filePath, dataString, { encoding: "utf8" });
|
|
323
260
|
|
|
324
|
-
return `Generated .js SDK driver at ${output.info(filePath)}
|
|
261
|
+
return `Generated .js SDK driver at ${output.info(filePath)}`;
|
|
325
262
|
}
|
|
326
263
|
|
|
327
|
-
async function downloadAndSave(
|
|
328
|
-
const {
|
|
329
|
-
|
|
264
|
+
async function downloadAndSave(sourceInformation, token) {
|
|
265
|
+
const { validProjects, variants, format, shouldFetchComponentLibrary } =
|
|
266
|
+
sourceInformation;
|
|
330
267
|
|
|
331
|
-
let msg = `\nFetching the latest text from
|
|
332
|
-
|
|
268
|
+
let msg = `\nFetching the latest text from ${sourcesToText(
|
|
269
|
+
validProjects,
|
|
270
|
+
shouldFetchComponentLibrary
|
|
333
271
|
)}\n`;
|
|
334
272
|
|
|
335
273
|
const spinner = ora(msg);
|
|
336
274
|
spinner.start();
|
|
337
275
|
|
|
338
|
-
|
|
339
|
-
|
|
276
|
+
// We'll need to move away from this solution if at some
|
|
277
|
+
// point down the road we stop allowing the component
|
|
278
|
+
// library to be returned from the /projects endpoint
|
|
279
|
+
if (shouldFetchComponentLibrary) {
|
|
280
|
+
validProjects.push({
|
|
281
|
+
id: "ditto_component_library",
|
|
282
|
+
name: "Ditto Component Library",
|
|
283
|
+
fileName: "ditto-component-library",
|
|
284
|
+
});
|
|
285
|
+
}
|
|
340
286
|
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
await new Promise((resolve) => setTimeout(resolve, 3000));
|
|
287
|
+
try {
|
|
288
|
+
msg += cleanOutputFiles();
|
|
344
289
|
|
|
345
290
|
msg += variants
|
|
346
|
-
? await downloadAndSaveVariants(
|
|
347
|
-
: await downloadAndSaveBase(
|
|
291
|
+
? await downloadAndSaveVariants(validProjects, format, token)
|
|
292
|
+
: await downloadAndSaveBase(validProjects, format, token);
|
|
348
293
|
|
|
349
|
-
msg += generateJsDriver(
|
|
294
|
+
msg += generateJsDriver(validProjects, variants, format);
|
|
350
295
|
|
|
351
296
|
msg += `\n${output.success("Done")}!`;
|
|
352
297
|
|
|
@@ -391,15 +336,15 @@ async function downloadAndSave(projectConfig, token) {
|
|
|
391
336
|
|
|
392
337
|
function pull() {
|
|
393
338
|
const token = config.getToken(consts.CONFIG_FILE, consts.API_HOST);
|
|
394
|
-
const
|
|
395
|
-
|
|
339
|
+
const sourceInformation = config.parseSourceInformation();
|
|
340
|
+
|
|
341
|
+
return downloadAndSave(sourceInformation, token);
|
|
396
342
|
}
|
|
397
343
|
|
|
398
344
|
module.exports = {
|
|
399
345
|
pull,
|
|
400
346
|
_testing: {
|
|
401
347
|
cleanOutputFiles,
|
|
402
|
-
getProjectsWithDedupedNames,
|
|
403
348
|
downloadAndSaveVariant,
|
|
404
349
|
downloadAndSaveVariants,
|
|
405
350
|
downloadAndSaveBase,
|
|
@@ -29,7 +29,7 @@ function getSelectedProjects(configFile = PROJECT_CONFIG_FILE) {
|
|
|
29
29
|
return [];
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
return
|
|
32
|
+
return contentjson.projects.filter(({ name, id }) => name && id);
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
module.exports = getSelectedProjects;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
const output = require("../output");
|
|
2
|
+
const projectsToText = require("./projectsToText");
|
|
3
|
+
|
|
4
|
+
function sourcesToText(projects, componentLibrary) {
|
|
5
|
+
let message = "";
|
|
6
|
+
|
|
7
|
+
if (componentLibrary) {
|
|
8
|
+
message += `the ${output.info("Ditto Component Library")}`;
|
|
9
|
+
|
|
10
|
+
if ((projects || []).length) {
|
|
11
|
+
message += " and ";
|
|
12
|
+
} else {
|
|
13
|
+
message += "..";
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if ((projects || []).length) {
|
|
18
|
+
message += `the following projects: ${projectsToText(projects)}\n`;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return message;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
module.exports = sourcesToText;
|