boltdocs 2.7.9 → 2.7.11
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/{cache-DorPMFgW.cjs → cache-Ba-DZQNH.cjs} +1 -1
- package/dist/{cache-CQKlT4fI.mjs → cache-BuMZ58L5.mjs} +1 -1
- package/dist/chunk-CU-zTemE.cjs +6 -0
- package/dist/client/index.cjs +1929 -1
- package/dist/client/index.js +1880 -1
- package/dist/client/mdx.cjs +7 -1
- package/dist/client/mdx.js +7 -1
- package/dist/client/primitives.cjs +60 -1
- package/dist/client/primitives.js +20 -1
- package/dist/docs-layout-BXHV0xw_.cjs +1431 -0
- package/dist/docs-layout-DwFndmj5.js +1231 -0
- package/dist/doctor-Be7Ly1oM.mjs +21 -0
- package/dist/{doctor-D4_Y7M4p.cjs → doctor-CrytFkqW.cjs} +1 -1
- package/dist/doctor-jMxWZyLJ.cjs +21 -0
- package/dist/generator-CHqxiQhF.cjs +21 -0
- package/dist/generator-ClVanhvi.mjs +21 -0
- package/dist/icons-dev-3cZMyt8r.cjs +1204 -0
- package/dist/icons-dev-Df8OQ481.js +839 -0
- package/dist/image-DtrI2cw3.cjs +268 -0
- package/dist/image-jxPb-2iV.js +214 -0
- package/dist/mdx-BdWkJTeB.cjs +523 -0
- package/dist/mdx-UTTLFWJq.js +494 -0
- package/dist/meta-loader-CWg2gnbY.mjs +6 -0
- package/dist/meta-loader-Cv9O0Pzl.cjs +6 -0
- package/dist/node/cli-entry.cjs +1 -1
- package/dist/node/cli-entry.mjs +1 -1
- package/dist/node/index.cjs +1 -1
- package/dist/node/index.mjs +1 -1
- package/dist/node/routes/worker.cjs +1 -1
- package/dist/node/routes/worker.mjs +1 -1
- package/dist/node-BSM4qcDK.cjs +111 -0
- package/dist/node-BspZN3R2.mjs +111 -0
- package/dist/{package-VfQM94VL.cjs → package-DIIrjuWI.cjs} +1 -1
- package/dist/{package-B4MD00N3.mjs → package-K0zsjGIz.mjs} +1 -1
- package/dist/{parser-Bh11BsdA.cjs → parser-Aq8LoH-0.cjs} +1 -1
- package/dist/{parser-DYRzXWmA.cjs → parser-CdNbqN5y.cjs} +1 -1
- package/dist/parser-nE792MLO.mjs +6 -0
- package/dist/rolldown-runtime-fkIsjY3S.mjs +6 -0
- package/dist/{routes-Co1mRM58.cjs → routes-2k3tbUmC.cjs} +1 -1
- package/dist/routes-CpxZIsMM.mjs +6 -0
- package/dist/{routes-CHf76Ye4.cjs → routes-DP1vmWRj.cjs} +1 -1
- package/dist/search-dialog-BHuIiUC6.js +8 -0
- package/dist/search-dialog-BNF10tDl.js +375 -0
- package/dist/search-dialog-BwkDuI9R.cjs +220 -0
- package/dist/search-dialog-C7xuvyNk.cjs +386 -0
- package/dist/search-dialog-CIQg6k8c.cjs +8 -0
- package/dist/search-dialog-D-DDN7zJ.js +208 -0
- package/dist/utils-CG65J0Sc.mjs +7 -0
- package/dist/utils-CKunkU96.cjs +7 -0
- package/dist/{worker-pool-BwU8ckrg.cjs → worker-pool-Crbqgw5R.cjs} +1 -1
- package/package.json +5 -5
- package/dist/chunk-Ds5LZdWN.cjs +0 -6
- package/dist/docs-layout-KoWNZc8_.js +0 -6
- package/dist/docs-layout-x2yKt2cL.cjs +0 -6
- package/dist/doctor-BD1BSB03.mjs +0 -23
- package/dist/doctor-BHc9ua6r.cjs +0 -23
- package/dist/generator-DGW6pkCC.cjs +0 -22
- package/dist/generator-Dv3wEmhZ.mjs +0 -22
- package/dist/icons-dev-B_RZIyxu.js +0 -6
- package/dist/icons-dev-BlV3wWFT.cjs +0 -6
- package/dist/image-BHhTvQzr.cjs +0 -6
- package/dist/image-CqKzYD8f.js +0 -6
- package/dist/mdx-DudBEac0.js +0 -7
- package/dist/mdx-r4cDQxWu.cjs +0 -7
- package/dist/meta-loader-0gJ4PtBC.cjs +0 -6
- package/dist/meta-loader-9IpAHWDS.mjs +0 -6
- package/dist/node-DBaH7kat.mjs +0 -111
- package/dist/node-t5C3Q85p.cjs +0 -111
- package/dist/parser-9cVdK7w9.mjs +0 -6
- package/dist/routes-DwrMa5-z.mjs +0 -6
- package/dist/search-dialog-B584t9ZF.js +0 -6
- package/dist/search-dialog-BvBopRsZ.cjs +0 -6
- package/dist/search-dialog-ByvGScjt.js +0 -6
- package/dist/search-dialog-Cyko6TJm.cjs +0 -6
- package/dist/search-dialog-D6BNohIJ.js +0 -6
- package/dist/search-dialog-DuYTIefy.cjs +0 -6
- package/dist/utils-BxNAXhZZ.mjs +0 -7
- package/dist/utils-Clzu7jvb.cjs +0 -7
- package/src/client/app/config-context.tsx +0 -51
- package/src/client/app/doc-page.tsx +0 -38
- package/src/client/app/docs-layout.tsx +0 -28
- package/src/client/app/head.tsx +0 -122
- package/src/client/app/helmet-compat.tsx +0 -36
- package/src/client/app/mdx-component.tsx +0 -8
- package/src/client/app/mdx-components-context.tsx +0 -72
- package/src/client/app/routes-context.tsx +0 -34
- package/src/client/app/scroll-handler.tsx +0 -74
- package/src/client/app/theme-context.tsx +0 -103
- package/src/client/app/ui-context.tsx +0 -42
- package/src/client/components/docs-layout-default.tsx +0 -85
- package/src/client/components/icons-dev.tsx +0 -282
- package/src/client/components/mdx/callout.tsx +0 -97
- package/src/client/components/mdx/card.tsx +0 -99
- package/src/client/components/mdx/cards.tsx +0 -27
- package/src/client/components/mdx/code-block.tsx +0 -184
- package/src/client/components/mdx/field.tsx +0 -33
- package/src/client/components/mdx/image.tsx +0 -44
- package/src/client/components/mdx/index.ts +0 -19
- package/src/client/components/mdx/table.tsx +0 -54
- package/src/client/components/mdx/typographics.tsx +0 -120
- package/src/client/components/mdx/use-code-block.ts +0 -34
- package/src/client/components/primitives/breadcrumbs.tsx +0 -54
- package/src/client/components/primitives/button-group.tsx +0 -54
- package/src/client/components/primitives/button.tsx +0 -6
- package/src/client/components/primitives/code-block.tsx +0 -120
- package/src/client/components/primitives/docs-layout.tsx +0 -125
- package/src/client/components/primitives/error-boundary.tsx +0 -107
- package/src/client/components/primitives/heading.tsx +0 -128
- package/src/client/components/primitives/helpers/observer.ts +0 -141
- package/src/client/components/primitives/image.tsx +0 -26
- package/src/client/components/primitives/link.tsx +0 -102
- package/src/client/components/primitives/menu.tsx +0 -137
- package/src/client/components/primitives/navbar.tsx +0 -466
- package/src/client/components/primitives/on-this-page.tsx +0 -430
- package/src/client/components/primitives/page-nav.tsx +0 -51
- package/src/client/components/primitives/popover.tsx +0 -28
- package/src/client/components/primitives/search-dialog.tsx +0 -193
- package/src/client/components/primitives/sidebar.tsx +0 -423
- package/src/client/components/primitives/skeleton.tsx +0 -26
- package/src/client/components/primitives/tabs.tsx +0 -70
- package/src/client/components/primitives/tooltip.tsx +0 -81
- package/src/client/components/primitives/types.ts +0 -11
- package/src/client/components/ui-base/banner.tsx +0 -66
- package/src/client/components/ui-base/breadcrumbs.tsx +0 -44
- package/src/client/components/ui-base/copy-markdown.tsx +0 -107
- package/src/client/components/ui-base/error-boundary.tsx +0 -15
- package/src/client/components/ui-base/github-stars.tsx +0 -29
- package/src/client/components/ui-base/icons.tsx +0 -240
- package/src/client/components/ui-base/index.ts +0 -16
- package/src/client/components/ui-base/last-updated.tsx +0 -27
- package/src/client/components/ui-base/navbar.tsx +0 -266
- package/src/client/components/ui-base/not-found.tsx +0 -26
- package/src/client/components/ui-base/on-this-page.tsx +0 -57
- package/src/client/components/ui-base/page-nav.tsx +0 -50
- package/src/client/components/ui-base/search-dialog.tsx +0 -163
- package/src/client/components/ui-base/search-highlight.tsx +0 -10
- package/src/client/components/ui-base/sidebar.tsx +0 -92
- package/src/client/components/ui-base/tabs.tsx +0 -83
- package/src/client/components/ui-base/theme-toggle.tsx +0 -130
- package/src/client/components/ui-base/version-i18n.tsx +0 -80
- package/src/client/hooks/index.ts +0 -13
- package/src/client/hooks/use-analytics.ts +0 -272
- package/src/client/hooks/use-breadcrumbs.ts +0 -22
- package/src/client/hooks/use-i18n.ts +0 -182
- package/src/client/hooks/use-localized-to.ts +0 -113
- package/src/client/hooks/use-location.ts +0 -5
- package/src/client/hooks/use-navbar.ts +0 -130
- package/src/client/hooks/use-page-nav.ts +0 -46
- package/src/client/hooks/use-routes.ts +0 -108
- package/src/client/hooks/use-search-highlight.ts +0 -185
- package/src/client/hooks/use-search.ts +0 -118
- package/src/client/hooks/use-sidebar.ts +0 -205
- package/src/client/hooks/use-tabs.ts +0 -46
- package/src/client/hooks/use-version.ts +0 -111
- package/src/client/index.ts +0 -31
- package/src/client/mdx.ts +0 -2
- package/src/client/primitives.ts +0 -19
- package/src/client/ssg/boltdocs-shell.tsx +0 -148
- package/src/client/ssg/create-routes.tsx +0 -473
- package/src/client/ssg/index.ts +0 -4
- package/src/client/ssg/mdx-page.tsx +0 -38
- package/src/client/store/boltdocs-context.tsx +0 -137
- package/src/client/theme/neutral.css +0 -141
- package/src/client/theme/reset.css +0 -189
- package/src/client/types.ts +0 -116
- package/src/client/utils/cn.ts +0 -6
- package/src/client/utils/copy-clipboard.ts +0 -22
- package/src/client/utils/get-base-file-path.ts +0 -21
- package/src/client/utils/github.ts +0 -121
- package/src/client/utils/i18n.ts +0 -23
- package/src/client/utils/path.ts +0 -9
- package/src/client/utils/react-to-text.ts +0 -34
- package/src/client/virtual.d.ts +0 -24
- /package/dist/{worker-pool-Bd8Y9KDv.mjs → worker-pool-CGn7DrLb.mjs} +0 -0
package/src/client/primitives.ts
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
export * from './components/primitives/docs-layout'
|
|
2
|
-
export * from './components/primitives/button-group'
|
|
3
|
-
export * from './components/primitives/tabs'
|
|
4
|
-
export * from './components/primitives/sidebar'
|
|
5
|
-
export * from './components/primitives/on-this-page'
|
|
6
|
-
export * from './components/primitives/code-block'
|
|
7
|
-
export * from './components/primitives/button'
|
|
8
|
-
export * from './components/primitives/popover'
|
|
9
|
-
export * from './components/primitives/tooltip'
|
|
10
|
-
export * from './components/primitives/link'
|
|
11
|
-
export * from './components/primitives/error-boundary'
|
|
12
|
-
export * from './components/primitives/heading'
|
|
13
|
-
export * from './components/primitives/image'
|
|
14
|
-
export * from './components/primitives/menu'
|
|
15
|
-
export * from './components/primitives/page-nav'
|
|
16
|
-
export * from './components/primitives/search-dialog'
|
|
17
|
-
export * from './components/primitives/skeleton'
|
|
18
|
-
export * from './components/primitives/breadcrumbs'
|
|
19
|
-
export * from './components/primitives/navbar'
|
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
import { useEffect, useMemo } from 'react'
|
|
2
|
-
import { Outlet, useLocation } from 'react-router-dom'
|
|
3
|
-
import { BoltdocsProvider, useBoltdocsContext } from '../store/boltdocs-context'
|
|
4
|
-
import { ThemeProvider } from '../app/theme-context'
|
|
5
|
-
import { MdxComponentsProvider } from '../app/mdx-components-context'
|
|
6
|
-
import { HelmetProvider } from '../app/helmet-compat'
|
|
7
|
-
import { ConfigContext } from '../app/config-context'
|
|
8
|
-
import { ScrollHandler } from '../app/scroll-handler'
|
|
9
|
-
import { mdxComponentsDefault } from '../app/mdx-component'
|
|
10
|
-
import { RoutesProvider } from '../app/routes-context'
|
|
11
|
-
import type { BoltdocsConfig } from '../../shared/types'
|
|
12
|
-
import type { ComponentRoute } from '../types'
|
|
13
|
-
import { UIProvider } from '../app/ui-context'
|
|
14
|
-
|
|
15
|
-
import virtualCustomComponents from 'virtual:boltdocs-mdx-components'
|
|
16
|
-
|
|
17
|
-
/** Normalize a path: strip trailing slash unless it is exactly '/'. */
|
|
18
|
-
function normalizePath(p: string): string {
|
|
19
|
-
return p.endsWith('/') && p.length > 1 ? p.slice(0, -1) : p
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Updates the HTML lang and dir attributes based on the current locale configuration.
|
|
24
|
-
*/
|
|
25
|
-
function I18nUpdater({ config }: { config: BoltdocsConfig }) {
|
|
26
|
-
const { currentLocale } = useBoltdocsContext()
|
|
27
|
-
|
|
28
|
-
useEffect(() => {
|
|
29
|
-
if (!config.i18n || typeof document === 'undefined') return
|
|
30
|
-
const locale = currentLocale || config.i18n.defaultLocale
|
|
31
|
-
const localeConfig = config.i18n.localeConfigs?.[locale]
|
|
32
|
-
document.documentElement.lang = localeConfig?.htmlLang || locale || 'en'
|
|
33
|
-
document.documentElement.dir = localeConfig?.direction || 'ltr'
|
|
34
|
-
}, [currentLocale, config.i18n])
|
|
35
|
-
|
|
36
|
-
return null
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Synchronizes the Zustand store with the current URL pathname.
|
|
41
|
-
* Receives a pre-built Map for O(1) route lookups instead of O(n) .find().
|
|
42
|
-
*/
|
|
43
|
-
function StoreSync({
|
|
44
|
-
config,
|
|
45
|
-
routeMap,
|
|
46
|
-
}: {
|
|
47
|
-
config: BoltdocsConfig
|
|
48
|
-
routeMap: Map<string, ComponentRoute>
|
|
49
|
-
}) {
|
|
50
|
-
const location = useLocation()
|
|
51
|
-
const { setLocale, setVersion } = useBoltdocsContext()
|
|
52
|
-
|
|
53
|
-
useEffect(() => {
|
|
54
|
-
const currentPath = normalizePath(location.pathname)
|
|
55
|
-
const matchedRoute = routeMap.get(currentPath)
|
|
56
|
-
|
|
57
|
-
if (matchedRoute) {
|
|
58
|
-
if (config.i18n) {
|
|
59
|
-
const targetLocale = matchedRoute.locale || config.i18n.defaultLocale
|
|
60
|
-
setLocale(targetLocale)
|
|
61
|
-
}
|
|
62
|
-
if (config.versions) {
|
|
63
|
-
const targetVersion =
|
|
64
|
-
matchedRoute.version || config.versions.defaultVersion
|
|
65
|
-
setVersion(targetVersion)
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
}, [location.pathname, config, routeMap, setLocale, setVersion])
|
|
69
|
-
|
|
70
|
-
return null
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
export function BoltdocsShell({
|
|
74
|
-
config,
|
|
75
|
-
routes,
|
|
76
|
-
components = {},
|
|
77
|
-
}: {
|
|
78
|
-
config: BoltdocsConfig
|
|
79
|
-
routes: ComponentRoute[]
|
|
80
|
-
components?: Record<string, React.ComponentType>
|
|
81
|
-
}) {
|
|
82
|
-
const allComponents = useMemo(
|
|
83
|
-
() => ({
|
|
84
|
-
...mdxComponentsDefault,
|
|
85
|
-
...virtualCustomComponents,
|
|
86
|
-
...components,
|
|
87
|
-
}),
|
|
88
|
-
[components],
|
|
89
|
-
)
|
|
90
|
-
|
|
91
|
-
const { pathname } = useLocation()
|
|
92
|
-
|
|
93
|
-
const currentPath = useMemo(() => normalizePath(pathname || '/'), [pathname])
|
|
94
|
-
|
|
95
|
-
// Build a single O(1) lookup Map from the routes array.
|
|
96
|
-
// This replaces the 3 separate O(n) .find() calls that previously ran on every render.
|
|
97
|
-
const routeMap = useMemo(() => {
|
|
98
|
-
const map = new Map<string, ComponentRoute>()
|
|
99
|
-
for (const r of routes) {
|
|
100
|
-
const key = normalizePath(r.path === '' ? '/' : r.path)
|
|
101
|
-
map.set(key, r)
|
|
102
|
-
}
|
|
103
|
-
return map
|
|
104
|
-
}, [routes])
|
|
105
|
-
|
|
106
|
-
// Calculate frame-perfect initial values derived AUTHORITATIVELY from the static route match
|
|
107
|
-
const initialData = useMemo(() => {
|
|
108
|
-
const matched = routeMap.get(currentPath)
|
|
109
|
-
|
|
110
|
-
let initLocale = undefined
|
|
111
|
-
let initVersion = undefined
|
|
112
|
-
|
|
113
|
-
if (matched) {
|
|
114
|
-
if (config.i18n) {
|
|
115
|
-
initLocale = matched.locale || config.i18n.defaultLocale
|
|
116
|
-
}
|
|
117
|
-
if (config.versions) {
|
|
118
|
-
initVersion = matched.version || config.versions.defaultVersion
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
return { initLocale, initVersion }
|
|
123
|
-
}, [currentPath, config, routeMap])
|
|
124
|
-
|
|
125
|
-
return (
|
|
126
|
-
<HelmetProvider>
|
|
127
|
-
<RoutesProvider routes={routes}>
|
|
128
|
-
<ThemeProvider>
|
|
129
|
-
<UIProvider>
|
|
130
|
-
<MdxComponentsProvider components={allComponents}>
|
|
131
|
-
<ConfigContext.Provider value={config}>
|
|
132
|
-
<ScrollHandler />
|
|
133
|
-
<BoltdocsProvider
|
|
134
|
-
initialLocale={initialData.initLocale}
|
|
135
|
-
initialVersion={initialData.initVersion}
|
|
136
|
-
>
|
|
137
|
-
<StoreSync config={config} routeMap={routeMap} />
|
|
138
|
-
<I18nUpdater config={config} />
|
|
139
|
-
<Outlet />
|
|
140
|
-
</BoltdocsProvider>
|
|
141
|
-
</ConfigContext.Provider>
|
|
142
|
-
</MdxComponentsProvider>
|
|
143
|
-
</UIProvider>
|
|
144
|
-
</ThemeProvider>
|
|
145
|
-
</RoutesProvider>
|
|
146
|
-
</HelmetProvider>
|
|
147
|
-
)
|
|
148
|
-
}
|
|
@@ -1,473 +0,0 @@
|
|
|
1
|
-
import type { RouteRecord } from '@bdocs/ssg'
|
|
2
|
-
import type { ComponentRoute, BoltdocsConfig } from '../types'
|
|
3
|
-
import { MdxPage } from './mdx-page'
|
|
4
|
-
import { BoltdocsShell } from './boltdocs-shell'
|
|
5
|
-
import { NotFound } from '../components/ui-base'
|
|
6
|
-
const Loading = () => <div className="text-muted text-sm py-4">Loading...</div>
|
|
7
|
-
import type React from 'react'
|
|
8
|
-
import { useEffect } from 'react'
|
|
9
|
-
|
|
10
|
-
interface CreateRoutesOptions {
|
|
11
|
-
routesData: ComponentRoute[]
|
|
12
|
-
config: BoltdocsConfig
|
|
13
|
-
mdxModules: Record<string, any>
|
|
14
|
-
Layout: React.ComponentType<{ children: React.ReactNode }>
|
|
15
|
-
|
|
16
|
-
externalPages?: Record<string, React.ComponentType>
|
|
17
|
-
externalLayout?: React.ComponentType<{ children: React.ReactNode }>
|
|
18
|
-
components?: Record<string, React.ComponentType>
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Stable component to render MDX pages.
|
|
23
|
-
* By being outside createRoutes, it prevents React from unmounting the page on HMR.
|
|
24
|
-
*/
|
|
25
|
-
const MdxRouteElement = ({
|
|
26
|
-
moduleLoader,
|
|
27
|
-
moduleKey,
|
|
28
|
-
route,
|
|
29
|
-
components,
|
|
30
|
-
}: {
|
|
31
|
-
moduleLoader: any
|
|
32
|
-
moduleKey: string | undefined
|
|
33
|
-
route: ComponentRoute
|
|
34
|
-
components: any
|
|
35
|
-
}) => {
|
|
36
|
-
const MDXComponent = moduleLoader?.default ?? moduleLoader ?? null
|
|
37
|
-
|
|
38
|
-
useEffect(() => {
|
|
39
|
-
if (!import.meta.hot || !moduleKey) return
|
|
40
|
-
|
|
41
|
-
const handler = (data: { relPath: string }) => {
|
|
42
|
-
const incoming = data.relPath.replace(/\\/g, '/').replace(/^\//, '')
|
|
43
|
-
const routeFile = route.filePath.replace(/\\/g, '/').replace(/^\//, '')
|
|
44
|
-
|
|
45
|
-
if (incoming !== routeFile) return
|
|
46
|
-
|
|
47
|
-
const cacheBustUrl = moduleKey + '?t=' + Date.now()
|
|
48
|
-
import(/* @vite-ignore */ cacheBustUrl).then((m: any) => {
|
|
49
|
-
MDXComponent
|
|
50
|
-
})
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
import.meta.hot.on('boltdocs:mdx-update', handler)
|
|
54
|
-
return () => import.meta.hot?.off('boltdocs:mdx-update', handler)
|
|
55
|
-
}, [moduleKey, route.filePath])
|
|
56
|
-
|
|
57
|
-
if (!MDXComponent) return <Loading />
|
|
58
|
-
|
|
59
|
-
return <MdxPage MDXComponent={MDXComponent} mdxComponents={components} />
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
import { useMdxComponents } from '../app/mdx-components-context'
|
|
63
|
-
|
|
64
|
-
const NotFoundWrapper = () => {
|
|
65
|
-
const components = useMdxComponents()
|
|
66
|
-
const ActiveNotFound = components.NotFound || components['404'] || NotFound
|
|
67
|
-
return <ActiveNotFound />
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
import { DocsLayout } from '../app/docs-layout'
|
|
71
|
-
|
|
72
|
-
export function createRoutes(options: CreateRoutesOptions): RouteRecord[] {
|
|
73
|
-
const {
|
|
74
|
-
routesData,
|
|
75
|
-
config,
|
|
76
|
-
mdxModules,
|
|
77
|
-
externalPages,
|
|
78
|
-
externalLayout,
|
|
79
|
-
components,
|
|
80
|
-
} = options
|
|
81
|
-
|
|
82
|
-
const EffectiveExternalLayout =
|
|
83
|
-
externalLayout || (({ children }: any) => <>{children}</>)
|
|
84
|
-
|
|
85
|
-
const withBase = (path: string) => {
|
|
86
|
-
// Future support for base path in config
|
|
87
|
-
const base = config.base || '/'
|
|
88
|
-
if (path.startsWith(base)) return path
|
|
89
|
-
const b = base === '/' ? '' : base.replace(/\/$/, '')
|
|
90
|
-
const p = path.startsWith('/') ? path : `/${path}`
|
|
91
|
-
return `${b}${p}` || '/'
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
const defaultVersionMetadata: ComponentRoute[] = []
|
|
95
|
-
|
|
96
|
-
// Inject virtual explicit routes for default version to ensure paths like /docs/latest/... aren't 404s
|
|
97
|
-
const defaultVersion = config.versions?.defaultVersion
|
|
98
|
-
const docsBase = (config.base || '/docs').replace(/\/$/, '')
|
|
99
|
-
|
|
100
|
-
// Base path under which all doc routes are nested (e.g., "/docs")
|
|
101
|
-
// Used to compute relative child paths for correct React Router nesting
|
|
102
|
-
let baseDocsPath = (config.base || '/docs').replace(/\/$/, '')
|
|
103
|
-
if (!baseDocsPath) baseDocsPath = '/'
|
|
104
|
-
|
|
105
|
-
if (defaultVersion) {
|
|
106
|
-
routesData.forEach((route) => {
|
|
107
|
-
// If this route explicitly already belongs to a version, do not clone.
|
|
108
|
-
if (route.version) return
|
|
109
|
-
|
|
110
|
-
// Compute path without docs base prefix to properly place version token
|
|
111
|
-
const p = route.path || ''
|
|
112
|
-
const subPath = p.startsWith(docsBase)
|
|
113
|
-
? p.substring(docsBase.length).replace(/^\//, '')
|
|
114
|
-
: p.replace(/^\//, '')
|
|
115
|
-
|
|
116
|
-
// Detect if it already includes the target version segment
|
|
117
|
-
const hasVersionPrefix =
|
|
118
|
-
subPath === defaultVersion || subPath.startsWith(`${defaultVersion}/`)
|
|
119
|
-
|
|
120
|
-
if (!hasVersionPrefix) {
|
|
121
|
-
// Standardize reconstruction: [docsBase] / [version] / [remaining_path]
|
|
122
|
-
const explicitPath =
|
|
123
|
-
`${docsBase}/${defaultVersion}/${subPath}`
|
|
124
|
-
.replace(/\/+/g, '/')
|
|
125
|
-
.replace(/\/$/, '') || '/'
|
|
126
|
-
|
|
127
|
-
defaultVersionMetadata.push({
|
|
128
|
-
...route,
|
|
129
|
-
path: explicitPath,
|
|
130
|
-
version: defaultVersion,
|
|
131
|
-
})
|
|
132
|
-
}
|
|
133
|
-
})
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
const docMetadata = [...routesData, ...defaultVersionMetadata]
|
|
137
|
-
|
|
138
|
-
// 0. Build a single pre-computed lookup map for the MDX modules (O(N) build, O(1) access).
|
|
139
|
-
// This replaces the inner findModuleKey loops that executed an O(N) scan for EVERY route.
|
|
140
|
-
const moduleMap = new Map<string, string>()
|
|
141
|
-
const mdxModuleKeys = Object.keys(mdxModules)
|
|
142
|
-
|
|
143
|
-
if (mdxModuleKeys.length > 0) {
|
|
144
|
-
// Detect docs directory structure from keys (e.g., "/docs/intro.md")
|
|
145
|
-
const firstKeyNormalized = mdxModuleKeys[0].replace(/\\/g, '/')
|
|
146
|
-
const parts = firstKeyNormalized.split('/').filter(Boolean)
|
|
147
|
-
const docsDirName = parts[0] || 'docs'
|
|
148
|
-
const primaryPrefix = `/${docsDirName}/`
|
|
149
|
-
const altPrefix = `./${docsDirName}/`
|
|
150
|
-
|
|
151
|
-
for (const rawKey of mdxModuleKeys) {
|
|
152
|
-
const k = rawKey.replace(/\\/g, '/')
|
|
153
|
-
let relativePath = ''
|
|
154
|
-
if (k.indexOf(primaryPrefix) !== -1) {
|
|
155
|
-
relativePath = k.substring(
|
|
156
|
-
k.indexOf(primaryPrefix) + primaryPrefix.length,
|
|
157
|
-
)
|
|
158
|
-
} else if (k.startsWith(altPrefix)) {
|
|
159
|
-
relativePath = k.substring(altPrefix.length)
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
if (relativePath) {
|
|
163
|
-
moduleMap.set(relativePath, rawKey)
|
|
164
|
-
} else {
|
|
165
|
-
// Fallback: store full normalized key as a catch-all
|
|
166
|
-
moduleMap.set(k, rawKey)
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
// 1. Documentation routes
|
|
172
|
-
const docRoutes: RouteRecord[] = docMetadata.map((route) => {
|
|
173
|
-
// Perform constant-time lookup using the pre-computed map
|
|
174
|
-
const normalizedFilePath = route.filePath.replace(/\\/g, '/')
|
|
175
|
-
const moduleKey = moduleMap.get(normalizedFilePath)
|
|
176
|
-
const moduleLoader = moduleKey ? mdxModules[moduleKey] : null
|
|
177
|
-
const fullPath = withBase(route.path === '' ? '/' : route.path)
|
|
178
|
-
const path =
|
|
179
|
-
fullPath === baseDocsPath
|
|
180
|
-
? '.'
|
|
181
|
-
: fullPath.startsWith(baseDocsPath + '/')
|
|
182
|
-
? fullPath.slice(baseDocsPath.length + 1)
|
|
183
|
-
: fullPath
|
|
184
|
-
|
|
185
|
-
return {
|
|
186
|
-
path,
|
|
187
|
-
element: (
|
|
188
|
-
<MdxRouteElement
|
|
189
|
-
key={moduleKey || path}
|
|
190
|
-
moduleKey={moduleKey}
|
|
191
|
-
moduleLoader={moduleLoader}
|
|
192
|
-
route={route}
|
|
193
|
-
components={components}
|
|
194
|
-
/>
|
|
195
|
-
),
|
|
196
|
-
loader: async () => ({
|
|
197
|
-
path,
|
|
198
|
-
frontmatter: {
|
|
199
|
-
title: route.title,
|
|
200
|
-
description: route.description || '',
|
|
201
|
-
...(route.frontmatter || {}),
|
|
202
|
-
},
|
|
203
|
-
headings: route.headings || [],
|
|
204
|
-
filePath: route.filePath,
|
|
205
|
-
locale: route.locale,
|
|
206
|
-
version: route.version,
|
|
207
|
-
group: route.group,
|
|
208
|
-
groupTitle: route.groupTitle,
|
|
209
|
-
date: route.date,
|
|
210
|
-
lastUpdated: route.lastUpdated,
|
|
211
|
-
}),
|
|
212
|
-
getStaticPaths: () => [path],
|
|
213
|
-
}
|
|
214
|
-
})
|
|
215
|
-
|
|
216
|
-
// 2. Auto-fallback for the base paths (e.g. /docs, /docs/es) to the first documentation page
|
|
217
|
-
|
|
218
|
-
const locales = config.i18n?.locales
|
|
219
|
-
? Array.isArray(config.i18n.locales)
|
|
220
|
-
? config.i18n.locales
|
|
221
|
-
: Object.keys(config.i18n.locales)
|
|
222
|
-
: []
|
|
223
|
-
|
|
224
|
-
// 2a. Generate dynamic permutation matrix of version/locale combinations
|
|
225
|
-
const allVersions = config.versions?.versions?.map((v) => v.path) || []
|
|
226
|
-
|
|
227
|
-
const targetBasePaths: Array<{
|
|
228
|
-
path: string
|
|
229
|
-
filter: (p: string) => boolean
|
|
230
|
-
}> = []
|
|
231
|
-
|
|
232
|
-
// Insert base root always
|
|
233
|
-
targetBasePaths.push({
|
|
234
|
-
path: baseDocsPath,
|
|
235
|
-
filter: () => true, // Take first available doc generally
|
|
236
|
-
})
|
|
237
|
-
|
|
238
|
-
// Permutation builder: version loop nested with locale loop
|
|
239
|
-
// Ensures paths like /docs/v2.0, /docs/es, and /docs/v2.0/es ALL receive fallback logic.
|
|
240
|
-
const subPaths: string[] = []
|
|
241
|
-
if (allVersions.length > 0) {
|
|
242
|
-
allVersions.forEach((v) => subPaths.push(`/${v}`))
|
|
243
|
-
}
|
|
244
|
-
if (locales.length > 0) {
|
|
245
|
-
locales.forEach((l) => subPaths.push(`/${l}`))
|
|
246
|
-
}
|
|
247
|
-
if (allVersions.length > 0 && locales.length > 0) {
|
|
248
|
-
allVersions.forEach((v) => {
|
|
249
|
-
locales.forEach((l) => {
|
|
250
|
-
subPaths.push(`/${v}/${l}`)
|
|
251
|
-
})
|
|
252
|
-
})
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
// Map permutations onto the physical base docs route
|
|
256
|
-
subPaths.forEach((sp) => {
|
|
257
|
-
const fullP = baseDocsPath === '/' ? sp : `${baseDocsPath}${sp}`
|
|
258
|
-
targetBasePaths.push({
|
|
259
|
-
path: fullP,
|
|
260
|
-
filter: (rp) => rp.startsWith(fullP.replace(/\/$/, '') + '/'),
|
|
261
|
-
})
|
|
262
|
-
})
|
|
263
|
-
|
|
264
|
-
// Pre-compute a Set of absolute and normalized path strings from the real routes
|
|
265
|
-
// to perform O(1) validation checks within the redirection loops below.
|
|
266
|
-
const docPathRegistry = new Set(
|
|
267
|
-
docRoutes.map((r) => (r.path || '').replace(/\/$/, '')),
|
|
268
|
-
)
|
|
269
|
-
|
|
270
|
-
// Pre-compute external pages paths so we do not hijack them with redirects
|
|
271
|
-
const externalPaths = new Set<string>()
|
|
272
|
-
if (externalPages) {
|
|
273
|
-
Object.keys(externalPages).forEach((rawPath) => {
|
|
274
|
-
const p = rawPath.startsWith('/') ? rawPath : `/${rawPath}`
|
|
275
|
-
externalPaths.add(p.replace(/\/$/, ''))
|
|
276
|
-
if (config.i18n) {
|
|
277
|
-
Object.keys(config.i18n.locales).forEach((locale) => {
|
|
278
|
-
externalPaths.add(
|
|
279
|
-
`/${locale}${p === '/' ? '' : p}`.replace(/\/$/, ''),
|
|
280
|
-
)
|
|
281
|
-
})
|
|
282
|
-
}
|
|
283
|
-
})
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
// 2b. Deploy smart redirects
|
|
287
|
-
targetBasePaths.forEach(({ path: bPath, filter }) => {
|
|
288
|
-
if (bPath === '/') return // Never hijack global app root
|
|
289
|
-
|
|
290
|
-
const normalizedPath = bPath.replace(/\/$/, '')
|
|
291
|
-
const hasExplicitMatch =
|
|
292
|
-
docPathRegistry.has(normalizedPath) || externalPaths.has(normalizedPath)
|
|
293
|
-
|
|
294
|
-
if (!hasExplicitMatch) {
|
|
295
|
-
const defaultTab = config.theme?.tabs?.[0]?.id
|
|
296
|
-
const defaultTabPath = defaultTab
|
|
297
|
-
? `${normalizedPath}/${defaultTab}`.replace(/\/+/g, '/')
|
|
298
|
-
: null
|
|
299
|
-
|
|
300
|
-
// Prioritize: Find a real route that matches the default tab first, then fall back to the first route beginning with this pattern.
|
|
301
|
-
let matchedRouteObj: RouteRecord | undefined =
|
|
302
|
-
defaultTabPath && docPathRegistry.has(defaultTabPath.replace(/\/$/, ''))
|
|
303
|
-
? docRoutes.find(
|
|
304
|
-
(r) =>
|
|
305
|
-
r.path.replace(/\/$/, '') === defaultTabPath.replace(/\/$/, ''),
|
|
306
|
-
)
|
|
307
|
-
: docRoutes.find((r) => filter(r.path) && r.path !== normalizedPath)
|
|
308
|
-
|
|
309
|
-
// Ultimate fallback: the absolute first document
|
|
310
|
-
if (!matchedRouteObj && docRoutes.length > 0) {
|
|
311
|
-
matchedRouteObj = docRoutes[0]
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
if (matchedRouteObj) {
|
|
315
|
-
const redirectPath =
|
|
316
|
-
bPath === baseDocsPath
|
|
317
|
-
? '.'
|
|
318
|
-
: bPath.startsWith(baseDocsPath + '/')
|
|
319
|
-
? bPath.slice(baseDocsPath.length + 1)
|
|
320
|
-
: bPath
|
|
321
|
-
|
|
322
|
-
// Use `index: true` for the docs base path (e.g. /docs) instead of
|
|
323
|
-
// `path: '.'`. The dot-path is a client-only React Router feature: it
|
|
324
|
-
// means "same URL as parent" in createBrowserRouter, but createStaticHandler
|
|
325
|
-
// does not recognise it during SSG. This caused the static handler to skip
|
|
326
|
-
// the fallback loader entirely → loaderData was empty for /docs → the SSR
|
|
327
|
-
// rendered an empty content slot while the client hydrated with the first
|
|
328
|
-
// doc's element → structural mismatch → visual page duplication on refresh.
|
|
329
|
-
// Index routes are correctly matched by both browser and static handler.
|
|
330
|
-
const isBasePathFallback = redirectPath === '.'
|
|
331
|
-
docRoutes.push({
|
|
332
|
-
...(isBasePathFallback
|
|
333
|
-
? { index: true as const }
|
|
334
|
-
: { path: redirectPath }),
|
|
335
|
-
element: matchedRouteObj.element,
|
|
336
|
-
loader: matchedRouteObj.loader,
|
|
337
|
-
getStaticPaths: () => [],
|
|
338
|
-
})
|
|
339
|
-
|
|
340
|
-
const matchedMetaObj = docMetadata.find((m) => {
|
|
341
|
-
const fullPath = withBase(m.path === '' ? '/' : m.path)
|
|
342
|
-
const p =
|
|
343
|
-
fullPath === baseDocsPath
|
|
344
|
-
? '.'
|
|
345
|
-
: fullPath.startsWith(baseDocsPath + '/')
|
|
346
|
-
? fullPath.slice(baseDocsPath.length + 1)
|
|
347
|
-
: fullPath
|
|
348
|
-
return p === matchedRouteObj.path
|
|
349
|
-
})
|
|
350
|
-
|
|
351
|
-
if (matchedMetaObj) {
|
|
352
|
-
const canonicalPath = withBase(matchedMetaObj.path)
|
|
353
|
-
const canonicalUrl = config.siteUrl
|
|
354
|
-
? `${config.siteUrl.replace(/\/$/, '')}${canonicalPath}`
|
|
355
|
-
: canonicalPath
|
|
356
|
-
|
|
357
|
-
docMetadata.push({
|
|
358
|
-
...matchedMetaObj,
|
|
359
|
-
path: bPath,
|
|
360
|
-
filePath: '',
|
|
361
|
-
slugParts: [],
|
|
362
|
-
seo: {
|
|
363
|
-
...matchedMetaObj.seo,
|
|
364
|
-
canonical: canonicalUrl,
|
|
365
|
-
},
|
|
366
|
-
})
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
})
|
|
371
|
-
|
|
372
|
-
// Group all documentation routes under the persistent DocsLayout
|
|
373
|
-
const docsLayoutRoute: RouteRecord = {
|
|
374
|
-
path: baseDocsPath,
|
|
375
|
-
element: <DocsLayout />,
|
|
376
|
-
children: docRoutes,
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
const children: RouteRecord[] = [docsLayoutRoute]
|
|
380
|
-
|
|
381
|
-
// 3. External pages
|
|
382
|
-
const externalMetadata: ComponentRoute[] = []
|
|
383
|
-
if (externalPages) {
|
|
384
|
-
Object.entries(externalPages).forEach(([rawPath, ExtComponent]) => {
|
|
385
|
-
// Use the raw path directly (do not prefix with base docs path)
|
|
386
|
-
const path = rawPath.startsWith('/') ? rawPath : `/${rawPath}`
|
|
387
|
-
if (!children.find((r) => r.path === path)) {
|
|
388
|
-
externalMetadata.push({
|
|
389
|
-
path,
|
|
390
|
-
locale: config.i18n?.defaultLocale,
|
|
391
|
-
title:
|
|
392
|
-
rawPath === '/'
|
|
393
|
-
? 'Home'
|
|
394
|
-
: rawPath.replace(/^\//, '').split('/').pop() || 'Page',
|
|
395
|
-
filePath: '',
|
|
396
|
-
headings: [],
|
|
397
|
-
} as any)
|
|
398
|
-
|
|
399
|
-
children.push({
|
|
400
|
-
path,
|
|
401
|
-
element: (
|
|
402
|
-
<EffectiveExternalLayout>
|
|
403
|
-
<ExtComponent />
|
|
404
|
-
</EffectiveExternalLayout>
|
|
405
|
-
),
|
|
406
|
-
loader: async () => ({
|
|
407
|
-
path,
|
|
408
|
-
locale: config.i18n?.defaultLocale,
|
|
409
|
-
}),
|
|
410
|
-
getStaticPaths: () => [path],
|
|
411
|
-
})
|
|
412
|
-
|
|
413
|
-
// Also add i18n variants for external pages if needed (do not prefix with base docs path)
|
|
414
|
-
if (config.i18n) {
|
|
415
|
-
Object.keys(config.i18n.locales).forEach((locale) => {
|
|
416
|
-
const localePath = `/${locale}${rawPath === '/' ? '' : rawPath}`
|
|
417
|
-
if (!children.find((r) => r.path === localePath)) {
|
|
418
|
-
externalMetadata.push({
|
|
419
|
-
path: localePath,
|
|
420
|
-
locale,
|
|
421
|
-
title: rawPath,
|
|
422
|
-
filePath: '',
|
|
423
|
-
headings: [],
|
|
424
|
-
} as any)
|
|
425
|
-
|
|
426
|
-
children.push({
|
|
427
|
-
path: localePath,
|
|
428
|
-
element: (
|
|
429
|
-
<EffectiveExternalLayout>
|
|
430
|
-
<ExtComponent />
|
|
431
|
-
</EffectiveExternalLayout>
|
|
432
|
-
),
|
|
433
|
-
loader: async () => ({
|
|
434
|
-
path: localePath,
|
|
435
|
-
locale,
|
|
436
|
-
}),
|
|
437
|
-
getStaticPaths: () => [localePath],
|
|
438
|
-
})
|
|
439
|
-
}
|
|
440
|
-
})
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
})
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
// --- 4. 404 catch-all ---
|
|
447
|
-
children.push({
|
|
448
|
-
path: '*',
|
|
449
|
-
element: (
|
|
450
|
-
<EffectiveExternalLayout>
|
|
451
|
-
<NotFoundWrapper />
|
|
452
|
-
</EffectiveExternalLayout>
|
|
453
|
-
),
|
|
454
|
-
})
|
|
455
|
-
|
|
456
|
-
const allMetadata = [...docMetadata, ...externalMetadata]
|
|
457
|
-
|
|
458
|
-
// Wrap everything in the Boltdocs shell (providers)
|
|
459
|
-
return [
|
|
460
|
-
{
|
|
461
|
-
// No path = Layout Route
|
|
462
|
-
// This allows children to retain their absolute paths while being wrapped in the shell.
|
|
463
|
-
element: (
|
|
464
|
-
<BoltdocsShell
|
|
465
|
-
config={config}
|
|
466
|
-
routes={allMetadata}
|
|
467
|
-
components={components}
|
|
468
|
-
/>
|
|
469
|
-
),
|
|
470
|
-
children,
|
|
471
|
-
},
|
|
472
|
-
]
|
|
473
|
-
}
|
package/src/client/ssg/index.ts
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { useLoaderData } from 'react-router-dom'
|
|
2
|
-
import { DocPage } from '../app/doc-page'
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Renders an MDX page by consuming pre-loaded module data.
|
|
6
|
-
* Uses DocPage to ensure consistent layout and metadata application.
|
|
7
|
-
*/
|
|
8
|
-
export function MdxPage({
|
|
9
|
-
MDXComponent: propMDX,
|
|
10
|
-
mdxComponents: propComponents,
|
|
11
|
-
}: any) {
|
|
12
|
-
const data = useLoaderData() as any
|
|
13
|
-
const MDXComponent = propMDX || data?.MDXComponent
|
|
14
|
-
const components = propComponents || data?.mdxComponents
|
|
15
|
-
if (!MDXComponent) return null
|
|
16
|
-
|
|
17
|
-
return (
|
|
18
|
-
<DocPage
|
|
19
|
-
route={
|
|
20
|
-
{
|
|
21
|
-
path: data.path,
|
|
22
|
-
filePath: data.filePath,
|
|
23
|
-
title: data.frontmatter.title,
|
|
24
|
-
description: data.frontmatter.description,
|
|
25
|
-
headings: data.headings,
|
|
26
|
-
locale: data.locale,
|
|
27
|
-
version: data.version,
|
|
28
|
-
group: data.group,
|
|
29
|
-
groupTitle: data.groupTitle,
|
|
30
|
-
lastUpdated: data.lastUpdated,
|
|
31
|
-
frontmatter: data.frontmatter,
|
|
32
|
-
} as any
|
|
33
|
-
}
|
|
34
|
-
content={MDXComponent}
|
|
35
|
-
mdxComponents={components}
|
|
36
|
-
/>
|
|
37
|
-
)
|
|
38
|
-
}
|