@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/bin/pull.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]="c9f589e3-b75d-5846-b29d-266ca10a8560")}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]="8e8abce7-7d1b-5b40-96a6-09318358142e")}catch(e){}}();
3
3
 
4
4
  var __create = Object.create;
5
5
  var __defProp = Object.defineProperty;
@@ -84,6 +84,9 @@ var import_cleanFileName = require("./utils/cleanFileName");
84
84
  var import_fetchVariants = require("./http/fetchVariants");
85
85
  var import_quit = require("./utils/quit");
86
86
  var import_axios = require("axios");
87
+ var import_fetchComponentFolders = require("./http/fetchComponentFolders");
88
+ const ensureEndsWithNewLine = (str) => str + (/[\r\n]$/.test(str) ? "" : "\n");
89
+ const writeFile = (path2, data) => new Promise((r) => import_fs.default.writeFile(path2, ensureEndsWithNewLine(data), r));
87
90
  const SUPPORTED_FORMATS = [
88
91
  "flat",
89
92
  "structured",
@@ -149,14 +152,19 @@ function downloadAndSaveVariant(variantApiId, projects, format, status, richText
149
152
  const params = { variant: variantApiId };
150
153
  if (format)
151
154
  params.format = format;
152
- if (status)
153
- params.status = status;
154
155
  if (richText)
155
156
  params.includeRichText = richText.toString();
157
+ if (status)
158
+ params.status = status;
156
159
  const savedMessages = yield Promise.all(
157
- projects.map((_0) => __async(this, [_0], function* ({ id, fileName }) {
158
- const { data } = yield api.get(`/projects/${id}`, {
159
- params,
160
+ projects.map((project) => __async(this, null, function* () {
161
+ const projectParams = __spreadValues({}, params);
162
+ if (project.status)
163
+ projectParams.status = project.status;
164
+ if (project.exclude_components)
165
+ projectParams.exclude_components = String(project.exclude_components);
166
+ const { data } = yield api.get(`/projects/${project.id}`, {
167
+ params: projectParams,
160
168
  headers: { Authorization: `token ${token}` }
161
169
  });
162
170
  if (!hasVariantData(data)) {
@@ -164,7 +172,7 @@ function downloadAndSaveVariant(variantApiId, projects, format, status, richText
164
172
  }
165
173
  const extension = getFormatExtension(format);
166
174
  const filename = (0, import_cleanFileName.cleanFileName)(
167
- fileName + ("__" + (variantApiId || "base")) + extension
175
+ project.fileName + ("__" + (variantApiId || "base")) + extension
168
176
  );
169
177
  const filepath = import_path.default.join(import_consts.default.TEXT_DIR, filename);
170
178
  let dataString = data;
@@ -175,7 +183,7 @@ function downloadAndSaveVariant(variantApiId, projects, format, status, richText
175
183
  if (!dataIsValid(dataString)) {
176
184
  return "";
177
185
  }
178
- import_fs.default.writeFileSync(filepath, dataString);
186
+ yield writeFile(filepath, dataString);
179
187
  return getSavedMessage(filename);
180
188
  }))
181
189
  );
@@ -199,18 +207,23 @@ function downloadAndSaveBase(projects, format, status, richText, token, options)
199
207
  const params = __spreadValues({}, options == null ? void 0 : options.meta);
200
208
  if (format)
201
209
  params.format = format;
202
- if (status)
203
- params.status = status;
204
210
  if (richText)
205
211
  params.includeRichText = richText.toString();
212
+ if (status)
213
+ params.status = status;
206
214
  const savedMessages = yield Promise.all(
207
- projects.map((_0) => __async(this, [_0], function* ({ id, fileName }) {
208
- const { data } = yield api.get(`/projects/${id}`, {
209
- params,
215
+ projects.map((project) => __async(this, null, function* () {
216
+ const projectParams = __spreadValues({}, params);
217
+ if (project.status)
218
+ projectParams.status = project.status;
219
+ if (project.exclude_components)
220
+ projectParams.exclude_components = String(project.exclude_components);
221
+ const { data } = yield api.get(`/projects/${project.id}`, {
222
+ params: projectParams,
210
223
  headers: { Authorization: `token ${token}` }
211
224
  });
212
225
  const extension = getFormatExtension(format);
213
- const filename = (0, import_cleanFileName.cleanFileName)(`${fileName}__base${extension}`);
226
+ const filename = (0, import_cleanFileName.cleanFileName)(`${project.fileName}__base${extension}`);
214
227
  const filepath = import_path.default.join(import_consts.default.TEXT_DIR, filename);
215
228
  let dataString = data;
216
229
  if (extension === ".json") {
@@ -220,7 +233,7 @@ function downloadAndSaveBase(projects, format, status, richText, token, options)
220
233
  if (!dataIsValid(dataString)) {
221
234
  return "";
222
235
  }
223
- import_fs.default.writeFileSync(filepath, dataString);
236
+ yield writeFile(filepath, dataString);
224
237
  return getSavedMessage(filename);
225
238
  }))
226
239
  );
@@ -252,13 +265,23 @@ function downloadAndSave(source, token, options) {
252
265
  shouldFetchComponentLibrary,
253
266
  status,
254
267
  richText,
255
- componentFolders
268
+ componentFolders: specifiedComponentFolders,
269
+ componentRoot
256
270
  } = source;
257
271
  const formats = getFormat(formatFromSource);
258
272
  let msg = "";
259
273
  const spinner = (0, import_ora.default)(msg);
260
274
  spinner.start();
261
- const variants = yield (0, import_fetchVariants.fetchVariants)(source);
275
+ const [variants, allComponentFoldersResponse] = yield Promise.all([
276
+ (0, import_fetchVariants.fetchVariants)(source),
277
+ (0, import_fetchComponentFolders.fetchComponentFolders)()
278
+ ]);
279
+ const allComponentFolders = Object.entries(
280
+ allComponentFoldersResponse
281
+ ).reduce(
282
+ (acc, [id, name]) => acc.concat([{ id, name }]),
283
+ []
284
+ );
262
285
  try {
263
286
  msg += cleanOutputFiles();
264
287
  msg += `
@@ -268,6 +291,39 @@ Fetching the latest text from ${(0, import_sourcesToText.default)(
268
291
  )}
269
292
  `;
270
293
  const meta = options ? options.meta : {};
294
+ const rootRequest = {
295
+ id: "__root__",
296
+ name: "Root",
297
+ // componentRoot can be a boolean or an object
298
+ status: typeof source.componentRoot === "object" ? source.componentRoot.status : void 0
299
+ };
300
+ let componentFolderRequests = [];
301
+ if (specifiedComponentFolders) {
302
+ switch (componentRoot) {
303
+ case void 0:
304
+ case false:
305
+ componentFolderRequests.push(...specifiedComponentFolders);
306
+ break;
307
+ default:
308
+ componentFolderRequests.push(...specifiedComponentFolders);
309
+ componentFolderRequests.push(rootRequest);
310
+ break;
311
+ }
312
+ } else {
313
+ switch (componentRoot) {
314
+ case void 0:
315
+ componentFolderRequests.push(...allComponentFolders);
316
+ componentFolderRequests.push(rootRequest);
317
+ break;
318
+ case false:
319
+ componentFolderRequests.push(...allComponentFolders);
320
+ break;
321
+ default:
322
+ componentFolderRequests.push(rootRequest);
323
+ break;
324
+ }
325
+ }
326
+ const componentSources = [];
271
327
  function fetchComponentLibrary(format) {
272
328
  return __async(this, null, function* () {
273
329
  const componentVariants = [{ apiID: void 0 }, ...variants || []];
@@ -276,36 +332,52 @@ Fetching the latest text from ${(0, import_sourcesToText.default)(
276
332
  Object.entries(options.meta).forEach(([k, v]) => params.append(k, v));
277
333
  if (format)
278
334
  params.append("format", format);
279
- if (status)
280
- params.append("status", status);
281
335
  if (richText)
282
336
  params.append("includeRichText", richText.toString());
283
- if (componentFolders) {
284
- componentFolders.forEach(({ id }) => params.append("folder_id[]", id));
285
- }
286
- const messages = yield Promise.all(
287
- componentVariants.map((_0) => __async(this, [_0], function* ({ apiID: variantApiId }) {
288
- const p = new URLSearchParams(params);
289
- if (variantApiId)
290
- p.append("variant", variantApiId);
291
- const { data } = yield api.get(`/components`, { params: p });
292
- const nameExt = getFormatExtension(format);
293
- const nameBase = "ditto-component-library";
294
- const namePostfix = `__${variantApiId || "base"}`;
295
- const fileName = (0, import_cleanFileName.cleanFileName)(`${nameBase}${namePostfix}${nameExt}`);
296
- const filePath = import_path.default.join(import_consts.default.TEXT_DIR, fileName);
297
- let dataString = data;
298
- if (nameExt === ".json") {
299
- dataString = JSON.stringify(data, null, 2);
300
- }
301
- const dataIsValid = getFormatDataIsValid[format];
302
- if (!dataIsValid(dataString)) {
303
- return "";
304
- }
305
- yield new Promise((r) => import_fs.default.writeFile(filePath, dataString, r));
306
- return getSavedMessage(fileName);
307
- }))
308
- );
337
+ if (status)
338
+ params.append("status", status);
339
+ const messagePromises = [];
340
+ componentVariants.forEach(({ apiID: variantApiId }) => {
341
+ messagePromises.push(
342
+ ...componentFolderRequests.map((componentFolder) => __async(this, null, function* () {
343
+ const componentFolderParams = new URLSearchParams(params);
344
+ if (variantApiId)
345
+ componentFolderParams.append("variant", variantApiId);
346
+ if (componentFolder.status)
347
+ componentFolderParams.append("status", componentFolder.status);
348
+ const url = componentFolder.id === "__root__" ? "/components?root_only=true" : `/component-folders/${componentFolder.id}/components`;
349
+ const { data } = yield api.get(url, {
350
+ params: componentFolderParams
351
+ });
352
+ const nameExt = getFormatExtension(format);
353
+ const nameBase = "components";
354
+ const nameFolder = `__${componentFolder.name}`;
355
+ const namePostfix = `__${variantApiId || "base"}`;
356
+ const fileName = (0, import_cleanFileName.cleanFileName)(
357
+ `${nameBase}${nameFolder}${namePostfix}${nameExt}`
358
+ );
359
+ const filePath = import_path.default.join(import_consts.default.TEXT_DIR, fileName);
360
+ let dataString = data;
361
+ if (nameExt === ".json") {
362
+ dataString = JSON.stringify(data, null, 2);
363
+ }
364
+ const dataIsValid = getFormatDataIsValid[format];
365
+ if (!dataIsValid(dataString)) {
366
+ return "";
367
+ }
368
+ yield writeFile(filePath, dataString);
369
+ componentSources.push({
370
+ type: "components",
371
+ id: "ditto_component_library",
372
+ name: "ditto_component_library",
373
+ fileName,
374
+ variant: variantApiId || "base"
375
+ });
376
+ return getSavedMessage(fileName);
377
+ }))
378
+ );
379
+ });
380
+ const messages = yield Promise.all(messagePromises);
309
381
  msg += messages.join("");
310
382
  });
311
383
  }
@@ -340,14 +412,7 @@ Fetching the latest text from ${(0, import_sourcesToText.default)(
340
412
  yield fetchProjects(format);
341
413
  }
342
414
  }
343
- const sources = [...validProjects];
344
- if (shouldFetchComponentLibrary) {
345
- sources.push({
346
- id: "ditto_component_library",
347
- name: "Ditto Component Library",
348
- fileName: "ditto-component-library"
349
- });
350
- }
415
+ const sources = [...validProjects, ...componentSources];
351
416
  if (formats.some((f) => JSON_FORMATS.includes(f)))
352
417
  msg += (0, import_generateJsDriver.generateJsDriver)(sources);
353
418
  msg += `
@@ -401,16 +466,21 @@ const pull = (options) => __async(void 0, null, function* () {
401
466
  try {
402
467
  return yield downloadAndSave(sourceInformation, token, { meta });
403
468
  } catch (e) {
404
- Sentry.captureException(e);
469
+ const eventId = Sentry.captureException(e);
470
+ const eventStr = `
471
+
472
+ Error ID: ${import_output.default.info(eventId)}`;
405
473
  if (e instanceof import_axios.AxiosError) {
406
474
  return (0, import_quit.quit)(
407
475
  import_output.default.errorText(
408
476
  "Something went wrong connecting to Ditto servers. Please contact support or try again later."
409
- )
477
+ ) + eventStr
410
478
  );
411
479
  }
412
480
  return (0, import_quit.quit)(
413
- import_output.default.errorText("Something went wrong. Please try again later.")
481
+ import_output.default.errorText(
482
+ "Something went wrong. Please contact support or try again later."
483
+ ) + eventStr
414
484
  );
415
485
  }
416
486
  });
@@ -430,4 +500,4 @@ var pull_default = {
430
500
  });
431
501
  //# sourceMappingURL=pull.js.map
432
502
 
433
- //# debugId=c9f589e3-b75d-5846-b29d-266ca10a8560
503
+ //# debugId=8e8abce7-7d1b-5b40-96a6-09318358142e
package/bin/pull.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../lib/pull.ts"],"sourcesContent":["import fs from \"fs\";\nimport path from \"path\";\n\nimport ora from \"ora\";\nimport * as Sentry from \"@sentry/node\";\n\nimport { createApiClient } from \"./api\";\nimport config from \"./config\";\nimport consts from \"./consts\";\nimport output from \"./output\";\nimport { collectAndSaveToken } from \"./init/token\";\nimport sourcesToText from \"./utils/sourcesToText\";\nimport { generateJsDriver } from \"./utils/generateJsDriver\";\nimport { cleanFileName } from \"./utils/cleanFileName\";\nimport { SourceInformation, Token, Project, SupportedFormat } from \"./types\";\nimport { fetchVariants } from \"./http/fetchVariants\";\nimport { kMaxLength } from \"buffer\";\nimport { quit } from \"./utils/quit\";\nimport { AxiosError } from \"axios\";\n\nconst SUPPORTED_FORMATS: SupportedFormat[] = [\n \"flat\",\n \"structured\",\n \"android\",\n \"ios-strings\",\n \"ios-stringsdict\",\n \"icu\",\n];\n\nconst JSON_FORMATS: SupportedFormat[] = [\"flat\", \"structured\", \"icu\"];\n\nconst FORMAT_EXTENSIONS = {\n flat: \".json\",\n structured: \".json\",\n android: \".xml\",\n \"ios-strings\": \".strings\",\n \"ios-stringsdict\": \".stringsdict\",\n icu: \".json\",\n};\n\nconst getJsonFormatIsValid = (data: string) => {\n try {\n return Object.keys(JSON.parse(data)).some(\n (k) => !k.startsWith(\"__variant\")\n );\n } catch {\n return false;\n }\n};\n\n// exported for test usage only\nexport const getFormatDataIsValid = {\n flat: getJsonFormatIsValid,\n structured: getJsonFormatIsValid,\n icu: getJsonFormatIsValid,\n android: (data: string) => data.includes(\"<string\"),\n \"ios-strings\": (data: string) => data.includes(`\" = \"`),\n \"ios-stringsdict\": (data: string) => data.includes(\"<key>\"),\n};\n\nconst getFormat = (\n formatFromSource: string | string[] | undefined\n): SupportedFormat[] => {\n const formats = (\n Array.isArray(formatFromSource) ? formatFromSource : [formatFromSource]\n ).filter((format) =>\n SUPPORTED_FORMATS.includes(format as SupportedFormat)\n ) as SupportedFormat[];\n\n if (formats.length) {\n return formats;\n }\n\n return [\"flat\"];\n};\n\nconst getFormatExtension = (format: SupportedFormat) => {\n return FORMAT_EXTENSIONS[format];\n};\n\nconst DEFAULT_FORMAT_KEYS = [\"projects\", \"exported_at\"];\nconst hasVariantData = (data: any) => {\n const hasTopLevelKeys =\n Object.keys(data).filter((key) => !DEFAULT_FORMAT_KEYS.includes(key))\n .length > 0;\n\n const hasProjectKeys = data.projects && Object.keys(data.projects).length > 0;\n\n return hasTopLevelKeys || hasProjectKeys;\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\n/**\n * For a given variant:\n * - if format is unspecified, fetch data for all projects from `/projects` and\n * save in `{variantApiId}.json`\n * - if format is `flat` or `structured`, fetch data for each project from `/project/:project_id` and\n * save in `{projectName}-${variantApiId}.json`\n */\nasync function downloadAndSaveVariant(\n variantApiId: string | null,\n projects: Project[],\n format: SupportedFormat,\n status: string | undefined,\n richText: boolean | undefined,\n token?: Token\n) {\n const api = createApiClient();\n const params: Record<string, string | null> = { variant: variantApiId };\n if (format) params.format = format;\n if (status) params.status = status;\n if (richText) params.includeRichText = richText.toString();\n\n const savedMessages = await Promise.all(\n projects.map(async ({ id, fileName }: Project) => {\n const { data } = await api.get(`/projects/${id}`, {\n params,\n headers: { Authorization: `token ${token}` },\n });\n\n if (!hasVariantData(data)) {\n return \"\";\n }\n\n const extension = getFormatExtension(format);\n\n const filename = cleanFileName(\n fileName + (\"__\" + (variantApiId || \"base\")) + extension\n );\n const filepath = path.join(consts.TEXT_DIR, filename);\n\n let dataString = data;\n if (extension === \".json\") {\n dataString = JSON.stringify(data, null, 2);\n }\n\n const dataIsValid = getFormatDataIsValid[format];\n if (!dataIsValid(dataString)) {\n return \"\";\n }\n\n fs.writeFileSync(filepath, dataString);\n return getSavedMessage(filename);\n })\n );\n\n return savedMessages.join(\"\");\n}\n\nasync function downloadAndSaveVariants(\n variants: { apiID: string }[],\n projects: Project[],\n format: SupportedFormat,\n status: string | undefined,\n richText: boolean | undefined,\n token?: Token\n) {\n const messages = await Promise.all([\n downloadAndSaveVariant(null, projects, format, status, richText, token),\n ...variants.map(({ apiID }: { apiID: string }) =>\n downloadAndSaveVariant(apiID, projects, format, status, richText, token)\n ),\n ]);\n\n return messages.join(\"\");\n}\n\nasync function downloadAndSaveBase(\n projects: Project[],\n format: SupportedFormat,\n status: string | undefined,\n richText?: boolean | undefined,\n token?: Token,\n options?: PullOptions\n) {\n const api = createApiClient();\n const params = { ...options?.meta };\n if (format) params.format = format;\n if (status) params.status = status;\n if (richText) params.includeRichText = richText.toString();\n\n const savedMessages = await Promise.all(\n projects.map(async ({ id, fileName }: Project) => {\n const { data } = await api.get(`/projects/${id}`, {\n params,\n headers: { Authorization: `token ${token}` },\n });\n\n const extension = getFormatExtension(format);\n const filename = cleanFileName(`${fileName}__base${extension}`);\n const filepath = path.join(consts.TEXT_DIR, filename);\n\n let dataString = data;\n if (extension === \".json\") {\n dataString = JSON.stringify(data, null, 2);\n }\n\n const dataIsValid = getFormatDataIsValid[format];\n if (!dataIsValid(dataString)) {\n return \"\";\n }\n\n fs.writeFileSync(filepath, dataString);\n return getSavedMessage(filename);\n })\n );\n\n return savedMessages.join(\"\");\n}\n\nfunction getSavedMessage(file: string) {\n return `Successfully saved to ${output.info(file)}\\n`;\n}\n\nfunction cleanOutputFiles() {\n if (!fs.existsSync(consts.TEXT_DIR)) {\n fs.mkdirSync(consts.TEXT_DIR);\n }\n\n const fileNames = fs.readdirSync(consts.TEXT_DIR);\n fileNames.forEach((fileName) => {\n if (/\\.js(on)?|\\.xml|\\.strings(dict)?$/.test(fileName)) {\n fs.unlinkSync(path.resolve(consts.TEXT_DIR, fileName));\n }\n });\n\n return \"Cleaning old output files..\\n\";\n}\n\nasync function downloadAndSave(\n source: SourceInformation,\n token?: Token,\n options?: PullOptions\n) {\n const api = createApiClient();\n const {\n validProjects,\n format: formatFromSource,\n shouldFetchComponentLibrary,\n status,\n richText,\n componentFolders,\n } = source;\n\n const formats = getFormat(formatFromSource);\n\n let msg = \"\";\n const spinner = ora(msg);\n spinner.start();\n\n const variants = await fetchVariants(source);\n\n try {\n msg += cleanOutputFiles();\n msg += `\\nFetching the latest text from ${sourcesToText(\n validProjects,\n shouldFetchComponentLibrary\n )}\\n`;\n\n const meta = options ? options.meta : {};\n\n async function fetchComponentLibrary(format: SupportedFormat) {\n // Always include a variant with an apiID of undefined to ensure that we\n // fetch the base text for the component library.\n const componentVariants = [{ apiID: undefined }, ...(variants || [])];\n\n const params = new URLSearchParams();\n if (options?.meta)\n Object.entries(options.meta).forEach(([k, v]) => params.append(k, v));\n if (format) params.append(\"format\", format);\n if (status) params.append(\"status\", status);\n if (richText) params.append(\"includeRichText\", richText.toString());\n if (componentFolders) {\n componentFolders.forEach(({ id }) => params.append(\"folder_id[]\", id));\n }\n\n const messages = await Promise.all(\n componentVariants.map(async ({ apiID: variantApiId }) => {\n const p = new URLSearchParams(params);\n if (variantApiId) p.append(\"variant\", variantApiId);\n\n const { data } = await api.get(`/components`, { params: p });\n\n const nameExt = getFormatExtension(format);\n const nameBase = \"ditto-component-library\";\n const namePostfix = `__${variantApiId || \"base\"}`;\n\n const fileName = cleanFileName(`${nameBase}${namePostfix}${nameExt}`);\n const filePath = path.join(consts.TEXT_DIR, fileName);\n\n let dataString = data;\n if (nameExt === \".json\") {\n dataString = JSON.stringify(data, null, 2);\n }\n\n const dataIsValid = getFormatDataIsValid[format];\n if (!dataIsValid(dataString)) {\n return \"\";\n }\n\n await new Promise((r) => fs.writeFile(filePath, dataString, r));\n return getSavedMessage(fileName);\n })\n );\n\n msg += messages.join(\"\");\n }\n\n if (shouldFetchComponentLibrary) {\n for (const format of formats) {\n await fetchComponentLibrary(format);\n }\n }\n\n async function fetchProjects(format: SupportedFormat) {\n msg += variants\n ? await downloadAndSaveVariants(\n variants,\n validProjects,\n format,\n status,\n richText,\n token\n )\n : await downloadAndSaveBase(\n validProjects,\n format,\n status,\n richText,\n token,\n {\n meta,\n }\n );\n }\n\n if (validProjects.length) {\n for (const format of formats) {\n await fetchProjects(format);\n }\n }\n\n const sources = [...validProjects];\n if (shouldFetchComponentLibrary) {\n sources.push({\n id: \"ditto_component_library\",\n name: \"Ditto Component Library\",\n fileName: \"ditto-component-library\",\n });\n }\n\n if (formats.some((f) => JSON_FORMATS.includes(f)))\n msg += generateJsDriver(sources);\n\n msg += `\\n${output.success(\"Done\")}!`;\n\n spinner.stop();\n return console.log(msg);\n } catch (e: any) {\n console.error(e);\n\n spinner.stop();\n let error = e.message;\n if (e.response && e.response.status === 404) {\n await askForAnotherToken();\n pull();\n return;\n }\n if (e.response && e.response.status === 401) {\n error = \"You don't have access to the selected projects\";\n msg = `${output.errorText(error)}.\\nChoose others using the ${output.info(\n \"project\"\n )} command, or update your API key.`;\n return console.log(msg);\n }\n if (e.response && e.response.status === 403) {\n error =\n \"One or more of the requested projects don't have Developer Mode enabled\";\n msg = `${output.errorText(\n error\n )}.\\nPlease choose different projects using the ${output.info(\n \"project\"\n )} command, or turn on Developer Mode for all selected projects. Learn more here: ${output.subtle(\n \"https://www.dittowords.com/docs/ditto-developer-mode\"\n )}.`;\n return console.log(msg);\n }\n if (e.response && e.response.status === 400) {\n error = \"projects not found\";\n }\n msg = `We hit an error fetching text from the projects: ${output.errorText(\n error\n )}.\\nChoose others using the ${output.info(\"project\")} command.`;\n return console.log(msg);\n }\n}\n\nexport interface PullOptions {\n meta?: Record<string, string>;\n}\n\nexport const pull = async (options?: PullOptions) => {\n const meta = options ? options.meta : {};\n const token = config.getToken(consts.CONFIG_FILE, consts.API_HOST);\n const sourceInformation = config.parseSourceInformation();\n\n try {\n return await downloadAndSave(sourceInformation, token, { meta });\n } catch (e) {\n Sentry.captureException(e);\n if (e instanceof AxiosError) {\n return quit(\n output.errorText(\n \"Something went wrong connecting to Ditto servers. Please contact support or try again later.\"\n )\n );\n }\n\n return quit(\n output.errorText(\"Something went wrong. Please try again later.\")\n );\n }\n};\n\nexport default {\n pull,\n _testing: {\n cleanOutputFiles,\n downloadAndSaveVariant,\n downloadAndSaveVariants,\n downloadAndSaveBase,\n },\n};\n"],"names":["config","consts","path","fs","output","ora","sourcesToText"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gBAAe;AACf,kBAAiB;AAEjB,iBAAgB;AAChB,aAAwB;AAExB,iBAAgC;AAChC,oBAAmB;AACnB,oBAAmB;AACnB,oBAAmB;AACnB,mBAAoC;AACpC,2BAA0B;AAC1B,8BAAiC;AACjC,2BAA8B;AAE9B,2BAA8B;AAE9B,kBAAqB;AACrB,mBAA2B;AAE3B,MAAM,oBAAuC;AAAA,EAC3C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,MAAM,eAAkC,CAAC,QAAQ,cAAc,KAAK;AAEpE,MAAM,oBAAoB;AAAA,EACxB,MAAM;AAAA,EACN,YAAY;AAAA,EACZ,SAAS;AAAA,EACT,eAAe;AAAA,EACf,mBAAmB;AAAA,EACnB,KAAK;AACP;AAEA,MAAM,uBAAuB,CAAC,SAAiB;AAC7C,MAAI;AACF,WAAO,OAAO,KAAK,KAAK,MAAM,IAAI,CAAC,EAAE;AAAA,MACnC,CAAC,MAAM,CAAC,EAAE,WAAW,WAAW;AAAA,IAClC;AAAA,EACF,SAAQ;AACN,WAAO;AAAA,EACT;AACF;AAGO,MAAM,uBAAuB;AAAA,EAClC,MAAM;AAAA,EACN,YAAY;AAAA,EACZ,KAAK;AAAA,EACL,SAAS,CAAC,SAAiB,KAAK,SAAS,SAAS;AAAA,EAClD,eAAe,CAAC,SAAiB,KAAK,SAAS,OAAO;AAAA,EACtD,mBAAmB,CAAC,SAAiB,KAAK,SAAS,OAAO;AAC5D;AAEA,MAAM,YAAY,CAChB,qBACsB;AACtB,QAAM,WACJ,MAAM,QAAQ,gBAAgB,IAAI,mBAAmB,CAAC,gBAAgB,GACtE;AAAA,IAAO,CAAC,WACR,kBAAkB,SAAS,MAAyB;AAAA,EACtD;AAEA,MAAI,QAAQ,QAAQ;AAClB,WAAO;AAAA,EACT;AAEA,SAAO,CAAC,MAAM;AAChB;AAEA,MAAM,qBAAqB,CAAC,WAA4B;AACtD,SAAO,kBAAkB,MAAM;AACjC;AAEA,MAAM,sBAAsB,CAAC,YAAY,aAAa;AACtD,MAAM,iBAAiB,CAAC,SAAc;AACpC,QAAM,kBACJ,OAAO,KAAK,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC,oBAAoB,SAAS,GAAG,CAAC,EACjE,SAAS;AAEd,QAAM,iBAAiB,KAAK,YAAY,OAAO,KAAK,KAAK,QAAQ,EAAE,SAAS;AAE5E,SAAO,mBAAmB;AAC5B;AAEA,SAAe,qBAAqB;AAAA;AAClC,kBAAAA,QAAO,YAAY,cAAAC,QAAO,aAAa,cAAAA,QAAO,QAAQ;AACtD,UAAM,UACJ;AACF,cAAM,kCAAoB,OAAO;AAAA,EACnC;AAAA;AASA,SAAe,uBACb,cACA,UACA,QACA,QACA,UACA,OACA;AAAA;AACA,UAAM,UAAM,4BAAgB;AAC5B,UAAM,SAAwC,EAAE,SAAS,aAAa;AACtE,QAAI;AAAQ,aAAO,SAAS;AAC5B,QAAI;AAAQ,aAAO,SAAS;AAC5B,QAAI;AAAU,aAAO,kBAAkB,SAAS,SAAS;AAEzD,UAAM,gBAAgB,MAAM,QAAQ;AAAA,MAClC,SAAS,IAAI,CAAO,OAA8B,eAA9B,KAA8B,WAA9B,EAAE,IAAI,SAAS,GAAe;AAChD,cAAM,EAAE,KAAK,IAAI,MAAM,IAAI,IAAI,aAAa,EAAE,IAAI;AAAA,UAChD;AAAA,UACA,SAAS,EAAE,eAAe,SAAS,KAAK,GAAG;AAAA,QAC7C,CAAC;AAED,YAAI,CAAC,eAAe,IAAI,GAAG;AACzB,iBAAO;AAAA,QACT;AAEA,cAAM,YAAY,mBAAmB,MAAM;AAE3C,cAAM,eAAW;AAAA,UACf,YAAY,QAAQ,gBAAgB,WAAW;AAAA,QACjD;AACA,cAAM,WAAW,YAAAC,QAAK,KAAK,cAAAD,QAAO,UAAU,QAAQ;AAEpD,YAAI,aAAa;AACjB,YAAI,cAAc,SAAS;AACzB,uBAAa,KAAK,UAAU,MAAM,MAAM,CAAC;AAAA,QAC3C;AAEA,cAAM,cAAc,qBAAqB,MAAM;AAC/C,YAAI,CAAC,YAAY,UAAU,GAAG;AAC5B,iBAAO;AAAA,QACT;AAEA,kBAAAE,QAAG,cAAc,UAAU,UAAU;AACrC,eAAO,gBAAgB,QAAQ;AAAA,MACjC,EAAC;AAAA,IACH;AAEA,WAAO,cAAc,KAAK,EAAE;AAAA,EAC9B;AAAA;AAEA,SAAe,wBACb,UACA,UACA,QACA,QACA,UACA,OACA;AAAA;AACA,UAAM,WAAW,MAAM,QAAQ,IAAI;AAAA,MACjC,uBAAuB,MAAM,UAAU,QAAQ,QAAQ,UAAU,KAAK;AAAA,MACtE,GAAG,SAAS;AAAA,QAAI,CAAC,EAAE,MAAM,MACvB,uBAAuB,OAAO,UAAU,QAAQ,QAAQ,UAAU,KAAK;AAAA,MACzE;AAAA,IACF,CAAC;AAED,WAAO,SAAS,KAAK,EAAE;AAAA,EACzB;AAAA;AAEA,SAAe,oBACb,UACA,QACA,QACA,UACA,OACA,SACA;AAAA;AACA,UAAM,UAAM,4BAAgB;AAC5B,UAAM,SAAS,mBAAK,mCAAS;AAC7B,QAAI;AAAQ,aAAO,SAAS;AAC5B,QAAI;AAAQ,aAAO,SAAS;AAC5B,QAAI;AAAU,aAAO,kBAAkB,SAAS,SAAS;AAEzD,UAAM,gBAAgB,MAAM,QAAQ;AAAA,MAClC,SAAS,IAAI,CAAO,OAA8B,eAA9B,KAA8B,WAA9B,EAAE,IAAI,SAAS,GAAe;AAChD,cAAM,EAAE,KAAK,IAAI,MAAM,IAAI,IAAI,aAAa,EAAE,IAAI;AAAA,UAChD;AAAA,UACA,SAAS,EAAE,eAAe,SAAS,KAAK,GAAG;AAAA,QAC7C,CAAC;AAED,cAAM,YAAY,mBAAmB,MAAM;AAC3C,cAAM,eAAW,oCAAc,GAAG,QAAQ,SAAS,SAAS,EAAE;AAC9D,cAAM,WAAW,YAAAD,QAAK,KAAK,cAAAD,QAAO,UAAU,QAAQ;AAEpD,YAAI,aAAa;AACjB,YAAI,cAAc,SAAS;AACzB,uBAAa,KAAK,UAAU,MAAM,MAAM,CAAC;AAAA,QAC3C;AAEA,cAAM,cAAc,qBAAqB,MAAM;AAC/C,YAAI,CAAC,YAAY,UAAU,GAAG;AAC5B,iBAAO;AAAA,QACT;AAEA,kBAAAE,QAAG,cAAc,UAAU,UAAU;AACrC,eAAO,gBAAgB,QAAQ;AAAA,MACjC,EAAC;AAAA,IACH;AAEA,WAAO,cAAc,KAAK,EAAE;AAAA,EAC9B;AAAA;AAEA,SAAS,gBAAgB,MAAc;AACrC,SAAO,yBAAyB,cAAAC,QAAO,KAAK,IAAI,CAAC;AAAA;AACnD;AAEA,SAAS,mBAAmB;AAC1B,MAAI,CAAC,UAAAD,QAAG,WAAW,cAAAF,QAAO,QAAQ,GAAG;AACnC,cAAAE,QAAG,UAAU,cAAAF,QAAO,QAAQ;AAAA,EAC9B;AAEA,QAAM,YAAY,UAAAE,QAAG,YAAY,cAAAF,QAAO,QAAQ;AAChD,YAAU,QAAQ,CAAC,aAAa;AAC9B,QAAI,oCAAoC,KAAK,QAAQ,GAAG;AACtD,gBAAAE,QAAG,WAAW,YAAAD,QAAK,QAAQ,cAAAD,QAAO,UAAU,QAAQ,CAAC;AAAA,IACvD;AAAA,EACF,CAAC;AAED,SAAO;AACT;AAEA,SAAe,gBACb,QACA,OACA,SACA;AAAA;AACA,UAAM,UAAM,4BAAgB;AAC5B,UAAM;AAAA,MACJ;AAAA,MACA,QAAQ;AAAA,MACR;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,IAAI;AAEJ,UAAM,UAAU,UAAU,gBAAgB;AAE1C,QAAI,MAAM;AACV,UAAM,cAAU,WAAAI,SAAI,GAAG;AACvB,YAAQ,MAAM;AAEd,UAAM,WAAW,UAAM,oCAAc,MAAM;AAE3C,QAAI;AACF,aAAO,iBAAiB;AACxB,aAAO;AAAA,oCAAmC,qBAAAC;AAAA,QACxC;AAAA,QACA;AAAA,MACF,CAAC;AAAA;AAED,YAAM,OAAO,UAAU,QAAQ,OAAO,CAAC;AAEvC,eAAe,sBAAsB,QAAyB;AAAA;AAG5D,gBAAM,oBAAoB,CAAC,EAAE,OAAO,OAAU,GAAG,GAAI,YAAY,CAAC,CAAE;AAEpE,gBAAM,SAAS,IAAI,gBAAgB;AACnC,cAAI,mCAAS;AACX,mBAAO,QAAQ,QAAQ,IAAI,EAAE,QAAQ,CAAC,CAAC,GAAG,CAAC,MAAM,OAAO,OAAO,GAAG,CAAC,CAAC;AACtE,cAAI;AAAQ,mBAAO,OAAO,UAAU,MAAM;AAC1C,cAAI;AAAQ,mBAAO,OAAO,UAAU,MAAM;AAC1C,cAAI;AAAU,mBAAO,OAAO,mBAAmB,SAAS,SAAS,CAAC;AAClE,cAAI,kBAAkB;AACpB,6BAAiB,QAAQ,CAAC,EAAE,GAAG,MAAM,OAAO,OAAO,eAAe,EAAE,CAAC;AAAA,UACvE;AAEA,gBAAM,WAAW,MAAM,QAAQ;AAAA,YAC7B,kBAAkB,IAAI,CAAO,OAA4B,eAA5B,KAA4B,WAA5B,EAAE,OAAO,aAAa,GAAM;AACvD,oBAAM,IAAI,IAAI,gBAAgB,MAAM;AACpC,kBAAI;AAAc,kBAAE,OAAO,WAAW,YAAY;AAElD,oBAAM,EAAE,KAAK,IAAI,MAAM,IAAI,IAAI,eAAe,EAAE,QAAQ,EAAE,CAAC;AAE3D,oBAAM,UAAU,mBAAmB,MAAM;AACzC,oBAAM,WAAW;AACjB,oBAAM,cAAc,KAAK,gBAAgB,MAAM;AAE/C,oBAAM,eAAW,oCAAc,GAAG,QAAQ,GAAG,WAAW,GAAG,OAAO,EAAE;AACpE,oBAAM,WAAW,YAAAJ,QAAK,KAAK,cAAAD,QAAO,UAAU,QAAQ;AAEpD,kBAAI,aAAa;AACjB,kBAAI,YAAY,SAAS;AACvB,6BAAa,KAAK,UAAU,MAAM,MAAM,CAAC;AAAA,cAC3C;AAEA,oBAAM,cAAc,qBAAqB,MAAM;AAC/C,kBAAI,CAAC,YAAY,UAAU,GAAG;AAC5B,uBAAO;AAAA,cACT;AAEA,oBAAM,IAAI,QAAQ,CAAC,MAAM,UAAAE,QAAG,UAAU,UAAU,YAAY,CAAC,CAAC;AAC9D,qBAAO,gBAAgB,QAAQ;AAAA,YACjC,EAAC;AAAA,UACH;AAEA,iBAAO,SAAS,KAAK,EAAE;AAAA,QACzB;AAAA;AAEA,UAAI,6BAA6B;AAC/B,mBAAW,UAAU,SAAS;AAC5B,gBAAM,sBAAsB,MAAM;AAAA,QACpC;AAAA,MACF;AAEA,eAAe,cAAc,QAAyB;AAAA;AACpD,iBAAO,WACH,MAAM;AAAA,YACJ;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,UACF,IACA,MAAM;AAAA,YACJ;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,cACE;AAAA,YACF;AAAA,UACF;AAAA,QACN;AAAA;AAEA,UAAI,cAAc,QAAQ;AACxB,mBAAW,UAAU,SAAS;AAC5B,gBAAM,cAAc,MAAM;AAAA,QAC5B;AAAA,MACF;AAEA,YAAM,UAAU,CAAC,GAAG,aAAa;AACjC,UAAI,6BAA6B;AAC/B,gBAAQ,KAAK;AAAA,UACX,IAAI;AAAA,UACJ,MAAM;AAAA,UACN,UAAU;AAAA,QACZ,CAAC;AAAA,MACH;AAEA,UAAI,QAAQ,KAAK,CAAC,MAAM,aAAa,SAAS,CAAC,CAAC;AAC9C,mBAAO,0CAAiB,OAAO;AAEjC,aAAO;AAAA,EAAK,cAAAC,QAAO,QAAQ,MAAM,CAAC;AAElC,cAAQ,KAAK;AACb,aAAO,QAAQ,IAAI,GAAG;AAAA,IACxB,SAAS,GAAQ;AACf,cAAQ,MAAM,CAAC;AAEf,cAAQ,KAAK;AACb,UAAI,QAAQ,EAAE;AACd,UAAI,EAAE,YAAY,EAAE,SAAS,WAAW,KAAK;AAC3C,cAAM,mBAAmB;AACzB,aAAK;AACL;AAAA,MACF;AACA,UAAI,EAAE,YAAY,EAAE,SAAS,WAAW,KAAK;AAC3C,gBAAQ;AACR,cAAM,GAAG,cAAAA,QAAO,UAAU,KAAK,CAAC;AAAA,0BAA8B,cAAAA,QAAO;AAAA,UACnE;AAAA,QACF,CAAC;AACD,eAAO,QAAQ,IAAI,GAAG;AAAA,MACxB;AACA,UAAI,EAAE,YAAY,EAAE,SAAS,WAAW,KAAK;AAC3C,gBACE;AACF,cAAM,GAAG,cAAAA,QAAO;AAAA,UACd;AAAA,QACF,CAAC;AAAA,6CAAiD,cAAAA,QAAO;AAAA,UACvD;AAAA,QACF,CAAC,mFAAmF,cAAAA,QAAO;AAAA,UACzF;AAAA,QACF,CAAC;AACD,eAAO,QAAQ,IAAI,GAAG;AAAA,MACxB;AACA,UAAI,EAAE,YAAY,EAAE,SAAS,WAAW,KAAK;AAC3C,gBAAQ;AAAA,MACV;AACA,YAAM,oDAAoD,cAAAA,QAAO;AAAA,QAC/D;AAAA,MACF,CAAC;AAAA,0BAA8B,cAAAA,QAAO,KAAK,SAAS,CAAC;AACrD,aAAO,QAAQ,IAAI,GAAG;AAAA,IACxB;AAAA,EACF;AAAA;AAMO,MAAM,OAAO,CAAO,YAA0B;AACnD,QAAM,OAAO,UAAU,QAAQ,OAAO,CAAC;AACvC,QAAM,QAAQ,cAAAJ,QAAO,SAAS,cAAAC,QAAO,aAAa,cAAAA,QAAO,QAAQ;AACjE,QAAM,oBAAoB,cAAAD,QAAO,uBAAuB;AAExD,MAAI;AACF,WAAO,MAAM,gBAAgB,mBAAmB,OAAO,EAAE,KAAK,CAAC;AAAA,EACjE,SAAS,GAAG;AACV,WAAO,iBAAiB,CAAC;AACzB,QAAI,aAAa,yBAAY;AAC3B,iBAAO;AAAA,QACL,cAAAI,QAAO;AAAA,UACL;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,eAAO;AAAA,MACL,cAAAA,QAAO,UAAU,+CAA+C;AAAA,IAClE;AAAA,EACF;AACF;AAEA,IAAO,eAAQ;AAAA,EACb;AAAA,EACA,UAAU;AAAA,IACR;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF","debug_id":"c9f589e3-b75d-5846-b29d-266ca10a8560"}
1
+ {"version":3,"sources":["../lib/pull.ts"],"sourcesContent":["import fs from \"fs\";\nimport path from \"path\";\n\nimport ora from \"ora\";\nimport * as Sentry from \"@sentry/node\";\n\nimport { createApiClient } from \"./api\";\nimport config from \"./config\";\nimport consts from \"./consts\";\nimport output from \"./output\";\nimport { collectAndSaveToken } from \"./init/token\";\nimport sourcesToText from \"./utils/sourcesToText\";\nimport { generateJsDriver } from \"./utils/generateJsDriver\";\nimport { cleanFileName } from \"./utils/cleanFileName\";\nimport {\n SourceInformation,\n Token,\n Project,\n SupportedFormat,\n ComponentFolder,\n ComponentSource,\n Source,\n} from \"./types\";\nimport { fetchVariants } from \"./http/fetchVariants\";\nimport { quit } from \"./utils/quit\";\nimport { AxiosError } from \"axios\";\nimport { fetchComponentFolders } from \"./http/fetchComponentFolders\";\n\nconst ensureEndsWithNewLine = (str: string) =>\n str + (/[\\r\\n]$/.test(str) ? \"\" : \"\\n\");\n\nconst writeFile = (path: string, data: string) =>\n new Promise((r) => fs.writeFile(path, ensureEndsWithNewLine(data), r));\n\nconst SUPPORTED_FORMATS: SupportedFormat[] = [\n \"flat\",\n \"structured\",\n \"android\",\n \"ios-strings\",\n \"ios-stringsdict\",\n \"icu\",\n];\n\nconst JSON_FORMATS: SupportedFormat[] = [\"flat\", \"structured\", \"icu\"];\n\nconst FORMAT_EXTENSIONS = {\n flat: \".json\",\n structured: \".json\",\n android: \".xml\",\n \"ios-strings\": \".strings\",\n \"ios-stringsdict\": \".stringsdict\",\n icu: \".json\",\n};\n\nconst getJsonFormatIsValid = (data: string) => {\n try {\n return Object.keys(JSON.parse(data)).some(\n (k) => !k.startsWith(\"__variant\")\n );\n } catch {\n return false;\n }\n};\n\n// exported for test usage only\nexport const getFormatDataIsValid = {\n flat: getJsonFormatIsValid,\n structured: getJsonFormatIsValid,\n icu: getJsonFormatIsValid,\n android: (data: string) => data.includes(\"<string\"),\n \"ios-strings\": (data: string) => data.includes(`\" = \"`),\n \"ios-stringsdict\": (data: string) => data.includes(\"<key>\"),\n};\n\nconst getFormat = (\n formatFromSource: string | string[] | undefined\n): SupportedFormat[] => {\n const formats = (\n Array.isArray(formatFromSource) ? formatFromSource : [formatFromSource]\n ).filter((format) =>\n SUPPORTED_FORMATS.includes(format as SupportedFormat)\n ) as SupportedFormat[];\n\n if (formats.length) {\n return formats;\n }\n\n return [\"flat\"];\n};\n\nconst getFormatExtension = (format: SupportedFormat) => {\n return FORMAT_EXTENSIONS[format];\n};\n\nconst DEFAULT_FORMAT_KEYS = [\"projects\", \"exported_at\"];\nconst hasVariantData = (data: any) => {\n const hasTopLevelKeys =\n Object.keys(data).filter((key) => !DEFAULT_FORMAT_KEYS.includes(key))\n .length > 0;\n\n const hasProjectKeys = data.projects && Object.keys(data.projects).length > 0;\n\n return hasTopLevelKeys || hasProjectKeys;\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\n/**\n * For a given variant:\n * - if format is unspecified, fetch data for all projects from `/projects` and\n * save in `{variantApiId}.json`\n * - if format is `flat` or `structured`, fetch data for each project from `/project/:project_id` and\n * save in `{projectName}-${variantApiId}.json`\n */\nasync function downloadAndSaveVariant(\n variantApiId: string | null,\n projects: Project[],\n format: SupportedFormat,\n status: string | undefined,\n richText: boolean | undefined,\n token?: Token\n) {\n const api = createApiClient();\n const params: Record<string, string | null> = { variant: variantApiId };\n if (format) params.format = format;\n if (richText) params.includeRichText = richText.toString();\n\n // Root-level status gets set as the default if specified\n if (status) params.status = status;\n\n const savedMessages = await Promise.all(\n projects.map(async (project) => {\n const projectParams = { ...params };\n // If project-level status is specified, overrides root-level status\n if (project.status) projectParams.status = project.status;\n if (project.exclude_components)\n projectParams.exclude_components = String(project.exclude_components);\n\n const { data } = await api.get(`/projects/${project.id}`, {\n params: projectParams,\n headers: { Authorization: `token ${token}` },\n });\n\n if (!hasVariantData(data)) {\n return \"\";\n }\n\n const extension = getFormatExtension(format);\n\n const filename = cleanFileName(\n project.fileName + (\"__\" + (variantApiId || \"base\")) + extension\n );\n const filepath = path.join(consts.TEXT_DIR, filename);\n\n let dataString = data;\n if (extension === \".json\") {\n dataString = JSON.stringify(data, null, 2);\n }\n\n const dataIsValid = getFormatDataIsValid[format];\n if (!dataIsValid(dataString)) {\n return \"\";\n }\n\n await writeFile(filepath, dataString);\n return getSavedMessage(filename);\n })\n );\n\n return savedMessages.join(\"\");\n}\n\nasync function downloadAndSaveVariants(\n variants: { apiID: string }[],\n projects: Project[],\n format: SupportedFormat,\n status: string | undefined,\n richText: boolean | undefined,\n token?: Token\n) {\n const messages = await Promise.all([\n downloadAndSaveVariant(null, projects, format, status, richText, token),\n ...variants.map(({ apiID }: { apiID: string }) =>\n downloadAndSaveVariant(apiID, projects, format, status, richText, token)\n ),\n ]);\n\n return messages.join(\"\");\n}\n\nasync function downloadAndSaveBase(\n projects: Project[],\n format: SupportedFormat,\n status: string | undefined,\n richText?: boolean | undefined,\n token?: Token,\n options?: PullOptions\n) {\n const api = createApiClient();\n const params = { ...options?.meta };\n if (format) params.format = format;\n if (richText) params.includeRichText = richText.toString();\n\n // Root-level status gets set as the default if specified\n if (status) params.status = status;\n\n const savedMessages = await Promise.all(\n projects.map(async (project) => {\n const projectParams = { ...params };\n // If project-level status is specified, overrides root-level status\n if (project.status) projectParams.status = project.status;\n if (project.exclude_components)\n projectParams.exclude_components = String(project.exclude_components);\n\n const { data } = await api.get(`/projects/${project.id}`, {\n params: projectParams,\n headers: { Authorization: `token ${token}` },\n });\n\n const extension = getFormatExtension(format);\n const filename = cleanFileName(`${project.fileName}__base${extension}`);\n const filepath = path.join(consts.TEXT_DIR, filename);\n\n let dataString = data;\n if (extension === \".json\") {\n dataString = JSON.stringify(data, null, 2);\n }\n\n const dataIsValid = getFormatDataIsValid[format];\n if (!dataIsValid(dataString)) {\n return \"\";\n }\n\n await writeFile(filepath, dataString);\n return getSavedMessage(filename);\n })\n );\n\n return savedMessages.join(\"\");\n}\n\nfunction getSavedMessage(file: string) {\n return `Successfully saved to ${output.info(file)}\\n`;\n}\n\nfunction cleanOutputFiles() {\n if (!fs.existsSync(consts.TEXT_DIR)) {\n fs.mkdirSync(consts.TEXT_DIR);\n }\n\n const fileNames = fs.readdirSync(consts.TEXT_DIR);\n fileNames.forEach((fileName) => {\n if (/\\.js(on)?|\\.xml|\\.strings(dict)?$/.test(fileName)) {\n fs.unlinkSync(path.resolve(consts.TEXT_DIR, fileName));\n }\n });\n\n return \"Cleaning old output files..\\n\";\n}\n\nasync function downloadAndSave(\n source: SourceInformation,\n token?: Token,\n options?: PullOptions\n) {\n const api = createApiClient();\n const {\n validProjects,\n format: formatFromSource,\n shouldFetchComponentLibrary,\n status,\n richText,\n componentFolders: specifiedComponentFolders,\n componentRoot,\n } = source;\n\n const formats = getFormat(formatFromSource);\n\n let msg = \"\";\n const spinner = ora(msg);\n spinner.start();\n\n const [variants, allComponentFoldersResponse] = await Promise.all([\n fetchVariants(source),\n fetchComponentFolders(),\n ]);\n\n const allComponentFolders = Object.entries(\n allComponentFoldersResponse\n ).reduce(\n (acc, [id, name]) => acc.concat([{ id, name }]),\n [] as ComponentFolder[]\n );\n\n try {\n msg += cleanOutputFiles();\n msg += `\\nFetching the latest text from ${sourcesToText(\n validProjects,\n shouldFetchComponentLibrary\n )}\\n`;\n\n const meta = options ? options.meta : {};\n\n const rootRequest = {\n id: \"__root__\",\n name: \"Root\",\n // componentRoot can be a boolean or an object\n status:\n typeof source.componentRoot === \"object\"\n ? source.componentRoot.status\n : undefined,\n };\n\n let componentFolderRequests: ComponentFolder[] = [];\n\n // there's a lot of complex logic here, and it's tempting to want to\n // simplify it. however, it's difficult to get rid of the complexity\n // without sacrificing specificity and expressiveness.\n //\n // if folders specified..\n if (specifiedComponentFolders) {\n switch (componentRoot) {\n // .. and no root specified, you only get components in the specified folders\n case undefined:\n case false:\n componentFolderRequests.push(...specifiedComponentFolders);\n break;\n // .. and root specified, you get components in folders and the root\n default:\n componentFolderRequests.push(...specifiedComponentFolders);\n componentFolderRequests.push(rootRequest);\n break;\n }\n }\n // if no folders specified..\n else {\n switch (componentRoot) {\n // .. and no root specified, you get all components including those in folders\n case undefined:\n componentFolderRequests.push(...allComponentFolders);\n componentFolderRequests.push(rootRequest);\n break;\n // .. and root specified as false, you only get components in folders\n case false:\n componentFolderRequests.push(...allComponentFolders);\n break;\n // .. and root specified as true or config object, you only get components in the root\n default:\n componentFolderRequests.push(rootRequest);\n break;\n }\n }\n\n // this array is populated while fetching from the component library and is used when\n // generating the index.js driver file\n const componentSources: ComponentSource[] = [];\n\n async function fetchComponentLibrary(format: SupportedFormat) {\n // Always include a variant with an apiID of undefined to ensure that we\n // fetch the base text for the component library.\n const componentVariants = [{ apiID: undefined }, ...(variants || [])];\n\n const params = new URLSearchParams();\n if (options?.meta)\n Object.entries(options.meta).forEach(([k, v]) => params.append(k, v));\n if (format) params.append(\"format\", format);\n if (richText) params.append(\"includeRichText\", richText.toString());\n\n // Root-level status gets set as the default if specified\n if (status) params.append(\"status\", status);\n\n const messagePromises: Promise<string>[] = [];\n\n componentVariants.forEach(({ apiID: variantApiId }) => {\n messagePromises.push(\n ...componentFolderRequests.map(async (componentFolder) => {\n const componentFolderParams = new URLSearchParams(params);\n\n if (variantApiId)\n componentFolderParams.append(\"variant\", variantApiId);\n\n // If folder-level status is specified, overrides root-level status\n if (componentFolder.status)\n componentFolderParams.append(\"status\", componentFolder.status);\n\n const url =\n componentFolder.id === \"__root__\"\n ? \"/components?root_only=true\"\n : `/component-folders/${componentFolder.id}/components`;\n\n const { data } = await api.get(url, {\n params: componentFolderParams,\n });\n\n const nameExt = getFormatExtension(format);\n const nameBase = \"components\";\n const nameFolder = `__${componentFolder.name}`;\n const namePostfix = `__${variantApiId || \"base\"}`;\n\n const fileName = cleanFileName(\n `${nameBase}${nameFolder}${namePostfix}${nameExt}`\n );\n const filePath = path.join(consts.TEXT_DIR, fileName);\n\n let dataString = data;\n if (nameExt === \".json\") {\n dataString = JSON.stringify(data, null, 2);\n }\n\n const dataIsValid = getFormatDataIsValid[format];\n if (!dataIsValid(dataString)) {\n return \"\";\n }\n\n await writeFile(filePath, dataString);\n\n componentSources.push({\n type: \"components\",\n id: \"ditto_component_library\",\n name: \"ditto_component_library\",\n fileName,\n variant: variantApiId || \"base\",\n });\n\n return getSavedMessage(fileName);\n })\n );\n });\n\n const messages = await Promise.all(messagePromises);\n msg += messages.join(\"\");\n }\n\n if (shouldFetchComponentLibrary) {\n for (const format of formats) {\n await fetchComponentLibrary(format);\n }\n }\n\n async function fetchProjects(format: SupportedFormat) {\n msg += variants\n ? await downloadAndSaveVariants(\n variants,\n validProjects,\n format,\n status,\n richText,\n token\n )\n : await downloadAndSaveBase(\n validProjects,\n format,\n status,\n richText,\n token,\n {\n meta,\n }\n );\n }\n\n if (validProjects.length) {\n for (const format of formats) {\n await fetchProjects(format);\n }\n }\n\n const sources: Source[] = [...validProjects, ...componentSources];\n\n if (formats.some((f) => JSON_FORMATS.includes(f)))\n msg += generateJsDriver(sources);\n\n msg += `\\n${output.success(\"Done\")}!`;\n\n spinner.stop();\n return console.log(msg);\n } catch (e: any) {\n console.error(e);\n\n spinner.stop();\n let error = e.message;\n if (e.response && e.response.status === 404) {\n await askForAnotherToken();\n pull();\n return;\n }\n if (e.response && e.response.status === 401) {\n error = \"You don't have access to the selected projects\";\n msg = `${output.errorText(error)}.\\nChoose others using the ${output.info(\n \"project\"\n )} command, or update your API key.`;\n return console.log(msg);\n }\n if (e.response && e.response.status === 403) {\n error =\n \"One or more of the requested projects don't have Developer Mode enabled\";\n msg = `${output.errorText(\n error\n )}.\\nPlease choose different projects using the ${output.info(\n \"project\"\n )} command, or turn on Developer Mode for all selected projects. Learn more here: ${output.subtle(\n \"https://www.dittowords.com/docs/ditto-developer-mode\"\n )}.`;\n return console.log(msg);\n }\n if (e.response && e.response.status === 400) {\n error = \"projects not found\";\n }\n msg = `We hit an error fetching text from the projects: ${output.errorText(\n error\n )}.\\nChoose others using the ${output.info(\"project\")} command.`;\n return console.log(msg);\n }\n}\n\nexport interface PullOptions {\n meta?: Record<string, string>;\n}\n\nexport const pull = async (options?: PullOptions) => {\n const meta = options ? options.meta : {};\n const token = config.getToken(consts.CONFIG_FILE, consts.API_HOST);\n const sourceInformation = config.parseSourceInformation();\n\n try {\n return await downloadAndSave(sourceInformation, token, { meta });\n } catch (e) {\n const eventId = Sentry.captureException(e);\n const eventStr = `\\n\\nError ID: ${output.info(eventId)}`;\n if (e instanceof AxiosError) {\n return quit(\n output.errorText(\n \"Something went wrong connecting to Ditto servers. Please contact support or try again later.\"\n ) + eventStr\n );\n }\n\n return quit(\n output.errorText(\n \"Something went wrong. Please contact support or try again later.\"\n ) + eventStr\n );\n }\n};\n\nexport default {\n pull,\n _testing: {\n cleanOutputFiles,\n downloadAndSaveVariant,\n downloadAndSaveVariants,\n downloadAndSaveBase,\n },\n};\n"],"names":["path","fs","config","consts","output","ora","sourcesToText"],"mappings":"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","debug_id":"8e8abce7-7d1b-5b40-96a6-09318358142e"}
package/bin/types.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]="9778a30d-4eba-5c79-89d3-78e5ca9db6fc")}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]="3a899a8b-8170-53ae-808a-dea1164e29fe")}catch(e){}}();
3
3
 
4
4
  var __defProp = Object.defineProperty;
5
5
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -18,4 +18,4 @@ var types_exports = {};
18
18
  module.exports = __toCommonJS(types_exports);
19
19
  //# sourceMappingURL=types.js.map
20
20
 
21
- //# debugId=9778a30d-4eba-5c79-89d3-78e5ca9db6fc
21
+ //# debugId=3a899a8b-8170-53ae-808a-dea1164e29fe
package/bin/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../lib/types.ts"],"sourcesContent":["export interface Project {\n name: string;\n id: string;\n url?: string;\n fileName?: string;\n}\n\nexport type Source = Project;\n\ninterface ComponentFolder {\n id: string;\n name: string;\n}\n\nexport type SupportedFormat =\n | \"flat\"\n | \"structured\"\n | \"android\"\n | \"ios-strings\"\n | \"ios-stringsdict\"\n | \"icu\";\n\nexport interface ConfigYAML {\n sources?: {\n components?: {\n enabled?: boolean;\n folders?: ComponentFolder[];\n };\n projects?: Project[];\n };\n format?: SupportedFormat;\n status?: string;\n variants?: boolean;\n richText?: boolean;\n\n // these are legacy fields - if they exist, we should output\n // a deprecation error, and suggest that they nest them under\n // a top-level `sources` property\n components?: boolean;\n projects?: Project[];\n}\n\nexport interface SourceInformation {\n hasSourceData: boolean;\n validProjects: Project[];\n shouldFetchComponentLibrary: boolean;\n variants: boolean;\n format: string | string[] | undefined;\n status: string | undefined;\n richText: boolean | undefined;\n componentFolders: ComponentFolder[] | null;\n}\n\nexport type Token = string | undefined;\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA;AAAA","debug_id":"9778a30d-4eba-5c79-89d3-78e5ca9db6fc"}
1
+ {"version":3,"sources":["../lib/types.ts"],"sourcesContent":["export interface Project {\n name: string;\n id: string;\n url?: string;\n fileName?: string;\n status?: string;\n exclude_components?: boolean;\n}\n\nexport type ComponentSource = ComponentFolder & {\n type: \"components\";\n fileName: string;\n variant: string;\n};\n\nexport type Source = (Project & { type?: undefined }) | ComponentSource;\n\nexport interface ComponentFolder {\n id: string;\n name: string;\n status?: string;\n}\n\nexport type SupportedFormat =\n | \"flat\"\n | \"structured\"\n | \"android\"\n | \"ios-strings\"\n | \"ios-stringsdict\"\n | \"icu\";\n\ntype ComponentsSourceBool = boolean;\ntype ComponentsSourceConfig = {\n root?: boolean | { status: string };\n folders?: ComponentFolder[];\n};\ntype ComponentsSource = ComponentsSourceBool | ComponentsSourceConfig;\n\nexport interface ConfigYAML {\n sources?: {\n components?: ComponentsSource;\n projects?: Project[];\n };\n format?: SupportedFormat;\n status?: string;\n variants?: boolean;\n richText?: boolean;\n\n // these are legacy fields - if they exist, we should output\n // a deprecation error, and suggest that they nest them under\n // a top-level `sources` property\n components?: boolean;\n projects?: Project[];\n}\n\nexport interface SourceInformation {\n hasSourceData: boolean;\n hasTopLevelProjectsField: boolean;\n hasTopLevelComponentsField: boolean;\n hasComponentLibraryInProjects: boolean;\n validProjects: Project[];\n shouldFetchComponentLibrary: boolean;\n variants: boolean;\n format: string | string[] | undefined;\n status: string | undefined;\n richText: boolean | undefined;\n componentRoot: boolean | { status: string } | undefined;\n componentFolders: ComponentFolder[] | undefined;\n}\n\nexport type Token = string | undefined;\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA;AAAA","debug_id":"3a899a8b-8170-53ae-808a-dea1164e29fe"}
@@ -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]="d33f7b20-9173-5593-839d-599b5b4b51ef")}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]="38a5733b-13a9-57f6-843f-d2de84c4c1d0")}catch(e){}}();
3
3
 
4
4
  var __defProp = Object.defineProperty;
5
5
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -40,4 +40,4 @@ function createSentryContext(obj) {
40
40
  });
41
41
  //# sourceMappingURL=createSentryContext.js.map
42
42
 
43
- //# debugId=d33f7b20-9173-5593-839d-599b5b4b51ef
43
+ //# debugId=38a5733b-13a9-57f6-843f-d2de84c4c1d0
@@ -1 +1 @@
1
- {"version":3,"sources":["../../lib/utils/createSentryContext.ts"],"sourcesContent":["type SentryContext = Record<\n string,\n string | number | boolean | null | undefined\n>;\n\n/**\n * Sentry context\n */\nexport function createSentryContext(obj: unknown) {\n if (typeof obj !== \"object\") return {};\n\n const ctx: SentryContext = {};\n for (const key in obj) {\n const k = key as keyof typeof obj;\n const r = obj[k];\n ctx[k] = typeof r === \"object\" || Array.isArray(r) ? JSON.stringify(r) : r;\n }\n\n return ctx;\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAQO,SAAS,oBAAoB,KAAc;AAChD,MAAI,OAAO,QAAQ;AAAU,WAAO,CAAC;AAErC,QAAM,MAAqB,CAAC;AAC5B,aAAW,OAAO,KAAK;AACrB,UAAM,IAAI;AACV,UAAM,IAAI,IAAI,CAAC;AACf,QAAI,CAAC,IAAI,OAAO,MAAM,YAAY,MAAM,QAAQ,CAAC,IAAI,KAAK,UAAU,CAAC,IAAI;AAAA,EAC3E;AAEA,SAAO;AACT","debug_id":"d33f7b20-9173-5593-839d-599b5b4b51ef"}
1
+ {"version":3,"sources":["../../lib/utils/createSentryContext.ts"],"sourcesContent":["type SentryContext = Record<\n string,\n string | number | boolean | null | undefined\n>;\n\n/**\n * Sentry context only supports properties one layer deep\n */\nexport function createSentryContext(obj: unknown) {\n if (typeof obj !== \"object\") return {};\n\n const ctx: SentryContext = {};\n for (const key in obj) {\n const k = key as keyof typeof obj;\n const r = obj[k];\n ctx[k] = typeof r === \"object\" || Array.isArray(r) ? JSON.stringify(r) : r;\n }\n\n return ctx;\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAQO,SAAS,oBAAoB,KAAc;AAChD,MAAI,OAAO,QAAQ;AAAU,WAAO,CAAC;AAErC,QAAM,MAAqB,CAAC;AAC5B,aAAW,OAAO,KAAK;AACrB,UAAM,IAAI;AACV,UAAM,IAAI,IAAI,CAAC;AACf,QAAI,CAAC,IAAI,OAAO,MAAM,YAAY,MAAM,QAAQ,CAAC,IAAI,KAAK,UAAU,CAAC,IAAI;AAAA,EAC3E;AAEA,SAAO;AACT","debug_id":"38a5733b-13a9-57f6-843f-d2de84c4c1d0"}
@@ -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]="e416d2b1-db35-5e4a-8bb1-6725adbec6e1")}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]="abf6148b-b36f-5809-b765-ac588ff7207f")}catch(e){}}();
3
3
 
