meno-astro 0.1.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,1385 @@
1
+ import {
2
+ singularize
3
+ } from "../../chunks/chunk-LEMVUKVG.js";
4
+ import "../../chunks/chunk-ZYQNHI3W.js";
5
+
6
+ // lib/dialect/emit/emitContext.ts
7
+ function createEmitContext(width = 80) {
8
+ return {
9
+ components: /* @__PURE__ */ new Set(),
10
+ runtime: /* @__PURE__ */ new Set(),
11
+ runtimeComponents: /* @__PURE__ */ new Set(),
12
+ frontmatterConsts: [],
13
+ listCounter: 0,
14
+ hoistCounter: 0,
15
+ tagCounter: 0,
16
+ width
17
+ };
18
+ }
19
+ function needRuntime(ctx, name) {
20
+ ctx.runtime.add(name);
21
+ return name;
22
+ }
23
+ function needRuntimeComponent(ctx, name) {
24
+ ctx.runtimeComponents.add(name);
25
+ return name;
26
+ }
27
+
28
+ // lib/dialect/emit/serialize.ts
29
+ var DEFAULT_WIDTH = 80;
30
+ var INDENT_STEP = 2;
31
+ var IDENT_RE = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
32
+ function isIdentifier(key) {
33
+ return IDENT_RE.test(key);
34
+ }
35
+ function renderKey(key) {
36
+ return isIdentifier(key) ? key : JSON.stringify(key);
37
+ }
38
+ function renderString(value) {
39
+ return JSON.stringify(value);
40
+ }
41
+ function renderNumber(value) {
42
+ return Number.isFinite(value) ? String(value) : "null";
43
+ }
44
+ function definedEntries(obj) {
45
+ return Object.entries(obj).filter(([, v]) => v !== void 0);
46
+ }
47
+ function renderInline(value) {
48
+ if (value === null) return "null";
49
+ if (value === void 0) return "undefined";
50
+ switch (typeof value) {
51
+ case "string":
52
+ return renderString(value);
53
+ case "number":
54
+ return renderNumber(value);
55
+ case "boolean":
56
+ return String(value);
57
+ case "object": {
58
+ if (Array.isArray(value)) {
59
+ if (value.length === 0) return "[]";
60
+ return "[" + value.map(renderInline).join(", ") + "]";
61
+ }
62
+ const entries = definedEntries(value);
63
+ if (entries.length === 0) return "{}";
64
+ return "{ " + entries.map(([k, v]) => `${renderKey(k)}: ${renderInline(v)}`).join(", ") + " }";
65
+ }
66
+ default:
67
+ return "null";
68
+ }
69
+ }
70
+ function serializeLiteral(value, opts = {}) {
71
+ const width = opts.width ?? DEFAULT_WIDTH;
72
+ const baseIndent = opts.indent ?? 0;
73
+ const startCol = opts.startCol ?? baseIndent;
74
+ const render = (v, contIndent, startCol2) => {
75
+ if (v === null || typeof v !== "object") return renderInline(v);
76
+ const inline = renderInline(v);
77
+ if (startCol2 + inline.length <= width) return inline;
78
+ const pad2 = " ".repeat(contIndent + INDENT_STEP);
79
+ const closePad = " ".repeat(contIndent);
80
+ if (Array.isArray(v)) {
81
+ if (v.length === 0) return "[]";
82
+ const items = v.map(
83
+ (item) => pad2 + render(item, contIndent + INDENT_STEP, contIndent + INDENT_STEP)
84
+ );
85
+ return "[\n" + items.join(",\n") + "\n" + closePad + "]";
86
+ }
87
+ const entries = definedEntries(v);
88
+ if (entries.length === 0) return "{}";
89
+ const lines = entries.map(([k, val]) => {
90
+ const prefix = pad2 + renderKey(k) + ": ";
91
+ return prefix + render(val, contIndent + INDENT_STEP, prefix.length);
92
+ });
93
+ return "{\n" + lines.join(",\n") + "\n" + closePad + "}";
94
+ };
95
+ return render(value, baseIndent, startCol);
96
+ }
97
+
98
+ // lib/dialect/emit/emitNode.ts
99
+ var INDENT = 2;
100
+ function pad(n) {
101
+ return " ".repeat(n);
102
+ }
103
+ function shift(block, indent) {
104
+ const p = pad(indent);
105
+ return block.split("\n").map((line) => line.length ? p + line : line).join("\n");
106
+ }
107
+ var TEMPLATE_RE = /\{\{([\s\S]*?)\}\}/g;
108
+ function hasTemplate(s) {
109
+ return /\{\{[\s\S]*?\}\}/.test(s);
110
+ }
111
+ function escapeBacktick(s) {
112
+ return s.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$\{/g, "\\${");
113
+ }
114
+ function templateToExpr(s) {
115
+ const matches = [...s.matchAll(TEMPLATE_RE)];
116
+ if (matches.length === 1 && matches[0].index === 0 && matches[0][0].length === s.length) {
117
+ return matches[0][1].trim();
118
+ }
119
+ let out = "";
120
+ let last = 0;
121
+ for (const m of matches) {
122
+ out += escapeBacktick(s.slice(last, m.index));
123
+ out += "${" + m[1].trim() + "}";
124
+ last = m.index + m[0].length;
125
+ }
126
+ out += escapeBacktick(s.slice(last));
127
+ return "`" + out + "`";
128
+ }
129
+ function isI18nValue(v) {
130
+ return typeof v === "object" && v !== null && v._i18n === true;
131
+ }
132
+ function emitAttr(name, value, ctx) {
133
+ if (isI18nValue(value)) {
134
+ needRuntime(ctx, "i18n");
135
+ return `${name}={i18n(${serializeLiteral(value, { indent: INDENT, width: ctx.width })})}`;
136
+ }
137
+ if (typeof value === "string") {
138
+ if (hasTemplate(value)) return `${name}={${templateToExpr(value)}}`;
139
+ if (!value.includes('"') && !value.includes("\n")) return `${name}="${value}"`;
140
+ return `${name}={${JSON.stringify(value)}}`;
141
+ }
142
+ if (typeof value === "number" || typeof value === "boolean") {
143
+ return `${name}={${value}}`;
144
+ }
145
+ if (value === null || value === void 0) return `${name}={null}`;
146
+ return `${name}={${serializeLiteral(value, { indent: INDENT, width: ctx.width })}}`;
147
+ }
148
+ function emitClassAttr(node, ctx, extraMeta) {
149
+ const meta = { ...extraMeta };
150
+ if (node.interactiveStyles !== void 0) meta.interactive = node.interactiveStyles;
151
+ if (node.label !== void 0) meta.label = node.label;
152
+ if (node.generateElementClass !== void 0) meta.genClass = node.generateElementClass;
153
+ const hasStyle = hasStyleContent(node.style);
154
+ const hasMeta = Object.keys(meta).length > 0;
155
+ if (!hasStyle && !hasMeta) return null;
156
+ needRuntime(ctx, "style");
157
+ const styleLit = serializeLiteral(node.style ?? {}, { indent: INDENT, width: ctx.width });
158
+ if (!hasMeta) return `class={style(${styleLit})}`;
159
+ const metaLit = serializeLiteral(meta, { indent: INDENT, width: ctx.width });
160
+ return `class={style(${styleLit}, ${metaLit})}`;
161
+ }
162
+ function hasStyleContent(style) {
163
+ if (!style || typeof style !== "object") return false;
164
+ for (const v of Object.values(style)) {
165
+ if (v === void 0 || v === null) continue;
166
+ if (typeof v === "object") {
167
+ if (Object.keys(v).length > 0) return true;
168
+ } else {
169
+ return true;
170
+ }
171
+ }
172
+ return false;
173
+ }
174
+ function emitAttributes(node, ctx) {
175
+ if (!node.attributes || typeof node.attributes !== "object") return [];
176
+ return Object.entries(node.attributes).map(([k, v]) => emitAttr(k, v, ctx));
177
+ }
178
+ var VOID_ELEMENTS = /* @__PURE__ */ new Set([
179
+ "img",
180
+ "br",
181
+ "hr",
182
+ "input",
183
+ "meta",
184
+ "link",
185
+ "area",
186
+ "base",
187
+ "col",
188
+ "embed",
189
+ "param",
190
+ "source",
191
+ "track",
192
+ "wbr"
193
+ ]);
194
+ var LOCALE_KNOWN_KEYS = /* @__PURE__ */ new Set([
195
+ "type",
196
+ "if",
197
+ "showCurrent",
198
+ "showSeparator",
199
+ "showFlag",
200
+ "displayType",
201
+ "style",
202
+ "itemStyle",
203
+ "activeItemStyle",
204
+ "separatorStyle",
205
+ "flagStyle",
206
+ "interactiveStyles",
207
+ "label",
208
+ "generateElementClass"
209
+ ]);
210
+ function emitTextChild(text, forceExpr = false) {
211
+ if (hasTemplate(text)) return `{${templateToExpr(text)}}`;
212
+ const safeRaw = !forceExpr && text.length > 0 && text === text.trim() && !/[{}<>]/.test(text);
213
+ return safeRaw ? text : `{${JSON.stringify(text)}}`;
214
+ }
215
+ function emitChildrenList(children, ctx) {
216
+ if (children === void 0 || children === null) return [];
217
+ if (typeof children === "string") {
218
+ return children.length ? [emitTextChild(children)] : [];
219
+ }
220
+ if (!Array.isArray(children)) return [];
221
+ const multi = children.length > 1;
222
+ return children.map(
223
+ (child) => typeof child === "string" ? emitTextChild(child, multi) : placeChild(renderNode(child, ctx), 0)
224
+ );
225
+ }
226
+ function composeElement(tag, attrs, childBlocks, forceVoid = false) {
227
+ const attrStr = attrs.length ? " " + attrs.join(" ") : "";
228
+ if (forceVoid || childBlocks.length === 0) {
229
+ return `<${tag}${attrStr} />`;
230
+ }
231
+ if (childBlocks.length === 1 && !childBlocks[0].includes("\n")) {
232
+ return `<${tag}${attrStr}>${childBlocks[0]}</${tag}>`;
233
+ }
234
+ const inner = childBlocks.map((c) => shift(c, INDENT)).join("\n");
235
+ return `<${tag}${attrStr}>
236
+ ${inner}
237
+ </${tag}>`;
238
+ }
239
+ function renderHtml(node, ctx) {
240
+ let tag = node.tag;
241
+ if (typeof tag === "string" && hasTemplate(tag)) {
242
+ const varName = `Tag_${ctx.tagCounter++}`;
243
+ ctx.frontmatterConsts.push(`const ${varName} = ${tagToTemplateLiteral(tag)};`);
244
+ tag = varName;
245
+ }
246
+ const attrs = [emitClassAttr(node, ctx), ...emitAttributes(node, ctx)].filter(Boolean);
247
+ const isVoid = VOID_ELEMENTS.has(String(node.tag).toLowerCase());
248
+ const childBlocks = isVoid ? [] : emitChildrenList(node.children, ctx);
249
+ return { kind: "element", markup: composeElement(tag, attrs, childBlocks, isVoid) };
250
+ }
251
+ function tagToTemplateLiteral(tag) {
252
+ const body = tag.replace(TEMPLATE_RE, (_m, e) => "${" + String(e).trim() + "}");
253
+ return "`" + body + "`";
254
+ }
255
+ function renderComponentInstance(node, ctx) {
256
+ const tag = astroComponentName(node.component);
257
+ ctx.components.add(node.component);
258
+ const attrs = [];
259
+ if (node.props && typeof node.props === "object") {
260
+ for (const [k, v] of Object.entries(node.props)) attrs.push(emitAttr(k, v, ctx));
261
+ }
262
+ const cls = emitClassAttr(node, ctx, hasStyleContent(node.style) ? { instance: true } : void 0);
263
+ if (cls) attrs.push(cls);
264
+ const childBlocks = emitChildrenList(node.children, ctx);
265
+ return { kind: "element", markup: composeElement(tag, attrs, childBlocks) };
266
+ }
267
+ function renderSlot(node, ctx) {
268
+ const def = node.default;
269
+ if (def === void 0) return { kind: "element", markup: "<slot />" };
270
+ const childBlocks = emitChildrenList(def, ctx);
271
+ return { kind: "element", markup: composeElement("slot", [], childBlocks) };
272
+ }
273
+ function renderLink(node, ctx) {
274
+ needRuntimeComponent(ctx, "Link");
275
+ const attrs = [emitHref(node.href, ctx)];
276
+ const cls = emitClassAttr(node, ctx);
277
+ if (cls) attrs.push(cls);
278
+ attrs.push(...emitAttributes(node, ctx));
279
+ const childBlocks = emitChildrenList(node.children, ctx);
280
+ return { kind: "element", markup: composeElement("Link", attrs.filter(Boolean), childBlocks) };
281
+ }
282
+ function emitHref(href, ctx) {
283
+ if (typeof href === "string") {
284
+ if (hasTemplate(href)) return `href={${templateToExpr(href)}}`;
285
+ return `href="${href}"`;
286
+ }
287
+ if (isI18nValue(href)) {
288
+ needRuntime(ctx, "i18n");
289
+ return `href={i18n(${serializeLiteral(href, { indent: INDENT, width: ctx.width })})}`;
290
+ }
291
+ needRuntime(ctx, "href");
292
+ return `href={href(${serializeLiteral(href, { indent: INDENT, width: ctx.width })})}`;
293
+ }
294
+ function renderEmbed(node, ctx) {
295
+ needRuntimeComponent(ctx, "Embed");
296
+ const attrs = [];
297
+ if (typeof node.html === "string") {
298
+ if (node.html.includes("\n")) {
299
+ const name = `__embed${ctx.hoistCounter++}`;
300
+ ctx.frontmatterConsts.push(`const ${name} = \`${escapeBacktick(node.html)}\`;`);
301
+ attrs.push(`html={${name}}`);
302
+ } else {
303
+ attrs.push(`html={\`${escapeBacktick(node.html)}\`}`);
304
+ }
305
+ } else {
306
+ needRuntime(ctx, "embedHtml");
307
+ attrs.push(`html={embedHtml(${serializeLiteral(node.html, { indent: INDENT, width: ctx.width })})}`);
308
+ }
309
+ const cls = emitClassAttr(node, ctx);
310
+ if (cls) attrs.push(cls);
311
+ attrs.push(...emitAttributes(node, ctx));
312
+ return { kind: "element", markup: composeElement("Embed", attrs, [], true) };
313
+ }
314
+ function renderLocaleList(node, ctx) {
315
+ needRuntimeComponent(ctx, "LocaleList");
316
+ const attrs = [];
317
+ const boolProps = ["showCurrent", "showSeparator", "showFlag"];
318
+ for (const p of boolProps) if (node[p] !== void 0) attrs.push(emitAttr(p, node[p], ctx));
319
+ if (node.displayType !== void 0) attrs.push(emitAttr("displayType", node.displayType, ctx));
320
+ const styleProps = ["style", "itemStyle", "activeItemStyle", "separatorStyle", "flagStyle"];
321
+ for (const sp of styleProps) {
322
+ if (hasStyleContent(node[sp])) {
323
+ needRuntime(ctx, "style");
324
+ attrs.push(`${sp}={style(${serializeLiteral(node[sp], { indent: INDENT, width: ctx.width })})}`);
325
+ }
326
+ }
327
+ if (node.interactiveStyles !== void 0 || node.label !== void 0 || node.generateElementClass !== void 0) {
328
+ const meta = {};
329
+ if (node.interactiveStyles !== void 0) meta.interactive = node.interactiveStyles;
330
+ if (node.label !== void 0) meta.label = node.label;
331
+ if (node.generateElementClass !== void 0) meta.genClass = node.generateElementClass;
332
+ attrs.push(`meta={${serializeLiteral(meta, { indent: INDENT, width: ctx.width })}}`);
333
+ }
334
+ for (const [k, v] of Object.entries(node)) {
335
+ if (LOCALE_KNOWN_KEYS.has(k)) continue;
336
+ if (typeof v === "string" || typeof v === "number" || typeof v === "boolean") {
337
+ attrs.push(emitAttr(k, v, ctx));
338
+ }
339
+ }
340
+ return { kind: "element", markup: composeElement("LocaleList", attrs, [], true) };
341
+ }
342
+ function renderList(node, ctx) {
343
+ const sourceType = node.sourceType ?? "prop";
344
+ const childBlocks = emitChildrenList(node.children, ctx);
345
+ const childRenderedAt2 = childBlocks.map((c) => shift(c, INDENT)).join("\n");
346
+ if (sourceType === "collection") {
347
+ needRuntime(ctx, "getCollectionList");
348
+ const itemVar2 = node.itemAs ?? singularize(node.source);
349
+ const indexVar2 = `${itemVar2}Index`;
350
+ const query = listQueryLiteral(node, ctx, ["filter", "sort", "limit", "offset", "items", "excludeCurrentItem", "emitTemplate"]);
351
+ const binding = uniqueBinding(ctx, `${sanitizeIdent(node.source)}List`);
352
+ ctx.frontmatterConsts.push(
353
+ `const ${binding} = await getCollectionList(${JSON.stringify(node.source)}${query ? ", " + query : ""}, Astro);`
354
+ );
355
+ const expr2 = `${binding}.map((${itemVar2}, ${indexVar2}) => (
356
+ ${childRenderedAt2}
357
+ ))`;
358
+ return { kind: "expr", expr: expr2 };
359
+ }
360
+ needRuntime(ctx, "list");
361
+ const itemVar = node.itemAs ?? "item";
362
+ const indexVar = `${itemVar}Index`;
363
+ const sourceExpr = typeof node.source === "string" && hasTemplate(node.source) ? templateToExpr(node.source) : sanitizeIdent(String(node.source));
364
+ const opts = listQueryLiteral(node, ctx, ["limit", "offset"]);
365
+ const listCall = opts ? `list(${sourceExpr}, ${opts})` : `list(${sourceExpr})`;
366
+ const expr = `${listCall}.map((${itemVar}, ${indexVar}) => (
367
+ ${childRenderedAt2}
368
+ ))`;
369
+ return { kind: "expr", expr };
370
+ }
371
+ function listQueryLiteral(node, ctx, keys) {
372
+ const obj = {};
373
+ for (const k of keys) if (node[k] !== void 0) obj[k] = node[k];
374
+ if (Object.keys(obj).length === 0) return "";
375
+ return serializeLiteral(obj, { indent: INDENT, width: ctx.width });
376
+ }
377
+ function uniqueBinding(ctx, base) {
378
+ const existing = ctx.frontmatterConsts.some((l) => l.startsWith(`const ${base} `));
379
+ if (!existing) return base;
380
+ return `${base}_${ctx.listCounter++}`;
381
+ }
382
+ function sanitizeIdent(s) {
383
+ return /^[A-Za-z_$][\w$]*$/.test(s) ? s : s.replace(/[^A-Za-z0-9_$]/g, "_");
384
+ }
385
+ function astroComponentName(name) {
386
+ const cleaned = name.replace(/[^A-Za-z0-9_$]/g, "");
387
+ return cleaned.charAt(0).toUpperCase() + cleaned.slice(1);
388
+ }
389
+ function renderNode(node, ctx) {
390
+ let rendered;
391
+ switch (node.type) {
392
+ case "node":
393
+ rendered = renderHtml(node, ctx);
394
+ break;
395
+ case "component":
396
+ rendered = renderComponentInstance(node, ctx);
397
+ break;
398
+ case "slot":
399
+ rendered = renderSlot(node, ctx);
400
+ break;
401
+ case "link":
402
+ rendered = renderLink(node, ctx);
403
+ break;
404
+ case "embed":
405
+ rendered = renderEmbed(node, ctx);
406
+ break;
407
+ case "locale-list":
408
+ rendered = renderLocaleList(node, ctx);
409
+ break;
410
+ case "list":
411
+ rendered = renderList(node, ctx);
412
+ break;
413
+ default:
414
+ rendered = { kind: "element", markup: `{/* meno:unknown ${JSON.stringify(node.type)} */}` };
415
+ }
416
+ return applyIf(node, rendered);
417
+ }
418
+ function applyIf(node, rendered) {
419
+ if (node.if === void 0 || node.if === true) return rendered;
420
+ const cond = ifConditionExpr(node.if);
421
+ if (rendered.kind === "element") {
422
+ return { kind: "expr", expr: `${cond} && (
423
+ ${shift(rendered.markup, INDENT)}
424
+ )` };
425
+ }
426
+ return { kind: "expr", expr: `${cond} && (${rendered.expr})` };
427
+ }
428
+ function ifConditionExpr(cond) {
429
+ if (cond === false) return "false";
430
+ if (cond === true) return "true";
431
+ if (typeof cond === "string") return hasTemplate(cond) ? templateToExpr(cond) : cond;
432
+ return `when(${serializeLiteral(cond)})`;
433
+ }
434
+ function placeChild(rendered, indent) {
435
+ if (rendered.kind === "element") return shift(rendered.markup, indent);
436
+ return shift(`{${rendered.expr}}`, indent);
437
+ }
438
+ function emitNode(node, ctx, indent) {
439
+ if (typeof node === "string") return shift(emitTextChild(node), indent);
440
+ return placeChild(renderNode(node, ctx), indent);
441
+ }
442
+
443
+ // lib/dialect/emit/frontmatter.ts
444
+ function buildImportLines(ctx, opts) {
445
+ const lines = [];
446
+ const types = [...new Set(opts.typeImports ?? [])].sort();
447
+ if (types.length) lines.push(`import type { ${types.join(", ")} } from 'meno-astro';`);
448
+ if (ctx.runtime.size) {
449
+ lines.push(`import { ${[...ctx.runtime].sort().join(", ")} } from 'meno-astro';`);
450
+ }
451
+ if (ctx.runtimeComponents.size) {
452
+ lines.push(`import { ${[...ctx.runtimeComponents].sort().join(", ")} } from 'meno-astro/components';`);
453
+ }
454
+ for (const name of [...ctx.components].sort()) {
455
+ lines.push(`import ${astroComponentName(name)} from '${opts.componentPrefix}${name}.astro';`);
456
+ }
457
+ return lines;
458
+ }
459
+ var WIDTH = 80;
460
+ var CALL_PREFIX = "resolveProps(Astro, ";
461
+ function buildPropsBlock(propInterface) {
462
+ const def = propInterface ?? {};
463
+ const names = [];
464
+ for (const name of Object.keys(def)) {
465
+ if (name === "children") continue;
466
+ names.push(name);
467
+ }
468
+ names.push("class: className");
469
+ const head = `const { ${names.join(", ")} } = ${CALL_PREFIX}`;
470
+ let prefix;
471
+ let closeCol;
472
+ if (head.length <= WIDTH) {
473
+ prefix = head;
474
+ closeCol = head.length;
475
+ } else {
476
+ prefix = ["const {", ...names.map((n) => ` ${n},`), `} = ${CALL_PREFIX}`].join("\n");
477
+ closeCol = `} = ${CALL_PREFIX}`.length;
478
+ }
479
+ const literal = serializeLiteral(def, { indent: 0, startCol: closeCol + 2, width: WIDTH });
480
+ return [`${prefix}${literal});`];
481
+ }
482
+
483
+ // lib/dialect/cmsRoute.ts
484
+ function isCmsTemplatePage(page) {
485
+ if (!page || typeof page !== "object") return false;
486
+ const meta = page.meta;
487
+ return !!meta && meta.source === "cms" && !!meta.cms && typeof meta.cms === "object";
488
+ }
489
+ function cmsRouteDirFromUrlPattern(urlPattern) {
490
+ if (!urlPattern) return "";
491
+ const withoutLeading = urlPattern.replace(/^\/+/, "");
492
+ const idx = withoutLeading.indexOf("{{");
493
+ const prefix = idx < 0 ? withoutLeading : withoutLeading.slice(0, idx);
494
+ return prefix.replace(/^\/+|\/+$/g, "");
495
+ }
496
+ function buildGetStaticPaths(cms) {
497
+ const collectionId = cms.id ?? "";
498
+ const slugField = cms.slugField || "slug";
499
+ return [
500
+ `export async function getStaticPaths() {`,
501
+ ` const entries = await getCollection(${JSON.stringify(collectionId)});`,
502
+ ` return entries.map((entry) => ({`,
503
+ ` params: { slug: entry.data.${slugField} ?? entry.id },`,
504
+ ` props: { cms: entry.data },`,
505
+ ` }));`,
506
+ `}`,
507
+ ``,
508
+ `const { cms } = Astro.props;`
509
+ ].join("\n");
510
+ }
511
+
512
+ // lib/dialect/emit/emitPage.ts
513
+ function emitPage(page) {
514
+ const ctx = createEmitContext();
515
+ const body = page.root ? emitNode(page.root, ctx, 2) : "";
516
+ needRuntimeComponent(ctx, "BaseLayout");
517
+ const isCms = isCmsTemplatePage(page);
518
+ const routeDir = isCms ? cmsRouteDirFromUrlPattern(page.meta.cms.urlPattern) : "";
519
+ const depth = routeDir ? routeDir.split("/").length : 0;
520
+ const componentPrefix = `${"../".repeat(depth + 1)}components/`;
521
+ const importLines = buildImportLines(ctx, {
522
+ typeImports: ["MenoPageMeta"],
523
+ componentPrefix
524
+ });
525
+ const fm = [];
526
+ if (isCms) fm.push(`import { getCollection } from 'astro:content';`);
527
+ fm.push(...importLines);
528
+ fm.push("");
529
+ if (isCms) {
530
+ fm.push(buildGetStaticPaths(page.meta.cms));
531
+ fm.push("");
532
+ }
533
+ fm.push(`export const meta = ${serializeLiteral(page.meta ?? {}, { indent: 0 })} satisfies MenoPageMeta;`);
534
+ if (ctx.frontmatterConsts.length) {
535
+ fm.push("");
536
+ fm.push(...ctx.frontmatterConsts);
537
+ }
538
+ const wrapped = body ? `<BaseLayout meta={meta}>
539
+ ${body}
540
+ </BaseLayout>` : `<BaseLayout meta={meta} />`;
541
+ return `---
542
+ ${fm.join("\n")}
543
+ ---
544
+ ${wrapped}
545
+ `;
546
+ }
547
+
548
+ // lib/dialect/emit/emitComponent.ts
549
+ var META_KEYS = ["category", "acceptsStyles", "libraries"];
550
+ function defineVarNames(def) {
551
+ if (def.defineVars === true) {
552
+ return Object.keys(def.interface ?? {}).filter((k) => k !== "children");
553
+ }
554
+ return def.defineVars ?? [];
555
+ }
556
+ function buildScriptBlock(def) {
557
+ if (!def.javascript) return "";
558
+ if (def.defineVars) {
559
+ const names = defineVarNames(def);
560
+ return `
561
+
562
+ <script define:vars={{ ${names.join(", ")} }}>
563
+ ${def.javascript}
564
+ </script>`;
565
+ }
566
+ return `
567
+
568
+ <script is:inline>
569
+ ${def.javascript}
570
+ </script>`;
571
+ }
572
+ function pickComponentMeta(def) {
573
+ const meta = {};
574
+ for (const k of META_KEYS) {
575
+ const v = def[k];
576
+ if (v !== void 0) meta[k] = v;
577
+ }
578
+ return meta;
579
+ }
580
+ function emitComponent(def) {
581
+ const ctx = createEmitContext();
582
+ const body = def.structure ? emitNode(def.structure, ctx, 0) : "<slot />";
583
+ const componentMeta = pickComponentMeta(def);
584
+ const hasMeta = Object.keys(componentMeta).length > 0;
585
+ ctx.runtime.add("resolveProps");
586
+ const typeImports = [];
587
+ if (hasMeta) typeImports.push("MenoComponentMeta");
588
+ const importLines = buildImportLines(ctx, { typeImports, componentPrefix: "./" });
589
+ const propsBlock = buildPropsBlock(def.interface);
590
+ const fm = [];
591
+ fm.push(...importLines);
592
+ fm.push("");
593
+ fm.push(...propsBlock);
594
+ if (hasMeta) {
595
+ fm.push("");
596
+ fm.push(`const __meno = ${serializeLiteral(componentMeta, { indent: 0 })} satisfies MenoComponentMeta;`);
597
+ }
598
+ if (ctx.frontmatterConsts.length) {
599
+ fm.push("");
600
+ fm.push(...ctx.frontmatterConsts);
601
+ }
602
+ const styleBlock = def.css ? `
603
+
604
+ <style>
605
+ ${def.css}
606
+ </style>` : "";
607
+ const scriptBlock = buildScriptBlock(def);
608
+ return `---
609
+ ${fm.join("\n")}
610
+ ---
611
+ ${body}
612
+ ${styleBlock}${scriptBlock}`.replace(/\n+$/, "\n");
613
+ }
614
+
615
+ // lib/dialect/parse/parseLiteral.ts
616
+ var WS = /* @__PURE__ */ new Set([" ", " ", "\r", "\n"]);
617
+ var IDENT_START = /[A-Za-z_$]/;
618
+ var IDENT_CHAR = /[A-Za-z0-9_$]/;
619
+ function skipWs(src, i) {
620
+ while (i < src.length && WS.has(src[i])) i++;
621
+ return i;
622
+ }
623
+ function fail(src, i, msg) {
624
+ const around = src.slice(Math.max(0, i - 20), i + 20);
625
+ throw new Error(`parseLiteral: ${msg} at index ${i} (\u2026${around}\u2026)`);
626
+ }
627
+ function parseString(src, i) {
628
+ let j = i + 1;
629
+ while (j < src.length) {
630
+ const c = src[j];
631
+ if (c === "\\") {
632
+ j += 2;
633
+ continue;
634
+ }
635
+ if (c === '"') {
636
+ j++;
637
+ break;
638
+ }
639
+ j++;
640
+ }
641
+ const raw = src.slice(i, j);
642
+ return { value: JSON.parse(raw), end: j };
643
+ }
644
+ function parseNumber(src, i) {
645
+ let j = i;
646
+ while (j < src.length && /[-+0-9.eE]/.test(src[j])) j++;
647
+ const raw = src.slice(i, j);
648
+ const n = Number(raw);
649
+ if (Number.isNaN(n) && raw !== "NaN") fail(src, i, `invalid number "${raw}"`);
650
+ return { value: n, end: j };
651
+ }
652
+ function parseKey(src, i) {
653
+ if (src[i] === '"') return parseString(src, i);
654
+ if (!IDENT_START.test(src[i])) fail(src, i, "expected object key");
655
+ let j = i + 1;
656
+ while (j < src.length && IDENT_CHAR.test(src[j])) j++;
657
+ return { value: src.slice(i, j), end: j };
658
+ }
659
+ function parseObject(src, i) {
660
+ const obj = {};
661
+ let j = skipWs(src, i + 1);
662
+ if (src[j] === "}") return { value: obj, end: j + 1 };
663
+ for (; ; ) {
664
+ j = skipWs(src, j);
665
+ const key = parseKey(src, j);
666
+ j = skipWs(src, key.end);
667
+ if (src[j] !== ":") fail(src, j, 'expected ":"');
668
+ j = skipWs(src, j + 1);
669
+ const val = parseValueAt(src, j);
670
+ obj[key.value] = val.value;
671
+ j = skipWs(src, val.end);
672
+ if (src[j] === ",") {
673
+ j++;
674
+ continue;
675
+ }
676
+ if (src[j] === "}") return { value: obj, end: j + 1 };
677
+ fail(src, j, 'expected "," or "}"');
678
+ }
679
+ }
680
+ function parseArray(src, i) {
681
+ const arr = [];
682
+ let j = skipWs(src, i + 1);
683
+ if (src[j] === "]") return { value: arr, end: j + 1 };
684
+ for (; ; ) {
685
+ j = skipWs(src, j);
686
+ const val = parseValueAt(src, j);
687
+ arr.push(val.value);
688
+ j = skipWs(src, val.end);
689
+ if (src[j] === ",") {
690
+ j++;
691
+ continue;
692
+ }
693
+ if (src[j] === "]") return { value: arr, end: j + 1 };
694
+ fail(src, j, 'expected "," or "]"');
695
+ }
696
+ }
697
+ function parseValueAt(src, i) {
698
+ i = skipWs(src, i);
699
+ const c = src[i];
700
+ if (c === "{") return parseObject(src, i);
701
+ if (c === "[") return parseArray(src, i);
702
+ if (c === '"') return parseString(src, i);
703
+ if (src.startsWith("true", i)) return { value: true, end: i + 4 };
704
+ if (src.startsWith("false", i)) return { value: false, end: i + 5 };
705
+ if (src.startsWith("null", i)) return { value: null, end: i + 4 };
706
+ if (c === "-" || c === "+" || c >= "0" && c <= "9") return parseNumber(src, i);
707
+ return fail(src, i, `unexpected character "${c ?? "<eof>"}"`);
708
+ }
709
+ function parseLiteral(src) {
710
+ const { value, end } = parseValueAt(src, 0);
711
+ const rest = skipWs(src, end);
712
+ if (rest !== src.length) fail(src, rest, "trailing content after literal");
713
+ return value;
714
+ }
715
+
716
+ // lib/dialect/parse/scan.ts
717
+ var CLOSERS = { "{": "}", "(": ")", "[": "]" };
718
+ function scanString(src, i) {
719
+ const q = src[i];
720
+ let j = i + 1;
721
+ while (j < src.length) {
722
+ if (src[j] === "\\") {
723
+ j += 2;
724
+ continue;
725
+ }
726
+ if (src[j] === q) return j + 1;
727
+ j++;
728
+ }
729
+ throw new Error(`scanString: unterminated string from ${i}`);
730
+ }
731
+ function scanTemplate(src, i) {
732
+ let j = i + 1;
733
+ while (j < src.length) {
734
+ if (src[j] === "\\") {
735
+ j += 2;
736
+ continue;
737
+ }
738
+ if (src[j] === "`") return j + 1;
739
+ if (src[j] === "$" && src[j + 1] === "{") {
740
+ j = scanBalanced(src, j + 1);
741
+ continue;
742
+ }
743
+ j++;
744
+ }
745
+ throw new Error(`scanTemplate: unterminated template from ${i}`);
746
+ }
747
+ function scanBalanced(src, i) {
748
+ if (!CLOSERS[src[i]]) throw new Error(`scanBalanced: no open delimiter at ${i} ("${src[i]}")`);
749
+ let depth = 0;
750
+ let j = i;
751
+ while (j < src.length) {
752
+ const c = src[j];
753
+ if (c === '"' || c === "'") {
754
+ j = scanString(src, j);
755
+ continue;
756
+ }
757
+ if (c === "`") {
758
+ j = scanTemplate(src, j);
759
+ continue;
760
+ }
761
+ if (c === "{" || c === "(" || c === "[") {
762
+ depth++;
763
+ j++;
764
+ continue;
765
+ }
766
+ if (c === "}" || c === ")" || c === "]") {
767
+ depth--;
768
+ j++;
769
+ if (depth === 0) return j;
770
+ continue;
771
+ }
772
+ j++;
773
+ }
774
+ throw new Error(`scanBalanced: unbalanced from ${i}`);
775
+ }
776
+ function findTrailingGroup(expr, openChar = "(") {
777
+ let j = 0;
778
+ while (j < expr.length) {
779
+ const c = expr[j];
780
+ if (c === '"' || c === "'") {
781
+ j = scanString(expr, j);
782
+ continue;
783
+ }
784
+ if (c === "`") {
785
+ j = scanTemplate(expr, j);
786
+ continue;
787
+ }
788
+ if (c === "{" || c === "(" || c === "[") {
789
+ const end = scanBalanced(expr, j);
790
+ if (c === openChar && end === expr.length) {
791
+ return { open: j, inner: expr.slice(j + 1, end - 1) };
792
+ }
793
+ j = end;
794
+ continue;
795
+ }
796
+ j++;
797
+ }
798
+ return null;
799
+ }
800
+ function splitTopLevel(src, sep) {
801
+ const parts = [];
802
+ let start = 0;
803
+ let j = 0;
804
+ while (j < src.length) {
805
+ const c = src[j];
806
+ if (c === '"' || c === "'") {
807
+ j = scanString(src, j);
808
+ continue;
809
+ }
810
+ if (c === "`") {
811
+ j = scanTemplate(src, j);
812
+ continue;
813
+ }
814
+ if (c === "{" || c === "(" || c === "[") {
815
+ j = scanBalanced(src, j);
816
+ continue;
817
+ }
818
+ if (c === sep) {
819
+ parts.push(src.slice(start, j));
820
+ start = j + 1;
821
+ j++;
822
+ continue;
823
+ }
824
+ j++;
825
+ }
826
+ parts.push(src.slice(start));
827
+ return parts.map((s) => s.trim());
828
+ }
829
+
830
+ // lib/dialect/parse/callArgs.ts
831
+ function callArgsOf(expr) {
832
+ const open = expr.indexOf("(");
833
+ const end = scanBalanced(expr, open);
834
+ return expr.slice(open + 1, end - 1);
835
+ }
836
+
837
+ // lib/dialect/parse/parseValue.ts
838
+ function reverseTemplate(content) {
839
+ let out = "";
840
+ let i = 0;
841
+ while (i < content.length) {
842
+ const c = content[i];
843
+ if (c === "\\") {
844
+ const n = content[i + 1];
845
+ out += n === "\\" ? "\\" : n === "`" ? "`" : n === "$" ? "$" : n;
846
+ i += 2;
847
+ continue;
848
+ }
849
+ if (c === "$" && content[i + 1] === "{") {
850
+ const end = scanBalanced(content, i + 1);
851
+ out += "{{" + content.slice(i + 2, end - 1).trim() + "}}";
852
+ i = end;
853
+ continue;
854
+ }
855
+ out += c;
856
+ i++;
857
+ }
858
+ return out;
859
+ }
860
+ function interpretExprValue(expr, ctx) {
861
+ const e = expr.trim();
862
+ if (ctx.embedConsts.has(e)) return ctx.embedConsts.get(e);
863
+ if (e.startsWith("i18n(")) return parseLiteral(callArgsOf(e));
864
+ if (e.startsWith("href(")) return parseLiteral(callArgsOf(e));
865
+ if (e.startsWith("embedHtml(")) return parseLiteral(callArgsOf(e));
866
+ if (e[0] === "`") return reverseTemplate(e.slice(1, -1));
867
+ if (e[0] === "{" || e[0] === "[") return parseLiteral(e);
868
+ if (e[0] === '"') return parseLiteral(e);
869
+ if (e === "true") return true;
870
+ if (e === "false") return false;
871
+ if (e === "null") return null;
872
+ if (/^[-+]?(\d|\.\d)/.test(e) && !Number.isNaN(Number(e))) return Number(e);
873
+ return `{{${e}}}`;
874
+ }
875
+ function interpretStyleCall(expr) {
876
+ const args = callArgsOf(expr);
877
+ const parts = splitTopLevel(args, ",").filter((p) => p.length > 0);
878
+ const out = {};
879
+ if (parts[0]) out.style = parseLiteral(parts[0]);
880
+ if (parts[1]) {
881
+ const meta = parseLiteral(parts[1]);
882
+ if (meta.interactive !== void 0) out.interactiveStyles = meta.interactive;
883
+ if (meta.label !== void 0) out.label = meta.label;
884
+ if (meta.genClass !== void 0) out.generateElementClass = meta.genClass;
885
+ }
886
+ return out;
887
+ }
888
+ function reverseCondition(cond) {
889
+ const c = cond.trim();
890
+ if (c === "false") return false;
891
+ if (c === "true") return true;
892
+ if (c.startsWith("when(")) return parseLiteral(callArgsOf(c));
893
+ return `{{${c}}}`;
894
+ }
895
+
896
+ // lib/dialect/parse/parseContext.ts
897
+ function createParseContext() {
898
+ return {
899
+ collectionBindings: /* @__PURE__ */ new Map(),
900
+ embedConsts: /* @__PURE__ */ new Map(),
901
+ tagConsts: /* @__PURE__ */ new Map(),
902
+ componentNames: /* @__PURE__ */ new Set()
903
+ };
904
+ }
905
+
906
+ // lib/dialect/parse/parseFrontmatter.ts
907
+ function literalAfter(code, anchor) {
908
+ const idx = code.indexOf(anchor);
909
+ if (idx < 0) return void 0;
910
+ return parseValueAt(code, idx + anchor.length).value;
911
+ }
912
+ function parseFrontmatter(code) {
913
+ const ctx = createParseContext();
914
+ for (const m of code.matchAll(/import\s+(\w+)\s+from\s+'(?:\.\/|(?:\.\.\/)+components\/)[\w.-]+\.astro'/g)) {
915
+ ctx.componentNames.add(m[1]);
916
+ }
917
+ for (const m of code.matchAll(/const\s+(__embed\d+)\s*=\s*/g)) {
918
+ const tickStart = code.indexOf("`", m.index + m[0].length);
919
+ if (tickStart < 0) continue;
920
+ const tickEnd = scanTemplate(code, tickStart);
921
+ ctx.embedConsts.set(m[1], reverseTemplate(code.slice(tickStart + 1, tickEnd - 1)));
922
+ }
923
+ for (const m of code.matchAll(/const\s+(Tag_\d+)\s*=\s*/g)) {
924
+ const tickStart = code.indexOf("`", m.index + m[0].length);
925
+ if (tickStart < 0) continue;
926
+ const tickEnd = scanTemplate(code, tickStart);
927
+ ctx.tagConsts.set(m[1], reverseTemplate(code.slice(tickStart + 1, tickEnd - 1)));
928
+ }
929
+ for (const m of code.matchAll(/const\s+(\w+)\s*=\s*await\s+getCollectionList\(/g)) {
930
+ const open = m.index + m[0].length - 1;
931
+ const inner = code.slice(open + 1, scanBalanced(code, open) - 1);
932
+ const args = splitTopLevel(inner, ",").filter(Boolean);
933
+ const source = parseLiteral(args[0]);
934
+ const query = args.length >= 3 ? parseLiteral(args[1]) : void 0;
935
+ ctx.collectionBindings.set(m[1], { source, query });
936
+ }
937
+ const propsInterface = literalAfter(code, "resolveProps(Astro, ");
938
+ const componentMeta = literalAfter(code, "const __meno = ") ?? {};
939
+ const meta = literalAfter(code, "export const meta = ");
940
+ const kind = code.includes("resolveProps(") ? "component" : "page";
941
+ return { kind, ctx, meta, propsInterface, componentMeta };
942
+ }
943
+
944
+ // lib/dialect/parse/parseBody.ts
945
+ var WS2 = /* @__PURE__ */ new Set([" ", " ", "\r", "\n"]);
946
+ var RUNTIME_TAGS = /* @__PURE__ */ new Set(["Link", "Embed", "LocaleList", "BaseLayout"]);
947
+ var LOCALE_STYLE_PROPS = /* @__PURE__ */ new Set([
948
+ "style",
949
+ "itemStyle",
950
+ "activeItemStyle",
951
+ "separatorStyle",
952
+ "flagStyle"
953
+ ]);
954
+ function skipWs2(src, i) {
955
+ while (i < src.length && WS2.has(src[i])) i++;
956
+ return i;
957
+ }
958
+ function readTagName(src, i) {
959
+ let j = i;
960
+ while (j < src.length && /[A-Za-z0-9.\-_]/.test(src[j])) j++;
961
+ return { name: src.slice(i, j), end: j };
962
+ }
963
+ function parseAttributes(src, i) {
964
+ const attrs = [];
965
+ let j = i;
966
+ for (; ; ) {
967
+ j = skipWs2(src, j);
968
+ if (src[j] === "/" && src[j + 1] === ">") return { attrs, end: j + 2, selfClose: true };
969
+ if (src[j] === ">") return { attrs, end: j + 1, selfClose: false };
970
+ const { name, end } = readTagName(src, j);
971
+ if (!name) throw new Error(`parseAttributes: expected attribute name at ${j} ("${src.slice(j, j + 15)}")`);
972
+ j = end;
973
+ if (src[j] === "=") {
974
+ j++;
975
+ if (src[j] === '"' || src[j] === "'") {
976
+ const q = src[j];
977
+ let k = j + 1;
978
+ while (k < src.length && src[k] !== q) {
979
+ if (src[k] === "\\") k++;
980
+ k++;
981
+ }
982
+ attrs.push({ name, raw: src.slice(j + 1, k), isExpr: false });
983
+ j = k + 1;
984
+ } else if (src[j] === "{") {
985
+ const close = scanBalanced(src, j);
986
+ attrs.push({ name, raw: src.slice(j + 1, close - 1), isExpr: true });
987
+ j = close;
988
+ } else {
989
+ throw new Error(`parseAttributes: bad attribute value for "${name}" at ${j}`);
990
+ }
991
+ } else {
992
+ attrs.push({ name, raw: "", isExpr: false, shorthand: true });
993
+ }
994
+ }
995
+ }
996
+ function attrValue(a, ctx) {
997
+ if (a.shorthand) return true;
998
+ if (!a.isExpr) return a.raw;
999
+ return interpretExprValue(a.raw, ctx);
1000
+ }
1001
+ function parseElement(src, i, ctx) {
1002
+ i = skipWs2(src, i);
1003
+ if (src[i] !== "<") throw new Error(`parseElement: expected "<" at ${i}`);
1004
+ const { name: tag, end: afterTag } = readTagName(src, i + 1);
1005
+ const { attrs, end: afterAttrs, selfClose } = parseAttributes(src, afterTag);
1006
+ let children = [];
1007
+ let end = afterAttrs;
1008
+ if (!selfClose) {
1009
+ const inner = parseNodes(src, afterAttrs, ctx, tag);
1010
+ children = inner.nodes;
1011
+ const close = src.indexOf(">", inner.end);
1012
+ end = close + 1;
1013
+ }
1014
+ return { node: elementToNode(tag, attrs, children, ctx), end };
1015
+ }
1016
+ function parseNodes(src, i, ctx, stopTag) {
1017
+ const nodes = [];
1018
+ let j = i;
1019
+ while (j < src.length) {
1020
+ const k = skipWs2(src, j);
1021
+ if (k >= src.length) {
1022
+ j = k;
1023
+ break;
1024
+ }
1025
+ if (stopTag && src[k] === "<" && src[k + 1] === "/") return { nodes, end: k };
1026
+ if (src[k] === "<") {
1027
+ const { node, end } = parseElement(src, k, ctx);
1028
+ nodes.push(node);
1029
+ j = end;
1030
+ continue;
1031
+ }
1032
+ if (src[k] === "{") {
1033
+ const end = scanBalanced(src, k);
1034
+ const child = interpretChildExpr(src.slice(k + 1, end - 1), ctx);
1035
+ if (child !== void 0 && child !== null && child !== "") nodes.push(child);
1036
+ j = end;
1037
+ continue;
1038
+ }
1039
+ let t = k;
1040
+ while (t < src.length && src[t] !== "<" && src[t] !== "{") t++;
1041
+ const text = src.slice(k, t).trim();
1042
+ if (text.length) nodes.push(text);
1043
+ j = t;
1044
+ }
1045
+ return { nodes, end: j };
1046
+ }
1047
+ function interpretChildExpr(inner, ctx) {
1048
+ const e = inner.trim();
1049
+ if (!e) return void 0;
1050
+ const grp = findTrailingGroup(e, "(");
1051
+ if (grp) {
1052
+ const before = e.slice(0, grp.open).trim();
1053
+ if (before.endsWith("&&")) {
1054
+ const cond = before.slice(0, -2).trim();
1055
+ const body = grp.inner.trim();
1056
+ const node = body.startsWith("<") ? parseElement(body, 0, ctx).node : interpretChildExpr(body, ctx);
1057
+ if (node && typeof node === "object") node.if = reverseCondition(cond);
1058
+ return node;
1059
+ }
1060
+ if (before.endsWith(".map")) {
1061
+ return parseMapExpr(e, ctx);
1062
+ }
1063
+ }
1064
+ const val = interpretExprValue(e, ctx);
1065
+ return val;
1066
+ }
1067
+ function parseMapExpr(e, ctx) {
1068
+ const mapIdx = e.indexOf(".map(");
1069
+ const head = e.slice(0, mapIdx).trim();
1070
+ const argOpen = mapIdx + 4;
1071
+ const argEnd = scanBalanced(e, argOpen);
1072
+ const arg = e.slice(argOpen + 1, argEnd - 1).trim();
1073
+ const paramsEnd = scanBalanced(arg, 0);
1074
+ const params = splitTopLevel(arg.slice(1, paramsEnd - 1), ",").filter(Boolean);
1075
+ const itemVar = params[0];
1076
+ const bodyGrp = findTrailingGroup(arg.slice(paramsEnd).trim(), "(");
1077
+ const children = bodyGrp ? parseNodes(bodyGrp.inner, 0, ctx).nodes : [];
1078
+ if (head.startsWith("list(")) {
1079
+ const inner = callArgsOf(head);
1080
+ const parts = splitTopLevel(inner, ",").filter(Boolean);
1081
+ const opts = parts[1] ? parseLiteral(parts[1]) : {};
1082
+ const node2 = {
1083
+ type: "list",
1084
+ sourceType: "prop",
1085
+ source: `{{${parts[0]}}}`,
1086
+ ...opts,
1087
+ children
1088
+ };
1089
+ if (itemVar && itemVar !== "item") node2.itemAs = itemVar;
1090
+ return node2;
1091
+ }
1092
+ const binding = ctx.collectionBindings.get(head);
1093
+ const source = binding?.source ?? head;
1094
+ const node = {
1095
+ type: "list",
1096
+ sourceType: "collection",
1097
+ source,
1098
+ ...binding?.query ?? {},
1099
+ children
1100
+ };
1101
+ if (itemVar && itemVar !== singularize(source)) node.itemAs = itemVar;
1102
+ return node;
1103
+ }
1104
+ function applyClass(node, attrs) {
1105
+ const cls = attrs.find((a) => a.name === "class");
1106
+ if (!cls) return;
1107
+ const parsed = interpretStyleCall(cls.raw);
1108
+ if (parsed.style !== void 0) node.style = parsed.style;
1109
+ if (parsed.interactiveStyles !== void 0) node.interactiveStyles = parsed.interactiveStyles;
1110
+ if (parsed.label !== void 0) node.label = parsed.label;
1111
+ if (parsed.generateElementClass !== void 0) node.generateElementClass = parsed.generateElementClass;
1112
+ }
1113
+ function otherAttrs(attrs, ctx, skip) {
1114
+ const out = {};
1115
+ for (const a of attrs) {
1116
+ if (skip.has(a.name)) continue;
1117
+ out[a.name] = attrValue(a, ctx);
1118
+ }
1119
+ return out;
1120
+ }
1121
+ function elementToNode(tag, attrs, children, ctx) {
1122
+ if (ctx.tagConsts.has(tag)) {
1123
+ const node2 = { type: "node", tag: ctx.tagConsts.get(tag) };
1124
+ applyClass(node2, attrs);
1125
+ const attributes2 = otherAttrs(attrs, ctx, /* @__PURE__ */ new Set(["class"]));
1126
+ if (Object.keys(attributes2).length) node2.attributes = attributes2;
1127
+ if (children.length) node2.children = children;
1128
+ return node2;
1129
+ }
1130
+ if (tag === "slot") {
1131
+ const node2 = { type: "slot" };
1132
+ if (children.length) node2.default = children;
1133
+ return node2;
1134
+ }
1135
+ if (tag === "Link") {
1136
+ const node2 = { type: "link" };
1137
+ const href = attrs.find((a) => a.name === "href");
1138
+ if (href) node2.href = attrValue(href, ctx);
1139
+ applyClass(node2, attrs);
1140
+ const rest = otherAttrs(attrs, ctx, /* @__PURE__ */ new Set(["href", "class"]));
1141
+ if (Object.keys(rest).length) node2.attributes = rest;
1142
+ if (children.length) node2.children = children;
1143
+ return node2;
1144
+ }
1145
+ if (tag === "Embed") {
1146
+ const node2 = { type: "embed" };
1147
+ const html = attrs.find((a) => a.name === "html");
1148
+ if (html) node2.html = attrValue(html, ctx);
1149
+ applyClass(node2, attrs);
1150
+ const rest = otherAttrs(attrs, ctx, /* @__PURE__ */ new Set(["html", "class"]));
1151
+ if (Object.keys(rest).length) node2.attributes = rest;
1152
+ return node2;
1153
+ }
1154
+ if (tag === "LocaleList") {
1155
+ const node2 = { type: "locale-list" };
1156
+ for (const a of attrs) {
1157
+ if (LOCALE_STYLE_PROPS.has(a.name) && a.isExpr && a.raw.trimStart().startsWith("style(")) {
1158
+ node2[a.name] = parseLiteral(callArgsOf(a.raw));
1159
+ } else if (a.name === "meta" && a.isExpr) {
1160
+ const meta = parseLiteral(a.raw);
1161
+ if (meta.interactive !== void 0) node2.interactiveStyles = meta.interactive;
1162
+ if (meta.label !== void 0) node2.label = meta.label;
1163
+ if (meta.genClass !== void 0) node2.generateElementClass = meta.genClass;
1164
+ } else {
1165
+ node2[a.name] = attrValue(a, ctx);
1166
+ }
1167
+ }
1168
+ return node2;
1169
+ }
1170
+ const isComponent = /^[A-Z]/.test(tag) && !RUNTIME_TAGS.has(tag);
1171
+ if (isComponent) {
1172
+ const node2 = { type: "component", component: tag };
1173
+ applyClass(node2, attrs);
1174
+ const props = otherAttrs(attrs, ctx, /* @__PURE__ */ new Set(["class"]));
1175
+ if (Object.keys(props).length) node2.props = props;
1176
+ if (children.length) node2.children = children;
1177
+ return node2;
1178
+ }
1179
+ const node = { type: "node", tag };
1180
+ applyClass(node, attrs);
1181
+ const attributes = otherAttrs(attrs, ctx, /* @__PURE__ */ new Set(["class"]));
1182
+ if (Object.keys(attributes).length) node.attributes = attributes;
1183
+ if (children.length) node.children = children;
1184
+ return node;
1185
+ }
1186
+
1187
+ // lib/dialect/parse/parseFile.ts
1188
+ function splitFrontmatter(source) {
1189
+ const m = source.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
1190
+ return m ? { code: m[1], body: m[2] } : { code: "", body: source };
1191
+ }
1192
+ function parseDefineVars(openTag) {
1193
+ const m = openTag.match(/define:vars=\{\{([^}]*)\}\}/);
1194
+ if (!m) return void 0;
1195
+ return m[1].split(",").map((s) => s.trim()).filter(Boolean);
1196
+ }
1197
+ function splitComponentBody(body, ctx) {
1198
+ let rest = body;
1199
+ let javascript;
1200
+ let defineVars;
1201
+ let css;
1202
+ const scriptM = rest.match(/\n*<script([^>]*)>\n([\s\S]*?)\n<\/script>\s*$/);
1203
+ if (scriptM) {
1204
+ javascript = scriptM[2];
1205
+ defineVars = parseDefineVars(scriptM[1]);
1206
+ rest = rest.slice(0, scriptM.index);
1207
+ }
1208
+ const styleM = rest.match(/\n*<style>\n([\s\S]*?)\n<\/style>\s*$/);
1209
+ if (styleM) {
1210
+ css = styleM[1];
1211
+ rest = rest.slice(0, styleM.index);
1212
+ }
1213
+ const markup = rest.trim();
1214
+ const structure = markup ? parseNodes(markup, 0, ctx).nodes[0] : void 0;
1215
+ return { structure, css, javascript, defineVars };
1216
+ }
1217
+ function parsePageRoot(body, ctx) {
1218
+ const trimmed = body.trim();
1219
+ if (!trimmed.startsWith("<")) return void 0;
1220
+ const wrapper = parseElement(trimmed, 0, ctx).node;
1221
+ const children = wrapper.children;
1222
+ return Array.isArray(children) ? children[0] : void 0;
1223
+ }
1224
+ function parseFile(source) {
1225
+ const { code, body } = splitFrontmatter(source);
1226
+ const front = parseFrontmatter(code);
1227
+ if (front.kind === "component") {
1228
+ const { structure, css, javascript, defineVars } = splitComponentBody(body, front.ctx);
1229
+ const def = {};
1230
+ if (front.propsInterface && Object.keys(front.propsInterface).length) {
1231
+ def.interface = front.propsInterface;
1232
+ }
1233
+ if (structure !== void 0) def.structure = structure;
1234
+ Object.assign(def, front.componentMeta);
1235
+ if (css !== void 0) def.css = css;
1236
+ if (javascript !== void 0) def.javascript = javascript;
1237
+ if (defineVars !== void 0) def.defineVars = defineVars;
1238
+ return { model: { component: def } };
1239
+ }
1240
+ const root = parsePageRoot(body, front.ctx);
1241
+ const page = {};
1242
+ if (front.meta !== void 0) page.meta = front.meta;
1243
+ if (root !== void 0) page.root = root;
1244
+ return { model: page };
1245
+ }
1246
+
1247
+ // lib/dialect/normalize.ts
1248
+ function hasStyleContent2(style) {
1249
+ if (!style || typeof style !== "object") return false;
1250
+ for (const v of Object.values(style)) {
1251
+ if (v === void 0 || v === null) continue;
1252
+ if (typeof v === "object") {
1253
+ if (Object.keys(v).length > 0) return true;
1254
+ } else {
1255
+ return true;
1256
+ }
1257
+ }
1258
+ return false;
1259
+ }
1260
+ function normalizeChildren(children) {
1261
+ if (typeof children === "string") return children;
1262
+ if (!Array.isArray(children)) return void 0;
1263
+ const items = children.map(normalizeChild);
1264
+ if (items.length === 0) return void 0;
1265
+ if (items.length === 1 && typeof items[0] === "string") return items[0];
1266
+ return items;
1267
+ }
1268
+ function normalizeChild(child) {
1269
+ return typeof child === "string" ? child : normalizeNode(child);
1270
+ }
1271
+ function migrateLegacy(n) {
1272
+ if (n.type === "cms-list") {
1273
+ const { type, collection, style, attributes, children, ...rest } = n;
1274
+ const list = {
1275
+ type: "list",
1276
+ sourceType: "collection",
1277
+ source: collection,
1278
+ ...rest
1279
+ };
1280
+ if (list.itemAs === void 0) list.itemAs = "item";
1281
+ if (children !== void 0) list.children = children;
1282
+ if (style !== void 0 || attributes !== void 0) {
1283
+ const wrapper = { type: "node", tag: "div" };
1284
+ if (style !== void 0) wrapper.style = style;
1285
+ if (attributes !== void 0) wrapper.attributes = attributes;
1286
+ wrapper.children = [list];
1287
+ return wrapper;
1288
+ }
1289
+ return list;
1290
+ }
1291
+ if (n.type === "image") {
1292
+ const { type, src, alt, style, attributes, ...rest } = n;
1293
+ const attrs = { ...attributes };
1294
+ if (src !== void 0) attrs.src = src;
1295
+ if (alt !== void 0) attrs.alt = alt;
1296
+ const img = { type: "node", tag: "img", ...rest };
1297
+ if (Object.keys(attrs).length) img.attributes = attrs;
1298
+ if (style !== void 0) img.style = style;
1299
+ return img;
1300
+ }
1301
+ return n;
1302
+ }
1303
+ function normalizeNode(node) {
1304
+ if (typeof node === "string") return node;
1305
+ if (!node || typeof node !== "object") return node;
1306
+ const out = migrateLegacy({ ...node });
1307
+ if ("style" in out && !hasStyleContent2(out.style)) delete out.style;
1308
+ if (out.type === "node" && out.props && typeof out.props === "object") {
1309
+ out.attributes = { ...out.props, ...out.attributes ?? {} };
1310
+ delete out.props;
1311
+ }
1312
+ if (out.type === "list") {
1313
+ const sourceType = out.sourceType ?? "prop";
1314
+ if (sourceType !== "collection" && typeof out.source === "string" && !out.source.includes("{{")) {
1315
+ out.source = `{{${out.source}}}`;
1316
+ }
1317
+ const defaultItem = sourceType === "collection" ? singularize(String(out.source)) : "item";
1318
+ if (out.itemAs === defaultItem) delete out.itemAs;
1319
+ }
1320
+ if ("children" in out) {
1321
+ const c = normalizeChildren(out.children);
1322
+ if (c === void 0) delete out.children;
1323
+ else out.children = c;
1324
+ }
1325
+ if ("default" in out) {
1326
+ const d = normalizeChildren(out.default);
1327
+ if (d === void 0) delete out.default;
1328
+ else out.default = d;
1329
+ }
1330
+ return out;
1331
+ }
1332
+ function normalizeDefineVars(comp) {
1333
+ if (comp.defineVars === void 0) return;
1334
+ if (!comp.javascript) {
1335
+ delete comp.defineVars;
1336
+ return;
1337
+ }
1338
+ if (Array.isArray(comp.defineVars)) {
1339
+ const names = comp.defineVars;
1340
+ const all = Object.keys(comp.interface ?? {}).filter(
1341
+ (k) => k !== "children"
1342
+ );
1343
+ const sameSet = names.length === all.length && new Set(names).size === all.length && all.every((k) => names.includes(k));
1344
+ if (sameSet) comp.defineVars = true;
1345
+ }
1346
+ }
1347
+ function normalizeModel(model) {
1348
+ if (!model || typeof model !== "object") return model;
1349
+ const m = model;
1350
+ if (m.component && typeof m.component === "object") {
1351
+ const comp = { ...m.component };
1352
+ if ("interface" in comp && (!comp.interface || Object.keys(comp.interface).length === 0)) {
1353
+ delete comp.interface;
1354
+ }
1355
+ if (comp.structure !== void 0) comp.structure = normalizeNode(comp.structure);
1356
+ normalizeDefineVars(comp);
1357
+ return { ...m, component: comp };
1358
+ }
1359
+ const out = { ...m };
1360
+ if ("meta" in out && (!out.meta || Object.keys(out.meta).length === 0)) delete out.meta;
1361
+ if (out.root !== void 0) out.root = normalizeNode(out.root);
1362
+ return out;
1363
+ }
1364
+
1365
+ // lib/dialect/index.ts
1366
+ function emit(model) {
1367
+ const m = normalizeModel(model);
1368
+ if (m && typeof m === "object") {
1369
+ if (m.component && typeof m.component === "object") return emitComponent(m.component);
1370
+ if (m.structure !== void 0 || m.interface !== void 0 || m.javascript !== void 0 || m.css !== void 0) {
1371
+ return emitComponent(m);
1372
+ }
1373
+ }
1374
+ return emitPage(m);
1375
+ }
1376
+ function parse(source) {
1377
+ const { model } = parseFile(source);
1378
+ return { model: normalizeModel(model), regions: [] };
1379
+ }
1380
+ export {
1381
+ emit,
1382
+ normalizeModel,
1383
+ parse
1384
+ };
1385
+ //# sourceMappingURL=index.js.map