@dittowords/cli 4.5.2 → 5.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -5
- package/bin/ditto.js +110 -285
- package/package.json +16 -10
- package/.github/actions/install-node-dependencies/action.yml +0 -24
- package/.github/workflows/required-checks.yml +0 -24
- package/.husky/pre-commit +0 -4
- package/.prettierignore +0 -0
- package/.prettierrc.json +0 -1
- package/__mocks__/fs.js +0 -2
- package/babel.config.js +0 -6
- package/bin/__mocks__/api.js +0 -48
- package/bin/__mocks__/api.js.map +0 -1
- package/bin/add-project.js +0 -104
- package/bin/add-project.js.map +0 -1
- package/bin/api.js +0 -54
- package/bin/api.js.map +0 -1
- package/bin/component-folders.js +0 -59
- package/bin/component-folders.js.map +0 -1
- package/bin/config.js +0 -242
- package/bin/config.js.map +0 -1
- package/bin/config.test.js +0 -93
- package/bin/config.test.js.map +0 -1
- package/bin/consts.js +0 -57
- package/bin/consts.js.map +0 -1
- package/bin/ditto.js.map +0 -1
- package/bin/generate-suggestions.js +0 -183
- package/bin/generate-suggestions.js.map +0 -1
- package/bin/generate-suggestions.test.js +0 -200
- package/bin/generate-suggestions.test.js.map +0 -1
- package/bin/http/__mocks__/fetchComponentFolders.js +0 -71
- package/bin/http/__mocks__/fetchComponentFolders.js.map +0 -1
- package/bin/http/__mocks__/fetchComponents.js +0 -73
- package/bin/http/__mocks__/fetchComponents.js.map +0 -1
- package/bin/http/__mocks__/fetchVariants.js +0 -71
- package/bin/http/__mocks__/fetchVariants.js.map +0 -1
- package/bin/http/fetchComponentFolders.js +0 -64
- package/bin/http/fetchComponentFolders.js.map +0 -1
- package/bin/http/fetchComponents.js +0 -78
- package/bin/http/fetchComponents.js.map +0 -1
- package/bin/http/fetchVariants.js +0 -87
- package/bin/http/fetchVariants.js.map +0 -1
- package/bin/http/http.test.js +0 -159
- package/bin/http/http.test.js.map +0 -1
- package/bin/http/importComponents.js +0 -114
- package/bin/http/importComponents.js.map +0 -1
- package/bin/importComponents.js +0 -65
- package/bin/importComponents.js.map +0 -1
- package/bin/init/init.js +0 -126
- package/bin/init/init.js.map +0 -1
- package/bin/init/project.js +0 -182
- package/bin/init/project.js.map +0 -1
- package/bin/init/project.test.js +0 -26
- package/bin/init/project.test.js.map +0 -1
- package/bin/init/token.js +0 -196
- package/bin/init/token.js.map +0 -1
- package/bin/init/token.test.js +0 -147
- package/bin/init/token.test.js.map +0 -1
- package/bin/output.js +0 -76
- package/bin/output.js.map +0 -1
- package/bin/pull-lib.test.js +0 -379
- package/bin/pull-lib.test.js.map +0 -1
- package/bin/pull.js +0 -562
- package/bin/pull.js.map +0 -1
- package/bin/pull.test.js +0 -151
- package/bin/pull.test.js.map +0 -1
- package/bin/remove-project.js +0 -99
- package/bin/remove-project.js.map +0 -1
- package/bin/replace.js +0 -171
- package/bin/replace.js.map +0 -1
- package/bin/replace.test.js +0 -197
- package/bin/replace.test.js.map +0 -1
- package/bin/types.js +0 -21
- package/bin/types.js.map +0 -1
- package/bin/utils/cleanFileName.js +0 -40
- package/bin/utils/cleanFileName.js.map +0 -1
- package/bin/utils/cleanFileName.test.js +0 -15
- package/bin/utils/cleanFileName.test.js.map +0 -1
- package/bin/utils/createSentryContext.js +0 -43
- package/bin/utils/createSentryContext.js.map +0 -1
- package/bin/utils/determineModuleType.js +0 -79
- package/bin/utils/determineModuleType.js.map +0 -1
- package/bin/utils/determineModuleType.test.js +0 -60
- package/bin/utils/determineModuleType.test.js.map +0 -1
- package/bin/utils/generateIOSBundles.js +0 -147
- package/bin/utils/generateIOSBundles.js.map +0 -1
- package/bin/utils/generateJsDriver.js +0 -178
- package/bin/utils/generateJsDriver.js.map +0 -1
- package/bin/utils/generateJsDriverTypeFile.js +0 -105
- package/bin/utils/generateJsDriverTypeFile.js.map +0 -1
- package/bin/utils/generateSwiftDriver.js +0 -93
- package/bin/utils/generateSwiftDriver.js.map +0 -1
- package/bin/utils/getSelectedProjects.js +0 -67
- package/bin/utils/getSelectedProjects.js.map +0 -1
- package/bin/utils/processMetaOption.js +0 -40
- package/bin/utils/processMetaOption.js.map +0 -1
- package/bin/utils/processMetaOption.test.js +0 -45
- package/bin/utils/processMetaOption.test.js.map +0 -1
- package/bin/utils/projectsToText.js +0 -58
- package/bin/utils/projectsToText.js.map +0 -1
- package/bin/utils/promptForProject.js +0 -96
- package/bin/utils/promptForProject.js.map +0 -1
- package/bin/utils/quit.js +0 -73
- package/bin/utils/quit.js.map +0 -1
- package/bin/utils/sourcesToText.js +0 -57
- package/bin/utils/sourcesToText.js.map +0 -1
- package/etsc.config.js +0 -13
- package/jest.config.ts +0 -16
- package/jsconfig.json +0 -5
- package/lib/__mocks__/api.ts +0 -12
- package/lib/add-project.ts +0 -48
- package/lib/api.ts +0 -16
- package/lib/component-folders.ts +0 -9
- package/lib/config.test.ts +0 -79
- package/lib/config.ts +0 -279
- package/lib/consts.ts +0 -22
- package/lib/ditto.ts +0 -285
- package/lib/generate-suggestions.test.ts +0 -169
- package/lib/generate-suggestions.ts +0 -166
- package/lib/http/__mocks__/fetchComponentFolders.ts +0 -23
- package/lib/http/__mocks__/fetchComponents.ts +0 -24
- package/lib/http/__mocks__/fetchVariants.ts +0 -21
- package/lib/http/fetchComponentFolders.ts +0 -23
- package/lib/http/fetchComponents.ts +0 -43
- package/lib/http/fetchVariants.ts +0 -42
- package/lib/http/http.test.ts +0 -122
- package/lib/http/importComponents.ts +0 -79
- package/lib/importComponents.ts +0 -24
- package/lib/init/init.ts +0 -79
- package/lib/init/project.test.ts +0 -26
- package/lib/init/project.ts +0 -136
- package/lib/init/token.test.ts +0 -99
- package/lib/init/token.ts +0 -156
- package/lib/output.ts +0 -21
- package/lib/pull-lib.test.ts +0 -367
- package/lib/pull.test.ts +0 -117
- package/lib/pull.ts +0 -629
- package/lib/remove-project.ts +0 -44
- package/lib/replace.test.ts +0 -157
- package/lib/replace.ts +0 -140
- package/lib/types.ts +0 -83
- package/lib/utils/cleanFileName.test.ts +0 -11
- package/lib/utils/cleanFileName.ts +0 -8
- package/lib/utils/createSentryContext.ts +0 -20
- package/lib/utils/determineModuleType.test.ts +0 -48
- package/lib/utils/determineModuleType.ts +0 -55
- package/lib/utils/generateIOSBundles.ts +0 -122
- package/lib/utils/generateJsDriver.ts +0 -207
- package/lib/utils/generateJsDriverTypeFile.ts +0 -75
- package/lib/utils/generateSwiftDriver.ts +0 -48
- package/lib/utils/getSelectedProjects.ts +0 -36
- package/lib/utils/processMetaOption.test.ts +0 -18
- package/lib/utils/processMetaOption.ts +0 -16
- package/lib/utils/projectsToText.ts +0 -29
- package/lib/utils/promptForProject.ts +0 -61
- package/lib/utils/quit.ts +0 -7
- package/lib/utils/sourcesToText.ts +0 -25
- package/pull_request_template.md +0 -20
- package/testfiles/en.json +0 -5
- package/testfiles/es.json +0 -5
- package/testfiles/fr.json +0 -5
- package/testfiles/test1.jsx +0 -18
- package/testfiles/test2.jsx +0 -9
- package/testing/.gitkeep +0 -0
- package/testing/fixtures/bad-yaml.yml +0 -6
- package/testing/fixtures/ditto-config-no-token +0 -2
- package/testing/fixtures/project-config-empty-projects.yml +0 -1
- package/testing/fixtures/project-config-no-id.yml +0 -2
- package/testing/fixtures/project-config-no-name.yml +0 -2
- package/testing/fixtures/project-config-pull.yml +0 -0
- package/testing/fixtures/project-config-working.yml +0 -3
- package/tsconfig.json +0 -16
package/README.md
CHANGED
|
@@ -17,7 +17,7 @@ The official documentation can be found [here](http://developer.dittowords.com/c
|
|
|
17
17
|
## Installation
|
|
18
18
|
|
|
19
19
|
```sh
|
|
20
|
-
npm install --save-dev @dittowords/cli
|
|
20
|
+
npm install --save-dev @dittowords/cli@beta
|
|
21
21
|
```
|
|
22
22
|
|
|
23
23
|
It's recommended to install the CLI as a development dependency to ensure your whole team is on the same version.
|
|
@@ -37,10 +37,11 @@ The first time you run the CLI, a `ditto/` folder will be created if it doesn't
|
|
|
37
37
|
The default file looks like this:
|
|
38
38
|
|
|
39
39
|
```yml
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
format:
|
|
40
|
+
projects: [],
|
|
41
|
+
variants: [],
|
|
42
|
+
outputs:
|
|
43
|
+
- format: json,
|
|
44
|
+
framework: i18next
|
|
44
45
|
```
|
|
45
46
|
|
|
46
47
|
For more information on configuring the CLI, see [http://developer.dittowords.com/cli-reference/configuration](http://developer.dittowords.com/cli-reference/configuration).
|
package/bin/ditto.js
CHANGED
|
@@ -1,290 +1,115 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
"use strict";
|
|
3
|
-
!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]="
|
|
3
|
+
!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]="4fa6a938-f8ef-56a0-9e03-daab22de6e0a")}catch(e){}}();
|
|
4
|
+
var bn=Object.create;var Zt=Object.defineProperty;var Fn=Object.getOwnPropertyDescriptor;var On=Object.getOwnPropertyNames;var Pn=Object.getPrototypeOf,kn=Object.prototype.hasOwnProperty;var Ne=t=>{throw TypeError(t)};var n=(t,e)=>Zt(t,"name",{value:e,configurable:!0});var An=(t,e,o,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of On(e))!kn.call(t,s)&&s!==o&&Zt(t,s,{get:()=>e[s],enumerable:!(r=Fn(e,s))||r.enumerable});return t};var m=(t,e,o)=>(o=t!=null?bn(Pn(t)):{},An(e||!t||!t.__esModule?Zt(o,"default",{value:t,enumerable:!0}):o,t));var _e=(t,e,o)=>e.has(t)||Ne("Cannot "+o);var E=(t,e,o)=>(_e(t,e,"read from private field"),o?o.call(t):e.get(t)),V=(t,e,o)=>e.has(t)?Ne("Cannot add the same private member more than once"):e instanceof WeakSet?e.add(t):e.set(t,o),R=(t,e,o,r)=>(_e(t,e,"write to private field"),r?r.call(t,o):e.set(t,o),o);var dn=m(require("@sentry/node"));var tt="5.0.0-beta.1";var G=require("commander");var to=m(require("boxen")),Mt=m(require("chalk"));var Ke=m(require("ora"));var Ge=m(require("axios"));var L=m(require("fs")),Le=m(require("path")),Je=m(require("url")),ot=m(require("js-yaml")),Ve=m(require("@sentry/node"));var Me=require("os"),et=m(require("path")),u=new class{get API_HOST(){return process.env.DITTO_API_HOST||"https://api.dittowords.com"}get CONFIG_FILE(){return process.env.DITTO_CONFIG_FILE||et.default.join((0,Me.homedir)(),".config","ditto")}get PROJECT_CONFIG_FILE(){return et.default.normalize(et.default.join("ditto","config.yml"))}get TEXT_DIR(){return process.env.DITTO_TEXT_DIR||"ditto"}get TEXT_FILE(){return et.default.normalize(et.default.join(this.TEXT_DIR,"text.json"))}};function Re(t){if(typeof t!="object")return{};let e={};for(let o in t){let r=o,s=t[r];e[r]=typeof s=="object"||Array.isArray(s)?JSON.stringify(s):s}return e}n(Re,"createSentryContext");var En={sources:{components:!0},variants:!0,format:"flat"},Ye=ot.default.dump(En);function gt(t,e){let o=Le.default.dirname(t);L.default.existsSync(o)||L.default.mkdirSync(o),L.default.existsSync(t)||L.default.writeFileSync(t,e||"","utf-8")}n(gt,"createFileIfMissing");function Nn(t){return typeof t=="object"}n(Nn,"jsonIsConfigYAML");function _n(t){return!!t&&typeof t=="object"&&Object.values(t).every(e=>e.every&&e.every(o=>typeof o=="object"&&Object.keys(o).includes("token")))}n(_n,"jsonIsGlobalYAML");function Kt(t=u.PROJECT_CONFIG_FILE,e={}){gt(t,Ye);let o=L.default.readFileSync(t,"utf8"),r=ot.default.load(o);return Nn(r)?r:e}n(Kt,"readProjectConfigData");function yt(t=u.CONFIG_FILE,e={}){gt(t);let o=L.default.readFileSync(t,"utf8"),r=ot.default.load(o);return _n(r)?r:e}n(yt,"readGlobalConfigData");function Mn(t,e){gt(t,Ye);let o=Kt(t),r={...o,...e,sources:{...o.sources,...e.sources}},s=ot.default.dump(r);L.default.writeFileSync(t,s,"utf8")}n(Mn,"writeProjectConfigData");function Qt(t,e){gt(t);let o=yt(t),r=ot.default.dump({...o,...e});L.default.writeFileSync(t,r,"utf8")}n(Qt,"writeGlobalConfigData");function Et(t){return t.includes("://")?Je.default.parse(t).hostname||"":t}n(Et,"justTheHost");function Rn(t,e){let o=yt(t),r=Et(e);o[r]=[],o[r][0]={token:""},Qt(t,o)}n(Rn,"deleteToken");function $n(t,e,o){let r=yt(t),s=Et(e);r[s]=[],r[s][0]={token:o},Qt(t,r)}n($n,"saveToken");function Be(){return process.env.DITTO_API_KEY}n(Be,"getTokenFromEnv");function Ln(t,e){let o=Be();if(o)return o;let s=yt(t)[Et(e)];if(!s)return;let{length:i}=s;return s[i-1].token}n(Ln,"getToken");var $e=/-(\d+$)/;function Jn(t,e){let o=e;if(t.has(o))for(;t.has(o);){let[r,s]=o.match($e)||[];s&&!isNaN(parseInt(s))?o=`${o.replace($e,"")}-${parseInt(s)+1}`:o=`${o}-1`}return o}n(Jn,"dedupeProjectName");function Vn(t){let{sources:e,variants:o,format:r,status:s,richText:i,iosLocales:c,projects:a,components:l,disableJsDriver:g}=Kt(t),f=e?.projects||[],d=new Set,S=[],h=!1;(f||[]).forEach(P=>{if(P.id&&P.name){if(P.id==="ditto_component_library"){h=!0;return}P.fileName=Jn(d,P.name),d.add(P.fileName),S.push(P)}});let C=!!e?.components,N=typeof e?.components=="object"?e.components.root:void 0,F=typeof e?.components=="object"?e.components.folders:void 0,I={hasSourceData:!!S.length||C,validProjects:S,shouldFetchComponentLibrary:C,variants:o||!1,format:r,status:s,richText:i,hasTopLevelProjectsField:!!a,hasTopLevelComponentsField:!!l,hasComponentLibraryInProjects:h,componentRoot:N,componentFolders:F,localeByVariantApiId:c?c.reduce((P,K)=>({...P,...K}),{}):void 0,disableJsDriver:g};return Ve.setContext("config",Re(I)),I}n(Vn,"parseSourceInformation");var w={createFileIfMissing:gt,readProjectConfigData:Kt,readGlobalConfigData:yt,writeGlobalConfigData:Qt,writeProjectConfigData:Mn,justTheHost:Et,saveToken:$n,deleteToken:Rn,getToken:Ln,getTokenFromEnv:Be,parseSourceInformation:Vn};function j(t){return Ge.default.create({baseURL:u.API_HOST,headers:{Authorization:`token ${t||w.getToken(u.CONFIG_FILE,u.API_HOST)}`,"x-ditto-cli":!0}})}n(j,"createApiClient");var Y=m(require("chalk"));var Yn=n(t=>Y.default.magenta(t),"errorText"),Bn=n(t=>Y.default.yellow(t),"warnText"),Gn=n(t=>Y.default.blueBright(t),"info"),Un=n(t=>Y.default.green(t),"success"),Wn=n(t=>Y.default.blueBright.underline(t),"url"),qn=n(t=>Y.default.grey(t),"subtle"),zn=n(t=>Y.default.white(t),"write"),Hn=n(()=>console.log(`
|
|
5
|
+
`),"nl"),p={errorText:Yn,warnText:Bn,info:Gn,success:Un,url:Wn,subtle:qn,write:zn,nl:Hn};var We=m(require("fs")),qe=m(require("@sentry/node")),ze=m(require("chalk")),He=require("enquirer");var Ue=m(require("@sentry/node"));async function b(t,e=2){t&&console.log(`
|
|
6
|
+
${t}
|
|
7
|
+
`),await Ue.flush(),process.exit(e)}n(b,"quit");var Xe=require("axios");var te=n((t,e=u.API_HOST)=>{if(w.getTokenFromEnv())return!1;let o=t||u.CONFIG_FILE;if(!We.default.existsSync(o))return!0;let r=w.readGlobalConfigData(o);return!r[w.justTheHost(e)]||r[w.justTheHost(e)][0].token===""},"needsToken");async function Xn(t){let e=j(t),o="/token-check",r;try{r=await e.get(o)}catch(s){if(!(s instanceof Xe.AxiosError))return{success:!1,output:[p.warnText("Sorry! We're having trouble reaching the Ditto API.")]};if(s.code==="ENOTFOUND")return{success:!1,output:[p.errorText(`Can't connect to API: ${p.url(u.API_HOST)}`)]};if(s.response?.status===401||s.response?.status===404)return{success:!1,output:[p.errorText("This API key isn't valid. Please try another.")]}}return typeof r=="string"?{success:!1,output:[r]}:r?.status===200?{success:!0}:{success:!1,output:[p.errorText("This API key isn't valid. Please try another.")]}}n(Xn,"verifyTokenUsingTokenCheck");async function Zn(t){let e=await Xn(t);return e.success?!0:e.output.join(`
|
|
8
|
+
`)}n(Zn,"checkToken");async function Kn(t){let e=p.info,o=p.url("https://app.dittowords.com/account/devtools"),r=`${ze.default.bold(e("API Keys"))}`,s=t||`To get started, you'll need your Ditto API key. You can find this at: ${o} under "${r}".`;return console.log(s),(await(0,He.prompt)({type:"input",name:"token",message:"What is your API key?",validate:n(c=>Zn(c),"validate")})).token}n(Kn,"collectToken");var nt=n(async(t=null)=>{try{let e=await Kn(t);return console.log(`Thanks for authenticating. We'll save the key to: ${p.info(u.CONFIG_FILE)}
|
|
9
|
+
`),w.saveToken(u.CONFIG_FILE,u.API_HOST,e),e}catch(e){if(e===""){await b("",0);return}let o=qe.captureException(e),r=`
|
|
4
10
|
|
|
5
|
-
var
|
|
6
|
-
|
|
7
|
-
var
|
|
8
|
-
var
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
var
|
|
12
|
-
var
|
|
13
|
-
|
|
14
|
-
var
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
));
|
|
41
|
-
var __async = (__this, __arguments, generator) => {
|
|
42
|
-
return new Promise((resolve, reject) => {
|
|
43
|
-
var fulfilled = (value) => {
|
|
44
|
-
try {
|
|
45
|
-
step(generator.next(value));
|
|
46
|
-
} catch (e) {
|
|
47
|
-
reject(e);
|
|
48
|
-
}
|
|
49
|
-
};
|
|
50
|
-
var rejected = (value) => {
|
|
51
|
-
try {
|
|
52
|
-
step(generator.throw(value));
|
|
53
|
-
} catch (e) {
|
|
54
|
-
reject(e);
|
|
55
|
-
}
|
|
56
|
-
};
|
|
57
|
-
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
|
|
58
|
-
step((generator = generator.apply(__this, __arguments)).next());
|
|
59
|
-
});
|
|
60
|
-
};
|
|
61
|
-
var import_commander = require("commander");
|
|
62
|
-
var import_v8_compile_cache = require("v8-compile-cache");
|
|
63
|
-
var import_fs = __toESM(require("fs"));
|
|
64
|
-
var import_path = __toESM(require("path"));
|
|
65
|
-
var Sentry = __toESM(require("@sentry/node"));
|
|
66
|
-
var import_package = require("../package.json");
|
|
67
|
-
var import_init = require("./init/init");
|
|
68
|
-
var import_pull = require("./pull");
|
|
69
|
-
var import_quit = require("./utils/quit");
|
|
70
|
-
var import_add_project = __toESM(require("./add-project"));
|
|
71
|
-
var import_remove_project = __toESM(require("./remove-project"));
|
|
72
|
-
var import_replace = require("./replace");
|
|
73
|
-
var import_generate_suggestions = require("./generate-suggestions");
|
|
74
|
-
var import_processMetaOption = __toESM(require("./utils/processMetaOption"));
|
|
75
|
-
var import_importComponents = require("./importComponents");
|
|
76
|
-
var import_component_folders = require("./component-folders");
|
|
77
|
-
const environment = "production";
|
|
78
|
-
Sentry.init({ dsn: "https://9c1d99fa4267f54c6b914f720b4ed3a2@o979374.ingest.sentry.io/4505705213919232", environment, release: import_package.version });
|
|
79
|
-
function getVersion() {
|
|
80
|
-
const packageJsonPath = import_path.default.join(__dirname, "..", "package.json");
|
|
81
|
-
const packageJsonContent = import_fs.default.readFileSync(packageJsonPath, "utf8");
|
|
82
|
-
const packageJson = JSON.parse(packageJsonContent);
|
|
83
|
-
return packageJson.version;
|
|
11
|
+
Error ID: ${p.info(o)}`;return await b(p.errorText("Something went wrong. Please contact support or try again later.")+r)}},"collectAndSaveToken");var Ze=m(require("js-yaml"));var z=n((t=u.PROJECT_CONFIG_FILE)=>w.parseSourceInformation(t).validProjects,"getSelectedProjects"),rt=n((t=u.PROJECT_CONFIG_FILE)=>w.parseSourceInformation(t).shouldFetchComponentLibrary,"getIsUsingComponents");var ee=n(t=>{let e="https://app.dittowords.com";return t==="ditto_component_library"?`${e}/components`:`${e}/doc/${t}`},"getSourceUrl"),Qn=n(t=>(t||[]).reduce((e,{name:o,id:r})=>e+(`
|
|
12
|
+
- `+p.info(o)+" "+p.subtle(ee(r))),"")+`
|
|
13
|
+
`,"projectsToText"),ht=Qn;var{AutoComplete:tr}=require("enquirer");function er(t){return t.name+" "+p.subtle(t.url||ee(t.id))}n(er,"formatProjectChoice");function or(t){if(!t)return null;let[,e,o]=t.split(/^(.*)\s.*http.*\/(\w+).*$/);return o==="all"?{name:e,id:"ditto_component_library"}:{name:e,id:o}}n(or,"parseResponse");var nr=n(async({message:t,projects:e,limit:o=10})=>{p.write(`
|
|
14
|
+
`);let r=e.map(er),s=new tr({name:"project",message:t,limit:o,choices:r}),i;try{i=await s.run()}catch{i=null}return or(i)},"promptForProject"),Nt=nr;function rr(t,e,o){if(o==="components"){w.writeProjectConfigData(t,{sources:{components:!0}});return}let r=[...z(t),{name:e,id:o}];w.writeProjectConfigData(t,{sources:{projects:r}})}n(rr,"saveProject");var Qe=n(()=>!w.parseSourceInformation().hasSourceData,"needsSource");async function sr(){w.deleteToken(u.CONFIG_FILE,u.API_HOST),await nt("Looks like the API key you have saved no longer works. Please enter another one.")}n(sr,"askForAnotherToken");async function ir(t,e){let o=j(),r=(0,Ke.default)("Fetching sources in your workspace...");r.start();let s;try{s=await o.get("/v1/projects")}catch(a){throw r.stop(),a}let i=e.reduce((a,l)=>a.add(l.id.toString()),new Set),c=s.data.filter(({id:a})=>a!=="ditto_component_library"&&!i.has(a.toString()));return r.stop(),c}n(ir,"listProjects");async function ar(t,e){let o=z(),r=rt(),s=await ir(t,o);return e&&!r&&(s=[{id:"ditto_component_library",name:"Ditto Component Library"},...s]),s?.length?Nt({projects:s,message:"Choose the source you'd like to sync text from"}):(console.log("You're currently syncing all projects in your workspace."),console.log(p.warnText("Not seeing a project that you were expecting? Verify that developer mode is enabled on that project. More info: https://www.dittowords.com/docs/ditto-developer-mode")),null)}n(ar,"collectSource");var xt=n(async({components:t=!1}={components:!1})=>{try{let e=w.getToken(u.CONFIG_FILE,u.API_HOST),o=await ar(e,t);if(!o){await b(null,0);return}console.log(`
|
|
15
|
+
Thanks for adding ${p.info(o.name)} to your selected sources.
|
|
16
|
+
We saved your updated configuration to: ${p.info(u.PROJECT_CONFIG_FILE)}
|
|
17
|
+
`),rr(u.PROJECT_CONFIG_FILE,o.name,o.id)}catch(e){console.log(e),e.response&&e.response.status===404?(await sr(),await xt({components:t})):await b(null,2)}},"collectAndSaveSource");var cr=n((t,e)=>{let o="";return e&&(o+=`the ${p.info("Ditto Component Library")}`,(t||[]).length?o+=" and ":o+=".."),(t||[]).length&&(o+=`the following projects: ${ht(t)}
|
|
18
|
+
`),o},"sourcesToText"),_t=cr;var eo=n(()=>te()||Qe(),"needsTokenOrSource");function pr(){let t=Mt.default.white(`${Mt.default.bold("Welcome to the",Mt.default.magentaBright("Ditto CLI"))}.
|
|
19
|
+
|
|
20
|
+
We're glad to have you here.`);console.log((0,to.default)(t,{padding:1}))}n(pr,"welcome");var oo=n(async()=>{pr(),te()&&await nt();let{hasSourceData:t,validProjects:e,shouldFetchComponentLibrary:o,hasTopLevelComponentsField:r,hasTopLevelProjectsField:s}=w.parseSourceInformation();if(s)return await b(`${p.errorText(`Support for ${p.warnText("projects")} as a top-level field has been removed; please configure ${p.warnText("sources.projects")} instead.`)}
|
|
21
|
+
See ${p.url("https://github.com/dittowords/cli")} for more information.`);if(r)return await b(`${p.errorText("Support for `components` as a top-level field has been removed; please configure `sources.components` instead.")}
|
|
22
|
+
See ${p.url("https://github.com/dittowords/cli")} for more information.`);if(!t){console.log(`Looks like there are no Ditto sources selected for your current directory: ${p.info(process.cwd())}.`),await xt({initialize:!0,components:!0});return}let i="You're currently set up to sync text from "+_t(e,o);console.log(i)},"init");var H=m(require("fs")),st=m(require("path")),fo=m(require("ora")),go=m(require("@sentry/node"));var oe=m(require("fs")),ne=m(require("path"));function B(t){let e=t.split(/\s{1,}/g);return e=e.map(o=>o.replace(/[^a-zA-Z0-9-_.]/g,"").toLowerCase()),e=e.filter(o=>o!==""),e.join("-")}n(B,"cleanFileName");var Rt=m(require("fs")),$t=m(require("path"));function no(t=process.cwd()){let e=lr(t);return mr(e)}n(no,"determineModuleType");function lr(t){if(process.env.DITTO_MODULE_TYPE)return process.env.DITTO_MODULE_TYPE;for(;t;){let e=$t.join(t,"package.json");if(Rt.existsSync(e)){let o=Rt.readFileSync(e,"utf8");try{let r=JSON.parse(o);if(r?.type)return r.type}catch{}return null}if(t==="/")break;t=$t.dirname(t)}return null}n(lr,"getRawTypeFromPackageJson");function mr(t){let e=t?.toLowerCase()||"";return e==="commonjs"||e==="module"?e:"commonjs"}n(mr,"getTypeOrDefault");var ro=m(require("fs")),so=m(require("path"));function ur(t){switch(t){case"flat":return"IJSONFlat";case"nested":return"IJSONNested";case"structured":return"IJSONStructured";case"icu":return"IJSONICU";default:return"_JSON"}}n(ur,"getFormatString");function fr(t,e){return e==="commonjs"?`export = ${t};`:`export default ${t};`}n(fr,"getExportString");function dr(t){return`
|
|
23
|
+
interface IJSONFlat {
|
|
24
|
+
[key: string]: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
interface IJSONStructured {
|
|
28
|
+
[key: string]: {
|
|
29
|
+
text: string;
|
|
30
|
+
status?: string;
|
|
31
|
+
notes?: string;
|
|
32
|
+
[property: string]: any;
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
interface IJSONNested {
|
|
37
|
+
[key: string]: string | IJSONNested;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
type _JSON = IJSONFlat | IJSONStructured | IJSONNested;
|
|
41
|
+
|
|
42
|
+
interface IDriverFile {
|
|
43
|
+
[sourceKey: string]: {
|
|
44
|
+
[variantKey: string]: ${ur(t.format)};
|
|
45
|
+
};
|
|
84
46
|
}
|
|
85
|
-
const VERSION = getVersion();
|
|
86
|
-
const CONFIG_FILE_RELIANT_COMMANDS = [
|
|
87
|
-
"pull",
|
|
88
|
-
"none",
|
|
89
|
-
"project",
|
|
90
|
-
"project add",
|
|
91
|
-
"project remove"
|
|
92
|
-
];
|
|
93
|
-
const COMMANDS = [
|
|
94
|
-
{
|
|
95
|
-
name: "pull",
|
|
96
|
-
description: "Sync copy from Ditto into the current working directory",
|
|
97
|
-
flags: {
|
|
98
|
-
"--sample-data": {
|
|
99
|
-
description: "Include sample data. Currently only supports variants."
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
},
|
|
103
|
-
{
|
|
104
|
-
name: "project",
|
|
105
|
-
description: "Add a Ditto project to sync copy from",
|
|
106
|
-
commands: [
|
|
107
|
-
{
|
|
108
|
-
name: "add",
|
|
109
|
-
description: "Add a Ditto project to sync copy from"
|
|
110
|
-
},
|
|
111
|
-
{
|
|
112
|
-
name: "remove",
|
|
113
|
-
description: "Stop syncing copy from a Ditto project"
|
|
114
|
-
}
|
|
115
|
-
]
|
|
116
|
-
},
|
|
117
|
-
{
|
|
118
|
-
name: "component-folders",
|
|
119
|
-
description: "List component folders in your workspace. More information about component folders can be found here: https://www.dittowords.com/docs/component-folders.",
|
|
120
|
-
flags: {
|
|
121
|
-
"-s, --sample-data": {
|
|
122
|
-
description: "Includes the sample components folder in the output"
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
},
|
|
126
|
-
{
|
|
127
|
-
name: "generate-suggestions",
|
|
128
|
-
description: "Find text that can be potentially replaced with Ditto text",
|
|
129
|
-
flags: {
|
|
130
|
-
"-d, --directory [value]": {
|
|
131
|
-
description: "Directory to search for text"
|
|
132
|
-
},
|
|
133
|
-
"-f, --files [value]": {
|
|
134
|
-
description: "Files to search for text (will override -d)",
|
|
135
|
-
processor: (value) => value.split(",")
|
|
136
|
-
},
|
|
137
|
-
"-cf, --component-folder [value]": {
|
|
138
|
-
description: "Component folder to search for matches"
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
},
|
|
142
|
-
{
|
|
143
|
-
name: "replace",
|
|
144
|
-
description: "Find and replace Ditto text with code",
|
|
145
|
-
flags: {
|
|
146
|
-
"-ln, --line-numbers [value]": {
|
|
147
|
-
description: "Only replace text on a specific line number",
|
|
148
|
-
processor: (value) => value.split(",").map(Number)
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
},
|
|
152
|
-
{
|
|
153
|
-
name: "import-components",
|
|
154
|
-
description: "Import components via a file. For more information please see: https://www.dittowords.com/docs/importing-string-files.",
|
|
155
|
-
flags: {
|
|
156
|
-
"-t, --text [value]": {
|
|
157
|
-
description: "Text column index (.csv format only)"
|
|
158
|
-
},
|
|
159
|
-
"-n, --component-name [value]": {
|
|
160
|
-
description: "Name column indexes (comma separated) (.csv format only)"
|
|
161
|
-
},
|
|
162
|
-
"-no, --notes [value]": {
|
|
163
|
-
description: "Notes column index (.csv format only)"
|
|
164
|
-
},
|
|
165
|
-
"-t, --tags [value]": {
|
|
166
|
-
description: "Tags column index (.csv format only)"
|
|
167
|
-
},
|
|
168
|
-
"-s, --status [value]": {
|
|
169
|
-
description: "Status column index (.csv format only)"
|
|
170
|
-
},
|
|
171
|
-
"-c, --component-id [value]": {
|
|
172
|
-
description: "Component ID column index (.csv format only)"
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
];
|
|
177
|
-
const setupCommands = () => {
|
|
178
|
-
import_commander.program.name("ditto-cli");
|
|
179
|
-
COMMANDS.forEach((commandConfig) => {
|
|
180
|
-
const cmd = import_commander.program.command(commandConfig.name).description(commandConfig.description).action((options) => {
|
|
181
|
-
return executeCommand(commandConfig.name, options);
|
|
182
|
-
});
|
|
183
|
-
if (commandConfig.flags) {
|
|
184
|
-
Object.entries(commandConfig.flags).forEach(
|
|
185
|
-
([flags, { description, processor }]) => {
|
|
186
|
-
if (processor) {
|
|
187
|
-
cmd.option(flags, description, processor);
|
|
188
|
-
} else {
|
|
189
|
-
cmd.option(flags, description);
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
);
|
|
193
|
-
}
|
|
194
|
-
if ("commands" in commandConfig && commandConfig.commands) {
|
|
195
|
-
commandConfig.commands.forEach((nestedCommand) => {
|
|
196
|
-
cmd.command(nestedCommand.name).description(nestedCommand.description).action((str, options) => {
|
|
197
|
-
if (commandConfig.name === "project") {
|
|
198
|
-
const command = `${commandConfig.name} ${nestedCommand.name}`;
|
|
199
|
-
return executeCommand(command, options);
|
|
200
|
-
}
|
|
201
|
-
});
|
|
202
|
-
});
|
|
203
|
-
}
|
|
204
|
-
});
|
|
205
|
-
};
|
|
206
|
-
const setupOptions = () => {
|
|
207
|
-
import_commander.program.option(
|
|
208
|
-
"-m, --meta <data...>",
|
|
209
|
-
"Include arbitrary data in requests to the Ditto API. Ex: -m githubActionRequest:true trigger:manual"
|
|
210
|
-
);
|
|
211
|
-
import_commander.program.version(VERSION, "-v, --version", "Output the current version");
|
|
212
|
-
};
|
|
213
|
-
const executeCommand = (command, options) => __async(exports, null, function* () {
|
|
214
|
-
const needsInitialization = CONFIG_FILE_RELIANT_COMMANDS.includes(command) && (0, import_init.needsTokenOrSource)();
|
|
215
|
-
if (needsInitialization) {
|
|
216
|
-
try {
|
|
217
|
-
yield (0, import_init.init)();
|
|
218
|
-
} catch (error) {
|
|
219
|
-
yield (0, import_quit.quit)("Exiting Ditto CLI...");
|
|
220
|
-
return;
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
const { meta } = import_commander.program.opts();
|
|
224
|
-
switch (command) {
|
|
225
|
-
case "none":
|
|
226
|
-
case "pull": {
|
|
227
|
-
return (0, import_pull.pull)({
|
|
228
|
-
meta: (0, import_processMetaOption.default)(meta),
|
|
229
|
-
includeSampleData: options.sampleData || false
|
|
230
|
-
});
|
|
231
|
-
}
|
|
232
|
-
case "project":
|
|
233
|
-
case "project add": {
|
|
234
|
-
if (needsInitialization)
|
|
235
|
-
return;
|
|
236
|
-
return (0, import_add_project.default)();
|
|
237
|
-
}
|
|
238
|
-
case "project remove": {
|
|
239
|
-
return (0, import_remove_project.default)();
|
|
240
|
-
}
|
|
241
|
-
case "component-folders": {
|
|
242
|
-
return (0, import_component_folders.showComponentFolders)({
|
|
243
|
-
showSampleData: options.sampleData
|
|
244
|
-
});
|
|
245
|
-
}
|
|
246
|
-
case "generate-suggestions": {
|
|
247
|
-
return (0, import_generate_suggestions.generateSuggestions)({
|
|
248
|
-
directory: options.directory,
|
|
249
|
-
files: options.files,
|
|
250
|
-
componentFolder: options.componentFolder
|
|
251
|
-
});
|
|
252
|
-
}
|
|
253
|
-
case "replace": {
|
|
254
|
-
return (0, import_replace.replace)(options.args, __spreadValues({}, (options == null ? void 0 : options.lineNumbers) ? { lineNumbers: options.lineNumbers } : {}));
|
|
255
|
-
}
|
|
256
|
-
case "import-components": {
|
|
257
|
-
if (options.args.length === 0) {
|
|
258
|
-
console.info("Please provide a file path.");
|
|
259
|
-
return;
|
|
260
|
-
}
|
|
261
|
-
return (0, import_importComponents.importComponents)(options.args[0], {
|
|
262
|
-
csvColumnMapping: {
|
|
263
|
-
name: options.componentName,
|
|
264
|
-
text: options.text,
|
|
265
|
-
notes: options.notes,
|
|
266
|
-
tags: options.tags,
|
|
267
|
-
status: options.status,
|
|
268
|
-
componentId: options.componentId
|
|
269
|
-
}
|
|
270
|
-
});
|
|
271
|
-
}
|
|
272
|
-
default: {
|
|
273
|
-
yield (0, import_quit.quit)("Exiting Ditto CLI...");
|
|
274
|
-
return;
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
});
|
|
278
|
-
const main = () => __async(exports, null, function* () {
|
|
279
|
-
setupCommands();
|
|
280
|
-
setupOptions();
|
|
281
|
-
if (process.argv.length <= 2 && process.argv[1].includes("ditto-cli")) {
|
|
282
|
-
yield executeCommand("none", []);
|
|
283
|
-
return;
|
|
284
|
-
}
|
|
285
|
-
import_commander.program.parse(process.argv);
|
|
286
|
-
});
|
|
287
|
-
main();
|
|
288
|
-
//# sourceMappingURL=ditto.js.map
|
|
289
47
|
|
|
290
|
-
|
|
48
|
+
declare const driver: IDriverFile;
|
|
49
|
+
|
|
50
|
+
${fr("driver",t.moduleType)}
|
|
51
|
+
`.trim()}n(dr,"getTypesString");function io(t){let e=dr(t);ro.default.writeFileSync(so.default.resolve(u.TEXT_DIR,"index.d.ts"),e+`
|
|
52
|
+
`,"utf8")}n(io,"generateJsDriverTypeFile");var gr=n(t=>t==="ditto_component_library"?t:`project_${t}`,"stringifySourceId");function ao(t,e){let o=no(),r=yr(t),s=hr(),i=[],c={},a={};r.forEach(f=>{var S;let d;if(f.type==="components")d=s.generate(f.fileName.split(".")[0]);else{let h=f.fileName.split(".")[0];d=s.generate(h.split("__")[0])}if(i.push(Tr(f.fileName,d,o)),f.type==="project"){let{variantApiId:h}=f,C=gr(f.projectId);c[C]??(c[C]={}),c[C][h]=`{...${d}}`}else a[S=f.variantApiId]??(a[S]=[]),a[f.variantApiId].push(`...${d}`)}),Object.keys(a).forEach(f=>{c.ditto_component_library??(c.ditto_component_library={});let d="{";a[f].forEach((S,h)=>{d+=S,h<a[f].length-1&&(d+=", ")}),d+="}",c.ditto_component_library[f]=d});let l="";l+=i.join(`
|
|
53
|
+
`)+`
|
|
54
|
+
|
|
55
|
+
`,l+=`${xr(o)}`,l+=`${JSON.stringify(c,null,2)}`.replace(/"\{/g,"{").replace(/\}"/g,"}");let g=ne.default.resolve(u.TEXT_DIR,"index.js");return oe.default.writeFileSync(g,l,{encoding:"utf8"}),io({format:e,moduleType:o}),`Generated .js SDK driver at ${p.info(g)}`}n(ao,"generateJsDriver");function yr(t){let e=new Map;return t.forEach(r=>{!r.fileName||r.type==="components"||e.set(B(r.fileName),r.id)}),oe.default.readdirSync(u.TEXT_DIR).filter(r=>ne.default.extname(r)===".json").map(r=>{let s=r.split("__");if(s.length===3){let[,i,c]=s,[a]=c.split(".");return{type:"components",variantApiId:a,folderApiId:i,fileName:r}}if(s.length===2){let[i,c]=s,[a]=c.split("."),l=B(r.split("__")[0]);return{type:"project",projectId:e.get(l)||"",projectName:i,variantApiId:a,fileName:r}}throw new Error("Invalid JSON file generated: "+r)})}n(yr,"getFullyQualifiedJSONSources");function hr(){let t=new Set;return{generate:n(e=>{let o=e.replace(/(\W|-)/g,"_"),r=o,s=1;for(;t.has(r);)r=`${o}${s}`,s++;return t.add(r),r},"generate")}}n(hr,"createVariableNameGenerator");function xr(t){if(t==="commonjs")return"module.exports = ";if(t==="module")return"export default ";throw new Error("Unknown module type: "+t)}n(xr,"getExportPrefix");function Tr(t,e,o){if(o==="commonjs")return`const ${e} = require('./${t}');`;if(o==="module")return`import ${e} from './${t}';`;throw new Error("Unknown module type: "+o)}n(Tr,"getImportStatement");async function co(t,e={}){let o=j();if(!t.variants)return null;let{shouldFetchComponentLibrary:r,validProjects:s}=t,i={params:{...e?.meta,showSampleData:e.includeSampleData}};s.length&&!r&&(i.params.projectIds=s.map(({id:a})=>a));let{data:c}=await o.get("/v1/variants",i);return c}n(co,"fetchVariants");var yo=require("axios");async function Lt(t={}){let e=j(),o="/v1/component-folders";t.showSampleData===!0&&(o+="?showSampleData=true");let{data:r}=await e.get(o,{});return r}n(Lt,"fetchComponentFolders");var po=m(require("path"));async function lo(t){let e=j(),o={variants:t.variants,localeByVariantId:t.localeByVariantApiId};t.componentFolders||t.componentRoot?(o.components={},t.componentFolders&&(o.components.folders=t.componentFolders),t.componentRoot&&(o.components.root=t.componentRoot)):t.shouldFetchComponentLibrary&&(o.components=!0),t.validProjects&&(o.projects=t.validProjects);let{data:r}=await e.post("/v1/ios/swift-driver",o),s=po.default.join(u.TEXT_DIR,"Ditto.swift");return await Tt(s,r),`Successfully saved Swift driver to ${p.info("Ditto.swift")}`}n(lo,"generateSwiftDriver");var Jt=m(require("path")),O=m(require("fs"));var Sr=/\.(strings|stringsdict)$/;async function mo(t){let e=O.default.readdirSync(u.TEXT_DIR),o={};for(let r of e){if(!Sr.test(r))continue;let[s,i]=r.split(".");if(!s.length)continue;let c=s.split("__"),a=c[0],l=c[c.length-1];if(!(a&&l))continue;let g=t&&t[l]?t[l]:l,f=`${g}.lproj`,d=Jt.default.join(u.TEXT_DIR,f);O.default.existsSync(d)||O.default.mkdirSync(d);let S=Jt.default.join(u.TEXT_DIR,r),h=Jt.default.join(d,`${a}.${i}`);wr(a,i,S,h),o[f]={mappedVariant:l===g?void 0:l}}return Object.keys(o).map(r=>{let s=`Successfully generated iOS bundle ${p.info(r)}`,i=o[r].mappedVariant;return i&&(s+=` ${p.subtle(`(mapped to variant '${i}')`)}`),s}).join(`
|
|
56
|
+
`)+`
|
|
57
|
+
`}n(mo,"generateIOSBundles");function wr(t,e,o,r){if(!O.default.existsSync(r))return O.default.renameSync(o,r);if(t!=="components")throw new Error("Bundle path for "+t+" already exists");if(e==="strings")return Ir(o,r);if(e==="stringsdict")return Cr(o,r);throw new Error("Unsupported extension "+e)}n(wr,"handleBundleGeneration");function Ir(t,e){let o=O.default.readFileSync(t,"utf-8"),s=O.default.readFileSync(e,"utf-8")+`
|
|
58
|
+
`+o;O.default.writeFileSync(e,s),O.default.unlinkSync(t)}n(Ir,"appendStringsFile");function Cr(t,e){let r=O.default.readFileSync(t,"utf-8").split(`
|
|
59
|
+
`).slice(3,-4),c=`<?xml version="1.0" encoding="utf-8"?>
|
|
60
|
+
<plist version="1.0">
|
|
61
|
+
<dict>
|
|
62
|
+
${[O.default.readFileSync(e,"utf-8").split(`
|
|
63
|
+
`).slice(3,-4),r].join(`
|
|
64
|
+
`)}
|
|
65
|
+
</dict>
|
|
66
|
+
</plist>
|
|
67
|
+
`;O.default.writeFileSync(e,c),O.default.unlinkSync(t)}n(Cr,"appendStringsDictFile");var vr=n(t=>t+(/[\r\n]$/.test(t)?"":`
|
|
68
|
+
`),"ensureEndsWithNewLine"),Tt=n((t,e)=>new Promise(o=>H.default.writeFile(t,vr(e),o)),"writeFile"),jr=["flat","nested","structured","android","ios-strings","ios-stringsdict","icu"],br=["ios-strings","ios-stringsdict"],ho=["flat","nested","structured","icu"],Fr=n(t=>{let e=t.filter(o=>ho.includes(o));return e[e.length-1]||"flat"},"getJsonFormat"),Or={flat:".json",nested:".json",structured:".json",android:".xml","ios-strings":".strings","ios-stringsdict":".stringsdict",icu:".json"},Vt=n(t=>{try{return Object.keys(JSON.parse(t)).some(e=>!e.startsWith("__variant"))}catch{return!1}},"getJsonFormatIsValid"),re={flat:Vt,nested:Vt,structured:Vt,icu:Vt,android:n(t=>t.includes("<string"),"android"),"ios-strings":n(t=>t.includes('" = "'),"ios-strings"),"ios-stringsdict":n(t=>t.includes("<key>"),"ios-stringsdict")},Pr=n(t=>{let e=(Array.isArray(t)?t:[t]).filter(o=>jr.includes(o));return e.length?e:["flat"]},"getFormat"),se=n(t=>Or[t],"getFormatExtension"),kr=["projects","exported_at"],Ar=n(t=>{let e=Object.keys(t).filter(r=>!kr.includes(r)).length>0,o=t.projects&&Object.keys(t.projects).length>0;return e||o},"hasVariantData");async function Dr(){w.deleteToken(u.CONFIG_FILE,u.API_HOST),await nt("Looks like the API key you have saved no longer works. Please enter another one.")}n(Dr,"askForAnotherToken");async function uo(t,e){let{projects:o,format:r,status:s,richText:i,token:c}=e,a=j(),l={variant:t};return r&&(l.format=r),i&&(l.includeRichText=i.toString()),s&&(l.status=s),(await Promise.all(o.map(async f=>{let d={...l};f.status&&(d.status=f.status),f.exclude_components&&(d.exclude_components=String(f.exclude_components));let{data:S}=await a.get(`/v1/projects/${f.id}`,{params:d,headers:{Authorization:`token ${c}`}});if(!Ar(S))return"";let h=se(r),C=B(f.fileName+("__"+(t||"base"))+h),N=st.default.join(u.TEXT_DIR,C),F=S;h===".json"&&(F=JSON.stringify(S,null,2));let _=re[r];return _(F)?(await Tt(N,F),ie(C)):""}))).join("")}n(uo,"downloadAndSaveVariant");async function Er(t){return(await Promise.all([uo(null,t),...t.variants.map(({apiID:o})=>uo(o,t))])).join("")}n(Er,"downloadAndSaveVariants");async function Nr(t){let{projects:e,format:o,status:r,richText:s,token:i,options:c}=t,a=j(),l={...c?.meta};return o&&(l.format=o),s&&(l.includeRichText=s.toString()),r&&(l.status=r),(await Promise.all(e.map(async f=>{let d={...l};f.status&&(d.status=f.status),f.exclude_components&&(d.exclude_components=String(f.exclude_components));let{data:S}=await a.get(`/v1/projects/${f.id}`,{params:d,headers:{Authorization:`token ${i}`}}),h=se(o),C=B(`${f.fileName}__base${h}`),N=st.default.join(u.TEXT_DIR,C),F=S;h===".json"&&(F=JSON.stringify(S,null,2));let _=re[o];return _(F)?(await Tt(N,F),ie(C)):""}))).join("")}n(Nr,"downloadAndSaveBase");function ie(t){return`Successfully saved to ${p.info(t)}
|
|
69
|
+
`}n(ie,"getSavedMessage");function _r(){return H.default.existsSync(u.TEXT_DIR)||H.default.mkdirSync(u.TEXT_DIR),H.default.readdirSync(u.TEXT_DIR,{withFileTypes:!0}).forEach(e=>{if(e.isDirectory()&&/\.lproj$/.test(e.name))return H.default.rmSync(st.default.resolve(u.TEXT_DIR,e.name),{recursive:!0,force:!0});if(e.isFile()&&/\.js(on)?|\.ts|\.xml|\.strings(dict)?$|\.swift$/.test(e.name))return H.default.unlinkSync(st.default.resolve(u.TEXT_DIR,e.name))}),`Cleaning old output files..
|
|
70
|
+
`}n(_r,"cleanOutputFiles");async function Mr(t,e,o){let r=j(),{validProjects:s,format:i,shouldFetchComponentLibrary:c,status:a,richText:l,componentFolders:g,componentRoot:f,localeByVariantApiId:d,disableJsDriver:S}=t,h=Pr(i),C=h.some(v=>ho.includes(v)),F=h.some(v=>br.includes(v))&&d,_=!F,I="",P=(0,fo.default)(I);P.start();let[K,gn]=await Promise.all([co(t,o),Lt({})]),Pe=Object.entries(gn).reduce((v,[D,$])=>v.concat([{id:D,name:$}]),[]);try{I+=_r(),I+=`
|
|
71
|
+
Fetching the latest text from ${_t(s,c)}
|
|
72
|
+
`;let v=o?o.meta:{},D={id:"__root__",name:"Root",status:typeof t.componentRoot=="object"?t.componentRoot.status:void 0},$=[];if(g)switch(f){case void 0:case!1:$.push(...g);break;default:$.push(...g),$.push(D);break}else switch(f){case void 0:$.push(...Pe),$.push(D);break;case!1:$.push(...Pe);break;default:$.push(D);break}let ke=[];async function yn(M){let ft=[{apiID:void 0},...K||[]],dt=new URLSearchParams;o?.meta&&Object.entries(o.meta).forEach(([Q,q])=>dt.append(Q,q)),M&&dt.append("format",M),l&&dt.append("includeRichText",l.toString()),a&&dt.append("status",a);let Ae=[];ft.forEach(({apiID:Q})=>{Ae.push(...$.map(async q=>{let zt=new URLSearchParams(dt);Q&&zt.append("variant",Q),q.status&&zt.append("status",q.status);let Sn=q.id==="__root__"?"/v1/components?root_only=true":`/v1/component-folders/${q.id}/components`,{data:De}=await r.get(Sn,{params:zt}),Ee=se(M),wn="components",In=`__${B(q.name)}`,Cn=`__${Q||"base"}`,Ht=B(`${wn}${In}${Cn}${Ee}`),vn=st.default.join(u.TEXT_DIR,Ht),Xt=De;Ee===".json"&&(Xt=JSON.stringify(De,null,2));let jn=re[M];return jn(Xt)?(await Tt(vn,Xt),ke.push({type:"components",id:"ditto_component_library",name:"ditto_component_library",fileName:Ht,variant:Q||"base"}),ie(Ht)):""}))});let Tn=await Promise.all(Ae);_&&(I+=Tn.join(""))}if(n(yn,"fetchComponentLibrary"),c)for(let M of h)await yn(M);async function hn(M){let ft="";K?ft=await Er({variants:K,projects:s,format:M,status:a,richText:l,token:e}):ft=await Nr({projects:s,format:M,status:a,richText:l,token:e,options:{meta:v}}),_&&(I+=ft)}if(n(hn,"fetchProjects"),s.length)for(let M of h)await hn(M);let xn=[...s,...ke];return C&&!S&&(I+=ao(xn,Fr(h))),F&&(I+=`iOS locale information detected, generating bundles..
|
|
73
|
+
|
|
74
|
+
`,I+=await mo(d),I+=await lo(t)),I+=`
|
|
75
|
+
|
|
76
|
+
${p.success("Done")}!`,P.stop(),console.log(I)}catch(v){console.error(v),P.stop();let D=v.message;if(v.response&&v.response.status===404){await Dr(),ae();return}return v.response&&v.response.status===401?(D="You don't have access to the selected projects",I=`${p.errorText(D)}.
|
|
77
|
+
Choose others using the ${p.info("project")} command, or update your API key.`,console.log(I)):v.response&&v.response.status===403?(D="One or more of the requested projects don't have Developer Mode enabled",I=`${p.errorText(D)}.
|
|
78
|
+
Please choose different projects using the ${p.info("project")} command, or turn on Developer Mode for all selected projects. Learn more here: ${p.subtle("https://www.dittowords.com/docs/ditto-developer-mode")}.`,console.log(I)):(v.response&&v.response.status===400&&(D="projects not found"),I=`We hit an error fetching text from the projects: ${p.errorText(D)}.
|
|
79
|
+
Choose others using the ${p.info("project")} command.`,console.log(I))}}n(Mr,"downloadAndSave");var ae=n(async t=>{let e=t?t.meta:{},o=t?.includeSampleData||!1,r=w.getToken(u.CONFIG_FILE,u.API_HOST),s=w.parseSourceInformation();try{return await Mr(s,r,{meta:e,includeSampleData:o})}catch(i){let c=go.captureException(i),a=`
|
|
80
|
+
|
|
81
|
+
Error ID: ${p.info(c)}`;return i instanceof yo.AxiosError?await b(p.errorText("Something went wrong connecting to Ditto servers. Please contact support or try again later.")+a):await b(p.errorText("Something went wrong. Please contact support or try again later.")+a)}},"pull");var Rr=n(async()=>{let t=z(),e=rt();try{e?t.length?console.log(`
|
|
82
|
+
You're currently syncing text from the ${p.info("Component Library")} and from the following projects: ${ht(t)}`):console.log(`
|
|
83
|
+
You're currently only syncing text from the ${p.info("Component Library")}`):t.length&&console.log(`
|
|
84
|
+
You're currently set up to sync text from the following projects: ${ht(t)}`),await xt({components:!1})}catch(o){console.log(`
|
|
85
|
+
Sorry, there was an error adding a project to your workspace: `,o),await b("Project selection was not updated.")}},"addProject"),xo=Rr;async function $r(){let t=z(),e=rt();if(!t.length&&!e){console.log(`
|
|
86
|
+
No projects found in your current configuration.
|
|
87
|
+
Try adding one with: ${p.info("ditto-cli project add")}
|
|
88
|
+
`);return}let o=await Nt({projects:t,message:"Select a project to remove"});o&&(w.writeProjectConfigData(u.PROJECT_CONFIG_FILE,{components:e&&o.id!=="components",projects:t.filter(({id:r})=>r!==o.id)}),console.log(`
|
|
89
|
+
${p.info(o.name)} has been removed from your selected projects.
|
|
90
|
+
We saved your updated configuration to: ${p.info(u.PROJECT_CONFIG_FILE)}
|
|
91
|
+
`))}n($r,"removeProject");var To=$r;var St=m(require("fs")),So=require("@babel/parser"),wo=m(require("@babel/traverse")),k=m(require("@babel/types")),Io=require("@babel/core");async function Lr(t,e,o){let r=await new Promise((c,a)=>St.default.readFile(t,"utf-8",(l,g)=>{l?a(l):c(g)})),s=(0,So.parse)(r,{sourceType:"module",plugins:["jsx","typescript"]});(0,wo.default)(s,{JSXText(c){let{searchString:a,replaceWith:l}=e,g=a.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");if(new RegExp(g,"gi").test(c.node.value)){if(o.lineNumbers&&c.node.loc&&!o.lineNumbers.includes(c.node.loc.start.line))return;let d=Jr(c.node.value,g),S=[];d.forEach(h=>{if(h.toLowerCase()===a.toLowerCase()){let C=k.jsxIdentifier("DittoComponent"),N=k.jsxAttribute(k.jsxIdentifier("componentId"),k.stringLiteral(l)),F=k.jsxOpeningElement(C,[N],!0),_=k.jsxElement(F,void 0,[],!0);S.push(_)}else S.push(k.jsxText(h))}),c.replaceWithMultiple(S)}}});let{code:i}=(0,Io.transformFromAst)(s,r,{configFile:!1});await new Promise((c,a)=>St.default.writeFile(t,i,l=>{l?a(l):c(null)}))}n(Lr,"replaceJSXTextInFile");function Jr(t,e){return t.split(new RegExp(`(${e})`,"gi")).filter(o=>o!=="")}n(Jr,"splitByCaseInsensitive");function Co(t,e){let o,r,s;try{let i=Vr(t);o=i.filePath,r=i.searchString,s=i.replaceWith}catch(i){console.error(i),console.error("Usage for replace: ditto-cli replace <file path> <search string> <replace with>");return}Lr(o,{searchString:r,replaceWith:s},e)}n(Co,"replace");function Vr(t){if(t.length!==3)throw new Error("The options array must contain <file path> <search string> <replace with>.");let e=t[0];if(!(St.default.existsSync(e)&&St.default.lstatSync(e).isFile()))throw new Error(`${e} is not a valid file path.`);return{filePath:e,searchString:t[1],replaceWith:t[2]}}n(Vr,"parseOptions");var jo=m(require("fs")),bo=m(require("glob")),Fo=require("@babel/parser"),Oo=m(require("@babel/traverse"));async function vo(t={}){let e=j();if(t.componentFolder)try{let{data:o}=await e.get(`/v1/component-folders/${t.componentFolder}/components`,{});return o}catch{return console.log(`Failed to get components for ${t.componentFolder}. Please verify the folder's API ID.`),{}}else{let{data:o}=await e.get("/v1/components?format=structured",{});return o}}n(vo,"fetchComponents");async function Po(t){let e=await vo({...t.componentFolder?{componentFolder:t.componentFolder}:{}}),o=t.directory||".",r=await Yr({directory:o,files:t.files,components:e});console.log(JSON.stringify(r,null,2))}n(Po,"generateSuggestions");async function Yr(t){let e={},o=t.files||bo.default.sync(`${t.directory}/**/*.+(jsx|tsx)`,{ignore:"**/node_modules/**"}),r=[];async function s(i){let c=await new Promise((l,g)=>jo.default.readFile(i,"utf-8",(f,d)=>{f?g(f):l(d)})),a=(0,Fo.parse)(c,{sourceType:"module",plugins:["jsx","typescript"]});(0,Oo.default)(a,{JSXText(l){for(let[g,f]of Object.entries(t.components)){if(e[g]||(e[g]={apiId:g,...f,occurrences:{}}),!/^\s*$/.test(l.node.value)&&!/^\s*$/.test(f.text)&&l.node.value.includes(f.text)){let d=f.text.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),S=new RegExp(d,"g"),h;for(;(h=S.exec(l.node.value))!==null;){let C=l.node.value.slice(0,h.index).split(`
|
|
92
|
+
`);if(!l.node.loc)continue;let N=l.node.loc.start.line+C.length-1,_=c.split(`
|
|
93
|
+
`)[N-1],I=Br(_,h.index,f.text,`${f.text}`);e[g].occurrences[i]||(e[g].occurrences[i]=[]),e[g].occurrences[i].push({lineNumber:N,preview:I})}}Object.keys(e[g].occurrences).length===0&&delete e[g]}}})}n(s,"handleFile");for(let i of o)r.push(s(i));return await Promise.all(r),e}n(Yr,"findComponentsInJSXFiles");function Br(t,e,o,r){return t.substring(0,e)+t.substring(e,t.length).replace(o,r)}n(Br,"replaceAt");var Gr=n(t=>{let e={};return Array.isArray(t)&&t.forEach(o=>{let[r,s]=o.split(":");e[r]=s}),e},"processMetaOption"),ko=Gr;var Ao=m(require("form-data")),ce=m(require("fs"));async function Do(t,e){let o=j();if(!ce.default.existsSync(t))return console.error("Failed to import file: couldn't find file at path "+t),{componentsInserted:0,firstImportedId:"null"};let r=new Ao.default;r.append("import",ce.default.createReadStream(t));let s={method:"POST",url:"/v1/components/file",params:{...e.csvColumnMapping?.name?{name:`[${e.csvColumnMapping.name}]`}:{},...e.csvColumnMapping?.text?{text:e.csvColumnMapping.text}:{},...e.csvColumnMapping?.notes?{notes:e.csvColumnMapping.notes}:{},...e.csvColumnMapping?.status?{status:e.csvColumnMapping.status}:{},...e.csvColumnMapping?.tags?{tags:e.csvColumnMapping.tags}:{},...e.csvColumnMapping?.componentId?{componentId:e.csvColumnMapping.componentId}:{}},headers:{"content-type":"multipart/form-data"},data:r};try{let{data:i}=await o(s);return i}catch(i){return console.error("Failed to import file."),console.error(i.response?.data?.message||i.message),{componentsInserted:0,firstImportedId:"null"}}}n(Do,"importComponents");async function Eo(t,e){if(t.endsWith(".csv")&&(!e.csvColumnMapping?.name||!e.csvColumnMapping?.text))throw new Error(".csv files require the --component-name and --text flags.");let o=await Do(t,e);console.log(JSON.stringify(o))}n(Eo,"importComponents");async function No(t){let e=await Lt(t);console.log(JSON.stringify(e))}n(No,"showComponentFolders");var Ur=["pull","none","project","project add","project remove"],Wr=[{name:"pull",description:"Sync copy from Ditto into the current working directory",flags:{"--sample-data":{description:"Include sample data. Currently only supports variants."}}},{name:"project",description:"Add a Ditto project to sync copy from",commands:[{name:"add",description:"Add a Ditto project to sync copy from"},{name:"remove",description:"Stop syncing copy from a Ditto project"}]},{name:"component-folders",description:"List component folders in your workspace. More information about component folders can be found here: https://www.dittowords.com/docs/component-folders.",flags:{"-s, --sample-data":{description:"Includes the sample components folder in the output"}}},{name:"generate-suggestions",description:"Find text that can be potentially replaced with Ditto text",flags:{"-d, --directory [value]":{description:"Directory to search for text"},"-f, --files [value]":{description:"Files to search for text (will override -d)",processor:n(t=>t.split(","),"processor")},"-cf, --component-folder [value]":{description:"Component folder to search for matches"}}},{name:"replace",description:"Find and replace Ditto text with code",flags:{"-ln, --line-numbers [value]":{description:"Only replace text on a specific line number",processor:n(t=>t.split(",").map(Number),"processor")}}},{name:"import-components",description:"Import components via a file. For more information please see: https://www.dittowords.com/docs/importing-string-files.",flags:{"-t, --text [value]":{description:"Text column index (.csv format only)"},"-n, --component-name [value]":{description:"Name column indexes (comma separated) (.csv format only)"},"-no, --notes [value]":{description:"Notes column index (.csv format only)"},"-t, --tags [value]":{description:"Tags column index (.csv format only)"},"-s, --status [value]":{description:"Status column index (.csv format only)"},"-c, --component-id [value]":{description:"Component ID column index (.csv format only)"}}}],qr=n(()=>{G.program.name("ditto-cli"),Wr.forEach(t=>{let e=G.program.command(t.name).description(t.description).action(o=>pe(t.name,o));t.flags&&Object.entries(t.flags).forEach(([o,{description:r,processor:s}])=>{s?e.option(o,r,s):e.option(o,r)}),"commands"in t&&t.commands&&t.commands.forEach(o=>{e.command(o.name).description(o.description).action((r,s)=>{if(t.name==="project"){let i=`${t.name} ${o.name}`;return pe(i,s)}})})})},"setupCommands"),zr=n(()=>{G.program.option("-l, --legacy","Run in legacy mode"),G.program.option("-m, --meta <data...>","Include arbitrary data in requests to the Ditto API. Ex: -m githubActionRequest:true trigger:manual"),G.program.version(tt,"-v, --version","Output the current version")},"setupOptions"),pe=n(async(t,e)=>{let o=Ur.includes(t)&&eo();if(o)try{await oo()}catch{await b("Exiting Ditto CLI...");return}let{meta:r}=G.program.opts();switch(t){case"none":case"pull":return ae({meta:ko(r),includeSampleData:e.sampleData||!1});case"project":case"project add":return o?void 0:xo();case"project remove":return To();case"component-folders":return No({showSampleData:e.sampleData});case"generate-suggestions":return Po({directory:e.directory,files:e.files,componentFolder:e.componentFolder});case"replace":return Co(e.args,{...e?.lineNumbers?{lineNumbers:e.lineNumbers}:{}});case"import-components":{if(e.args.length===0){console.info("Please provide a file path.");return}return Eo(e.args[0],{csvColumnMapping:{name:e.componentName,text:e.text,notes:e.notes,tags:e.tags,status:e.status,componentId:e.componentId}})}default:{await b("Exiting Ditto CLI...");return}}},"executeCommand"),Hr=n(async()=>{if(qr(),zr(),process.argv.length<=2&&process.argv[1].includes("ditto-cli")){await pe("none",[]);return}G.program.parse(process.argv)},"legacyAppEntry"),_o=Hr;var mn=m(require("@sentry/node")),ut=require("commander");var qo=require("os"),it=m(require("path")),zo=m(require("crypto"));var Go=require("zod"),Uo=m(require("fs"));var Mo=m(require("path")),wt=m(require("fs")),Ro=m(require("fs/promises"));function It(t,e=""){let o=Mo.default.dirname(t);return wt.default.existsSync(o)||wt.default.mkdirSync(o),wt.default.existsSync(t)?!1:(Xr(t,e),!0)}n(It,"createFileIfMissingSync");function Xr(t,e){wt.default.writeFileSync(t,e,"utf-8")}n(Xr,"writeFileSync");async function $o(t,e){await Ro.default.writeFile(t,e,"utf-8")}n($o,"writeFile");var Lo=n(t=>t+(/[\r\n]$/.test(t)?"":`
|
|
94
|
+
`),"ensureEndsWithNewLine");var le=m(require("js-yaml"));var U=require("zod"),Yt=U.z.object({projects:U.z.array(U.z.object({id:U.z.string()})).optional(),variants:U.z.array(U.z.object({id:U.z.string()})).optional()});var Yo=require("zod");var Ct=require("zod");var Jo=Yt.extend({format:Ct.z.literal("json"),framework:Ct.z.undefined()}),Zr=Jo.extend({framework:Ct.z.literal("i18next")}),Vo=Ct.z.discriminatedUnion("framework",[Jo,Zr]);var Bo=Yo.z.union([...Vo.options]);var Kr=Yt.extend({outputs:Go.z.array(Bo)}).strict(),me={projects:[],variants:[],outputs:[{format:"json"}]};async function Wo(){let t=Qr();x.setProjectConfig(t)}n(Wo,"initProjectConfig");function Qr(t=x.projectConfigFile,e=me){It(t,le.default.dump(e));let o=Uo.default.readFileSync(t,"utf8"),r=le.default.load(o),s=Kr.safeParse(r);if(!s.success)throw new Error("Failed to parse project config file");return s.data}n(Qr,"readProjectConfigData");var at,W,vt,jt,ct,bt,X,fe=class fe{constructor(){V(this,at);V(this,W);V(this,vt);V(this,jt);V(this,ct);V(this,bt);V(this,X);R(this,at,process.env.DITTO_API_HOST||"https://api.dittowords.com"),R(this,W,process.env.DITTO_TOKEN),R(this,vt,process.env.DITTO_CONFIG_FILE||it.default.join((0,qo.homedir)(),".config","ditto")),R(this,ct,process.env.DITTO_PROJECT_CONFIG_FILE||it.default.normalize(it.default.join("ditto","config.yml"))),R(this,jt,it.default.normalize(it.default.dirname(E(this,ct)))),R(this,bt,zo.default.randomUUID()),R(this,X,me)}get apiHost(){return E(this,at)}set apiHost(e){R(this,at,e)}get apiToken(){return E(this,W)}get apiTokenOrThrow(){if(!E(this,W))throw new Error("No API Token found.");return E(this,W)}get configFile(){return E(this,vt)}get projectConfigFile(){return E(this,ct)}get clientId(){return E(this,bt)}setApiToken(e){R(this,W,e)}get projectConfig(){return E(this,X)}setProjectConfig(e){R(this,X,e)}get selectedProjectConfigOutputs(){return E(this,X).outputs}get projectConfigDir(){return E(this,jt)}};at=new WeakMap,W=new WeakMap,vt=new WeakMap,jt=new WeakMap,ct=new WeakMap,bt=new WeakMap,X=new WeakMap,n(fe,"AppContext");var ue=fe,ts=new ue,x=ts;var Ho=m(require("axios"));function de(t){return function(e){return e.baseURL=x.apiHost,e.headers["x-ditto-client-id"]=x.clientId,e.headers["x-ditto-app"]="cli",e.headers.Authorization=t||x.apiToken,e}}n(de,"defaultInterceptor");var Xo=Ho.default.create({});Xo.interceptors.request.use(de());var Bt=Xo;var Zo=require("axios"),A=require("zod");var es=A.z.array(A.z.object({id:A.z.string(),text:A.z.string(),status:A.z.string(),notes:A.z.string(),tags:A.z.array(A.z.string()),variableIds:A.z.array(A.z.string()),projectId:A.z.string(),variantId:A.z.string().nullable()}));async function ge(t){try{let e=await Bt.get("/v2/textItems",{params:{filter:JSON.stringify(t)}});return es.parse(e.data)}catch(e){throw e instanceof Zo.AxiosError?e.response?.status===400?new Error("Invalid filters. Please check your filters and try again."):e:new Error("Sorry! We're having trouble reaching the Ditto API. Please try again later.")}}n(ge,"fetchText");var Ko=require("axios"),y=require("zod");var Ft=y.z.object({id:y.z.string(),name:y.z.string()}),os=Ft.merge(y.z.object({type:y.z.literal("number"),data:y.z.object({example:y.z.union([y.z.number(),y.z.string()]),fallback:y.z.union([y.z.number(),y.z.string()]).optional()})})),ns=Ft.merge(y.z.object({type:y.z.literal("string"),data:y.z.object({example:y.z.string(),fallback:y.z.string().optional()})})),rs=Ft.merge(y.z.object({type:y.z.literal("hyperlink"),data:y.z.object({text:y.z.string(),url:y.z.string()})})),ss=Ft.merge(y.z.object({type:y.z.literal("list"),data:y.z.array(y.z.string())})),is=Ft.merge(y.z.object({type:y.z.literal("map"),data:y.z.record(y.z.string())})),as=y.z.discriminatedUnion("type",[ns,os,rs,ss,is]),cs=y.z.array(as);async function ye(){try{let t=await Bt.get("/v2/variables");return cs.parse(t.data)}catch(t){throw t instanceof Ko.AxiosError?t:new Error("Sorry! We're having trouble reaching the Ditto API. Please try again later.")}}n(ye,"fetchVariables");var J=m(require("chalk"));var ps=n(t=>J.default.magenta(t),"errorText"),ls=n(t=>J.default.yellow(t),"warnText"),ms=n(t=>J.default.blueBright(t),"info"),us=n(t=>J.default.green(t),"success"),fs=n(t=>J.default.blueBright.underline(t),"url"),ds=n(t=>J.default.grey(t),"subtle"),gs=n(t=>J.default.white(t),"write"),ys=n(t=>J.default.bold(t),"bold"),hs=n(t=>console.log(t),"writeLine"),T={errorText:ps,warnText:ls,info:ms,success:us,url:fs,subtle:ds,write:gs,writeLine:hs,bold:ys};var he=class he{constructor(e,o){this.output=e,this.projectConfig=o}async fetchAPIData(){return{}}async transformAPIData(e){return[]}async format(e,o){let r=await this.fetchAPIData(),s=await this.transformAPIData(r);await this.writeFiles(s)}async writeFiles(e){await Promise.all(e.map(o=>$o(o.fullPath,o.formattedContent).then(()=>{T.writeLine(`Successfully saved to ${T.info(o.fullPath)}`)})))}};n(he,"BaseFormatter");var Ot=he;var xe=class xe{constructor(e){this.filename=e.filename,this.path=e.path,this.extension=e.extension,this.content=e.content,this.metadata=e.metadata??{}}get fullPath(){return`${this.path}/${this.filename}.${this.extension}`}get filenameWithExtension(){return`${this.filename}.${this.extension}`}get formattedContent(){throw new Error("Not implemented")}};n(xe,"OutputFile");var Z=xe;var Te=class Te extends Z{constructor(e){super({filename:e.filename,path:e.path,extension:"json",content:e.content??{},metadata:e.metadata??{}})}get formattedContent(){return JSON.stringify(this.content,null,2)}};n(Te,"JSONOutputFile");var pt=Te;function Gt(t,...e){if(e.length>5)throw new Error("Maximum of 5 mixins supported");return e.reduce((o,r)=>r(o),t)}n(Gt,"applyMixins");var Se=class Se extends Z{constructor(o){super({filename:o.filename,path:o.path,extension:"js",content:o.content??"",metadata:o.metadata??{}});this.indentSpaces=2}get formattedContent(){return Lo(this.content??"")}};n(Se,"JavascriptOutputFile");var Pt=Se;function we(t){var e;return e=class extends t{constructor(){super(...arguments);this.indentSpaces=2}sanitizeStringForJSVariableName(s){return s.replace(/[^a-zA-Z0-9]/g,"_")}codegenNamedImport(s,i){return`import { ${s.map(a=>a.alias?`${a.name} as ${a.alias}`:a.name).sort().join(", ")} } from "${i}";
|
|
95
|
+
`}codegenDefaultImport(s,i){return`import ${s} from "${i}";
|
|
96
|
+
`}codegenDefaultExport(s){return`export default ${s};`}codegenPad(s){return" ".repeat(s*this.indentSpaces)}},n(e,"JavascriptCodegenHelpers"),e}n(we,"javascriptCodegenMixin");var Ie=class Ie{constructor(e){this.format=e}process(...e){throw new Error("Not implemented")}};n(Ie,"BaseFramework");var kt=Ie;var Ce=class Ce extends Gt(kt,we){process(e){let o=x.projectConfigDir,r=new Pt({filename:"index",path:o}),s=Object.values(e).reduce((i,c)=>{let a=c.metadata.variantId;return i[a]??(i[a]=[]),i[a].push(c),i},{});return r.content+=this.generateImportStatements(e),r.content+=`
|
|
97
|
+
`,r.content+=this.generateDefaultExportString(s),[r]}generateImportStatements(e){let o="";for(let r of Object.values(e))o+=this.codegenDefaultImport(this.sanitizeStringForJSVariableName(r.filename),`./${r.filenameWithExtension}`);return o}generateDefaultExportString(e){let o=Object.keys(e),r=`{
|
|
98
|
+
`;for(let s=0;s<o.length;s++){let i=o[s],c=e[i];r+=`${this.codegenPad(1)}"${i}": {
|
|
99
|
+
`;for(let a of c)r+=`${this.codegenPad(2)}...${this.sanitizeStringForJSVariableName(a.filename)},
|
|
100
|
+
`;r+=`${this.codegenPad(1)}}${s<o.length-1?`,
|
|
101
|
+
`:`
|
|
102
|
+
`}`}return r+="}",this.codegenDefaultExport(r)}};n(Ce,"I18NextFramework");var At=Ce;function Qo(t){switch(t){case"i18next":return new At(t);default:throw new Error(`Unsupported framework: ${t}`)}}n(Qo,"getFrameworkProcessor");var ve=class ve extends Gt(Ot){async fetchAPIData(){let e=this.generatePullFilter(),o=await ge(e),s=(await ye()).reduce((i,c)=>(i[c.id]=c,i),{});return{textItems:o,variablesById:s}}async transformAPIData(e){let o=x.projectConfigDir,r={},s=new pt({filename:"variables",path:x.projectConfigDir});for(let c=0;c<e.textItems.length;c++){let a=e.textItems[c],l=`${a.projectId}___${a.variantId||"base"}`;r[l]??(r[l]=new pt({filename:l,path:o,metadata:{variantId:a.variantId||"base"}})),r[l].content[a.id]=a.text;for(let g of a.variableIds){let f=e.variablesById[g];s.content[g]=f.data}}let i=[...Object.values(r),s];return this.output.framework&&i.push(...Qo(this.output.framework).process(r)),i}generatePullFilter(){let e={projects:this.projectConfig.projects,variants:this.projectConfig.variants};return this.output.projects&&(e.projects=this.output.projects),this.output.variants&&(e.variants=this.output.variants),e}};n(ve,"JSONFormatter");var Dt=ve;function je(t,e){switch(t.format){case"json":return new Dt(t,e).format(t,e);default:throw new Error(`Unsupported output format: ${t}`)}}n(je,"handleOutput");var tn=n(async()=>{for(let t of x.selectedProjectConfigOutputs)await je(t,x.projectConfig)},"pull");var en=m(require("@sentry/node"));async function lt(t,e=2){t&&T.writeLine(`
|
|
103
|
+
${t}
|
|
104
|
+
`),await en.flush(),process.exit(e)}n(lt,"quit");var rn=m(require("fs")),sn=m(require("url"));var be=m(require("fs")),Fe=m(require("js-yaml")),mt=require("zod");var xs=mt.z.record(mt.z.string(),mt.z.array(mt.z.object({token:mt.z.string()})));function Ut(t=x.configFile){It(t);let e=be.default.readFileSync(t,"utf8"),o=Fe.default.load(e),r=xs.safeParse(o);return r.success?r.data:{}}n(Ut,"readGlobalConfigData");function Ts(t,e){It(t);let o=Ut(t),r=Fe.default.dump({...o,...e});be.default.writeFileSync(t,r,"utf8")}n(Ts,"writeGlobalConfigData");function on(t,e,o){let r=Ut(t);r[e]=[{token:o}],Ts(t,r)}n(on,"saveToken");var Wt=m(require("axios"));async function qt(t){try{let e=Wt.default.create({});return e.interceptors.request.use(de(t)),(await e.get("/token-check")).status===200?{success:!0}:{success:!1,output:[T.errorText("This API key isn't valid. Please try another.")]}}catch(e){return e instanceof Wt.AxiosError?e.code==="ENOTFOUND"?{success:!1,output:[T.errorText(`Can't connect to API: ${T.url(x.apiHost)}`)]}:e.response?.status===401||e.response?.status===404?{success:!1,output:[T.errorText("This API key isn't valid. Please try another.")]}:{success:!1,output:[T.errorText("Sorry! We're having trouble reaching the Ditto API. Please try again later.")]}:{success:!1,output:[T.warnText("Sorry! We're having trouble reaching the Ditto API. Please try again later.")]}}}n(qt,"checkToken");var an=m(require("@sentry/node")),cn=require("enquirer");async function pn(t=x.apiToken,e=x.configFile,o=x.apiHost){if(t)return await nn(t);if(!rn.default.existsSync(e))return await Oe();let r=Ut(e),s=ln(o);return!r[s]||!r[s][0]||r[s][0].token===""?await Oe(s):await nn(r[s][0].token)}n(pn,"initAPIToken");async function Oe(t=x.apiHost){try{let e=await ws();T.writeLine(`Thanks for authenticating. We'll save the key to: ${T.info(x.configFile)}
|
|
105
|
+
`);let o=ln(t);return on(x.configFile,o,e),x.setApiToken(e),e}catch(e){if(e==="")return await lt("",0),"";let o=an.captureException(e),r=`
|
|
106
|
+
|
|
107
|
+
Error ID: ${T.info(o)}`;return await lt(T.errorText("Something went wrong. Please contact support or try again later.")+r),""}}n(Oe,"collectAndSaveToken");async function ws(){let t=T.url("https://app.dittowords.com/account/devtools"),e=T.bold(T.info("API Keys")),o=`To get started, you'll need your Ditto API key. You can find this at: ${t} under "${e}".`;return T.writeLine(o),(await Is()).token}n(ws,"collectToken");async function Is(){return await(0,cn.prompt)({type:"input",name:"token",message:"What is your API key?",validate:n(async e=>{console.log("token",e);let o=await qt(e);return o.success?!0:o.output?.join(`
|
|
108
|
+
`)||"Invalid API key"},"validate")})}n(Is,"promptForApiToken");function ln(t){return t.includes("://")?sn.default.parse(t).hostname||"":t}n(ln,"getURLHostname");async function nn(t){return(await qt(t)).success?t:await Oe()}n(nn,"validateToken");var Cs=[{name:"pull",description:"Sync copy from Ditto into the current working directory"}],vs=n(()=>{ut.program.name("ditto-cli"),Cs.forEach(t=>{let e=ut.program.command(t.name).description(t.description).action(o=>un(t.name,o));t.flags&&Object.entries(t.flags).forEach(([o,{description:r,processor:s}])=>{s?e.option(o,r,s):e.option(o,r)})})},"setupCommands"),js=n(()=>{ut.program.option("-l, --legacy","Run in legacy mode"),ut.program.version(tt,"-v, --version","Output the current version")},"setupOptions"),un=n(async(t,e)=>{try{let o=await pn();switch(x.setApiToken(o),await Wo(),t){case"none":case"pull":return await tn();default:{await lt(`Invalid command: ${t}. Exiting Ditto CLI...`);return}}}catch(o){let r=mn.captureException(o),s=`
|
|
109
|
+
|
|
110
|
+
Error ID: ${T.info(r)}`;return process.env.DEBUG==="true"&&console.error(T.info(`Development stack trace:
|
|
111
|
+
`),o),await lt(T.errorText("Something went wrong. Please contact support or try again later.")+s)}},"executeCommand"),bs=n(async()=>{if(vs(),js(),process.argv.length<=2&&process.argv[1].includes("ditto-cli")){await un("none",[]);return}ut.program.parse(process.argv)},"appEntry"),fn=bs;var Fs="production";dn.init({dsn:"https://9c1d99fa4267f54c6b914f720b4ed3a2@o979374.ingest.sentry.io/4505705213919232",environment:Fs,release:tt});var Os=n(async()=>{process.argv.includes("--legacy")?(console.log(T.warnText(`
|
|
112
|
+
Ditto CLI is running in legacy mode. This mode is deprecated and will be removed in a future release.
|
|
113
|
+
`)),_o()):fn()},"main");Os();
|
|
114
|
+
|
|
115
|
+
//# debugId=4fa6a938-f8ef-56a0-9e03-daab22de6e0a
|
package/package.json
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dittowords/cli",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "5.0.0-beta.1",
|
|
4
4
|
"description": "Command Line Interface for Ditto (dittowords.com).",
|
|
5
5
|
"license": "MIT",
|
|
6
|
-
"main": "bin/
|
|
6
|
+
"main": "bin/ditto.js",
|
|
7
7
|
"scripts": {
|
|
8
|
-
"prepublishOnly": "ENV=production
|
|
8
|
+
"prepublishOnly": "ENV=production node esbuild.mjs && sentry-cli sourcemaps inject ./bin && npx sentry-cli sourcemaps upload ./bin --release=\"$(cat package.json | jq -r '.version')\"",
|
|
9
9
|
"prepare": "husky install",
|
|
10
|
-
"start": "
|
|
11
|
-
"sync": "
|
|
12
|
-
"dev": "tsc --noEmit --excludeFiles './**/*.test.ts' && etsc --watch"
|
|
10
|
+
"start": "node esbuild.mjs && node --enable-source-maps --require dotenv/config bin/ditto.js",
|
|
11
|
+
"sync": "node esbuild.mjs && node --enable-source-maps --require dotenv/config bin/ditto.js pull"
|
|
13
12
|
},
|
|
14
13
|
"repository": {
|
|
15
14
|
"type": "git",
|
|
@@ -32,6 +31,14 @@
|
|
|
32
31
|
"bin": {
|
|
33
32
|
"ditto-cli": "bin/ditto.js"
|
|
34
33
|
},
|
|
34
|
+
"files": [
|
|
35
|
+
"bin",
|
|
36
|
+
"!bin/ditto.js.map",
|
|
37
|
+
"package.json",
|
|
38
|
+
"yarn.lock",
|
|
39
|
+
"README.md",
|
|
40
|
+
"LICENSE"
|
|
41
|
+
],
|
|
35
42
|
"devDependencies": {
|
|
36
43
|
"@babel/preset-env": "^7.20.2",
|
|
37
44
|
"@babel/preset-typescript": "^7.18.6",
|
|
@@ -43,8 +50,7 @@
|
|
|
43
50
|
"@types/node": "^18.0.0",
|
|
44
51
|
"babel-jest": "^29.3.1",
|
|
45
52
|
"dotenv": "^16.3.1",
|
|
46
|
-
"esbuild": "^0.
|
|
47
|
-
"esbuild-node-tsc": "^2.0.5",
|
|
53
|
+
"esbuild": "^0.25.2",
|
|
48
54
|
"husky": "^7.0.4",
|
|
49
55
|
"jest": "^29.3.1",
|
|
50
56
|
"lint-staged": "^11.2.4",
|
|
@@ -53,7 +59,7 @@
|
|
|
53
59
|
"source-map": "^0.7.3",
|
|
54
60
|
"tempy": "^0.6.0",
|
|
55
61
|
"ts-node": "^10.9.2",
|
|
56
|
-
"typescript": "^
|
|
62
|
+
"typescript": "^5.8.3"
|
|
57
63
|
},
|
|
58
64
|
"dependencies": {
|
|
59
65
|
"@babel/core": "^7.11.4",
|
|
@@ -73,7 +79,7 @@
|
|
|
73
79
|
"js-yaml": "^4.1.0",
|
|
74
80
|
"memfs": "^4.7.7",
|
|
75
81
|
"ora": "^5.0.0",
|
|
76
|
-
"
|
|
82
|
+
"zod": "^3.24.2"
|
|
77
83
|
},
|
|
78
84
|
"lint-staged": {
|
|
79
85
|
"src/**/*.{js,jsx,ts,tsx,css,json}": "prettier --write"
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
name: "Install Node Dependencies"
|
|
2
|
-
description: "Attempts to install Node.js dependencing leveraging yarn and caching"
|
|
3
|
-
|
|
4
|
-
inputs:
|
|
5
|
-
working-directory:
|
|
6
|
-
required: false
|
|
7
|
-
description: "The directory to run the install command in"
|
|
8
|
-
default: ./
|
|
9
|
-
|
|
10
|
-
runs:
|
|
11
|
-
using: "composite"
|
|
12
|
-
steps:
|
|
13
|
-
- uses: actions/cache@v3
|
|
14
|
-
env:
|
|
15
|
-
cache-name: node_modules-cache
|
|
16
|
-
with:
|
|
17
|
-
path: ${{ inputs.working-directory }}node_modules
|
|
18
|
-
key: ${{ runner.os }}-build-${{ hashFiles('**/yarn.lock') }}
|
|
19
|
-
restore-keys: |
|
|
20
|
-
${{ runner.os }}-build
|
|
21
|
-
|
|
22
|
-
- name: Install new dependencies
|
|
23
|
-
shell: bash
|
|
24
|
-
run: cd ${{ inputs.working-directory }} && yarn install --prefer-offline --frozen-lockfile
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
name: "Required Checks"
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
pull_request:
|
|
5
|
-
branches:
|
|
6
|
-
- master
|
|
7
|
-
|
|
8
|
-
jobs:
|
|
9
|
-
jest-tests:
|
|
10
|
-
runs-on: ubuntu-20.04
|
|
11
|
-
timeout-minutes: 5
|
|
12
|
-
strategy:
|
|
13
|
-
fail-fast: false
|
|
14
|
-
steps:
|
|
15
|
-
- uses: actions/checkout@v3
|
|
16
|
-
- name: Use Node.js
|
|
17
|
-
uses: actions/setup-node@v3
|
|
18
|
-
with:
|
|
19
|
-
node-version: 20
|
|
20
|
-
- uses: ./.github/actions/install-node-dependencies
|
|
21
|
-
- name: Jest Tests
|
|
22
|
-
run: |
|
|
23
|
-
npx jest --ci --silent --maxWorkers=1
|
|
24
|
-
shell: bash
|