4
4
  var __create = Object.create;
5
5
  var __defProp = Object.defineProperty;
@@ -57,7 +57,6 @@ var import_output = __toESM(require("../output"));
57
57
  var import_cleanFileName = require("./cleanFileName");
58
58
  const stringifySourceId = (projectId) => projectId === "ditto_component_library" ? projectId : `project_${projectId}`;
59
59
  function generateJsDriver(sources) {
60
- const fileNames = import_fs.default.readdirSync(import_consts.default.TEXT_DIR).filter((fileName) => /\.json$/.test(fileName));
61
60
  const sourceIdsByName = sources.reduce(
62
61
  (agg, source) => {
63
62
  if (source.fileName) {
@@ -67,7 +66,10 @@ function generateJsDriver(sources) {
67
66
  },
68
67
  {}
69
68
  );
70
- const data = fileNames.reduce(
69
+ const projectFileNames = import_fs.default.readdirSync(import_consts.default.TEXT_DIR).filter(
70
+ (fileName) => /\.json$/.test(fileName) && !/^components__/.test(fileName)
71
+ );
72
+ const data = projectFileNames.reduce(
71
73
  (obj, fileName) => {
72
74
  const [sourceId, rest] = fileName.split("__");
73
75
  const [variantApiId] = rest.split(".");
@@ -81,7 +83,29 @@ function generateJsDriver(sources) {
81
83
  },
82
84
  {}
83
85
  );
84
- let dataString = `module.exports = ${JSON.stringify(data, null, 2)}`.replace(/"require\((.*)\)"/g, "require($1)");
86
+ const componentData = {};
87
+ sources.filter((s) => s.type === "components").forEach((componentSource) => {
88
+ var _a, _b;
89
+ if (componentSource.type !== "components")
90
+ return;
91
+ (_b = componentData[_a = componentSource.variant]) != null ? _b : componentData[_a] = [];
92
+ componentData[componentSource.variant].push(
93
+ `...require('./${componentSource.fileName}')`
94
+ );
95
+ });
96
+ Object.keys(componentData).forEach((key) => {
97
+ var _a;
98
+ (_a = data.ditto_component_library) != null ? _a : data.ditto_component_library = {};
99
+ let str = "{";
100
+ componentData[key].forEach((k, i) => {
101
+ str += k;
102
+ if (i < componentData[key].length - 1)
103
+ str += ", ";
104
+ });
105
+ str += "}";
106
+ data.ditto_component_library[key] = str;
107
+ });
108
+ let dataString = `module.exports = ${JSON.stringify(data, null, 2)}`.replace(/"require\((.*)\)"/g, "require($1)").replace(/"\{/g, "{").replace(/\}"/g, "}");
85
109
  const filePath = import_path.default.resolve(import_consts.default.TEXT_DIR, "index.js");
86
110
  import_fs.default.writeFileSync(filePath, dataString, { encoding: "utf8" });
87
111
  return `Generated .js SDK driver at ${import_output.default.info(filePath)}`;
@@ -92,4 +116,4 @@ function generateJsDriver(sources) {
92
116
  });
93
117
  //# sourceMappingURL=generateJsDriver.js.map
94
118
 
95
- //# debugId=e416d2b1-db35-5e4a-8bb1-6725adbec6e1
119
+ //# debugId=abf6148b-b36f-5809-b765-ac588ff7207f
@@ -1 +1 @@
1
- {"version":3,"sources":["../../lib/utils/generateJsDriver.ts"],"sourcesContent":["import fs from \"fs\";\nimport path from \"path\";\nimport consts from \"../consts\";\nimport output from \"../output\";\nimport { Source } from \"../types\";\nimport { cleanFileName } from \"./cleanFileName\";\n\n// compatability with legacy method of specifying project ids\n// that is still used by the default format\nconst stringifySourceId = (projectId: string) =>\n projectId === \"ditto_component_library\" ? projectId : `project_${projectId}`;\n\n/**\n * Generates an index.js file that can be consumed\n * by an SDK - this is a big DX improvement because\n * it provides a single entry point to get all data\n * (including variants) instead of having to import\n * each generated file individually.\n *\n * The generated file will have a unified format\n * independent of the CLI configuration used to fetch\n * data from Ditto.\n */\n\n// TODO: support ESM\nexport function generateJsDriver(sources: Source[]) {\n const fileNames = fs\n .readdirSync(consts.TEXT_DIR)\n .filter((fileName) => /\\.json$/.test(fileName));\n\n const sourceIdsByName: Record<string, string> = sources.reduce(\n (agg, source) => {\n if (source.fileName) {\n return { ...agg, [cleanFileName(source.fileName)]: source.id };\n }\n\n return agg;\n },\n {}\n );\n\n const data = fileNames.reduce(\n (obj: Record<string, Record<string, string>>, fileName) => {\n const [sourceId, rest] = fileName.split(\"__\");\n const [variantApiId] = rest.split(\".\");\n\n const projectId = sourceIdsByName[sourceId];\n const projectIdStr = stringifySourceId(projectId);\n\n if (!obj[projectIdStr]) {\n obj[projectIdStr] = {};\n }\n\n obj[projectIdStr][variantApiId] = `require('./${fileName}')`;\n return obj;\n },\n {}\n );\n\n let dataString = `module.exports = ${JSON.stringify(data, null, 2)}`\n // remove quotes around require statements\n .replace(/\"require\\((.*)\\)\"/g, \"require($1)\");\n\n const filePath = path.resolve(consts.TEXT_DIR, \"index.js\");\n fs.writeFileSync(filePath, dataString, { encoding: \"utf8\" });\n\n return `Generated .js SDK driver at ${output.info(filePath)}`;\n}\n"],"names":["fs","consts","path","output"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gBAAe;AACf,kBAAiB;AACjB,oBAAmB;AACnB,oBAAmB;AAEnB,2BAA8B;AAI9B,MAAM,oBAAoB,CAAC,cACzB,cAAc,4BAA4B,YAAY,WAAW,SAAS;AAerE,SAAS,iBAAiB,SAAmB;AAClD,QAAM,YAAY,UAAAA,QACf,YAAY,cAAAC,QAAO,QAAQ,EAC3B,OAAO,CAAC,aAAa,UAAU,KAAK,QAAQ,CAAC;AAEhD,QAAM,kBAA0C,QAAQ;AAAA,IACtD,CAAC,KAAK,WAAW;AACf,UAAI,OAAO,UAAU;AACnB,eAAO,iCAAK,MAAL,EAAU,KAAC,oCAAc,OAAO,QAAQ,CAAC,GAAG,OAAO,GAAG;AAAA,MAC/D;AAEA,aAAO;AAAA,IACT;AAAA,IACA,CAAC;AAAA,EACH;AAEA,QAAM,OAAO,UAAU;AAAA,IACrB,CAAC,KAA6C,aAAa;AACzD,YAAM,CAAC,UAAU,IAAI,IAAI,SAAS,MAAM,IAAI;AAC5C,YAAM,CAAC,YAAY,IAAI,KAAK,MAAM,GAAG;AAErC,YAAM,YAAY,gBAAgB,QAAQ;AAC1C,YAAM,eAAe,kBAAkB,SAAS;AAEhD,UAAI,CAAC,IAAI,YAAY,GAAG;AACtB,YAAI,YAAY,IAAI,CAAC;AAAA,MACvB;AAEA,UAAI,YAAY,EAAE,YAAY,IAAI,cAAc,QAAQ;AACxD,aAAO;AAAA,IACT;AAAA,IACA,CAAC;AAAA,EACH;AAEA,MAAI,aAAa,oBAAoB,KAAK,UAAU,MAAM,MAAM,CAAC,CAAC,GAE/D,QAAQ,sBAAsB,aAAa;AAE9C,QAAM,WAAW,YAAAC,QAAK,QAAQ,cAAAD,QAAO,UAAU,UAAU;AACzD,YAAAD,QAAG,cAAc,UAAU,YAAY,EAAE,UAAU,OAAO,CAAC;AAE3D,SAAO,+BAA+B,cAAAG,QAAO,KAAK,QAAQ,CAAC;AAC7D","debug_id":"e416d2b1-db35-5e4a-8bb1-6725adbec6e1"}
1
+ {"version":3,"sources":["../../lib/utils/generateJsDriver.ts"],"sourcesContent":["import fs from \"fs\";\nimport path from \"path\";\nimport consts from \"../consts\";\nimport output from \"../output\";\nimport { Source } from \"../types\";\nimport { cleanFileName } from \"./cleanFileName\";\n\n// compatability with legacy method of specifying project ids\n// that is still used by the default format\nconst stringifySourceId = (projectId: string) =>\n projectId === \"ditto_component_library\" ? projectId : `project_${projectId}`;\n\n/**\n * Generates an index.js file that can be consumed\n * by an SDK - this is a big DX improvement because\n * it provides a single entry point to get all data\n * (including variants) instead of having to import\n * each generated file individually.\n *\n * The generated file will have a unified format\n * independent of the CLI configuration used to fetch\n * data from Ditto.\n */\n\n// TODO: support ESM\nexport function generateJsDriver(sources: Source[]) {\n const sourceIdsByName: Record<string, string> = sources.reduce(\n (agg, source) => {\n if (source.fileName) {\n return { ...agg, [cleanFileName(source.fileName)]: source.id };\n }\n\n return agg;\n },\n {}\n );\n\n const projectFileNames = fs\n .readdirSync(consts.TEXT_DIR)\n .filter(\n (fileName) => /\\.json$/.test(fileName) && !/^components__/.test(fileName)\n );\n\n type DriverFile = Record<string, Record<string, string | object>>;\n const data: DriverFile = projectFileNames.reduce(\n (obj: Record<string, Record<string, string>>, fileName) => {\n const [sourceId, rest] = fileName.split(\"__\");\n const [variantApiId] = rest.split(\".\");\n\n const projectId = sourceIdsByName[sourceId];\n const projectIdStr = stringifySourceId(projectId);\n\n if (!obj[projectIdStr]) {\n obj[projectIdStr] = {};\n }\n\n obj[projectIdStr][variantApiId] = `require('./${fileName}')`;\n return obj;\n },\n {}\n );\n\n // Create arrays of stringified \"...require()\" statements,\n // each of which corresponds to one of the component files\n // (which are created on a per-component-folder basis)\n const componentData: Record<string, string[]> = {};\n sources\n .filter((s) => s.type === \"components\")\n .forEach((componentSource) => {\n if (componentSource.type !== \"components\") return;\n componentData[componentSource.variant] ??= [];\n componentData[componentSource.variant].push(\n `...require('./${componentSource.fileName}')`\n );\n });\n // Convert each array of stringified \"...require()\" statements\n // into a unified string, and set it on the final data object\n // that will be written to the driver file\n Object.keys(componentData).forEach((key) => {\n data.ditto_component_library ??= {};\n\n let str = \"{\";\n componentData[key].forEach((k, i) => {\n str += k;\n if (i < componentData[key].length - 1) str += \", \";\n });\n str += \"}\";\n data.ditto_component_library[key] = str;\n });\n\n let dataString = `module.exports = ${JSON.stringify(data, null, 2)}`\n // remove quotes around require statements\n .replace(/\"require\\((.*)\\)\"/g, \"require($1)\")\n // remove quotes around opening & closing curlies\n .replace(/\"\\{/g, \"{\")\n .replace(/\\}\"/g, \"}\");\n\n const filePath = path.resolve(consts.TEXT_DIR, \"index.js\");\n fs.writeFileSync(filePath, dataString, { encoding: \"utf8\" });\n\n return `Generated .js SDK driver at ${output.info(filePath)}`;\n}\n"],"names":["fs","consts","path","output"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gBAAe;AACf,kBAAiB;AACjB,oBAAmB;AACnB,oBAAmB;AAEnB,2BAA8B;AAI9B,MAAM,oBAAoB,CAAC,cACzB,cAAc,4BAA4B,YAAY,WAAW,SAAS;AAerE,SAAS,iBAAiB,SAAmB;AAClD,QAAM,kBAA0C,QAAQ;AAAA,IACtD,CAAC,KAAK,WAAW;AACf,UAAI,OAAO,UAAU;AACnB,eAAO,iCAAK,MAAL,EAAU,KAAC,oCAAc,OAAO,QAAQ,CAAC,GAAG,OAAO,GAAG;AAAA,MAC/D;AAEA,aAAO;AAAA,IACT;AAAA,IACA,CAAC;AAAA,EACH;AAEA,QAAM,mBAAmB,UAAAA,QACtB,YAAY,cAAAC,QAAO,QAAQ,EAC3B;AAAA,IACC,CAAC,aAAa,UAAU,KAAK,QAAQ,KAAK,CAAC,gBAAgB,KAAK,QAAQ;AAAA,EAC1E;AAGF,QAAM,OAAmB,iBAAiB;AAAA,IACxC,CAAC,KAA6C,aAAa;AACzD,YAAM,CAAC,UAAU,IAAI,IAAI,SAAS,MAAM,IAAI;AAC5C,YAAM,CAAC,YAAY,IAAI,KAAK,MAAM,GAAG;AAErC,YAAM,YAAY,gBAAgB,QAAQ;AAC1C,YAAM,eAAe,kBAAkB,SAAS;AAEhD,UAAI,CAAC,IAAI,YAAY,GAAG;AACtB,YAAI,YAAY,IAAI,CAAC;AAAA,MACvB;AAEA,UAAI,YAAY,EAAE,YAAY,IAAI,cAAc,QAAQ;AACxD,aAAO;AAAA,IACT;AAAA,IACA,CAAC;AAAA,EACH;AAKA,QAAM,gBAA0C,CAAC;AACjD,UACG,OAAO,CAAC,MAAM,EAAE,SAAS,YAAY,EACrC,QAAQ,CAAC,oBAAoB;AApElC;AAqEM,QAAI,gBAAgB,SAAS;AAAc;AAC3C,6BAAc,gBAAgB,aAA9B,gCAA2C,CAAC;AAC5C,kBAAc,gBAAgB,OAAO,EAAE;AAAA,MACrC,iBAAiB,gBAAgB,QAAQ;AAAA,IAC3C;AAAA,EACF,CAAC;AAIH,SAAO,KAAK,aAAa,EAAE,QAAQ,CAAC,QAAQ;AA9E9C;AA+EI,eAAK,4BAAL,iBAAK,0BAA4B,CAAC;AAElC,QAAI,MAAM;AACV,kBAAc,GAAG,EAAE,QAAQ,CAAC,GAAG,MAAM;AACnC,aAAO;AACP,UAAI,IAAI,cAAc,GAAG,EAAE,SAAS;AAAG,eAAO;AAAA,IAChD,CAAC;AACD,WAAO;AACP,SAAK,wBAAwB,GAAG,IAAI;AAAA,EACtC,CAAC;AAED,MAAI,aAAa,oBAAoB,KAAK,UAAU,MAAM,MAAM,CAAC,CAAC,GAE/D,QAAQ,sBAAsB,aAAa,EAE3C,QAAQ,QAAQ,GAAG,EACnB,QAAQ,QAAQ,GAAG;AAEtB,QAAM,WAAW,YAAAC,QAAK,QAAQ,cAAAD,QAAO,UAAU,UAAU;AACzD,YAAAD,QAAG,cAAc,UAAU,YAAY,EAAE,UAAU,OAAO,CAAC;AAE3D,SAAO,+BAA+B,cAAAG,QAAO,KAAK,QAAQ,CAAC;AAC7D","debug_id":"abf6148b-b36f-5809-b765-ac588ff7207f"}
package/lib/config.ts CHANGED
@@ -5,12 +5,12 @@ import yaml from "js-yaml";
5
5
  import * as Sentry from "@sentry/node";
6
6
 
7
7
  import consts from "./consts";
8
- import { Project, ConfigYAML } from "./types";
9
8
  import { createSentryContext } from "./utils/createSentryContext";
9
+ import { Project, ConfigYAML, SourceInformation } from "./types";
10
10
 
11
11
  export const DEFAULT_CONFIG_JSON: ConfigYAML = {
12
12
  sources: {
13
- components: { enabled: true },
13
+ components: true,
14
14
  },
15
15
  variants: true,
16
16
  format: "flat",
@@ -188,7 +188,7 @@ function dedupeProjectName(projectNames: Set<string>, projectName: string) {
188
188
  * - an array of valid, deduped projects
189
189
  * - the `variants` and `format` config options
190
190
  */
191
- function parseSourceInformation(file?: string) {
191
+ function parseSourceInformation(file?: string): SourceInformation {
192
192
  const {
193
193
  sources,
194
194
  variants,
@@ -222,8 +222,20 @@ function parseSourceInformation(file?: string) {
222
222
  validProjects.push(project);
223
223
  });
224
224
 
225
- const shouldFetchComponentLibrary = Boolean(sources?.components?.enabled);
226
-
225
+ const shouldFetchComponentLibrary = Boolean(sources?.components);
226
+ const componentRoot =
227
+ typeof sources?.components === "object"
228
+ ? sources.components.root
229
+ : undefined;
230
+ const componentFolders =
231
+ typeof sources?.components === "object"
232
+ ? sources.components.folders
233
+ : undefined;
234
+
235
+ /**
236
+ * If it's not specified to fetch projects or the component library, then there
237
+ * is no source data to pull.
238
+ */
227
239
  const hasSourceData = !!validProjects.length || shouldFetchComponentLibrary;
228
240
 
229
241
  const result = {
@@ -237,7 +249,8 @@ function parseSourceInformation(file?: string) {
237
249
  hasTopLevelProjectsField: !!projectsRoot,
238
250
  hasTopLevelComponentsField: !!componentsRoot,
239
251
  hasComponentLibraryInProjects,
240
- componentFolders: sources?.components?.folders || null,
252
+ componentRoot,
253
+ componentFolders,
241
254
  };
242
255
 
243
256
  Sentry.setContext("config", createSentryContext(result));
@@ -17,7 +17,7 @@ import { quit } from "../utils/quit";
17
17
  function saveProject(file: string, name: string, id: string) {
18
18
  if (id === "components") {
19
19
  config.writeProjectConfigData(file, {
20
- sources: { components: { enabled: true } },
20
+ sources: { components: true },
21
21
  });
22
22
  return;
23
23
  }