@dittowords/cli 4.4.1 → 4.5.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/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]="907226eb-d4b7-553b-a3ea-7aa63bccb645")}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]="e8a84d0c-2e74-5c27-aee1-a1e1a393e89e")}catch(e){}}();
3
3
 
4
4
  var __create = Object.create;
5
5
  var __defProp = Object.defineProperty;
@@ -176,7 +176,8 @@ function parseSourceInformation(file) {
176
176
  richText,
177
177
  iosLocales,
178
178
  projects: projectsRoot,
179
- components: componentsRoot
179
+ components: componentsRoot,
180
+ disableJsDriver
180
181
  } = readProjectConfigData(file);
181
182
  const projects = (sources == null ? void 0 : sources.projects) || [];
182
183
  const projectNames = /* @__PURE__ */ new Set();
@@ -212,7 +213,8 @@ function parseSourceInformation(file) {
212
213
  hasComponentLibraryInProjects,
213
214
  componentRoot,
214
215
  componentFolders,
215
- localeByVariantApiId: iosLocales ? iosLocales.reduce((acc, e) => __spreadValues(__spreadValues({}, acc), e), {}) : void 0
216
+ localeByVariantApiId: iosLocales ? iosLocales.reduce((acc, e) => __spreadValues(__spreadValues({}, acc), e), {}) : void 0,
217
+ disableJsDriver
216
218
  };
217
219
  Sentry.setContext("config", (0, import_createSentryContext.createSentryContext)(result));
218
220
  return result;
@@ -237,4 +239,4 @@ var config_default = {
237
239
  });
238
240
  //# sourceMappingURL=config.js.map
239
241
 
240
- //# debugId=907226eb-d4b7-553b-a3ea-7aa63bccb645
242
+ //# debugId=e8a84d0c-2e74-5c27-aee1-a1e1a393e89e
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 { 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 iosLocales,\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 localeByVariantApiId: iosLocales\n ? iosLocales.reduce((acc, e) => ({ ...acc, ...e }), {} as any)\n : undefined,\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":"907226eb-d4b7-553b-a3ea-7aa63bccb645"}
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, Source } 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 iosLocales,\n projects: projectsRoot,\n components: componentsRoot,\n disableJsDriver,\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: SourceInformation = {\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 localeByVariantApiId: iosLocales\n ? iosLocales.reduce((acc, e) => ({ ...acc, ...e }), {} as any)\n : undefined,\n disableJsDriver,\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":"e8a84d0c-2e74-5c27-aee1-a1e1a393e89e"}
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]="3d86aea7-bd78-5d3c-b8fe-f346f5c810ab")}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]="5c3ec8e4-cdb7-575c-aea7-e0d8c4bee495")}catch(e){}}();
3
3
 
4
4
  var __create = Object.create;
5
5
  var __defProp = Object.defineProperty;
@@ -274,7 +274,7 @@ function cleanOutputFiles() {
274
274
  force: true
275
275
  });
276
276
  }
277
- if (item.isFile() && /\.js(on)?|\.xml|\.strings(dict)?$|\.swift$/.test(item.name)) {
277
+ if (item.isFile() && /\.js(on)?|\.ts|\.xml|\.strings(dict)?$|\.swift$/.test(item.name)) {
278
278
  return import_fs.default.unlinkSync(import_path.default.resolve(import_consts.default.TEXT_DIR, item.name));
279
279
  }
280
280
  });
@@ -291,7 +291,8 @@ function downloadAndSave(source, token, options) {
291
291
  richText,
292
292
  componentFolders: specifiedComponentFolders,
293
293
  componentRoot,
294
- localeByVariantApiId
294
+ localeByVariantApiId,
295
+ disableJsDriver
295
296
  } = source;
296
297
  const formats = getFormat(formatFromSource);
