@dittowords/cli 4.0.0-alpha.0 → 4.0.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 CHANGED
@@ -14,7 +14,7 @@ npm install --save-dev @dittowords/cli
14
14
  npm install --global @dittowords/cli
15
15
  ```
16
16
 
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`.
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) like `npx @dittowords/cli`.
18
18
 
19
19
  The first time you run the CLI, you'll be asked to provide an API key (found at [https://app.dittowords.com/account/user](https://app.dittowords.com/account/user) under **API Keys**):
20
20
 
@@ -35,7 +35,7 @@ Thanks for authenticating.
35
35
  We'll save the key to: /Users/{username}/.config/ditto
36
36
  ```
37
37
 
38
- Once you've successfully authenticated, you'll be asked to choose a source (a project or your component library) to pull data **from**:
38
+ Once you've successfully authenticated, you'll be asked to choose a source (a project or your component library) to pull data from:
39
39
 
40
40
  ```
41
41
  Looks like there are no Ditto sources selected for your current directory: /Users/ditto
@@ -46,15 +46,15 @@ Looks like there are no Ditto sources selected for your current directory: /User
46
46
  ...
47
47
  ```
48
48
 
49
- After selecting a source, 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 [config.yml documentation](#files) further down in this README for a full reference of how the CLI can be configured.
49
+ After selecting a source, 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 [config.yml documentation](#files) for a full reference of how the CLI can be configured.
50
50
 
51
- Once you've successfully authenticated and a config file has been created, you’re ready to start fetching copy! If you need to use the CLI with multiple configurations, simply run `ditto-cli` in multiple directories.
51
+ Once you've successfully authenticated and a config file has been created, you’re ready to start fetching copy! If you need to use the CLI with multiple configurations, simply initialize it in multiple directories.
52
52
 
53
53
  ## API Keys
54
54
 
55
55
  The CLI will not prompt for an API key if a value is provided in the environment variable `DITTO_API_KEY`.
56
56
 
57
- If the `DITTO_API_KEY` environment variable is not set, the CLI will attempt to parse a token from [your authentication file](#authentication). If this file does not exist or does not contain a valid API key, the CLI will prompt for one.
57
+ If the `DITTO_API_KEY` environment variable is not set, the CLI will look for an API token in [your authentication file](#authentication). If this file does not exist or does not contain a valid API key, the CLI will prompt for one.
58
58
 
59
59
  We don't recommend editing the authentication file by hand; if you need to remove a saved API key or swap one key with another, it's better to fully delete the file and then re-run the CLI.
60
60
 
@@ -66,7 +66,7 @@ We don't recommend editing the authentication file by hand; if you need to remov
66
66
 
67
67
  **Action:** Pulls data from Ditto according to configured sources.
68
68
 
69
- Generate files your local `ditto/` folder (file extension is determined by the `format` property specified in `config.yml`).
69
+ Generate files your local `ditto/` folder. File extension is determined by the `format` property specified in `config.yml`.
70
70
 
71
71
  If no format is specified, the `flat` format will be used by default. Each time text is pulled from Ditto, the existing files in the `ditto/` directory are removed before new files are created in their place.
72
72
 
@@ -88,7 +88,9 @@ For more details on files generated by this command, see [Output Files](#output-
88
88
 
89
89
  **Usage:** `ditto-cli component-folders`
90
90
 
91
- **Action:** List component folders in your workspace. More information about component folders can be found here: https://www.dittowords.com/docs/component-folders.
91
+ **Action:** List component folders in your workspace.
92
+
93
+ More information about component folders in Ditto can be found [here](https://www.dittowords.com/docs/component-folders).
92
94
 
93
95
  ### Import components
94
96
 
@@ -129,7 +131,7 @@ variants: true
129
131
 
130
132
  A list of places the CLI should pull text data from. For the CLI to function, at least one source type (`projects` or `components`) is required.
131
133
 
132
- #### `sources.projects`
134
+ ##### `sources.projects`
133
135
 
134
136
  A list of projects to pull text from.
135
137
 
@@ -144,28 +146,79 @@ sources:
144
146
 
145
147
  The `name` property is used for display purposes when referencing a project in the CLI, but does not have to be an exact match with the project name in Ditto.
146
148
 
147
- #### `sources.components`
149
+ An `exclude_components` property can be added on a per-project basis to indicate that text items should only be pulled which are not associated with a component:
150
+
151
+ ```yml
152
+ sources:
153
+ projects:
154
+ - id: 61b8d26105f8f400e97fdd14
155
+ name: Landing Page Copy
156
+ exclude_components: true
157
+ ```
158
+
159
+ ##### `sources.components`
160
+
161
+ A boolean or configuration object indicating how component data should be pulled from your component library.
162
+
163
+ The simplest configuration is a boolean, which indicates that all components in your component library should be fetched:
164
+
165
+ ```yml
166
+ sources:
167
+ components: true
168
+ ```
169
+
170
+ You can also pass an object that supports two complementary properties: `root` and `folders`.
171
+
172
+ - `root` controls behavior for components that are NOT in folders (i.e. that are at the _root_ of the component library)
173
+ - `folders` controls behavior for components that are ARE in folders
148
174
 
149
- An object to configure pulling component data from your component library.
175
+ If `root` is `true` and `folders` is unspecified, **only components not in folders** will be fetched:
150
176
 
151
177
  ```yml
