Skip to content

Commit 050b899

Browse files
authored
fix: cannot modulo parse hangup (#1057)
1 parent fa612d3 commit 050b899

File tree

9 files changed

+601
-4
lines changed

9 files changed

+601
-4
lines changed

packages/message-compiler/src/tokenizer.ts

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,23 @@ export function createTokenizer(
344344
return ret
345345
}
346346

347+
function detectModuloStart(scnr: Scanner): {
348+
isModulo: boolean
349+
hasSpace: boolean
350+
} {
351+
const spaces = peekSpaces(scnr)
352+
353+
const ret =
354+
scnr.currentPeek() === TokenChars.Modulo &&
355+
scnr.peek() === TokenChars.BraceLeft
356+
scnr.resetPeek()
357+
358+
return {
359+
isModulo: ret,
360+
hasSpace: spaces.length > 0
361+
}
362+
}
363+
347364
function isTextStart(scnr: Scanner, reset = true): boolean {
348365
const fn = (hasSpace = false, prev = '', detectModulo = false): boolean => {
349366
const ch = scnr.currentPeek()
@@ -437,6 +454,16 @@ export function createTokenizer(
437454
return num
438455
}
439456

457+
function readModulo(scnr: Scanner): string {
458+
skipSpaces(scnr)
459+
const ch = scnr.currentChar()
460+
if (ch !== TokenChars.Modulo) {
461+
emitError(CompileErrorCodes.EXPECTED_TOKEN, currentPosition(), 0, ch)
462+
}
463+
scnr.next()
464+
return TokenChars.Modulo
465+
}
466+
440467
function readText(scnr: Scanner): string {
441468
let buf = ''
442469
while (true) {
@@ -941,14 +968,17 @@ export function createTokenizer(
941968
return token
942969
}
943970

971+
const { isModulo, hasSpace } = detectModuloStart(scnr)
972+
if (isModulo) {
973+
return hasSpace
974+
? getToken(context, TokenTypes.Text, readText(scnr))
975+
: getToken(context, TokenTypes.Modulo, readModulo(scnr))
976+
}
977+
944978
if (isTextStart(scnr)) {
945979
return getToken(context, TokenTypes.Text, readText(scnr))
946980
}
947981

948-
if (ch === TokenChars.Modulo) {
949-
scnr.next()
950-
return getToken(context, TokenTypes.Modulo, TokenChars.Modulo)
951-
}
952982
break
953983
}
954984

packages/message-compiler/test/__snapshots__/compiler.test.ts.snap

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,15 @@ exports[`edge cases %: code 1`] = `
312312
}"
313313
`;
314314
315+
exports[`edge cases %{nickname} %{action} issue %{code}: code 1`] = `
316+
"function __msg__ (ctx) {
317+
const { normalize: _normalize, interpolate: _interpolate, named: _named } = ctx
318+
return _normalize([
319+
_interpolate(_named(\\"nickname\\")), \\" \\", _interpolate(_named(\\"action\\")), \\" issue \\", _interpolate(_named(\\"code\\"))
320+
])
321+
}"
322+
`;
323+
315324
exports[`edge cases {_field} with the same value already exists.: code 1`] = `
316325
"function __msg__ (ctx) {
317326
const { normalize: _normalize, interpolate: _interpolate, named: _named } = ctx

packages/message-compiler/test/compiler.test.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,4 +105,9 @@ describe('edge cases', () => {
105105
const { code } = compile(`hi @._upper:{_name} !`)
106106
expect(code).toMatchSnapshot('code')
107107
})
108+
109+
test(`%{nickname} %{action} issue %{code}`, () => {
110+
const { code } = compile(`%{nickname} %{action} issue %{code}`)
111+
expect(code).toMatchSnapshot('code')
112+
})
108113
})

packages/message-compiler/test/parser/__snapshots__/modulo.test.ts.snap

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,135 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

3+
exports[`%{nickname} %{action} issue %{code} 1`] = `
4+
Object {
5+
"body": Object {
6+
"end": 35,
7+
"items": Array [
8+
Object {
9+
"end": 11,
10+
"key": "nickname",
11+
"loc": Object {
12+
"end": Object {
13+
"column": 12,
14+
"line": 1,
15+
"offset": 11,
16+
},
17+
"start": Object {
18+
"column": 2,
19+
"line": 1,
20+
"offset": 1,
21+
},
22+
},
23+
"start": 1,
24+
"type": 4,
25+
},
26+
Object {
27+
"end": 12,
28+
"loc": Object {
29+
"end": Object {
30+
"column": 13,
31+
"line": 1,
32+
"offset": 12,
33+
},
34+
"start": Object {
35+
"column": 12,
36+
"line": 1,
37+
"offset": 11,
38+
},
39+
},
40+
"start": 11,
41+
"type": 3,
42+
"value": " ",
43+
},
44+
Object {
45+
"end": 21,
46+
"key": "action",
47+
"loc": Object {
48+
"end": Object {
49+
"column": 22,
50+
"line": 1,
51+
"offset": 21,
52+
},
53+
"start": Object {
54+
"column": 14,
55+
"line": 1,
56+
"offset": 13,
57+
},
58+
},
59+
"start": 13,
60+
"type": 4,
61+
},
62+
Object {
63+
"end": 28,
64+
"loc": Object {
65+
"end": Object {
66+
"column": 29,
67+
"line": 1,
68+
"offset": 28,
69+
},
70+
"start": Object {
71+
"column": 22,
72+
"line": 1,
73+
"offset": 21,
74+
},
75+
},
76+
"start": 21,
77+
"type": 3,
78+
"value": " issue ",
79+
},
80+
Object {
81+
"end": 35,
82+
"key": "code",
83+
"loc": Object {
84+
"end": Object {
85+
"column": 36,
86+
"line": 1,
87+
"offset": 35,
88+
},
89+
"start": Object {
90+
"column": 30,
91+
"line": 1,
92+
"offset": 29,
93+
},
94+
},
95+
"start": 29,
96+
"type": 4,
97+
},
98+
],
99+
"loc": Object {
100+
"end": Object {
101+
"column": 36,
102+
"line": 1,
103+
"offset": 35,
104+
},
105+
"start": Object {
106+
"column": 1,
107+
"line": 1,
108+
"offset": 0,
109+
},
110+
},
111+
"start": 0,
112+
"type": 2,
113+
},
114+
"end": 35,
115+
"loc": Object {
116+
"end": Object {
117+
"column": 36,
118+
"line": 1,
119+
"offset": 35,
120+
},
121+
"source": "%{nickname} %{action} issue %{code}",
122+
"start": Object {
123+
"column": 1,
124+
"line": 1,
125+
"offset": 0,
126+
},
127+
},
128+
"start": 0,
129+
"type": 0,
130+
}
131+
`;
132+
3133
exports[`hi % {name}! 1`] = `
4134
Object {
5135
"body": Object {

packages/message-compiler/test/parser/modulo.test.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,3 +179,39 @@ test('no apples %| one apple % | too much apples ', () => {
179179
}
180180
])
181181
})
182+
183+
test(`%{nickname} %{action} issue %{code}`, () => {
184+
const text = `%{nickname} %{action} issue %{code}`
185+
const parser = createParser({ onError: spy })
186+
const ast = parser.parse(text)
187+
188+
expect(ast).toMatchSnapshot()
189+
expect(spy).not.toHaveBeenCalled()
190+
191+
expect(ast.type).toEqual(NodeTypes.Resource)
192+
expect(ast.body.type).toEqual(NodeTypes.Message)
193+
const message = ast.body as MessageNode
194+
expect(message.items).toHaveLength(5)
195+
expect(message.items).toMatchObject([
196+
{
197+
type: NodeTypes.Named,
198+
key: 'nickname'
199+
},
200+
{
201+
type: NodeTypes.Text,
202+
value: ' '
203+
},
204+
{
205+
type: NodeTypes.Named,
206+
key: 'action'
207+
},
208+
{
209+
type: NodeTypes.Text,
210+
value: ' issue '
211+
},
212+
{
213+
type: NodeTypes.Named,
214+
key: 'code'
215+
}
216+
])
217+
})

0 commit comments

Comments
 (0)