meno-core 1.0.39 → 1.0.40
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build-astro.ts +195 -68
- package/dist/bin/cli.js +1 -1
- package/dist/build-static.js +6 -6
- package/dist/chunks/{chunk-WK5XLASY.js → chunk-3NOZVNM4.js} +3 -3
- package/dist/chunks/{chunk-W6HDII4T.js → chunk-GKICS7CF.js} +27 -14
- package/dist/chunks/chunk-GKICS7CF.js.map +7 -0
- package/dist/chunks/{chunk-P3FX5HJM.js → chunk-LOJLO2EY.js} +1 -1
- package/dist/chunks/chunk-LOJLO2EY.js.map +7 -0
- package/dist/chunks/{chunk-HNAS6BSS.js → chunk-MOCRENNU.js} +55 -5
- package/dist/chunks/{chunk-HNAS6BSS.js.map → chunk-MOCRENNU.js.map} +3 -3
- package/dist/chunks/{chunk-NV25WXCA.js → chunk-OJ5SROQN.js} +5 -3
- package/dist/chunks/chunk-OJ5SROQN.js.map +7 -0
- package/dist/chunks/{chunk-AIXKUVNG.js → chunk-V4SVSX3X.js} +3 -3
- package/dist/chunks/{chunk-KULPBDC7.js → chunk-Z7SAOCDG.js} +5 -2
- package/dist/chunks/{chunk-KULPBDC7.js.map → chunk-Z7SAOCDG.js.map} +2 -2
- package/dist/chunks/{constants-5CRJRQNR.js → constants-L75FR445.js} +2 -2
- package/dist/entries/server-router.js +6 -6
- package/dist/lib/client/index.js +5 -5
- package/dist/lib/client/index.js.map +2 -2
- package/dist/lib/server/index.js +2007 -197
- package/dist/lib/server/index.js.map +4 -4
- package/dist/lib/shared/index.js +3 -3
- package/dist/lib/test-utils/index.js +1 -1
- package/lib/client/core/builders/embedBuilder.ts +2 -2
- package/lib/server/astro/cmsPageEmitter.ts +417 -0
- package/lib/server/astro/componentEmitter.ts +90 -5
- package/lib/server/astro/nodeToAstro.ts +830 -37
- package/lib/server/astro/pageEmitter.ts +39 -3
- package/lib/server/astro/tailwindMapper.ts +69 -8
- package/lib/server/astro/templateTransformer.ts +107 -0
- package/lib/server/index.ts +9 -0
- package/lib/server/routes/api/components.ts +62 -0
- package/lib/server/routes/api/core-routes.ts +8 -0
- package/lib/server/ssr/ssrRenderer.ts +30 -10
- package/lib/server/webflow/buildWebflow.ts +415 -0
- package/lib/server/webflow/index.ts +22 -0
- package/lib/server/webflow/nodeToWebflow.ts +423 -0
- package/lib/server/webflow/styleMapper.ts +241 -0
- package/lib/server/webflow/types.ts +196 -0
- package/lib/shared/constants.ts +2 -0
- package/lib/shared/types/components.ts +1 -0
- package/lib/shared/validation/schemas.ts +1 -0
- package/package.json +1 -1
- package/dist/chunks/chunk-NV25WXCA.js.map +0 -7
- package/dist/chunks/chunk-P3FX5HJM.js.map +0 -7
- package/dist/chunks/chunk-W6HDII4T.js.map +0 -7
- /package/dist/chunks/{chunk-WK5XLASY.js.map → chunk-3NOZVNM4.js.map} +0 -0
- /package/dist/chunks/{chunk-AIXKUVNG.js.map → chunk-V4SVSX3X.js.map} +0 -0
- /package/dist/chunks/{constants-5CRJRQNR.js.map → constants-L75FR445.js.map} +0 -0
package/dist/lib/server/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
} from "../../chunks/chunk-4OFZP5NQ.js";
|
|
4
4
|
import {
|
|
5
5
|
buildStaticPages
|
|
6
|
-
} from "../../chunks/chunk-
|
|
6
|
+
} from "../../chunks/chunk-3NOZVNM4.js";
|
|
7
7
|
import {
|
|
8
8
|
ComponentService,
|
|
9
9
|
EnumService,
|
|
@@ -32,7 +32,7 @@ import {
|
|
|
32
32
|
logResponseTime,
|
|
33
33
|
withErrorHandling,
|
|
34
34
|
withLogging
|
|
35
|
-
} from "../../chunks/chunk-
|
|
35
|
+
} from "../../chunks/chunk-MOCRENNU.js";
|
|
36
36
|
import {
|
|
37
37
|
CMSService,
|
|
38
38
|
ColorService,
|
|
@@ -43,6 +43,7 @@ import {
|
|
|
43
43
|
buildAttributes,
|
|
44
44
|
buildComponentHTML,
|
|
45
45
|
buildImageMetadataMap,
|
|
46
|
+
buildSlugIndex,
|
|
46
47
|
clearJSValidationCache,
|
|
47
48
|
collectComponentCSS,
|
|
48
49
|
collectComponentJavaScript,
|
|
@@ -75,8 +76,9 @@ import {
|
|
|
75
76
|
renderPageSSR,
|
|
76
77
|
resetFontConfig,
|
|
77
78
|
styleToString,
|
|
79
|
+
translatePath,
|
|
78
80
|
variableService
|
|
79
|
-
} from "../../chunks/chunk-
|
|
81
|
+
} from "../../chunks/chunk-GKICS7CF.js";
|
|
80
82
|
import {
|
|
81
83
|
ConfigService,
|
|
82
84
|
configService
|
|
@@ -110,18 +112,23 @@ import {
|
|
|
110
112
|
writeFile
|
|
111
113
|
} from "../../chunks/chunk-WQFG7PAH.js";
|
|
112
114
|
import "../../chunks/chunk-LIHJ6OUH.js";
|
|
113
|
-
import "../../chunks/chunk-
|
|
114
|
-
import "../../chunks/chunk-
|
|
115
|
+
import "../../chunks/chunk-LOJLO2EY.js";
|
|
116
|
+
import "../../chunks/chunk-V4SVSX3X.js";
|
|
115
117
|
import {
|
|
116
118
|
extractInteractiveStyleMappings,
|
|
119
|
+
extractUtilityClassesFromHTML,
|
|
117
120
|
generateAllInteractiveCSS,
|
|
118
121
|
generateElementClassName,
|
|
122
|
+
generateUtilityCSS,
|
|
119
123
|
hasInteractiveStyleMappings,
|
|
120
124
|
isItemDraftForLocale,
|
|
121
|
-
isVoidElement
|
|
122
|
-
|
|
125
|
+
isVoidElement,
|
|
126
|
+
singularize
|
|
127
|
+
} from "../../chunks/chunk-OJ5SROQN.js";
|
|
123
128
|
import {
|
|
124
129
|
DEFAULT_BREAKPOINTS,
|
|
130
|
+
DEFAULT_I18N_CONFIG,
|
|
131
|
+
buildLocalizedPath,
|
|
125
132
|
isI18nValue,
|
|
126
133
|
resolveI18nValue
|
|
127
134
|
} from "../../chunks/chunk-PGH3ATYI.js";
|
|
@@ -130,10 +137,11 @@ import {
|
|
|
130
137
|
HMR_ROUTE,
|
|
131
138
|
MAX_PORT_ATTEMPTS,
|
|
132
139
|
NODE_TYPE,
|
|
140
|
+
RAW_HTML_PREFIX,
|
|
133
141
|
SERVER_PORT,
|
|
134
142
|
SERVE_PORT,
|
|
135
143
|
init_constants
|
|
136
|
-
} from "../../chunks/chunk-
|
|
144
|
+
} from "../../chunks/chunk-Z7SAOCDG.js";
|
|
137
145
|
import "../../chunks/chunk-KSBZ2L7C.js";
|
|
138
146
|
|
|
139
147
|
// build-astro.ts
|
|
@@ -374,7 +382,11 @@ var singleValueMatches = {
|
|
|
374
382
|
"top:0": "top-0",
|
|
375
383
|
"right:0": "right-0",
|
|
376
384
|
"bottom:0": "bottom-0",
|
|
377
|
-
"left:0": "left-0"
|
|
385
|
+
"left:0": "left-0",
|
|
386
|
+
"outline:none": "[outline:none]",
|
|
387
|
+
"background:none": "[background:none]",
|
|
388
|
+
"background:transparent": "[background:transparent]",
|
|
389
|
+
"backgroundColor:transparent": "bg-transparent"
|
|
378
390
|
};
|
|
379
391
|
var arbitraryPrefixMap = {
|
|
380
392
|
// Spacing
|
|
@@ -433,7 +445,7 @@ var arbitraryPrefixMap = {
|
|
|
433
445
|
backdropFilter: "backdrop",
|
|
434
446
|
transform: "[transform]",
|
|
435
447
|
transformOrigin: "origin",
|
|
436
|
-
transition: "transition",
|
|
448
|
+
transition: "[transition]",
|
|
437
449
|
mixBlendMode: "mix-blend",
|
|
438
450
|
clipPath: "[clip-path]",
|
|
439
451
|
// Positioning
|
|
@@ -485,10 +497,29 @@ function propertyToTailwind(property, value) {
|
|
|
485
497
|
if (property === "color" || property === "backgroundColor" || property === "borderColor") {
|
|
486
498
|
const prefix = property === "color" ? "text" : property === "backgroundColor" ? "bg" : "border";
|
|
487
499
|
if (strValue.includes("var(")) {
|
|
488
|
-
return `${prefix}-[
|
|
500
|
+
return `${prefix}-[color:${strValue}]`;
|
|
489
501
|
}
|
|
490
502
|
if (!strValue.match(/^[#\d]/) && !strValue.includes("rgb") && !strValue.includes("hsl")) {
|
|
491
|
-
return `${prefix}-[var(--${strValue})]`;
|
|
503
|
+
return `${prefix}-[color:var(--${strValue})]`;
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
if (property === "borderColor" || property === "color") {
|
|
507
|
+
const prefix = property === "color" ? "text" : "border";
|
|
508
|
+
const sanitized2 = strValue.replace(/\s+/g, "_");
|
|
509
|
+
return `${prefix}-[color:${sanitized2}]`;
|
|
510
|
+
}
|
|
511
|
+
if (property === "border" || property === "borderTop" || property === "borderRight" || property === "borderBottom" || property === "borderLeft") {
|
|
512
|
+
if (strValue.includes("solid") || strValue.includes("dashed") || strValue.includes("dotted") || strValue.includes("none")) {
|
|
513
|
+
const cssProp = property.replace(/([A-Z])/g, "-$1").toLowerCase();
|
|
514
|
+
const sanitized2 = strValue.replace(/\s+/g, "_");
|
|
515
|
+
return `[${cssProp}:${sanitized2}]`;
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
if (property === "background") {
|
|
519
|
+
const isSimpleColor = /^(#[0-9a-fA-F]{3,8}|rgb|hsl|var\()/.test(strValue);
|
|
520
|
+
if (!isSimpleColor) {
|
|
521
|
+
const sanitized2 = strValue.replace(/\s+/g, "_");
|
|
522
|
+
return `[background:${sanitized2}]`;
|
|
492
523
|
}
|
|
493
524
|
}
|
|
494
525
|
const twPrefix = arbitraryPrefixMap[property];
|
|
@@ -502,14 +533,28 @@ function propertyToTailwind(property, value) {
|
|
|
502
533
|
return `${twPrefix.slice(0, -1)}:${sanitized2}]`;
|
|
503
534
|
}
|
|
504
535
|
const sanitized = strValue.replace(/\s+/g, "_");
|
|
505
|
-
if (property === "
|
|
506
|
-
return
|
|
536
|
+
if (property === "fontSize") {
|
|
537
|
+
return `text-[length:${sanitized}]`;
|
|
538
|
+
}
|
|
539
|
+
if (property === "fontFamily") {
|
|
540
|
+
return `font-[family-name:${sanitized}]`;
|
|
541
|
+
}
|
|
542
|
+
if (property === "fontWeight") {
|
|
543
|
+
return `font-[number:${sanitized}]`;
|
|
507
544
|
}
|
|
508
545
|
return `${twPrefix}-[${sanitized}]`;
|
|
509
546
|
}
|
|
510
547
|
function stylesToTailwind(style) {
|
|
511
548
|
const classes = [];
|
|
512
549
|
const dynamicStyles = {};
|
|
550
|
+
const hasBorderColor = "borderColor" in style && !isStyleMapping(style.borderColor);
|
|
551
|
+
const borderShorthands = /* @__PURE__ */ new Set([
|
|
552
|
+
"border",
|
|
553
|
+
"borderTop",
|
|
554
|
+
"borderRight",
|
|
555
|
+
"borderBottom",
|
|
556
|
+
"borderLeft"
|
|
557
|
+
]);
|
|
513
558
|
for (const [prop, value] of Object.entries(style)) {
|
|
514
559
|
if (isStyleMapping(value)) continue;
|
|
515
560
|
const strValue = String(value);
|
|
@@ -518,6 +563,15 @@ function stylesToTailwind(style) {
|
|
|
518
563
|
dynamicStyles[cssProp] = strValue;
|
|
519
564
|
continue;
|
|
520
565
|
}
|
|
566
|
+
if (hasBorderColor && borderShorthands.has(prop)) {
|
|
567
|
+
const parts = strValue.split(/\s+/);
|
|
568
|
+
const width = parts.find((p) => /^\d/.test(p) || p === "0");
|
|
569
|
+
const borderStyle = parts.find((p) => /^(solid|dashed|dotted|double|groove|ridge|inset|outset|none|hidden)$/.test(p));
|
|
570
|
+
const cssProp = prop.replace(/([A-Z])/g, "-$1").toLowerCase();
|
|
571
|
+
if (width) classes.push(`[${cssProp}-width:${width}]`);
|
|
572
|
+
if (borderStyle) classes.push(`[${cssProp}-style:${borderStyle}]`);
|
|
573
|
+
continue;
|
|
574
|
+
}
|
|
521
575
|
const twClass = propertyToTailwind(prop, value);
|
|
522
576
|
if (twClass) {
|
|
523
577
|
classes.push(twClass);
|
|
@@ -569,15 +623,121 @@ function responsiveStylesToTailwind(style, breakpoints) {
|
|
|
569
623
|
|
|
570
624
|
// lib/server/astro/nodeToAstro.ts
|
|
571
625
|
init_constants();
|
|
626
|
+
|
|
627
|
+
// lib/server/astro/templateTransformer.ts
|
|
628
|
+
var CMS_TEMPLATE_PATTERN = /\{\{cms\.([^}]+)\}\}/g;
|
|
629
|
+
var ITEM_TEMPLATE_PATTERN = /\{\{([^}]+)\}\}/g;
|
|
630
|
+
function isTemplateExpression(text) {
|
|
631
|
+
return /\{\{.+?\}\}/.test(text);
|
|
632
|
+
}
|
|
633
|
+
function transformCMSTemplate(text, binding = "entry", richTextFields, wrapFn) {
|
|
634
|
+
const w = (expr) => wrapFn ? `${wrapFn}(${expr})` : expr;
|
|
635
|
+
const fullMatch = text.match(/^\{\{cms\.([^}]+)\}\}$/);
|
|
636
|
+
if (fullMatch) {
|
|
637
|
+
const fieldPath = fullMatch[1].trim();
|
|
638
|
+
const topLevelField = fieldPath.split(".")[0];
|
|
639
|
+
if (richTextFields?.has(topLevelField)) {
|
|
640
|
+
return `<Fragment set:html={${w(`${binding}.data.${fieldPath}`)}} />`;
|
|
641
|
+
}
|
|
642
|
+
return `{${w(`${binding}.data.${fieldPath}`)}}`;
|
|
643
|
+
}
|
|
644
|
+
if (CMS_TEMPLATE_PATTERN.test(text)) {
|
|
645
|
+
CMS_TEMPLATE_PATTERN.lastIndex = 0;
|
|
646
|
+
const replaced = text.replace(CMS_TEMPLATE_PATTERN, (_, fieldPath) => {
|
|
647
|
+
return `\${${w(`${binding}.data.${fieldPath.trim()}`)}}`;
|
|
648
|
+
});
|
|
649
|
+
return `{\`${replaced}\`}`;
|
|
650
|
+
}
|
|
651
|
+
return text;
|
|
652
|
+
}
|
|
653
|
+
function rewriteItemVar(expr, itemVar) {
|
|
654
|
+
if (itemVar === "item") return expr;
|
|
655
|
+
return expr.replace(/\bitem\./g, `${itemVar}.`);
|
|
656
|
+
}
|
|
657
|
+
function replaceItemMetaVars(expr, indexVar, sourceVar, itemVar) {
|
|
658
|
+
const lastExpr = sourceVar ? `(${indexVar} === ${sourceVar}.length - 1)` : `false /* itemLast not supported */`;
|
|
659
|
+
let result = expr.replace(/\bitemIndex\b/g, indexVar).replace(/\bitemFirst\b/g, `(${indexVar} === 0)`).replace(/\bitemLast\b/g, lastExpr);
|
|
660
|
+
if (itemVar) result = rewriteItemVar(result, itemVar);
|
|
661
|
+
return result;
|
|
662
|
+
}
|
|
663
|
+
function transformItemTemplate(text, itemVar = "item", indexVar, sourceVar) {
|
|
664
|
+
const fullMatch = text.match(/^\{\{(.+)\}\}$/);
|
|
665
|
+
if (fullMatch) {
|
|
666
|
+
let expr = fullMatch[1].trim();
|
|
667
|
+
expr = rewriteItemVar(expr, itemVar);
|
|
668
|
+
if (indexVar) expr = replaceItemMetaVars(expr, indexVar, sourceVar);
|
|
669
|
+
if (expr.startsWith(`${itemVar}.`)) {
|
|
670
|
+
return `{${expr}}`;
|
|
671
|
+
}
|
|
672
|
+
return `{${expr}}`;
|
|
673
|
+
}
|
|
674
|
+
if (ITEM_TEMPLATE_PATTERN.test(text)) {
|
|
675
|
+
ITEM_TEMPLATE_PATTERN.lastIndex = 0;
|
|
676
|
+
const replaced = text.replace(ITEM_TEMPLATE_PATTERN, (_, expr) => {
|
|
677
|
+
let trimmed = expr.trim();
|
|
678
|
+
trimmed = rewriteItemVar(trimmed, itemVar);
|
|
679
|
+
if (indexVar) trimmed = replaceItemMetaVars(trimmed, indexVar, sourceVar);
|
|
680
|
+
return `\${${trimmed}}`;
|
|
681
|
+
});
|
|
682
|
+
return `{\`${replaced}\`}`;
|
|
683
|
+
}
|
|
684
|
+
return text;
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
// lib/server/astro/nodeToAstro.ts
|
|
572
688
|
function ind(ctx) {
|
|
573
689
|
return " ".repeat(ctx.indent);
|
|
574
690
|
}
|
|
691
|
+
function localizeHref(href, ctx) {
|
|
692
|
+
if (!href.startsWith("/") || href.startsWith("//")) return href;
|
|
693
|
+
const { locale, i18nDefaultLocale, slugMappings } = ctx;
|
|
694
|
+
if (!locale || !i18nDefaultLocale) return href;
|
|
695
|
+
if (slugMappings && slugMappings.length > 0) {
|
|
696
|
+
const slugIndex = buildSlugIndex(slugMappings);
|
|
697
|
+
return translatePath(href, locale, i18nDefaultLocale, i18nDefaultLocale, slugIndex);
|
|
698
|
+
} else if (locale !== i18nDefaultLocale) {
|
|
699
|
+
return buildLocalizedPath(href, locale);
|
|
700
|
+
}
|
|
701
|
+
return href;
|
|
702
|
+
}
|
|
575
703
|
function isStyleMapping2(value) {
|
|
576
704
|
return typeof value === "object" && value !== null && "_mapping" in value && value._mapping === true;
|
|
577
705
|
}
|
|
578
706
|
function isLinkMapping(value) {
|
|
579
707
|
return typeof value === "object" && value !== null && "_mapping" in value && value._mapping === true;
|
|
580
708
|
}
|
|
709
|
+
function emitAttrValue(key, value, ctx) {
|
|
710
|
+
if (ctx.cmsMode && /\{\{cms\./.test(value)) {
|
|
711
|
+
const b = ctx.cmsEntryBinding || "entry";
|
|
712
|
+
const w = (expr) => ctx.cmsWrapFn ? `${ctx.cmsWrapFn}(${expr})` : expr;
|
|
713
|
+
const fullMatch = value.match(/^\{\{cms\.([^}]+)\}\}$/);
|
|
714
|
+
if (fullMatch) {
|
|
715
|
+
return `${key}={${w(`${b}.data.${fullMatch[1].trim()}`)}}`;
|
|
716
|
+
}
|
|
717
|
+
const replaced = value.replace(
|
|
718
|
+
/\{\{cms\.([^}]+)\}\}/g,
|
|
719
|
+
(_, fp) => `\${${w(`${b}.data.${fp.trim()}`)}}`
|
|
720
|
+
);
|
|
721
|
+
return `${key}={\`${replaced}\`}`;
|
|
722
|
+
}
|
|
723
|
+
if (ctx.listItemBinding && /\{\{/.test(value)) {
|
|
724
|
+
const fullMatch = value.match(/^\{\{(.+)\}\}$/);
|
|
725
|
+
if (fullMatch) {
|
|
726
|
+
let expr = fullMatch[1].trim();
|
|
727
|
+
expr = rewriteItemVar(expr, ctx.listItemBinding);
|
|
728
|
+
if (ctx.listIndexVar) expr = replaceItemMetaVars(expr, ctx.listIndexVar, ctx.listSourceVar);
|
|
729
|
+
return `${key}={${expr}}`;
|
|
730
|
+
}
|
|
731
|
+
const replaced = value.replace(/\{\{(.+?)\}\}/g, (_, expr) => {
|
|
732
|
+
let trimmed = expr.trim();
|
|
733
|
+
trimmed = rewriteItemVar(trimmed, ctx.listItemBinding);
|
|
734
|
+
if (ctx.listIndexVar) trimmed = replaceItemMetaVars(trimmed, ctx.listIndexVar, ctx.listSourceVar);
|
|
735
|
+
return `\${${trimmed}}`;
|
|
736
|
+
});
|
|
737
|
+
return `${key}={\`${replaced}\`}`;
|
|
738
|
+
}
|
|
739
|
+
return `${key}="${escapeJSX(value)}"`;
|
|
740
|
+
}
|
|
581
741
|
function isHtmlMapping(value) {
|
|
582
742
|
return typeof value === "object" && value !== null && "_mapping" in value && value._mapping === true;
|
|
583
743
|
}
|
|
@@ -622,13 +782,13 @@ function mappingToClassListEntries(mapping, property, breakpointPrefix, ctx) {
|
|
|
622
782
|
const cls1 = getClassForValue(property, css1, breakpointPrefix);
|
|
623
783
|
const cls2 = getClassForValue(property, css2, breakpointPrefix);
|
|
624
784
|
if (cls1 && cls2) {
|
|
625
|
-
entries.push(
|
|
785
|
+
entries.push(`String(${propRef}) === ${JSON.stringify(String(coerceValue(val1)))} ? '${cls1}' : '${cls2}'`);
|
|
626
786
|
}
|
|
627
787
|
} else {
|
|
628
788
|
for (const [val, cssValue] of values) {
|
|
629
789
|
const cls = getClassForValue(property, cssValue, breakpointPrefix);
|
|
630
790
|
if (cls) {
|
|
631
|
-
entries.push(
|
|
791
|
+
entries.push(`String(${propRef}) === ${JSON.stringify(String(coerceValue(val)))} && '${cls}'`);
|
|
632
792
|
}
|
|
633
793
|
}
|
|
634
794
|
}
|
|
@@ -663,12 +823,22 @@ function buildClassAndStyleExpression(style, interactiveStyles, elementClass, ct
|
|
|
663
823
|
if (Object.keys(dynamicStyles).length > 0 && ctx.isComponentDef) {
|
|
664
824
|
const styleParts = [];
|
|
665
825
|
for (const [cssProp, value] of Object.entries(dynamicStyles)) {
|
|
666
|
-
const resolved = value.replace(/\{\{(.+?)\}\}/g, (_, expr) =>
|
|
826
|
+
const resolved = value.replace(/\{\{(.+?)\}\}/g, (_, expr) => {
|
|
827
|
+
let trimmed = expr.trim();
|
|
828
|
+
if (ctx.listItemBinding) trimmed = rewriteItemVar(trimmed, ctx.listItemBinding);
|
|
829
|
+
if (ctx.listIndexVar) trimmed = replaceItemMetaVars(trimmed, ctx.listIndexVar, ctx.listSourceVar);
|
|
830
|
+
return `\${${trimmed}}`;
|
|
831
|
+
});
|
|
667
832
|
styleParts.push(`${cssProp}: \${${resolved.includes("${") ? resolved.replace(/\$\{(.+?)\}/g, "$1") : `'${resolved}'`}}`);
|
|
668
833
|
}
|
|
669
834
|
const entries = [];
|
|
670
835
|
for (const [cssProp, value] of Object.entries(dynamicStyles)) {
|
|
671
|
-
const resolved = value.replace(/\{\{(.+?)\}\}/g, (_, expr) =>
|
|
836
|
+
const resolved = value.replace(/\{\{(.+?)\}\}/g, (_, expr) => {
|
|
837
|
+
let trimmed = expr.trim();
|
|
838
|
+
if (ctx.listItemBinding) trimmed = rewriteItemVar(trimmed, ctx.listItemBinding);
|
|
839
|
+
if (ctx.listIndexVar) trimmed = replaceItemMetaVars(trimmed, ctx.listIndexVar, ctx.listSourceVar);
|
|
840
|
+
return `\${${trimmed}}`;
|
|
841
|
+
});
|
|
672
842
|
entries.push(`${cssProp}: ${resolved}`);
|
|
673
843
|
}
|
|
674
844
|
styleAttr = ` style={\`${entries.join("; ")}\`}`;
|
|
@@ -723,9 +893,20 @@ function resolveTemplate(text, ctx) {
|
|
|
723
893
|
}
|
|
724
894
|
const fullMatch = text.match(/^\{\{(.+)\}\}$/);
|
|
725
895
|
if (fullMatch) {
|
|
726
|
-
|
|
896
|
+
let propName = fullMatch[1].trim();
|
|
897
|
+
if (ctx.listItemBinding) propName = rewriteItemVar(propName, ctx.listItemBinding);
|
|
898
|
+
if (ctx.listIndexVar) propName = replaceItemMetaVars(propName, ctx.listIndexVar, ctx.listSourceVar);
|
|
899
|
+
if (ctx.componentProps[propName]?.type === "rich-text") {
|
|
900
|
+
return `<Fragment set:html={${propName}} />`;
|
|
901
|
+
}
|
|
902
|
+
return `{${propName}}`;
|
|
727
903
|
}
|
|
728
|
-
return text.replace(/\{\{(.+?)\}\}/g, (_, expr) =>
|
|
904
|
+
return text.replace(/\{\{(.+?)\}\}/g, (_, expr) => {
|
|
905
|
+
let trimmed = expr.trim();
|
|
906
|
+
if (ctx.listItemBinding) trimmed = rewriteItemVar(trimmed, ctx.listItemBinding);
|
|
907
|
+
if (ctx.listIndexVar) trimmed = replaceItemMetaVars(trimmed, ctx.listIndexVar, ctx.listSourceVar);
|
|
908
|
+
return `{${trimmed}}`;
|
|
909
|
+
});
|
|
729
910
|
}
|
|
730
911
|
function hasTemplates(text) {
|
|
731
912
|
return /\{\{.+?\}\}/.test(text);
|
|
@@ -749,11 +930,53 @@ function buildAttributesString(attributes, ctx) {
|
|
|
749
930
|
if (hasTemplates(strVal) && ctx.isComponentDef) {
|
|
750
931
|
const fullMatch = strVal.match(/^\{\{(.+)\}\}$/);
|
|
751
932
|
if (fullMatch) {
|
|
752
|
-
|
|
933
|
+
let expr = fullMatch[1].trim();
|
|
934
|
+
if (ctx.listItemBinding) expr = rewriteItemVar(expr, ctx.listItemBinding);
|
|
935
|
+
if (ctx.listIndexVar) expr = replaceItemMetaVars(expr, ctx.listIndexVar, ctx.listSourceVar);
|
|
936
|
+
const propDef = ctx.componentProps[expr];
|
|
937
|
+
if (propDef && propDef.type === "link") {
|
|
938
|
+
parts.push(`${key}={${expr}?.href ?? "#"}`);
|
|
939
|
+
} else {
|
|
940
|
+
parts.push(`${key}={${expr} || undefined}`);
|
|
941
|
+
}
|
|
942
|
+
} else {
|
|
943
|
+
const resolved = strVal.replace(/\{\{(.+?)\}\}/g, (_, expr) => {
|
|
944
|
+
let trimmed = expr.trim();
|
|
945
|
+
if (ctx.listItemBinding) trimmed = rewriteItemVar(trimmed, ctx.listItemBinding);
|
|
946
|
+
if (ctx.listIndexVar) trimmed = replaceItemMetaVars(trimmed, ctx.listIndexVar, ctx.listSourceVar);
|
|
947
|
+
const pd = ctx.componentProps[trimmed];
|
|
948
|
+
return pd?.type === "link" ? `\${${trimmed}?.href ?? "#"}` : `\${${trimmed}}`;
|
|
949
|
+
});
|
|
950
|
+
parts.push(`${key}={\`${resolved}\`}`);
|
|
951
|
+
}
|
|
952
|
+
} else if (ctx.listItemBinding && hasTemplates(strVal)) {
|
|
953
|
+
const fullMatch = strVal.match(/^\{\{(.+)\}\}$/);
|
|
954
|
+
if (fullMatch) {
|
|
955
|
+
let expr = fullMatch[1].trim();
|
|
956
|
+
expr = rewriteItemVar(expr, ctx.listItemBinding);
|
|
957
|
+
if (ctx.listIndexVar) expr = replaceItemMetaVars(expr, ctx.listIndexVar, ctx.listSourceVar);
|
|
958
|
+
parts.push(`${key}={${expr} || undefined}`);
|
|
753
959
|
} else {
|
|
754
|
-
const resolved = strVal.replace(/\{\{(.+?)\}\}/g, (_, expr) =>
|
|
960
|
+
const resolved = strVal.replace(/\{\{(.+?)\}\}/g, (_, expr) => {
|
|
961
|
+
let trimmed = expr.trim();
|
|
962
|
+
trimmed = rewriteItemVar(trimmed, ctx.listItemBinding);
|
|
963
|
+
if (ctx.listIndexVar) trimmed = replaceItemMetaVars(trimmed, ctx.listIndexVar, ctx.listSourceVar);
|
|
964
|
+
return `\${${trimmed}}`;
|
|
965
|
+
});
|
|
755
966
|
parts.push(`${key}={\`${resolved}\`}`);
|
|
756
967
|
}
|
|
968
|
+
} else if (ctx.cmsMode && /\{\{cms\./.test(strVal)) {
|
|
969
|
+
const b = ctx.cmsEntryBinding || "entry";
|
|
970
|
+
const w = (expr) => ctx.cmsWrapFn ? `${ctx.cmsWrapFn}(${expr})` : expr;
|
|
971
|
+
const fullMatch = strVal.match(/^\{\{cms\.([^}]+)\}\}$/);
|
|
972
|
+
if (fullMatch) {
|
|
973
|
+
parts.push(`${key}={${w(`${b}.data.${fullMatch[1].trim()}`)}}`);
|
|
974
|
+
} else {
|
|
975
|
+
const replaced = strVal.replace(/\{\{cms\.([^}]+)\}\}/g, (_, fieldPath) => {
|
|
976
|
+
return `\${${w(`${b}.data.${fieldPath.trim()}`)}}`;
|
|
977
|
+
});
|
|
978
|
+
parts.push(`${key}={\`${replaced}\`}`);
|
|
979
|
+
}
|
|
757
980
|
} else {
|
|
758
981
|
parts.push(`${key}="${escapeJSX(strVal)}"`);
|
|
759
982
|
}
|
|
@@ -768,11 +991,46 @@ function formatPropValue(value) {
|
|
|
768
991
|
if (value === null || value === void 0) return `{undefined}`;
|
|
769
992
|
return `{${JSON.stringify(value)}}`;
|
|
770
993
|
}
|
|
994
|
+
function resolveI18n(value, ctx) {
|
|
995
|
+
if (ctx.locale && isI18nValue(value)) {
|
|
996
|
+
return resolveI18nValue(value, ctx.locale, DEFAULT_I18N_CONFIG);
|
|
997
|
+
}
|
|
998
|
+
return value;
|
|
999
|
+
}
|
|
771
1000
|
function nodeToAstro(node, ctx) {
|
|
772
1001
|
if (node === null || node === void 0) return "";
|
|
1002
|
+
if (typeof node === "object" && !Array.isArray(node) && isI18nValue(node)) {
|
|
1003
|
+
const resolved = resolveI18n(node, ctx);
|
|
1004
|
+
if (typeof resolved === "string") {
|
|
1005
|
+
return `${ind(ctx)}${escapeJSX(resolved)}
|
|
1006
|
+
`;
|
|
1007
|
+
}
|
|
1008
|
+
if (ctx.isComponentDef && isI18nValue(resolved)) {
|
|
1009
|
+
ctx.needsI18nResolver = true;
|
|
1010
|
+
return `${ind(ctx)}{r(${JSON.stringify(resolved)})}
|
|
1011
|
+
`;
|
|
1012
|
+
}
|
|
1013
|
+
return `${ind(ctx)}${String(resolved ?? "")}
|
|
1014
|
+
`;
|
|
1015
|
+
}
|
|
773
1016
|
if (typeof node === "string") {
|
|
1017
|
+
if (ctx.cmsMode && isTemplateExpression(node) && /\{\{cms\./.test(node)) {
|
|
1018
|
+
const transformed = transformCMSTemplate(node, ctx.cmsEntryBinding || "entry", ctx.cmsRichTextFields, ctx.cmsWrapFn);
|
|
1019
|
+
return `${ind(ctx)}${transformed}
|
|
1020
|
+
`;
|
|
1021
|
+
}
|
|
1022
|
+
if (ctx.listItemBinding && isTemplateExpression(node)) {
|
|
1023
|
+
const transformed = transformItemTemplate(node, ctx.listItemBinding, ctx.listIndexVar, ctx.listSourceVar);
|
|
1024
|
+
return `${ind(ctx)}${transformed}
|
|
1025
|
+
`;
|
|
1026
|
+
}
|
|
774
1027
|
if (hasTemplates(node) && ctx.isComponentDef) {
|
|
775
1028
|
return `${ind(ctx)}${resolveTemplate(node, ctx)}
|
|
1029
|
+
`;
|
|
1030
|
+
}
|
|
1031
|
+
if (node.startsWith(RAW_HTML_PREFIX)) {
|
|
1032
|
+
const rawHtml = node.slice(RAW_HTML_PREFIX.length);
|
|
1033
|
+
return `${ind(ctx)}<Fragment set:html={\`${escapeTemplateLiteral(rawHtml)}\`} />
|
|
776
1034
|
`;
|
|
777
1035
|
}
|
|
778
1036
|
return `${ind(ctx)}${escapeJSX(node)}
|
|
@@ -787,7 +1045,7 @@ function nodeToAstro(node, ctx) {
|
|
|
787
1045
|
for (let i = 0; i < node.length; i++) {
|
|
788
1046
|
const child = node[i];
|
|
789
1047
|
const savedPath = [...ctx.elementPath];
|
|
790
|
-
ctx.elementPath = [...ctx.elementPath, i];
|
|
1048
|
+
ctx.elementPath = [...ctx.elementPath.slice(0, -1), i];
|
|
791
1049
|
result += nodeToAstro(child, ctx);
|
|
792
1050
|
ctx.elementPath = savedPath;
|
|
793
1051
|
}
|
|
@@ -805,16 +1063,116 @@ function nodeToAstro(node, ctx) {
|
|
|
805
1063
|
case NODE_TYPE.LINK:
|
|
806
1064
|
return emitLinkNode(node, ctx);
|
|
807
1065
|
case NODE_TYPE.LOCALE_LIST:
|
|
808
|
-
return
|
|
1066
|
+
return emitLocaleListNode(node, ctx);
|
|
809
1067
|
case NODE_TYPE.LIST:
|
|
810
1068
|
case "cms-list":
|
|
811
|
-
return
|
|
1069
|
+
return emitListNode(node, ctx);
|
|
1070
|
+
case "image":
|
|
1071
|
+
return emitImageTypeNode(node, ctx);
|
|
812
1072
|
default:
|
|
813
1073
|
return emitFallback(ctx);
|
|
814
1074
|
}
|
|
815
1075
|
}
|
|
1076
|
+
var IMG_TAILWIND_PREFIXES = ["object-", "rounded", "border", "shadow", "[filter", "[transform", "mix-blend"];
|
|
1077
|
+
var IMG_OPACITY_PATTERN = /^opacity-/;
|
|
1078
|
+
var DEFAULT_SIZES2 = "100vw";
|
|
1079
|
+
function splitImageClasses(allClasses) {
|
|
1080
|
+
const imgClasses = [];
|
|
1081
|
+
const pictureClasses = [];
|
|
1082
|
+
for (const cls of allClasses) {
|
|
1083
|
+
const baseCls = cls.includes(":") ? cls.split(":").pop() : cls;
|
|
1084
|
+
if (IMG_TAILWIND_PREFIXES.some((p) => baseCls.startsWith(p)) || IMG_OPACITY_PATTERN.test(baseCls)) {
|
|
1085
|
+
imgClasses.push(cls);
|
|
1086
|
+
} else {
|
|
1087
|
+
pictureClasses.push(cls);
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1090
|
+
return { pictureClasses, imgClasses };
|
|
1091
|
+
}
|
|
1092
|
+
function emitImageNode(node, ctx) {
|
|
1093
|
+
const style = node.style;
|
|
1094
|
+
let elementClass = null;
|
|
1095
|
+
if (node.interactiveStyles && node.interactiveStyles.length > 0 || node.generateElementClass) {
|
|
1096
|
+
elementClass = buildElementClass(ctx, node.label);
|
|
1097
|
+
}
|
|
1098
|
+
const { classExpr, styleAttr } = buildClassAndStyleExpression(
|
|
1099
|
+
style,
|
|
1100
|
+
node.interactiveStyles,
|
|
1101
|
+
elementClass,
|
|
1102
|
+
ctx
|
|
1103
|
+
);
|
|
1104
|
+
const attrs = node.attributes || {};
|
|
1105
|
+
const src = attrs.src;
|
|
1106
|
+
const alt = attrs.alt;
|
|
1107
|
+
const loading = attrs.loading;
|
|
1108
|
+
const fetchpriority = attrs.fetchpriority;
|
|
1109
|
+
let width = attrs.width;
|
|
1110
|
+
let height = attrs.height;
|
|
1111
|
+
const sizes = attrs.sizes;
|
|
1112
|
+
const metadata = src ? ctx.imageMetadataMap?.get(String(src)) : void 0;
|
|
1113
|
+
if (metadata) {
|
|
1114
|
+
if (width === void 0 && metadata.width) width = metadata.width;
|
|
1115
|
+
if (height === void 0 && metadata.height) height = metadata.height;
|
|
1116
|
+
}
|
|
1117
|
+
const sizesValue = sizes || DEFAULT_SIZES2;
|
|
1118
|
+
const imageSpecificKeys = /* @__PURE__ */ new Set(["src", "alt", "loading", "width", "height", "sizes", "srcset", "fetchpriority"]);
|
|
1119
|
+
const otherAttrs = {};
|
|
1120
|
+
if (node.attributes) {
|
|
1121
|
+
for (const [k, v] of Object.entries(node.attributes)) {
|
|
1122
|
+
if (!imageSpecificKeys.has(k)) otherAttrs[k] = v;
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
const otherAttrsStr = buildAttributesString(otherAttrs, ctx);
|
|
1126
|
+
let imgAttrs = "";
|
|
1127
|
+
if (src) imgAttrs += ` ${emitAttrValue("src", String(src), ctx)}`;
|
|
1128
|
+
if (alt !== void 0) imgAttrs += ` ${emitAttrValue("alt", String(alt), ctx)}`;
|
|
1129
|
+
if (fetchpriority) imgAttrs += ` fetchpriority="${escapeJSX(String(fetchpriority))}"`;
|
|
1130
|
+
if (loading) imgAttrs += ` loading="${escapeJSX(String(loading))}"`;
|
|
1131
|
+
if (width !== void 0) imgAttrs += ` width="${escapeJSX(String(width))}"`;
|
|
1132
|
+
if (height !== void 0) imgAttrs += ` height="${escapeJSX(String(height))}"`;
|
|
1133
|
+
let blurStyle = "";
|
|
1134
|
+
if (metadata?.blurHash) {
|
|
1135
|
+
blurStyle = ` style="background-image: url(${escapeJSX(metadata.blurHash)}); background-size: cover;" onload="this.style.backgroundImage=''"`;
|
|
1136
|
+
}
|
|
1137
|
+
const ifExpr = emitIfOpen(node, ctx);
|
|
1138
|
+
const ifClose = emitIfClose(node, ctx);
|
|
1139
|
+
if (metadata?.avifSrcset) {
|
|
1140
|
+
const classMatch = classExpr.match(/class="([^"]*)"/);
|
|
1141
|
+
const classListMatch = classExpr.match(/class:list={\[(.+)\]}/);
|
|
1142
|
+
if (classListMatch) {
|
|
1143
|
+
return `${ifExpr}${ind(ctx)}<picture${classExpr}${styleAttr}>
|
|
1144
|
+
${ind(ctx)} <source type="image/avif" srcset="${escapeJSX(metadata.avifSrcset)}" sizes="${escapeJSX(sizesValue)}" />
|
|
1145
|
+
${ind(ctx)} <source type="image/webp" srcset="${escapeJSX(metadata.srcset)}" sizes="${escapeJSX(sizesValue)}" />
|
|
1146
|
+
${ind(ctx)} <img${imgAttrs}${blurStyle}${otherAttrsStr} />
|
|
1147
|
+
${ind(ctx)}</picture>
|
|
1148
|
+
${ifClose}`;
|
|
1149
|
+
}
|
|
1150
|
+
const allClasses = classMatch ? classMatch[1].split(/\s+/).filter(Boolean) : [];
|
|
1151
|
+
const { pictureClasses, imgClasses } = splitImageClasses(allClasses);
|
|
1152
|
+
const pictureClassAttr = pictureClasses.length > 0 ? ` class="${pictureClasses.join(" ")}"` : "";
|
|
1153
|
+
const imgClassAttr = imgClasses.length > 0 ? ` class="${imgClasses.join(" ")}"` : "";
|
|
1154
|
+
return `${ifExpr}${ind(ctx)}<picture${pictureClassAttr}${styleAttr}>
|
|
1155
|
+
${ind(ctx)} <source type="image/avif" srcset="${escapeJSX(metadata.avifSrcset)}" sizes="${escapeJSX(sizesValue)}" />
|
|
1156
|
+
${ind(ctx)} <source type="image/webp" srcset="${escapeJSX(metadata.srcset)}" sizes="${escapeJSX(sizesValue)}" />
|
|
1157
|
+
${ind(ctx)} <img${imgClassAttr}${imgAttrs}${blurStyle}${otherAttrsStr} />
|
|
1158
|
+
${ind(ctx)}</picture>
|
|
1159
|
+
${ifClose}`;
|
|
1160
|
+
}
|
|
1161
|
+
if (metadata?.srcset) {
|
|
1162
|
+
imgAttrs += ` srcset="${escapeJSX(metadata.srcset)}"`;
|
|
1163
|
+
imgAttrs += ` sizes="${escapeJSX(sizesValue)}"`;
|
|
1164
|
+
}
|
|
1165
|
+
return `${ifExpr}${ind(ctx)}<img${classExpr}${styleAttr}${imgAttrs}${blurStyle}${otherAttrsStr} />
|
|
1166
|
+
${ifClose}`;
|
|
1167
|
+
}
|
|
816
1168
|
function emitHtmlNode(node, ctx) {
|
|
817
1169
|
let tag = node.tag;
|
|
1170
|
+
if (tag && /^[A-Z]/.test(tag)) {
|
|
1171
|
+
tag = tag.toLowerCase();
|
|
1172
|
+
}
|
|
1173
|
+
if (tag === "img" && ctx.imageMetadataMap) {
|
|
1174
|
+
return emitImageNode(node, ctx);
|
|
1175
|
+
}
|
|
818
1176
|
const label = node.label;
|
|
819
1177
|
const style = node.style;
|
|
820
1178
|
let isDynamic = false;
|
|
@@ -854,16 +1212,40 @@ function emitComponentInstance(node, ctx) {
|
|
|
854
1212
|
const ifExpr = emitIfOpen(node, ctx);
|
|
855
1213
|
const propParts = [];
|
|
856
1214
|
if (node.props) {
|
|
857
|
-
for (const [key,
|
|
1215
|
+
for (const [key, rawValue] of Object.entries(node.props)) {
|
|
858
1216
|
if (key === "children") continue;
|
|
1217
|
+
const value = resolveI18n(rawValue, ctx);
|
|
859
1218
|
if (typeof value === "string" && hasTemplates(value) && ctx.isComponentDef) {
|
|
860
1219
|
const fullMatch = value.match(/^\{\{(.+)\}\}$/);
|
|
861
1220
|
if (fullMatch) {
|
|
862
|
-
|
|
1221
|
+
let expr = fullMatch[1].trim();
|
|
1222
|
+
if (ctx.listItemBinding) expr = rewriteItemVar(expr, ctx.listItemBinding);
|
|
1223
|
+
if (ctx.listIndexVar) expr = replaceItemMetaVars(expr, ctx.listIndexVar, ctx.listSourceVar);
|
|
1224
|
+
propParts.push(`${key}={${expr}}`);
|
|
863
1225
|
} else {
|
|
864
|
-
const resolved = value.replace(/\{\{(.+?)\}\}/g, (_, expr) =>
|
|
1226
|
+
const resolved = value.replace(/\{\{(.+?)\}\}/g, (_, expr) => {
|
|
1227
|
+
let trimmed = expr.trim();
|
|
1228
|
+
if (ctx.listItemBinding) trimmed = rewriteItemVar(trimmed, ctx.listItemBinding);
|
|
1229
|
+
if (ctx.listIndexVar) trimmed = replaceItemMetaVars(trimmed, ctx.listIndexVar, ctx.listSourceVar);
|
|
1230
|
+
return `\${${trimmed}}`;
|
|
1231
|
+
});
|
|
865
1232
|
propParts.push(`${key}={\`${resolved}\`}`);
|
|
866
1233
|
}
|
|
1234
|
+
} else if (typeof value === "string" && ctx.cmsMode && /\{\{cms\./.test(value)) {
|
|
1235
|
+
const b = ctx.cmsEntryBinding || "entry";
|
|
1236
|
+
const w = (expr) => ctx.cmsWrapFn ? `${ctx.cmsWrapFn}(${expr})` : expr;
|
|
1237
|
+
const fullMatch = value.match(/^\{\{cms\.([^}]+)\}\}$/);
|
|
1238
|
+
if (fullMatch) {
|
|
1239
|
+
propParts.push(`${key}={${w(`${b}.data.${fullMatch[1].trim()}`)}}`);
|
|
1240
|
+
} else {
|
|
1241
|
+
const replaced = value.replace(/\{\{cms\.([^}]+)\}\}/g, (_, fieldPath) => {
|
|
1242
|
+
return `\${${w(`${b}.data.${fieldPath.trim()}`)}}`;
|
|
1243
|
+
});
|
|
1244
|
+
propParts.push(`${key}={\`${replaced}\`}`);
|
|
1245
|
+
}
|
|
1246
|
+
} else if (ctx.isComponentDef && isI18nValue(value)) {
|
|
1247
|
+
ctx.needsI18nResolver = true;
|
|
1248
|
+
propParts.push(`${key}={r(${JSON.stringify(value)})}`);
|
|
867
1249
|
} else {
|
|
868
1250
|
propParts.push(`${key}=${formatPropValue(value)}`);
|
|
869
1251
|
}
|
|
@@ -946,26 +1328,55 @@ function emitLinkNode(node, ctx) {
|
|
|
946
1328
|
finalClassExpr = ' class="olink"';
|
|
947
1329
|
}
|
|
948
1330
|
}
|
|
1331
|
+
const resolvedHref = resolveI18n(node.href, ctx);
|
|
1332
|
+
const nodeHref = resolvedHref;
|
|
949
1333
|
let hrefAttr;
|
|
950
|
-
if (isLinkMapping(
|
|
1334
|
+
if (isLinkMapping(nodeHref)) {
|
|
951
1335
|
if (ctx.isComponentDef) {
|
|
952
|
-
const propRef =
|
|
953
|
-
hrefAttr = ` href={${propRef}
|
|
1336
|
+
const propRef = nodeHref.prop;
|
|
1337
|
+
hrefAttr = ` href={${propRef}?.href ?? "#"}`;
|
|
954
1338
|
} else {
|
|
955
1339
|
hrefAttr = ' href="#"';
|
|
956
1340
|
}
|
|
957
1341
|
} else {
|
|
958
|
-
const href = typeof
|
|
1342
|
+
const href = typeof nodeHref === "string" ? nodeHref : "#";
|
|
959
1343
|
if (hasTemplates(href) && ctx.isComponentDef) {
|
|
960
1344
|
const fullMatch = href.match(/^\{\{(.+)\}\}$/);
|
|
961
1345
|
if (fullMatch) {
|
|
962
|
-
|
|
1346
|
+
let expr = fullMatch[1].trim();
|
|
1347
|
+
if (ctx.listItemBinding) expr = rewriteItemVar(expr, ctx.listItemBinding);
|
|
1348
|
+
if (ctx.listIndexVar) expr = replaceItemMetaVars(expr, ctx.listIndexVar, ctx.listSourceVar);
|
|
1349
|
+
const propDef = ctx.componentProps[expr];
|
|
1350
|
+
if (propDef && propDef.type === "link") {
|
|
1351
|
+
hrefAttr = ` href={${expr}?.href ?? "#"}`;
|
|
1352
|
+
} else {
|
|
1353
|
+
hrefAttr = ` href={${expr}}`;
|
|
1354
|
+
}
|
|
963
1355
|
} else {
|
|
964
|
-
const resolved = href.replace(/\{\{(.+?)\}\}/g, (_, expr) =>
|
|
1356
|
+
const resolved = href.replace(/\{\{(.+?)\}\}/g, (_, expr) => {
|
|
1357
|
+
let trimmed = expr.trim();
|
|
1358
|
+
if (ctx.listItemBinding) trimmed = rewriteItemVar(trimmed, ctx.listItemBinding);
|
|
1359
|
+
if (ctx.listIndexVar) trimmed = replaceItemMetaVars(trimmed, ctx.listIndexVar, ctx.listSourceVar);
|
|
1360
|
+
const pd = ctx.componentProps[trimmed];
|
|
1361
|
+
return pd?.type === "link" ? `\${${trimmed}?.href ?? "#"}` : `\${${trimmed}}`;
|
|
1362
|
+
});
|
|
965
1363
|
hrefAttr = ` href={\`${resolved}\`}`;
|
|
966
1364
|
}
|
|
1365
|
+
} else if (ctx.cmsMode && /\{\{cms\./.test(href)) {
|
|
1366
|
+
const b = ctx.cmsEntryBinding || "entry";
|
|
1367
|
+
const w = (expr) => ctx.cmsWrapFn ? `${ctx.cmsWrapFn}(${expr})` : expr;
|
|
1368
|
+
const fullMatch = href.match(/^\{\{cms\.([^}]+)\}\}$/);
|
|
1369
|
+
if (fullMatch) {
|
|
1370
|
+
hrefAttr = ` href={${w(`${b}.data.${fullMatch[1].trim()}`)}}`;
|
|
1371
|
+
} else {
|
|
1372
|
+
const replaced = href.replace(/\{\{cms\.([^}]+)\}\}/g, (_, fieldPath) => {
|
|
1373
|
+
return `\${${w(`${b}.data.${fieldPath.trim()}`)}}`;
|
|
1374
|
+
});
|
|
1375
|
+
hrefAttr = ` href={\`${replaced}\`}`;
|
|
1376
|
+
}
|
|
967
1377
|
} else {
|
|
968
|
-
|
|
1378
|
+
const localizedHref = localizeHref(href, ctx);
|
|
1379
|
+
hrefAttr = ` href="${escapeJSX(localizedHref)}"`;
|
|
969
1380
|
}
|
|
970
1381
|
}
|
|
971
1382
|
const attrs = buildAttributesString(node.attributes, ctx);
|
|
@@ -978,6 +1389,234 @@ ${emitIfClose(node, ctx)}`;
|
|
|
978
1389
|
` + children + `${ind(ctx)}</a>
|
|
979
1390
|
${emitIfClose(node, ctx)}`;
|
|
980
1391
|
}
|
|
1392
|
+
function emitImageTypeNode(node, ctx) {
|
|
1393
|
+
const style = node.style;
|
|
1394
|
+
let elementClass = null;
|
|
1395
|
+
if (node.interactiveStyles && node.interactiveStyles.length > 0 || node.generateElementClass) {
|
|
1396
|
+
elementClass = buildElementClass(ctx, node.label);
|
|
1397
|
+
}
|
|
1398
|
+
const { classExpr, styleAttr } = buildClassAndStyleExpression(
|
|
1399
|
+
style,
|
|
1400
|
+
node.interactiveStyles,
|
|
1401
|
+
elementClass,
|
|
1402
|
+
ctx
|
|
1403
|
+
);
|
|
1404
|
+
const src = node.src;
|
|
1405
|
+
const alt = node.alt;
|
|
1406
|
+
let imgAttrs = "";
|
|
1407
|
+
if (src) imgAttrs += ` src="${escapeJSX(String(src))}"`;
|
|
1408
|
+
if (alt !== void 0) imgAttrs += ` alt="${escapeJSX(String(alt))}"`;
|
|
1409
|
+
const metadata = src ? ctx.imageMetadataMap?.get(String(src)) : void 0;
|
|
1410
|
+
if (metadata) {
|
|
1411
|
+
let width = metadata.width;
|
|
1412
|
+
let height = metadata.height;
|
|
1413
|
+
if (width !== void 0) imgAttrs += ` width="${width}"`;
|
|
1414
|
+
if (height !== void 0) imgAttrs += ` height="${height}"`;
|
|
1415
|
+
let blurStyle = "";
|
|
1416
|
+
if (metadata.blurHash) {
|
|
1417
|
+
blurStyle = ` style="background-image: url(${escapeJSX(metadata.blurHash)}); background-size: cover;" onload="this.style.backgroundImage=''"`;
|
|
1418
|
+
}
|
|
1419
|
+
const sizesValue = DEFAULT_SIZES2;
|
|
1420
|
+
if (metadata.avifSrcset) {
|
|
1421
|
+
const classMatch = classExpr.match(/class="([^"]*)"/);
|
|
1422
|
+
const allClasses = classMatch ? classMatch[1].split(/\s+/).filter(Boolean) : [];
|
|
1423
|
+
const { pictureClasses, imgClasses } = splitImageClasses(allClasses);
|
|
1424
|
+
const pictureClassAttr = pictureClasses.length > 0 ? ` class="${pictureClasses.join(" ")}"` : "";
|
|
1425
|
+
const imgClassAttr = imgClasses.length > 0 ? ` class="${imgClasses.join(" ")}"` : "";
|
|
1426
|
+
return `${ind(ctx)}<picture${pictureClassAttr}${styleAttr}>
|
|
1427
|
+
${ind(ctx)} <source type="image/avif" srcset="${escapeJSX(metadata.avifSrcset)}" sizes="${escapeJSX(sizesValue)}" />
|
|
1428
|
+
${ind(ctx)} <source type="image/webp" srcset="${escapeJSX(metadata.srcset)}" sizes="${escapeJSX(sizesValue)}" />
|
|
1429
|
+
${ind(ctx)} <img${imgClassAttr}${imgAttrs}${blurStyle} />
|
|
1430
|
+
${ind(ctx)}</picture>
|
|
1431
|
+
`;
|
|
1432
|
+
}
|
|
1433
|
+
if (metadata.srcset) {
|
|
1434
|
+
imgAttrs += ` srcset="${escapeJSX(metadata.srcset)}"`;
|
|
1435
|
+
imgAttrs += ` sizes="${escapeJSX(sizesValue)}"`;
|
|
1436
|
+
}
|
|
1437
|
+
}
|
|
1438
|
+
return `${ind(ctx)}<img${classExpr}${styleAttr}${imgAttrs} />
|
|
1439
|
+
`;
|
|
1440
|
+
}
|
|
1441
|
+
function emitListNode(node, ctx) {
|
|
1442
|
+
const sourceType = node.sourceType || "prop";
|
|
1443
|
+
const itemAs = node.itemAs || "item";
|
|
1444
|
+
if (sourceType === "collection") {
|
|
1445
|
+
return emitCollectionListNode(node, ctx);
|
|
1446
|
+
}
|
|
1447
|
+
if (!ctx.isComponentDef && !ctx.listItemBinding) {
|
|
1448
|
+
return emitFallback(ctx);
|
|
1449
|
+
}
|
|
1450
|
+
let source = node.source || "items";
|
|
1451
|
+
const templateMatch = source.match(/^\{\{(.+)\}\}$/);
|
|
1452
|
+
if (templateMatch) {
|
|
1453
|
+
source = templateMatch[1].trim();
|
|
1454
|
+
}
|
|
1455
|
+
let mapSource = source;
|
|
1456
|
+
if (node.offset && node.limit) {
|
|
1457
|
+
mapSource = `${source}.slice(${node.offset}, ${node.offset + node.limit})`;
|
|
1458
|
+
} else if (node.offset) {
|
|
1459
|
+
mapSource = `${source}.slice(${node.offset})`;
|
|
1460
|
+
} else if (node.limit) {
|
|
1461
|
+
mapSource = `${source}.slice(0, ${node.limit})`;
|
|
1462
|
+
}
|
|
1463
|
+
const indexVar = `${itemAs}Index`;
|
|
1464
|
+
const innerCtx = {
|
|
1465
|
+
...ctx,
|
|
1466
|
+
indent: ctx.indent + 1,
|
|
1467
|
+
listItemBinding: itemAs,
|
|
1468
|
+
listIndexVar: indexVar,
|
|
1469
|
+
listSourceVar: mapSource,
|
|
1470
|
+
elementPath: [...ctx.elementPath, 0]
|
|
1471
|
+
};
|
|
1472
|
+
const children = node.children ? node.children.map((child, i) => {
|
|
1473
|
+
const childCtx = { ...innerCtx, elementPath: [...ctx.elementPath, i] };
|
|
1474
|
+
const out = nodeToAstro(child, childCtx);
|
|
1475
|
+
if (childCtx.needsI18nResolver) ctx.needsI18nResolver = true;
|
|
1476
|
+
return out;
|
|
1477
|
+
}).join("") : "";
|
|
1478
|
+
return `${ind(ctx)}{${mapSource}.map((${itemAs}, ${indexVar}) => (
|
|
1479
|
+
` + children + `${ind(ctx)}))}
|
|
1480
|
+
`;
|
|
1481
|
+
}
|
|
1482
|
+
function emitCollectionListNode(node, ctx) {
|
|
1483
|
+
const source = node.source || "";
|
|
1484
|
+
const itemAs = node.itemAs || singularize(source);
|
|
1485
|
+
if (!ctx.frontmatterLines) ctx.frontmatterLines = [];
|
|
1486
|
+
if (!ctx.astroImports) ctx.astroImports = /* @__PURE__ */ new Set();
|
|
1487
|
+
ctx.astroImports.add("getCollection");
|
|
1488
|
+
const collectionVar = `${source}List`;
|
|
1489
|
+
let queryChain = `await getCollection('${source}')`;
|
|
1490
|
+
if (node.filter) {
|
|
1491
|
+
if (typeof node.filter === "object" && !Array.isArray(node.filter) && "field" in node.filter) {
|
|
1492
|
+
const f = node.filter;
|
|
1493
|
+
const op = f.operator || "eq";
|
|
1494
|
+
if (op === "eq") {
|
|
1495
|
+
queryChain += `.then(items => items.filter(e => e.data.${f.field} === ${JSON.stringify(f.value)}))`;
|
|
1496
|
+
}
|
|
1497
|
+
}
|
|
1498
|
+
}
|
|
1499
|
+
if (node.sort) {
|
|
1500
|
+
const sortConfig = Array.isArray(node.sort) ? node.sort[0] : node.sort;
|
|
1501
|
+
if (sortConfig) {
|
|
1502
|
+
const order = sortConfig.order === "desc" ? -1 : 1;
|
|
1503
|
+
queryChain += `.then(items => items.sort((a, b) => a.data.${sortConfig.field} > b.data.${sortConfig.field} ? ${order} : ${-order}))`;
|
|
1504
|
+
}
|
|
1505
|
+
}
|
|
1506
|
+
if (node.offset || node.limit) {
|
|
1507
|
+
const start = node.offset || 0;
|
|
1508
|
+
const end = node.limit ? start + node.limit : void 0;
|
|
1509
|
+
queryChain += `.then(items => items.slice(${start}${end !== void 0 ? `, ${end}` : ""}))`;
|
|
1510
|
+
}
|
|
1511
|
+
ctx.frontmatterLines.push(`const ${collectionVar} = ${queryChain};`);
|
|
1512
|
+
const indexVar = `${itemAs}Index`;
|
|
1513
|
+
const innerCtx = {
|
|
1514
|
+
...ctx,
|
|
1515
|
+
indent: ctx.indent + 1,
|
|
1516
|
+
listItemBinding: itemAs,
|
|
1517
|
+
listIndexVar: indexVar,
|
|
1518
|
+
listSourceVar: collectionVar,
|
|
1519
|
+
cmsMode: true,
|
|
1520
|
+
cmsEntryBinding: itemAs,
|
|
1521
|
+
elementPath: [...ctx.elementPath, 0]
|
|
1522
|
+
};
|
|
1523
|
+
const children = node.children ? node.children.map((child, i) => {
|
|
1524
|
+
const childCtx = { ...innerCtx, elementPath: [...ctx.elementPath, i] };
|
|
1525
|
+
const out = nodeToAstro(child, childCtx);
|
|
1526
|
+
if (childCtx.needsI18nResolver) ctx.needsI18nResolver = true;
|
|
1527
|
+
return out;
|
|
1528
|
+
}).join("") : "";
|
|
1529
|
+
return `${ind(ctx)}{${collectionVar}.map((${itemAs}, ${indexVar}) => (
|
|
1530
|
+
` + children + `${ind(ctx)}))}
|
|
1531
|
+
`;
|
|
1532
|
+
}
|
|
1533
|
+
function emitLocaleListNode(node, ctx) {
|
|
1534
|
+
if (!ctx.i18nConfig || !ctx.currentPageSlugMap) {
|
|
1535
|
+
return emitFallback(ctx);
|
|
1536
|
+
}
|
|
1537
|
+
const i18nConfig = ctx.i18nConfig;
|
|
1538
|
+
const slugMap = ctx.currentPageSlugMap;
|
|
1539
|
+
const showCurrent = node.showCurrent !== false;
|
|
1540
|
+
const showSeparator = node.showSeparator !== false;
|
|
1541
|
+
const showFlag = node.showFlag !== false;
|
|
1542
|
+
const displayType = node.displayType || "nativeName";
|
|
1543
|
+
const style = node.style;
|
|
1544
|
+
let elementClass = null;
|
|
1545
|
+
if (node.interactiveStyles && node.interactiveStyles.length > 0 || node.generateElementClass) {
|
|
1546
|
+
elementClass = buildElementClass(ctx, node.label);
|
|
1547
|
+
}
|
|
1548
|
+
const { classExpr: containerClassExpr, styleAttr: containerStyleAttr } = buildClassAndStyleExpression(
|
|
1549
|
+
style,
|
|
1550
|
+
node.interactiveStyles,
|
|
1551
|
+
elementClass,
|
|
1552
|
+
ctx
|
|
1553
|
+
);
|
|
1554
|
+
const itemStyle = node.itemStyle;
|
|
1555
|
+
const itemResult = itemStyle ? responsiveStylesToTailwind(itemStyle, ctx.breakpoints) : { classes: [], dynamicStyles: {} };
|
|
1556
|
+
const itemClasses = itemResult.classes;
|
|
1557
|
+
const activeItemStyle = node.activeItemStyle;
|
|
1558
|
+
const activeResult = activeItemStyle ? responsiveStylesToTailwind(activeItemStyle, ctx.breakpoints) : { classes: [], dynamicStyles: {} };
|
|
1559
|
+
const activeItemClasses = [...itemClasses, ...activeResult.classes];
|
|
1560
|
+
const separatorStyle = node.separatorStyle;
|
|
1561
|
+
const sepResult = separatorStyle ? responsiveStylesToTailwind(separatorStyle, ctx.breakpoints) : { classes: [], dynamicStyles: {} };
|
|
1562
|
+
const separatorClasses = sepResult.classes;
|
|
1563
|
+
const localeIconMap = /* @__PURE__ */ new Map();
|
|
1564
|
+
for (const localeConfig of i18nConfig.locales) {
|
|
1565
|
+
if (localeConfig.icon) {
|
|
1566
|
+
localeIconMap.set(localeConfig.code, localeConfig.icon);
|
|
1567
|
+
}
|
|
1568
|
+
}
|
|
1569
|
+
const flagStyle = node.flagStyle;
|
|
1570
|
+
const flagResult = flagStyle ? responsiveStylesToTailwind(flagStyle, ctx.breakpoints) : { classes: [], dynamicStyles: {} };
|
|
1571
|
+
const flagClasses = flagResult.classes;
|
|
1572
|
+
const links = [];
|
|
1573
|
+
const currentLocale = ctx.locale || i18nConfig.defaultLocale;
|
|
1574
|
+
for (const localeConfig of i18nConfig.locales) {
|
|
1575
|
+
const code = localeConfig.code;
|
|
1576
|
+
const isCurrent = code === currentLocale;
|
|
1577
|
+
if (!showCurrent && isCurrent) continue;
|
|
1578
|
+
const path = slugMap[code] || "/";
|
|
1579
|
+
const classes = isCurrent ? activeItemClasses : itemClasses;
|
|
1580
|
+
const classAttr = classes.length > 0 ? ` class="${classes.join(" ")}"` : "";
|
|
1581
|
+
const currentAttr = isCurrent ? ' data-current="true"' : ' data-current="false"';
|
|
1582
|
+
const hreflangAttr = ` hreflang="${localeConfig.langTag}"`;
|
|
1583
|
+
let displayText;
|
|
1584
|
+
switch (displayType) {
|
|
1585
|
+
case "code":
|
|
1586
|
+
displayText = code.toUpperCase();
|
|
1587
|
+
break;
|
|
1588
|
+
case "name":
|
|
1589
|
+
displayText = localeConfig.name;
|
|
1590
|
+
break;
|
|
1591
|
+
case "nativeName":
|
|
1592
|
+
default:
|
|
1593
|
+
displayText = localeConfig.nativeName;
|
|
1594
|
+
break;
|
|
1595
|
+
}
|
|
1596
|
+
let linkContent = "";
|
|
1597
|
+
const localeIcon = localeIconMap.get(code);
|
|
1598
|
+
if (showFlag && localeIcon) {
|
|
1599
|
+
const flagClassAttr = flagClasses.length > 0 ? ` class="${flagClasses.join(" ")}"` : "";
|
|
1600
|
+
linkContent += `<img src="${escapeJSX(localeIcon)}" alt="${escapeJSX(localeConfig.nativeName)} flag"${flagClassAttr}>`;
|
|
1601
|
+
}
|
|
1602
|
+
linkContent += `<div>${escapeJSX(displayText)}</div>`;
|
|
1603
|
+
links.push(`${ind(ctx)} <a href="${escapeJSX(path)}"${hreflangAttr}${currentAttr} data-locale="${escapeJSX(code)}"${classAttr}>${linkContent}</a>`);
|
|
1604
|
+
}
|
|
1605
|
+
let linksContent;
|
|
1606
|
+
if (showSeparator && links.length > 1) {
|
|
1607
|
+
const sepClassAttr = separatorClasses.length > 0 ? ` class="${separatorClasses.join(" ")}"` : "";
|
|
1608
|
+
linksContent = links.join(`
|
|
1609
|
+
${ind(ctx)} <span${sepClassAttr}></span>
|
|
1610
|
+
`);
|
|
1611
|
+
} else {
|
|
1612
|
+
linksContent = links.join("\n");
|
|
1613
|
+
}
|
|
1614
|
+
const attrs = buildAttributesString(node.attributes, ctx);
|
|
1615
|
+
return `${ind(ctx)}<div data-locale-list="true"${containerClassExpr}${containerStyleAttr}${attrs}>
|
|
1616
|
+
` + linksContent + `
|
|
1617
|
+
${ind(ctx)}</div>
|
|
1618
|
+
`;
|
|
1619
|
+
}
|
|
981
1620
|
function emitFallback(ctx) {
|
|
982
1621
|
const pathKey = ctx.elementPath.join(".");
|
|
983
1622
|
const ssrHtml = ctx.ssrFallbacks.get(pathKey);
|
|
@@ -997,14 +1636,43 @@ function emitIfOpen(node, ctx) {
|
|
|
997
1636
|
`;
|
|
998
1637
|
}
|
|
999
1638
|
if (typeof ifValue === "object" && ifValue._mapping && ctx.isComponentDef) {
|
|
1000
|
-
|
|
1639
|
+
const trueValues = Object.entries(ifValue.values).filter(([, v]) => v === true).map(([k]) => `'${k}'`);
|
|
1640
|
+
if (trueValues.length === 0) return `${ind(ctx)}{/* hidden */}
|
|
1641
|
+
`;
|
|
1642
|
+
if (trueValues.length === 1) {
|
|
1643
|
+
return `${ind(ctx)}{${ifValue.prop} === ${trueValues[0]} && (
|
|
1644
|
+
`;
|
|
1645
|
+
}
|
|
1646
|
+
return `${ind(ctx)}{[${trueValues.join(", ")}].includes(${ifValue.prop}) && (
|
|
1001
1647
|
`;
|
|
1002
1648
|
}
|
|
1003
|
-
if (typeof ifValue === "string"
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1649
|
+
if (typeof ifValue === "string") {
|
|
1650
|
+
if (ctx.cmsMode && ifValue.includes("{{cms.")) {
|
|
1651
|
+
const match = ifValue.match(/^\{\{cms\.([^}]+)\}\}$/);
|
|
1652
|
+
if (match) {
|
|
1653
|
+
const binding = ctx.cmsEntryBinding || "entry";
|
|
1654
|
+
return `${ind(ctx)}{${binding}.data.${match[1].trim()} && (
|
|
1007
1655
|
`;
|
|
1656
|
+
}
|
|
1657
|
+
}
|
|
1658
|
+
if (ctx.listItemBinding && /\{\{/.test(ifValue)) {
|
|
1659
|
+
const match = ifValue.match(/^\{\{([^}]+)\}\}$/);
|
|
1660
|
+
if (match) {
|
|
1661
|
+
let expr = match[1].trim();
|
|
1662
|
+
expr = rewriteItemVar(expr, ctx.listItemBinding);
|
|
1663
|
+
if (ctx.listIndexVar) expr = replaceItemMetaVars(expr, ctx.listIndexVar, ctx.listSourceVar);
|
|
1664
|
+
return `${ind(ctx)}{${expr} && (
|
|
1665
|
+
`;
|
|
1666
|
+
}
|
|
1667
|
+
}
|
|
1668
|
+
if (ctx.isComponentDef) {
|
|
1669
|
+
const fullMatch = ifValue.match(/^\{\{(.+)\}\}$/);
|
|
1670
|
+
let expr = fullMatch ? fullMatch[1].trim() : ifValue.replace(/\{\{(.+?)\}\}/g, "$1");
|
|
1671
|
+
if (ctx.listItemBinding) expr = rewriteItemVar(expr, ctx.listItemBinding);
|
|
1672
|
+
if (ctx.listIndexVar) expr = replaceItemMetaVars(expr, ctx.listIndexVar, ctx.listSourceVar);
|
|
1673
|
+
return `${ind(ctx)}{${expr} && (
|
|
1674
|
+
`;
|
|
1675
|
+
}
|
|
1008
1676
|
}
|
|
1009
1677
|
return "";
|
|
1010
1678
|
}
|
|
@@ -1012,22 +1680,40 @@ function emitIfClose(node, ctx) {
|
|
|
1012
1680
|
const ifValue = node.if;
|
|
1013
1681
|
if (ifValue === void 0 || ifValue === true) return "";
|
|
1014
1682
|
if (typeof ifValue === "boolean") return "";
|
|
1015
|
-
if (typeof ifValue === "object" && ifValue._mapping && ctx.isComponentDef
|
|
1683
|
+
if (typeof ifValue === "object" && ifValue._mapping && ctx.isComponentDef) {
|
|
1016
1684
|
return `${ind(ctx)})}
|
|
1017
1685
|
`;
|
|
1018
1686
|
}
|
|
1687
|
+
if (typeof ifValue === "string") {
|
|
1688
|
+
const hasCmsCondition = ctx.cmsMode && ifValue.includes("{{cms.");
|
|
1689
|
+
const hasItemCondition = ctx.listItemBinding && /\{\{/.test(ifValue);
|
|
1690
|
+
if (hasCmsCondition || hasItemCondition || ctx.isComponentDef) {
|
|
1691
|
+
return `${ind(ctx)})}
|
|
1692
|
+
`;
|
|
1693
|
+
}
|
|
1694
|
+
}
|
|
1019
1695
|
return "";
|
|
1020
1696
|
}
|
|
1021
1697
|
function emitChildren(children, ctx) {
|
|
1022
1698
|
if (!children) return "";
|
|
1023
1699
|
const innerCtx = { ...ctx, indent: ctx.indent + 1, elementPath: [...ctx.elementPath] };
|
|
1024
1700
|
if (typeof children === "string") {
|
|
1025
|
-
|
|
1701
|
+
const out2 = nodeToAstro(children, innerCtx);
|
|
1702
|
+
if (innerCtx.needsI18nResolver) ctx.needsI18nResolver = true;
|
|
1703
|
+
return out2;
|
|
1026
1704
|
}
|
|
1027
1705
|
if (Array.isArray(children)) {
|
|
1028
|
-
|
|
1706
|
+
let result = "";
|
|
1707
|
+
for (let i = 0; i < children.length; i++) {
|
|
1708
|
+
const childCtx = { ...innerCtx, elementPath: [...ctx.elementPath, i] };
|
|
1709
|
+
result += nodeToAstro(children[i], childCtx);
|
|
1710
|
+
if (childCtx.needsI18nResolver) ctx.needsI18nResolver = true;
|
|
1711
|
+
}
|
|
1712
|
+
return result;
|
|
1029
1713
|
}
|
|
1030
|
-
|
|
1714
|
+
const out = nodeToAstro(children, innerCtx);
|
|
1715
|
+
if (innerCtx.needsI18nResolver) ctx.needsI18nResolver = true;
|
|
1716
|
+
return out;
|
|
1031
1717
|
}
|
|
1032
1718
|
|
|
1033
1719
|
// lib/server/astro/componentEmitter.ts
|
|
@@ -1073,7 +1759,7 @@ function formatDefault(def) {
|
|
|
1073
1759
|
}
|
|
1074
1760
|
return JSON.stringify(val);
|
|
1075
1761
|
}
|
|
1076
|
-
function emitAstroComponent(name, def, allComponents, breakpoints = DEFAULT_BREAKPOINTS) {
|
|
1762
|
+
function emitAstroComponent(name, def, allComponents, breakpoints = DEFAULT_BREAKPOINTS, defaultLocale = "en") {
|
|
1077
1763
|
const comp = def.component;
|
|
1078
1764
|
const propDefs = comp.interface || {};
|
|
1079
1765
|
const structure = comp.structure;
|
|
@@ -1090,25 +1776,22 @@ function emitAstroComponent(name, def, allComponents, breakpoints = DEFAULT_BREA
|
|
|
1090
1776
|
elementPath: [0],
|
|
1091
1777
|
fileType: "component",
|
|
1092
1778
|
fileName: name,
|
|
1093
|
-
breakpoints
|
|
1779
|
+
breakpoints,
|
|
1780
|
+
defaultLocale
|
|
1094
1781
|
};
|
|
1095
1782
|
const templateBody = nodeToAstro(structure, ctx);
|
|
1096
|
-
const frontmatter = buildFrontmatter(name, propDefs, ctx.imports, ctx.dynamicTags);
|
|
1783
|
+
const frontmatter = buildFrontmatter(name, propDefs, ctx.imports, ctx.dynamicTags, ctx.needsI18nResolver ? defaultLocale : void 0);
|
|
1097
1784
|
const styleSection = comp.css ? `
|
|
1098
1785
|
<style>
|
|
1099
1786
|
${comp.css}
|
|
1100
1787
|
</style>
|
|
1101
1788
|
` : "";
|
|
1102
|
-
const scriptSection = comp.javascript ?
|
|
1103
|
-
<script>
|
|
1104
|
-
${comp.javascript}
|
|
1105
|
-
</script>
|
|
1106
|
-
` : "";
|
|
1789
|
+
const scriptSection = comp.javascript ? buildScriptSection(comp.javascript, comp, propDefs) : "";
|
|
1107
1790
|
return `---
|
|
1108
1791
|
${frontmatter}---
|
|
1109
1792
|
${templateBody}${styleSection}${scriptSection}`;
|
|
1110
1793
|
}
|
|
1111
|
-
function buildFrontmatter(componentName, propDefs, imports, dynamicTags) {
|
|
1794
|
+
function buildFrontmatter(componentName, propDefs, imports, dynamicTags, i18nDefaultLocale) {
|
|
1112
1795
|
const lines = [];
|
|
1113
1796
|
for (const imp of Array.from(imports).sort()) {
|
|
1114
1797
|
lines.push(`import ${imp} from './${imp}.astro';`);
|
|
@@ -1131,6 +1814,8 @@ function buildFrontmatter(componentName, propDefs, imports, dynamicTags) {
|
|
|
1131
1814
|
const defaultVal = formatDefault(propDef);
|
|
1132
1815
|
if (defaultVal !== null) {
|
|
1133
1816
|
destructParts.push(`${propName} = ${defaultVal}`);
|
|
1817
|
+
} else if (propDef.type === "link") {
|
|
1818
|
+
destructParts.push(`${propName} = { href: "#" }`);
|
|
1134
1819
|
} else {
|
|
1135
1820
|
destructParts.push(propName);
|
|
1136
1821
|
}
|
|
@@ -1153,6 +1838,16 @@ function buildFrontmatter(componentName, propDefs, imports, dynamicTags) {
|
|
|
1153
1838
|
lines.push(`const ${varName} = \`${templateExpr}\`;`);
|
|
1154
1839
|
}
|
|
1155
1840
|
}
|
|
1841
|
+
if (i18nDefaultLocale) {
|
|
1842
|
+
lines.push("");
|
|
1843
|
+
lines.push(`const r = (v: any) => {`);
|
|
1844
|
+
lines.push(` if (v && typeof v === 'object' && v._i18n) {`);
|
|
1845
|
+
lines.push(` const locale = Astro.currentLocale ?? '${i18nDefaultLocale}';`);
|
|
1846
|
+
lines.push(` return v[locale] ?? v['${i18nDefaultLocale}'] ?? Object.values(v).find((s: any) => typeof s === 'string' && s !== '') ?? '';`);
|
|
1847
|
+
lines.push(` }`);
|
|
1848
|
+
lines.push(` return v ?? '';`);
|
|
1849
|
+
lines.push(`};`);
|
|
1850
|
+
}
|
|
1156
1851
|
if (lines.length > 0) lines.push("");
|
|
1157
1852
|
return lines.join("\n");
|
|
1158
1853
|
}
|
|
@@ -1164,12 +1859,56 @@ ${comp.css}
|
|
|
1164
1859
|
</style>
|
|
1165
1860
|
`;
|
|
1166
1861
|
if (comp.javascript) content += `
|
|
1167
|
-
<script>
|
|
1862
|
+
<script is:inline>
|
|
1168
1863
|
${comp.javascript}
|
|
1169
1864
|
</script>
|
|
1170
1865
|
`;
|
|
1171
1866
|
return content;
|
|
1172
1867
|
}
|
|
1868
|
+
function transformDefineVarsJS(js, varNames) {
|
|
1869
|
+
let result = js;
|
|
1870
|
+
result = result.replace(
|
|
1871
|
+
/^\s*(const|let|var)\s+\{([^}]+)\}\s*=\s*props\s*;?\s*$/gm,
|
|
1872
|
+
(match, _keyword, inner) => {
|
|
1873
|
+
const names = inner.split(",").map((s) => s.trim()).filter(Boolean);
|
|
1874
|
+
if (names.every((n) => varNames.includes(n))) return "";
|
|
1875
|
+
return match;
|
|
1876
|
+
}
|
|
1877
|
+
);
|
|
1878
|
+
const sorted = [...varNames].sort((a, b) => b.length - a.length);
|
|
1879
|
+
for (const name of sorted) {
|
|
1880
|
+
result = result.replace(new RegExp(`props\\.${name}\\b`, "g"), name);
|
|
1881
|
+
}
|
|
1882
|
+
for (const name of varNames) {
|
|
1883
|
+
result = result.replace(
|
|
1884
|
+
new RegExp(`^\\s*(var|let|const)\\s+${name}\\s*=[^;]*;?\\s*$`, "gm"),
|
|
1885
|
+
""
|
|
1886
|
+
);
|
|
1887
|
+
}
|
|
1888
|
+
return result;
|
|
1889
|
+
}
|
|
1890
|
+
function buildScriptSection(js, comp, propDefs) {
|
|
1891
|
+
const elInit = "const el = document.currentScript.previousElementSibling;";
|
|
1892
|
+
if (comp.defineVars) {
|
|
1893
|
+
const vars = comp.defineVars === true ? Object.keys(propDefs).filter((k) => k !== "children") : comp.defineVars;
|
|
1894
|
+
if (vars.length > 0) {
|
|
1895
|
+
const transformedJS = transformDefineVarsJS(js, vars);
|
|
1896
|
+
const defineVarsObj = `{ ${vars.join(", ")} }`;
|
|
1897
|
+
return `
|
|
1898
|
+
<script define:vars={${defineVarsObj}}>
|
|
1899
|
+
${elInit}
|
|
1900
|
+
${transformedJS}
|
|
1901
|
+
</script>
|
|
1902
|
+
`;
|
|
1903
|
+
}
|
|
1904
|
+
}
|
|
1905
|
+
return `
|
|
1906
|
+
<script is:inline>
|
|
1907
|
+
${elInit}
|
|
1908
|
+
${js}
|
|
1909
|
+
</script>
|
|
1910
|
+
`;
|
|
1911
|
+
}
|
|
1173
1912
|
|
|
1174
1913
|
// lib/server/astro/pageEmitter.ts
|
|
1175
1914
|
function escapeTemplateLiteral2(s) {
|
|
@@ -1197,7 +1936,11 @@ function emitAstroPage(options) {
|
|
|
1197
1936
|
fileDepth,
|
|
1198
1937
|
ssrFallbacks,
|
|
1199
1938
|
pageName,
|
|
1200
|
-
breakpoints: breakpointsOpt
|
|
1939
|
+
breakpoints: breakpointsOpt,
|
|
1940
|
+
imageMetadataMap,
|
|
1941
|
+
i18nConfig,
|
|
1942
|
+
currentPageSlugMap,
|
|
1943
|
+
slugMappings
|
|
1201
1944
|
} = options;
|
|
1202
1945
|
const breakpoints = breakpointsOpt ?? DEFAULT_BREAKPOINTS;
|
|
1203
1946
|
const root = pageData.root;
|
|
@@ -1215,10 +1958,22 @@ function emitAstroPage(options) {
|
|
|
1215
1958
|
elementPath: [0],
|
|
1216
1959
|
fileType: "page",
|
|
1217
1960
|
fileName: pageName,
|
|
1218
|
-
breakpoints
|
|
1961
|
+
breakpoints,
|
|
1962
|
+
imageMetadataMap,
|
|
1963
|
+
locale,
|
|
1964
|
+
i18nConfig,
|
|
1965
|
+
currentPageSlugMap,
|
|
1966
|
+
frontmatterLines: [],
|
|
1967
|
+
astroImports: /* @__PURE__ */ new Set(),
|
|
1968
|
+
slugMappings,
|
|
1969
|
+
i18nDefaultLocale: i18nConfig?.defaultLocale
|
|
1219
1970
|
};
|
|
1220
1971
|
const templateBody = nodeToAstro(root, ctx);
|
|
1221
1972
|
const importLines = [];
|
|
1973
|
+
if (ctx.astroImports && ctx.astroImports.size > 0) {
|
|
1974
|
+
const astroImports = Array.from(ctx.astroImports);
|
|
1975
|
+
importLines.push(`import { ${astroImports.join(", ")} } from 'astro:content';`);
|
|
1976
|
+
}
|
|
1222
1977
|
importLines.push(`import BaseLayout from '${layoutImportPath2}';`);
|
|
1223
1978
|
const componentImports = Array.from(ctx.imports).sort();
|
|
1224
1979
|
for (const comp of componentImports) {
|
|
@@ -1229,8 +1984,9 @@ function emitAstroPage(options) {
|
|
|
1229
1984
|
const libraryTagsLiteral = `{ headCSS: \`${escapeTemplateLiteral2(libraryTags.headCSS || "")}\`, headJS: \`${escapeTemplateLiteral2(libraryTags.headJS || "")}\`, bodyEndJS: \`${escapeTemplateLiteral2(libraryTags.bodyEndJS || "")}\` }`;
|
|
1230
1985
|
const escapedMeta = escapeTemplateLiteral2(meta);
|
|
1231
1986
|
const escapedFontPreloads = escapeTemplateLiteral2(fontPreloads);
|
|
1987
|
+
const extraFrontmatter = ctx.frontmatterLines && ctx.frontmatterLines.length > 0 ? "\n" + ctx.frontmatterLines.join("\n") : "";
|
|
1232
1988
|
return `---
|
|
1233
|
-
${importLines.join("\n")}
|
|
1989
|
+
${importLines.join("\n")}${extraFrontmatter}
|
|
1234
1990
|
---
|
|
1235
1991
|
<BaseLayout
|
|
1236
1992
|
title="${escapeJSX2(title)}"
|
|
@@ -1241,7 +1997,9 @@ ${importLines.join("\n")}
|
|
|
1241
1997
|
fontPreloads={\`${escapedFontPreloads}\`}
|
|
1242
1998
|
libraryTags={${libraryTagsLiteral}}
|
|
1243
1999
|
>
|
|
1244
|
-
|
|
2000
|
+
<div id="root">
|
|
2001
|
+
${templateBody} </div>
|
|
2002
|
+
</BaseLayout>
|
|
1245
2003
|
`;
|
|
1246
2004
|
}
|
|
1247
2005
|
function buildEmptyPage(layoutImport, title, meta, locale, theme, fontPreloads, libraryTags, scriptPaths) {
|
|
@@ -1265,88 +2023,333 @@ import BaseLayout from '${layoutImport}';
|
|
|
1265
2023
|
`;
|
|
1266
2024
|
}
|
|
1267
2025
|
|
|
1268
|
-
// lib/server/astro/
|
|
1269
|
-
function
|
|
1270
|
-
return
|
|
2026
|
+
// lib/server/astro/cmsPageEmitter.ts
|
|
2027
|
+
function escapeTemplateLiteral3(s) {
|
|
2028
|
+
return s.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$\{/g, "\\${");
|
|
1271
2029
|
}
|
|
1272
|
-
function
|
|
1273
|
-
return "
|
|
2030
|
+
function escapeJSX3(s) {
|
|
2031
|
+
return s.replace(/&/g, "&").replace(/"/g, """);
|
|
1274
2032
|
}
|
|
1275
|
-
function
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
for (const [bp, bpStyle] of Object.entries(style)) {
|
|
1279
|
-
if (!bpStyle) continue;
|
|
1280
|
-
let prefix = "";
|
|
1281
|
-
if (bp !== "base") {
|
|
1282
|
-
const bpValue = breakpoints[bp]?.breakpoint;
|
|
1283
|
-
if (bpValue) {
|
|
1284
|
-
prefix = `max-[${bpValue}px]:`;
|
|
1285
|
-
}
|
|
1286
|
-
}
|
|
1287
|
-
collectFromFlatStyle(bpStyle, prefix, classes);
|
|
1288
|
-
}
|
|
1289
|
-
} else {
|
|
1290
|
-
collectFromFlatStyle(style, "", classes);
|
|
1291
|
-
}
|
|
2033
|
+
function componentImportPath2(fileDepth, componentName) {
|
|
2034
|
+
const ups = "../".repeat(fileDepth + 1);
|
|
2035
|
+
return `${ups}components/${componentName}.astro`;
|
|
1292
2036
|
}
|
|
1293
|
-
function
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
if (twClass) {
|
|
1299
|
-
classes.add(prefix ? `${prefix}${twClass}` : twClass);
|
|
1300
|
-
}
|
|
2037
|
+
function collectRichTextFields(schema) {
|
|
2038
|
+
const richTextFields = /* @__PURE__ */ new Set();
|
|
2039
|
+
for (const [fieldName, fieldDef] of Object.entries(schema.fields)) {
|
|
2040
|
+
if (fieldDef.type === "rich-text") {
|
|
2041
|
+
richTextFields.add(fieldName);
|
|
1301
2042
|
}
|
|
1302
2043
|
}
|
|
2044
|
+
return richTextFields;
|
|
1303
2045
|
}
|
|
1304
|
-
function
|
|
1305
|
-
if (
|
|
1306
|
-
|
|
1307
|
-
for (const child of node) {
|
|
1308
|
-
walkNode(child, classes, breakpoints);
|
|
1309
|
-
}
|
|
1310
|
-
return;
|
|
1311
|
-
}
|
|
1312
|
-
if ("style" in node && node.style) {
|
|
1313
|
-
collectFromStyle(node.style, classes, breakpoints);
|
|
1314
|
-
}
|
|
1315
|
-
if ("interactiveStyles" in node && Array.isArray(node.interactiveStyles)) {
|
|
1316
|
-
for (const rule of node.interactiveStyles) {
|
|
1317
|
-
if (rule.style) {
|
|
1318
|
-
collectFromStyle(rule.style, classes, breakpoints);
|
|
1319
|
-
}
|
|
1320
|
-
}
|
|
2046
|
+
function transformTitleExpression(title, binding, richTextFields, wrapFn) {
|
|
2047
|
+
if (!/\{\{cms\./.test(title)) {
|
|
2048
|
+
return `"${escapeJSX3(title)}"`;
|
|
1321
2049
|
}
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
}
|
|
1327
|
-
}
|
|
2050
|
+
const w = (expr) => wrapFn ? `${wrapFn}(${expr})` : expr;
|
|
2051
|
+
const fullMatch = title.match(/^\{\{cms\.([^}]+)\}\}$/);
|
|
2052
|
+
if (fullMatch) {
|
|
2053
|
+
return `{${w(`${binding}.data.${fullMatch[1].trim()}`)}}`;
|
|
1328
2054
|
}
|
|
2055
|
+
const replaced = title.replace(/\{\{cms\.([^}]+)\}\}/g, (_, fieldPath) => {
|
|
2056
|
+
return `\${${w(`${binding}.data.${fieldPath.trim()}`)}}`;
|
|
2057
|
+
});
|
|
2058
|
+
return `{\`${replaced}\`}`;
|
|
1329
2059
|
}
|
|
1330
|
-
function
|
|
1331
|
-
const
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
2060
|
+
function extractPathPrefix(urlPattern) {
|
|
2061
|
+
const withoutLeading = urlPattern.replace(/^\//, "");
|
|
2062
|
+
const idx = withoutLeading.indexOf("{{");
|
|
2063
|
+
if (idx <= 0) return "";
|
|
2064
|
+
return withoutLeading.substring(0, idx);
|
|
2065
|
+
}
|
|
2066
|
+
function buildGetStaticPaths(schema, isMultiLocale, i18nConfig, locale) {
|
|
2067
|
+
const collectionId = schema.id;
|
|
2068
|
+
const slugField = schema.slugField || "slug";
|
|
2069
|
+
const pathPrefix = extractPathPrefix(schema.urlPattern);
|
|
2070
|
+
const targetLocale = locale || i18nConfig.defaultLocale;
|
|
2071
|
+
if (!isMultiLocale) {
|
|
2072
|
+
const slugExpr = i18nConfig.locales.length > 1 ? `entry.data.${slugField}?.${targetLocale} || entry.data.${slugField} || entry.id` : `entry.data.${slugField} || entry.id`;
|
|
2073
|
+
return [
|
|
2074
|
+
`export async function getStaticPaths() {`,
|
|
2075
|
+
` const entries = await getCollection('${collectionId}');`,
|
|
2076
|
+
` return entries.map(entry => ({`,
|
|
2077
|
+
` params: { slug: ${slugExpr} },`,
|
|
2078
|
+
` props: { entry },`,
|
|
2079
|
+
` }));`,
|
|
2080
|
+
`}`,
|
|
2081
|
+
``,
|
|
2082
|
+
`const { entry } = Astro.props;`
|
|
2083
|
+
].join("\n");
|
|
2084
|
+
}
|
|
2085
|
+
const defaultLocale = i18nConfig.defaultLocale;
|
|
2086
|
+
const locales = i18nConfig.locales;
|
|
2087
|
+
const lines = [
|
|
2088
|
+
`export async function getStaticPaths() {`,
|
|
2089
|
+
` const entries = await getCollection('${collectionId}');`,
|
|
2090
|
+
` const paths = [];`,
|
|
2091
|
+
` for (const entry of entries) {`
|
|
2092
|
+
];
|
|
2093
|
+
for (const locale2 of locales) {
|
|
2094
|
+
const code = locale2.code;
|
|
2095
|
+
const slugExpr = `entry.data.${slugField}?.${code} || entry.data.${slugField} || entry.id`;
|
|
2096
|
+
if (code === defaultLocale) {
|
|
2097
|
+
if (pathPrefix) {
|
|
2098
|
+
lines.push(
|
|
2099
|
+
` paths.push({`,
|
|
2100
|
+
` params: { slug: \`${pathPrefix}\${${slugExpr}}\` },`,
|
|
2101
|
+
` props: { entry, locale: '${code}' },`,
|
|
2102
|
+
` });`
|
|
2103
|
+
);
|
|
2104
|
+
} else {
|
|
2105
|
+
lines.push(
|
|
2106
|
+
` paths.push({`,
|
|
2107
|
+
` params: { slug: ${slugExpr} },`,
|
|
2108
|
+
` props: { entry, locale: '${code}' },`,
|
|
2109
|
+
` });`
|
|
2110
|
+
);
|
|
2111
|
+
}
|
|
2112
|
+
} else {
|
|
2113
|
+
lines.push(
|
|
2114
|
+
` paths.push({`,
|
|
2115
|
+
` params: { slug: \`${code}/${pathPrefix}\${${slugExpr}}\` },`,
|
|
2116
|
+
` props: { entry, locale: '${code}' },`,
|
|
2117
|
+
` });`
|
|
2118
|
+
);
|
|
1336
2119
|
}
|
|
1337
2120
|
}
|
|
1338
|
-
|
|
1339
|
-
}
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
2121
|
+
lines.push(
|
|
2122
|
+
` }`,
|
|
2123
|
+
` return paths;`,
|
|
2124
|
+
`}`,
|
|
2125
|
+
``,
|
|
2126
|
+
`const { entry, locale = '${defaultLocale}' } = Astro.props;`
|
|
2127
|
+
);
|
|
2128
|
+
return lines.join("\n");
|
|
1344
2129
|
}
|
|
1345
|
-
function
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
2130
|
+
function emitCMSPage(options) {
|
|
2131
|
+
const {
|
|
2132
|
+
pageData,
|
|
2133
|
+
globalComponents,
|
|
2134
|
+
cmsSchema,
|
|
2135
|
+
title,
|
|
2136
|
+
meta,
|
|
2137
|
+
locale,
|
|
2138
|
+
theme,
|
|
2139
|
+
fontPreloads,
|
|
2140
|
+
libraryTags,
|
|
2141
|
+
scriptPaths,
|
|
2142
|
+
layoutImportPath: layoutImportPath2,
|
|
2143
|
+
fileDepth,
|
|
2144
|
+
ssrFallbacks,
|
|
2145
|
+
pageName,
|
|
2146
|
+
breakpoints: breakpointsOpt,
|
|
2147
|
+
imageMetadataMap,
|
|
2148
|
+
i18nConfig,
|
|
2149
|
+
isMultiLocale,
|
|
2150
|
+
slugMappings
|
|
2151
|
+
} = options;
|
|
2152
|
+
const breakpoints = breakpointsOpt ?? DEFAULT_BREAKPOINTS;
|
|
2153
|
+
const binding = "entry";
|
|
2154
|
+
const richTextFields = collectRichTextFields(cmsSchema);
|
|
2155
|
+
const wrapFn = "r";
|
|
2156
|
+
const root = pageData.root;
|
|
2157
|
+
if (!root) {
|
|
2158
|
+
return buildEmptyCMSPage(
|
|
2159
|
+
layoutImportPath2,
|
|
2160
|
+
title,
|
|
2161
|
+
meta,
|
|
2162
|
+
locale,
|
|
2163
|
+
theme,
|
|
2164
|
+
fontPreloads,
|
|
2165
|
+
libraryTags,
|
|
2166
|
+
scriptPaths,
|
|
2167
|
+
cmsSchema,
|
|
2168
|
+
isMultiLocale,
|
|
2169
|
+
i18nConfig,
|
|
2170
|
+
binding,
|
|
2171
|
+
richTextFields
|
|
2172
|
+
);
|
|
2173
|
+
}
|
|
2174
|
+
const ctx = {
|
|
2175
|
+
imports: /* @__PURE__ */ new Set(),
|
|
2176
|
+
isComponentDef: false,
|
|
2177
|
+
componentProps: {},
|
|
2178
|
+
globalComponents,
|
|
2179
|
+
indent: 1,
|
|
2180
|
+
// inside BaseLayout
|
|
2181
|
+
ssrFallbacks,
|
|
2182
|
+
elementPath: [0],
|
|
2183
|
+
fileType: "page",
|
|
2184
|
+
fileName: pageName,
|
|
2185
|
+
breakpoints,
|
|
2186
|
+
imageMetadataMap,
|
|
2187
|
+
locale,
|
|
2188
|
+
cmsMode: true,
|
|
2189
|
+
cmsEntryBinding: binding,
|
|
2190
|
+
cmsRichTextFields: richTextFields,
|
|
2191
|
+
cmsWrapFn: wrapFn,
|
|
2192
|
+
slugMappings,
|
|
2193
|
+
i18nDefaultLocale: i18nConfig.defaultLocale
|
|
2194
|
+
};
|
|
2195
|
+
const templateBody = nodeToAstro(root, ctx);
|
|
2196
|
+
const importLines = [];
|
|
2197
|
+
importLines.push(`import { getCollection } from 'astro:content';`);
|
|
2198
|
+
importLines.push(`import BaseLayout from '${layoutImportPath2}';`);
|
|
2199
|
+
const componentImports = Array.from(ctx.imports).sort();
|
|
2200
|
+
for (const comp of componentImports) {
|
|
2201
|
+
const path = componentImportPath2(fileDepth, comp);
|
|
2202
|
+
importLines.push(`import ${comp} from '${path}';`);
|
|
2203
|
+
}
|
|
2204
|
+
const staticPaths = buildGetStaticPaths(cmsSchema, isMultiLocale, i18nConfig, locale);
|
|
2205
|
+
const scriptsArrayLiteral = scriptPaths.length > 0 ? `[${scriptPaths.map((s) => `"${s}"`).join(", ")}]` : "[]";
|
|
2206
|
+
const libraryTagsLiteral = `{ headCSS: \`${escapeTemplateLiteral3(libraryTags.headCSS || "")}\`, headJS: \`${escapeTemplateLiteral3(libraryTags.headJS || "")}\`, bodyEndJS: \`${escapeTemplateLiteral3(libraryTags.bodyEndJS || "")}\` }`;
|
|
2207
|
+
const escapedMeta = escapeTemplateLiteral3(meta).replace(
|
|
2208
|
+
/\{\{cms\.([^}]+)\}\}/g,
|
|
2209
|
+
(_, fieldPath) => `\${${wrapFn}(${binding}.data.${fieldPath.trim()})}`
|
|
2210
|
+
);
|
|
2211
|
+
const escapedFontPreloads = escapeTemplateLiteral3(fontPreloads);
|
|
2212
|
+
const titleExpr = transformTitleExpression(title, binding, richTextFields, wrapFn);
|
|
2213
|
+
const resolverHelper = `function r(v) {
|
|
2214
|
+
if (v && typeof v === 'object' && v._i18n) return v['${locale}'] ?? v['${i18nConfig.defaultLocale}'] ?? Object.values(v).find(x => x !== true && x !== undefined) ?? '';
|
|
2215
|
+
return v ?? '';
|
|
2216
|
+
}`;
|
|
2217
|
+
return `---
|
|
2218
|
+
${importLines.join("\n")}
|
|
2219
|
+
|
|
2220
|
+
${staticPaths}
|
|
2221
|
+
|
|
2222
|
+
${resolverHelper}
|
|
2223
|
+
---
|
|
2224
|
+
<BaseLayout
|
|
2225
|
+
title=${titleExpr}
|
|
2226
|
+
meta={\`${escapedMeta}\`}
|
|
2227
|
+
scripts={${scriptsArrayLiteral}}
|
|
2228
|
+
locale="${locale}"
|
|
2229
|
+
theme="${theme}"
|
|
2230
|
+
fontPreloads={\`${escapedFontPreloads}\`}
|
|
2231
|
+
libraryTags={${libraryTagsLiteral}}
|
|
2232
|
+
>
|
|
2233
|
+
<div id="root">
|
|
2234
|
+
${templateBody} </div>
|
|
2235
|
+
</BaseLayout>
|
|
2236
|
+
`;
|
|
2237
|
+
}
|
|
2238
|
+
function buildEmptyCMSPage(layoutImport, title, meta, locale, theme, fontPreloads, libraryTags, scriptPaths, cmsSchema, isMultiLocale, i18nConfig, binding, richTextFields) {
|
|
2239
|
+
const escapedMeta = escapeTemplateLiteral3(meta);
|
|
2240
|
+
const escapedFontPreloads = escapeTemplateLiteral3(fontPreloads);
|
|
2241
|
+
const scriptsArrayLiteral = scriptPaths.length > 0 ? `[${scriptPaths.map((s) => `"${s}"`).join(", ")}]` : "[]";
|
|
2242
|
+
const libraryTagsLiteral = `{ headCSS: \`${escapeTemplateLiteral3(libraryTags.headCSS || "")}\`, headJS: \`${escapeTemplateLiteral3(libraryTags.headJS || "")}\`, bodyEndJS: \`${escapeTemplateLiteral3(libraryTags.bodyEndJS || "")}\` }`;
|
|
2243
|
+
const wrapFn = "r";
|
|
2244
|
+
const staticPaths = buildGetStaticPaths(cmsSchema, isMultiLocale, i18nConfig, locale);
|
|
2245
|
+
const titleExpr = transformTitleExpression(title, binding, richTextFields, wrapFn);
|
|
2246
|
+
const resolverHelper = `function r(v) {
|
|
2247
|
+
if (v && typeof v === 'object' && v._i18n) return v['${locale}'] ?? v['${i18nConfig.defaultLocale}'] ?? Object.values(v).find(x => x !== true && x !== undefined) ?? '';
|
|
2248
|
+
return v ?? '';
|
|
2249
|
+
}`;
|
|
2250
|
+
return `---
|
|
2251
|
+
import { getCollection } from 'astro:content';
|
|
2252
|
+
import BaseLayout from '${layoutImport}';
|
|
2253
|
+
|
|
2254
|
+
${staticPaths}
|
|
2255
|
+
|
|
2256
|
+
${resolverHelper}
|
|
2257
|
+
---
|
|
2258
|
+
<BaseLayout
|
|
2259
|
+
title=${titleExpr}
|
|
2260
|
+
meta={\`${escapedMeta}\`}
|
|
2261
|
+
scripts={${scriptsArrayLiteral}}
|
|
2262
|
+
locale="${locale}"
|
|
2263
|
+
theme="${theme}"
|
|
2264
|
+
fontPreloads={\`${escapedFontPreloads}\`}
|
|
2265
|
+
libraryTags={${libraryTagsLiteral}}
|
|
2266
|
+
>
|
|
2267
|
+
</BaseLayout>
|
|
2268
|
+
`;
|
|
2269
|
+
}
|
|
2270
|
+
|
|
2271
|
+
// lib/server/astro/cssCollector.ts
|
|
2272
|
+
function isStyleMapping3(value) {
|
|
2273
|
+
return typeof value === "object" && value !== null && "_mapping" in value && value._mapping === true;
|
|
2274
|
+
}
|
|
2275
|
+
function isResponsiveStyle3(style) {
|
|
2276
|
+
return "base" in style || "tablet" in style || "mobile" in style;
|
|
2277
|
+
}
|
|
2278
|
+
function collectFromStyle(style, classes, breakpoints) {
|
|
2279
|
+
if (!style) return;
|
|
2280
|
+
if (isResponsiveStyle3(style)) {
|
|
2281
|
+
for (const [bp, bpStyle] of Object.entries(style)) {
|
|
2282
|
+
if (!bpStyle) continue;
|
|
2283
|
+
let prefix = "";
|
|
2284
|
+
if (bp !== "base") {
|
|
2285
|
+
const bpValue = breakpoints[bp]?.breakpoint;
|
|
2286
|
+
if (bpValue) {
|
|
2287
|
+
prefix = `max-[${bpValue}px]:`;
|
|
2288
|
+
}
|
|
2289
|
+
}
|
|
2290
|
+
collectFromFlatStyle(bpStyle, prefix, classes);
|
|
2291
|
+
}
|
|
2292
|
+
} else {
|
|
2293
|
+
collectFromFlatStyle(style, "", classes);
|
|
2294
|
+
}
|
|
2295
|
+
}
|
|
2296
|
+
function collectFromFlatStyle(style, prefix, classes) {
|
|
2297
|
+
for (const [property, value] of Object.entries(style)) {
|
|
2298
|
+
if (!isStyleMapping3(value)) continue;
|
|
2299
|
+
for (const [, cssValue] of Object.entries(value.values)) {
|
|
2300
|
+
const twClass = propertyToTailwind(property, cssValue);
|
|
2301
|
+
if (twClass) {
|
|
2302
|
+
classes.add(prefix ? `${prefix}${twClass}` : twClass);
|
|
2303
|
+
}
|
|
2304
|
+
}
|
|
2305
|
+
}
|
|
2306
|
+
}
|
|
2307
|
+
function walkNode(node, classes, breakpoints) {
|
|
2308
|
+
if (!node || typeof node === "string" || typeof node === "number") return;
|
|
2309
|
+
if (Array.isArray(node)) {
|
|
2310
|
+
for (const child of node) {
|
|
2311
|
+
walkNode(child, classes, breakpoints);
|
|
2312
|
+
}
|
|
2313
|
+
return;
|
|
2314
|
+
}
|
|
2315
|
+
if ("style" in node && node.style) {
|
|
2316
|
+
collectFromStyle(node.style, classes, breakpoints);
|
|
2317
|
+
}
|
|
2318
|
+
if ("interactiveStyles" in node && Array.isArray(node.interactiveStyles)) {
|
|
2319
|
+
for (const rule of node.interactiveStyles) {
|
|
2320
|
+
if (rule.style) {
|
|
2321
|
+
collectFromStyle(rule.style, classes, breakpoints);
|
|
2322
|
+
}
|
|
2323
|
+
}
|
|
2324
|
+
}
|
|
2325
|
+
if ("children" in node && node.children) {
|
|
2326
|
+
if (Array.isArray(node.children)) {
|
|
2327
|
+
for (const child of node.children) {
|
|
2328
|
+
walkNode(child, classes, breakpoints);
|
|
2329
|
+
}
|
|
2330
|
+
}
|
|
2331
|
+
}
|
|
2332
|
+
}
|
|
2333
|
+
function collectAllMappingClasses(componentDefs, breakpoints = DEFAULT_BREAKPOINTS) {
|
|
2334
|
+
const classes = /* @__PURE__ */ new Set();
|
|
2335
|
+
for (const def of Object.values(componentDefs)) {
|
|
2336
|
+
const structure = def.component?.structure;
|
|
2337
|
+
if (structure) {
|
|
2338
|
+
walkNode(structure, classes, breakpoints);
|
|
2339
|
+
}
|
|
2340
|
+
}
|
|
2341
|
+
return classes;
|
|
2342
|
+
}
|
|
2343
|
+
|
|
2344
|
+
// build-astro.ts
|
|
2345
|
+
function hashContent2(content) {
|
|
2346
|
+
return createHash("sha256").update(content).digest("hex").slice(0, 8);
|
|
2347
|
+
}
|
|
2348
|
+
function copyDirectory(src, dest) {
|
|
2349
|
+
if (!existsSync(src)) return;
|
|
2350
|
+
if (!existsSync(dest)) mkdirSync(dest, { recursive: true });
|
|
2351
|
+
const files = readdirSync(src);
|
|
2352
|
+
for (const file of files) {
|
|
1350
2353
|
const srcPath = join(src, file);
|
|
1351
2354
|
const destPath = join(dest, file);
|
|
1352
2355
|
const stat = statSync(srcPath);
|
|
@@ -1357,13 +2360,6 @@ function copyDirectory(src, dest) {
|
|
|
1357
2360
|
function isCMSPage(pageData) {
|
|
1358
2361
|
return pageData.meta?.source === "cms" && !!pageData.meta?.cms;
|
|
1359
2362
|
}
|
|
1360
|
-
function buildCMSItemPath(urlPattern, item, slugField, locale, i18nConfig) {
|
|
1361
|
-
let slug = item[slugField] ?? item._slug ?? item._id;
|
|
1362
|
-
if (isI18nValue(slug)) {
|
|
1363
|
-
slug = resolveI18nValue(slug, locale, i18nConfig);
|
|
1364
|
-
}
|
|
1365
|
-
return urlPattern.replace("{{slug}}", String(slug));
|
|
1366
|
-
}
|
|
1367
2363
|
function scanJSONFiles(dir, prefix = "") {
|
|
1368
2364
|
const results = [];
|
|
1369
2365
|
if (!existsSync(dir)) return results;
|
|
@@ -1381,15 +2377,29 @@ function layoutImportPath(fileDepth) {
|
|
|
1381
2377
|
const ups = "../".repeat(fileDepth + 1);
|
|
1382
2378
|
return `${ups}layouts/BaseLayout.astro`;
|
|
1383
2379
|
}
|
|
1384
|
-
function
|
|
2380
|
+
function escapeTemplateLiteral4(s) {
|
|
1385
2381
|
return s.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$\{/g, "\\${");
|
|
1386
2382
|
}
|
|
2383
|
+
function computePageSlugMap(slugs, i18nConfig) {
|
|
2384
|
+
const map = {};
|
|
2385
|
+
for (const localeConfig of i18nConfig.locales) {
|
|
2386
|
+
const code = localeConfig.code;
|
|
2387
|
+
const isDefault = code === i18nConfig.defaultLocale;
|
|
2388
|
+
const slug = slugs[code] || "";
|
|
2389
|
+
if (isDefault) {
|
|
2390
|
+
map[code] = slug === "" ? "/" : `/${slug}`;
|
|
2391
|
+
} else {
|
|
2392
|
+
map[code] = slug === "" ? `/${code}` : `/${code}/${slug}`;
|
|
2393
|
+
}
|
|
2394
|
+
}
|
|
2395
|
+
return map;
|
|
2396
|
+
}
|
|
1387
2397
|
function cmsFieldToZod(field) {
|
|
1388
2398
|
switch (field.type) {
|
|
1389
2399
|
case "string":
|
|
1390
2400
|
case "text":
|
|
1391
2401
|
case "rich-text":
|
|
1392
|
-
return "z.string()";
|
|
2402
|
+
return "z.union([z.string(), z.object({ _i18n: z.literal(true) }).passthrough()])";
|
|
1393
2403
|
case "number":
|
|
1394
2404
|
return "z.number()";
|
|
1395
2405
|
case "boolean":
|
|
@@ -1412,11 +2422,11 @@ function cmsFieldToZod(field) {
|
|
|
1412
2422
|
}
|
|
1413
2423
|
}
|
|
1414
2424
|
function buildSSRFallbackPage(result, importPath, fontPreloads, libraryTags, defaultTheme, scriptPaths) {
|
|
1415
|
-
const escapedMeta =
|
|
1416
|
-
const escapedHTML =
|
|
1417
|
-
const escapedFontPreloads =
|
|
2425
|
+
const escapedMeta = escapeTemplateLiteral4(result.meta);
|
|
2426
|
+
const escapedHTML = escapeTemplateLiteral4(result.html);
|
|
2427
|
+
const escapedFontPreloads = escapeTemplateLiteral4(fontPreloads);
|
|
1418
2428
|
const scriptsArrayLiteral = scriptPaths.length > 0 ? `[${scriptPaths.map((s) => `"${s}"`).join(", ")}]` : "[]";
|
|
1419
|
-
const libraryTagsLiteral = `{ headCSS: \`${
|
|
2429
|
+
const libraryTagsLiteral = `{ headCSS: \`${escapeTemplateLiteral4(libraryTags.headCSS || "")}\`, headJS: \`${escapeTemplateLiteral4(libraryTags.headJS || "")}\`, bodyEndJS: \`${escapeTemplateLiteral4(libraryTags.bodyEndJS || "")}\` }`;
|
|
1420
2430
|
return `---
|
|
1421
2431
|
import BaseLayout from '${importPath}';
|
|
1422
2432
|
---
|
|
@@ -1463,6 +2473,11 @@ async function buildAstroProject(projectRoot, outputDir) {
|
|
|
1463
2473
|
await configService.load();
|
|
1464
2474
|
const globalLibraries = configService.getLibraries();
|
|
1465
2475
|
const componentLibraries = collectComponentLibraries(globalComponents);
|
|
2476
|
+
const imageMetadataMap = await buildImageMetadataMap();
|
|
2477
|
+
if (imageMetadataMap.size > 0) {
|
|
2478
|
+
console.log(`Loaded image metadata for ${imageMetadataMap.size} image(s)
|
|
2479
|
+
`);
|
|
2480
|
+
}
|
|
1466
2481
|
const outDir = outputDir || join(projectPaths.project, "astro-export");
|
|
1467
2482
|
if (existsSync(outDir)) {
|
|
1468
2483
|
rmSync(outDir, { recursive: true, force: true });
|
|
@@ -1517,7 +2532,7 @@ async function buildAstroProject(projectRoot, outputDir) {
|
|
|
1517
2532
|
}
|
|
1518
2533
|
}
|
|
1519
2534
|
}
|
|
1520
|
-
function processRenderResult(result, urlPath, astroFilePath, fileDepth, pageData, pageName,
|
|
2535
|
+
function processRenderResult(result, urlPath, astroFilePath, fileDepth, pageData, pageName, isCMSPage3) {
|
|
1521
2536
|
mergeInteractiveStyles(result.interactiveStylesMap);
|
|
1522
2537
|
if (result.componentCSS) {
|
|
1523
2538
|
allComponentCSS.add(result.componentCSS);
|
|
@@ -1541,7 +2556,8 @@ async function buildAstroProject(projectRoot, outputDir) {
|
|
|
1541
2556
|
astroFilePath,
|
|
1542
2557
|
pageData,
|
|
1543
2558
|
pageName,
|
|
1544
|
-
isCMSPage:
|
|
2559
|
+
isCMSPage: isCMSPage3,
|
|
2560
|
+
ssrFallbackCollector: result.ssrFallbackCollector
|
|
1545
2561
|
});
|
|
1546
2562
|
}
|
|
1547
2563
|
for (const file of pageFiles) {
|
|
@@ -1598,6 +2614,11 @@ async function buildAstroProject(projectRoot, outputDir) {
|
|
|
1598
2614
|
errorCount++;
|
|
1599
2615
|
}
|
|
1600
2616
|
}
|
|
2617
|
+
const fontPreloads = generateFontPreloadTags();
|
|
2618
|
+
const mergedLibraries = mergeLibraries(globalLibraries, componentLibraries);
|
|
2619
|
+
const buildLibraries = filterLibrariesByContext(mergedLibraries, "build");
|
|
2620
|
+
const libraryTags = generateLibraryTags(buildLibraries);
|
|
2621
|
+
const defaultTheme = themeConfig.default || "light";
|
|
1601
2622
|
const templatesDir = projectPaths.templates();
|
|
1602
2623
|
const templateSchemas = [];
|
|
1603
2624
|
let cmsPageCount = 0;
|
|
@@ -1626,42 +2647,87 @@ Processing ${templateFiles.length} CMS template(s)...
|
|
|
1626
2647
|
templateSchemas.push(cmsSchema);
|
|
1627
2648
|
console.log(` CMS Collection: ${cmsSchema.id}`);
|
|
1628
2649
|
const items = await cmsService.queryItems({ collection: cmsSchema.id });
|
|
1629
|
-
|
|
2650
|
+
const itemCount = items.length;
|
|
2651
|
+
if (itemCount === 0) {
|
|
1630
2652
|
console.log(` No items found in cms/${cmsSchema.id}/`);
|
|
1631
|
-
|
|
2653
|
+
} else {
|
|
2654
|
+
console.log(` Found ${itemCount} item(s)`);
|
|
1632
2655
|
}
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
2656
|
+
const defaultLocale = i18nConfig.defaultLocale;
|
|
2657
|
+
const dummyPath = cmsSchema.urlPattern.replace("{{slug}}", "__placeholder__");
|
|
2658
|
+
const metaResult = await renderPageSSR(
|
|
2659
|
+
pageData,
|
|
2660
|
+
globalComponents,
|
|
2661
|
+
dummyPath,
|
|
2662
|
+
siteUrl,
|
|
2663
|
+
defaultLocale,
|
|
2664
|
+
i18nConfig,
|
|
2665
|
+
slugMappings,
|
|
2666
|
+
void 0,
|
|
2667
|
+
// no CMS context - just collecting metadata
|
|
2668
|
+
cmsService,
|
|
2669
|
+
true
|
|
2670
|
+
);
|
|
2671
|
+
mergeInteractiveStyles(metaResult.interactiveStylesMap);
|
|
2672
|
+
if (metaResult.componentCSS) {
|
|
2673
|
+
allComponentCSS.add(metaResult.componentCSS);
|
|
2674
|
+
}
|
|
2675
|
+
const scriptPaths = [];
|
|
2676
|
+
if (metaResult.javascript) {
|
|
2677
|
+
const hash = hashContent2(metaResult.javascript);
|
|
2678
|
+
if (!jsContents.has(hash)) {
|
|
2679
|
+
jsContents.set(hash, metaResult.javascript);
|
|
2680
|
+
}
|
|
2681
|
+
scriptPaths.push(`/_scripts/${hash}.js`);
|
|
2682
|
+
}
|
|
2683
|
+
const isMultiLocale = i18nConfig.locales.length > 1;
|
|
2684
|
+
const urlPatternWithoutSlash = cmsSchema.urlPattern.replace(/^\//, "");
|
|
2685
|
+
const slugPlaceholderIdx = urlPatternWithoutSlash.indexOf("{{");
|
|
2686
|
+
const pathPrefix = slugPlaceholderIdx > 0 ? urlPatternWithoutSlash.substring(0, slugPlaceholderIdx) : "";
|
|
2687
|
+
const ssrFallbacks = metaResult.ssrFallbackCollector ?? /* @__PURE__ */ new Map();
|
|
2688
|
+
const localesToEmit = isMultiLocale ? i18nConfig.locales : [{ code: i18nConfig.defaultLocale }];
|
|
2689
|
+
for (const localeEntry of localesToEmit) {
|
|
2690
|
+
const localeCode = localeEntry.code;
|
|
2691
|
+
const isDefault = localeCode === i18nConfig.defaultLocale;
|
|
2692
|
+
let astroFilePath;
|
|
2693
|
+
if (pathPrefix) {
|
|
2694
|
+
astroFilePath = isDefault ? `${pathPrefix}[slug].astro` : `${localeCode}/${pathPrefix}[slug].astro`;
|
|
2695
|
+
} else {
|
|
2696
|
+
astroFilePath = isDefault ? "[slug].astro" : `${localeCode}/[slug].astro`;
|
|
1663
2697
|
}
|
|
2698
|
+
const fileDepth = astroFilePath.split("/").length - 1;
|
|
2699
|
+
const importPath = layoutImportPath(fileDepth);
|
|
2700
|
+
const astroContent = emitCMSPage({
|
|
2701
|
+
pageData,
|
|
2702
|
+
globalComponents,
|
|
2703
|
+
cmsSchema,
|
|
2704
|
+
title: String(pageData.meta?.title || cmsSchema.name),
|
|
2705
|
+
meta: metaResult.meta,
|
|
2706
|
+
locale: localeCode,
|
|
2707
|
+
theme: defaultTheme,
|
|
2708
|
+
fontPreloads,
|
|
2709
|
+
libraryTags,
|
|
2710
|
+
scriptPaths,
|
|
2711
|
+
layoutImportPath: importPath,
|
|
2712
|
+
fileDepth,
|
|
2713
|
+
ssrFallbacks,
|
|
2714
|
+
pageName: file.replace(".json", ""),
|
|
2715
|
+
breakpoints,
|
|
2716
|
+
imageMetadataMap,
|
|
2717
|
+
i18nConfig,
|
|
2718
|
+
isMultiLocale: false,
|
|
2719
|
+
// Each file handles one locale
|
|
2720
|
+
slugMappings
|
|
2721
|
+
});
|
|
2722
|
+
const astroFileFull = join(pagesOutDir, astroFilePath);
|
|
2723
|
+
const astroFileDir = astroFileFull.substring(0, astroFileFull.lastIndexOf("/"));
|
|
2724
|
+
if (!existsSync(astroFileDir)) {
|
|
2725
|
+
mkdirSync(astroFileDir, { recursive: true });
|
|
2726
|
+
}
|
|
2727
|
+
await writeFile2(astroFileFull, astroContent, "utf-8");
|
|
1664
2728
|
}
|
|
2729
|
+
console.log(` Generated: ${pathPrefix}[slug].astro (${itemCount} items \xD7 ${localesToEmit.length} locale(s))`);
|
|
2730
|
+
cmsPageCount += itemCount * i18nConfig.locales.length;
|
|
1665
2731
|
} catch (error) {
|
|
1666
2732
|
console.error(` Error processing template ${file}:`, error?.message || error);
|
|
1667
2733
|
errorCount++;
|
|
@@ -1690,10 +2756,6 @@ Processing ${templateFiles.length} CMS template(s)...
|
|
|
1690
2756
|
await writeFile2(join(stylesDir, "global.css"), globalCSS, "utf-8");
|
|
1691
2757
|
console.log(`
|
|
1692
2758
|
Generated global.css (${(globalCSS.length / 1024).toFixed(1)} KB)`);
|
|
1693
|
-
const fontPreloads = generateFontPreloadTags();
|
|
1694
|
-
const mergedLibraries = mergeLibraries(globalLibraries, componentLibraries);
|
|
1695
|
-
const buildLibraries = filterLibrariesByContext(mergedLibraries, "build");
|
|
1696
|
-
const libraryTags = generateLibraryTags(buildLibraries);
|
|
1697
2759
|
const baseLayoutContent = `---
|
|
1698
2760
|
import '../styles/global.css';
|
|
1699
2761
|
|
|
@@ -1732,7 +2794,7 @@ const { title, meta = '', scripts = [], locale = 'en', theme = '${themeConfig.de
|
|
|
1732
2794
|
let componentFileCount = 0;
|
|
1733
2795
|
for (const [compName, compDef] of Object.entries(globalComponents)) {
|
|
1734
2796
|
try {
|
|
1735
|
-
const astroContent = emitAstroComponent(compName, compDef, globalComponents, breakpoints);
|
|
2797
|
+
const astroContent = emitAstroComponent(compName, compDef, globalComponents, breakpoints, i18nConfig.defaultLocale);
|
|
1736
2798
|
await writeFile2(join(componentsOutDir, `${compName}.astro`), astroContent, "utf-8");
|
|
1737
2799
|
componentFileCount++;
|
|
1738
2800
|
} catch (error) {
|
|
@@ -1740,7 +2802,7 @@ const { title, meta = '', scripts = [], locale = 'en', theme = '${themeConfig.de
|
|
|
1740
2802
|
}
|
|
1741
2803
|
}
|
|
1742
2804
|
console.log(`Generated ${componentFileCount} component .astro file(s)`);
|
|
1743
|
-
const
|
|
2805
|
+
const allFallbackHtml = [];
|
|
1744
2806
|
for (const result of allResults) {
|
|
1745
2807
|
const importPath = layoutImportPath(result.fileDepth);
|
|
1746
2808
|
const scriptPaths = [];
|
|
@@ -1758,8 +2820,13 @@ const { title, meta = '', scripts = [], locale = 'en', theme = '${themeConfig.de
|
|
|
1758
2820
|
scriptPaths.push(scriptPublicPath);
|
|
1759
2821
|
}
|
|
1760
2822
|
let astroContent;
|
|
1761
|
-
if (result.pageData
|
|
2823
|
+
if (result.pageData) {
|
|
1762
2824
|
try {
|
|
2825
|
+
const ssrFallbacks = result.ssrFallbackCollector ?? /* @__PURE__ */ new Map();
|
|
2826
|
+
ssrFallbacks.forEach((html) => {
|
|
2827
|
+
allFallbackHtml.push(html);
|
|
2828
|
+
});
|
|
2829
|
+
const pageSlugMap = result.pageData.meta?.slugs ? computePageSlugMap(result.pageData.meta.slugs, i18nConfig) : void 0;
|
|
1763
2830
|
astroContent = emitAstroPage({
|
|
1764
2831
|
pageData: result.pageData,
|
|
1765
2832
|
globalComponents,
|
|
@@ -1772,10 +2839,13 @@ const { title, meta = '', scripts = [], locale = 'en', theme = '${themeConfig.de
|
|
|
1772
2839
|
scriptPaths,
|
|
1773
2840
|
layoutImportPath: importPath,
|
|
1774
2841
|
fileDepth: result.fileDepth,
|
|
1775
|
-
ssrFallbacks
|
|
1776
|
-
// SSR fallbacks for complex nodes
|
|
2842
|
+
ssrFallbacks,
|
|
1777
2843
|
pageName: result.pageName || "index",
|
|
1778
|
-
breakpoints
|
|
2844
|
+
breakpoints,
|
|
2845
|
+
imageMetadataMap,
|
|
2846
|
+
i18nConfig: i18nConfig.locales.length > 1 ? i18nConfig : void 0,
|
|
2847
|
+
currentPageSlugMap: pageSlugMap,
|
|
2848
|
+
slugMappings: i18nConfig.locales.length > 1 ? slugMappings : void 0
|
|
1779
2849
|
});
|
|
1780
2850
|
} catch (error) {
|
|
1781
2851
|
console.warn(` Warning: component emission failed for ${result.urlPath}, using SSR fallback: ${error?.message}`);
|
|
@@ -1783,6 +2853,7 @@ const { title, meta = '', scripts = [], locale = 'en', theme = '${themeConfig.de
|
|
|
1783
2853
|
}
|
|
1784
2854
|
} else {
|
|
1785
2855
|
astroContent = buildSSRFallbackPage(result, importPath, fontPreloads, libraryTags, defaultTheme, scriptPaths);
|
|
2856
|
+
allFallbackHtml.push(result.html);
|
|
1786
2857
|
}
|
|
1787
2858
|
const astroFileFull = join(pagesOutDir, result.astroFilePath);
|
|
1788
2859
|
const astroFileDir = astroFileFull.substring(0, astroFileFull.lastIndexOf("/"));
|
|
@@ -1792,6 +2863,22 @@ const { title, meta = '', scripts = [], locale = 'en', theme = '${themeConfig.de
|
|
|
1792
2863
|
await writeFile2(astroFileFull, astroContent, "utf-8");
|
|
1793
2864
|
}
|
|
1794
2865
|
console.log(`Generated ${allResults.length} .astro page file(s)`);
|
|
2866
|
+
if (allFallbackHtml.length > 0) {
|
|
2867
|
+
const allClasses = /* @__PURE__ */ new Set();
|
|
2868
|
+
for (const html of allFallbackHtml) {
|
|
2869
|
+
for (const cls of extractUtilityClassesFromHTML(html)) {
|
|
2870
|
+
allClasses.add(cls);
|
|
2871
|
+
}
|
|
2872
|
+
}
|
|
2873
|
+
if (allClasses.size > 0) {
|
|
2874
|
+
const utilityCSS = generateUtilityCSS(allClasses, breakpoints, responsiveScales);
|
|
2875
|
+
if (utilityCSS) {
|
|
2876
|
+
const existingCSS = await readFile(join(stylesDir, "global.css"), "utf-8");
|
|
2877
|
+
await writeFile2(join(stylesDir, "global.css"), existingCSS + "\n\n/* SSR fallback utility classes */\n" + utilityCSS, "utf-8");
|
|
2878
|
+
console.log(`Added ${allClasses.size} utility classes for SSR fallback content`);
|
|
2879
|
+
}
|
|
2880
|
+
}
|
|
2881
|
+
}
|
|
1795
2882
|
let collectionCount = 0;
|
|
1796
2883
|
if (templateSchemas.length > 0) {
|
|
1797
2884
|
const contentDir = join(srcDir, "content");
|
|
@@ -1807,14 +2894,7 @@ const { title, meta = '', scripts = [], locale = 'en', theme = '${themeConfig.de
|
|
|
1807
2894
|
try {
|
|
1808
2895
|
const rawContent = await readFile(join(cmsItemsDir, itemFile), "utf-8");
|
|
1809
2896
|
const item = JSON.parse(rawContent);
|
|
1810
|
-
const resolved = {};
|
|
1811
|
-
for (const [key, value] of Object.entries(item)) {
|
|
1812
|
-
if (isI18nValue(value)) {
|
|
1813
|
-
resolved[key] = resolveI18nValue(value, i18nConfig.defaultLocale, i18nConfig);
|
|
1814
|
-
} else {
|
|
1815
|
-
resolved[key] = value;
|
|
1816
|
-
}
|
|
1817
|
-
}
|
|
2897
|
+
const resolved = { ...item };
|
|
1818
2898
|
await writeFile2(
|
|
1819
2899
|
join(collectionDir, itemFile),
|
|
1820
2900
|
JSON.stringify(resolved, null, 2),
|
|
@@ -1882,19 +2962,24 @@ export { collections };
|
|
|
1882
2962
|
},
|
|
1883
2963
|
dependencies: {
|
|
1884
2964
|
"astro": "^4.0.0",
|
|
1885
|
-
"@astrojs/sitemap": "^3.0.0",
|
|
1886
2965
|
"@astrojs/tailwind": "^5.0.0",
|
|
1887
2966
|
"tailwindcss": "^3.4.0"
|
|
1888
2967
|
}
|
|
1889
2968
|
};
|
|
1890
2969
|
await writeFile2(join(outDir, "package.json"), JSON.stringify(packageJson, null, 2), "utf-8");
|
|
2970
|
+
const localeCodes = i18nConfig.locales.map((l) => l.code);
|
|
2971
|
+
const i18nBlock = i18nConfig.locales.length > 1 ? `
|
|
2972
|
+
i18n: {
|
|
2973
|
+
defaultLocale: '${i18nConfig.defaultLocale}',
|
|
2974
|
+
locales: [${localeCodes.map((c) => `'${c}'`).join(", ")}],
|
|
2975
|
+
routing: { prefixDefaultLocale: false },
|
|
2976
|
+
},` : "";
|
|
1891
2977
|
const astroConfig = `import { defineConfig } from 'astro/config';
|
|
1892
|
-
import sitemap from '@astrojs/sitemap';
|
|
1893
2978
|
import tailwind from '@astrojs/tailwind';
|
|
1894
2979
|
|
|
1895
2980
|
export default defineConfig({${siteUrl ? `
|
|
1896
|
-
site: '${siteUrl}',` : ""}
|
|
1897
|
-
integrations: [
|
|
2981
|
+
site: '${siteUrl}',` : ""}${i18nBlock}
|
|
2982
|
+
integrations: [tailwind({ applyBaseStyles: false })],
|
|
1898
2983
|
});
|
|
1899
2984
|
`;
|
|
1900
2985
|
const safelistArray = Array.from(mappingClasses);
|
|
@@ -1943,6 +3028,730 @@ export default {
|
|
|
1943
3028
|
};
|
|
1944
3029
|
}
|
|
1945
3030
|
|
|
3031
|
+
// lib/server/webflow/buildWebflow.ts
|
|
3032
|
+
import { existsSync as existsSync2, readdirSync as readdirSync2 } from "fs";
|
|
3033
|
+
import { join as join2 } from "path";
|
|
3034
|
+
|
|
3035
|
+
// lib/server/webflow/types.ts
|
|
3036
|
+
function mapCMSFieldType(menoType) {
|
|
3037
|
+
switch (menoType) {
|
|
3038
|
+
case "string":
|
|
3039
|
+
return "PlainText";
|
|
3040
|
+
case "text":
|
|
3041
|
+
case "rich-text":
|
|
3042
|
+
return "RichText";
|
|
3043
|
+
case "number":
|
|
3044
|
+
return "Number";
|
|
3045
|
+
case "boolean":
|
|
3046
|
+
return "Switch";
|
|
3047
|
+
case "image":
|
|
3048
|
+
return "Image";
|
|
3049
|
+
case "date":
|
|
3050
|
+
return "Date";
|
|
3051
|
+
case "select":
|
|
3052
|
+
return "Option";
|
|
3053
|
+
case "file":
|
|
3054
|
+
return "File";
|
|
3055
|
+
case "reference":
|
|
3056
|
+
return "Reference";
|
|
3057
|
+
default:
|
|
3058
|
+
return "PlainText";
|
|
3059
|
+
}
|
|
3060
|
+
}
|
|
3061
|
+
|
|
3062
|
+
// lib/server/webflow/nodeToWebflow.ts
|
|
3063
|
+
init_constants();
|
|
3064
|
+
|
|
3065
|
+
// lib/server/webflow/styleMapper.ts
|
|
3066
|
+
var UNITLESS_PROPERTIES = /* @__PURE__ */ new Set([
|
|
3067
|
+
"opacity",
|
|
3068
|
+
"z-index",
|
|
3069
|
+
"flex-grow",
|
|
3070
|
+
"flex-shrink",
|
|
3071
|
+
"flex",
|
|
3072
|
+
"order",
|
|
3073
|
+
"orphans",
|
|
3074
|
+
"widows",
|
|
3075
|
+
"column-count",
|
|
3076
|
+
"font-weight",
|
|
3077
|
+
"tab-size"
|
|
3078
|
+
]);
|
|
3079
|
+
function isStyleMapping4(value) {
|
|
3080
|
+
return typeof value === "object" && value !== null && "_mapping" in value && value._mapping === true;
|
|
3081
|
+
}
|
|
3082
|
+
function isResponsiveStyle4(style) {
|
|
3083
|
+
return "base" in style || "tablet" in style || "mobile" in style;
|
|
3084
|
+
}
|
|
3085
|
+
function toKebabCase(prop) {
|
|
3086
|
+
return prop.replace(/([A-Z])/g, "-$1").toLowerCase();
|
|
3087
|
+
}
|
|
3088
|
+
function styleObjectToCSS(style) {
|
|
3089
|
+
const css = {};
|
|
3090
|
+
for (const [prop, value] of Object.entries(style)) {
|
|
3091
|
+
if (isStyleMapping4(value)) continue;
|
|
3092
|
+
if (value === "" || value === void 0 || value === null) continue;
|
|
3093
|
+
if (typeof value === "boolean" || typeof value === "object") continue;
|
|
3094
|
+
const cssProp = toKebabCase(prop);
|
|
3095
|
+
if (typeof value === "number") {
|
|
3096
|
+
if (isNaN(value)) continue;
|
|
3097
|
+
css[cssProp] = UNITLESS_PROPERTIES.has(cssProp) ? String(value) : `${value}px`;
|
|
3098
|
+
} else {
|
|
3099
|
+
css[cssProp] = String(value);
|
|
3100
|
+
}
|
|
3101
|
+
}
|
|
3102
|
+
return css;
|
|
3103
|
+
}
|
|
3104
|
+
function collectStyleMappings2(style) {
|
|
3105
|
+
if (!style) return [];
|
|
3106
|
+
const result = [];
|
|
3107
|
+
if (isResponsiveStyle4(style)) {
|
|
3108
|
+
const base = style.base;
|
|
3109
|
+
if (base) {
|
|
3110
|
+
for (const [prop, value] of Object.entries(base)) {
|
|
3111
|
+
if (isStyleMapping4(value)) {
|
|
3112
|
+
result.push({ property: prop, mapping: value });
|
|
3113
|
+
}
|
|
3114
|
+
}
|
|
3115
|
+
}
|
|
3116
|
+
} else {
|
|
3117
|
+
for (const [prop, value] of Object.entries(style)) {
|
|
3118
|
+
if (isStyleMapping4(value)) {
|
|
3119
|
+
result.push({ property: prop, mapping: value });
|
|
3120
|
+
}
|
|
3121
|
+
}
|
|
3122
|
+
}
|
|
3123
|
+
return result;
|
|
3124
|
+
}
|
|
3125
|
+
function postfixToPseudoState(postfix) {
|
|
3126
|
+
if (postfix.includes(":hover")) return "hover";
|
|
3127
|
+
if (postfix.includes(":focus-visible")) return "focus-visible";
|
|
3128
|
+
if (postfix.includes(":focus")) return "focus";
|
|
3129
|
+
if (postfix.includes(":active")) return "active";
|
|
3130
|
+
if (postfix.includes(":visited")) return "visited";
|
|
3131
|
+
return null;
|
|
3132
|
+
}
|
|
3133
|
+
function mapStylesToWebflow(className, style, interactiveStyles, breakpoints) {
|
|
3134
|
+
const webflowClassName = className.replace(/_/g, "-");
|
|
3135
|
+
const primaryClass = {
|
|
3136
|
+
name: webflowClassName,
|
|
3137
|
+
base: {}
|
|
3138
|
+
};
|
|
3139
|
+
if (style) {
|
|
3140
|
+
if (isResponsiveStyle4(style)) {
|
|
3141
|
+
const responsive = style;
|
|
3142
|
+
if (responsive.base) {
|
|
3143
|
+
primaryClass.base = styleObjectToCSS(responsive.base);
|
|
3144
|
+
}
|
|
3145
|
+
if (responsive.tablet) {
|
|
3146
|
+
if (!primaryClass.breakpoints) primaryClass.breakpoints = {};
|
|
3147
|
+
primaryClass.breakpoints.Tablet = styleObjectToCSS(responsive.tablet);
|
|
3148
|
+
}
|
|
3149
|
+
if (responsive.mobile) {
|
|
3150
|
+
if (!primaryClass.breakpoints) primaryClass.breakpoints = {};
|
|
3151
|
+
primaryClass.breakpoints.MobilePortrait = styleObjectToCSS(responsive.mobile);
|
|
3152
|
+
}
|
|
3153
|
+
for (const [bpName, bpStyle] of Object.entries(responsive)) {
|
|
3154
|
+
if (!bpStyle || bpName === "base" || bpName === "tablet" || bpName === "mobile") continue;
|
|
3155
|
+
if (!primaryClass.breakpoints) primaryClass.breakpoints = {};
|
|
3156
|
+
primaryClass.breakpoints.Tablet = {
|
|
3157
|
+
...primaryClass.breakpoints.Tablet,
|
|
3158
|
+
...styleObjectToCSS(bpStyle)
|
|
3159
|
+
};
|
|
3160
|
+
}
|
|
3161
|
+
} else {
|
|
3162
|
+
primaryClass.base = styleObjectToCSS(style);
|
|
3163
|
+
}
|
|
3164
|
+
}
|
|
3165
|
+
if (interactiveStyles && interactiveStyles.length > 0) {
|
|
3166
|
+
for (const rule of interactiveStyles) {
|
|
3167
|
+
if (!rule.postfix) continue;
|
|
3168
|
+
const pseudoState = postfixToPseudoState(rule.postfix);
|
|
3169
|
+
if (!pseudoState) continue;
|
|
3170
|
+
const ruleStyle = rule.style;
|
|
3171
|
+
if (!primaryClass.pseudoStates) primaryClass.pseudoStates = {};
|
|
3172
|
+
if (isResponsiveStyle4(ruleStyle)) {
|
|
3173
|
+
const responsive = ruleStyle;
|
|
3174
|
+
if (responsive.base) {
|
|
3175
|
+
primaryClass.pseudoStates[pseudoState] = {
|
|
3176
|
+
...primaryClass.pseudoStates[pseudoState],
|
|
3177
|
+
...styleObjectToCSS(responsive.base)
|
|
3178
|
+
};
|
|
3179
|
+
}
|
|
3180
|
+
} else {
|
|
3181
|
+
primaryClass.pseudoStates[pseudoState] = {
|
|
3182
|
+
...primaryClass.pseudoStates[pseudoState],
|
|
3183
|
+
...styleObjectToCSS(ruleStyle)
|
|
3184
|
+
};
|
|
3185
|
+
}
|
|
3186
|
+
}
|
|
3187
|
+
}
|
|
3188
|
+
const comboClasses = [];
|
|
3189
|
+
const mappings = collectStyleMappings2(style);
|
|
3190
|
+
for (const { property, mapping } of mappings) {
|
|
3191
|
+
for (const [value, cssValue] of Object.entries(mapping.values)) {
|
|
3192
|
+
if (cssValue === "" || cssValue === void 0) continue;
|
|
3193
|
+
const comboName = `is-${sanitizeClassName(mapping.prop)}-${sanitizeClassName(String(value))}`;
|
|
3194
|
+
const comboClass = {
|
|
3195
|
+
name: comboName,
|
|
3196
|
+
base: {
|
|
3197
|
+
[toKebabCase(property)]: typeof cssValue === "number" ? UNITLESS_PROPERTIES.has(toKebabCase(property)) ? String(cssValue) : `${cssValue}px` : String(cssValue)
|
|
3198
|
+
},
|
|
3199
|
+
comboParent: webflowClassName
|
|
3200
|
+
};
|
|
3201
|
+
comboClasses.push(comboClass);
|
|
3202
|
+
}
|
|
3203
|
+
}
|
|
3204
|
+
return { primaryClass, comboClasses };
|
|
3205
|
+
}
|
|
3206
|
+
function sanitizeClassName(name) {
|
|
3207
|
+
return name.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
|
|
3208
|
+
}
|
|
3209
|
+
|
|
3210
|
+
// lib/server/webflow/nodeToWebflow.ts
|
|
3211
|
+
function buildElementClass2(ctx, label) {
|
|
3212
|
+
return generateElementClassName({
|
|
3213
|
+
fileType: ctx.fileType,
|
|
3214
|
+
fileName: ctx.fileName,
|
|
3215
|
+
label,
|
|
3216
|
+
path: ctx.elementPath
|
|
3217
|
+
});
|
|
3218
|
+
}
|
|
3219
|
+
function resolveTemplate2(text, props) {
|
|
3220
|
+
if (!props) return text;
|
|
3221
|
+
return text.replace(/\{\{(.+?)\}\}/g, (_, expr) => {
|
|
3222
|
+
const trimmed = expr.trim();
|
|
3223
|
+
const orMatch = trimmed.match(/^(.+?)\s*\|\|\s*['"](.+?)['"]$/);
|
|
3224
|
+
if (orMatch) {
|
|
3225
|
+
const value2 = resolveNestedProp(props, orMatch[1].trim());
|
|
3226
|
+
return value2 !== void 0 && value2 !== "" && value2 !== null ? String(value2) : orMatch[2];
|
|
3227
|
+
}
|
|
3228
|
+
const ternaryMatch = trimmed.match(/^(.+?)\s*\?\s*['"](.+?)['"]\s*:\s*['"](.+?)['"]$/);
|
|
3229
|
+
if (ternaryMatch) {
|
|
3230
|
+
const value2 = resolveNestedProp(props, ternaryMatch[1].trim());
|
|
3231
|
+
return value2 ? ternaryMatch[2] : ternaryMatch[3];
|
|
3232
|
+
}
|
|
3233
|
+
const value = resolveNestedProp(props, trimmed);
|
|
3234
|
+
return value !== void 0 ? String(value) : "";
|
|
3235
|
+
});
|
|
3236
|
+
}
|
|
3237
|
+
function resolveNestedProp(obj, path) {
|
|
3238
|
+
const parts = path.split(".");
|
|
3239
|
+
let current = obj;
|
|
3240
|
+
for (const part of parts) {
|
|
3241
|
+
if (current === null || current === void 0 || typeof current !== "object") return void 0;
|
|
3242
|
+
current = current[part];
|
|
3243
|
+
}
|
|
3244
|
+
return current;
|
|
3245
|
+
}
|
|
3246
|
+
function hasTemplates2(text) {
|
|
3247
|
+
return /\{\{.+?\}\}/.test(text);
|
|
3248
|
+
}
|
|
3249
|
+
function nodeToWebflow(node, ctx, instanceProps) {
|
|
3250
|
+
if (node === null || node === void 0) return [];
|
|
3251
|
+
if (typeof node === "string") {
|
|
3252
|
+
const text = instanceProps ? resolveTemplate2(node, instanceProps) : node;
|
|
3253
|
+
return [{ tag: "span", textContent: text }];
|
|
3254
|
+
}
|
|
3255
|
+
if (typeof node === "number") {
|
|
3256
|
+
return [{ tag: "span", textContent: String(node) }];
|
|
3257
|
+
}
|
|
3258
|
+
if (Array.isArray(node)) {
|
|
3259
|
+
const results = [];
|
|
3260
|
+
for (let i = 0; i < node.length; i++) {
|
|
3261
|
+
const child = node[i];
|
|
3262
|
+
const savedPath = [...ctx.elementPath];
|
|
3263
|
+
ctx.elementPath = [...ctx.elementPath, i];
|
|
3264
|
+
results.push(...nodeToWebflow(child, ctx, instanceProps));
|
|
3265
|
+
ctx.elementPath = savedPath;
|
|
3266
|
+
}
|
|
3267
|
+
return results;
|
|
3268
|
+
}
|
|
3269
|
+
switch (node.type) {
|
|
3270
|
+
case NODE_TYPE.NODE:
|
|
3271
|
+
return [emitHtmlNode2(node, ctx, instanceProps)];
|
|
3272
|
+
case NODE_TYPE.COMPONENT:
|
|
3273
|
+
return emitComponentInstance2(node, ctx, instanceProps);
|
|
3274
|
+
case NODE_TYPE.SLOT:
|
|
3275
|
+
return emitSlotMarker2(node, ctx, instanceProps);
|
|
3276
|
+
case NODE_TYPE.EMBED:
|
|
3277
|
+
return [emitEmbedNode2(node, ctx, instanceProps)];
|
|
3278
|
+
case NODE_TYPE.LINK:
|
|
3279
|
+
return [emitLinkNode2(node, ctx, instanceProps)];
|
|
3280
|
+
case NODE_TYPE.LIST:
|
|
3281
|
+
case "cms-list":
|
|
3282
|
+
case NODE_TYPE.LOCALE_LIST:
|
|
3283
|
+
return [{ tag: "div", attributes: { "data-meno-type": node.type } }];
|
|
3284
|
+
default:
|
|
3285
|
+
return [];
|
|
3286
|
+
}
|
|
3287
|
+
}
|
|
3288
|
+
function emitHtmlNode2(node, ctx, instanceProps) {
|
|
3289
|
+
const tag = hasTemplates2(node.tag) && instanceProps ? resolveTemplate2(node.tag, instanceProps) : node.tag;
|
|
3290
|
+
const style = node.style;
|
|
3291
|
+
const interactiveStyles = node.interactiveStyles;
|
|
3292
|
+
const needsClass = style || interactiveStyles && interactiveStyles.length > 0 || node.generateElementClass;
|
|
3293
|
+
let className;
|
|
3294
|
+
let comboClassNames;
|
|
3295
|
+
if (needsClass) {
|
|
3296
|
+
const elementClass = buildElementClass2(ctx, node.label);
|
|
3297
|
+
const { primaryClass, comboClasses } = mapStylesToWebflow(
|
|
3298
|
+
elementClass,
|
|
3299
|
+
style,
|
|
3300
|
+
interactiveStyles,
|
|
3301
|
+
ctx.breakpoints
|
|
3302
|
+
);
|
|
3303
|
+
className = primaryClass.name;
|
|
3304
|
+
ctx.styleClasses.set(primaryClass.name, primaryClass);
|
|
3305
|
+
if (comboClasses.length > 0) {
|
|
3306
|
+
comboClassNames = [];
|
|
3307
|
+
for (const combo of comboClasses) {
|
|
3308
|
+
ctx.styleClasses.set(combo.name, combo);
|
|
3309
|
+
comboClassNames.push(combo.name);
|
|
3310
|
+
}
|
|
3311
|
+
}
|
|
3312
|
+
}
|
|
3313
|
+
const attributes = {};
|
|
3314
|
+
if (node.attributes) {
|
|
3315
|
+
for (const [key, value] of Object.entries(node.attributes)) {
|
|
3316
|
+
if (instanceProps && typeof value === "string" && hasTemplates2(value)) {
|
|
3317
|
+
attributes[key] = resolveTemplate2(value, instanceProps);
|
|
3318
|
+
} else {
|
|
3319
|
+
attributes[key] = value;
|
|
3320
|
+
}
|
|
3321
|
+
}
|
|
3322
|
+
}
|
|
3323
|
+
let children;
|
|
3324
|
+
let textContent;
|
|
3325
|
+
if (!isVoidElement(tag) && node.children) {
|
|
3326
|
+
if (typeof node.children === "string") {
|
|
3327
|
+
textContent = instanceProps ? resolveTemplate2(node.children, instanceProps) : node.children;
|
|
3328
|
+
} else if (Array.isArray(node.children) && node.children.length === 1 && typeof node.children[0] === "string") {
|
|
3329
|
+
const text = node.children[0];
|
|
3330
|
+
textContent = instanceProps ? resolveTemplate2(text, instanceProps) : text;
|
|
3331
|
+
} else {
|
|
3332
|
+
const innerCtx = { ...ctx, elementPath: [...ctx.elementPath] };
|
|
3333
|
+
children = convertChildren(node.children, innerCtx, instanceProps);
|
|
3334
|
+
if (children.length === 0) children = void 0;
|
|
3335
|
+
}
|
|
3336
|
+
}
|
|
3337
|
+
let conditional;
|
|
3338
|
+
const ifValue = node.if;
|
|
3339
|
+
if (ifValue !== void 0 && ifValue !== true) {
|
|
3340
|
+
if (typeof ifValue === "object" && ifValue._mapping) {
|
|
3341
|
+
conditional = { prop: ifValue.prop, condition: "truthy" };
|
|
3342
|
+
} else if (typeof ifValue === "string") {
|
|
3343
|
+
const match = ifValue.match(/^\{\{(.+)\}\}$/);
|
|
3344
|
+
conditional = { prop: match ? match[1].trim() : ifValue, condition: "truthy" };
|
|
3345
|
+
}
|
|
3346
|
+
}
|
|
3347
|
+
const element = { tag };
|
|
3348
|
+
if (className) element.className = className;
|
|
3349
|
+
if (comboClassNames) element.comboClasses = comboClassNames;
|
|
3350
|
+
if (textContent) element.textContent = textContent;
|
|
3351
|
+
if (children) element.children = children;
|
|
3352
|
+
if (Object.keys(attributes).length > 0) element.attributes = attributes;
|
|
3353
|
+
if (conditional) element.conditional = conditional;
|
|
3354
|
+
return element;
|
|
3355
|
+
}
|
|
3356
|
+
function emitComponentInstance2(node, ctx, parentProps) {
|
|
3357
|
+
const compDef = ctx.globalComponents[node.component];
|
|
3358
|
+
if (!compDef) {
|
|
3359
|
+
return [{ tag: "div", attributes: { "data-component": node.component } }];
|
|
3360
|
+
}
|
|
3361
|
+
const resolvedProps = {};
|
|
3362
|
+
const structured = compDef.component;
|
|
3363
|
+
if (structured?.interface) {
|
|
3364
|
+
for (const [key, propDef] of Object.entries(structured.interface)) {
|
|
3365
|
+
resolvedProps[key] = propDef.default;
|
|
3366
|
+
}
|
|
3367
|
+
}
|
|
3368
|
+
if (node.props) {
|
|
3369
|
+
for (const [key, value] of Object.entries(node.props)) {
|
|
3370
|
+
if (key === "children") continue;
|
|
3371
|
+
if (typeof value === "string" && hasTemplates2(value) && parentProps) {
|
|
3372
|
+
resolvedProps[key] = resolveTemplate2(value, parentProps);
|
|
3373
|
+
} else {
|
|
3374
|
+
resolvedProps[key] = value;
|
|
3375
|
+
}
|
|
3376
|
+
}
|
|
3377
|
+
}
|
|
3378
|
+
const body = structured?.structure || compDef.node;
|
|
3379
|
+
if (!body) return [];
|
|
3380
|
+
const compCtx = {
|
|
3381
|
+
...ctx,
|
|
3382
|
+
fileType: "component",
|
|
3383
|
+
fileName: node.component,
|
|
3384
|
+
elementPath: [0],
|
|
3385
|
+
slotChildren: node.children
|
|
3386
|
+
};
|
|
3387
|
+
return nodeToWebflow(body, compCtx, resolvedProps);
|
|
3388
|
+
}
|
|
3389
|
+
function emitSlotMarker2(node, ctx, instanceProps) {
|
|
3390
|
+
if (ctx.slotChildren) {
|
|
3391
|
+
const parentCtx = {
|
|
3392
|
+
...ctx,
|
|
3393
|
+
slotChildren: void 0
|
|
3394
|
+
// prevent infinite slot nesting
|
|
3395
|
+
};
|
|
3396
|
+
return convertChildren(ctx.slotChildren, parentCtx, instanceProps);
|
|
3397
|
+
}
|
|
3398
|
+
if (node.default) {
|
|
3399
|
+
return convertChildren(node.default, ctx, instanceProps);
|
|
3400
|
+
}
|
|
3401
|
+
return [];
|
|
3402
|
+
}
|
|
3403
|
+
function emitEmbedNode2(node, ctx, instanceProps) {
|
|
3404
|
+
const style = node.style;
|
|
3405
|
+
const interactiveStyles = node.interactiveStyles;
|
|
3406
|
+
let className;
|
|
3407
|
+
if (style || interactiveStyles && interactiveStyles.length > 0) {
|
|
3408
|
+
const elementClass = buildElementClass2(ctx, node.label);
|
|
3409
|
+
const { primaryClass } = mapStylesToWebflow(
|
|
3410
|
+
elementClass,
|
|
3411
|
+
style,
|
|
3412
|
+
interactiveStyles,
|
|
3413
|
+
ctx.breakpoints
|
|
3414
|
+
);
|
|
3415
|
+
className = primaryClass.name;
|
|
3416
|
+
ctx.styleClasses.set(primaryClass.name, primaryClass);
|
|
3417
|
+
}
|
|
3418
|
+
const htmlStr = typeof node.html === "string" ? node.html : "";
|
|
3419
|
+
const element = {
|
|
3420
|
+
tag: "div",
|
|
3421
|
+
rawHtml: htmlStr
|
|
3422
|
+
};
|
|
3423
|
+
if (className) element.className = className;
|
|
3424
|
+
return element;
|
|
3425
|
+
}
|
|
3426
|
+
function emitLinkNode2(node, ctx, instanceProps) {
|
|
3427
|
+
const style = node.style;
|
|
3428
|
+
const interactiveStyles = node.interactiveStyles;
|
|
3429
|
+
let className;
|
|
3430
|
+
if (style || interactiveStyles && interactiveStyles.length > 0) {
|
|
3431
|
+
const elementClass = buildElementClass2(ctx, node.label);
|
|
3432
|
+
const { primaryClass } = mapStylesToWebflow(
|
|
3433
|
+
elementClass,
|
|
3434
|
+
style,
|
|
3435
|
+
interactiveStyles,
|
|
3436
|
+
ctx.breakpoints
|
|
3437
|
+
);
|
|
3438
|
+
className = primaryClass.name;
|
|
3439
|
+
ctx.styleClasses.set(primaryClass.name, primaryClass);
|
|
3440
|
+
}
|
|
3441
|
+
let href = "#";
|
|
3442
|
+
if (typeof node.href === "string") {
|
|
3443
|
+
href = instanceProps && hasTemplates2(node.href) ? resolveTemplate2(node.href, instanceProps) : node.href;
|
|
3444
|
+
}
|
|
3445
|
+
const attributes = { href };
|
|
3446
|
+
if (node.attributes) {
|
|
3447
|
+
for (const [key, value] of Object.entries(node.attributes)) {
|
|
3448
|
+
attributes[key] = value;
|
|
3449
|
+
}
|
|
3450
|
+
}
|
|
3451
|
+
let children;
|
|
3452
|
+
if (node.children) {
|
|
3453
|
+
children = convertChildren(node.children, ctx, instanceProps);
|
|
3454
|
+
if (children.length === 0) children = void 0;
|
|
3455
|
+
}
|
|
3456
|
+
const element = { tag: "a", attributes };
|
|
3457
|
+
if (className) element.className = className;
|
|
3458
|
+
if (children) element.children = children;
|
|
3459
|
+
return element;
|
|
3460
|
+
}
|
|
3461
|
+
function convertChildren(children, ctx, instanceProps) {
|
|
3462
|
+
if (!children) return [];
|
|
3463
|
+
if (typeof children === "string") {
|
|
3464
|
+
return nodeToWebflow(children, ctx, instanceProps);
|
|
3465
|
+
}
|
|
3466
|
+
if (Array.isArray(children)) {
|
|
3467
|
+
return nodeToWebflow(children, ctx, instanceProps);
|
|
3468
|
+
}
|
|
3469
|
+
return nodeToWebflow(children, ctx, instanceProps);
|
|
3470
|
+
}
|
|
3471
|
+
|
|
3472
|
+
// lib/server/webflow/buildWebflow.ts
|
|
3473
|
+
function scanJSONFiles2(dir, prefix = "") {
|
|
3474
|
+
const results = [];
|
|
3475
|
+
if (!existsSync2(dir)) return results;
|
|
3476
|
+
const entries = readdirSync2(dir, { withFileTypes: true });
|
|
3477
|
+
for (const entry of entries) {
|
|
3478
|
+
if (entry.isFile() && entry.name.endsWith(".json")) {
|
|
3479
|
+
results.push(prefix ? `${prefix}/${entry.name}` : entry.name);
|
|
3480
|
+
} else if (entry.isDirectory()) {
|
|
3481
|
+
results.push(...scanJSONFiles2(join2(dir, entry.name), prefix ? `${prefix}/${entry.name}` : entry.name));
|
|
3482
|
+
}
|
|
3483
|
+
}
|
|
3484
|
+
return results;
|
|
3485
|
+
}
|
|
3486
|
+
function isCMSPage2(pageData) {
|
|
3487
|
+
return pageData.meta?.source === "cms" && !!pageData.meta?.cms;
|
|
3488
|
+
}
|
|
3489
|
+
function buildCMSItemPath(urlPattern, item, slugField, locale, i18nConfig) {
|
|
3490
|
+
let slug = item[slugField] ?? item._slug ?? item._id;
|
|
3491
|
+
if (isI18nValue(slug)) {
|
|
3492
|
+
slug = resolveI18nValue(slug, locale, i18nConfig);
|
|
3493
|
+
}
|
|
3494
|
+
return urlPattern.replace("{{slug}}", String(slug));
|
|
3495
|
+
}
|
|
3496
|
+
function scanAssets(projectRoot) {
|
|
3497
|
+
const assets = [];
|
|
3498
|
+
const assetDirs = [
|
|
3499
|
+
{ dir: "images", type: "image" },
|
|
3500
|
+
{ dir: "fonts", type: "font" },
|
|
3501
|
+
{ dir: "videos", type: "video" },
|
|
3502
|
+
{ dir: "assets", type: "file" }
|
|
3503
|
+
];
|
|
3504
|
+
for (const { dir, type } of assetDirs) {
|
|
3505
|
+
const fullDir = join2(projectRoot, dir);
|
|
3506
|
+
if (!existsSync2(fullDir)) continue;
|
|
3507
|
+
const files = scanJSONFiles2(fullDir).map((f) => f.replace(".json", ""));
|
|
3508
|
+
const allFiles = scanAllFiles(fullDir);
|
|
3509
|
+
for (const file of allFiles) {
|
|
3510
|
+
assets.push({
|
|
3511
|
+
localPath: `${dir}/${file}`,
|
|
3512
|
+
type,
|
|
3513
|
+
fileName: file.split("/").pop()
|
|
3514
|
+
});
|
|
3515
|
+
}
|
|
3516
|
+
}
|
|
3517
|
+
return assets;
|
|
3518
|
+
}
|
|
3519
|
+
function scanAllFiles(dir, prefix = "") {
|
|
3520
|
+
const results = [];
|
|
3521
|
+
if (!existsSync2(dir)) return results;
|
|
3522
|
+
const entries = readdirSync2(dir, { withFileTypes: true });
|
|
3523
|
+
for (const entry of entries) {
|
|
3524
|
+
const relativePath = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
3525
|
+
if (entry.isFile()) {
|
|
3526
|
+
results.push(relativePath);
|
|
3527
|
+
} else if (entry.isDirectory()) {
|
|
3528
|
+
results.push(...scanAllFiles(join2(dir, entry.name), relativePath));
|
|
3529
|
+
}
|
|
3530
|
+
}
|
|
3531
|
+
return results;
|
|
3532
|
+
}
|
|
3533
|
+
function extractCSSVariables(themeColorCSS, variablesCSS) {
|
|
3534
|
+
const vars = {};
|
|
3535
|
+
const regex = /--([\w-]+)\s*:\s*([^;]+)/g;
|
|
3536
|
+
for (const css of [themeColorCSS, variablesCSS]) {
|
|
3537
|
+
let match;
|
|
3538
|
+
while ((match = regex.exec(css)) !== null) {
|
|
3539
|
+
vars[`--${match[1]}`] = match[2].trim();
|
|
3540
|
+
}
|
|
3541
|
+
}
|
|
3542
|
+
return vars;
|
|
3543
|
+
}
|
|
3544
|
+
async function buildWebflowPayload(projectRoot) {
|
|
3545
|
+
configService.reset();
|
|
3546
|
+
const projectConfig = await loadProjectConfig();
|
|
3547
|
+
const siteUrl = projectConfig.siteUrl?.replace(/\/$/, "") || "";
|
|
3548
|
+
const i18nConfig = await loadI18nConfig();
|
|
3549
|
+
await migrateTemplatesDirectory();
|
|
3550
|
+
const { components } = await loadComponentDirectory(projectPaths.components());
|
|
3551
|
+
const globalComponents = {};
|
|
3552
|
+
components.forEach((value, key) => {
|
|
3553
|
+
globalComponents[key] = value;
|
|
3554
|
+
});
|
|
3555
|
+
const cmsProvider = new FileSystemCMSProvider(projectPaths.templates(), projectPaths.cms());
|
|
3556
|
+
const cmsService = new CMSService(cmsProvider);
|
|
3557
|
+
await cmsService.initialize();
|
|
3558
|
+
const themeConfig = await colorService.loadThemeConfig();
|
|
3559
|
+
const variablesConfig = await variableService.loadConfig();
|
|
3560
|
+
const breakpoints = await loadBreakpointConfig();
|
|
3561
|
+
const responsiveScales = await loadResponsiveScalesConfig();
|
|
3562
|
+
await configService.load();
|
|
3563
|
+
const pagesDir = projectPaths.pages();
|
|
3564
|
+
if (!existsSync2(pagesDir)) {
|
|
3565
|
+
return emptyPayload();
|
|
3566
|
+
}
|
|
3567
|
+
const pageFiles = scanJSONFiles2(pagesDir);
|
|
3568
|
+
if (pageFiles.length === 0) {
|
|
3569
|
+
return emptyPayload();
|
|
3570
|
+
}
|
|
3571
|
+
const slugMappings = [];
|
|
3572
|
+
for (const file of pageFiles) {
|
|
3573
|
+
const pageName = file.replace(".json", "");
|
|
3574
|
+
const basePath = mapPageNameToPath(pageName);
|
|
3575
|
+
const pageContent = await loadJSONFile(join2(pagesDir, file));
|
|
3576
|
+
if (!pageContent) continue;
|
|
3577
|
+
try {
|
|
3578
|
+
const pageData = parseJSON(pageContent);
|
|
3579
|
+
if (pageData.meta?.slugs) {
|
|
3580
|
+
const pageId = basePath === "/" ? "index" : basePath.substring(1);
|
|
3581
|
+
slugMappings.push({ pageId, slugs: pageData.meta.slugs });
|
|
3582
|
+
}
|
|
3583
|
+
} catch {
|
|
3584
|
+
}
|
|
3585
|
+
}
|
|
3586
|
+
const allPages = [];
|
|
3587
|
+
const allStyleClasses = /* @__PURE__ */ new Map();
|
|
3588
|
+
for (const file of pageFiles) {
|
|
3589
|
+
const pageName = file.replace(".json", "");
|
|
3590
|
+
const basePath = mapPageNameToPath(pageName);
|
|
3591
|
+
const pageContent = await loadJSONFile(join2(pagesDir, file));
|
|
3592
|
+
if (!pageContent) continue;
|
|
3593
|
+
try {
|
|
3594
|
+
const pageData = parseJSON(pageContent);
|
|
3595
|
+
if (pageData.meta?.draft === true) continue;
|
|
3596
|
+
const slugs = pageData.meta?.slugs;
|
|
3597
|
+
for (const localeConfig of i18nConfig.locales) {
|
|
3598
|
+
const locale = localeConfig.code;
|
|
3599
|
+
const isDefault = locale === i18nConfig.defaultLocale;
|
|
3600
|
+
let slug;
|
|
3601
|
+
if (slugs && slugs[locale]) {
|
|
3602
|
+
slug = slugs[locale];
|
|
3603
|
+
} else if (basePath === "/") {
|
|
3604
|
+
slug = "";
|
|
3605
|
+
} else {
|
|
3606
|
+
slug = basePath.substring(1);
|
|
3607
|
+
}
|
|
3608
|
+
const urlPath = isDefault ? slug === "" ? "/" : `/${slug}` : slug === "" ? `/${locale}` : `/${locale}/${slug}`;
|
|
3609
|
+
const result = await renderPageSSR(
|
|
3610
|
+
pageData,
|
|
3611
|
+
globalComponents,
|
|
3612
|
+
urlPath,
|
|
3613
|
+
siteUrl,
|
|
3614
|
+
locale,
|
|
3615
|
+
i18nConfig,
|
|
3616
|
+
slugMappings,
|
|
3617
|
+
void 0,
|
|
3618
|
+
cmsService,
|
|
3619
|
+
true
|
|
3620
|
+
);
|
|
3621
|
+
const ctx = {
|
|
3622
|
+
globalComponents,
|
|
3623
|
+
elementPath: [0],
|
|
3624
|
+
fileType: "page",
|
|
3625
|
+
fileName: pageName,
|
|
3626
|
+
breakpoints,
|
|
3627
|
+
styleClasses: allStyleClasses
|
|
3628
|
+
};
|
|
3629
|
+
const body = pageData.root || pageData.node;
|
|
3630
|
+
const elements = body ? nodeToWebflow(body, ctx) : [];
|
|
3631
|
+
allPages.push({
|
|
3632
|
+
title: result.title,
|
|
3633
|
+
slug: slug || "index",
|
|
3634
|
+
metaDescription: typeof pageData.meta?.description === "string" ? pageData.meta.description : void 0,
|
|
3635
|
+
elements,
|
|
3636
|
+
locale
|
|
3637
|
+
});
|
|
3638
|
+
}
|
|
3639
|
+
} catch (error) {
|
|
3640
|
+
console.error(`Error processing ${basePath}:`, error?.message);
|
|
3641
|
+
}
|
|
3642
|
+
}
|
|
3643
|
+
const templatesDir = projectPaths.templates();
|
|
3644
|
+
const cmsCollections = [];
|
|
3645
|
+
if (existsSync2(templatesDir)) {
|
|
3646
|
+
const templateFiles = readdirSync2(templatesDir).filter((f) => f.endsWith(".json"));
|
|
3647
|
+
for (const file of templateFiles) {
|
|
3648
|
+
const templateContent = await loadJSONFile(join2(templatesDir, file));
|
|
3649
|
+
if (!templateContent) continue;
|
|
3650
|
+
try {
|
|
3651
|
+
const pageData = parseJSON(templateContent);
|
|
3652
|
+
if (pageData.meta?.draft === true) continue;
|
|
3653
|
+
if (!isCMSPage2(pageData)) continue;
|
|
3654
|
+
const cmsSchema = pageData.meta.cms;
|
|
3655
|
+
const items = await cmsService.queryItems({ collection: cmsSchema.id });
|
|
3656
|
+
const fields = [];
|
|
3657
|
+
if (cmsSchema.fields) {
|
|
3658
|
+
for (const [fieldName, fieldDef] of Object.entries(cmsSchema.fields)) {
|
|
3659
|
+
fields.push({
|
|
3660
|
+
name: fieldDef.label || fieldName,
|
|
3661
|
+
slug: fieldName,
|
|
3662
|
+
type: mapCMSFieldType(fieldDef.type),
|
|
3663
|
+
required: fieldDef.required,
|
|
3664
|
+
options: fieldDef.options
|
|
3665
|
+
});
|
|
3666
|
+
}
|
|
3667
|
+
}
|
|
3668
|
+
const resolvedItems = [];
|
|
3669
|
+
for (const item of items) {
|
|
3670
|
+
const resolved = {};
|
|
3671
|
+
for (const [key, value] of Object.entries(item)) {
|
|
3672
|
+
if (isI18nValue(value)) {
|
|
3673
|
+
resolved[key] = resolveI18nValue(value, i18nConfig.defaultLocale, i18nConfig);
|
|
3674
|
+
} else {
|
|
3675
|
+
resolved[key] = value;
|
|
3676
|
+
}
|
|
3677
|
+
}
|
|
3678
|
+
resolvedItems.push(resolved);
|
|
3679
|
+
}
|
|
3680
|
+
cmsCollections.push({
|
|
3681
|
+
name: cmsSchema.id,
|
|
3682
|
+
slug: cmsSchema.id,
|
|
3683
|
+
urlPattern: cmsSchema.urlPattern,
|
|
3684
|
+
fields,
|
|
3685
|
+
items: resolvedItems
|
|
3686
|
+
});
|
|
3687
|
+
for (const item of items) {
|
|
3688
|
+
for (const localeConfig of i18nConfig.locales) {
|
|
3689
|
+
const locale = localeConfig.code;
|
|
3690
|
+
if (isItemDraftForLocale(item, locale)) continue;
|
|
3691
|
+
const itemPath = buildCMSItemPath(cmsSchema.urlPattern, item, cmsSchema.slugField, locale, i18nConfig);
|
|
3692
|
+
const itemWithUrl = { ...item, _url: itemPath };
|
|
3693
|
+
const result = await renderPageSSR(
|
|
3694
|
+
pageData,
|
|
3695
|
+
globalComponents,
|
|
3696
|
+
itemPath,
|
|
3697
|
+
siteUrl,
|
|
3698
|
+
locale,
|
|
3699
|
+
i18nConfig,
|
|
3700
|
+
slugMappings,
|
|
3701
|
+
{ cms: itemWithUrl },
|
|
3702
|
+
cmsService,
|
|
3703
|
+
true
|
|
3704
|
+
);
|
|
3705
|
+
const ctx = {
|
|
3706
|
+
globalComponents,
|
|
3707
|
+
elementPath: [0],
|
|
3708
|
+
fileType: "page",
|
|
3709
|
+
fileName: file.replace(".json", ""),
|
|
3710
|
+
breakpoints,
|
|
3711
|
+
styleClasses: allStyleClasses
|
|
3712
|
+
};
|
|
3713
|
+
const body = pageData.root || pageData.node;
|
|
3714
|
+
const cmsProps = { cms: itemWithUrl };
|
|
3715
|
+
const elements = body ? nodeToWebflow(body, ctx, cmsProps) : [];
|
|
3716
|
+
const slug = itemPath.startsWith("/") ? itemPath.substring(1) : itemPath;
|
|
3717
|
+
allPages.push({
|
|
3718
|
+
title: result.title,
|
|
3719
|
+
slug,
|
|
3720
|
+
elements,
|
|
3721
|
+
locale
|
|
3722
|
+
});
|
|
3723
|
+
}
|
|
3724
|
+
}
|
|
3725
|
+
} catch (error) {
|
|
3726
|
+
console.error(`Error processing template ${file}:`, error?.message);
|
|
3727
|
+
}
|
|
3728
|
+
}
|
|
3729
|
+
}
|
|
3730
|
+
const themeColorCSS = generateThemeColorVariablesCSS(themeConfig);
|
|
3731
|
+
const variablesCSS = generateVariablesCSS(variablesConfig, breakpoints, responsiveScales);
|
|
3732
|
+
const cssVariables = extractCSSVariables(themeColorCSS, variablesCSS);
|
|
3733
|
+
const assets = scanAssets(projectPaths.project);
|
|
3734
|
+
return {
|
|
3735
|
+
version: 1,
|
|
3736
|
+
exportedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3737
|
+
pages: allPages,
|
|
3738
|
+
styles: Array.from(allStyleClasses.values()),
|
|
3739
|
+
cms: cmsCollections,
|
|
3740
|
+
assets,
|
|
3741
|
+
cssVariables: Object.keys(cssVariables).length > 0 ? cssVariables : void 0
|
|
3742
|
+
};
|
|
3743
|
+
}
|
|
3744
|
+
function emptyPayload() {
|
|
3745
|
+
return {
|
|
3746
|
+
version: 1,
|
|
3747
|
+
exportedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3748
|
+
pages: [],
|
|
3749
|
+
styles: [],
|
|
3750
|
+
cms: [],
|
|
3751
|
+
assets: []
|
|
3752
|
+
};
|
|
3753
|
+
}
|
|
3754
|
+
|
|
1946
3755
|
// lib/server/index.ts
|
|
1947
3756
|
init_constants();
|
|
1948
3757
|
export {
|
|
@@ -1970,6 +3779,7 @@ export {
|
|
|
1970
3779
|
buildImageMetadataMap,
|
|
1971
3780
|
buildLineMap,
|
|
1972
3781
|
buildStaticPages,
|
|
3782
|
+
buildWebflowPayload,
|
|
1973
3783
|
bundleFile,
|
|
1974
3784
|
clearJSValidationCache,
|
|
1975
3785
|
collectComponentCSS,
|