polen 0.10.0-next.4 → 0.10.0-next.5

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.
Files changed (133) hide show
  1. package/README.md +2 -1
  2. package/build/api/config/load.js +5 -5
  3. package/build/api/config/load.js.map +1 -1
  4. package/build/api/config-resolver/resolve.js +2 -2
  5. package/build/api/config-resolver/resolve.js.map +1 -1
  6. package/build/api/content/$$.d.ts +5 -0
  7. package/build/api/content/$$.d.ts.map +1 -0
  8. package/build/api/content/$$.js +5 -0
  9. package/build/api/content/$$.js.map +1 -0
  10. package/build/api/content/$.d.ts +2 -0
  11. package/build/api/content/$.d.ts.map +1 -0
  12. package/build/api/content/$.js +2 -0
  13. package/build/api/content/$.js.map +1 -0
  14. package/build/api/content/metadata.d.ts +10 -0
  15. package/build/api/content/metadata.d.ts.map +1 -0
  16. package/build/api/content/metadata.js +9 -0
  17. package/build/api/content/metadata.js.map +1 -0
  18. package/build/api/content/page.d.ts +11 -0
  19. package/build/api/content/page.d.ts.map +1 -0
  20. package/build/api/content/page.js +2 -0
  21. package/build/api/content/page.js.map +1 -0
  22. package/build/api/content/scan.d.ts +19 -0
  23. package/build/api/content/scan.d.ts.map +1 -0
  24. package/build/api/content/scan.js +57 -0
  25. package/build/api/content/scan.js.map +1 -0
  26. package/build/{lib/file-router/sidebar/types.d.ts → api/content/sidebar.d.ts} +8 -1
  27. package/build/api/content/sidebar.d.ts.map +1 -0
  28. package/build/api/content/sidebar.js +90 -0
  29. package/build/api/content/sidebar.js.map +1 -0
  30. package/build/api/schema/data-sources/schema-directory/schema-directory.js +1 -1
  31. package/build/api/schema/data-sources/schema-directory/schema-directory.js.map +1 -1
  32. package/build/api/vite/plugins/branding/index.js +4 -4
  33. package/build/api/vite/plugins/branding/index.js.map +1 -1
  34. package/build/api/vite/plugins/core.js +4 -4
  35. package/build/api/vite/plugins/core.js.map +1 -1
  36. package/build/api/vite/plugins/pages.d.ts +6 -8
  37. package/build/api/vite/plugins/pages.d.ts.map +1 -1
  38. package/build/api/vite/plugins/pages.js +99 -155
  39. package/build/api/vite/plugins/pages.js.map +1 -1
  40. package/build/api/vite/plugins/serve.js +5 -5
  41. package/build/api/vite/plugins/serve.js.map +1 -1
  42. package/build/cli/_/self-contained-mode.js +5 -5
  43. package/build/cli/_/self-contained-mode.js.map +1 -1
  44. package/build/exports/components.d.ts +2 -0
  45. package/build/exports/components.d.ts.map +1 -0
  46. package/build/exports/components.js +2 -0
  47. package/build/exports/components.js.map +1 -0
  48. package/build/lib/demos/config-schema.d.ts +14 -14
  49. package/build/lib/file-router/file-router.d.ts +0 -2
  50. package/build/lib/file-router/file-router.d.ts.map +1 -1
  51. package/build/lib/file-router/file-router.js +0 -2
  52. package/build/lib/file-router/file-router.js.map +1 -1
  53. package/build/lib/file-router/route.d.ts +2 -0
  54. package/build/lib/file-router/route.d.ts.map +1 -1
  55. package/build/lib/file-router/route.js.map +1 -1
  56. package/build/lib/file-router/scan.d.ts.map +1 -1
  57. package/build/lib/file-router/scan.js +16 -12
  58. package/build/lib/file-router/scan.js.map +1 -1
  59. package/build/singletons/debug.d.ts +1 -1
  60. package/build/singletons/debug.d.ts.map +1 -1
  61. package/build/singletons/debug.js +1 -1
  62. package/build/singletons/debug.js.map +1 -1
  63. package/build/template/components/content/$$.d.ts +2 -0
  64. package/build/template/components/content/$$.d.ts.map +1 -0
  65. package/build/template/components/content/$$.js +2 -0
  66. package/build/template/components/content/$$.js.map +1 -0
  67. package/build/template/components/sidebar/Sidebar.d.ts +2 -2
  68. package/build/template/components/sidebar/Sidebar.d.ts.map +1 -1
  69. package/build/template/components/sidebar/SidebarItem.d.ts +3 -3
  70. package/build/template/components/sidebar/SidebarItem.d.ts.map +1 -1
  71. package/build/template/components/sidebar/SidebarItem.jsx +1 -1
  72. package/build/template/components/sidebar/SidebarItem.jsx.map +1 -1
  73. package/package.json +10 -3
  74. package/src/api/config/load.ts +5 -5
  75. package/src/api/config-resolver/resolve.ts +2 -2
  76. package/src/api/content/$$.ts +4 -0
  77. package/src/api/content/$.test.ts +72 -0
  78. package/src/api/content/$.ts +1 -0
  79. package/src/api/content/metadata.ts +11 -0
  80. package/src/api/content/page.ts +12 -0
  81. package/src/api/content/scan.ts +82 -0
  82. package/src/api/content/sidebar.ts +136 -0
  83. package/src/api/schema/data-sources/schema-directory/schema-directory.ts +1 -1
  84. package/src/api/vite/plugins/branding/index.ts +4 -4
  85. package/src/api/vite/plugins/core.ts +4 -4
  86. package/src/api/vite/plugins/pages.ts +117 -171
  87. package/src/api/vite/plugins/serve.ts +5 -5
  88. package/src/cli/_/self-contained-mode.ts +5 -5
  89. package/src/exports/components.ts +1 -0
  90. package/src/lib/deployment/$$.ts +1 -1
  91. package/src/lib/deployment/$.test.ts +3 -3
  92. package/src/lib/deployment/$.ts +1 -1
  93. package/src/lib/file-router/file-router.ts +0 -2
  94. package/src/lib/file-router/linter.test.ts +2 -0
  95. package/src/lib/file-router/route.ts +2 -0
  96. package/src/lib/file-router/scan.ts +19 -13
  97. package/src/lib/task/$.test.ts +3 -3
  98. package/src/singletons/debug.ts +1 -1
  99. package/src/template/components/content/$$.ts +1 -0
  100. package/src/template/components/sidebar/Sidebar.tsx +2 -2
  101. package/src/template/components/sidebar/SidebarItem.tsx +8 -8
  102. package/build/lib/file-router/scan-tree.d.ts +0 -20
  103. package/build/lib/file-router/scan-tree.d.ts.map +0 -1
  104. package/build/lib/file-router/scan-tree.js +0 -158
  105. package/build/lib/file-router/scan-tree.js.map +0 -1
  106. package/build/lib/file-router/sidebar/index.d.ts +0 -3
  107. package/build/lib/file-router/sidebar/index.d.ts.map +0 -1
  108. package/build/lib/file-router/sidebar/index.js +0 -4
  109. package/build/lib/file-router/sidebar/index.js.map +0 -1
  110. package/build/lib/file-router/sidebar/sidebar-tree.d.ts +0 -9
  111. package/build/lib/file-router/sidebar/sidebar-tree.d.ts.map +0 -1
  112. package/build/lib/file-router/sidebar/sidebar-tree.js +0 -85
  113. package/build/lib/file-router/sidebar/sidebar-tree.js.map +0 -1
  114. package/build/lib/file-router/sidebar/types.d.ts.map +0 -1
  115. package/build/lib/file-router/sidebar/types.js +0 -2
  116. package/build/lib/file-router/sidebar/types.js.map +0 -1
  117. package/build/lib/tree/index.d.ts +0 -3
  118. package/build/lib/tree/index.d.ts.map +0 -1
  119. package/build/lib/tree/index.js +0 -2
  120. package/build/lib/tree/index.js.map +0 -1
  121. package/build/lib/tree/tree.d.ts +0 -62
  122. package/build/lib/tree/tree.d.ts.map +0 -1
  123. package/build/lib/tree/tree.js +0 -134
  124. package/build/lib/tree/tree.js.map +0 -1
  125. package/src/lib/file-router/scan-tree.test.ts +0 -189
  126. package/src/lib/file-router/scan-tree.ts +0 -205
  127. package/src/lib/file-router/sidebar/index.ts +0 -3
  128. package/src/lib/file-router/sidebar/sidebar-tree.test.ts +0 -123
  129. package/src/lib/file-router/sidebar/sidebar-tree.ts +0 -110
  130. package/src/lib/file-router/sidebar/types.ts +0 -19
  131. package/src/lib/tree/index.ts +0 -2
  132. package/src/lib/tree/tree.test.ts +0 -117
  133. package/src/lib/tree/tree.ts +0 -183
