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
|
@@ -1,203 +1,196 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var fs = require('node:fs');
|
|
4
|
+
var path = require('node:path');
|
|
5
|
+
var mkdirp = require('mkdirp');
|
|
6
|
+
var convertToFlatFormat = require('./convertToFlatFormat.js');
|
|
7
|
+
var formats = require('./formats.js');
|
|
8
|
+
var xcstrings2locize = require('locize-xcstrings/cjs/xcstrings2locize');
|
|
9
|
+
|
|
10
|
+
const fileExtensionsMap = formats.fileExtensionsMap;
|
|
11
|
+
const acceptedFileExtensions = formats.acceptedFileExtensions;
|
|
10
12
|
|
|
11
13
|
const getFiles = (srcpath) => {
|
|
12
14
|
return fs.readdirSync(srcpath).filter((file) => {
|
|
13
15
|
return !fs.statSync(path.join(srcpath, file)).isDirectory()
|
|
14
16
|
}).filter((file) => acceptedFileExtensions.indexOf(path.extname(file)) > -1)
|
|
15
|
-
}
|
|
17
|
+
};
|
|
16
18
|
|
|
17
19
|
const getDirectories = (srcpath) => {
|
|
18
20
|
return fs.readdirSync(srcpath).filter((file) => {
|
|
19
21
|
return fs.statSync(path.join(srcpath, file)).isDirectory()
|
|
20
22
|
})
|
|
21
|
-
}
|
|
23
|
+
};
|
|
22
24
|
|
|
23
|
-
const parseLocalLanguage = (opt, lng
|
|
24
|
-
const hasNamespaceInPath = opt.pathMask.indexOf(`${opt.pathMaskInterpolationPrefix}namespace${opt.pathMaskInterpolationSuffix}`) > -1
|
|
25
|
-
const filledLngMask = opt.pathMask.replace(`${opt.pathMaskInterpolationPrefix}language${opt.pathMaskInterpolationSuffix}`, opt.format === 'xcstrings' ? '' : lng)
|
|
26
|
-
let firstPartLngMask, lastPartLngMask
|
|
25
|
+
const parseLocalLanguage = async (opt, lng) => {
|
|
26
|
+
const hasNamespaceInPath = opt.pathMask.indexOf(`${opt.pathMaskInterpolationPrefix}namespace${opt.pathMaskInterpolationSuffix}`) > -1;
|
|
27
|
+
const filledLngMask = opt.pathMask.replace(`${opt.pathMaskInterpolationPrefix}language${opt.pathMaskInterpolationSuffix}`, opt.format === 'xcstrings' ? '' : lng);
|
|
28
|
+
let firstPartLngMask, lastPartLngMask;
|
|
27
29
|
if (opt.pathMask.indexOf(`${opt.pathMaskInterpolationPrefix}language${opt.pathMaskInterpolationSuffix}`) > opt.pathMask.indexOf(`${opt.pathMaskInterpolationPrefix}namespace${opt.pathMaskInterpolationSuffix}`)) {
|
|
28
|
-
const secondPartMask = opt.pathMask.substring(opt.pathMask.lastIndexOf(path.sep) + 1)
|
|
29
|
-
firstPartLngMask = secondPartMask.substring(0, secondPartMask.indexOf(`${opt.pathMaskInterpolationPrefix}language${opt.pathMaskInterpolationSuffix}`))
|
|
30
|
-
lastPartLngMask = secondPartMask.substring(secondPartMask.indexOf(`${opt.pathMaskInterpolationPrefix}language${opt.pathMaskInterpolationSuffix}`) + `${opt.pathMaskInterpolationPrefix}language${opt.pathMaskInterpolationSuffix}`.length)
|
|
30
|
+
const secondPartMask = opt.pathMask.substring(opt.pathMask.lastIndexOf(path.sep) + 1);
|
|
31
|
+
firstPartLngMask = secondPartMask.substring(0, secondPartMask.indexOf(`${opt.pathMaskInterpolationPrefix}language${opt.pathMaskInterpolationSuffix}`));
|
|
32
|
+
lastPartLngMask = secondPartMask.substring(secondPartMask.indexOf(`${opt.pathMaskInterpolationPrefix}language${opt.pathMaskInterpolationSuffix}`) + `${opt.pathMaskInterpolationPrefix}language${opt.pathMaskInterpolationSuffix}`.length);
|
|
31
33
|
}
|
|
32
|
-
let lngPath
|
|
34
|
+
let lngPath;
|
|
33
35
|
if (filledLngMask.lastIndexOf(path.sep) > 0) {
|
|
34
|
-
lngPath = filledLngMask.substring(0, filledLngMask.lastIndexOf(path.sep))
|
|
36
|
+
lngPath = filledLngMask.substring(0, filledLngMask.lastIndexOf(path.sep));
|
|
35
37
|
}
|
|
36
|
-
if (!opt.dry && lngPath && lngPath.indexOf(`${opt.pathMaskInterpolationPrefix}namespace${opt.pathMaskInterpolationSuffix}`) < 0) mkdirp.sync(path.join(opt.path, lngPath))
|
|
37
|
-
|
|
38
|
+
if (!opt.dry && lngPath && lngPath.indexOf(`${opt.pathMaskInterpolationPrefix}namespace${opt.pathMaskInterpolationSuffix}`) < 0) mkdirp.mkdirp.sync(path.join(opt.path, lngPath));
|
|
39
|
+
|
|
40
|
+
let files = [];
|
|
38
41
|
try {
|
|
39
42
|
if (lngPath) {
|
|
40
43
|
if (lngPath.indexOf(`${opt.pathMaskInterpolationPrefix}namespace${opt.pathMaskInterpolationSuffix}`) > -1) {
|
|
41
|
-
const firstPart = lngPath.substring(0, lngPath.indexOf(`${opt.pathMaskInterpolationPrefix}namespace${opt.pathMaskInterpolationSuffix}`))
|
|
42
|
-
const lastPart = lngPath.substring(lngPath.indexOf(`${opt.pathMaskInterpolationPrefix}namespace${opt.pathMaskInterpolationSuffix}`) + `${opt.pathMaskInterpolationPrefix}namespace${opt.pathMaskInterpolationSuffix}`.length)
|
|
43
|
-
let additionalSubDirsLeft = ''
|
|
44
|
-
let additionalSubDirs = ''
|
|
45
|
-
const splittedP = lngPath.split(path.sep)
|
|
46
|
-
const foundSplitted = splittedP.find((s) => s.indexOf(`${opt.pathMaskInterpolationPrefix}namespace${opt.pathMaskInterpolationSuffix}`) > -1)
|
|
47
|
-
const foundSplittedIndex = splittedP.indexOf(foundSplitted)
|
|
44
|
+
const firstPart = lngPath.substring(0, lngPath.indexOf(`${opt.pathMaskInterpolationPrefix}namespace${opt.pathMaskInterpolationSuffix}`));
|
|
45
|
+
const lastPart = lngPath.substring(lngPath.indexOf(`${opt.pathMaskInterpolationPrefix}namespace${opt.pathMaskInterpolationSuffix}`) + `${opt.pathMaskInterpolationPrefix}namespace${opt.pathMaskInterpolationSuffix}`.length);
|
|
46
|
+
let additionalSubDirsLeft = '';
|
|
47
|
+
let additionalSubDirs = '';
|
|
48
|
+
const splittedP = lngPath.split(path.sep);
|
|
49
|
+
const foundSplitted = splittedP.find((s) => s.indexOf(`${opt.pathMaskInterpolationPrefix}namespace${opt.pathMaskInterpolationSuffix}`) > -1);
|
|
50
|
+
const foundSplittedIndex = splittedP.indexOf(foundSplitted);
|
|
48
51
|
if (splittedP.length > 2) {
|
|
49
|
-
additionalSubDirsLeft = splittedP.slice(0, foundSplittedIndex).join(path.sep)
|
|
50
|
-
additionalSubDirs = splittedP.slice(foundSplittedIndex + 1).join(path.sep)
|
|
52
|
+
additionalSubDirsLeft = splittedP.slice(0, foundSplittedIndex).join(path.sep);
|
|
53
|
+
additionalSubDirs = splittedP.slice(foundSplittedIndex + 1).join(path.sep);
|
|
51
54
|
}
|
|
52
|
-
let dirs = getDirectories(path.join(opt.path, additionalSubDirsLeft))
|
|
55
|
+
let dirs = getDirectories(path.join(opt.path, additionalSubDirsLeft));
|
|
53
56
|
if (additionalSubDirs === '') {
|
|
54
|
-
dirs = dirs.filter((d) => d.startsWith(firstPart) && d.endsWith(lastPart))
|
|
57
|
+
dirs = dirs.filter((d) => d.startsWith(firstPart) && d.endsWith(lastPart));
|
|
55
58
|
}
|
|
56
59
|
dirs.forEach((d) => {
|
|
57
60
|
if (additionalSubDirs && fs.statSync(path.join(opt.path, additionalSubDirsLeft, d)).isDirectory()) {
|
|
58
|
-
let directoryExists = false
|
|
61
|
+
let directoryExists = false;
|
|
59
62
|
try {
|
|
60
|
-
directoryExists = fs.statSync(path.join(opt.path, additionalSubDirsLeft, d, additionalSubDirs)).isDirectory()
|
|
63
|
+
directoryExists = fs.statSync(path.join(opt.path, additionalSubDirsLeft, d, additionalSubDirs)).isDirectory();
|
|
61
64
|
} catch (e) {}
|
|
62
65
|
if (directoryExists) {
|
|
63
|
-
let subFls = getFiles(path.join(opt.path, additionalSubDirsLeft, d, additionalSubDirs))
|
|
64
|
-
if (firstPartLngMask || lastPartLngMask) subFls = subFls.filter((f) => path.basename(f, path.extname(f)) === `${firstPartLngMask}${lng}${lastPartLngMask}`)
|
|
66
|
+
let subFls = getFiles(path.join(opt.path, additionalSubDirsLeft, d, additionalSubDirs));
|
|
67
|
+
if (firstPartLngMask || lastPartLngMask) subFls = subFls.filter((f) => path.basename(f, path.extname(f)) === `${firstPartLngMask}${lng}${lastPartLngMask}`);
|
|
65
68
|
|
|
66
69
|
subFls = subFls.filter((f) => {
|
|
67
|
-
const a = path.join(additionalSubDirsLeft, d, additionalSubDirs, path.basename(f, path.extname(f)))
|
|
68
|
-
const startIndexOfNs = filledLngMask.indexOf(`${opt.pathMaskInterpolationPrefix}namespace${opt.pathMaskInterpolationSuffix}`)
|
|
70
|
+
const a = path.join(additionalSubDirsLeft, d, additionalSubDirs, path.basename(f, path.extname(f)));
|
|
71
|
+
const startIndexOfNs = filledLngMask.indexOf(`${opt.pathMaskInterpolationPrefix}namespace${opt.pathMaskInterpolationSuffix}`);
|
|
69
72
|
if (startIndexOfNs === -1) return true
|
|
70
|
-
const afterNs = filledLngMask.substring(startIndexOfNs + `${opt.pathMaskInterpolationPrefix}namespace${opt.pathMaskInterpolationSuffix}`.length)
|
|
71
|
-
const nsName = a.substring(startIndexOfNs, a.indexOf(afterNs))
|
|
72
|
-
const b = filledLngMask.replace(`${opt.pathMaskInterpolationPrefix}namespace${opt.pathMaskInterpolationSuffix}`, nsName)
|
|
73
|
+
const afterNs = filledLngMask.substring(startIndexOfNs + `${opt.pathMaskInterpolationPrefix}namespace${opt.pathMaskInterpolationSuffix}`.length);
|
|
74
|
+
const nsName = a.substring(startIndexOfNs, a.indexOf(afterNs));
|
|
75
|
+
const b = filledLngMask.replace(`${opt.pathMaskInterpolationPrefix}namespace${opt.pathMaskInterpolationSuffix}`, nsName);
|
|
73
76
|
return a === b
|
|
74
|
-
})
|
|
77
|
+
});
|
|
75
78
|
|
|
76
|
-
files = files.concat(subFls.map((f) => `${additionalSubDirsLeft ? additionalSubDirsLeft + path.sep : ''}${d}${path.sep}${additionalSubDirs}${path.sep}${f}`))
|
|
79
|
+
files = files.concat(subFls.map((f) => `${additionalSubDirsLeft ? additionalSubDirsLeft + path.sep : ''}${d}${path.sep}${additionalSubDirs}${path.sep}${f}`));
|
|
77
80
|
}
|
|
78
81
|
} else {
|
|
79
|
-
const fls = getFiles(path.join(opt.path, additionalSubDirsLeft, d)).filter((f) => path.basename(f, path.extname(f)) === `${firstPartLngMask}${lng}${lastPartLngMask}`)
|
|
80
|
-
files = files.concat(fls.map((f) => `${additionalSubDirsLeft ? additionalSubDirsLeft + path.sep : ''}${d}${path.sep}${f}`))
|
|
82
|
+
const fls = getFiles(path.join(opt.path, additionalSubDirsLeft, d)).filter((f) => path.basename(f, path.extname(f)) === `${firstPartLngMask}${lng}${lastPartLngMask}`);
|
|
83
|
+
files = files.concat(fls.map((f) => `${additionalSubDirsLeft ? additionalSubDirsLeft + path.sep : ''}${d}${path.sep}${f}`));
|
|
81
84
|
}
|
|
82
|
-
})
|
|
85
|
+
});
|
|
83
86
|
} else {
|
|
84
|
-
files = getFiles(path.join(opt.path, lngPath))
|
|
87
|
+
files = getFiles(path.join(opt.path, lngPath));
|
|
85
88
|
}
|
|
86
89
|
} else {
|
|
87
|
-
files = getFiles(opt.path)
|
|
90
|
+
files = getFiles(opt.path);
|
|
88
91
|
// filter lng files...
|
|
89
|
-
const lngIndex = filledLngMask.indexOf(lng)
|
|
90
|
-
const lngLeftLength = filledLngMask.length - lngIndex
|
|
92
|
+
const lngIndex = filledLngMask.indexOf(lng);
|
|
93
|
+
const lngLeftLength = filledLngMask.length - lngIndex;
|
|
91
94
|
files = files.filter((f) => { // {{language}} can be left or right of {{namespace}}
|
|
92
95
|
if (opt.pathMask.indexOf(`${opt.pathMaskInterpolationPrefix}language${opt.pathMaskInterpolationSuffix}`) < opt.pathMask.indexOf(`${opt.pathMaskInterpolationPrefix}namespace${opt.pathMaskInterpolationSuffix}`)) {
|
|
93
96
|
return f.indexOf(lng) === lngIndex
|
|
94
97
|
}
|
|
95
98
|
return (path.basename(f, path.extname(f)).length - f.indexOf(lng)) === lngLeftLength
|
|
96
|
-
})
|
|
99
|
+
});
|
|
97
100
|
}
|
|
98
101
|
} catch (err) {}
|
|
99
|
-
|
|
100
|
-
|
|
102
|
+
|
|
103
|
+
// Async map logic using Promise.all
|
|
104
|
+
const results = await Promise.all(files.map(async (fileOrig) => {
|
|
105
|
+
let file = fileOrig;
|
|
106
|
+
let dirPath;
|
|
101
107
|
if (file.lastIndexOf(path.sep) > 0) {
|
|
102
|
-
dirPath = file.substring(0, file.lastIndexOf(path.sep))
|
|
103
|
-
file = file.substring(file.lastIndexOf(path.sep) + 1)
|
|
108
|
+
dirPath = file.substring(0, file.lastIndexOf(path.sep));
|
|
109
|
+
file = file.substring(file.lastIndexOf(path.sep) + 1);
|
|
104
110
|
}
|
|
105
|
-
const fExt = path.extname(file)
|
|
106
|
-
let namespace = path.basename(file, fExt)
|
|
107
|
-
const nsMask = `${opt.pathMaskInterpolationPrefix}namespace${opt.pathMaskInterpolationSuffix}
|
|
108
|
-
const filledNsMask = lngPath && lngPath.indexOf(nsMask) > -1 ? filledLngMask : filledLngMask.substring(filledLngMask.lastIndexOf(path.sep) + 1)
|
|
109
|
-
const startNsIndex = filledNsMask.indexOf(nsMask)
|
|
110
|
-
let restNsMask = filledNsMask.substring((startNsIndex || 0) + nsMask.length)
|
|
111
|
-
namespace = namespace.substring(startNsIndex || 0, namespace.lastIndexOf(restNsMask))
|
|
111
|
+
const fExt = path.extname(file);
|
|
112
|
+
let namespace = path.basename(file, fExt);
|
|
113
|
+
const nsMask = `${opt.pathMaskInterpolationPrefix}namespace${opt.pathMaskInterpolationSuffix}`;
|
|
114
|
+
const filledNsMask = lngPath && lngPath.indexOf(nsMask) > -1 ? filledLngMask : filledLngMask.substring(filledLngMask.lastIndexOf(path.sep) + 1);
|
|
115
|
+
const startNsIndex = filledNsMask.indexOf(nsMask);
|
|
116
|
+
let restNsMask = filledNsMask.substring((startNsIndex || 0) + nsMask.length);
|
|
117
|
+
namespace = namespace.substring(startNsIndex || 0, namespace.lastIndexOf(restNsMask));
|
|
112
118
|
if (lngPath && lngPath.indexOf(nsMask) > -1) {
|
|
113
|
-
restNsMask = restNsMask.substring(0, restNsMask.lastIndexOf(path.sep))
|
|
119
|
+
restNsMask = restNsMask.substring(0, restNsMask.lastIndexOf(path.sep));
|
|
114
120
|
if (dirPath.indexOf(restNsMask) > 0) {
|
|
115
|
-
namespace = dirPath.substring(filledNsMask.indexOf(nsMask), dirPath.indexOf(restNsMask))
|
|
121
|
+
namespace = dirPath.substring(filledNsMask.indexOf(nsMask), dirPath.indexOf(restNsMask));
|
|
116
122
|
} else {
|
|
117
|
-
namespace = dirPath.substring(filledNsMask.indexOf(nsMask))
|
|
123
|
+
namespace = dirPath.substring(filledNsMask.indexOf(nsMask));
|
|
118
124
|
}
|
|
119
125
|
} else if (!hasNamespaceInPath && startNsIndex < 0) {
|
|
120
|
-
namespace = opt.namespace
|
|
126
|
+
namespace = opt.namespace;
|
|
121
127
|
}
|
|
122
|
-
let fPath = path.join(opt.path, lngPath || '', file)
|
|
128
|
+
let fPath = path.join(opt.path, lngPath || '', file);
|
|
123
129
|
if (dirPath && lngPath.indexOf(nsMask) > -1) {
|
|
124
|
-
fPath = path.join(opt.path, dirPath.replace(nsMask, namespace), file)
|
|
130
|
+
fPath = path.join(opt.path, dirPath.replace(nsMask, namespace), file);
|
|
125
131
|
}
|
|
126
|
-
if (!namespace)
|
|
127
|
-
if (opt.namespaces && opt.namespaces.indexOf(namespace) < 0) return
|
|
128
|
-
if (opt.namespace && opt.namespace !== namespace) return
|
|
129
|
-
fs.readFile(fPath
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
132
|
+
if (!namespace) throw new Error(`namespace could not be found in ${fPath}`)
|
|
133
|
+
if (opt.namespaces && opt.namespaces.indexOf(namespace) < 0) return undefined
|
|
134
|
+
if (opt.namespace && opt.namespace !== namespace) return undefined
|
|
135
|
+
const data = await fs.promises.readFile(fPath);
|
|
136
|
+
if (fileExtensionsMap[fExt].indexOf(opt.format) < 0) {
|
|
137
|
+
throw new Error(`Format mismatch! Found ${fileExtensionsMap[fExt][0]} but requested ${opt.format}!`)
|
|
138
|
+
}
|
|
139
|
+
if (opt.namespace) {
|
|
140
|
+
let hasNamespaceInPathPask = !opt.pathMask || !opt.pathMaskInterpolationPrefix || !opt.pathMaskInterpolationSuffix;
|
|
141
|
+
hasNamespaceInPathPask = !hasNamespaceInPathPask && opt.pathMask.indexOf(`${opt.pathMaskInterpolationPrefix}namespace${opt.pathMaskInterpolationSuffix}`) > -1;
|
|
142
|
+
if (!hasNamespaceInPathPask && namespace === lng) {
|
|
143
|
+
namespace = opt.namespace;
|
|
134
144
|
}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
145
|
+
}
|
|
146
|
+
if (opt.format === 'xcstrings') {
|
|
147
|
+
try {
|
|
148
|
+
const content = xcstrings2locize(data);
|
|
149
|
+
const stat = await fs.promises.stat(fPath);
|
|
150
|
+
return Object.keys(content.resources).map((l) => ({
|
|
151
|
+
namespace,
|
|
152
|
+
path: fPath,
|
|
153
|
+
extension: fExt,
|
|
154
|
+
content: content.resources[l],
|
|
155
|
+
language: l,
|
|
156
|
+
mtime: stat.mtime
|
|
157
|
+
}))
|
|
158
|
+
} catch (err) {
|
|
159
|
+
err.message = 'Invalid content for "' + opt.format + '" format!\n' + (err.message || '');
|
|
160
|
+
err.message += '\n' + fPath;
|
|
161
|
+
throw err
|
|
142
162
|
}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
clb(null, Object.keys(content.resources).map((l) => ({
|
|
152
|
-
namespace,
|
|
153
|
-
path: fPath,
|
|
154
|
-
extension: fExt,
|
|
155
|
-
content: content.resources[l],
|
|
156
|
-
language: l,
|
|
157
|
-
mtime: stat.mtime
|
|
158
|
-
})))
|
|
159
|
-
})
|
|
160
|
-
} catch (e) {
|
|
161
|
-
err.message = 'Invalid content for "' + opt.format + '" format!\n' + (err.message || '')
|
|
162
|
-
err.message += '\n' + fPath
|
|
163
|
-
return clb(err)
|
|
164
|
-
}
|
|
165
|
-
} else { // 1 file per namespace/lng
|
|
166
|
-
convertToFlatFormat(opt, data, lng, (err, content) => {
|
|
167
|
-
if (err) {
|
|
168
|
-
err.message = 'Invalid content for "' + opt.format + '" format!\n' + (err.message || '')
|
|
169
|
-
err.message += '\n' + fPath
|
|
170
|
-
return clb(err)
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
fs.stat(fPath, (err, stat) => {
|
|
174
|
-
if (err) return clb(err)
|
|
175
|
-
|
|
176
|
-
clb(null, {
|
|
177
|
-
namespace,
|
|
178
|
-
path: fPath,
|
|
179
|
-
extension: fExt,
|
|
180
|
-
content,
|
|
181
|
-
language: lng,
|
|
182
|
-
mtime: stat.mtime
|
|
183
|
-
})
|
|
184
|
-
})
|
|
185
|
-
})
|
|
163
|
+
} else {
|
|
164
|
+
let content;
|
|
165
|
+
try {
|
|
166
|
+
content = await convertToFlatFormat(opt, data, lng);
|
|
167
|
+
} catch (err) {
|
|
168
|
+
err.message = 'Invalid content for "' + opt.format + '" format!\n' + (err.message || '');
|
|
169
|
+
err.message += '\n' + fPath;
|
|
170
|
+
throw err
|
|
186
171
|
}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
prev.push(cur)
|
|
172
|
+
const stat = await fs.promises.stat(fPath);
|
|
173
|
+
return {
|
|
174
|
+
namespace,
|
|
175
|
+
path: fPath,
|
|
176
|
+
extension: fExt,
|
|
177
|
+
content,
|
|
178
|
+
language: lng,
|
|
179
|
+
mtime: stat.mtime
|
|
196
180
|
}
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
181
|
+
}
|
|
182
|
+
}));
|
|
183
|
+
|
|
184
|
+
// xcstrings, returns array in array
|
|
185
|
+
const r = results.filter((r) => r !== undefined).reduce((prev, cur) => {
|
|
186
|
+
if (Array.isArray(cur)) {
|
|
187
|
+
prev = prev.concat(cur);
|
|
188
|
+
} else {
|
|
189
|
+
prev.push(cur);
|
|
190
|
+
}
|
|
191
|
+
return prev
|
|
192
|
+
}, []);
|
|
193
|
+
return r
|
|
194
|
+
};
|
|
202
195
|
|
|
203
|
-
module.exports = parseLocalLanguage
|
|
196
|
+
module.exports = parseLocalLanguage;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var parseLocalLanguage = require('./parseLocalLanguage.js');
|
|
4
|
+
var filterNamespaces = require('./filterNamespaces.js');
|
|
5
|
+
|
|
6
|
+
const parseLocalLanguages = async (opt, lngs) => {
|
|
7
|
+
let res = [];
|
|
8
|
+
for (const lng of lngs) {
|
|
9
|
+
if (opt.language && (lng !== opt.language && lng !== opt.referenceLanguage)) {
|
|
10
|
+
continue
|
|
11
|
+
}
|
|
12
|
+
const nss = await parseLocalLanguage(opt, lng);
|
|
13
|
+
res = res.concat(filterNamespaces(opt, nss));
|
|
14
|
+
}
|
|
15
|
+
return res
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
module.exports = parseLocalLanguages;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var parseLocalLanguage = require('./parseLocalLanguage.js');
|
|
4
|
+
var filterNamespaces = require('./filterNamespaces.js');
|
|
5
|
+
|
|
6
|
+
const parseLocalReference = async (opt) => {
|
|
7
|
+
const nss = await parseLocalLanguage(opt, opt.referenceLanguage);
|
|
8
|
+
return filterNamespaces(opt, nss).filter((n) => n.language === opt.referenceLanguage)
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
module.exports = parseLocalReference;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var colors = require('colors');
|
|
4
|
+
var request = require('./request.js');
|
|
5
|
+
var getJob = require('./getJob.js');
|
|
6
|
+
|
|
7
|
+
const publishVersion = async (opt) => {
|
|
8
|
+
const { res, obj } = await request(opt.apiEndpoint + '/publish/' + opt.projectId + '/' + opt.version + (opt.tenants ? '?tenants=true' : ''), {
|
|
9
|
+
method: 'post',
|
|
10
|
+
headers: {
|
|
11
|
+
Authorization: opt.apiKey
|
|
12
|
+
}
|
|
13
|
+
});
|
|
14
|
+
if (obj && (obj.errorMessage || obj.message)) {
|
|
15
|
+
console.log(colors.red(`publishing failed for ${opt.version}...`));
|
|
16
|
+
throw new Error(obj.errorMessage || obj.message)
|
|
17
|
+
}
|
|
18
|
+
if (res.status >= 300) {
|
|
19
|
+
console.error(colors.red(res.statusText + ' (' + res.status + ')'));
|
|
20
|
+
throw new Error(res.statusText + ' (' + res.status + ')')
|
|
21
|
+
}
|
|
22
|
+
if (!obj || !obj.jobId) {
|
|
23
|
+
console.error(colors.red('No jobId! Something went wrong!'));
|
|
24
|
+
throw new Error('No jobId! Something went wrong!')
|
|
25
|
+
}
|
|
26
|
+
// Poll for job completion
|
|
27
|
+
while (true) {
|
|
28
|
+
const job = await getJob(opt, obj.jobId);
|
|
29
|
+
if (job && !job.timeouted) {
|
|
30
|
+
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
31
|
+
continue
|
|
32
|
+
}
|
|
33
|
+
if (job && job.timeouted) {
|
|
34
|
+
console.error(colors.red('Job timeouted!'));
|
|
35
|
+
throw new Error('Job timeouted!')
|
|
36
|
+
}
|
|
37
|
+
break
|
|
38
|
+
}
|
|
39
|
+
console.log(colors.green(`publishing for ${opt.version} succesfully requested`));
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
module.exports = publishVersion;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// rails seems to start date relevant information in an array with 1 instead of 0
|
|
4
|
+
function removeUndefinedFromArrays (obj) {
|
|
5
|
+
if (!obj) return obj
|
|
6
|
+
|
|
7
|
+
const propNames = Object.keys(obj);
|
|
8
|
+
propNames.forEach((propName) => {
|
|
9
|
+
if (Array.isArray(obj[propName]) && obj[propName][0] === undefined) {
|
|
10
|
+
obj[propName].shift();
|
|
11
|
+
} else if (typeof obj[propName] === 'object') {
|
|
12
|
+
removeUndefinedFromArrays(obj[propName]);
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
return obj
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
module.exports = removeUndefinedFromArrays;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var colors = require('colors');
|
|
4
|
+
var request = require('./request.js');
|
|
5
|
+
var getJob = require('./getJob.js');
|
|
6
|
+
|
|
7
|
+
const removeVersion = async (opt) => {
|
|
8
|
+
const { res, obj } = await request(opt.apiEndpoint + '/version/' + opt.projectId + '/' + opt.version, {
|
|
9
|
+
method: 'delete',
|
|
10
|
+
headers: {
|
|
11
|
+
Authorization: opt.apiKey
|
|
12
|
+
}
|
|
13
|
+
});
|
|
14
|
+
if (obj && (obj.errorMessage || obj.message)) {
|
|
15
|
+
console.log(colors.red(`remove failed for version ${opt.version}...`));
|
|
16
|
+
throw new Error(obj.errorMessage || obj.message)
|
|
17
|
+
}
|
|
18
|
+
if (res.status >= 300) {
|
|
19
|
+
console.error(colors.red(res.statusText + ' (' + res.status + ')'));
|
|
20
|
+
throw new Error(res.statusText + ' (' + res.status + ')')
|
|
21
|
+
}
|
|
22
|
+
if (!obj || !obj.jobId) {
|
|
23
|
+
console.error(colors.red('No jobId! Something went wrong!'));
|
|
24
|
+
throw new Error('No jobId! Something went wrong!')
|
|
25
|
+
}
|
|
26
|
+
// Poll for job completion
|
|
27
|
+
while (true) {
|
|
28
|
+
const job = await getJob(opt, obj.jobId);
|
|
29
|
+
if (job && !job.timeouted) {
|
|
30
|
+
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
31
|
+
continue
|
|
32
|
+
}
|
|
33
|
+
if (job && job.timeouted) {
|
|
34
|
+
console.error(colors.red('Job timeouted!'));
|
|
35
|
+
throw new Error('Job timeouted!')
|
|
36
|
+
}
|
|
37
|
+
break
|
|
38
|
+
}
|
|
39
|
+
console.log(colors.green(`remove version ${opt.version} succesfully requested`));
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
module.exports = removeVersion;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var httpsProxyAgent = require('https-proxy-agent');
|
|
4
|
+
var https = require('https');
|
|
5
|
+
var CacheableLookup = require('cacheable-lookup');
|
|
6
|
+
|
|
7
|
+
const cacheable = new CacheableLookup();
|
|
8
|
+
cacheable.install(https.globalAgent);
|
|
9
|
+
|
|
10
|
+
const httpProxy = process.env.http_proxy || process.env.HTTP_PROXY || process.env.https_proxy || process.env.HTTPS_PROXY;
|
|
11
|
+
const isRetriableError = (err) => {
|
|
12
|
+
return err && err.message && (
|
|
13
|
+
err.message.indexOf('ETIMEDOUT') > -1 || // on timeout retry
|
|
14
|
+
err.message.indexOf('FetchError') > -1 ||
|
|
15
|
+
err.code === 'ETIMEDOUT' ||
|
|
16
|
+
// on dns errors
|
|
17
|
+
err.message.indexOf('ENOTFOUND') > -1 ||
|
|
18
|
+
err.message.indexOf('ENODATA') > -1 ||
|
|
19
|
+
err.message.indexOf('ENOENT') > -1 // Windows: name exists, but not this record type
|
|
20
|
+
)
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const isJSONResponse = (res) => res.headers.get('content-type') && res.headers.get('content-type').indexOf('json') > 0;
|
|
24
|
+
|
|
25
|
+
const handleResponse = (res) => {
|
|
26
|
+
if (isJSONResponse(res)) {
|
|
27
|
+
return new Promise((resolve, reject) => res.json().then((obj) => resolve({ res, obj })).catch(reject))
|
|
28
|
+
} else {
|
|
29
|
+
return { res }
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
async function request (url, options) {
|
|
34
|
+
if (httpProxy) {
|
|
35
|
+
const httpsProxyAgent$1 = new httpsProxyAgent.HttpsProxyAgent(httpProxy);
|
|
36
|
+
cacheable.install(httpsProxyAgent$1);
|
|
37
|
+
options.agent = httpsProxyAgent$1;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
options.headers = options.headers || {};
|
|
41
|
+
options.headers['User-Agent'] = `__packageName__/v__packageVersion__ (node/${process.version}; ${process.platform} ${process.arch})`; // This string is replaced with the actual version at build time by rollup
|
|
42
|
+
options.headers['X-User-Agent'] = options.headers['User-Agent'];
|
|
43
|
+
if (options.body || options.method !== 'get') options.headers['Content-Type'] = 'application/json';
|
|
44
|
+
if (options.body) {
|
|
45
|
+
if (typeof options.body !== 'string') {
|
|
46
|
+
options.body = JSON.stringify(options.body);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
if (options.headers['Authorization'] === undefined) delete options.headers['Authorization'];
|
|
50
|
+
|
|
51
|
+
async function retriableFetch (maxRetries) {
|
|
52
|
+
try {
|
|
53
|
+
const response = await fetch(url, options);
|
|
54
|
+
const result = await handleResponse(response);
|
|
55
|
+
return result
|
|
56
|
+
} catch (err) {
|
|
57
|
+
if (maxRetries < 1) throw err
|
|
58
|
+
if (!isRetriableError(err)) throw err
|
|
59
|
+
await new Promise(resolve => setTimeout(resolve, 5000));
|
|
60
|
+
return retriableFetch(--maxRetries)
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return retriableFetch(3)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
module.exports = request;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const shouldUnflatten = (json) => {
|
|
4
|
+
const keys = Object.keys(json);
|
|
5
|
+
let shouldUnflatten = true;
|
|
6
|
+
for (let i = 0, len = keys.length; i < len; i++) {
|
|
7
|
+
const key = keys[i];
|
|
8
|
+
|
|
9
|
+
if (shouldUnflatten && /( |,|\?)/.test(key)) {
|
|
10
|
+
shouldUnflatten = false;
|
|
11
|
+
return shouldUnflatten
|
|
12
|
+
} else if (shouldUnflatten && key.indexOf('.') > -1 && keys.indexOf(key.substring(0, key.lastIndexOf('.'))) > -1) {
|
|
13
|
+
shouldUnflatten = false;
|
|
14
|
+
return shouldUnflatten
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return shouldUnflatten
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
module.exports = shouldUnflatten;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const sortFlatResources = (resources) => {
|
|
4
|
+
const keys = Object.keys(resources).sort();
|
|
5
|
+
const cleaned = {};
|
|
6
|
+
for (let i = 0, len = keys.length; i < len; i++) {
|
|
7
|
+
const key = keys[i];
|
|
8
|
+
cleaned[key] = resources[key];
|
|
9
|
+
}
|
|
10
|
+
return cleaned
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
module.exports = sortFlatResources;
|