@aerobuilt/core 0.3.1 → 0.3.2

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.
@@ -26,6 +26,65 @@ function isDirectiveAttr(attrName, config = defaultConfig) {
26
26
  return prefixes.some((p) => attrName.startsWith(p));
27
27
  }
28
28
 
29
+ //#endregion
30
+ //#region src/compiler/constants.ts
31
+ /**
32
+ * Shared constants for the Aero compiler (parser, codegen, helpers).
33
+ *
34
+ * @remarks
35
+ * Attribute names are used with optional `data-` prefix (e.g. `data-each`). Script taxonomy uses
36
+ * `is:build`, `is:inline`, `is:blocking`; default scripts are treated as client (virtual module).
37
+ */
38
+ /** Prefix for data attributes (e.g. `data-each` → ATTR_PREFIX + ATTR_EACH). */
39
+ const ATTR_PREFIX = "data-";
40
+ /** Attribute for spreading props onto a component: `data-props` or `data-props="{ ... }"`. */
41
+ const ATTR_PROPS = "props";
42
+ /** Attribute for iteration: `data-each="{ item in items }"`. */
43
+ const ATTR_EACH = "each";
44
+ const ATTR_IF = "if";
45
+ const ATTR_ELSE_IF = "else-if";
46
+ const ATTR_ELSE = "else";
47
+ /** Slot name (on `<slot>` or content). */
48
+ const ATTR_NAME = "name";
49
+ const ATTR_SLOT = "slot";
50
+ /** Script runs at build time; extracted and becomes render function body. */
51
+ const ATTR_IS_BUILD = "is:build";
52
+ /** Script left in template in place; not extracted. */
53
+ const ATTR_IS_INLINE = "is:inline";
54
+ /** Script hoisted to head; extracted. */
55
+ const ATTR_IS_BLOCKING = "is:blocking";
56
+ /** Script/style receives data from template: `pass:data="{ config }"` or `pass:data="{ ...theme }"`. */
57
+ const ATTR_PASS_DATA = "pass:data";
58
+ /** Script external source (HTML attribute). */
59
+ const ATTR_SRC = "src";
60
+ const TAG_SLOT = "slot";
61
+ /** Default slot name when no name is given. */
62
+ const SLOT_NAME_DEFAULT = "default";
63
+ /** Matches `item in items` for data-each (captures: loop variable, iterable expression). */
64
+ const EACH_REGEX = /^(\w+)\s+in\s+(.+)$/;
65
+ /** Matches tag names ending with `-component` or `-layout`. */
66
+ const COMPONENT_SUFFIX_REGEX = /-(component|layout)$/;
67
+ /** Self-closing tag: `<tag ... />`. */
68
+ const SELF_CLOSING_TAG_REGEX = /<([a-z0-9-]+)([^>]*?)\/>/gi;
69
+ const SELF_CLOSING_TAIL_REGEX = /\/>$/;
70
+ /** HTML void elements that have no closing tag. */
71
+ const VOID_TAGS = new Set([
72
+ "area",
73
+ "base",
74
+ "br",
75
+ "col",
76
+ "embed",
77
+ "hr",
78
+ "img",
79
+ "input",
80
+ "link",
81
+ "meta",
82
+ "param",
83
+ "source",
84
+ "track",
85
+ "wbr"
86
+ ]);
87
+
29
88
  //#endregion
30
89
  //#region src/compiler/build-script-analysis.ts