297
298
  const hasJSONFormat = formats.some(
@@ -454,7 +455,7 @@ Fetching the latest text from ${(0, import_sourcesToText.default)(
454
455
  }
455
456
  }
456
457
  const sources = [...validProjects, ...componentSources];
457
- if (hasJSONFormat)
458
+ if (hasJSONFormat && !disableJsDriver)
458
459
  msg += (0, import_generateJsDriver.generateJsDriver)(sources, getJsonFormat(formats));
459
460
  if (shouldGenerateIOSBundles) {
460
461
  msg += "iOS locale information detected, generating bundles..\n\n";
@@ -558,4 +559,4 @@ const _test = {
558
559
  });
559
560
  //# sourceMappingURL=pull.js.map
560
561
 
561
- //# debugId=3d86aea7-bd78-5d3c-b8fe-f346f5c810ab
562
+ //# debugId=5c3ec8e4-cdb7-575c-aea7-e0d8c4bee495
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 {\n SourceInformation,\n Token,\n Project,\n SupportedFormat,\n SupportedExtension,\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\";\nimport { generateSwiftDriver } from \"./utils/generateSwiftDriver\";\nimport { generateIOSBundles } from \"./utils/generateIOSBundles\";\n\ninterface IRequestOptions {\n projects: Project[];\n format: SupportedFormat;\n status: string | undefined;\n richText?: boolean | undefined;\n token?: Token;\n options?: PullOptions;\n}\n\ninterface IRequestOptionsWithVariants extends IRequestOptions {\n variants: { apiID: string }[];\n}\n\nconst ensureEndsWithNewLine = (str: string) =>\n str + (/[\\r\\n]$/.test(str) ? \"\" : \"\\n\");\n\nexport const writeFile = (path: string, data: string) =>\n new Promise((r) => fs.writeFile(path, ensureEndsWithNewLine(data), r));\n\nconst SUPPORTED_FORMATS: SupportedFormat[] = [\n \"flat\",\n \"nested\",\n \"structured\",\n \"android\",\n \"ios-strings\",\n \"ios-stringsdict\",\n \"icu\",\n];\n\nexport type JSONFormat = \"flat\" | \"nested\" | \"structured\" | \"icu\";\n\nconst IOS_FORMATS: SupportedFormat[] = [\"ios-strings\", \"ios-stringsdict\"];\nconst JSON_FORMATS: JSONFormat[] = [\"flat\", \"nested\", \"structured\", \"icu\"];\n\nconst getJsonFormat = (formats: string[]): JSONFormat => {\n // edge case: multiple json formats specified\n // we should grab the last one\n const jsonFormats = formats.filter((f) =>\n JSON_FORMATS.includes(f as JSONFormat)\n ) as JSONFormat[];\n\n return jsonFormats[jsonFormats.length - 1] || \"flat\";\n};\n\nconst FORMAT_EXTENSIONS: Record<SupportedFormat, SupportedExtension> = {\n flat: \".json\",\n nested: \".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 nested: 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 requestOptions: IRequestOptions\n) {\n const { projects, format, status, richText, token } = requestOptions;\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(`/v1/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 requestOptions: IRequestOptionsWithVariants\n) {\n const messages = await Promise.all([\n downloadAndSaveVariant(null, requestOptions),\n ...requestOptions.variants.map(({ apiID }: { apiID: string }) =>\n downloadAndSaveVariant(apiID, requestOptions)\n ),\n ]);\n\n return messages.join(\"\");\n}\n\nasync function downloadAndSaveBase(requestOptions: IRequestOptions) {\n const { projects, format, status, richText, token, options } = requestOptions;\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(`/v1/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 directoryContents = fs.readdirSync(consts.TEXT_DIR, {\n withFileTypes: true,\n });\n\n directoryContents.forEach((item) => {\n if (item.isDirectory() && /\\.lproj$/.test(item.name)) {\n return fs.rmSync(path.resolve(consts.TEXT_DIR, item.name), {\n recursive: true,\n force: true,\n });\n }\n\n if (\n item.isFile() &&\n /\\.js(on)?|\\.xml|\\.strings(dict)?$|\\.swift$/.test(item.name)\n ) {\n return fs.unlinkSync(path.resolve(consts.TEXT_DIR, item.name));\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 localeByVariantApiId,\n } = source;\n\n const formats = getFormat(formatFromSource);\n\n const hasJSONFormat = formats.some((f) =>\n JSON_FORMATS.includes(f as JSONFormat)\n );\n const hasIOSFormat = formats.some((f) => IOS_FORMATS.includes(f));\n const shouldGenerateIOSBundles = hasIOSFormat && localeByVariantApiId;\n\n const shouldLogOutputFiles = !shouldGenerateIOSBundles;\n\n let msg = \"\";\n const spinner = ora(msg);\n spinner.start();\n\n const [variants, allComponentFoldersResponse] = await Promise.all([\n fetchVariants(source, options),\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 ? \"/v1/components?root_only=true\"\n : `/v1/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\n // we need to clean the folder name by itself first, otherwise we can\n // end up with \"empty\" words and weird hyphenation.\n const nameFolder = `__${cleanFileName(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 if (shouldLogOutputFiles) {\n msg += messages.join(\"\");\n }\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 let result = \"\";\n if (variants) {\n result = await downloadAndSaveVariants({\n variants,\n projects: validProjects,\n format,\n status,\n richText,\n token,\n });\n } else {\n result = await downloadAndSaveBase({\n projects: validProjects,\n format,\n status,\n richText,\n token,\n options: {\n meta,\n },\n });\n }\n\n if (shouldLogOutputFiles) {\n msg += result;\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 (hasJSONFormat) msg += generateJsDriver(sources, getJsonFormat(formats));\n\n if (shouldGenerateIOSBundles) {\n msg += \"iOS locale information detected, generating bundles..\\n\\n\";\n msg += await generateIOSBundles(localeByVariantApiId);\n msg += await generateSwiftDriver(source);\n }\n\n msg += `\\n\\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 includeSampleData?: boolean;\n}\n\nexport const pull = async (options?: PullOptions) => {\n const meta = options ? options.meta : {};\n const includeSampleData = options?.includeSampleData || false;\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, {\n meta,\n includeSampleData,\n });\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\nexport const _test = {\n getJsonFormat,\n getJsonFormatIsValid,\n ensureEndsWithNewLine,\n};\n"],"names":["path","fs","config","consts","output","ora","sourcesToText"],"mappings":"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","debug_id":"3d86aea7-bd78-5d3c-b8fe-f346f5c810ab"}
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 SupportedExtension,\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\";\nimport { generateSwiftDriver } from \"./utils/generateSwiftDriver\";\nimport { generateIOSBundles } from \"./utils/generateIOSBundles\";\n\ninterface IRequestOptions {\n projects: Project[];\n format: SupportedFormat;\n status: string | undefined;\n richText?: boolean | undefined;\n token?: Token;\n options?: PullOptions;\n}\n\ninterface IRequestOptionsWithVariants extends IRequestOptions {\n variants: { apiID: string }[];\n}\n\nconst ensureEndsWithNewLine = (str: string) =>\n str + (/[\\r\\n]$/.test(str) ? \"\" : \"\\n\");\n\nexport const writeFile = (path: string, data: string) =>\n new Promise((r) => fs.writeFile(path, ensureEndsWithNewLine(data), r));\n\nconst SUPPORTED_FORMATS: SupportedFormat[] = [\n \"flat\",\n \"nested\",\n \"structured\",\n \"android\",\n \"ios-strings\",\n \"ios-stringsdict\",\n \"icu\",\n];\n\nexport type JSONFormat = \"flat\" | \"nested\" | \"structured\" | \"icu\";\n\nconst IOS_FORMATS: SupportedFormat[] = [\"ios-strings\", \"ios-stringsdict\"];\nconst JSON_FORMATS: JSONFormat[] = [\"flat\", \"nested\", \"structured\", \"icu\"];\n\nconst getJsonFormat = (formats: string[]): JSONFormat => {\n // edge case: multiple json formats specified\n // we should grab the last one\n const jsonFormats = formats.filter((f) =>\n JSON_FORMATS.includes(f as JSONFormat)\n ) as JSONFormat[];\n\n return jsonFormats[jsonFormats.length - 1] || \"flat\";\n};\n\nconst FORMAT_EXTENSIONS: Record<SupportedFormat, SupportedExtension> = {\n flat: \".json\",\n nested: \".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 nested: 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 requestOptions: IRequestOptions\n) {\n const { projects, format, status, richText, token } = requestOptions;\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(`/v1/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 requestOptions: IRequestOptionsWithVariants\n) {\n const messages = await Promise.all([\n downloadAndSaveVariant(null, requestOptions),\n ...requestOptions.variants.map(({ apiID }: { apiID: string }) =>\n downloadAndSaveVariant(apiID, requestOptions)\n ),\n ]);\n\n return messages.join(\"\");\n}\n\nasync function downloadAndSaveBase(requestOptions: IRequestOptions) {\n const { projects, format, status, richText, token, options } = requestOptions;\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(`/v1/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 directoryContents = fs.readdirSync(consts.TEXT_DIR, {\n withFileTypes: true,\n });\n\n directoryContents.forEach((item) => {\n if (item.isDirectory() && /\\.lproj$/.test(item.name)) {\n return fs.rmSync(path.resolve(consts.TEXT_DIR, item.name), {\n recursive: true,\n force: true,\n });\n }\n\n if (\n item.isFile() &&\n /\\.js(on)?|\\.ts|\\.xml|\\.strings(dict)?$|\\.swift$/.test(item.name)\n ) {\n return fs.unlinkSync(path.resolve(consts.TEXT_DIR, item.name));\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 localeByVariantApiId,\n disableJsDriver,\n } = source;\n\n const formats = getFormat(formatFromSource);\n\n const hasJSONFormat = formats.some((f) =>\n JSON_FORMATS.includes(f as JSONFormat)\n );\n const hasIOSFormat = formats.some((f) => IOS_FORMATS.includes(f));\n const shouldGenerateIOSBundles = hasIOSFormat && localeByVariantApiId;\n\n const shouldLogOutputFiles = !shouldGenerateIOSBundles;\n\n let msg = \"\";\n const spinner = ora(msg);\n spinner.start();\n\n const [variants, allComponentFoldersResponse] = await Promise.all([\n fetchVariants(source, options),\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 ? \"/v1/components?root_only=true\"\n : `/v1/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\n // we need to clean the folder name by itself first, otherwise we can\n // end up with \"empty\" words and weird hyphenation.\n const nameFolder = `__${cleanFileName(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 if (shouldLogOutputFiles) {\n msg += messages.join(\"\");\n }\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 let result = \"\";\n if (variants) {\n result = await downloadAndSaveVariants({\n variants,\n projects: validProjects,\n format,\n status,\n richText,\n token,\n });\n } else {\n result = await downloadAndSaveBase({\n projects: validProjects,\n format,\n status,\n richText,\n token,\n options: {\n meta,\n },\n });\n }\n\n if (shouldLogOutputFiles) {\n msg += result;\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 (hasJSONFormat && !disableJsDriver)\n msg += generateJsDriver(sources, getJsonFormat(formats));\n\n if (shouldGenerateIOSBundles) {\n msg += \"iOS locale information detected, generating bundles..\\n\\n\";\n msg += await generateIOSBundles(localeByVariantApiId);\n msg += await generateSwiftDriver(source);\n }\n\n msg += `\\n\\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 includeSampleData?: boolean;\n}\n\nexport const pull = async (options?: PullOptions) => {\n const meta = options ? options.meta : {};\n const includeSampleData = options?.includeSampleData || false;\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, {\n meta,\n includeSampleData,\n });\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\nexport const _test = {\n getJsonFormat,\n getJsonFormatIsValid,\n ensureEndsWithNewLine,\n};\n"],"names":["path","fs","config","consts","output","ora","sourcesToText"],"mappings":"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","debug_id":"5c3ec8e4-cdb7-575c-aea7-e0d8c4bee495"}
package/bin/pull.test.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]="ad385829-c058-59ae-8358-bf84acb2d6d9")}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]="4ca59558-b2d6-536a-a5a5-bd049d48303f")}catch(e){}}();
3
3
 
