@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.
@@ -1,4 +1,4 @@
1
- import { books } from 'virtual:docsector-books'
1
+ import { pageEntries, versions } from 'virtual:docsector-books'
2
2
  import boot from 'pages/boot'
3
3
 
4
4
  const normalizeInternalLink = (linkTo) => {
@@ -31,114 +31,146 @@ const resolveInternalLinkBasePath = (linkTo) => {
31
31
  return normalizeRoutePath(withoutSubpage || '/')
32
32
  }
33
33
 
34
- const routeConfigByPath = new Map()
35
- for (const [bookId, book] of Object.entries(books || {})) {
36
- const bookRoutes = book?.routes || {}
34
+ const versionPrefixes = (versions || [])
35
+ .map(version => normalizeRoutePath(version?.routePrefix || ''))
36
+ .filter(prefix => prefix !== '/')
37
37
 
38
- for (const [path, page] of Object.entries(bookRoutes)) {
39
- const config = page?.config
40
- if (config === null) {
41
- continue
42
- }
38
+ const linkHasVersionPrefix = (linkTo) => {
39
+ const normalized = normalizeRoutePath(linkTo)
40
+ return versionPrefixes.some(prefix => normalized === prefix || normalized.startsWith(`${prefix}/`))
41
+ }
43
42
 
44
- const topPage = config?.book ?? config?.type ?? bookId ?? 'manual'
45
- const routePath = normalizeRoutePath('/' + topPage + path)
43
+ const normalizeVersionedInternalLink = (linkTo, versionPrefix = '') => {
44
+ const normalized = normalizeInternalLink(linkTo)
45
+ const prefix = normalizeRoutePath(versionPrefix)
46
46
 
47
- routeConfigByPath.set(routePath, config || {})
47
+ if (prefix === '/' || linkHasVersionPrefix(normalized)) {
48
+ return normalized
48
49
  }
50
+
51
+ return normalizeRoutePath(`${prefix}${normalized}`)
52
+ }
53
+
54
+ const buildSourcePathBase = (entry, book, path) => {
55
+ return [entry?.sourceRoot, `${book}${path}`]
56
+ .filter(Boolean)
57
+ .map(segment => String(segment).replace(/^\/+|\/+$/g, ''))
58
+ .join('/')
59
+ }
60
+
61
+ const routeConfigByPath = new Map()
62
+ for (const entry of pageEntries || []) {
63
+ const config = entry?.page?.config
64
+ if (config === null) {
65
+ continue
66
+ }
67
+
68
+ const topPage = config?.book ?? config?.type ?? entry?.book ?? 'manual'
69
+ const routePath = normalizeRoutePath(`${entry?.versionPrefix || ''}/${topPage}${entry?.pagePath || ''}`)
70
+
71
+ routeConfigByPath.set(routePath, config || {})
49
72
  }
50
73
 
51
74
  const pagesRoutes = []
52
- for (const [bookId, book] of Object.entries(books || {})) {
53
- const bookRoutes = book?.routes || {}
54
-
55
- for (const [path, page] of Object.entries(bookRoutes)) {
56
- const rawConfig = page.config
57
- if (rawConfig === null) {
58
- continue
59
- }
60
-
61
- const config = rawConfig || {}
62
- const menu = (typeof config.menu === 'object' && config.menu !== null) ? config.menu : {}
63
- const subpages = {
64
- showcase: config?.subpages?.showcase === true,
65
- vs: config?.subpages?.vs === true
66
- }
67
-
68
- const topPage = config.book ?? config.type ?? bookId ?? 'manual'
69
- const hasInternalLink = typeof config?.link?.to === 'string' && config.link.to.trim().length > 0
70
- const internalLinkTo = hasInternalLink ? normalizeInternalLink(config.link.to) : null
71
- const linkedConfig = hasInternalLink
72
- ? routeConfigByPath.get(resolveInternalLinkBasePath(config.link.to))
73
- : null
74
- const icon = config.icon ?? linkedConfig?.icon
75
- const status = typeof config.status === 'string'
76
- ? config.status
77
- : (typeof linkedConfig?.status === 'string' ? linkedConfig.status : 'done')
78
-
79
- // @ Construct children
80
- const children = hasInternalLink
81
- ? [
82
- {
83
- path: '',
84
- redirect: () => internalLinkTo
85
- },
86
- {
87
- path: 'overview',
88
- redirect: () => internalLinkTo
89
- }
90
- ]
91
- : [
92
- {
93
- path: '',
94
- redirect: (to) => `${to.path.replace(/\/$/, '')}/overview/`
95
- },
96
- {
97
- path: 'overview',
98
- component: () => import('components/DSubpage.vue'),
99
- meta: {
100
- status
101
- }
102
- }
103
- ]
75
+ for (const entry of pageEntries || []) {
76
+ const path = entry?.pagePath || ''
77
+ const page = entry?.page || {}
78
+ const rawConfig = page.config
79
+ if (rawConfig === null) {
80
+ continue
81
+ }
104
82
 
105
- if (!hasInternalLink && subpages.showcase === true) {
106
- children.push({
107
- path: 'showcase',
108
- component: () => import('components/DSubpage.vue'),
109
- meta: {
110
- status
83
+ const config = rawConfig || {}
84
+ const menu = (typeof config.menu === 'object' && config.menu !== null) ? config.menu : {}
85
+ const subpages = {
86
+ showcase: config?.subpages?.showcase === true,
87
+ vs: config?.subpages?.vs === true
88
+ }
89
+
90
+ const topPage = config.book ?? config.type ?? entry?.book ?? 'manual'
91
+ const routePath = normalizeRoutePath(`${entry?.versionPrefix || ''}/${topPage}${path}`)
92
+ const hasInternalLink = typeof config?.link?.to === 'string' && config.link.to.trim().length > 0
93
+ const internalLinkTo = hasInternalLink ? normalizeVersionedInternalLink(config.link.to, entry?.versionPrefix || '') : null
94
+ const linkedConfig = hasInternalLink
95
+ ? routeConfigByPath.get(resolveInternalLinkBasePath(internalLinkTo))
96
+ : null
97
+ const icon = config.icon ?? linkedConfig?.icon
98
+ const status = typeof config.status === 'string'
99
+ ? config.status
100
+ : (typeof linkedConfig?.status === 'string' ? linkedConfig.status : 'done')
101
+
102
+ // @ Construct children
103
+ const children = hasInternalLink
104
+ ? [
105
+ {
106
+ path: '',
107
+ redirect: () => internalLinkTo
108
+ },
109
+ {
110
+ path: 'overview',
111
+ redirect: () => internalLinkTo
111
112
  }
112
- })
113
- }
114
- if (!hasInternalLink && subpages.vs === true) {
115
- children.push({
116
- path: 'vs',
117
- component: () => import('components/DSubpage.vue'),
118
- meta: {
119
- status
113
+ ]
114
+ : [
115
+ {
116
+ path: '',
117
+ redirect: (to) => `${to.path.replace(/\/$/, '')}/overview/`
118
+ },
119
+ {
120
+ path: 'overview',
121
+ component: () => import('components/DSubpage.vue'),
122
+ meta: {
123
+ status
124
+ }
120
125
  }
121
- })
122
- }
126
+ ]
123
127
 
124
- // @ Push route to pageRoutes
125
- pagesRoutes.push({
126
- path: '/' + topPage + path,
127
- component: () => import('layouts/DefaultLayout.vue'),
128
+ if (!hasInternalLink && subpages.showcase === true) {
129
+ children.push({
130
+ path: 'showcase',
131
+ component: () => import('components/DSubpage.vue'),
128
132
  meta: {
129
- ...config,
130
- icon,
131
- status,
132
- menu,
133
- subpages,
134
- data: page.data,
135
- book: topPage,
136
- // legacy compatibility
137
- type: topPage
138
- },
139
- children
133
+ status
134
+ }
140
135
  })
141
136
  }
137
+ if (!hasInternalLink && subpages.vs === true) {
138
+ children.push({
139
+ path: 'vs',
140
+ component: () => import('components/DSubpage.vue'),
141
+ meta: {
142
+ status
143
+ }
144
+ })
145
+ }
146
+
147
+ // @ Push route to pageRoutes
148
+ pagesRoutes.push({
149
+ path: routePath,
150
+ component: () => import('layouts/DefaultLayout.vue'),
151
+ meta: {
152
+ ...config,
153
+ icon,
154
+ status,
155
+ menu,
156
+ subpages,
157
+ data: page.data,
158
+ book: topPage,
159
+ // legacy compatibility
160
+ type: topPage,
161
+ version: entry.version,
162
+ versionLabel: entry.versionLabel,
163
+ versionCurrent: entry.versionCurrent,
164
+ versionPrefix: entry.versionPrefix || '',
165
+ sourceRoot: entry.sourceRoot || '',
166
+ sourcePathBase: buildSourcePathBase(entry, topPage, path),
167
+ pagePath: path,
168
+ i18nSegments: entry.i18nSegments || [topPage, ...String(path).replace(/^\//, '').split('/').filter(Boolean)],
169
+ menuGroupPath: String(path).replace(/^\//, '').split('/').filter(Boolean)[0] || '',
170
+ unversionedPath: entry.unversionedPath || `/${topPage}${path}`
171
+ },
172
+ children
173
+ })
142
174
  }
143
175
 
144
176
  const routes = [
package/src/store/App.js CHANGED
@@ -5,7 +5,7 @@ export default {
5
5
  getters: {},
6
6
  mutations: {},
7
7
  actions: {
8
- configureLanguage ({ commit, state }, routeMatched) {
8
+ configureLanguage ({ commit }, routeMatched) {
9
9
  // Reset stale nodes before configuring new language state
10
10
  commit('page/resetAnchor', null, { root: true })
11
11
  commit('page/resetAnchors', null, { root: true })
@@ -14,6 +14,7 @@ export default {
14
14
  // Route
15
15
  const firstRoutePath = routeMatched[0]?.path || ''
16
16
  const secondRoutePath = routeMatched[1]?.path || ''
17
+ const routeMeta = routeMatched[0]?.meta || {}
17
18
 
18
19
  const base = firstRoutePath === '/' ? 'home' : firstRoutePath.substr(1)
19
20
  let relative = secondRoutePath.substr(firstRoutePath.length)
@@ -31,12 +32,21 @@ export default {
31
32
  commit('page/setAbsolute', base + relative, { root: true })
32
33
 
33
34
  if (firstRoutePath) {
34
- const i18nBase = base.replace(/_$/, '').replace(/\//g, '.')
35
- const i18nRelative = relative.replace(/_$/, '').replace(/\//g, '.')
35
+ const fallbackBaseSegments = base
36
+ .replace(/_$/, '')
37
+ .split('/')
38
+ .filter(Boolean)
39
+ const i18nBase = Array.isArray(routeMeta.i18nSegments) && routeMeta.i18nSegments.length > 0
40
+ ? routeMeta.i18nSegments
41
+ : fallbackBaseSegments
42
+ const i18nRelative = relative
43
+ .replace(/_$/, '')
44
+ .split('/')
45
+ .filter(Boolean)
36
46
 
37
47
  commit('i18n/setBase', i18nBase, { root: true })
38
- commit('i18n/setRelative', i18nRelative.substr(1), { root: true })
39
- commit('i18n/setAbsolute', i18nBase + i18nRelative, { root: true })
48
+ commit('i18n/setRelative', i18nRelative, { root: true })
49
+ commit('i18n/setAbsolute', [...i18nBase, ...i18nRelative], { root: true })
40
50
  } else {
41
51
  commit('i18n/setBase', '', { root: true })
42
52
  commit('i18n/setRelative', '', { root: true })