31
90
  /**
@@ -190,4 +249,4 @@ function analyzeBuildScriptForEditor(script) {
190
249
  }
191
250
 
192
251
  //#endregion
193
- export { compileInterpolationFromSegments as a, isDirectiveAttr as i, analyzeBuildScriptForEditor as n, tokenizeCurlyInterpolation as o, DEFAULT_DIRECTIVE_PREFIXES as r, analyzeBuildScript as t };
252
+ export { DEFAULT_DIRECTIVE_PREFIXES as C, tokenizeCurlyInterpolation as E, VOID_TAGS as S, compileInterpolationFromSegments as T, EACH_REGEX as _, ATTR_ELSE_IF as a, SLOT_NAME_DEFAULT as b, ATTR_IS_BUILD as c, ATTR_PASS_DATA as d, ATTR_PREFIX as f, COMPONENT_SUFFIX_REGEX as g, ATTR_SRC as h, ATTR_ELSE as i, ATTR_IS_INLINE as l, ATTR_SLOT as m, analyzeBuildScriptForEditor as n, ATTR_IF as o, ATTR_PROPS as p, ATTR_EACH as r, ATTR_IS_BLOCKING as s, analyzeBuildScript as t, ATTR_NAME as u, SELF_CLOSING_TAG_REGEX as v, isDirectiveAttr as w, TAG_SLOT as x, SELF_CLOSING_TAIL_REGEX as y };
@@ -3,8 +3,7 @@ import { InterpolationSegment, LiteralSegment, Segment, TokenizeOptions, compile
3
3
  //#region src/compiler/directive-attributes.d.ts
4
4
  /**
5
5
  * Classifier for directive attributes (Alpine.js, HTMX, Vue, etc.) that should
6
- * skip { } interpolation in the compiler. Replaces ALPINE_ATTR_REGEX with a
7
- * declarative list for clearer semantics and easier extension.
6
+ * skip { } interpolation in the compiler.
8
7
  *
9
8
  * @packageDocumentation
10
9
  */
@@ -30,6 +29,10 @@ declare const DEFAULT_DIRECTIVE_PREFIXES: string[];
30
29
  */
31
30
  declare function isDirectiveAttr(attrName: string, config?: DirectiveAttrConfig): boolean;
32
31
  //#endregion
32
+ //#region src/compiler/constants.d.ts
33
+ /** Matches tag names ending with `-component` or `-layout`. */
34
+ declare const COMPONENT_SUFFIX_REGEX: RegExp;
35
+ //#endregion
33
36
  //#region src/compiler/build-script-analysis.d.ts
34
37
  /**
35
38
  * AST-based analysis of Aero build scripts: extract imports and getStaticPaths export.
@@ -71,4 +74,4 @@ interface BuildScriptAnalysisForEditorResult {
71
74
  */
72
75
  declare function analyzeBuildScriptForEditor(script: string): BuildScriptAnalysisForEditorResult;
73
76
  //#endregion
74
- export { type BuildScriptAnalysisForEditorResult, type BuildScriptImportForEditor, DEFAULT_DIRECTIVE_PREFIXES, type DirectiveAttrConfig, type InterpolationSegment, type LiteralSegment, type Segment, type TokenizeOptions, analyzeBuildScriptForEditor, compileInterpolationFromSegments, isDirectiveAttr, tokenizeCurlyInterpolation };
77
+ export { type BuildScriptAnalysisForEditorResult, type BuildScriptImportForEditor, COMPONENT_SUFFIX_REGEX, DEFAULT_DIRECTIVE_PREFIXES, type DirectiveAttrConfig, type InterpolationSegment, type LiteralSegment, type Segment, type TokenizeOptions, analyzeBuildScriptForEditor, compileInterpolationFromSegments, isDirectiveAttr, tokenizeCurlyInterpolation };
@@ -1,3 +1,3 @@
1
- import { a as compileInterpolationFromSegments, i as isDirectiveAttr, n as analyzeBuildScriptForEditor, o as tokenizeCurlyInterpolation, r as DEFAULT_DIRECTIVE_PREFIXES } from "./build-script-analysis-Bd9EyItC.mjs";
1
+ import { C as DEFAULT_DIRECTIVE_PREFIXES, E as tokenizeCurlyInterpolation, T as compileInterpolationFromSegments, g as COMPONENT_SUFFIX_REGEX, n as analyzeBuildScriptForEditor, w as isDirectiveAttr } from "./build-script-analysis-Bll0Ujh4.mjs";
2
2
 
3
- export { DEFAULT_DIRECTIVE_PREFIXES, analyzeBuildScriptForEditor, compileInterpolationFromSegments, isDirectiveAttr, tokenizeCurlyInterpolation };
3
+ export { COMPONENT_SUFFIX_REGEX, DEFAULT_DIRECTIVE_PREFIXES, analyzeBuildScriptForEditor, compileInterpolationFromSegments, isDirectiveAttr, tokenizeCurlyInterpolation };
@@ -1,5 +1,5 @@
1
1
  import { a as isDynamicRoutePattern, i as expandRoutePattern, n as resolvePageName, o as toPosix, s as toPosixRelative, t as pagePathToKey } from "../routing-Bai79LCq.mjs";