152
178
  sources:
153
179
  components:
154
- # type: boolean
155
- # required: true
156
- #
157
- # if set to true, enables pulling data from the component
158
- # library. if set to false, CLI behaves as if `sources.components`
159
- # is not defined
160
- enabled: true
180
+ root: true
181
+ ```
161
182
 
162
- # type: { id: string; name: string; }
163
- # required: false
164
- #
165
- # if defined, restricts the CLI to only pulling data for components that are in the specified folders.
183
+ If `root` is `false` and `folders` is unspecified, **only components in any folder** will be fetched:
184
+
185
+ ```yml
186
+ sources:
187
+ components:
188
+ root: false
189
+ ```
190
+
191
+ If `root` is unspecified and `folders` contains a list of component folders, **only components in the specified folders** will be fetched:
192
+
193
+ ```yml
194
+ sources:
195
+ components:
166
196
  folders:
167
- - id: 61b8d26105f8f400e97fdd14
168
- name: Onboarding
197
+ - id: folder-api-id-1
198
+ name: Folder 1
199
+ - id: folder-api-id-2
200
+ name: Folder 2
201
+ ```
202
+
203
+ If `root` is `true` and `folders` contains a list of component folders, **non-folder components and components in the specified folders** will be fetched:
204
+
205
+ ```yml
206
+ sources:
207
+ components:
208
+ folders:
209
+ - id: folder-api-id-1
210
+ name: Folder 1
211
+ - id: folder-api-id-2
212
+ name: Folder 2
213
+ ```
214
+
215
+ `root` can also be specified as a configuration object with a `status` property to indicate that non-folder components should be fetched that have the indicated status:
216
+
217
+ ```yml
218
+ sources:
219
+ components:
220
+ root:
221
+ status: WIP
169
222
  ```
170
223
 
171
224
  #### Variants
@@ -178,7 +231,7 @@ Defaults to `false` if not specified.
178
231
  variants: true
179
232
  ```
180
233
 
181
- ##### Format
234
+ #### Format
182
235
 
183
236
  The format that text data should be generated in. Accepted values:
184
237
 
@@ -202,26 +255,56 @@ format:
202
255
  - ios-stringsdict
203
256
  ```
204
257
 
258
+ You should not specify multiple JSON formats in the same configuration, as they will overwrite one another when writing to disk.
259
+
205
260
  #### Status
206
261
 
207
- If defined, data pulled will be restricted to text items or components that have the specified status. Accepted values:
262
+ If specified, only source data with the indicated status will be fetched. Accepted values:
208
263
 
209
264
  - `NONE`
210
265
  - `WIP`
211
266
  - `REVIEW`
212
267
  - `FINAL`
213
268
 
269
+ If `status` is specified at the top level of the configuration, it will apply to all sources:
270
+
214
271
  ```yml
215
272
  status: FINAL
273
+ sources:
274
+ components: true
275
+ projects:
276
+ - id: project-1
277
+ name: Project 1
216
278
  ```
217
279
 
218
- Defaults to no status restriction if not specified.
280
+ `status` can also be specified at the level of individual sources:
219
281
 
220
- More information about statuses can be found [here](https://www.dittowords.com/docs/tips-for-collaborating).
282
+ ```yml
283
+ sources:
284
+ components:
285
+ root:
286
+ status: REVIEW
287
+ folders:
288
+ - id: folder-api-id-1
289
+ name: Folder 1
290
+ status: NONE
291
+ projects:
292
+ - id: project-1
293
+ name: Project 1
294
+ status: WIP
295
+ ```
296
+
297
+ If both are specified, a source-level `status` overrides a top-level `status`.
298
+
299
+ More information about Ditto statuses can be found [here](https://www.dittowords.com/docs/tips-for-collaborating).
221
300
 
222
301
  #### Rich Text
223
302
 
224
- If defined in conjunction with the `structured` format, output data will include an HTML string (rich text) for each text item or component that is sourced. You can read more about Ditto's rich text feature [here](https://www.dittowords.com/docs/rich-text).
303
+ If defined with the `flat` format, output values will be HTML strings (rich text) for each piece of source data.
304
+
305
+ If defined with the `structured` format, output data will include a `rich_text` property that is an HTML string (rich text) for each piece of source data.
306
+
307
+ You can read more about Ditto's rich text feature [here](https://www.dittowords.com/docs/rich-text).
225
308
 
226
309
  ```yml
227
310
  richText: true
@@ -232,17 +315,21 @@ richText: true
232
315
  ```yml
233
316
  sources:
234
317
  components:
235
- enabled: true
318
+ root: true
236
319
  folders:
237
320
  - id: 61b8d26105f8f400e97fdd14
238
321
  name: Onboarding
322
+ - id: 61b8d26105f8f400e97fdd15
323
+ name: Onboarding 2
324
+ status: WIP
239
325
  projects:
240
326
  - name: Landing Page Copy
241
327
  id: 61b8d26105f8f400e97fdd14
242
328
  - name: User Settings
243
329
  id: 606cb89ac55041013d552f8b
330
+ status: WIP
244
331
  variants: true
245
- format: flat
332
+ format: structured
246
333
  status: FINAL
247
334
  richText: false
248
335
  ```
