glotstack 0.0.7 → 0.0.8
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/dist/cli.js +33 -43
- package/dist/cli.js.map +1 -1
- package/dist/util/findConfig.d.ts +1 -1
- package/dist/util/findConfig.js +40 -13
- package/dist/util/findConfig.js.map +1 -1
- package/package.json +1 -1
- package/src/cli.tsx +37 -45
- package/src/util/findConfig.ts +27 -11
package/dist/cli.js
CHANGED
|
@@ -53,7 +53,7 @@ const promises_1 = require("node:fs/promises");
|
|
|
53
53
|
const node_path_1 = require("node:path");
|
|
54
54
|
const fetchGlotstack = function (url, apiKey, body, overrideHeaders) {
|
|
55
55
|
return __awaiter(this, void 0, void 0, function* () {
|
|
56
|
-
console.info(`
|
|
56
|
+
console.info(`Fetching glotstack.ai: ${url}`);
|
|
57
57
|
const headers = Object.assign({ 'authorization': `Bearer ${apiKey}` }, (overrideHeaders == null ? {} : overrideHeaders));
|
|
58
58
|
let payloadBody;
|
|
59
59
|
if (!(body instanceof undici_2.FormData)) {
|
|
@@ -94,41 +94,42 @@ function unflatten(flat) {
|
|
|
94
94
|
}
|
|
95
95
|
return result;
|
|
96
96
|
}
|
|
97
|
+
const DEFAULT_OPTIONS = {
|
|
98
|
+
sourcePath: '.',
|
|
99
|
+
sourceLocale: 'en-US',
|
|
100
|
+
apiOrigin: 'https://glotstack.ai'
|
|
101
|
+
};
|
|
97
102
|
function resolveConfigAndOptions(options) {
|
|
98
103
|
return __awaiter(this, void 0, void 0, function* () {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
if (configPath != null) {
|
|
102
|
-
console.info('Loading config file at ', configPath);
|
|
103
|
-
try {
|
|
104
|
-
const text = yield fs_1.promises.readFile(configPath, 'utf-8');
|
|
105
|
-
config = JSON.parse(text);
|
|
106
|
-
console.info('Loaded config file', config);
|
|
107
|
-
}
|
|
108
|
-
catch (err) {
|
|
109
|
-
//pass
|
|
110
|
-
}
|
|
111
|
-
}
|
|
104
|
+
var _a;
|
|
105
|
+
const config = (_a = yield (0, findConfig_1.findGlotstackConfig)((0, process_1.cwd)())) !== null && _a !== void 0 ? _a : {};
|
|
112
106
|
if ('outputLocales' in options) {
|
|
113
107
|
if (options.outputLocales.includes('en-US')) {
|
|
114
108
|
console.warn('en-US detected in outputLocales, removing');
|
|
115
109
|
options.outputLocales = options.outputLocales.filter((x) => x !== 'en-US');
|
|
116
110
|
}
|
|
117
111
|
}
|
|
118
|
-
|
|
112
|
+
const resolved = (0, object_1.merge)({}, DEFAULT_OPTIONS, config, options);
|
|
113
|
+
// special case to match source
|
|
114
|
+
if (resolved.outputDir == null) {
|
|
115
|
+
resolved.outputDir = resolved.sourcePath;
|
|
116
|
+
}
|
|
117
|
+
return resolved;
|
|
119
118
|
});
|
|
120
119
|
}
|
|
121
120
|
function run(args) {
|
|
122
121
|
return __awaiter(this, void 0, void 0, function* () {
|
|
123
|
-
var _a, _b;
|
|
124
122
|
commander_1.program
|
|
125
123
|
.command('extract-translations')
|
|
126
124
|
.description('extract translations from all compatible source files.')
|
|
127
|
-
.option('--source-path [path]',
|
|
128
|
-
.option('--
|
|
125
|
+
.option('--source-path [path]', `path directory containing [locale].json files (default=${DEFAULT_OPTIONS['sourcePath']})`)
|
|
126
|
+
.option('--source-locale [locale]', `the locale you provide "context" in, your primary locale (default=${DEFAULT_OPTIONS['sourceLocale']})`)
|
|
127
|
+
.option('--api-origin [url]', `glotstack api origin (default=${DEFAULT_OPTIONS['apiOrigin']})`)
|
|
128
|
+
.option('--output-dir [path]', 'path to output directory (default=<source-path>')
|
|
129
129
|
.option('--api-key [key]', 'api key for glotstack.ai')
|
|
130
|
-
.option('--yes', 'skip confirm checks'
|
|
131
|
-
.action((
|
|
130
|
+
.option('--yes', 'skip confirm checks')
|
|
131
|
+
.action((inputOptions) => __awaiter(this, void 0, void 0, function* () {
|
|
132
|
+
const options = yield resolveConfigAndOptions(inputOptions);
|
|
132
133
|
if (!options.apiOrigin) {
|
|
133
134
|
throw new Error('apiOrigin must be specified');
|
|
134
135
|
}
|
|
@@ -156,7 +157,7 @@ function run(args) {
|
|
|
156
157
|
});
|
|
157
158
|
const send = yield askToSend();
|
|
158
159
|
if (send) {
|
|
159
|
-
console.info('Sending files to
|
|
160
|
+
console.info('Sending files to generate new source and extracted strings');
|
|
160
161
|
const url = `${options.apiOrigin}/uploads/translations/extract`;
|
|
161
162
|
const form = new undici_2.FormData();
|
|
162
163
|
for (let i = 0; i < filesWithIssues.length; i++) {
|
|
@@ -165,7 +166,7 @@ function run(args) {
|
|
|
165
166
|
console.debug(`Uploading file: ${filePath}`);
|
|
166
167
|
}
|
|
167
168
|
const data = yield fetchGlotstack(url, options.apiKey, form);
|
|
168
|
-
data.translations.map(elem => console.info(
|
|
169
|
+
data.translations.map(elem => console.info(`Source and translations available for: ${elem.name}:\n ${elem.modified_source.url}\n\n`));
|
|
169
170
|
rl.close();
|
|
170
171
|
}
|
|
171
172
|
else {
|
|
@@ -175,26 +176,14 @@ function run(args) {
|
|
|
175
176
|
commander_1.program
|
|
176
177
|
.command('get-translations')
|
|
177
178
|
.description('fetch translations for all [output-locals...]. Use .glotstack.json for repeatable results.')
|
|
178
|
-
.option('--source-path [path]',
|
|
179
|
-
.option('--
|
|
180
|
-
.option('--
|
|
179
|
+
.option('--source-path [path]', `path directory containing [locale].json files (default=${DEFAULT_OPTIONS['sourcePath']})`)
|
|
180
|
+
.option('--source-locale [locale]', `the locale you provide "context" in, your primary locale (default=${DEFAULT_OPTIONS['sourceLocale']})`)
|
|
181
|
+
.option('--api-origin [url]', `glotstack api origin (default=${DEFAULT_OPTIONS['apiOrigin']})`)
|
|
182
|
+
.option('--output-dir [path]', 'path to output directory (default=<source-path>')
|
|
181
183
|
.option('--api-key [key]', 'api key for glotstack.ai')
|
|
182
184
|
.option('--project-id [id]', '(optional) specific project to use')
|
|
183
185
|
.argument('[output-locales...]', 'locales to get translations for')
|
|
184
186
|
.action((outputLocales, options, command) => __awaiter(this, void 0, void 0, function* () {
|
|
185
|
-
const configPath = (0, findConfig_1.findGlotstackConfig)((0, process_1.cwd)());
|
|
186
|
-
let config = {};
|
|
187
|
-
if (configPath != null) {
|
|
188
|
-
console.info('Loading config file at ', configPath);
|
|
189
|
-
try {
|
|
190
|
-
const text = yield fs_1.promises.readFile(configPath, 'utf-8');
|
|
191
|
-
config = JSON.parse(text);
|
|
192
|
-
console.info('Loaded config file', config);
|
|
193
|
-
}
|
|
194
|
-
catch (err) {
|
|
195
|
-
//pass
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
187
|
const resolved = yield resolveConfigAndOptions(Object.assign(Object.assign({}, options), { outputLocales: outputLocales }));
|
|
199
188
|
if (!resolved.sourcePath) {
|
|
200
189
|
throw new Error('sourcePath must be specified');
|
|
@@ -205,7 +194,7 @@ function run(args) {
|
|
|
205
194
|
if (!resolved.outputDir) {
|
|
206
195
|
throw new Error('outputDir must be specified');
|
|
207
196
|
}
|
|
208
|
-
const absPath = path_1.default.resolve(resolved.sourcePath);
|
|
197
|
+
const absPath = path_1.default.resolve(resolved.sourcePath, `${resolved.sourceLocale}.json`);
|
|
209
198
|
const fileContent = yield fs_1.promises.readFile(absPath, 'utf-8');
|
|
210
199
|
let json = null;
|
|
211
200
|
try {
|
|
@@ -221,7 +210,7 @@ function run(args) {
|
|
|
221
210
|
}
|
|
222
211
|
}
|
|
223
212
|
const body = Object.assign({ locales: resolved.outputLocales, translations: json }, Object.assign({}, (resolved.projectId != null ? { projectId: resolved.projectId } : {})));
|
|
224
|
-
const url = `${
|
|
213
|
+
const url = `${resolved.apiOrigin}/api/translations`;
|
|
225
214
|
const data = yield fetchGlotstack(url, resolved.apiKey, body);
|
|
226
215
|
console.info('Received translations:', data);
|
|
227
216
|
Object.entries(data.data).map(([key, val]) => {
|
|
@@ -233,9 +222,10 @@ function run(args) {
|
|
|
233
222
|
commander_1.program
|
|
234
223
|
.command('format-json')
|
|
235
224
|
.description('format files in --source-path [path] to nested (not flat)')
|
|
236
|
-
.option('--source-path [path]',
|
|
237
|
-
.option('--yes', 'skip confirm checks'
|
|
238
|
-
.action((
|
|
225
|
+
.option('--source-path [path]', `path directory containing [locale].json files (default=${DEFAULT_OPTIONS['sourcePath']})`)
|
|
226
|
+
.option('--yes', 'skip confirm checks')
|
|
227
|
+
.action((inputOptions) => __awaiter(this, void 0, void 0, function* () {
|
|
228
|
+
const options = yield resolveConfigAndOptions(inputOptions);
|
|
239
229
|
if (!options.sourcePath) {
|
|
240
230
|
throw new Error('sourcePath must be specified');
|
|
241
231
|
}
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.tsx"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,yCAA4C;AAC5C,gDAAuB;AACvB,2BAAqD;AACrD,kDAAuD;AACvD,qCAA6B;AAC7B,0CAAqC;AACrC,sCAAsC;AACtC,oDAA2B;AAC3B,iEAAkD;AAClD,+CAA+D;AAE/D,mCAA8B;AAC9B,mCAAiC;AACjC,qCAAoC;AACpC,+CAA+D;AAC/D,yCAAmC;AAEnC,MAAM,cAAc,GAAG,UAAmB,GAAW,EAAE,MAAc,EAAE,IAAoC,EAAE,eAAqC;;QAChJ,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.tsx"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,yCAA4C;AAC5C,gDAAuB;AACvB,2BAAqD;AACrD,kDAAuD;AACvD,qCAA6B;AAC7B,0CAAqC;AACrC,sCAAsC;AACtC,oDAA2B;AAC3B,iEAAkD;AAClD,+CAA+D;AAE/D,mCAA8B;AAC9B,mCAAiC;AACjC,qCAAoC;AACpC,+CAA+D;AAC/D,yCAAmC;AAEnC,MAAM,cAAc,GAAG,UAAmB,GAAW,EAAE,MAAc,EAAE,IAAoC,EAAE,eAAqC;;QAChJ,OAAO,CAAC,IAAI,CAAC,0BAA0B,GAAG,EAAE,CAAC,CAAA;QAE7C,MAAM,OAAO,mBACX,eAAe,EAAE,UAAU,MAAM,EAAE,IAChC,CAAC,eAAe,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,eAAe,CAAC,CACpD,CAAA;QAED,IAAI,WAA8B,CAAA;QAElC,IAAI,CAAC,CAAC,IAAI,YAAY,iBAAQ,CAAC,EAAE,CAAC;YAChC,OAAO,CAAC,cAAc,CAAC,GAAG,kBAAkB,CAAA;YAC5C,WAAW,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA;QACpC,CAAC;aAAM,CAAC;YACN,WAAW,GAAG,IAAI,CAAA;QACpB,CAAC;QAED,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,IAAA,cAAK,EAAC,GAAG,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC,CAAA;YAC5E,IAAI,CAAC,GAAG,CAAC,EAAE;gBAAE,MAAM,IAAI,KAAK,CAAC,QAAQ,GAAG,CAAC,MAAM,KAAK,GAAG,CAAC,UAAU,EAAE,CAAC,CAAA;YACrE,OAAO,GAAG,CAAC,IAAI,EAAO,CAAA;QACxB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,eAAe,EAAE,GAAG,CAAC,CAAA;YACnC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QACjB,CAAC;IACH,CAAC;CAAA,CAAA;AAED,SAAS,SAAS,CAAC,IAAyB;IAC1C,MAAM,MAAM,GAAwB,EAAE,CAAA;IAEtC,KAAK,MAAM,OAAO,IAAI,IAAI,EAAE,CAAC;QAC3B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;QAChC,IAAI,OAAO,GAAG,MAAM,CAAA;QAEpB,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE;YAC1B,IAAI,GAAG,KAAK,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC7B,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,CAAA;YAC/B,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,CAAC,IAAI,IAAI,OAAO,CAAC,EAAE,CAAC;oBACvB,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAA;gBACpB,CAAC;gBACD,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;YACzB,CAAC;QACH,CAAC,CAAC,CAAA;IACJ,CAAC;IAED,OAAO,MAAM,CAAA;AACf,CAAC;AAED,MAAM,eAAe,GAA2B;IAC9C,UAAU,EAAE,GAAG;IACf,YAAY,EAAE,OAAO;IACrB,SAAS,EAAE,sBAAsB;CAClC,CAAA;AAED,SAAe,uBAAuB,CAAC,OAA4B;;;QAEjE,MAAM,MAAM,GAAG,MAAA,MAAM,IAAA,gCAAmB,EAAC,IAAA,aAAG,GAAE,CAAC,mCAAI,EAAE,CAAA;QAErD,IAAI,eAAe,IAAI,OAAO,EAAE,CAAC;YAC/B,IAAK,OAAO,CAAC,aAA0B,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;gBAC1D,OAAO,CAAC,IAAI,CAAC,2CAA2C,CAAC,CAAA;gBACzD,OAAO,CAAC,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,KAAK,OAAO,CAAC,CAAA;YACpF,CAAC;QACH,CAAC;QAED,MAAM,QAAQ,GAAG,IAAA,cAAK,EAAC,EAAE,EAAE,eAAe,EAAE,MAAM,EAAE,OAAO,CAAC,CAAA;QAE5D,+BAA+B;QAC/B,IAAI,QAAQ,CAAC,SAAS,IAAI,IAAI,EAAE,CAAC;YAC/B,QAAQ,CAAC,SAAS,GAAG,QAAQ,CAAC,UAAU,CAAA;QAC1C,CAAC;QAED,OAAO,QAAQ,CAAA;IACjB,CAAC;CAAA;AAGD,SAAe,GAAG,CAAC,IAAc;;QAC/B,mBAAO;aACJ,OAAO,CAAC,sBAAsB,CAAC;aAC/B,WAAW,CAAC,wDAAwD,CAAC;aACrE,MAAM,CAAC,sBAAsB,EAAE,0DAA0D,eAAe,CAAC,YAAY,CAAC,GAAG,CAAC;aAC1H,MAAM,CAAC,0BAA0B,EAAE,qEAAqE,eAAe,CAAC,cAAc,CAAC,GAAG,CAAC;aAC3I,MAAM,CAAC,oBAAoB,EAAE,iCAAiC,eAAe,CAAC,WAAW,CAAC,GAAG,CAAC;aAC9F,MAAM,CAAC,qBAAqB,EAAE,iDAAiD,CAAC;aAChF,MAAM,CAAC,iBAAiB,EAAE,0BAA0B,CAAC;aACrD,MAAM,CAAC,OAAO,EAAE,qBAAqB,CAAC;aACtC,MAAM,CAAC,CAAO,YAAiC,EAAE,EAAE;YAClD,MAAM,OAAO,GAAG,MAAM,uBAAuB,CAAC,YAAY,CAAC,CAAA;YAC3D,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC;gBACvB,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAA;YAChD,CAAC;YAED,MAAM,MAAM,GAAG,IAAI,gBAAM,CAAC,MAAM,CAAC,EAAE,kBAAkB,EAAE,cAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,uBAAuB,CAAC,EAAE,CAAC,CAAA;YAC7G,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAA;YAClD,MAAM,eAAe,GAAG,OAAO;iBAC5B,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,YAAY,GAAG,CAAC,CAAC;iBAChD,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAA;YAEzB,MAAM,EAAE,GAAG,QAAQ,CAAC,eAAe,CAAC,EAAE,KAAK,EAAL,oBAAK,EAAE,MAAM,EAAN,qBAAM,EAAE,CAAC,CAAA;YACtD,MAAM,SAAS,GAAG,GAA2B,EAAE;gBAC7C,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;oBAChB,OAAO,IAAI,CAAA;gBACb,CAAC;gBACD,MAAM,QAAQ,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,wGAAwG,CAAC,CAAA;gBAC5I,IAAI,QAAQ,KAAK,KAAK,EAAE,CAAC;oBACvB,OAAO,IAAI,CAAA;gBACb,CAAC;qBAAM,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;oBAC7B,OAAO,CAAC,KAAK,CAAC,gCAAgC,CAAC,CAAA;oBAC/C,OAAO,SAAS,EAAE,CAAA;gBACpB,CAAC;qBAAM,CAAC;oBACN,OAAO,KAAK,CAAA;gBACd,CAAC;YACH,CAAC,CAAA,CAAA;YAED,MAAM,IAAI,GAAG,MAAM,SAAS,EAAE,CAAA;YAC9B,IAAI,IAAI,EAAE,CAAC;gBACT,OAAO,CAAC,IAAI,CAAC,4DAA4D,CAAC,CAAA;gBAC1E,MAAM,GAAG,GAAG,GAAG,OAAO,CAAC,SAAS,+BAA+B,CAAA;gBAC/D,MAAM,IAAI,GAAG,IAAI,iBAAQ,EAAE,CAAA;gBAE3B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,eAAe,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;oBAChD,MAAM,QAAQ,GAAG,eAAe,CAAC,CAAC,CAAC,CAAA;oBACnC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,IAAA,oBAAU,EAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC,CAAA;oBAC9D,OAAO,CAAC,KAAK,CAAC,mBAAmB,QAAQ,EAAE,CAAC,CAAA;gBAC9C,CAAC;gBACD,MAAM,IAAI,GAAG,MAAM,cAAc,CAAyE,GAAG,EAAE,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,CAAA;gBACpI,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,0CAA0C,IAAI,CAAC,IAAI,QAAQ,IAAI,CAAC,eAAe,CAAC,GAAG,MAAM,CAAC,CAAC,CAAA;gBACtI,EAAE,CAAC,KAAK,EAAE,CAAA;YACZ,CAAC;iBAAM,CAAC;gBACN,EAAE,CAAC,KAAK,EAAE,CAAA;YACZ,CAAC;QACH,CAAC,CAAA,CAAC,CAAA;QAEJ,mBAAO;aACJ,OAAO,CAAC,kBAAkB,CAAC;aAC3B,WAAW,CAAC,4FAA4F,CAAC;aACzG,MAAM,CAAC,sBAAsB,EAAE,0DAA0D,eAAe,CAAC,YAAY,CAAC,GAAG,CAAC;aAC1H,MAAM,CAAC,0BAA0B,EAAE,qEAAqE,eAAe,CAAC,cAAc,CAAC,GAAG,CAAC;aAC3I,MAAM,CAAC,oBAAoB,EAAE,iCAAiC,eAAe,CAAC,WAAW,CAAC,GAAG,CAAC;aAC9F,MAAM,CAAC,qBAAqB,EAAE,iDAAiD,CAAC;aAChF,MAAM,CAAC,iBAAiB,EAAE,0BAA0B,CAAC;aACrD,MAAM,CAAC,mBAAmB,EAAE,oCAAoC,CAAC;aACjE,QAAQ,CAAC,qBAAqB,EAAE,iCAAiC,CAAC;aAClE,MAAM,CAAC,CAAO,aAAuB,EAAE,OAA4B,EAAE,OAAgB,EAAE,EAAE;YACxF,MAAM,QAAQ,GAAG,MAAM,uBAAuB,iCAAM,OAAO,KAAE,aAAa,EAAE,aAAa,IAAG,CAAA;YAC5F,IAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,CAAC;gBACzB,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAA;YACjD,CAAC;YACD,IAAI,CAAC,QAAQ,CAAC,SAAS,EAAE,CAAC;gBACxB,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAA;YAChD,CAAC;YACD,IAAI,CAAC,QAAQ,CAAC,SAAS,EAAE,CAAC;gBACxB,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAA;YAChD,CAAC;YAED,MAAM,OAAO,GAAG,cAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,UAAU,EAAE,GAAG,QAAQ,CAAC,YAAY,OAAO,CAAC,CAAA;YAClF,MAAM,WAAW,GAAG,MAAM,aAAE,CAAC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;YAEvD,IAAI,IAAI,GAAG,IAAI,CAAA;YACf,IAAI,CAAC;gBACH,IAAI,GAAG,IAAA,eAAQ,EAAC,WAAW,CAAC,CAAA;YAC9B,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,IAAI,CAAC;oBACH,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAA;gBAChC,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACb,OAAO,CAAC,KAAK,CAAC,8BAA8B,EAAE,OAAO,EAAE,GAAG,CAAC,CAAA;oBAC3D,MAAM,GAAG,CAAA;gBACX,CAAC;YACH,CAAC;YAED,MAAM,IAAI,mBACR,OAAO,EAAE,QAAQ,CAAC,aAAa,EAC/B,YAAY,EAAE,IAAI,sBACT,CAAC,QAAQ,CAAC,SAAS,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,QAAQ,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAC/E,CAAA;YAED,MAAM,GAAG,GAAG,GAAG,QAAQ,CAAC,SAAS,mBAAmB,CAAA;YACpD,MAAM,IAAI,GAAG,MAAM,cAAc,CAAyB,GAAG,EAAE,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC,CAAA;YACrF,OAAO,CAAC,IAAI,CAAC,wBAAwB,EAAE,IAAI,CAAC,CAAA;YAC5C,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,EAAE;gBAC3C,MAAM,CAAC,GAAG,GAAG,QAAQ,CAAC,SAAS,IAAI,GAAG,OAAO,CAAA;gBAC7C,OAAO,CAAC,IAAI,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAA;gBACjC,aAAE,CAAC,SAAS,CAAC,GAAG,QAAQ,CAAC,SAAS,IAAI,GAAG,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAA;YACjF,CAAC,CAAC,CAAA;QACJ,CAAC,CAAA,CAAC,CAAA;QAEJ,mBAAO;aACJ,OAAO,CAAC,aAAa,CAAC;aACtB,WAAW,CAAC,2DAA2D,CAAC;aACxE,MAAM,CAAC,sBAAsB,EAAE,0DAA0D,eAAe,CAAC,YAAY,CAAC,GAAG,CAAC;aAC1H,MAAM,CAAC,OAAO,EAAE,qBAAqB,CAAC;aACtC,MAAM,CAAC,CAAO,YAAiC,EAAE,EAAE;YAClD,MAAM,OAAO,GAAG,MAAM,uBAAuB,CAAC,YAAY,CAAC,CAAA;YAE3D,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC;gBACxB,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAA;YACjD,CAAC;YACD,MAAM,EAAE,GAAG,QAAQ,CAAC,eAAe,CAAC,EAAE,KAAK,EAAL,oBAAK,EAAE,MAAM,EAAN,qBAAM,EAAE,CAAC,CAAA;YACtD,MAAM,SAAS,GAAG,GAA2B,EAAE;gBAC7C,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;oBAChB,OAAO,IAAI,CAAA;gBACb,CAAC;gBACD,MAAM,QAAQ,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,yGAAyG,CAAC,CAAA;gBAC7I,IAAI,QAAQ,KAAK,KAAK,EAAE,CAAC;oBACvB,OAAO,IAAI,CAAA;gBACb,CAAC;qBAAM,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;oBAC7B,OAAO,CAAC,KAAK,CAAC,gCAAgC,CAAC,CAAA;oBAC/C,OAAO,SAAS,EAAE,CAAA;gBACpB,CAAC;qBAAM,CAAC;oBACN,OAAO,KAAK,CAAA;gBACd,CAAC;YACH,CAAC,CAAA,CAAA;YACD,MAAM,GAAG,GAAG,MAAM,SAAS,EAAE,CAAA;YAC7B,IAAI,GAAG,EAAE,CAAC;gBACR,MAAM,KAAK,GAAG,MAAM,IAAA,kBAAO,EAAC,OAAO,CAAC,UAAU,CAAC,CAAA;gBAC/C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;oBAC9C,MAAM,EAAE,GAAG,IAAA,mBAAO,EAAC,OAAO,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;oBAChD,MAAM,IAAI,GAAG,MAAM,IAAA,mBAAQ,EAAC,EAAE,EAAE,OAAO,CAAC,CAAA;oBACxC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;oBAC7B,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;oBAC1D,MAAM,IAAA,oBAAS,EAAC,EAAE,EAAE,SAAS,CAAC,CAAA;gBAChC,CAAC;gBACD,EAAE,CAAC,KAAK,EAAE,CAAA;YACZ,CAAC;YACD,EAAE,CAAC,KAAK,EAAE,CAAA;QAEZ,CAAC,CAAA,CAAC,CAAA;QAGJ,MAAM,mBAAO,CAAC,UAAU,CAAC,IAAI,CAAC,CAAA;IAChC,CAAC;CAAA;AAED,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA"}
|
|
@@ -3,4 +3,4 @@
|
|
|
3
3
|
* @param startDir The directory to start the search from. Defaults to process.cwd().
|
|
4
4
|
* @returns The absolute path to the file if found, or null if not found.
|
|
5
5
|
*/
|
|
6
|
-
export declare function findGlotstackConfig(startDir?: string):
|
|
6
|
+
export declare function findGlotstackConfig(startDir?: string): Promise<object | null>;
|
package/dist/util/findConfig.js
CHANGED
|
@@ -22,29 +22,56 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
22
22
|
__setModuleDefault(result, mod);
|
|
23
23
|
return result;
|
|
24
24
|
};
|
|
25
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
26
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
27
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
28
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
29
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
30
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
31
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
32
|
+
});
|
|
33
|
+
};
|
|
25
34
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
35
|
exports.findGlotstackConfig = void 0;
|
|
27
|
-
const
|
|
36
|
+
const fs_1 = require("fs");
|
|
37
|
+
const promises_1 = require("fs/promises");
|
|
28
38
|
const path = __importStar(require("path"));
|
|
29
39
|
/**
|
|
30
40
|
* Recursively looks for `.glotstack.json` from the current directory up to the root.
|
|
31
41
|
* @param startDir The directory to start the search from. Defaults to process.cwd().
|
|
32
42
|
* @returns The absolute path to the file if found, or null if not found.
|
|
33
43
|
*/
|
|
34
|
-
function findGlotstackConfig(
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
44
|
+
function findGlotstackConfig() {
|
|
45
|
+
return __awaiter(this, arguments, void 0, function* (startDir = process.cwd()) {
|
|
46
|
+
let currentDir = path.resolve(startDir);
|
|
47
|
+
let configPath = null;
|
|
48
|
+
while (true) {
|
|
49
|
+
const candidate = path.join(currentDir, '.glotstack.json');
|
|
50
|
+
if ((0, fs_1.existsSync)(candidate)) {
|
|
51
|
+
configPath = candidate;
|
|
52
|
+
}
|
|
53
|
+
const parentDir = path.dirname(currentDir);
|
|
54
|
+
if (parentDir === currentDir) {
|
|
55
|
+
break; // Reached root
|
|
56
|
+
}
|
|
57
|
+
currentDir = parentDir;
|
|
40
58
|
}
|
|
41
|
-
|
|
42
|
-
if (
|
|
43
|
-
|
|
59
|
+
let config = {};
|
|
60
|
+
if (configPath != null) {
|
|
61
|
+
console.info('Loading config file at ', configPath);
|
|
62
|
+
try {
|
|
63
|
+
const text = yield (0, promises_1.readFile)(configPath, 'utf-8');
|
|
64
|
+
config = JSON.parse(text);
|
|
65
|
+
console.info('Loaded config file', config);
|
|
66
|
+
return config;
|
|
67
|
+
}
|
|
68
|
+
catch (err) {
|
|
69
|
+
console.warn('Could not load config', configPath);
|
|
70
|
+
}
|
|
44
71
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
72
|
+
console.warn('Could not find any .glotstack.json config files');
|
|
73
|
+
return null;
|
|
74
|
+
});
|
|
48
75
|
}
|
|
49
76
|
exports.findGlotstackConfig = findGlotstackConfig;
|
|
50
77
|
//# sourceMappingURL=findConfig.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"findConfig.js","sourceRoot":"","sources":["../../src/util/findConfig.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"findConfig.js","sourceRoot":"","sources":["../../src/util/findConfig.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,2BAA+B;AAC/B,0CAAsC;AACtC,2CAA4B;AAE5B;;;;GAIG;AACH,SAAsB,mBAAmB;yDAAC,WAAmB,OAAO,CAAC,GAAG,EAAE;QACxE,IAAI,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;QACvC,IAAI,UAAU,GAAG,IAAI,CAAA;QAErB,OAAO,IAAI,EAAE,CAAC;YACZ,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,iBAAiB,CAAC,CAAA;YAC1D,IAAI,IAAA,eAAU,EAAC,SAAS,CAAC,EAAE,CAAC;gBAC1B,UAAU,GAAG,SAAS,CAAA;YACxB,CAAC;YAED,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAA;YAC1C,IAAI,SAAS,KAAK,UAAU,EAAE,CAAC;gBAC7B,MAAK,CAAC,eAAe;YACvB,CAAC;YACD,UAAU,GAAG,SAAS,CAAA;QACxB,CAAC;QAED,IAAI,MAAM,GAAG,EAAE,CAAA;QAEf,IAAI,UAAU,IAAI,IAAI,EAAE,CAAC;YACvB,OAAO,CAAC,IAAI,CAAC,yBAAyB,EAAE,UAAU,CAAC,CAAA;YACnD,IAAI,CAAC;gBACH,MAAM,IAAI,GAAG,MAAM,IAAA,mBAAQ,EAAC,UAAU,EAAE,OAAO,CAAC,CAAA;gBAChD,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;gBACzB,OAAO,CAAC,IAAI,CAAC,oBAAoB,EAAE,MAAM,CAAC,CAAA;gBAC1C,OAAO,MAAM,CAAA;YACf,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,OAAO,CAAC,IAAI,CAAC,uBAAuB,EAAE,UAAU,CAAC,CAAA;YACnD,CAAC;QACH,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,iDAAiD,CAAC,CAAA;QAC/D,OAAO,IAAI,CAAA;IACb,CAAC;CAAA;AAhCD,kDAgCC"}
|
package/package.json
CHANGED
package/src/cli.tsx
CHANGED
|
@@ -16,7 +16,7 @@ import { readdir, readFile, writeFile } from 'node:fs/promises'
|
|
|
16
16
|
import { resolve } from 'node:path'
|
|
17
17
|
|
|
18
18
|
const fetchGlotstack = async function <T>(url: string, apiKey: string, body: Record<string, any> | FormData, overrideHeaders?: Record<string, any>): Promise<T> {
|
|
19
|
-
console.info(`
|
|
19
|
+
console.info(`Fetching glotstack.ai: ${url}`)
|
|
20
20
|
|
|
21
21
|
const headers: Record<string, any> = {
|
|
22
22
|
'authorization': `Bearer ${apiKey}`,
|
|
@@ -64,21 +64,15 @@ function unflatten(flat: Record<string, any>): Record<string, any> {
|
|
|
64
64
|
return result
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
+
const DEFAULT_OPTIONS: Record<string, string> = {
|
|
68
|
+
sourcePath: '.',
|
|
69
|
+
sourceLocale: 'en-US',
|
|
70
|
+
apiOrigin: 'https://glotstack.ai'
|
|
71
|
+
}
|
|
72
|
+
|
|
67
73
|
async function resolveConfigAndOptions(options: Record<string, any>) {
|
|
68
|
-
|
|
69
|
-
const
|
|
70
|
-
let config = {}
|
|
71
|
-
|
|
72
|
-
if (configPath != null) {
|
|
73
|
-
console.info('Loading config file at ', configPath)
|
|
74
|
-
try {
|
|
75
|
-
const text = await fs.readFile(configPath, 'utf-8')
|
|
76
|
-
config = JSON.parse(text)
|
|
77
|
-
console.info('Loaded config file', config)
|
|
78
|
-
} catch (err) {
|
|
79
|
-
//pass
|
|
80
|
-
}
|
|
81
|
-
}
|
|
74
|
+
|
|
75
|
+
const config = await findGlotstackConfig(cwd()) ?? {}
|
|
82
76
|
|
|
83
77
|
if ('outputLocales' in options) {
|
|
84
78
|
if ((options.outputLocales as string[]).includes('en-US')) {
|
|
@@ -87,7 +81,14 @@ async function resolveConfigAndOptions(options: Record<string, any>) {
|
|
|
87
81
|
}
|
|
88
82
|
}
|
|
89
83
|
|
|
90
|
-
|
|
84
|
+
const resolved = merge({}, DEFAULT_OPTIONS, config, options)
|
|
85
|
+
|
|
86
|
+
// special case to match source
|
|
87
|
+
if (resolved.outputDir == null) {
|
|
88
|
+
resolved.outputDir = resolved.sourcePath
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return resolved
|
|
91
92
|
}
|
|
92
93
|
|
|
93
94
|
|
|
@@ -95,11 +96,14 @@ async function run(args: string[]) {
|
|
|
95
96
|
program
|
|
96
97
|
.command('extract-translations')
|
|
97
98
|
.description('extract translations from all compatible source files.')
|
|
98
|
-
.option('--source-path [path]',
|
|
99
|
-
.option('--
|
|
99
|
+
.option('--source-path [path]', `path directory containing [locale].json files (default=${DEFAULT_OPTIONS['sourcePath']})`)
|
|
100
|
+
.option('--source-locale [locale]', `the locale you provide "context" in, your primary locale (default=${DEFAULT_OPTIONS['sourceLocale']})`)
|
|
101
|
+
.option('--api-origin [url]', `glotstack api origin (default=${DEFAULT_OPTIONS['apiOrigin']})`)
|
|
102
|
+
.option('--output-dir [path]', 'path to output directory (default=<source-path>')
|
|
100
103
|
.option('--api-key [key]', 'api key for glotstack.ai')
|
|
101
|
-
.option('--yes', 'skip confirm checks'
|
|
102
|
-
.action(async (
|
|
104
|
+
.option('--yes', 'skip confirm checks')
|
|
105
|
+
.action(async (inputOptions: Record<string, any>) => {
|
|
106
|
+
const options = await resolveConfigAndOptions(inputOptions)
|
|
103
107
|
if (!options.apiOrigin) {
|
|
104
108
|
throw new Error('apiOrigin must be specified')
|
|
105
109
|
}
|
|
@@ -128,7 +132,7 @@ async function run(args: string[]) {
|
|
|
128
132
|
|
|
129
133
|
const send = await askToSend()
|
|
130
134
|
if (send) {
|
|
131
|
-
console.info('Sending files to
|
|
135
|
+
console.info('Sending files to generate new source and extracted strings')
|
|
132
136
|
const url = `${options.apiOrigin}/uploads/translations/extract`
|
|
133
137
|
const form = new FormData()
|
|
134
138
|
|
|
@@ -138,7 +142,7 @@ async function run(args: string[]) {
|
|
|
138
142
|
console.debug(`Uploading file: ${filePath}`)
|
|
139
143
|
}
|
|
140
144
|
const data = await fetchGlotstack<{ translations: { name: string; modified_source: { url: string } }[] }>(url, options.apiKey, form)
|
|
141
|
-
data.translations.map(elem => console.info(
|
|
145
|
+
data.translations.map(elem => console.info(`Source and translations available for: ${elem.name}:\n ${elem.modified_source.url}\n\n`))
|
|
142
146
|
rl.close()
|
|
143
147
|
} else {
|
|
144
148
|
rl.close()
|
|
@@ -148,28 +152,15 @@ async function run(args: string[]) {
|
|
|
148
152
|
program
|
|
149
153
|
.command('get-translations')
|
|
150
154
|
.description('fetch translations for all [output-locals...]. Use .glotstack.json for repeatable results.')
|
|
151
|
-
.option('--source-path [path]',
|
|
152
|
-
.option('--
|
|
153
|
-
.option('--
|
|
155
|
+
.option('--source-path [path]', `path directory containing [locale].json files (default=${DEFAULT_OPTIONS['sourcePath']})`)
|
|
156
|
+
.option('--source-locale [locale]', `the locale you provide "context" in, your primary locale (default=${DEFAULT_OPTIONS['sourceLocale']})`)
|
|
157
|
+
.option('--api-origin [url]', `glotstack api origin (default=${DEFAULT_OPTIONS['apiOrigin']})`)
|
|
158
|
+
.option('--output-dir [path]', 'path to output directory (default=<source-path>')
|
|
154
159
|
.option('--api-key [key]', 'api key for glotstack.ai')
|
|
155
160
|
.option('--project-id [id]', '(optional) specific project to use')
|
|
156
161
|
.argument('[output-locales...]', 'locales to get translations for')
|
|
157
162
|
.action(async (outputLocales: string[], options: Record<string, any>, command: Command) => {
|
|
158
|
-
const
|
|
159
|
-
let config = {}
|
|
160
|
-
|
|
161
|
-
if (configPath != null) {
|
|
162
|
-
console.info('Loading config file at ', configPath)
|
|
163
|
-
try {
|
|
164
|
-
const text = await fs.readFile(configPath, 'utf-8')
|
|
165
|
-
config = JSON.parse(text)
|
|
166
|
-
console.info('Loaded config file', config)
|
|
167
|
-
} catch (err) {
|
|
168
|
-
//pass
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
const resolved = await resolveConfigAndOptions({...options, outputLocales: outputLocales})
|
|
163
|
+
const resolved = await resolveConfigAndOptions({ ...options, outputLocales: outputLocales })
|
|
173
164
|
if (!resolved.sourcePath) {
|
|
174
165
|
throw new Error('sourcePath must be specified')
|
|
175
166
|
}
|
|
@@ -180,7 +171,7 @@ async function run(args: string[]) {
|
|
|
180
171
|
throw new Error('outputDir must be specified')
|
|
181
172
|
}
|
|
182
173
|
|
|
183
|
-
const absPath = path.resolve(resolved.sourcePath)
|
|
174
|
+
const absPath = path.resolve(resolved.sourcePath, `${resolved.sourceLocale}.json`)
|
|
184
175
|
const fileContent = await fs.readFile(absPath, 'utf-8')
|
|
185
176
|
|
|
186
177
|
let json = null
|
|
@@ -201,7 +192,7 @@ async function run(args: string[]) {
|
|
|
201
192
|
...{ ... (resolved.projectId != null ? { projectId: resolved.projectId } : {}) },
|
|
202
193
|
}
|
|
203
194
|
|
|
204
|
-
const url = `${
|
|
195
|
+
const url = `${resolved.apiOrigin}/api/translations`
|
|
205
196
|
const data = await fetchGlotstack<{ data: Translations }>(url, resolved.apiKey, body)
|
|
206
197
|
console.info('Received translations:', data)
|
|
207
198
|
Object.entries(data.data).map(([key, val]) => {
|
|
@@ -214,9 +205,10 @@ async function run(args: string[]) {
|
|
|
214
205
|
program
|
|
215
206
|
.command('format-json')
|
|
216
207
|
.description('format files in --source-path [path] to nested (not flat)')
|
|
217
|
-
.option('--source-path [path]',
|
|
218
|
-
.option('--yes', 'skip confirm checks'
|
|
219
|
-
.action(async (
|
|
208
|
+
.option('--source-path [path]', `path directory containing [locale].json files (default=${DEFAULT_OPTIONS['sourcePath']})`)
|
|
209
|
+
.option('--yes', 'skip confirm checks')
|
|
210
|
+
.action(async (inputOptions: Record<string, any>) => {
|
|
211
|
+
const options = await resolveConfigAndOptions(inputOptions)
|
|
220
212
|
|
|
221
213
|
if (!options.sourcePath) {
|
|
222
214
|
throw new Error('sourcePath must be specified')
|
package/src/util/findConfig.ts
CHANGED
|
@@ -1,26 +1,42 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
1
|
+
import { existsSync } from 'fs'
|
|
2
|
+
import { readFile } from 'fs/promises'
|
|
3
|
+
import * as path from 'path'
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Recursively looks for `.glotstack.json` from the current directory up to the root.
|
|
6
7
|
* @param startDir The directory to start the search from. Defaults to process.cwd().
|
|
7
8
|
* @returns The absolute path to the file if found, or null if not found.
|
|
8
9
|
*/
|
|
9
|
-
export function findGlotstackConfig(startDir: string = process.cwd()):
|
|
10
|
-
let currentDir = path.resolve(startDir)
|
|
10
|
+
export async function findGlotstackConfig(startDir: string = process.cwd()): Promise<object | null> {
|
|
11
|
+
let currentDir = path.resolve(startDir)
|
|
12
|
+
let configPath = null
|
|
11
13
|
|
|
12
14
|
while (true) {
|
|
13
|
-
const candidate = path.join(currentDir, '.glotstack.json')
|
|
14
|
-
if (
|
|
15
|
-
|
|
15
|
+
const candidate = path.join(currentDir, '.glotstack.json')
|
|
16
|
+
if (existsSync(candidate)) {
|
|
17
|
+
configPath = candidate
|
|
16
18
|
}
|
|
17
19
|
|
|
18
|
-
const parentDir = path.dirname(currentDir)
|
|
20
|
+
const parentDir = path.dirname(currentDir)
|
|
19
21
|
if (parentDir === currentDir) {
|
|
20
|
-
break
|
|
22
|
+
break // Reached root
|
|
21
23
|
}
|
|
22
|
-
currentDir = parentDir
|
|
24
|
+
currentDir = parentDir
|
|
23
25
|
}
|
|
24
26
|
|
|
25
|
-
|
|
27
|
+
let config = {}
|
|
28
|
+
|
|
29
|
+
if (configPath != null) {
|
|
30
|
+
console.info('Loading config file at ', configPath)
|
|
31
|
+
try {
|
|
32
|
+
const text = await readFile(configPath, 'utf-8')
|
|
33
|
+
config = JSON.parse(text)
|
|
34
|
+
console.info('Loaded config file', config)
|
|
35
|
+
return config
|
|
36
|
+
} catch (err) {
|
|
37
|
+
console.warn('Could not load config', configPath)
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
console.warn('Could not find any .glotstack.json config files')
|
|
41
|
+
return null
|
|
26
42
|
}
|