@tsrx/core 0.1.7 → 0.1.8
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/package.json +6 -6
- package/src/plugin.js +185 -104
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"description": "Core compiler infrastructure for TSRX syntax",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": "Dominic Gannaway",
|
|
6
|
-
"version": "0.1.
|
|
6
|
+
"version": "0.1.8",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"repository": {
|
|
9
9
|
"type": "git",
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
"@types/estree-jsx": "^1.0.5",
|
|
65
65
|
"@types/estree": "^1.0.8",
|
|
66
66
|
"acorn": "^8.15.0",
|
|
67
|
-
"esrap": "^2.2.
|
|
67
|
+
"esrap": "^2.2.8",
|
|
68
68
|
"is-reference": "^3.0.3",
|
|
69
69
|
"magic-string": "^0.30.18",
|
|
70
70
|
"zimmerframe": "^1.1.2"
|
|
@@ -82,10 +82,10 @@
|
|
|
82
82
|
"vscode-languageserver-types": "^3.17.5",
|
|
83
83
|
"vue": "3.6.0-beta.10",
|
|
84
84
|
"vue-jsx-vapor": "^3.2.12",
|
|
85
|
-
"@tsrx/preact": "0.1.
|
|
86
|
-
"@tsrx/react": "0.2.
|
|
87
|
-
"@tsrx/solid": "0.1.
|
|
88
|
-
"@tsrx/vue": "0.1.
|
|
85
|
+
"@tsrx/preact": "0.1.8",
|
|
86
|
+
"@tsrx/react": "0.2.8",
|
|
87
|
+
"@tsrx/solid": "0.1.8",
|
|
88
|
+
"@tsrx/vue": "0.1.8"
|
|
89
89
|
},
|
|
90
90
|
"files": [
|
|
91
91
|
"src",
|
package/src/plugin.js
CHANGED
|
@@ -20,6 +20,39 @@ import { DIAGNOSTIC_CODES } from './diagnostics.js';
|
|
|
20
20
|
const JSX_EXPRESSION_VALUE_ERROR =
|
|
21
21
|
'JSX elements cannot be used as expressions. Wrap JSX with `<>...</>` or `<tsx>...</tsx>`, wrap TSRX templates with `<tsrx>...</tsrx>`, or use elements as statements within a component.';
|
|
22
22
|
|
|
23
|
+
const CharCode = Object.freeze({
|
|
24
|
+
tab: 9,
|
|
25
|
+
lineFeed: 10,
|
|
26
|
+
carriageReturn: 13,
|
|
27
|
+
space: 32,
|
|
28
|
+
doubleQuote: 34,
|
|
29
|
+
dollar: 36,
|
|
30
|
+
ampersand: 38,
|
|
31
|
+
singleQuote: 39,
|
|
32
|
+
openParen: 40,
|
|
33
|
+
closeParen: 41,
|
|
34
|
+
asterisk: 42,
|
|
35
|
+
slash: 47,
|
|
36
|
+
colon: 58,
|
|
37
|
+
semicolon: 59,
|
|
38
|
+
lessThan: 60,
|
|
39
|
+
equals: 61,
|
|
40
|
+
greaterThan: 62,
|
|
41
|
+
at: 64,
|
|
42
|
+
digit0: 48,
|
|
43
|
+
digit9: 57,
|
|
44
|
+
uppercaseA: 65,
|
|
45
|
+
uppercaseZ: 90,
|
|
46
|
+
openBracket: 91,
|
|
47
|
+
backslash: 92,
|
|
48
|
+
underscore: 95,
|
|
49
|
+
backtick: 96,
|
|
50
|
+
lowercaseA: 97,
|
|
51
|
+
lowercaseZ: 122,
|
|
52
|
+
openBrace: 123,
|
|
53
|
+
closeBrace: 125,
|
|
54
|
+
});
|
|
55
|
+
|
|
23
56
|
/** @type {WeakMap<Record<string, boolean>, Map<string, number>>} */
|
|
24
57
|
const argument_clash_first_positions = new WeakMap();
|
|
25
58
|
/** @type {WeakMap<Record<string, boolean>, Set<string>>} */
|
|
@@ -58,7 +91,13 @@ function get_argument_clash_reported_names(check_clashes) {
|
|
|
58
91
|
function skip_whitespace_from(input, i) {
|
|
59
92
|
while (i < input.length) {
|
|
60
93
|
const ch = input.charCodeAt(i);
|
|
61
|
-
if (
|
|
94
|
+
if (
|
|
95
|
+
ch !== CharCode.space &&
|
|
96
|
+
ch !== CharCode.tab &&
|
|
97
|
+
ch !== CharCode.lineFeed &&
|
|
98
|
+
ch !== CharCode.carriageReturn
|
|
99
|
+
)
|
|
100
|
+
break;
|
|
62
101
|
i++;
|
|
63
102
|
}
|
|
64
103
|
return i;
|
|
@@ -75,7 +114,7 @@ function skip_string_from(input, i, quote) {
|
|
|
75
114
|
while (i < input.length) {
|
|
76
115
|
const ch = input.charCodeAt(i);
|
|
77
116
|
i++;
|
|
78
|
-
if (ch ===
|
|
117
|
+
if (ch === CharCode.backslash)
|
|
79
118
|
i++; // backslash escape
|
|
80
119
|
else if (ch === quote) return i;
|
|
81
120
|
}
|
|
@@ -95,7 +134,7 @@ function scan_balanced_from(input, i, open, close) {
|
|
|
95
134
|
i++;
|
|
96
135
|
while (i < input.length) {
|
|
97
136
|
const ch = input.charCodeAt(i);
|
|
98
|
-
if (ch ===
|
|
137
|
+
if (ch === CharCode.doubleQuote || ch === CharCode.singleQuote || ch === CharCode.backtick) {
|
|
99
138
|
i = skip_string_from(input, i, ch);
|
|
100
139
|
continue;
|
|
101
140
|
}
|
|
@@ -114,47 +153,50 @@ function scan_balanced_from(input, i, open, close) {
|
|
|
114
153
|
* @param {number} pos
|
|
115
154
|
*/
|
|
116
155
|
function looks_like_generic_arrow(input, pos) {
|
|
117
|
-
if (input.charCodeAt(pos) !==
|
|
156
|
+
if (input.charCodeAt(pos) !== CharCode.lessThan) return false;
|
|
118
157
|
|
|
119
158
|
// Match the angle brackets, skipping over string literals.
|
|
120
159
|
let i = pos + 1;
|
|
121
160
|
let depth = 1;
|
|
122
161
|
while (i < input.length) {
|
|
123
162
|
const ch = input.charCodeAt(i);
|
|
124
|
-
if (ch ===
|
|
163
|
+
if (ch === CharCode.doubleQuote || ch === CharCode.singleQuote || ch === CharCode.backtick) {
|
|
125
164
|
i = skip_string_from(input, i, ch);
|
|
126
165
|
continue;
|
|
127
166
|
}
|
|
128
|
-
if (ch ===
|
|
129
|
-
else if (ch ===
|
|
167
|
+
if (ch === CharCode.lessThan) depth++;
|
|
168
|
+
else if (ch === CharCode.greaterThan && --depth === 0) break;
|
|
130
169
|
i++;
|
|
131
170
|
}
|
|
132
171
|
if (depth !== 0) return false;
|
|
133
172
|
|
|
134
173
|
// `>` must be followed by `(...)`.
|
|
135
174
|
i = skip_whitespace_from(input, i + 1);
|
|
136
|
-
if (input.charCodeAt(i) !==
|
|
137
|
-
i = scan_balanced_from(input, i,
|
|
175
|
+
if (input.charCodeAt(i) !== CharCode.openParen) return false;
|
|
176
|
+
i = scan_balanced_from(input, i, CharCode.openParen, CharCode.closeParen);
|
|
138
177
|
if (i === -1) return false;
|
|
139
178
|
|
|
140
179
|
// Optional `: ReturnType` before `=>`.
|
|
141
180
|
i = skip_whitespace_from(input, i);
|
|
142
|
-
if (input.charCodeAt(i) ===
|
|
181
|
+
if (input.charCodeAt(i) === CharCode.colon) {
|
|
143
182
|
i++;
|
|
144
183
|
while (i < input.length) {
|
|
145
184
|
const ch = input.charCodeAt(i);
|
|
146
|
-
if (ch ===
|
|
185
|
+
if (ch === CharCode.doubleQuote || ch === CharCode.singleQuote || ch === CharCode.backtick) {
|
|
147
186
|
i = skip_string_from(input, i, ch);
|
|
148
187
|
continue;
|
|
149
188
|
}
|
|
150
|
-
if (ch ===
|
|
151
|
-
if (ch ===
|
|
189
|
+
if (ch === CharCode.equals && input.charCodeAt(i + 1) === CharCode.greaterThan) return true;
|
|
190
|
+
if (ch === CharCode.semicolon || ch === CharCode.openBrace || ch === CharCode.closeBrace)
|
|
191
|
+
return false;
|
|
152
192
|
i++;
|
|
153
193
|
}
|
|
154
194
|
return false;
|
|
155
195
|
}
|
|
156
196
|
|
|
157
|
-
return
|
|
197
|
+
return (
|
|
198
|
+
input.charCodeAt(i) === CharCode.equals && input.charCodeAt(i + 1) === CharCode.greaterThan
|
|
199
|
+
);
|
|
158
200
|
}
|
|
159
201
|
|
|
160
202
|
/**
|
|
@@ -176,7 +218,13 @@ function previous_word_before(input, pos) {
|
|
|
176
218
|
let i = pos - 1;
|
|
177
219
|
while (i >= 0) {
|
|
178
220
|
const ch = input.charCodeAt(i);
|
|
179
|
-
if (
|
|
221
|
+
if (
|
|
222
|
+
ch !== CharCode.space &&
|
|
223
|
+
ch !== CharCode.tab &&
|
|
224
|
+
ch !== CharCode.lineFeed &&
|
|
225
|
+
ch !== CharCode.carriageReturn
|
|
226
|
+
)
|
|
227
|
+
break;
|
|
180
228
|
i--;
|
|
181
229
|
}
|
|
182
230
|
const end = i + 1;
|
|
@@ -266,7 +314,12 @@ export function TSRXPlugin(config) {
|
|
|
266
314
|
let index = this.pos - 1;
|
|
267
315
|
while (index >= 0) {
|
|
268
316
|
const ch = this.input.charCodeAt(index);
|
|
269
|
-
if (
|
|
317
|
+
if (
|
|
318
|
+
ch !== CharCode.space &&
|
|
319
|
+
ch !== CharCode.tab &&
|
|
320
|
+
ch !== CharCode.lineFeed &&
|
|
321
|
+
ch !== CharCode.carriageReturn
|
|
322
|
+
) {
|
|
270
323
|
return ch;
|
|
271
324
|
}
|
|
272
325
|
index--;
|
|
@@ -454,7 +507,7 @@ export function TSRXPlugin(config) {
|
|
|
454
507
|
}
|
|
455
508
|
|
|
456
509
|
const after = this.input.charCodeAt(this.pos + 4);
|
|
457
|
-
return after ===
|
|
510
|
+
return after === CharCode.greaterThan;
|
|
458
511
|
}
|
|
459
512
|
|
|
460
513
|
#parseTsxIslandText() {
|
|
@@ -466,7 +519,7 @@ export function TSRXPlugin(config) {
|
|
|
466
519
|
const ch = this.input.charCodeAt(this.pos);
|
|
467
520
|
|
|
468
521
|
// Stop at opening tag, expression, or the component-closing brace
|
|
469
|
-
if (ch ===
|
|
522
|
+
if (ch === CharCode.lessThan || ch === CharCode.openBrace || ch === CharCode.closeBrace) {
|
|
470
523
|
break;
|
|
471
524
|
}
|
|
472
525
|
|
|
@@ -496,24 +549,27 @@ export function TSRXPlugin(config) {
|
|
|
496
549
|
// fragment props like `content={<></>}` still need the JSX context.
|
|
497
550
|
while (index < this.input.length) {
|
|
498
551
|
const ch = this.input.charCodeAt(index);
|
|
499
|
-
if (ch ===
|
|
552
|
+
if (ch === CharCode.space || ch === CharCode.tab) {
|
|
500
553
|
index++;
|
|
501
|
-
} else if (ch ===
|
|
554
|
+
} else if (ch === CharCode.lineFeed || ch === CharCode.carriageReturn) {
|
|
502
555
|
has_newline = true;
|
|
503
556
|
index++;
|
|
504
|
-
} else if (
|
|
557
|
+
} else if (
|
|
558
|
+
ch === CharCode.slash &&
|
|
559
|
+
this.input.charCodeAt(index + 1) === CharCode.asterisk
|
|
560
|
+
) {
|
|
505
561
|
const end = this.input.indexOf('*/', index + 2);
|
|
506
562
|
const comment_end = end === -1 ? this.input.length : end + 2;
|
|
507
563
|
if (this.input.slice(index, comment_end).match(regex_newline_characters)) {
|
|
508
564
|
has_newline = true;
|
|
509
565
|
}
|
|
510
566
|
index = comment_end;
|
|
511
|
-
} else if (ch ===
|
|
567
|
+
} else if (ch === CharCode.slash && this.input.charCodeAt(index + 1) === CharCode.slash) {
|
|
512
568
|
has_newline = true;
|
|
513
569
|
index += 2;
|
|
514
570
|
while (index < this.input.length) {
|
|
515
571
|
const comment_ch = this.input.charCodeAt(index);
|
|
516
|
-
if (comment_ch ===
|
|
572
|
+
if (comment_ch === CharCode.lineFeed || comment_ch === CharCode.carriageReturn) break;
|
|
517
573
|
index++;
|
|
518
574
|
}
|
|
519
575
|
} else {
|
|
@@ -521,7 +577,7 @@ export function TSRXPlugin(config) {
|
|
|
521
577
|
}
|
|
522
578
|
}
|
|
523
579
|
|
|
524
|
-
if (!has_newline || this.input.charCodeAt(index) !==
|
|
580
|
+
if (!has_newline || this.input.charCodeAt(index) !== CharCode.openBrace) {
|
|
525
581
|
return;
|
|
526
582
|
}
|
|
527
583
|
|
|
@@ -544,16 +600,24 @@ export function TSRXPlugin(config) {
|
|
|
544
600
|
#skipWhitespaceAndComments(index) {
|
|
545
601
|
while (index < this.input.length) {
|
|
546
602
|
const ch = this.input.charCodeAt(index);
|
|
547
|
-
if (
|
|
603
|
+
if (
|
|
604
|
+
ch === CharCode.space ||
|
|
605
|
+
ch === CharCode.tab ||
|
|
606
|
+
ch === CharCode.lineFeed ||
|
|
607
|
+
ch === CharCode.carriageReturn
|
|
608
|
+
) {
|
|
548
609
|
index++;
|
|
549
|
-
} else if (
|
|
610
|
+
} else if (
|
|
611
|
+
ch === CharCode.slash &&
|
|
612
|
+
this.input.charCodeAt(index + 1) === CharCode.asterisk
|
|
613
|
+
) {
|
|
550
614
|
const end = this.input.indexOf('*/', index + 2);
|
|
551
615
|
index = end === -1 ? this.input.length : end + 2;
|
|
552
|
-
} else if (ch ===
|
|
616
|
+
} else if (ch === CharCode.slash && this.input.charCodeAt(index + 1) === CharCode.slash) {
|
|
553
617
|
index += 2;
|
|
554
618
|
while (index < this.input.length) {
|
|
555
619
|
const comment_ch = this.input.charCodeAt(index);
|
|
556
|
-
if (comment_ch ===
|
|
620
|
+
if (comment_ch === CharCode.lineFeed || comment_ch === CharCode.carriageReturn) break;
|
|
557
621
|
index++;
|
|
558
622
|
}
|
|
559
623
|
} else {
|
|
@@ -569,7 +633,7 @@ export function TSRXPlugin(config) {
|
|
|
569
633
|
let count = 0;
|
|
570
634
|
while (index < this.input.length) {
|
|
571
635
|
index = this.#skipWhitespaceAndComments(index);
|
|
572
|
-
if (this.input.charCodeAt(index) !==
|
|
636
|
+
if (this.input.charCodeAt(index) !== CharCode.closeBrace) break;
|
|
573
637
|
count++;
|
|
574
638
|
index++;
|
|
575
639
|
}
|
|
@@ -701,11 +765,11 @@ export function TSRXPlugin(config) {
|
|
|
701
765
|
const prev = this.#previousNonWhitespaceChar();
|
|
702
766
|
return (
|
|
703
767
|
prev === null ||
|
|
704
|
-
prev ===
|
|
705
|
-
prev ===
|
|
706
|
-
prev ===
|
|
707
|
-
(prev ===
|
|
708
|
-
prev ===
|
|
768
|
+
prev === CharCode.doubleQuote ||
|
|
769
|
+
prev === CharCode.semicolon ||
|
|
770
|
+
prev === CharCode.greaterThan ||
|
|
771
|
+
(prev === CharCode.openBrace && this.#allowDoubleQuotedTextChildAfterBrace) ||
|
|
772
|
+
prev === CharCode.closeBrace
|
|
709
773
|
);
|
|
710
774
|
}
|
|
711
775
|
|
|
@@ -718,13 +782,13 @@ export function TSRXPlugin(config) {
|
|
|
718
782
|
while (this.pos < this.input.length) {
|
|
719
783
|
const ch = this.input.charCodeAt(this.pos);
|
|
720
784
|
|
|
721
|
-
if (ch ===
|
|
785
|
+
if (ch === CharCode.doubleQuote) {
|
|
722
786
|
out += this.input.slice(chunkStart, this.pos);
|
|
723
787
|
this.pos++;
|
|
724
788
|
return this.finishToken(tt.string, out);
|
|
725
789
|
}
|
|
726
790
|
|
|
727
|
-
if (ch ===
|
|
791
|
+
if (ch === CharCode.ampersand) {
|
|
728
792
|
out += this.input.slice(chunkStart, this.pos);
|
|
729
793
|
out += this.jsx_readEntity();
|
|
730
794
|
chunkStart = this.pos;
|
|
@@ -1050,7 +1114,7 @@ export function TSRXPlugin(config) {
|
|
|
1050
1114
|
* @type {Parse.Parser['readToken']}
|
|
1051
1115
|
*/
|
|
1052
1116
|
readToken(code) {
|
|
1053
|
-
if (code ===
|
|
1117
|
+
if (code === CharCode.lessThan && looks_like_generic_arrow(this.input, this.pos)) {
|
|
1054
1118
|
++this.pos;
|
|
1055
1119
|
return this.finishToken(tt.relational, '<');
|
|
1056
1120
|
}
|
|
@@ -1062,7 +1126,19 @@ export function TSRXPlugin(config) {
|
|
|
1062
1126
|
* @type {Parse.Parser['getTokenFromCode']}
|
|
1063
1127
|
*/
|
|
1064
1128
|
getTokenFromCode(code) {
|
|
1065
|
-
|
|
1129
|
+
// Callback props that return `<tsrx>...</tsrx>` without a semicolon can
|
|
1130
|
+
// leave the attribute expression context above the still-open tag. Drop
|
|
1131
|
+
// it before tokenizing `/>`, otherwise Acorn treats `/` as a regexp.
|
|
1132
|
+
if (
|
|
1133
|
+
code === CharCode.slash &&
|
|
1134
|
+
this.input.charCodeAt(this.pos + 1) === CharCode.greaterThan &&
|
|
1135
|
+
this.curContext() === b_expr &&
|
|
1136
|
+
this.context[this.context.length - 2] === tstc.tc_oTag
|
|
1137
|
+
) {
|
|
1138
|
+
this.context.pop();
|
|
1139
|
+
this.exprAllowed = false;
|
|
1140
|
+
}
|
|
1141
|
+
if (code === CharCode.doubleQuote) {
|
|
1066
1142
|
const is_double_quoted_text_child = this.#isDoubleQuotedTextChildStart();
|
|
1067
1143
|
this.#allowDoubleQuotedTextChildAfterBrace = false;
|
|
1068
1144
|
if (is_double_quoted_text_child) {
|
|
@@ -1072,11 +1148,11 @@ export function TSRXPlugin(config) {
|
|
|
1072
1148
|
this.#allowDoubleQuotedTextChildAfterBrace = false;
|
|
1073
1149
|
}
|
|
1074
1150
|
|
|
1075
|
-
if (code !==
|
|
1151
|
+
if (code !== CharCode.lessThan) {
|
|
1076
1152
|
this.#allowTagStartAfterDoubleQuotedText = false;
|
|
1077
1153
|
}
|
|
1078
1154
|
|
|
1079
|
-
if (code ===
|
|
1155
|
+
if (code === CharCode.lessThan) {
|
|
1080
1156
|
// < character
|
|
1081
1157
|
const inComponent = this.#isInsideComponentTemplate();
|
|
1082
1158
|
/** @type {number | null} */
|
|
@@ -1093,7 +1169,7 @@ export function TSRXPlugin(config) {
|
|
|
1093
1169
|
// Skip whitespace backwards
|
|
1094
1170
|
while (lookback >= 0) {
|
|
1095
1171
|
const ch = this.input.charCodeAt(lookback);
|
|
1096
|
-
if (ch !==
|
|
1172
|
+
if (ch !== CharCode.space && ch !== CharCode.tab) break; // not space or tab
|
|
1097
1173
|
lookback--;
|
|
1098
1174
|
}
|
|
1099
1175
|
|
|
@@ -1105,12 +1181,12 @@ export function TSRXPlugin(config) {
|
|
|
1105
1181
|
// If preceded by identifier character (letter, digit, _, $) or closing paren,
|
|
1106
1182
|
// this is likely TypeScript generics, not JSX
|
|
1107
1183
|
const isIdentifierChar =
|
|
1108
|
-
(prevChar >=
|
|
1109
|
-
(prevChar >=
|
|
1110
|
-
(prevChar >=
|
|
1111
|
-
prevChar ===
|
|
1112
|
-
prevChar ===
|
|
1113
|
-
prevChar ===
|
|
1184
|
+
(prevChar >= CharCode.uppercaseA && prevChar <= CharCode.uppercaseZ) ||
|
|
1185
|
+
(prevChar >= CharCode.lowercaseA && prevChar <= CharCode.lowercaseZ) ||
|
|
1186
|
+
(prevChar >= CharCode.digit0 && prevChar <= CharCode.digit9) ||
|
|
1187
|
+
prevChar === CharCode.underscore ||
|
|
1188
|
+
prevChar === CharCode.dollar ||
|
|
1189
|
+
prevChar === CharCode.closeParen;
|
|
1114
1190
|
|
|
1115
1191
|
if (isIdentifierChar) {
|
|
1116
1192
|
return super.getTokenFromCode(code);
|
|
@@ -1125,23 +1201,26 @@ export function TSRXPlugin(config) {
|
|
|
1125
1201
|
const nextChar =
|
|
1126
1202
|
this.pos + 1 < this.input.length ? this.input.charCodeAt(this.pos + 1) : -1;
|
|
1127
1203
|
const isWhitespaceAfterLt =
|
|
1128
|
-
nextChar ===
|
|
1204
|
+
nextChar === CharCode.space ||
|
|
1205
|
+
nextChar === CharCode.tab ||
|
|
1206
|
+
nextChar === CharCode.lineFeed ||
|
|
1207
|
+
nextChar === CharCode.carriageReturn;
|
|
1129
1208
|
const isTagLikeAfterLt =
|
|
1130
1209
|
!isWhitespaceAfterLt &&
|
|
1131
|
-
(nextChar ===
|
|
1132
|
-
nextChar ===
|
|
1133
|
-
nextChar ===
|
|
1134
|
-
nextChar ===
|
|
1135
|
-
nextChar ===
|
|
1136
|
-
(nextChar >=
|
|
1137
|
-
(nextChar >=
|
|
1210
|
+
(nextChar === CharCode.slash ||
|
|
1211
|
+
nextChar === CharCode.greaterThan ||
|
|
1212
|
+
nextChar === CharCode.at ||
|
|
1213
|
+
nextChar === CharCode.dollar ||
|
|
1214
|
+
nextChar === CharCode.underscore ||
|
|
1215
|
+
(nextChar >= CharCode.uppercaseA && nextChar <= CharCode.uppercaseZ) ||
|
|
1216
|
+
(nextChar >= CharCode.lowercaseA && nextChar <= CharCode.lowercaseZ));
|
|
1138
1217
|
const prevAllowsTagStart =
|
|
1139
1218
|
prevNonWhitespaceChar === null ||
|
|
1140
|
-
prevNonWhitespaceChar ===
|
|
1141
|
-
prevNonWhitespaceChar ===
|
|
1142
|
-
prevNonWhitespaceChar ===
|
|
1143
|
-
prevNonWhitespaceChar ===
|
|
1144
|
-
prevNonWhitespaceChar ===
|
|
1219
|
+
prevNonWhitespaceChar === CharCode.lineFeed || // '\n'
|
|
1220
|
+
prevNonWhitespaceChar === CharCode.carriageReturn || // '\r'
|
|
1221
|
+
prevNonWhitespaceChar === CharCode.openBrace ||
|
|
1222
|
+
prevNonWhitespaceChar === CharCode.closeBrace ||
|
|
1223
|
+
prevNonWhitespaceChar === CharCode.greaterThan;
|
|
1145
1224
|
|
|
1146
1225
|
if (!inComponent && prevAllowsTagStart && isTagLikeAfterLt) {
|
|
1147
1226
|
++this.pos;
|
|
@@ -1153,10 +1232,10 @@ export function TSRXPlugin(config) {
|
|
|
1153
1232
|
// a newline/indentation before the next '<'. This is important for inputs
|
|
1154
1233
|
// like `<div />` and `</div><style>...</style>` which Prettier formats.
|
|
1155
1234
|
if (
|
|
1156
|
-
(prevNonWhitespaceChar ===
|
|
1235
|
+
(prevNonWhitespaceChar === CharCode.doubleQuote &&
|
|
1157
1236
|
this.#allowTagStartAfterDoubleQuotedText) ||
|
|
1158
|
-
prevNonWhitespaceChar ===
|
|
1159
|
-
prevNonWhitespaceChar ===
|
|
1237
|
+
prevNonWhitespaceChar === CharCode.openBrace ||
|
|
1238
|
+
prevNonWhitespaceChar === CharCode.greaterThan
|
|
1160
1239
|
) {
|
|
1161
1240
|
if (!isWhitespaceAfterLt) {
|
|
1162
1241
|
this.#allowTagStartAfterDoubleQuotedText = false;
|
|
@@ -1172,8 +1251,8 @@ export function TSRXPlugin(config) {
|
|
|
1172
1251
|
let lineStart = this.pos - 1;
|
|
1173
1252
|
while (
|
|
1174
1253
|
lineStart >= 0 &&
|
|
1175
|
-
this.input.charCodeAt(lineStart) !==
|
|
1176
|
-
this.input.charCodeAt(lineStart) !==
|
|
1254
|
+
this.input.charCodeAt(lineStart) !== CharCode.lineFeed &&
|
|
1255
|
+
this.input.charCodeAt(lineStart) !== CharCode.carriageReturn
|
|
1177
1256
|
) {
|
|
1178
1257
|
lineStart--;
|
|
1179
1258
|
}
|
|
@@ -1183,7 +1262,7 @@ export function TSRXPlugin(config) {
|
|
|
1183
1262
|
let allWhitespace = true;
|
|
1184
1263
|
for (let i = lineStart; i < this.pos; i++) {
|
|
1185
1264
|
const ch = this.input.charCodeAt(i);
|
|
1186
|
-
if (ch !==
|
|
1265
|
+
if (ch !== CharCode.space && ch !== CharCode.tab) {
|
|
1187
1266
|
allWhitespace = false;
|
|
1188
1267
|
break;
|
|
1189
1268
|
}
|
|
@@ -1205,7 +1284,7 @@ export function TSRXPlugin(config) {
|
|
|
1205
1284
|
/**
|
|
1206
1285
|
* Override isLet to recognize `let &{` and `let &[` as variable declarations.
|
|
1207
1286
|
* Acorn's isLet checks the char after `let` and only recognizes `{`, `[`, or identifiers.
|
|
1208
|
-
* The `&`
|
|
1287
|
+
* The `&` character is not in that set, so `let &{...}` would not be parsed as a declaration.
|
|
1209
1288
|
* @type {Parse.Parser['isLet']}
|
|
1210
1289
|
*/
|
|
1211
1290
|
isLet(context) {
|
|
@@ -1217,9 +1296,9 @@ export function TSRXPlugin(config) {
|
|
|
1217
1296
|
const next = this.pos + match[0].length;
|
|
1218
1297
|
const nextCh = this.input.charCodeAt(next);
|
|
1219
1298
|
// If next char is &, check if char after & is { or [
|
|
1220
|
-
if (nextCh ===
|
|
1299
|
+
if (nextCh === CharCode.ampersand) {
|
|
1221
1300
|
const afterAmp = this.input.charCodeAt(next + 1);
|
|
1222
|
-
if (afterAmp ===
|
|
1301
|
+
if (afterAmp === CharCode.openBrace || afterAmp === CharCode.openBracket) return true;
|
|
1223
1302
|
}
|
|
1224
1303
|
return super.isLet(context);
|
|
1225
1304
|
}
|
|
@@ -1233,7 +1312,7 @@ export function TSRXPlugin(config) {
|
|
|
1233
1312
|
if (this.type === tt.bitwiseAND) {
|
|
1234
1313
|
// Check that the char immediately after & is { or [ (no whitespace)
|
|
1235
1314
|
const charAfterAmp = this.input.charCodeAt(this.end);
|
|
1236
|
-
if (charAfterAmp ===
|
|
1315
|
+
if (charAfterAmp === CharCode.openBrace || charAfterAmp === CharCode.openBracket) {
|
|
1237
1316
|
// & directly followed by { or [ — lazy destructuring
|
|
1238
1317
|
this.next(); // consume &, now current token is { or [
|
|
1239
1318
|
const pattern = super.parseBindingAtom();
|
|
@@ -2121,20 +2200,20 @@ export function TSRXPlugin(config) {
|
|
|
2121
2200
|
let ch = this.input.charCodeAt(this.pos);
|
|
2122
2201
|
|
|
2123
2202
|
switch (ch) {
|
|
2124
|
-
case
|
|
2125
|
-
case
|
|
2203
|
+
case CharCode.lessThan:
|
|
2204
|
+
case CharCode.openBrace:
|
|
2126
2205
|
// In JSX text mode, '<' and '{' always start a tag/expression container.
|
|
2127
2206
|
// `exprAllowed` can be false here due to surrounding parser state, but
|
|
2128
2207
|
// throwing breaks valid templates (e.g. sibling tags after a close).
|
|
2129
|
-
if (ch ===
|
|
2208
|
+
if (ch === CharCode.lessThan) {
|
|
2130
2209
|
++this.pos;
|
|
2131
2210
|
return this.finishToken(tstt.jsxTagStart);
|
|
2132
2211
|
}
|
|
2133
2212
|
return this.getTokenFromCode(ch);
|
|
2134
2213
|
|
|
2135
|
-
case
|
|
2214
|
+
case CharCode.slash:
|
|
2136
2215
|
// Check if this is a comment (// or /*)
|
|
2137
|
-
if (this.input.charCodeAt(this.pos + 1) ===
|
|
2216
|
+
if (this.input.charCodeAt(this.pos + 1) === CharCode.slash) {
|
|
2138
2217
|
// '//'
|
|
2139
2218
|
// Line comment - handle it properly
|
|
2140
2219
|
const commentStart = this.pos;
|
|
@@ -2168,7 +2247,7 @@ export function TSRXPlugin(config) {
|
|
|
2168
2247
|
|
|
2169
2248
|
// Continue processing from current position
|
|
2170
2249
|
break;
|
|
2171
|
-
} else if (this.input.charCodeAt(this.pos + 1) ===
|
|
2250
|
+
} else if (this.input.charCodeAt(this.pos + 1) === CharCode.asterisk) {
|
|
2172
2251
|
// '/*'
|
|
2173
2252
|
// Block comment - handle it properly
|
|
2174
2253
|
const commentStart = this.pos;
|
|
@@ -2178,8 +2257,8 @@ export function TSRXPlugin(config) {
|
|
|
2178
2257
|
let commentText = '';
|
|
2179
2258
|
while (this.pos < this.input.length - 1) {
|
|
2180
2259
|
if (
|
|
2181
|
-
this.input.charCodeAt(this.pos) ===
|
|
2182
|
-
this.input.charCodeAt(this.pos + 1) ===
|
|
2260
|
+
this.input.charCodeAt(this.pos) === CharCode.asterisk &&
|
|
2261
|
+
this.input.charCodeAt(this.pos + 1) === CharCode.slash
|
|
2183
2262
|
) {
|
|
2184
2263
|
this.pos += 2;
|
|
2185
2264
|
break;
|
|
@@ -2214,17 +2293,16 @@ export function TSRXPlugin(config) {
|
|
|
2214
2293
|
this.exprAllowed = true;
|
|
2215
2294
|
return original.readToken.call(this, ch);
|
|
2216
2295
|
|
|
2217
|
-
case
|
|
2296
|
+
case CharCode.ampersand:
|
|
2218
2297
|
out += this.input.slice(chunkStart, this.pos);
|
|
2219
2298
|
out += this.jsx_readEntity();
|
|
2220
2299
|
chunkStart = this.pos;
|
|
2221
2300
|
break;
|
|
2222
2301
|
|
|
2223
|
-
case
|
|
2224
|
-
case
|
|
2225
|
-
// '}'
|
|
2302
|
+
case CharCode.greaterThan:
|
|
2303
|
+
case CharCode.closeBrace: {
|
|
2226
2304
|
if (
|
|
2227
|
-
ch ===
|
|
2305
|
+
ch === CharCode.closeBrace &&
|
|
2228
2306
|
(this.#path.length === 0 ||
|
|
2229
2307
|
this.#path.at(-1)?.type === 'Component' ||
|
|
2230
2308
|
this.#path.at(-1)?.type === 'Element' ||
|
|
@@ -2238,7 +2316,7 @@ export function TSRXPlugin(config) {
|
|
|
2238
2316
|
'Unexpected token `' +
|
|
2239
2317
|
this.input[this.pos] +
|
|
2240
2318
|
'`. Did you mean `' +
|
|
2241
|
-
(ch ===
|
|
2319
|
+
(ch === CharCode.greaterThan ? '>' : '}') +
|
|
2242
2320
|
'` or ' +
|
|
2243
2321
|
'`{"' +
|
|
2244
2322
|
this.input[this.pos] +
|
|
@@ -2252,7 +2330,7 @@ export function TSRXPlugin(config) {
|
|
|
2252
2330
|
out += this.input.slice(chunkStart, this.pos);
|
|
2253
2331
|
out += this.jsx_readNewLine(true);
|
|
2254
2332
|
chunkStart = this.pos;
|
|
2255
|
-
} else if (ch ===
|
|
2333
|
+
} else if (ch === CharCode.space || ch === CharCode.tab) {
|
|
2256
2334
|
++this.pos;
|
|
2257
2335
|
} else {
|
|
2258
2336
|
this.#resetTokenStartToCurrentPosition();
|
|
@@ -2283,28 +2361,28 @@ export function TSRXPlugin(config) {
|
|
|
2283
2361
|
// Check if the element being parsed IS a <tsx>, <tsrx>, or <tsx:*> tag
|
|
2284
2362
|
// Current token is jsxTagStart, this.end is position after '<'
|
|
2285
2363
|
const tag_name_start = this.end;
|
|
2286
|
-
const is_fragment_tag = this.input.charCodeAt(tag_name_start) ===
|
|
2364
|
+
const is_fragment_tag = this.input.charCodeAt(tag_name_start) === CharCode.greaterThan;
|
|
2287
2365
|
const char_after_tsx = this.input.charCodeAt(tag_name_start + 3);
|
|
2288
2366
|
const char_after_tsrx = this.input.charCodeAt(tag_name_start + 4);
|
|
2289
2367
|
const is_tsx_tag =
|
|
2290
2368
|
this.input.startsWith('tsx', tag_name_start) &&
|
|
2291
2369
|
(tag_name_start + 3 >= this.input.length ||
|
|
2292
|
-
char_after_tsx ===
|
|
2293
|
-
char_after_tsx ===
|
|
2294
|
-
char_after_tsx ===
|
|
2295
|
-
char_after_tsx ===
|
|
2296
|
-
char_after_tsx ===
|
|
2297
|
-
char_after_tsx ===
|
|
2298
|
-
char_after_tsx ===
|
|
2370
|
+
char_after_tsx === CharCode.greaterThan ||
|
|
2371
|
+
char_after_tsx === CharCode.slash ||
|
|
2372
|
+
char_after_tsx === CharCode.space ||
|
|
2373
|
+
char_after_tsx === CharCode.tab ||
|
|
2374
|
+
char_after_tsx === CharCode.lineFeed ||
|
|
2375
|
+
char_after_tsx === CharCode.carriageReturn ||
|
|
2376
|
+
char_after_tsx === CharCode.colon);
|
|
2299
2377
|
const is_tsrx_tag =
|
|
2300
2378
|
this.input.startsWith('tsrx', tag_name_start) &&
|
|
2301
2379
|
(tag_name_start + 4 >= this.input.length ||
|
|
2302
|
-
char_after_tsrx ===
|
|
2303
|
-
char_after_tsrx ===
|
|
2304
|
-
char_after_tsrx ===
|
|
2305
|
-
char_after_tsrx ===
|
|
2306
|
-
char_after_tsrx ===
|
|
2307
|
-
char_after_tsrx ===
|
|
2380
|
+
char_after_tsrx === CharCode.greaterThan ||
|
|
2381
|
+
char_after_tsrx === CharCode.slash ||
|
|
2382
|
+
char_after_tsrx === CharCode.space ||
|
|
2383
|
+
char_after_tsrx === CharCode.tab ||
|
|
2384
|
+
char_after_tsrx === CharCode.lineFeed ||
|
|
2385
|
+
char_after_tsrx === CharCode.carriageReturn);
|
|
2308
2386
|
|
|
2309
2387
|
if (is_fragment_tag || is_tsx_tag || is_tsrx_tag) {
|
|
2310
2388
|
// Use Ripple's parseElement to create a Tsx/Tsrx/TsxCompat node.
|
|
@@ -2787,7 +2865,10 @@ export function TSRXPlugin(config) {
|
|
|
2787
2865
|
}
|
|
2788
2866
|
if (this.type === tt.braceL) {
|
|
2789
2867
|
body.push(this.#parseNativeTemplateExpressionContainer());
|
|
2790
|
-
} else if (
|
|
2868
|
+
} else if (
|
|
2869
|
+
this.type === tt.string &&
|
|
2870
|
+
this.input.charCodeAt(this.start) === CharCode.doubleQuote
|
|
2871
|
+
) {
|
|
2791
2872
|
body.push(this.parseDoubleQuotedTextChild());
|
|
2792
2873
|
} else if (this.type === tt.braceR) {
|
|
2793
2874
|
// Leaving a component/template body. We may still be in TSX/JSX tokenization
|
|
@@ -2800,8 +2881,8 @@ export function TSRXPlugin(config) {
|
|
|
2800
2881
|
return;
|
|
2801
2882
|
} else if (
|
|
2802
2883
|
this.type === tstt.jsxTagStart ||
|
|
2803
|
-
(this.input.charCodeAt(this.start) ===
|
|
2804
|
-
this.input.charCodeAt(this.start + 1) ===
|
|
2884
|
+
(this.input.charCodeAt(this.start) === CharCode.lessThan &&
|
|
2885
|
+
this.input.charCodeAt(this.start + 1) === CharCode.slash)
|
|
2805
2886
|
) {
|
|
2806
2887
|
const startPos = this.start;
|
|
2807
2888
|
const startLoc = this.startLoc;
|
|
@@ -3082,7 +3163,7 @@ export function TSRXPlugin(config) {
|
|
|
3082
3163
|
if (
|
|
3083
3164
|
this.#functionBodyDepth === 0 &&
|
|
3084
3165
|
this.type === tt.string &&
|
|
3085
|
-
this.input.charCodeAt(this.start) ===
|
|
3166
|
+
this.input.charCodeAt(this.start) === CharCode.doubleQuote &&
|
|
3086
3167
|
(this.#path.at(-1)?.type === 'Component' || this.#path.at(-1)?.type === 'Element')
|
|
3087
3168
|
) {
|
|
3088
3169
|
this.pos = this.start;
|
|
@@ -3096,7 +3177,7 @@ export function TSRXPlugin(config) {
|
|
|
3096
3177
|
// e.g., &[data] = track(0); or &{x, y} = obj;
|
|
3097
3178
|
if (this.type === tt.bitwiseAND) {
|
|
3098
3179
|
const charAfterAmp = this.input.charCodeAt(this.end);
|
|
3099
|
-
if (charAfterAmp ===
|
|
3180
|
+
if (charAfterAmp === CharCode.openBrace || charAfterAmp === CharCode.openBracket) {
|
|
3100
3181
|
const node = /** @type {AST.ExpressionStatement} */ (this.startNode());
|
|
3101
3182
|
const assign_node = /** @type {AST.AssignmentExpression} */ (this.startNode());
|
|
3102
3183
|
this.next(); // consume &
|