locize-cli 11.0.0 → 12.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/LICENSE +1 -1
- package/README.md +1 -0
- package/dist/cjs/add.js +90 -0
- package/{bin/locize → dist/cjs/cli.js} +390 -670
- package/dist/cjs/combineSubkeyPreprocessor.js +155 -0
- package/dist/cjs/convertToDesiredFormat.js +205 -0
- package/dist/cjs/convertToFlatFormat.js +231 -0
- package/dist/cjs/copyVersion.js +60 -0
- package/dist/cjs/createBranch.js +59 -0
- package/dist/cjs/deleteBranch.js +89 -0
- package/dist/cjs/deleteNamespace.js +37 -0
- package/dist/cjs/download.js +376 -0
- package/dist/cjs/filterNamespaces.js +13 -0
- package/dist/cjs/format.js +156 -0
- package/dist/cjs/formats.js +33 -0
- package/dist/cjs/get.js +66 -0
- package/dist/cjs/getBranches.js +37 -0
- package/dist/cjs/getJob.js +37 -0
- package/dist/cjs/getProjectStats.js +37 -0
- package/dist/cjs/getRemoteLanguages.js +38 -0
- package/dist/cjs/getRemoteNamespace.js +125 -0
- package/dist/cjs/index.js +37 -0
- package/dist/cjs/isValidUuid.js +6 -0
- package/dist/cjs/lngs.js +215 -0
- package/dist/cjs/mapLimit.js +22 -0
- package/dist/cjs/mergeBranch.js +80 -0
- package/dist/cjs/migrate.js +239 -0
- package/dist/cjs/missing.js +162 -0
- package/dist/cjs/package.json +5 -0
- package/{parseLocalLanguage.js → dist/cjs/parseLocalLanguage.js} +135 -142
- package/dist/cjs/parseLocalLanguages.js +18 -0
- package/dist/cjs/parseLocalReference.js +11 -0
- package/dist/cjs/publishVersion.js +42 -0
- package/dist/cjs/removeUndefinedFromArrays.js +19 -0
- package/dist/cjs/removeVersion.js +42 -0
- package/dist/cjs/request.js +66 -0
- package/dist/cjs/shouldUnflatten.js +21 -0
- package/dist/cjs/sortFlatResources.js +13 -0
- package/dist/cjs/sync.js +772 -0
- package/dist/cjs/unflatten.js +81 -0
- package/dist/esm/add.js +88 -0
- package/dist/esm/cli.js +1020 -0
- package/{combineSubkeyPreprocessor.js → dist/esm/combineSubkeyPreprocessor.js} +70 -73
- package/dist/esm/convertToDesiredFormat.js +203 -0
- package/dist/esm/convertToFlatFormat.js +229 -0
- package/dist/esm/copyVersion.js +58 -0
- package/dist/esm/createBranch.js +57 -0
- package/dist/esm/deleteBranch.js +87 -0
- package/dist/esm/deleteNamespace.js +35 -0
- package/dist/esm/download.js +374 -0
- package/{filterNamespaces.js → dist/esm/filterNamespaces.js} +4 -4
- package/dist/esm/format.js +154 -0
- package/{formats.js → dist/esm/formats.js} +7 -11
- package/dist/esm/get.js +64 -0
- package/dist/esm/getBranches.js +35 -0
- package/dist/esm/getJob.js +35 -0
- package/dist/esm/getProjectStats.js +35 -0
- package/dist/esm/getRemoteLanguages.js +36 -0
- package/dist/esm/getRemoteNamespace.js +123 -0
- package/dist/esm/index.js +16 -0
- package/dist/esm/isValidUuid.js +4 -0
- package/dist/esm/lngs.js +213 -0
- package/dist/esm/mapLimit.js +20 -0
- package/dist/esm/mergeBranch.js +78 -0
- package/dist/esm/migrate.js +237 -0
- package/dist/esm/missing.js +160 -0
- package/dist/esm/parseLocalLanguage.js +194 -0
- package/dist/esm/parseLocalLanguages.js +16 -0
- package/dist/esm/parseLocalReference.js +9 -0
- package/dist/esm/publishVersion.js +40 -0
- package/{removeUndefinedFromArrays.js → dist/esm/removeUndefinedFromArrays.js} +5 -5
- package/dist/esm/removeVersion.js +40 -0
- package/dist/esm/request.js +64 -0
- package/{shouldUnflatten.js → dist/esm/shouldUnflatten.js} +7 -7
- package/dist/esm/sortFlatResources.js +11 -0
- package/dist/esm/sync.js +770 -0
- package/{unflatten.js → dist/esm/unflatten.js} +36 -34
- package/package.json +39 -18
- package/rollup.config.js +57 -0
- package/add.js +0 -105
- package/convertToDesiredFormat.js +0 -268
- package/convertToFlatFormat.js +0 -322
- package/copyVersion.js +0 -69
- package/createBranch.js +0 -61
- package/deleteBranch.js +0 -97
- package/deleteNamespace.js +0 -39
- package/download.js +0 -516
- package/format.js +0 -206
- package/get.js +0 -81
- package/getBranches.js +0 -40
- package/getJob.js +0 -40
- package/getProjectStats.js +0 -40
- package/getRemoteLanguages.js +0 -40
- package/getRemoteNamespace.js +0 -122
- package/index.js +0 -9
- package/isValidUuid.js +0 -2
- package/lngs.json +0 -211
- package/mergeBranch.js +0 -102
- package/migrate.js +0 -314
- package/missing.js +0 -169
- package/parseLocalLanguages.js +0 -22
- package/parseLocalReference.js +0 -10
- package/publishVersion.js +0 -64
- package/removeVersion.js +0 -64
- package/request.js +0 -64
- package/sortFlatResources.js +0 -9
- package/sync.js +0 -786
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var colors = require('colors');
|
|
4
|
+
var fs = require('node:fs');
|
|
5
|
+
var path = require('node:path');
|
|
6
|
+
var diff = require('diff');
|
|
7
|
+
var convertToFlatFormat = require('./convertToFlatFormat.js');
|
|
8
|
+
var convertToDesiredFormat = require('./convertToDesiredFormat.js');
|
|
9
|
+
var sortFlatResources = require('./sortFlatResources.js');
|
|
10
|
+
var formats = require('./formats.js');
|
|
11
|
+
|
|
12
|
+
const fileExtensionsMap = formats.fileExtensionsMap;
|
|
13
|
+
const acceptedFileExtensions = formats.acceptedFileExtensions;
|
|
14
|
+
const reversedFileExtensionsMap = formats.reversedFileExtensionsMap;
|
|
15
|
+
|
|
16
|
+
const getFiles = (srcpath) => {
|
|
17
|
+
let files = [];
|
|
18
|
+
fs.readdirSync(srcpath).forEach((file) => {
|
|
19
|
+
if (fs.statSync(path.join(srcpath, file)).isDirectory()) {
|
|
20
|
+
files = files.concat(getFiles(path.join(srcpath, file)));
|
|
21
|
+
} else if (acceptedFileExtensions.indexOf(path.extname(file)) > -1) {
|
|
22
|
+
files.push(path.join(srcpath, file));
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
return files
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
async function readLocalFile (opt, fPath) {
|
|
29
|
+
const fExt = path.extname(fPath);
|
|
30
|
+
const namespace = path.basename(fPath, fExt);
|
|
31
|
+
const splitted = fPath.split(path.sep);
|
|
32
|
+
const lng = splitted[splitted.length - 2];
|
|
33
|
+
const data = await fs.promises.readFile(fPath);
|
|
34
|
+
const stat = await fs.promises.stat(fPath);
|
|
35
|
+
return {
|
|
36
|
+
namespace,
|
|
37
|
+
path: fPath,
|
|
38
|
+
extension: fExt,
|
|
39
|
+
original: data.toString(),
|
|
40
|
+
language: lng,
|
|
41
|
+
mtime: stat.mtime
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async function readLocalFiles (opt, filePaths) {
|
|
46
|
+
return await Promise.all(filePaths.map(f => readLocalFile(opt, f)))
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async function convertAllFilesToFlatFormat (opt, files) {
|
|
50
|
+
return await Promise.all(files.map(async file => {
|
|
51
|
+
if (fileExtensionsMap[file.extension].indexOf(opt.format) < 0) {
|
|
52
|
+
throw new Error(`Format mismatch! Found ${fileExtensionsMap[file.extension][0]} but requested ${opt.format}!`)
|
|
53
|
+
}
|
|
54
|
+
let content;
|
|
55
|
+
try {
|
|
56
|
+
content = await convertToFlatFormat(opt, file.original);
|
|
57
|
+
} catch (err) {
|
|
58
|
+
err.message = 'Invalid content for "' + opt.format + '" format!\n' + (err.message || '') + '\n' + file.path;
|
|
59
|
+
throw err
|
|
60
|
+
}
|
|
61
|
+
file.content = sortFlatResources(content);
|
|
62
|
+
return file
|
|
63
|
+
}))
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async function convertAllFilesToDesiredFormat (opt, files) {
|
|
67
|
+
return await Promise.all(files.map(async file => {
|
|
68
|
+
let res;
|
|
69
|
+
try {
|
|
70
|
+
res = await convertToDesiredFormat(opt, file.namespace, file.language, file.content, file.mtime);
|
|
71
|
+
} catch (err) {
|
|
72
|
+
err.message = 'Invalid content for "' + opt.format + '" format!\n' + (err.message || '');
|
|
73
|
+
throw err
|
|
74
|
+
}
|
|
75
|
+
res = (opt.format !== 'xlsx' && !res.endsWith('\n')) ? (res + '\n') : res;
|
|
76
|
+
file.converted = res;
|
|
77
|
+
return file
|
|
78
|
+
}))
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async function writeLocalFile (opt, file) {
|
|
82
|
+
if (file.converted === file.original) {
|
|
83
|
+
console.log(colors.grey(`${file.path} unchanged`));
|
|
84
|
+
return false
|
|
85
|
+
}
|
|
86
|
+
const d = diff.diffLines(file.original, file.converted);
|
|
87
|
+
d.forEach((part) => {
|
|
88
|
+
const color = part.added ? 'green' : part.removed ? 'red' : 'grey';
|
|
89
|
+
console.log(part.value[color]);
|
|
90
|
+
});
|
|
91
|
+
console.log(colors.yellow(`reformatting ${file.path}...`));
|
|
92
|
+
if (opt.dry) {
|
|
93
|
+
console.log(colors.yellow(`would have reformatted ${file.path}...`));
|
|
94
|
+
return true
|
|
95
|
+
}
|
|
96
|
+
const fileContent = (opt.format !== 'xlsx' && !file.converted.endsWith('\n')) ? (file.converted + '\n') : file.converted;
|
|
97
|
+
await fs.promises.writeFile(file.path, fileContent);
|
|
98
|
+
return true
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
async function writeLocalFiles (opt, files) {
|
|
102
|
+
return await Promise.all(files.map(f => writeLocalFile(opt, f)))
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
async function processFiles (opt, filePaths) {
|
|
106
|
+
const orgFiles = await readLocalFiles(opt, filePaths);
|
|
107
|
+
if (!opt.format) {
|
|
108
|
+
if (orgFiles.length === 0) {
|
|
109
|
+
throw new Error('Please provide a format!')
|
|
110
|
+
}
|
|
111
|
+
opt.format = fileExtensionsMap[orgFiles[0].extension][0];
|
|
112
|
+
console.log(colors.bgYellow(`No format argument was passed, so guessing "${opt.format}" format.`));
|
|
113
|
+
}
|
|
114
|
+
const files = await convertAllFilesToFlatFormat(opt, orgFiles);
|
|
115
|
+
opt.getNamespace = async (o, lng, ns) => {
|
|
116
|
+
const foundOrgFile = orgFiles.find((f) => f.namespace === ns && f.language === lng);
|
|
117
|
+
if (!foundOrgFile) {
|
|
118
|
+
throw new Error(`No file found for language "${lng}" and namespace "${ns}" locally!`)
|
|
119
|
+
}
|
|
120
|
+
return { content: foundOrgFile.content, mtime: foundOrgFile.mtime }
|
|
121
|
+
};
|
|
122
|
+
files.forEach((f) => {
|
|
123
|
+
if (f.content) {
|
|
124
|
+
Object.keys(f.content).forEach((k) => {
|
|
125
|
+
if (f.content[k] && typeof f.content[k] === 'object' && f.content[k].value !== undefined) {
|
|
126
|
+
f.content[k] = f.content[k].value;
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
const convertedFiles = await convertAllFilesToDesiredFormat(opt, files);
|
|
132
|
+
return await writeLocalFiles(opt, convertedFiles)
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
async function format (opt) {
|
|
136
|
+
if (opt.format && !reversedFileExtensionsMap[opt.format]) {
|
|
137
|
+
throw new Error(`${opt.format} is not a valid format!`)
|
|
138
|
+
}
|
|
139
|
+
const stat = await fs.promises.lstat(opt.fileOrDirectory);
|
|
140
|
+
const isDirectory = stat.isDirectory();
|
|
141
|
+
let filePaths = [];
|
|
142
|
+
if (isDirectory) {
|
|
143
|
+
try {
|
|
144
|
+
filePaths = getFiles(opt.fileOrDirectory);
|
|
145
|
+
} catch (err) {}
|
|
146
|
+
} else {
|
|
147
|
+
filePaths = [opt.fileOrDirectory];
|
|
148
|
+
}
|
|
149
|
+
const writeResults = await processFiles(opt, filePaths);
|
|
150
|
+
console.log(colors.green('FINISHED'));
|
|
151
|
+
if (opt.dry && writeResults.find((wr) => !!wr)) {
|
|
152
|
+
process.exit(1);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
module.exports = format;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fileExtensionsMap = {
|
|
4
|
+
'.json': ['json', 'nested', 'flat'],
|
|
5
|
+
'.po': ['po', 'gettext', 'po_i18next', 'gettext_i18next'],
|
|
6
|
+
'.xml': ['android'],
|
|
7
|
+
'.strings': ['strings'],
|
|
8
|
+
'.csv': ['csv'],
|
|
9
|
+
'.resx': ['resx'],
|
|
10
|
+
'.yaml': ['yaml', 'yaml-rails', 'yaml-rails-ns', 'yaml-nested'],
|
|
11
|
+
'.yml': ['yml', 'yml-rails', 'yml-rails-ns', 'yml-nested'],
|
|
12
|
+
'.xlsx': ['xlsx'],
|
|
13
|
+
'.xliff': ['xliff2', 'xliff12'],
|
|
14
|
+
'.xlf': ['xlf2', 'xlf12'],
|
|
15
|
+
'.ftl': ['fluent'],
|
|
16
|
+
'.tmx': ['tmx'],
|
|
17
|
+
'.php': ['laravel'],
|
|
18
|
+
'.properties': ['properties'],
|
|
19
|
+
'.xcstrings': ['xcstrings']
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const acceptedFileExtensions = Object.keys(fileExtensionsMap);
|
|
23
|
+
|
|
24
|
+
const reversedFileExtensionsMap = {};
|
|
25
|
+
acceptedFileExtensions.forEach((ext) => {
|
|
26
|
+
fileExtensionsMap[ext].forEach((format) => {
|
|
27
|
+
reversedFileExtensionsMap[format] = ext;
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
exports.acceptedFileExtensions = acceptedFileExtensions;
|
|
32
|
+
exports.fileExtensionsMap = fileExtensionsMap;
|
|
33
|
+
exports.reversedFileExtensionsMap = reversedFileExtensionsMap;
|
package/dist/cjs/get.js
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var colors = require('colors');
|
|
4
|
+
var request = require('./request.js');
|
|
5
|
+
var flatten = require('flat');
|
|
6
|
+
|
|
7
|
+
const get = async (opt) => {
|
|
8
|
+
const url = `${opt.apiEndpoint}/{{projectId}}/{{version}}/{{lng}}/{{ns}}`
|
|
9
|
+
.replace('{{projectId}}', opt.projectId)
|
|
10
|
+
.replace('{{ver}}', opt.version)
|
|
11
|
+
.replace('{{version}}', opt.version)
|
|
12
|
+
.replace('{{language}}', opt.language)
|
|
13
|
+
.replace('{{lng}}', opt.language)
|
|
14
|
+
.replace('{{ns}}', opt.namespace)
|
|
15
|
+
.replace('{{namespace}}', opt.namespace);
|
|
16
|
+
|
|
17
|
+
if (opt.key && opt.key.indexOf(',') > 0 && opt.key.indexOf(' ') < 0) {
|
|
18
|
+
opt.keys = opt.key.split(',');
|
|
19
|
+
delete opt.key;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const { res, obj, err } = await request(`${url}${opt.cdnType === 'standard' ? '?cache=no' : ''}`, {
|
|
23
|
+
method: 'get'
|
|
24
|
+
});
|
|
25
|
+
if (err) {
|
|
26
|
+
console.log(colors.red(`get failed for ${opt.key || (opt.keys && opt.keys.join(', '))} from ${opt.version}/${opt.language}/${opt.namespace}...`));
|
|
27
|
+
throw err
|
|
28
|
+
}
|
|
29
|
+
const ignore404 = res.status === 404 && opt.cdnType === 'standard';
|
|
30
|
+
if (res.status >= 300 && !ignore404) {
|
|
31
|
+
console.error(colors.red(res.statusText + ' (' + res.status + ')'));
|
|
32
|
+
throw new Error(res.statusText + ' (' + res.status + ')')
|
|
33
|
+
}
|
|
34
|
+
const flatObj = flatten(ignore404 ? {} : obj);
|
|
35
|
+
if (opt.key) {
|
|
36
|
+
if (!flatObj[opt.key]) {
|
|
37
|
+
console.error(colors.red(`${opt.key} not found in ${opt.version}/${opt.language}/${opt.namespace} => ${JSON.stringify(obj, null, 2)}`));
|
|
38
|
+
throw new Error(`${opt.key} not found in ${opt.version}/${opt.language}/${opt.namespace} => ${JSON.stringify(obj, null, 2)}`)
|
|
39
|
+
}
|
|
40
|
+
console.log(flatObj[opt.key]);
|
|
41
|
+
}
|
|
42
|
+
if (opt.keys) {
|
|
43
|
+
const ret = {};
|
|
44
|
+
const retWitAllKeys = {};
|
|
45
|
+
opt.keys.forEach((k) => {
|
|
46
|
+
if (flatObj[k] !== undefined) {
|
|
47
|
+
ret[k] = flatObj[k];
|
|
48
|
+
}
|
|
49
|
+
retWitAllKeys[k] = flatObj[k];
|
|
50
|
+
});
|
|
51
|
+
const retKeys = Object.keys(ret);
|
|
52
|
+
if (retKeys.length === 0) {
|
|
53
|
+
console.error(colors.red(`${opt.keys.join(', ')} not found in ${opt.version}/${opt.language}/${opt.namespace} => ${JSON.stringify(obj, null, 2)}`));
|
|
54
|
+
throw new Error(`${opt.keys.join(', ')} not found in ${opt.version}/${opt.language}/${opt.namespace} => ${JSON.stringify(obj, null, 2)}`)
|
|
55
|
+
}
|
|
56
|
+
if (console.table) {
|
|
57
|
+
console.table(retWitAllKeys);
|
|
58
|
+
} else {
|
|
59
|
+
opt.keys.forEach((k) => {
|
|
60
|
+
console.log(`${k}\t=>\t${ret[k] || ''}`);
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
module.exports = get;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var colors = require('colors');
|
|
4
|
+
var request = require('./request.js');
|
|
5
|
+
|
|
6
|
+
const getBranches = async (opt) => {
|
|
7
|
+
const { res, obj, err } = await request(opt.apiEndpoint + '/branches/' + opt.projectId, {
|
|
8
|
+
method: 'get',
|
|
9
|
+
headers: {
|
|
10
|
+
Authorization: opt.apiKey
|
|
11
|
+
}
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
if (err || (obj && (obj.errorMessage || obj.message))) {
|
|
15
|
+
console.log(colors.red('getting branches failed...'));
|
|
16
|
+
if (err) {
|
|
17
|
+
console.error(colors.red(err.message));
|
|
18
|
+
throw err
|
|
19
|
+
}
|
|
20
|
+
if (obj && (obj.errorMessage || obj.message)) {
|
|
21
|
+
console.error(colors.red((obj.errorMessage || obj.message)));
|
|
22
|
+
throw new Error((obj.errorMessage || obj.message))
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
if (res.status === 404) {
|
|
26
|
+
console.error(colors.yellow(res.statusText + ' (' + res.status + ')'));
|
|
27
|
+
return null
|
|
28
|
+
}
|
|
29
|
+
if (res.status >= 300) {
|
|
30
|
+
console.error(colors.red(res.statusText + ' (' + res.status + ')'));
|
|
31
|
+
throw new Error(res.statusText + ' (' + res.status + ')')
|
|
32
|
+
}
|
|
33
|
+
console.log(colors.green('getting branches successful'));
|
|
34
|
+
return obj
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
module.exports = getBranches;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var colors = require('colors');
|
|
4
|
+
var request = require('./request.js');
|
|
5
|
+
|
|
6
|
+
const getJob = async (opt, jobId) => {
|
|
7
|
+
const { res, obj, err } = await request(opt.apiEndpoint + '/jobs/' + opt.projectId + '/' + jobId, {
|
|
8
|
+
method: 'get',
|
|
9
|
+
headers: {
|
|
10
|
+
Authorization: opt.apiKey
|
|
11
|
+
}
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
if (err || (obj && (obj.errorMessage || obj.message))) {
|
|
15
|
+
console.log(colors.red('getting job failed...'));
|
|
16
|
+
if (err) {
|
|
17
|
+
console.error(colors.red(err.message));
|
|
18
|
+
throw err
|
|
19
|
+
}
|
|
20
|
+
if (obj && (obj.errorMessage || obj.message)) {
|
|
21
|
+
console.error(colors.red((obj.errorMessage || obj.message)));
|
|
22
|
+
throw new Error((obj.errorMessage || obj.message))
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
if (res.status === 404) {
|
|
26
|
+
console.error(colors.yellow(res.statusText + ' (' + res.status + ')'));
|
|
27
|
+
return null
|
|
28
|
+
}
|
|
29
|
+
if (res.status >= 300) {
|
|
30
|
+
console.error(colors.red(res.statusText + ' (' + res.status + ')'));
|
|
31
|
+
throw new Error(res.statusText + ' (' + res.status + ')')
|
|
32
|
+
}
|
|
33
|
+
console.log(colors.green('getting job successful'));
|
|
34
|
+
return obj
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
module.exports = getJob;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var colors = require('colors');
|
|
4
|
+
var request = require('./request.js');
|
|
5
|
+
|
|
6
|
+
const getProjectStats = async (opt) => {
|
|
7
|
+
const { res, obj, err } = await request(opt.apiEndpoint + '/stats/project/' + opt.projectId, {
|
|
8
|
+
method: 'get',
|
|
9
|
+
headers: {
|
|
10
|
+
Authorization: opt.apiKey
|
|
11
|
+
}
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
if (err || (obj && (obj.errorMessage || obj.message))) {
|
|
15
|
+
console.log(colors.red('getting job failed...'));
|
|
16
|
+
if (err) {
|
|
17
|
+
console.error(colors.red(err.message));
|
|
18
|
+
throw err
|
|
19
|
+
}
|
|
20
|
+
if (obj && (obj.errorMessage || obj.message)) {
|
|
21
|
+
console.error(colors.red((obj.errorMessage || obj.message)));
|
|
22
|
+
throw new Error((obj.errorMessage || obj.message))
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
if (res.status === 404) {
|
|
26
|
+
console.error(colors.yellow(res.statusText + ' (' + res.status + ')'));
|
|
27
|
+
return null
|
|
28
|
+
}
|
|
29
|
+
if (res.status >= 300) {
|
|
30
|
+
console.error(colors.red(res.statusText + ' (' + res.status + ')'));
|
|
31
|
+
throw new Error(res.statusText + ' (' + res.status + ')')
|
|
32
|
+
}
|
|
33
|
+
console.log(colors.green('getting project stats successful'));
|
|
34
|
+
return obj
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
module.exports = getProjectStats;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var request = require('./request.js');
|
|
4
|
+
|
|
5
|
+
const getRemoteLanguages = async (opt) => {
|
|
6
|
+
const { res, obj } = await request(opt.apiEndpoint + '/languages/' + opt.projectId + '?ts=' + Date.now() + (opt.cdnType === 'standard' ? '&cache=no' : ''), {
|
|
7
|
+
method: 'get'
|
|
8
|
+
});
|
|
9
|
+
if ((obj && (obj.errorMessage || obj.message))) {
|
|
10
|
+
if (res && res.statusText && res.status) {
|
|
11
|
+
throw new Error(res.statusText + ' (' + res.status + ') | ' + (obj.errorMessage || obj.message))
|
|
12
|
+
}
|
|
13
|
+
throw new Error((obj.errorMessage || obj.message))
|
|
14
|
+
}
|
|
15
|
+
if (res.status >= 300) throw new Error(res.statusText + ' (' + res.status + ')')
|
|
16
|
+
|
|
17
|
+
if (Object.keys(obj).length === 0) {
|
|
18
|
+
throw new Error('Project with id "' + opt.projectId + '" not found!')
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const lngs = Object.keys(obj);
|
|
22
|
+
let foundRefLng = null;
|
|
23
|
+
lngs.forEach((l) => {
|
|
24
|
+
if (obj[l].isReferenceLanguage) foundRefLng = l;
|
|
25
|
+
});
|
|
26
|
+
if (!foundRefLng) {
|
|
27
|
+
throw new Error('Reference language for project with id "' + opt.projectId + '" not found!')
|
|
28
|
+
}
|
|
29
|
+
opt.referenceLanguage = foundRefLng;
|
|
30
|
+
|
|
31
|
+
// reflng first
|
|
32
|
+
lngs.splice(lngs.indexOf(opt.referenceLanguage), 1);
|
|
33
|
+
lngs.unshift(opt.referenceLanguage);
|
|
34
|
+
|
|
35
|
+
return lngs
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
module.exports = getRemoteLanguages;
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var request = require('./request.js');
|
|
4
|
+
var flatten = require('flat');
|
|
5
|
+
var sortFlatResources = require('./sortFlatResources.js');
|
|
6
|
+
|
|
7
|
+
const getRandomDelay = (delayFrom, delayTo) => Math.floor(Math.random() * delayTo) + delayFrom;
|
|
8
|
+
|
|
9
|
+
function onlyKeysFlat (resources, prefix, ret) {
|
|
10
|
+
ret = ret || {};
|
|
11
|
+
if (!resources) return ret
|
|
12
|
+
Object.keys(resources).forEach((k) => {
|
|
13
|
+
if (typeof resources[k] === 'string' || !resources[k] || typeof resources[k].value === 'string') {
|
|
14
|
+
if (prefix) {
|
|
15
|
+
ret[prefix + '.' + k] = resources[k];
|
|
16
|
+
} else {
|
|
17
|
+
ret[k] = resources[k];
|
|
18
|
+
}
|
|
19
|
+
} else {
|
|
20
|
+
onlyKeysFlat(resources[k], prefix ? prefix + '.' + k : k, ret);
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
return ret
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
|
|
27
|
+
|
|
28
|
+
const pullNamespacePaged = async (opt, lng, ns, next = '', retry = 0) => {
|
|
29
|
+
const { res, obj, err } = await request(opt.apiEndpoint + '/pull/' + opt.projectId + '/' + opt.version + '/' + lng + '/' + ns + '?' + 'next=' + next + ((opt.raw || opt.overriddenOnly) ? '&raw=true' : '') + '&ts=' + Date.now(), {
|
|
30
|
+
method: 'get',
|
|
31
|
+
headers: {
|
|
32
|
+
Authorization: opt.apiKey
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
if (err) throw err
|
|
36
|
+
if (res.status >= 300) {
|
|
37
|
+
if (retry < 3 && res.status !== 401) {
|
|
38
|
+
await sleep(getRandomDelay(3000, 10000));
|
|
39
|
+
return await pullNamespacePaged(opt, lng, ns, next, retry + 1)
|
|
40
|
+
}
|
|
41
|
+
if (obj && (obj.errorMessage || obj.message)) {
|
|
42
|
+
if (res.statusText && res.status) {
|
|
43
|
+
throw new Error(res.statusText + ' (' + res.status + ') | ' + (obj.errorMessage || obj.message))
|
|
44
|
+
}
|
|
45
|
+
throw new Error((obj.errorMessage || obj.message))
|
|
46
|
+
}
|
|
47
|
+
throw new Error(res.statusText + ' (' + res.status + ')')
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
let resultObj = obj;
|
|
51
|
+
if (opt.overriddenOnly && obj) {
|
|
52
|
+
const newObj = {};
|
|
53
|
+
Object.keys(obj).forEach((k) => {
|
|
54
|
+
if (obj[k].overrides !== undefined) {
|
|
55
|
+
if (opt.raw) {
|
|
56
|
+
newObj[k] = obj[k];
|
|
57
|
+
} else {
|
|
58
|
+
newObj[k] = obj[k].value;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
resultObj = newObj;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return {
|
|
66
|
+
result: opt.raw ? sortFlatResources(onlyKeysFlat(resultObj)) : sortFlatResources(flatten(resultObj)),
|
|
67
|
+
next: res.headers.get('x-next-page'),
|
|
68
|
+
lastModified: res.headers.get('last-modified') ? new Date(res.headers.get('last-modified')) : undefined
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const pullNamespace = async (opt, lng, ns) => {
|
|
73
|
+
const ret = {};
|
|
74
|
+
let lastModified = new Date(2000, 0, 1);
|
|
75
|
+
let next = '';
|
|
76
|
+
while (true) {
|
|
77
|
+
const info = await pullNamespacePaged(opt, lng, ns, next);
|
|
78
|
+
Object.keys(info.result).forEach((k) => {
|
|
79
|
+
ret[k] = info.result[k];
|
|
80
|
+
});
|
|
81
|
+
if (info.lastModified && info.lastModified.getTime() > (lastModified ? lastModified.getTime() : 0)) {
|
|
82
|
+
lastModified = info.lastModified;
|
|
83
|
+
}
|
|
84
|
+
if (info.next) {
|
|
85
|
+
next = info.next;
|
|
86
|
+
continue
|
|
87
|
+
}
|
|
88
|
+
break
|
|
89
|
+
}
|
|
90
|
+
return { result: ret, lastModified }
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const getRemoteNamespace = async (opt, lng, ns) => {
|
|
94
|
+
if (opt.unpublished) {
|
|
95
|
+
const { result, lastModified } = await pullNamespace(opt, lng, ns);
|
|
96
|
+
return { result, lastModified }
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const { res, obj, err } = await request(opt.apiEndpoint + (opt.isPrivate ? '/private' : '') + '/' + opt.projectId + '/' + opt.version + '/' + lng + '/' + ns + '?ts=' + Date.now() + (opt.cdnType === 'standard' ? '&cache=no' : ''), {
|
|
100
|
+
method: 'get',
|
|
101
|
+
headers: opt.isPrivate
|
|
102
|
+
? {
|
|
103
|
+
Authorization: opt.apiKey
|
|
104
|
+
}
|
|
105
|
+
: undefined
|
|
106
|
+
});
|
|
107
|
+
if (err) throw err
|
|
108
|
+
const ignore404 = res.status === 404 && opt.cdnType === 'standard';
|
|
109
|
+
if (ignore404) return { result: {}, lastModified: undefined }
|
|
110
|
+
if (res.status >= 300) {
|
|
111
|
+
if (obj && (obj.errorMessage || obj.message)) {
|
|
112
|
+
if (res.statusText && res.status) {
|
|
113
|
+
throw new Error(res.statusText + ' (' + res.status + ') | ' + (obj.errorMessage || obj.message))
|
|
114
|
+
}
|
|
115
|
+
throw new Error((obj.errorMessage || obj.message))
|
|
116
|
+
}
|
|
117
|
+
throw new Error(res.statusText + ' (' + res.status + ')')
|
|
118
|
+
}
|
|
119
|
+
return {
|
|
120
|
+
result: sortFlatResources(flatten(obj)),
|
|
121
|
+
lastModified: res.headers.get('last-modified') ? new Date(res.headers.get('last-modified')) : undefined
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
module.exports = getRemoteNamespace;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var add = require('./add.js');
|
|
4
|
+
var get = require('./get.js');
|
|
5
|
+
var download = require('./download.js');
|
|
6
|
+
var migrate = require('./migrate.js');
|
|
7
|
+
var sync = require('./sync.js');
|
|
8
|
+
var publishVersion = require('./publishVersion.js');
|
|
9
|
+
var copyVersion = require('./copyVersion.js');
|
|
10
|
+
var createBranch = require('./createBranch.js');
|
|
11
|
+
var deleteBranch = require('./deleteBranch.js');
|
|
12
|
+
var deleteNamespace = require('./deleteNamespace.js');
|
|
13
|
+
var format = require('./format.js');
|
|
14
|
+
var getBranches = require('./getBranches.js');
|
|
15
|
+
var getJob = require('./getJob.js');
|
|
16
|
+
var mergeBranch = require('./mergeBranch.js');
|
|
17
|
+
var missing = require('./missing.js');
|
|
18
|
+
var removeVersion = require('./removeVersion.js');
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
exports.add = add;
|
|
23
|
+
exports.get = get;
|
|
24
|
+
exports.download = download;
|
|
25
|
+
exports.migrate = migrate;
|
|
26
|
+
exports.sync = sync;
|
|
27
|
+
exports.publishVersion = publishVersion;
|
|
28
|
+
exports.copyVersion = copyVersion;
|
|
29
|
+
exports.createBranch = createBranch;
|
|
30
|
+
exports.deleteBranch = deleteBranch;
|
|
31
|
+
exports.deleteNamespace = deleteNamespace;
|
|
32
|
+
exports.format = format;
|
|
33
|
+
exports.getBranches = getBranches;
|
|
34
|
+
exports.getJob = getJob;
|
|
35
|
+
exports.mergeBranch = mergeBranch;
|
|
36
|
+
exports.missing = missing;
|
|
37
|
+
exports.removeVersion = removeVersion;
|