@reckona/mreact-compiler 0.0.66 → 0.0.67
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 +4 -3
- package/src/compiler-module-context.ts +31 -0
- package/src/diagnostics.ts +184 -0
- package/src/emit-client.ts +837 -0
- package/src/emit-compat.ts +567 -0
- package/src/emit-escape-helper.ts +45 -0
- package/src/emit-server-shared.ts +384 -0
- package/src/emit-server-stream.ts +2558 -0
- package/src/emit-server.ts +1827 -0
- package/src/index.ts +44 -0
- package/src/internal.ts +1905 -0
- package/src/ir.ts +151 -0
- package/src/oxc-analysis-types.ts +5 -0
- package/src/oxc-await-analysis.ts +165 -0
- package/src/oxc-await-ids.ts +62 -0
- package/src/oxc-await-validation.ts +117 -0
- package/src/oxc-bindings.ts +70 -0
- package/src/oxc-body-lowering.ts +430 -0
- package/src/oxc-child-analysis.ts +791 -0
- package/src/oxc-code-utils.ts +19 -0
- package/src/oxc-component-detection.ts +459 -0
- package/src/oxc-component-props.ts +170 -0
- package/src/oxc-component-references.ts +613 -0
- package/src/oxc-dom-lowering.ts +127 -0
- package/src/oxc-expression-utils.ts +42 -0
- package/src/oxc-jsx-attributes.ts +110 -0
- package/src/oxc-jsx-text.ts +84 -0
- package/src/oxc-nested-lowering.ts +319 -0
- package/src/oxc-node-utils.ts +65 -0
- package/src/oxc-raw-jsx.ts +239 -0
- package/src/oxc-render-values.ts +620 -0
- package/src/oxc-runtime-emit.ts +212 -0
- package/src/oxc-transform.ts +77 -0
- package/src/oxc.ts +932 -0
- package/src/transform.ts +634 -0
- package/src/types.ts +117 -0
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
import { parseSync } from "oxc-parser";
|
|
2
|
+
import { readArray, readObject, unwrapOxcParentheses } from "./oxc-node-utils.js";
|
|
3
|
+
|
|
4
|
+
export interface StaticStyleObjectEntry {
|
|
5
|
+
cssName: string;
|
|
6
|
+
valueCode: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const URL_ATTRIBUTE_NAMES = new Set([
|
|
10
|
+
"href",
|
|
11
|
+
"src",
|
|
12
|
+
"action",
|
|
13
|
+
"formaction",
|
|
14
|
+
"xlink:href",
|
|
15
|
+
"ping",
|
|
16
|
+
"poster",
|
|
17
|
+
"background",
|
|
18
|
+
"manifest",
|
|
19
|
+
]);
|
|
20
|
+
|
|
21
|
+
const DANGEROUS_HTML_ATTRIBUTE_NAMES = new Set(["srcdoc"]);
|
|
22
|
+
|
|
23
|
+
const SIMPLE_IDENT_CHAIN_RE = /^(this|[A-Za-z_$][\w$]*)(\.[A-Za-z_$][\w$]*)*$/;
|
|
24
|
+
const NUMERIC_LITERAL_RE = /^-?(?:\d+(?:\.\d+)?|\.\d+)$/;
|
|
25
|
+
const SIMPLE_STRING_LITERAL_RE = /^"(?:[^"\\]|\\.)*"$/;
|
|
26
|
+
const SIMPLE_SINGLE_QUOTE_RE = /^'(?:[^'\\]|\\.)*'$/;
|
|
27
|
+
|
|
28
|
+
const HTML_ATTRIBUTE_ALIASES: Record<string, string> = {
|
|
29
|
+
acceptCharset: "accept-charset",
|
|
30
|
+
autoFocus: "autofocus",
|
|
31
|
+
autoPlay: "autoplay",
|
|
32
|
+
charSet: "charset",
|
|
33
|
+
className: "class",
|
|
34
|
+
colSpan: "colspan",
|
|
35
|
+
contentEditable: "contenteditable",
|
|
36
|
+
crossOrigin: "crossorigin",
|
|
37
|
+
encType: "enctype",
|
|
38
|
+
formAction: "formaction",
|
|
39
|
+
frameBorder: "frameborder",
|
|
40
|
+
htmlFor: "for",
|
|
41
|
+
httpEquiv: "http-equiv",
|
|
42
|
+
maxLength: "maxlength",
|
|
43
|
+
minLength: "minlength",
|
|
44
|
+
noValidate: "novalidate",
|
|
45
|
+
playsInline: "playsinline",
|
|
46
|
+
readOnly: "readonly",
|
|
47
|
+
rowSpan: "rowspan",
|
|
48
|
+
spellCheck: "spellcheck",
|
|
49
|
+
srcDoc: "srcdoc",
|
|
50
|
+
srcSet: "srcset",
|
|
51
|
+
tabIndex: "tabindex",
|
|
52
|
+
useMap: "usemap",
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export function isUrlAttribute(name: string): boolean {
|
|
56
|
+
return URL_ATTRIBUTE_NAMES.has(name);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function isDangerousHtmlAttribute(name: string): boolean {
|
|
60
|
+
return DANGEROUS_HTML_ATTRIBUTE_NAMES.has(name);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function isStaticUrlValueUnsafe(name: string, value: string): boolean {
|
|
64
|
+
let start = 0;
|
|
65
|
+
|
|
66
|
+
while (start < value.length && value.charCodeAt(start) <= 0x20) {
|
|
67
|
+
start += 1;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const canonical = value.slice(start).replace(/[\t\r\n]/g, "");
|
|
71
|
+
const match = /^([a-zA-Z][a-zA-Z0-9+.-]*):/.exec(canonical);
|
|
72
|
+
if (match === null || match[1] === undefined) return false;
|
|
73
|
+
const scheme = match[1].toLowerCase();
|
|
74
|
+
if (scheme === "javascript" || scheme === "vbscript" || scheme === "livescript" || scheme === "mhtml" || scheme === "file") return true;
|
|
75
|
+
if (scheme === "data") {
|
|
76
|
+
if ((name === "src" || name === "poster") && /^data:image\/(?!svg\+xml(?:[;,]|$))/i.test(canonical)) return false;
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export function parseStyleLiteralValue(code: string): string | number | null | undefined {
|
|
83
|
+
const trimmed = unwrapParenthesized(code.trim());
|
|
84
|
+
|
|
85
|
+
if (trimmed === "null" || trimmed === "false" || trimmed === "undefined") {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (trimmed === "true") {
|
|
90
|
+
return "";
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (NUMERIC_LITERAL_RE.test(trimmed)) {
|
|
94
|
+
return Number(trimmed);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (SIMPLE_STRING_LITERAL_RE.test(trimmed)) {
|
|
98
|
+
return JSON.parse(trimmed) as string;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (SIMPLE_SINGLE_QUOTE_RE.test(trimmed)) {
|
|
102
|
+
return JSON.parse(`"${trimmed.slice(1, -1).replaceAll('"', '\\"')}"`) as string;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return undefined;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export function parseStaticStyleObjectLiteral(
|
|
109
|
+
code: string,
|
|
110
|
+
): StaticStyleObjectEntry[] | undefined {
|
|
111
|
+
const objectCode = unwrapParenthesized(code.trim());
|
|
112
|
+
const stringParsedEntries = parseStaticStyleObjectLiteralFromString(objectCode);
|
|
113
|
+
|
|
114
|
+
if (stringParsedEntries !== undefined) {
|
|
115
|
+
return stringParsedEntries;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return parseStaticStyleObjectLiteralWithOxc(objectCode);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function parseStaticStyleObjectLiteralFromString(
|
|
122
|
+
objectCode: string,
|
|
123
|
+
): StaticStyleObjectEntry[] | undefined {
|
|
124
|
+
if (!objectCode.startsWith("{") || !objectCode.endsWith("}")) {
|
|
125
|
+
return undefined;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const body = objectCode.slice(1, -1).trim();
|
|
129
|
+
|
|
130
|
+
if (body === "") {
|
|
131
|
+
return [];
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const entries: StaticStyleObjectEntry[] = [];
|
|
135
|
+
|
|
136
|
+
for (const property of splitTopLevel(body, ",")) {
|
|
137
|
+
const trimmed = property.trim();
|
|
138
|
+
|
|
139
|
+
if (trimmed === "" || trimmed.startsWith("...") || trimmed.startsWith("[")) {
|
|
140
|
+
return undefined;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const colonIndex = findTopLevelColon(trimmed);
|
|
144
|
+
|
|
145
|
+
if (colonIndex < 0) {
|
|
146
|
+
return undefined;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const rawKey = trimmed.slice(0, colonIndex).trim();
|
|
150
|
+
const valueCode = trimmed.slice(colonIndex + 1).trim();
|
|
151
|
+
const key = parseStaticObjectKey(rawKey);
|
|
152
|
+
|
|
153
|
+
if (key === undefined || valueCode === "") {
|
|
154
|
+
return undefined;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
entries.push({ cssName: cssPropertyName(key), valueCode });
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return entries;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function parseStaticStyleObjectLiteralWithOxc(
|
|
164
|
+
objectCode: string,
|
|
165
|
+
): StaticStyleObjectEntry[] | undefined {
|
|
166
|
+
if (!objectCode.startsWith("{") || !objectCode.endsWith("}")) {
|
|
167
|
+
return undefined;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const prefix = "const __mreactStyle = ";
|
|
171
|
+
const source = `${prefix}${objectCode};`;
|
|
172
|
+
const parsed = parseSync("style-object.tsx", source, {
|
|
173
|
+
lang: "tsx",
|
|
174
|
+
sourceType: "module",
|
|
175
|
+
astType: "ts",
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
if (parsed.errors.length > 0) {
|
|
179
|
+
return undefined;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const body = readArray(readObject(parsed.program).body);
|
|
183
|
+
const declaration = readArray(readObject(body[0]).declarations)[0];
|
|
184
|
+
const init = unwrapOxcParentheses(readObject(readObject(declaration).init));
|
|
185
|
+
|
|
186
|
+
if (init.type !== "ObjectExpression") {
|
|
187
|
+
return undefined;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const entries: StaticStyleObjectEntry[] = [];
|
|
191
|
+
|
|
192
|
+
for (const property of readArray(init.properties)) {
|
|
193
|
+
const propertyObject = readObject(property);
|
|
194
|
+
|
|
195
|
+
if (
|
|
196
|
+
propertyObject.type !== "Property" ||
|
|
197
|
+
propertyObject.kind !== "init" ||
|
|
198
|
+
propertyObject.method === true ||
|
|
199
|
+
propertyObject.computed === true ||
|
|
200
|
+
propertyObject.shorthand === true
|
|
201
|
+
) {
|
|
202
|
+
return undefined;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const key = readStaticOxcObjectKey(propertyObject.key);
|
|
206
|
+
const value = readObject(propertyObject.value);
|
|
207
|
+
const start = readNumber(value.start);
|
|
208
|
+
const end = readNumber(value.end);
|
|
209
|
+
|
|
210
|
+
if (key === undefined || start < prefix.length || end < start) {
|
|
211
|
+
return undefined;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
entries.push({
|
|
215
|
+
cssName: cssPropertyName(key),
|
|
216
|
+
valueCode: source.slice(start, end),
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
return entries;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function readStaticOxcObjectKey(node: unknown): string | undefined {
|
|
224
|
+
const key = readObject(node);
|
|
225
|
+
|
|
226
|
+
if (key.type === "Identifier") {
|
|
227
|
+
return typeof key.name === "string" ? key.name : undefined;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
if (key.type === "Literal") {
|
|
231
|
+
return typeof key.value === "string" ? key.value : undefined;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
return undefined;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
function readNumber(value: unknown): number {
|
|
238
|
+
return typeof value === "number" ? value : -1;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
export function simpleSideEffectFreeExpression(code: string): string | undefined {
|
|
242
|
+
const trimmed = unwrapParenthesized(code.trim());
|
|
243
|
+
|
|
244
|
+
if (trimmed === "") {
|
|
245
|
+
return undefined;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
if (
|
|
249
|
+
trimmed === "true" ||
|
|
250
|
+
trimmed === "false" ||
|
|
251
|
+
trimmed === "null" ||
|
|
252
|
+
trimmed === "undefined"
|
|
253
|
+
) {
|
|
254
|
+
return trimmed;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if (
|
|
258
|
+
NUMERIC_LITERAL_RE.test(trimmed) ||
|
|
259
|
+
SIMPLE_STRING_LITERAL_RE.test(trimmed) ||
|
|
260
|
+
SIMPLE_SINGLE_QUOTE_RE.test(trimmed) ||
|
|
261
|
+
SIMPLE_IDENT_CHAIN_RE.test(trimmed)
|
|
262
|
+
) {
|
|
263
|
+
return trimmed;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
return undefined;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
export function htmlAttributeName(name: string): string {
|
|
270
|
+
return HTML_ATTRIBUTE_ALIASES[name] ?? name;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
function unwrapParenthesized(code: string): string {
|
|
274
|
+
let current = code;
|
|
275
|
+
|
|
276
|
+
while (current.startsWith("(") && current.endsWith(")") && findMatchingClose(current, 0) === current.length - 1) {
|
|
277
|
+
current = current.slice(1, -1).trim();
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
return current;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
function splitTopLevel(code: string, separator: string): string[] {
|
|
284
|
+
const parts: string[] = [];
|
|
285
|
+
let start = 0;
|
|
286
|
+
let depth = 0;
|
|
287
|
+
let quote: string | undefined;
|
|
288
|
+
|
|
289
|
+
for (let index = 0; index < code.length; index += 1) {
|
|
290
|
+
const char = code[index];
|
|
291
|
+
|
|
292
|
+
if (quote !== undefined) {
|
|
293
|
+
if (char === "\\") {
|
|
294
|
+
index += 1;
|
|
295
|
+
} else if (char === quote) {
|
|
296
|
+
quote = undefined;
|
|
297
|
+
}
|
|
298
|
+
continue;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
if (char === "\"" || char === "'" || char === "`") {
|
|
302
|
+
quote = char;
|
|
303
|
+
continue;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
if (char === "{" || char === "[" || char === "(") {
|
|
307
|
+
depth += 1;
|
|
308
|
+
continue;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
if (char === "}" || char === "]" || char === ")") {
|
|
312
|
+
depth -= 1;
|
|
313
|
+
continue;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
if (depth === 0 && char === separator) {
|
|
317
|
+
parts.push(code.slice(start, index));
|
|
318
|
+
start = index + 1;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
parts.push(code.slice(start));
|
|
323
|
+
return parts;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
function findTopLevelColon(code: string): number {
|
|
327
|
+
return splitTopLevel(code, ":")[0]?.length ?? -1;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
function findMatchingClose(code: string, openIndex: number): number {
|
|
331
|
+
let depth = 0;
|
|
332
|
+
let quote: string | undefined;
|
|
333
|
+
|
|
334
|
+
for (let index = openIndex; index < code.length; index += 1) {
|
|
335
|
+
const char = code[index];
|
|
336
|
+
|
|
337
|
+
if (quote !== undefined) {
|
|
338
|
+
if (char === "\\") {
|
|
339
|
+
index += 1;
|
|
340
|
+
} else if (char === quote) {
|
|
341
|
+
quote = undefined;
|
|
342
|
+
}
|
|
343
|
+
continue;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
if (char === "\"" || char === "'" || char === "`") {
|
|
347
|
+
quote = char;
|
|
348
|
+
continue;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
if (char === "(") {
|
|
352
|
+
depth += 1;
|
|
353
|
+
} else if (char === ")") {
|
|
354
|
+
depth -= 1;
|
|
355
|
+
|
|
356
|
+
if (depth === 0) {
|
|
357
|
+
return index;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
return -1;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
function parseStaticObjectKey(rawKey: string): string | undefined {
|
|
366
|
+
if (/^[A-Za-z_$][\w$-]*$/.test(rawKey)) {
|
|
367
|
+
return rawKey;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
if (
|
|
371
|
+
(rawKey.startsWith("\"") && rawKey.endsWith("\"")) ||
|
|
372
|
+
(rawKey.startsWith("'") && rawKey.endsWith("'"))
|
|
373
|
+
) {
|
|
374
|
+
return rawKey.slice(1, -1);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
return undefined;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
function cssPropertyName(name: string): string {
|
|
381
|
+
return name.startsWith("--")
|
|
382
|
+
? name
|
|
383
|
+
: name.replace(/[A-Z]/g, (char) => `-${char.toLowerCase()}`);
|
|
384
|
+
}
|