@docsector/docsector-reader 2.0.7 → 2.1.0
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/README.md +16 -5
- package/bin/docsector.js +10 -5
- package/docsector.config.js +13 -1
- package/package.json +1 -1
- package/src/components/DMenu.vue +224 -12
- package/src/components/DPageBar.vue +5 -0
- package/src/components/DPageMeta.vue +37 -23
- package/src/i18n/helpers.js +34 -18
- package/src/i18n/index.js +5 -3
- package/src/i18n/path.js +15 -2
- package/src/index.js +2 -2
- package/src/layouts/DefaultLayout.vue +16 -2
- package/src/pages/.old/v0.x/guide/getting-started.overview.en-US.md +7 -0
- package/src/pages/.old/v0.x/guide/getting-started.overview.pt-BR.md +7 -0
- package/src/pages/.old/v0.x/guide.book.js +12 -0
- package/src/pages/.old/v0.x/guide.index.js +28 -0
- package/src/pages/guide/configuration.overview.en-US.md +13 -2
- package/src/pages/guide/configuration.overview.pt-BR.md +13 -2
- package/src/pages/guide/pages-and-routing.overview.en-US.md +2 -0
- package/src/pages/guide/pages-and-routing.overview.pt-BR.md +2 -0
- package/src/pages/manual/components/d-menu.overview.en-US.md +6 -2
- package/src/pages/manual/components/d-menu.overview.pt-BR.md +6 -2
- package/src/quasar.factory.js +648 -91
- package/src/router/routes.js +127 -95
- package/src/store/App.js +15 -5
package/src/quasar.factory.js
CHANGED
|
@@ -67,19 +67,63 @@ function normalizePathForMatch (path) {
|
|
|
67
67
|
return String(path || '').replace(/\\/g, '/')
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
70
|
+
const CURRENT_VERSION_KEY = '__current__'
|
|
71
|
+
|
|
72
|
+
function trimSlashes (value) {
|
|
73
|
+
return String(value || '').replace(/^\/+|\/+$/g, '')
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function normalizeVersionId (value) {
|
|
77
|
+
return String(value || '').trim()
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function normalizeRoutePrefix (value) {
|
|
81
|
+
const normalized = trimSlashes(value)
|
|
82
|
+
return normalized ? `/${normalized}` : ''
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function getVersionRoots (projectRoot) {
|
|
79
86
|
const pagesDir = resolve(projectRoot, 'src', 'pages')
|
|
80
87
|
if (!existsSync(pagesDir)) return []
|
|
81
88
|
|
|
82
|
-
const
|
|
89
|
+
const roots = [
|
|
90
|
+
{
|
|
91
|
+
versionId: CURRENT_VERSION_KEY,
|
|
92
|
+
current: true,
|
|
93
|
+
rootDir: pagesDir,
|
|
94
|
+
importPrefix: '',
|
|
95
|
+
sourceRoot: '',
|
|
96
|
+
routePrefix: ''
|
|
97
|
+
}
|
|
98
|
+
]
|
|
99
|
+
|
|
100
|
+
const oldDir = resolve(pagesDir, '.old')
|
|
101
|
+
if (!existsSync(oldDir)) return roots
|
|
102
|
+
|
|
103
|
+
const oldVersionRoots = readdirSync(oldDir, { withFileTypes: true })
|
|
104
|
+
.filter(entry => entry.isDirectory())
|
|
105
|
+
.map(entry => entry.name)
|
|
106
|
+
.filter(name => normalizeVersionId(name).length > 0)
|
|
107
|
+
.sort()
|
|
108
|
+
|
|
109
|
+
for (const versionId of oldVersionRoots) {
|
|
110
|
+
roots.push({
|
|
111
|
+
versionId,
|
|
112
|
+
current: false,
|
|
113
|
+
rootDir: resolve(oldDir, versionId),
|
|
114
|
+
importPrefix: `.old/${versionId}/`,
|
|
115
|
+
sourceRoot: `.old/${versionId}`,
|
|
116
|
+
routePrefix: normalizeRoutePrefix(versionId)
|
|
117
|
+
})
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return roots
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function getPagesRegistryFilesForRoot (root) {
|
|
124
|
+
if (!root || !existsSync(root.rootDir)) return []
|
|
125
|
+
|
|
126
|
+
const names = readdirSync(root.rootDir, { withFileTypes: true })
|
|
83
127
|
.filter(entry => entry.isFile())
|
|
84
128
|
.map(entry => entry.name)
|
|
85
129
|
|
|
@@ -89,37 +133,80 @@ function getPagesRegistryFiles (projectRoot) {
|
|
|
89
133
|
return /^[^/]+\.book\.js$/.test(name) || /^[^/]+\.index\.js$/.test(name)
|
|
90
134
|
})
|
|
91
135
|
.sort()
|
|
92
|
-
.map(name => resolve(
|
|
136
|
+
.map(name => resolve(root.rootDir, name))
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function normalizeBookConfig (rawConfig = {}, fallbackId = 'manual', index = 0) {
|
|
140
|
+
const resolvedId = rawConfig.id || fallbackId || `book-${index + 1}`
|
|
141
|
+
const label = rawConfig.label || (resolvedId.charAt(0).toUpperCase() + resolvedId.slice(1))
|
|
142
|
+
|
|
143
|
+
return {
|
|
144
|
+
...rawConfig,
|
|
145
|
+
id: resolvedId,
|
|
146
|
+
label,
|
|
147
|
+
icon: rawConfig.icon || 'menu_book',
|
|
148
|
+
order: rawConfig.order ?? (index + 1),
|
|
149
|
+
color: normalizeBookColorConfig(rawConfig.color)
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function buildPageRoutePath (entry, subpage, { leadingSlash = false } = {}) {
|
|
154
|
+
const versionPrefix = trimSlashes(entry?.versionPrefix || '')
|
|
155
|
+
const base = trimSlashes(`${entry?.book || 'manual'}${entry?.pagePath || ''}`)
|
|
156
|
+
const routePath = [versionPrefix, base, trimSlashes(subpage)].filter(Boolean).join('/')
|
|
157
|
+
|
|
158
|
+
return leadingSlash ? `/${routePath}` : routePath
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function resolveMarkdownSourceFile (pagesDir, entry, subpage, lang) {
|
|
162
|
+
const sourceRoot = entry?.sourceRoot || ''
|
|
163
|
+
return resolve(pagesDir, sourceRoot, `${entry.book}${entry.pagePath}.${subpage}.${lang}.md`)
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* List top-level page registry definition files.
|
|
168
|
+
*
|
|
169
|
+
* Includes:
|
|
170
|
+
* - src/pages/index.js (legacy)
|
|
171
|
+
* - src/pages/*.book.js
|
|
172
|
+
* - src/pages/*.index.js
|
|
173
|
+
*/
|
|
174
|
+
function getPagesRegistryFiles (projectRoot) {
|
|
175
|
+
return getVersionRoots(projectRoot)
|
|
176
|
+
.flatMap(root => getPagesRegistryFilesForRoot(root))
|
|
93
177
|
}
|
|
94
178
|
|
|
95
179
|
/**
|
|
96
180
|
* Discover configured books from src/pages/*.book.js paired with *.index.js.
|
|
97
181
|
*/
|
|
98
182
|
function getBookRegistryEntries (projectRoot) {
|
|
99
|
-
const pagesDir = resolve(projectRoot, 'src', 'pages')
|
|
100
|
-
if (!existsSync(pagesDir)) return []
|
|
101
|
-
|
|
102
|
-
const names = readdirSync(pagesDir, { withFileTypes: true })
|
|
103
|
-
.filter(entry => entry.isFile())
|
|
104
|
-
.map(entry => entry.name)
|
|
105
|
-
|
|
106
|
-
const books = names
|
|
107
|
-
.filter(name => /^[^/]+\.book\.js$/.test(name))
|
|
108
|
-
.sort()
|
|
109
|
-
|
|
110
183
|
const entries = []
|
|
111
|
-
for (const
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
184
|
+
for (const root of getVersionRoots(projectRoot)) {
|
|
185
|
+
const names = readdirSync(root.rootDir, { withFileTypes: true })
|
|
186
|
+
.filter(entry => entry.isFile())
|
|
187
|
+
.map(entry => entry.name)
|
|
188
|
+
|
|
189
|
+
const books = names
|
|
190
|
+
.filter(name => /^[^/]+\.book\.js$/.test(name))
|
|
191
|
+
.sort()
|
|
192
|
+
|
|
193
|
+
for (const bookFile of books) {
|
|
194
|
+
const baseName = bookFile.slice(0, -'.book.js'.length)
|
|
195
|
+
const indexFile = `${baseName}.index.js`
|
|
196
|
+
if (!names.includes(indexFile)) continue
|
|
197
|
+
|
|
198
|
+
entries.push({
|
|
199
|
+
versionId: root.versionId,
|
|
200
|
+
currentVersion: root.current,
|
|
201
|
+
routePrefix: root.routePrefix,
|
|
202
|
+
sourceRoot: root.sourceRoot,
|
|
203
|
+
id: baseName,
|
|
204
|
+
bookFile: `${root.importPrefix}${bookFile}`,
|
|
205
|
+
indexFile: `${root.importPrefix}${indexFile}`,
|
|
206
|
+
bookPath: resolve(root.rootDir, bookFile),
|
|
207
|
+
indexPath: resolve(root.rootDir, indexFile)
|
|
208
|
+
})
|
|
209
|
+
}
|
|
123
210
|
}
|
|
124
211
|
|
|
125
212
|
return entries
|
|
@@ -170,7 +257,93 @@ function buildVirtualBooksModule (projectRoot) {
|
|
|
170
257
|
|
|
171
258
|
// Legacy fallback: support projects that still define src/pages/index.js only.
|
|
172
259
|
if (bookEntries.length === 0) {
|
|
173
|
-
return `import
|
|
260
|
+
return `import docsectorConfig from 'docsector.config.js'
|
|
261
|
+
import legacyPages from 'pages'
|
|
262
|
+
|
|
263
|
+
const CURRENT_VERSION_KEY = ${JSON.stringify(CURRENT_VERSION_KEY)}
|
|
264
|
+
|
|
265
|
+
const normalizeVersionBadge = (rawBadge, { released, releaseStatus }) => {
|
|
266
|
+
const normalizedStatus = String(releaseStatus || '').toLowerCase()
|
|
267
|
+
const deprecated = normalizedStatus === 'deprecated'
|
|
268
|
+
const defaultColor = deprecated ? 'negative' : (released ? 'positive' : 'warning')
|
|
269
|
+
const defaultTextColor = (deprecated || released) ? 'white' : 'dark'
|
|
270
|
+
|
|
271
|
+
if (rawBadge === false || rawBadge === null) {
|
|
272
|
+
return { label: releaseStatus, color: defaultColor, textColor: defaultTextColor }
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
if (typeof rawBadge === 'string') {
|
|
276
|
+
return { label: rawBadge, color: defaultColor, textColor: defaultTextColor }
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
if (typeof rawBadge === 'object' && rawBadge !== null) {
|
|
280
|
+
const label = rawBadge.label || rawBadge.text || releaseStatus
|
|
281
|
+
if (!label) {
|
|
282
|
+
return null
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
return {
|
|
286
|
+
...rawBadge,
|
|
287
|
+
label,
|
|
288
|
+
color: rawBadge.color || defaultColor,
|
|
289
|
+
textColor: rawBadge.textColor || defaultTextColor
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
return { label: releaseStatus || (released ? 'released' : 'draft'), color: defaultColor, textColor: defaultTextColor }
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
const normalizeVersionDescriptor = (raw, fallback = {}) => {
|
|
297
|
+
const value = typeof raw === 'string' ? { id: raw, label: raw } : (raw || {})
|
|
298
|
+
const current = value.current === true || fallback.current === true
|
|
299
|
+
const id = current
|
|
300
|
+
? (value.id || docsectorConfig.branding?.version || fallback.id || 'current')
|
|
301
|
+
: (value.id || fallback.id || value.label || '')
|
|
302
|
+
const label = value.label || id
|
|
303
|
+
const normalizedPrefix = String(value.routePrefix || fallback.routePrefix || id || '').replace(/^\\/+|\\/+$/g, '')
|
|
304
|
+
const configuredStatus = value.deprecated === true || fallback.deprecated === true
|
|
305
|
+
? 'deprecated'
|
|
306
|
+
: (value.releaseStatus || value.status || fallback.releaseStatus || fallback.status)
|
|
307
|
+
const explicitlyReleased = value.released !== undefined
|
|
308
|
+
? value.released !== false
|
|
309
|
+
: (fallback.released !== undefined ? fallback.released !== false : null)
|
|
310
|
+
const released = configuredStatus === 'deprecated'
|
|
311
|
+
? true
|
|
312
|
+
: (explicitlyReleased ?? !['draft', 'unreleased', 'preview', 'next'].includes(String(configuredStatus || '').toLowerCase()))
|
|
313
|
+
const releaseStatus = configuredStatus || (released ? 'released' : 'draft')
|
|
314
|
+
const badge = normalizeVersionBadge(value.badge ?? value.releaseBadge ?? fallback.badge ?? fallback.releaseBadge, { released, releaseStatus })
|
|
315
|
+
|
|
316
|
+
return {
|
|
317
|
+
...fallback,
|
|
318
|
+
...value,
|
|
319
|
+
id,
|
|
320
|
+
label,
|
|
321
|
+
released,
|
|
322
|
+
releaseStatus,
|
|
323
|
+
deprecated: releaseStatus === 'deprecated',
|
|
324
|
+
badge,
|
|
325
|
+
current,
|
|
326
|
+
routePrefix: current ? '' : (normalizedPrefix ? '/' + normalizedPrefix : ''),
|
|
327
|
+
sourceRoot: current ? '' : (value.sourceRoot || fallback.sourceRoot || (id ? '.old/' + id : ''))
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
const discoveredVersions = [
|
|
332
|
+
normalizeVersionDescriptor(null, { id: CURRENT_VERSION_KEY, current: true })
|
|
333
|
+
]
|
|
334
|
+
|
|
335
|
+
const configuredVersions = Array.isArray(docsectorConfig.branding?.versions) ? docsectorConfig.branding.versions : []
|
|
336
|
+
const currentVersion = normalizeVersionDescriptor(
|
|
337
|
+
configuredVersions.find(version => typeof version === 'object' && version?.current === true),
|
|
338
|
+
{ id: docsectorConfig.branding?.version || CURRENT_VERSION_KEY, current: true }
|
|
339
|
+
)
|
|
340
|
+
|
|
341
|
+
export const versions = [currentVersion]
|
|
342
|
+
|
|
343
|
+
export const versionById = versions.reduce((accumulator, version) => {
|
|
344
|
+
accumulator[version.id] = version
|
|
345
|
+
return accumulator
|
|
346
|
+
}, {})
|
|
174
347
|
|
|
175
348
|
const defaultBook = {
|
|
176
349
|
id: 'manual',
|
|
@@ -185,13 +358,33 @@ const defaultBook = {
|
|
|
185
358
|
|
|
186
359
|
const normalizedPages = legacyPages || {}
|
|
187
360
|
|
|
188
|
-
export const
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
361
|
+
export const booksByVersion = {
|
|
362
|
+
[currentVersion.id]: {
|
|
363
|
+
version: currentVersion,
|
|
364
|
+
books: {
|
|
365
|
+
manual: {
|
|
366
|
+
config: defaultBook,
|
|
367
|
+
routes: normalizedPages
|
|
368
|
+
}
|
|
369
|
+
},
|
|
370
|
+
allBooks: [defaultBook]
|
|
192
371
|
}
|
|
193
372
|
}
|
|
194
373
|
|
|
374
|
+
export const books = booksByVersion[currentVersion.id].books
|
|
375
|
+
|
|
376
|
+
export const pageEntries = Object.entries(normalizedPages).map(([pagePath, page]) => ({
|
|
377
|
+
version: currentVersion.id,
|
|
378
|
+
versionLabel: currentVersion.label,
|
|
379
|
+
versionCurrent: true,
|
|
380
|
+
versionPrefix: '',
|
|
381
|
+
sourceRoot: '',
|
|
382
|
+
book: page?.config?.book ?? page?.config?.type ?? 'manual',
|
|
383
|
+
bookConfig: defaultBook,
|
|
384
|
+
pagePath,
|
|
385
|
+
page
|
|
386
|
+
}))
|
|
387
|
+
|
|
195
388
|
export const allBooks = [defaultBook]
|
|
196
389
|
export const allPages = normalizedPages
|
|
197
390
|
|
|
@@ -199,17 +392,30 @@ export default books
|
|
|
199
392
|
`
|
|
200
393
|
}
|
|
201
394
|
|
|
202
|
-
const imports = []
|
|
395
|
+
const imports = ['import docsectorConfig from \'docsector.config.js\'']
|
|
203
396
|
const rows = []
|
|
397
|
+
const discoveredVersionIds = new Map()
|
|
204
398
|
|
|
205
399
|
for (const [index, entry] of bookEntries.entries()) {
|
|
206
400
|
imports.push(`import __book_${index} from 'pages/${entry.bookFile}'`)
|
|
207
401
|
imports.push(`import __routes_${index} from 'pages/${entry.indexFile}'`)
|
|
208
|
-
rows.push(` { fallbackId: ${JSON.stringify(entry.id)}, config: __book_${index}, routes: __routes_${index} }`)
|
|
402
|
+
rows.push(` { versionId: ${JSON.stringify(entry.versionId)}, currentVersion: ${JSON.stringify(entry.currentVersion)}, routePrefix: ${JSON.stringify(entry.routePrefix)}, sourceRoot: ${JSON.stringify(entry.sourceRoot)}, fallbackId: ${JSON.stringify(entry.id)}, config: __book_${index}, routes: __routes_${index} }`)
|
|
403
|
+
discoveredVersionIds.set(entry.versionId, {
|
|
404
|
+
id: entry.versionId,
|
|
405
|
+
current: entry.currentVersion,
|
|
406
|
+
routePrefix: entry.routePrefix,
|
|
407
|
+
sourceRoot: entry.sourceRoot
|
|
408
|
+
})
|
|
209
409
|
}
|
|
210
410
|
|
|
411
|
+
const discoveredVersions = Array.from(discoveredVersionIds.values())
|
|
412
|
+
|
|
211
413
|
return `${imports.join('\n')}
|
|
212
414
|
|
|
415
|
+
const CURRENT_VERSION_KEY = ${JSON.stringify(CURRENT_VERSION_KEY)}
|
|
416
|
+
|
|
417
|
+
const discoveredVersions = ${JSON.stringify(discoveredVersions, null, 2)}
|
|
418
|
+
|
|
213
419
|
const entries = [
|
|
214
420
|
${rows.join(',\n')}
|
|
215
421
|
]
|
|
@@ -219,6 +425,39 @@ const DEFAULT_BOOK_COLORS = Object.freeze({
|
|
|
219
425
|
inactive: 'rgba(255, 255, 255, 0.72)'
|
|
220
426
|
})
|
|
221
427
|
|
|
428
|
+
const normalizeVersionBadge = (rawBadge, { released, releaseStatus }) => {
|
|
429
|
+
const normalizedStatus = String(releaseStatus || '').toLowerCase()
|
|
430
|
+
const deprecated = normalizedStatus === 'deprecated'
|
|
431
|
+
const defaultColor = deprecated ? 'negative' : (released ? 'positive' : 'warning')
|
|
432
|
+
const defaultTextColor = (deprecated || released) ? 'white' : 'dark'
|
|
433
|
+
|
|
434
|
+
if (rawBadge === false || rawBadge === null) {
|
|
435
|
+
return { label: releaseStatus, color: defaultColor, textColor: defaultTextColor }
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
if (typeof rawBadge === 'string') {
|
|
439
|
+
return { label: rawBadge, color: defaultColor, textColor: defaultTextColor }
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
if (typeof rawBadge === 'object' && rawBadge !== null) {
|
|
443
|
+
const label = rawBadge.label || rawBadge.text || releaseStatus
|
|
444
|
+
if (!label) {
|
|
445
|
+
return null
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
return {
|
|
449
|
+
...rawBadge,
|
|
450
|
+
label,
|
|
451
|
+
color: rawBadge.color || defaultColor,
|
|
452
|
+
textColor: rawBadge.textColor || defaultTextColor
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
return { label: releaseStatus || (released ? 'released' : 'draft'), color: defaultColor, textColor: defaultTextColor }
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
const trimSlashes = (value) => String(value || '').replace(/^\\/+|\\/+$/g, '')
|
|
460
|
+
|
|
222
461
|
const normalizeBookColor = (rawColor) => {
|
|
223
462
|
if (typeof rawColor === 'object' && rawColor !== null && !Array.isArray(rawColor)) {
|
|
224
463
|
const active = typeof rawColor.active === 'string' && rawColor.active.trim().length > 0
|
|
@@ -243,7 +482,93 @@ const normalizeBookColor = (rawColor) => {
|
|
|
243
482
|
return { ...DEFAULT_BOOK_COLORS }
|
|
244
483
|
}
|
|
245
484
|
|
|
246
|
-
|
|
485
|
+
const normalizeVersionDescriptor = (raw, fallback = {}) => {
|
|
486
|
+
const value = typeof raw === 'string' ? { id: raw, label: raw } : (raw || {})
|
|
487
|
+
const current = value.current === true || fallback.current === true
|
|
488
|
+
const id = current
|
|
489
|
+
? (value.id || docsectorConfig.branding?.version || fallback.id || 'current')
|
|
490
|
+
: (value.id || fallback.id || value.label || '')
|
|
491
|
+
const label = value.label || id
|
|
492
|
+
const prefixSource = value.routePrefix ?? fallback.routePrefix ?? id
|
|
493
|
+
const normalizedPrefix = trimSlashes(prefixSource)
|
|
494
|
+
const configuredStatus = value.deprecated === true || fallback.deprecated === true
|
|
495
|
+
? 'deprecated'
|
|
496
|
+
: (value.releaseStatus || value.status || fallback.releaseStatus || fallback.status)
|
|
497
|
+
const explicitlyReleased = value.released !== undefined
|
|
498
|
+
? value.released !== false
|
|
499
|
+
: (fallback.released !== undefined ? fallback.released !== false : null)
|
|
500
|
+
const released = configuredStatus === 'deprecated'
|
|
501
|
+
? true
|
|
502
|
+
: (explicitlyReleased ?? !['draft', 'unreleased', 'preview', 'next'].includes(String(configuredStatus || '').toLowerCase()))
|
|
503
|
+
const releaseStatus = configuredStatus || (released ? 'released' : 'draft')
|
|
504
|
+
const badge = normalizeVersionBadge(value.badge ?? value.releaseBadge ?? fallback.badge ?? fallback.releaseBadge, { released, releaseStatus })
|
|
505
|
+
|
|
506
|
+
return {
|
|
507
|
+
...fallback,
|
|
508
|
+
...value,
|
|
509
|
+
id,
|
|
510
|
+
label,
|
|
511
|
+
released,
|
|
512
|
+
releaseStatus,
|
|
513
|
+
deprecated: releaseStatus === 'deprecated',
|
|
514
|
+
badge,
|
|
515
|
+
current,
|
|
516
|
+
routePrefix: current ? '' : (normalizedPrefix ? '/' + normalizedPrefix : ''),
|
|
517
|
+
sourceRoot: current ? '' : (value.sourceRoot || fallback.sourceRoot || (id ? '.old/' + id : ''))
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
const configuredVersions = Array.isArray(docsectorConfig.branding?.versions) ? docsectorConfig.branding.versions : []
|
|
522
|
+
const currentVersion = normalizeVersionDescriptor(
|
|
523
|
+
configuredVersions.find(version => typeof version === 'object' && version?.current === true),
|
|
524
|
+
{ id: docsectorConfig.branding?.version || CURRENT_VERSION_KEY, current: true }
|
|
525
|
+
)
|
|
526
|
+
|
|
527
|
+
const configuredVersionDescriptors = configuredVersions
|
|
528
|
+
.filter(version => !(typeof version === 'object' && version?.current === true))
|
|
529
|
+
.map(version => {
|
|
530
|
+
const value = typeof version === 'string' ? { id: version, label: version } : version
|
|
531
|
+
const discovered = discoveredVersions.find(item => item.id === value?.id || item.id === value?.label) || {}
|
|
532
|
+
const isCurrent = value?.id === currentVersion.id || value?.label === currentVersion.id
|
|
533
|
+
|
|
534
|
+
return normalizeVersionDescriptor(value, isCurrent ? { ...currentVersion, current: true } : discovered)
|
|
535
|
+
})
|
|
536
|
+
|
|
537
|
+
export const versions = [currentVersion]
|
|
538
|
+
|
|
539
|
+
for (const version of configuredVersionDescriptors) {
|
|
540
|
+
if (!versions.some(item => item.id === version.id)) {
|
|
541
|
+
versions.push(version)
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
for (const discovered of discoveredVersions) {
|
|
546
|
+
if (discovered.current) continue
|
|
547
|
+
if (!versions.some(item => item.id === discovered.id)) {
|
|
548
|
+
versions.push(normalizeVersionDescriptor(null, discovered))
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
export const versionById = versions.reduce((accumulator, version) => {
|
|
553
|
+
accumulator[version.id] = version
|
|
554
|
+
return accumulator
|
|
555
|
+
}, {})
|
|
556
|
+
|
|
557
|
+
const resolveEntryVersion = (entry) => {
|
|
558
|
+
if (entry.currentVersion === true || entry.versionId === CURRENT_VERSION_KEY) {
|
|
559
|
+
return currentVersion
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
return versionById[entry.versionId] || normalizeVersionDescriptor(null, {
|
|
563
|
+
id: entry.versionId,
|
|
564
|
+
current: false,
|
|
565
|
+
routePrefix: entry.routePrefix,
|
|
566
|
+
sourceRoot: entry.sourceRoot
|
|
567
|
+
})
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
export const booksByVersion = entries.reduce((accumulator, entry, index) => {
|
|
571
|
+
const version = resolveEntryVersion(entry)
|
|
247
572
|
const config = entry.config || {}
|
|
248
573
|
const resolvedId = config.id || entry.fallbackId || ('book-' + (index + 1))
|
|
249
574
|
const label = config.label || (resolvedId.charAt(0).toUpperCase() + resolvedId.slice(1))
|
|
@@ -253,17 +578,30 @@ export const books = entries.reduce((accumulator, entry, index) => {
|
|
|
253
578
|
label,
|
|
254
579
|
icon: config.icon || 'menu_book',
|
|
255
580
|
order: config.order ?? (index + 1),
|
|
256
|
-
color: normalizeBookColor(config.color)
|
|
581
|
+
color: normalizeBookColor(config.color),
|
|
582
|
+
version: version.id,
|
|
583
|
+
versionPrefix: version.routePrefix
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
if (!accumulator[version.id]) {
|
|
587
|
+
accumulator[version.id] = {
|
|
588
|
+
version,
|
|
589
|
+
books: {},
|
|
590
|
+
allBooks: []
|
|
591
|
+
}
|
|
257
592
|
}
|
|
258
593
|
|
|
259
|
-
accumulator[resolvedId] = {
|
|
594
|
+
accumulator[version.id].books[resolvedId] = {
|
|
260
595
|
config: normalizedConfig,
|
|
261
596
|
routes: entry.routes || {}
|
|
262
597
|
}
|
|
598
|
+
accumulator[version.id].allBooks = Object.values(accumulator[version.id].books).map(book => book.config)
|
|
263
599
|
return accumulator
|
|
264
600
|
}, {})
|
|
265
601
|
|
|
266
|
-
export const
|
|
602
|
+
export const books = booksByVersion[currentVersion.id]?.books || {}
|
|
603
|
+
|
|
604
|
+
export const allBooks = booksByVersion[currentVersion.id]?.allBooks || []
|
|
267
605
|
export const allPages = Object.values(books).reduce((accumulator, book) => {
|
|
268
606
|
return {
|
|
269
607
|
...accumulator,
|
|
@@ -271,6 +609,34 @@ export const allPages = Object.values(books).reduce((accumulator, book) => {
|
|
|
271
609
|
}
|
|
272
610
|
}, {})
|
|
273
611
|
|
|
612
|
+
export const pageEntries = Object.entries(booksByVersion).flatMap(([versionId, versionBooks]) => {
|
|
613
|
+
const version = versionBooks.version
|
|
614
|
+
|
|
615
|
+
return Object.entries(versionBooks.books || {}).flatMap(([bookId, book]) => {
|
|
616
|
+
const fallbackBook = book?.config?.id || bookId || 'manual'
|
|
617
|
+
|
|
618
|
+
return Object.entries(book?.routes || {}).map(([pagePath, page]) => {
|
|
619
|
+
const bookName = page?.config?.book ?? page?.config?.type ?? fallbackBook
|
|
620
|
+
const pathSegments = String(pagePath || '').replace(/^\\//, '').split('/').filter(Boolean)
|
|
621
|
+
const i18nSegments = version.current ? [bookName, ...pathSegments] : [version.id, bookName, ...pathSegments]
|
|
622
|
+
|
|
623
|
+
return {
|
|
624
|
+
version: versionId,
|
|
625
|
+
versionLabel: version.label,
|
|
626
|
+
versionCurrent: version.current,
|
|
627
|
+
versionPrefix: version.routePrefix,
|
|
628
|
+
sourceRoot: version.sourceRoot || '',
|
|
629
|
+
book: bookName,
|
|
630
|
+
bookConfig: book.config,
|
|
631
|
+
pagePath,
|
|
632
|
+
page,
|
|
633
|
+
i18nSegments,
|
|
634
|
+
unversionedPath: '/' + bookName + pagePath
|
|
635
|
+
}
|
|
636
|
+
})
|
|
637
|
+
})
|
|
638
|
+
})
|
|
639
|
+
|
|
274
640
|
export default books
|
|
275
641
|
`
|
|
276
642
|
}
|
|
@@ -283,6 +649,17 @@ async function loadBooksRegistry (projectRoot) {
|
|
|
283
649
|
|
|
284
650
|
// Legacy fallback
|
|
285
651
|
if (entries.length === 0) {
|
|
652
|
+
const configPath = resolve(projectRoot, 'docsector.config.js')
|
|
653
|
+
const { default: config = {} } = existsSync(configPath)
|
|
654
|
+
? await import(pathToFileURL(configPath).href)
|
|
655
|
+
: { default: {} }
|
|
656
|
+
const currentVersion = {
|
|
657
|
+
id: config.branding?.version || 'current',
|
|
658
|
+
label: config.branding?.version || 'current',
|
|
659
|
+
current: true,
|
|
660
|
+
routePrefix: '',
|
|
661
|
+
sourceRoot: ''
|
|
662
|
+
}
|
|
286
663
|
const legacyPath = resolve(projectRoot, 'src', 'pages', 'index.js')
|
|
287
664
|
const pages = existsSync(legacyPath)
|
|
288
665
|
? ((await import(pathToFileURL(legacyPath).href)).default || {})
|
|
@@ -296,52 +673,203 @@ async function loadBooksRegistry (projectRoot) {
|
|
|
296
673
|
color: {
|
|
297
674
|
active: 'white',
|
|
298
675
|
inactive: 'rgba(255, 255, 255, 0.72)'
|
|
676
|
+
},
|
|
677
|
+
version: currentVersion.id,
|
|
678
|
+
versionPrefix: ''
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
const books = {
|
|
682
|
+
manual: {
|
|
683
|
+
config: defaultBook,
|
|
684
|
+
routes: pages
|
|
299
685
|
}
|
|
300
686
|
}
|
|
301
687
|
|
|
688
|
+
const pageEntries = getBookPageEntries({
|
|
689
|
+
[currentVersion.id]: {
|
|
690
|
+
version: currentVersion,
|
|
691
|
+
books
|
|
692
|
+
}
|
|
693
|
+
})
|
|
694
|
+
|
|
302
695
|
return {
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
696
|
+
versions: [currentVersion],
|
|
697
|
+
booksByVersion: {
|
|
698
|
+
[currentVersion.id]: {
|
|
699
|
+
version: currentVersion,
|
|
700
|
+
books,
|
|
701
|
+
allBooks: [defaultBook]
|
|
307
702
|
}
|
|
308
703
|
},
|
|
704
|
+
pageEntries,
|
|
705
|
+
books,
|
|
309
706
|
allBooks: [defaultBook],
|
|
310
707
|
allPages: pages
|
|
311
708
|
}
|
|
312
709
|
}
|
|
313
710
|
|
|
314
|
-
const
|
|
711
|
+
const configPath = resolve(projectRoot, 'docsector.config.js')
|
|
712
|
+
const { default: config = {} } = existsSync(configPath)
|
|
713
|
+
? await import(pathToFileURL(configPath).href)
|
|
714
|
+
: { default: {} }
|
|
715
|
+
|
|
716
|
+
const discoveredVersions = Array.from(new Map(entries.map(entry => [entry.versionId, {
|
|
717
|
+
id: entry.versionId,
|
|
718
|
+
current: entry.currentVersion,
|
|
719
|
+
routePrefix: entry.routePrefix,
|
|
720
|
+
sourceRoot: entry.sourceRoot
|
|
721
|
+
}])).values())
|
|
722
|
+
|
|
723
|
+
const normalizeVersionBadge = (rawBadge, { released, releaseStatus }) => {
|
|
724
|
+
const normalizedStatus = String(releaseStatus || '').toLowerCase()
|
|
725
|
+
const deprecated = normalizedStatus === 'deprecated'
|
|
726
|
+
const defaultColor = deprecated ? 'negative' : (released ? 'positive' : 'warning')
|
|
727
|
+
const defaultTextColor = (deprecated || released) ? 'white' : 'dark'
|
|
728
|
+
|
|
729
|
+
if (rawBadge === false || rawBadge === null) {
|
|
730
|
+
return { label: releaseStatus, color: defaultColor, textColor: defaultTextColor }
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
if (typeof rawBadge === 'string') {
|
|
734
|
+
return { label: rawBadge, color: defaultColor, textColor: defaultTextColor }
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
if (typeof rawBadge === 'object' && rawBadge !== null) {
|
|
738
|
+
const label = rawBadge.label || rawBadge.text || releaseStatus
|
|
739
|
+
if (!label) {
|
|
740
|
+
return null
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
return {
|
|
744
|
+
...rawBadge,
|
|
745
|
+
label,
|
|
746
|
+
color: rawBadge.color || defaultColor,
|
|
747
|
+
textColor: rawBadge.textColor || defaultTextColor
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
return { label: releaseStatus || (released ? 'released' : 'draft'), color: defaultColor, textColor: defaultTextColor }
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
const normalizeVersionDescriptor = (raw, fallback = {}) => {
|
|
755
|
+
const value = typeof raw === 'string' ? { id: raw, label: raw } : (raw || {})
|
|
756
|
+
const current = value.current === true || fallback.current === true
|
|
757
|
+
const id = current
|
|
758
|
+
? (value.id || config.branding?.version || fallback.id || 'current')
|
|
759
|
+
: (value.id || fallback.id || value.label || '')
|
|
760
|
+
const label = value.label || id
|
|
761
|
+
const prefixSource = value.routePrefix ?? fallback.routePrefix ?? id
|
|
762
|
+
const normalizedPrefix = trimSlashes(prefixSource)
|
|
763
|
+
const configuredStatus = value.deprecated === true || fallback.deprecated === true
|
|
764
|
+
? 'deprecated'
|
|
765
|
+
: (value.releaseStatus || value.status || fallback.releaseStatus || fallback.status)
|
|
766
|
+
const explicitlyReleased = value.released !== undefined
|
|
767
|
+
? value.released !== false
|
|
768
|
+
: (fallback.released !== undefined ? fallback.released !== false : null)
|
|
769
|
+
const released = configuredStatus === 'deprecated'
|
|
770
|
+
? true
|
|
771
|
+
: (explicitlyReleased ?? !['draft', 'unreleased', 'preview', 'next'].includes(String(configuredStatus || '').toLowerCase()))
|
|
772
|
+
const releaseStatus = configuredStatus || (released ? 'released' : 'draft')
|
|
773
|
+
const badge = normalizeVersionBadge(value.badge ?? value.releaseBadge ?? fallback.badge ?? fallback.releaseBadge, { released, releaseStatus })
|
|
774
|
+
|
|
775
|
+
return {
|
|
776
|
+
...fallback,
|
|
777
|
+
...value,
|
|
778
|
+
id,
|
|
779
|
+
label,
|
|
780
|
+
released,
|
|
781
|
+
releaseStatus,
|
|
782
|
+
deprecated: releaseStatus === 'deprecated',
|
|
783
|
+
badge,
|
|
784
|
+
current,
|
|
785
|
+
routePrefix: current ? '' : (normalizedPrefix ? `/${normalizedPrefix}` : ''),
|
|
786
|
+
sourceRoot: current ? '' : (value.sourceRoot || fallback.sourceRoot || (id ? `.old/${id}` : ''))
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
const configuredVersions = Array.isArray(config.branding?.versions) ? config.branding.versions : []
|
|
791
|
+
const currentVersion = normalizeVersionDescriptor(
|
|
792
|
+
configuredVersions.find(version => typeof version === 'object' && version?.current === true),
|
|
793
|
+
{ id: config.branding?.version || CURRENT_VERSION_KEY, current: true }
|
|
794
|
+
)
|
|
795
|
+
const versions = [currentVersion]
|
|
796
|
+
|
|
797
|
+
for (const configured of configuredVersions) {
|
|
798
|
+
if (typeof configured === 'object' && configured?.current === true) continue
|
|
799
|
+
|
|
800
|
+
const value = typeof configured === 'string' ? { id: configured, label: configured } : configured
|
|
801
|
+
const discovered = discoveredVersions.find(item => item.id === value?.id || item.id === value?.label) || {}
|
|
802
|
+
const isCurrent = value?.id === currentVersion.id || value?.label === currentVersion.id
|
|
803
|
+
const version = normalizeVersionDescriptor(value, isCurrent ? { ...currentVersion, current: true } : discovered)
|
|
804
|
+
|
|
805
|
+
if (!versions.some(item => item.id === version.id)) {
|
|
806
|
+
versions.push(version)
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
for (const discovered of discoveredVersions) {
|
|
811
|
+
if (discovered.current) continue
|
|
812
|
+
if (!versions.some(item => item.id === discovered.id)) {
|
|
813
|
+
versions.push(normalizeVersionDescriptor(null, discovered))
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
const versionById = versions.reduce((accumulator, version) => {
|
|
818
|
+
accumulator[version.id] = version
|
|
819
|
+
return accumulator
|
|
820
|
+
}, {})
|
|
821
|
+
|
|
822
|
+
const booksByVersion = {}
|
|
823
|
+
const currentBooks = {}
|
|
315
824
|
const allPages = {}
|
|
316
825
|
|
|
317
826
|
for (const [index, entry] of entries.entries()) {
|
|
827
|
+
const rawVersion = entry.currentVersion || entry.versionId === CURRENT_VERSION_KEY
|
|
828
|
+
? currentVersion
|
|
829
|
+
: (versionById[entry.versionId] || normalizeVersionDescriptor(null, entry))
|
|
318
830
|
const { default: rawConfig = {} } = await import(pathToFileURL(entry.bookPath).href)
|
|
319
831
|
const { default: routes = {} } = await import(pathToFileURL(entry.indexPath).href)
|
|
320
832
|
|
|
321
|
-
const resolvedId = rawConfig.id || entry.id || `book-${index + 1}`
|
|
322
|
-
const label = rawConfig.label || (resolvedId.charAt(0).toUpperCase() + resolvedId.slice(1))
|
|
323
|
-
|
|
324
833
|
const config = {
|
|
325
|
-
...rawConfig,
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
834
|
+
...normalizeBookConfig(rawConfig, entry.id, index),
|
|
835
|
+
version: rawVersion.id,
|
|
836
|
+
versionPrefix: rawVersion.routePrefix
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
if (!booksByVersion[rawVersion.id]) {
|
|
840
|
+
booksByVersion[rawVersion.id] = {
|
|
841
|
+
version: rawVersion,
|
|
842
|
+
books: {},
|
|
843
|
+
allBooks: []
|
|
844
|
+
}
|
|
331
845
|
}
|
|
332
846
|
|
|
333
|
-
books[
|
|
847
|
+
booksByVersion[rawVersion.id].books[config.id] = {
|
|
334
848
|
config,
|
|
335
849
|
routes
|
|
336
850
|
}
|
|
337
851
|
|
|
338
|
-
|
|
852
|
+
if (rawVersion.current) {
|
|
853
|
+
currentBooks[config.id] = {
|
|
854
|
+
config,
|
|
855
|
+
routes
|
|
856
|
+
}
|
|
857
|
+
Object.assign(allPages, routes || {})
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
for (const versionBooks of Object.values(booksByVersion)) {
|
|
862
|
+
versionBooks.allBooks = Object.values(versionBooks.books).map(book => book.config)
|
|
339
863
|
}
|
|
340
864
|
|
|
341
|
-
const allBooks = Object.values(
|
|
865
|
+
const allBooks = Object.values(currentBooks).map(book => book.config)
|
|
866
|
+
const pageEntries = getBookPageEntries(booksByVersion)
|
|
342
867
|
|
|
343
868
|
return {
|
|
344
|
-
|
|
869
|
+
versions,
|
|
870
|
+
booksByVersion,
|
|
871
|
+
pageEntries,
|
|
872
|
+
books: currentBooks,
|
|
345
873
|
allBooks,
|
|
346
874
|
allPages
|
|
347
875
|
}
|
|
@@ -355,18 +883,39 @@ async function loadBooksRegistry (projectRoot) {
|
|
|
355
883
|
* `guide.index.js` and `manual.index.js`. Build artifacts that need concrete
|
|
356
884
|
* URLs must iterate per book instead.
|
|
357
885
|
*/
|
|
358
|
-
function getBookPageEntries (
|
|
886
|
+
function getBookPageEntries (booksByVersion = {}) {
|
|
359
887
|
const pageEntries = []
|
|
360
888
|
|
|
361
|
-
for (const [
|
|
362
|
-
const
|
|
889
|
+
for (const [versionId, versionBooks] of Object.entries(booksByVersion || {})) {
|
|
890
|
+
const version = versionBooks?.version || {
|
|
891
|
+
id: versionId,
|
|
892
|
+
label: versionId,
|
|
893
|
+
current: true,
|
|
894
|
+
routePrefix: '',
|
|
895
|
+
sourceRoot: ''
|
|
896
|
+
}
|
|
363
897
|
|
|
364
|
-
for (const [
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
page
|
|
369
|
-
|
|
898
|
+
for (const [bookId, book] of Object.entries(versionBooks?.books || {})) {
|
|
899
|
+
const fallbackBook = book?.config?.id || bookId || 'manual'
|
|
900
|
+
|
|
901
|
+
for (const [pagePath, page] of Object.entries(book?.routes || {})) {
|
|
902
|
+
const bookName = resolvePageBook(page?.config, fallbackBook)
|
|
903
|
+
const pathSegments = String(pagePath || '').replace(/^\//, '').split('/').filter(Boolean)
|
|
904
|
+
|
|
905
|
+
pageEntries.push({
|
|
906
|
+
version: version.id,
|
|
907
|
+
versionLabel: version.label || version.id,
|
|
908
|
+
versionCurrent: version.current === true,
|
|
909
|
+
versionPrefix: version.routePrefix || '',
|
|
910
|
+
sourceRoot: version.sourceRoot || '',
|
|
911
|
+
book: bookName,
|
|
912
|
+
bookConfig: book.config,
|
|
913
|
+
pagePath,
|
|
914
|
+
page,
|
|
915
|
+
i18nSegments: version.current === true ? [bookName, ...pathSegments] : [version.id, bookName, ...pathSegments],
|
|
916
|
+
unversionedPath: `/${bookName}${pagePath}`
|
|
917
|
+
})
|
|
918
|
+
}
|
|
370
919
|
}
|
|
371
920
|
}
|
|
372
921
|
|
|
@@ -385,7 +934,11 @@ function isPagesRegistryFile (projectRoot, changedPath) {
|
|
|
385
934
|
const relativePath = normalizedPath.slice(prefix.length)
|
|
386
935
|
|
|
387
936
|
if (relativePath === 'index.js') return true
|
|
388
|
-
|
|
937
|
+
if (/^[^/]+\.book\.js$/.test(relativePath) || /^[^/]+\.index\.js$/.test(relativePath)) {
|
|
938
|
+
return true
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
return /^\.old\/[^/]+\/(?:index\.js|[^/]+\.book\.js|[^/]+\.index\.js)$/.test(relativePath)
|
|
389
942
|
}
|
|
390
943
|
|
|
391
944
|
/**
|
|
@@ -489,8 +1042,7 @@ function createPrerenderMetaPlugin (projectRoot) {
|
|
|
489
1042
|
// Dynamic import books registry and docsector config
|
|
490
1043
|
const configUrl = pathToFileURL(resolve(projectRoot, 'docsector.config.js')).href
|
|
491
1044
|
|
|
492
|
-
const {
|
|
493
|
-
const pageEntries = getBookPageEntries(books)
|
|
1045
|
+
const { pageEntries } = await loadBooksRegistry(projectRoot)
|
|
494
1046
|
const { default: config } = await import(configUrl)
|
|
495
1047
|
|
|
496
1048
|
const brandingName = config.branding?.name || ''
|
|
@@ -508,7 +1060,8 @@ function createPrerenderMetaPlugin (projectRoot) {
|
|
|
508
1060
|
|
|
509
1061
|
let count = 0
|
|
510
1062
|
|
|
511
|
-
for (const
|
|
1063
|
+
for (const entry of pageEntries) {
|
|
1064
|
+
const { page } = entry
|
|
512
1065
|
if (page.config === null) continue
|
|
513
1066
|
|
|
514
1067
|
const titleData = page.data?.[defaultLang] || page.data?.['*'] || page.data?.['en-US'] || Object.values(page.data || {})[0]
|
|
@@ -526,7 +1079,7 @@ function createPrerenderMetaPlugin (projectRoot) {
|
|
|
526
1079
|
if (page.config.subpages?.vs) subpages.push('vs')
|
|
527
1080
|
|
|
528
1081
|
for (const subpage of subpages) {
|
|
529
|
-
const routePath =
|
|
1082
|
+
const routePath = buildPageRoutePath(entry, subpage)
|
|
530
1083
|
|
|
531
1084
|
const html = baseHtml
|
|
532
1085
|
.replace(/<title>[^<]*<\/title>/, () => `<title>${fullTitle}</title>`)
|
|
@@ -1101,13 +1654,13 @@ function createMarkdownBuildPlugin (projectRoot) {
|
|
|
1101
1654
|
const configUrl = pathToFileURL(resolve(projectRoot, 'docsector.config.js')).href
|
|
1102
1655
|
|
|
1103
1656
|
const { default: config } = await import(configUrl)
|
|
1104
|
-
const {
|
|
1105
|
-
const pageEntries = getBookPageEntries(books)
|
|
1657
|
+
const { pageEntries } = await loadBooksRegistry(projectRoot)
|
|
1106
1658
|
|
|
1107
1659
|
const defaultLang = config.defaultLanguage || config.languages?.[0]?.value || 'en-US'
|
|
1108
1660
|
let count = 0
|
|
1109
1661
|
|
|
1110
|
-
for (const
|
|
1662
|
+
for (const entry of pageEntries) {
|
|
1663
|
+
const { page } = entry
|
|
1111
1664
|
if (page.config === null) continue
|
|
1112
1665
|
if (page.config.status === 'empty') continue
|
|
1113
1666
|
|
|
@@ -1116,10 +1669,10 @@ function createMarkdownBuildPlugin (projectRoot) {
|
|
|
1116
1669
|
if (page.config.subpages?.vs) subpages.push('vs')
|
|
1117
1670
|
|
|
1118
1671
|
for (const subpage of subpages) {
|
|
1119
|
-
const srcFile =
|
|
1672
|
+
const srcFile = resolveMarkdownSourceFile(pagesDir, entry, subpage, defaultLang)
|
|
1120
1673
|
if (!existsSync(srcFile)) continue
|
|
1121
1674
|
|
|
1122
|
-
const routePath =
|
|
1675
|
+
const routePath = buildPageRoutePath(entry, subpage)
|
|
1123
1676
|
const destFile = resolve(distDir, `${routePath}.md`)
|
|
1124
1677
|
const destDir = resolve(destFile, '..')
|
|
1125
1678
|
|
|
@@ -1154,7 +1707,8 @@ function createMarkdownBuildPlugin (projectRoot) {
|
|
|
1154
1707
|
const today = new Date().toISOString().split('T')[0]
|
|
1155
1708
|
let urls = ''
|
|
1156
1709
|
|
|
1157
|
-
for (const
|
|
1710
|
+
for (const entry of pageEntries) {
|
|
1711
|
+
const { page } = entry
|
|
1158
1712
|
if (page.config === null) continue
|
|
1159
1713
|
if (page.config.status === 'empty') continue
|
|
1160
1714
|
|
|
@@ -1163,10 +1717,10 @@ function createMarkdownBuildPlugin (projectRoot) {
|
|
|
1163
1717
|
if (page.config.subpages?.vs) subpages.push('vs')
|
|
1164
1718
|
|
|
1165
1719
|
for (const subpage of subpages) {
|
|
1166
|
-
const srcFile =
|
|
1720
|
+
const srcFile = resolveMarkdownSourceFile(pagesDir, entry, subpage, defaultLang)
|
|
1167
1721
|
if (!existsSync(srcFile)) continue
|
|
1168
1722
|
|
|
1169
|
-
const routePath =
|
|
1723
|
+
const routePath = buildPageRoutePath(entry, subpage, { leadingSlash: true })
|
|
1170
1724
|
urls += ` <url>\n <loc>${siteUrl}${routePath}</loc>\n <lastmod>${today}</lastmod>\n </url>\n`
|
|
1171
1725
|
}
|
|
1172
1726
|
}
|
|
@@ -1185,7 +1739,8 @@ function createMarkdownBuildPlugin (projectRoot) {
|
|
|
1185
1739
|
|
|
1186
1740
|
const llmsSections = {}
|
|
1187
1741
|
|
|
1188
|
-
for (const
|
|
1742
|
+
for (const entry of pageEntries) {
|
|
1743
|
+
const { book, pagePath, page } = entry
|
|
1189
1744
|
if (page.config === null) continue
|
|
1190
1745
|
if (page.config.status === 'empty') continue
|
|
1191
1746
|
|
|
@@ -1200,10 +1755,10 @@ function createMarkdownBuildPlugin (projectRoot) {
|
|
|
1200
1755
|
if (page.config.subpages?.vs) subpages.push('vs')
|
|
1201
1756
|
|
|
1202
1757
|
for (const subpage of subpages) {
|
|
1203
|
-
const srcFile =
|
|
1758
|
+
const srcFile = resolveMarkdownSourceFile(pagesDir, entry, subpage, defaultLang)
|
|
1204
1759
|
if (!existsSync(srcFile)) continue
|
|
1205
1760
|
|
|
1206
|
-
const routePath =
|
|
1761
|
+
const routePath = buildPageRoutePath(entry, subpage)
|
|
1207
1762
|
const mdUrl = `${siteUrl}/${routePath}.md`
|
|
1208
1763
|
const pageUrl = `${siteUrl}/${routePath}`
|
|
1209
1764
|
|
|
@@ -1805,7 +2360,8 @@ export async function onRequest (context) {
|
|
|
1805
2360
|
|
|
1806
2361
|
// Collect page index for MCP
|
|
1807
2362
|
const mcpPages = []
|
|
1808
|
-
for (const
|
|
2363
|
+
for (const entry of pageEntries) {
|
|
2364
|
+
const { book, pagePath, page } = entry
|
|
1809
2365
|
if (page.config === null) continue
|
|
1810
2366
|
if (page.config.status === 'empty') continue
|
|
1811
2367
|
|
|
@@ -1820,13 +2376,14 @@ export async function onRequest (context) {
|
|
|
1820
2376
|
if (page.config.subpages?.vs) subpageList.push('vs')
|
|
1821
2377
|
|
|
1822
2378
|
for (const subpage of subpageList) {
|
|
1823
|
-
const srcFile =
|
|
2379
|
+
const srcFile = resolveMarkdownSourceFile(pagesDir, entry, subpage, defaultLang)
|
|
1824
2380
|
if (!existsSync(srcFile)) continue
|
|
1825
2381
|
|
|
1826
2382
|
mcpPages.push({
|
|
1827
|
-
path:
|
|
2383
|
+
path: buildPageRoutePath(entry, subpage),
|
|
1828
2384
|
title: defaultTitle,
|
|
1829
2385
|
book,
|
|
2386
|
+
version: entry.version,
|
|
1830
2387
|
type: book,
|
|
1831
2388
|
subpage
|
|
1832
2389
|
})
|