@@ -1,110 +0,0 @@
1
- import { Tree } from '#lib/tree/index'
2
- import { Str } from '@wollybeard/kit'
3
- import * as FileRouter from '../file-router.ts'
4
- import type { RouteTreeNode } from '../scan-tree.ts'
5
- import type { ItemLink, ItemSection, Sidebar } from './types.ts'
6
-
7
- export * from './types.ts'
8
-
9
- /**
10
- * Build sidebar from tree structure
11
- */
12
- export const buildFromTree = (routeTree: RouteTreeNode, basePath: FileRouter.Path): Sidebar => {
13
- const links: ItemLink[] = []
14
- const sections: ItemSection[] = []
15
-
16
- // Process only the children of the root node
17
- for (const child of routeTree.children) {
18
- processNode(child, basePath, [], links, sections)
19
- }
20
-
21
- const items = [...links, ...sections]
22
-
23
- return {
24
- items,
25
- }
26
- }
27
-
28
- const processNode = (
29
- node: RouteTreeNode,
30
- basePath: FileRouter.Path,
31
- parentPath: string[],
32
- links: ItemLink[],
33
- sections: ItemSection[],
34
- ): void => {
35
- const currentPath = [...parentPath, node.value.name]
36
-
37
- if (node.value.type === 'directory') {
38
- // This is a directory - create a section
39
- const sectionPath = [...basePath, ...currentPath]
40
- const sectionPathExp = FileRouter.pathToExpression(sectionPath)
41
- const sectionTitle = Str.titlizeSlug(node.value.name)
42
-
43
- const section: ItemSection = {
44
- type: `ItemSection`,
45
- title: sectionTitle,
46
- pathExp: sectionPathExp.startsWith('/') ? sectionPathExp.slice(1) : sectionPathExp,
47
- isLinkToo: false,
48
- links: [],
49
- }
50
-
51
- // Check if this directory has an index file
52
- const indexChild = node.children.find(child => child.value.type === 'file' && child.value.name === 'index')
53
- if (indexChild) {
54
- section.isLinkToo = true
55
- }
56
-
57
- // Process all non-index children as links for this section
58
- for (const child of node.children) {
59
- if (child.value.type === 'file' && child.value.name !== 'index' && child.value.route) {
60
- // Pass the parent path of the route, not the section path
61
- const routeParentPath = child.value.route.logical.path.slice(0, -1)
62
- section.links.push(routeToItemLink(child.value.route, routeParentPath))
63
- } else if (child.value.type === 'directory') {
64
- // Recursively process subdirectories
65
- // Note: This creates nested sections which the original implementation doesn't support
66
- // For now, we'll just add the files from subdirectories to the parent section
67
- collectFilesFromDirectory(child, child.value.route?.logical.path || [], section.links)
68
- }
69
- }
70
-
71
- sections.push(section)
72
- } else if (node.value.type === 'file' && node.value.route) {
73
- // This is a top-level file - add as nav
74
- if (node.value.name !== 'index') {
75
- links.push(routeToItemLink(node.value.route, basePath))
76
- }
77
- }
78
- }
79
-
80
- const collectFilesFromDirectory = (
81
- node: RouteTreeNode,
82
- basePath: FileRouter.Path,
83
- links: ItemLink[],
84
- ): void => {
85
- Tree.visit(node, (n) => {
86
- if (n.value.type === 'file' && n.value.route && n.value.name !== 'index') {
87
- // Use the route's parent path for relative title generation
88
- const routeParentPath = n.value.route.logical.path.slice(0, -1)
89
- links.push(routeToItemLink(n.value.route, routeParentPath))
90
- }
91
- })
92
- }
93
-
94
- const routeToItemLink = (route: FileRouter.Route, basePath: FileRouter.Path): ItemLink => {
95
- const pagePathExp = FileRouter.routeToPathExpression(route)
96
- const pageRelative = FileRouter.makeRelativeUnsafe(route, basePath)
97
- const pageRelativePathExp = FileRouter.routeToPathExpression(pageRelative)
98
-
99
- // Remove leading slash for title generation
100
- const titlePath = pageRelativePathExp.startsWith('/') ? pageRelativePathExp.slice(1) : pageRelativePathExp
101
-
102
- // Use only the last segment for the title
103
- const titleSegment = pageRelative.logical.path[pageRelative.logical.path.length - 1] || titlePath
104
-
105
- return {
106
- type: `ItemLink`,
107
- pathExp: pagePathExp.startsWith('/') ? pagePathExp.slice(1) : pagePathExp,
108
- title: Str.titlizeSlug(titleSegment),
109
- }
110
- }
@@ -1,19 +0,0 @@
1
- export interface Sidebar {
2
- items: Item[]
3
- }
4
-
5
- export type Item = ItemLink | ItemSection
6
-
7
- export interface ItemLink {
8
- type: `ItemLink`
9
- title: string
10
- pathExp: string
11
- }
12
-
13
- export interface ItemSection {
14
- type: `ItemSection`
15
- title: string
16
- pathExp: string
17
- isLinkToo: boolean
18
- links: ItemLink[]
19
- }
@@ -1,2 +0,0 @@
1
- export * as Tree from './tree.ts'
2
- export type { TreeMapper, TreeNode, TreePredicate, TreeVisitor } from './tree.ts'
@@ -1,117 +0,0 @@
1
- import { describe, expect, test } from 'vitest'
2
- import * as Tree from './tree.ts'
3
-
4
- describe('Tree', () => {
5
- const sampleTree = Tree.node('root', [
6
- Tree.node('a', [
7
- Tree.node('a1'),
8
- Tree.node('a2'),
9
- ]),
10
- Tree.node('b', [
11
- Tree.node('b1'),
12
- ]),
13
- Tree.node('c'),
14
- ])
15
-
16
- test('node creates a tree node', () => {
17
- const leaf = Tree.node('leaf')
18
- expect(leaf).toEqual({ value: 'leaf', children: [] })
19
-
20
- const parent = Tree.node('parent', [leaf])
21
- expect(parent).toEqual({ value: 'parent', children: [leaf] })
22
- })
23
-
24
- test('map transforms node values', () => {
25
- const upperTree = Tree.map(sampleTree, value => value.toUpperCase())
26
-
27
- expect(upperTree.value).toBe('ROOT')
28
- expect(upperTree.children[0]!.value).toBe('A')
29
- expect(upperTree.children[0]!.children[0]!.value).toBe('A1')
30
- })
31
-
32
- test('map provides depth and path', () => {
33
- const depths: number[] = []
34
- const paths: string[][] = []
35
-
36
- Tree.map(sampleTree, (value, depth, path) => {
37
- depths.push(depth)
38
- paths.push(path)
39
- return value
40
- })
41
-
42
- expect(depths).toEqual([0, 1, 2, 2, 1, 2, 1])
43
- expect(paths[0]).toEqual([])
44
- expect(paths[1]).toEqual(['root'])
45
- expect(paths[2]).toEqual(['root', 'a'])
46
- })
47
-
48
- test('visit traverses all nodes', () => {
49
- const visited: string[] = []
50
- Tree.visit(sampleTree, node => visited.push(node.value))
51
-
52
- expect(visited).toEqual(['root', 'a', 'a1', 'a2', 'b', 'b1', 'c'])
53
- })
54
-
55
- test('find locates node', () => {
56
- const found = Tree.find(sampleTree, value => value === 'b1')
57
- expect(found?.value).toBe('b1')
58
-
59
- const notFound = Tree.find(sampleTree, value => value === 'x')
60
- expect(notFound).toBeUndefined()
61
- })
62
-
63
- test('filter removes non-matching nodes', () => {
64
- const filtered = Tree.filter(sampleTree, value => !value.includes('2'))
65
-
66
- expect(filtered).toBeDefined()
67
- expect(Tree.flatten(filtered!)).toEqual(['root', 'a', 'a1', 'b', 'b1', 'c'])
68
- })
69
-
70
- test('sort orders children', () => {
71
- const sorted = Tree.sort(sampleTree, (a, b) => b.localeCompare(a))
72
-
73
- expect(sorted.children.map(c => c.value)).toEqual(['c', 'b', 'a'])
74
- expect(sorted.children[2]!.children.map(c => c.value)).toEqual(['a2', 'a1'])
75
- })
76
-
77
- test('flatten returns all values', () => {
78
- const flat = Tree.flatten(sampleTree)
79
- expect(flat).toEqual(['root', 'a', 'a1', 'a2', 'b', 'b1', 'c'])
80
- })
81
-
82
- test('depth calculates tree depth', () => {
83
- expect(Tree.depth(Tree.node('single'))).toBe(0)
84
- expect(Tree.depth(sampleTree)).toBe(2)
85
- })
86
-
87
- test('count counts all nodes', () => {
88
- expect(Tree.count(Tree.node('single'))).toBe(1)
89
- expect(Tree.count(sampleTree)).toBe(7)
90
- })
91
-
92
- test('isLeaf identifies leaf nodes', () => {
93
- expect(Tree.isLeaf(sampleTree)).toBe(false)
94
- expect(Tree.isLeaf(sampleTree.children[0]!)).toBe(false)
95
- expect(Tree.isLeaf(sampleTree.children[0]!.children[0]!)).toBe(true)
96
- })
97
-
98
- test('leaves gets all leaf nodes', () => {
99
- const leafNodes = Tree.leaves(sampleTree)
100
- expect(leafNodes.map(n => n.value)).toEqual(['a1', 'a2', 'b1', 'c'])
101
- })
102
-
103
- test('fromList builds tree from flat list', () => {
104
- const items = [
105
- { id: '1', name: 'root' },
106
- { id: '2', parentId: '1', name: 'child1' },
107
- { id: '3', parentId: '1', name: 'child2' },
108
- { id: '4', parentId: '2', name: 'grandchild' },
109
- ]
110
-
111
- const trees = Tree.fromList(items, undefined)
112
- expect(trees).toHaveLength(1)
113
- expect(trees[0]!.value.name).toBe('root')
114
- expect(trees[0]!.children).toHaveLength(2)
115
- expect(trees[0]!.children[0]!.children[0]!.value.name).toBe('grandchild')
116
- })
117
- })
@@ -1,183 +0,0 @@
1
- /**
2
- * Generic tree data structure and utilities
3
- */
4
-
5
- export interface TreeNode<T> {
6
- value: T
7
- children: TreeNode<T>[]
8
- }
9
-
10
- export type TreeVisitor<T, R = void> = (node: TreeNode<T>, depth: number, path: T[]) => R
11
-
12
- export type TreeMapper<T, U> = (value: T, depth: number, path: T[]) => U
13
-
14
- export type TreePredicate<T> = (value: T, depth: number, path: T[]) => boolean
15
-
16
- /**
17
- * Create a new tree node
18
- */
19
- export const node = <T>(value: T, children: TreeNode<T>[] = []): TreeNode<T> => ({
20
- value,
21
- children,
22
- })
23
-
24
- /**
25
- * Map over a tree, transforming each node's value
26
- */
27
- export const map = <T, U>(
28
- tree: TreeNode<T>,
29
- mapper: TreeMapper<T, U>,
30
- depth = 0,
31
- path: T[] = [],
32
- ): TreeNode<U> => {
33
- const newPath = [...path, tree.value]
34
- return {
35
- value: mapper(tree.value, depth, path),
36
- children: tree.children.map(child => map(child, mapper, depth + 1, newPath)),
37
- }
38
- }
39
-
40
- /**
41
- * Visit each node in the tree (depth-first)
42
- */
43
- export const visit = <T>(
44
- tree: TreeNode<T>,
45
- visitor: TreeVisitor<T>,
46
- depth = 0,
47
- path: T[] = [],
48
- ): void => {
49
- visitor(tree, depth, path)
50
- const newPath = [...path, tree.value]
51
- tree.children.forEach(child => visit(child, visitor, depth + 1, newPath))
52
- }
53
-
54
- /**
55
- * Find a node in the tree
56
- */
57
- export const find = <T>(
58
- tree: TreeNode<T>,
59
- predicate: TreePredicate<T>,
60
- depth = 0,
61
- path: T[] = [],
62
- ): TreeNode<T> | undefined => {
63
- if (predicate(tree.value, depth, path)) {
64
- return tree
65
- }
66
- const newPath = [...path, tree.value]
67
- for (const child of tree.children) {
68
- const found = find(child, predicate, depth + 1, newPath)
69
- if (found) return found
70
- }
71
- return undefined
72
- }
73
-
74
- /**
75
- * Filter tree nodes (keeps structure, removes non-matching nodes)
76
- */
77
- export const filter = <T>(
78
- tree: TreeNode<T>,
79
- predicate: TreePredicate<T>,
80
- depth = 0,
81
- path: T[] = [],
82
- ): TreeNode<T> | undefined => {
83
- const newPath = [...path, tree.value]
84
- const filteredChildren = tree.children
85
- .map(child => filter(child, predicate, depth + 1, newPath))
86
- .filter((child): child is TreeNode<T> => child !== undefined)
87
-
88
- // Keep node if it matches or has matching children
89
- if (predicate(tree.value, depth, path) || filteredChildren.length > 0) {
90
- return {
91
- value: tree.value,
92
- children: filteredChildren,
93
- }
94
- }
95
-
96
- return undefined
97
- }
98
-
99
- /**
100
- * Sort a tree's children at each level
101
- */
102
- export const sort = <T>(
103
- tree: TreeNode<T>,
104
- compareFn: (a: T, b: T) => number,
105
- ): TreeNode<T> => ({
106
- value: tree.value,
107
- children: tree.children
108
- .map(child => sort(child, compareFn))
109
- .sort((a, b) => compareFn(a.value, b.value)),
110
- })
111
-
112
- /**
113
- * Flatten a tree into an array (depth-first)
114
- */
115
- export const flatten = <T>(tree: TreeNode<T>): T[] => {
116
- const result: T[] = [tree.value]
117
- tree.children.forEach(child => {
118
- result.push(...flatten(child))
119
- })
120
- return result
121
- }
122
-
123
- /**
124
- * Get the depth of the tree
125
- */
126
- export const depth = <T>(tree: TreeNode<T>): number => {
127
- if (tree.children.length === 0) return 0
128
- return 1 + Math.max(...tree.children.map(depth))
129
- }
130
-
131
- /**
132
- * Count total nodes in the tree
133
- */
134
- export const count = <T>(tree: TreeNode<T>): number => {
135
- return 1 + tree.children.reduce((sum, child) => sum + count(child), 0)
136
- }
137
-
138
- /**
139
- * Check if a node is a leaf (has no children)
140
- */
141
- export const isLeaf = <T>(node: TreeNode<T>): boolean => {
142
- return node.children.length === 0
143
- }
144
-
145
- /**
146
- * Get all leaf nodes
147
- */
148
- export const leaves = <T>(tree: TreeNode<T>): TreeNode<T>[] => {
149
- if (isLeaf(tree)) return [tree]
150
- return tree.children.flatMap(leaves)
151
- }
152
-
153
- /**
154
- * Build a tree from a flat list with parent references
155
- */
156
- export const fromList = <T extends { id: string; parentId?: string }>(
157
- items: T[],
158
- rootId?: string,
159
- ): TreeNode<T>[] => {
160
- const itemMap = new Map(items.map(item => [item.id, item]))
161
- const roots: TreeNode<T>[] = []
162
- const nodeMap = new Map<string, TreeNode<T>>()
163
-
164
- // Create all nodes
165
- items.forEach(item => {
166
- nodeMap.set(item.id, node(item))
167
- })
168
-
169
- // Build hierarchy
170
- items.forEach(item => {
171
- const itemNode = nodeMap.get(item.id)!
172
- if (item.parentId === rootId) {
173
- roots.push(itemNode)
174
- } else if (item.parentId) {
175
- const parent = nodeMap.get(item.parentId)
176
- if (parent) {
177
- parent.children.push(itemNode)
178
- }
179
- }
180
- })
181
-
182
- return roots
183
- }