2
- import { a as compileInterpolationFromSegments, i as isDirectiveAttr, o as tokenizeCurlyInterpolation, t as analyzeBuildScript } from "../build-script-analysis-Bd9EyItC.mjs";
2
+ import { E as tokenizeCurlyInterpolation, S as VOID_TAGS, T as compileInterpolationFromSegments, _ as EACH_REGEX, a as ATTR_ELSE_IF, b as SLOT_NAME_DEFAULT, c as ATTR_IS_BUILD, d as ATTR_PASS_DATA, f as ATTR_PREFIX, g as COMPONENT_SUFFIX_REGEX, h as ATTR_SRC, i as ATTR_ELSE, l as ATTR_IS_INLINE, m as ATTR_SLOT, o as ATTR_IF, p as ATTR_PROPS, r as ATTR_EACH, s as ATTR_IS_BLOCKING, t as analyzeBuildScript, u as ATTR_NAME, v as SELF_CLOSING_TAG_REGEX, w as isDirectiveAttr, x as TAG_SLOT, y as SELF_CLOSING_TAIL_REGEX } from "../build-script-analysis-Bll0Ujh4.mjs";
3
3
  import { loadTsconfigAliases, mergeWithDefaultAliases } from "../utils/aliases.mjs";
4
4
  import { redirectsToRouteRules } from "../utils/redirects.mjs";
5
5
  import { createRequire } from "node:module";
@@ -117,65 +117,6 @@ function resolveDirs(dirs) {
117
117
  };
118
118
  }
119
119
 
120
- //#endregion
121
- //#region src/compiler/constants.ts
122
- /**
123
- * Shared constants for the Aero compiler (parser, codegen, helpers).
124
- *
125
- * @remarks
126
- * Attribute names are used with optional `data-` prefix (e.g. `data-each`). Script taxonomy uses
127
- * `is:build`, `is:inline`, `is:blocking`; default scripts are treated as client (virtual module).
128
- */
129
- /** Prefix for data attributes (e.g. `data-each` → ATTR_PREFIX + ATTR_EACH). */
130
- const ATTR_PREFIX = "data-";
131
- /** Attribute for spreading props onto a component: `data-props` or `data-props="{ ... }"`. */
132
- const ATTR_PROPS = "props";
133
- /** Attribute for iteration: `data-each="{ item in items }"`. */
134
- const ATTR_EACH = "each";
135
- const ATTR_IF = "if";
136
- const ATTR_ELSE_IF = "else-if";
137
- const ATTR_ELSE = "else";
138
- /** Slot name (on `<slot>` or content). */
139
- const ATTR_NAME = "name";
140
- const ATTR_SLOT = "slot";
141
- /** Script runs at build time; extracted and becomes render function body. */
142
- const ATTR_IS_BUILD = "is:build";
143
- /** Script left in template in place; not extracted. */
144
- const ATTR_IS_INLINE = "is:inline";
145
- /** Script hoisted to head; extracted. */
146
- const ATTR_IS_BLOCKING = "is:blocking";
147
- /** Script/style receives data from template: `pass:data="{ config }"` or `pass:data="{ ...theme }"`. */
148
- const ATTR_PASS_DATA = "pass:data";
149
- /** Script external source (HTML attribute). */
150
- const ATTR_SRC = "src";
151
- const TAG_SLOT = "slot";
152
- /** Default slot name when no name is given. */
153
- const SLOT_NAME_DEFAULT = "default";
154
- /** Matches `item in items` for data-each (captures: loop variable, iterable expression). */
155
- const EACH_REGEX = /^(\w+)\s+in\s+(.+)$/;
156
- /** Matches tag names ending with `-component` or `-layout`. */
157
- const COMPONENT_SUFFIX_REGEX = /-(component|layout)$/;
158
- /** Self-closing tag: `<tag ... />`. */
159
- const SELF_CLOSING_TAG_REGEX = /<([a-z0-9-]+)([^>]*?)\/>/gi;
160
- const SELF_CLOSING_TAIL_REGEX = /\/>$/;
161
- /** HTML void elements that have no closing tag. */
162
- const VOID_TAGS = new Set([
163
- "area",
164
- "base",
165
- "br",
166
- "col",
167
- "embed",
168
- "hr",
169
- "img",
170
- "input",
171
- "link",
172
- "meta",
173
- "param",
174
- "source",
175
- "track",
176
- "wbr"
177
- ]);
178
-
179
120
  //#endregion
180
121
  //#region src/compiler/parser.ts
181
122
  /** Serialize element attributes to a string, excluding given names (case-insensitive). Values are XML-escaped. */
