pudui 0.0.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.
@@ -0,0 +1,707 @@
1
+ import MagicString from "magic-string";
2
+ import { parseSync, visitorKeys } from "oxc-parser";
3
+ //#region src/transform/path.ts
4
+ /**
5
+ * Converts path separators to forward slashes.
6
+ *
7
+ * @param path Path to normalize.
8
+ * @returns Path using `/` separators.
9
+ */
10
+ function normalizePath(path) {
11
+ return path.replaceAll("\\", "/");
12
+ }
13
+ /**
14
+ * Reads the final path segment.
15
+ *
16
+ * @param path Path to inspect.
17
+ * @param extension Optional extension to trim from the basename.
18
+ * @returns Final path segment.
19
+ */
20
+ function pathBasename(path, extension) {
21
+ const normalizedPath = normalizePath(path);
22
+ const name = normalizedPath.slice(normalizedPath.lastIndexOf("/") + 1);
23
+ if (extension !== void 0 && extension !== "" && name.endsWith(extension)) return name.slice(0, -extension.length);
24
+ return name;
25
+ }
26
+ /**
27
+ * Reads the extension from a path.
28
+ *
29
+ * @param path Path to inspect.
30
+ * @returns Extension including the leading `.`, or an empty string.
31
+ */
32
+ function pathExtname(path) {
33
+ const name = pathBasename(path);
34
+ const dotIndex = name.lastIndexOf(".");
35
+ return dotIndex === -1 ? "" : name.slice(dotIndex);
36
+ }
37
+ //#endregion
38
+ //#region src/transform/ast.ts
39
+ /**
40
+ * Parses source code as an Oxc program.
41
+ *
42
+ * @param code Source code to parse.
43
+ * @param id Module identifier used to infer language mode.
44
+ * @returns Parsed Oxc program.
45
+ */
46
+ function parseProgram(code, id) {
47
+ const result = parseSync(id, code, {
48
+ lang: languageForId(id),
49
+ range: true,
50
+ sourceType: "module"
51
+ });
52
+ if (result.errors.length > 0) throw new Error(result.errors[0].message);
53
+ return result.program;
54
+ }
55
+ /**
56
+ * Infers Oxc parser language mode from a module id.
57
+ *
58
+ * @param id Module identifier or path.
59
+ * @returns Parser language mode.
60
+ */
61
+ function languageForId(id) {
62
+ const extension = pathExtname(id);
63
+ if (extension === ".tsx") return "tsx";
64
+ if (extension === ".ts" || extension === ".mts" || extension === ".cts") return "ts";
65
+ if (extension === ".jsx") return "jsx";
66
+ return "js";
67
+ }
68
+ /**
69
+ * Walks an AST depth first.
70
+ *
71
+ * @param node Root node to visit.
72
+ * @param enter Callback run before visiting child nodes.
73
+ * @param leave Callback run after visiting child nodes.
74
+ */
75
+ function walk(node, enter, leave) {
76
+ enter(node);
77
+ for (const key of visitorKeys[node.type] ?? []) {
78
+ const value = node[key];
79
+ if (Array.isArray(value)) {
80
+ for (const child of value) if (isNode(child)) walk(child, enter, leave);
81
+ } else if (isNode(value)) walk(value, enter, leave);
82
+ }
83
+ leave?.(node);
84
+ }
85
+ /**
86
+ * Walks an AST while reporting lexical scope boundaries.
87
+ *
88
+ * @param node Root node to visit.
89
+ * @param parent Parent node for the root.
90
+ * @param callbacks Scope and visit callbacks.
91
+ */
92
+ function walkWithScopes(node, parent, callbacks) {
93
+ const createsScope = isFunctionLike(node) || node.type === "BlockStatement";
94
+ if (createsScope) callbacks.enterScope(node);
95
+ callbacks.visit(node, parent);
96
+ for (const key of visitorKeys[node.type] ?? []) {
97
+ const value = node[key];
98
+ if (Array.isArray(value)) {
99
+ for (const child of value) if (isNode(child)) walkWithScopes(child, node, callbacks);
100
+ } else if (isNode(value)) walkWithScopes(value, node, callbacks);
101
+ }
102
+ if (createsScope) callbacks.leaveScope();
103
+ }
104
+ /**
105
+ * Walks an AST without entering nested function bodies.
106
+ *
107
+ * @param node Root node to visit.
108
+ * @param enter Callback run for each visited node.
109
+ */
110
+ function walkSkippingNestedFunctions(node, enter) {
111
+ enter(node);
112
+ for (const key of visitorKeys[node.type] ?? []) {
113
+ const value = node[key];
114
+ if (Array.isArray(value)) {
115
+ for (const child of value) if (isNode(child) && !isFunctionLike(child)) walkSkippingNestedFunctions(child, enter);
116
+ } else if (isNode(value) && !isFunctionLike(value)) walkSkippingNestedFunctions(value, enter);
117
+ }
118
+ }
119
+ /**
120
+ * Checks whether a node creates a function scope.
121
+ *
122
+ * @param node Node to inspect.
123
+ * @returns `true` for function declarations, expressions, and arrows.
124
+ */
125
+ function isFunctionLike(node) {
126
+ return node.type === "ArrowFunctionExpression" || node.type === "FunctionDeclaration" || node.type === "FunctionExpression";
127
+ }
128
+ /**
129
+ * Checks whether a value has the minimal Oxc node shape.
130
+ *
131
+ * @param value Value to inspect.
132
+ * @returns `true` when the value is an Oxc node.
133
+ */
134
+ function isNode(value) {
135
+ return typeof value === "object" && value !== null && typeof value.type === "string" && typeof value.start === "number" && typeof value.end === "number";
136
+ }
137
+ /**
138
+ * Reads only AST nodes from an unknown array-like value.
139
+ *
140
+ * @param value Value to inspect.
141
+ * @returns AST nodes contained in the value.
142
+ */
143
+ function readNodeArray(value) {
144
+ return Array.isArray(value) ? value.filter(isNode) : [];
145
+ }
146
+ /**
147
+ * Reads an optional AST node.
148
+ *
149
+ * @param value Value to inspect.
150
+ * @returns The node, or `undefined`.
151
+ */
152
+ function readOptionalNode(value) {
153
+ return isNode(value) ? value : void 0;
154
+ }
155
+ /**
156
+ * Reads an identifier name from a node-like value.
157
+ *
158
+ * @param value Value to inspect.
159
+ * @returns Identifier name, or an empty string.
160
+ */
161
+ function readIdentifierName(value) {
162
+ const node = readOptionalNode(value);
163
+ if (node?.type !== "Identifier") return "";
164
+ return typeof node.name === "string" ? node.name : "";
165
+ }
166
+ /**
167
+ * Reads a string literal value.
168
+ *
169
+ * @param value Value to inspect.
170
+ * @returns Literal string value, or an empty string.
171
+ */
172
+ function readLiteralValue(value) {
173
+ const node = readOptionalNode(value);
174
+ if (node?.type !== "Literal") return "";
175
+ return typeof node.value === "string" ? node.value : "";
176
+ }
177
+ /**
178
+ * Reads a static string from a literal or no-substitution template.
179
+ *
180
+ * @param value Value to inspect.
181
+ * @returns Static string value, or an empty string.
182
+ */
183
+ function readStringValue(value) {
184
+ const node = readOptionalNode(value);
185
+ if (node?.type === "Literal") return typeof node.value === "string" ? node.value : "";
186
+ if (node?.type !== "TemplateLiteral" || readNodeArray(node.expressions).length > 0) return "";
187
+ const quasi = readNodeArray(node.quasis)[0];
188
+ const cooked = typeof quasi?.value === "object" && quasi.value !== null ? quasi.value.cooked : void 0;
189
+ return typeof cooked === "string" ? cooked : "";
190
+ }
191
+ /**
192
+ * Reads a required static string.
193
+ *
194
+ * @param value Value to inspect.
195
+ * @returns Static string value.
196
+ */
197
+ function readStringLiteral(value) {
198
+ const literal = readStringValue(value);
199
+ if (literal === "") throw new Error("Invalid hydrate metadata marker.");
200
+ return literal;
201
+ }
202
+ /**
203
+ * Reads the top-level body nodes from a program.
204
+ *
205
+ * @param program Program to inspect.
206
+ * @returns Top-level statement nodes.
207
+ */
208
+ function getBody(program) {
209
+ return readNodeArray(program.body);
210
+ }
211
+ //#endregion
212
+ //#region src/transforms/paths.ts
213
+ const supportedModuleExtensions = new Set([
214
+ ".cjs",
215
+ ".cts",
216
+ ".js",
217
+ ".jsx",
218
+ ".mjs",
219
+ ".mts",
220
+ ".ts",
221
+ ".tsx"
222
+ ]);
223
+ /**
224
+ * Removes query and hash suffixes from a module id.
225
+ *
226
+ * @param id Raw module id.
227
+ * @returns Clean module id.
228
+ */
229
+ function cleanModuleId(id) {
230
+ const queryIndex = id.indexOf("?");
231
+ const hashIndex = id.indexOf("#");
232
+ const end = Math.min(queryIndex === -1 ? id.length : queryIndex, hashIndex === -1 ? id.length : hashIndex);
233
+ return id.slice(0, end);
234
+ }
235
+ /**
236
+ * Checks whether a module id is eligible for Pudui transforms.
237
+ *
238
+ * @param id Clean module id.
239
+ * @returns `true` when the module is source code outside `node_modules`.
240
+ */
241
+ function shouldTransformModule(id) {
242
+ return !id.includes("/node_modules/") && supportedModuleExtensions.has(pathExtname(id));
243
+ }
244
+ /**
245
+ * Resolves the development browser path for the configured browser entry.
246
+ *
247
+ * @param id Browser entry module id.
248
+ * @param config Vite config used for base and root.
249
+ * @returns Browser-served module path.
250
+ */
251
+ function devBrowserEntryPath(id, config) {
252
+ if (id === "") return "";
253
+ if (isAbsolutePath(id)) return devModulePath(id, config);
254
+ return `${normalizeBase(config?.base)}${stripLeadingSlashes(normalizePath(id))}`;
255
+ }
256
+ /**
257
+ * Resolves a module id to its Vite development module path.
258
+ *
259
+ * @param id Module id.
260
+ * @param config Vite config used for base and root.
261
+ * @returns Browser-served module path.
262
+ */
263
+ function devModulePath(id, config) {
264
+ if (config === void 0) return normalizePath(id);
265
+ const relativePath = relativeToRoot(config.root, id);
266
+ if (relativePath.startsWith("../")) return `/@fs/${normalizePath(id)}`;
267
+ return `${normalizeBase(config.base)}${relativePath}`;
268
+ }
269
+ /**
270
+ * Resolves an emitted asset filename to a public URL path.
271
+ *
272
+ * @param fileName Emitted asset filename.
273
+ * @param config Vite config used for base.
274
+ * @returns Public asset path.
275
+ */
276
+ function publicAssetPath(fileName, config) {
277
+ return `${normalizeBase(config?.base)}${normalizePath(fileName)}`;
278
+ }
279
+ /**
280
+ * Computes a normalized path from the Vite root to a module id.
281
+ *
282
+ * @param root Vite project root.
283
+ * @param id Module id.
284
+ * @returns Root-relative path, or a `..` path for files outside the root.
285
+ */
286
+ function relativeToRoot(root, id) {
287
+ const normalizedRoot = normalizePath(root).replace(/\/$/u, "");
288
+ const normalizedId = normalizePath(id);
289
+ if (normalizedId === normalizedRoot) return "";
290
+ if (normalizedId.startsWith(`${normalizedRoot}/`)) return normalizedId.slice(normalizedRoot.length + 1);
291
+ return `../${normalizedId}`;
292
+ }
293
+ function normalizeBase(base) {
294
+ if (base === void 0 || base === "") return "/";
295
+ return base.endsWith("/") ? base : `${base}/`;
296
+ }
297
+ function isAbsolutePath(path) {
298
+ return path.startsWith("/") || path.length >= 3 && isAsciiLetter(path[0] ?? "") && path[1] === ":" && (path[2] === "/" || path[2] === "\\");
299
+ }
300
+ function isAsciiLetter(char) {
301
+ return char >= "A" && char <= "Z" || char >= "a" && char <= "z";
302
+ }
303
+ function stripLeadingSlashes(path) {
304
+ let start = 0;
305
+ while (path[start] === "/") start++;
306
+ return path.slice(start);
307
+ }
308
+ //#endregion
309
+ //#region src/transforms/markers.ts
310
+ /**
311
+ * Build marker function name for entry metadata placeholders.
312
+ */
313
+ const entryMarkerName = "__PUDUI_ENTRY__";
314
+ /**
315
+ * Build marker function name for hydration metadata placeholders.
316
+ */
317
+ const hydrateMarkerName = "__PUDUI_HYDRATE__";
318
+ const placeholderScheme = "pudui:";
319
+ /**
320
+ * Creates a serialized marker for a hydrated component export.
321
+ *
322
+ * @param id Module identifier.
323
+ * @param exportName Component export name.
324
+ * @returns Serialized marker string.
325
+ */
326
+ function createHydrateMarker(id, exportName) {
327
+ return `${placeholderScheme}${normalizePath(id)}#${exportName}`;
328
+ }
329
+ /**
330
+ * Creates a serialized marker for an entry macro call.
331
+ *
332
+ * @param id Module identifier.
333
+ * @returns Serialized marker string.
334
+ */
335
+ function createEntryMarker(id) {
336
+ return `${placeholderScheme}${normalizePath(id)}`;
337
+ }
338
+ /**
339
+ * Parses a hydrated component marker.
340
+ *
341
+ * @param marker Marker string to parse.
342
+ * @returns Parsed marker data, or `undefined` for invalid markers.
343
+ */
344
+ function parseHydrateMarker(marker) {
345
+ if (!marker.startsWith(placeholderScheme)) return;
346
+ const value = marker.slice(6);
347
+ const exportNameStart = value.lastIndexOf("#");
348
+ if (exportNameStart === -1) return;
349
+ return {
350
+ id: value.slice(0, exportNameStart),
351
+ exportName: value.slice(exportNameStart + 1)
352
+ };
353
+ }
354
+ /**
355
+ * Parses an entry marker.
356
+ *
357
+ * @param marker Marker string to parse.
358
+ * @returns Parsed marker data, or `undefined` for invalid markers.
359
+ */
360
+ function parseEntryMarker(marker) {
361
+ if (!marker.startsWith(placeholderScheme)) return;
362
+ const id = marker.slice(6);
363
+ if (id === "" || id.includes("#")) return;
364
+ return { id };
365
+ }
366
+ //#endregion
367
+ //#region src/transforms.ts
368
+ const entryName = "entry";
369
+ const hydrateName = "hydrate";
370
+ const macroModuleIds = new Set(["#pudui/macros", "pudui/macros"]);
371
+ const macroNamesByImport = new Map([[entryName, "entry"], [hydrateName, "hydrate"]]);
372
+ /**
373
+ * Injects hydration macros into exported components in a `"use client"` module.
374
+ *
375
+ * The transform looks for exported component factories that create
376
+ * `new Component({ ... })` and appends `hydrate: hydrate()` when needed.
377
+ *
378
+ * @param code Module source code.
379
+ * @param id Stable module identifier used for parsing diagnostics.
380
+ * @returns Transform result, or `null` when the module does not need changes.
381
+ *
382
+ * @example
383
+ * ```ts
384
+ * const result = transformUseClient('"use client"; export function App() {}', "/src/app.tsx");
385
+ * ```
386
+ */
387
+ function transformUseClient(code, id) {
388
+ if (!code.includes("Component") || !code.includes("use client")) return null;
389
+ const program = parseProgram(code, id);
390
+ const directives = readModuleDirectives(program);
391
+ if (!directives.hasUseClient) return null;
392
+ const componentOptions = findUseClientComponents(program);
393
+ if (componentOptions.length === 0) return null;
394
+ const hydrateLocalName = uniqueIdentifier(program, hydrateName);
395
+ const transformed = new MagicString(code);
396
+ const hydrateImport = hydrateLocalName === hydrateName ? hydrateName : `${hydrateName} as ${hydrateLocalName}`;
397
+ transformed.appendLeft(directives.end, `\nimport { ${hydrateImport} } from "#pudui/macros";`);
398
+ for (const options of componentOptions) appendHydrateOption(code, transformed, options, hydrateLocalName);
399
+ return {
400
+ code: transformed.toString(),
401
+ componentOptions,
402
+ map: null
403
+ };
404
+ }
405
+ /**
406
+ * Replaces `hydrate()` and `entry()` macro calls with runtime metadata.
407
+ *
408
+ * This is the lower-level transform used by the Vite plugin. Applications
409
+ * usually import the macros from `pudui/macros` and let the plugin call this.
410
+ *
411
+ * @param code Module source code.
412
+ * @param id Stable module identifier used in hydration metadata.
413
+ * @param options Mode-specific transform options.
414
+ * @returns Transform result, or `null` when the module does not use macros.
415
+ */
416
+ function transformHydrate(code, id, options) {
417
+ if (!code.includes(hydrateName) && !code.includes(entryName)) return null;
418
+ const program = parseProgram(code, id);
419
+ const macroImports = findMacroImports(program);
420
+ const hydrateNames = new Set(macroImports.filter((macroImport) => macroImport.kind === "hydrate").map((macroImport) => macroImport.localName));
421
+ const entryNames = new Set(macroImports.filter((macroImport) => macroImport.kind === "entry").map((macroImport) => macroImport.localName));
422
+ if (hydrateNames.size === 0 && entryNames.size === 0) return null;
423
+ const hydrateCalls = findHydrateCalls(program, hydrateNames);
424
+ const entryCalls = findEntryCalls(program, entryNames);
425
+ if (hydrateCalls.length === 0 && entryCalls.length === 0) return null;
426
+ const transformed = new MagicString(code);
427
+ removeMacroImports(transformed, macroImports);
428
+ for (const call of hydrateCalls) transformed.update(call.start, call.end, replacementForHydrateCall(id, call.exportName, options));
429
+ for (const call of entryCalls) transformed.update(call.start, call.end, replacementForEntryCall(options));
430
+ return {
431
+ code: transformed.toString(),
432
+ entryCalls,
433
+ hydrateCalls,
434
+ map: null
435
+ };
436
+ }
437
+ /**
438
+ * Replaces build-time hydration marker calls with manifest-derived metadata.
439
+ *
440
+ * @param code Generated bundle code containing marker calls.
441
+ * @param resolveMarker Function that maps marker strings to replacement arrays.
442
+ * @returns Code with resolved marker calls replaced by JSON arrays.
443
+ */
444
+ function replaceHydrateMarkers(code, resolveMarker) {
445
+ if (!code.includes("__PUDUI_HYDRATE__") && !code.includes("__PUDUI_ENTRY__")) return code;
446
+ const program = parseProgram(code, "hydrate-marker.js");
447
+ const transformed = new MagicString(code);
448
+ walk(program, (node) => {
449
+ if (!isMarkerCall(node, "__PUDUI_HYDRATE__") && !isMarkerCall(node, "__PUDUI_ENTRY__")) return;
450
+ const replacement = resolveMarker(readStringLiteral(readNodeArray(node.arguments)[0]));
451
+ if (replacement !== void 0) transformed.update(node.start, node.end, JSON.stringify(replacement));
452
+ });
453
+ return transformed.toString();
454
+ }
455
+ /**
456
+ * Quickly checks whether source may contain Pudui macro calls.
457
+ *
458
+ * @param code Module source code.
459
+ * @returns `true` when the source should be parsed for `hydrate()` or `entry()` macros.
460
+ */
461
+ function shouldTransformHydrate(code) {
462
+ return code.includes("pudui/macros") && (code.includes(hydrateName) || code.includes(entryName));
463
+ }
464
+ /**
465
+ * Quickly checks whether source may contain `"use client"` components.
466
+ *
467
+ * @param code Module source code.
468
+ * @returns `true` when the source should be parsed by {@link transformUseClient}.
469
+ */
470
+ function shouldTransformUseClient(code) {
471
+ return code.includes("use client") && code.includes("Component");
472
+ }
473
+ function readModuleDirectives(program) {
474
+ let end = 0;
475
+ let hasUseClient = false;
476
+ for (const statement of getBody(program)) {
477
+ if (statement.type !== "ExpressionStatement") break;
478
+ const expression = readOptionalNode(statement.expression);
479
+ if (expression?.type !== "Literal" || typeof expression.value !== "string") break;
480
+ end = statement.end;
481
+ hasUseClient ||= expression.value === "use client";
482
+ }
483
+ return {
484
+ end,
485
+ hasUseClient
486
+ };
487
+ }
488
+ function findUseClientComponents(program) {
489
+ const exportedFunctions = findExportedFunctions(program);
490
+ const componentOptions = [];
491
+ for (const statement of getBody(program)) for (const functionNode of collectTopLevelFunctionNodes(statement)) {
492
+ if (!exportedFunctions.has(functionNode)) continue;
493
+ componentOptions.push(...collectComponentOptions(functionNode));
494
+ }
495
+ return componentOptions;
496
+ }
497
+ function collectTopLevelFunctionNodes(statement) {
498
+ const declaration = statement.type === "ExportNamedDeclaration" || statement.type === "ExportDefaultDeclaration" ? readOptionalNode(statement.declaration) : statement;
499
+ if (declaration === void 0) return [];
500
+ if (isFunctionLike(declaration)) return [declaration];
501
+ if (declaration.type !== "VariableDeclaration") return [];
502
+ const functions = [];
503
+ for (const declarator of readNodeArray(declaration.declarations)) {
504
+ const init = readOptionalNode(declarator.init);
505
+ if (init !== void 0 && isFunctionLike(init)) functions.push(init);
506
+ }
507
+ return functions;
508
+ }
509
+ function collectComponentOptions(functionNode) {
510
+ const body = readOptionalNode(functionNode.body);
511
+ if (body?.type !== "BlockStatement") return [];
512
+ const componentOptions = [];
513
+ visitComponentFactoryBody(body, (node) => {
514
+ if (node.type !== "NewExpression") return;
515
+ const callee = readOptionalNode(node.callee);
516
+ if (callee?.type !== "Identifier" || readIdentifierName(callee) !== "Component") return;
517
+ const options = readNodeArray(node.arguments)[0];
518
+ if (options?.type === "ObjectExpression" && !hasObjectProperty(options, "hydrate")) componentOptions.push(options);
519
+ });
520
+ return componentOptions;
521
+ }
522
+ function visitComponentFactoryBody(node, enter) {
523
+ walkSkippingNestedFunctions(node, enter);
524
+ }
525
+ function hasObjectProperty(object, name) {
526
+ for (const property of readNodeArray(object.properties)) {
527
+ if (property.type !== "Property") continue;
528
+ const key = readOptionalNode(property.key);
529
+ if (!(property.computed === true) && key?.type === "Identifier" && readIdentifierName(key) === name) return true;
530
+ if (key?.type === "Literal" && key.value === name) return true;
531
+ }
532
+ return false;
533
+ }
534
+ function uniqueIdentifier(program, baseName) {
535
+ const names = /* @__PURE__ */ new Set();
536
+ walk(program, (node) => {
537
+ if (node.type === "Identifier") names.add(readIdentifierName(node));
538
+ });
539
+ if (!names.has(baseName)) return baseName;
540
+ let index = 2;
541
+ while (names.has(`${baseName}${index}`)) index++;
542
+ return `${baseName}${index}`;
543
+ }
544
+ function appendHydrateOption(code, transformed, options, hydrateLocalName) {
545
+ const lastProperty = readNodeArray(options.properties).at(-1);
546
+ if (lastProperty === void 0) {
547
+ transformed.appendLeft(options.end - 1, `hydrate: ${hydrateLocalName}()`);
548
+ return;
549
+ }
550
+ const hasTrailingComma = code.slice(lastProperty.end, options.end - 1).includes(",");
551
+ transformed.appendLeft(options.end - 1, `${hasTrailingComma ? "" : ","} hydrate: ${hydrateLocalName}()`);
552
+ }
553
+ function replacementForHydrateCall(id, exportName, options) {
554
+ if (options.mode === "client") return "undefined";
555
+ if (options.mode === "build") return `${hydrateMarkerName}(${JSON.stringify(options.createHydrateMarker(id, exportName))})`;
556
+ return JSON.stringify([
557
+ options.modulePath,
558
+ exportName,
559
+ [],
560
+ []
561
+ ]);
562
+ }
563
+ function replacementForEntryCall(options) {
564
+ if (options.mode === "client") return "[]";
565
+ if (options.mode === "build") return `${entryMarkerName}(${JSON.stringify(options.createEntryMarker(options.browserEntry))})`;
566
+ return `[${JSON.stringify(browserEntryPath(options))},[],${options.entryStylesExpression ?? "[]"}]`;
567
+ }
568
+ function browserEntryPath(options) {
569
+ if (options.mode !== "dev") return "";
570
+ return options.browserEntryPath ?? devBrowserEntryPath(options.browserEntry ?? "", void 0);
571
+ }
572
+ function findMacroImports(program) {
573
+ const imports = [];
574
+ for (const statement of getBody(program)) {
575
+ if (statement.type !== "ImportDeclaration" || !macroModuleIds.has(readLiteralValue(statement.source))) continue;
576
+ let specifierTotal = 0;
577
+ for (const specifier of readNodeArray(statement.specifiers)) if (specifier.type === "ImportSpecifier") specifierTotal++;
578
+ for (const specifier of readNodeArray(statement.specifiers)) {
579
+ if (specifier.type !== "ImportSpecifier" || !macroNamesByImport.has(readIdentifierName(specifier.imported))) continue;
580
+ imports.push({
581
+ kind: macroNamesByImport.get(readIdentifierName(specifier.imported)),
582
+ importEnd: statement.end,
583
+ importStart: statement.start,
584
+ localName: readIdentifierName(specifier.local),
585
+ specifierEnd: specifier.end,
586
+ specifierStart: specifier.start,
587
+ specifierTotal
588
+ });
589
+ }
590
+ }
591
+ return imports;
592
+ }
593
+ function removeMacroImports(code, macroImports) {
594
+ const importsByDeclaration = /* @__PURE__ */ new Map();
595
+ for (const macroImport of macroImports) {
596
+ const key = `${macroImport.importStart}:${macroImport.importEnd}`;
597
+ importsByDeclaration.set(key, [...importsByDeclaration.get(key) ?? [], macroImport]);
598
+ }
599
+ for (const imports of importsByDeclaration.values()) {
600
+ const firstImport = imports[0];
601
+ if (imports.length === firstImport.specifierTotal) {
602
+ code.remove(firstImport.importStart, firstImport.importEnd);
603
+ continue;
604
+ }
605
+ for (const macroImport of imports) code.remove(macroImport.specifierStart, macroImport.specifierEnd);
606
+ }
607
+ }
608
+ function findHydrateCalls(program, macroNames) {
609
+ const exportedFunctions = findExportedFunctions(program);
610
+ const functionStack = [];
611
+ const calls = [];
612
+ walk(program, (node) => {
613
+ if (isFunctionLike(node)) functionStack.push(exportedFunctions.get(node));
614
+ if (!isHydrateCall(node, macroNames)) return;
615
+ const exportName = functionStack.at(-1);
616
+ if (exportName === void 0) throw new Error("hydrate() must be called inside an exported component function.");
617
+ calls.push({
618
+ start: node.start,
619
+ end: node.end,
620
+ exportName
621
+ });
622
+ }, (node) => {
623
+ if (isFunctionLike(node)) functionStack.pop();
624
+ });
625
+ return calls;
626
+ }
627
+ function findEntryCalls(program, macroNames) {
628
+ const calls = [];
629
+ walk(program, (node) => {
630
+ if (!isEntryCall(node, macroNames)) return;
631
+ calls.push({
632
+ start: node.start,
633
+ end: node.end
634
+ });
635
+ });
636
+ return calls;
637
+ }
638
+ function findExportedFunctions(program) {
639
+ const topLevelFunctions = /* @__PURE__ */ new Map();
640
+ const namedExports = /* @__PURE__ */ new Map();
641
+ const exportedFunctions = /* @__PURE__ */ new WeakMap();
642
+ for (const statement of getBody(program)) if (statement.type === "FunctionDeclaration") topLevelFunctions.set(readIdentifierName(statement.id), statement);
643
+ else if (statement.type === "VariableDeclaration") collectVariableFunctions(statement, topLevelFunctions);
644
+ else if (statement.type === "ExportNamedDeclaration") collectNamedExport(statement, topLevelFunctions, namedExports, exportedFunctions);
645
+ else if (statement.type === "ExportDefaultDeclaration") collectDefaultExport(statement, topLevelFunctions, namedExports, exportedFunctions);
646
+ for (const [localName, exportName] of namedExports) {
647
+ const functionNode = topLevelFunctions.get(localName);
648
+ if (functionNode !== void 0) exportedFunctions.set(functionNode, exportName);
649
+ }
650
+ return exportedFunctions;
651
+ }
652
+ function collectNamedExport(statement, topLevelFunctions, namedExports, exportedFunctions) {
653
+ const declaration = readOptionalNode(statement.declaration);
654
+ if (declaration !== void 0) {
655
+ if (declaration.type === "FunctionDeclaration") exportedFunctions.set(declaration, readIdentifierName(declaration.id));
656
+ else if (declaration.type === "VariableDeclaration") collectVariableFunctions(declaration, topLevelFunctions, exportedFunctions);
657
+ return;
658
+ }
659
+ if (statement.source !== null) return;
660
+ for (const specifier of readNodeArray(statement.specifiers)) if (specifier.type === "ExportSpecifier") namedExports.set(readIdentifierName(specifier.local), readIdentifierName(specifier.exported));
661
+ }
662
+ function collectDefaultExport(statement, topLevelFunctions, namedExports, exportedFunctions) {
663
+ const declaration = readOptionalNode(statement.declaration);
664
+ if (declaration === void 0) return;
665
+ if (isFunctionLike(declaration)) exportedFunctions.set(declaration, "default");
666
+ else if (declaration.type === "Identifier") namedExports.set(readIdentifierName(declaration), "default");
667
+ else if (declaration.type === "VariableDeclaration") collectVariableFunctions(declaration, topLevelFunctions, exportedFunctions, "default");
668
+ }
669
+ function collectVariableFunctions(declaration, topLevelFunctions, exportedFunctions, exportName) {
670
+ for (const declarator of readNodeArray(declaration.declarations)) {
671
+ const id = readOptionalNode(declarator.id);
672
+ const init = readOptionalNode(declarator.init);
673
+ if (id?.type === "Identifier" && init !== void 0 && isFunctionLike(init)) {
674
+ const localName = readIdentifierName(id);
675
+ topLevelFunctions.set(localName, init);
676
+ exportedFunctions?.set(init, exportName ?? localName);
677
+ }
678
+ }
679
+ }
680
+ function isHydrateCall(node, macroNames) {
681
+ if (node.type !== "CallExpression") return false;
682
+ if (readNodeArray(node.arguments).length > 0) {
683
+ const callee = readOptionalNode(node.callee);
684
+ if (callee?.type === "Identifier" && macroNames.has(readIdentifierName(callee))) throw new Error("hydrate() does not accept arguments.");
685
+ return false;
686
+ }
687
+ const callee = readOptionalNode(node.callee);
688
+ return callee?.type === "Identifier" && macroNames.has(readIdentifierName(callee));
689
+ }
690
+ function isEntryCall(node, macroNames) {
691
+ if (node.type !== "CallExpression") return false;
692
+ if (readNodeArray(node.arguments).length > 0) {
693
+ const callee = readOptionalNode(node.callee);
694
+ if (callee?.type === "Identifier" && macroNames.has(readIdentifierName(callee))) throw new Error("entry() does not accept arguments.");
695
+ return false;
696
+ }
697
+ const callee = readOptionalNode(node.callee);
698
+ return callee?.type === "Identifier" && macroNames.has(readIdentifierName(callee));
699
+ }
700
+ function isMarkerCall(node, name) {
701
+ if (node.type !== "CallExpression") return false;
702
+ const callee = readOptionalNode(node.callee);
703
+ const args = readNodeArray(node.arguments);
704
+ return callee?.type === "Identifier" && readIdentifierName(callee) === name && args.length === 1;
705
+ }
706
+ //#endregion
707
+ export { readNodeArray as C, walkWithScopes as D, walkSkippingNestedFunctions as E, normalizePath as O, readLiteralValue as S, walk as T, shouldTransformModule as _, transformUseClient as a, parseProgram as b, entryMarkerName as c, parseHydrateMarker as d, cleanModuleId as f, relativeToRoot as g, publicAssetPath as h, transformHydrate as i, pathExtname as k, hydrateMarkerName as l, devModulePath as m, shouldTransformHydrate as n, createEntryMarker as o, devBrowserEntryPath as p, shouldTransformUseClient as r, createHydrateMarker as s, replaceHydrateMarkers as t, parseEntryMarker as u, getBody as v, readOptionalNode as w, readIdentifierName as x, isFunctionLike as y };