4
4
  var __create = Object.create;
5
5
  var __defProp = Object.defineProperty;
@@ -117,7 +117,35 @@ describe("pull", () => {
117
117
  });
118
118
  expect(filesOnDiskExpected.size).toBe(0);
119
119
  }));
120
+ it("correctly does not write index.js or index.d.ts when `disableJsDriver: true` is specified", () => __async(exports, null, function* () {
121
+ process.env.DITTO_TEXT_DIR = "/ditto";
122
+ process.env.DITTO_PROJECT_CONFIG_FILE = "/ditto/config.yml";
123
+ axiosMock.get.mockImplementation(
124
+ () => Promise.resolve({ data: "data" })
125
+ );
126
+ import_memfs.vol.fromJSON({
127
+ [import_consts.default.CONFIG_FILE]: mockGlobalConfigFile,
128
+ [import_consts.default.PROJECT_CONFIG_FILE]: mockProjectConfigFile + "\ndisableJsDriver: true"
129
+ });
130
+ yield (0, import_pull.pull)();
131
+ const filesOnDiskExpected = /* @__PURE__ */ new Set([
132
+ "components__example-folder__base.json",
133
+ "components__example-folder__example-variant-1.json",
134
+ "components__example-folder__example-variant-2.json",
135
+ "components__root__base.json",
136
+ "components__root__example-variant-1.json",
137
+ "components__root__example-variant-2.json",
138
+ "test-project__base.json",
139
+ "test-project__example-variant-1.json",
140
+ "test-project__example-variant-2.json"
141
+ ]);
142
+ const filesOnDisk = import_fs.default.readdirSync("/ditto");
143
+ filesOnDisk.forEach((file) => {
144
+ filesOnDiskExpected.delete(file);
145
+ });
146
+ expect(filesOnDiskExpected.size).toBe(0);
147
+ }));
120
148
  });
