@uniweb/build 0.4.2 → 0.4.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uniweb/build",
3
- "version": "0.4.2",
3
+ "version": "0.4.4",
4
4
  "description": "Build tooling for the Uniweb Component Web Platform",
5
5
  "type": "module",
6
6
  "exports": {
@@ -50,8 +50,8 @@
50
50
  "sharp": "^0.33.2"
51
51
  },
52
52
  "optionalDependencies": {
53
- "@uniweb/content-reader": "1.1.1",
54
- "@uniweb/runtime": "0.5.2"
53
+ "@uniweb/runtime": "0.5.7",
54
+ "@uniweb/content-reader": "1.1.2"
55
55
  },
56
56
  "peerDependencies": {
57
57
  "vite": "^5.0.0 || ^6.0.0 || ^7.0.0",
@@ -60,7 +60,7 @@
60
60
  "@tailwindcss/vite": "^4.0.0",
61
61
  "@vitejs/plugin-react": "^4.0.0 || ^5.0.0",
62
62
  "vite-plugin-svgr": "^4.0.0",
63
- "@uniweb/core": "0.3.3"
63
+ "@uniweb/core": "0.3.7"
64
64
  },
65
65
  "peerDependenciesMeta": {
66
66
  "vite": {
@@ -759,8 +759,13 @@ async function collectPagesRecursive(dirPath, parentRoute, siteRoot, orderConfig
759
759
  }
760
760
 
761
761
  // Determine which page is the index for this level
762
+ // A directory with its own .md content is a real page, not a container —
763
+ // never promote a child as index, even if explicit config says so
764
+ // (that config is likely a leftover from before the directory had content)
762
765
  const regularFolders = pageFolders.filter(f => !f.name.startsWith('@'))
763
- const indexPageName = determineIndexPage(orderConfig, regularFolders)
766
+ const hasExplicitOrder = orderConfig?.index || (Array.isArray(orderConfig?.pages) && orderConfig.pages.length > 0)
767
+ const hasMdContent = entries.some(e => isMarkdownFile(e))
768
+ const indexPageName = hasMdContent ? null : determineIndexPage(orderConfig, regularFolders)
764
769
 
765
770
  // Second pass: process each page folder
766
771
  for (const folder of pageFolders) {
@@ -804,7 +809,12 @@ async function collectPagesRecursive(dirPath, parentRoute, siteRoot, orderConfig
804
809
  // Recursively process subdirectories (but not special @ directories)
805
810
  if (!isSpecial) {
806
811
  // The child route depends on whether this page is the index
807
- const childParentRoute = isIndex ? parentRoute : page.route
812
+ // For explicit index (from site.yml `index:` or `pages:`), children use parentRoute
813
+ // since that's a true structural promotion. For auto-detected index, children use
814
+ // the page's original folder path so they nest correctly under it.
815
+ const childParentRoute = isIndex
816
+ ? (hasExplicitOrder ? parentRoute : (page.sourcePath || page.route))
817
+ : page.route
808
818
  // Pass this page's fetch config to children (for dynamic routes that inherit parent data)
809
819
  const childFetch = page.fetch || parentFetch
810
820
  // Pass version context to children (maintains version scope)
@@ -901,6 +911,51 @@ export async function collectSiteContent(sitePath, options = {}) {
901
911
  const { pages, assetCollection, iconCollection, header, footer, left, right, notFound, versionedScopes } =
902
912
  await collectPagesRecursive(pagesPath, '/', sitePath, siteOrderConfig)
903
913
 
914
+ // Deduplicate: remove content-less container pages whose route duplicates
915
+ // a content-bearing page (e.g., a promoted index page)
916
+ const routeCounts = new Map()
917
+ for (const page of pages) {
918
+ const existing = routeCounts.get(page.route)
919
+ if (!existing) {
920
+ routeCounts.set(page.route, [page])
921
+ } else {
922
+ existing.push(page)
923
+ }
924
+ }
925
+ for (const [route, group] of routeCounts) {
926
+ if (group.length > 1) {
927
+ // Keep the page with content, remove content-less duplicates
928
+ const withContent = group.filter(p => p.sections && p.sections.length > 0)
929
+ const toRemove = withContent.length > 0
930
+ ? group.filter(p => !p.sections || p.sections.length === 0)
931
+ : group.slice(1) // If none have content, keep first
932
+ for (const page of toRemove) {
933
+ const idx = pages.indexOf(page)
934
+ if (idx !== -1) pages.splice(idx, 1)
935
+ }
936
+ }
937
+ }
938
+
939
+ // Compute parent route for each page (hierarchy declaration)
940
+ // This runs once at build time so runtime doesn't need to re-derive hierarchy
941
+ const pageRouteMap = new Map()
942
+ for (const page of pages) {
943
+ pageRouteMap.set(page.route, page)
944
+ if (page.sourcePath) {
945
+ pageRouteMap.set(page.sourcePath, page)
946
+ }
947
+ }
948
+ for (const page of pages) {
949
+ const segments = page.route.split('/').filter(Boolean)
950
+ if (segments.length <= 1) {
951
+ page.parent = null
952
+ continue
953
+ }
954
+ const parentRoute = '/' + segments.slice(0, -1).join('/')
955
+ const parentPage = pageRouteMap.get(parentRoute)
956
+ page.parent = parentPage ? parentPage.route : null
957
+ }
958
+
904
959
  // Sort pages by order
905
960
  pages.sort((a, b) => (a.order ?? 999) - (b.order ?? 999))
906
961