polen 0.8.0-next.4 → 0.8.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.
- package/build/api/vite/plugins/core.d.ts.map +1 -1
- package/build/api/vite/plugins/core.js +83 -52
- package/build/api/vite/plugins/core.js.map +1 -1
- package/build/lib/file-router/linter.d.ts.map +1 -1
- package/build/lib/file-router/linter.js +3 -3
- package/build/lib/file-router/linter.js.map +1 -1
- package/build/lib/file-router/route.d.ts +48 -10
- package/build/lib/file-router/route.d.ts.map +1 -1
- package/build/lib/file-router/route.js +68 -3
- package/build/lib/file-router/route.js.map +1 -1
- package/build/lib/file-router/scan.d.ts +2 -2
- package/build/lib/file-router/scan.d.ts.map +1 -1
- package/build/lib/file-router/scan.js +8 -8
- package/build/lib/file-router/scan.js.map +1 -1
- package/build/lib/kit-temp.d.ts +2 -0
- package/build/lib/kit-temp.d.ts.map +1 -0
- package/build/lib/kit-temp.js +23 -0
- package/build/lib/kit-temp.js.map +1 -0
- package/build/project-data.d.ts +10 -1
- package/build/project-data.d.ts.map +1 -1
- package/build/template/components/Sidebar.d.ts +11 -0
- package/build/template/components/Sidebar.d.ts.map +1 -0
- package/build/template/components/Sidebar.jsx +47 -0
- package/build/template/components/Sidebar.jsx.map +1 -0
- package/build/template/routes/root.d.ts.map +1 -1
- package/build/template/routes/root.jsx +28 -5
- package/build/template/routes/root.jsx.map +1 -1
- package/package.json +1 -1
- package/src/api/vite/plugins/core.ts +97 -54
- package/src/lib/file-router/index.test.ts +5 -5
- package/src/lib/file-router/linter.ts +3 -3
- package/src/lib/file-router/route.ts +147 -11
- package/src/lib/file-router/scan.ts +9 -9
- package/src/lib/kit-temp.ts +21 -0
- package/src/project-data.ts +12 -1
- package/src/template/components/Sidebar.tsx +92 -0
- package/src/template/routes/root.tsx +35 -5
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"root.d.ts","sourceRoot":"","sources":["../../../src/template/routes/root.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAA;
|
1
|
+
{"version":3,"file":"root.d.ts","sourceRoot":"","sources":["../../../src/template/routes/root.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAA;AA0B7D,eAAO,MAAM,SAAS,mCA6BrB,CAAA;AAgJD,eAAO,MAAM,IAAI;;;;CAIf,CAAA"}
|
@@ -4,10 +4,11 @@ import { Box, Button, Heading, Text } from '@radix-ui/themes';
|
|
4
4
|
import { Flex, Theme } from '@radix-ui/themes';
|
5
5
|
import radixStylesUrl from '@radix-ui/themes/styles.css?url';
|
6
6
|
import { Link as LinkReactRouter } from 'react-router';
|
7
|
-
import { Outlet, ScrollRestoration } from 'react-router';
|
7
|
+
import { Outlet, ScrollRestoration, useLocation } from 'react-router';
|
8
8
|
import { PROJECT_DATA } from 'virtual:polen/project/data';
|
9
9
|
import { templateVariables } from 'virtual:polen/template/variables';
|
10
10
|
import { Link } from '../components/Link.jsx';
|
11
|
+
import { Sidebar } from '../components/Sidebar.jsx';
|
11
12
|
import entryClientUrl from '../entry.client.jsx?url';
|
12
13
|
import { changelog } from './changelog.jsx';
|
13
14
|
import { index } from './index.jsx';
|
@@ -40,6 +41,20 @@ export const Component = () => {
|
|
40
41
|
</html>);
|
41
42
|
};
|
42
43
|
const Layout = () => {
|
44
|
+
const location = useLocation();
|
45
|
+
// Determine if we should show sidebar based on current path
|
46
|
+
const getCurrentNavPathExp = () => {
|
47
|
+
// todo: general path manipulation lib because we are duplicating logic here found in FileRouter
|
48
|
+
// todo: kit: try a Str.split that returns [] | string[] so that our predicates can refine on it?
|
49
|
+
const segments = location.pathname.split(`/`).filter(Boolean);
|
50
|
+
if (Arr.isntEmpty(segments)) {
|
51
|
+
return `/${segments[0]}`;
|
52
|
+
}
|
53
|
+
return null;
|
54
|
+
};
|
55
|
+
const currentNavPathExp = getCurrentNavPathExp();
|
56
|
+
const sidebarItems = currentNavPathExp && PROJECT_DATA.sidebar[currentNavPathExp];
|
57
|
+
const showSidebar = sidebarItems && sidebarItems.length > 0;
|
43
58
|
return (<Theme asChild>
|
44
59
|
<Box m='8'>
|
45
60
|
<Flex align='center' gap='8' pb='4' mb='8' style={{
|
@@ -54,14 +69,21 @@ const Layout = () => {
|
|
54
69
|
</Flex>
|
55
70
|
</LinkReactRouter>
|
56
71
|
<Flex direction='row' gap='4'>
|
57
|
-
{PROJECT_DATA.siteNavigationItems.map((item, key) => (<Link key={key} color='gray' to={item.
|
72
|
+
{PROJECT_DATA.siteNavigationItems.map((item, key) => (<Link key={key} color='gray' to={item.pathExp}>
|
58
73
|
{item.title}
|
59
74
|
</Link>))}
|
60
75
|
</Flex>
|
61
76
|
</Flex>
|
62
|
-
|
63
|
-
|
64
|
-
|
77
|
+
{showSidebar
|
78
|
+
? (<Flex gap='8'>
|
79
|
+
<Sidebar items={sidebarItems}/>
|
80
|
+
<Box style={{ flex: 1 }}>
|
81
|
+
<Outlet />
|
82
|
+
</Box>
|
83
|
+
</Flex>)
|
84
|
+
: (<Box>
|
85
|
+
<Outlet />
|
86
|
+
</Box>)}
|
65
87
|
</Box>
|
66
88
|
</Theme>);
|
67
89
|
};
|
@@ -127,6 +149,7 @@ children.push(notFoundRoute);
|
|
127
149
|
// ━━━━━━━━━━━━━━ • Root Route
|
128
150
|
//
|
129
151
|
//
|
152
|
+
import { Arr } from '@wollybeard/kit';
|
130
153
|
import { pages } from 'virtual:polen/project/pages.jsx';
|
131
154
|
export const root = createRoute({
|
132
155
|
path: `/`,
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"root.jsx","sourceRoot":"","sources":["../../../src/template/routes/root.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,2CAA2C,CAAA;AACvE,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AACtD,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAA;AAC7D,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAA;AAC9C,OAAO,cAAc,MAAM,iCAAiC,CAAA;AAC5D,OAAO,EAAE,IAAI,IAAI,eAAe,EAAE,MAAM,cAAc,CAAA;AACtD,OAAO,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAA;
|
1
|
+
{"version":3,"file":"root.jsx","sourceRoot":"","sources":["../../../src/template/routes/root.tsx"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
@@ -1,13 +1,12 @@
|
|
1
|
-
import { Markdown } from '#api/singletons/markdown/index.js'
|
2
1
|
import type { ReactRouter } from '#dep/react-router/index.js'
|
3
2
|
import type { Vite } from '#dep/vite/index.js'
|
4
3
|
import { FileRouter } from '#lib/file-router/index.js'
|
5
4
|
import { ViteVirtual } from '#lib/vite-virtual/index.js'
|
6
5
|
import mdx from '@mdx-js/rollup'
|
7
|
-
import { Cache,
|
6
|
+
import { Cache, Json, Path, Str } from '@wollybeard/kit'
|
8
7
|
import jsesc from 'jsesc'
|
9
8
|
import remarkGfm from 'remark-gfm'
|
10
|
-
import type { ProjectData, SiteNavigationItem } from '../../../project-data.js'
|
9
|
+
import type { ProjectData, Sidebar, SidebarItem, SiteNavigationItem } from '../../../project-data.js'
|
11
10
|
import { superjson } from '../../../singletons/superjson.js'
|
12
11
|
import type { Configurator } from '../../configurator/index.js'
|
13
12
|
import { SchemaAugmentation } from '../../schema-augmentation/index.js'
|
@@ -53,27 +52,31 @@ export const Core = (config: Configurator.Config): Vite.PluginOption[] => {
|
|
53
52
|
],
|
54
53
|
}),
|
55
54
|
},
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
55
|
+
// TODO: We can remove, mdx subsumes this
|
56
|
+
// TODO: First we need to investigate how e can make our api singleton Markdown used by MDX.
|
57
|
+
// If we cannot, then we might want to ditch MDX instead and use our lower level solution here.
|
58
|
+
// It depends in part on how complex our Markdown singleton gets.
|
59
|
+
// {
|
60
|
+
// name: `polen:markdown`,
|
61
|
+
// enforce: `pre`,
|
62
|
+
// resolveId(id) {
|
63
|
+
// if (id.endsWith(`.md`)) {
|
64
|
+
// return id
|
65
|
+
// }
|
66
|
+
// return null
|
67
|
+
// },
|
68
|
+
// async load(id) {
|
69
|
+
// if (id.endsWith(`.md`)) {
|
70
|
+
// const markdownString = await Fs.read(id)
|
71
|
+
// if (!markdownString) return null
|
72
|
+
// const htmlString = await Markdown.parse(markdownString)
|
73
|
+
|
74
|
+
// const code = `export default ${JSON.stringify(htmlString)}`
|
75
|
+
// return code
|
76
|
+
// }
|
77
|
+
// return null
|
78
|
+
// },
|
79
|
+
// },
|
77
80
|
{
|
78
81
|
name: `polen:core:alias`,
|
79
82
|
resolveId(id, importer) {
|
@@ -136,35 +139,84 @@ export const Core = (config: Configurator.Config): Vite.PluginOption[] => {
|
|
136
139
|
async loader() {
|
137
140
|
// todo: parallel
|
138
141
|
const schema = await readSchema()
|
139
|
-
console.log({ schema })
|
140
142
|
const pagesScanResult = await scanPageRoutes()
|
141
143
|
|
142
144
|
const siteNavigationItems: SiteNavigationItem[] = []
|
143
145
|
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
.map(route => {
|
148
|
-
const path = FileRouter.routeToString(route)
|
149
|
-
const title = Str.titlizeSlug(path)
|
150
|
-
return {
|
151
|
-
path,
|
152
|
-
title,
|
153
|
-
}
|
154
|
-
})
|
146
|
+
//
|
147
|
+
// ━━ Build Navbar
|
148
|
+
//
|
155
149
|
|
156
|
-
|
150
|
+
// ━ Top pages become navigation items
|
151
|
+
const topPages = pagesScanResult.routes.filter(FileRouter.routeIsTopLevel)
|
152
|
+
|
153
|
+
for (const page of topPages) {
|
154
|
+
const path = FileRouter.routeToPathExpression(page)
|
155
|
+
const title = Str.titlizeSlug(path)
|
156
|
+
siteNavigationItems.push({ pathExp: path, title })
|
157
|
+
}
|
157
158
|
|
159
|
+
// ━ Top directories become navigation items
|
160
|
+
const topDirsPaths = pagesScanResult.routes
|
161
|
+
.filter(FileRouter.routeIsSubLevel)
|
162
|
+
// todo: kit, slice that understands non-empty
|
163
|
+
// Arr.slice(route.path.segments, 1)
|
164
|
+
.map(route => [route.logical.path[0]])
|
165
|
+
|
166
|
+
for (const dir of topDirsPaths) {
|
167
|
+
const pathExp = FileRouter.pathToExpression(dir)
|
168
|
+
const title = Str.titlizeSlug(pathExp)
|
169
|
+
// todo: this should never happen, if it does, swarn user
|
170
|
+
// Only add if not already added as a top page
|
171
|
+
if (!siteNavigationItems.some(item => item.pathExp === pathExp)) {
|
172
|
+
siteNavigationItems.push({ pathExp: pathExp, title })
|
173
|
+
}
|
174
|
+
}
|
175
|
+
|
176
|
+
// ━ Schema presence causes adding some navbar items
|
158
177
|
if (schema) {
|
159
|
-
siteNavigationItems.push({
|
178
|
+
siteNavigationItems.push({ pathExp: `/reference`, title: `Reference` })
|
160
179
|
if (schema.versions.length > 1) {
|
161
|
-
siteNavigationItems.push({
|
180
|
+
siteNavigationItems.push({ pathExp: `/changelog`, title: `Changelog` })
|
162
181
|
}
|
163
182
|
}
|
164
183
|
|
184
|
+
//
|
185
|
+
// ━━ Build Sidebar
|
186
|
+
//
|
187
|
+
|
188
|
+
const sidebar: Sidebar = {}
|
189
|
+
|
190
|
+
for (const dirPath of topDirsPaths) {
|
191
|
+
const childPages = pagesScanResult.routes.filter(page => FileRouter.routeIsSubOf(page, dirPath))
|
192
|
+
|
193
|
+
const sidebarItems: SidebarItem[] = []
|
194
|
+
|
195
|
+
// ━ Pages in this dir become sidebar items
|
196
|
+
for (const childPage of childPages) {
|
197
|
+
const childPageRelative = FileRouter.makeRelativeUnsafe(childPage, dirPath)
|
198
|
+
|
199
|
+
if (FileRouter.routeIsRootLevel(childPageRelative)) {
|
200
|
+
// We elide root from items. Root represents this whole group of items.
|
201
|
+
continue
|
202
|
+
}
|
203
|
+
|
204
|
+
if (FileRouter.routeIsTopLevel(childPageRelative)) {
|
205
|
+
const pathExp = FileRouter.routeToPathExpression(childPage)
|
206
|
+
const relativePathExp = FileRouter.routeToPathExpression(childPageRelative)
|
207
|
+
const title = Str.titlizeSlug(relativePathExp)
|
208
|
+
sidebarItems.push({ pathExp, title })
|
209
|
+
}
|
210
|
+
// TODO: Handle nested directories in phase 3
|
211
|
+
}
|
212
|
+
|
213
|
+
sidebar[FileRouter.pathToExpression(dirPath)] = sidebarItems
|
214
|
+
}
|
215
|
+
|
165
216
|
const projectData: ProjectData = {
|
166
217
|
schema,
|
167
218
|
siteNavigationItems,
|
219
|
+
sidebar,
|
168
220
|
faviconPath: `/logo.svg`,
|
169
221
|
pagesScanResult: pagesScanResult,
|
170
222
|
paths: config.paths.project,
|
@@ -204,25 +256,16 @@ export const Core = (config: Configurator.Config): Vite.PluginOption[] => {
|
|
204
256
|
|
205
257
|
// todo: kit fs should accept parsed file paths
|
206
258
|
for (const route of pagesScanResult.routes) {
|
207
|
-
const
|
208
|
-
const
|
209
|
-
const ident = Str.Case.camel(`page ` + Str.titlizeSlug(
|
259
|
+
const filePathExp = Path.format(route.file.path.absolute)
|
260
|
+
const pathExp = FileRouter.routeToPathExpression(route)
|
261
|
+
const ident = Str.Case.camel(`page ` + Str.titlizeSlug(pathExp))
|
210
262
|
|
211
263
|
s`
|
212
|
-
import ${ident} from '${
|
264
|
+
import ${ident} from '${filePathExp}'
|
213
265
|
|
214
266
|
${$.pages}.push({
|
215
|
-
path: '${
|
216
|
-
Component:
|
217
|
-
if (typeof ${ident} === 'function') {
|
218
|
-
// ━ MDX
|
219
|
-
const Component = ${ident}
|
220
|
-
return <Component />
|
221
|
-
} else {
|
222
|
-
// ━ MD
|
223
|
-
return <div dangerouslySetInnerHTML={{ __html: ${ident} }} />
|
224
|
-
}
|
225
|
-
}
|
267
|
+
path: '${pathExp}',
|
268
|
+
Component: ${ident}
|
226
269
|
})
|
227
270
|
`
|
228
271
|
}
|
@@ -21,7 +21,7 @@ describe('.scan', () => {
|
|
21
21
|
const routes = await scan(project.dir)
|
22
22
|
expect(routes).toMatchObject($({
|
23
23
|
routes: [{
|
24
|
-
|
24
|
+
logical: { path: ['a'] },
|
25
25
|
file: { path: { relative: { dir: '', base: 'a.md' } } },
|
26
26
|
}],
|
27
27
|
}))
|
@@ -31,7 +31,7 @@ describe('.scan', () => {
|
|
31
31
|
const routes = await scan(project.dir)
|
32
32
|
expect(routes).toMatchObject($({
|
33
33
|
routes: [{
|
34
|
-
|
34
|
+
logical: { path: ['a', 'b'] },
|
35
35
|
file: { path: { relative: { dir: 'a', base: 'b.md' } } },
|
36
36
|
}],
|
37
37
|
}))
|
@@ -43,7 +43,7 @@ describe('.scan', () => {
|
|
43
43
|
const routes = await scan(project.dir)
|
44
44
|
expect(routes).toMatchObject($({
|
45
45
|
routes: [{
|
46
|
-
|
46
|
+
logical: { path: [] },
|
47
47
|
file: { path: { relative: { dir: '', base: 'index.md' } } },
|
48
48
|
}],
|
49
49
|
}))
|
@@ -53,7 +53,7 @@ describe('.scan', () => {
|
|
53
53
|
const routes = await scan(project.dir)
|
54
54
|
expect(routes).toMatchObject($({
|
55
55
|
routes: [{
|
56
|
-
|
56
|
+
logical: { path: ['a'] },
|
57
57
|
file: { path: { relative: { dir: 'a', base: 'index.md' } } },
|
58
58
|
}],
|
59
59
|
}))
|
@@ -66,7 +66,7 @@ describe('.scan', () => {
|
|
66
66
|
expect(routes).toMatchObject($({
|
67
67
|
diagnostics: [{}],
|
68
68
|
routes: [{
|
69
|
-
|
69
|
+
logical: { path: ['a'] },
|
70
70
|
file: { path: { relative: { dir: '', base: 'a.md' } } },
|
71
71
|
}],
|
72
72
|
}))
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import { Idx, Path } from '@wollybeard/kit'
|
2
|
-
import { type Route, type RouteFile,
|
2
|
+
import { type Route, type RouteFile, routeIsFromIndexFile, routeToPathExpression } from './route.js'
|
3
3
|
|
4
4
|
export type Diagnostic = DiagnosticIndexConflict
|
5
5
|
|
@@ -21,7 +21,7 @@ export interface LintResult {
|
|
21
21
|
export const lint = (routes: Route[]): LintResult => {
|
22
22
|
const diagnostics: Diagnostic[] = []
|
23
23
|
|
24
|
-
const seen = Idx.create({ toKey:
|
24
|
+
const seen = Idx.create({ toKey: routeToPathExpression })
|
25
25
|
|
26
26
|
// ━ Check for conflict between index and literal.
|
27
27
|
// Note: There is no other way for paths to conflict so we safely assuming the cause is index+literal.
|
@@ -31,7 +31,7 @@ export const lint = (routes: Route[]): LintResult => {
|
|
31
31
|
|
32
32
|
if (seenRoute) {
|
33
33
|
// Fix - ignore the index
|
34
|
-
const [index, literal] =
|
34
|
+
const [index, literal] = routeIsFromIndexFile(route) ? [route, seenRoute] : [seenRoute, route]
|
35
35
|
if (seenRoute === index) {
|
36
36
|
seen.set(route)
|
37
37
|
}
|
@@ -1,9 +1,45 @@
|
|
1
|
-
import
|
1
|
+
import { arrayEquals } from '#lib/kit-temp.js'
|
2
|
+
import { type Path } from '@wollybeard/kit'
|
2
3
|
|
3
|
-
|
4
|
+
//
|
5
|
+
//
|
6
|
+
//
|
7
|
+
//
|
8
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ • Path
|
9
|
+
//
|
10
|
+
//
|
4
11
|
|
5
|
-
export
|
6
|
-
|
12
|
+
export type Path = PathSegment[]
|
13
|
+
|
14
|
+
export type PathRoot = []
|
15
|
+
|
16
|
+
export type PathTop = [PathSegment]
|
17
|
+
|
18
|
+
export type PathSub = [PathSegment, PathSegment, ...PathSegment[]]
|
19
|
+
|
20
|
+
export type PathSegment = string
|
21
|
+
|
22
|
+
export const sep = `/`
|
23
|
+
|
24
|
+
export const pathToExpression = (path: Path) => {
|
25
|
+
return sep + path.join(sep)
|
26
|
+
}
|
27
|
+
|
28
|
+
//
|
29
|
+
//
|
30
|
+
//
|
31
|
+
//
|
32
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ • Route (Generic)
|
33
|
+
//
|
34
|
+
//
|
35
|
+
|
36
|
+
export interface Route {
|
37
|
+
logical: RouteLogical
|
38
|
+
file: RouteFile
|
39
|
+
}
|
40
|
+
|
41
|
+
export interface RouteLogical {
|
42
|
+
path: Path
|
7
43
|
}
|
8
44
|
|
9
45
|
export interface RouteFile {
|
@@ -13,21 +49,121 @@ export interface RouteFile {
|
|
13
49
|
}
|
14
50
|
}
|
15
51
|
|
16
|
-
|
17
|
-
|
18
|
-
|
52
|
+
//
|
53
|
+
//
|
54
|
+
//
|
55
|
+
//
|
56
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ • Top Level Route
|
57
|
+
//
|
58
|
+
//
|
59
|
+
|
60
|
+
export interface TopLevelRoute extends Route {
|
61
|
+
logical: TopLevelRouteLogical
|
19
62
|
}
|
20
63
|
|
21
|
-
export
|
64
|
+
export interface TopLevelRouteLogical {
|
65
|
+
path: PathTop
|
66
|
+
}
|
22
67
|
|
23
|
-
|
24
|
-
|
68
|
+
/**
|
69
|
+
* Route is top level meaning exists directly under the root.
|
70
|
+
*
|
71
|
+
* It excludes the root level route.
|
72
|
+
*/
|
73
|
+
export const routeIsTopLevel = (route: Route): route is TopLevelRoute => {
|
74
|
+
return route.logical.path.length === 1
|
25
75
|
}
|
26
76
|
|
27
|
-
|
77
|
+
//
|
78
|
+
// ━━ Sub Level
|
79
|
+
//
|
80
|
+
|
81
|
+
//
|
82
|
+
//
|
83
|
+
//
|
84
|
+
//
|
85
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ • Sub Level Route
|
86
|
+
//
|
87
|
+
//
|
88
|
+
|
89
|
+
export interface RouteSubLevel extends Route {
|
90
|
+
logical: RoutePathSubLevel
|
91
|
+
}
|
92
|
+
|
93
|
+
export interface RoutePathSubLevel {
|
94
|
+
path: PathSub
|
95
|
+
}
|
96
|
+
|
97
|
+
/**
|
98
|
+
* Route is not top or root level
|
99
|
+
*/
|
100
|
+
export const routeIsSubLevel = (route: Route): route is RouteSubLevel => {
|
101
|
+
return route.logical.path.length > 1
|
102
|
+
}
|
103
|
+
|
104
|
+
//
|
105
|
+
// ━━ Root Level
|
106
|
+
//
|
107
|
+
|
108
|
+
//
|
109
|
+
//
|
110
|
+
//
|
111
|
+
//
|
112
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ • Root Level Route
|
113
|
+
//
|
114
|
+
//
|
115
|
+
|
116
|
+
/**
|
117
|
+
* Route is the singular root route.
|
118
|
+
|
119
|
+
* This is the case of index under root.
|
120
|
+
*/
|
121
|
+
export const routeIsRootLevel = (route: Route): route is TopLevelRoute => {
|
122
|
+
// No need to check for name "index"
|
123
|
+
// Segments is uniquely empty for <root>/index
|
124
|
+
return route.logical.path.length === 0
|
125
|
+
}
|
126
|
+
|
127
|
+
//
|
128
|
+
//
|
129
|
+
//
|
130
|
+
// ━━━━━━━━━━━━━━ • Route Functions
|
131
|
+
//
|
132
|
+
//
|
133
|
+
|
134
|
+
export const routeIsFromIndexFile = (route: Route): boolean => {
|
28
135
|
return route.file.path.relative.name === conventions.index.name
|
29
136
|
}
|
30
137
|
|
138
|
+
export const routeIsSubOf = (route: Route, potentialAncestorPath: PathSegment[]): boolean => {
|
139
|
+
if (route.logical.path.length <= potentialAncestorPath.length) {
|
140
|
+
return false
|
141
|
+
}
|
142
|
+
return arrayEquals(
|
143
|
+
route.logical.path.slice(0, potentialAncestorPath.length),
|
144
|
+
potentialAncestorPath,
|
145
|
+
)
|
146
|
+
}
|
147
|
+
|
148
|
+
/**
|
149
|
+
* You are responsible for ensuring given ancestor path is really an ancestor of given route's path.
|
150
|
+
*/
|
151
|
+
export const makeRelativeUnsafe = (route: Route, assumedAncestorPath: PathSegment[]): Route => {
|
152
|
+
// We assume that we're working with paths where index is elided per our FileRouter system.
|
153
|
+
const newPath = route.logical.path.slice(assumedAncestorPath.length)
|
154
|
+
return {
|
155
|
+
...route,
|
156
|
+
logical: {
|
157
|
+
...route.logical,
|
158
|
+
path: newPath,
|
159
|
+
},
|
160
|
+
}
|
161
|
+
}
|
162
|
+
|
163
|
+
export const routeToPathExpression = (route: Route) => {
|
164
|
+
return pathToExpression(route.logical.path)
|
165
|
+
}
|
166
|
+
|
31
167
|
const conventions = {
|
32
168
|
index: {
|
33
169
|
name: `index`,
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import { TinyGlobby } from '#dep/tiny-globby/index.js'
|
2
2
|
import { Path, Str } from '@wollybeard/kit'
|
3
3
|
import { type Diagnostic, lint } from './linter.js'
|
4
|
-
import type { Route, RouteFile,
|
4
|
+
import type { Route, RouteFile, RouteLogical } from './route.js'
|
5
5
|
|
6
6
|
//
|
7
7
|
//
|
@@ -64,26 +64,26 @@ export const filePathToRoute = (filePathExpression: string, rootDir: string): Ro
|
|
64
64
|
relative: Path.parse(Path.relative(rootDir, filePathExpression)),
|
65
65
|
},
|
66
66
|
}
|
67
|
-
const
|
67
|
+
const logical = filePathToRouteLogical(file.path.relative)
|
68
68
|
|
69
69
|
return {
|
70
|
-
|
70
|
+
logical,
|
71
71
|
file,
|
72
72
|
}
|
73
73
|
}
|
74
74
|
|
75
|
-
export const
|
76
|
-
const
|
75
|
+
export const filePathToRouteLogical = (filePath: Path.Parsed): RouteLogical => {
|
76
|
+
const dirPath = Str.split(Str.removeSurrounding(filePath.dir, Path.sep), Path.sep)
|
77
77
|
|
78
78
|
if (Str.isMatch(filePath.name, conventions.index.name)) {
|
79
|
-
const
|
79
|
+
const path = dirPath
|
80
80
|
return {
|
81
|
-
|
81
|
+
path,
|
82
82
|
}
|
83
83
|
}
|
84
84
|
|
85
|
-
const
|
85
|
+
const path = dirPath.concat(filePath.name)
|
86
86
|
return {
|
87
|
-
|
87
|
+
path,
|
88
88
|
}
|
89
89
|
}
|
@@ -0,0 +1,21 @@
|
|
1
|
+
//
|
2
|
+
//
|
3
|
+
//
|
4
|
+
//
|
5
|
+
//
|
6
|
+
// Holding Module for Missing @wollybeard/kit Functionality
|
7
|
+
//
|
8
|
+
// ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
|
9
|
+
//
|
10
|
+
// Code here is meant to be migrated eventually to @wollybeard/kit.
|
11
|
+
//
|
12
|
+
//
|
13
|
+
//
|
14
|
+
|
15
|
+
export const arrayEquals = (a: any[], b: any[]) => {
|
16
|
+
if (a.length !== b.length) return false
|
17
|
+
for (let i = 0; i < a.length; i++) {
|
18
|
+
if (a[i] !== b[i]) return false
|
19
|
+
}
|
20
|
+
return true
|
21
|
+
}
|
package/src/project-data.ts
CHANGED
@@ -5,6 +5,7 @@ import type { Schema } from './api/schema/index.js'
|
|
5
5
|
export interface ProjectData {
|
6
6
|
schema: null | Schema.Schema
|
7
7
|
siteNavigationItems: SiteNavigationItem[]
|
8
|
+
sidebar: Sidebar
|
8
9
|
faviconPath: string
|
9
10
|
paths: Configurator.Config[`paths`][`project`]
|
10
11
|
pagesScanResult: FileRouter.ScanResult
|
@@ -18,5 +19,15 @@ export interface ProjectData {
|
|
18
19
|
|
19
20
|
export interface SiteNavigationItem {
|
20
21
|
title: string
|
21
|
-
|
22
|
+
pathExp: string
|
23
|
+
}
|
24
|
+
|
25
|
+
export interface Sidebar {
|
26
|
+
[navPath: string]: SidebarItem[]
|
27
|
+
}
|
28
|
+
|
29
|
+
export interface SidebarItem {
|
30
|
+
title: string
|
31
|
+
pathExp: string
|
32
|
+
children?: SidebarItem[]
|
22
33
|
}
|