121
149
  //# sourceMappingURL=pull.test.js.map
122
150
 
123
- //# debugId=ad385829-c058-59ae-8358-bf84acb2d6d9
151
+ //# debugId=4ca59558-b2d6-536a-a5a5-bd049d48303f
@@ -1 +1 @@
1
- {"version":3,"sources":["../lib/pull.test.ts"],"sourcesContent":["import { pull } from \"./pull\";\nimport { vol } from \"memfs\";\nimport consts from \"./consts\";\nimport { jest } from \"@jest/globals\";\nimport axios from \"axios\";\nconst axiosMock = jest.mocked(axios);\nimport fs from \"fs\";\n\njest.mock(\"fs\");\njest.mock(\"./api\");\n\njest.mock(\"./http/fetchComponentFolders\");\njest.mock(\"./http/fetchComponents\");\njest.mock(\"./http/fetchVariants\");\n\nconst defaultEnv = { ...process.env };\n\nbeforeEach(() => {\n vol.reset();\n process.env = { ...defaultEnv };\n});\n\nconst mockGlobalConfigFile = `\napi.dittowords.com:\n - token: xxx-xxx-xxx\n`;\nconst mockProjectConfigFile = `\nsources:\n components: true\n projects:\n - id: project-id-1\n name: Test Project\nvariants: true\n`;\n\ndescribe(\"pull\", () => {\n it(\"correctly writes files to disk per source for basic config\", async () => {\n process.env.DITTO_TEXT_DIR = \"/ditto\";\n process.env.DITTO_PROJECT_CONFIG_FILE = \"/ditto/config.yml\";\n\n // we need to manually mock responses for the http calls that happen\n // directly within the pull function; we don't need to mock the http\n // calls that happen by way of http/* function calls since those have\n // their own mocks already.\n axiosMock.get.mockImplementation(\n (): Promise<any> => Promise.resolve({ data: \"data\" })\n );\n\n vol.fromJSON({\n [consts.CONFIG_FILE]: mockGlobalConfigFile,\n [consts.PROJECT_CONFIG_FILE]: mockProjectConfigFile,\n });\n\n await pull();\n\n const filesOnDiskExpected = new Set([\n \"components__example-folder__base.json\",\n \"components__example-folder__example-variant-1.json\",\n \"components__example-folder__example-variant-2.json\",\n \"components__root__base.json\",\n \"components__root__example-variant-1.json\",\n \"components__root__example-variant-2.json\",\n \"test-project__base.json\",\n \"test-project__example-variant-1.json\",\n \"test-project__example-variant-2.json\",\n \"index.d.ts\",\n \"index.js\",\n ]);\n\n const filesOnDisk = fs.readdirSync(\"/ditto\");\n filesOnDisk.forEach((file) => {\n filesOnDiskExpected.delete(file);\n });\n\n expect(filesOnDiskExpected.size).toBe(0);\n });\n});\n"],"names":["axios","consts","fs"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,kBAAqB;AACrB,mBAAoB;AACpB,oBAAmB;AACnB,qBAAqB;AACrB,mBAAkB;AAElB,gBAAe;AADf,MAAM,YAAY,oBAAK,OAAO,aAAAA,OAAK;AAGnC,oBAAK,KAAK,IAAI;AACd,oBAAK,KAAK,OAAO;AAEjB,oBAAK,KAAK,8BAA8B;AACxC,oBAAK,KAAK,wBAAwB;AAClC,oBAAK,KAAK,sBAAsB;AAEhC,MAAM,aAAa,mBAAK,QAAQ;AAEhC,WAAW,MAAM;AACf,mBAAI,MAAM;AACV,UAAQ,MAAM,mBAAK;AACrB,CAAC;AAED,MAAM,uBAAuB;AAAA;AAAA;AAAA;AAI7B,MAAM,wBAAwB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAS9B,SAAS,QAAQ,MAAM;AACrB,KAAG,8DAA8D,MAAY;AAC3E,YAAQ,IAAI,iBAAiB;AAC7B,YAAQ,IAAI,4BAA4B;AAMxC,cAAU,IAAI;AAAA,MACZ,MAAoB,QAAQ,QAAQ,EAAE,MAAM,OAAO,CAAC;AAAA,IACtD;AAEA,qBAAI,SAAS;AAAA,MACX,CAAC,cAAAC,QAAO,WAAW,GAAG;AAAA,MACtB,CAAC,cAAAA,QAAO,mBAAmB,GAAG;AAAA,IAChC,CAAC;AAED,cAAM,kBAAK;AAEX,UAAM,sBAAsB,oBAAI,IAAI;AAAA,MAClC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAED,UAAM,cAAc,UAAAC,QAAG,YAAY,QAAQ;AAC3C,gBAAY,QAAQ,CAAC,SAAS;AAC5B,0BAAoB,OAAO,IAAI;AAAA,IACjC,CAAC;AAED,WAAO,oBAAoB,IAAI,EAAE,KAAK,CAAC;AAAA,EACzC,EAAC;AACH,CAAC","debug_id":"ad385829-c058-59ae-8358-bf84acb2d6d9"}
1
+ {"version":3,"sources":["../lib/pull.test.ts"],"sourcesContent":["import { pull } from \"./pull\";\nimport { vol } from \"memfs\";\nimport consts from \"./consts\";\nimport { jest } from \"@jest/globals\";\nimport axios from \"axios\";\nconst axiosMock = jest.mocked(axios);\nimport fs from \"fs\";\n\njest.mock(\"fs\");\njest.mock(\"./api\");\n\njest.mock(\"./http/fetchComponentFolders\");\njest.mock(\"./http/fetchComponents\");\njest.mock(\"./http/fetchVariants\");\n\nconst defaultEnv = { ...process.env };\n\nbeforeEach(() => {\n vol.reset();\n process.env = { ...defaultEnv };\n});\n\nconst mockGlobalConfigFile = `\napi.dittowords.com:\n - token: xxx-xxx-xxx\n`;\nconst mockProjectConfigFile = `\nsources:\n components: true\n projects:\n - id: project-id-1\n name: Test Project\nvariants: true\n`;\n\ndescribe(\"pull\", () => {\n it(\"correctly writes files to disk per source for basic config\", async () => {\n process.env.DITTO_TEXT_DIR = \"/ditto\";\n process.env.DITTO_PROJECT_CONFIG_FILE = \"/ditto/config.yml\";\n\n // we need to manually mock responses for the http calls that happen\n // directly within the pull function; we don't need to mock the http\n // calls that happen by way of http/* function calls since those have\n // their own mocks already.\n axiosMock.get.mockImplementation(\n (): Promise<any> => Promise.resolve({ data: \"data\" })\n );\n\n vol.fromJSON({\n [consts.CONFIG_FILE]: mockGlobalConfigFile,\n [consts.PROJECT_CONFIG_FILE]: mockProjectConfigFile,\n });\n\n await pull();\n\n const filesOnDiskExpected = new Set([\n \"components__example-folder__base.json\",\n \"components__example-folder__example-variant-1.json\",\n \"components__example-folder__example-variant-2.json\",\n \"components__root__base.json\",\n \"components__root__example-variant-1.json\",\n \"components__root__example-variant-2.json\",\n \"test-project__base.json\",\n \"test-project__example-variant-1.json\",\n \"test-project__example-variant-2.json\",\n \"index.d.ts\",\n \"index.js\",\n ]);\n\n const filesOnDisk = fs.readdirSync(\"/ditto\");\n filesOnDisk.forEach((file) => {\n filesOnDiskExpected.delete(file);\n });\n\n expect(filesOnDiskExpected.size).toBe(0);\n });\n\n it(\"correctly does not write index.js or index.d.ts when `disableJsDriver: true` is specified\", async () => {\n process.env.DITTO_TEXT_DIR = \"/ditto\";\n process.env.DITTO_PROJECT_CONFIG_FILE = \"/ditto/config.yml\";\n\n // we need to manually mock responses for the http calls that happen\n // directly within the pull function; we don't need to mock the http\n // calls that happen by way of http/* function calls since those have\n // their own mocks already.\n axiosMock.get.mockImplementation(\n (): Promise<any> => Promise.resolve({ data: \"data\" })\n );\n\n vol.fromJSON({\n [consts.CONFIG_FILE]: mockGlobalConfigFile,\n [consts.PROJECT_CONFIG_FILE]:\n mockProjectConfigFile + \"\\n\" + \"disableJsDriver: true\",\n });\n\n await pull();\n\n const filesOnDiskExpected = new Set([\n \"components__example-folder__base.json\",\n \"components__example-folder__example-variant-1.json\",\n \"components__example-folder__example-variant-2.json\",\n \"components__root__base.json\",\n \"components__root__example-variant-1.json\",\n \"components__root__example-variant-2.json\",\n \"test-project__base.json\",\n \"test-project__example-variant-1.json\",\n \"test-project__example-variant-2.json\",\n ]);\n\n const filesOnDisk = fs.readdirSync(\"/ditto\");\n filesOnDisk.forEach((file) => {\n filesOnDiskExpected.delete(file);\n });\n\n expect(filesOnDiskExpected.size).toBe(0);\n });\n});\n"],"names":["axios","consts","fs"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,kBAAqB;AACrB,mBAAoB;AACpB,oBAAmB;AACnB,qBAAqB;AACrB,mBAAkB;AAElB,gBAAe;AADf,MAAM,YAAY,oBAAK,OAAO,aAAAA,OAAK;AAGnC,oBAAK,KAAK,IAAI;AACd,oBAAK,KAAK,OAAO;AAEjB,oBAAK,KAAK,8BAA8B;AACxC,oBAAK,KAAK,wBAAwB;AAClC,oBAAK,KAAK,sBAAsB;AAEhC,MAAM,aAAa,mBAAK,QAAQ;AAEhC,WAAW,MAAM;AACf,mBAAI,MAAM;AACV,UAAQ,MAAM,mBAAK;AACrB,CAAC;AAED,MAAM,uBAAuB;AAAA;AAAA;AAAA;AAI7B,MAAM,wBAAwB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAS9B,SAAS,QAAQ,MAAM;AACrB,KAAG,8DAA8D,MAAY;AAC3E,YAAQ,IAAI,iBAAiB;AAC7B,YAAQ,IAAI,4BAA4B;AAMxC,cAAU,IAAI;AAAA,MACZ,MAAoB,QAAQ,QAAQ,EAAE,MAAM,OAAO,CAAC;AAAA,IACtD;AAEA,qBAAI,SAAS;AAAA,MACX,CAAC,cAAAC,QAAO,WAAW,GAAG;AAAA,MACtB,CAAC,cAAAA,QAAO,mBAAmB,GAAG;AAAA,IAChC,CAAC;AAED,cAAM,kBAAK;AAEX,UAAM,sBAAsB,oBAAI,IAAI;AAAA,MAClC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAED,UAAM,cAAc,UAAAC,QAAG,YAAY,QAAQ;AAC3C,gBAAY,QAAQ,CAAC,SAAS;AAC5B,0BAAoB,OAAO,IAAI;AAAA,IACjC,CAAC;AAED,WAAO,oBAAoB,IAAI,EAAE,KAAK,CAAC;AAAA,EACzC,EAAC;AAED,KAAG,6FAA6F,MAAY;AAC1G,YAAQ,IAAI,iBAAiB;AAC7B,YAAQ,IAAI,4BAA4B;AAMxC,cAAU,IAAI;AAAA,MACZ,MAAoB,QAAQ,QAAQ,EAAE,MAAM,OAAO,CAAC;AAAA,IACtD;AAEA,qBAAI,SAAS;AAAA,MACX,CAAC,cAAAD,QAAO,WAAW,GAAG;AAAA,MACtB,CAAC,cAAAA,QAAO,mBAAmB,GACzB,wBAAwB;AAAA,IAC5B,CAAC;AAED,cAAM,kBAAK;AAEX,UAAM,sBAAsB,oBAAI,IAAI;AAAA,MAClC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAED,UAAM,cAAc,UAAAC,QAAG,YAAY,QAAQ;AAC3C,gBAAY,QAAQ,CAAC,SAAS;AAC5B,0BAAoB,OAAO,IAAI;AAAA,IACjC,CAAC;AAED,WAAO,oBAAoB,IAAI,EAAE,KAAK,CAAC;AAAA,EACzC,EAAC;AACH,CAAC","debug_id":"4ca59558-b2d6-536a-a5a5-bd049d48303f"}
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]="adad285b-cb83-5dca-a453-8ef2b50a6237")}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]="31cef992-b35d-58a1-b36c-4df7755fb649")}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=adad285b-cb83-5dca-a453-8ef2b50a6237
21
+ //# debugId=31cef992-b35d-58a1-b36c-4df7755fb649
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 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 | \"nested\"\n | \"structured\"\n | \"android\"\n | \"ios-strings\"\n | \"ios-stringsdict\"\n | \"icu\";\n\nexport type SupportedExtension = \".json\" | \".xml\" | \".strings\" | \".stringsdict\";\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 // TODO: might want to rename this at some point\n iosLocales?: Record<string, string>[];\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 localeByVariantApiId: Record<string, string> | undefined;\n}\n\nexport type Token = string | undefined;\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA;AAAA","debug_id":"adad285b-cb83-5dca-a453-8ef2b50a6237"}
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 | \"nested\"\n | \"structured\"\n | \"android\"\n | \"ios-strings\"\n | \"ios-stringsdict\"\n | \"icu\";\n\nexport type SupportedExtension = \".json\" | \".xml\" | \".strings\" | \".stringsdict\";\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 // TODO: might want to rename this at some point\n iosLocales?: Record<string, string>[];\n\n // prevents the generation of index.js and index.d.ts files\n // when working with JSON formats\n disableJsDriver?: 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 localeByVariantApiId: Record<string, string> | undefined;\n disableJsDriver?: boolean;\n}\n\nexport type Token = string | undefined;\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA;AAAA","debug_id":"31cef992-b35d-58a1-b36c-4df7755fb649"}
package/lib/config.ts CHANGED
@@ -6,7 +6,7 @@ import * as Sentry from "@sentry/node";
6
6
 