@@ -274,19 +361,21 @@ All files created will adhere to the following template:
274
361
  {source_name}__{variant_name}.{extension}
275
362
  ```
276
363
 
277
- - `source_name`: the name of a project or `ditto_component_library` for files containing component data
278
- - `variant_name`: the ID of a variant or `base` for files generated for non-variant text
279
- - `extension`: the file extension that corresponds to your configured format
364
+ - `source_name`: the name of the source a given file holds data for
365
+ - for projects, this is `{project-name}`
366
+ - for components, this is `components__{folder_name}`
367
+ - `variant_name`: the API ID of a variant or `base` for files generated for non-variant text
368
+ - `extension`: the file extension that corresponds to the configured format(s)
280
369
 
281
- To help with keeping cross-platform behavior consistent, file names will be fully lowercase, have whitespace replaced with hyphens, and have non-word characters (with the exception of `-` and `_`) removed.
370
+ To keep cross-platform behavior consistent, file names will be fully lowercase, have whitespace replaced with hyphens, and have non-word characters (with the exception of `-` and `_`) removed.
282
371
 
283
372
  If the configured format(s) result(s) in JSON files being generated, an `index.js` "driver file" is also created to simplify the process of integrating Ditto into web apps:
284
373
 
285
374
  ```js
286
375
  module.exports = {
287
376
  ditto_component_library: {
288
- base: require("./ditto_component_library__base.json"),
289
- spanish: require("./ditto_component_library__spanish.json"),
377
+ base: require("./components__root__base.json"),
378
+ spanish: require("./components__root__spanish.json"),
290
379
  },
291
380
  project_xxx: {
292
381
  base: require("./example-project__base.json"),
package/bin/config.js CHANGED
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{},n=(new Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="ee8aabef-5bac-5c7b-a33a-2a40689fc6dc")}catch(e){}}();
2
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{},n=(new Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="3f451b9b-6016-532a-b399-58b8b273e73c")}catch(e){}}();
3
3
 
4
4
  var __create = Object.create;
5
5
  var __defProp = Object.defineProperty;
@@ -61,7 +61,7 @@ var import_consts = __toESM(require("./consts"));
61
61
  var import_createSentryContext = require("./utils/createSentryContext");
