meno-core 1.1.1 → 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-QWTQZHG3.js → chunk-FQBIC2OB.js} +1 -1
- package/dist/chunks/chunk-FQBIC2OB.js.map +7 -0
- package/dist/lib/server/index.js +790 -213
- package/dist/lib/server/index.js.map +4 -4
- package/dist/lib/shared/index.js +1 -1
- 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/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/types/colors.ts +6 -2
- package/lib/shared/types/variables.ts +14 -7
- package/package.json +1 -1
- package/dist/chunks/chunk-QWTQZHG3.js.map +0 -7
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";
|
|
@@ -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) {
|
|
@@ -8440,8 +9006,8 @@ ${plainTextErrors}`;
|
|
|
8440
9006
|
}
|
|
8441
9007
|
|
|
8442
9008
|
// lib/server/services/pageService.ts
|
|
8443
|
-
import { existsSync as
|
|
8444
|
-
import { join as
|
|
9009
|
+
import { existsSync as existsSync5, readdirSync as readdirSync2, mkdirSync, rmdirSync } from "node:fs";
|
|
9010
|
+
import { join as join4 } from "node:path";
|
|
8445
9011
|
|
|
8446
9012
|
// lib/server/utils/jsonLineMapper.ts
|
|
8447
9013
|
function buildLineMap(jsonText) {
|
|
@@ -8853,7 +9419,7 @@ var PageService = class {
|
|
|
8853
9419
|
*/
|
|
8854
9420
|
getAllFolders() {
|
|
8855
9421
|
const pagesDir = this.pagesBaseDir();
|
|
8856
|
-
if (!
|
|
9422
|
+
if (!existsSync5(pagesDir)) {
|
|
8857
9423
|
return [];
|
|
8858
9424
|
}
|
|
8859
9425
|
const collectFolders = (dir, prefix) => {
|
|
@@ -8864,7 +9430,7 @@ var PageService = class {
|
|
|
8864
9430
|
if (!entry.isDirectory()) continue;
|
|
8865
9431
|
const relativePath = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
8866
9432
|
result.push(relativePath);
|
|
8867
|
-
result.push(...collectFolders(
|
|
9433
|
+
result.push(...collectFolders(join4(dir, entry.name), relativePath));
|
|
8868
9434
|
}
|
|
8869
9435
|
return result;
|
|
8870
9436
|
} catch {
|
|
@@ -8895,8 +9461,8 @@ var PageService = class {
|
|
|
8895
9461
|
}
|
|
8896
9462
|
}
|
|
8897
9463
|
const pagesDir = this.pagesBaseDir();
|
|
8898
|
-
const folderPath =
|
|
8899
|
-
if (
|
|
9464
|
+
const folderPath = join4(pagesDir, trimmed);
|
|
9465
|
+
if (existsSync5(folderPath)) {
|
|
8900
9466
|
throw new Error("Folder already exists");
|
|
8901
9467
|
}
|
|
8902
9468
|
mkdirSync(folderPath, { recursive: true });
|
|
@@ -8917,18 +9483,18 @@ var PageService = class {
|
|
|
8917
9483
|
const pageName = pagePath === "/" ? "index" : pagePath.substring(1);
|
|
8918
9484
|
const slashIndex = pageName.lastIndexOf("/");
|
|
8919
9485
|
const baseName = slashIndex >= 0 ? pageName.substring(slashIndex + 1) : pageName;
|
|
8920
|
-
const sourceFile =
|
|
8921
|
-
const targetFile = newFolder ?
|
|
9486
|
+
const sourceFile = join4(pagesDir, `${pageName}${ext}`);
|
|
9487
|
+
const targetFile = newFolder ? join4(pagesDir, newFolder, `${baseName}${ext}`) : join4(pagesDir, `${baseName}${ext}`);
|
|
8922
9488
|
if (!isPathWithinRoot(sourceFile, pagesDir) || !isPathWithinRoot(targetFile, pagesDir)) {
|
|
8923
9489
|
throw new Error(`movePage path escapes pages dir: ${pagePath} -> ${newFolder}`);
|
|
8924
9490
|
}
|
|
8925
9491
|
if (newFolder) {
|
|
8926
|
-
const targetDir =
|
|
8927
|
-
if (!
|
|
9492
|
+
const targetDir = join4(pagesDir, newFolder);
|
|
9493
|
+
if (!existsSync5(targetDir)) {
|
|
8928
9494
|
mkdirSync(targetDir, { recursive: true });
|
|
8929
9495
|
}
|
|
8930
9496
|
}
|
|
8931
|
-
if (!
|
|
9497
|
+
if (!existsSync5(sourceFile)) {
|
|
8932
9498
|
throw new Error(`Page not found: ${pagePath}`);
|
|
8933
9499
|
}
|
|
8934
9500
|
await rename2(sourceFile, targetFile);
|
|
@@ -8940,7 +9506,7 @@ var PageService = class {
|
|
|
8940
9506
|
const lineMap = buildLineMap(content);
|
|
8941
9507
|
this.pageCache.set(newPath, content, lineMap);
|
|
8942
9508
|
}
|
|
8943
|
-
const sourceDir = slashIndex >= 0 ?
|
|
9509
|
+
const sourceDir = slashIndex >= 0 ? join4(pagesDir, pageName.substring(0, slashIndex)) : null;
|
|
8944
9510
|
if (sourceDir && sourceDir !== pagesDir) {
|
|
8945
9511
|
try {
|
|
8946
9512
|
const remaining = readdirSync2(sourceDir);
|
|
@@ -8989,12 +9555,12 @@ var PageService = class {
|
|
|
8989
9555
|
const { rename: rename2 } = await import("node:fs/promises");
|
|
8990
9556
|
const pagesDir = this.pagesBaseDir();
|
|
8991
9557
|
const ext = this.pageExt();
|
|
8992
|
-
const sourceFile =
|
|
8993
|
-
const targetFile =
|
|
8994
|
-
if (!
|
|
9558
|
+
const sourceFile = join4(pagesDir, `${oldName}${ext}`);
|
|
9559
|
+
const targetFile = join4(pagesDir, `${newName}${ext}`);
|
|
9560
|
+
if (!existsSync5(sourceFile)) {
|
|
8995
9561
|
throw new Error(`Page not found: ${oldPath}`);
|
|
8996
9562
|
}
|
|
8997
|
-
if (
|
|
9563
|
+
if (existsSync5(targetFile)) {
|
|
8998
9564
|
throw new Error(`Page already exists: ${newPath}`);
|
|
8999
9565
|
}
|
|
9000
9566
|
await rename2(sourceFile, targetFile);
|
|
@@ -9044,8 +9610,8 @@ var PageService = class {
|
|
|
9044
9610
|
};
|
|
9045
9611
|
|
|
9046
9612
|
// lib/server/services/componentService.ts
|
|
9047
|
-
import { join as
|
|
9048
|
-
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";
|
|
9049
9615
|
var ComponentService = class {
|
|
9050
9616
|
components = /* @__PURE__ */ new Map();
|
|
9051
9617
|
componentCategories = /* @__PURE__ */ new Map();
|
|
@@ -9277,7 +9843,7 @@ var ComponentService = class {
|
|
|
9277
9843
|
const componentsDir = this.componentsBaseDir();
|
|
9278
9844
|
if (!isSafePathSegment(name)) throw new Error(`unsafe component name: ${name}`);
|
|
9279
9845
|
const cat = this.resolveComponentCategory(name, category);
|
|
9280
|
-
const dir = cat ?
|
|
9846
|
+
const dir = cat ? join5(componentsDir, cat) : componentsDir;
|
|
9281
9847
|
if (!isPathWithinRoot(dir, componentsDir)) throw new Error(`component category escapes components dir: ${cat}`);
|
|
9282
9848
|
return dir;
|
|
9283
9849
|
}
|
|
@@ -9308,10 +9874,10 @@ var ComponentService = class {
|
|
|
9308
9874
|
*/
|
|
9309
9875
|
findComponentCategoryOnDisk(name) {
|
|
9310
9876
|
const componentsDir = this.componentsBaseDir();
|
|
9311
|
-
if (!
|
|
9877
|
+
if (!existsSync6(componentsDir)) return void 0;
|
|
9312
9878
|
const ext = this.writer ? null : ".json";
|
|
9313
9879
|
const existsAt = (dir) => {
|
|
9314
|
-
if (ext) return
|
|
9880
|
+
if (ext) return existsSync6(join5(dir, `${name}${ext}`));
|
|
9315
9881
|
try {
|
|
9316
9882
|
return readdirSync3(dir, { withFileTypes: true }).some(
|
|
9317
9883
|
(e) => e.isFile() && (e.name === `${name}.json` || e.name === `${name}.astro`)
|
|
@@ -9323,7 +9889,7 @@ var ComponentService = class {
|
|
|
9323
9889
|
if (existsAt(componentsDir)) return void 0;
|
|
9324
9890
|
try {
|
|
9325
9891
|
for (const entry of readdirSync3(componentsDir, { withFileTypes: true })) {
|
|
9326
|
-
if (entry.isDirectory() && existsAt(
|
|
9892
|
+
if (entry.isDirectory() && existsAt(join5(componentsDir, entry.name))) {
|
|
9327
9893
|
return entry.name;
|
|
9328
9894
|
}
|
|
9329
9895
|
}
|
|
@@ -9350,7 +9916,7 @@ var ComponentService = class {
|
|
|
9350
9916
|
*/
|
|
9351
9917
|
async getComponentJavaScript(name) {
|
|
9352
9918
|
const componentDir = this.getComponentDir(name);
|
|
9353
|
-
const jsFilePath =
|
|
9919
|
+
const jsFilePath = join5(componentDir, `${name}.js`);
|
|
9354
9920
|
try {
|
|
9355
9921
|
if (await fileExists(jsFilePath)) {
|
|
9356
9922
|
return await readTextFile(jsFilePath);
|
|
@@ -9398,15 +9964,15 @@ var ComponentService = class {
|
|
|
9398
9964
|
const dataWithJS = javascript !== void 0 ? { ...dataWithoutJS, component: { ...dataWithoutJS.component, javascript } } : dataWithoutJS;
|
|
9399
9965
|
const targetCategory = this.resolveComponentCategory(name, category);
|
|
9400
9966
|
const componentsDir = this.componentsBaseDir();
|
|
9401
|
-
const componentDir = targetCategory ?
|
|
9967
|
+
const componentDir = targetCategory ? join5(componentsDir, targetCategory) : componentsDir;
|
|
9402
9968
|
if (this.writer) {
|
|
9403
9969
|
await this.writer.writeComponent(componentDir, name, dataWithJS);
|
|
9404
9970
|
} else {
|
|
9405
9971
|
const writeFile3 = this.fs ? this.fs.writeFile.bind(this.fs) : (await import("node:fs/promises")).writeFile;
|
|
9406
|
-
if (targetCategory && !
|
|
9972
|
+
if (targetCategory && !existsSync6(componentDir)) {
|
|
9407
9973
|
mkdirSync2(componentDir, { recursive: true });
|
|
9408
9974
|
}
|
|
9409
|
-
const filePath =
|
|
9975
|
+
const filePath = join5(componentDir, `${name}.json`);
|
|
9410
9976
|
await writeFile3(filePath, JSON.stringify(dataWithoutJS, null, 2), "utf-8");
|
|
9411
9977
|
}
|
|
9412
9978
|
this.components.set(name, dataWithJS);
|
|
@@ -9439,9 +10005,9 @@ var ComponentService = class {
|
|
|
9439
10005
|
return;
|
|
9440
10006
|
}
|
|
9441
10007
|
const writeFile3 = this.fs ? this.fs.writeFile.bind(this.fs) : (await import("node:fs/promises")).writeFile;
|
|
9442
|
-
const jsFilePath =
|
|
10008
|
+
const jsFilePath = join5(componentDir, `${name}.js`);
|
|
9443
10009
|
await writeFile3(jsFilePath, javascript || "", "utf-8");
|
|
9444
|
-
const componentPath =
|
|
10010
|
+
const componentPath = join5(componentDir, `${name}.json`);
|
|
9445
10011
|
const componentData = await loadJSONFile(componentPath);
|
|
9446
10012
|
if (componentData) {
|
|
9447
10013
|
const parsed = parseJSON(componentData);
|
|
@@ -9485,9 +10051,9 @@ var ComponentService = class {
|
|
|
9485
10051
|
return;
|
|
9486
10052
|
}
|
|
9487
10053
|
const writeFile3 = this.fs ? this.fs.writeFile.bind(this.fs) : (await import("node:fs/promises")).writeFile;
|
|
9488
|
-
const cssFilePath =
|
|
10054
|
+
const cssFilePath = join5(componentDir, `${name}.css`);
|
|
9489
10055
|
await writeFile3(cssFilePath, css || "", "utf-8");
|
|
9490
|
-
const componentPath =
|
|
10056
|
+
const componentPath = join5(componentDir, `${name}.json`);
|
|
9491
10057
|
const componentData = await loadJSONFile(componentPath);
|
|
9492
10058
|
if (componentData) {
|
|
9493
10059
|
const parsed = parseJSON(componentData);
|
|
@@ -9520,7 +10086,7 @@ var ComponentService = class {
|
|
|
9520
10086
|
*/
|
|
9521
10087
|
getAllFolders() {
|
|
9522
10088
|
const componentsDir = this.componentsBaseDir();
|
|
9523
|
-
if (!
|
|
10089
|
+
if (!existsSync6(componentsDir)) {
|
|
9524
10090
|
return [];
|
|
9525
10091
|
}
|
|
9526
10092
|
try {
|
|
@@ -9555,8 +10121,8 @@ var ComponentService = class {
|
|
|
9555
10121
|
throw new Error("Folder name can only contain lowercase letters, numbers, dashes, and underscores");
|
|
9556
10122
|
}
|
|
9557
10123
|
const componentsDir = this.componentsBaseDir();
|
|
9558
|
-
const folderPath =
|
|
9559
|
-
if (
|
|
10124
|
+
const folderPath = join5(componentsDir, folderName);
|
|
10125
|
+
if (existsSync6(folderPath)) {
|
|
9560
10126
|
throw new Error("Folder already exists");
|
|
9561
10127
|
}
|
|
9562
10128
|
mkdirSync2(folderPath, { recursive: true });
|
|
@@ -9589,20 +10155,20 @@ var ComponentService = class {
|
|
|
9589
10155
|
return;
|
|
9590
10156
|
}
|
|
9591
10157
|
const componentsDir = this.componentsBaseDir();
|
|
9592
|
-
const sourceDir = currentCategory ?
|
|
9593
|
-
const targetDir = targetCategory ?
|
|
10158
|
+
const sourceDir = currentCategory ? join5(componentsDir, currentCategory) : componentsDir;
|
|
10159
|
+
const targetDir = targetCategory ? join5(componentsDir, targetCategory) : componentsDir;
|
|
9594
10160
|
if (this.writer) {
|
|
9595
10161
|
await this.writer.moveComponent(sourceDir, targetDir, name);
|
|
9596
10162
|
} else {
|
|
9597
|
-
if (targetCategory && !
|
|
10163
|
+
if (targetCategory && !existsSync6(targetDir)) {
|
|
9598
10164
|
mkdirSync2(targetDir, { recursive: true });
|
|
9599
10165
|
}
|
|
9600
10166
|
const extensions = [".json", ".js", ".css"];
|
|
9601
10167
|
const { rename: rename2 } = await import("node:fs/promises");
|
|
9602
10168
|
for (const ext of extensions) {
|
|
9603
|
-
const sourcePath =
|
|
9604
|
-
const targetPath =
|
|
9605
|
-
if (
|
|
10169
|
+
const sourcePath = join5(sourceDir, `${name}${ext}`);
|
|
10170
|
+
const targetPath = join5(targetDir, `${name}${ext}`);
|
|
10171
|
+
if (existsSync6(sourcePath)) {
|
|
9606
10172
|
await rename2(sourcePath, targetPath);
|
|
9607
10173
|
}
|
|
9608
10174
|
}
|
|
@@ -9657,7 +10223,7 @@ var ComponentService = class {
|
|
|
9657
10223
|
}
|
|
9658
10224
|
const category = this.componentCategories.get(oldName);
|
|
9659
10225
|
const componentsDir = this.componentsBaseDir();
|
|
9660
|
-
const dir = category ?
|
|
10226
|
+
const dir = category ? join5(componentsDir, category) : componentsDir;
|
|
9661
10227
|
if (this.writer) {
|
|
9662
10228
|
if (await this.writer.componentExists(dir, trimmedNew)) {
|
|
9663
10229
|
throw new Error(`Component "${trimmedNew}" already exists in components/${category ?? ""}`);
|
|
@@ -9665,15 +10231,15 @@ var ComponentService = class {
|
|
|
9665
10231
|
await this.writer.moveComponent(dir, dir, oldName, trimmedNew);
|
|
9666
10232
|
} else {
|
|
9667
10233
|
for (const ext of [".json", ".js", ".css"]) {
|
|
9668
|
-
if (
|
|
10234
|
+
if (existsSync6(join5(dir, `${trimmedNew}${ext}`))) {
|
|
9669
10235
|
throw new Error(`File "${trimmedNew}${ext}" already exists in components/${category ?? ""}`);
|
|
9670
10236
|
}
|
|
9671
10237
|
}
|
|
9672
10238
|
const { rename: rename2 } = await import("node:fs/promises");
|
|
9673
10239
|
for (const ext of [".json", ".js", ".css"]) {
|
|
9674
|
-
const src =
|
|
9675
|
-
const dst =
|
|
9676
|
-
if (
|
|
10240
|
+
const src = join5(dir, `${oldName}${ext}`);
|
|
10241
|
+
const dst = join5(dir, `${trimmedNew}${ext}`);
|
|
10242
|
+
if (existsSync6(src)) {
|
|
9677
10243
|
await rename2(src, dst);
|
|
9678
10244
|
}
|
|
9679
10245
|
}
|
|
@@ -9691,7 +10257,7 @@ var ComponentService = class {
|
|
|
9691
10257
|
if (!structure) continue;
|
|
9692
10258
|
if (rewriteComponentRefs(structure, oldName, trimmedNew)) {
|
|
9693
10259
|
const otherCategory = this.componentCategories.get(name);
|
|
9694
|
-
const otherDir = otherCategory ?
|
|
10260
|
+
const otherDir = otherCategory ? join5(componentsDir, otherCategory) : componentsDir;
|
|
9695
10261
|
const persisted = JSON.parse(JSON.stringify(otherDef));
|
|
9696
10262
|
if (persisted?.component?.javascript !== void 0) {
|
|
9697
10263
|
delete persisted.component.javascript;
|
|
@@ -9699,7 +10265,7 @@ var ComponentService = class {
|
|
|
9699
10265
|
if (this.writer) {
|
|
9700
10266
|
await this.writer.writeComponent(otherDir, name, persisted);
|
|
9701
10267
|
} else {
|
|
9702
|
-
await writeFile3(
|
|
10268
|
+
await writeFile3(join5(otherDir, `${name}.json`), JSON.stringify(persisted, null, 2), "utf-8");
|
|
9703
10269
|
}
|
|
9704
10270
|
componentRefs++;
|
|
9705
10271
|
}
|
|
@@ -10239,9 +10805,9 @@ var CMSService = class {
|
|
|
10239
10805
|
};
|
|
10240
10806
|
|
|
10241
10807
|
// lib/server/providers/fileSystemCMSProvider.ts
|
|
10242
|
-
import { existsSync as
|
|
10243
|
-
import { join as
|
|
10244
|
-
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");
|
|
10245
10811
|
var DRAFT_FILE_SUFFIX = `${CMS_DRAFT_SUFFIX}.json`;
|
|
10246
10812
|
async function loadJSONFile2(filePath) {
|
|
10247
10813
|
try {
|
|
@@ -10250,7 +10816,7 @@ async function loadJSONFile2(filePath) {
|
|
|
10250
10816
|
}
|
|
10251
10817
|
return null;
|
|
10252
10818
|
} catch (error) {
|
|
10253
|
-
|
|
10819
|
+
log6.warn(`Failed to parse JSON at ${filePath}:`, error instanceof Error ? error.message : error);
|
|
10254
10820
|
return null;
|
|
10255
10821
|
}
|
|
10256
10822
|
}
|
|
@@ -10312,14 +10878,14 @@ var FileSystemCMSProvider = class {
|
|
|
10312
10878
|
return this.schemaCache;
|
|
10313
10879
|
}
|
|
10314
10880
|
const schemas = /* @__PURE__ */ new Map();
|
|
10315
|
-
if (!
|
|
10881
|
+
if (!existsSync7(this.templatesDir)) {
|
|
10316
10882
|
return schemas;
|
|
10317
10883
|
}
|
|
10318
10884
|
const files = readdirSync4(this.templatesDir);
|
|
10319
10885
|
const jsonFiles = files.filter((f) => f.endsWith(".json"));
|
|
10320
10886
|
const results = await Promise.all(
|
|
10321
10887
|
jsonFiles.map(async (file) => {
|
|
10322
|
-
const filePath =
|
|
10888
|
+
const filePath = join6(this.templatesDir, file);
|
|
10323
10889
|
const content = await loadJSONFile2(filePath);
|
|
10324
10890
|
return { filePath, content };
|
|
10325
10891
|
})
|
|
@@ -10344,15 +10910,15 @@ var FileSystemCMSProvider = class {
|
|
|
10344
10910
|
*/
|
|
10345
10911
|
async getItems(collection) {
|
|
10346
10912
|
this.validateCollection(collection);
|
|
10347
|
-
const collectionDir =
|
|
10348
|
-
if (!
|
|
10913
|
+
const collectionDir = join6(this.cmsDir, collection);
|
|
10914
|
+
if (!existsSync7(collectionDir)) {
|
|
10349
10915
|
return [];
|
|
10350
10916
|
}
|
|
10351
10917
|
const files = readdirSync4(collectionDir);
|
|
10352
10918
|
const jsonFiles = files.filter((f) => f.endsWith(".json") && !f.endsWith(DRAFT_FILE_SUFFIX));
|
|
10353
10919
|
const results = await Promise.all(
|
|
10354
10920
|
jsonFiles.map(async (file) => {
|
|
10355
|
-
const filePath =
|
|
10921
|
+
const filePath = join6(collectionDir, file);
|
|
10356
10922
|
const content = await loadJSONFile2(filePath);
|
|
10357
10923
|
return { file, filePath, content };
|
|
10358
10924
|
})
|
|
@@ -10366,7 +10932,7 @@ var FileSystemCMSProvider = class {
|
|
|
10366
10932
|
if (validation.valid) {
|
|
10367
10933
|
items.push(validation.data);
|
|
10368
10934
|
} else {
|
|
10369
|
-
|
|
10935
|
+
log6.warn(`Invalid CMS item at ${filePath}:`, validation.errors);
|
|
10370
10936
|
}
|
|
10371
10937
|
}
|
|
10372
10938
|
}
|
|
@@ -10385,7 +10951,7 @@ var FileSystemCMSProvider = class {
|
|
|
10385
10951
|
async getItemByFilename(collection, filename) {
|
|
10386
10952
|
this.validateCollection(collection);
|
|
10387
10953
|
this.validateFilename(filename);
|
|
10388
|
-
const filePath =
|
|
10954
|
+
const filePath = join6(this.cmsDir, collection, `${filename}.json`);
|
|
10389
10955
|
const content = await loadJSONFile2(filePath);
|
|
10390
10956
|
if (!content || typeof content !== "object") {
|
|
10391
10957
|
return null;
|
|
@@ -10395,7 +10961,7 @@ var FileSystemCMSProvider = class {
|
|
|
10395
10961
|
if (validation.valid) {
|
|
10396
10962
|
return validation.data;
|
|
10397
10963
|
}
|
|
10398
|
-
|
|
10964
|
+
log6.warn(`Invalid CMS item at ${filePath}:`, validation.errors);
|
|
10399
10965
|
return null;
|
|
10400
10966
|
}
|
|
10401
10967
|
/**
|
|
@@ -10437,12 +11003,12 @@ var FileSystemCMSProvider = class {
|
|
|
10437
11003
|
throw new Error("Cannot derive filename: item is missing _id, _filename, and a usable slug-field value.");
|
|
10438
11004
|
}
|
|
10439
11005
|
this.validateFilename(filename);
|
|
10440
|
-
const collectionDir =
|
|
10441
|
-
if (!
|
|
11006
|
+
const collectionDir = join6(this.cmsDir, collection);
|
|
11007
|
+
if (!existsSync7(collectionDir)) {
|
|
10442
11008
|
mkdirSync3(collectionDir, { recursive: true });
|
|
10443
11009
|
}
|
|
10444
11010
|
const itemData = stripTransient(item);
|
|
10445
|
-
const filePath =
|
|
11011
|
+
const filePath = join6(collectionDir, `${filename}.json`);
|
|
10446
11012
|
await writeFile3(filePath, JSON.stringify(itemData, null, 2), "utf-8");
|
|
10447
11013
|
}
|
|
10448
11014
|
/**
|
|
@@ -10452,18 +11018,18 @@ var FileSystemCMSProvider = class {
|
|
|
10452
11018
|
this.validateCollection(collection);
|
|
10453
11019
|
this.validateFilename(filename);
|
|
10454
11020
|
const { unlink } = await import("node:fs/promises");
|
|
10455
|
-
const publishedPath =
|
|
10456
|
-
if (
|
|
11021
|
+
const publishedPath = join6(this.cmsDir, collection, `${filename}.json`);
|
|
11022
|
+
if (existsSync7(publishedPath)) {
|
|
10457
11023
|
await unlink(publishedPath);
|
|
10458
11024
|
}
|
|
10459
11025
|
const draftPath = this.draftPath(collection, filename);
|
|
10460
|
-
if (
|
|
11026
|
+
if (existsSync7(draftPath)) {
|
|
10461
11027
|
await unlink(draftPath);
|
|
10462
11028
|
}
|
|
10463
11029
|
}
|
|
10464
11030
|
// ---- Draft helpers ----------------------------------------------------
|
|
10465
11031
|
draftPath(collection, filename) {
|
|
10466
|
-
return
|
|
11032
|
+
return join6(this.cmsDir, collection, `${filename}${DRAFT_FILE_SUFFIX}`);
|
|
10467
11033
|
}
|
|
10468
11034
|
/**
|
|
10469
11035
|
* Get the draft version of an item, or null if no draft file exists.
|
|
@@ -10490,12 +11056,12 @@ var FileSystemCMSProvider = class {
|
|
|
10490
11056
|
*/
|
|
10491
11057
|
async getAllDrafts(collection) {
|
|
10492
11058
|
this.validateCollection(collection);
|
|
10493
|
-
const collectionDir =
|
|
10494
|
-
if (!
|
|
11059
|
+
const collectionDir = join6(this.cmsDir, collection);
|
|
11060
|
+
if (!existsSync7(collectionDir)) return [];
|
|
10495
11061
|
const files = readdirSync4(collectionDir).filter((f) => f.endsWith(DRAFT_FILE_SUFFIX));
|
|
10496
11062
|
const results = await Promise.all(
|
|
10497
11063
|
files.map(async (file) => {
|
|
10498
|
-
const filePath =
|
|
11064
|
+
const filePath = join6(collectionDir, file);
|
|
10499
11065
|
const content = await loadJSONFile2(filePath);
|
|
10500
11066
|
return { file, content };
|
|
10501
11067
|
})
|
|
@@ -10517,7 +11083,7 @@ var FileSystemCMSProvider = class {
|
|
|
10517
11083
|
async hasDraft(collection, filename) {
|
|
10518
11084
|
this.validateCollection(collection);
|
|
10519
11085
|
this.validateFilename(filename);
|
|
10520
|
-
return
|
|
11086
|
+
return existsSync7(this.draftPath(collection, filename));
|
|
10521
11087
|
}
|
|
10522
11088
|
/**
|
|
10523
11089
|
* Save the draft version of an item. Loose validation — drafts may have
|
|
@@ -10551,8 +11117,8 @@ var FileSystemCMSProvider = class {
|
|
|
10551
11117
|
throw new Error("Cannot derive draft filename: item is missing _id, _filename, and a usable slug-field value.");
|
|
10552
11118
|
}
|
|
10553
11119
|
this.validateFilename(filename);
|
|
10554
|
-
const collectionDir =
|
|
10555
|
-
if (!
|
|
11120
|
+
const collectionDir = join6(this.cmsDir, collection);
|
|
11121
|
+
if (!existsSync7(collectionDir)) {
|
|
10556
11122
|
mkdirSync3(collectionDir, { recursive: true });
|
|
10557
11123
|
}
|
|
10558
11124
|
const itemData = stripTransient(item);
|
|
@@ -10572,7 +11138,7 @@ var FileSystemCMSProvider = class {
|
|
|
10572
11138
|
this.validateFilename(filename);
|
|
10573
11139
|
const { unlink } = await import("node:fs/promises");
|
|
10574
11140
|
const filePath = this.draftPath(collection, filename);
|
|
10575
|
-
if (
|
|
11141
|
+
if (existsSync7(filePath)) {
|
|
10576
11142
|
await unlink(filePath);
|
|
10577
11143
|
}
|
|
10578
11144
|
}
|
|
@@ -10600,14 +11166,14 @@ var FileSystemCMSProvider = class {
|
|
|
10600
11166
|
const messages = validation.errors.map((e) => `${e.path}: ${e.message}`).join(", ");
|
|
10601
11167
|
throw new Error(`Cannot publish invalid draft: ${messages}`);
|
|
10602
11168
|
}
|
|
10603
|
-
const collectionDir =
|
|
10604
|
-
if (!
|
|
11169
|
+
const collectionDir = join6(this.cmsDir, collection);
|
|
11170
|
+
if (!existsSync7(collectionDir)) {
|
|
10605
11171
|
mkdirSync3(collectionDir, { recursive: true });
|
|
10606
11172
|
}
|
|
10607
11173
|
const itemData = stripTransient(validation.data);
|
|
10608
|
-
const publishedPath =
|
|
11174
|
+
const publishedPath = join6(collectionDir, `${filename}.json`);
|
|
10609
11175
|
await writeFile3(publishedPath, JSON.stringify(itemData, null, 2), "utf-8");
|
|
10610
|
-
if (
|
|
11176
|
+
if (existsSync7(draftFilePath)) {
|
|
10611
11177
|
await unlink(draftFilePath);
|
|
10612
11178
|
}
|
|
10613
11179
|
return normalizeItem(itemData, filename);
|
|
@@ -10628,18 +11194,18 @@ var FileSystemCMSProvider = class {
|
|
|
10628
11194
|
);
|
|
10629
11195
|
}
|
|
10630
11196
|
const { writeFile: writeFile3, mkdir } = await import("node:fs/promises");
|
|
10631
|
-
if (!
|
|
11197
|
+
if (!existsSync7(this.templatesDir)) {
|
|
10632
11198
|
await mkdir(this.templatesDir, { recursive: true });
|
|
10633
11199
|
}
|
|
10634
|
-
const pageFilePath =
|
|
10635
|
-
if (
|
|
11200
|
+
const pageFilePath = join6(this.templatesDir, `${collectionId}.json`);
|
|
11201
|
+
if (existsSync7(pageFilePath)) {
|
|
10636
11202
|
throw new Error(`Page file already exists: templates/${collectionId}.json`);
|
|
10637
11203
|
}
|
|
10638
11204
|
await writeFile3(pageFilePath, JSON.stringify(pageData, null, 2), "utf-8");
|
|
10639
11205
|
const schemaSource = pageData?.meta?.cms?.source;
|
|
10640
11206
|
if (schemaSource !== "sanity") {
|
|
10641
|
-
const collectionDir =
|
|
10642
|
-
if (!
|
|
11207
|
+
const collectionDir = join6(this.cmsDir, collectionId);
|
|
11208
|
+
if (!existsSync7(collectionDir)) {
|
|
10643
11209
|
await mkdir(collectionDir, { recursive: true });
|
|
10644
11210
|
}
|
|
10645
11211
|
}
|
|
@@ -10656,8 +11222,8 @@ var FileSystemCMSProvider = class {
|
|
|
10656
11222
|
);
|
|
10657
11223
|
}
|
|
10658
11224
|
const { readFile: readFile2, writeFile: writeFile3 } = await import("node:fs/promises");
|
|
10659
|
-
const pageFilePath =
|
|
10660
|
-
if (!
|
|
11225
|
+
const pageFilePath = join6(this.templatesDir, `${collectionId}.json`);
|
|
11226
|
+
if (!existsSync7(pageFilePath)) {
|
|
10661
11227
|
throw new Error(`Collection not found: ${collectionId}`);
|
|
10662
11228
|
}
|
|
10663
11229
|
const content = await readFile2(pageFilePath, "utf-8");
|
|
@@ -10783,8 +11349,8 @@ var DraftPageStore = class {
|
|
|
10783
11349
|
};
|
|
10784
11350
|
|
|
10785
11351
|
// lib/server/fileWatcher.ts
|
|
10786
|
-
import { watch, existsSync as
|
|
10787
|
-
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";
|
|
10788
11354
|
function watchRecursive(root, listener) {
|
|
10789
11355
|
const nested = [];
|
|
10790
11356
|
const watchedDirs = /* @__PURE__ */ new Set();
|
|
@@ -10800,7 +11366,7 @@ function watchRecursive(root, listener) {
|
|
|
10800
11366
|
attachDir(abs);
|
|
10801
11367
|
try {
|
|
10802
11368
|
for (const e of readdirSync5(abs, { withFileTypes: true })) {
|
|
10803
|
-
const child =
|
|
11369
|
+
const child = join7(abs, e.name);
|
|
10804
11370
|
if (e.isDirectory()) coverNewDir(child);
|
|
10805
11371
|
else listener("rename", relative(root, child));
|
|
10806
11372
|
}
|
|
@@ -10814,7 +11380,7 @@ function watchRecursive(root, listener) {
|
|
|
10814
11380
|
try {
|
|
10815
11381
|
w = watch(absDir, { recursive: true }, (event, filename) => {
|
|
10816
11382
|
if (!filename) return;
|
|
10817
|
-
const abs =
|
|
11383
|
+
const abs = join7(absDir, filename);
|
|
10818
11384
|
listener(event, relative(root, abs));
|
|
10819
11385
|
coverNewDir(abs);
|
|
10820
11386
|
});
|
|
@@ -10840,19 +11406,19 @@ function watchRecursive(root, listener) {
|
|
|
10840
11406
|
return handle;
|
|
10841
11407
|
}
|
|
10842
11408
|
function attachWhenDirExists(dirPath, attach, setWatcher) {
|
|
10843
|
-
if (
|
|
11409
|
+
if (existsSync8(dirPath)) {
|
|
10844
11410
|
setWatcher(attach());
|
|
10845
11411
|
return;
|
|
10846
11412
|
}
|
|
10847
11413
|
const parentDir = dirname2(dirPath);
|
|
10848
11414
|
const targetName = basename2(dirPath);
|
|
10849
|
-
if (!
|
|
11415
|
+
if (!existsSync8(parentDir)) {
|
|
10850
11416
|
return;
|
|
10851
11417
|
}
|
|
10852
11418
|
let parentWatcher = null;
|
|
10853
11419
|
parentWatcher = watch(parentDir, (_event, filename) => {
|
|
10854
11420
|
if (filename !== targetName) return;
|
|
10855
|
-
if (!
|
|
11421
|
+
if (!existsSync8(dirPath)) return;
|
|
10856
11422
|
parentWatcher?.close();
|
|
10857
11423
|
parentWatcher = null;
|
|
10858
11424
|
setWatcher(attach());
|
|
@@ -10882,7 +11448,7 @@ var FileWatcher = class {
|
|
|
10882
11448
|
* Watches both .json and .js files to detect component definition and JavaScript changes
|
|
10883
11449
|
*/
|
|
10884
11450
|
watchComponents(dirPath = projectPaths.components()) {
|
|
10885
|
-
if (!
|
|
11451
|
+
if (!existsSync8(dirPath)) {
|
|
10886
11452
|
return;
|
|
10887
11453
|
}
|
|
10888
11454
|
this.componentsWatcher = watchRecursive(dirPath, async (_event, filename) => {
|
|
@@ -10898,7 +11464,7 @@ var FileWatcher = class {
|
|
|
10898
11464
|
* Start watching pages directory
|
|
10899
11465
|
*/
|
|
10900
11466
|
watchPages(dirPath = projectPaths.pages()) {
|
|
10901
|
-
if (!
|
|
11467
|
+
if (!existsSync8(dirPath)) {
|
|
10902
11468
|
return;
|
|
10903
11469
|
}
|
|
10904
11470
|
this.pagesWatcher = watchRecursive(dirPath, async (_event, filename) => {
|
|
@@ -10938,7 +11504,7 @@ var FileWatcher = class {
|
|
|
10938
11504
|
* Start watching colors.json file
|
|
10939
11505
|
*/
|
|
10940
11506
|
watchColors(filePath = projectPaths.colors()) {
|
|
10941
|
-
if (!
|
|
11507
|
+
if (!existsSync8(filePath)) {
|
|
10942
11508
|
return;
|
|
10943
11509
|
}
|
|
10944
11510
|
const dirPath = getProjectRoot();
|
|
@@ -10995,7 +11561,7 @@ var FileWatcher = class {
|
|
|
10995
11561
|
* Start watching images directory for new source images
|
|
10996
11562
|
*/
|
|
10997
11563
|
watchImages(dirPath = projectPaths.images()) {
|
|
10998
|
-
if (!
|
|
11564
|
+
if (!existsSync8(dirPath)) {
|
|
10999
11565
|
return;
|
|
11000
11566
|
}
|
|
11001
11567
|
this.imagesWatcher = watch(dirPath, { recursive: false }, async (event, filename) => {
|
|
@@ -11022,7 +11588,7 @@ var FileWatcher = class {
|
|
|
11022
11588
|
* Start watching libraries directory for CSS/JS changes
|
|
11023
11589
|
*/
|
|
11024
11590
|
watchLibraries(dirPath = projectPaths.libraries()) {
|
|
11025
|
-
if (!
|
|
11591
|
+
if (!existsSync8(dirPath)) {
|
|
11026
11592
|
return;
|
|
11027
11593
|
}
|
|
11028
11594
|
this.librariesWatcher = watchRecursive(dirPath, async (_event, filename) => {
|
|
@@ -11046,7 +11612,7 @@ var FileWatcher = class {
|
|
|
11046
11612
|
* early-out and the first collection's item edits wouldn't live-reload until a
|
|
11047
11613
|
* dev-server restart.
|
|
11048
11614
|
*/
|
|
11049
|
-
watchAstroPages(dirPath =
|
|
11615
|
+
watchAstroPages(dirPath = join7(getProjectRoot(), "src", "pages")) {
|
|
11050
11616
|
attachWhenDirExists(
|
|
11051
11617
|
dirPath,
|
|
11052
11618
|
() => watchRecursive(dirPath, async (_event, filename) => {
|
|
@@ -11063,7 +11629,7 @@ var FileWatcher = class {
|
|
|
11063
11629
|
}
|
|
11064
11630
|
);
|
|
11065
11631
|
}
|
|
11066
|
-
watchAstroComponents(dirPath =
|
|
11632
|
+
watchAstroComponents(dirPath = join7(getProjectRoot(), "src", "components")) {
|
|
11067
11633
|
attachWhenDirExists(
|
|
11068
11634
|
dirPath,
|
|
11069
11635
|
() => watchRecursive(dirPath, async (_event, filename) => {
|
|
@@ -11076,7 +11642,7 @@ var FileWatcher = class {
|
|
|
11076
11642
|
}
|
|
11077
11643
|
);
|
|
11078
11644
|
}
|
|
11079
|
-
watchAstroContent(dirPath =
|
|
11645
|
+
watchAstroContent(dirPath = join7(getProjectRoot(), "src", "content")) {
|
|
11080
11646
|
attachWhenDirExists(
|
|
11081
11647
|
dirPath,
|
|
11082
11648
|
() => watchRecursive(dirPath, async (_event, filename) => {
|
|
@@ -11279,22 +11845,22 @@ var FileWatcherService = class {
|
|
|
11279
11845
|
};
|
|
11280
11846
|
|
|
11281
11847
|
// lib/server/migrateTemplates.ts
|
|
11282
|
-
import { existsSync as
|
|
11848
|
+
import { existsSync as existsSync9 } from "node:fs";
|
|
11283
11849
|
import { rename } from "node:fs/promises";
|
|
11284
|
-
import { join as
|
|
11850
|
+
import { join as join8 } from "node:path";
|
|
11285
11851
|
async function migrateTemplatesDirectory() {
|
|
11286
|
-
const oldDir =
|
|
11852
|
+
const oldDir = join8(projectPaths.pages(), "templates");
|
|
11287
11853
|
const newDir = projectPaths.templates();
|
|
11288
|
-
if (!
|
|
11289
|
-
if (
|
|
11854
|
+
if (!existsSync9(oldDir)) return;
|
|
11855
|
+
if (existsSync9(newDir)) return;
|
|
11290
11856
|
await rename(oldDir, newDir);
|
|
11291
11857
|
console.log("Migrated CMS templates: pages/templates/ \u2192 templates/");
|
|
11292
11858
|
}
|
|
11293
11859
|
|
|
11294
11860
|
// build-astro.ts
|
|
11295
|
-
import { existsSync as
|
|
11861
|
+
import { existsSync as existsSync10, readdirSync as readdirSync6, mkdirSync as mkdirSync4, rmSync, statSync as statSync2, copyFileSync, writeFileSync } from "node:fs";
|
|
11296
11862
|
import { writeFile as writeFile2, readFile } from "node:fs/promises";
|
|
11297
|
-
import { join as
|
|
11863
|
+
import { join as join9 } from "node:path";
|
|
11298
11864
|
import { createHash } from "node:crypto";
|
|
11299
11865
|
|
|
11300
11866
|
// lib/server/astro/tailwindMapper.ts
|
|
@@ -14147,23 +14713,23 @@ function writePageScript(javascript, scriptsDir) {
|
|
|
14147
14713
|
if (!javascript) return [];
|
|
14148
14714
|
const hash = hashContent3(javascript);
|
|
14149
14715
|
const scriptFile = `${hash}.js`;
|
|
14150
|
-
if (!
|
|
14716
|
+
if (!existsSync10(scriptsDir)) {
|
|
14151
14717
|
mkdirSync4(scriptsDir, { recursive: true });
|
|
14152
14718
|
}
|
|
14153
|
-
const fullScriptPath =
|
|
14154
|
-
if (!
|
|
14719
|
+
const fullScriptPath = join9(scriptsDir, scriptFile);
|
|
14720
|
+
if (!existsSync10(fullScriptPath)) {
|
|
14155
14721
|
writeFileSync(fullScriptPath, javascript, "utf-8");
|
|
14156
14722
|
}
|
|
14157
14723
|
return [`/_scripts/${scriptFile}`];
|
|
14158
14724
|
}
|
|
14159
14725
|
function copyDirectory(src, dest, filter) {
|
|
14160
|
-
if (!
|
|
14161
|
-
if (!
|
|
14726
|
+
if (!existsSync10(src)) return;
|
|
14727
|
+
if (!existsSync10(dest)) mkdirSync4(dest, { recursive: true });
|
|
14162
14728
|
const files = readdirSync6(src);
|
|
14163
14729
|
for (const file of files) {
|
|
14164
14730
|
if (filter && !filter(file)) continue;
|
|
14165
|
-
const srcPath =
|
|
14166
|
-
const destPath =
|
|
14731
|
+
const srcPath = join9(src, file);
|
|
14732
|
+
const destPath = join9(dest, file);
|
|
14167
14733
|
const stat = statSync2(srcPath);
|
|
14168
14734
|
if (stat.isDirectory()) copyDirectory(srcPath, destPath, filter);
|
|
14169
14735
|
else copyFileSync(srcPath, destPath);
|
|
@@ -14180,13 +14746,13 @@ function isCMSPage(pageData) {
|
|
|
14180
14746
|
}
|
|
14181
14747
|
function scanJSONFiles(dir, prefix = "") {
|
|
14182
14748
|
const results = [];
|
|
14183
|
-
if (!
|
|
14749
|
+
if (!existsSync10(dir)) return results;
|
|
14184
14750
|
const entries = readdirSync6(dir, { withFileTypes: true });
|
|
14185
14751
|
for (const entry of entries) {
|
|
14186
14752
|
if (entry.isFile() && entry.name.endsWith(".json")) {
|
|
14187
14753
|
results.push(prefix ? `${prefix}/${entry.name}` : entry.name);
|
|
14188
14754
|
} else if (entry.isDirectory()) {
|
|
14189
|
-
results.push(...scanJSONFiles(
|
|
14755
|
+
results.push(...scanJSONFiles(join9(dir, entry.name), prefix ? `${prefix}/${entry.name}` : entry.name));
|
|
14190
14756
|
}
|
|
14191
14757
|
}
|
|
14192
14758
|
return results;
|
|
@@ -14352,23 +14918,23 @@ async function buildAstroProject(_projectRoot, outputDir) {
|
|
|
14352
14918
|
const globalLibraries = configService.getLibraries();
|
|
14353
14919
|
const componentLibraries = collectComponentLibraries(globalComponents);
|
|
14354
14920
|
const imageMetadataMap = await buildImageMetadataMap();
|
|
14355
|
-
const outDir = outputDir ||
|
|
14356
|
-
if (
|
|
14921
|
+
const outDir = outputDir || join9(projectPaths.project, "astro-export");
|
|
14922
|
+
if (existsSync10(outDir)) {
|
|
14357
14923
|
rmSync(outDir, { recursive: true, force: true });
|
|
14358
14924
|
}
|
|
14359
14925
|
mkdirSync4(outDir, { recursive: true });
|
|
14360
|
-
const srcDir =
|
|
14361
|
-
const pagesOutDir =
|
|
14362
|
-
const layoutsDir =
|
|
14363
|
-
const stylesDir =
|
|
14364
|
-
const componentsOutDir =
|
|
14365
|
-
const publicDir =
|
|
14366
|
-
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");
|
|
14367
14933
|
for (const d of [srcDir, pagesOutDir, layoutsDir, stylesDir, componentsOutDir, publicDir]) {
|
|
14368
14934
|
mkdirSync4(d, { recursive: true });
|
|
14369
14935
|
}
|
|
14370
14936
|
const pagesDir = projectPaths.pages();
|
|
14371
|
-
if (!
|
|
14937
|
+
if (!existsSync10(pagesDir)) {
|
|
14372
14938
|
console.error("Pages directory not found!");
|
|
14373
14939
|
return { pages: 0, cmsPages: 0, collections: 0, errors: 1 };
|
|
14374
14940
|
}
|
|
@@ -14381,7 +14947,7 @@ async function buildAstroProject(_projectRoot, outputDir) {
|
|
|
14381
14947
|
for (const file of pageFiles) {
|
|
14382
14948
|
const pageName = file.replace(".json", "");
|
|
14383
14949
|
const basePath = mapPageNameToPath(pageName);
|
|
14384
|
-
const pageContent = await loadJSONFile(
|
|
14950
|
+
const pageContent = await loadJSONFile(join9(pagesDir, file));
|
|
14385
14951
|
if (!pageContent) continue;
|
|
14386
14952
|
try {
|
|
14387
14953
|
const pageData = parseJSON(pageContent);
|
|
@@ -14440,7 +15006,7 @@ async function buildAstroProject(_projectRoot, outputDir) {
|
|
|
14440
15006
|
for (const file of pageFiles) {
|
|
14441
15007
|
const pageName = file.replace(".json", "");
|
|
14442
15008
|
const basePath = mapPageNameToPath(pageName);
|
|
14443
|
-
const pageContent = await loadJSONFile(
|
|
15009
|
+
const pageContent = await loadJSONFile(join9(pagesDir, file));
|
|
14444
15010
|
if (!pageContent) {
|
|
14445
15011
|
console.warn(` Skipping ${basePath} (empty file)`);
|
|
14446
15012
|
errorCount++;
|
|
@@ -14498,8 +15064,8 @@ async function buildAstroProject(_projectRoot, outputDir) {
|
|
|
14498
15064
|
if (!css.url.startsWith("/")) continue;
|
|
14499
15065
|
const shouldInline = css.inline !== false;
|
|
14500
15066
|
const relPath = css.url.slice(1);
|
|
14501
|
-
const srcPath =
|
|
14502
|
-
if (!
|
|
15067
|
+
const srcPath = join9(projectPaths.project, relPath);
|
|
15068
|
+
if (!existsSync10(srcPath)) continue;
|
|
14503
15069
|
if (shouldInline) {
|
|
14504
15070
|
try {
|
|
14505
15071
|
inlineContents.set(css.url, await readFile(srcPath, "utf-8"));
|
|
@@ -14513,7 +15079,7 @@ async function buildAstroProject(_projectRoot, outputDir) {
|
|
|
14513
15079
|
for (const js of buildLibraries.js || []) {
|
|
14514
15080
|
if (js.url.startsWith("/")) {
|
|
14515
15081
|
const relPath = js.url.slice(1);
|
|
14516
|
-
if (
|
|
15082
|
+
if (existsSync10(join9(projectPaths.project, relPath))) {
|
|
14517
15083
|
localLibsToCopy.push(relPath);
|
|
14518
15084
|
}
|
|
14519
15085
|
}
|
|
@@ -14534,9 +15100,9 @@ async function buildAstroProject(_projectRoot, outputDir) {
|
|
|
14534
15100
|
const cmsConsumerComponents = computeCmsConsumerComponents(globalComponents);
|
|
14535
15101
|
const collectionUrlExpr = /* @__PURE__ */ new Map();
|
|
14536
15102
|
const mergedRichTextFields = /* @__PURE__ */ new Set();
|
|
14537
|
-
if (
|
|
15103
|
+
if (existsSync10(templatesDir)) {
|
|
14538
15104
|
for (const file of readdirSync6(templatesDir).filter((f) => f.endsWith(".json"))) {
|
|
14539
|
-
const tc = await loadJSONFile(
|
|
15105
|
+
const tc = await loadJSONFile(join9(templatesDir, file));
|
|
14540
15106
|
if (!tc) continue;
|
|
14541
15107
|
try {
|
|
14542
15108
|
const pd = parseJSON(tc);
|
|
@@ -14550,10 +15116,10 @@ async function buildAstroProject(_projectRoot, outputDir) {
|
|
|
14550
15116
|
}
|
|
14551
15117
|
}
|
|
14552
15118
|
}
|
|
14553
|
-
if (
|
|
15119
|
+
if (existsSync10(templatesDir)) {
|
|
14554
15120
|
const templateFiles = readdirSync6(templatesDir).filter((f) => f.endsWith(".json"));
|
|
14555
15121
|
for (const file of templateFiles) {
|
|
14556
|
-
const templateContent = await loadJSONFile(
|
|
15122
|
+
const templateContent = await loadJSONFile(join9(templatesDir, file));
|
|
14557
15123
|
if (!templateContent) continue;
|
|
14558
15124
|
try {
|
|
14559
15125
|
const pageData = parseJSON(templateContent);
|
|
@@ -14642,9 +15208,9 @@ async function buildAstroProject(_projectRoot, outputDir) {
|
|
|
14642
15208
|
cmsConsumers: cmsConsumerComponents,
|
|
14643
15209
|
collectionUrlExpr
|
|
14644
15210
|
});
|
|
14645
|
-
const astroFileFull =
|
|
15211
|
+
const astroFileFull = join9(pagesOutDir, astroFilePath);
|
|
14646
15212
|
const astroFileDir = astroFileFull.substring(0, astroFileFull.lastIndexOf("/"));
|
|
14647
|
-
if (!
|
|
15213
|
+
if (!existsSync10(astroFileDir)) {
|
|
14648
15214
|
mkdirSync4(astroFileDir, { recursive: true });
|
|
14649
15215
|
}
|
|
14650
15216
|
await writeFile2(astroFileFull, astroContent, "utf-8");
|
|
@@ -14676,7 +15242,7 @@ async function buildAstroProject(_projectRoot, outputDir) {
|
|
|
14676
15242
|
|
|
14677
15243
|
${safelistDirectives}` : `@import "tailwindcss";`;
|
|
14678
15244
|
const globalCSS = [tailwindDirectives, fontCSS, themeColorCSS, variablesCSS, baseCSS, componentCSSCombined].filter(Boolean).join("\n\n");
|
|
14679
|
-
await writeFile2(
|
|
15245
|
+
await writeFile2(join9(stylesDir, "global.css"), globalCSS, "utf-8");
|
|
14680
15246
|
const escForTemplateLiteral = (s) => s.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$\{/g, "\\${");
|
|
14681
15247
|
const customHeadLiteral = escForTemplateLiteral(customCode.head || "");
|
|
14682
15248
|
const customBodyStartLiteral = escForTemplateLiteral(customCode.bodyStart || "");
|
|
@@ -14723,7 +15289,7 @@ const { title, meta = '', scripts = [], locale = 'en', theme = '${themeConfig.de
|
|
|
14723
15289
|
</body>
|
|
14724
15290
|
</html>
|
|
14725
15291
|
`;
|
|
14726
|
-
await writeFile2(
|
|
15292
|
+
await writeFile2(join9(layoutsDir, "BaseLayout.astro"), baseLayoutContent, "utf-8");
|
|
14727
15293
|
const emittableComponents = normalizeOrphanTemplateProps(globalComponents);
|
|
14728
15294
|
let _componentFileCount = 0;
|
|
14729
15295
|
for (const [compName, compDef] of Object.entries(emittableComponents)) {
|
|
@@ -14742,7 +15308,7 @@ const { title, meta = '', scripts = [], locale = 'en', theme = '${themeConfig.de
|
|
|
14742
15308
|
collectionUrlExpr
|
|
14743
15309
|
}
|
|
14744
15310
|
);
|
|
14745
|
-
await writeFile2(
|
|
15311
|
+
await writeFile2(join9(componentsOutDir, `${compName}.astro`), astroContent, "utf-8");
|
|
14746
15312
|
_componentFileCount++;
|
|
14747
15313
|
} catch (error) {
|
|
14748
15314
|
console.warn(
|
|
@@ -14793,9 +15359,9 @@ const { title, meta = '', scripts = [], locale = 'en', theme = '${themeConfig.de
|
|
|
14793
15359
|
scriptPaths = writePageScript(result.javascript, scriptsDir);
|
|
14794
15360
|
astroContent = buildSSRFallbackPage(result, importPath, fontPreloads, libraryTags, defaultTheme, scriptPaths);
|
|
14795
15361
|
}
|
|
14796
|
-
const astroFileFull =
|
|
15362
|
+
const astroFileFull = join9(pagesOutDir, result.astroFilePath);
|
|
14797
15363
|
const astroFileDir = astroFileFull.substring(0, astroFileFull.lastIndexOf("/"));
|
|
14798
|
-
if (!
|
|
15364
|
+
if (!existsSync10(astroFileDir)) {
|
|
14799
15365
|
mkdirSync4(astroFileDir, { recursive: true });
|
|
14800
15366
|
}
|
|
14801
15367
|
await writeFile2(astroFileFull, astroContent, "utf-8");
|
|
@@ -14816,31 +15382,31 @@ export const GET: APIRoute = () => {
|
|
|
14816
15382
|
});
|
|
14817
15383
|
};
|
|
14818
15384
|
`;
|
|
14819
|
-
await writeFile2(
|
|
15385
|
+
await writeFile2(join9(pagesOutDir, "robots.txt.ts"), robotsTsContent, "utf-8");
|
|
14820
15386
|
let collectionCount = 0;
|
|
14821
15387
|
if (templateSchemas.length > 0) {
|
|
14822
|
-
const contentDir =
|
|
15388
|
+
const contentDir = join9(srcDir, "content");
|
|
14823
15389
|
mkdirSync4(contentDir, { recursive: true });
|
|
14824
15390
|
const collectionDefs = [];
|
|
14825
15391
|
for (const schema of templateSchemas) {
|
|
14826
|
-
const collectionDir =
|
|
15392
|
+
const collectionDir = join9(contentDir, schema.id);
|
|
14827
15393
|
mkdirSync4(collectionDir, { recursive: true });
|
|
14828
15394
|
const richTextFieldNames = Object.entries(schema.fields || {}).filter(([, fd]) => fd.type === "rich-text").map(([fn]) => fn);
|
|
14829
|
-
const cmsItemsDir =
|
|
14830
|
-
if (
|
|
15395
|
+
const cmsItemsDir = join9(projectPaths.cms(), schema.id);
|
|
15396
|
+
if (existsSync10(cmsItemsDir)) {
|
|
14831
15397
|
const isDevBuild = process.env.MENO_DEV_BUILD === "true";
|
|
14832
15398
|
const itemFiles = readdirSync6(cmsItemsDir).filter(
|
|
14833
15399
|
(f) => f.endsWith(".json") && (isDevBuild || !f.endsWith(`${CMS_DRAFT_SUFFIX}.json`))
|
|
14834
15400
|
);
|
|
14835
15401
|
for (const itemFile of itemFiles) {
|
|
14836
15402
|
try {
|
|
14837
|
-
const rawContent = await readFile(
|
|
15403
|
+
const rawContent = await readFile(join9(cmsItemsDir, itemFile), "utf-8");
|
|
14838
15404
|
const item = JSON.parse(rawContent);
|
|
14839
15405
|
const resolved = { ...item };
|
|
14840
15406
|
for (const fieldName of richTextFieldNames) {
|
|
14841
15407
|
resolved[fieldName] = serializeRichTextValue(resolved[fieldName]);
|
|
14842
15408
|
}
|
|
14843
|
-
await writeFile2(
|
|
15409
|
+
await writeFile2(join9(collectionDir, itemFile), JSON.stringify(resolved, null, 2), "utf-8");
|
|
14844
15410
|
} catch (err) {
|
|
14845
15411
|
console.warn(
|
|
14846
15412
|
` Warning: could not process CMS item ${itemFile}: ${err instanceof Error ? err.message : String(err)}`
|
|
@@ -14873,29 +15439,29 @@ ${collectionDefs.join(",\n")}
|
|
|
14873
15439
|
|
|
14874
15440
|
export { collections };
|
|
14875
15441
|
`;
|
|
14876
|
-
await writeFile2(
|
|
15442
|
+
await writeFile2(join9(srcDir, "content.config.ts"), configContent, "utf-8");
|
|
14877
15443
|
}
|
|
14878
|
-
const imagesSrcDir =
|
|
14879
|
-
if (
|
|
14880
|
-
copyDirectory(imagesSrcDir,
|
|
14881
|
-
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"));
|
|
14882
15448
|
}
|
|
14883
15449
|
const publicAssetDirs = ["fonts", "icons", "videos", "assets"];
|
|
14884
15450
|
for (const dir of publicAssetDirs) {
|
|
14885
|
-
const srcAssetDir =
|
|
14886
|
-
if (
|
|
14887
|
-
copyDirectory(srcAssetDir,
|
|
15451
|
+
const srcAssetDir = join9(projectPaths.project, dir);
|
|
15452
|
+
if (existsSync10(srcAssetDir)) {
|
|
15453
|
+
copyDirectory(srcAssetDir, join9(publicDir, dir));
|
|
14888
15454
|
}
|
|
14889
15455
|
}
|
|
14890
|
-
const librariesDir =
|
|
14891
|
-
if (
|
|
14892
|
-
copyDirectory(librariesDir,
|
|
15456
|
+
const librariesDir = join9(projectPaths.project, "libraries");
|
|
15457
|
+
if (existsSync10(librariesDir)) {
|
|
15458
|
+
copyDirectory(librariesDir, join9(publicDir, "libraries"));
|
|
14893
15459
|
}
|
|
14894
15460
|
for (const relPath of localLibsToCopy) {
|
|
14895
|
-
const srcPath =
|
|
14896
|
-
const destPath =
|
|
15461
|
+
const srcPath = join9(projectPaths.project, relPath);
|
|
15462
|
+
const destPath = join9(publicDir, relPath);
|
|
14897
15463
|
const destDir = destPath.substring(0, destPath.lastIndexOf("/"));
|
|
14898
|
-
if (destDir && !
|
|
15464
|
+
if (destDir && !existsSync10(destDir)) mkdirSync4(destDir, { recursive: true });
|
|
14899
15465
|
copyFileSync(srcPath, destPath);
|
|
14900
15466
|
}
|
|
14901
15467
|
const packageJson = {
|
|
@@ -14918,7 +15484,7 @@ export { collections };
|
|
|
14918
15484
|
tailwindcss: "^4.0.0"
|
|
14919
15485
|
}
|
|
14920
15486
|
};
|
|
14921
|
-
await writeFile2(
|
|
15487
|
+
await writeFile2(join9(outDir, "package.json"), JSON.stringify(packageJson, null, 2), "utf-8");
|
|
14922
15488
|
const localeCodes = i18nConfig.locales.map((l) => l.code);
|
|
14923
15489
|
const i18nBlock = i18nConfig.locales.length > 1 ? `
|
|
14924
15490
|
i18n: {
|
|
@@ -14938,11 +15504,11 @@ export default defineConfig({${siteUrl ? `
|
|
|
14938
15504
|
},
|
|
14939
15505
|
});
|
|
14940
15506
|
`;
|
|
14941
|
-
await writeFile2(
|
|
15507
|
+
await writeFile2(join9(outDir, "astro.config.mjs"), astroConfig, "utf-8");
|
|
14942
15508
|
const tsConfig = {
|
|
14943
15509
|
extends: "astro/tsconfigs/strict"
|
|
14944
15510
|
};
|
|
14945
|
-
await writeFile2(
|
|
15511
|
+
await writeFile2(join9(outDir, "tsconfig.json"), JSON.stringify(tsConfig, null, 2), "utf-8");
|
|
14946
15512
|
const baseNetlifyToml = `# Generated by Meno's Astro build.
|
|
14947
15513
|
[build]
|
|
14948
15514
|
command = "npm run build"
|
|
@@ -14952,8 +15518,8 @@ export default defineConfig({${siteUrl ? `
|
|
|
14952
15518
|
NODE_VERSION = "22"
|
|
14953
15519
|
`;
|
|
14954
15520
|
const netlifyToml = syncNetlifyLocale404Block(baseNetlifyToml, i18nConfig, pageFiles.includes("404.json"));
|
|
14955
|
-
await writeFile2(
|
|
14956
|
-
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");
|
|
14957
15523
|
const totalPages = allResults.length;
|
|
14958
15524
|
return {
|
|
14959
15525
|
pages: totalPages - cmsPageCount,
|
|
@@ -15017,6 +15583,7 @@ export {
|
|
|
15017
15583
|
getModuleDir,
|
|
15018
15584
|
getPackageRoot,
|
|
15019
15585
|
getProjectRoot,
|
|
15586
|
+
groupForSectionLabel,
|
|
15020
15587
|
handleCollectionSchemaRoute,
|
|
15021
15588
|
handleCollectionsRoute,
|
|
15022
15589
|
handleCoreApiRoutes,
|
|
@@ -15025,11 +15592,15 @@ export {
|
|
|
15025
15592
|
handleItemsRoute,
|
|
15026
15593
|
handleRouteError,
|
|
15027
15594
|
hashContent,
|
|
15595
|
+
inferGroup,
|
|
15028
15596
|
inspect,
|
|
15029
15597
|
isBun3 as isBun,
|
|
15598
|
+
isColorValue,
|
|
15599
|
+
isThemeCssProject,
|
|
15030
15600
|
jsonResponse,
|
|
15031
15601
|
lineMapToObject,
|
|
15032
15602
|
loadProjectConfig,
|
|
15603
|
+
loadThemeModel,
|
|
15033
15604
|
logError,
|
|
15034
15605
|
logRequest,
|
|
15035
15606
|
logResponseTime,
|
|
@@ -15039,19 +15610,25 @@ export {
|
|
|
15039
15610
|
needsFormHandler,
|
|
15040
15611
|
needsMenoFilter,
|
|
15041
15612
|
packagePaths,
|
|
15613
|
+
parseThemeCss,
|
|
15042
15614
|
processCMSPropsTemplate,
|
|
15043
15615
|
processCMSTemplate,
|
|
15044
15616
|
projectPaths,
|
|
15045
15617
|
readJsonFile,
|
|
15046
15618
|
readTextFile,
|
|
15619
|
+
regenerateThemeCss,
|
|
15047
15620
|
renderPageSSR,
|
|
15048
15621
|
resetFontConfig,
|
|
15049
15622
|
resolvePackagePath,
|
|
15050
15623
|
resolveProjectPath,
|
|
15624
|
+
saveColors,
|
|
15625
|
+
saveVariables,
|
|
15626
|
+
serializeThemeCss,
|
|
15051
15627
|
serveFile,
|
|
15052
15628
|
setProjectRoot,
|
|
15053
15629
|
spawnProcess,
|
|
15054
15630
|
styleToString,
|
|
15631
|
+
themeCssPath,
|
|
15055
15632
|
validateJS,
|
|
15056
15633
|
variableService,
|
|
15057
15634
|
watchRecursive,
|