@lingui/cli 3.17.0 → 3.17.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 +24 -0
- package/build/api/catalog.js +64 -142
- package/build/api/compile.js +12 -22
- package/build/api/detect.js +0 -16
- package/build/api/extract.js +5 -24
- package/build/api/extractors/babel.js +2 -10
- package/build/api/extractors/index.js +0 -12
- package/build/api/extractors/typescript.js +4 -17
- package/build/api/formats/csv.js +0 -15
- package/build/api/formats/index.js +1 -9
- package/build/api/formats/lingui.js +2 -18
- package/build/api/formats/minimal.js +5 -18
- package/build/api/formats/po-gettext.js +45 -79
- package/build/api/formats/po.js +6 -30
- package/build/api/help.js +3 -8
- package/build/api/index.js +8 -12
- package/build/api/locales.js +3 -12
- package/build/api/pseudoLocalize.js +5 -15
- package/build/api/stats.js +2 -8
- package/build/api/utils.js +11 -31
- package/build/lingui-add-locale.js +0 -3
- package/build/lingui-compile.js +24 -53
- package/build/lingui-extract-template.js +5 -14
- package/build/lingui-extract.js +26 -48
- package/build/lingui.js +5 -13
- package/build/services/translationIO.js +61 -85
- package/build/tests.js +2 -16
- package/package.json +12 -11
|
@@ -4,21 +4,13 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.default = syncProcess;
|
|
7
|
-
|
|
8
7
|
var _fs = _interopRequireDefault(require("fs"));
|
|
9
|
-
|
|
10
8
|
var _path = require("path");
|
|
11
|
-
|
|
12
9
|
var _pofile = _interopRequireDefault(require("pofile"));
|
|
13
|
-
|
|
14
10
|
var _https = _interopRequireDefault(require("https"));
|
|
15
|
-
|
|
16
11
|
var _glob = _interopRequireDefault(require("glob"));
|
|
17
|
-
|
|
18
12
|
var _dateFns = require("date-fns");
|
|
19
|
-
|
|
20
13
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
21
|
-
|
|
22
14
|
const getCreateHeaders = language => ({
|
|
23
15
|
"POT-Creation-Date": (0, _dateFns.format)(new Date(), "yyyy-MM-dd HH:mmxxxx"),
|
|
24
16
|
"MIME-Version": "1.0",
|
|
@@ -26,74 +18,69 @@ const getCreateHeaders = language => ({
|
|
|
26
18
|
"Content-Transfer-Encoding": "8bit",
|
|
27
19
|
"X-Generator": "@lingui/cli",
|
|
28
20
|
Language: language
|
|
29
|
-
});
|
|
30
|
-
|
|
21
|
+
});
|
|
31
22
|
|
|
23
|
+
// Main sync method, call "Init" or "Sync" depending on the project context
|
|
32
24
|
function syncProcess(config, options) {
|
|
33
|
-
if (config.format !=
|
|
25
|
+
if (config.format != "po") {
|
|
34
26
|
console.error(`\n----------\nTranslation.io service is only compatible with the "po" format. Please update your Lingui configuration accordingly.\n----------`);
|
|
35
27
|
process.exit(1);
|
|
36
28
|
}
|
|
37
|
-
|
|
38
29
|
const successCallback = project => {
|
|
39
30
|
console.log(`\n----------\nProject successfully synchronized. Please use this URL to translate: ${project.url}\n----------`);
|
|
40
31
|
};
|
|
41
|
-
|
|
42
32
|
const failCallback = errors => {
|
|
43
|
-
console.error(`\n----------\nSynchronization with Translation.io failed: ${errors.join(
|
|
33
|
+
console.error(`\n----------\nSynchronization with Translation.io failed: ${errors.join(", ")}\n----------`);
|
|
44
34
|
};
|
|
45
|
-
|
|
46
35
|
init(config, options, successCallback, errors => {
|
|
47
|
-
if (errors.length && errors[0] ===
|
|
36
|
+
if (errors.length && errors[0] === "This project has already been initialized.") {
|
|
48
37
|
sync(config, options, successCallback, failCallback);
|
|
49
38
|
} else {
|
|
50
39
|
failCallback(errors);
|
|
51
40
|
}
|
|
52
41
|
});
|
|
53
|
-
}
|
|
54
|
-
// Cf. https://translation.io/docs/create-library#initialization
|
|
55
|
-
|
|
42
|
+
}
|
|
56
43
|
|
|
44
|
+
// Initialize project with source and existing translations (only first time!)
|
|
45
|
+
// Cf. https://translation.io/docs/create-library#initialization
|
|
57
46
|
function init(config, options, successCallback, failCallback) {
|
|
58
|
-
const sourceLocale = config.sourceLocale ||
|
|
59
|
-
const pseudoLocale = config.pseudoLocale ||
|
|
47
|
+
const sourceLocale = config.sourceLocale || "en";
|
|
48
|
+
const pseudoLocale = config.pseudoLocale || "pseudo";
|
|
60
49
|
const targetLocales = config.locales.filter(value => value != sourceLocale && value != pseudoLocale);
|
|
61
50
|
const paths = poPathsPerLocale(config);
|
|
62
51
|
let segments = {};
|
|
63
52
|
targetLocales.forEach(targetLocale => {
|
|
64
53
|
segments[targetLocale] = [];
|
|
65
|
-
});
|
|
54
|
+
});
|
|
66
55
|
|
|
56
|
+
// Create segments from source locale PO items
|
|
67
57
|
paths[sourceLocale].forEach(path => {
|
|
68
58
|
let raw = _fs.default.readFileSync(path).toString();
|
|
69
|
-
|
|
70
59
|
let po = _pofile.default.parse(raw);
|
|
71
|
-
|
|
72
|
-
po.items.filter(item => !item['obsolete']).forEach(item => {
|
|
60
|
+
po.items.filter(item => !item["obsolete"]).forEach(item => {
|
|
73
61
|
targetLocales.forEach(targetLocale => {
|
|
74
62
|
let newSegment = createSegmentFromPoItem(item);
|
|
75
63
|
segments[targetLocale].push(newSegment);
|
|
76
64
|
});
|
|
77
65
|
});
|
|
78
|
-
});
|
|
66
|
+
});
|
|
79
67
|
|
|
68
|
+
// Add translations to segments from target locale PO items
|
|
80
69
|
targetLocales.forEach(targetLocale => {
|
|
81
70
|
paths[targetLocale].forEach(path => {
|
|
82
71
|
let raw = _fs.default.readFileSync(path).toString();
|
|
83
|
-
|
|
84
72
|
let po = _pofile.default.parse(raw);
|
|
85
|
-
|
|
86
|
-
po.items.filter(item => !item['obsolete']).forEach((item, index) => {
|
|
73
|
+
po.items.filter(item => !item["obsolete"]).forEach((item, index) => {
|
|
87
74
|
segments[targetLocale][index].target = item.msgstr[0];
|
|
88
75
|
});
|
|
89
76
|
});
|
|
90
77
|
});
|
|
91
78
|
let request = {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
79
|
+
client: "lingui",
|
|
80
|
+
version: require("@lingui/core/package.json").version,
|
|
81
|
+
source_language: sourceLocale,
|
|
82
|
+
target_languages: targetLocales,
|
|
83
|
+
segments: segments
|
|
97
84
|
};
|
|
98
85
|
postTio("init", request, config.service.apiKey, response => {
|
|
99
86
|
if (response.errors) {
|
|
@@ -105,38 +92,37 @@ function init(config, options, successCallback, failCallback) {
|
|
|
105
92
|
}, error => {
|
|
106
93
|
console.error(`\n----------\nSynchronization with Translation.io failed: ${error}\n----------`);
|
|
107
94
|
});
|
|
108
|
-
}
|
|
109
|
-
// Cf. https://translation.io/docs/create-library#synchronization
|
|
110
|
-
|
|
95
|
+
}
|
|
111
96
|
|
|
97
|
+
// Send all source text from PO to Translation.io and create new PO based on received translations
|
|
98
|
+
// Cf. https://translation.io/docs/create-library#synchronization
|
|
112
99
|
function sync(config, options, successCallback, failCallback) {
|
|
113
|
-
const sourceLocale = config.sourceLocale ||
|
|
100
|
+
const sourceLocale = config.sourceLocale || "en";
|
|
114
101
|
const targetLocales = config.locales.filter(value => value != sourceLocale);
|
|
115
102
|
const paths = poPathsPerLocale(config);
|
|
116
|
-
let segments = [];
|
|
103
|
+
let segments = [];
|
|
117
104
|
|
|
105
|
+
// Create segments with correct source
|
|
118
106
|
paths[sourceLocale].forEach(path => {
|
|
119
107
|
let raw = _fs.default.readFileSync(path).toString();
|
|
120
|
-
|
|
121
108
|
let po = _pofile.default.parse(raw);
|
|
122
|
-
|
|
123
|
-
po.items.filter(item => !item['obsolete']).forEach(item => {
|
|
109
|
+
po.items.filter(item => !item["obsolete"]).forEach(item => {
|
|
124
110
|
let newSegment = createSegmentFromPoItem(item);
|
|
125
111
|
segments.push(newSegment);
|
|
126
112
|
});
|
|
127
113
|
});
|
|
128
114
|
let request = {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
};
|
|
115
|
+
client: "lingui",
|
|
116
|
+
version: require("@lingui/core/package.json").version,
|
|
117
|
+
source_language: sourceLocale,
|
|
118
|
+
target_languages: targetLocales,
|
|
119
|
+
segments: segments
|
|
120
|
+
};
|
|
135
121
|
|
|
122
|
+
// Sync and then remove unused segments (not present in the local application) from Translation.io
|
|
136
123
|
if (options.clean) {
|
|
137
|
-
request[
|
|
124
|
+
request["purge"] = true;
|
|
138
125
|
}
|
|
139
|
-
|
|
140
126
|
postTio("sync", request, config.service.apiKey, response => {
|
|
141
127
|
if (response.errors) {
|
|
142
128
|
failCallback(response.errors);
|
|
@@ -148,63 +134,56 @@ function sync(config, options, successCallback, failCallback) {
|
|
|
148
134
|
console.error(`\n----------\nSynchronization with Translation.io failed: ${error}\n----------`);
|
|
149
135
|
});
|
|
150
136
|
}
|
|
151
|
-
|
|
152
137
|
function createSegmentFromPoItem(item) {
|
|
153
138
|
let itemHasId = item.msgid != item.msgstr[0] && item.msgstr[0].length;
|
|
154
139
|
let segment = {
|
|
155
|
-
type:
|
|
140
|
+
type: "source",
|
|
156
141
|
// No way to edit text for source language (inside code), so not using "key" here
|
|
157
142
|
source: itemHasId ? item.msgstr[0] : item.msgid,
|
|
158
143
|
// msgstr may be empty if --overwrite is used and no ID is used
|
|
159
|
-
context:
|
|
144
|
+
context: "",
|
|
160
145
|
references: [],
|
|
161
|
-
comment:
|
|
146
|
+
comment: ""
|
|
162
147
|
};
|
|
163
|
-
|
|
164
148
|
if (itemHasId) {
|
|
165
149
|
segment.context = item.msgid;
|
|
166
150
|
}
|
|
167
|
-
|
|
168
151
|
if (item.references.length) {
|
|
169
152
|
segment.references = item.references;
|
|
170
153
|
}
|
|
171
|
-
|
|
172
154
|
if (item.extractedComments.length) {
|
|
173
|
-
segment.comment = item.extractedComments.join(
|
|
155
|
+
segment.comment = item.extractedComments.join(" | ");
|
|
174
156
|
}
|
|
175
|
-
|
|
176
157
|
return segment;
|
|
177
158
|
}
|
|
178
|
-
|
|
179
159
|
function createPoItemFromSegment(segment) {
|
|
180
160
|
let item = new _pofile.default.Item();
|
|
181
161
|
item.msgid = segment.context ? segment.context : segment.source;
|
|
182
162
|
item.msgstr = [segment.target];
|
|
183
163
|
item.references = segment.references && segment.references.length ? segment.references : [];
|
|
184
|
-
item.extractedComments = segment.comment ? segment.comment.split(
|
|
164
|
+
item.extractedComments = segment.comment ? segment.comment.split(" | ") : [];
|
|
185
165
|
return item;
|
|
186
166
|
}
|
|
187
|
-
|
|
188
167
|
function saveSegmentsToTargetPos(config, paths, segmentsPerLocale) {
|
|
189
168
|
Object.keys(segmentsPerLocale).forEach(targetLocale => {
|
|
190
169
|
// Remove existing target POs and JS for this target locale
|
|
191
170
|
paths[targetLocale].forEach(path => {
|
|
192
171
|
const jsPath = path.replace(/\.po?$/, "") + ".js";
|
|
193
|
-
const dirPath = (0, _path.dirname)(path);
|
|
172
|
+
const dirPath = (0, _path.dirname)(path);
|
|
194
173
|
|
|
174
|
+
// Remove PO, JS and empty dir
|
|
195
175
|
if (_fs.default.existsSync(path)) {
|
|
196
176
|
_fs.default.unlinkSync(path);
|
|
197
177
|
}
|
|
198
|
-
|
|
199
178
|
if (_fs.default.existsSync(jsPath)) {
|
|
200
179
|
_fs.default.unlinkSync(jsPath);
|
|
201
180
|
}
|
|
202
|
-
|
|
203
181
|
if (_fs.default.existsSync(dirPath) && _fs.default.readdirSync(dirPath).length === 0) {
|
|
204
182
|
_fs.default.rmdirSync(dirPath);
|
|
205
183
|
}
|
|
206
|
-
});
|
|
184
|
+
});
|
|
207
185
|
|
|
186
|
+
// Find target path (ignoring {name})
|
|
208
187
|
const localePath = "".concat(config.catalogs[0].path.replace(/{locale}/g, targetLocale).replace(/{name}/g, ""), ".po");
|
|
209
188
|
const segments = segmentsPerLocale[targetLocale];
|
|
210
189
|
let po = new _pofile.default();
|
|
@@ -213,26 +192,26 @@ function saveSegmentsToTargetPos(config, paths, segmentsPerLocale) {
|
|
|
213
192
|
segments.forEach(segment => {
|
|
214
193
|
let item = createPoItemFromSegment(segment);
|
|
215
194
|
items.push(item);
|
|
216
|
-
});
|
|
195
|
+
});
|
|
217
196
|
|
|
197
|
+
// Sort items by messageId
|
|
218
198
|
po.items = items.sort((a, b) => {
|
|
219
199
|
if (a.msgid < b.msgid) {
|
|
220
200
|
return -1;
|
|
221
201
|
}
|
|
222
|
-
|
|
223
202
|
if (a.msgid > b.msgid) {
|
|
224
203
|
return 1;
|
|
225
204
|
}
|
|
226
|
-
|
|
227
205
|
return 0;
|
|
228
|
-
});
|
|
206
|
+
});
|
|
229
207
|
|
|
208
|
+
// Check that localePath directory exists and save PO file
|
|
230
209
|
_fs.default.promises.mkdir((0, _path.dirname)(localePath), {
|
|
231
210
|
recursive: true
|
|
232
211
|
}).then(() => {
|
|
233
212
|
po.save(localePath, err => {
|
|
234
213
|
if (err) {
|
|
235
|
-
console.error(
|
|
214
|
+
console.error("Error while saving target PO files:");
|
|
236
215
|
console.error(err);
|
|
237
216
|
process.exit(1);
|
|
238
217
|
}
|
|
@@ -240,15 +219,15 @@ function saveSegmentsToTargetPos(config, paths, segmentsPerLocale) {
|
|
|
240
219
|
});
|
|
241
220
|
});
|
|
242
221
|
}
|
|
243
|
-
|
|
244
222
|
function poPathsPerLocale(config) {
|
|
245
223
|
const paths = [];
|
|
246
224
|
config.locales.forEach(locale => {
|
|
247
225
|
paths[locale] = [];
|
|
248
226
|
config.catalogs.forEach(catalog => {
|
|
249
|
-
const path = "".concat(catalog.path.replace(/{locale}/g, locale).replace(/{name}/g, "*"), ".po");
|
|
227
|
+
const path = "".concat(catalog.path.replace(/{locale}/g, locale).replace(/{name}/g, "*"), ".po");
|
|
250
228
|
|
|
251
|
-
|
|
229
|
+
// If {name} is present (replaced by *), list all the existing POs
|
|
230
|
+
if (path.includes("*")) {
|
|
252
231
|
paths[locale] = paths[locale].concat(_glob.default.sync(path));
|
|
253
232
|
} else {
|
|
254
233
|
paths[locale].push(path);
|
|
@@ -257,31 +236,28 @@ function poPathsPerLocale(config) {
|
|
|
257
236
|
});
|
|
258
237
|
return paths;
|
|
259
238
|
}
|
|
260
|
-
|
|
261
239
|
function postTio(action, request, apiKey, successCallback, failCallback) {
|
|
262
240
|
let jsonRequest = JSON.stringify(request);
|
|
263
241
|
let options = {
|
|
264
|
-
hostname:
|
|
265
|
-
path:
|
|
266
|
-
method:
|
|
242
|
+
hostname: "translation.io",
|
|
243
|
+
path: "/api/v1/segments/" + action + ".json?api_key=" + apiKey,
|
|
244
|
+
method: "POST",
|
|
267
245
|
headers: {
|
|
268
|
-
|
|
246
|
+
"Content-Type": "application/json"
|
|
269
247
|
}
|
|
270
248
|
};
|
|
271
|
-
|
|
272
249
|
let req = _https.default.request(options, res => {
|
|
273
|
-
res.setEncoding(
|
|
250
|
+
res.setEncoding("utf8");
|
|
274
251
|
let body = "";
|
|
275
|
-
res.on(
|
|
252
|
+
res.on("data", chunk => {
|
|
276
253
|
body = body.concat(chunk);
|
|
277
254
|
});
|
|
278
|
-
res.on(
|
|
255
|
+
res.on("end", () => {
|
|
279
256
|
let response = JSON.parse(body);
|
|
280
257
|
successCallback(response);
|
|
281
258
|
});
|
|
282
259
|
});
|
|
283
|
-
|
|
284
|
-
req.on('error', e => {
|
|
260
|
+
req.on("error", e => {
|
|
285
261
|
failCallback(e);
|
|
286
262
|
});
|
|
287
263
|
req.write(jsonRequest);
|
package/build/tests.js
CHANGED
|
@@ -4,32 +4,22 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.copyFixture = copyFixture;
|
|
7
|
-
exports.makePrevMessage = makePrevMessage;
|
|
8
|
-
exports.makeNextMessage = makeNextMessage;
|
|
9
7
|
exports.makeCatalog = exports.defaultMergeOptions = exports.defaultMakeTemplateOptions = exports.defaultMakeOptions = void 0;
|
|
10
|
-
|
|
8
|
+
exports.makeNextMessage = makeNextMessage;
|
|
9
|
+
exports.makePrevMessage = makePrevMessage;
|
|
11
10
|
var _os = _interopRequireDefault(require("os"));
|
|
12
|
-
|
|
13
11
|
var _fsExtra = _interopRequireDefault(require("fs-extra"));
|
|
14
|
-
|
|
15
12
|
var _path = _interopRequireDefault(require("path"));
|
|
16
|
-
|
|
17
13
|
var _jestMocks = require("@lingui/jest-mocks");
|
|
18
|
-
|
|
19
14
|
var _catalog = require("./api/catalog");
|
|
20
|
-
|
|
21
15
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
22
|
-
|
|
23
16
|
function copyFixture(fixtureDir) {
|
|
24
17
|
const tmpDir = _fsExtra.default.mkdtempSync(_path.default.join(_os.default.tmpdir(), `lingui-test-${process.pid}`));
|
|
25
|
-
|
|
26
18
|
if (_fsExtra.default.existsSync(fixtureDir)) {
|
|
27
19
|
_fsExtra.default.copySync(fixtureDir, tmpDir);
|
|
28
20
|
}
|
|
29
|
-
|
|
30
21
|
return tmpDir;
|
|
31
22
|
}
|
|
32
|
-
|
|
33
23
|
const defaultMakeOptions = {
|
|
34
24
|
verbose: false,
|
|
35
25
|
clean: false,
|
|
@@ -50,7 +40,6 @@ const defaultMergeOptions = {
|
|
|
50
40
|
overwrite: false
|
|
51
41
|
};
|
|
52
42
|
exports.defaultMergeOptions = defaultMergeOptions;
|
|
53
|
-
|
|
54
43
|
const makeCatalog = (config = {}) => {
|
|
55
44
|
return new _catalog.Catalog({
|
|
56
45
|
name: "messages",
|
|
@@ -59,16 +48,13 @@ const makeCatalog = (config = {}) => {
|
|
|
59
48
|
exclude: []
|
|
60
49
|
}, (0, _jestMocks.mockConfig)(config));
|
|
61
50
|
};
|
|
62
|
-
|
|
63
51
|
exports.makeCatalog = makeCatalog;
|
|
64
|
-
|
|
65
52
|
function makePrevMessage(message = {}) {
|
|
66
53
|
return {
|
|
67
54
|
translation: "",
|
|
68
55
|
...makeNextMessage(message)
|
|
69
56
|
};
|
|
70
57
|
}
|
|
71
|
-
|
|
72
58
|
function makeNextMessage(message = {}) {
|
|
73
59
|
return {
|
|
74
60
|
origin: [["catalog.test.ts", 1]],
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lingui/cli",
|
|
3
|
-
"version": "3.17.
|
|
3
|
+
"version": "3.17.2",
|
|
4
4
|
"description": "CLI for working wit message catalogs",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|
|
@@ -45,14 +45,15 @@
|
|
|
45
45
|
"build/"
|
|
46
46
|
],
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"@babel/generator": "^7.
|
|
49
|
-
"@babel/parser": "^7.
|
|
50
|
-
"@babel/plugin-syntax-jsx": "^7.
|
|
51
|
-
"@babel/runtime": "^7.
|
|
52
|
-
"@babel/types": "^7.
|
|
53
|
-
"@lingui/babel-plugin-extract-messages": "3.17.
|
|
54
|
-
"@lingui/conf": "3.17.
|
|
55
|
-
"@lingui/core": "3.17.
|
|
48
|
+
"@babel/generator": "^7.20.14",
|
|
49
|
+
"@babel/parser": "^7.20.15",
|
|
50
|
+
"@babel/plugin-syntax-jsx": "^7.18.6",
|
|
51
|
+
"@babel/runtime": "^7.20.13",
|
|
52
|
+
"@babel/types": "^7.20.7",
|
|
53
|
+
"@lingui/babel-plugin-extract-messages": "3.17.2",
|
|
54
|
+
"@lingui/conf": "3.17.2",
|
|
55
|
+
"@lingui/core": "3.17.2",
|
|
56
|
+
"@messageformat/parser": "^5.0.0",
|
|
56
57
|
"babel-plugin-macros": "^3.0.1",
|
|
57
58
|
"bcp-47": "^1.0.7",
|
|
58
59
|
"chalk": "^4.1.0",
|
|
@@ -83,12 +84,12 @@
|
|
|
83
84
|
"@types/papaparse": "^5.2.3",
|
|
84
85
|
"@types/plurals-cldr": "^1.0.1",
|
|
85
86
|
"mockdate": "^3.0.2",
|
|
86
|
-
"typescript": "^4.
|
|
87
|
+
"typescript": "^4.9.5"
|
|
87
88
|
},
|
|
88
89
|
"peerDependencies": {
|
|
89
90
|
"@babel/core": "^7.0.0",
|
|
90
91
|
"babel-plugin-macros": "2 || 3",
|
|
91
92
|
"typescript": "2 || 3 || 4"
|
|
92
93
|
},
|
|
93
|
-
"gitHead": "
|
|
94
|
+
"gitHead": "31dcab5a9a8f88bfa8b3a2c7cd12aa2d908a1d80"
|
|
94
95
|
}
|