@constela/start 1.2.15 → 1.2.17
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/{chunk-7KQYNZ2A.js → chunk-CRQMVEYP.js} +140 -32
- package/dist/cli/index.js +1 -1
- package/dist/index.js +1 -1
- package/package.json +3 -3
|
@@ -2448,13 +2448,39 @@ async function loadLayout2(layoutName, layoutsDir) {
|
|
|
2448
2448
|
}
|
|
2449
2449
|
try {
|
|
2450
2450
|
const content = readFileSync5(layoutPath, "utf-8");
|
|
2451
|
-
|
|
2452
|
-
|
|
2451
|
+
const parsed = JSON.parse(content);
|
|
2452
|
+
if (parsed.imports && Object.keys(parsed.imports).length > 0) {
|
|
2453
|
+
const layoutDir = dirname5(layoutPath);
|
|
2454
|
+
const resolvedImports = await resolveImports(layoutDir, parsed.imports);
|
|
2455
|
+
return { ...parsed, importData: resolvedImports };
|
|
2456
|
+
}
|
|
2457
|
+
return parsed;
|
|
2458
|
+
} catch (error) {
|
|
2459
|
+
if (error instanceof Error && error.message.includes("not found")) {
|
|
2460
|
+
throw error;
|
|
2461
|
+
}
|
|
2453
2462
|
throw new Error(`Invalid JSON in layout file: ${layoutPath}`);
|
|
2454
2463
|
}
|
|
2455
2464
|
}
|
|
2456
|
-
function applyLayout(pageView, layoutView) {
|
|
2457
|
-
return replaceSlot(layoutView, pageView);
|
|
2465
|
+
function applyLayout(pageView, layoutView, namedSlots) {
|
|
2466
|
+
return replaceSlot(layoutView, pageView, namedSlots);
|
|
2467
|
+
}
|
|
2468
|
+
function extractMdxContentSlot2(loadedData, dataSourceName, routeParams) {
|
|
2469
|
+
const dataSource = loadedData[dataSourceName];
|
|
2470
|
+
if (!Array.isArray(dataSource)) {
|
|
2471
|
+
return void 0;
|
|
2472
|
+
}
|
|
2473
|
+
const slug = routeParams["slug"] || "index";
|
|
2474
|
+
const item = dataSource.find(
|
|
2475
|
+
(entry) => typeof entry === "object" && entry !== null && "slug" in entry && entry.slug === slug
|
|
2476
|
+
);
|
|
2477
|
+
if (!item || typeof item !== "object" || !("content" in item)) {
|
|
2478
|
+
return void 0;
|
|
2479
|
+
}
|
|
2480
|
+
return { "mdx-content": item.content };
|
|
2481
|
+
}
|
|
2482
|
+
function isEventHandler(value) {
|
|
2483
|
+
return typeof value === "object" && value !== null && "event" in value && typeof value.event === "string" && "action" in value && typeof value.action === "string";
|
|
2458
2484
|
}
|
|
2459
2485
|
function normalizeProps(props) {
|
|
2460
2486
|
if (!props || typeof props !== "object") {
|
|
@@ -2464,6 +2490,8 @@ function normalizeProps(props) {
|
|
|
2464
2490
|
for (const [key, value] of Object.entries(props)) {
|
|
2465
2491
|
if (value && typeof value === "object" && "expr" in value) {
|
|
2466
2492
|
normalized[key] = value;
|
|
2493
|
+
} else if (isEventHandler(value)) {
|
|
2494
|
+
normalized[key] = value;
|
|
2467
2495
|
} else if (value !== void 0 && value !== null) {
|
|
2468
2496
|
normalized[key] = { expr: "lit", value };
|
|
2469
2497
|
}
|
|
@@ -2570,59 +2598,127 @@ function substituteLayoutParamsInNode(node, layoutParams) {
|
|
|
2570
2598
|
}
|
|
2571
2599
|
return result;
|
|
2572
2600
|
}
|
|
2573
|
-
function replaceSlot(node, content) {
|
|
2601
|
+
function replaceSlot(node, content, namedSlots) {
|
|
2574
2602
|
if (!node || typeof node !== "object") {
|
|
2575
2603
|
return node;
|
|
2576
2604
|
}
|
|
2577
2605
|
const nodeObj = node;
|
|
2578
2606
|
if (nodeObj["kind"] === "slot") {
|
|
2579
|
-
|
|
2607
|
+
const slotName = nodeObj["name"];
|
|
2608
|
+
if (slotName && namedSlots && slotName in namedSlots) {
|
|
2609
|
+
return namedSlots[slotName];
|
|
2610
|
+
}
|
|
2611
|
+
if (!slotName || slotName === "default") {
|
|
2612
|
+
return content;
|
|
2613
|
+
}
|
|
2614
|
+
return node;
|
|
2580
2615
|
}
|
|
2581
2616
|
if (Array.isArray(nodeObj["children"])) {
|
|
2582
2617
|
return {
|
|
2583
2618
|
...nodeObj,
|
|
2584
|
-
children: nodeObj["children"].map((child) => replaceSlot(child, content))
|
|
2619
|
+
children: nodeObj["children"].map((child) => replaceSlot(child, content, namedSlots))
|
|
2585
2620
|
};
|
|
2586
2621
|
}
|
|
2587
2622
|
return node;
|
|
2588
2623
|
}
|
|
2589
|
-
async function
|
|
2624
|
+
async function collectLayoutChain(layoutName, layoutsDir, visited = /* @__PURE__ */ new Set()) {
|
|
2625
|
+
if (visited.has(layoutName)) {
|
|
2626
|
+
throw new Error(`Circular layout reference detected: ${layoutName}`);
|
|
2627
|
+
}
|
|
2628
|
+
visited.add(layoutName);
|
|
2629
|
+
const layout = await loadLayout2(layoutName, layoutsDir);
|
|
2630
|
+
const chain = [layout];
|
|
2631
|
+
if (layout.layout) {
|
|
2632
|
+
const parentChain = await collectLayoutChain(layout.layout, layoutsDir, visited);
|
|
2633
|
+
chain.push(...parentChain);
|
|
2634
|
+
}
|
|
2635
|
+
return chain;
|
|
2636
|
+
}
|
|
2637
|
+
async function processLayouts(pageInfo, layoutsDir, routeParams = {}) {
|
|
2590
2638
|
const layoutName = pageInfo.page.route?.layout;
|
|
2591
2639
|
if (!layoutName || !layoutsDir) {
|
|
2592
2640
|
return pageInfo;
|
|
2593
2641
|
}
|
|
2594
|
-
const
|
|
2595
|
-
|
|
2596
|
-
let
|
|
2642
|
+
const layoutChain = await collectLayoutChain(layoutName, layoutsDir);
|
|
2643
|
+
let mergedImports = { ...pageInfo.resolvedImports };
|
|
2644
|
+
for (let i = layoutChain.length - 1; i >= 0; i--) {
|
|
2645
|
+
const layout = layoutChain[i];
|
|
2646
|
+
if (layout?.importData) {
|
|
2647
|
+
mergedImports = {
|
|
2648
|
+
...layout.importData,
|
|
2649
|
+
...mergedImports
|
|
2650
|
+
// Inner layout/page imports take precedence
|
|
2651
|
+
};
|
|
2652
|
+
}
|
|
2653
|
+
}
|
|
2654
|
+
let namedSlots;
|
|
2655
|
+
let effectiveRouteParams = routeParams;
|
|
2656
|
+
if (!routeParams["slug"] && pageInfo.page.route?.path) {
|
|
2657
|
+
const pathSegments = pageInfo.page.route.path.split("/").filter(Boolean);
|
|
2658
|
+
const lastSegment = pathSegments[pathSegments.length - 1];
|
|
2659
|
+
if (lastSegment && !lastSegment.startsWith(":")) {
|
|
2660
|
+
effectiveRouteParams = { ...routeParams, slug: lastSegment };
|
|
2661
|
+
}
|
|
2662
|
+
}
|
|
2663
|
+
if (pageInfo.loadedData && Object.keys(pageInfo.loadedData).length > 0) {
|
|
2664
|
+
for (const dataSourceName of Object.keys(pageInfo.loadedData)) {
|
|
2665
|
+
const slots = extractMdxContentSlot2(pageInfo.loadedData, dataSourceName, effectiveRouteParams);
|
|
2666
|
+
if (slots) {
|
|
2667
|
+
namedSlots = namedSlots ? { ...namedSlots, ...slots } : slots;
|
|
2668
|
+
break;
|
|
2669
|
+
}
|
|
2670
|
+
}
|
|
2671
|
+
}
|
|
2672
|
+
if (!namedSlots && pageInfo.resolvedImports && Object.keys(pageInfo.resolvedImports).length > 0) {
|
|
2673
|
+
for (const importName of Object.keys(pageInfo.resolvedImports)) {
|
|
2674
|
+
const slots = extractMdxContentSlot2(
|
|
2675
|
+
pageInfo.resolvedImports,
|
|
2676
|
+
importName,
|
|
2677
|
+
effectiveRouteParams
|
|
2678
|
+
);
|
|
2679
|
+
if (slots) {
|
|
2680
|
+
namedSlots = slots;
|
|
2681
|
+
break;
|
|
2682
|
+
}
|
|
2683
|
+
}
|
|
2684
|
+
}
|
|
2685
|
+
const pageWithImportData = pageInfo.page;
|
|
2686
|
+
if (!namedSlots && pageWithImportData.importData && Object.keys(pageWithImportData.importData).length > 0) {
|
|
2687
|
+
for (const importName of Object.keys(pageWithImportData.importData)) {
|
|
2688
|
+
const slots = extractMdxContentSlot2(
|
|
2689
|
+
pageWithImportData.importData,
|
|
2690
|
+
importName,
|
|
2691
|
+
effectiveRouteParams
|
|
2692
|
+
);
|
|
2693
|
+
if (slots) {
|
|
2694
|
+
namedSlots = slots;
|
|
2695
|
+
break;
|
|
2696
|
+
}
|
|
2697
|
+
}
|
|
2698
|
+
}
|
|
2699
|
+
let currentView = pageInfo.page.view;
|
|
2700
|
+
for (const layout of layoutChain) {
|
|
2701
|
+
const normalizedLayoutView = normalizeViewNode(structuredClone(layout.view));
|
|
2702
|
+
currentView = applyLayout(currentView, normalizedLayoutView, namedSlots);
|
|
2703
|
+
}
|
|
2597
2704
|
const layoutParams = pageInfo.page.route?.layoutParams;
|
|
2598
2705
|
if (layoutParams && Object.keys(layoutParams).length > 0) {
|
|
2599
|
-
|
|
2706
|
+
currentView = substituteLayoutParamsInNode(currentView, layoutParams);
|
|
2600
2707
|
}
|
|
2601
2708
|
let updatedRoute;
|
|
2602
2709
|
if (pageInfo.page.route) {
|
|
2603
2710
|
const { layout: _layout, ...routeWithoutLayout } = pageInfo.page.route;
|
|
2604
2711
|
updatedRoute = routeWithoutLayout;
|
|
2605
2712
|
}
|
|
2606
|
-
|
|
2713
|
+
const updatedPageInfo = {
|
|
2607
2714
|
...pageInfo,
|
|
2715
|
+
resolvedImports: mergedImports,
|
|
2608
2716
|
page: {
|
|
2609
2717
|
...pageInfo.page,
|
|
2610
|
-
view:
|
|
2718
|
+
view: currentView,
|
|
2611
2719
|
route: updatedRoute
|
|
2612
2720
|
}
|
|
2613
2721
|
};
|
|
2614
|
-
if (layout.layout) {
|
|
2615
|
-
const parentLayout = await loadLayout2(layout.layout, layoutsDir);
|
|
2616
|
-
const normalizedParentLayoutView = normalizeViewNode(structuredClone(parentLayout.view));
|
|
2617
|
-
const doubleWrappedView = applyLayout(updatedPageInfo.page.view, normalizedParentLayoutView);
|
|
2618
|
-
updatedPageInfo = {
|
|
2619
|
-
...updatedPageInfo,
|
|
2620
|
-
page: {
|
|
2621
|
-
...updatedPageInfo.page,
|
|
2622
|
-
view: doubleWrappedView
|
|
2623
|
-
}
|
|
2624
|
-
};
|
|
2625
|
-
}
|
|
2626
2722
|
return updatedPageInfo;
|
|
2627
2723
|
}
|
|
2628
2724
|
async function renderPageToHtml(program, params, runtimePath, cssPath) {
|
|
@@ -2748,13 +2844,14 @@ async function build2(options) {
|
|
|
2748
2844
|
if (!staticPathsResult || staticPathsResult.length === 0) {
|
|
2749
2845
|
continue;
|
|
2750
2846
|
}
|
|
2751
|
-
if (layoutsDir) {
|
|
2752
|
-
pageInfo = await processLayouts(pageInfo, layoutsDir);
|
|
2753
|
-
}
|
|
2754
2847
|
for (const pathEntry of staticPathsResult) {
|
|
2755
2848
|
const params = pathEntry.params;
|
|
2756
2849
|
const outputPath = paramsToOutputPath(route.pattern, params, outDir);
|
|
2757
|
-
|
|
2850
|
+
let processedPageInfo = pageInfo;
|
|
2851
|
+
if (layoutsDir) {
|
|
2852
|
+
processedPageInfo = await processLayouts(pageInfo, layoutsDir, params);
|
|
2853
|
+
}
|
|
2854
|
+
const program = await convertToCompiledProgram(processedPageInfo);
|
|
2758
2855
|
const html = await renderPageToHtml(program, params, runtimePath, cssPath);
|
|
2759
2856
|
await mkdir2(dirname5(outputPath), { recursive: true });
|
|
2760
2857
|
await writeFile(outputPath, html, "utf-8");
|
|
@@ -2767,11 +2864,22 @@ async function build2(options) {
|
|
|
2767
2864
|
routes.push(routePath);
|
|
2768
2865
|
}
|
|
2769
2866
|
} else {
|
|
2770
|
-
const outputPath = getOutputPath(relPathFromRoutesDir, outDir);
|
|
2771
2867
|
const loader = new JsonPageLoader(projectRoot, { routesDir: absoluteRoutesDir });
|
|
2772
2868
|
let pageInfo = await loader.loadPage(relPathFromProjectRoot);
|
|
2869
|
+
let outputPath;
|
|
2870
|
+
if (pageInfo.page.route?.path) {
|
|
2871
|
+
const routePath = pageInfo.page.route.path;
|
|
2872
|
+
const relativePath = routePath.startsWith("/") ? routePath.slice(1) : routePath;
|
|
2873
|
+
if (relativePath === "" || relativePath === "/") {
|
|
2874
|
+
outputPath = join9(outDir, "index.html");
|
|
2875
|
+
} else {
|
|
2876
|
+
outputPath = join9(outDir, relativePath, "index.html");
|
|
2877
|
+
}
|
|
2878
|
+
} else {
|
|
2879
|
+
outputPath = getOutputPath(relPathFromRoutesDir, outDir);
|
|
2880
|
+
}
|
|
2773
2881
|
if (layoutsDir) {
|
|
2774
|
-
pageInfo = await processLayouts(pageInfo, layoutsDir);
|
|
2882
|
+
pageInfo = await processLayouts(pageInfo, layoutsDir, {});
|
|
2775
2883
|
}
|
|
2776
2884
|
const program = await convertToCompiledProgram(pageInfo);
|
|
2777
2885
|
const html = await renderPageToHtml(program, {}, runtimePath, cssPath);
|
package/dist/cli/index.js
CHANGED
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@constela/start",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.17",
|
|
4
4
|
"description": "Meta-framework for Constela applications",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -44,9 +44,9 @@
|
|
|
44
44
|
"@tailwindcss/postcss": "^4.0.0",
|
|
45
45
|
"tailwindcss": "^4.0.0",
|
|
46
46
|
"@constela/core": "0.7.0",
|
|
47
|
-
"@constela/compiler": "0.7.1",
|
|
48
|
-
"@constela/router": "8.0.0",
|
|
49
47
|
"@constela/runtime": "0.10.2",
|
|
48
|
+
"@constela/router": "8.0.0",
|
|
49
|
+
"@constela/compiler": "0.7.1",
|
|
50
50
|
"@constela/server": "3.0.1"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|