@life-and-dev/mdsite 0.0.12 → 0.0.19
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/commands/prepare.js +4 -11
- package/dist/commands/prepare.js.map +1 -1
- package/dist/commands/prepare.test.js +22 -3
- package/dist/commands/prepare.test.js.map +1 -1
- package/mdsite-nuxt/app/components/AppFooter.vue +15 -2
- package/mdsite-nuxt/example.config.yml +1 -1
- package/mdsite-nuxt/nuxt.config.ts +2 -0
- package/mdsite-nuxt/scripts/generate-indices.test.ts +131 -0
- package/mdsite-nuxt/scripts/generate-indices.ts +54 -6
- package/package.json +1 -1
package/dist/commands/prepare.js
CHANGED
|
@@ -46,18 +46,11 @@ function buildGithubWorkflow(config) {
|
|
|
46
46
|
' steps:',
|
|
47
47
|
' - name: Checkout',
|
|
48
48
|
' uses: actions/checkout@v7',
|
|
49
|
+
' with:',
|
|
50
|
+
' submodules: true',
|
|
49
51
|
'',
|
|
50
|
-
' - name:
|
|
51
|
-
|
|
52
|
-
' npm install --no-save @life-and-dev/mdsite',
|
|
53
|
-
" node <<'NODE'",
|
|
54
|
-
" const fs = require('node:fs')",
|
|
55
|
-
" const path = require('node:path')",
|
|
56
|
-
" const ignored = new Set(['node_modules', '.nuxt', '.output', 'dist', '.cache'])",
|
|
57
|
-
" const source = path.join(process.cwd(), 'node_modules', '@life-and-dev', 'mdsite', 'mdsite-nuxt')",
|
|
58
|
-
` const target = path.join(process.cwd(), ${JSON.stringify(rendererPath)})`,
|
|
59
|
-
' fs.cpSync(source, target, { recursive: true, force: true, filter: (sourcePath) => !ignored.has(path.basename(sourcePath)) })',
|
|
60
|
-
' NODE',
|
|
52
|
+
' - name: Use checked-in mdsite renderer',
|
|
53
|
+
` run: test -f ${rendererPath}/package.json`,
|
|
61
54
|
'',
|
|
62
55
|
' - name: Setup Node',
|
|
63
56
|
' uses: actions/setup-node@v6',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prepare.js","sourceRoot":"","sources":["../../src/commands/prepare.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AACnD,OAAO,IAAI,MAAM,WAAW,CAAA;AAE5B,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAA;AAC7D,OAAO,EAAE,iCAAiC,EAAE,0BAA0B,EAAE,yBAAyB,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAA;AAE7J,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAAC,UAAkB;IAC9D,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,UAAU,CAAC,CAAA;IACjD,MAAM,iCAAiC,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACjF,MAAM,EAAE,WAAW,EAAE,WAAW,EAAE,GAAG,MAAM,yBAAyB,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAE9G,MAAM,0BAA0B,CAAC,WAAW,CAAC,CAAA;IAC7C,MAAM,sBAAsB,CAAC,WAAW,EAAE,WAAW,CAAC,CAAA;IAEtD,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,YAAY,CAAC,CAAA;IAChF,MAAM,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAC5D,MAAM,SAAS,CAAC,YAAY,EAAE,mBAAmB,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAA;IAEzE,OAAO,sCAAsC,YAAY,EAAE,CAAA;AAC7D,CAAC;AAED,SAAS,mBAAmB,CAAC,MAA8D;IACzF,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAA;IACjF,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,CAAA;IAChH,MAAM,YAAY,GAAG,aAAa,CAAA;IAClC,MAAM,YAAY,GAAG,KAAK,UAAU,SAAS,CAAA;IAC7C,MAAM,oBAAoB,GAAG,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,4BAA4B,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,yBAAyB,CAAA;IAE3K,OAAO;QACL,SAAS,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,EAAE;QACvC,EAAE;QACF,KAAK;QACL,SAAS;QACT,wBAAwB;QACxB,sBAAsB;QACtB,EAAE;QACF,cAAc;QACd,kBAAkB;QAClB,gBAAgB;QAChB,mBAAmB;QACnB,EAAE;QACF,cAAc;QACd,kBAAkB;QAClB,6BAA6B;QAC7B,EAAE;QACF,OAAO;QACP,UAAU;QACV,4BAA4B;QAC5B,UAAU;QACV,6BAA6B,oBAAoB,GAAG;QACpD,uBAAuB,oBAAoB,GAAG;QAC9C,gEAAgE;QAChE,YAAY;QACZ,wBAAwB;QACxB,mCAAmC;QACnC,
|
|
1
|
+
{"version":3,"file":"prepare.js","sourceRoot":"","sources":["../../src/commands/prepare.ts"],"names":[],"mappings":"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"}
|
|
@@ -51,9 +51,15 @@ describe('runPrepareGithubCommand', () => {
|
|
|
51
51
|
expect(workflow).toContain(' renderer/node_modules');
|
|
52
52
|
expect(workflow).not.toContain(' renderer/.nuxt');
|
|
53
53
|
expect(workflow).not.toContain(' renderer/build/site');
|
|
54
|
-
expect(workflow).toContain('name:
|
|
55
|
-
expect(workflow).toContain('
|
|
56
|
-
expect(workflow).toContain(
|
|
54
|
+
expect(workflow).toContain('name: Use checked-in mdsite renderer');
|
|
55
|
+
expect(workflow).toContain('run: test -f renderer/package.json');
|
|
56
|
+
expect(workflow).toContain('name: Install dependencies');
|
|
57
|
+
expect(workflow).toContain('run: npm install');
|
|
58
|
+
expect(workflow).not.toContain('name: Setup mdsite renderer');
|
|
59
|
+
expect(workflow).not.toContain('npm install --no-save @life-and-dev/mdsite');
|
|
60
|
+
expect(workflow).not.toContain('@life-and-dev/mdsite');
|
|
61
|
+
expect(workflow).not.toContain('node_modules/@life-and-dev/mdsite');
|
|
62
|
+
expect(workflow).not.toContain("node_modules', '@life-and-dev', 'mdsite', 'mdsite-nuxt");
|
|
57
63
|
expect(workflow).toContain('renderer/build/site');
|
|
58
64
|
expect(workflow).toContain('path: "./renderer/build/site/public"');
|
|
59
65
|
expect(workflow).toContain('run: npm run generate');
|
|
@@ -92,6 +98,13 @@ describe('runPrepareGithubCommand', () => {
|
|
|
92
98
|
expect(workflow).toContain('MDSITE_CONFIG_PATH: "${{ github.workspace }}/mdsite.yml"');
|
|
93
99
|
expect(workflow).toContain('working-directory: renderer');
|
|
94
100
|
expect(workflow).toContain('node-version: "24"');
|
|
101
|
+
expect(workflow).toContain('NUXT_APP_BASE_URL: ${{ steps.pages.outputs.base_path }}/');
|
|
102
|
+
expect(workflow).toContain('run: test -f renderer/package.json');
|
|
103
|
+
expect(workflow).toContain('run: npm install');
|
|
104
|
+
expect(workflow).not.toContain('npm install --no-save @life-and-dev/mdsite');
|
|
105
|
+
expect(workflow).not.toContain('@life-and-dev/mdsite');
|
|
106
|
+
expect(workflow).not.toContain('node_modules/@life-and-dev/mdsite');
|
|
107
|
+
expect(workflow).not.toContain("node_modules', '@life-and-dev', 'mdsite', 'mdsite-nuxt");
|
|
95
108
|
expect(workflow).toContain('run: npm run generate');
|
|
96
109
|
expect(workflow).not.toContain('npm start -- --generate');
|
|
97
110
|
expect(workflow).toContain('path: "./renderer/build/site/public"');
|
|
@@ -120,6 +133,12 @@ describe('runPrepareGithubCommand', () => {
|
|
|
120
133
|
expect(workflow).toContain('working-directory: .mdsite');
|
|
121
134
|
expect(workflow).toContain('node-version: "24"');
|
|
122
135
|
expect(workflow).toContain('cache-dependency-path: ".mdsite/package-lock.json"');
|
|
136
|
+
expect(workflow).toContain('run: test -f .mdsite/package.json');
|
|
137
|
+
expect(workflow).toContain('run: npm install');
|
|
138
|
+
expect(workflow).not.toContain('npm install --no-save @life-and-dev/mdsite');
|
|
139
|
+
expect(workflow).not.toContain('@life-and-dev/mdsite');
|
|
140
|
+
expect(workflow).not.toContain('node_modules/@life-and-dev/mdsite');
|
|
141
|
+
expect(workflow).not.toContain("node_modules', '@life-and-dev', 'mdsite', 'mdsite-nuxt");
|
|
123
142
|
expect(workflow).toContain('path: "./.mdsite/.output/public"');
|
|
124
143
|
expect(workflow).toContain('run: npm run generate');
|
|
125
144
|
expect(workflow).not.toContain('npm start -- --generate');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prepare.test.js","sourceRoot":"","sources":["../../src/commands/prepare.test.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"prepare.test.js","sourceRoot":"","sources":["../../src/commands/prepare.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
<v-container class="d-flex justify-center align-center">
|
|
9
9
|
<div class="footer-links">
|
|
10
10
|
<v-btn
|
|
11
|
+
v-if="hasAboutPage"
|
|
11
12
|
:href="aboutLink"
|
|
12
13
|
variant="text"
|
|
13
14
|
color="on-surface-appbar"
|
|
@@ -16,9 +17,10 @@
|
|
|
16
17
|
About
|
|
17
18
|
</v-btn>
|
|
18
19
|
|
|
19
|
-
<v-divider vertical class="mx-2" />
|
|
20
|
+
<v-divider v-if="hasAboutPage && hasDisclaimerPage" vertical class="mx-2" />
|
|
20
21
|
|
|
21
22
|
<v-btn
|
|
23
|
+
v-if="hasDisclaimerPage"
|
|
22
24
|
:href="disclaimerLink"
|
|
23
25
|
variant="text"
|
|
24
26
|
color="on-surface-appbar"
|
|
@@ -27,7 +29,7 @@
|
|
|
27
29
|
Disclaimer
|
|
28
30
|
</v-btn>
|
|
29
31
|
|
|
30
|
-
<v-divider v-if="
|
|
32
|
+
<v-divider v-if="showEditDivider" vertical class="mx-2" />
|
|
31
33
|
|
|
32
34
|
<v-btn
|
|
33
35
|
v-if="editUrl"
|
|
@@ -47,15 +49,26 @@
|
|
|
47
49
|
|
|
48
50
|
<script setup lang="ts">
|
|
49
51
|
import { useSourceEdit } from '~/composables/useSourceEdit';
|
|
52
|
+
import { useSearchIndex } from '~/composables/useSearchIndex'
|
|
50
53
|
import { withBasePath } from '../../utils/base-url'
|
|
51
54
|
|
|
52
55
|
const appBaseURL = useRuntimeConfig().app.baseURL
|
|
53
56
|
const { getEditUrl } = useSourceEdit()
|
|
57
|
+
const { loadSearchIndex } = useSearchIndex()
|
|
58
|
+
const footerPagePaths = ref<string[]>([])
|
|
54
59
|
|
|
55
60
|
// Generate links to root content files
|
|
56
61
|
const aboutLink = computed(() => withBasePath('/about', appBaseURL))
|
|
57
62
|
const disclaimerLink = computed(() => withBasePath('/disclaimer', appBaseURL))
|
|
58
63
|
const editUrl = computed(() => getEditUrl())
|
|
64
|
+
const hasAboutPage = computed(() => footerPagePaths.value.includes('/about'))
|
|
65
|
+
const hasDisclaimerPage = computed(() => footerPagePaths.value.includes('/disclaimer'))
|
|
66
|
+
const showEditDivider = computed(() => editUrl.value && (hasAboutPage.value || hasDisclaimerPage.value))
|
|
67
|
+
|
|
68
|
+
onMounted(async () => {
|
|
69
|
+
const searchIndex = await loadSearchIndex()
|
|
70
|
+
footerPagePaths.value = searchIndex.map(entry => entry.path)
|
|
71
|
+
})
|
|
59
72
|
</script>
|
|
60
73
|
|
|
61
74
|
<style scoped>
|
|
@@ -48,6 +48,8 @@ export default defineNuxtConfig({
|
|
|
48
48
|
|
|
49
49
|
vite: {
|
|
50
50
|
build: {
|
|
51
|
+
// Disable esbuild CSS minify because it drops semicolons from nested Vuetify @layer rules, causing noisy warnings.
|
|
52
|
+
cssMinify: false,
|
|
51
53
|
rollupOptions: {
|
|
52
54
|
external: ['fs/promises', 'path']
|
|
53
55
|
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import fs from 'node:fs/promises'
|
|
2
|
+
import os from 'node:os'
|
|
3
|
+
import path from 'node:path'
|
|
4
|
+
|
|
5
|
+
import { afterEach, beforeEach, describe, expect, it } from 'vitest'
|
|
6
|
+
|
|
7
|
+
import { generateNavigationJson, generateSearchIndexJson } from './generate-indices.js'
|
|
8
|
+
|
|
9
|
+
describe('generated content indices', () => {
|
|
10
|
+
const originalEnv = { ...process.env }
|
|
11
|
+
let tempDir: string
|
|
12
|
+
let contentDir: string
|
|
13
|
+
let publicDir: string
|
|
14
|
+
|
|
15
|
+
beforeEach(async () => {
|
|
16
|
+
process.env = { ...originalEnv }
|
|
17
|
+
tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'mdsite-indices-'))
|
|
18
|
+
contentDir = path.join(tempDir, 'content')
|
|
19
|
+
publicDir = path.join(tempDir, 'public')
|
|
20
|
+
await fs.mkdir(contentDir, { recursive: true })
|
|
21
|
+
process.env.CONTENT_DIR = contentDir
|
|
22
|
+
process.env.MDSITE_PUBLIC_DIR = publicDir
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
afterEach(async () => {
|
|
26
|
+
process.env = { ...originalEnv }
|
|
27
|
+
await fs.rm(tempDir, { force: true, recursive: true })
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
it('falls back to markdown files when no menu exists', async () => {
|
|
31
|
+
await fs.writeFile(path.join(contentDir, 'index.md'), '# Home\n\nWelcome home.', 'utf8')
|
|
32
|
+
await fs.writeFile(path.join(contentDir, 'guide.md'), '# Guide\n\nUseful guide.', 'utf8')
|
|
33
|
+
|
|
34
|
+
await generateNavigationJson()
|
|
35
|
+
|
|
36
|
+
const navigation = JSON.parse(await fs.readFile(path.join(publicDir, '_navigation.json'), 'utf8'))
|
|
37
|
+
expect(navigation).toEqual(expect.arrayContaining([
|
|
38
|
+
expect.objectContaining({ path: '/', title: 'Home' }),
|
|
39
|
+
expect.objectContaining({ path: '/guide', title: 'Guide' }),
|
|
40
|
+
]))
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
it('writes searchable markdown pages with excerpts', async () => {
|
|
44
|
+
await fs.writeFile(path.join(contentDir, 'guide.md'), '# Guide\n\nUseful guide content for search.', 'utf8')
|
|
45
|
+
|
|
46
|
+
await generateSearchIndexJson()
|
|
47
|
+
|
|
48
|
+
const searchIndex = JSON.parse(await fs.readFile(path.join(publicDir, '_search-index.json'), 'utf8'))
|
|
49
|
+
expect(searchIndex).toEqual([
|
|
50
|
+
expect.objectContaining({
|
|
51
|
+
excerpt: 'Useful guide content for search.',
|
|
52
|
+
path: '/guide',
|
|
53
|
+
title: 'Guide',
|
|
54
|
+
}),
|
|
55
|
+
])
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
describe('index path normalization in navigation', () => {
|
|
59
|
+
async function readNavigation() {
|
|
60
|
+
return JSON.parse(await fs.readFile(path.join(publicDir, '_navigation.json'), 'utf8'))
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
it('normalizes top-level string "index" to path "/"', async () => {
|
|
64
|
+
await fs.writeFile(path.join(contentDir, 'index.md'), '# Home\n\nWelcome.', 'utf8')
|
|
65
|
+
await fs.writeFile(path.join(contentDir, '_menu.yml'), '- index\n- guide\n', 'utf8')
|
|
66
|
+
await fs.writeFile(path.join(contentDir, 'guide.md'), '# Guide\n\nContent.', 'utf8')
|
|
67
|
+
|
|
68
|
+
await generateNavigationJson()
|
|
69
|
+
|
|
70
|
+
const navigation = await readNavigation()
|
|
71
|
+
const home = navigation.find((n: { path: string }) => n.path === '/')
|
|
72
|
+
expect(home).toBeDefined()
|
|
73
|
+
expect(home).toEqual(expect.objectContaining({ path: '/', title: 'Home' }))
|
|
74
|
+
// No node should still have /index after normalization
|
|
75
|
+
const leaked = navigation.find((n: { path: string }) => n.path === '/index')
|
|
76
|
+
expect(leaked).toBeUndefined()
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
it('preserves non-index paths', async () => {
|
|
80
|
+
await fs.writeFile(path.join(contentDir, 'guide.md'), '# Guide\n\nContent.', 'utf8')
|
|
81
|
+
await fs.writeFile(path.join(contentDir, '_menu.yml'), '- guide\n', 'utf8')
|
|
82
|
+
|
|
83
|
+
await generateNavigationJson()
|
|
84
|
+
|
|
85
|
+
const navigation = await readNavigation()
|
|
86
|
+
expect(navigation).toEqual([
|
|
87
|
+
expect.objectContaining({ path: '/guide', title: 'Guide' }),
|
|
88
|
+
])
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
it('normalizes submenu key "index" to path "/"', async () => {
|
|
92
|
+
await fs.mkdir(path.join(contentDir, 'features'), { recursive: true })
|
|
93
|
+
await fs.writeFile(path.join(contentDir, 'index.md'), '# Home\n\nWelcome.', 'utf8')
|
|
94
|
+
await fs.writeFile(path.join(contentDir, 'features', 'index.md'), '# Features Landing\n\nOverview.', 'utf8')
|
|
95
|
+
await fs.writeFile(path.join(contentDir, '_menu.yml'), [
|
|
96
|
+
'- index:',
|
|
97
|
+
' - features/bible-tooltips',
|
|
98
|
+
'- features:',
|
|
99
|
+
' - index',
|
|
100
|
+
' - features/source-edit',
|
|
101
|
+
'',
|
|
102
|
+
].join('\n'), 'utf8')
|
|
103
|
+
await fs.writeFile(path.join(contentDir, 'features', 'bible-tooltips.md'), '# Bible Tooltips\n\nContent.', 'utf8')
|
|
104
|
+
await fs.writeFile(path.join(contentDir, 'features', 'source-edit.md'), '# Source Edit\n\nContent.', 'utf8')
|
|
105
|
+
|
|
106
|
+
await generateNavigationJson()
|
|
107
|
+
|
|
108
|
+
const navigation = await readNavigation()
|
|
109
|
+
// Top-level "index:" submenu key -> "/"
|
|
110
|
+
const topIndex = navigation.find((n: { path: string, children?: unknown[] }) => n.path === '/')
|
|
111
|
+
expect(topIndex).toBeDefined()
|
|
112
|
+
expect(Array.isArray(topIndex!.children)).toBe(true)
|
|
113
|
+
// Nested "index" under features submenu -> "/features"
|
|
114
|
+
const featuresNode = navigation.find((n: { path: string, children?: unknown[] }) => n.path === '/features')
|
|
115
|
+
expect(featuresNode).toBeDefined()
|
|
116
|
+
const nestedIndex = featuresNode!.children!.find((c: { path: string }) => c.path === '/features')
|
|
117
|
+
expect(nestedIndex).toBeDefined()
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
it('normalizes alias (custom title) targeting "index" to path "/"', async () => {
|
|
121
|
+
await fs.writeFile(path.join(contentDir, 'index.md'), '# Home\n\nWelcome.', 'utf8')
|
|
122
|
+
await fs.writeFile(path.join(contentDir, '_menu.yml'), '- Homepage: index\n', 'utf8')
|
|
123
|
+
|
|
124
|
+
await generateNavigationJson()
|
|
125
|
+
|
|
126
|
+
const navigation = await readNavigation()
|
|
127
|
+
const alias = navigation.find((n: { title: string, path: string }) => n.title === 'Homepage')
|
|
128
|
+
expect(alias).toEqual(expect.objectContaining({ path: '/', title: 'Homepage' }))
|
|
129
|
+
})
|
|
130
|
+
})
|
|
131
|
+
})
|
|
@@ -31,6 +31,7 @@ function getSourceDir(): string {
|
|
|
31
31
|
* Get target public directory
|
|
32
32
|
*/
|
|
33
33
|
function getTargetDir(): string {
|
|
34
|
+
if (process.env.MDSITE_PUBLIC_DIR) return process.env.MDSITE_PUBLIC_DIR
|
|
34
35
|
return path.resolve(__dirname, '..', 'public')
|
|
35
36
|
}
|
|
36
37
|
|
|
@@ -109,6 +110,24 @@ export interface MinimalTreeNode {
|
|
|
109
110
|
|
|
110
111
|
type MenuItemType = string | { [key: string]: string | null | MenuItemType[] } | null
|
|
111
112
|
|
|
113
|
+
/**
|
|
114
|
+
* Normalize URL path so a trailing /index resolves to its parent.
|
|
115
|
+
* Mirrors filePathToUrlPath behavior so menu paths match content routes.
|
|
116
|
+
*
|
|
117
|
+
* Examples:
|
|
118
|
+
* /index -> /
|
|
119
|
+
* /features/index -> /features
|
|
120
|
+
* / -> /
|
|
121
|
+
* /architecture -> /architecture
|
|
122
|
+
*/
|
|
123
|
+
function normalizeIndexPath(resolvedPath: string): string {
|
|
124
|
+
if (resolvedPath === '/index') return '/'
|
|
125
|
+
if (resolvedPath.endsWith('/index')) {
|
|
126
|
+
return resolvedPath.slice(0, -('/index'.length))
|
|
127
|
+
}
|
|
128
|
+
return resolvedPath
|
|
129
|
+
}
|
|
130
|
+
|
|
112
131
|
/**
|
|
113
132
|
* Resolve relative/absolute paths in menu
|
|
114
133
|
*/
|
|
@@ -196,7 +215,7 @@ async function processMenuItems(
|
|
|
196
215
|
nodes.push({
|
|
197
216
|
id: `${resolvedPath.split('/').filter(Boolean).pop() || 'home'}-${order}`,
|
|
198
217
|
title: title || item,
|
|
199
|
-
path: resolvedPath,
|
|
218
|
+
path: normalizeIndexPath(resolvedPath),
|
|
200
219
|
type: 'link',
|
|
201
220
|
description,
|
|
202
221
|
isPrimary: true
|
|
@@ -269,7 +288,7 @@ async function processMenuItems(
|
|
|
269
288
|
nodes.push({
|
|
270
289
|
id: `${submenuPath.split('/').filter(Boolean).pop() || 'home'}-${order}`,
|
|
271
290
|
title: title || key,
|
|
272
|
-
path: submenuPath,
|
|
291
|
+
path: normalizeIndexPath(submenuPath),
|
|
273
292
|
type: 'link',
|
|
274
293
|
description,
|
|
275
294
|
isPrimary: true,
|
|
@@ -298,7 +317,7 @@ async function processMenuItems(
|
|
|
298
317
|
nodes.push({
|
|
299
318
|
id: `link-${key.replace(/\s+/g, '-').toLowerCase()}-${order}`,
|
|
300
319
|
title: key,
|
|
301
|
-
path: resolvedPath,
|
|
320
|
+
path: normalizeIndexPath(resolvedPath),
|
|
302
321
|
type: 'link',
|
|
303
322
|
description,
|
|
304
323
|
isPrimary: false // Aliases are NOT primary
|
|
@@ -325,6 +344,29 @@ function countNodes(nodes: MinimalTreeNode[]): number {
|
|
|
325
344
|
return count
|
|
326
345
|
}
|
|
327
346
|
|
|
347
|
+
async function buildFallbackNavigationTree(sourceDir: string): Promise<MinimalTreeNode[]> {
|
|
348
|
+
const markdownFiles = await getAllMarkdownFiles(sourceDir)
|
|
349
|
+
const nodes: MinimalTreeNode[] = []
|
|
350
|
+
|
|
351
|
+
for (const [order, filePath] of markdownFiles.sort().entries()) {
|
|
352
|
+
const content = await fs.readFile(filePath, 'utf-8')
|
|
353
|
+
const metadata = extractMarkdownMetadata(content)
|
|
354
|
+
const urlPath = filePathToUrlPath(filePath, sourceDir)
|
|
355
|
+
const title = metadata.title ?? path.basename(filePath, '.md')
|
|
356
|
+
|
|
357
|
+
nodes.push({
|
|
358
|
+
id: `${urlPath.split('/').filter(Boolean).pop() || 'home'}-${order}`,
|
|
359
|
+
title,
|
|
360
|
+
path: urlPath,
|
|
361
|
+
type: 'link',
|
|
362
|
+
description: metadata.description,
|
|
363
|
+
isPrimary: true
|
|
364
|
+
})
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
return nodes
|
|
368
|
+
}
|
|
369
|
+
|
|
328
370
|
/**
|
|
329
371
|
* Generate navigation JSON file
|
|
330
372
|
*/
|
|
@@ -343,9 +385,11 @@ export async function generateNavigationJson() {
|
|
|
343
385
|
try {
|
|
344
386
|
if (await fs.pathExists(menuPath)) {
|
|
345
387
|
const menuContent = await fs.readFile(menuPath, 'utf-8')
|
|
346
|
-
const menuItems = parseYaml(menuContent) as MenuItemType[]
|
|
347
|
-
|
|
348
|
-
|
|
388
|
+
const menuItems = parseYaml(menuContent) as MenuItemType[] | null
|
|
389
|
+
if (Array.isArray(menuItems) && menuItems.length > 0) {
|
|
390
|
+
const result = await processMenuItems(menuItems, '/')
|
|
391
|
+
tree = result.nodes
|
|
392
|
+
}
|
|
349
393
|
} else {
|
|
350
394
|
console.warn('⚠️ No _menu.yml or _menu.yaml found at:', menuPath)
|
|
351
395
|
}
|
|
@@ -353,6 +397,10 @@ export async function generateNavigationJson() {
|
|
|
353
397
|
console.error('Error building navigation tree:', error)
|
|
354
398
|
}
|
|
355
399
|
|
|
400
|
+
if (tree.length === 0) {
|
|
401
|
+
tree = await buildFallbackNavigationTree(sourceDir)
|
|
402
|
+
}
|
|
403
|
+
|
|
356
404
|
const targetDir = getTargetDir()
|
|
357
405
|
const outputPath = path.join(targetDir, '_navigation.json')
|
|
358
406
|
|