locize-cli 7.15.0 → 7.15.2

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 CHANGED
@@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file.
5
5
  Project versioning adheres to [Semantic Versioning](http://semver.org/).
6
6
  Change log format is based on [Keep a Changelog](http://keepachangelog.com/).
7
7
 
8
+ ## [7.15.2](https://github.com/locize/locize-cli/compare/v7.15.1...v7.15.2) - 2023-01-06
9
+
10
+ - optimize --skip-empty false handling for download command
11
+
12
+ ## [7.15.1](https://github.com/locize/locize-cli/compare/v7.15.0...v7.15.1) - 2023-12-19
13
+
14
+ - refactor retriable requests handling
15
+
8
16
  ## [7.15.0](https://github.com/locize/locize-cli/compare/v7.14.15...v7.15.0) - 2023-12-18
9
17
 
10
18
  - locize sync: show publish mode advice if necessary
package/download.js CHANGED
@@ -151,6 +151,43 @@ const handleError = (err, cb) => {
151
151
  if (cb) cb(err);
152
152
  };
153
153
 
154
+ const filterDownloads = (opt, downloads) => {
155
+ if (opt.skipEmpty) return downloads.filter((d) => d.size > 2);
156
+ if (downloads.length < 1) return downloads;
157
+
158
+ const allNamespaces = [];
159
+ const downloadMap = {};
160
+ downloads.forEach((d) => {
161
+ const splitted = d.key.split('/');
162
+ const p = splitted[d.isPrivate ? 1 : 0];
163
+ const v = splitted[d.isPrivate ? 2 : 1];
164
+ const l = splitted[d.isPrivate ? 3 : 2];
165
+ const n = splitted[d.isPrivate ? 4 : 3];
166
+ downloadMap[p] = downloadMap[p] || {};
167
+ downloadMap[p][v] = downloadMap[p][v] || {};
168
+ downloadMap[p][v][l] = downloadMap[p][v][l] || {};
169
+ downloadMap[p][v][l][n] = d;
170
+ if (allNamespaces.indexOf(n) < 0) allNamespaces.push(n);
171
+ });
172
+ Object.keys(downloadMap).forEach((projectId) => {
173
+ Object.keys(downloadMap[projectId]).forEach((version) => {
174
+ Object.keys(downloadMap[projectId][version]).forEach((language) => {
175
+ allNamespaces.forEach((namespace) => {
176
+ if (!downloadMap[projectId][version][language][namespace]) {
177
+ downloads.push({
178
+ url: `${opt.apiPath}/${projectId}/${version}/${language}/${namespace}`,
179
+ key: `${projectId}/${version}/${language}/${namespace}`,
180
+ lastModified: '1960-01-01T00:00:00.000Z',
181
+ size: 0
182
+ });
183
+ }
184
+ });
185
+ });
186
+ });
187
+ });
188
+ return downloads;
189
+ };
190
+
154
191
  const download = (opt, cb) => {
155
192
  opt.format = opt.format || 'json';
156
193
  if (!reversedFileExtensionsMap[opt.format]) {
@@ -203,20 +240,18 @@ const download = (opt, cb) => {
203
240
  'Authorization': opt.apiKey
204
241
  } : undefined
205
242
  }, (err, res, obj) => {
206
- obj = obj || [];
207
243
  if (res && res.status === 401) {
208
244
  opt.apiKey = null;
209
245
  request(url, {
210
246
  method: 'get',
211
247
  }, (err, res, obj) => {
212
- obj = obj || [];
213
- if (opt.skipEmpty) obj = obj.filter((d) => d.size > 2);
248
+ obj = filterDownloads(opt, obj || []);
214
249
  handleDownload(opt, url, err, res, obj, cb);
215
250
  });
216
251
  return;
217
252
  }
218
253
 
219
- if (opt.skipEmpty) obj = obj.filter((d) => d.size > 2);
254
+ obj = filterDownloads(opt, obj || []);
220
255
  handleDownload(opt, url, err, res, obj, cb);
221
256
  });
222
257
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "locize-cli",
3
- "version": "7.15.0",
3
+ "version": "7.15.2",
4
4
  "description": "locize cli to import locales",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -34,7 +34,7 @@
34
34
  "xlsx": "https://cdn.sheetjs.com/xlsx-0.20.0/xlsx-0.20.0.tgz"
35
35
  },
36
36
  "devDependencies": {
37
- "eslint": "8.53.0",
37
+ "eslint": "8.56.0",
38
38
  "gh-release": "7.0.2",
39
39
  "pkg": "5.8.1"
40
40
  },
package/request.js CHANGED
@@ -8,6 +8,28 @@ cacheable.install(https.globalAgent);
8
8
 
9
9
  const httpProxy = process.env.http_proxy || process.env.HTTP_PROXY || process.env.https_proxy || process.env.HTTPS_PROXY;
10
10
 
11
+ const isRetriableError = (err) => {
12
+ return err && err.message && (
13
+ err.message.indexOf('ETIMEDOUT') > -1 || // on timeout retry
14
+ // on dns errors
15
+ err.message.indexOf('ENOTFOUND') > -1 ||
16
+ err.message.indexOf('ENODATA') > -1 ||
17
+ err.message.indexOf('ENOENT') > -1 // Windows: name exists, but not this record type
18
+ );
19
+ };
20
+
21
+ const isJSONResponse = (res) => res.headers.get('content-type') && res.headers.get('content-type').indexOf('json') > 0;
22
+
23
+ const handleResponse = (res) => {
24
+ if (isJSONResponse(res)) {
25
+ return new Promise((resolve, reject) => res.json().then((obj) => resolve({ res, obj })).catch(reject));
26
+ } else {
27
+ return { res };
28
+ }
29
+ };
30
+
31
+ const handleSuccessful = (callback) => (ret) => callback(null, ret.res, ret.obj);
32
+
11
33
  module.exports = (url, options, callback) => {
12
34
  if (httpProxy) {
13
35
  const httpsProxyAgent = new HttpsProxyAgent(httpProxy);
@@ -25,31 +47,16 @@ module.exports = (url, options, callback) => {
25
47
  }
26
48
  }
27
49
  if (options.headers['Authorization'] === undefined) delete options.headers['Authorization'];
28
- fetch(url, options).then((res) => {
29
- if (res.headers.get('content-type') && res.headers.get('content-type').indexOf('json') > 0) {
30
- return new Promise((resolve, reject) => res.json().then((obj) => resolve({ res, obj })).catch(reject));
31
- } else {
32
- return { res };
33
- }
34
- }).then((ret) => callback(null, ret.res, ret.obj)).catch((err) => {
35
- if (err && err.message && (
36
- err.message.indexOf('ETIMEDOUT') > -1 || // on timeout retry
37
- // on dns errors
38
- err.message.indexOf('ENOTFOUND') > -1 ||
39
- err.message.indexOf('ENODATA') > -1 ||
40
- err.message.indexOf('ENOENT') > -1 // Windows: name exists, but not this record type
41
- )) {
50
+
51
+ function retriableFetch(maxRetries) {
52
+ fetch(url, options).then(handleResponse).then(handleSuccessful(callback)).catch((err) => {
53
+ if (maxRetries < 1) return callback(err);
54
+ if (!isRetriableError(err)) return callback(err);
42
55
  setTimeout(() => {
43
- fetch(url, options).then((res) => {
44
- if (res.headers.get('content-type') && res.headers.get('content-type').indexOf('json') > 0) {
45
- return new Promise((resolve, reject) => res.json().then((obj) => resolve({ res, obj })).catch(reject));
46
- } else {
47
- return { res };
48
- }
49
- }).then((ret) => callback(null, ret.res, ret.obj)).catch(callback);
56
+ retriableFetch(--maxRetries);
50
57
  }, 5000);
51
- return;
52
- }
53
- callback(err);
54
- });
58
+ });
59
+ }
60
+
61
+ retriableFetch(3);
55
62
  };