@b9g/crank 0.5.7 → 0.6.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.
- package/README.md +225 -22
- package/crank.cjs +2008 -1984
- package/crank.cjs.map +1 -1
- package/crank.d.ts +491 -486
- package/crank.js +2008 -1984
- package/crank.js.map +1 -1
- package/dom.cjs +320 -289
- package/dom.cjs.map +1 -1
- package/dom.d.ts +14 -14
- package/dom.js +321 -290
- package/dom.js.map +1 -1
- package/html.cjs +154 -136
- package/html.cjs.map +1 -1
- package/html.d.ts +17 -17
- package/html.js +155 -137
- package/html.js.map +1 -1
- package/jsx-runtime.cjs +13 -8
- package/jsx-runtime.cjs.map +1 -1
- package/jsx-runtime.d.ts +6 -5
- package/jsx-runtime.js +13 -9
- package/jsx-runtime.js.map +1 -1
- package/jsx-tag.cjs +424 -421
- package/jsx-tag.cjs.map +1 -1
- package/jsx-tag.d.ts +4 -2
- package/jsx-tag.js +424 -422
- package/jsx-tag.js.map +1 -1
- package/package.json +30 -30
- package/standalone.cjs +1 -0
- package/standalone.cjs.map +1 -1
- package/standalone.d.ts +2 -2
- package/standalone.js +1 -1
- package/umd.d.ts +3 -3
- package/umd.js +2479 -2406
- package/umd.js.map +1 -1
package/jsx-tag.cjs
CHANGED
|
@@ -2,428 +2,431 @@
|
|
|
2
2
|
|
|
3
3
|
var crank = require('./crank.cjs');
|
|
4
4
|
|
|
5
|
-
const cache = new Map();
|
|
6
|
-
function jsx(spans, ...expressions) {
|
|
7
|
-
const key = JSON.stringify(spans.raw);
|
|
8
|
-
let parseResult = cache.get(key);
|
|
9
|
-
if (parseResult == null) {
|
|
10
|
-
parseResult = parse(spans.raw);
|
|
11
|
-
cache.set(key, parseResult);
|
|
12
|
-
}
|
|
13
|
-
const { element, targets } = parseResult;
|
|
14
|
-
for (let i = 0; i < expressions.length; i++) {
|
|
15
|
-
const exp = expressions[i];
|
|
16
|
-
const target = targets[i];
|
|
17
|
-
if (target) {
|
|
18
|
-
if (target.type === "error") {
|
|
19
|
-
throw new SyntaxError(target.message.replace("${}", formatTagForError(exp)));
|
|
20
|
-
}
|
|
21
|
-
target.value = exp;
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
return build(element);
|
|
25
|
-
}
|
|
26
|
-
/**
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
* Group
|
|
32
|
-
* Group
|
|
33
|
-
* Group
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
* the
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
* Group
|
|
46
|
-
* Group
|
|
47
|
-
* Group
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
const
|
|
52
|
-
const
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
let
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
//
|
|
89
|
-
//
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
element
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
element
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
//
|
|
247
|
-
//
|
|
248
|
-
//
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
const
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
prop.
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
//
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
case "
|
|
388
|
-
return "\
|
|
389
|
-
case "
|
|
390
|
-
return "\
|
|
391
|
-
case "
|
|
392
|
-
return "\
|
|
393
|
-
case "
|
|
394
|
-
return "\
|
|
395
|
-
case "
|
|
396
|
-
return "\
|
|
397
|
-
case "
|
|
398
|
-
return
|
|
399
|
-
case "
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
return
|
|
406
|
-
|
|
407
|
-
return
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
5
|
+
const cache = new Map();
|
|
6
|
+
function jsx(spans, ...expressions) {
|
|
7
|
+
const key = JSON.stringify(spans.raw);
|
|
8
|
+
let parseResult = cache.get(key);
|
|
9
|
+
if (parseResult == null) {
|
|
10
|
+
parseResult = parse(spans.raw);
|
|
11
|
+
cache.set(key, parseResult);
|
|
12
|
+
}
|
|
13
|
+
const { element, targets } = parseResult;
|
|
14
|
+
for (let i = 0; i < expressions.length; i++) {
|
|
15
|
+
const exp = expressions[i];
|
|
16
|
+
const target = targets[i];
|
|
17
|
+
if (target) {
|
|
18
|
+
if (target.type === "error") {
|
|
19
|
+
throw new SyntaxError(target.message.replace("${}", formatTagForError(exp)));
|
|
20
|
+
}
|
|
21
|
+
target.value = exp;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return build(element);
|
|
25
|
+
}
|
|
26
|
+
/** Alias for `jsx` template tag. */
|
|
27
|
+
const html = jsx;
|
|
28
|
+
/**
|
|
29
|
+
* Matches first significant character in children mode.
|
|
30
|
+
*
|
|
31
|
+
* Group 1: newline
|
|
32
|
+
* Group 2: comment
|
|
33
|
+
* Group 3: tag
|
|
34
|
+
* Group 4: closing slash
|
|
35
|
+
* Group 5: tag name
|
|
36
|
+
*
|
|
37
|
+
* The comment group must appear first because the tag group can potentially
|
|
38
|
+
* match a comment, so that we can handle tag expressions where we’ve reached
|
|
39
|
+
* the end of a span.
|
|
40
|
+
*/
|
|
41
|
+
const CHILDREN_RE = /((?:\r|\n|\r\n)\s*)|(<!--[\S\s]*?(?:-->|$))|(<\s*(\/{0,2})\s*([-_$\w]*))/g;
|
|
42
|
+
/**
|
|
43
|
+
* Matches props after element tags.
|
|
44
|
+
*
|
|
45
|
+
* Group 1: tag end
|
|
46
|
+
* Group 2: spread props
|
|
47
|
+
* Group 3: prop name
|
|
48
|
+
* Group 4: equals
|
|
49
|
+
* Group 5: prop value string
|
|
50
|
+
*/
|
|
51
|
+
const PROPS_RE = /\s*(?:(\/?\s*>)|(\.\.\.\s*)|(?:([-_$\w]+)\s*(=)?\s*(?:("(\\"|[\S\s])*?(?:"|$)|'(?:\\'|[\S\s])*?(?:'|$)))?))/g;
|
|
52
|
+
const CLOSING_BRACKET_RE = />/g;
|
|
53
|
+
const CLOSING_SINGLE_QUOTE_RE = /[^\\]?'/g;
|
|
54
|
+
const CLOSING_DOUBLE_QUOTE_RE = /[^\\]?"/g;
|
|
55
|
+
const CLOSING_COMMENT_RE = /-->/g;
|
|
56
|
+
function parse(spans) {
|
|
57
|
+
let matcher = CHILDREN_RE;
|
|
58
|
+
const stack = [];
|
|
59
|
+
let element = {
|
|
60
|
+
type: "element",
|
|
61
|
+
open: { type: "tag", slash: "", value: "" },
|
|
62
|
+
close: null,
|
|
63
|
+
props: [],
|
|
64
|
+
children: [],
|
|
65
|
+
};
|
|
66
|
+
const targets = [];
|
|
67
|
+
let lineStart = true;
|
|
68
|
+
for (let s = 0; s < spans.length; s++) {
|
|
69
|
+
const span = spans[s];
|
|
70
|
+
// Whether or not an expression is upcoming. Used to provide better errors.
|
|
71
|
+
const expressing = s < spans.length - 1;
|
|
72
|
+
let expressionTarget = null;
|
|
73
|
+
for (let i = 0, end = i; i < span.length; i = end) {
|
|
74
|
+
matcher.lastIndex = i;
|
|
75
|
+
const match = matcher.exec(span);
|
|
76
|
+
end = match ? match.index + match[0].length : span.length;
|
|
77
|
+
switch (matcher) {
|
|
78
|
+
case CHILDREN_RE: {
|
|
79
|
+
if (match) {
|
|
80
|
+
const [, newline, comment, tag, closingSlash, tagName] = match;
|
|
81
|
+
if (i < match.index) {
|
|
82
|
+
let before = span.slice(i, match.index);
|
|
83
|
+
if (lineStart) {
|
|
84
|
+
before = before.replace(/^\s*/, "");
|
|
85
|
+
}
|
|
86
|
+
if (newline) {
|
|
87
|
+
if (span[Math.max(0, match.index - 1)] === "\\") {
|
|
88
|
+
// We preserve whitespace before escaped newlines and have to
|
|
89
|
+
// remove the backslash.
|
|
90
|
+
// jsx` \
|
|
91
|
+
// `
|
|
92
|
+
before = before.slice(0, -1);
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
before = before.replace(/\s*$/, "");
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
if (before) {
|
|
99
|
+
element.children.push({ type: "value", value: before });
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
lineStart = !!newline;
|
|
103
|
+
if (comment) {
|
|
104
|
+
if (end === span.length) {
|
|
105
|
+
// Expression in a comment:
|
|
106
|
+
// jsx`<!-- ${exp} -->`
|
|
107
|
+
matcher = CLOSING_COMMENT_RE;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
else if (tag) {
|
|
111
|
+
if (closingSlash) {
|
|
112
|
+
element.close = {
|
|
113
|
+
type: "tag",
|
|
114
|
+
slash: closingSlash,
|
|
115
|
+
value: tagName,
|
|
116
|
+
};
|
|
117
|
+
if (!stack.length) {
|
|
118
|
+
if (end !== span.length) {
|
|
119
|
+
throw new SyntaxError(`Unmatched closing tag "${tagName}"`);
|
|
120
|
+
}
|
|
121
|
+
// ERROR EXPRESSION
|
|
122
|
+
expressionTarget = {
|
|
123
|
+
type: "error",
|
|
124
|
+
message: "Unmatched closing tag ${}",
|
|
125
|
+
value: null,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
if (end === span.length) {
|
|
130
|
+
// TAG EXPRESSION
|
|
131
|
+
expressionTarget = element.close;
|
|
132
|
+
}
|
|
133
|
+
element = stack.pop();
|
|
134
|
+
matcher = CLOSING_BRACKET_RE;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
const next = {
|
|
139
|
+
type: "element",
|
|
140
|
+
open: {
|
|
141
|
+
type: "tag",
|
|
142
|
+
slash: "",
|
|
143
|
+
value: tagName,
|
|
144
|
+
},
|
|
145
|
+
close: null,
|
|
146
|
+
props: [],
|
|
147
|
+
children: [],
|
|
148
|
+
};
|
|
149
|
+
element.children.push(next);
|
|
150
|
+
stack.push(element);
|
|
151
|
+
element = next;
|
|
152
|
+
matcher = PROPS_RE;
|
|
153
|
+
if (end === span.length) {
|
|
154
|
+
// TAG EXPRESSION
|
|
155
|
+
expressionTarget = element.open;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
if (i < span.length) {
|
|
162
|
+
let after = span.slice(i);
|
|
163
|
+
if (!expressing) {
|
|
164
|
+
// trim trailing whitespace
|
|
165
|
+
after = after.replace(/\s*$/, "");
|
|
166
|
+
}
|
|
167
|
+
if (after) {
|
|
168
|
+
element.children.push({ type: "value", value: after });
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
break;
|
|
173
|
+
}
|
|
174
|
+
case PROPS_RE: {
|
|
175
|
+
if (match) {
|
|
176
|
+
const [, tagEnd, spread, name, equals, string] = match;
|
|
177
|
+
if (i < match.index) {
|
|
178
|
+
throw new SyntaxError(`Unexpected text \`${span.slice(i, match.index).trim()}\``);
|
|
179
|
+
}
|
|
180
|
+
if (tagEnd) {
|
|
181
|
+
if (tagEnd[0] === "/") {
|
|
182
|
+
// This is a self-closing element, so there will always be a
|
|
183
|
+
// result on the stack.
|
|
184
|
+
element = stack.pop();
|
|
185
|
+
}
|
|
186
|
+
matcher = CHILDREN_RE;
|
|
187
|
+
}
|
|
188
|
+
else if (spread) {
|
|
189
|
+
const value = {
|
|
190
|
+
type: "value",
|
|
191
|
+
value: null,
|
|
192
|
+
};
|
|
193
|
+
element.props.push(value);
|
|
194
|
+
// SPREAD PROP EXPRESSION
|
|
195
|
+
expressionTarget = value;
|
|
196
|
+
if (!(expressing && end === span.length)) {
|
|
197
|
+
throw new SyntaxError('Expression expected after "..."');
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
else if (name) {
|
|
201
|
+
let value;
|
|
202
|
+
if (string == null) {
|
|
203
|
+
if (!equals) {
|
|
204
|
+
value = { type: "value", value: true };
|
|
205
|
+
}
|
|
206
|
+
else if (end < span.length) {
|
|
207
|
+
throw new SyntaxError(`Unexpected text \`${span.slice(end, end + 20)}\``);
|
|
208
|
+
}
|
|
209
|
+
else {
|
|
210
|
+
value = { type: "value", value: null };
|
|
211
|
+
// PROP EXPRESSION
|
|
212
|
+
expressionTarget = value;
|
|
213
|
+
if (!(expressing && end === span.length)) {
|
|
214
|
+
throw new SyntaxError(`Expression expected for prop "${name}"`);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
219
|
+
const quote = string[0];
|
|
220
|
+
value = { type: "propString", parts: [] };
|
|
221
|
+
value.parts.push(string);
|
|
222
|
+
if (end === span.length) {
|
|
223
|
+
matcher =
|
|
224
|
+
quote === "'"
|
|
225
|
+
? CLOSING_SINGLE_QUOTE_RE
|
|
226
|
+
: CLOSING_DOUBLE_QUOTE_RE;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
const prop = {
|
|
230
|
+
type: "prop",
|
|
231
|
+
name,
|
|
232
|
+
value,
|
|
233
|
+
};
|
|
234
|
+
element.props.push(prop);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
else {
|
|
238
|
+
if (!expressing) {
|
|
239
|
+
if (i === span.length) {
|
|
240
|
+
throw new SyntaxError(`Expected props but reached end of document`);
|
|
241
|
+
}
|
|
242
|
+
else {
|
|
243
|
+
throw new SyntaxError(`Unexpected text \`${span.slice(i, i + 20).trim()}\``);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
// Unexpected expression errors are handled in the outer loop.
|
|
247
|
+
//
|
|
248
|
+
// This would most likely be the starting point for the logic of
|
|
249
|
+
// prop name expressions.
|
|
250
|
+
// jsx`<p ${name}=${value}>`
|
|
251
|
+
}
|
|
252
|
+
break;
|
|
253
|
+
}
|
|
254
|
+
case CLOSING_BRACKET_RE: {
|
|
255
|
+
// We’re in a closing tag and looking for the >.
|
|
256
|
+
if (match) {
|
|
257
|
+
if (i < match.index) {
|
|
258
|
+
throw new SyntaxError(`Unexpected text \`${span.slice(i, match.index).trim()}\``);
|
|
259
|
+
}
|
|
260
|
+
matcher = CHILDREN_RE;
|
|
261
|
+
}
|
|
262
|
+
else {
|
|
263
|
+
if (!expressing) {
|
|
264
|
+
throw new SyntaxError(`Unexpected text \`${span.slice(i, i + 20).trim()}\``);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
break;
|
|
268
|
+
}
|
|
269
|
+
case CLOSING_SINGLE_QUOTE_RE:
|
|
270
|
+
case CLOSING_DOUBLE_QUOTE_RE: {
|
|
271
|
+
const string = span.slice(i, end);
|
|
272
|
+
const prop = element.props[element.props.length - 1];
|
|
273
|
+
const propString = prop.value;
|
|
274
|
+
propString.parts.push(string);
|
|
275
|
+
if (match) {
|
|
276
|
+
matcher = PROPS_RE;
|
|
277
|
+
}
|
|
278
|
+
else {
|
|
279
|
+
if (!expressing) {
|
|
280
|
+
throw new SyntaxError(`Missing \`${matcher === CLOSING_SINGLE_QUOTE_RE ? "'" : '"'}\``);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
break;
|
|
284
|
+
}
|
|
285
|
+
case CLOSING_COMMENT_RE: {
|
|
286
|
+
if (match) {
|
|
287
|
+
matcher = CHILDREN_RE;
|
|
288
|
+
}
|
|
289
|
+
else {
|
|
290
|
+
if (!expressing) {
|
|
291
|
+
throw new SyntaxError("Expected `-->` but reached end of template");
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
break;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
if (expressing) {
|
|
299
|
+
if (expressionTarget) {
|
|
300
|
+
targets.push(expressionTarget);
|
|
301
|
+
if (expressionTarget.type === "error") {
|
|
302
|
+
break;
|
|
303
|
+
}
|
|
304
|
+
continue;
|
|
305
|
+
}
|
|
306
|
+
switch (matcher) {
|
|
307
|
+
case CHILDREN_RE: {
|
|
308
|
+
const target = { type: "value", value: null };
|
|
309
|
+
element.children.push(target);
|
|
310
|
+
targets.push(target);
|
|
311
|
+
break;
|
|
312
|
+
}
|
|
313
|
+
case CLOSING_SINGLE_QUOTE_RE:
|
|
314
|
+
case CLOSING_DOUBLE_QUOTE_RE: {
|
|
315
|
+
const prop = element.props[element.props.length - 1];
|
|
316
|
+
const target = { type: "value", value: null };
|
|
317
|
+
prop.value.parts.push(target);
|
|
318
|
+
targets.push(target);
|
|
319
|
+
break;
|
|
320
|
+
}
|
|
321
|
+
case CLOSING_COMMENT_RE:
|
|
322
|
+
targets.push(null);
|
|
323
|
+
break;
|
|
324
|
+
default:
|
|
325
|
+
throw new SyntaxError("Unexpected expression");
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
else if (expressionTarget) {
|
|
329
|
+
throw new SyntaxError("Expression expected");
|
|
330
|
+
}
|
|
331
|
+
lineStart = false;
|
|
332
|
+
}
|
|
333
|
+
if (stack.length) {
|
|
334
|
+
const ti = targets.indexOf(element.open);
|
|
335
|
+
if (ti === -1) {
|
|
336
|
+
throw new SyntaxError(`Unmatched opening tag "${element.open.value}"`);
|
|
337
|
+
}
|
|
338
|
+
targets[ti] = {
|
|
339
|
+
type: "error",
|
|
340
|
+
message: "Unmatched opening tag ${}",
|
|
341
|
+
value: null,
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
if (element.children.length === 1 && element.children[0].type === "element") {
|
|
345
|
+
element = element.children[0];
|
|
346
|
+
}
|
|
347
|
+
return { element, targets };
|
|
348
|
+
}
|
|
349
|
+
function build(parsed) {
|
|
350
|
+
if (parsed.close !== null &&
|
|
351
|
+
parsed.close.slash !== "//" &&
|
|
352
|
+
parsed.open.value !== parsed.close.value) {
|
|
353
|
+
throw new SyntaxError(`Unmatched closing tag ${formatTagForError(parsed.close.value)}, expected ${formatTagForError(parsed.open.value)}`);
|
|
354
|
+
}
|
|
355
|
+
const children = [];
|
|
356
|
+
for (let i = 0; i < parsed.children.length; i++) {
|
|
357
|
+
const child = parsed.children[i];
|
|
358
|
+
children.push(child.type === "element" ? build(child) : child.value);
|
|
359
|
+
}
|
|
360
|
+
let props = parsed.props.length ? {} : null;
|
|
361
|
+
for (let i = 0; i < parsed.props.length; i++) {
|
|
362
|
+
const prop = parsed.props[i];
|
|
363
|
+
if (prop.type === "prop") {
|
|
364
|
+
let value;
|
|
365
|
+
if (prop.value.type === "value") {
|
|
366
|
+
value = prop.value.value;
|
|
367
|
+
}
|
|
368
|
+
else {
|
|
369
|
+
let string = "";
|
|
370
|
+
for (let i = 0; i < prop.value.parts.length; i++) {
|
|
371
|
+
const part = prop.value.parts[i];
|
|
372
|
+
if (typeof part === "string") {
|
|
373
|
+
string += part;
|
|
374
|
+
}
|
|
375
|
+
else if (typeof part.value !== "boolean" && part.value != null) {
|
|
376
|
+
string +=
|
|
377
|
+
typeof part.value === "string" ? part.value : String(part.value);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
value = string
|
|
381
|
+
// remove quotes
|
|
382
|
+
.slice(1, -1)
|
|
383
|
+
// unescape things
|
|
384
|
+
// adapted from https://stackoverflow.com/a/57330383/1825413
|
|
385
|
+
.replace(/\\x[0-9a-f]{2}|\\u[0-9a-f]{4}|\\u\{[0-9a-f]+\}|\\./gi, (match) => {
|
|
386
|
+
switch (match[1]) {
|
|
387
|
+
case "b":
|
|
388
|
+
return "\b";
|
|
389
|
+
case "f":
|
|
390
|
+
return "\f";
|
|
391
|
+
case "n":
|
|
392
|
+
return "\n";
|
|
393
|
+
case "r":
|
|
394
|
+
return "\r";
|
|
395
|
+
case "t":
|
|
396
|
+
return "\t";
|
|
397
|
+
case "v":
|
|
398
|
+
return "\v";
|
|
399
|
+
case "x":
|
|
400
|
+
return String.fromCharCode(parseInt(match.slice(2), 16));
|
|
401
|
+
case "u":
|
|
402
|
+
if (match[2] === "{") {
|
|
403
|
+
return String.fromCodePoint(parseInt(match.slice(3, -1), 16));
|
|
404
|
+
}
|
|
405
|
+
return String.fromCharCode(parseInt(match.slice(2), 16));
|
|
406
|
+
case "0":
|
|
407
|
+
return "\0";
|
|
408
|
+
default:
|
|
409
|
+
return match.slice(1);
|
|
410
|
+
}
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
props[prop.name] = value;
|
|
414
|
+
}
|
|
415
|
+
else {
|
|
416
|
+
// spread prop
|
|
417
|
+
props = { ...props, ...prop.value };
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
return crank.createElement(parsed.open.value, props, ...children);
|
|
421
|
+
}
|
|
422
|
+
function formatTagForError(tag) {
|
|
423
|
+
return typeof tag === "function"
|
|
424
|
+
? tag.name + "()"
|
|
425
|
+
: typeof tag === "string"
|
|
426
|
+
? `"${tag}"`
|
|
427
|
+
: JSON.stringify(tag);
|
|
426
428
|
}
|
|
427
429
|
|
|
430
|
+
exports.html = html;
|
|
428
431
|
exports.jsx = jsx;
|
|
429
432
|
//# sourceMappingURL=jsx-tag.cjs.map
|