meno-core 1.1.0 → 1.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunks/{chunk-NUP7H7D3.js → chunk-7ZLF4NE5.js} +2 -2
- package/dist/chunks/{chunk-QWTQZHG3.js → chunk-FQBIC2OB.js} +1 -1
- package/dist/chunks/chunk-FQBIC2OB.js.map +7 -0
- package/dist/chunks/{chunk-2IIQK7T3.js → chunk-J4IPTP5X.js} +393 -3
- package/dist/chunks/{chunk-2IIQK7T3.js.map → chunk-J4IPTP5X.js.map} +3 -3
- package/dist/lib/client/index.js +2 -2
- package/dist/lib/server/index.js +804 -218
- package/dist/lib/server/index.js.map +4 -4
- package/dist/lib/shared/index.js +6 -2
- package/dist/lib/shared/index.js.map +2 -2
- package/lib/server/index.ts +19 -0
- package/lib/server/services/ColorService.ts +38 -7
- package/lib/server/services/VariableService.ts +34 -5
- package/lib/server/ssr/htmlGenerator.ts +18 -2
- package/lib/server/ssr/ssrRenderer.test.ts +25 -0
- package/lib/server/ssr/ssrRenderer.ts +12 -2
- package/lib/server/themeCssCodec.test.ts +154 -0
- package/lib/server/themeCssCodec.ts +488 -0
- package/lib/server/themeCssStore.test.ts +139 -0
- package/lib/server/themeCssStore.ts +210 -0
- package/lib/shared/cssGeneration.test.ts +10 -0
- package/lib/shared/cssGeneration.ts +10 -8
- package/lib/shared/index.ts +6 -0
- package/lib/shared/interactiveStyles.test.ts +3 -1
- package/lib/shared/tailwindThemeScale.ts +256 -0
- package/lib/shared/types/colors.ts +6 -2
- package/lib/shared/types/variables.ts +14 -7
- package/lib/shared/utilityClassConfig.ts +116 -0
- package/lib/shared/utilityClassMapper.test.ts +148 -0
- package/lib/shared/utilityClassMapper.ts +33 -0
- package/lib/shared/utilityClassNames.ts +146 -0
- package/package.json +1 -1
- package/dist/chunks/chunk-QWTQZHG3.js.map +0 -7
- /package/dist/chunks/{chunk-NUP7H7D3.js.map → chunk-7ZLF4NE5.js.map} +0 -0
package/dist/lib/server/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
CMS_DRAFT_SUFFIX,
|
|
3
|
+
VARIABLE_GROUPS,
|
|
3
4
|
buildSlugIndex,
|
|
4
5
|
collectComponentLibraries,
|
|
5
6
|
createLogger,
|
|
@@ -8,6 +9,7 @@ import {
|
|
|
8
9
|
fontFaceCss,
|
|
9
10
|
fontPreloadLinks,
|
|
10
11
|
generateLibraryTags,
|
|
12
|
+
getDefaultScalingType,
|
|
11
13
|
getLocaleLinks,
|
|
12
14
|
isPathWithinRoot,
|
|
13
15
|
isReservedDraftFilename,
|
|
@@ -18,7 +20,7 @@ import {
|
|
|
18
20
|
resolveSlugToPageId,
|
|
19
21
|
rewriteComponentRefs,
|
|
20
22
|
translatePath
|
|
21
|
-
} from "../../chunks/chunk-
|
|
23
|
+
} from "../../chunks/chunk-FQBIC2OB.js";
|
|
22
24
|
import {
|
|
23
25
|
syncNetlifyLocale404Block
|
|
24
26
|
} from "../../chunks/chunk-2AR55GYH.js";
|
|
@@ -31,7 +33,7 @@ import {
|
|
|
31
33
|
processStructure,
|
|
32
34
|
resolveHtmlMapping,
|
|
33
35
|
skipEmptyTemplateAttributes
|
|
34
|
-
} from "../../chunks/chunk-
|
|
36
|
+
} from "../../chunks/chunk-7ZLF4NE5.js";
|
|
35
37
|
import {
|
|
36
38
|
DEFAULT_BREAKPOINTS,
|
|
37
39
|
DEFAULT_FLUID_RANGE,
|
|
@@ -90,7 +92,7 @@ import {
|
|
|
90
92
|
validateCMSDraftItem,
|
|
91
93
|
validateCMSItem,
|
|
92
94
|
validateComponentDefinition
|
|
93
|
-
} from "../../chunks/chunk-
|
|
95
|
+
} from "../../chunks/chunk-J4IPTP5X.js";
|
|
94
96
|
import {
|
|
95
97
|
DEFAULT_I18N_CONFIG,
|
|
96
98
|
buildLocalizedPath,
|
|
@@ -457,13 +459,13 @@ async function bundleWithBun(entrypoint, opts) {
|
|
|
457
459
|
const code = await result.outputs[0].text();
|
|
458
460
|
return { code, success: true, errors: [] };
|
|
459
461
|
}
|
|
460
|
-
const errors = (result.logs || []).map((
|
|
462
|
+
const errors = (result.logs || []).map((log7) => {
|
|
461
463
|
const parts = [];
|
|
462
|
-
if (
|
|
463
|
-
if (
|
|
464
|
-
if (
|
|
465
|
-
if (
|
|
466
|
-
return parts.length > 0 ? parts.join("\n") : String(
|
|
464
|
+
if (log7.position?.file) parts.push(`File: ${log7.position.file}`);
|
|
465
|
+
if (log7.position?.line) parts.push(`Line ${log7.position.line}:${log7.position.column || 0}`);
|
|
466
|
+
if (log7.position?.lineText) parts.push(log7.position.lineText);
|
|
467
|
+
if (log7.message) parts.push(log7.message);
|
|
468
|
+
return parts.length > 0 ? parts.join("\n") : String(log7);
|
|
467
469
|
});
|
|
468
470
|
return { code: "", success: false, errors };
|
|
469
471
|
} catch (err) {
|
|
@@ -471,12 +473,12 @@ async function bundleWithBun(entrypoint, opts) {
|
|
|
471
473
|
if (opts.throw) throw err;
|
|
472
474
|
const errors = [];
|
|
473
475
|
if (be.logs && Array.isArray(be.logs)) {
|
|
474
|
-
for (const
|
|
476
|
+
for (const log7 of be.logs) {
|
|
475
477
|
const parts = [];
|
|
476
|
-
if (
|
|
477
|
-
if (
|
|
478
|
-
if (
|
|
479
|
-
errors.push(parts.length > 0 ? parts.join("\n") : String(
|
|
478
|
+
if (log7.position?.line) parts.push(`Line ${log7.position.line}:${log7.position.column || 0}`);
|
|
479
|
+
if (log7.position?.lineText) parts.push(log7.position.lineText);
|
|
480
|
+
if (log7.message) parts.push(log7.message);
|
|
481
|
+
errors.push(parts.length > 0 ? parts.join("\n") : String(log7));
|
|
480
482
|
}
|
|
481
483
|
} else {
|
|
482
484
|
errors.push(be.message || String(err));
|
|
@@ -486,8 +488,8 @@ async function bundleWithBun(entrypoint, opts) {
|
|
|
486
488
|
}
|
|
487
489
|
async function minifyWithBun(code) {
|
|
488
490
|
const { writeFile: writeFile3, rm: _rm } = await import("node:fs/promises");
|
|
489
|
-
const { join:
|
|
490
|
-
const tempFile =
|
|
491
|
+
const { join: join10 } = await import("node:path");
|
|
492
|
+
const tempFile = join10("/tmp", `meno-minify-${Date.now()}.js`);
|
|
491
493
|
try {
|
|
492
494
|
await writeFile3(tempFile, code, "utf-8");
|
|
493
495
|
const result = await Bun.build({
|
|
@@ -506,12 +508,12 @@ async function minifyWithBun(code) {
|
|
|
506
508
|
const { inspect: inspect2 } = await import("../../chunks/fs-G3ANWEFP.js");
|
|
507
509
|
let details = "";
|
|
508
510
|
if (be.logs && Array.isArray(be.logs)) {
|
|
509
|
-
details = be.logs.map((
|
|
511
|
+
details = be.logs.map((log7) => {
|
|
510
512
|
const parts = [];
|
|
511
|
-
if (
|
|
512
|
-
if (
|
|
513
|
-
if (
|
|
514
|
-
return parts.length > 0 ? parts.join("\n") : String(
|
|
513
|
+
if (log7.position?.line) parts.push(`Line ${log7.position.line}:${log7.position.column || 0}`);
|
|
514
|
+
if (log7.position?.lineText) parts.push(log7.position.lineText);
|
|
515
|
+
if (log7.message) parts.push(log7.message);
|
|
516
|
+
return parts.length > 0 ? parts.join("\n") : String(log7);
|
|
515
517
|
}).join("\n\n");
|
|
516
518
|
}
|
|
517
519
|
if (!details) {
|
|
@@ -524,16 +526,16 @@ async function minifyWithBun(code) {
|
|
|
524
526
|
return { code: "", success: false, errors: [details] };
|
|
525
527
|
} finally {
|
|
526
528
|
try {
|
|
527
|
-
const { rm } = await import("node:fs/promises");
|
|
528
|
-
await
|
|
529
|
+
const { rm: rm2 } = await import("node:fs/promises");
|
|
530
|
+
await rm2(tempFile, { force: true });
|
|
529
531
|
} catch {
|
|
530
532
|
}
|
|
531
533
|
}
|
|
532
534
|
}
|
|
533
535
|
async function validateWithBun(code) {
|
|
534
|
-
const { writeFile: writeFile3, rm } = await import("node:fs/promises");
|
|
535
|
-
const { join:
|
|
536
|
-
const tempFile =
|
|
536
|
+
const { writeFile: writeFile3, rm: rm2 } = await import("node:fs/promises");
|
|
537
|
+
const { join: join10 } = await import("node:path");
|
|
538
|
+
const tempFile = join10("/tmp", `meno-validate-${Date.now()}-${Math.random().toString(36).slice(2)}.js`);
|
|
537
539
|
try {
|
|
538
540
|
await writeFile3(tempFile, code, "utf-8");
|
|
539
541
|
await Bun.build({
|
|
@@ -547,12 +549,12 @@ async function validateWithBun(code) {
|
|
|
547
549
|
const { inspect: inspect2 } = await import("../../chunks/fs-G3ANWEFP.js");
|
|
548
550
|
let details = "";
|
|
549
551
|
if (be.logs && Array.isArray(be.logs)) {
|
|
550
|
-
details = be.logs.map((
|
|
552
|
+
details = be.logs.map((log7) => {
|
|
551
553
|
const parts = [];
|
|
552
|
-
if (
|
|
553
|
-
if (
|
|
554
|
-
if (
|
|
555
|
-
return parts.length > 0 ? parts.join("\n") : String(
|
|
554
|
+
if (log7.position?.line) parts.push(`Line ${log7.position.line}:${log7.position.column || 0}`);
|
|
555
|
+
if (log7.position?.lineText) parts.push(log7.position.lineText);
|
|
556
|
+
if (log7.message) parts.push(log7.message);
|
|
557
|
+
return parts.length > 0 ? parts.join("\n") : String(log7);
|
|
556
558
|
}).join("\n\n");
|
|
557
559
|
}
|
|
558
560
|
if (!details) {
|
|
@@ -565,7 +567,7 @@ async function validateWithBun(code) {
|
|
|
565
567
|
return details || "Unknown JavaScript error";
|
|
566
568
|
} finally {
|
|
567
569
|
try {
|
|
568
|
-
await
|
|
570
|
+
await rm2(tempFile, { force: true });
|
|
569
571
|
} catch {
|
|
570
572
|
}
|
|
571
573
|
}
|
|
@@ -1690,6 +1692,9 @@ async function handleComponentsConfigRoute() {
|
|
|
1690
1692
|
}
|
|
1691
1693
|
}
|
|
1692
1694
|
|
|
1695
|
+
// lib/server/services/ColorService.ts
|
|
1696
|
+
import { existsSync as existsSync3 } from "node:fs";
|
|
1697
|
+
|
|
1693
1698
|
// lib/server/services/CachedConfigLoader.ts
|
|
1694
1699
|
var CachedConfigLoader = class {
|
|
1695
1700
|
config = null;
|
|
@@ -1730,8 +1735,511 @@ var CachedConfigLoader = class {
|
|
|
1730
1735
|
}
|
|
1731
1736
|
};
|
|
1732
1737
|
|
|
1738
|
+
// lib/server/themeCssStore.ts
|
|
1739
|
+
import { existsSync as existsSync2, readFileSync } from "node:fs";
|
|
1740
|
+
import { rm } from "node:fs/promises";
|
|
1741
|
+
import { join as join2 } from "node:path";
|
|
1742
|
+
|
|
1743
|
+
// lib/server/themeCssCodec.ts
|
|
1744
|
+
var COLORS_LABEL = "Colors";
|
|
1745
|
+
var OTHER_LABEL = "Other";
|
|
1746
|
+
var HEADER_BANNER = `/*
|
|
1747
|
+
* Meno design tokens \u2014 theme.css is the source of truth for this project's colors and
|
|
1748
|
+
* variables. Edit values here, or use the Studio color/variable panels. Variables are
|
|
1749
|
+
* grouped by the comment sections below; the @media regions are regenerated on save
|
|
1750
|
+
* (responsive scaling is configured in project.config.json).
|
|
1751
|
+
*/`;
|
|
1752
|
+
var AUTO_BANNER = "/* === Responsive scaling \u2014 auto-generated from project.config.json; regenerated on save === */";
|
|
1753
|
+
var OVERRIDES_BANNER = "/* === Responsive overrides \u2014 per-variable; preserved across regen === */";
|
|
1754
|
+
function sectionLabelForGroup(group) {
|
|
1755
|
+
if (!group || group === "other") return OTHER_LABEL;
|
|
1756
|
+
return VARIABLE_GROUPS.find((g) => g.value === group)?.label ?? OTHER_LABEL;
|
|
1757
|
+
}
|
|
1758
|
+
var LABEL_TO_GROUP = new Map(VARIABLE_GROUPS.map((g) => [g.label.toLowerCase(), g.value]));
|
|
1759
|
+
function groupForSectionLabel(label) {
|
|
1760
|
+
return LABEL_TO_GROUP.get(label.trim().toLowerCase()) ?? null;
|
|
1761
|
+
}
|
|
1762
|
+
function isColorValue(value) {
|
|
1763
|
+
const v = value.trim().toLowerCase();
|
|
1764
|
+
if (/^#[0-9a-f]{3,8}$/.test(v)) return true;
|
|
1765
|
+
if (/^(rgb|rgba|hsl|hsla|hwb|lab|lch|oklab|oklch|color)\(/.test(v)) return true;
|
|
1766
|
+
if (v === "transparent" || v === "currentcolor") return true;
|
|
1767
|
+
return false;
|
|
1768
|
+
}
|
|
1769
|
+
function inferGroup(cssVar, value) {
|
|
1770
|
+
const v = value.trim().toLowerCase();
|
|
1771
|
+
if (/^\d+(\.\d+)?m?s$/.test(v)) return "duration";
|
|
1772
|
+
if (/^(normal|bold|lighter|bolder)$/.test(v)) return "font-weight";
|
|
1773
|
+
if (/^\d+$/.test(v)) {
|
|
1774
|
+
const n = Number(v);
|
|
1775
|
+
if (n >= 100 && n <= 900 && n % 100 === 0) return "font-weight";
|
|
1776
|
+
}
|
|
1777
|
+
if (/^\d*\.\d+$/.test(v) || /^[1-9](\.\d+)?$/.test(v)) return "line-height";
|
|
1778
|
+
const name = cssVar.replace(/^--/, "").toLowerCase();
|
|
1779
|
+
for (const g of VARIABLE_GROUPS) {
|
|
1780
|
+
if (g.value !== "other" && name.includes(g.value)) return g.value;
|
|
1781
|
+
}
|
|
1782
|
+
return "other";
|
|
1783
|
+
}
|
|
1784
|
+
function groupVariables(variables) {
|
|
1785
|
+
const buckets = /* @__PURE__ */ new Map();
|
|
1786
|
+
for (const v of variables) {
|
|
1787
|
+
const label = sectionLabelForGroup(v.group);
|
|
1788
|
+
(buckets.get(label) ?? buckets.set(label, []).get(label)).push(v);
|
|
1789
|
+
}
|
|
1790
|
+
const ordered = [];
|
|
1791
|
+
for (const g of VARIABLE_GROUPS) {
|
|
1792
|
+
if (g.value === "other") continue;
|
|
1793
|
+
const vars = buckets.get(g.label);
|
|
1794
|
+
if (vars?.length) {
|
|
1795
|
+
ordered.push({ label: g.label, vars });
|
|
1796
|
+
buckets.delete(g.label);
|
|
1797
|
+
}
|
|
1798
|
+
}
|
|
1799
|
+
for (const [label, vars] of buckets) if (vars.length) ordered.push({ label, vars });
|
|
1800
|
+
return ordered;
|
|
1801
|
+
}
|
|
1802
|
+
function buildAutoMediaBlocks(scalable, cfg) {
|
|
1803
|
+
const { breakpoints, responsiveScales } = cfg;
|
|
1804
|
+
const baseRef = responsiveScales.baseReference || 16;
|
|
1805
|
+
const sorted = Object.entries(breakpoints).sort((a, b) => b[1].breakpoint - a[1].breakpoint);
|
|
1806
|
+
const blocks = [];
|
|
1807
|
+
for (const [bpName, bp] of sorted) {
|
|
1808
|
+
const lines = [];
|
|
1809
|
+
for (const v of scalable) {
|
|
1810
|
+
if (v.scales?.[bpName] !== void 0) continue;
|
|
1811
|
+
const categoryScales = responsiveScales[v.type];
|
|
1812
|
+
const scale = categoryScales?.[bpName];
|
|
1813
|
+
if (scale == null) continue;
|
|
1814
|
+
const scaled = scalePropertyValue(v.value, baseRef, scale);
|
|
1815
|
+
if (scaled !== null && scaled !== v.value) lines.push(` ${v.cssVar}: ${scaled};`);
|
|
1816
|
+
}
|
|
1817
|
+
if (lines.length) blocks.push(`@media (max-width: ${bp.breakpoint}px) {
|
|
1818
|
+
:root {
|
|
1819
|
+
${lines.join("\n")}
|
|
1820
|
+
}
|
|
1821
|
+
}`);
|
|
1822
|
+
}
|
|
1823
|
+
return blocks.join("\n\n");
|
|
1824
|
+
}
|
|
1825
|
+
function buildOverrideMediaBlocks(variables, breakpoints) {
|
|
1826
|
+
const sorted = Object.entries(breakpoints).sort((a, b) => b[1].breakpoint - a[1].breakpoint);
|
|
1827
|
+
const blocks = [];
|
|
1828
|
+
for (const [bpName, bp] of sorted) {
|
|
1829
|
+
const lines = [];
|
|
1830
|
+
for (const v of variables) {
|
|
1831
|
+
const override = v.scales?.[bpName];
|
|
1832
|
+
if (override !== void 0 && override !== v.value) lines.push(` ${v.cssVar}: ${override};`);
|
|
1833
|
+
}
|
|
1834
|
+
if (lines.length) blocks.push(`@media (max-width: ${bp.breakpoint}px) {
|
|
1835
|
+
:root {
|
|
1836
|
+
${lines.join("\n")}
|
|
1837
|
+
}
|
|
1838
|
+
}`);
|
|
1839
|
+
}
|
|
1840
|
+
return blocks.join("\n\n");
|
|
1841
|
+
}
|
|
1842
|
+
function serializeThemeCss(model, scaleConfig2) {
|
|
1843
|
+
const { themes, variables, raw = [] } = model;
|
|
1844
|
+
const palette = themes?.palette;
|
|
1845
|
+
const defaultName = themes?.default ?? "default";
|
|
1846
|
+
const defaultTheme = themes?.themes?.[defaultName];
|
|
1847
|
+
const sections = [];
|
|
1848
|
+
const colorEntries = Object.entries(defaultTheme?.colors ?? {});
|
|
1849
|
+
if (colorEntries.length) {
|
|
1850
|
+
sections.push(
|
|
1851
|
+
[
|
|
1852
|
+
` /* ${COLORS_LABEL}: ${defaultName} */`,
|
|
1853
|
+
...colorEntries.map(([k, val]) => ` --${k}: ${resolvePaletteColor(val, palette)};`)
|
|
1854
|
+
].join("\n")
|
|
1855
|
+
);
|
|
1856
|
+
}
|
|
1857
|
+
for (const { label, vars } of groupVariables(variables)) {
|
|
1858
|
+
sections.push([` /* ${label} */`, ...vars.map((v) => ` ${v.cssVar}: ${v.value};`)].join("\n"));
|
|
1859
|
+
}
|
|
1860
|
+
const blocks = [HEADER_BANNER];
|
|
1861
|
+
blocks.push(sections.length ? `:root {
|
|
1862
|
+
${sections.join("\n\n")}
|
|
1863
|
+
}` : ":root {}");
|
|
1864
|
+
for (const [name, theme] of Object.entries(themes?.themes ?? {})) {
|
|
1865
|
+
if (name === defaultName) continue;
|
|
1866
|
+
const lines = Object.entries(theme.colors ?? {}).map(
|
|
1867
|
+
([k, val]) => ` --${k}: ${resolvePaletteColor(val, palette)};`
|
|
1868
|
+
);
|
|
1869
|
+
if (lines.length) blocks.push(`[theme="${name}"] {
|
|
1870
|
+
${lines.join("\n")}
|
|
1871
|
+
}`);
|
|
1872
|
+
}
|
|
1873
|
+
if (scaleConfig2.responsiveScales?.enabled) {
|
|
1874
|
+
const auto = buildAutoMediaBlocks(
|
|
1875
|
+
variables.filter((v) => v.type && v.type !== "none"),
|
|
1876
|
+
scaleConfig2
|
|
1877
|
+
);
|
|
1878
|
+
if (auto) blocks.push(AUTO_BANNER, auto);
|
|
1879
|
+
}
|
|
1880
|
+
const overrides = buildOverrideMediaBlocks(variables, scaleConfig2.breakpoints);
|
|
1881
|
+
if (overrides) blocks.push(OVERRIDES_BANNER, overrides);
|
|
1882
|
+
for (const r of raw) {
|
|
1883
|
+
const t = r.trim();
|
|
1884
|
+
if (t) blocks.push(t);
|
|
1885
|
+
}
|
|
1886
|
+
return `${blocks.join("\n\n")}
|
|
1887
|
+
`;
|
|
1888
|
+
}
|
|
1889
|
+
function skipString(s, i) {
|
|
1890
|
+
const q = s[i];
|
|
1891
|
+
i++;
|
|
1892
|
+
while (i < s.length) {
|
|
1893
|
+
if (s[i] === "\\") {
|
|
1894
|
+
i += 2;
|
|
1895
|
+
continue;
|
|
1896
|
+
}
|
|
1897
|
+
if (s[i] === q) return i + 1;
|
|
1898
|
+
i++;
|
|
1899
|
+
}
|
|
1900
|
+
return i;
|
|
1901
|
+
}
|
|
1902
|
+
function readBlock(s, open) {
|
|
1903
|
+
let i = open + 1;
|
|
1904
|
+
let depth = 1;
|
|
1905
|
+
const bodyStart = i;
|
|
1906
|
+
while (i < s.length && depth > 0) {
|
|
1907
|
+
if (s[i] === "/" && s[i + 1] === "*") {
|
|
1908
|
+
const e = s.indexOf("*/", i + 2);
|
|
1909
|
+
i = e === -1 ? s.length : e + 2;
|
|
1910
|
+
continue;
|
|
1911
|
+
}
|
|
1912
|
+
if (s[i] === '"' || s[i] === "'") {
|
|
1913
|
+
i = skipString(s, i);
|
|
1914
|
+
continue;
|
|
1915
|
+
}
|
|
1916
|
+
if (s[i] === "{") depth++;
|
|
1917
|
+
else if (s[i] === "}") {
|
|
1918
|
+
depth--;
|
|
1919
|
+
if (depth === 0) break;
|
|
1920
|
+
}
|
|
1921
|
+
i++;
|
|
1922
|
+
}
|
|
1923
|
+
return { body: s.slice(bodyStart, i), end: i < s.length ? i + 1 : s.length };
|
|
1924
|
+
}
|
|
1925
|
+
function scanTopLevel(css) {
|
|
1926
|
+
const nodes = [];
|
|
1927
|
+
let i = 0;
|
|
1928
|
+
while (i < css.length) {
|
|
1929
|
+
while (i < css.length && /\s/.test(css[i])) i++;
|
|
1930
|
+
if (i >= css.length) break;
|
|
1931
|
+
if (css[i] === "/" && css[i + 1] === "*") {
|
|
1932
|
+
const e = css.indexOf("*/", i + 2);
|
|
1933
|
+
const stop = e === -1 ? css.length : e + 2;
|
|
1934
|
+
const text = css.slice(i, stop);
|
|
1935
|
+
nodes.push({ kind: "comment", text, raw: text });
|
|
1936
|
+
i = stop;
|
|
1937
|
+
continue;
|
|
1938
|
+
}
|
|
1939
|
+
const start = i;
|
|
1940
|
+
while (i < css.length) {
|
|
1941
|
+
const c = css[i];
|
|
1942
|
+
if (c === "/" && css[i + 1] === "*") {
|
|
1943
|
+
const e = css.indexOf("*/", i + 2);
|
|
1944
|
+
i = e === -1 ? css.length : e + 2;
|
|
1945
|
+
continue;
|
|
1946
|
+
}
|
|
1947
|
+
if (c === '"' || c === "'") {
|
|
1948
|
+
i = skipString(css, i);
|
|
1949
|
+
continue;
|
|
1950
|
+
}
|
|
1951
|
+
if (c === "{" || c === ";") break;
|
|
1952
|
+
i++;
|
|
1953
|
+
}
|
|
1954
|
+
if (i < css.length && css[i] === "{") {
|
|
1955
|
+
const prelude = css.slice(start, i).trim();
|
|
1956
|
+
const { body, end } = readBlock(css, i);
|
|
1957
|
+
nodes.push({ kind: "block", prelude, body, raw: css.slice(start, end) });
|
|
1958
|
+
i = end;
|
|
1959
|
+
} else {
|
|
1960
|
+
const stop = i < css.length ? i + 1 : css.length;
|
|
1961
|
+
const raw = css.slice(start, stop).trim();
|
|
1962
|
+
if (raw) nodes.push({ kind: "statement", raw });
|
|
1963
|
+
i = stop;
|
|
1964
|
+
}
|
|
1965
|
+
}
|
|
1966
|
+
return nodes;
|
|
1967
|
+
}
|
|
1968
|
+
function scanDeclarations(body) {
|
|
1969
|
+
const items = [];
|
|
1970
|
+
let i = 0;
|
|
1971
|
+
while (i < body.length) {
|
|
1972
|
+
while (i < body.length && /\s/.test(body[i])) i++;
|
|
1973
|
+
if (i >= body.length) break;
|
|
1974
|
+
if (body[i] === "/" && body[i + 1] === "*") {
|
|
1975
|
+
const e = body.indexOf("*/", i + 2);
|
|
1976
|
+
const stop = e === -1 ? body.length : e + 2;
|
|
1977
|
+
items.push({ kind: "comment", text: body.slice(i, stop) });
|
|
1978
|
+
i = stop;
|
|
1979
|
+
continue;
|
|
1980
|
+
}
|
|
1981
|
+
const start = i;
|
|
1982
|
+
while (i < body.length) {
|
|
1983
|
+
const c = body[i];
|
|
1984
|
+
if (c === "/" && body[i + 1] === "*") {
|
|
1985
|
+
const e = body.indexOf("*/", i + 2);
|
|
1986
|
+
i = e === -1 ? body.length : e + 2;
|
|
1987
|
+
continue;
|
|
1988
|
+
}
|
|
1989
|
+
if (c === '"' || c === "'") {
|
|
1990
|
+
i = skipString(body, i);
|
|
1991
|
+
continue;
|
|
1992
|
+
}
|
|
1993
|
+
if (c === ";") break;
|
|
1994
|
+
i++;
|
|
1995
|
+
}
|
|
1996
|
+
const text = body.slice(start, i).trim();
|
|
1997
|
+
i = i < body.length ? i + 1 : body.length;
|
|
1998
|
+
const colon = text.indexOf(":");
|
|
1999
|
+
if (colon > 0) {
|
|
2000
|
+
items.push({ kind: "decl", prop: text.slice(0, colon).trim(), value: text.slice(colon + 1).trim() });
|
|
2001
|
+
}
|
|
2002
|
+
}
|
|
2003
|
+
return items;
|
|
2004
|
+
}
|
|
2005
|
+
function commentInner(text) {
|
|
2006
|
+
return text.replace(/^\/\*+/, "").replace(/\*+\/$/, "").trim();
|
|
2007
|
+
}
|
|
2008
|
+
function isHeaderBanner(text) {
|
|
2009
|
+
const t = commentInner(text);
|
|
2010
|
+
return /meno design tokens/i.test(t) || /AUTO-GENERATED by meno-astro/i.test(t);
|
|
2011
|
+
}
|
|
2012
|
+
function prettifyName(name) {
|
|
2013
|
+
return name.replace(/[-_]/g, " ").replace(/([a-z])([A-Z])/g, "$1 $2").replace(/\b\w/g, (c) => c.toUpperCase());
|
|
2014
|
+
}
|
|
2015
|
+
function maxWidthPx(prelude) {
|
|
2016
|
+
const m = prelude.match(/max-width:\s*(\d+)px/i);
|
|
2017
|
+
return m ? Number(m[1]) : null;
|
|
2018
|
+
}
|
|
2019
|
+
function bpNameForPx(px, breakpoints) {
|
|
2020
|
+
for (const [name, entry] of Object.entries(breakpoints)) if (entry.breakpoint === px) return name;
|
|
2021
|
+
return null;
|
|
2022
|
+
}
|
|
2023
|
+
function parseThemeCss(css, breakpoints) {
|
|
2024
|
+
const themesMap = {};
|
|
2025
|
+
const variables = [];
|
|
2026
|
+
const varByCssVar = /* @__PURE__ */ new Map();
|
|
2027
|
+
const raw = [];
|
|
2028
|
+
let defaultName = null;
|
|
2029
|
+
let region = null;
|
|
2030
|
+
for (const node of scanTopLevel(css)) {
|
|
2031
|
+
if (node.kind === "comment") {
|
|
2032
|
+
if (isHeaderBanner(node.text)) continue;
|
|
2033
|
+
const inner = commentInner(node.text);
|
|
2034
|
+
if (/responsive overrides/i.test(inner)) {
|
|
2035
|
+
region = "overrides";
|
|
2036
|
+
continue;
|
|
2037
|
+
}
|
|
2038
|
+
if (/responsive scaling|auto-generated from project\.config/i.test(inner)) {
|
|
2039
|
+
region = "auto";
|
|
2040
|
+
continue;
|
|
2041
|
+
}
|
|
2042
|
+
raw.push(node.raw);
|
|
2043
|
+
continue;
|
|
2044
|
+
}
|
|
2045
|
+
if (node.kind === "statement") {
|
|
2046
|
+
raw.push(node.raw);
|
|
2047
|
+
continue;
|
|
2048
|
+
}
|
|
2049
|
+
const sel = node.prelude;
|
|
2050
|
+
if (sel === ":root") {
|
|
2051
|
+
let section = null;
|
|
2052
|
+
for (const it of scanDeclarations(node.body)) {
|
|
2053
|
+
if (it.kind === "comment") {
|
|
2054
|
+
const inner = commentInner(it.text);
|
|
2055
|
+
if (/^colors\b/i.test(inner)) {
|
|
2056
|
+
section = "colors";
|
|
2057
|
+
const dn = inner.match(/^colors\s*:\s*([\w-]+)/i);
|
|
2058
|
+
if (dn) defaultName = dn[1];
|
|
2059
|
+
} else {
|
|
2060
|
+
const g = groupForSectionLabel(inner);
|
|
2061
|
+
if (g) section = g;
|
|
2062
|
+
}
|
|
2063
|
+
continue;
|
|
2064
|
+
}
|
|
2065
|
+
if (!it.prop.startsWith("--")) continue;
|
|
2066
|
+
const name = it.prop.slice(2);
|
|
2067
|
+
if (section === "colors" || section === null && isColorValue(it.value)) {
|
|
2068
|
+
const dn = defaultName ??= "default";
|
|
2069
|
+
(themesMap[dn] ??= { colors: {} }).colors[name] = it.value;
|
|
2070
|
+
} else {
|
|
2071
|
+
const group = section ?? inferGroup(it.prop, it.value);
|
|
2072
|
+
const v = { cssVar: it.prop, value: it.value, type: getDefaultScalingType(group), group };
|
|
2073
|
+
variables.push(v);
|
|
2074
|
+
varByCssVar.set(it.prop, v);
|
|
2075
|
+
}
|
|
2076
|
+
}
|
|
2077
|
+
continue;
|
|
2078
|
+
}
|
|
2079
|
+
const themeMatch = sel.match(/^\[theme=["']?([^"'\]]+)["']?\]$/);
|
|
2080
|
+
if (themeMatch) {
|
|
2081
|
+
const theme = themesMap[themeMatch[1]] ??= { colors: {} };
|
|
2082
|
+
for (const it of scanDeclarations(node.body)) {
|
|
2083
|
+
if (it.kind === "decl" && it.prop.startsWith("--")) theme.colors[it.prop.slice(2)] = it.value;
|
|
2084
|
+
}
|
|
2085
|
+
continue;
|
|
2086
|
+
}
|
|
2087
|
+
if (/^@media\b/i.test(sel)) {
|
|
2088
|
+
const px = maxWidthPx(sel);
|
|
2089
|
+
if (region === "auto") continue;
|
|
2090
|
+
const bpName = px != null && breakpoints ? bpNameForPx(px, breakpoints) : null;
|
|
2091
|
+
if (!bpName) {
|
|
2092
|
+
raw.push(node.raw);
|
|
2093
|
+
continue;
|
|
2094
|
+
}
|
|
2095
|
+
for (const inner of scanTopLevel(node.body)) {
|
|
2096
|
+
if (inner.kind !== "block" || inner.prelude !== ":root") continue;
|
|
2097
|
+
for (const it of scanDeclarations(inner.body)) {
|
|
2098
|
+
if (it.kind !== "decl" || !it.prop.startsWith("--")) continue;
|
|
2099
|
+
const v = varByCssVar.get(it.prop);
|
|
2100
|
+
if (v) (v.scales ??= {})[bpName] = it.value;
|
|
2101
|
+
}
|
|
2102
|
+
}
|
|
2103
|
+
continue;
|
|
2104
|
+
}
|
|
2105
|
+
raw.push(node.raw);
|
|
2106
|
+
}
|
|
2107
|
+
if (!defaultName) defaultName = Object.keys(themesMap)[0] ?? "default";
|
|
2108
|
+
(themesMap[defaultName] ??= { colors: {} }).label ??= prettifyName(defaultName);
|
|
2109
|
+
for (const [name, t] of Object.entries(themesMap)) t.label ??= prettifyName(name);
|
|
2110
|
+
return { themes: { default: defaultName, themes: themesMap }, variables, raw };
|
|
2111
|
+
}
|
|
2112
|
+
|
|
2113
|
+
// lib/server/themeCssStore.ts
|
|
2114
|
+
var log2 = createLogger("themeCssStore");
|
|
2115
|
+
function themeCssPath(root = getProjectRoot()) {
|
|
2116
|
+
return join2(root, "src", "styles", "theme.css");
|
|
2117
|
+
}
|
|
2118
|
+
function isThemeCssProject(root = getProjectRoot()) {
|
|
2119
|
+
if (existsSync2(themeCssPath(root))) return true;
|
|
2120
|
+
if (existsSync2(join2(root, "src", "pages"))) return true;
|
|
2121
|
+
try {
|
|
2122
|
+
const cfg = JSON.parse(readFileSync(join2(root, "project.config.json"), "utf8"));
|
|
2123
|
+
if (cfg.format === "astro") return true;
|
|
2124
|
+
} catch {
|
|
2125
|
+
}
|
|
2126
|
+
return false;
|
|
2127
|
+
}
|
|
2128
|
+
var writeChain = Promise.resolve();
|
|
2129
|
+
function enqueue(fn) {
|
|
2130
|
+
const run = writeChain.then(fn, fn);
|
|
2131
|
+
writeChain = run.then(
|
|
2132
|
+
() => void 0,
|
|
2133
|
+
() => void 0
|
|
2134
|
+
);
|
|
2135
|
+
return run;
|
|
2136
|
+
}
|
|
2137
|
+
async function readJsonSafe(path3) {
|
|
2138
|
+
try {
|
|
2139
|
+
return JSON.parse(await readTextFile(path3));
|
|
2140
|
+
} catch {
|
|
2141
|
+
return null;
|
|
2142
|
+
}
|
|
2143
|
+
}
|
|
2144
|
+
function scaleConfig() {
|
|
2145
|
+
return { breakpoints: configService.getBreakpoints(), responsiveScales: configService.getResponsiveScales() };
|
|
2146
|
+
}
|
|
2147
|
+
function emptyModel() {
|
|
2148
|
+
return { themes: { default: "default", themes: { default: { colors: {} } } }, variables: [], raw: [] };
|
|
2149
|
+
}
|
|
2150
|
+
async function readModel(root) {
|
|
2151
|
+
const path3 = themeCssPath(root);
|
|
2152
|
+
if (!await fileExists(path3)) return emptyModel();
|
|
2153
|
+
return parseThemeCss(await readTextFile(path3), configService.getBreakpoints());
|
|
2154
|
+
}
|
|
2155
|
+
async function writeModel(root, model) {
|
|
2156
|
+
const css = serializeThemeCss(model, scaleConfig());
|
|
2157
|
+
await ensureDir(join2(root, "src", "styles"));
|
|
2158
|
+
await writeFile(themeCssPath(root), css);
|
|
2159
|
+
}
|
|
2160
|
+
function hasColors(themes) {
|
|
2161
|
+
return Object.values(themes.themes ?? {}).some((t) => Object.keys(t.colors ?? {}).length > 0);
|
|
2162
|
+
}
|
|
2163
|
+
function mergeThemes(current, incoming) {
|
|
2164
|
+
if (!incoming?.themes) return current;
|
|
2165
|
+
if (!hasColors(current)) return incoming;
|
|
2166
|
+
const out = { default: current.default, palette: current.palette, themes: { ...current.themes } };
|
|
2167
|
+
for (const [name, theme] of Object.entries(incoming.themes)) {
|
|
2168
|
+
const existing = out.themes[name];
|
|
2169
|
+
out.themes[name] = existing ? { ...existing, colors: { ...theme.colors, ...existing.colors } } : theme;
|
|
2170
|
+
}
|
|
2171
|
+
return out;
|
|
2172
|
+
}
|
|
2173
|
+
function mergeVariables(current, incoming) {
|
|
2174
|
+
if (!incoming?.length) return current;
|
|
2175
|
+
const seen = new Set(current.map((v) => v.cssVar));
|
|
2176
|
+
return [...current, ...incoming.filter((v) => !seen.has(v.cssVar))];
|
|
2177
|
+
}
|
|
2178
|
+
var AUTHORED_MARKER = "Meno design tokens";
|
|
2179
|
+
async function migrateIfNeeded(root) {
|
|
2180
|
+
const colorsJson = join2(root, "colors.json");
|
|
2181
|
+
const variablesJson = join2(root, "variables.json");
|
|
2182
|
+
const hasColorsJson = existsSync2(colorsJson);
|
|
2183
|
+
const hasVarsJson = existsSync2(variablesJson);
|
|
2184
|
+
if (!hasColorsJson && !hasVarsJson) return;
|
|
2185
|
+
try {
|
|
2186
|
+
const jsonColors = hasColorsJson ? await readJsonSafe(colorsJson) : null;
|
|
2187
|
+
const jsonVars = hasVarsJson ? await readJsonSafe(variablesJson) : null;
|
|
2188
|
+
let current = emptyModel();
|
|
2189
|
+
let authored = false;
|
|
2190
|
+
if (await fileExists(themeCssPath(root))) {
|
|
2191
|
+
const text = await readTextFile(themeCssPath(root));
|
|
2192
|
+
authored = text.includes(AUTHORED_MARKER);
|
|
2193
|
+
current = parseThemeCss(text, configService.getBreakpoints());
|
|
2194
|
+
}
|
|
2195
|
+
const base = authored ? current : emptyModel();
|
|
2196
|
+
const merged = {
|
|
2197
|
+
themes: mergeThemes(base.themes, jsonColors?.themes ? jsonColors : null),
|
|
2198
|
+
variables: mergeVariables(base.variables, jsonVars?.variables),
|
|
2199
|
+
raw: current.raw
|
|
2200
|
+
};
|
|
2201
|
+
await writeModel(root, merged);
|
|
2202
|
+
await rm(colorsJson, { force: true });
|
|
2203
|
+
await rm(variablesJson, { force: true });
|
|
2204
|
+
log2.info("Folded colors.json / variables.json into src/styles/theme.css");
|
|
2205
|
+
} catch (err) {
|
|
2206
|
+
log2.warn("theme.css migration failed; keeping JSON files:", err);
|
|
2207
|
+
}
|
|
2208
|
+
}
|
|
2209
|
+
async function loadThemeModel(root = getProjectRoot()) {
|
|
2210
|
+
await configService.load();
|
|
2211
|
+
return enqueue(async () => {
|
|
2212
|
+
await migrateIfNeeded(root);
|
|
2213
|
+
return readModel(root);
|
|
2214
|
+
});
|
|
2215
|
+
}
|
|
2216
|
+
async function saveColors(themes, root = getProjectRoot()) {
|
|
2217
|
+
await configService.load();
|
|
2218
|
+
return enqueue(async () => {
|
|
2219
|
+
await migrateIfNeeded(root);
|
|
2220
|
+
const current = await readModel(root);
|
|
2221
|
+
await writeModel(root, { themes, variables: current.variables, raw: current.raw });
|
|
2222
|
+
});
|
|
2223
|
+
}
|
|
2224
|
+
async function saveVariables(variables, root = getProjectRoot()) {
|
|
2225
|
+
await configService.load();
|
|
2226
|
+
return enqueue(async () => {
|
|
2227
|
+
await migrateIfNeeded(root);
|
|
2228
|
+
const current = await readModel(root);
|
|
2229
|
+
await writeModel(root, { themes: current.themes, variables, raw: current.raw });
|
|
2230
|
+
});
|
|
2231
|
+
}
|
|
2232
|
+
async function regenerateThemeCss(root = getProjectRoot()) {
|
|
2233
|
+
await configService.load();
|
|
2234
|
+
return enqueue(async () => {
|
|
2235
|
+
await migrateIfNeeded(root);
|
|
2236
|
+
if (!await fileExists(themeCssPath(root))) return;
|
|
2237
|
+
await writeModel(root, await readModel(root));
|
|
2238
|
+
});
|
|
2239
|
+
}
|
|
2240
|
+
|
|
1733
2241
|
// lib/server/services/ColorService.ts
|
|
1734
|
-
var
|
|
2242
|
+
var log3 = createLogger("ColorService");
|
|
1735
2243
|
var ColorService = class extends CachedConfigLoader {
|
|
1736
2244
|
/**
|
|
1737
2245
|
* Load theme configuration from colors.json
|
|
@@ -1740,9 +2248,19 @@ var ColorService = class extends CachedConfigLoader {
|
|
|
1740
2248
|
return this.load();
|
|
1741
2249
|
}
|
|
1742
2250
|
/**
|
|
1743
|
-
* Perform the actual loading from file
|
|
2251
|
+
* Perform the actual loading from file.
|
|
2252
|
+
* Astro projects read colors from `src/styles/theme.css` (the token source of truth);
|
|
2253
|
+
* legacy JSON projects read `colors.json`.
|
|
1744
2254
|
*/
|
|
1745
2255
|
async performLoad() {
|
|
2256
|
+
if (isThemeCssProject()) {
|
|
2257
|
+
try {
|
|
2258
|
+
return (await loadThemeModel()).themes;
|
|
2259
|
+
} catch (error) {
|
|
2260
|
+
log3.warn("Failed to load colors from theme.css:", error);
|
|
2261
|
+
return this.getDefaultThemeConfig();
|
|
2262
|
+
}
|
|
2263
|
+
}
|
|
1746
2264
|
try {
|
|
1747
2265
|
const content = await loadJSONFile(projectPaths.colors());
|
|
1748
2266
|
if (content) {
|
|
@@ -1752,7 +2270,7 @@ var ColorService = class extends CachedConfigLoader {
|
|
|
1752
2270
|
}
|
|
1753
2271
|
}
|
|
1754
2272
|
} catch (error) {
|
|
1755
|
-
|
|
2273
|
+
log3.warn("Failed to load colors.json:", error);
|
|
1756
2274
|
}
|
|
1757
2275
|
return this.getDefaultThemeConfig();
|
|
1758
2276
|
}
|
|
@@ -1832,6 +2350,23 @@ var ColorService = class extends CachedConfigLoader {
|
|
|
1832
2350
|
* Distinguishes between missing file, invalid JSON, and valid config
|
|
1833
2351
|
*/
|
|
1834
2352
|
async getConfigWithStatus() {
|
|
2353
|
+
if (isThemeCssProject()) {
|
|
2354
|
+
const filePath2 = themeCssPath();
|
|
2355
|
+
if (!existsSync3(filePath2)) {
|
|
2356
|
+
return { status: "missing", config: this.getMinimalConfig(), filePath: filePath2 };
|
|
2357
|
+
}
|
|
2358
|
+
try {
|
|
2359
|
+
const model = await loadThemeModel();
|
|
2360
|
+
return { status: "valid", config: model.themes, filePath: filePath2 };
|
|
2361
|
+
} catch (error) {
|
|
2362
|
+
return {
|
|
2363
|
+
status: "invalid",
|
|
2364
|
+
config: this.getMinimalConfig(),
|
|
2365
|
+
error: error instanceof Error ? error.message : "Parse error",
|
|
2366
|
+
filePath: filePath2
|
|
2367
|
+
};
|
|
2368
|
+
}
|
|
2369
|
+
}
|
|
1835
2370
|
const filePath = projectPaths.colors();
|
|
1836
2371
|
try {
|
|
1837
2372
|
const content = await loadJSONFile(filePath);
|
|
@@ -1882,7 +2417,7 @@ var ColorService = class extends CachedConfigLoader {
|
|
|
1882
2417
|
const config = await this.loadThemeConfig();
|
|
1883
2418
|
return Object.entries(config.themes).map(([name, theme]) => ({
|
|
1884
2419
|
name,
|
|
1885
|
-
label: theme.label
|
|
2420
|
+
label: theme.label ?? name
|
|
1886
2421
|
}));
|
|
1887
2422
|
}
|
|
1888
2423
|
/**
|
|
@@ -1916,12 +2451,15 @@ var ColorService = class extends CachedConfigLoader {
|
|
|
1916
2451
|
return this.loadThemeConfig();
|
|
1917
2452
|
}
|
|
1918
2453
|
/**
|
|
1919
|
-
* Save theme configuration
|
|
2454
|
+
* Save theme configuration. Astro projects write the colors half of
|
|
2455
|
+
* `src/styles/theme.css` (preserving variables); legacy JSON projects write `colors.json`.
|
|
1920
2456
|
*/
|
|
1921
2457
|
async saveThemeConfig(config) {
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
2458
|
+
if (isThemeCssProject()) {
|
|
2459
|
+
await saveColors(config);
|
|
2460
|
+
} else {
|
|
2461
|
+
await writeFile(projectPaths.colors(), JSON.stringify(config, null, 2));
|
|
2462
|
+
}
|
|
1925
2463
|
this.setCache(config);
|
|
1926
2464
|
}
|
|
1927
2465
|
};
|
|
@@ -1948,7 +2486,8 @@ async function handleColorsStatusRoute() {
|
|
|
1948
2486
|
}
|
|
1949
2487
|
|
|
1950
2488
|
// lib/server/services/VariableService.ts
|
|
1951
|
-
|
|
2489
|
+
import { existsSync as existsSync4 } from "node:fs";
|
|
2490
|
+
var log4 = createLogger("VariableService");
|
|
1952
2491
|
var VariableService = class extends CachedConfigLoader {
|
|
1953
2492
|
/**
|
|
1954
2493
|
* Load variables configuration from variables.json
|
|
@@ -1957,6 +2496,14 @@ var VariableService = class extends CachedConfigLoader {
|
|
|
1957
2496
|
return this.load();
|
|
1958
2497
|
}
|
|
1959
2498
|
async performLoad() {
|
|
2499
|
+
if (isThemeCssProject()) {
|
|
2500
|
+
try {
|
|
2501
|
+
return { variables: (await loadThemeModel()).variables };
|
|
2502
|
+
} catch (error) {
|
|
2503
|
+
log4.warn("Failed to load variables from theme.css:", error);
|
|
2504
|
+
return this.getDefaultConfig();
|
|
2505
|
+
}
|
|
2506
|
+
}
|
|
1960
2507
|
try {
|
|
1961
2508
|
const content = await loadJSONFile(projectPaths.variables());
|
|
1962
2509
|
if (content) {
|
|
@@ -1966,7 +2513,7 @@ var VariableService = class extends CachedConfigLoader {
|
|
|
1966
2513
|
}
|
|
1967
2514
|
}
|
|
1968
2515
|
} catch (error) {
|
|
1969
|
-
|
|
2516
|
+
log4.warn("Failed to load variables.json:", error);
|
|
1970
2517
|
}
|
|
1971
2518
|
return this.getDefaultConfig();
|
|
1972
2519
|
}
|
|
@@ -1979,7 +2526,7 @@ var VariableService = class extends CachedConfigLoader {
|
|
|
1979
2526
|
migrateConfig(config) {
|
|
1980
2527
|
for (const variable of config.variables) {
|
|
1981
2528
|
if (variable.group === "spacing") {
|
|
1982
|
-
const lower = `${variable.cssVar} ${variable.name}`.toLowerCase();
|
|
2529
|
+
const lower = `${variable.cssVar} ${variable.name ?? ""}`.toLowerCase();
|
|
1983
2530
|
if (lower.includes("margin")) {
|
|
1984
2531
|
variable.group = "margin";
|
|
1985
2532
|
} else if (lower.includes("gap")) {
|
|
@@ -1995,6 +2542,22 @@ var VariableService = class extends CachedConfigLoader {
|
|
|
1995
2542
|
* Get config with status info (for editor UI)
|
|
1996
2543
|
*/
|
|
1997
2544
|
async getConfigWithStatus() {
|
|
2545
|
+
if (isThemeCssProject()) {
|
|
2546
|
+
const filePath2 = themeCssPath();
|
|
2547
|
+
if (!existsSync4(filePath2)) {
|
|
2548
|
+
return { status: "missing", config: this.getDefaultConfig(), filePath: filePath2 };
|
|
2549
|
+
}
|
|
2550
|
+
try {
|
|
2551
|
+
return { status: "valid", config: { variables: (await loadThemeModel()).variables }, filePath: filePath2 };
|
|
2552
|
+
} catch (error) {
|
|
2553
|
+
return {
|
|
2554
|
+
status: "invalid",
|
|
2555
|
+
config: this.getDefaultConfig(),
|
|
2556
|
+
error: error instanceof Error ? error.message : "Parse error",
|
|
2557
|
+
filePath: filePath2
|
|
2558
|
+
};
|
|
2559
|
+
}
|
|
2560
|
+
}
|
|
1998
2561
|
const filePath = projectPaths.variables();
|
|
1999
2562
|
try {
|
|
2000
2563
|
const content = await loadJSONFile(filePath);
|
|
@@ -2021,12 +2584,15 @@ var VariableService = class extends CachedConfigLoader {
|
|
|
2021
2584
|
}
|
|
2022
2585
|
}
|
|
2023
2586
|
/**
|
|
2024
|
-
* Save variables configuration
|
|
2587
|
+
* Save variables configuration. Astro projects write the variables half of
|
|
2588
|
+
* `src/styles/theme.css` (preserving colors); legacy JSON projects write `variables.json`.
|
|
2025
2589
|
*/
|
|
2026
2590
|
async saveConfig(config) {
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2591
|
+
if (isThemeCssProject()) {
|
|
2592
|
+
await saveVariables(config.variables);
|
|
2593
|
+
} else {
|
|
2594
|
+
await writeFile(projectPaths.variables(), JSON.stringify(config, null, 2));
|
|
2595
|
+
}
|
|
2030
2596
|
this.setCache(config);
|
|
2031
2597
|
}
|
|
2032
2598
|
};
|
|
@@ -2142,7 +2708,7 @@ async function handleVariablesCSSRoute() {
|
|
|
2142
2708
|
}
|
|
2143
2709
|
|
|
2144
2710
|
// lib/server/services/EnumService.ts
|
|
2145
|
-
var
|
|
2711
|
+
var log5 = createLogger("EnumService");
|
|
2146
2712
|
var EnumService = class extends CachedConfigLoader {
|
|
2147
2713
|
/**
|
|
2148
2714
|
* Load enums configuration from enums.json
|
|
@@ -2162,7 +2728,7 @@ var EnumService = class extends CachedConfigLoader {
|
|
|
2162
2728
|
return this.validateEnums(data);
|
|
2163
2729
|
}
|
|
2164
2730
|
} catch (error) {
|
|
2165
|
-
|
|
2731
|
+
log5.warn("Failed to parse enums.json:", error);
|
|
2166
2732
|
}
|
|
2167
2733
|
}
|
|
2168
2734
|
if (configContent) {
|
|
@@ -4237,7 +4803,8 @@ async function renderNode(node, ctx) {
|
|
|
4237
4803
|
const nodeAttributesWithoutClass = { ...nodeAttributes };
|
|
4238
4804
|
delete nodeAttributesWithoutClass.className;
|
|
4239
4805
|
delete nodeAttributesWithoutClass.class;
|
|
4240
|
-
const
|
|
4806
|
+
const instanceClassName = typeof nodeProps.class === "string" ? nodeProps.class : "";
|
|
4807
|
+
const allClassNames = [elementClass, attrClassName, ...utilityClasses, instanceClassName].filter(Boolean);
|
|
4241
4808
|
const mergedClassName = allClassNames.length > 0 ? allClassNames.join(" ") : "";
|
|
4242
4809
|
const propsWithStyleAndAttrs = {
|
|
4243
4810
|
...nodeProps,
|
|
@@ -5043,17 +5610,25 @@ ${escapedJavaScript}
|
|
|
5043
5610
|
const themeConfig = await colorService.loadThemeConfig();
|
|
5044
5611
|
const themeColorVariablesCSS = generateThemeColorVariablesCSS(themeConfig);
|
|
5045
5612
|
const componentCSS = rendered.componentCSS || "";
|
|
5046
|
-
const usedUtilityClasses = extractUtilityClassesFromHTML(rendered.html);
|
|
5047
5613
|
const breakpointConfig = await loadBreakpointConfig();
|
|
5048
5614
|
const responsiveScalesConfig = configService.getResponsiveScales();
|
|
5049
5615
|
const variablesConfig = await variableService.loadConfig();
|
|
5050
5616
|
const variablesCSS = generateVariablesCSS(variablesConfig, breakpointConfig, responsiveScalesConfig);
|
|
5051
5617
|
const remConversionConfig = configService.getRemConversion();
|
|
5618
|
+
const knownTokens = /* @__PURE__ */ new Set();
|
|
5619
|
+
for (const theme of Object.values(themeConfig.themes)) {
|
|
5620
|
+
for (const name of Object.keys(theme.colors)) knownTokens.add(name);
|
|
5621
|
+
}
|
|
5622
|
+
for (const variable of variablesConfig.variables) {
|
|
5623
|
+
if (variable.cssVar) knownTokens.add(variable.cssVar.replace(/^--/, ""));
|
|
5624
|
+
}
|
|
5625
|
+
const usedUtilityClasses = extractUtilityClassesFromHTML(rendered.html, knownTokens);
|
|
5052
5626
|
const utilityCSS = generateUtilityCSS(
|
|
5053
5627
|
usedUtilityClasses,
|
|
5054
5628
|
breakpointConfig,
|
|
5055
5629
|
responsiveScalesConfig,
|
|
5056
|
-
remConversionConfig
|
|
5630
|
+
remConversionConfig,
|
|
5631
|
+
knownTokens
|
|
5057
5632
|
);
|
|
5058
5633
|
const interactiveCSS = rendered.interactiveStylesMap.size > 0 ? generateAllInteractiveCSS(
|
|
5059
5634
|
rendered.interactiveStylesMap,
|
|
@@ -8431,8 +9006,8 @@ ${plainTextErrors}`;
|
|
|
8431
9006
|
}
|
|
8432
9007
|
|
|
8433
9008
|
// lib/server/services/pageService.ts
|
|
8434
|
-
import { existsSync as
|
|
8435
|
-
import { join as
|
|
9009
|
+
import { existsSync as existsSync5, readdirSync as readdirSync2, mkdirSync, rmdirSync } from "node:fs";
|
|
9010
|
+
import { join as join4 } from "node:path";
|
|
8436
9011
|
|
|
8437
9012
|
// lib/server/utils/jsonLineMapper.ts
|
|
8438
9013
|
function buildLineMap(jsonText) {
|
|
@@ -8844,7 +9419,7 @@ var PageService = class {
|
|
|
8844
9419
|
*/
|
|
8845
9420
|
getAllFolders() {
|
|
8846
9421
|
const pagesDir = this.pagesBaseDir();
|
|
8847
|
-
if (!
|
|
9422
|
+
if (!existsSync5(pagesDir)) {
|
|
8848
9423
|
return [];
|
|
8849
9424
|
}
|
|
8850
9425
|
const collectFolders = (dir, prefix) => {
|
|
@@ -8855,7 +9430,7 @@ var PageService = class {
|
|
|
8855
9430
|
if (!entry.isDirectory()) continue;
|
|
8856
9431
|
const relativePath = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
8857
9432
|
result.push(relativePath);
|
|
8858
|
-
result.push(...collectFolders(
|
|
9433
|
+
result.push(...collectFolders(join4(dir, entry.name), relativePath));
|
|
8859
9434
|
}
|
|
8860
9435
|
return result;
|
|
8861
9436
|
} catch {
|
|
@@ -8886,8 +9461,8 @@ var PageService = class {
|
|
|
8886
9461
|
}
|
|
8887
9462
|
}
|
|
8888
9463
|
const pagesDir = this.pagesBaseDir();
|
|
8889
|
-
const folderPath =
|
|
8890
|
-
if (
|
|
9464
|
+
const folderPath = join4(pagesDir, trimmed);
|
|
9465
|
+
if (existsSync5(folderPath)) {
|
|
8891
9466
|
throw new Error("Folder already exists");
|
|
8892
9467
|
}
|
|
8893
9468
|
mkdirSync(folderPath, { recursive: true });
|
|
@@ -8908,18 +9483,18 @@ var PageService = class {
|
|
|
8908
9483
|
const pageName = pagePath === "/" ? "index" : pagePath.substring(1);
|
|
8909
9484
|
const slashIndex = pageName.lastIndexOf("/");
|
|
8910
9485
|
const baseName = slashIndex >= 0 ? pageName.substring(slashIndex + 1) : pageName;
|
|
8911
|
-
const sourceFile =
|
|
8912
|
-
const targetFile = newFolder ?
|
|
9486
|
+
const sourceFile = join4(pagesDir, `${pageName}${ext}`);
|
|
9487
|
+
const targetFile = newFolder ? join4(pagesDir, newFolder, `${baseName}${ext}`) : join4(pagesDir, `${baseName}${ext}`);
|
|
8913
9488
|
if (!isPathWithinRoot(sourceFile, pagesDir) || !isPathWithinRoot(targetFile, pagesDir)) {
|
|
8914
9489
|
throw new Error(`movePage path escapes pages dir: ${pagePath} -> ${newFolder}`);
|
|
8915
9490
|
}
|
|
8916
9491
|
if (newFolder) {
|
|
8917
|
-
const targetDir =
|
|
8918
|
-
if (!
|
|
9492
|
+
const targetDir = join4(pagesDir, newFolder);
|
|
9493
|
+
if (!existsSync5(targetDir)) {
|
|
8919
9494
|
mkdirSync(targetDir, { recursive: true });
|
|
8920
9495
|
}
|
|
8921
9496
|
}
|
|
8922
|
-
if (!
|
|
9497
|
+
if (!existsSync5(sourceFile)) {
|
|
8923
9498
|
throw new Error(`Page not found: ${pagePath}`);
|
|
8924
9499
|
}
|
|
8925
9500
|
await rename2(sourceFile, targetFile);
|
|
@@ -8931,7 +9506,7 @@ var PageService = class {
|
|
|
8931
9506
|
const lineMap = buildLineMap(content);
|
|
8932
9507
|
this.pageCache.set(newPath, content, lineMap);
|
|
8933
9508
|
}
|
|
8934
|
-
const sourceDir = slashIndex >= 0 ?
|
|
9509
|
+
const sourceDir = slashIndex >= 0 ? join4(pagesDir, pageName.substring(0, slashIndex)) : null;
|
|
8935
9510
|
if (sourceDir && sourceDir !== pagesDir) {
|
|
8936
9511
|
try {
|
|
8937
9512
|
const remaining = readdirSync2(sourceDir);
|
|
@@ -8980,12 +9555,12 @@ var PageService = class {
|
|
|
8980
9555
|
const { rename: rename2 } = await import("node:fs/promises");
|
|
8981
9556
|
const pagesDir = this.pagesBaseDir();
|
|
8982
9557
|
const ext = this.pageExt();
|
|
8983
|
-
const sourceFile =
|
|
8984
|
-
const targetFile =
|
|
8985
|
-
if (!
|
|
9558
|
+
const sourceFile = join4(pagesDir, `${oldName}${ext}`);
|
|
9559
|
+
const targetFile = join4(pagesDir, `${newName}${ext}`);
|
|
9560
|
+
if (!existsSync5(sourceFile)) {
|
|
8986
9561
|
throw new Error(`Page not found: ${oldPath}`);
|
|
8987
9562
|
}
|
|
8988
|
-
if (
|
|
9563
|
+
if (existsSync5(targetFile)) {
|
|
8989
9564
|
throw new Error(`Page already exists: ${newPath}`);
|
|
8990
9565
|
}
|
|
8991
9566
|
await rename2(sourceFile, targetFile);
|
|
@@ -9035,8 +9610,8 @@ var PageService = class {
|
|
|
9035
9610
|
};
|
|
9036
9611
|
|
|
9037
9612
|
// lib/server/services/componentService.ts
|
|
9038
|
-
import { join as
|
|
9039
|
-
import { existsSync as
|
|
9613
|
+
import { join as join5 } from "node:path";
|
|
9614
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync2, readdirSync as readdirSync3, rmdirSync as rmdirSync2 } from "node:fs";
|
|
9040
9615
|
var ComponentService = class {
|
|
9041
9616
|
components = /* @__PURE__ */ new Map();
|
|
9042
9617
|
componentCategories = /* @__PURE__ */ new Map();
|
|
@@ -9268,7 +9843,7 @@ var ComponentService = class {
|
|
|
9268
9843
|
const componentsDir = this.componentsBaseDir();
|
|
9269
9844
|
if (!isSafePathSegment(name)) throw new Error(`unsafe component name: ${name}`);
|
|
9270
9845
|
const cat = this.resolveComponentCategory(name, category);
|
|
9271
|
-
const dir = cat ?
|
|
9846
|
+
const dir = cat ? join5(componentsDir, cat) : componentsDir;
|
|
9272
9847
|
if (!isPathWithinRoot(dir, componentsDir)) throw new Error(`component category escapes components dir: ${cat}`);
|
|
9273
9848
|
return dir;
|
|
9274
9849
|
}
|
|
@@ -9299,10 +9874,10 @@ var ComponentService = class {
|
|
|
9299
9874
|
*/
|
|
9300
9875
|
findComponentCategoryOnDisk(name) {
|
|
9301
9876
|
const componentsDir = this.componentsBaseDir();
|
|
9302
|
-
if (!
|
|
9877
|
+
if (!existsSync6(componentsDir)) return void 0;
|
|
9303
9878
|
const ext = this.writer ? null : ".json";
|
|
9304
9879
|
const existsAt = (dir) => {
|
|
9305
|
-
if (ext) return
|
|
9880
|
+
if (ext) return existsSync6(join5(dir, `${name}${ext}`));
|
|
9306
9881
|
try {
|
|
9307
9882
|
return readdirSync3(dir, { withFileTypes: true }).some(
|
|
9308
9883
|
(e) => e.isFile() && (e.name === `${name}.json` || e.name === `${name}.astro`)
|
|
@@ -9314,7 +9889,7 @@ var ComponentService = class {
|
|
|
9314
9889
|
if (existsAt(componentsDir)) return void 0;
|
|
9315
9890
|
try {
|
|
9316
9891
|
for (const entry of readdirSync3(componentsDir, { withFileTypes: true })) {
|
|
9317
|
-
if (entry.isDirectory() && existsAt(
|
|
9892
|
+
if (entry.isDirectory() && existsAt(join5(componentsDir, entry.name))) {
|
|
9318
9893
|
return entry.name;
|
|
9319
9894
|
}
|
|
9320
9895
|
}
|
|
@@ -9341,7 +9916,7 @@ var ComponentService = class {
|
|
|
9341
9916
|
*/
|
|
9342
9917
|
async getComponentJavaScript(name) {
|
|
9343
9918
|
const componentDir = this.getComponentDir(name);
|
|
9344
|
-
const jsFilePath =
|
|
9919
|
+
const jsFilePath = join5(componentDir, `${name}.js`);
|
|
9345
9920
|
try {
|
|
9346
9921
|
if (await fileExists(jsFilePath)) {
|
|
9347
9922
|
return await readTextFile(jsFilePath);
|
|
@@ -9389,15 +9964,15 @@ var ComponentService = class {
|
|
|
9389
9964
|
const dataWithJS = javascript !== void 0 ? { ...dataWithoutJS, component: { ...dataWithoutJS.component, javascript } } : dataWithoutJS;
|
|
9390
9965
|
const targetCategory = this.resolveComponentCategory(name, category);
|
|
9391
9966
|
const componentsDir = this.componentsBaseDir();
|
|
9392
|
-
const componentDir = targetCategory ?
|
|
9967
|
+
const componentDir = targetCategory ? join5(componentsDir, targetCategory) : componentsDir;
|
|
9393
9968
|
if (this.writer) {
|
|
9394
9969
|
await this.writer.writeComponent(componentDir, name, dataWithJS);
|
|
9395
9970
|
} else {
|
|
9396
9971
|
const writeFile3 = this.fs ? this.fs.writeFile.bind(this.fs) : (await import("node:fs/promises")).writeFile;
|
|
9397
|
-
if (targetCategory && !
|
|
9972
|
+
if (targetCategory && !existsSync6(componentDir)) {
|
|
9398
9973
|
mkdirSync2(componentDir, { recursive: true });
|
|
9399
9974
|
}
|
|
9400
|
-
const filePath =
|
|
9975
|
+
const filePath = join5(componentDir, `${name}.json`);
|
|
9401
9976
|
await writeFile3(filePath, JSON.stringify(dataWithoutJS, null, 2), "utf-8");
|
|
9402
9977
|
}
|
|
9403
9978
|
this.components.set(name, dataWithJS);
|
|
@@ -9430,9 +10005,9 @@ var ComponentService = class {
|
|
|
9430
10005
|
return;
|
|
9431
10006
|
}
|
|
9432
10007
|
const writeFile3 = this.fs ? this.fs.writeFile.bind(this.fs) : (await import("node:fs/promises")).writeFile;
|
|
9433
|
-
const jsFilePath =
|
|
10008
|
+
const jsFilePath = join5(componentDir, `${name}.js`);
|
|
9434
10009
|
await writeFile3(jsFilePath, javascript || "", "utf-8");
|
|
9435
|
-
const componentPath =
|
|
10010
|
+
const componentPath = join5(componentDir, `${name}.json`);
|
|
9436
10011
|
const componentData = await loadJSONFile(componentPath);
|
|
9437
10012
|
if (componentData) {
|
|
9438
10013
|
const parsed = parseJSON(componentData);
|
|
@@ -9476,9 +10051,9 @@ var ComponentService = class {
|
|
|
9476
10051
|
return;
|
|
9477
10052
|
}
|
|
9478
10053
|
const writeFile3 = this.fs ? this.fs.writeFile.bind(this.fs) : (await import("node:fs/promises")).writeFile;
|
|
9479
|
-
const cssFilePath =
|
|
10054
|
+
const cssFilePath = join5(componentDir, `${name}.css`);
|
|
9480
10055
|
await writeFile3(cssFilePath, css || "", "utf-8");
|
|
9481
|
-
const componentPath =
|
|
10056
|
+
const componentPath = join5(componentDir, `${name}.json`);
|
|
9482
10057
|
const componentData = await loadJSONFile(componentPath);
|
|
9483
10058
|
if (componentData) {
|
|
9484
10059
|
const parsed = parseJSON(componentData);
|
|
@@ -9511,7 +10086,7 @@ var ComponentService = class {
|
|
|
9511
10086
|
*/
|
|
9512
10087
|
getAllFolders() {
|
|
9513
10088
|
const componentsDir = this.componentsBaseDir();
|
|
9514
|
-
if (!
|
|
10089
|
+
if (!existsSync6(componentsDir)) {
|
|
9515
10090
|
return [];
|
|
9516
10091
|
}
|
|
9517
10092
|
try {
|
|
@@ -9546,8 +10121,8 @@ var ComponentService = class {
|
|
|
9546
10121
|
throw new Error("Folder name can only contain lowercase letters, numbers, dashes, and underscores");
|
|
9547
10122
|
}
|
|
9548
10123
|
const componentsDir = this.componentsBaseDir();
|
|
9549
|
-
const folderPath =
|
|
9550
|
-
if (
|
|
10124
|
+
const folderPath = join5(componentsDir, folderName);
|
|
10125
|
+
if (existsSync6(folderPath)) {
|
|
9551
10126
|
throw new Error("Folder already exists");
|
|
9552
10127
|
}
|
|
9553
10128
|
mkdirSync2(folderPath, { recursive: true });
|
|
@@ -9580,20 +10155,20 @@ var ComponentService = class {
|
|
|
9580
10155
|
return;
|
|
9581
10156
|
}
|
|
9582
10157
|
const componentsDir = this.componentsBaseDir();
|
|
9583
|
-
const sourceDir = currentCategory ?
|
|
9584
|
-
const targetDir = targetCategory ?
|
|
10158
|
+
const sourceDir = currentCategory ? join5(componentsDir, currentCategory) : componentsDir;
|
|
10159
|
+
const targetDir = targetCategory ? join5(componentsDir, targetCategory) : componentsDir;
|
|
9585
10160
|
if (this.writer) {
|
|
9586
10161
|
await this.writer.moveComponent(sourceDir, targetDir, name);
|
|
9587
10162
|
} else {
|
|
9588
|
-
if (targetCategory && !
|
|
10163
|
+
if (targetCategory && !existsSync6(targetDir)) {
|
|
9589
10164
|
mkdirSync2(targetDir, { recursive: true });
|
|
9590
10165
|
}
|
|
9591
10166
|
const extensions = [".json", ".js", ".css"];
|
|
9592
10167
|
const { rename: rename2 } = await import("node:fs/promises");
|
|
9593
10168
|
for (const ext of extensions) {
|
|
9594
|
-
const sourcePath =
|
|
9595
|
-
const targetPath =
|
|
9596
|
-
if (
|
|
10169
|
+
const sourcePath = join5(sourceDir, `${name}${ext}`);
|
|
10170
|
+
const targetPath = join5(targetDir, `${name}${ext}`);
|
|
10171
|
+
if (existsSync6(sourcePath)) {
|
|
9597
10172
|
await rename2(sourcePath, targetPath);
|
|
9598
10173
|
}
|
|
9599
10174
|
}
|
|
@@ -9648,7 +10223,7 @@ var ComponentService = class {
|
|
|
9648
10223
|
}
|
|
9649
10224
|
const category = this.componentCategories.get(oldName);
|
|
9650
10225
|
const componentsDir = this.componentsBaseDir();
|
|
9651
|
-
const dir = category ?
|
|
10226
|
+
const dir = category ? join5(componentsDir, category) : componentsDir;
|
|
9652
10227
|
if (this.writer) {
|
|
9653
10228
|
if (await this.writer.componentExists(dir, trimmedNew)) {
|
|
9654
10229
|
throw new Error(`Component "${trimmedNew}" already exists in components/${category ?? ""}`);
|
|
@@ -9656,15 +10231,15 @@ var ComponentService = class {
|
|
|
9656
10231
|
await this.writer.moveComponent(dir, dir, oldName, trimmedNew);
|
|
9657
10232
|
} else {
|
|
9658
10233
|
for (const ext of [".json", ".js", ".css"]) {
|
|
9659
|
-
if (
|
|
10234
|
+
if (existsSync6(join5(dir, `${trimmedNew}${ext}`))) {
|
|
9660
10235
|
throw new Error(`File "${trimmedNew}${ext}" already exists in components/${category ?? ""}`);
|
|
9661
10236
|
}
|
|
9662
10237
|
}
|
|
9663
10238
|
const { rename: rename2 } = await import("node:fs/promises");
|
|
9664
10239
|
for (const ext of [".json", ".js", ".css"]) {
|
|
9665
|
-
const src =
|
|
9666
|
-
const dst =
|
|
9667
|
-
if (
|
|
10240
|
+
const src = join5(dir, `${oldName}${ext}`);
|
|
10241
|
+
const dst = join5(dir, `${trimmedNew}${ext}`);
|
|
10242
|
+
if (existsSync6(src)) {
|
|
9668
10243
|
await rename2(src, dst);
|
|
9669
10244
|
}
|
|
9670
10245
|
}
|
|
@@ -9682,7 +10257,7 @@ var ComponentService = class {
|
|
|
9682
10257
|
if (!structure) continue;
|
|
9683
10258
|
if (rewriteComponentRefs(structure, oldName, trimmedNew)) {
|
|
9684
10259
|
const otherCategory = this.componentCategories.get(name);
|
|
9685
|
-
const otherDir = otherCategory ?
|
|
10260
|
+
const otherDir = otherCategory ? join5(componentsDir, otherCategory) : componentsDir;
|
|
9686
10261
|
const persisted = JSON.parse(JSON.stringify(otherDef));
|
|
9687
10262
|
if (persisted?.component?.javascript !== void 0) {
|
|
9688
10263
|
delete persisted.component.javascript;
|
|
@@ -9690,7 +10265,7 @@ var ComponentService = class {
|
|
|
9690
10265
|
if (this.writer) {
|
|
9691
10266
|
await this.writer.writeComponent(otherDir, name, persisted);
|
|
9692
10267
|
} else {
|
|
9693
|
-
await writeFile3(
|
|
10268
|
+
await writeFile3(join5(otherDir, `${name}.json`), JSON.stringify(persisted, null, 2), "utf-8");
|
|
9694
10269
|
}
|
|
9695
10270
|
componentRefs++;
|
|
9696
10271
|
}
|
|
@@ -10230,9 +10805,9 @@ var CMSService = class {
|
|
|
10230
10805
|
};
|
|
10231
10806
|
|
|
10232
10807
|
// lib/server/providers/fileSystemCMSProvider.ts
|
|
10233
|
-
import { existsSync as
|
|
10234
|
-
import { join as
|
|
10235
|
-
var
|
|
10808
|
+
import { existsSync as existsSync7, readdirSync as readdirSync4, mkdirSync as mkdirSync3 } from "node:fs";
|
|
10809
|
+
import { join as join6 } from "node:path";
|
|
10810
|
+
var log6 = createLogger("FileSystemCMSProvider");
|
|
10236
10811
|
var DRAFT_FILE_SUFFIX = `${CMS_DRAFT_SUFFIX}.json`;
|
|
10237
10812
|
async function loadJSONFile2(filePath) {
|
|
10238
10813
|
try {
|
|
@@ -10241,7 +10816,7 @@ async function loadJSONFile2(filePath) {
|
|
|
10241
10816
|
}
|
|
10242
10817
|
return null;
|
|
10243
10818
|
} catch (error) {
|
|
10244
|
-
|
|
10819
|
+
log6.warn(`Failed to parse JSON at ${filePath}:`, error instanceof Error ? error.message : error);
|
|
10245
10820
|
return null;
|
|
10246
10821
|
}
|
|
10247
10822
|
}
|
|
@@ -10303,14 +10878,14 @@ var FileSystemCMSProvider = class {
|
|
|
10303
10878
|
return this.schemaCache;
|
|
10304
10879
|
}
|
|
10305
10880
|
const schemas = /* @__PURE__ */ new Map();
|
|
10306
|
-
if (!
|
|
10881
|
+
if (!existsSync7(this.templatesDir)) {
|
|
10307
10882
|
return schemas;
|
|
10308
10883
|
}
|
|
10309
10884
|
const files = readdirSync4(this.templatesDir);
|
|
10310
10885
|
const jsonFiles = files.filter((f) => f.endsWith(".json"));
|
|
10311
10886
|
const results = await Promise.all(
|
|
10312
10887
|
jsonFiles.map(async (file) => {
|
|
10313
|
-
const filePath =
|
|
10888
|
+
const filePath = join6(this.templatesDir, file);
|
|
10314
10889
|
const content = await loadJSONFile2(filePath);
|
|
10315
10890
|
return { filePath, content };
|
|
10316
10891
|
})
|
|
@@ -10335,15 +10910,15 @@ var FileSystemCMSProvider = class {
|
|
|
10335
10910
|
*/
|
|
10336
10911
|
async getItems(collection) {
|
|
10337
10912
|
this.validateCollection(collection);
|
|
10338
|
-
const collectionDir =
|
|
10339
|
-
if (!
|
|
10913
|
+
const collectionDir = join6(this.cmsDir, collection);
|
|
10914
|
+
if (!existsSync7(collectionDir)) {
|
|
10340
10915
|
return [];
|
|
10341
10916
|
}
|
|
10342
10917
|
const files = readdirSync4(collectionDir);
|
|
10343
10918
|
const jsonFiles = files.filter((f) => f.endsWith(".json") && !f.endsWith(DRAFT_FILE_SUFFIX));
|
|
10344
10919
|
const results = await Promise.all(
|
|
10345
10920
|
jsonFiles.map(async (file) => {
|
|
10346
|
-
const filePath =
|
|
10921
|
+
const filePath = join6(collectionDir, file);
|
|
10347
10922
|
const content = await loadJSONFile2(filePath);
|
|
10348
10923
|
return { file, filePath, content };
|
|
10349
10924
|
})
|
|
@@ -10357,7 +10932,7 @@ var FileSystemCMSProvider = class {
|
|
|
10357
10932
|
if (validation.valid) {
|
|
10358
10933
|
items.push(validation.data);
|
|
10359
10934
|
} else {
|
|
10360
|
-
|
|
10935
|
+
log6.warn(`Invalid CMS item at ${filePath}:`, validation.errors);
|
|
10361
10936
|
}
|
|
10362
10937
|
}
|
|
10363
10938
|
}
|
|
@@ -10376,7 +10951,7 @@ var FileSystemCMSProvider = class {
|
|
|
10376
10951
|
async getItemByFilename(collection, filename) {
|
|
10377
10952
|
this.validateCollection(collection);
|
|
10378
10953
|
this.validateFilename(filename);
|
|
10379
|
-
const filePath =
|
|
10954
|
+
const filePath = join6(this.cmsDir, collection, `${filename}.json`);
|
|
10380
10955
|
const content = await loadJSONFile2(filePath);
|
|
10381
10956
|
if (!content || typeof content !== "object") {
|
|
10382
10957
|
return null;
|
|
@@ -10386,7 +10961,7 @@ var FileSystemCMSProvider = class {
|
|
|
10386
10961
|
if (validation.valid) {
|
|
10387
10962
|
return validation.data;
|
|
10388
10963
|
}
|
|
10389
|
-
|
|
10964
|
+
log6.warn(`Invalid CMS item at ${filePath}:`, validation.errors);
|
|
10390
10965
|
return null;
|
|
10391
10966
|
}
|
|
10392
10967
|
/**
|
|
@@ -10428,12 +11003,12 @@ var FileSystemCMSProvider = class {
|
|
|
10428
11003
|
throw new Error("Cannot derive filename: item is missing _id, _filename, and a usable slug-field value.");
|
|
10429
11004
|
}
|
|
10430
11005
|
this.validateFilename(filename);
|
|
10431
|
-
const collectionDir =
|
|
10432
|
-
if (!
|
|
11006
|
+
const collectionDir = join6(this.cmsDir, collection);
|
|
11007
|
+
if (!existsSync7(collectionDir)) {
|
|
10433
11008
|
mkdirSync3(collectionDir, { recursive: true });
|
|
10434
11009
|
}
|
|
10435
11010
|
const itemData = stripTransient(item);
|
|
10436
|
-
const filePath =
|
|
11011
|
+
const filePath = join6(collectionDir, `${filename}.json`);
|
|
10437
11012
|
await writeFile3(filePath, JSON.stringify(itemData, null, 2), "utf-8");
|
|
10438
11013
|
}
|
|
10439
11014
|
/**
|
|
@@ -10443,18 +11018,18 @@ var FileSystemCMSProvider = class {
|
|
|
10443
11018
|
this.validateCollection(collection);
|
|
10444
11019
|
this.validateFilename(filename);
|
|
10445
11020
|
const { unlink } = await import("node:fs/promises");
|
|
10446
|
-
const publishedPath =
|
|
10447
|
-
if (
|
|
11021
|
+
const publishedPath = join6(this.cmsDir, collection, `${filename}.json`);
|
|
11022
|
+
if (existsSync7(publishedPath)) {
|
|
10448
11023
|
await unlink(publishedPath);
|
|
10449
11024
|
}
|
|
10450
11025
|
const draftPath = this.draftPath(collection, filename);
|
|
10451
|
-
if (
|
|
11026
|
+
if (existsSync7(draftPath)) {
|
|
10452
11027
|
await unlink(draftPath);
|
|
10453
11028
|
}
|
|
10454
11029
|
}
|
|
10455
11030
|
// ---- Draft helpers ----------------------------------------------------
|
|
10456
11031
|
draftPath(collection, filename) {
|
|
10457
|
-
return
|
|
11032
|
+
return join6(this.cmsDir, collection, `${filename}${DRAFT_FILE_SUFFIX}`);
|
|
10458
11033
|
}
|
|
10459
11034
|
/**
|
|
10460
11035
|
* Get the draft version of an item, or null if no draft file exists.
|
|
@@ -10481,12 +11056,12 @@ var FileSystemCMSProvider = class {
|
|
|
10481
11056
|
*/
|
|
10482
11057
|
async getAllDrafts(collection) {
|
|
10483
11058
|
this.validateCollection(collection);
|
|
10484
|
-
const collectionDir =
|
|
10485
|
-
if (!
|
|
11059
|
+
const collectionDir = join6(this.cmsDir, collection);
|
|
11060
|
+
if (!existsSync7(collectionDir)) return [];
|
|
10486
11061
|
const files = readdirSync4(collectionDir).filter((f) => f.endsWith(DRAFT_FILE_SUFFIX));
|
|
10487
11062
|
const results = await Promise.all(
|
|
10488
11063
|
files.map(async (file) => {
|
|
10489
|
-
const filePath =
|
|
11064
|
+
const filePath = join6(collectionDir, file);
|
|
10490
11065
|
const content = await loadJSONFile2(filePath);
|
|
10491
11066
|
return { file, content };
|
|
10492
11067
|
})
|
|
@@ -10508,7 +11083,7 @@ var FileSystemCMSProvider = class {
|
|
|
10508
11083
|
async hasDraft(collection, filename) {
|
|
10509
11084
|
this.validateCollection(collection);
|
|
10510
11085
|
this.validateFilename(filename);
|
|
10511
|
-
return
|
|
11086
|
+
return existsSync7(this.draftPath(collection, filename));
|
|
10512
11087
|
}
|
|
10513
11088
|
/**
|
|
10514
11089
|
* Save the draft version of an item. Loose validation — drafts may have
|
|
@@ -10542,8 +11117,8 @@ var FileSystemCMSProvider = class {
|
|
|
10542
11117
|
throw new Error("Cannot derive draft filename: item is missing _id, _filename, and a usable slug-field value.");
|
|
10543
11118
|
}
|
|
10544
11119
|
this.validateFilename(filename);
|
|
10545
|
-
const collectionDir =
|
|
10546
|
-
if (!
|
|
11120
|
+
const collectionDir = join6(this.cmsDir, collection);
|
|
11121
|
+
if (!existsSync7(collectionDir)) {
|
|
10547
11122
|
mkdirSync3(collectionDir, { recursive: true });
|
|
10548
11123
|
}
|
|
10549
11124
|
const itemData = stripTransient(item);
|
|
@@ -10563,7 +11138,7 @@ var FileSystemCMSProvider = class {
|
|
|
10563
11138
|
this.validateFilename(filename);
|
|
10564
11139
|
const { unlink } = await import("node:fs/promises");
|
|
10565
11140
|
const filePath = this.draftPath(collection, filename);
|
|
10566
|
-
if (
|
|
11141
|
+
if (existsSync7(filePath)) {
|
|
10567
11142
|
await unlink(filePath);
|
|
10568
11143
|
}
|
|
10569
11144
|
}
|
|
@@ -10591,14 +11166,14 @@ var FileSystemCMSProvider = class {
|
|
|
10591
11166
|
const messages = validation.errors.map((e) => `${e.path}: ${e.message}`).join(", ");
|
|
10592
11167
|
throw new Error(`Cannot publish invalid draft: ${messages}`);
|
|
10593
11168
|
}
|
|
10594
|
-
const collectionDir =
|
|
10595
|
-
if (!
|
|
11169
|
+
const collectionDir = join6(this.cmsDir, collection);
|
|
11170
|
+
if (!existsSync7(collectionDir)) {
|
|
10596
11171
|
mkdirSync3(collectionDir, { recursive: true });
|
|
10597
11172
|
}
|
|
10598
11173
|
const itemData = stripTransient(validation.data);
|
|
10599
|
-
const publishedPath =
|
|
11174
|
+
const publishedPath = join6(collectionDir, `${filename}.json`);
|
|
10600
11175
|
await writeFile3(publishedPath, JSON.stringify(itemData, null, 2), "utf-8");
|
|
10601
|
-
if (
|
|
11176
|
+
if (existsSync7(draftFilePath)) {
|
|
10602
11177
|
await unlink(draftFilePath);
|
|
10603
11178
|
}
|
|
10604
11179
|
return normalizeItem(itemData, filename);
|
|
@@ -10619,18 +11194,18 @@ var FileSystemCMSProvider = class {
|
|
|
10619
11194
|
);
|
|
10620
11195
|
}
|
|
10621
11196
|
const { writeFile: writeFile3, mkdir } = await import("node:fs/promises");
|
|
10622
|
-
if (!
|
|
11197
|
+
if (!existsSync7(this.templatesDir)) {
|
|
10623
11198
|
await mkdir(this.templatesDir, { recursive: true });
|
|
10624
11199
|
}
|
|
10625
|
-
const pageFilePath =
|
|
10626
|
-
if (
|
|
11200
|
+
const pageFilePath = join6(this.templatesDir, `${collectionId}.json`);
|
|
11201
|
+
if (existsSync7(pageFilePath)) {
|
|
10627
11202
|
throw new Error(`Page file already exists: templates/${collectionId}.json`);
|
|
10628
11203
|
}
|
|
10629
11204
|
await writeFile3(pageFilePath, JSON.stringify(pageData, null, 2), "utf-8");
|
|
10630
11205
|
const schemaSource = pageData?.meta?.cms?.source;
|
|
10631
11206
|
if (schemaSource !== "sanity") {
|
|
10632
|
-
const collectionDir =
|
|
10633
|
-
if (!
|
|
11207
|
+
const collectionDir = join6(this.cmsDir, collectionId);
|
|
11208
|
+
if (!existsSync7(collectionDir)) {
|
|
10634
11209
|
await mkdir(collectionDir, { recursive: true });
|
|
10635
11210
|
}
|
|
10636
11211
|
}
|
|
@@ -10647,8 +11222,8 @@ var FileSystemCMSProvider = class {
|
|
|
10647
11222
|
);
|
|
10648
11223
|
}
|
|
10649
11224
|
const { readFile: readFile2, writeFile: writeFile3 } = await import("node:fs/promises");
|
|
10650
|
-
const pageFilePath =
|
|
10651
|
-
if (!
|
|
11225
|
+
const pageFilePath = join6(this.templatesDir, `${collectionId}.json`);
|
|
11226
|
+
if (!existsSync7(pageFilePath)) {
|
|
10652
11227
|
throw new Error(`Collection not found: ${collectionId}`);
|
|
10653
11228
|
}
|
|
10654
11229
|
const content = await readFile2(pageFilePath, "utf-8");
|
|
@@ -10774,8 +11349,8 @@ var DraftPageStore = class {
|
|
|
10774
11349
|
};
|
|
10775
11350
|
|
|
10776
11351
|
// lib/server/fileWatcher.ts
|
|
10777
|
-
import { watch, existsSync as
|
|
10778
|
-
import { basename as basename2, dirname as dirname2, join as
|
|
11352
|
+
import { watch, existsSync as existsSync8, statSync, readdirSync as readdirSync5 } from "node:fs";
|
|
11353
|
+
import { basename as basename2, dirname as dirname2, join as join7, relative } from "node:path";
|
|
10779
11354
|
function watchRecursive(root, listener) {
|
|
10780
11355
|
const nested = [];
|
|
10781
11356
|
const watchedDirs = /* @__PURE__ */ new Set();
|
|
@@ -10791,7 +11366,7 @@ function watchRecursive(root, listener) {
|
|
|
10791
11366
|
attachDir(abs);
|
|
10792
11367
|
try {
|
|
10793
11368
|
for (const e of readdirSync5(abs, { withFileTypes: true })) {
|
|
10794
|
-
const child =
|
|
11369
|
+
const child = join7(abs, e.name);
|
|
10795
11370
|
if (e.isDirectory()) coverNewDir(child);
|
|
10796
11371
|
else listener("rename", relative(root, child));
|
|
10797
11372
|
}
|
|
@@ -10805,7 +11380,7 @@ function watchRecursive(root, listener) {
|
|
|
10805
11380
|
try {
|
|
10806
11381
|
w = watch(absDir, { recursive: true }, (event, filename) => {
|
|
10807
11382
|
if (!filename) return;
|
|
10808
|
-
const abs =
|
|
11383
|
+
const abs = join7(absDir, filename);
|
|
10809
11384
|
listener(event, relative(root, abs));
|
|
10810
11385
|
coverNewDir(abs);
|
|
10811
11386
|
});
|
|
@@ -10831,19 +11406,19 @@ function watchRecursive(root, listener) {
|
|
|
10831
11406
|
return handle;
|
|
10832
11407
|
}
|
|
10833
11408
|
function attachWhenDirExists(dirPath, attach, setWatcher) {
|
|
10834
|
-
if (
|
|
11409
|
+
if (existsSync8(dirPath)) {
|
|
10835
11410
|
setWatcher(attach());
|
|
10836
11411
|
return;
|
|
10837
11412
|
}
|
|
10838
11413
|
const parentDir = dirname2(dirPath);
|
|
10839
11414
|
const targetName = basename2(dirPath);
|
|
10840
|
-
if (!
|
|
11415
|
+
if (!existsSync8(parentDir)) {
|
|
10841
11416
|
return;
|
|
10842
11417
|
}
|
|
10843
11418
|
let parentWatcher = null;
|
|
10844
11419
|
parentWatcher = watch(parentDir, (_event, filename) => {
|
|
10845
11420
|
if (filename !== targetName) return;
|
|
10846
|
-
if (!
|
|
11421
|
+
if (!existsSync8(dirPath)) return;
|
|
10847
11422
|
parentWatcher?.close();
|
|
10848
11423
|
parentWatcher = null;
|
|
10849
11424
|
setWatcher(attach());
|
|
@@ -10873,7 +11448,7 @@ var FileWatcher = class {
|
|
|
10873
11448
|
* Watches both .json and .js files to detect component definition and JavaScript changes
|
|
10874
11449
|
*/
|
|
10875
11450
|
watchComponents(dirPath = projectPaths.components()) {
|
|
10876
|
-
if (!
|
|
11451
|
+
if (!existsSync8(dirPath)) {
|
|
10877
11452
|
return;
|
|
10878
11453
|
}
|
|
10879
11454
|
this.componentsWatcher = watchRecursive(dirPath, async (_event, filename) => {
|
|
@@ -10889,7 +11464,7 @@ var FileWatcher = class {
|
|
|
10889
11464
|
* Start watching pages directory
|
|
10890
11465
|
*/
|
|
10891
11466
|
watchPages(dirPath = projectPaths.pages()) {
|
|
10892
|
-
if (!
|
|
11467
|
+
if (!existsSync8(dirPath)) {
|
|
10893
11468
|
return;
|
|
10894
11469
|
}
|
|
10895
11470
|
this.pagesWatcher = watchRecursive(dirPath, async (_event, filename) => {
|
|
@@ -10929,7 +11504,7 @@ var FileWatcher = class {
|
|
|
10929
11504
|
* Start watching colors.json file
|
|
10930
11505
|
*/
|
|
10931
11506
|
watchColors(filePath = projectPaths.colors()) {
|
|
10932
|
-
if (!
|
|
11507
|
+
if (!existsSync8(filePath)) {
|
|
10933
11508
|
return;
|
|
10934
11509
|
}
|
|
10935
11510
|
const dirPath = getProjectRoot();
|
|
@@ -10986,7 +11561,7 @@ var FileWatcher = class {
|
|
|
10986
11561
|
* Start watching images directory for new source images
|
|
10987
11562
|
*/
|
|
10988
11563
|
watchImages(dirPath = projectPaths.images()) {
|
|
10989
|
-
if (!
|
|
11564
|
+
if (!existsSync8(dirPath)) {
|
|
10990
11565
|
return;
|
|
10991
11566
|
}
|
|
10992
11567
|
this.imagesWatcher = watch(dirPath, { recursive: false }, async (event, filename) => {
|
|
@@ -11013,7 +11588,7 @@ var FileWatcher = class {
|
|
|
11013
11588
|
* Start watching libraries directory for CSS/JS changes
|
|
11014
11589
|
*/
|
|
11015
11590
|
watchLibraries(dirPath = projectPaths.libraries()) {
|
|
11016
|
-
if (!
|
|
11591
|
+
if (!existsSync8(dirPath)) {
|
|
11017
11592
|
return;
|
|
11018
11593
|
}
|
|
11019
11594
|
this.librariesWatcher = watchRecursive(dirPath, async (_event, filename) => {
|
|
@@ -11037,7 +11612,7 @@ var FileWatcher = class {
|
|
|
11037
11612
|
* early-out and the first collection's item edits wouldn't live-reload until a
|
|
11038
11613
|
* dev-server restart.
|
|
11039
11614
|
*/
|
|
11040
|
-
watchAstroPages(dirPath =
|
|
11615
|
+
watchAstroPages(dirPath = join7(getProjectRoot(), "src", "pages")) {
|
|
11041
11616
|
attachWhenDirExists(
|
|
11042
11617
|
dirPath,
|
|
11043
11618
|
() => watchRecursive(dirPath, async (_event, filename) => {
|
|
@@ -11054,7 +11629,7 @@ var FileWatcher = class {
|
|
|
11054
11629
|
}
|
|
11055
11630
|
);
|
|
11056
11631
|
}
|
|
11057
|
-
watchAstroComponents(dirPath =
|
|
11632
|
+
watchAstroComponents(dirPath = join7(getProjectRoot(), "src", "components")) {
|
|
11058
11633
|
attachWhenDirExists(
|
|
11059
11634
|
dirPath,
|
|
11060
11635
|
() => watchRecursive(dirPath, async (_event, filename) => {
|
|
@@ -11067,7 +11642,7 @@ var FileWatcher = class {
|
|
|
11067
11642
|
}
|
|
11068
11643
|
);
|
|
11069
11644
|
}
|
|
11070
|
-
watchAstroContent(dirPath =
|
|
11645
|
+
watchAstroContent(dirPath = join7(getProjectRoot(), "src", "content")) {
|
|
11071
11646
|
attachWhenDirExists(
|
|
11072
11647
|
dirPath,
|
|
11073
11648
|
() => watchRecursive(dirPath, async (_event, filename) => {
|
|
@@ -11270,22 +11845,22 @@ var FileWatcherService = class {
|
|
|
11270
11845
|
};
|
|
11271
11846
|
|
|
11272
11847
|
// lib/server/migrateTemplates.ts
|
|
11273
|
-
import { existsSync as
|
|
11848
|
+
import { existsSync as existsSync9 } from "node:fs";
|
|
11274
11849
|
import { rename } from "node:fs/promises";
|
|
11275
|
-
import { join as
|
|
11850
|
+
import { join as join8 } from "node:path";
|
|
11276
11851
|
async function migrateTemplatesDirectory() {
|
|
11277
|
-
const oldDir =
|
|
11852
|
+
const oldDir = join8(projectPaths.pages(), "templates");
|
|
11278
11853
|
const newDir = projectPaths.templates();
|
|
11279
|
-
if (!
|
|
11280
|
-
if (
|
|
11854
|
+
if (!existsSync9(oldDir)) return;
|
|
11855
|
+
if (existsSync9(newDir)) return;
|
|
11281
11856
|
await rename(oldDir, newDir);
|
|
11282
11857
|
console.log("Migrated CMS templates: pages/templates/ \u2192 templates/");
|
|
11283
11858
|
}
|
|
11284
11859
|
|
|
11285
11860
|
// build-astro.ts
|
|
11286
|
-
import { existsSync as
|
|
11861
|
+
import { existsSync as existsSync10, readdirSync as readdirSync6, mkdirSync as mkdirSync4, rmSync, statSync as statSync2, copyFileSync, writeFileSync } from "node:fs";
|
|
11287
11862
|
import { writeFile as writeFile2, readFile } from "node:fs/promises";
|
|
11288
|
-
import { join as
|
|
11863
|
+
import { join as join9 } from "node:path";
|
|
11289
11864
|
import { createHash } from "node:crypto";
|
|
11290
11865
|
|
|
11291
11866
|
// lib/server/astro/tailwindMapper.ts
|
|
@@ -14138,23 +14713,23 @@ function writePageScript(javascript, scriptsDir) {
|
|
|
14138
14713
|
if (!javascript) return [];
|
|
14139
14714
|
const hash = hashContent3(javascript);
|
|
14140
14715
|
const scriptFile = `${hash}.js`;
|
|
14141
|
-
if (!
|
|
14716
|
+
if (!existsSync10(scriptsDir)) {
|
|
14142
14717
|
mkdirSync4(scriptsDir, { recursive: true });
|
|
14143
14718
|
}
|
|
14144
|
-
const fullScriptPath =
|
|
14145
|
-
if (!
|
|
14719
|
+
const fullScriptPath = join9(scriptsDir, scriptFile);
|
|
14720
|
+
if (!existsSync10(fullScriptPath)) {
|
|
14146
14721
|
writeFileSync(fullScriptPath, javascript, "utf-8");
|
|
14147
14722
|
}
|
|
14148
14723
|
return [`/_scripts/${scriptFile}`];
|
|
14149
14724
|
}
|
|
14150
14725
|
function copyDirectory(src, dest, filter) {
|
|
14151
|
-
if (!
|
|
14152
|
-
if (!
|
|
14726
|
+
if (!existsSync10(src)) return;
|
|
14727
|
+
if (!existsSync10(dest)) mkdirSync4(dest, { recursive: true });
|
|
14153
14728
|
const files = readdirSync6(src);
|
|
14154
14729
|
for (const file of files) {
|
|
14155
14730
|
if (filter && !filter(file)) continue;
|
|
14156
|
-
const srcPath =
|
|
14157
|
-
const destPath =
|
|
14731
|
+
const srcPath = join9(src, file);
|
|
14732
|
+
const destPath = join9(dest, file);
|
|
14158
14733
|
const stat = statSync2(srcPath);
|
|
14159
14734
|
if (stat.isDirectory()) copyDirectory(srcPath, destPath, filter);
|
|
14160
14735
|
else copyFileSync(srcPath, destPath);
|
|
@@ -14171,13 +14746,13 @@ function isCMSPage(pageData) {
|
|
|
14171
14746
|
}
|
|
14172
14747
|
function scanJSONFiles(dir, prefix = "") {
|
|
14173
14748
|
const results = [];
|
|
14174
|
-
if (!
|
|
14749
|
+
if (!existsSync10(dir)) return results;
|
|
14175
14750
|
const entries = readdirSync6(dir, { withFileTypes: true });
|
|
14176
14751
|
for (const entry of entries) {
|
|
14177
14752
|
if (entry.isFile() && entry.name.endsWith(".json")) {
|
|
14178
14753
|
results.push(prefix ? `${prefix}/${entry.name}` : entry.name);
|
|
14179
14754
|
} else if (entry.isDirectory()) {
|
|
14180
|
-
results.push(...scanJSONFiles(
|
|
14755
|
+
results.push(...scanJSONFiles(join9(dir, entry.name), prefix ? `${prefix}/${entry.name}` : entry.name));
|
|
14181
14756
|
}
|
|
14182
14757
|
}
|
|
14183
14758
|
return results;
|
|
@@ -14343,23 +14918,23 @@ async function buildAstroProject(_projectRoot, outputDir) {
|
|
|
14343
14918
|
const globalLibraries = configService.getLibraries();
|
|
14344
14919
|
const componentLibraries = collectComponentLibraries(globalComponents);
|
|
14345
14920
|
const imageMetadataMap = await buildImageMetadataMap();
|
|
14346
|
-
const outDir = outputDir ||
|
|
14347
|
-
if (
|
|
14921
|
+
const outDir = outputDir || join9(projectPaths.project, "astro-export");
|
|
14922
|
+
if (existsSync10(outDir)) {
|
|
14348
14923
|
rmSync(outDir, { recursive: true, force: true });
|
|
14349
14924
|
}
|
|
14350
14925
|
mkdirSync4(outDir, { recursive: true });
|
|
14351
|
-
const srcDir =
|
|
14352
|
-
const pagesOutDir =
|
|
14353
|
-
const layoutsDir =
|
|
14354
|
-
const stylesDir =
|
|
14355
|
-
const componentsOutDir =
|
|
14356
|
-
const publicDir =
|
|
14357
|
-
const scriptsDir =
|
|
14926
|
+
const srcDir = join9(outDir, "src");
|
|
14927
|
+
const pagesOutDir = join9(srcDir, "pages");
|
|
14928
|
+
const layoutsDir = join9(srcDir, "layouts");
|
|
14929
|
+
const stylesDir = join9(srcDir, "styles");
|
|
14930
|
+
const componentsOutDir = join9(srcDir, "components");
|
|
14931
|
+
const publicDir = join9(outDir, "public");
|
|
14932
|
+
const scriptsDir = join9(publicDir, "_scripts");
|
|
14358
14933
|
for (const d of [srcDir, pagesOutDir, layoutsDir, stylesDir, componentsOutDir, publicDir]) {
|
|
14359
14934
|
mkdirSync4(d, { recursive: true });
|
|
14360
14935
|
}
|
|
14361
14936
|
const pagesDir = projectPaths.pages();
|
|
14362
|
-
if (!
|
|
14937
|
+
if (!existsSync10(pagesDir)) {
|
|
14363
14938
|
console.error("Pages directory not found!");
|
|
14364
14939
|
return { pages: 0, cmsPages: 0, collections: 0, errors: 1 };
|
|
14365
14940
|
}
|
|
@@ -14372,7 +14947,7 @@ async function buildAstroProject(_projectRoot, outputDir) {
|
|
|
14372
14947
|
for (const file of pageFiles) {
|
|
14373
14948
|
const pageName = file.replace(".json", "");
|
|
14374
14949
|
const basePath = mapPageNameToPath(pageName);
|
|
14375
|
-
const pageContent = await loadJSONFile(
|
|
14950
|
+
const pageContent = await loadJSONFile(join9(pagesDir, file));
|
|
14376
14951
|
if (!pageContent) continue;
|
|
14377
14952
|
try {
|
|
14378
14953
|
const pageData = parseJSON(pageContent);
|
|
@@ -14431,7 +15006,7 @@ async function buildAstroProject(_projectRoot, outputDir) {
|
|
|
14431
15006
|
for (const file of pageFiles) {
|
|
14432
15007
|
const pageName = file.replace(".json", "");
|
|
14433
15008
|
const basePath = mapPageNameToPath(pageName);
|
|
14434
|
-
const pageContent = await loadJSONFile(
|
|
15009
|
+
const pageContent = await loadJSONFile(join9(pagesDir, file));
|
|
14435
15010
|
if (!pageContent) {
|
|
14436
15011
|
console.warn(` Skipping ${basePath} (empty file)`);
|
|
14437
15012
|
errorCount++;
|
|
@@ -14489,8 +15064,8 @@ async function buildAstroProject(_projectRoot, outputDir) {
|
|
|
14489
15064
|
if (!css.url.startsWith("/")) continue;
|
|
14490
15065
|
const shouldInline = css.inline !== false;
|
|
14491
15066
|
const relPath = css.url.slice(1);
|
|
14492
|
-
const srcPath =
|
|
14493
|
-
if (!
|
|
15067
|
+
const srcPath = join9(projectPaths.project, relPath);
|
|
15068
|
+
if (!existsSync10(srcPath)) continue;
|
|
14494
15069
|
if (shouldInline) {
|
|
14495
15070
|
try {
|
|
14496
15071
|
inlineContents.set(css.url, await readFile(srcPath, "utf-8"));
|
|
@@ -14504,7 +15079,7 @@ async function buildAstroProject(_projectRoot, outputDir) {
|
|
|
14504
15079
|
for (const js of buildLibraries.js || []) {
|
|
14505
15080
|
if (js.url.startsWith("/")) {
|
|
14506
15081
|
const relPath = js.url.slice(1);
|
|
14507
|
-
if (
|
|
15082
|
+
if (existsSync10(join9(projectPaths.project, relPath))) {
|
|
14508
15083
|
localLibsToCopy.push(relPath);
|
|
14509
15084
|
}
|
|
14510
15085
|
}
|
|
@@ -14525,9 +15100,9 @@ async function buildAstroProject(_projectRoot, outputDir) {
|
|
|
14525
15100
|
const cmsConsumerComponents = computeCmsConsumerComponents(globalComponents);
|
|
14526
15101
|
const collectionUrlExpr = /* @__PURE__ */ new Map();
|
|
14527
15102
|
const mergedRichTextFields = /* @__PURE__ */ new Set();
|
|
14528
|
-
if (
|
|
15103
|
+
if (existsSync10(templatesDir)) {
|
|
14529
15104
|
for (const file of readdirSync6(templatesDir).filter((f) => f.endsWith(".json"))) {
|
|
14530
|
-
const tc = await loadJSONFile(
|
|
15105
|
+
const tc = await loadJSONFile(join9(templatesDir, file));
|
|
14531
15106
|
if (!tc) continue;
|
|
14532
15107
|
try {
|
|
14533
15108
|
const pd = parseJSON(tc);
|
|
@@ -14541,10 +15116,10 @@ async function buildAstroProject(_projectRoot, outputDir) {
|
|
|
14541
15116
|
}
|
|
14542
15117
|
}
|
|
14543
15118
|
}
|
|
14544
|
-
if (
|
|
15119
|
+
if (existsSync10(templatesDir)) {
|
|
14545
15120
|
const templateFiles = readdirSync6(templatesDir).filter((f) => f.endsWith(".json"));
|
|
14546
15121
|
for (const file of templateFiles) {
|
|
14547
|
-
const templateContent = await loadJSONFile(
|
|
15122
|
+
const templateContent = await loadJSONFile(join9(templatesDir, file));
|
|
14548
15123
|
if (!templateContent) continue;
|
|
14549
15124
|
try {
|
|
14550
15125
|
const pageData = parseJSON(templateContent);
|
|
@@ -14633,9 +15208,9 @@ async function buildAstroProject(_projectRoot, outputDir) {
|
|
|
14633
15208
|
cmsConsumers: cmsConsumerComponents,
|
|
14634
15209
|
collectionUrlExpr
|
|
14635
15210
|
});
|
|
14636
|
-
const astroFileFull =
|
|
15211
|
+
const astroFileFull = join9(pagesOutDir, astroFilePath);
|
|
14637
15212
|
const astroFileDir = astroFileFull.substring(0, astroFileFull.lastIndexOf("/"));
|
|
14638
|
-
if (!
|
|
15213
|
+
if (!existsSync10(astroFileDir)) {
|
|
14639
15214
|
mkdirSync4(astroFileDir, { recursive: true });
|
|
14640
15215
|
}
|
|
14641
15216
|
await writeFile2(astroFileFull, astroContent, "utf-8");
|
|
@@ -14667,7 +15242,7 @@ async function buildAstroProject(_projectRoot, outputDir) {
|
|
|
14667
15242
|
|
|
14668
15243
|
${safelistDirectives}` : `@import "tailwindcss";`;
|
|
14669
15244
|
const globalCSS = [tailwindDirectives, fontCSS, themeColorCSS, variablesCSS, baseCSS, componentCSSCombined].filter(Boolean).join("\n\n");
|
|
14670
|
-
await writeFile2(
|
|
15245
|
+
await writeFile2(join9(stylesDir, "global.css"), globalCSS, "utf-8");
|
|
14671
15246
|
const escForTemplateLiteral = (s) => s.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$\{/g, "\\${");
|
|
14672
15247
|
const customHeadLiteral = escForTemplateLiteral(customCode.head || "");
|
|
14673
15248
|
const customBodyStartLiteral = escForTemplateLiteral(customCode.bodyStart || "");
|
|
@@ -14714,7 +15289,7 @@ const { title, meta = '', scripts = [], locale = 'en', theme = '${themeConfig.de
|
|
|
14714
15289
|
</body>
|
|
14715
15290
|
</html>
|
|
14716
15291
|
`;
|
|
14717
|
-
await writeFile2(
|
|
15292
|
+
await writeFile2(join9(layoutsDir, "BaseLayout.astro"), baseLayoutContent, "utf-8");
|
|
14718
15293
|
const emittableComponents = normalizeOrphanTemplateProps(globalComponents);
|
|
14719
15294
|
let _componentFileCount = 0;
|
|
14720
15295
|
for (const [compName, compDef] of Object.entries(emittableComponents)) {
|
|
@@ -14733,7 +15308,7 @@ const { title, meta = '', scripts = [], locale = 'en', theme = '${themeConfig.de
|
|
|
14733
15308
|
collectionUrlExpr
|
|
14734
15309
|
}
|
|
14735
15310
|
);
|
|
14736
|
-
await writeFile2(
|
|
15311
|
+
await writeFile2(join9(componentsOutDir, `${compName}.astro`), astroContent, "utf-8");
|
|
14737
15312
|
_componentFileCount++;
|
|
14738
15313
|
} catch (error) {
|
|
14739
15314
|
console.warn(
|
|
@@ -14784,9 +15359,9 @@ const { title, meta = '', scripts = [], locale = 'en', theme = '${themeConfig.de
|
|
|
14784
15359
|
scriptPaths = writePageScript(result.javascript, scriptsDir);
|
|
14785
15360
|
astroContent = buildSSRFallbackPage(result, importPath, fontPreloads, libraryTags, defaultTheme, scriptPaths);
|
|
14786
15361
|
}
|
|
14787
|
-
const astroFileFull =
|
|
15362
|
+
const astroFileFull = join9(pagesOutDir, result.astroFilePath);
|
|
14788
15363
|
const astroFileDir = astroFileFull.substring(0, astroFileFull.lastIndexOf("/"));
|
|
14789
|
-
if (!
|
|
15364
|
+
if (!existsSync10(astroFileDir)) {
|
|
14790
15365
|
mkdirSync4(astroFileDir, { recursive: true });
|
|
14791
15366
|
}
|
|
14792
15367
|
await writeFile2(astroFileFull, astroContent, "utf-8");
|
|
@@ -14807,31 +15382,31 @@ export const GET: APIRoute = () => {
|
|
|
14807
15382
|
});
|
|
14808
15383
|
};
|
|
14809
15384
|
`;
|
|
14810
|
-
await writeFile2(
|
|
15385
|
+
await writeFile2(join9(pagesOutDir, "robots.txt.ts"), robotsTsContent, "utf-8");
|
|
14811
15386
|
let collectionCount = 0;
|
|
14812
15387
|
if (templateSchemas.length > 0) {
|
|
14813
|
-
const contentDir =
|
|
15388
|
+
const contentDir = join9(srcDir, "content");
|
|
14814
15389
|
mkdirSync4(contentDir, { recursive: true });
|
|
14815
15390
|
const collectionDefs = [];
|
|
14816
15391
|
for (const schema of templateSchemas) {
|
|
14817
|
-
const collectionDir =
|
|
15392
|
+
const collectionDir = join9(contentDir, schema.id);
|
|
14818
15393
|
mkdirSync4(collectionDir, { recursive: true });
|
|
14819
15394
|
const richTextFieldNames = Object.entries(schema.fields || {}).filter(([, fd]) => fd.type === "rich-text").map(([fn]) => fn);
|
|
14820
|
-
const cmsItemsDir =
|
|
14821
|
-
if (
|
|
15395
|
+
const cmsItemsDir = join9(projectPaths.cms(), schema.id);
|
|
15396
|
+
if (existsSync10(cmsItemsDir)) {
|
|
14822
15397
|
const isDevBuild = process.env.MENO_DEV_BUILD === "true";
|
|
14823
15398
|
const itemFiles = readdirSync6(cmsItemsDir).filter(
|
|
14824
15399
|
(f) => f.endsWith(".json") && (isDevBuild || !f.endsWith(`${CMS_DRAFT_SUFFIX}.json`))
|
|
14825
15400
|
);
|
|
14826
15401
|
for (const itemFile of itemFiles) {
|
|
14827
15402
|
try {
|
|
14828
|
-
const rawContent = await readFile(
|
|
15403
|
+
const rawContent = await readFile(join9(cmsItemsDir, itemFile), "utf-8");
|
|
14829
15404
|
const item = JSON.parse(rawContent);
|
|
14830
15405
|
const resolved = { ...item };
|
|
14831
15406
|
for (const fieldName of richTextFieldNames) {
|
|
14832
15407
|
resolved[fieldName] = serializeRichTextValue(resolved[fieldName]);
|
|
14833
15408
|
}
|
|
14834
|
-
await writeFile2(
|
|
15409
|
+
await writeFile2(join9(collectionDir, itemFile), JSON.stringify(resolved, null, 2), "utf-8");
|
|
14835
15410
|
} catch (err) {
|
|
14836
15411
|
console.warn(
|
|
14837
15412
|
` Warning: could not process CMS item ${itemFile}: ${err instanceof Error ? err.message : String(err)}`
|
|
@@ -14864,29 +15439,29 @@ ${collectionDefs.join(",\n")}
|
|
|
14864
15439
|
|
|
14865
15440
|
export { collections };
|
|
14866
15441
|
`;
|
|
14867
|
-
await writeFile2(
|
|
15442
|
+
await writeFile2(join9(srcDir, "content.config.ts"), configContent, "utf-8");
|
|
14868
15443
|
}
|
|
14869
|
-
const imagesSrcDir =
|
|
14870
|
-
if (
|
|
14871
|
-
copyDirectory(imagesSrcDir,
|
|
14872
|
-
copyDirectory(imagesSrcDir,
|
|
15444
|
+
const imagesSrcDir = join9(projectPaths.project, "images");
|
|
15445
|
+
if (existsSync10(imagesSrcDir)) {
|
|
15446
|
+
copyDirectory(imagesSrcDir, join9(srcDir, "assets", "images"), shouldCopyImageForAstro);
|
|
15447
|
+
copyDirectory(imagesSrcDir, join9(publicDir, "images"));
|
|
14873
15448
|
}
|
|
14874
15449
|
const publicAssetDirs = ["fonts", "icons", "videos", "assets"];
|
|
14875
15450
|
for (const dir of publicAssetDirs) {
|
|
14876
|
-
const srcAssetDir =
|
|
14877
|
-
if (
|
|
14878
|
-
copyDirectory(srcAssetDir,
|
|
15451
|
+
const srcAssetDir = join9(projectPaths.project, dir);
|
|
15452
|
+
if (existsSync10(srcAssetDir)) {
|
|
15453
|
+
copyDirectory(srcAssetDir, join9(publicDir, dir));
|
|
14879
15454
|
}
|
|
14880
15455
|
}
|
|
14881
|
-
const librariesDir =
|
|
14882
|
-
if (
|
|
14883
|
-
copyDirectory(librariesDir,
|
|
15456
|
+
const librariesDir = join9(projectPaths.project, "libraries");
|
|
15457
|
+
if (existsSync10(librariesDir)) {
|
|
15458
|
+
copyDirectory(librariesDir, join9(publicDir, "libraries"));
|
|
14884
15459
|
}
|
|
14885
15460
|
for (const relPath of localLibsToCopy) {
|
|
14886
|
-
const srcPath =
|
|
14887
|
-
const destPath =
|
|
15461
|
+
const srcPath = join9(projectPaths.project, relPath);
|
|
15462
|
+
const destPath = join9(publicDir, relPath);
|
|
14888
15463
|
const destDir = destPath.substring(0, destPath.lastIndexOf("/"));
|
|
14889
|
-
if (destDir && !
|
|
15464
|
+
if (destDir && !existsSync10(destDir)) mkdirSync4(destDir, { recursive: true });
|
|
14890
15465
|
copyFileSync(srcPath, destPath);
|
|
14891
15466
|
}
|
|
14892
15467
|
const packageJson = {
|
|
@@ -14909,7 +15484,7 @@ export { collections };
|
|
|
14909
15484
|
tailwindcss: "^4.0.0"
|
|
14910
15485
|
}
|
|
14911
15486
|
};
|
|
14912
|
-
await writeFile2(
|
|
15487
|
+
await writeFile2(join9(outDir, "package.json"), JSON.stringify(packageJson, null, 2), "utf-8");
|
|
14913
15488
|
const localeCodes = i18nConfig.locales.map((l) => l.code);
|
|
14914
15489
|
const i18nBlock = i18nConfig.locales.length > 1 ? `
|
|
14915
15490
|
i18n: {
|
|
@@ -14929,11 +15504,11 @@ export default defineConfig({${siteUrl ? `
|
|
|
14929
15504
|
},
|
|
14930
15505
|
});
|
|
14931
15506
|
`;
|
|
14932
|
-
await writeFile2(
|
|
15507
|
+
await writeFile2(join9(outDir, "astro.config.mjs"), astroConfig, "utf-8");
|
|
14933
15508
|
const tsConfig = {
|
|
14934
15509
|
extends: "astro/tsconfigs/strict"
|
|
14935
15510
|
};
|
|
14936
|
-
await writeFile2(
|
|
15511
|
+
await writeFile2(join9(outDir, "tsconfig.json"), JSON.stringify(tsConfig, null, 2), "utf-8");
|
|
14937
15512
|
const baseNetlifyToml = `# Generated by Meno's Astro build.
|
|
14938
15513
|
[build]
|
|
14939
15514
|
command = "npm run build"
|
|
@@ -14943,8 +15518,8 @@ export default defineConfig({${siteUrl ? `
|
|
|
14943
15518
|
NODE_VERSION = "22"
|
|
14944
15519
|
`;
|
|
14945
15520
|
const netlifyToml = syncNetlifyLocale404Block(baseNetlifyToml, i18nConfig, pageFiles.includes("404.json"));
|
|
14946
|
-
await writeFile2(
|
|
14947
|
-
await writeFile2(
|
|
15521
|
+
await writeFile2(join9(outDir, "netlify.toml"), netlifyToml, "utf-8");
|
|
15522
|
+
await writeFile2(join9(outDir, "src", "env.d.ts"), '/// <reference path="../.astro/types.d.ts" />\n', "utf-8");
|
|
14948
15523
|
const totalPages = allResults.length;
|
|
14949
15524
|
return {
|
|
14950
15525
|
pages: totalPages - cmsPageCount,
|
|
@@ -15008,6 +15583,7 @@ export {
|
|
|
15008
15583
|
getModuleDir,
|
|
15009
15584
|
getPackageRoot,
|
|
15010
15585
|
getProjectRoot,
|
|
15586
|
+
groupForSectionLabel,
|
|
15011
15587
|
handleCollectionSchemaRoute,
|
|
15012
15588
|
handleCollectionsRoute,
|
|
15013
15589
|
handleCoreApiRoutes,
|
|
@@ -15016,11 +15592,15 @@ export {
|
|
|
15016
15592
|
handleItemsRoute,
|
|
15017
15593
|
handleRouteError,
|
|
15018
15594
|
hashContent,
|
|
15595
|
+
inferGroup,
|
|
15019
15596
|
inspect,
|
|
15020
15597
|
isBun3 as isBun,
|
|
15598
|
+
isColorValue,
|
|
15599
|
+
isThemeCssProject,
|
|
15021
15600
|
jsonResponse,
|
|
15022
15601
|
lineMapToObject,
|
|
15023
15602
|
loadProjectConfig,
|
|
15603
|
+
loadThemeModel,
|
|
15024
15604
|
logError,
|
|
15025
15605
|
logRequest,
|
|
15026
15606
|
logResponseTime,
|
|
@@ -15030,19 +15610,25 @@ export {
|
|
|
15030
15610
|
needsFormHandler,
|
|
15031
15611
|
needsMenoFilter,
|
|
15032
15612
|
packagePaths,
|
|
15613
|
+
parseThemeCss,
|
|
15033
15614
|
processCMSPropsTemplate,
|
|
15034
15615
|
processCMSTemplate,
|
|
15035
15616
|
projectPaths,
|
|
15036
15617
|
readJsonFile,
|
|
15037
15618
|
readTextFile,
|
|
15619
|
+
regenerateThemeCss,
|
|
15038
15620
|
renderPageSSR,
|
|
15039
15621
|
resetFontConfig,
|
|
15040
15622
|
resolvePackagePath,
|
|
15041
15623
|
resolveProjectPath,
|
|
15624
|
+
saveColors,
|
|
15625
|
+
saveVariables,
|
|
15626
|
+
serializeThemeCss,
|
|
15042
15627
|
serveFile,
|
|
15043
15628
|
setProjectRoot,
|
|
15044
15629
|
spawnProcess,
|
|
15045
15630
|
styleToString,
|
|
15631
|
+
themeCssPath,
|
|
15046
15632
|
validateJS,
|
|
15047
15633
|
variableService,
|
|
15048
15634
|
watchRecursive,
|