@@ -1085,6 +1026,109 @@ function compile(parsed, options) {
1085
1026
  });
1086
1027
  return importsCode + "\n" + renderFn;
1087
1028
  }
1029
+ /**
1030
+ * Compile an HTML template source into a JavaScript module string. Single entry for parse + compile.
1031
+ * When optional `parsed` is provided (e.g. after registering client scripts in the plugin), it is used to avoid parsing twice.
1032
+ *
1033
+ * @param htmlSource - Raw HTML template string.
1034
+ * @param options - CompileOptions (root, resolvePath, importer, optional script overrides).
1035
+ * @param parsed - Optional pre-parsed result; when provided, used instead of parsing htmlSource again.
1036
+ * @returns Module source (async render function + optional getStaticPaths).
1037
+ */
1038
+ function compileTemplate(htmlSource, options, parsed) {
1039
+ const p = parsed ?? parse(htmlSource);
1040
+ return compile(p, {
1041
+ ...options,
1042
+ clientScripts: options.clientScripts ?? p.clientScripts,
1043
+ inlineScripts: options.inlineScripts ?? p.inlineScripts,
1044
+ blockingScripts: options.blockingScripts ?? p.blockingScripts
1045
+ });
1046
+ }
1047
+
1048
+ //#endregion
1049
+ //#region src/vite/rewrite.ts
1050
+ /** Route path to output file path (e.g. '' → index.html, about → about/index.html). */
1051
+ function toOutputFile(routePath) {
1052
+ if (routePath === "") return "index.html";
1053
+ if (routePath === "404") return "404.html";
1054
+ return toPosix(path$1.join(routePath, "index.html"));
1055
+ }
1056
+ /** Relative path from fromDir to targetPath, always starting with ./ when non-empty. */
1057
+ function normalizeRelativeLink(fromDir, targetPath) {
1058
+ const rel = path$1.posix.relative(fromDir, targetPath);
1059
+ if (!rel) return "./";
1060
+ if (rel.startsWith(".")) return rel;
1061
+ return `./${rel}`;
1062
+ }
1063
+ /** Relative path to a route (directory index); appends trailing slash for non-root routes. */
1064
+ function normalizeRelativeRouteLink(fromDir, routePath) {
1065
+ const targetDir = routePath === "" ? "" : routePath;
1066
+ const rel = path$1.posix.relative(fromDir, targetDir);
1067
+ let res = !rel ? "./" : rel.startsWith(".") ? rel : `./${rel}`;
1068
+ if (routePath !== "" && routePath !== "404" && !res.endsWith("/")) res += "/";
1069
+ return res;
1070
+ }
1071
+ function normalizeRoutePathFromHref(value) {
1072
+ if (value === "/") return "";
1073
+ return value.replace(/^\/+/, "").replace(/\/+$/, "");
1074
+ }
1075
+ function isSkippableUrl$1(value) {
1076
+ if (!value) return true;
1077
+ return SKIP_PROTOCOL_REGEX.test(value);
1078
+ }
1079
+ const ASSET_IMAGE_EXT = /\.(jpg|jpeg|png|gif|webp|svg|ico)(\?|$)/i;
1080
+ /** Rewrite one absolute URL to dist-relative using manifest and route set; leaves API and external URLs unchanged. */
1081
+ function rewriteAbsoluteUrl(value, fromDir, manifest, routeSet, apiPrefix = DEFAULT_API_PREFIX) {
1082
+ if (value.startsWith(apiPrefix)) return value;
1083
+ const noQuery = value.split(/[?#]/)[0] || value;
1084
+ const suffix = value.slice(noQuery.length);
1085
+ const manifestKey = noQuery.replace(/^\//, "");
1086
+ let manifestEntry = manifest[noQuery] ?? manifest[manifestKey];
1087
+ if (!manifestEntry && noQuery.startsWith("assets/")) {
1088
+ const entry = Object.values(manifest).find((e) => e?.file === noQuery || e?.file === manifestKey);
1089
+ if (entry) manifestEntry = entry;
1090
+ }
1091
+ if (manifestEntry?.file) return normalizeRelativeLink(fromDir, manifestEntry.assets?.find((a) => ASSET_IMAGE_EXT.test(a)) ?? manifestEntry.file) + suffix;
1092
+ if (noQuery.startsWith("/assets/")) return normalizeRelativeLink(fromDir, noQuery.replace(/^\//, "")) + suffix;
1093
+ const route = normalizeRoutePathFromHref(noQuery);
1094
+ if (routeSet.has(route) || route === "") return (route === "404" ? normalizeRelativeLink(fromDir, toOutputFile(route)) : normalizeRelativeRouteLink(fromDir, route)) + suffix;
1095
+ return normalizeRelativeLink(fromDir, noQuery.replace(/^\//, "")) + suffix;
1096
+ }
1097
+ /** Rewrite script src (virtual client → hashed asset) and LINK_ATTRS in rendered HTML; add doctype. */
1098
+ function rewriteRenderedHtml(html, outputFile, manifest, routeSet, apiPrefix = DEFAULT_API_PREFIX) {
1099
+ const fromDir = path$1.posix.dirname(outputFile);
1100
+ const { document } = parseHTML(html);
1101
+ for (const script of Array.from(document.querySelectorAll("script[src]"))) {
1102
+ const src = script.getAttribute("src") || "";
1103
+ if (src.startsWith(CLIENT_SCRIPT_PREFIX)) {
1104
+ const newSrc = rewriteAbsoluteUrl(src, fromDir, manifest, routeSet, apiPrefix);
1105
+ script.setAttribute("src", newSrc);
1106
+ script.setAttribute("type", "module");
1107
+ script.removeAttribute("defer");
1108
+ continue;
1109
+ }
1110
+ if (script.getAttribute("type") === "module") script.removeAttribute("defer");
1111
+ }
1112
+ for (const el of Array.from(document.querySelectorAll("*"))) for (const attrName of LINK_ATTRS) {
1113
+ if (!el.hasAttribute(attrName)) continue;
1114
+ const current = (el.getAttribute(attrName) || "").trim();
1115
+ if (!current || isSkippableUrl$1(current)) continue;
1116
+ if (!current.startsWith("/")) continue;
1117
+ el.setAttribute(attrName, rewriteAbsoluteUrl(current, fromDir, manifest, routeSet, apiPrefix));
1118
+ }
1119
+ const htmlTag = document.documentElement;
1120
+ if (htmlTag) return addDoctype(htmlTag.outerHTML);
1121
+ return addDoctype(document.toString());
1122
+ }
1123
+ /** Prepend `<!doctype html>` if missing. */
1124
+ function addDoctype(html) {
1125
+ return /^\s*<!doctype\s+html/i.test(html) ? html : `<!doctype html>\n${html}`;
1126
+ }
1127
+ function readManifest(distDir) {
1128
+ const manifestPath = path$1.join(distDir, ".vite", "manifest.json");
1129
+ if (!fs.existsSync(manifestPath)) return {};
1130
+ return JSON.parse(fs.readFileSync(manifestPath, "utf-8"));
1131
+ }
1088
1132
 
1089
1133
  //#endregion
1090
1134
  //#region src/vite/build.ts
@@ -1132,12 +1176,6 @@ function toRouteFromPageName(pageName) {
1132
1176
  if (pageName.endsWith("/index")) return pageName.slice(0, -6);
1133
1177
  return pageName;
1134
1178
  }
1135
- /** Route path to output file path (e.g. '' → index.html, about → about/index.html). */
1136
- function toOutputFile(routePath) {
1137
- if (routePath === "") return "index.html";
1138
- if (routePath === "404") return "404.html";
1139
- return toPosix(path$1.join(routePath, "index.html"));
1140
- }
1141
1179
  /**
1142
1180
  * Generate sitemap.xml from route paths. Only called when site URL is set.
1143
1181
  * Excludes 404. Writes to distDir/sitemap.xml.
@@ -1152,34 +1190,15 @@ function writeSitemap(routePaths, site, distDir) {
1152
1190
  function escapeXml(s) {
1153
1191
  return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
1154
1192
  }
1155
- /** Relative path from fromDir to targetPath, always starting with ./ when non-empty. */
1156
- function normalizeRelativeLink(fromDir, targetPath) {
1157
- const rel = path$1.posix.relative(fromDir, targetPath);
1158
- if (!rel) return "./";
1159
- if (rel.startsWith(".")) return rel;
1160
- return `./${rel}`;
1161
- }
1162
- /** Relative path to a route (directory index); appends trailing slash for non-root routes. */
1163
- function normalizeRelativeRouteLink(fromDir, routePath) {
1164
- const targetDir = routePath === "" ? "" : routePath;
1165
- const rel = path$1.posix.relative(fromDir, targetDir);
1166
- let res = !rel ? "./" : rel.startsWith(".") ? rel : `./${rel}`;
1167
- if (routePath !== "" && routePath !== "404" && !res.endsWith("/")) res += "/";
1168
- return res;
1169
- }
1170
- function normalizeRoutePathFromHref(value) {
1171
- if (value === "/") return "";
1172
- return value.replace(/^\/+/, "").replace(/\/+$/, "");
1193
+ /** Root-relative path for manifest key (posix). */
1194
+ function toManifestKey(root, filePath) {
1195
+ return toPosixRelative(filePath, root);
1173
1196
  }
1174
1197
  /** True if URL is empty or matches SKIP_PROTOCOL_REGEX (external, hash, etc.). */
1175
1198
  function isSkippableUrl(value) {
1176
1199
  if (!value) return true;
1177
1200
  return SKIP_PROTOCOL_REGEX.test(value);
1178
1201
  }
1179
- /** Root-relative path for manifest key (posix). */
1180
- function toManifestKey(root, filePath) {
1181
- return toPosixRelative(filePath, root);
1182
- }
1183
1202
  /** Resolve script/link src or href to absolute path; returns null for external/skippable or unresolvable. */
1184
1203
  function resolveTemplateAssetPath(rawValue, templateFile, root, resolvePath) {
1185
1204
  if (!rawValue || isSkippableUrl(rawValue)) return null;
@@ -1299,60 +1318,6 @@ function walkFiles(dir) {
1299
1318
  }
1300
1319
  return files;
1301
1320
  }
1302
- /** Prepend `<!doctype html>` if missing. */
1303
- function addDoctype(html) {
1304
- return /^\s*<!doctype\s+html/i.test(html) ? html : `<!doctype html>\n${html}`;
1305
- }
1306
- /** Image extensions: when a manifest entry's .file is a .js chunk but .assets lists the real image, use it. */
1307
- const ASSET_IMAGE_EXT = /\.(jpg|jpeg|png|gif|webp|svg|ico)(\?|$)/i;
1308
- /** Rewrite one absolute URL to dist-relative using manifest and route set; leaves API and external URLs unchanged. */
1309
- function rewriteAbsoluteUrl(value, fromDir, manifest, routeSet, apiPrefix = DEFAULT_API_PREFIX) {
1310
- if (value.startsWith(apiPrefix)) return value;
1311
- const noQuery = value.split(/[?#]/)[0] || value;
1312
- const suffix = value.slice(noQuery.length);
1313
- const manifestKey = noQuery.replace(/^\//, "");
1314
- let manifestEntry = manifest[noQuery] ?? manifest[manifestKey];
1315
- if (!manifestEntry && noQuery.startsWith("assets/")) {
1316
- const entry = Object.values(manifest).find((e) => e?.file === noQuery || e?.file === manifestKey);
1317
- if (entry) manifestEntry = entry;
1318
- }
1319
- if (manifestEntry?.file) return normalizeRelativeLink(fromDir, manifestEntry.assets?.find((a) => ASSET_IMAGE_EXT.test(a)) ?? manifestEntry.file) + suffix;
1320
- if (noQuery.startsWith("/assets/")) return normalizeRelativeLink(fromDir, noQuery.replace(/^\//, "")) + suffix;
1321
- const route = normalizeRoutePathFromHref(noQuery);
1322
- if (routeSet.has(route) || route === "") return (route === "404" ? normalizeRelativeLink(fromDir, toOutputFile(route)) : normalizeRelativeRouteLink(fromDir, route)) + suffix;
1323
- return normalizeRelativeLink(fromDir, noQuery.replace(/^\//, "")) + suffix;
1324
- }
1325
- /** Rewrite script src (virtual client → hashed asset) and LINK_ATTRS in rendered HTML; add doctype. */
1326
- function rewriteRenderedHtml(html, outputFile, manifest, routeSet, apiPrefix = DEFAULT_API_PREFIX) {
1327
- const fromDir = path$1.posix.dirname(outputFile);
1328
- const { document } = parseHTML(html);
1329
- for (const script of Array.from(document.querySelectorAll("script[src]"))) {
1330
- const src = script.getAttribute("src") || "";
1331
- if (src.startsWith(CLIENT_SCRIPT_PREFIX)) {
1332
- const newSrc = rewriteAbsoluteUrl(src, fromDir, manifest, routeSet, apiPrefix);
1333
- script.setAttribute("src", newSrc);
1334
- script.setAttribute("type", "module");
1335
- script.removeAttribute("defer");
1336
- continue;
1337
- }
1338
- if (script.getAttribute("type") === "module") script.removeAttribute("defer");
1339
- }
1340
- for (const el of Array.from(document.querySelectorAll("*"))) for (const attrName of LINK_ATTRS) {
1341
- if (!el.hasAttribute(attrName)) continue;
1342
- const current = (el.getAttribute(attrName) || "").trim();
1343
- if (!current || isSkippableUrl(current)) continue;
1344
- if (!current.startsWith("/")) continue;
1345
- el.setAttribute(attrName, rewriteAbsoluteUrl(current, fromDir, manifest, routeSet, apiPrefix));
1346
- }
1347
- const htmlTag = document.documentElement;
1348
- if (htmlTag) return addDoctype(htmlTag.outerHTML);
1349
- return addDoctype(document.toString());
1350
- }
1351
- function readManifest(distDir) {
1352
- const manifestPath = path$1.join(distDir, ".vite", "manifest.json");
1353
- if (!fs.existsSync(manifestPath)) return {};
1354
- return JSON.parse(fs.readFileSync(manifestPath, "utf-8"));
1355
- }
1356
1321
  /**
1357
1322
  * Render all static pages into outDir: discover pages, expand dynamic routes via getStaticPaths, run Vite in middleware mode, rewrite URLs, optionally minify.
1358
1323
  *
@@ -1665,19 +1630,20 @@ function createAeroVirtualsPlugin(state) {
1665
1630
  if (!state.config || !state.aliasResult) return null;
1666
1631
  this.addWatchFile(filePath);
1667
1632
  try {
1668
- const parsed = parse(readFileSync(filePath, "utf-8"));
1633
+ const code = readFileSync(filePath, "utf-8");
1634
+ const parsed = parse(code);
1669
1635
  const baseName = toPosixRelative(filePath, state.config.root).replace(/\.html$/i, "");
1670
1636
  registerClientScriptsToMap(parsed, baseName, state.clientScripts);
1671
1637
  for (let i = 0; i < parsed.clientScripts.length; i++) parsed.clientScripts[i].content = getClientScriptVirtualUrl(baseName, i, parsed.clientScripts.length);
1672
1638
  return {
1673
- code: compile(parsed, {
1639
+ code: compileTemplate(code, {
1674
1640
  root: state.config.root,
1675
1641
  clientScripts: parsed.clientScripts,
1676
1642
  blockingScripts: parsed.blockingScripts,
1677
1643
  inlineScripts: parsed.inlineScripts,
1678
1644
  resolvePath: state.aliasResult.resolve,
1679
1645
  importer: filePath
1680
- }),
1646
+ }, parsed),
1681
1647
  map: null
1682
1648
  };
1683
1649
  } catch {
@@ -1714,14 +1680,14 @@ function createAeroTransformPlugin(state) {
1714
1680
  for (let i = 0; i < parsed.clientScripts.length; i++) parsed.clientScripts[i].content = getClientScriptVirtualUrl(baseName, i, parsed.clientScripts.length);
1715
1681
  }
1716
1682
  return {
1717
- code: compile(parsed, {
1683
+ code: compileTemplate(code, {
1718
1684
  root: state.config.root,
1719
1685
  clientScripts: parsed.clientScripts,
1720
1686
  blockingScripts: parsed.blockingScripts,
1721
1687
  inlineScripts: parsed.inlineScripts,
1722
1688
  resolvePath: state.aliasResult.resolve,
1723
1689
  importer: id
1724
- }),
1690
+ }, parsed),
1725
1691
  map: null
1726
1692
  };
1727
1693
  } catch (err) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aerobuilt/core",
3
- "version": "0.3.1",
3
+ "version": "0.3.2",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "author": "Jamie Wilson",
@@ -60,7 +60,7 @@
60
60
  "sharp": "^0.34.5",
61
61
  "svgo": "^4.0.0",
62
62
  "vite-plugin-image-optimizer": "^2.0.3",
63
- "@aerobuilt/interpolation": "0.3.1"
63
+ "@aerobuilt/interpolation": "0.3.2"
64
64
  },
65
65
  "peerDependencies": {
66
66
  "vite": "^8.0.0-0"