@theia/localization-manager 1.47.1 → 1.48.1

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.
@@ -1,369 +1,369 @@
1
- "use strict";
2
- // *****************************************************************************
3
- // Copyright (C) 2021 TypeFox and others.
4
- //
5
- // This program and the accompanying materials are made available under the
6
- // terms of the Eclipse Public License v. 2.0 which is available at
7
- // http://www.eclipse.org/legal/epl-2.0.
8
- //
9
- // This Source Code may also be made available under the following Secondary
10
- // Licenses when the conditions for such availability set forth in the Eclipse
11
- // Public License v. 2.0 are satisfied: GNU General Public License, version 2
12
- // with the GNU Classpath Exception which is available at
13
- // https://www.gnu.org/software/classpath/license.html.
14
- //
15
- // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
16
- // *****************************************************************************
17
- Object.defineProperty(exports, "__esModule", { value: true });
18
- exports.extractFromFile = exports.extract = void 0;
19
- const fs = require("fs-extra");
20
- const ts = require("typescript");
21
- const os = require("os");
22
- const path = require("path");
23
- const glob_1 = require("glob");
24
- const util_1 = require("util");
25
- const deepmerge = require("deepmerge");
26
- const common_1 = require("./common");
27
- const globPromise = (0, util_1.promisify)(glob_1.glob);
28
- class SingleFileServiceHost {
29
- constructor(options, filename, contents) {
30
- this.options = options;
31
- this.filename = filename;
32
- this.getCompilationSettings = () => this.options;
33
- this.getScriptFileNames = () => [this.filename];
34
- this.getScriptVersion = () => '1';
35
- this.getScriptSnapshot = (name) => name === this.filename ? this.file : this.lib;
36
- this.getCurrentDirectory = () => '';
37
- this.getDefaultLibFileName = () => 'lib.d.ts';
38
- this.file = ts.ScriptSnapshot.fromString(contents);
39
- this.lib = ts.ScriptSnapshot.fromString('');
40
- }
41
- }
42
- class TypeScriptError extends Error {
43
- constructor(message, node) {
44
- super(buildErrorMessage(message, node));
45
- }
46
- }
47
- function buildErrorMessage(message, node) {
48
- const source = node.getSourceFile();
49
- const sourcePath = source.fileName;
50
- const pos = source.getLineAndCharacterOfPosition(node.pos);
51
- return `${sourcePath}(${pos.line + 1},${pos.character + 1}): ${message}`;
52
- }
53
- const tsOptions = {
54
- allowJs: true
55
- };
56
- async function extract(options) {
57
- var _a, _b, _c;
58
- const cwd = path.resolve(process.env.INIT_CWD || process.cwd(), (_a = options.root) !== null && _a !== void 0 ? _a : '');
59
- const files = [];
60
- await Promise.all(((_b = options.files) !== null && _b !== void 0 ? _b : ['**/src/**/*.{ts,tsx}']).map(async (pattern) => files.push(...await globPromise(pattern, { cwd }))));
61
- let localization = {};
62
- const errors = [];
63
- for (const file of files) {
64
- const filePath = path.resolve(cwd, file);
65
- const content = await fs.readFile(filePath, 'utf8');
66
- const fileLocalization = await extractFromFile(file, content, errors, options);
67
- localization = deepmerge(localization, fileLocalization);
68
- }
69
- if (errors.length > 0 && options.logs) {
70
- await fs.writeFile(options.logs, errors.join(os.EOL));
71
- }
72
- const out = path.resolve(process.env.INIT_CWD || process.cwd(), (_c = options.output) !== null && _c !== void 0 ? _c : '');
73
- if (options.merge && await fs.pathExists(out)) {
74
- const existing = await fs.readJson(out);
75
- localization = deepmerge(existing, localization);
76
- }
77
- localization = (0, common_1.sortLocalization)(localization);
78
- await fs.mkdirs(path.dirname(out));
79
- await fs.writeJson(out, localization, {
80
- spaces: 2
81
- });
82
- }
83
- exports.extract = extract;
84
- async function extractFromFile(file, content, errors, options) {
85
- const serviceHost = new SingleFileServiceHost(tsOptions, file, content);
86
- const service = ts.createLanguageService(serviceHost);
87
- const sourceFile = service.getProgram().getSourceFile(file);
88
- const localization = {};
89
- const localizationCalls = collect(sourceFile, node => isLocalizeCall(node));
90
- for (const call of localizationCalls) {
91
- try {
92
- const extracted = extractFromLocalizeCall(call, options);
93
- if (extracted) {
94
- insert(localization, extracted);
95
- }
96
- }
97
- catch (err) {
98
- const tsError = err;
99
- errors === null || errors === void 0 ? void 0 : errors.push(tsError.message);
100
- if (!(options === null || options === void 0 ? void 0 : options.quiet)) {
101
- console.log(tsError.message);
102
- }
103
- }
104
- }
105
- const localizedCommands = collect(sourceFile, node => isCommandLocalizeUtility(node));
106
- for (const command of localizedCommands) {
107
- try {
108
- const extracted = extractFromLocalizedCommandCall(command, errors, options);
109
- const label = extracted.label;
110
- const category = extracted.category;
111
- if (!isExcluded(options, label[0])) {
112
- insert(localization, label);
113
- }
114
- if (category && !isExcluded(options, category[0])) {
115
- insert(localization, category);
116
- }
117
- }
118
- catch (err) {
119
- const tsError = err;
120
- errors === null || errors === void 0 ? void 0 : errors.push(tsError.message);
121
- if (!(options === null || options === void 0 ? void 0 : options.quiet)) {
122
- console.log(tsError.message);
123
- }
124
- }
125
- }
126
- return localization;
127
- }
128
- exports.extractFromFile = extractFromFile;
129
- function isExcluded(options, key) {
130
- return !!(options === null || options === void 0 ? void 0 : options.exclude) && key.startsWith(options.exclude);
131
- }
132
- function insert(localization, values) {
133
- const key = values[0];
134
- const value = values[1];
135
- const node = values[2];
136
- const parts = key.split('/');
137
- parts.forEach((part, i) => {
138
- let entry = localization[part];
139
- if (i === parts.length - 1) {
140
- if (typeof entry === 'object') {
141
- throw new TypeScriptError(`Multiple translation keys already exist at '${key}'`, node);
142
- }
143
- localization[part] = value;
144
- }
145
- else {
146
- if (typeof entry === 'string') {
147
- throw new TypeScriptError(`String entry already exists at '${parts.splice(0, i + 1).join('/')}'`, node);
148
- }
149
- if (!entry) {
150
- entry = {};
151
- }
152
- localization[part] = entry;
153
- localization = entry;
154
- }
155
- });
156
- }
157
- function collect(n, fn) {
158
- const result = [];
159
- function loop(node) {
160
- const stepResult = fn(node);
161
- if (stepResult) {
162
- result.push(node);
163
- }
164
- else {
165
- ts.forEachChild(node, loop);
166
- }
167
- }
168
- loop(n);
169
- return result;
170
- }
171
- function isLocalizeCall(node) {
172
- if (!ts.isCallExpression(node)) {
173
- return false;
174
- }
175
- return node.expression.getText() === 'nls.localize';
176
- }
177
- function extractFromLocalizeCall(node, options) {
178
- if (!ts.isCallExpression(node)) {
179
- throw new TypeScriptError('Invalid node type', node);
180
- }
181
- const args = node.arguments;
182
- if (args.length < 2) {
183
- throw new TypeScriptError('Localize call needs at least 2 arguments', node);
184
- }
185
- const key = extractString(args[0]);
186
- const value = extractString(args[1]);
187
- if (isExcluded(options, key)) {
188
- return undefined;
189
- }
190
- return [key, value, args[1]];
191
- }
192
- function extractFromLocalizedCommandCall(node, errors, options) {
193
- if (!ts.isCallExpression(node)) {
194
- throw new TypeScriptError('Invalid node type', node);
195
- }
196
- const args = node.arguments;
197
- if (args.length < 1) {
198
- throw new TypeScriptError('Command localization call needs at least one argument', node);
199
- }
200
- const commandObj = args[0];
201
- if (!ts.isObjectLiteralExpression(commandObj)) {
202
- throw new TypeScriptError('First argument of "toLocalizedCommand" needs to be an object literal', node);
203
- }
204
- const properties = commandObj.properties;
205
- const propertyMap = new Map();
206
- const relevantProps = ['id', 'label', 'category'];
207
- let labelNode = node;
208
- for (const property of properties) {
209
- if (!property.name) {
210
- continue;
211
- }
212
- if (!ts.isPropertyAssignment(property)) {
213
- throw new TypeScriptError('Only property assignments in "toLocalizedCommand" are allowed', property);
214
- }
215
- if (!ts.isIdentifier(property.name)) {
216
- throw new TypeScriptError('Only identifiers are allowed as property names in "toLocalizedCommand"', property);
217
- }
218
- const name = property.name.text;
219
- if (!relevantProps.includes(property.name.text)) {
220
- continue;
221
- }
222
- if (property.name.text === 'label') {
223
- labelNode = property.initializer;
224
- }
225
- try {
226
- const value = extractString(property.initializer);
227
- propertyMap.set(name, value);
228
- }
229
- catch (err) {
230
- const tsError = err;
231
- errors === null || errors === void 0 ? void 0 : errors.push(tsError.message);
232
- if (!(options === null || options === void 0 ? void 0 : options.quiet)) {
233
- console.log(tsError.message);
234
- }
235
- }
236
- }
237
- let labelKey = propertyMap.get('id');
238
- let categoryKey = undefined;
239
- let categoryNode;
240
- // We have an explicit label translation key
241
- if (args.length > 1) {
242
- try {
243
- const labelOverrideKey = extractStringOrUndefined(args[1]);
244
- if (labelOverrideKey) {
245
- labelKey = labelOverrideKey;
246
- labelNode = args[1];
247
- }
248
- }
249
- catch (err) {
250
- const tsError = err;
251
- errors === null || errors === void 0 ? void 0 : errors.push(tsError.message);
252
- if (!(options === null || options === void 0 ? void 0 : options.quiet)) {
253
- console.log(tsError.message);
254
- }
255
- }
256
- }
257
- // We have an explicit category translation key
258
- if (args.length > 2) {
259
- try {
260
- categoryKey = extractStringOrUndefined(args[2]);
261
- categoryNode = args[2];
262
- }
263
- catch (err) {
264
- const tsError = err;
265
- errors === null || errors === void 0 ? void 0 : errors.push(tsError.message);
266
- if (!(options === null || options === void 0 ? void 0 : options.quiet)) {
267
- console.log(tsError.message);
268
- }
269
- }
270
- }
271
- if (!labelKey) {
272
- throw new TypeScriptError('No label key found', node);
273
- }
274
- if (!propertyMap.get('label')) {
275
- throw new TypeScriptError('No default label found', node);
276
- }
277
- let categoryLocalization = undefined;
278
- const categoryLabel = propertyMap.get('category');
279
- if (categoryKey && categoryLabel && categoryNode) {
280
- categoryLocalization = [categoryKey, categoryLabel, categoryNode];
281
- }
282
- return {
283
- label: [labelKey, propertyMap.get('label'), labelNode],
284
- category: categoryLocalization
285
- };
286
- }
287
- function extractStringOrUndefined(node) {
288
- if (node.getText() === 'undefined') {
289
- return undefined;
290
- }
291
- return extractString(node);
292
- }
293
- function extractString(node) {
294
- if (ts.isIdentifier(node)) {
295
- const reference = followReference(node);
296
- if (!reference) {
297
- throw new TypeScriptError(`Could not resolve reference to '${node.text}'`, node);
298
- }
299
- node = reference;
300
- }
301
- if (ts.isTemplateLiteral(node)) {
302
- throw new TypeScriptError("Template literals are not supported for localization. Please use the additional arguments of the 'nls.localize' function to format strings", node);
303
- }
304
- if (!ts.isStringLiteralLike(node)) {
305
- throw new TypeScriptError(`'${node.getText()}' is not a string constant`, node);
306
- }
307
- return unescapeString(node.text);
308
- }
309
- function followReference(node) {
310
- const scope = collectScope(node);
311
- const next = scope.get(node.text);
312
- if (next && ts.isIdentifier(next)) {
313
- return followReference(next);
314
- }
315
- return next;
316
- }
317
- function collectScope(node, map = new Map()) {
318
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
319
- const locals = node['locals'];
320
- if (locals) {
321
- for (const [key, value] of locals.entries()) {
322
- if (!map.has(key)) {
323
- const declaration = value.valueDeclaration;
324
- if (declaration && ts.isVariableDeclaration(declaration) && declaration.initializer) {
325
- map.set(key, declaration.initializer);
326
- }
327
- }
328
- }
329
- }
330
- if (node.parent) {
331
- collectScope(node.parent, map);
332
- }
333
- return map;
334
- }
335
- function isCommandLocalizeUtility(node) {
336
- if (!ts.isCallExpression(node)) {
337
- return false;
338
- }
339
- return node.expression.getText() === 'Command.toLocalizedCommand';
340
- }
341
- const unescapeMap = {
342
- '\'': '\'',
343
- '"': '"',
344
- '\\': '\\',
345
- 'n': '\n',
346
- 'r': '\r',
347
- 't': '\t',
348
- 'b': '\b',
349
- 'f': '\f'
350
- };
351
- function unescapeString(str) {
352
- const result = [];
353
- for (let i = 0; i < str.length; i++) {
354
- const ch = str.charAt(i);
355
- if (ch === '\\') {
356
- if (i + 1 < str.length) {
357
- const replace = unescapeMap[str.charAt(i + 1)];
358
- if (replace !== undefined) {
359
- result.push(replace);
360
- i++;
361
- continue;
362
- }
363
- }
364
- }
365
- result.push(ch);
366
- }
367
- return result.join('');
368
- }
1
+ "use strict";
2
+ // *****************************************************************************
3
+ // Copyright (C) 2021 TypeFox and others.
4
+ //
5
+ // This program and the accompanying materials are made available under the
6
+ // terms of the Eclipse Public License v. 2.0 which is available at
7
+ // http://www.eclipse.org/legal/epl-2.0.
8
+ //
9
+ // This Source Code may also be made available under the following Secondary
10
+ // Licenses when the conditions for such availability set forth in the Eclipse
11
+ // Public License v. 2.0 are satisfied: GNU General Public License, version 2
12
+ // with the GNU Classpath Exception which is available at
13
+ // https://www.gnu.org/software/classpath/license.html.
14
+ //
15
+ // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
16
+ // *****************************************************************************
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports.extractFromFile = exports.extract = void 0;
19
+ const fs = require("fs-extra");
20
+ const ts = require("typescript");
21
+ const os = require("os");
22
+ const path = require("path");
23
+ const glob_1 = require("glob");
24
+ const util_1 = require("util");
25
+ const deepmerge = require("deepmerge");
26
+ const common_1 = require("./common");
27
+ const globPromise = (0, util_1.promisify)(glob_1.glob);
28
+ class SingleFileServiceHost {
29
+ constructor(options, filename, contents) {
30
+ this.options = options;
31
+ this.filename = filename;
32
+ this.getCompilationSettings = () => this.options;
33
+ this.getScriptFileNames = () => [this.filename];
34
+ this.getScriptVersion = () => '1';
35
+ this.getScriptSnapshot = (name) => name === this.filename ? this.file : this.lib;
36
+ this.getCurrentDirectory = () => '';
37
+ this.getDefaultLibFileName = () => 'lib.d.ts';
38
+ this.file = ts.ScriptSnapshot.fromString(contents);
39
+ this.lib = ts.ScriptSnapshot.fromString('');
40
+ }
41
+ }
42
+ class TypeScriptError extends Error {
43
+ constructor(message, node) {
44
+ super(buildErrorMessage(message, node));
45
+ }
46
+ }
47
+ function buildErrorMessage(message, node) {
48
+ const source = node.getSourceFile();
49
+ const sourcePath = source.fileName;
50
+ const pos = source.getLineAndCharacterOfPosition(node.pos);
51
+ return `${sourcePath}(${pos.line + 1},${pos.character + 1}): ${message}`;
52
+ }
53
+ const tsOptions = {
54
+ allowJs: true
55
+ };
56
+ async function extract(options) {
57
+ var _a, _b, _c;
58
+ const cwd = path.resolve(process.env.INIT_CWD || process.cwd(), (_a = options.root) !== null && _a !== void 0 ? _a : '');
59
+ const files = [];
60
+ await Promise.all(((_b = options.files) !== null && _b !== void 0 ? _b : ['**/src/**/*.{ts,tsx}']).map(async (pattern) => files.push(...await globPromise(pattern, { cwd }))));
61
+ let localization = {};
62
+ const errors = [];
63
+ for (const file of files) {
64
+ const filePath = path.resolve(cwd, file);
65
+ const content = await fs.readFile(filePath, 'utf8');
66
+ const fileLocalization = await extractFromFile(file, content, errors, options);
67
+ localization = deepmerge(localization, fileLocalization);
68
+ }
69
+ if (errors.length > 0 && options.logs) {
70
+ await fs.writeFile(options.logs, errors.join(os.EOL));
71
+ }
72
+ const out = path.resolve(process.env.INIT_CWD || process.cwd(), (_c = options.output) !== null && _c !== void 0 ? _c : '');
73
+ if (options.merge && await fs.pathExists(out)) {
74
+ const existing = await fs.readJson(out);
75
+ localization = deepmerge(existing, localization);
76
+ }
77
+ localization = (0, common_1.sortLocalization)(localization);
78
+ await fs.mkdirs(path.dirname(out));
79
+ await fs.writeJson(out, localization, {
80
+ spaces: 2
81
+ });
82
+ }
83
+ exports.extract = extract;
84
+ async function extractFromFile(file, content, errors, options) {
85
+ const serviceHost = new SingleFileServiceHost(tsOptions, file, content);
86
+ const service = ts.createLanguageService(serviceHost);
87
+ const sourceFile = service.getProgram().getSourceFile(file);
88
+ const localization = {};
89
+ const localizationCalls = collect(sourceFile, node => isLocalizeCall(node));
90
+ for (const call of localizationCalls) {
91
+ try {
92
+ const extracted = extractFromLocalizeCall(call, options);
93
+ if (extracted) {
94
+ insert(localization, extracted);
95
+ }
96
+ }
97
+ catch (err) {
98
+ const tsError = err;
99
+ errors === null || errors === void 0 ? void 0 : errors.push(tsError.message);
100
+ if (!(options === null || options === void 0 ? void 0 : options.quiet)) {
101
+ console.log(tsError.message);
102
+ }
103
+ }
104
+ }
105
+ const localizedCommands = collect(sourceFile, node => isCommandLocalizeUtility(node));
106
+ for (const command of localizedCommands) {
107
+ try {
108
+ const extracted = extractFromLocalizedCommandCall(command, errors, options);
109
+ const label = extracted.label;
110
+ const category = extracted.category;
111
+ if (!isExcluded(options, label[0])) {
112
+ insert(localization, label);
113
+ }
114
+ if (category && !isExcluded(options, category[0])) {
115
+ insert(localization, category);
116
+ }
117
+ }
118
+ catch (err) {
119
+ const tsError = err;
120
+ errors === null || errors === void 0 ? void 0 : errors.push(tsError.message);
121
+ if (!(options === null || options === void 0 ? void 0 : options.quiet)) {
122
+ console.log(tsError.message);
123
+ }
124
+ }
125
+ }
126
+ return localization;
127
+ }
128
+ exports.extractFromFile = extractFromFile;
129
+ function isExcluded(options, key) {
130
+ return !!(options === null || options === void 0 ? void 0 : options.exclude) && key.startsWith(options.exclude);
131
+ }
132
+ function insert(localization, values) {
133
+ const key = values[0];
134
+ const value = values[1];
135
+ const node = values[2];
136
+ const parts = key.split('/');
137
+ parts.forEach((part, i) => {
138
+ let entry = localization[part];
139
+ if (i === parts.length - 1) {
140
+ if (typeof entry === 'object') {
141
+ throw new TypeScriptError(`Multiple translation keys already exist at '${key}'`, node);
142
+ }
143
+ localization[part] = value;
144
+ }
145
+ else {
146
+ if (typeof entry === 'string') {
147
+ throw new TypeScriptError(`String entry already exists at '${parts.splice(0, i + 1).join('/')}'`, node);
148
+ }
149
+ if (!entry) {
150
+ entry = {};
151
+ }
152
+ localization[part] = entry;
153
+ localization = entry;
154
+ }
155
+ });
156
+ }
157
+ function collect(n, fn) {
158
+ const result = [];
159
+ function loop(node) {
160
+ const stepResult = fn(node);
161
+ if (stepResult) {
162
+ result.push(node);
163
+ }
164
+ else {
165
+ ts.forEachChild(node, loop);
166
+ }
167
+ }
168
+ loop(n);
169
+ return result;
170
+ }
171
+ function isLocalizeCall(node) {
172
+ if (!ts.isCallExpression(node)) {
173
+ return false;
174
+ }
175
+ return node.expression.getText() === 'nls.localize';
176
+ }
177
+ function extractFromLocalizeCall(node, options) {
178
+ if (!ts.isCallExpression(node)) {
179
+ throw new TypeScriptError('Invalid node type', node);
180
+ }
181
+ const args = node.arguments;
182
+ if (args.length < 2) {
183
+ throw new TypeScriptError('Localize call needs at least 2 arguments', node);
184
+ }
185
+ const key = extractString(args[0]);
186
+ const value = extractString(args[1]);
187
+ if (isExcluded(options, key)) {
188
+ return undefined;
189
+ }
190
+ return [key, value, args[1]];
191
+ }
192
+ function extractFromLocalizedCommandCall(node, errors, options) {
193
+ if (!ts.isCallExpression(node)) {
194
+ throw new TypeScriptError('Invalid node type', node);
195
+ }
196
+ const args = node.arguments;
197
+ if (args.length < 1) {
198
+ throw new TypeScriptError('Command localization call needs at least one argument', node);
199
+ }
200
+ const commandObj = args[0];
201
+ if (!ts.isObjectLiteralExpression(commandObj)) {
202
+ throw new TypeScriptError('First argument of "toLocalizedCommand" needs to be an object literal', node);
203
+ }
204
+ const properties = commandObj.properties;
205
+ const propertyMap = new Map();
206
+ const relevantProps = ['id', 'label', 'category'];
207
+ let labelNode = node;
208
+ for (const property of properties) {
209
+ if (!property.name) {
210
+ continue;
211
+ }
212
+ if (!ts.isPropertyAssignment(property)) {
213
+ throw new TypeScriptError('Only property assignments in "toLocalizedCommand" are allowed', property);
214
+ }
215
+ if (!ts.isIdentifier(property.name)) {
216
+ throw new TypeScriptError('Only identifiers are allowed as property names in "toLocalizedCommand"', property);
217
+ }
218
+ const name = property.name.text;
219
+ if (!relevantProps.includes(property.name.text)) {
220
+ continue;
221
+ }
222
+ if (property.name.text === 'label') {
223
+ labelNode = property.initializer;
224
+ }
225
+ try {
226
+ const value = extractString(property.initializer);
227
+ propertyMap.set(name, value);
228
+ }
229
+ catch (err) {
230
+ const tsError = err;
231
+ errors === null || errors === void 0 ? void 0 : errors.push(tsError.message);
232
+ if (!(options === null || options === void 0 ? void 0 : options.quiet)) {
233
+ console.log(tsError.message);
234
+ }
235
+ }
236
+ }
237
+ let labelKey = propertyMap.get('id');
238
+ let categoryKey = undefined;
239
+ let categoryNode;
240
+ // We have an explicit label translation key
241
+ if (args.length > 1) {
242
+ try {
243
+ const labelOverrideKey = extractStringOrUndefined(args[1]);
244
+ if (labelOverrideKey) {
245
+ labelKey = labelOverrideKey;
246
+ labelNode = args[1];
247
+ }
248
+ }
249
+ catch (err) {
250
+ const tsError = err;
251
+ errors === null || errors === void 0 ? void 0 : errors.push(tsError.message);
252
+ if (!(options === null || options === void 0 ? void 0 : options.quiet)) {
253
+ console.log(tsError.message);
254
+ }
255
+ }
256
+ }
257
+ // We have an explicit category translation key
258
+ if (args.length > 2) {
259
+ try {
260
+ categoryKey = extractStringOrUndefined(args[2]);
261
+ categoryNode = args[2];
262
+ }
263
+ catch (err) {
264
+ const tsError = err;
265
+ errors === null || errors === void 0 ? void 0 : errors.push(tsError.message);
266
+ if (!(options === null || options === void 0 ? void 0 : options.quiet)) {
267
+ console.log(tsError.message);
268
+ }
269
+ }
270
+ }
271
+ if (!labelKey) {
272
+ throw new TypeScriptError('No label key found', node);
273
+ }
274
+ if (!propertyMap.get('label')) {
275
+ throw new TypeScriptError('No default label found', node);
276
+ }
277
+ let categoryLocalization = undefined;
278
+ const categoryLabel = propertyMap.get('category');
279
+ if (categoryKey && categoryLabel && categoryNode) {
280
+ categoryLocalization = [categoryKey, categoryLabel, categoryNode];
281
+ }
282
+ return {
283
+ label: [labelKey, propertyMap.get('label'), labelNode],
284
+ category: categoryLocalization
285
+ };
286
+ }
287
+ function extractStringOrUndefined(node) {
288
+ if (node.getText() === 'undefined') {
289
+ return undefined;
290
+ }
291
+ return extractString(node);
292
+ }
293
+ function extractString(node) {
294
+ if (ts.isIdentifier(node)) {
295
+ const reference = followReference(node);
296
+ if (!reference) {
297
+ throw new TypeScriptError(`Could not resolve reference to '${node.text}'`, node);
298
+ }
299
+ node = reference;
300
+ }
301
+ if (ts.isTemplateLiteral(node)) {
302
+ throw new TypeScriptError("Template literals are not supported for localization. Please use the additional arguments of the 'nls.localize' function to format strings", node);
303
+ }
304
+ if (!ts.isStringLiteralLike(node)) {
305
+ throw new TypeScriptError(`'${node.getText()}' is not a string constant`, node);
306
+ }
307
+ return unescapeString(node.text);
308
+ }
309
+ function followReference(node) {
310
+ const scope = collectScope(node);
311
+ const next = scope.get(node.text);
312
+ if (next && ts.isIdentifier(next)) {
313
+ return followReference(next);
314
+ }
315
+ return next;
316
+ }
317
+ function collectScope(node, map = new Map()) {
318
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
319
+ const locals = node['locals'];
320
+ if (locals) {
321
+ for (const [key, value] of locals.entries()) {
322
+ if (!map.has(key)) {
323
+ const declaration = value.valueDeclaration;
324
+ if (declaration && ts.isVariableDeclaration(declaration) && declaration.initializer) {
325
+ map.set(key, declaration.initializer);
326
+ }
327
+ }
328
+ }
329
+ }
330
+ if (node.parent) {
331
+ collectScope(node.parent, map);
332
+ }
333
+ return map;
334
+ }
335
+ function isCommandLocalizeUtility(node) {
336
+ if (!ts.isCallExpression(node)) {
337
+ return false;
338
+ }
339
+ return node.expression.getText() === 'Command.toLocalizedCommand';
340
+ }
341
+ const unescapeMap = {
342
+ '\'': '\'',
343
+ '"': '"',
344
+ '\\': '\\',
345
+ 'n': '\n',
346
+ 'r': '\r',
347
+ 't': '\t',
348
+ 'b': '\b',
349
+ 'f': '\f'
350
+ };
351
+ function unescapeString(str) {
352
+ const result = [];
353
+ for (let i = 0; i < str.length; i++) {
354
+ const ch = str.charAt(i);
355
+ if (ch === '\\') {
356
+ if (i + 1 < str.length) {
357
+ const replace = unescapeMap[str.charAt(i + 1)];
358
+ if (replace !== undefined) {
359
+ result.push(replace);
360
+ i++;
361
+ continue;
362
+ }
363
+ }
364
+ }
365
+ result.push(ch);
366
+ }
367
+ return result.join('');
368
+ }
369
369
  //# sourceMappingURL=localization-extractor.js.map