@curly-message/conformance 1.0.0-next.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/LICENSE +21 -0
- package/README.md +266 -0
- package/bin/conformance.js +37 -0
- package/bin/manifest.js +24 -0
- package/dist/index.d.ts +225 -0
- package/dist/index.js +4 -0
- package/fixtures/comparisons.json +916 -0
- package/fixtures/conversion.json +231 -0
- package/fixtures/escaping-extensions.json +84 -0
- package/fixtures/escaping.json +546 -0
- package/fixtures/extensions.json +826 -0
- package/fixtures/fallback-intl.json +51 -0
- package/fixtures/fallback.json +774 -0
- package/fixtures/grammar.json +875 -0
- package/fixtures/intl.json +3057 -0
- package/fixtures/limits.json +63 -0
- package/fixtures/nesting.json +251 -0
- package/fixtures/reports.json +512 -0
- package/fixtures/resolution.json +742 -0
- package/fixtures/security-extensions.json +52 -0
- package/fixtures/security.json +246 -0
- package/fixtures/whitespace.json +1000 -0
- package/index.json +102 -0
- package/package.json +76 -0
- package/schema/fixture.schema.json +264 -0
|
@@ -0,0 +1,875 @@
|
|
|
1
|
+
{
|
|
2
|
+
"format": "curly-message-1",
|
|
3
|
+
"level": "core",
|
|
4
|
+
"section": "6",
|
|
5
|
+
"cases": [
|
|
6
|
+
{
|
|
7
|
+
"id": "grammar/literal-text",
|
|
8
|
+
"description": "A message that holds no placeholder resolves to its own text.",
|
|
9
|
+
"message": "NO_PLACEHOLDER",
|
|
10
|
+
"payload": {},
|
|
11
|
+
"expected": {
|
|
12
|
+
"output": "NO_PLACEHOLDER"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"id": "grammar/placeholder-full-form",
|
|
17
|
+
"description": "A placeholder is an opening pair, a selector, semicolon-led segments and a closing pair.",
|
|
18
|
+
"message": "{{v:eq; a:A; b:B; default:D}}",
|
|
19
|
+
"payload": {
|
|
20
|
+
"v": "a"
|
|
21
|
+
},
|
|
22
|
+
"expected": {
|
|
23
|
+
"output": "A"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"id": "grammar/no-whitespace-required",
|
|
28
|
+
"description": "No production requires whitespace, so a placeholder written without any derives.",
|
|
29
|
+
"message": "{{v:eq;a:A;default:D}}",
|
|
30
|
+
"payload": {
|
|
31
|
+
"v": "a"
|
|
32
|
+
},
|
|
33
|
+
"expected": {
|
|
34
|
+
"output": "A"
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"id": "grammar/line-terminator-inside-key-lf",
|
|
39
|
+
"description": "A construct whose key holds a line feed is literal text.",
|
|
40
|
+
"section": "A.10",
|
|
41
|
+
"message": "{{v\u000ax}}",
|
|
42
|
+
"payload": {
|
|
43
|
+
"v\u000ax": "HIT"
|
|
44
|
+
},
|
|
45
|
+
"expected": {
|
|
46
|
+
"output": "{{v\u000ax}}"
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"id": "grammar/line-terminator-beside-resolved-lf",
|
|
51
|
+
"description": "Whether a construct is a placeholder does not depend on what another resolved to: one spanning a line feed stays literal beside a resolved one.",
|
|
52
|
+
"section": "A.10",
|
|
53
|
+
"message": "{{a}} {{\u000av\u000a}}",
|
|
54
|
+
"payload": {
|
|
55
|
+
"a": "A",
|
|
56
|
+
"v": "HIT"
|
|
57
|
+
},
|
|
58
|
+
"expected": {
|
|
59
|
+
"output": "A {{\u000av\u000a}}"
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
"id": "grammar/line-terminator-in-value-lf",
|
|
64
|
+
"description": "A construct whose option value holds a line feed is literal text.",
|
|
65
|
+
"section": "6",
|
|
66
|
+
"message": "{{v; a:\u000ab; default:D}}",
|
|
67
|
+
"payload": {
|
|
68
|
+
"v": "HIT"
|
|
69
|
+
},
|
|
70
|
+
"expected": {
|
|
71
|
+
"output": "{{v; a:\u000ab; default:D}}"
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
"id": "grammar/line-terminator-escaped-lf",
|
|
76
|
+
"description": "Escaping a line feed does not admit it into a placeholder: the construct is literal text, and the escape is removed from it.",
|
|
77
|
+
"section": "6",
|
|
78
|
+
"message": "{{v\\\u000ax}}",
|
|
79
|
+
"payload": {
|
|
80
|
+
"v\u000ax": "HIT"
|
|
81
|
+
},
|
|
82
|
+
"expected": {
|
|
83
|
+
"output": "{{v\u000ax}}"
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
"id": "grammar/line-terminator-inside-key-cr",
|
|
88
|
+
"description": "A construct whose key holds a carriage return is literal text.",
|
|
89
|
+
"section": "A.10",
|
|
90
|
+
"message": "{{v\u000dx}}",
|
|
91
|
+
"payload": {
|
|
92
|
+
"v\u000dx": "HIT"
|
|
93
|
+
},
|
|
94
|
+
"expected": {
|
|
95
|
+
"output": "{{v\u000dx}}"
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
"id": "grammar/line-terminator-beside-resolved-cr",
|
|
100
|
+
"description": "Whether a construct is a placeholder does not depend on what another resolved to: one spanning a carriage return stays literal beside a resolved one.",
|
|
101
|
+
"section": "6",
|
|
102
|
+
"message": "{{a}} {{\u000dv\u000d}}",
|
|
103
|
+
"payload": {
|
|
104
|
+
"a": "A",
|
|
105
|
+
"v": "HIT"
|
|
106
|
+
},
|
|
107
|
+
"expected": {
|
|
108
|
+
"output": "A {{\u000dv\u000d}}"
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
"id": "grammar/line-terminator-in-value-cr",
|
|
113
|
+
"description": "A construct whose option value holds a carriage return is literal text.",
|
|
114
|
+
"section": "6",
|
|
115
|
+
"message": "{{v; a:\u000db; default:D}}",
|
|
116
|
+
"payload": {
|
|
117
|
+
"v": "HIT"
|
|
118
|
+
},
|
|
119
|
+
"expected": {
|
|
120
|
+
"output": "{{v; a:\u000db; default:D}}"
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
"id": "grammar/line-terminator-escaped-cr",
|
|
125
|
+
"description": "Escaping a carriage return does not admit it into a placeholder: the construct is literal text, and the escape is removed from it.",
|
|
126
|
+
"section": "6",
|
|
127
|
+
"message": "{{v\\\u000dx}}",
|
|
128
|
+
"payload": {
|
|
129
|
+
"v\u000dx": "HIT"
|
|
130
|
+
},
|
|
131
|
+
"expected": {
|
|
132
|
+
"output": "{{v\u000dx}}"
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
"id": "grammar/line-terminator-inside-key-ls",
|
|
137
|
+
"description": "A construct whose key holds a line separator (U+2028) is literal text.",
|
|
138
|
+
"section": "A.10",
|
|
139
|
+
"message": "{{v\u2028x}}",
|
|
140
|
+
"payload": {
|
|
141
|
+
"v\u2028x": "HIT"
|
|
142
|
+
},
|
|
143
|
+
"expected": {
|
|
144
|
+
"output": "{{v\u2028x}}"
|
|
145
|
+
}
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
"id": "grammar/line-terminator-beside-resolved-ls",
|
|
149
|
+
"description": "Whether a construct is a placeholder does not depend on what another resolved to: one spanning a line separator (U+2028) stays literal beside a resolved one.",
|
|
150
|
+
"section": "6",
|
|
151
|
+
"message": "{{a}} {{\u2028v\u2028}}",
|
|
152
|
+
"payload": {
|
|
153
|
+
"a": "A",
|
|
154
|
+
"v": "HIT"
|
|
155
|
+
},
|
|
156
|
+
"expected": {
|
|
157
|
+
"output": "A {{\u2028v\u2028}}"
|
|
158
|
+
}
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
"id": "grammar/line-terminator-in-value-ls",
|
|
162
|
+
"description": "A construct whose option value holds a line separator (U+2028) is literal text.",
|
|
163
|
+
"section": "6",
|
|
164
|
+
"message": "{{v; a:\u2028b; default:D}}",
|
|
165
|
+
"payload": {
|
|
166
|
+
"v": "HIT"
|
|
167
|
+
},
|
|
168
|
+
"expected": {
|
|
169
|
+
"output": "{{v; a:\u2028b; default:D}}"
|
|
170
|
+
}
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
"id": "grammar/line-terminator-escaped-ls",
|
|
174
|
+
"description": "Escaping a line separator (U+2028) does not admit it into a placeholder: the construct is literal text, and the escape is removed from it.",
|
|
175
|
+
"section": "6",
|
|
176
|
+
"message": "{{v\\\u2028x}}",
|
|
177
|
+
"payload": {
|
|
178
|
+
"v\u2028x": "HIT"
|
|
179
|
+
},
|
|
180
|
+
"expected": {
|
|
181
|
+
"output": "{{v\u2028x}}"
|
|
182
|
+
}
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
"id": "grammar/line-terminator-inside-key-ps",
|
|
186
|
+
"description": "A construct whose key holds a paragraph separator (U+2029) is literal text.",
|
|
187
|
+
"section": "A.10",
|
|
188
|
+
"message": "{{v\u2029x}}",
|
|
189
|
+
"payload": {
|
|
190
|
+
"v\u2029x": "HIT"
|
|
191
|
+
},
|
|
192
|
+
"expected": {
|
|
193
|
+
"output": "{{v\u2029x}}"
|
|
194
|
+
}
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
"id": "grammar/line-terminator-beside-resolved-ps",
|
|
198
|
+
"description": "Whether a construct is a placeholder does not depend on what another resolved to: one spanning a paragraph separator (U+2029) stays literal beside a resolved one.",
|
|
199
|
+
"section": "6",
|
|
200
|
+
"message": "{{a}} {{\u2029v\u2029}}",
|
|
201
|
+
"payload": {
|
|
202
|
+
"a": "A",
|
|
203
|
+
"v": "HIT"
|
|
204
|
+
},
|
|
205
|
+
"expected": {
|
|
206
|
+
"output": "A {{\u2029v\u2029}}"
|
|
207
|
+
}
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
"id": "grammar/line-terminator-in-value-ps",
|
|
211
|
+
"description": "A construct whose option value holds a paragraph separator (U+2029) is literal text.",
|
|
212
|
+
"section": "6",
|
|
213
|
+
"message": "{{v; a:\u2029b; default:D}}",
|
|
214
|
+
"payload": {
|
|
215
|
+
"v": "HIT"
|
|
216
|
+
},
|
|
217
|
+
"expected": {
|
|
218
|
+
"output": "{{v; a:\u2029b; default:D}}"
|
|
219
|
+
}
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
"id": "grammar/line-terminator-escaped-ps",
|
|
223
|
+
"description": "Escaping a paragraph separator (U+2029) does not admit it into a placeholder: the construct is literal text, and the escape is removed from it.",
|
|
224
|
+
"section": "6",
|
|
225
|
+
"message": "{{v\\\u2029x}}",
|
|
226
|
+
"payload": {
|
|
227
|
+
"v\u2029x": "HIT"
|
|
228
|
+
},
|
|
229
|
+
"expected": {
|
|
230
|
+
"output": "{{v\u2029x}}"
|
|
231
|
+
}
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
"id": "grammar/key-escaped-colon",
|
|
235
|
+
"description": "A key holds a colon as an escape sequence and is matched after unescaping.",
|
|
236
|
+
"section": "6",
|
|
237
|
+
"message": "{{a\\:b}}",
|
|
238
|
+
"payload": {
|
|
239
|
+
"a:b": "HIT",
|
|
240
|
+
"a\\:b": "RAW"
|
|
241
|
+
},
|
|
242
|
+
"expected": {
|
|
243
|
+
"output": "HIT"
|
|
244
|
+
}
|
|
245
|
+
},
|
|
246
|
+
{
|
|
247
|
+
"id": "grammar/key-escaped-semicolon",
|
|
248
|
+
"description": "A key holds a semicolon as an escape sequence.",
|
|
249
|
+
"section": "6",
|
|
250
|
+
"message": "{{a\\;b}}",
|
|
251
|
+
"payload": {
|
|
252
|
+
"a;b": "HIT"
|
|
253
|
+
},
|
|
254
|
+
"expected": {
|
|
255
|
+
"output": "HIT"
|
|
256
|
+
}
|
|
257
|
+
},
|
|
258
|
+
{
|
|
259
|
+
"id": "grammar/key-any-character",
|
|
260
|
+
"description": "A key may hold spaces, dots, digits and non-ASCII text.",
|
|
261
|
+
"section": "6",
|
|
262
|
+
"message": "{{a b.c1 \u00fc}}",
|
|
263
|
+
"payload": {
|
|
264
|
+
"a b.c1 \u00fc": "HIT"
|
|
265
|
+
},
|
|
266
|
+
"expected": {
|
|
267
|
+
"output": "HIT"
|
|
268
|
+
}
|
|
269
|
+
},
|
|
270
|
+
{
|
|
271
|
+
"id": "grammar/key-astral-code-point",
|
|
272
|
+
"description": "The grammar is defined over code points, so a key may be a character outside the Basic Multilingual Plane.",
|
|
273
|
+
"section": "6",
|
|
274
|
+
"message": "{{\ud83d\ude00; default:D}}",
|
|
275
|
+
"payload": {
|
|
276
|
+
"\ud83d\ude00": "HIT"
|
|
277
|
+
},
|
|
278
|
+
"expected": {
|
|
279
|
+
"output": "HIT"
|
|
280
|
+
}
|
|
281
|
+
},
|
|
282
|
+
{
|
|
283
|
+
"id": "grammar/key-exact-code-points",
|
|
284
|
+
"description": "Keys are compared by exact code-point equality, so a decomposed spelling does not match a precomposed key.",
|
|
285
|
+
"section": "6",
|
|
286
|
+
"message": "{{caf\u00e9; default:D}}",
|
|
287
|
+
"payload": {
|
|
288
|
+
"cafe\u0301": "X"
|
|
289
|
+
},
|
|
290
|
+
"expected": {
|
|
291
|
+
"output": "D"
|
|
292
|
+
}
|
|
293
|
+
},
|
|
294
|
+
{
|
|
295
|
+
"id": "grammar/key-case-sensitive",
|
|
296
|
+
"description": "A key is compared case-sensitively.",
|
|
297
|
+
"section": "6",
|
|
298
|
+
"message": "{{Name}}",
|
|
299
|
+
"payload": {
|
|
300
|
+
"name": "lower",
|
|
301
|
+
"Name": "HIT"
|
|
302
|
+
},
|
|
303
|
+
"expected": {
|
|
304
|
+
"output": "HIT"
|
|
305
|
+
}
|
|
306
|
+
},
|
|
307
|
+
{
|
|
308
|
+
"id": "grammar/modifier-name-after-first-colon",
|
|
309
|
+
"description": "Everything after the selector's first unescaped colon is the modifier name, later colons included, so eq:x names a modifier nobody defined.",
|
|
310
|
+
"section": "6",
|
|
311
|
+
"message": "{{v:eq:x; a:A; default:D}}",
|
|
312
|
+
"payload": {
|
|
313
|
+
"v": "a"
|
|
314
|
+
},
|
|
315
|
+
"key": "grammar.modifier-name",
|
|
316
|
+
"expected": {
|
|
317
|
+
"output": "D",
|
|
318
|
+
"reports": [
|
|
319
|
+
{
|
|
320
|
+
"code": "unknown-modifier",
|
|
321
|
+
"origin": "message",
|
|
322
|
+
"key": "grammar.modifier-name"
|
|
323
|
+
}
|
|
324
|
+
]
|
|
325
|
+
}
|
|
326
|
+
},
|
|
327
|
+
{
|
|
328
|
+
"id": "grammar/selector-colon-skips-escaped",
|
|
329
|
+
"description": "The selector's colon is the first unescaped one, so an escaped colon stays in the key.",
|
|
330
|
+
"section": "6",
|
|
331
|
+
"message": "{{a\\:b:eq; x:X; default:D}}",
|
|
332
|
+
"payload": {
|
|
333
|
+
"a:b": "x"
|
|
334
|
+
},
|
|
335
|
+
"expected": {
|
|
336
|
+
"output": "X"
|
|
337
|
+
}
|
|
338
|
+
},
|
|
339
|
+
{
|
|
340
|
+
"id": "grammar/unknown-modifier-is-not-literal",
|
|
341
|
+
"description": "A modifier name this format does not specify is a message error, not literal text.",
|
|
342
|
+
"section": "6",
|
|
343
|
+
"message": "{{v:plural; default:D}}",
|
|
344
|
+
"payload": {
|
|
345
|
+
"v": "a"
|
|
346
|
+
},
|
|
347
|
+
"key": "grammar.unknown",
|
|
348
|
+
"expected": {
|
|
349
|
+
"output": "D",
|
|
350
|
+
"reports": [
|
|
351
|
+
{
|
|
352
|
+
"code": "unknown-modifier",
|
|
353
|
+
"origin": "message",
|
|
354
|
+
"key": "grammar.unknown"
|
|
355
|
+
}
|
|
356
|
+
]
|
|
357
|
+
}
|
|
358
|
+
},
|
|
359
|
+
{
|
|
360
|
+
"id": "grammar/option-value-keeps-colons",
|
|
361
|
+
"description": "An option's colon is the first unescaped one in the segment, so the value keeps every colon after it.",
|
|
362
|
+
"section": "6",
|
|
363
|
+
"message": "{{v; a:10:30; default:D}}",
|
|
364
|
+
"payload": {
|
|
365
|
+
"v": "a"
|
|
366
|
+
},
|
|
367
|
+
"expected": {
|
|
368
|
+
"output": "10:30"
|
|
369
|
+
}
|
|
370
|
+
},
|
|
371
|
+
{
|
|
372
|
+
"id": "grammar/inline-default-starts-with-colon",
|
|
373
|
+
"description": "An inline default whose value begins with a colon keeps that colon.",
|
|
374
|
+
"section": "6",
|
|
375
|
+
"message": "{{v; default::x}}",
|
|
376
|
+
"payload": {},
|
|
377
|
+
"expected": {
|
|
378
|
+
"output": ":x"
|
|
379
|
+
}
|
|
380
|
+
},
|
|
381
|
+
{
|
|
382
|
+
"id": "grammar/option-colon-skips-escaped",
|
|
383
|
+
"description": "An escaped colon in an option key does not end the key, so the text before it is not the key compared.",
|
|
384
|
+
"section": "6",
|
|
385
|
+
"message": "{{v; a\\:b:X; default:D}}",
|
|
386
|
+
"payload": {
|
|
387
|
+
"v": "a"
|
|
388
|
+
},
|
|
389
|
+
"expected": {
|
|
390
|
+
"output": "D"
|
|
391
|
+
}
|
|
392
|
+
},
|
|
393
|
+
{
|
|
394
|
+
"id": "grammar/escaped-backslash-then-colon",
|
|
395
|
+
"description": "An escaped backslash is a complete escape sequence, so the colon after it is the option's colon.",
|
|
396
|
+
"section": "6",
|
|
397
|
+
"message": "{{v; a\\\\:b:X; default:D}}",
|
|
398
|
+
"payload": {
|
|
399
|
+
"v": "a\\"
|
|
400
|
+
},
|
|
401
|
+
"expected": {
|
|
402
|
+
"output": "b:X"
|
|
403
|
+
}
|
|
404
|
+
},
|
|
405
|
+
{
|
|
406
|
+
"id": "grammar/semicolon-ends-segment",
|
|
407
|
+
"description": "An unescaped semicolon ends the segment, so a value stops there.",
|
|
408
|
+
"section": "6",
|
|
409
|
+
"message": "{{v; a:x;y; default:D}}",
|
|
410
|
+
"payload": {
|
|
411
|
+
"v": "a"
|
|
412
|
+
},
|
|
413
|
+
"expected": {
|
|
414
|
+
"output": "x"
|
|
415
|
+
}
|
|
416
|
+
},
|
|
417
|
+
{
|
|
418
|
+
"id": "grammar/escaped-opening-first-brace",
|
|
419
|
+
"description": "A backslash before the opening pair suppresses it, so the construct is literal text.",
|
|
420
|
+
"section": "A.15",
|
|
421
|
+
"message": "\\{{v}}",
|
|
422
|
+
"payload": {
|
|
423
|
+
"v": "HIT"
|
|
424
|
+
},
|
|
425
|
+
"expected": {
|
|
426
|
+
"output": "{{v}}"
|
|
427
|
+
}
|
|
428
|
+
},
|
|
429
|
+
{
|
|
430
|
+
"id": "grammar/escaped-opening-without-value",
|
|
431
|
+
"description": "A suppressed opening pair renders the same over an empty payload, because nothing about it is resolved.",
|
|
432
|
+
"section": "A.15",
|
|
433
|
+
"message": "\\{{v}}",
|
|
434
|
+
"payload": {},
|
|
435
|
+
"expected": {
|
|
436
|
+
"output": "{{v}}"
|
|
437
|
+
}
|
|
438
|
+
},
|
|
439
|
+
{
|
|
440
|
+
"id": "grammar/escaped-opening-second-brace",
|
|
441
|
+
"description": "A backslash consuming the second brace of an opening pair leaves the first standing alone, so the construct is literal text.",
|
|
442
|
+
"section": "6",
|
|
443
|
+
"message": "{\\{v}}",
|
|
444
|
+
"payload": {
|
|
445
|
+
"v": "HIT"
|
|
446
|
+
},
|
|
447
|
+
"expected": {
|
|
448
|
+
"output": "{{v}}"
|
|
449
|
+
}
|
|
450
|
+
},
|
|
451
|
+
{
|
|
452
|
+
"id": "grammar/escaped-closing-second-brace",
|
|
453
|
+
"description": "A backslash consuming the second brace of a closing pair leaves no closing pair, so the construct is literal text.",
|
|
454
|
+
"section": "6",
|
|
455
|
+
"message": "{{v}\\}",
|
|
456
|
+
"payload": {
|
|
457
|
+
"v": "HIT"
|
|
458
|
+
},
|
|
459
|
+
"expected": {
|
|
460
|
+
"output": "{{v}}"
|
|
461
|
+
}
|
|
462
|
+
},
|
|
463
|
+
{
|
|
464
|
+
"id": "grammar/escaped-closing-first-brace",
|
|
465
|
+
"description": "A backslash consuming the first brace of a closing pair leaves no closing pair, so the construct is literal text.",
|
|
466
|
+
"section": "A.16",
|
|
467
|
+
"message": "{{v\\}}",
|
|
468
|
+
"payload": {
|
|
469
|
+
"v": "HIT"
|
|
470
|
+
},
|
|
471
|
+
"expected": {
|
|
472
|
+
"output": "{{v}}"
|
|
473
|
+
}
|
|
474
|
+
},
|
|
475
|
+
{
|
|
476
|
+
"id": "grammar/escaped-closing-not-in-key",
|
|
477
|
+
"description": "The backslash before a closing brace is not read into the key: the construct is literal text whatever the payload spells.",
|
|
478
|
+
"section": "A.16",
|
|
479
|
+
"message": "{{v\\}}",
|
|
480
|
+
"payload": {
|
|
481
|
+
"v\\": "BS",
|
|
482
|
+
"v": "V"
|
|
483
|
+
},
|
|
484
|
+
"expected": {
|
|
485
|
+
"output": "{{v}}"
|
|
486
|
+
}
|
|
487
|
+
},
|
|
488
|
+
{
|
|
489
|
+
"id": "grammar/key-ends-in-backslash",
|
|
490
|
+
"description": "An escaped backslash ends a key as one backslash, a spelling distinct from an escaped brace.",
|
|
491
|
+
"section": "A.16",
|
|
492
|
+
"message": "{{v\\\\}}",
|
|
493
|
+
"payload": {
|
|
494
|
+
"v\\": "BS",
|
|
495
|
+
"v\\\\": "BS2"
|
|
496
|
+
},
|
|
497
|
+
"expected": {
|
|
498
|
+
"output": "BS"
|
|
499
|
+
}
|
|
500
|
+
},
|
|
501
|
+
{
|
|
502
|
+
"id": "grammar/key-ends-in-closing-brace",
|
|
503
|
+
"description": "Consuming one brace disturbs no other, so a key may end in a closing brace and the remaining two close the placeholder.",
|
|
504
|
+
"section": "A.16",
|
|
505
|
+
"message": "{{v\\}}}",
|
|
506
|
+
"payload": {
|
|
507
|
+
"v}": "HIT"
|
|
508
|
+
},
|
|
509
|
+
"expected": {
|
|
510
|
+
"output": "HIT"
|
|
511
|
+
}
|
|
512
|
+
},
|
|
513
|
+
{
|
|
514
|
+
"id": "grammar/escaped-delimiters-in-value",
|
|
515
|
+
"description": "Escaped delimiters inside a value are content, and neither close the placeholder nor open another.",
|
|
516
|
+
"section": "6",
|
|
517
|
+
"message": "{{v; a:x\\{\\{y\\}\\}z; default:D}}",
|
|
518
|
+
"payload": {
|
|
519
|
+
"v": "a"
|
|
520
|
+
},
|
|
521
|
+
"expected": {
|
|
522
|
+
"output": "x{{y}}z"
|
|
523
|
+
}
|
|
524
|
+
},
|
|
525
|
+
{
|
|
526
|
+
"id": "grammar/unpaired-closing-brace-in-key",
|
|
527
|
+
"description": "A closing brace that starts no pair needs no escape inside a key.",
|
|
528
|
+
"section": "6",
|
|
529
|
+
"message": "{{a}b}}",
|
|
530
|
+
"payload": {
|
|
531
|
+
"a}b": "HIT"
|
|
532
|
+
},
|
|
533
|
+
"expected": {
|
|
534
|
+
"output": "HIT"
|
|
535
|
+
}
|
|
536
|
+
},
|
|
537
|
+
{
|
|
538
|
+
"id": "grammar/escaped-brace-after-opening-pair",
|
|
539
|
+
"description": "An escaped brace right after the opening pair is the key's first character, the pair itself intact.",
|
|
540
|
+
"section": "6",
|
|
541
|
+
"message": "{{\\{v}}",
|
|
542
|
+
"payload": {
|
|
543
|
+
"{v": "HIT"
|
|
544
|
+
},
|
|
545
|
+
"expected": {
|
|
546
|
+
"output": "HIT"
|
|
547
|
+
}
|
|
548
|
+
},
|
|
549
|
+
{
|
|
550
|
+
"id": "grammar/consumed-brace-breaks-inner-pair",
|
|
551
|
+
"description": "A brace a backslash consumed cannot start an inner opening pair, so the key runs on through it.",
|
|
552
|
+
"section": "6",
|
|
553
|
+
"message": "{{a\\{{b}}",
|
|
554
|
+
"payload": {
|
|
555
|
+
"a{{b": "NESTKEY",
|
|
556
|
+
"b": "B"
|
|
557
|
+
},
|
|
558
|
+
"expected": {
|
|
559
|
+
"output": "NESTKEY"
|
|
560
|
+
}
|
|
561
|
+
},
|
|
562
|
+
{
|
|
563
|
+
"id": "grammar/unclosed-construct-is-literal",
|
|
564
|
+
"description": "A placeholder begins only where a complete one derives, so an opening pair with no closing pair is literal text.",
|
|
565
|
+
"section": "6",
|
|
566
|
+
"message": "{{v",
|
|
567
|
+
"payload": {
|
|
568
|
+
"v": "HIT"
|
|
569
|
+
},
|
|
570
|
+
"expected": {
|
|
571
|
+
"output": "{{v"
|
|
572
|
+
}
|
|
573
|
+
},
|
|
574
|
+
{
|
|
575
|
+
"id": "grammar/inner-opening-pair-ends-attempt",
|
|
576
|
+
"description": "Where a scan reaches no closing pair, only the opening brace is literal and the scan resumes at the next code point, where the inner pair opens for itself.",
|
|
577
|
+
"section": "6",
|
|
578
|
+
"message": "{{a{{b}}",
|
|
579
|
+
"payload": {
|
|
580
|
+
"a{{b": "NESTKEY",
|
|
581
|
+
"b": "B"
|
|
582
|
+
},
|
|
583
|
+
"expected": {
|
|
584
|
+
"output": "{{aB"
|
|
585
|
+
}
|
|
586
|
+
},
|
|
587
|
+
{
|
|
588
|
+
"id": "grammar/four-braces",
|
|
589
|
+
"description": "Four opening braces are one literal brace followed by a placeholder whose key starts with a brace.",
|
|
590
|
+
"section": "6",
|
|
591
|
+
"message": "{{{{a}}",
|
|
592
|
+
"payload": {
|
|
593
|
+
"{a": "BRACEA",
|
|
594
|
+
"a": "A"
|
|
595
|
+
},
|
|
596
|
+
"expected": {
|
|
597
|
+
"output": "{BRACEA"
|
|
598
|
+
}
|
|
599
|
+
},
|
|
600
|
+
{
|
|
601
|
+
"id": "grammar/closing-pair-first-left-standing",
|
|
602
|
+
"description": "The closing pair is the first one left standing, so a second closing pair is literal text.",
|
|
603
|
+
"section": "6",
|
|
604
|
+
"message": "{{v}}}}",
|
|
605
|
+
"payload": {
|
|
606
|
+
"v": "HIT"
|
|
607
|
+
},
|
|
608
|
+
"expected": {
|
|
609
|
+
"output": "HIT}}"
|
|
610
|
+
}
|
|
611
|
+
},
|
|
612
|
+
{
|
|
613
|
+
"id": "grammar/underived-construct-reaches-no-step",
|
|
614
|
+
"description": "A construct section 6 does not derive is rendered as it stands, and neither looks up its key nor takes the chain.",
|
|
615
|
+
"section": "9.1",
|
|
616
|
+
"message": "{{v; default:D",
|
|
617
|
+
"payload": {
|
|
618
|
+
"v": "HIT",
|
|
619
|
+
"default": "P"
|
|
620
|
+
},
|
|
621
|
+
"expected": {
|
|
622
|
+
"output": "{{v; default:D"
|
|
623
|
+
}
|
|
624
|
+
},
|
|
625
|
+
{
|
|
626
|
+
"id": "grammar/empty-selector-looks-nothing-up",
|
|
627
|
+
"description": "An empty placeholder names no key and resolves none of the payload keys \"\", \"null\" or \"undefined\".",
|
|
628
|
+
"section": "9.1",
|
|
629
|
+
"message": "{{}}",
|
|
630
|
+
"payload": {
|
|
631
|
+
"": "EMPTY",
|
|
632
|
+
"null": "NULL",
|
|
633
|
+
"undefined": "UNDEFINED"
|
|
634
|
+
},
|
|
635
|
+
"expected": {
|
|
636
|
+
"output": ""
|
|
637
|
+
}
|
|
638
|
+
},
|
|
639
|
+
{
|
|
640
|
+
"id": "grammar/blank-selector-looks-nothing-up",
|
|
641
|
+
"description": "A placeholder whose selector is only whitespace names no key and resolves none of the payload keys \"\", \"null\" or \"undefined\".",
|
|
642
|
+
"section": "9.1",
|
|
643
|
+
"message": "{{ }}",
|
|
644
|
+
"payload": {
|
|
645
|
+
"": "EMPTY",
|
|
646
|
+
"null": "NULL",
|
|
647
|
+
"undefined": "UNDEFINED"
|
|
648
|
+
},
|
|
649
|
+
"expected": {
|
|
650
|
+
"output": ""
|
|
651
|
+
}
|
|
652
|
+
},
|
|
653
|
+
{
|
|
654
|
+
"id": "grammar/modifier-only-selector-looks-nothing-up",
|
|
655
|
+
"description": "A selector naming a modifier and no key looks nothing up, and is neither a substitution nor a selection to report.",
|
|
656
|
+
"section": "9.1",
|
|
657
|
+
"message": "{{:eq}}",
|
|
658
|
+
"payload": {
|
|
659
|
+
"": "EMPTY",
|
|
660
|
+
"null": "NULL",
|
|
661
|
+
"undefined": "UNDEFINED"
|
|
662
|
+
},
|
|
663
|
+
"key": "grammar.modifier-only",
|
|
664
|
+
"expected": {
|
|
665
|
+
"output": "",
|
|
666
|
+
"reports": []
|
|
667
|
+
}
|
|
668
|
+
},
|
|
669
|
+
{
|
|
670
|
+
"id": "grammar/empty-placeholder-no-default",
|
|
671
|
+
"description": "An empty placeholder is a placeholder and resolves to the chain, the empty string where no link yields text.",
|
|
672
|
+
"section": "A.14",
|
|
673
|
+
"message": "{{}}",
|
|
674
|
+
"payload": {},
|
|
675
|
+
"expected": {
|
|
676
|
+
"output": ""
|
|
677
|
+
}
|
|
678
|
+
},
|
|
679
|
+
{
|
|
680
|
+
"id": "grammar/empty-placeholder-payload-default",
|
|
681
|
+
"description": "An empty placeholder resolves to the payload's default.",
|
|
682
|
+
"section": "A.14",
|
|
683
|
+
"message": "{{}}",
|
|
684
|
+
"payload": {
|
|
685
|
+
"default": "D"
|
|
686
|
+
},
|
|
687
|
+
"expected": {
|
|
688
|
+
"output": "D"
|
|
689
|
+
}
|
|
690
|
+
},
|
|
691
|
+
{
|
|
692
|
+
"id": "grammar/blank-placeholder-no-default",
|
|
693
|
+
"description": "A placeholder holding one space is recognized exactly as the empty one is.",
|
|
694
|
+
"section": "A.14",
|
|
695
|
+
"message": "{{ }}",
|
|
696
|
+
"payload": {},
|
|
697
|
+
"expected": {
|
|
698
|
+
"output": ""
|
|
699
|
+
}
|
|
700
|
+
},
|
|
701
|
+
{
|
|
702
|
+
"id": "grammar/blank-placeholder-payload-default",
|
|
703
|
+
"description": "A placeholder holding one space resolves to the payload's default exactly as the empty one does.",
|
|
704
|
+
"section": "A.14",
|
|
705
|
+
"message": "{{ }}",
|
|
706
|
+
"payload": {
|
|
707
|
+
"default": "D"
|
|
708
|
+
},
|
|
709
|
+
"expected": {
|
|
710
|
+
"output": "D"
|
|
711
|
+
}
|
|
712
|
+
},
|
|
713
|
+
{
|
|
714
|
+
"id": "grammar/keyless-inline-default",
|
|
715
|
+
"description": "A selector naming no key resolves to the chain, the inline default included.",
|
|
716
|
+
"section": "9.1",
|
|
717
|
+
"message": "{{; default:D}}",
|
|
718
|
+
"payload": {},
|
|
719
|
+
"expected": {
|
|
720
|
+
"output": "D"
|
|
721
|
+
}
|
|
722
|
+
},
|
|
723
|
+
{
|
|
724
|
+
"id": "grammar/keyless-with-option",
|
|
725
|
+
"description": "A placeholder that names no key but carries an option is still a placeholder that names no key, and resolves to the chain.",
|
|
726
|
+
"section": "A.14",
|
|
727
|
+
"message": "{{ ; x:1 }}",
|
|
728
|
+
"payload": {
|
|
729
|
+
"default": "D"
|
|
730
|
+
},
|
|
731
|
+
"expected": {
|
|
732
|
+
"output": "D"
|
|
733
|
+
}
|
|
734
|
+
},
|
|
735
|
+
{
|
|
736
|
+
"id": "grammar/empty-pair-inside-construct",
|
|
737
|
+
"description": "An empty pair inside another construct resolves as a placeholder, and the construct around it does not derive.",
|
|
738
|
+
"section": "A.14",
|
|
739
|
+
"message": "{{;a:{{}}",
|
|
740
|
+
"payload": {
|
|
741
|
+
"default": "D"
|
|
742
|
+
},
|
|
743
|
+
"expected": {
|
|
744
|
+
"output": "{{;a:D"
|
|
745
|
+
}
|
|
746
|
+
},
|
|
747
|
+
{
|
|
748
|
+
"id": "grammar/inline-default-encloses",
|
|
749
|
+
"description": "An inline default written around a placeholder resolves through the inner one first, and the enclosing construct derives on the next pass.",
|
|
750
|
+
"section": "12",
|
|
751
|
+
"message": "{{v; default:{{w}}}}",
|
|
752
|
+
"payload": {
|
|
753
|
+
"w": "W"
|
|
754
|
+
},
|
|
755
|
+
"expected": {
|
|
756
|
+
"output": "W"
|
|
757
|
+
}
|
|
758
|
+
},
|
|
759
|
+
{
|
|
760
|
+
"id": "grammar/option-value-encloses",
|
|
761
|
+
"description": "An option value written around a placeholder resolves through the inner one first, and the enclosing construct derives on the next pass.",
|
|
762
|
+
"section": "12",
|
|
763
|
+
"message": "{{v; a:{{w}}}}",
|
|
764
|
+
"payload": {
|
|
765
|
+
"v": "a",
|
|
766
|
+
"w": "W"
|
|
767
|
+
},
|
|
768
|
+
"expected": {
|
|
769
|
+
"output": "W"
|
|
770
|
+
}
|
|
771
|
+
},
|
|
772
|
+
{
|
|
773
|
+
"id": "grammar/option-key-encloses",
|
|
774
|
+
"description": "An option key written around a placeholder resolves through the inner one first, and the enclosing construct derives on the next pass.",
|
|
775
|
+
"section": "12",
|
|
776
|
+
"message": "{{v; {{k}}:X; default:D}}",
|
|
777
|
+
"payload": {
|
|
778
|
+
"v": "a",
|
|
779
|
+
"k": "a"
|
|
780
|
+
},
|
|
781
|
+
"expected": {
|
|
782
|
+
"output": "X"
|
|
783
|
+
}
|
|
784
|
+
},
|
|
785
|
+
{
|
|
786
|
+
"id": "grammar/modifier-name-encloses",
|
|
787
|
+
"description": "A modifier name written around a placeholder resolves through the inner one first, and the enclosing construct derives on the next pass.",
|
|
788
|
+
"section": "12",
|
|
789
|
+
"message": "{{v:{{m}}; a:A; default:D}}",
|
|
790
|
+
"payload": {
|
|
791
|
+
"v": "a",
|
|
792
|
+
"m": "eq"
|
|
793
|
+
},
|
|
794
|
+
"expected": {
|
|
795
|
+
"output": "A"
|
|
796
|
+
}
|
|
797
|
+
},
|
|
798
|
+
{
|
|
799
|
+
"id": "grammar/enclosing-derives-on-later-pass",
|
|
800
|
+
"description": "A construct enclosing another is not a placeholder; the inner one resolves first, and the enclosing one is scanned again over what it resolved to.",
|
|
801
|
+
"section": "12",
|
|
802
|
+
"message": "{{a{{b}}c}}",
|
|
803
|
+
"payload": {
|
|
804
|
+
"b": "x",
|
|
805
|
+
"axc": "HIT"
|
|
806
|
+
},
|
|
807
|
+
"expected": {
|
|
808
|
+
"output": "HIT"
|
|
809
|
+
}
|
|
810
|
+
},
|
|
811
|
+
{
|
|
812
|
+
"id": "grammar/inner-value-closes-early",
|
|
813
|
+
"description": "A value carrying a closing pair closes the enclosing construct early on the next pass.",
|
|
814
|
+
"section": "12",
|
|
815
|
+
"message": "{{a{{b}}c}}",
|
|
816
|
+
"payload": {
|
|
817
|
+
"b": "x}}",
|
|
818
|
+
"ax": "HIT"
|
|
819
|
+
},
|
|
820
|
+
"expected": {
|
|
821
|
+
"output": "HITc}}"
|
|
822
|
+
}
|
|
823
|
+
},
|
|
824
|
+
{
|
|
825
|
+
"id": "grammar/inner-value-opens-pair",
|
|
826
|
+
"description": "A value carrying an opening pair keeps the enclosing construct from deriving at all.",
|
|
827
|
+
"section": "12",
|
|
828
|
+
"message": "{{a{{b}}c}}",
|
|
829
|
+
"payload": {
|
|
830
|
+
"b": "{{",
|
|
831
|
+
"c": "C"
|
|
832
|
+
},
|
|
833
|
+
"expected": {
|
|
834
|
+
"output": "{{aC"
|
|
835
|
+
}
|
|
836
|
+
},
|
|
837
|
+
{
|
|
838
|
+
"id": "grammar/value-carrying-opening-pair",
|
|
839
|
+
"description": "A value carrying an opening pair alone leaves nothing to derive on the following pass.",
|
|
840
|
+
"section": "12",
|
|
841
|
+
"message": "[{{v}}]",
|
|
842
|
+
"payload": {
|
|
843
|
+
"v": "{{"
|
|
844
|
+
},
|
|
845
|
+
"expected": {
|
|
846
|
+
"output": "[{{]"
|
|
847
|
+
}
|
|
848
|
+
},
|
|
849
|
+
{
|
|
850
|
+
"id": "grammar/value-carrying-closing-pair",
|
|
851
|
+
"description": "A value carrying a closing pair alone leaves nothing to derive on the following pass.",
|
|
852
|
+
"section": "12",
|
|
853
|
+
"message": "[{{v}}]",
|
|
854
|
+
"payload": {
|
|
855
|
+
"v": "}}"
|
|
856
|
+
},
|
|
857
|
+
"expected": {
|
|
858
|
+
"output": "[}}]"
|
|
859
|
+
}
|
|
860
|
+
},
|
|
861
|
+
{
|
|
862
|
+
"id": "grammar/resolved-text-is-ordinary",
|
|
863
|
+
"description": "What a placeholder resolved to is ordinary text to the next pass, so a line terminator it carried keeps the enclosing construct literal.",
|
|
864
|
+
"section": "12",
|
|
865
|
+
"message": "{{a{{b}}c}}",
|
|
866
|
+
"payload": {
|
|
867
|
+
"b": "\u000a",
|
|
868
|
+
"a\u000ac": "LEAKED"
|
|
869
|
+
},
|
|
870
|
+
"expected": {
|
|
871
|
+
"output": "{{a\u000ac}}"
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
]
|
|
875
|
+
}
|