7
7
  import consts from "./consts";
8
8
  import { createSentryContext } from "./utils/createSentryContext";
9
- import { Project, ConfigYAML, SourceInformation } from "./types";
9
+ import { Project, ConfigYAML, SourceInformation, Source } from "./types";
10
10
 
11
11
  export const DEFAULT_CONFIG_JSON: ConfigYAML = {
12
12
  sources: {
@@ -198,6 +198,7 @@ function parseSourceInformation(file?: string): SourceInformation {
198
198
  iosLocales,
199
199
  projects: projectsRoot,
200
200
  components: componentsRoot,
201
+ disableJsDriver,
201
202
  } = readProjectConfigData(file);
202
203
 
203
204
  const projects = sources?.projects || [];
@@ -239,7 +240,7 @@ function parseSourceInformation(file?: string): SourceInformation {
239
240
  */
240
241
  const hasSourceData = !!validProjects.length || shouldFetchComponentLibrary;
241
242
 
242
- const result = {
243
+ const result: SourceInformation = {
243
244
  hasSourceData,
244
245
  validProjects,
245
246
  shouldFetchComponentLibrary,
@@ -255,6 +256,7 @@ function parseSourceInformation(file?: string): SourceInformation {
255
256
  localeByVariantApiId: iosLocales
256
257
  ? iosLocales.reduce((acc, e) => ({ ...acc, ...e }), {} as any)
257
258
  : undefined,
259
+ disableJsDriver,
258
260
  };
259
261
 
260
262
  Sentry.setContext("config", createSentryContext(result));
package/lib/pull.test.ts CHANGED
@@ -74,4 +74,44 @@ describe("pull", () => {
74
74
 
75
75
  expect(filesOnDiskExpected.size).toBe(0);
76
76
  });
77
+
78
+ it("correctly does not write index.js or index.d.ts when `disableJsDriver: true` is specified", async () => {
79
+ process.env.DITTO_TEXT_DIR = "/ditto";
80
+ process.env.DITTO_PROJECT_CONFIG_FILE = "/ditto/config.yml";
81
+
82
+ // we need to manually mock responses for the http calls that happen
83
+ // directly within the pull function; we don't need to mock the http
84
+ // calls that happen by way of http/* function calls since those have
85
+ // their own mocks already.
86
+ axiosMock.get.mockImplementation(
87
+ (): Promise<any> => Promise.resolve({ data: "data" })
88
+ );
89
+
90
+ vol.fromJSON({
91
+ [consts.CONFIG_FILE]: mockGlobalConfigFile,
92
+ [consts.PROJECT_CONFIG_FILE]:
93
+ mockProjectConfigFile + "\n" + "disableJsDriver: true",
94
+ });
95
+
96
+ await pull();
97
+
98
+ const filesOnDiskExpected = new Set([
99
+ "components__example-folder__base.json",
100
+ "components__example-folder__example-variant-1.json",
101
+ "components__example-folder__example-variant-2.json",
102
+ "components__root__base.json",
103
+ "components__root__example-variant-1.json",
104
+ "components__root__example-variant-2.json",
105
+ "test-project__base.json",
106
+ "test-project__example-variant-1.json",
107
+ "test-project__example-variant-2.json",
108
+ ]);
109
+
110
+ const filesOnDisk = fs.readdirSync("/ditto");
111
+ filesOnDisk.forEach((file) => {
112
+ filesOnDiskExpected.delete(file);
113
+ });
114
+
115
+ expect(filesOnDiskExpected.size).toBe(0);
116
+ });
77
117
  });
package/lib/pull.ts CHANGED
@@ -286,7 +286,7 @@ function cleanOutputFiles() {
286
286
 
287
287
  if (
288
288
  item.isFile() &&
289
- /\.js(on)?|\.xml|\.strings(dict)?$|\.swift$/.test(item.name)
289
+ /\.js(on)?|\.ts|\.xml|\.strings(dict)?$|\.swift$/.test(item.name)
290
290
  ) {
291
291
  return fs.unlinkSync(path.resolve(consts.TEXT_DIR, item.name));
292
292
  }
@@ -310,6 +310,7 @@ async function downloadAndSave(
310
310
  componentFolders: specifiedComponentFolders,
311
311
  componentRoot,
312
312
  localeByVariantApiId,
313
+ disableJsDriver,
313
314
  } = source;
314
315
 
315
316
  const formats = getFormat(formatFromSource);
@@ -525,7 +526,8 @@ async function downloadAndSave(
525
526
 
526
527
  const sources: Source[] = [...validProjects, ...componentSources];
527
528
 
528
- if (hasJSONFormat) msg += generateJsDriver(sources, getJsonFormat(formats));
529
+ if (hasJSONFormat && !disableJsDriver)
530
+ msg += generateJsDriver(sources, getJsonFormat(formats));
529
531
 
530
532
  if (shouldGenerateIOSBundles) {
531
533
  msg += "iOS locale information detected, generating bundles..\n\n";
package/lib/types.ts CHANGED
@@ -52,6 +52,10 @@ export interface ConfigYAML {
52
52
  // TODO: might want to rename this at some point
53
53
  iosLocales?: Record<string, string>[];
54
54
 
55
+ // prevents the generation of index.js and index.d.ts files
56
+ // when working with JSON formats
57
+ disableJsDriver?: boolean;
58
+
55
59
  // these are legacy fields - if they exist, we should output
56
60
  // a deprecation error, and suggest that they nest them under
57
61
  // a top-level `sources` property
@@ -73,6 +77,7 @@ export interface SourceInformation {
73
77
  componentRoot: boolean | { status: string } | undefined;
74
78
  componentFolders: ComponentFolder[] | undefined;
75
79
  localeByVariantApiId: Record<string, string> | undefined;
80
+ disableJsDriver?: boolean;
76
81
  }
77
82
 
78
83
  export type Token = string | undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dittowords/cli",
3
- "version": "4.4.1",
3
+ "version": "4.5.0",
4
4
  "description": "Command Line Interface for Ditto (dittowords.com).",
5
5
  "license": "MIT",
6
6
  "main": "bin/index.js",
package/.sentryclirc DELETED
@@ -1,3 +0,0 @@
1
-
2
- [auth]
3
- token=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