abret 0.1.4 → 0.1.5
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/dist/html.d.ts +0 -45
- package/dist/html.js +100 -83
- package/dist/middleware/transpiler/index.js +71 -16
- package/package.json +1 -1
package/dist/html.d.ts
CHANGED
|
@@ -6,57 +6,12 @@ export { AsyncBuffer, SafeString, VNode, Fragment, type JSXNode };
|
|
|
6
6
|
export declare class HTMLResponse extends Response {
|
|
7
7
|
private _bodySource;
|
|
8
8
|
constructor(body: any, init?: ResponseInit);
|
|
9
|
-
/**
|
|
10
|
-
* Initializes the response with new options.
|
|
11
|
-
*
|
|
12
|
-
* @param newInit - The new options to apply to the response.
|
|
13
|
-
* @returns A new HTMLResponse instance with the updated options.
|
|
14
|
-
*
|
|
15
|
-
* @example
|
|
16
|
-
* ```ts
|
|
17
|
-
* const response = new HTMLResponse(<div>Hello World</div>).init({ status: 200 });
|
|
18
|
-
* ```
|
|
19
|
-
*/
|
|
20
9
|
init(newInit: ResponseInit): HTMLResponse;
|
|
21
|
-
/**
|
|
22
|
-
* Adds a DOCTYPE declaration to the response body.
|
|
23
|
-
*
|
|
24
|
-
* @param dt - The DOCTYPE declaration to add. Can be a string or a boolean.
|
|
25
|
-
* @returns A new HTMLResponse instance with the DOCTYPE declaration added.
|
|
26
|
-
*
|
|
27
|
-
* @example
|
|
28
|
-
* ```ts
|
|
29
|
-
* const response = new HTMLResponse(<div>Hello World</div>).doctype(true);
|
|
30
|
-
* ```
|
|
31
|
-
*/
|
|
32
10
|
doctype(dt?: string | boolean): HTMLResponse;
|
|
33
11
|
}
|
|
34
12
|
/**
|
|
35
13
|
* Creates an implementation of `HTMLResponse`.
|
|
36
14
|
*/
|
|
37
15
|
export declare function html(bodyOrStrings: JSXNode | TemplateStringsArray, ...args: any[]): HTMLResponse;
|
|
38
|
-
/**
|
|
39
|
-
* Renders a JSXNode to a SafeString or Promise<SafeString>.
|
|
40
|
-
*
|
|
41
|
-
* @param node - The JSXNode to render.
|
|
42
|
-
* @returns A SafeString or Promise<SafeString> containing the rendered HTML.
|
|
43
|
-
*
|
|
44
|
-
* @example
|
|
45
|
-
* ```tsx
|
|
46
|
-
* const rendered = render(<div>Hello World</div>);
|
|
47
|
-
* ```
|
|
48
|
-
*/
|
|
49
16
|
export declare function render(node: any): SafeString | Promise<SafeString>;
|
|
50
|
-
/**
|
|
51
|
-
* Creates a raw HTML string that will not be escaped when rendered.
|
|
52
|
-
* Equivalent to using `new SafeString(str)`.
|
|
53
|
-
*
|
|
54
|
-
* @param str - The raw HTML string.
|
|
55
|
-
* @returns A SafeString instance.
|
|
56
|
-
*
|
|
57
|
-
* @example
|
|
58
|
-
* ```tsx
|
|
59
|
-
* <div>{raw("<span>Raw HTML</span>")}</div>
|
|
60
|
-
* ```
|
|
61
|
-
*/
|
|
62
17
|
export declare function raw(str: string): SafeString;
|
package/dist/html.js
CHANGED
|
@@ -6,10 +6,15 @@ import {
|
|
|
6
6
|
VNode
|
|
7
7
|
} from "./chunk-m9t91z6h.js";
|
|
8
8
|
import {
|
|
9
|
-
|
|
9
|
+
createContext,
|
|
10
|
+
getContextStore,
|
|
11
|
+
runWithContextValue,
|
|
12
|
+
useContext
|
|
10
13
|
} from "./chunk-xw5b0251.js";
|
|
11
14
|
|
|
12
15
|
// src/html.ts
|
|
16
|
+
var HeadContext = createContext("abret-head");
|
|
17
|
+
|
|
13
18
|
class HTMLResponse extends Response {
|
|
14
19
|
_bodySource;
|
|
15
20
|
constructor(body, init) {
|
|
@@ -68,19 +73,19 @@ var MODE_PROPVAL = 4;
|
|
|
68
73
|
var MODE_PROPVAL_QUOTE = 5;
|
|
69
74
|
var MODE_CLOSE_TAG = 6;
|
|
70
75
|
function html(bodyOrStrings, ...args) {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
return
|
|
76
|
+
const headCollection = [];
|
|
77
|
+
const runRender = () => {
|
|
78
|
+
if (Array.isArray(bodyOrStrings) && bodyOrStrings.raw) {
|
|
79
|
+
const vnode = parse(bodyOrStrings, args);
|
|
80
|
+
return render(vnode);
|
|
76
81
|
}
|
|
77
|
-
return
|
|
78
|
-
}
|
|
79
|
-
const rendered =
|
|
82
|
+
return render(bodyOrStrings);
|
|
83
|
+
};
|
|
84
|
+
const rendered = runWithContextValue(HeadContext, headCollection, runRender);
|
|
80
85
|
if (rendered instanceof Promise) {
|
|
81
|
-
return new HTMLResponse(rendered.then((s) => raw(
|
|
86
|
+
return new HTMLResponse(rendered.then((s) => raw(injectMetadata(s.toString(), headCollection))));
|
|
82
87
|
}
|
|
83
|
-
return new HTMLResponse(raw(
|
|
88
|
+
return new HTMLResponse(raw(injectMetadata(rendered.toString(), headCollection)));
|
|
84
89
|
}
|
|
85
90
|
function parse(statics, fields) {
|
|
86
91
|
let mode = MODE_TEXT;
|
|
@@ -106,7 +111,7 @@ function parse(statics, fields) {
|
|
|
106
111
|
if (buffer === "...") {
|
|
107
112
|
Object.assign(active.props, val);
|
|
108
113
|
buffer = "";
|
|
109
|
-
}
|
|
114
|
+
}
|
|
110
115
|
} else if (mode === MODE_PROPNAME) {
|
|
111
116
|
propName = fields[i - 1];
|
|
112
117
|
mode = MODE_PROPVAL;
|
|
@@ -301,6 +306,59 @@ function render(node) {
|
|
|
301
306
|
if (typeof node.tag === "string") {
|
|
302
307
|
const tag = node.tag;
|
|
303
308
|
const { children, dangerouslySetInnerHTML, ...rest } = node.props;
|
|
309
|
+
if (tag === "title" || tag === "meta" || tag === "link") {
|
|
310
|
+
const headStore = useContext(HeadContext);
|
|
311
|
+
if (headStore) {
|
|
312
|
+
const attrs2 = Object.entries(rest).map(([key2, value]) => {
|
|
313
|
+
if (value === null || value === undefined || value === false)
|
|
314
|
+
return "";
|
|
315
|
+
if (key2 === "className")
|
|
316
|
+
key2 = "class";
|
|
317
|
+
if (key2 === "style")
|
|
318
|
+
value = renderStyle(value);
|
|
319
|
+
if (value === true)
|
|
320
|
+
return ` ${key2}`;
|
|
321
|
+
return ` ${key2}="${escapeHtml(String(value))}"`;
|
|
322
|
+
}).join("");
|
|
323
|
+
if (tag === "title") {
|
|
324
|
+
const childrenList2 = Array.isArray(children) ? children : [children];
|
|
325
|
+
const renderedContent = render(childrenList2);
|
|
326
|
+
const pushTitle = (content) => {
|
|
327
|
+
headStore.push({
|
|
328
|
+
type: "title",
|
|
329
|
+
content: `<title${attrs2}>${escapeHtml(content)}</title>`
|
|
330
|
+
});
|
|
331
|
+
};
|
|
332
|
+
if (renderedContent instanceof Promise) {
|
|
333
|
+
return renderedContent.then((c) => {
|
|
334
|
+
pushTitle(c.toString());
|
|
335
|
+
return raw("");
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
pushTitle(renderedContent.toString());
|
|
339
|
+
return raw("");
|
|
340
|
+
}
|
|
341
|
+
let key;
|
|
342
|
+
if (tag === "meta") {
|
|
343
|
+
if (rest.name)
|
|
344
|
+
key = `name:${rest.name}`;
|
|
345
|
+
else if (rest.property)
|
|
346
|
+
key = `property:${rest.property}`;
|
|
347
|
+
else if (rest.charset)
|
|
348
|
+
key = "charset";
|
|
349
|
+
else if (rest["http-equiv"])
|
|
350
|
+
key = `http-equiv:${rest["http-equiv"]}`;
|
|
351
|
+
} else if (tag === "link" && rest.rel?.toLowerCase() === "canonical") {
|
|
352
|
+
key = "canonical";
|
|
353
|
+
}
|
|
354
|
+
headStore.push({
|
|
355
|
+
type: tag,
|
|
356
|
+
key,
|
|
357
|
+
content: `<${tag}${attrs2} />`
|
|
358
|
+
});
|
|
359
|
+
return raw("");
|
|
360
|
+
}
|
|
361
|
+
}
|
|
304
362
|
const attrs = Object.entries(rest).map(([key, value]) => {
|
|
305
363
|
if (value === null || value === undefined || value === false)
|
|
306
364
|
return "";
|
|
@@ -308,6 +366,9 @@ function render(node) {
|
|
|
308
366
|
key = "class";
|
|
309
367
|
if (key === "style")
|
|
310
368
|
value = renderStyle(value);
|
|
369
|
+
if ((key === "href" || key === "src") && typeof value === "string" && value.trim().toLowerCase().startsWith("javascript:")) {
|
|
370
|
+
value = "";
|
|
371
|
+
}
|
|
311
372
|
if (value === true)
|
|
312
373
|
return ` ${key}`;
|
|
313
374
|
return ` ${key}="${escapeHtml(String(value))}"`;
|
|
@@ -365,87 +426,43 @@ function renderStyle(style) {
|
|
|
365
426
|
return style;
|
|
366
427
|
return Object.entries(style).map(([k, v]) => `${kebabCase(k)}:${v}`).join(";");
|
|
367
428
|
}
|
|
368
|
-
function
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
let titleTag = null;
|
|
372
|
-
const extractedHtml = html2.replace(/<title(?:\s[^>]*)?>([\s\S]*?)<\/title>|<meta(?:\s[^>]*)?\/?>|<link(?:\s[^>]*)?\/?>/gi, (match) => {
|
|
373
|
-
if (match.toLowerCase().startsWith("<title")) {
|
|
374
|
-
titleTag = match;
|
|
375
|
-
return "";
|
|
376
|
-
}
|
|
377
|
-
if (match.toLowerCase().startsWith("<meta")) {
|
|
378
|
-
const name = match.match(/name=["']([^"']+)["']/i);
|
|
379
|
-
const property = match.match(/property=["']([^"']+)["']/i);
|
|
380
|
-
const charset = match.match(/charset=["']([^"']+)["']/i);
|
|
381
|
-
const httpEquiv = match.match(/http-equiv=["']([^"']+)["']/i);
|
|
382
|
-
let key;
|
|
383
|
-
if (name?.[1])
|
|
384
|
-
key = `name:${name[1]}`;
|
|
385
|
-
else if (property?.[1])
|
|
386
|
-
key = `property:${property[1]}`;
|
|
387
|
-
else if (charset?.[1])
|
|
388
|
-
key = "charset";
|
|
389
|
-
else if (httpEquiv?.[1])
|
|
390
|
-
key = `http-equiv:${httpEquiv[1]}`;
|
|
391
|
-
metaTags.push({ tag: "meta", content: match, key });
|
|
392
|
-
return "";
|
|
393
|
-
}
|
|
394
|
-
if (match.toLowerCase().startsWith("<link")) {
|
|
395
|
-
const rel = match.match(/rel=["']([^"']+)["']/i);
|
|
396
|
-
const key = rel?.[1]?.toLowerCase() === "canonical" ? "canonical" : undefined;
|
|
397
|
-
linkTags.push({ tag: "link", content: match, key });
|
|
398
|
-
return "";
|
|
399
|
-
}
|
|
400
|
-
return match;
|
|
401
|
-
});
|
|
429
|
+
function injectMetadata(html2, tags) {
|
|
430
|
+
if (tags.length === 0)
|
|
431
|
+
return html2;
|
|
402
432
|
const headContent = [];
|
|
403
433
|
const metaMap = new Map;
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
434
|
+
let titleString = null;
|
|
435
|
+
for (const t of tags) {
|
|
436
|
+
if (t.type === "title") {
|
|
437
|
+
titleString = t.content;
|
|
438
|
+
} else if (t.key) {
|
|
439
|
+
metaMap.set(t.key, t.content);
|
|
440
|
+
} else {
|
|
441
|
+
headContent.push(t.content);
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
const finalHead = [];
|
|
408
445
|
if (metaMap.has("charset")) {
|
|
409
|
-
|
|
410
|
-
if (charsetTag)
|
|
411
|
-
headContent.push(charsetTag);
|
|
446
|
+
finalHead.push(metaMap.get("charset"));
|
|
412
447
|
metaMap.delete("charset");
|
|
413
448
|
}
|
|
414
|
-
if (
|
|
415
|
-
|
|
449
|
+
if (titleString) {
|
|
450
|
+
finalHead.push(titleString);
|
|
451
|
+
}
|
|
416
452
|
if (metaMap.has("name:viewport")) {
|
|
417
|
-
|
|
418
|
-
if (viewportTag)
|
|
419
|
-
headContent.push(viewportTag);
|
|
453
|
+
finalHead.push(metaMap.get("name:viewport"));
|
|
420
454
|
metaMap.delete("name:viewport");
|
|
421
455
|
}
|
|
422
|
-
metaMap.forEach((v) =>
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
});
|
|
428
|
-
const linkMap = new Map;
|
|
429
|
-
linkTags.forEach((l) => {
|
|
430
|
-
if (l.key)
|
|
431
|
-
linkMap.set(l.key, l.content);
|
|
432
|
-
else
|
|
433
|
-
headContent.push(l.content);
|
|
434
|
-
});
|
|
435
|
-
linkMap.forEach((v) => {
|
|
436
|
-
headContent.push(v);
|
|
437
|
-
});
|
|
438
|
-
const headString = headContent.join("");
|
|
439
|
-
if (extractedHtml.includes("<head>")) {
|
|
440
|
-
return extractedHtml.replace("<head>", `<head>${headString}`);
|
|
441
|
-
}
|
|
442
|
-
if (extractedHtml.match(/<html/i)) {
|
|
443
|
-
return extractedHtml.replace(/(<html[^>]*>)/i, `$1<head>${headString}</head>`);
|
|
456
|
+
metaMap.forEach((v) => finalHead.push(v));
|
|
457
|
+
finalHead.push(...headContent);
|
|
458
|
+
const headString = finalHead.join("");
|
|
459
|
+
if (html2.includes("<head>")) {
|
|
460
|
+
return html2.replace("<head>", `<head>${headString}`);
|
|
444
461
|
}
|
|
445
|
-
if (
|
|
446
|
-
return
|
|
462
|
+
if (html2.toLowerCase().includes("<html")) {
|
|
463
|
+
return html2.replace(/(<html[^>]*>)/i, `$1<head>${headString}</head>`);
|
|
447
464
|
}
|
|
448
|
-
return
|
|
465
|
+
return `<head>${headString}</head>${html2}`;
|
|
449
466
|
}
|
|
450
467
|
function raw(str) {
|
|
451
468
|
return new SafeString(str);
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
import"../../chunk-xw5b0251.js";
|
|
6
6
|
|
|
7
7
|
// src/middleware/transpiler/index.ts
|
|
8
|
-
import { existsSync, mkdirSync, statSync } from "fs";
|
|
8
|
+
import { existsSync, mkdirSync, readFileSync, statSync } from "fs";
|
|
9
9
|
import path from "path";
|
|
10
10
|
var transpiler = (options) => {
|
|
11
11
|
const {
|
|
@@ -37,12 +37,49 @@ var transpiler = (options) => {
|
|
|
37
37
|
...publicEnv,
|
|
38
38
|
...define
|
|
39
39
|
};
|
|
40
|
+
const trustedDependencies = new Set([
|
|
41
|
+
...prewarm || [],
|
|
42
|
+
...Object.keys(globals)
|
|
43
|
+
]);
|
|
44
|
+
function registerTrustedDependency(moduleName) {
|
|
45
|
+
if (!moduleName)
|
|
46
|
+
return;
|
|
47
|
+
const normalizedName = moduleName.trim();
|
|
48
|
+
if (normalizedName && !trustedDependencies.has(normalizedName)) {
|
|
49
|
+
trustedDependencies.add(normalizedName);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
if (existsSync(cacheDir)) {
|
|
53
|
+
const files = new Bun.Glob("*.js").scanSync(cacheDir);
|
|
54
|
+
for (const file of files) {
|
|
55
|
+
const moduleName = file.slice(0, -3).replace(/__/g, "/");
|
|
56
|
+
registerTrustedDependency(moduleName);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
const absSourcePath = path.resolve(process.cwd(), sourcePath);
|
|
60
|
+
if (existsSync(absSourcePath)) {
|
|
61
|
+
const glob = new Bun.Glob("**/*.{ts,tsx,js,jsx}");
|
|
62
|
+
const scanner = new Bun.Transpiler({ loader: "tsx" });
|
|
63
|
+
for (const relativePath of glob.scanSync(absSourcePath)) {
|
|
64
|
+
try {
|
|
65
|
+
const fullPath = path.join(absSourcePath, relativePath);
|
|
66
|
+
const contents = readFileSync(fullPath, "utf8");
|
|
67
|
+
const imports = scanner.scan(contents).imports;
|
|
68
|
+
for (const imp of imports) {
|
|
69
|
+
if (!imp.path.startsWith(".") && !imp.path.startsWith("/")) {
|
|
70
|
+
registerTrustedDependency(imp.path);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
} catch {}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
40
76
|
const activeBundles = new Map;
|
|
41
77
|
function resolveModulePath(moduleName) {
|
|
42
78
|
if (globals[moduleName])
|
|
43
79
|
return moduleName;
|
|
44
80
|
try {
|
|
45
81
|
Bun.resolveSync(moduleName, process.cwd());
|
|
82
|
+
registerTrustedDependency(moduleName);
|
|
46
83
|
return `${basePrefix}${vendorPath.replace(/^\/|\/$/g, "")}/${moduleName}`;
|
|
47
84
|
} catch {
|
|
48
85
|
if (cdnFallback) {
|
|
@@ -96,7 +133,10 @@ var transpiler = (options) => {
|
|
|
96
133
|
build.onResolve({ filter: /^[^./]/ }, (args) => {
|
|
97
134
|
if (args.path === moduleName || globals[args.path])
|
|
98
135
|
return null;
|
|
99
|
-
|
|
136
|
+
if (/^(https?:|(?:\/\/))/.test(args.path)) {
|
|
137
|
+
return { path: args.path, external: true };
|
|
138
|
+
}
|
|
139
|
+
return { path: resolveModulePath(args.path), external: true };
|
|
100
140
|
});
|
|
101
141
|
}
|
|
102
142
|
},
|
|
@@ -111,18 +151,12 @@ var transpiler = (options) => {
|
|
|
111
151
|
if (!output)
|
|
112
152
|
return;
|
|
113
153
|
const rawContent = await output.text();
|
|
114
|
-
const content = rawContent
|
|
115
|
-
if (/^(https?:|(?:\/\/))/.test(path2))
|
|
116
|
-
return match;
|
|
117
|
-
if (!path2.startsWith(".") && !path2.startsWith("/")) {
|
|
118
|
-
return `${prefix}${resolveModulePath(path2)}${suffix}`;
|
|
119
|
-
}
|
|
120
|
-
return match;
|
|
121
|
-
});
|
|
154
|
+
const content = rawContent;
|
|
122
155
|
await Bun.write(cachedFile, content);
|
|
123
156
|
console.log(`[Abret] Pre-bundled: ${moduleName}`);
|
|
124
157
|
} catch (err) {
|
|
125
158
|
console.error(`[Abret] Error bundling ${moduleName}:`, err);
|
|
159
|
+
throw err;
|
|
126
160
|
} finally {
|
|
127
161
|
activeBundles.delete(cacheKey);
|
|
128
162
|
}
|
|
@@ -143,6 +177,9 @@ var transpiler = (options) => {
|
|
|
143
177
|
}
|
|
144
178
|
if (pathname.startsWith(vendorPrefix)) {
|
|
145
179
|
const moduleName = pathname.slice(vendorPrefix.length);
|
|
180
|
+
if (!cdnFallback && !trustedDependencies.has(moduleName)) {
|
|
181
|
+
return next();
|
|
182
|
+
}
|
|
146
183
|
const cacheKey = moduleName.replace(/\//g, "__");
|
|
147
184
|
const cachedFile = path.join(cacheDir, `${cacheKey}.js`);
|
|
148
185
|
if (existsSync(cachedFile)) {
|
|
@@ -153,7 +190,13 @@ var transpiler = (options) => {
|
|
|
153
190
|
}
|
|
154
191
|
});
|
|
155
192
|
}
|
|
156
|
-
|
|
193
|
+
try {
|
|
194
|
+
await bundleVendorModule(moduleName);
|
|
195
|
+
} catch (_err) {
|
|
196
|
+
if (cdnFallback) {
|
|
197
|
+
return Response.redirect(`https://esm.sh/${moduleName}`, 302);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
157
200
|
if (existsSync(cachedFile)) {
|
|
158
201
|
return new Response(Bun.file(cachedFile), {
|
|
159
202
|
headers: {
|
|
@@ -168,9 +211,17 @@ var transpiler = (options) => {
|
|
|
168
211
|
const extname = path.extname(internalPath);
|
|
169
212
|
let sourceFile = "";
|
|
170
213
|
let contentType = "application/javascript";
|
|
214
|
+
const secureResolve = (relativePath) => {
|
|
215
|
+
const cleanRelative = relativePath.startsWith("/") ? relativePath.slice(1) : relativePath;
|
|
216
|
+
const resolvedPath = path.join(absSourcePath, cleanRelative);
|
|
217
|
+
if (!resolvedPath.startsWith(absSourcePath)) {
|
|
218
|
+
return null;
|
|
219
|
+
}
|
|
220
|
+
return resolvedPath;
|
|
221
|
+
};
|
|
171
222
|
if (extname === ".css") {
|
|
172
|
-
const p =
|
|
173
|
-
if (existsSync(p)) {
|
|
223
|
+
const p = secureResolve(internalPath);
|
|
224
|
+
if (p && existsSync(p)) {
|
|
174
225
|
sourceFile = p;
|
|
175
226
|
contentType = "text/css";
|
|
176
227
|
}
|
|
@@ -178,8 +229,8 @@ var transpiler = (options) => {
|
|
|
178
229
|
const baseFileName = internalPath.endsWith(".js") ? internalPath.slice(0, -3) : internalPath;
|
|
179
230
|
const possibleExtensions = [".tsx", ".ts", ".jsx", ".js"];
|
|
180
231
|
for (const ext of possibleExtensions) {
|
|
181
|
-
const p =
|
|
182
|
-
if (existsSync(p)) {
|
|
232
|
+
const p = secureResolve(baseFileName + ext);
|
|
233
|
+
if (p && existsSync(p)) {
|
|
183
234
|
sourceFile = p;
|
|
184
235
|
break;
|
|
185
236
|
}
|
|
@@ -243,7 +294,11 @@ var transpiler = (options) => {
|
|
|
243
294
|
if (contentType === "text/css") {
|
|
244
295
|
return { content: transpiledCode, contentType };
|
|
245
296
|
}
|
|
246
|
-
const
|
|
297
|
+
const tokenRegex = /("(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'|`(?:[^`\\]|\\.)*`|\/\/[^\n]*|\/\*[\s\S]*?\*\/)|((?:import|export)\s*[\s\S]*?from\s*['"]|import\s*\(['"])([^'"]+)(['"]\)?)/g;
|
|
298
|
+
const finalCode = transpiledCode.replace(tokenRegex, (match, stringOrComment, prefix, path2, suffix) => {
|
|
299
|
+
if (stringOrComment) {
|
|
300
|
+
return match;
|
|
301
|
+
}
|
|
247
302
|
if (/^(https?:|(?:\/\/))/.test(path2))
|
|
248
303
|
return match;
|
|
249
304
|
if (!path2.startsWith(".") && !path2.startsWith("/")) {
|