@tolgee/cli 2.1.8 → 2.2.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/extractor/extractor.js +11 -4
- package/dist/extractor/parser/extractComment.js +7 -10
- package/dist/extractor/parser/generalMapper.js +4 -4
- package/dist/extractor/parser/mergerMachine.js +42 -11
- package/dist/extractor/parser/tokenMergers/closingTagMerger.js +1 -1
- package/dist/extractor/parser/tokenMergers/commentsMerger.js +8 -5
- package/dist/extractor/parser/tokenMergers/stringMerger.js +5 -5
- package/dist/extractor/parser/tokenMergers/templateStringMerger.js +1 -1
- package/dist/extractor/parser/tree/getTranslateProps.js +1 -1
- package/dist/extractor/parserNgx/ParserNgx.js +29 -0
- package/dist/extractor/parserNgx/ngxMapper.js +67 -0
- package/dist/extractor/parserNgx/ngxTreeTransform.js +46 -0
- package/dist/extractor/parserNgx/rules/componentWithT.js +43 -0
- package/dist/extractor/parserNgx/rules/helpers/parsePipeArgs.js +26 -0
- package/dist/extractor/parserNgx/rules/translateFunction.js +7 -0
- package/dist/extractor/parserNgx/rules/translatePipe.js +57 -0
- package/dist/extractor/parserNgx/tokenMergers/elementMerger.js +29 -0
- package/dist/extractor/parserNgx/tokenMergers/pipeMerger.js +19 -0
- package/dist/extractor/parserNgx/tokenMergers/translateMerger.js +41 -0
- package/dist/extractor/parserSvelte/svelteMapper.js +2 -2
- package/dist/extractor/parserVue/vueMapper.js +2 -2
- package/dist/extractor/runner.js +11 -1
- package/dist/extractor/tokenizer.js +12 -6
- package/dist/options.js +1 -1
- package/extractor.d.ts +1 -1
- package/package.json +1 -1
- package/schema.json +1 -1
- package/textmate/AngularHtml.tmLanguage +1 -0
- package/textmate/THIRD_PARTY_NOTICE +32 -0
@@ -3,6 +3,7 @@ import { ParserReact } from './parserReact/ParserReact.js';
|
|
3
3
|
import { tokensList } from './visualizers/printTokens.js';
|
4
4
|
import { visualizeRules } from './visualizers/visualizeRules.js';
|
5
5
|
import { ParserVue } from './parserVue/ParserVue.js';
|
6
|
+
import { ParserNgx } from './parserNgx/ParserNgx.js';
|
6
7
|
import { ParserSvelte } from './parserSvelte/ParserSvelte.js';
|
7
8
|
function pickParser(format) {
|
8
9
|
switch (format) {
|
@@ -12,6 +13,8 @@ function pickParser(format) {
|
|
12
13
|
return ParserVue();
|
13
14
|
case 'svelte':
|
14
15
|
return ParserSvelte();
|
16
|
+
case 'ngx':
|
17
|
+
return ParserNgx();
|
15
18
|
}
|
16
19
|
}
|
17
20
|
export async function extractTreeAndReport(code, fileName, parserType, options) {
|
@@ -33,10 +36,14 @@ export async function extractTreeAndReport(code, fileName, parserType, options)
|
|
33
36
|
options,
|
34
37
|
});
|
35
38
|
if (debug) {
|
36
|
-
console.log(JSON.stringify(result.tree, null, 2)
|
37
|
-
|
38
|
-
|
39
|
-
|
39
|
+
console.log(JSON.stringify(result.tree, null, 2) +
|
40
|
+
'\n' +
|
41
|
+
tokensList(tokensMerged) +
|
42
|
+
'\n' +
|
43
|
+
visualizeRules(tokensMerged, code) +
|
44
|
+
'\n' +
|
45
|
+
visualizeRules(tokensWithRules, code) +
|
46
|
+
'\n');
|
40
47
|
}
|
41
48
|
return result;
|
42
49
|
}
|
@@ -14,16 +14,13 @@ function isValidKeyOverride(data) {
|
|
14
14
|
}
|
15
15
|
return true;
|
16
16
|
}
|
17
|
-
function getEndLine(token) {
|
18
|
-
return token.line + (token.token.match(/\n/gm)?.length ?? 0);
|
19
|
-
}
|
20
17
|
export function extractComment(token) {
|
21
|
-
const comment = token.token.trim();
|
18
|
+
const comment = token.token.replaceAll(/[^\n]([\w]*\*+)/g, '').trim();
|
22
19
|
if (comment.startsWith('@tolgee-ignore')) {
|
23
20
|
return {
|
24
21
|
type: 'MAGIC_COMMENT',
|
25
22
|
kind: 'ignore',
|
26
|
-
line:
|
23
|
+
line: token.line,
|
27
24
|
};
|
28
25
|
}
|
29
26
|
if (comment.startsWith('@tolgee-key')) {
|
@@ -34,7 +31,7 @@ export function extractComment(token) {
|
|
34
31
|
type: 'MAGIC_COMMENT',
|
35
32
|
kind: 'key',
|
36
33
|
keyName: data.slice(1),
|
37
|
-
line:
|
34
|
+
line: token.line,
|
38
35
|
};
|
39
36
|
}
|
40
37
|
// Data is a json5 struct
|
@@ -46,7 +43,7 @@ export function extractComment(token) {
|
|
46
43
|
return {
|
47
44
|
type: 'WARNING',
|
48
45
|
kind: 'W_INVALID_KEY_OVERRIDE',
|
49
|
-
line:
|
46
|
+
line: token.line,
|
50
47
|
};
|
51
48
|
}
|
52
49
|
else {
|
@@ -56,7 +53,7 @@ export function extractComment(token) {
|
|
56
53
|
keyName: key.key,
|
57
54
|
namespace: key.ns,
|
58
55
|
defaultValue: key.defaultValue,
|
59
|
-
line:
|
56
|
+
line: token.line,
|
60
57
|
};
|
61
58
|
}
|
62
59
|
}
|
@@ -64,7 +61,7 @@ export function extractComment(token) {
|
|
64
61
|
return {
|
65
62
|
type: 'WARNING',
|
66
63
|
kind: 'W_MALFORMED_KEY_OVERRIDE',
|
67
|
-
line:
|
64
|
+
line: token.line,
|
68
65
|
};
|
69
66
|
}
|
70
67
|
}
|
@@ -72,7 +69,7 @@ export function extractComment(token) {
|
|
72
69
|
type: 'MAGIC_COMMENT',
|
73
70
|
kind: 'key',
|
74
71
|
keyName: data,
|
75
|
-
line:
|
72
|
+
line: token.line,
|
76
73
|
};
|
77
74
|
}
|
78
75
|
}
|
@@ -13,9 +13,9 @@ export const generalMapper = (token) => {
|
|
13
13
|
return 'primitive.null';
|
14
14
|
// plain strings
|
15
15
|
case 'punctuation.definition.string.begin.ts':
|
16
|
-
return 'string.
|
16
|
+
return 'string.quote';
|
17
17
|
case 'punctuation.definition.string.end.ts':
|
18
|
-
return 'string.
|
18
|
+
return 'string.quote';
|
19
19
|
case 'string.quoted.single.ts':
|
20
20
|
case 'string.quoted.double.ts':
|
21
21
|
return 'string.body';
|
@@ -23,9 +23,9 @@ export const generalMapper = (token) => {
|
|
23
23
|
return 'escaped.character';
|
24
24
|
// template strings
|
25
25
|
case 'punctuation.definition.string.template.begin.ts':
|
26
|
-
return 'string.teplate.
|
26
|
+
return 'string.teplate.quote';
|
27
27
|
case 'punctuation.definition.string.template.end.ts':
|
28
|
-
return 'string.template.
|
28
|
+
return 'string.template.quote';
|
29
29
|
case 'string.template.ts':
|
30
30
|
return 'string.template.body';
|
31
31
|
// variables
|
@@ -1,13 +1,15 @@
|
|
1
|
-
function defaultResultToken(matched) {
|
2
|
-
return matched.map((t) => t.token).join('');
|
3
|
-
}
|
4
1
|
const MERGE_ALL = Symbol('MERGE_ALL');
|
5
2
|
const MERGE_WITHOUT_LAST = Symbol('MERGE_WITHOUT_LAST');
|
3
|
+
const REPLACE_FIRST = Symbol('REPLACE_FIRST');
|
4
|
+
const MERGE_CUSTOM = Symbol('MERGE_CUSTOM');
|
6
5
|
export const endOptions = {
|
7
6
|
MERGE_ALL,
|
8
7
|
MERGE_WITHOUT_LAST,
|
8
|
+
REPLACE_FIRST,
|
9
|
+
MERGE_CUSTOM,
|
9
10
|
};
|
10
11
|
function createNewToken(tokens, customType, merger) {
|
12
|
+
const mergerData = merger?.(tokens);
|
11
13
|
return {
|
12
14
|
customType,
|
13
15
|
type: 'custom',
|
@@ -15,7 +17,8 @@ function createNewToken(tokens, customType, merger) {
|
|
15
17
|
endIndex: tokens[tokens.length - 1].endIndex,
|
16
18
|
scopes: [],
|
17
19
|
line: tokens[0].line,
|
18
|
-
token:
|
20
|
+
token: tokens.map((t) => t.token).join(''),
|
21
|
+
...mergerData,
|
19
22
|
};
|
20
23
|
}
|
21
24
|
export function createMachine(machine) {
|
@@ -34,15 +37,43 @@ export function createMachine(machine) {
|
|
34
37
|
continue;
|
35
38
|
}
|
36
39
|
else if (newState === endOptions.MERGE_ALL ||
|
37
|
-
newState === endOptions.MERGE_WITHOUT_LAST
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
40
|
+
newState === endOptions.MERGE_WITHOUT_LAST ||
|
41
|
+
newState === endOptions.REPLACE_FIRST ||
|
42
|
+
newState === endOptions.MERGE_CUSTOM) {
|
43
|
+
let before = [];
|
44
|
+
let toMerge;
|
45
|
+
let after;
|
46
|
+
if (newState === endOptions.MERGE_ALL) {
|
47
|
+
toMerge = stack;
|
48
|
+
after = [];
|
49
|
+
}
|
50
|
+
else if (newState === endOptions.MERGE_WITHOUT_LAST) {
|
51
|
+
after = [stack.pop()];
|
52
|
+
toMerge = stack;
|
53
|
+
}
|
54
|
+
else if (newState === endOptions.REPLACE_FIRST) {
|
55
|
+
toMerge = [stack.shift()];
|
56
|
+
after = stack;
|
57
|
+
}
|
58
|
+
else {
|
59
|
+
if (!machine.customMerge) {
|
60
|
+
throw new Error('No custom merge cpecified');
|
61
|
+
}
|
62
|
+
const result = machine.customMerge(stack);
|
63
|
+
before = result.before;
|
64
|
+
toMerge = result.toMerge;
|
65
|
+
after = result.after;
|
66
|
+
}
|
67
|
+
const newToken = createNewToken(toMerge, machine.customType, machine.resultToken);
|
68
|
+
for (const result of before) {
|
69
|
+
yield result;
|
70
|
+
}
|
42
71
|
yield newToken;
|
43
|
-
|
44
|
-
yield
|
72
|
+
for (const result of after) {
|
73
|
+
yield result;
|
45
74
|
}
|
75
|
+
stack = [];
|
76
|
+
state = machine.initial;
|
46
77
|
continue;
|
47
78
|
}
|
48
79
|
else {
|
@@ -12,7 +12,7 @@ export const commentsMerger = {
|
|
12
12
|
if (type === 'comment.line') {
|
13
13
|
return end.MERGE_ALL;
|
14
14
|
}
|
15
|
-
else if (type === 'comment.block') {
|
15
|
+
else if (type === 'comment.block' || token.token === '\n') {
|
16
16
|
return 2 /* S.CommentBlock */;
|
17
17
|
}
|
18
18
|
break;
|
@@ -27,10 +27,13 @@ export const commentsMerger = {
|
|
27
27
|
}
|
28
28
|
},
|
29
29
|
resultToken: (matched) => {
|
30
|
-
return
|
31
|
-
|
32
|
-
|
33
|
-
|
30
|
+
return {
|
31
|
+
token: matched
|
32
|
+
.filter((t) => t.customType && t.customType !== 'comment.definition')
|
33
|
+
.map((t) => t.token)
|
34
|
+
.join(''),
|
35
|
+
line: matched[matched.length - 1].line,
|
36
|
+
};
|
34
37
|
},
|
35
38
|
customType: 'comment',
|
36
39
|
};
|
@@ -5,10 +5,10 @@ export const stringMerger = {
|
|
5
5
|
const type = token.customType;
|
6
6
|
switch (state) {
|
7
7
|
case 0 /* S.Idle */:
|
8
|
-
if (type === 'string.
|
8
|
+
if (type === 'string.quote') {
|
9
9
|
return 1 /* S.RegularString */;
|
10
10
|
}
|
11
|
-
else if (type === 'string.teplate.
|
11
|
+
else if (type === 'string.teplate.quote') {
|
12
12
|
return 2 /* S.TemplateString */;
|
13
13
|
}
|
14
14
|
break;
|
@@ -19,7 +19,7 @@ export const stringMerger = {
|
|
19
19
|
else if (type === 'escaped.character') {
|
20
20
|
return 1 /* S.RegularString */;
|
21
21
|
}
|
22
|
-
else if (type === 'string.
|
22
|
+
else if (type === 'string.quote') {
|
23
23
|
return end.MERGE_ALL;
|
24
24
|
}
|
25
25
|
break;
|
@@ -30,7 +30,7 @@ export const stringMerger = {
|
|
30
30
|
else if (type === 'escaped.character') {
|
31
31
|
return 2 /* S.TemplateString */;
|
32
32
|
}
|
33
|
-
else if (type === 'string.template.
|
33
|
+
else if (type === 'string.template.quote') {
|
34
34
|
return end.MERGE_ALL;
|
35
35
|
}
|
36
36
|
break;
|
@@ -50,6 +50,6 @@ export const stringMerger = {
|
|
50
50
|
}
|
51
51
|
})
|
52
52
|
.join('');
|
53
|
-
return unescape(escaped);
|
53
|
+
return { token: unescape(escaped) };
|
54
54
|
},
|
55
55
|
};
|
@@ -0,0 +1,29 @@
|
|
1
|
+
import { pipeMachines } from '../parser/mergerMachine.js';
|
2
|
+
import { DEFAULT_BLOCKS, DEFAULT_MERGERERS, Parser } from '../parser/parser.js';
|
3
|
+
import { generalMapper } from '../parser/generalMapper.js';
|
4
|
+
import { ngxMapper } from './ngxMapper.js';
|
5
|
+
import { ngxTreeTransform } from './ngxTreeTransform.js';
|
6
|
+
import { componentWithTMerger } from './tokenMergers/elementMerger.js';
|
7
|
+
import { translateMerger } from './tokenMergers/translateMerger.js';
|
8
|
+
import { pipeMerger } from './tokenMergers/pipeMerger.js';
|
9
|
+
import { componentWithT } from './rules/componentWithT.js';
|
10
|
+
import { translatePipe } from './rules/translatePipe.js';
|
11
|
+
import { translateFunction } from './rules/translateFunction.js';
|
12
|
+
const ngxMappers = [ngxMapper, generalMapper];
|
13
|
+
export const ngxMergers = pipeMachines([
|
14
|
+
...DEFAULT_MERGERERS,
|
15
|
+
componentWithTMerger,
|
16
|
+
pipeMerger,
|
17
|
+
translateMerger,
|
18
|
+
]);
|
19
|
+
export const ParserNgx = () => {
|
20
|
+
return Parser({
|
21
|
+
mappers: ngxMappers,
|
22
|
+
blocks: {
|
23
|
+
...DEFAULT_BLOCKS,
|
24
|
+
},
|
25
|
+
rules: [componentWithT, translatePipe, translateFunction],
|
26
|
+
merger: ngxMergers,
|
27
|
+
treeTransform: ngxTreeTransform,
|
28
|
+
});
|
29
|
+
};
|
@@ -0,0 +1,67 @@
|
|
1
|
+
export const ngxMapper = (token) => {
|
2
|
+
switch (token.type) {
|
3
|
+
// ngx template tags
|
4
|
+
case 'punctuation.definition.tag.begin.html':
|
5
|
+
return token.token === '</' ? 'tag.closing.begin' : 'tag.regular.begin';
|
6
|
+
case 'punctuation.definition.tag.end.html':
|
7
|
+
return token.token === '/>' ? 'tag.self-closing.end' : 'tag.regular.end';
|
8
|
+
case 'html-template.tag.html':
|
9
|
+
return 'tag.name';
|
10
|
+
case 'html-template.ng.attributes.generic':
|
11
|
+
return 'tag.attribute.name';
|
12
|
+
case 'punctuation.separator.key-value.html-template.ng':
|
13
|
+
return 'operator.assignment';
|
14
|
+
case 'entity.other.attribute-name.html':
|
15
|
+
return 'tag.attribute.name';
|
16
|
+
case 'punctuation.separator.key-value.html':
|
17
|
+
return 'operator.assignment';
|
18
|
+
// html string attributes
|
19
|
+
case 'punctuation.definition.string.begin.html':
|
20
|
+
return 'string.quote';
|
21
|
+
case 'punctuation.definition.string.end.html':
|
22
|
+
return 'string.quote';
|
23
|
+
case 'string.quoted.single.html':
|
24
|
+
case 'string.quoted.double.html':
|
25
|
+
if (token.token === '"' || token.token === "'") {
|
26
|
+
// ignoring qotes around strings and expressions
|
27
|
+
// we can just take the content without them
|
28
|
+
// as otherwise we would need to distinguish if it's an expression or string
|
29
|
+
// (angular grammar doesn't do this for some reason)
|
30
|
+
return 'ignore';
|
31
|
+
}
|
32
|
+
else {
|
33
|
+
return 'string';
|
34
|
+
}
|
35
|
+
case 'string.unquoted.html':
|
36
|
+
return 'string';
|
37
|
+
case 'html-template.ng.attributes.input-binding.first-level':
|
38
|
+
case 'html-template.ng.attributes.event-handler':
|
39
|
+
return 'tag.attribute.name';
|
40
|
+
case 'punctuation.definition.ng-binding-name.begin.html':
|
41
|
+
case 'punctuation.definition.ng-binding-name.end.html':
|
42
|
+
// ignoring binding brackets, irrelevant for us
|
43
|
+
return 'ignore';
|
44
|
+
// html comments
|
45
|
+
case 'punctuation.definition.comment.begin.html':
|
46
|
+
case 'punctuation.definition.comment.end.html':
|
47
|
+
case 'punctuation.definition.comment.html':
|
48
|
+
return 'comment.definition';
|
49
|
+
case 'comment.block.html':
|
50
|
+
return 'comment.block';
|
51
|
+
// pipeline operators
|
52
|
+
case 'html-template.ng.expression.operator.logical':
|
53
|
+
return 'operator.logical';
|
54
|
+
case 'html-template.ng.expression.operator.navigator':
|
55
|
+
return 'operator.navigator';
|
56
|
+
case 'variable.other.property.ts':
|
57
|
+
case 'entity.name.function.pipe.ng':
|
58
|
+
return 'function.call.pipe';
|
59
|
+
case 'variable.other.object.property.ts':
|
60
|
+
return 'variable';
|
61
|
+
// angular interpolation
|
62
|
+
case 'html-template.ng.interpolation.begin':
|
63
|
+
return 'expression.template.begin';
|
64
|
+
case 'html-template.ng.interpolation.end':
|
65
|
+
return 'expression.template.end';
|
66
|
+
}
|
67
|
+
};
|
@@ -0,0 +1,46 @@
|
|
1
|
+
import { simplifyNode } from '../parser/nodeUtils.js';
|
2
|
+
function transformRecursive(root) {
|
3
|
+
if (!root) {
|
4
|
+
return;
|
5
|
+
}
|
6
|
+
switch (root.type) {
|
7
|
+
case 'expr':
|
8
|
+
case 'array':
|
9
|
+
root.values.forEach((item, i) => {
|
10
|
+
if (item.type === 'keyInfo' && item.keyName === undefined) {
|
11
|
+
const nodeBefore = simplifyNode(root.values[i - 1]);
|
12
|
+
if (nodeBefore.type === 'dict') {
|
13
|
+
item.keyName = nodeBefore.value['key'];
|
14
|
+
item.namespace = nodeBefore.value['ns'] ?? item.namespace;
|
15
|
+
item.defaultValue =
|
16
|
+
nodeBefore.value['defaultValue'] ?? item.defaultValue;
|
17
|
+
}
|
18
|
+
else {
|
19
|
+
item.keyName = nodeBefore;
|
20
|
+
}
|
21
|
+
}
|
22
|
+
transformRecursive(item);
|
23
|
+
});
|
24
|
+
break;
|
25
|
+
case 'dict':
|
26
|
+
Object.values(root.value).forEach(transformRecursive);
|
27
|
+
root.unknown.forEach(transformRecursive);
|
28
|
+
break;
|
29
|
+
case 'keyInfo':
|
30
|
+
transformRecursive(root.defaultValue);
|
31
|
+
transformRecursive(root.keyName);
|
32
|
+
transformRecursive(root.namespace);
|
33
|
+
root.values.forEach(transformRecursive);
|
34
|
+
break;
|
35
|
+
case 'nsInfo':
|
36
|
+
transformRecursive(root.name);
|
37
|
+
root.values.forEach(transformRecursive);
|
38
|
+
break;
|
39
|
+
case 'primitive':
|
40
|
+
return;
|
41
|
+
}
|
42
|
+
}
|
43
|
+
export const ngxTreeTransform = (root) => {
|
44
|
+
transformRecursive(root);
|
45
|
+
return { tree: root, report: { keys: [], warnings: [] } };
|
46
|
+
};
|
@@ -0,0 +1,43 @@
|
|
1
|
+
import { parseTag } from '../../parser/tree/parseTag.js';
|
2
|
+
// <div t key="test"></div>
|
3
|
+
// ^-----------------^^^^^^
|
4
|
+
export const componentWithT = {
|
5
|
+
trigger: 'trigger.component.with.t',
|
6
|
+
call(context) {
|
7
|
+
const { getCurrentLine } = context;
|
8
|
+
const line = getCurrentLine();
|
9
|
+
context.tokens.next();
|
10
|
+
const { props, child } = parseTag(context);
|
11
|
+
if (props.type !== 'dict' || !props.value['t']) {
|
12
|
+
const result = { type: 'array', line, values: [props] };
|
13
|
+
if (child) {
|
14
|
+
result.values.push(child);
|
15
|
+
}
|
16
|
+
return result;
|
17
|
+
}
|
18
|
+
else {
|
19
|
+
const result = {
|
20
|
+
type: 'keyInfo',
|
21
|
+
line,
|
22
|
+
dependsOnContext: false,
|
23
|
+
values: [],
|
24
|
+
};
|
25
|
+
for (const [key, value] of Object.entries(props.value)) {
|
26
|
+
switch (key) {
|
27
|
+
case 'key':
|
28
|
+
result.keyName = value;
|
29
|
+
break;
|
30
|
+
case 'default':
|
31
|
+
result.defaultValue = value;
|
32
|
+
break;
|
33
|
+
case 'ns':
|
34
|
+
result.namespace = value;
|
35
|
+
break;
|
36
|
+
default:
|
37
|
+
result.values.push(value);
|
38
|
+
}
|
39
|
+
}
|
40
|
+
return result;
|
41
|
+
}
|
42
|
+
},
|
43
|
+
};
|
@@ -0,0 +1,26 @@
|
|
1
|
+
import { parseGeneral } from '../../../../extractor/parser/tree/parseGeneral.js';
|
2
|
+
/*
|
3
|
+
* :{ noWrap: true }:'item'
|
4
|
+
* ^----------------------^
|
5
|
+
*/
|
6
|
+
export function parsePipeArgs(context, end) {
|
7
|
+
const { tokens, getCurrentLine } = context;
|
8
|
+
const line = getCurrentLine();
|
9
|
+
const result = { type: 'array', line, values: [] };
|
10
|
+
let token;
|
11
|
+
while ((token = tokens.current())) {
|
12
|
+
if (end.includes(token.customType)) {
|
13
|
+
break;
|
14
|
+
}
|
15
|
+
switch (token.customType) {
|
16
|
+
case 'operator.navigator':
|
17
|
+
tokens.next();
|
18
|
+
break;
|
19
|
+
default:
|
20
|
+
result.values.push(parseGeneral(context, {
|
21
|
+
end: ['operator.navigator', ...end],
|
22
|
+
}));
|
23
|
+
}
|
24
|
+
}
|
25
|
+
return result;
|
26
|
+
}
|
@@ -0,0 +1,57 @@
|
|
1
|
+
import { isString } from '../../../extractor/parser/nodeUtils.js';
|
2
|
+
import { parsePipeArgs } from './helpers/parsePipeArgs.js';
|
3
|
+
// <div title={{'test' | translate:{noWrap: true}:'default value'}}></div>
|
4
|
+
// ^^^^^^^^^^^----------------^^^^^^^^^^^^^^^
|
5
|
+
export const translatePipe = {
|
6
|
+
trigger: 'trigger.translate.pipe',
|
7
|
+
call(context) {
|
8
|
+
const { tokens, getCurrentLine } = context;
|
9
|
+
const line = getCurrentLine();
|
10
|
+
tokens.next();
|
11
|
+
const args = parsePipeArgs(context, [
|
12
|
+
'operator.logical',
|
13
|
+
'expression.template.end',
|
14
|
+
'expression.end',
|
15
|
+
'tag.regular.end',
|
16
|
+
'tag.self-closing.end',
|
17
|
+
'tag.attribute.name',
|
18
|
+
]);
|
19
|
+
const keyNode = {
|
20
|
+
type: 'keyInfo',
|
21
|
+
line,
|
22
|
+
keyName: undefined,
|
23
|
+
dependsOnContext: false,
|
24
|
+
values: [],
|
25
|
+
};
|
26
|
+
let options = undefined;
|
27
|
+
if (args.values.length === 1) {
|
28
|
+
if (isString(args.values[0])) {
|
29
|
+
keyNode.defaultValue = args.values[0];
|
30
|
+
}
|
31
|
+
else {
|
32
|
+
options = args.values[0];
|
33
|
+
}
|
34
|
+
}
|
35
|
+
else if (args.values.length > 1) {
|
36
|
+
options = args.values.shift();
|
37
|
+
keyNode.defaultValue = args.values.shift();
|
38
|
+
keyNode.values = args.values;
|
39
|
+
}
|
40
|
+
if (options?.type === 'dict') {
|
41
|
+
for (const [key, value] of Object.entries(options.value)) {
|
42
|
+
switch (key) {
|
43
|
+
case 'ns':
|
44
|
+
keyNode.namespace = value;
|
45
|
+
break;
|
46
|
+
default:
|
47
|
+
// unknown parameter
|
48
|
+
keyNode.values.push(value);
|
49
|
+
}
|
50
|
+
}
|
51
|
+
}
|
52
|
+
else if (options) {
|
53
|
+
keyNode.optionsDynamic = true;
|
54
|
+
}
|
55
|
+
return keyNode;
|
56
|
+
},
|
57
|
+
};
|
@@ -0,0 +1,29 @@
|
|
1
|
+
// <div ... t
|
2
|
+
export const componentWithTMerger = {
|
3
|
+
initial: 0 /* S.Idle */,
|
4
|
+
step: (state, t, end) => {
|
5
|
+
const type = t.customType;
|
6
|
+
switch (state) {
|
7
|
+
case 0 /* S.Idle */:
|
8
|
+
if (type === 'tag.regular.begin') {
|
9
|
+
return 1 /* S.ExpectName */;
|
10
|
+
}
|
11
|
+
break;
|
12
|
+
case 1 /* S.ExpectName */:
|
13
|
+
if (type === 'tag.name') {
|
14
|
+
return 2 /* S.ExpectTParam */;
|
15
|
+
}
|
16
|
+
break;
|
17
|
+
case 2 /* S.ExpectTParam */:
|
18
|
+
if (type === 'tag.attribute.name' && t.token === 't') {
|
19
|
+
return end.REPLACE_FIRST;
|
20
|
+
}
|
21
|
+
else if (type === 'tag.self-closing.end' ||
|
22
|
+
type === 'tag.regular.end') {
|
23
|
+
return undefined;
|
24
|
+
}
|
25
|
+
return 2 /* S.ExpectTParam */;
|
26
|
+
}
|
27
|
+
},
|
28
|
+
customType: 'trigger.component.with.t',
|
29
|
+
};
|
@@ -0,0 +1,19 @@
|
|
1
|
+
// <div ... t
|
2
|
+
export const pipeMerger = {
|
3
|
+
initial: 0 /* S.Idle */,
|
4
|
+
step: (state, t, end) => {
|
5
|
+
const type = t.customType;
|
6
|
+
switch (state) {
|
7
|
+
case 0 /* S.Idle */:
|
8
|
+
if (type === 'operator.logical') {
|
9
|
+
return 1 /* S.ExpectTranslate */;
|
10
|
+
}
|
11
|
+
break;
|
12
|
+
case 1 /* S.ExpectTranslate */:
|
13
|
+
if (type === 'function.call.pipe' && t.token === 'translate') {
|
14
|
+
return end.MERGE_ALL;
|
15
|
+
}
|
16
|
+
}
|
17
|
+
},
|
18
|
+
customType: 'trigger.translate.pipe',
|
19
|
+
};
|
@@ -0,0 +1,41 @@
|
|
1
|
+
const SERVICE_NAME_POSSIBILITIES = ['translateService'];
|
2
|
+
const TRANSLATE_FUNCTION_NAMES = ['translate', 'instant', 'get'];
|
3
|
+
// translateService.translate('key1', 'default-1', { ns: 'ns-1' })
|
4
|
+
export const translateMerger = {
|
5
|
+
initial: 0 /* S.Idle */,
|
6
|
+
step: (state, t, end) => {
|
7
|
+
const type = t.customType;
|
8
|
+
const token = t.token;
|
9
|
+
switch (state) {
|
10
|
+
case 0 /* S.Idle */:
|
11
|
+
if (['variable', 'function.call.pipe'].includes(type) &&
|
12
|
+
SERVICE_NAME_POSSIBILITIES.includes(token)) {
|
13
|
+
return 2 /* S.ExpectDot */;
|
14
|
+
}
|
15
|
+
break;
|
16
|
+
case 2 /* S.ExpectDot */:
|
17
|
+
if (type === 'acessor.dot') {
|
18
|
+
return 3 /* S.ExpectCall */;
|
19
|
+
}
|
20
|
+
break;
|
21
|
+
case 3 /* S.ExpectCall */:
|
22
|
+
if (type === 'function.call' &&
|
23
|
+
TRANSLATE_FUNCTION_NAMES.includes(token)) {
|
24
|
+
return 1 /* S.ExpectBracket */;
|
25
|
+
}
|
26
|
+
break;
|
27
|
+
case 1 /* S.ExpectBracket */:
|
28
|
+
if (type === 'expression.begin') {
|
29
|
+
return end.MERGE_CUSTOM;
|
30
|
+
}
|
31
|
+
}
|
32
|
+
},
|
33
|
+
customType: 'trigger.translate.function',
|
34
|
+
customMerge(tokens) {
|
35
|
+
return {
|
36
|
+
before: tokens.slice(0, -2),
|
37
|
+
toMerge: tokens.slice(-2),
|
38
|
+
after: [],
|
39
|
+
};
|
40
|
+
},
|
41
|
+
};
|