@docsector/docsector-reader 1.7.1 → 2.0.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/.eslintrc.cjs +2 -0
- package/README.md +91 -9
- package/bin/docsector.js +27 -13
- package/package.json +1 -1
- package/src/components/DH1.vue +2 -1
- package/src/components/DMenu.vue +70 -30
- package/src/components/DMenuItem.vue +12 -6
- package/src/components/DPage.vue +124 -31
- package/src/components/DPageAnchor.vue +13 -1
- package/src/components/DPageBar.vue +2 -1
- package/src/components/DPageMeta.vue +9 -4
- package/src/components/DPageSection.vue +2 -1
- package/src/composables/useWebMcp.js +2 -1
- package/src/i18n/helpers.js +36 -9
- package/src/i18n/index.js +2 -2
- package/src/i18n/path.js +101 -0
- package/src/index.js +25 -2
- package/src/layouts/DefaultLayout.vue +181 -2
- package/src/pages/guide/getting-started.overview.en-US.md +3 -2
- package/src/pages/guide/getting-started.overview.pt-BR.md +3 -2
- package/src/pages/guide/pages-and-routing.overview.en-US.md +6 -6
- package/src/pages/guide/pages-and-routing.overview.pt-BR.md +6 -6
- package/src/pages/guide.book.js +12 -0
- package/src/pages/guide.index.js +184 -0
- package/src/pages/manual.book.js +12 -0
- package/src/pages/{index.js → manual.index.js} +13 -216
- package/src/quasar.factory.js +370 -49
- package/src/router/routes.js +132 -46
package/src/quasar.factory.js
CHANGED
|
@@ -61,33 +61,344 @@ function getPackageRoot (projectRoot) {
|
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
/**
|
|
64
|
-
*
|
|
65
|
-
|
|
66
|
-
|
|
64
|
+
* Normalize paths for cross-platform file matching.
|
|
65
|
+
*/
|
|
66
|
+
function normalizePathForMatch (path) {
|
|
67
|
+
return String(path || '').replace(/\\/g, '/')
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* List top-level page registry definition files.
|
|
72
|
+
*
|
|
73
|
+
* Includes:
|
|
74
|
+
* - src/pages/index.js (legacy)
|
|
75
|
+
* - src/pages/*.book.js
|
|
76
|
+
* - src/pages/*.index.js
|
|
77
|
+
*/
|
|
78
|
+
function getPagesRegistryFiles (projectRoot) {
|
|
79
|
+
const pagesDir = resolve(projectRoot, 'src', 'pages')
|
|
80
|
+
if (!existsSync(pagesDir)) return []
|
|
81
|
+
|
|
82
|
+
const names = readdirSync(pagesDir, { withFileTypes: true })
|
|
83
|
+
.filter(entry => entry.isFile())
|
|
84
|
+
.map(entry => entry.name)
|
|
85
|
+
|
|
86
|
+
return names
|
|
87
|
+
.filter(name => {
|
|
88
|
+
if (name === 'index.js') return true
|
|
89
|
+
return /^[^/]+\.book\.js$/.test(name) || /^[^/]+\.index\.js$/.test(name)
|
|
90
|
+
})
|
|
91
|
+
.sort()
|
|
92
|
+
.map(name => resolve(pagesDir, name))
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Discover configured books from src/pages/*.book.js paired with *.index.js.
|
|
97
|
+
*/
|
|
98
|
+
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
|
+
const entries = []
|
|
111
|
+
for (const bookFile of books) {
|
|
112
|
+
const baseName = bookFile.slice(0, -'.book.js'.length)
|
|
113
|
+
const indexFile = `${baseName}.index.js`
|
|
114
|
+
if (!names.includes(indexFile)) continue
|
|
115
|
+
|
|
116
|
+
entries.push({
|
|
117
|
+
id: baseName,
|
|
118
|
+
bookFile,
|
|
119
|
+
indexFile,
|
|
120
|
+
bookPath: resolve(pagesDir, bookFile),
|
|
121
|
+
indexPath: resolve(pagesDir, indexFile)
|
|
122
|
+
})
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return entries
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Resolve book identifier from page config with legacy fallback support.
|
|
130
|
+
*/
|
|
131
|
+
function resolvePageBook (config, fallbackBook = 'manual') {
|
|
132
|
+
if (!config || typeof config !== 'object') return fallbackBook
|
|
133
|
+
return config.book ?? config.type ?? fallbackBook
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const DEFAULT_BOOK_COLORS = Object.freeze({
|
|
137
|
+
active: 'white',
|
|
138
|
+
inactive: 'rgba(255, 255, 255, 0.72)'
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
function normalizeBookColorConfig (rawColor) {
|
|
142
|
+
if (typeof rawColor === 'object' && rawColor !== null && !Array.isArray(rawColor)) {
|
|
143
|
+
const active = typeof rawColor.active === 'string' && rawColor.active.trim().length > 0
|
|
144
|
+
? rawColor.active.trim()
|
|
145
|
+
: DEFAULT_BOOK_COLORS.active
|
|
146
|
+
|
|
147
|
+
const inactive = typeof rawColor.inactive === 'string' && rawColor.inactive.trim().length > 0
|
|
148
|
+
? rawColor.inactive.trim()
|
|
149
|
+
: active
|
|
150
|
+
|
|
151
|
+
return { active, inactive }
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (typeof rawColor === 'string' && rawColor.trim().length > 0) {
|
|
155
|
+
const normalized = rawColor.trim()
|
|
156
|
+
return {
|
|
157
|
+
active: normalized,
|
|
158
|
+
inactive: normalized
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return { ...DEFAULT_BOOK_COLORS }
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Build source code for the virtual module `virtual:docsector-books`.
|
|
167
|
+
*/
|
|
168
|
+
function buildVirtualBooksModule (projectRoot) {
|
|
169
|
+
const bookEntries = getBookRegistryEntries(projectRoot)
|
|
170
|
+
|
|
171
|
+
// Legacy fallback: support projects that still define src/pages/index.js only.
|
|
172
|
+
if (bookEntries.length === 0) {
|
|
173
|
+
return `import legacyPages from 'pages'
|
|
174
|
+
|
|
175
|
+
const defaultBook = {
|
|
176
|
+
id: 'manual',
|
|
177
|
+
label: 'Manual',
|
|
178
|
+
icon: 'menu_book',
|
|
179
|
+
order: 1,
|
|
180
|
+
color: {
|
|
181
|
+
active: 'white',
|
|
182
|
+
inactive: 'rgba(255, 255, 255, 0.72)'
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const normalizedPages = legacyPages || {}
|
|
187
|
+
|
|
188
|
+
export const books = {
|
|
189
|
+
manual: {
|
|
190
|
+
config: defaultBook,
|
|
191
|
+
routes: normalizedPages
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
export const allBooks = [defaultBook]
|
|
196
|
+
export const allPages = normalizedPages
|
|
197
|
+
|
|
198
|
+
export default books
|
|
199
|
+
`
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const imports = []
|
|
203
|
+
const rows = []
|
|
204
|
+
|
|
205
|
+
for (const [index, entry] of bookEntries.entries()) {
|
|
206
|
+
imports.push(`import __book_${index} from 'pages/${entry.bookFile}'`)
|
|
207
|
+
imports.push(`import __routes_${index} from 'pages/${entry.indexFile}'`)
|
|
208
|
+
rows.push(` { fallbackId: ${JSON.stringify(entry.id)}, config: __book_${index}, routes: __routes_${index} }`)
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return `${imports.join('\n')}
|
|
212
|
+
|
|
213
|
+
const entries = [
|
|
214
|
+
${rows.join(',\n')}
|
|
215
|
+
]
|
|
216
|
+
|
|
217
|
+
const DEFAULT_BOOK_COLORS = Object.freeze({
|
|
218
|
+
active: 'white',
|
|
219
|
+
inactive: 'rgba(255, 255, 255, 0.72)'
|
|
220
|
+
})
|
|
221
|
+
|
|
222
|
+
const normalizeBookColor = (rawColor) => {
|
|
223
|
+
if (typeof rawColor === 'object' && rawColor !== null && !Array.isArray(rawColor)) {
|
|
224
|
+
const active = typeof rawColor.active === 'string' && rawColor.active.trim().length > 0
|
|
225
|
+
? rawColor.active.trim()
|
|
226
|
+
: DEFAULT_BOOK_COLORS.active
|
|
227
|
+
|
|
228
|
+
const inactive = typeof rawColor.inactive === 'string' && rawColor.inactive.trim().length > 0
|
|
229
|
+
? rawColor.inactive.trim()
|
|
230
|
+
: active
|
|
231
|
+
|
|
232
|
+
return { active, inactive }
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
if (typeof rawColor === 'string' && rawColor.trim().length > 0) {
|
|
236
|
+
const normalized = rawColor.trim()
|
|
237
|
+
return {
|
|
238
|
+
active: normalized,
|
|
239
|
+
inactive: normalized
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
return { ...DEFAULT_BOOK_COLORS }
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
export const books = entries.reduce((accumulator, entry, index) => {
|
|
247
|
+
const config = entry.config || {}
|
|
248
|
+
const resolvedId = config.id || entry.fallbackId || ('book-' + (index + 1))
|
|
249
|
+
const label = config.label || (resolvedId.charAt(0).toUpperCase() + resolvedId.slice(1))
|
|
250
|
+
const normalizedConfig = {
|
|
251
|
+
...config,
|
|
252
|
+
id: resolvedId,
|
|
253
|
+
label,
|
|
254
|
+
icon: config.icon || 'menu_book',
|
|
255
|
+
order: config.order ?? (index + 1),
|
|
256
|
+
color: normalizeBookColor(config.color)
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
accumulator[resolvedId] = {
|
|
260
|
+
config: normalizedConfig,
|
|
261
|
+
routes: entry.routes || {}
|
|
262
|
+
}
|
|
263
|
+
return accumulator
|
|
264
|
+
}, {})
|
|
265
|
+
|
|
266
|
+
export const allBooks = Object.values(books).map(book => book.config)
|
|
267
|
+
export const allPages = Object.values(books).reduce((accumulator, book) => {
|
|
268
|
+
return {
|
|
269
|
+
...accumulator,
|
|
270
|
+
...(book.routes || {})
|
|
271
|
+
}
|
|
272
|
+
}, {})
|
|
273
|
+
|
|
274
|
+
export default books
|
|
275
|
+
`
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Load books and merged pages for build-time plugins (Node context).
|
|
280
|
+
*/
|
|
281
|
+
async function loadBooksRegistry (projectRoot) {
|
|
282
|
+
const entries = getBookRegistryEntries(projectRoot)
|
|
283
|
+
|
|
284
|
+
// Legacy fallback
|
|
285
|
+
if (entries.length === 0) {
|
|
286
|
+
const legacyPath = resolve(projectRoot, 'src', 'pages', 'index.js')
|
|
287
|
+
const pages = existsSync(legacyPath)
|
|
288
|
+
? ((await import(pathToFileURL(legacyPath).href)).default || {})
|
|
289
|
+
: {}
|
|
290
|
+
|
|
291
|
+
const defaultBook = {
|
|
292
|
+
id: 'manual',
|
|
293
|
+
label: 'Manual',
|
|
294
|
+
icon: 'menu_book',
|
|
295
|
+
order: 1,
|
|
296
|
+
color: {
|
|
297
|
+
active: 'white',
|
|
298
|
+
inactive: 'rgba(255, 255, 255, 0.72)'
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
return {
|
|
303
|
+
books: {
|
|
304
|
+
manual: {
|
|
305
|
+
config: defaultBook,
|
|
306
|
+
routes: pages
|
|
307
|
+
}
|
|
308
|
+
},
|
|
309
|
+
allBooks: [defaultBook],
|
|
310
|
+
allPages: pages
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
const books = {}
|
|
315
|
+
const allPages = {}
|
|
316
|
+
|
|
317
|
+
for (const [index, entry] of entries.entries()) {
|
|
318
|
+
const { default: rawConfig = {} } = await import(pathToFileURL(entry.bookPath).href)
|
|
319
|
+
const { default: routes = {} } = await import(pathToFileURL(entry.indexPath).href)
|
|
320
|
+
|
|
321
|
+
const resolvedId = rawConfig.id || entry.id || `book-${index + 1}`
|
|
322
|
+
const label = rawConfig.label || (resolvedId.charAt(0).toUpperCase() + resolvedId.slice(1))
|
|
323
|
+
|
|
324
|
+
const config = {
|
|
325
|
+
...rawConfig,
|
|
326
|
+
id: resolvedId,
|
|
327
|
+
label,
|
|
328
|
+
icon: rawConfig.icon || 'menu_book',
|
|
329
|
+
order: rawConfig.order ?? (index + 1),
|
|
330
|
+
color: normalizeBookColorConfig(rawConfig.color)
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
books[resolvedId] = {
|
|
334
|
+
config,
|
|
335
|
+
routes
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
Object.assign(allPages, routes || {})
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
const allBooks = Object.values(books).map(book => book.config)
|
|
342
|
+
|
|
343
|
+
return {
|
|
344
|
+
books,
|
|
345
|
+
allBooks,
|
|
346
|
+
allPages
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* Check if a file path is a book registry definition file.
|
|
352
|
+
*/
|
|
353
|
+
function isPagesRegistryFile (projectRoot, changedPath) {
|
|
354
|
+
const pagesDir = normalizePathForMatch(resolve(projectRoot, 'src', 'pages'))
|
|
355
|
+
const normalizedPath = normalizePathForMatch(changedPath)
|
|
356
|
+
const prefix = `${pagesDir}/`
|
|
357
|
+
|
|
358
|
+
if (!normalizedPath.startsWith(prefix)) return false
|
|
359
|
+
const relativePath = normalizedPath.slice(prefix.length)
|
|
360
|
+
|
|
361
|
+
if (relativePath === 'index.js') return true
|
|
362
|
+
return /^[^/]+\.book\.js$/.test(relativePath) || /^[^/]+\.index\.js$/.test(relativePath)
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* Create a Vite plugin that exposes discovered books through
|
|
367
|
+
* `virtual:docsector-books` and restarts dev server when definitions change.
|
|
67
368
|
*
|
|
68
369
|
* Why: The router module (`routes.js`) imports consumer content via the
|
|
69
370
|
* `pages` alias. Vite's dep optimizer pre-bundles the router with the
|
|
70
371
|
* consumer content inlined, but the optimizer cache hash is based on config
|
|
71
|
-
* and lockfile only — NOT on consumer source files. So when
|
|
72
|
-
*
|
|
73
|
-
* until the cache is manually cleared.
|
|
74
|
-
*
|
|
75
|
-
* Fix: When pages/index.js changes, the watcher plugin clears the dep cache,
|
|
76
|
-
* sets an env flag, and restarts the server. On restart, the config reads the
|
|
77
|
-
* flag and sets `optimizeDeps.force = true`, which makes Vite generate a new
|
|
78
|
-
* browserHash — effectively busting the browser module cache.
|
|
372
|
+
* and lockfile only — NOT on consumer source files. So when page registries
|
|
373
|
+
* change during development, the optimizer can serve stale pre-bundled code.
|
|
79
374
|
*/
|
|
80
|
-
function
|
|
81
|
-
const
|
|
375
|
+
function createBooksPlugin (projectRoot) {
|
|
376
|
+
const virtualId = 'virtual:docsector-books'
|
|
377
|
+
const resolvedId = '\0' + virtualId
|
|
378
|
+
|
|
82
379
|
return {
|
|
83
|
-
name: 'docsector-
|
|
380
|
+
name: 'docsector-books',
|
|
381
|
+
resolveId (id) {
|
|
382
|
+
if (id === virtualId) return resolvedId
|
|
383
|
+
},
|
|
384
|
+
load (id) {
|
|
385
|
+
if (id !== resolvedId) return null
|
|
386
|
+
return buildVirtualBooksModule(projectRoot)
|
|
387
|
+
},
|
|
84
388
|
configureServer (server) {
|
|
85
|
-
|
|
86
|
-
if (changedPath
|
|
389
|
+
const onPagesRegistryChange = (changedPath) => {
|
|
390
|
+
if (isPagesRegistryFile(projectRoot, changedPath)) {
|
|
87
391
|
server.config.logger.info(
|
|
88
|
-
|
|
392
|
+
`\\x1b[36m[docsector]\\x1b[0m pages registry changed (${changedPath}) — clearing dep cache and restarting...`,
|
|
89
393
|
{ timestamp: true }
|
|
90
394
|
)
|
|
395
|
+
|
|
396
|
+
// Invalidate virtual module before restart
|
|
397
|
+
const module = server.moduleGraph.getModuleById(resolvedId)
|
|
398
|
+
if (module) {
|
|
399
|
+
server.moduleGraph.invalidateModule(module)
|
|
400
|
+
}
|
|
401
|
+
|
|
91
402
|
// Signal the restarted config to force a new optimizer hash
|
|
92
403
|
process.env.__DOCSECTOR_FORCE_OPTIMIZE = '1'
|
|
93
404
|
// Delete the stale optimizer cache
|
|
@@ -95,7 +406,11 @@ function createPagesWatchPlugin (projectRoot) {
|
|
|
95
406
|
rmSync(cacheDir, { recursive: true, force: true })
|
|
96
407
|
server.restart()
|
|
97
408
|
}
|
|
98
|
-
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
server.watcher.on('add', onPagesRegistryChange)
|
|
412
|
+
server.watcher.on('change', onPagesRegistryChange)
|
|
413
|
+
server.watcher.on('unlink', onPagesRegistryChange)
|
|
99
414
|
}
|
|
100
415
|
}
|
|
101
416
|
}
|
|
@@ -145,11 +460,10 @@ function createPrerenderMetaPlugin (projectRoot) {
|
|
|
145
460
|
|
|
146
461
|
const baseHtml = readFileSync(baseHtmlPath, 'utf-8')
|
|
147
462
|
|
|
148
|
-
// Dynamic import
|
|
149
|
-
const pagesUrl = pathToFileURL(resolve(projectRoot, 'src', 'pages', 'index.js')).href
|
|
463
|
+
// Dynamic import books registry and docsector config
|
|
150
464
|
const configUrl = pathToFileURL(resolve(projectRoot, 'docsector.config.js')).href
|
|
151
465
|
|
|
152
|
-
const {
|
|
466
|
+
const { allPages: pages } = await loadBooksRegistry(projectRoot)
|
|
153
467
|
const { default: config } = await import(configUrl)
|
|
154
468
|
|
|
155
469
|
const brandingName = config.branding?.name || ''
|
|
@@ -170,7 +484,7 @@ function createPrerenderMetaPlugin (projectRoot) {
|
|
|
170
484
|
for (const [pagePath, page] of Object.entries(pages)) {
|
|
171
485
|
if (page.config === null) continue
|
|
172
486
|
|
|
173
|
-
const
|
|
487
|
+
const book = resolvePageBook(page.config, 'manual')
|
|
174
488
|
const titleData = page.data?.[defaultLang] || page.data?.['*'] || page.data?.['en-US'] || Object.values(page.data || {})[0]
|
|
175
489
|
const title = titleData?.title || ''
|
|
176
490
|
const fullTitle = title
|
|
@@ -186,7 +500,7 @@ function createPrerenderMetaPlugin (projectRoot) {
|
|
|
186
500
|
if (page.config.subpages?.vs) subpages.push('vs')
|
|
187
501
|
|
|
188
502
|
for (const subpage of subpages) {
|
|
189
|
-
const routePath = `${
|
|
503
|
+
const routePath = `${book}${pagePath}/${subpage}`
|
|
190
504
|
|
|
191
505
|
const html = baseHtml
|
|
192
506
|
.replace(/<title>[^<]*<\/title>/, () => `<title>${fullTitle}</title>`)
|
|
@@ -759,10 +1073,9 @@ function createMarkdownBuildPlugin (projectRoot) {
|
|
|
759
1073
|
|
|
760
1074
|
const pagesDir = resolve(projectRoot, 'src', 'pages')
|
|
761
1075
|
const configUrl = pathToFileURL(resolve(projectRoot, 'docsector.config.js')).href
|
|
762
|
-
const pagesUrl = pathToFileURL(resolve(projectRoot, 'src', 'pages', 'index.js')).href
|
|
763
1076
|
|
|
764
1077
|
const { default: config } = await import(configUrl)
|
|
765
|
-
const {
|
|
1078
|
+
const { allPages: pages } = await loadBooksRegistry(projectRoot)
|
|
766
1079
|
|
|
767
1080
|
const defaultLang = config.defaultLanguage || config.languages?.[0]?.value || 'en-US'
|
|
768
1081
|
let count = 0
|
|
@@ -771,17 +1084,17 @@ function createMarkdownBuildPlugin (projectRoot) {
|
|
|
771
1084
|
if (page.config === null) continue
|
|
772
1085
|
if (page.config.status === 'empty') continue
|
|
773
1086
|
|
|
774
|
-
const
|
|
1087
|
+
const book = resolvePageBook(page.config, 'manual')
|
|
775
1088
|
|
|
776
1089
|
const subpages = ['overview']
|
|
777
1090
|
if (page.config.subpages?.showcase) subpages.push('showcase')
|
|
778
1091
|
if (page.config.subpages?.vs) subpages.push('vs')
|
|
779
1092
|
|
|
780
1093
|
for (const subpage of subpages) {
|
|
781
|
-
const srcFile = resolve(pagesDir, `${
|
|
1094
|
+
const srcFile = resolve(pagesDir, `${book}${pagePath}.${subpage}.${defaultLang}.md`)
|
|
782
1095
|
if (!existsSync(srcFile)) continue
|
|
783
1096
|
|
|
784
|
-
const routePath = `${
|
|
1097
|
+
const routePath = `${book}${pagePath}/${subpage}`
|
|
785
1098
|
const destFile = resolve(distDir, `${routePath}.md`)
|
|
786
1099
|
const destDir = resolve(destFile, '..')
|
|
787
1100
|
|
|
@@ -820,17 +1133,17 @@ function createMarkdownBuildPlugin (projectRoot) {
|
|
|
820
1133
|
if (page.config === null) continue
|
|
821
1134
|
if (page.config.status === 'empty') continue
|
|
822
1135
|
|
|
823
|
-
const
|
|
1136
|
+
const book = resolvePageBook(page.config, 'manual')
|
|
824
1137
|
|
|
825
1138
|
const subpages = ['overview']
|
|
826
1139
|
if (page.config.subpages?.showcase) subpages.push('showcase')
|
|
827
1140
|
if (page.config.subpages?.vs) subpages.push('vs')
|
|
828
1141
|
|
|
829
1142
|
for (const subpage of subpages) {
|
|
830
|
-
const srcFile = resolve(pagesDir, `${
|
|
1143
|
+
const srcFile = resolve(pagesDir, `${book}${pagePath}.${subpage}.${defaultLang}.md`)
|
|
831
1144
|
if (!existsSync(srcFile)) continue
|
|
832
1145
|
|
|
833
|
-
const routePath = `/${
|
|
1146
|
+
const routePath = `/${book}${pagePath}/${subpage}`
|
|
834
1147
|
urls += ` <url>\n <loc>${siteUrl}${routePath}</loc>\n <lastmod>${today}</lastmod>\n </url>\n`
|
|
835
1148
|
}
|
|
836
1149
|
}
|
|
@@ -853,7 +1166,7 @@ function createMarkdownBuildPlugin (projectRoot) {
|
|
|
853
1166
|
if (page.config === null) continue
|
|
854
1167
|
if (page.config.status === 'empty') continue
|
|
855
1168
|
|
|
856
|
-
const
|
|
1169
|
+
const book = resolvePageBook(page.config, 'manual')
|
|
857
1170
|
const title = page.data?.['*']?.title
|
|
858
1171
|
|| page.data?.[defaultLang]?.title
|
|
859
1172
|
|| page.data?.['en-US']?.title
|
|
@@ -865,18 +1178,18 @@ function createMarkdownBuildPlugin (projectRoot) {
|
|
|
865
1178
|
if (page.config.subpages?.vs) subpages.push('vs')
|
|
866
1179
|
|
|
867
1180
|
for (const subpage of subpages) {
|
|
868
|
-
const srcFile = resolve(pagesDir, `${
|
|
1181
|
+
const srcFile = resolve(pagesDir, `${book}${pagePath}.${subpage}.${defaultLang}.md`)
|
|
869
1182
|
if (!existsSync(srcFile)) continue
|
|
870
1183
|
|
|
871
|
-
const routePath = `${
|
|
1184
|
+
const routePath = `${book}${pagePath}/${subpage}`
|
|
872
1185
|
const mdUrl = `${siteUrl}/${routePath}.md`
|
|
873
1186
|
const pageUrl = `${siteUrl}/${routePath}`
|
|
874
1187
|
|
|
875
1188
|
const desc = page.config.meta?.description
|
|
876
1189
|
const descText = typeof desc === 'object' ? (desc[defaultLang] || desc['en-US'] || '') : (desc || '')
|
|
877
1190
|
|
|
878
|
-
if (!llmsSections[
|
|
879
|
-
llmsSections[
|
|
1191
|
+
if (!llmsSections[book]) llmsSections[book] = []
|
|
1192
|
+
llmsSections[book].push(
|
|
880
1193
|
descText
|
|
881
1194
|
? `- [${title}](${mdUrl}): ${descText}`
|
|
882
1195
|
: `- [${title}](${mdUrl})`
|
|
@@ -1474,7 +1787,7 @@ export async function onRequest (context) {
|
|
|
1474
1787
|
if (page.config === null) continue
|
|
1475
1788
|
if (page.config.status === 'empty') continue
|
|
1476
1789
|
|
|
1477
|
-
const
|
|
1790
|
+
const book = resolvePageBook(page.config, 'manual')
|
|
1478
1791
|
const defaultTitle = page.data?.['*']?.title
|
|
1479
1792
|
|| page.data?.[defaultLang]?.title
|
|
1480
1793
|
|| page.data?.['en-US']?.title
|
|
@@ -1486,13 +1799,14 @@ export async function onRequest (context) {
|
|
|
1486
1799
|
if (page.config.subpages?.vs) subpageList.push('vs')
|
|
1487
1800
|
|
|
1488
1801
|
for (const subpage of subpageList) {
|
|
1489
|
-
const srcFile = resolve(pagesDir, `${
|
|
1802
|
+
const srcFile = resolve(pagesDir, `${book}${pagePath}.${subpage}.${defaultLang}.md`)
|
|
1490
1803
|
if (!existsSync(srcFile)) continue
|
|
1491
1804
|
|
|
1492
1805
|
mcpPages.push({
|
|
1493
|
-
path: `${
|
|
1806
|
+
path: `${book}${pagePath}/${subpage}`,
|
|
1494
1807
|
title: defaultTitle,
|
|
1495
|
-
|
|
1808
|
+
book,
|
|
1809
|
+
type: book,
|
|
1496
1810
|
subpage
|
|
1497
1811
|
})
|
|
1498
1812
|
}
|
|
@@ -1874,12 +2188,12 @@ export function createQuasarConfig (options = {}) {
|
|
|
1874
2188
|
vueRouterMode: 'history',
|
|
1875
2189
|
|
|
1876
2190
|
vitePlugins: [
|
|
2191
|
+
createBooksPlugin(projectRoot),
|
|
1877
2192
|
createHjsonPlugin(),
|
|
1878
2193
|
createHomePageOverridePlugin(projectRoot),
|
|
1879
2194
|
createGitDatesPlugin(projectRoot),
|
|
1880
2195
|
createMarkdownEndpointPlugin(projectRoot),
|
|
1881
2196
|
createMarkdownBuildPlugin(projectRoot),
|
|
1882
|
-
createPagesWatchPlugin(projectRoot),
|
|
1883
2197
|
createPrerenderMetaPlugin(projectRoot),
|
|
1884
2198
|
...vitePlugins
|
|
1885
2199
|
],
|
|
@@ -1897,16 +2211,23 @@ export function createQuasarConfig (options = {}) {
|
|
|
1897
2211
|
viteConf.optimizeDeps.force = true
|
|
1898
2212
|
}
|
|
1899
2213
|
|
|
1900
|
-
// Include a hash of
|
|
1901
|
-
//
|
|
1902
|
-
//
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
2214
|
+
// Include a hash of page registry definition files (legacy index.js,
|
|
2215
|
+
// plus *.book.js and *.index.js) in optimizer config so Vite's
|
|
2216
|
+
// configHash/browserHash changes whenever routes/books are edited.
|
|
2217
|
+
const pagesRegistryFiles = getPagesRegistryFiles(projectRoot)
|
|
2218
|
+
if (pagesRegistryFiles.length > 0) {
|
|
2219
|
+
const pagesHashBuilder = createHash('sha256')
|
|
2220
|
+
for (const file of pagesRegistryFiles) {
|
|
2221
|
+
pagesHashBuilder
|
|
2222
|
+
.update(file)
|
|
2223
|
+
.update(readFileSync(file))
|
|
2224
|
+
}
|
|
2225
|
+
|
|
1906
2226
|
const pagesHash = createHash('sha256')
|
|
1907
|
-
.update(
|
|
2227
|
+
.update(pagesHashBuilder.digest('hex'))
|
|
1908
2228
|
.digest('hex')
|
|
1909
2229
|
.slice(0, 8)
|
|
2230
|
+
|
|
1910
2231
|
viteConf.optimizeDeps.esbuildOptions = viteConf.optimizeDeps.esbuildOptions || {}
|
|
1911
2232
|
viteConf.optimizeDeps.esbuildOptions.define = {
|
|
1912
2233
|
...(viteConf.optimizeDeps.esbuildOptions.define || {}),
|
|
@@ -1950,7 +2271,7 @@ export function createQuasarConfig (options = {}) {
|
|
|
1950
2271
|
// The router is excluded because routes.js imports consumer content via
|
|
1951
2272
|
// the `pages` alias. If pre-bundled, consumer content gets embedded in
|
|
1952
2273
|
// the optimizer cache whose hash doesn't track source file changes,
|
|
1953
|
-
// causing stale routes after editing
|
|
2274
|
+
// causing stale routes after editing page registry files.
|
|
1954
2275
|
viteConf.optimizeDeps.exclude = [
|
|
1955
2276
|
...(viteConf.optimizeDeps.exclude || []),
|
|
1956
2277
|
'boot/i18n', 'boot/store', 'boot/QZoom', 'boot/axios'
|