@tolgee/cli 1.0.1 → 1.1.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/dist/commands/sync/compare.js +6 -4
- package/dist/commands/sync/sync.js +4 -4
- package/dist/commands/sync/syncUtils.js +26 -8
- package/dist/config/tolgeerc.js +3 -3
- package/dist/extractor/extractor.js +65 -0
- package/dist/extractor/machines/comments.js +83 -0
- package/dist/extractor/machines/react.js +25 -1
- package/dist/extractor/machines/shared/properties.js +47 -2
- package/dist/extractor/machines/svelte.js +495 -0
- package/dist/extractor/tokenizer.js +6 -1
- package/dist/extractor/warnings.js +0 -2
- package/dist/extractor/worker.js +2 -3
- package/dist/index.js +36 -28
- package/dist/options.js +1 -1
- package/dist/utils/moduleLoader.js +1 -0
- package/package.json +9 -3
- package/textmate/Svelte.tmLanguage +1084 -0
- package/textmate/THIRD_PARTY_NOTICE +13 -0
- package/textmate/TypeScript.tmLanguage +98 -90
- package/textmate/TypeScriptReact.tmLanguage +80 -72
- package/dist/extractor/presets/react.js +0 -29
@@ -23,17 +23,19 @@ async function compareHandler(pattern) {
|
|
23
23
|
}
|
24
24
|
console.log('Your code project and Tolgee project are out of sync.');
|
25
25
|
if (diff.added.length) {
|
26
|
-
|
26
|
+
const key = diff.added.length === 1 ? 'key' : 'keys';
|
27
|
+
console.log(ansi_colors_1.default.green.bold(`${diff.added.length} new ${key} found`));
|
27
28
|
for (const key of diff.added) {
|
28
|
-
(0, syncUtils_1.printKey)(key,
|
29
|
+
(0, syncUtils_1.printKey)(key, false);
|
29
30
|
}
|
30
31
|
// Line break
|
31
32
|
console.log('');
|
32
33
|
}
|
33
34
|
if (diff.removed.length) {
|
34
|
-
|
35
|
+
const key = diff.removed.length === 1 ? 'key' : 'keys';
|
36
|
+
console.log(ansi_colors_1.default.red.bold(`${diff.removed.length} unused ${key}`));
|
35
37
|
for (const key of diff.removed) {
|
36
|
-
(0, syncUtils_1.printKey)(key,
|
38
|
+
(0, syncUtils_1.printKey)(key, true);
|
37
39
|
}
|
38
40
|
// Line break
|
39
41
|
console.log('');
|
@@ -27,8 +27,8 @@ async function askForConfirmation(keys, operation) {
|
|
27
27
|
process.exit(1);
|
28
28
|
}
|
29
29
|
const str = `The following keys will be ${operation}:`;
|
30
|
-
console.log(operation === '
|
31
|
-
keys.forEach((k) => (0, syncUtils_1.printKey)(k, operation));
|
30
|
+
console.log(operation === 'created' ? ansi_colors_1.default.bold.green(str) : ansi_colors_1.default.bold.red(str));
|
31
|
+
keys.forEach((k) => (0, syncUtils_1.printKey)(k, operation === 'deleted'));
|
32
32
|
const shouldContinue = await (0, ask_1.askBoolean)('Does this look correct?', true);
|
33
33
|
if (!shouldContinue) {
|
34
34
|
(0, logger_1.error)('Aborting.');
|
@@ -65,7 +65,7 @@ async function syncHandler(pattern) {
|
|
65
65
|
// Create new keys
|
66
66
|
if (diff.added.length) {
|
67
67
|
if (!opts.yes) {
|
68
|
-
await askForConfirmation(diff.added, '
|
68
|
+
await askForConfirmation(diff.added, 'created');
|
69
69
|
}
|
70
70
|
const keys = diff.added.map((key) => ({
|
71
71
|
name: key.keyName,
|
@@ -80,7 +80,7 @@ async function syncHandler(pattern) {
|
|
80
80
|
// Delete unused keys.
|
81
81
|
if (diff.removed.length) {
|
82
82
|
if (!opts.yes) {
|
83
|
-
await askForConfirmation(diff.removed, '
|
83
|
+
await askForConfirmation(diff.removed, 'deleted');
|
84
84
|
}
|
85
85
|
const ids = await diff.removed.map((k) => k.id);
|
86
86
|
await (0, logger_1.loading)('Deleting unused keys...', opts.client.project.deleteBulkKeys(ids));
|
@@ -10,17 +10,17 @@ const ansi_colors_1 = __importDefault(require("ansi-colors"));
|
|
10
10
|
* Prints information about a key, with coloring and formatting.
|
11
11
|
*
|
12
12
|
* @param key The key to print.
|
13
|
-
* @param
|
13
|
+
* @param deletion True if the key is about to be deleted.
|
14
14
|
*/
|
15
|
-
function printKey(key,
|
15
|
+
function printKey(key, deletion) {
|
16
16
|
const namespace = key.namespace
|
17
17
|
? ` ${ansi_colors_1.default.italic(`(namespace: ${key.namespace})`)}`
|
18
18
|
: '';
|
19
|
-
if (
|
20
|
-
console.log(`${ansi_colors_1.default.
|
19
|
+
if (deletion) {
|
20
|
+
console.log(`${ansi_colors_1.default.red(`- ${key.keyName}`)}${namespace}`);
|
21
21
|
}
|
22
22
|
else {
|
23
|
-
console.log(`${ansi_colors_1.default.
|
23
|
+
console.log(`${ansi_colors_1.default.green(`+ ${key.keyName}`)}${namespace}`);
|
24
24
|
}
|
25
25
|
}
|
26
26
|
exports.printKey = printKey;
|
@@ -47,18 +47,36 @@ function compareKeys(local, remote) {
|
|
47
47
|
}
|
48
48
|
}
|
49
49
|
// Added keys
|
50
|
-
const namespaces = [...Object.keys(local)
|
50
|
+
const namespaces = [runner_1.NullNamespace, ...Object.keys(local).sort()];
|
51
51
|
for (const namespace of namespaces) {
|
52
52
|
if (namespace in local && local[namespace].size) {
|
53
|
-
|
53
|
+
const keys = local[namespace];
|
54
|
+
const keyNames = Array.from(local[namespace].keys()).sort();
|
55
|
+
for (const keyName of keyNames) {
|
54
56
|
result.added.push({
|
55
57
|
keyName: keyName,
|
56
58
|
namespace: namespace === runner_1.NullNamespace ? undefined : namespace,
|
57
|
-
defaultValue:
|
59
|
+
defaultValue: keys.get(keyName) || undefined,
|
58
60
|
});
|
59
61
|
}
|
60
62
|
}
|
61
63
|
}
|
64
|
+
// Sort keys
|
65
|
+
// This is only necessary for unused keys, because the added keys are sorted directly as they're added.
|
66
|
+
result.removed.sort((a, b) => {
|
67
|
+
if (a.namespace === b.namespace) {
|
68
|
+
return a.keyName > b.keyName ? 1 : a.keyName < b.keyName ? -1 : 0;
|
69
|
+
}
|
70
|
+
if (!a.namespace && b.namespace)
|
71
|
+
return -1;
|
72
|
+
if (a.namespace && !b.namespace)
|
73
|
+
return 1;
|
74
|
+
return a.namespace > b.namespace
|
75
|
+
? 1
|
76
|
+
: a.namespace < b.namespace
|
77
|
+
? -1
|
78
|
+
: 0;
|
79
|
+
});
|
62
80
|
return result;
|
63
81
|
}
|
64
82
|
exports.compareKeys = compareKeys;
|
package/dist/config/tolgeerc.js
CHANGED
@@ -26,10 +26,10 @@ function parseConfig(rc) {
|
|
26
26
|
}
|
27
27
|
}
|
28
28
|
if ('projectId' in rc) {
|
29
|
-
|
30
|
-
|
29
|
+
cfg.projectId = Number(rc.projectId); // Number("") returns 0
|
30
|
+
if (!Number.isInteger(cfg.projectId) || cfg.projectId <= 0) {
|
31
|
+
throw new Error('Invalid config: projectId should be an integer representing your project Id');
|
31
32
|
}
|
32
|
-
cfg.projectId = rc.projectId;
|
33
33
|
}
|
34
34
|
if ('sdk' in rc) {
|
35
35
|
if (!constants_1.SDKS.includes(rc.sdk)) {
|
@@ -0,0 +1,65 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
|
+
};
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
6
|
+
const path_1 = require("path");
|
7
|
+
const xstate_1 = require("xstate");
|
8
|
+
const react_1 = __importDefault(require("./machines/react"));
|
9
|
+
const svelte_1 = __importDefault(require("./machines/svelte"));
|
10
|
+
const comments_1 = __importDefault(require("./machines/comments"));
|
11
|
+
const tokenizer_1 = __importDefault(require("./tokenizer"));
|
12
|
+
const REACT_EXTS = [
|
13
|
+
'.js',
|
14
|
+
'.mjs',
|
15
|
+
'.cjs',
|
16
|
+
'.ts',
|
17
|
+
'.mts',
|
18
|
+
'.cts',
|
19
|
+
'.jsx',
|
20
|
+
'.tsx',
|
21
|
+
];
|
22
|
+
const ALL_EXTS = [
|
23
|
+
'.js',
|
24
|
+
'.mjs',
|
25
|
+
'.cjs',
|
26
|
+
'.ts',
|
27
|
+
'.mts',
|
28
|
+
'.cts',
|
29
|
+
'.jsx',
|
30
|
+
'.tsx',
|
31
|
+
'.svelte',
|
32
|
+
];
|
33
|
+
function pickMachine(code, fileName) {
|
34
|
+
const ext = (0, path_1.extname)(fileName);
|
35
|
+
if (REACT_EXTS.includes(ext) && code.includes('@tolgee/react')) {
|
36
|
+
return react_1.default;
|
37
|
+
}
|
38
|
+
if (ext === '.svelte' && code.includes('@tolgee/svelte')) {
|
39
|
+
return svelte_1.default;
|
40
|
+
}
|
41
|
+
if (ALL_EXTS.includes(ext) &&
|
42
|
+
(code.includes('@tolgee-key') || code.includes('@tolgee-ignore'))) {
|
43
|
+
return comments_1.default;
|
44
|
+
}
|
45
|
+
return null;
|
46
|
+
}
|
47
|
+
async function extractor(code, fileName) {
|
48
|
+
const machineSpec = pickMachine(code, fileName);
|
49
|
+
if (!machineSpec) {
|
50
|
+
return { warnings: [], keys: [] };
|
51
|
+
}
|
52
|
+
const tokens = await (0, tokenizer_1.default)(code, fileName);
|
53
|
+
// @ts-ignore -- Types are whacky, complains about withConfig but it's not a problem here.
|
54
|
+
const machine = (0, xstate_1.interpret)(machineSpec);
|
55
|
+
machine.start();
|
56
|
+
for (const token of tokens) {
|
57
|
+
machine.send(token);
|
58
|
+
}
|
59
|
+
const snapshot = machine.getSnapshot();
|
60
|
+
return {
|
61
|
+
warnings: snapshot.context.warnings,
|
62
|
+
keys: snapshot.context.keys,
|
63
|
+
};
|
64
|
+
}
|
65
|
+
exports.default = extractor;
|
@@ -0,0 +1,83 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
|
+
};
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
6
|
+
const xstate_1 = require("xstate");
|
7
|
+
const comments_1 = __importDefault(require("./shared/comments"));
|
8
|
+
exports.default = (0, xstate_1.createMachine)({
|
9
|
+
predictableActionArguments: true,
|
10
|
+
id: 'commentsExtractor',
|
11
|
+
context: {
|
12
|
+
keys: [],
|
13
|
+
warnings: [],
|
14
|
+
},
|
15
|
+
invoke: {
|
16
|
+
id: 'comments',
|
17
|
+
src: () => comments_1.default,
|
18
|
+
},
|
19
|
+
on: {
|
20
|
+
// Service messages
|
21
|
+
MAGIC_COMMENT: [
|
22
|
+
{
|
23
|
+
actions: 'warnUnusedIgnore',
|
24
|
+
cond: (_ctx, evt) => evt.kind === 'ignore',
|
25
|
+
},
|
26
|
+
{
|
27
|
+
actions: 'pushKey',
|
28
|
+
cond: (_ctx, evt) => evt.kind === 'key',
|
29
|
+
},
|
30
|
+
],
|
31
|
+
WARNING: {
|
32
|
+
actions: 'pushWarning',
|
33
|
+
},
|
34
|
+
// Code messages
|
35
|
+
'comment.line.double-slash.ts': {
|
36
|
+
actions: (0, xstate_1.send)((_ctx, evt) => ({
|
37
|
+
type: 'COMMENT',
|
38
|
+
data: evt.token,
|
39
|
+
line: evt.line,
|
40
|
+
}), { to: 'comments' }),
|
41
|
+
},
|
42
|
+
'comment.block.ts': {
|
43
|
+
actions: (0, xstate_1.send)((_ctx, evt) => ({
|
44
|
+
type: 'COMMENT',
|
45
|
+
data: evt.token,
|
46
|
+
line: evt.line,
|
47
|
+
}), { to: 'comments' }),
|
48
|
+
},
|
49
|
+
'comment.block.svelte': {
|
50
|
+
actions: (0, xstate_1.send)((_ctx, evt) => ({
|
51
|
+
type: 'COMMENT',
|
52
|
+
data: evt.token,
|
53
|
+
line: evt.line,
|
54
|
+
}), { to: 'comments' }),
|
55
|
+
},
|
56
|
+
},
|
57
|
+
}, {
|
58
|
+
actions: {
|
59
|
+
warnUnusedIgnore: (0, xstate_1.assign)({
|
60
|
+
warnings: (ctx, evt) => [
|
61
|
+
...ctx.warnings,
|
62
|
+
{ warning: 'W_UNUSED_IGNORE', line: evt.line },
|
63
|
+
],
|
64
|
+
}),
|
65
|
+
pushKey: (0, xstate_1.assign)({
|
66
|
+
keys: (ctx, evt) => [
|
67
|
+
...ctx.keys,
|
68
|
+
{
|
69
|
+
keyName: evt.keyName,
|
70
|
+
namespace: evt.namespace,
|
71
|
+
defaultValue: evt.defaultValue,
|
72
|
+
line: evt.line,
|
73
|
+
},
|
74
|
+
],
|
75
|
+
}),
|
76
|
+
pushWarning: (0, xstate_1.assign)({
|
77
|
+
warnings: (ctx, evt) => [
|
78
|
+
...ctx.warnings,
|
79
|
+
{ warning: evt.kind, line: evt.line },
|
80
|
+
],
|
81
|
+
}),
|
82
|
+
},
|
83
|
+
});
|
@@ -393,6 +393,30 @@ exports.default = (0, xstate_1.createMachine)({
|
|
393
393
|
target: 'idle',
|
394
394
|
actions: ['dynamicChildren', 'pushKey'],
|
395
395
|
},
|
396
|
+
'variable.other.object.ts': {
|
397
|
+
target: 'idle',
|
398
|
+
actions: ['dynamicChildren', 'pushKey'],
|
399
|
+
},
|
400
|
+
'entity.name.function.ts': {
|
401
|
+
target: 'idle',
|
402
|
+
actions: ['dynamicChildren', 'pushKey'],
|
403
|
+
},
|
404
|
+
'storage.type.function.ts': {
|
405
|
+
target: 'idle',
|
406
|
+
actions: ['dynamicChildren', 'pushKey'],
|
407
|
+
},
|
408
|
+
'storage.type.class.ts': {
|
409
|
+
target: 'idle',
|
410
|
+
actions: ['dynamicChildren', 'pushKey'],
|
411
|
+
},
|
412
|
+
'keyword.operator.new.ts': {
|
413
|
+
target: 'idle',
|
414
|
+
actions: ['dynamicChildren', 'pushKey'],
|
415
|
+
},
|
416
|
+
'punctuation.definition.block.ts': {
|
417
|
+
target: 'idle',
|
418
|
+
actions: ['dynamicChildren', 'pushKey'],
|
419
|
+
},
|
396
420
|
'punctuation.definition.template-expression.begin.ts': {
|
397
421
|
target: 'idle',
|
398
422
|
actions: ['dynamicChildren', 'pushKey'],
|
@@ -648,7 +672,7 @@ exports.default = (0, xstate_1.createMachine)({
|
|
648
672
|
...ctx.key,
|
649
673
|
namespace: ctx.hooks.length
|
650
674
|
? ctx.hooks[ctx.hooks.length - 1].namespace
|
651
|
-
:
|
675
|
+
: undefined,
|
652
676
|
}),
|
653
677
|
}),
|
654
678
|
dynamicKeyName: (0, xstate_1.assign)({
|
@@ -42,6 +42,13 @@ exports.default = (0, xstate_1.createMachine)({
|
|
42
42
|
target: 'value',
|
43
43
|
actions: 'markAsStatic',
|
44
44
|
},
|
45
|
+
// Svelte
|
46
|
+
'entity.other.attribute-name.svelte': {
|
47
|
+
actions: ['markPropertyAsDynamic', 'storePropertyType'],
|
48
|
+
},
|
49
|
+
'punctuation.separator.key-value.svelte': {
|
50
|
+
target: 'value',
|
51
|
+
},
|
45
52
|
},
|
46
53
|
},
|
47
54
|
complex_key: {
|
@@ -69,6 +76,8 @@ exports.default = (0, xstate_1.createMachine)({
|
|
69
76
|
// Extract strings
|
70
77
|
'punctuation.definition.string.begin.ts': 'value_string',
|
71
78
|
'punctuation.definition.string.template.begin.ts': 'value_string',
|
79
|
+
'punctuation.definition.string.begin.svelte': 'value_string',
|
80
|
+
'punctuation.definition.string.template.begin.svelte': 'value_string',
|
72
81
|
// Variable
|
73
82
|
'variable.other.readwrite.ts': {
|
74
83
|
target: 'idle',
|
@@ -82,6 +91,15 @@ exports.default = (0, xstate_1.createMachine)({
|
|
82
91
|
'punctuation.section.embedded.begin.tsx': {
|
83
92
|
actions: 'unmarkAsStatic',
|
84
93
|
},
|
94
|
+
// Svelte
|
95
|
+
'string.unquoted.svelte': {
|
96
|
+
target: 'idle',
|
97
|
+
actions: [
|
98
|
+
'storePropertyValue',
|
99
|
+
'clearPropertyType',
|
100
|
+
'unmarkAsStatic',
|
101
|
+
],
|
102
|
+
},
|
85
103
|
// Value end
|
86
104
|
'punctuation.separator.comma.ts': {
|
87
105
|
target: 'idle',
|
@@ -113,6 +131,14 @@ exports.default = (0, xstate_1.createMachine)({
|
|
113
131
|
target: 'idle',
|
114
132
|
actions: ['storeEmptyPropertyValue', 'clearPropertyType'],
|
115
133
|
},
|
134
|
+
'punctuation.definition.string.end.svelte': {
|
135
|
+
target: 'idle',
|
136
|
+
actions: ['storeEmptyPropertyValue', 'clearPropertyType'],
|
137
|
+
},
|
138
|
+
'punctuation.definition.string.template.end.svelte': {
|
139
|
+
target: 'idle',
|
140
|
+
actions: ['storeEmptyPropertyValue', 'clearPropertyType'],
|
141
|
+
},
|
116
142
|
'*': [
|
117
143
|
{
|
118
144
|
target: 'idle',
|
@@ -149,6 +175,19 @@ exports.default = (0, xstate_1.createMachine)({
|
|
149
175
|
target: 'idle',
|
150
176
|
actions: 'clearPropertyType',
|
151
177
|
},
|
178
|
+
// Svelte
|
179
|
+
'punctuation.section.embedded.begin.svelte': {
|
180
|
+
target: 'idle',
|
181
|
+
actions: ['markPropertyAsDynamic', 'clearPropertyType'],
|
182
|
+
},
|
183
|
+
'punctuation.definition.string.end.svelte': {
|
184
|
+
target: 'idle',
|
185
|
+
actions: 'clearPropertyType',
|
186
|
+
},
|
187
|
+
'punctuation.section.embedded.end.svelte': {
|
188
|
+
target: 'idle',
|
189
|
+
actions: 'clearPropertyType',
|
190
|
+
},
|
152
191
|
},
|
153
192
|
},
|
154
193
|
end: {
|
@@ -180,13 +219,19 @@ exports.default = (0, xstate_1.createMachine)({
|
|
180
219
|
target: 'end',
|
181
220
|
actions: 'markPropertyAsDynamic',
|
182
221
|
},
|
222
|
+
'punctuation.definition.tag.end.svelte': {
|
223
|
+
target: 'end',
|
224
|
+
actions: 'markPropertyAsDynamic',
|
225
|
+
},
|
183
226
|
},
|
184
227
|
}, {
|
185
228
|
guards: {
|
186
229
|
isOpenCurly: (_ctx, evt) => evt.token === '{' &&
|
187
|
-
!evt.scopes.includes('meta.embedded.expression.tsx')
|
230
|
+
!evt.scopes.includes('meta.embedded.expression.tsx') &&
|
231
|
+
!evt.scopes.includes('meta.embedded.expression.svelte'),
|
188
232
|
isCloseCurly: (_ctx, evt) => evt.token === '}' &&
|
189
|
-
!evt.scopes.includes('meta.embedded.expression.tsx')
|
233
|
+
!evt.scopes.includes('meta.embedded.expression.tsx') &&
|
234
|
+
!evt.scopes.includes('meta.embedded.expression.svelte'),
|
190
235
|
isFinalCloseCurly: (ctx, evt) => evt.token === '}' && ctx.depth === 1,
|
191
236
|
isOpenSquare: (_ctx, evt) => evt.token === '[',
|
192
237
|
isCloseSquare: (_ctx, evt) => evt.token === ']',
|