62
62
  const DEFAULT_CONFIG_JSON = {
63
63
  sources: {
64
- components: { enabled: true }
64
+ components: true
65
65
  },
66
66
  variants: true,
67
67
  format: "flat"
@@ -168,7 +168,6 @@ function dedupeProjectName(projectNames, projectName) {
168
168
  return dedupedName;
169
169
  }
170
170
  function parseSourceInformation(file) {
171
- var _a, _b;
172
171
  const {
173
172
  sources,
174
173
  variants,
@@ -195,7 +194,9 @@ function parseSourceInformation(file) {
195
194
  projectNames.add(project.fileName);
196
195
  validProjects.push(project);
197
196
  });
198
- const shouldFetchComponentLibrary = Boolean((_a = sources == null ? void 0 : sources.components) == null ? void 0 : _a.enabled);
197
+ const shouldFetchComponentLibrary = Boolean(sources == null ? void 0 : sources.components);
198
+ const componentRoot = typeof (sources == null ? void 0 : sources.components) === "object" ? sources.components.root : void 0;
199
+ const componentFolders = typeof (sources == null ? void 0 : sources.components) === "object" ? sources.components.folders : void 0;
199
200
  const hasSourceData = !!validProjects.length || shouldFetchComponentLibrary;
200
201
  const result = {
201
202
  hasSourceData,
@@ -208,7 +209,8 @@ function parseSourceInformation(file) {
208
209
  hasTopLevelProjectsField: !!projectsRoot,
209
210
  hasTopLevelComponentsField: !!componentsRoot,
210
211
  hasComponentLibraryInProjects,
211
- componentFolders: ((_b = sources == null ? void 0 : sources.components) == null ? void 0 : _b.folders) || null
212
+ componentRoot,
213
+ componentFolders
212
214
  };
213
215
  Sentry.setContext("config", (0, import_createSentryContext.createSentryContext)(result));
214
216
  return result;
@@ -233,4 +235,4 @@ var config_default = {
233
235
  });
234
236
  //# sourceMappingURL=config.js.map
235
237
 
236
- //# debugId=ee8aabef-5bac-5c7b-a33a-2a40689fc6dc
238
+ //# debugId=3f451b9b-6016-532a-b399-58b8b273e73c
package/bin/config.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../lib/config.ts"],"sourcesContent":["import fs from \"fs\";\nimport path from \"path\";\nimport url from \"url\";\nimport yaml from \"js-yaml\";\nimport * as Sentry from \"@sentry/node\";\n\nimport consts from \"./consts\";\nimport { Project, ConfigYAML } from \"./types\";\nimport { createSentryContext } from \"./utils/createSentryContext\";\n\nexport const DEFAULT_CONFIG_JSON: ConfigYAML = {\n sources: {\n components: { enabled: true },\n },\n variants: true,\n format: \"flat\",\n};\n\nexport const DEFAULT_CONFIG = yaml.dump(DEFAULT_CONFIG_JSON);\n\nfunction createFileIfMissing(filename: string, defaultContents?: any) {\n const dir = path.dirname(filename);\n\n // create the directory if it doesn't already exist\n if (!fs.existsSync(dir)) fs.mkdirSync(dir);\n\n // create the file if it doesn't already exist\n if (!fs.existsSync(filename)) {\n // create the file, writing the `defaultContents` if provided\n fs.writeFileSync(filename, defaultContents || \"\", \"utf-8\");\n }\n}\n\nfunction jsonIsConfigYAML(json: unknown): json is ConfigYAML {\n return typeof json === \"object\";\n}\n\nfunction jsonIsGlobalYAML(\n json: unknown\n): json is Record<string, { token: string }[]> {\n return (\n !!json &&\n typeof json === \"object\" &&\n Object.values(json).every(\n (arr) =>\n (arr as any).every &&\n arr.every(\n (val: any) =>\n typeof val === \"object\" && Object.keys(val).includes(\"token\")\n )\n )\n );\n}\n\n/**\n * Read data from a project config file\n * @param {string} file defaults to `PROJECT_CONFIG_FILE` defined in `constants.js`\n * @param {*} defaultData defaults to `{}`\n * @returns { ConfigYAML }\n */\nfunction readProjectConfigData(\n file = consts.PROJECT_CONFIG_FILE,\n defaultData = {}\n): ConfigYAML {\n createFileIfMissing(file, DEFAULT_CONFIG);\n const fileContents = fs.readFileSync(file, \"utf8\");\n const yamlData = yaml.load(fileContents);\n if (jsonIsConfigYAML(yamlData)) {\n return yamlData;\n }\n return defaultData;\n}\n\n/**\n * Read data from a global config file\n * @param {string} file defaults to `CONFIG_FILE` defined in `constants.js`\n * @param {*} defaultData defaults to `{}`\n * @returns { Record<string, { token: string }[]> }\n */\nfunction readGlobalConfigData(\n file = consts.CONFIG_FILE,\n defaultData = {}\n): Record<string, { token: string }[]> {\n createFileIfMissing(file);\n const fileContents = fs.readFileSync(file, \"utf8\");\n const yamlData = yaml.load(fileContents);\n if (jsonIsGlobalYAML(yamlData)) {\n return yamlData;\n }\n return defaultData;\n}\n\nfunction writeProjectConfigData(file: string, data: Partial<ConfigYAML>) {\n createFileIfMissing(file, DEFAULT_CONFIG);\n const existingData = readProjectConfigData(file);\n\n const configData: ConfigYAML = {\n ...existingData,\n ...data,\n sources: {\n ...existingData.sources,\n ...data.sources,\n },\n };\n\n const yamlStr = yaml.dump(configData);\n fs.writeFileSync(file, yamlStr, \"utf8\");\n}\n\nfunction writeGlobalConfigData(file: string, data: object) {\n createFileIfMissing(file);\n const existingData = readGlobalConfigData(file);\n const yamlStr = yaml.dump({ ...existingData, ...data });\n fs.writeFileSync(file, yamlStr, \"utf8\");\n}\n\nfunction justTheHost(host: string) {\n if (!host.includes(\"://\")) return host;\n return url.parse(host).hostname || \"\";\n}\n\nfunction deleteToken(file: string, host: string) {\n const data = readGlobalConfigData(file);\n const hostParsed = justTheHost(host);\n data[hostParsed] = [];\n data[hostParsed][0] = { token: \"\" };\n writeGlobalConfigData(file, data);\n}\n\nfunction saveToken(file: string, host: string, token: string) {\n const data = readGlobalConfigData(file);\n const hostParsed = justTheHost(host);\n data[hostParsed] = []; // only allow one token per host\n data[hostParsed][0] = { token };\n writeGlobalConfigData(file, data);\n}\n\nfunction getTokenFromEnv() {\n return process.env.DITTO_API_KEY;\n}\n\n/**\n *\n * @param {string} file\n * @param {string} host\n * @returns {Token}\n */\nfunction getToken(file: string, host: string) {\n const tokenFromEnv = getTokenFromEnv();\n if (tokenFromEnv) {\n return tokenFromEnv;\n }\n\n const data = readGlobalConfigData(file);\n const hostEntry = data[justTheHost(host)];\n if (!hostEntry) return undefined;\n const { length } = hostEntry;\n\n return hostEntry[length - 1].token;\n}\n\nconst IS_DUPLICATE = /-(\\d+$)/;\n\nfunction dedupeProjectName(projectNames: Set<string>, projectName: string) {\n let dedupedName = projectName;\n\n if (projectNames.has(dedupedName)) {\n while (projectNames.has(dedupedName)) {\n const [_, numberStr] = dedupedName.match(IS_DUPLICATE) || [];\n if (numberStr && !isNaN(parseInt(numberStr))) {\n dedupedName = `${dedupedName.replace(IS_DUPLICATE, \"\")}-${\n parseInt(numberStr) + 1\n }`;\n } else {\n dedupedName = `${dedupedName}-1`;\n }\n }\n }\n\n return dedupedName;\n}\n\n/**\n * Reads from the config file, filters out\n * invalid projects, dedupes those remaining, and returns:\n * - whether or not the data required to `pull` is present\n * - whether or not the component library should be fetched\n * - an array of valid, deduped projects\n * - the `variants` and `format` config options\n */\nfunction parseSourceInformation(file?: string) {\n const {\n sources,\n variants,\n format,\n status,\n richText,\n projects: projectsRoot,\n components: componentsRoot,\n } = readProjectConfigData(file);\n\n const projects = sources?.projects || [];\n\n const projectNames = new Set<string>();\n const validProjects: Project[] = [];\n let hasComponentLibraryInProjects = false;\n\n (projects || []).forEach((project) => {\n const isValid = project.id && project.name;\n if (!isValid) {\n return;\n }\n\n if (project.id === \"ditto_component_library\") {\n hasComponentLibraryInProjects = true;\n return;\n }\n\n project.fileName = dedupeProjectName(projectNames, project.name);\n projectNames.add(project.fileName);\n\n validProjects.push(project);\n });\n\n const shouldFetchComponentLibrary = Boolean(sources?.components?.enabled);\n\n const hasSourceData = !!validProjects.length || shouldFetchComponentLibrary;\n\n const result = {\n hasSourceData,\n validProjects,\n shouldFetchComponentLibrary,\n variants: variants || false,\n format,\n status,\n richText,\n hasTopLevelProjectsField: !!projectsRoot,\n hasTopLevelComponentsField: !!componentsRoot,\n hasComponentLibraryInProjects,\n componentFolders: sources?.components?.folders || null,\n };\n\n Sentry.setContext(\"config\", createSentryContext(result));\n\n return result;\n}\n\nexport default {\n createFileIfMissing,\n readProjectConfigData,\n readGlobalConfigData,\n writeGlobalConfigData,\n writeProjectConfigData,\n justTheHost,\n saveToken,\n deleteToken,\n getToken,\n getTokenFromEnv,\n parseSourceInformation,\n};\n"],"names":["yaml","path","fs","consts","url"],"mappings":"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","debug_id":"ee8aabef-5bac-5c7b-a33a-2a40689fc6dc"}
1
+ {"version":3,"sources":["../lib/config.ts"],"sourcesContent":["import fs from \"fs\";\nimport path from \"path\";\nimport url from \"url\";\nimport yaml from \"js-yaml\";\nimport * as Sentry from \"@sentry/node\";\n\nimport consts from \"./consts\";\nimport { createSentryContext } from \"./utils/createSentryContext\";\nimport { Project, ConfigYAML, SourceInformation } from \"./types\";\n\nexport const DEFAULT_CONFIG_JSON: ConfigYAML = {\n sources: {\n components: true,\n },\n variants: true,\n format: \"flat\",\n};\n\nexport const DEFAULT_CONFIG = yaml.dump(DEFAULT_CONFIG_JSON);\n\nfunction createFileIfMissing(filename: string, defaultContents?: any) {\n const dir = path.dirname(filename);\n\n // create the directory if it doesn't already exist\n if (!fs.existsSync(dir)) fs.mkdirSync(dir);\n\n // create the file if it doesn't already exist\n if (!fs.existsSync(filename)) {\n // create the file, writing the `defaultContents` if provided\n fs.writeFileSync(filename, defaultContents || \"\", \"utf-8\");\n }\n}\n\nfunction jsonIsConfigYAML(json: unknown): json is ConfigYAML {\n return typeof json === \"object\";\n}\n\nfunction jsonIsGlobalYAML(\n json: unknown\n): json is Record<string, { token: string }[]> {\n return (\n !!json &&\n typeof json === \"object\" &&\n Object.values(json).every(\n (arr) =>\n (arr as any).every &&\n arr.every(\n (val: any) =>\n typeof val === \"object\" && Object.keys(val).includes(\"token\")\n )\n )\n );\n}\n\n/**\n * Read data from a project config file\n * @param {string} file defaults to `PROJECT_CONFIG_FILE` defined in `constants.js`\n * @param {*} defaultData defaults to `{}`\n * @returns { ConfigYAML }\n */\nfunction readProjectConfigData(\n file = consts.PROJECT_CONFIG_FILE,\n defaultData = {}\n): ConfigYAML {\n createFileIfMissing(file, DEFAULT_CONFIG);\n const fileContents = fs.readFileSync(file, \"utf8\");\n const yamlData = yaml.load(fileContents);\n if (jsonIsConfigYAML(yamlData)) {\n return yamlData;\n }\n return defaultData;\n}\n\n/**\n * Read data from a global config file\n * @param {string} file defaults to `CONFIG_FILE` defined in `constants.js`\n * @param {*} defaultData defaults to `{}`\n * @returns { Record<string, { token: string }[]> }\n */\nfunction readGlobalConfigData(\n file = consts.CONFIG_FILE,\n defaultData = {}\n): Record<string, { token: string }[]> {\n createFileIfMissing(file);\n const fileContents = fs.readFileSync(file, \"utf8\");\n const yamlData = yaml.load(fileContents);\n if (jsonIsGlobalYAML(yamlData)) {\n return yamlData;\n }\n return defaultData;\n}\n\nfunction writeProjectConfigData(file: string, data: Partial<ConfigYAML>) {\n createFileIfMissing(file, DEFAULT_CONFIG);\n const existingData = readProjectConfigData(file);\n\n const configData: ConfigYAML = {\n ...existingData,\n ...data,\n sources: {\n ...existingData.sources,\n ...data.sources,\n },\n };\n\n const yamlStr = yaml.dump(configData);\n fs.writeFileSync(file, yamlStr, \"utf8\");\n}\n\nfunction writeGlobalConfigData(file: string, data: object) {\n createFileIfMissing(file);\n const existingData = readGlobalConfigData(file);\n const yamlStr = yaml.dump({ ...existingData, ...data });\n fs.writeFileSync(file, yamlStr, \"utf8\");\n}\n\nfunction justTheHost(host: string) {\n if (!host.includes(\"://\")) return host;\n return url.parse(host).hostname || \"\";\n}\n\nfunction deleteToken(file: string, host: string) {\n const data = readGlobalConfigData(file);\n const hostParsed = justTheHost(host);\n data[hostParsed] = [];\n data[hostParsed][0] = { token: \"\" };\n writeGlobalConfigData(file, data);\n}\n\nfunction saveToken(file: string, host: string, token: string) {\n const data = readGlobalConfigData(file);\n const hostParsed = justTheHost(host);\n data[hostParsed] = []; // only allow one token per host\n data[hostParsed][0] = { token };\n writeGlobalConfigData(file, data);\n}\n\nfunction getTokenFromEnv() {\n return process.env.DITTO_API_KEY;\n}\n\n/**\n *\n * @param {string} file\n * @param {string} host\n * @returns {Token}\n */\nfunction getToken(file: string, host: string) {\n const tokenFromEnv = getTokenFromEnv();\n if (tokenFromEnv) {\n return tokenFromEnv;\n }\n\n const data = readGlobalConfigData(file);\n const hostEntry = data[justTheHost(host)];\n if (!hostEntry) return undefined;\n const { length } = hostEntry;\n\n return hostEntry[length - 1].token;\n}\n\nconst IS_DUPLICATE = /-(\\d+$)/;\n\nfunction dedupeProjectName(projectNames: Set<string>, projectName: string) {\n let dedupedName = projectName;\n\n if (projectNames.has(dedupedName)) {\n while (projectNames.has(dedupedName)) {\n const [_, numberStr] = dedupedName.match(IS_DUPLICATE) || [];\n if (numberStr && !isNaN(parseInt(numberStr))) {\n dedupedName = `${dedupedName.replace(IS_DUPLICATE, \"\")}-${\n parseInt(numberStr) + 1\n }`;\n } else {\n dedupedName = `${dedupedName}-1`;\n }\n }\n }\n\n return dedupedName;\n}\n\n/**\n * Reads from the config file, filters out\n * invalid projects, dedupes those remaining, and returns:\n * - whether or not the data required to `pull` is present\n * - whether or not the component library should be fetched\n * - an array of valid, deduped projects\n * - the `variants` and `format` config options\n */\nfunction parseSourceInformation(file?: string): SourceInformation {\n const {\n sources,\n variants,\n format,\n status,\n richText,\n projects: projectsRoot,\n components: componentsRoot,\n } = readProjectConfigData(file);\n\n const projects = sources?.projects || [];\n\n const projectNames = new Set<string>();\n const validProjects: Project[] = [];\n let hasComponentLibraryInProjects = false;\n\n (projects || []).forEach((project) => {\n const isValid = project.id && project.name;\n if (!isValid) {\n return;\n }\n\n if (project.id === \"ditto_component_library\") {\n hasComponentLibraryInProjects = true;\n return;\n }\n\n project.fileName = dedupeProjectName(projectNames, project.name);\n projectNames.add(project.fileName);\n\n validProjects.push(project);\n });\n\n const shouldFetchComponentLibrary = Boolean(sources?.components);\n const componentRoot =\n typeof sources?.components === \"object\"\n ? sources.components.root\n : undefined;\n const componentFolders =\n typeof sources?.components === \"object\"\n ? sources.components.folders\n : undefined;\n\n /**\n * If it's not specified to fetch projects or the component library, then there\n * is no source data to pull.\n */\n const hasSourceData = !!validProjects.length || shouldFetchComponentLibrary;\n\n const result = {\n hasSourceData,\n validProjects,\n shouldFetchComponentLibrary,\n variants: variants || false,\n format,\n status,\n richText,\n hasTopLevelProjectsField: !!projectsRoot,\n hasTopLevelComponentsField: !!componentsRoot,\n hasComponentLibraryInProjects,\n componentRoot,\n componentFolders,\n };\n\n Sentry.setContext(\"config\", createSentryContext(result));\n\n return result;\n}\n\nexport default {\n createFileIfMissing,\n readProjectConfigData,\n readGlobalConfigData,\n writeGlobalConfigData,\n writeProjectConfigData,\n justTheHost,\n saveToken,\n deleteToken,\n getToken,\n getTokenFromEnv,\n parseSourceInformation,\n};\n"],"names":["yaml","path","fs","consts","url"],"mappings":"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","debug_id":"3f451b9b-6016-532a-b399-58b8b273e73c"}
package/bin/ditto.js CHANGED
@@ -74,7 +74,7 @@ var import_generate_suggestions = require("./generate-suggestions");
74
74
  var import_processMetaOption = __toESM(require("./utils/processMetaOption"));
75
75
  var import_importComponents = require("./importComponents");
76
76
  var import_component_folders = require("./component-folders");
77
- const environment = "development";
77
+ const environment = "production";
78
78
  Sentry.init({ dsn: "https://9c1d99fa4267f54c6b914f720b4ed3a2@o979374.ingest.sentry.io/4505705213919232", environment, release: import_package.version });
79
79
  function getVersion() {
80
80
  const packageJsonPath = import_path.default.join(__dirname, "..", "package.json");
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{},n=(new Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="b43cdc7c-6dfd-5905-973e-f9c6d8d334c3")}catch(e){}}();
2
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{},n=(new Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="fe72409f-ce5c-58cd-8ee2-da472d2578a7")}catch(e){}}();
3
3
 
4
4
  var __create = Object.create;
5
5
  var __defProp = Object.defineProperty;
@@ -68,7 +68,7 @@ var import_quit = require("../utils/quit");
68
68
  function saveProject(file, name, id) {
69
69
  if (id === "components") {
70
70
  import_config.default.writeProjectConfigData(file, {
71
- sources: { components: { enabled: true } }
71
+ sources: { components: true }
72
72
  });
73
73
  return;
74
74
  }
@@ -179,4 +179,4 @@ var project_default = { needsSource, collectAndSaveSource };
179
179
  });
180
180
  //# sourceMappingURL=project.js.map
181
181
 
182
- //# debugId=b43cdc7c-6dfd-5905-973e-f9c6d8d334c3
182
+ //# debugId=fe72409f-ce5c-58cd-8ee2-da472d2578a7
@@ -1 +1 @@
1
- {"version":3,"sources":["../../lib/init/project.ts"],"sourcesContent":["import ora from \"ora\";\n\nimport { createApiClient } from \"../api\";\nimport config from \"../config\";\nimport consts from \"../consts\";\nimport output from \"../output\";\nimport { collectAndSaveToken } from \"./token\";\nimport {\n getSelectedProjects,\n getIsUsingComponents,\n} from \"../utils/getSelectedProjects\";\nimport promptForProject from \"../utils/promptForProject\";\nimport { AxiosResponse } from \"axios\";\nimport { Project, Token } from \"../types\";\nimport { quit } from \"../utils/quit\";\n\nfunction saveProject(file: string, name: string, id: string) {\n if (id === \"components\") {\n config.writeProjectConfigData(file, {\n sources: { components: { enabled: true } },\n });\n return;\n }\n\n const projects = [...getSelectedProjects(file), { name, id }];\n config.writeProjectConfigData(file, { sources: { projects } });\n}\n\nexport const needsSource = () => {\n return !config.parseSourceInformation().hasSourceData;\n};\n\nasync function askForAnotherToken() {\n config.deleteToken(consts.CONFIG_FILE, consts.API_HOST);\n const message =\n \"Looks like the API key you have saved no longer works. Please enter another one.\";\n await collectAndSaveToken(message);\n}\n\nasync function listProjects(token: Token, projectsAlreadySelected: Project[]) {\n const api = createApiClient();\n const spinner = ora(\"Fetching sources in your workspace...\");\n spinner.start();\n\n let response: AxiosResponse<{ id: string; name: string }[]>;\n try {\n response = await api.get(\"/project-names\");\n } catch (e) {\n spinner.stop();\n throw e;\n }\n\n const projectsAlreadySelectedSet = projectsAlreadySelected.reduce(\n (set, project) => set.add(project.id.toString()),\n new Set<string>()\n );\n\n const result = response.data.filter(\n ({ id }) =>\n // covers an edge case where v0 of the API includes the component library\n // in the response from the `/project-names` endpoint\n id !== \"ditto_component_library\" &&\n !projectsAlreadySelectedSet.has(id.toString())\n );\n\n spinner.stop();\n\n return result;\n}\n\nasync function collectSource(token: Token, includeComponents: boolean) {\n const projectsAlreadySelected = getSelectedProjects();\n const componentSourceSelected = getIsUsingComponents();\n\n let sources = await listProjects(token, projectsAlreadySelected);\n if (includeComponents && !componentSourceSelected) {\n sources = [\n { id: \"ditto_component_library\", name: \"Ditto Component Library\" },\n ...sources,\n ];\n }\n\n if (!sources?.length) {\n console.log(\"You're currently syncing all projects in your workspace.\");\n console.log(\n output.warnText(\n \"Not seeing a project that you were expecting? Verify that developer mode is enabled on that project. More info: https://www.dittowords.com/docs/ditto-developer-mode\"\n )\n );\n return null;\n }\n\n return promptForProject({\n projects: sources,\n message: \"Choose the source you'd like to sync text from\",\n });\n}\n\nexport const collectAndSaveSource = async (\n { components = false }: { initialize?: boolean; components?: boolean } = {\n components: false,\n }\n) => {\n try {\n const token = config.getToken(consts.CONFIG_FILE, consts.API_HOST);\n const project = await collectSource(token, components);\n if (!project) {\n quit(null, 0);\n return;\n }\n\n console.log(\n \"\\n\" +\n `Thanks for adding ${output.info(\n project.name\n )} to your selected sources.\\n` +\n `We saved your updated configuration to: ${output.info(\n consts.PROJECT_CONFIG_FILE\n )}\\n`\n );\n\n saveProject(consts.PROJECT_CONFIG_FILE, project.name, project.id);\n } catch (e: any) {\n console.log(e);\n if (e.response && e.response.status === 404) {\n await askForAnotherToken();\n await collectAndSaveSource({ components });\n } else {\n quit(null, 2);\n }\n }\n};\n\nexport const _testing = { saveProject, needsSource };\n\nexport default { needsSource, collectAndSaveSource };\n"],"names":["config","consts","ora","output","promptForProject"],"mappings":"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","debug_id":"b43cdc7c-6dfd-5905-973e-f9c6d8d334c3"}
1
+ {"version":3,"sources":["../../lib/init/project.ts"],"sourcesContent":["import ora from \"ora\";\n\nimport { createApiClient } from \"../api\";\nimport config from \"../config\";\nimport consts from \"../consts\";\nimport output from \"../output\";\nimport { collectAndSaveToken } from \"./token\";\nimport {\n getSelectedProjects,\n getIsUsingComponents,\n} from \"../utils/getSelectedProjects\";\nimport promptForProject from \"../utils/promptForProject\";\nimport { AxiosResponse } from \"axios\";\nimport { Project, Token } from \"../types\";\nimport { quit } from \"../utils/quit\";\n\nfunction saveProject(file: string, name: string, id: string) {\n if (id === \"components\") {\n config.writeProjectConfigData(file, {\n sources: { components: true },\n });\n return;\n }\n\n const projects = [...getSelectedProjects(file), { name, id }];\n config.writeProjectConfigData(file, { sources: { projects } });\n}\n\nexport const needsSource = () => {\n return !config.parseSourceInformation().hasSourceData;\n};\n\nasync function askForAnotherToken() {\n config.deleteToken(consts.CONFIG_FILE, consts.API_HOST);\n const message =\n \"Looks like the API key you have saved no longer works. Please enter another one.\";\n await collectAndSaveToken(message);\n}\n\nasync function listProjects(token: Token, projectsAlreadySelected: Project[]) {\n const api = createApiClient();\n const spinner = ora(\"Fetching sources in your workspace...\");\n spinner.start();\n\n let response: AxiosResponse<{ id: string; name: string }[]>;\n try {\n response = await api.get(\"/project-names\");\n } catch (e) {\n spinner.stop();\n throw e;\n }\n\n const projectsAlreadySelectedSet = projectsAlreadySelected.reduce(\n (set, project) => set.add(project.id.toString()),\n new Set<string>()\n );\n\n const result = response.data.filter(\n ({ id }) =>\n // covers an edge case where v0 of the API includes the component library\n // in the response from the `/project-names` endpoint\n id !== \"ditto_component_library\" &&\n !projectsAlreadySelectedSet.has(id.toString())\n );\n\n spinner.stop();\n\n return result;\n}\n\nasync function collectSource(token: Token, includeComponents: boolean) {\n const projectsAlreadySelected = getSelectedProjects();\n const componentSourceSelected = getIsUsingComponents();\n\n let sources = await listProjects(token, projectsAlreadySelected);\n if (includeComponents && !componentSourceSelected) {\n sources = [\n { id: \"ditto_component_library\", name: \"Ditto Component Library\" },\n ...sources,\n ];\n }\n\n if (!sources?.length) {\n console.log(\"You're currently syncing all projects in your workspace.\");\n console.log(\n output.warnText(\n \"Not seeing a project that you were expecting? Verify that developer mode is enabled on that project. More info: https://www.dittowords.com/docs/ditto-developer-mode\"\n )\n );\n return null;\n }\n\n return promptForProject({\n projects: sources,\n message: \"Choose the source you'd like to sync text from\",\n });\n}\n\nexport const collectAndSaveSource = async (\n { components = false }: { initialize?: boolean; components?: boolean } = {\n components: false,\n }\n) => {\n try {\n const token = config.getToken(consts.CONFIG_FILE, consts.API_HOST);\n const project = await collectSource(token, components);\n if (!project) {\n quit(null, 0);\n return;\n }\n\n console.log(\n \"\\n\" +\n `Thanks for adding ${output.info(\n project.name\n )} to your selected sources.\\n` +\n `We saved your updated configuration to: ${output.info(\n consts.PROJECT_CONFIG_FILE\n )}\\n`\n );\n\n saveProject(consts.PROJECT_CONFIG_FILE, project.name, project.id);\n } catch (e: any) {\n console.log(e);\n if (e.response && e.response.status === 404) {\n await askForAnotherToken();\n await collectAndSaveSource({ components });\n } else {\n quit(null, 2);\n }\n }\n};\n\nexport const _testing = { saveProject, needsSource };\n\nexport default { needsSource, collectAndSaveSource };\n"],"names":["config","consts","ora","output","promptForProject"],"mappings":"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","debug_id":"fe72409f-ce5c-58cd-8ee2-da472d2578a7"}