@docusaurus/plugin-content-docs 3.8.1 → 3.9.0-canary-6403
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/lib/cli.js +1 -1
- package/lib/docs.js +2 -1
- package/lib/index.js +6 -6
- package/lib/props.d.ts +1 -1
- package/lib/props.js +6 -4
- package/lib/sidebars/generator.js +1 -0
- package/lib/sidebars/postProcessor.js +4 -1
- package/lib/sidebars/types.d.ts +5 -2
- package/lib/sidebars/validation.js +2 -0
- package/lib/translations.js +56 -23
- package/lib/versions/files.js +8 -5
- package/lib/versions/loadVersion.d.ts +4 -2
- package/lib/versions/loadVersion.js +98 -61
- package/lib/versions/version.js +26 -16
- package/package.json +12 -12
- package/src/cli.ts +2 -2
- package/src/docs.ts +3 -1
- package/src/index.ts +7 -8
- package/src/props.ts +9 -14
- package/src/sidebars/generator.ts +1 -0
- package/src/sidebars/postProcessor.ts +4 -1
- package/src/sidebars/types.ts +5 -2
- package/src/sidebars/validation.ts +2 -0
- package/src/translations.ts +63 -22
- package/src/versions/files.ts +15 -6
- package/src/versions/loadVersion.ts +135 -80
- package/src/versions/version.ts +37 -23
package/src/index.ts
CHANGED
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
|
|
8
8
|
import path from 'path';
|
|
9
9
|
import fs from 'fs-extra';
|
|
10
|
-
import logger from '@docusaurus/logger';
|
|
11
10
|
import {
|
|
12
11
|
normalizeUrl,
|
|
13
12
|
docuHash,
|
|
@@ -63,6 +62,12 @@ async function createMdxLoaderDependencyFile({
|
|
|
63
62
|
options: PluginOptions;
|
|
64
63
|
versionsMetadata: VersionMetadata[];
|
|
65
64
|
}): Promise<string | undefined> {
|
|
65
|
+
// Disabled for unit tests, the side effect produces infinite watch loops
|
|
66
|
+
// TODO find a better way :/
|
|
67
|
+
if (process.env.NODE_ENV === 'test') {
|
|
68
|
+
return undefined;
|
|
69
|
+
}
|
|
70
|
+
|
|
66
71
|
const filePath = path.join(dataDir, '__mdx-loader-dependency.json');
|
|
67
72
|
// the cache is invalidated whenever this file content changes
|
|
68
73
|
const fileContent = {
|
|
@@ -158,18 +163,12 @@ export default async function pluginContentDocs(
|
|
|
158
163
|
sourceFilePath,
|
|
159
164
|
versionsMetadata,
|
|
160
165
|
);
|
|
161
|
-
|
|
166
|
+
return resolveMarkdownLinkPathname(linkPathname, {
|
|
162
167
|
sourceFilePath,
|
|
163
168
|
sourceToPermalink: contentHelpers.sourceToPermalink,
|
|
164
169
|
siteDir,
|
|
165
170
|
contentPaths: version,
|
|
166
171
|
});
|
|
167
|
-
if (permalink === null) {
|
|
168
|
-
logger.report(
|
|
169
|
-
siteConfig.onBrokenMarkdownLinks,
|
|
170
|
-
)`Docs markdown link couldn't be resolved: (url=${linkPathname}) in source file path=${sourceFilePath} for version number=${version.versionName}`;
|
|
171
|
-
}
|
|
172
|
-
return permalink;
|
|
173
172
|
},
|
|
174
173
|
},
|
|
175
174
|
});
|
package/src/props.ts
CHANGED
|
@@ -38,28 +38,23 @@ export function toSidebarDocItemLinkProp({
|
|
|
38
38
|
'id' | 'title' | 'permalink' | 'unlisted' | 'frontMatter'
|
|
39
39
|
>;
|
|
40
40
|
}): PropSidebarItemLink {
|
|
41
|
-
const {
|
|
42
|
-
id,
|
|
43
|
-
title,
|
|
44
|
-
permalink,
|
|
45
|
-
frontMatter: {
|
|
46
|
-
sidebar_label: sidebarLabel,
|
|
47
|
-
sidebar_custom_props: customProps,
|
|
48
|
-
},
|
|
49
|
-
unlisted,
|
|
50
|
-
} = doc;
|
|
41
|
+
const {id, title, permalink, frontMatter, unlisted} = doc;
|
|
51
42
|
return {
|
|
52
43
|
type: 'link',
|
|
53
|
-
|
|
44
|
+
...(item.key && {key: item.key}),
|
|
54
45
|
href: permalink,
|
|
55
|
-
|
|
56
|
-
|
|
46
|
+
// Front Matter data takes precedence over sidebars.json
|
|
47
|
+
label: frontMatter.sidebar_label ?? item.label ?? title,
|
|
48
|
+
className: frontMatter.sidebar_class_name ?? item.className,
|
|
49
|
+
customProps: frontMatter.sidebar_custom_props ?? item.customProps,
|
|
57
50
|
docId: id,
|
|
58
51
|
unlisted,
|
|
59
52
|
};
|
|
60
53
|
}
|
|
61
54
|
|
|
62
|
-
export function toSidebarsProp(
|
|
55
|
+
export function toSidebarsProp(
|
|
56
|
+
loadedVersion: Pick<LoadedVersion, 'docs' | 'sidebars'>,
|
|
57
|
+
): PropSidebars {
|
|
63
58
|
const docsById = createDocsByIdIndex(loadedVersion.docs);
|
|
64
59
|
|
|
65
60
|
function getDocById(docId: string): DocMetadata {
|
|
@@ -77,10 +77,13 @@ function postProcessSidebarItem(
|
|
|
77
77
|
) {
|
|
78
78
|
return null;
|
|
79
79
|
}
|
|
80
|
+
const {label, className, customProps} = category;
|
|
80
81
|
return {
|
|
81
82
|
type: 'doc',
|
|
82
|
-
label: category.label,
|
|
83
83
|
id: category.link.id,
|
|
84
|
+
label,
|
|
85
|
+
...(className && {className}),
|
|
86
|
+
...(customProps && {customProps}),
|
|
84
87
|
};
|
|
85
88
|
}
|
|
86
89
|
// A non-collapsible category can't be collapsed!
|
package/src/sidebars/types.ts
CHANGED
|
@@ -19,6 +19,7 @@ import type {Slugger} from '@docusaurus/utils';
|
|
|
19
19
|
type Expand<T extends {[x: string]: unknown}> = {[P in keyof T]: T[P]};
|
|
20
20
|
|
|
21
21
|
export type SidebarItemBase = {
|
|
22
|
+
key?: string;
|
|
22
23
|
className?: string;
|
|
23
24
|
customProps?: {[key: string]: unknown};
|
|
24
25
|
};
|
|
@@ -28,8 +29,9 @@ export type SidebarItemDoc = SidebarItemBase & {
|
|
|
28
29
|
label?: string;
|
|
29
30
|
id: string;
|
|
30
31
|
/**
|
|
31
|
-
* This is an internal marker
|
|
32
|
-
* to be translated with JSON
|
|
32
|
+
* This is an internal marker set during the sidebar normalization process.
|
|
33
|
+
* Docs with labels defined in the config need to be translated with JSON.
|
|
34
|
+
* Otherwise, it's preferable to translate the MDX doc title or front matter.
|
|
33
35
|
*/
|
|
34
36
|
translatable?: true;
|
|
35
37
|
};
|
|
@@ -215,6 +217,7 @@ export type PropSidebarBreadcrumbsItem =
|
|
|
215
217
|
| PropSidebarItemCategory;
|
|
216
218
|
|
|
217
219
|
export type CategoryMetadataFile = {
|
|
220
|
+
key?: string;
|
|
218
221
|
label?: string;
|
|
219
222
|
position?: number;
|
|
220
223
|
description?: string;
|
|
@@ -28,6 +28,7 @@ import type {
|
|
|
28
28
|
// in normalization
|
|
29
29
|
|
|
30
30
|
const sidebarItemBaseSchema = Joi.object<SidebarItemBase>({
|
|
31
|
+
key: Joi.string(),
|
|
31
32
|
className: Joi.string(),
|
|
32
33
|
customProps: Joi.object().unknown(),
|
|
33
34
|
});
|
|
@@ -166,6 +167,7 @@ export function validateSidebars(sidebars: {
|
|
|
166
167
|
}
|
|
167
168
|
|
|
168
169
|
const categoryMetadataFileSchema = Joi.object<CategoryMetadataFile>({
|
|
170
|
+
key: Joi.string(),
|
|
169
171
|
label: Joi.string(),
|
|
170
172
|
description: Joi.string(),
|
|
171
173
|
position: Joi.number(),
|
package/src/translations.ts
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
import _ from 'lodash';
|
|
9
9
|
import {mergeTranslations} from '@docusaurus/utils';
|
|
10
|
+
import logger from '@docusaurus/logger';
|
|
10
11
|
import {CURRENT_VERSION_NAME} from './constants';
|
|
11
12
|
import {
|
|
12
13
|
collectSidebarCategories,
|
|
@@ -40,20 +41,53 @@ function getVersionFileName(versionName: string): string {
|
|
|
40
41
|
return `version-${versionName}`;
|
|
41
42
|
}
|
|
42
43
|
|
|
44
|
+
type TranslationMessageEntry = [string, TranslationMessage];
|
|
45
|
+
|
|
46
|
+
function ensureNoSidebarDuplicateEntries(
|
|
47
|
+
translationEntries: TranslationMessageEntry[],
|
|
48
|
+
): void {
|
|
49
|
+
const grouped = _.groupBy(translationEntries, (entry) => entry[0]);
|
|
50
|
+
const duplicates = Object.entries(grouped).filter(
|
|
51
|
+
(entry) => entry[1].length > 1,
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
if (duplicates.length > 0) {
|
|
55
|
+
throw new Error(`Multiple docs sidebar items produce the same translation key.
|
|
56
|
+
- ${duplicates
|
|
57
|
+
.map(([translationKey, entries]) => {
|
|
58
|
+
return `${logger.code(translationKey)}: ${logger.num(
|
|
59
|
+
entries.length,
|
|
60
|
+
)} duplicates found:\n - ${entries
|
|
61
|
+
.map((duplicate) => {
|
|
62
|
+
const desc = duplicate[1].description;
|
|
63
|
+
return `${logger.name(duplicate[1].message)} ${
|
|
64
|
+
desc ? `(${logger.subdue(desc)})` : ''
|
|
65
|
+
}`;
|
|
66
|
+
})
|
|
67
|
+
.join('\n - ')}`;
|
|
68
|
+
})
|
|
69
|
+
.join('\n\n- ')}
|
|
70
|
+
|
|
71
|
+
To avoid translation key conflicts, use the ${logger.code(
|
|
72
|
+
'key',
|
|
73
|
+
)} attribute on the sidebar items above to uniquely identify them.
|
|
74
|
+
`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
43
78
|
function getSidebarTranslationFileContent(
|
|
44
79
|
sidebar: Sidebar,
|
|
45
80
|
sidebarName: string,
|
|
46
81
|
): TranslationFileContent {
|
|
47
|
-
type TranslationMessageEntry = [string, TranslationMessage];
|
|
48
|
-
|
|
49
82
|
const categories = collectSidebarCategories(sidebar);
|
|
50
83
|
|
|
51
|
-
const
|
|
52
|
-
|
|
84
|
+
const categoryEntries: TranslationMessageEntry[] = categories.flatMap(
|
|
85
|
+
(category) => {
|
|
53
86
|
const entries: TranslationMessageEntry[] = [];
|
|
87
|
+
const categoryKey = category.key ?? category.label;
|
|
54
88
|
|
|
55
89
|
entries.push([
|
|
56
|
-
`sidebar.${sidebarName}.category.${
|
|
90
|
+
`sidebar.${sidebarName}.category.${categoryKey}`,
|
|
57
91
|
{
|
|
58
92
|
message: category.label,
|
|
59
93
|
description: `The label for category ${category.label} in sidebar ${sidebarName}`,
|
|
@@ -63,7 +97,7 @@ function getSidebarTranslationFileContent(
|
|
|
63
97
|
if (category.link?.type === 'generated-index') {
|
|
64
98
|
if (category.link.title) {
|
|
65
99
|
entries.push([
|
|
66
|
-
`sidebar.${sidebarName}.category.${
|
|
100
|
+
`sidebar.${sidebarName}.category.${categoryKey}.link.generated-index.title`,
|
|
67
101
|
{
|
|
68
102
|
message: category.link.title,
|
|
69
103
|
description: `The generated-index page title for category ${category.label} in sidebar ${sidebarName}`,
|
|
@@ -72,7 +106,7 @@ function getSidebarTranslationFileContent(
|
|
|
72
106
|
}
|
|
73
107
|
if (category.link.description) {
|
|
74
108
|
entries.push([
|
|
75
|
-
`sidebar.${sidebarName}.category.${
|
|
109
|
+
`sidebar.${sidebarName}.category.${categoryKey}.link.generated-index.description`,
|
|
76
110
|
{
|
|
77
111
|
message: category.link.description,
|
|
78
112
|
description: `The generated-index page description for category ${category.label} in sidebar ${sidebarName}`,
|
|
@@ -82,36 +116,40 @@ function getSidebarTranslationFileContent(
|
|
|
82
116
|
}
|
|
83
117
|
|
|
84
118
|
return entries;
|
|
85
|
-
}
|
|
119
|
+
},
|
|
86
120
|
);
|
|
87
121
|
|
|
88
122
|
const links = collectSidebarLinks(sidebar);
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
|
|
123
|
+
const linksEntries: TranslationMessageEntry[] = links.map((link) => {
|
|
124
|
+
const linkKey = link.key ?? link.label;
|
|
125
|
+
return [
|
|
126
|
+
`sidebar.${sidebarName}.link.${linkKey}`,
|
|
92
127
|
{
|
|
93
128
|
message: link.label,
|
|
94
129
|
description: `The label for link ${link.label} in sidebar ${sidebarName}, linking to ${link.href}`,
|
|
95
130
|
},
|
|
96
|
-
]
|
|
97
|
-
);
|
|
131
|
+
];
|
|
132
|
+
});
|
|
98
133
|
|
|
99
134
|
const docs = collectSidebarDocItems(sidebar)
|
|
100
135
|
.concat(collectSidebarRefs(sidebar))
|
|
101
136
|
.filter((item) => item.translatable);
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
|
|
137
|
+
const docLinksEntries: TranslationMessageEntry[] = docs.map((doc) => {
|
|
138
|
+
const docKey = doc.key ?? doc.label!;
|
|
139
|
+
return [
|
|
140
|
+
`sidebar.${sidebarName}.doc.${docKey}`,
|
|
105
141
|
{
|
|
106
142
|
message: doc.label!,
|
|
107
143
|
description: `The label for the doc item ${doc.label!} in sidebar ${sidebarName}, linking to the doc ${
|
|
108
144
|
doc.id
|
|
109
145
|
}`,
|
|
110
146
|
},
|
|
111
|
-
]
|
|
112
|
-
);
|
|
147
|
+
];
|
|
148
|
+
});
|
|
113
149
|
|
|
114
|
-
|
|
150
|
+
const allEntries = [...categoryEntries, ...linksEntries, ...docLinksEntries];
|
|
151
|
+
ensureNoSidebarDuplicateEntries(allEntries);
|
|
152
|
+
return Object.fromEntries(allEntries);
|
|
115
153
|
}
|
|
116
154
|
|
|
117
155
|
function translateSidebar({
|
|
@@ -150,27 +188,30 @@ function translateSidebar({
|
|
|
150
188
|
return transformSidebarItems(sidebar, (item) => {
|
|
151
189
|
if (item.type === 'category') {
|
|
152
190
|
const link = transformSidebarCategoryLink(item);
|
|
191
|
+
const categoryKey = item.key ?? item.label;
|
|
153
192
|
return {
|
|
154
193
|
...item,
|
|
155
194
|
label:
|
|
156
|
-
sidebarsTranslations[`sidebar.${sidebarName}.category.${
|
|
195
|
+
sidebarsTranslations[`sidebar.${sidebarName}.category.${categoryKey}`]
|
|
157
196
|
?.message ?? item.label,
|
|
158
197
|
...(link && {link}),
|
|
159
198
|
};
|
|
160
199
|
}
|
|
161
200
|
if (item.type === 'link') {
|
|
201
|
+
const linkKey = item.key ?? item.label;
|
|
162
202
|
return {
|
|
163
203
|
...item,
|
|
164
204
|
label:
|
|
165
|
-
sidebarsTranslations[`sidebar.${sidebarName}.link.${
|
|
205
|
+
sidebarsTranslations[`sidebar.${sidebarName}.link.${linkKey}`]
|
|
166
206
|
?.message ?? item.label,
|
|
167
207
|
};
|
|
168
208
|
}
|
|
169
209
|
if ((item.type === 'doc' || item.type === 'ref') && item.translatable) {
|
|
210
|
+
const docKey = item.key ?? item.label!;
|
|
170
211
|
return {
|
|
171
212
|
...item,
|
|
172
213
|
label:
|
|
173
|
-
sidebarsTranslations[`sidebar.${sidebarName}.doc.${
|
|
214
|
+
sidebarsTranslations[`sidebar.${sidebarName}.doc.${docKey}`]
|
|
174
215
|
?.message ?? item.label,
|
|
175
216
|
};
|
|
176
217
|
}
|
package/src/versions/files.ts
CHANGED
|
@@ -7,7 +7,11 @@
|
|
|
7
7
|
|
|
8
8
|
import path from 'path';
|
|
9
9
|
import fs from 'fs-extra';
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
getPluginI18nPath,
|
|
12
|
+
getLocaleConfig,
|
|
13
|
+
DEFAULT_PLUGIN_ID,
|
|
14
|
+
} from '@docusaurus/utils';
|
|
11
15
|
import {
|
|
12
16
|
VERSIONS_JSON_FILE,
|
|
13
17
|
VERSIONED_DOCS_DIR,
|
|
@@ -186,11 +190,16 @@ export async function getVersionMetadataPaths({
|
|
|
186
190
|
>
|
|
187
191
|
> {
|
|
188
192
|
const isCurrent = versionName === CURRENT_VERSION_NAME;
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
193
|
+
|
|
194
|
+
const shouldTranslate = getLocaleConfig(context.i18n).translate;
|
|
195
|
+
const contentPathLocalized = shouldTranslate
|
|
196
|
+
? getDocsDirPathLocalized({
|
|
197
|
+
localizationDir: context.localizationDir,
|
|
198
|
+
pluginId: options.id,
|
|
199
|
+
versionName,
|
|
200
|
+
})
|
|
201
|
+
: undefined;
|
|
202
|
+
|
|
194
203
|
const contentPath = isCurrent
|
|
195
204
|
? path.resolve(context.siteDir, options.path)
|
|
196
205
|
: getVersionDocsDirPath(context.siteDir, options.id, versionName);
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
import path from 'path';
|
|
9
9
|
import _ from 'lodash';
|
|
10
|
-
import {createSlugger} from '@docusaurus/utils';
|
|
10
|
+
import {aliasedSitePathToRelativePath, createSlugger} from '@docusaurus/utils';
|
|
11
11
|
import {getTagsFile} from '@docusaurus/utils-validation';
|
|
12
12
|
import logger from '@docusaurus/logger';
|
|
13
13
|
import {
|
|
@@ -29,102 +29,157 @@ import type {
|
|
|
29
29
|
import type {DocFile} from '../types';
|
|
30
30
|
import type {LoadContext} from '@docusaurus/types';
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
context,
|
|
34
|
-
options,
|
|
35
|
-
versionMetadata,
|
|
36
|
-
env,
|
|
37
|
-
}: {
|
|
32
|
+
type LoadVersionParams = {
|
|
38
33
|
context: LoadContext;
|
|
39
34
|
options: PluginOptions;
|
|
40
35
|
versionMetadata: VersionMetadata;
|
|
41
36
|
env: DocEnv;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
})
|
|
68
|
-
|
|
69
|
-
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
function ensureNoDuplicateDocId(docs: DocMetadataBase[]): void {
|
|
40
|
+
const duplicatesById = _.chain(docs)
|
|
41
|
+
.sort((d1, d2) => {
|
|
42
|
+
// Need to sort because Globby order is non-deterministic
|
|
43
|
+
// TODO maybe we should create a deterministic glob utils?
|
|
44
|
+
// see https://github.com/sindresorhus/globby/issues/131
|
|
45
|
+
return d1.source.localeCompare(d2.source);
|
|
46
|
+
})
|
|
47
|
+
.groupBy((d) => d.id)
|
|
48
|
+
.pickBy((group) => group.length > 1)
|
|
49
|
+
.value();
|
|
50
|
+
|
|
51
|
+
const duplicateIdEntries = Object.entries(duplicatesById);
|
|
52
|
+
|
|
53
|
+
if (duplicateIdEntries.length) {
|
|
54
|
+
const idMessages = duplicateIdEntries
|
|
55
|
+
.map(([id, duplicateDocs]) => {
|
|
56
|
+
return logger.interpolate`- code=${id} found in number=${
|
|
57
|
+
duplicateDocs.length
|
|
58
|
+
} docs:
|
|
59
|
+
- ${duplicateDocs
|
|
60
|
+
.map((d) => aliasedSitePathToRelativePath(d.source))
|
|
61
|
+
.join('\n - ')}`;
|
|
62
|
+
})
|
|
63
|
+
.join('\n\n');
|
|
64
|
+
|
|
65
|
+
const message = `The docs plugin found docs sharing the same id:
|
|
66
|
+
\n${idMessages}\n
|
|
67
|
+
Docs should have distinct ids.
|
|
68
|
+
In case of conflict, you can rename the docs file, or use the ${logger.code(
|
|
69
|
+
'id',
|
|
70
|
+
)} front matter to assign an explicit distinct id to each doc.
|
|
71
|
+
`;
|
|
72
|
+
|
|
73
|
+
throw new Error(message);
|
|
70
74
|
}
|
|
75
|
+
}
|
|
71
76
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
77
|
+
async function loadVersionDocsBase({
|
|
78
|
+
tagsFile,
|
|
79
|
+
context,
|
|
80
|
+
options,
|
|
81
|
+
versionMetadata,
|
|
82
|
+
env,
|
|
83
|
+
}: LoadVersionParams & {
|
|
84
|
+
tagsFile: TagsFile | null;
|
|
85
|
+
}): Promise<DocMetadataBase[]> {
|
|
86
|
+
const docFiles = await readVersionDocs(versionMetadata, options);
|
|
87
|
+
if (docFiles.length === 0) {
|
|
88
|
+
throw new Error(
|
|
89
|
+
`Docs version "${
|
|
90
|
+
versionMetadata.versionName
|
|
91
|
+
}" has no docs! At least one doc should exist at "${path.relative(
|
|
92
|
+
context.siteDir,
|
|
93
|
+
versionMetadata.contentPath,
|
|
94
|
+
)}".`,
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
function processVersionDoc(docFile: DocFile) {
|
|
98
|
+
return processDocMetadata({
|
|
99
|
+
docFile,
|
|
100
|
+
versionMetadata,
|
|
101
|
+
context,
|
|
102
|
+
options,
|
|
103
|
+
env,
|
|
104
|
+
tagsFile,
|
|
76
105
|
});
|
|
106
|
+
}
|
|
107
|
+
const docs = await Promise.all(docFiles.map(processVersionDoc));
|
|
108
|
+
ensureNoDuplicateDocId(docs);
|
|
109
|
+
return docs;
|
|
110
|
+
}
|
|
77
111
|
|
|
78
|
-
|
|
112
|
+
async function doLoadVersion({
|
|
113
|
+
context,
|
|
114
|
+
options,
|
|
115
|
+
versionMetadata,
|
|
116
|
+
env,
|
|
117
|
+
}: LoadVersionParams): Promise<LoadedVersion> {
|
|
118
|
+
const tagsFile = await getTagsFile({
|
|
119
|
+
contentPaths: versionMetadata,
|
|
120
|
+
tags: options.tags,
|
|
121
|
+
});
|
|
79
122
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
123
|
+
const docsBase: DocMetadataBase[] = await loadVersionDocsBase({
|
|
124
|
+
tagsFile,
|
|
125
|
+
context,
|
|
126
|
+
options,
|
|
127
|
+
versionMetadata,
|
|
128
|
+
env,
|
|
129
|
+
});
|
|
84
130
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
drafts,
|
|
90
|
-
version: versionMetadata,
|
|
91
|
-
sidebarOptions: {
|
|
92
|
-
sidebarCollapsed: options.sidebarCollapsed,
|
|
93
|
-
sidebarCollapsible: options.sidebarCollapsible,
|
|
94
|
-
},
|
|
95
|
-
categoryLabelSlugger: createSlugger(),
|
|
96
|
-
});
|
|
131
|
+
// TODO we only ever need draftIds in further code, not full draft items
|
|
132
|
+
// To simplify and prevent mistakes, avoid exposing draft
|
|
133
|
+
// replace draft=>draftIds in content loaded
|
|
134
|
+
const [drafts, docs] = _.partition(docsBase, (doc) => doc.draft);
|
|
97
135
|
|
|
98
|
-
|
|
136
|
+
const sidebars = await loadSidebars(versionMetadata.sidebarFilePath, {
|
|
137
|
+
sidebarItemsGenerator: options.sidebarItemsGenerator,
|
|
138
|
+
numberPrefixParser: options.numberPrefixParser,
|
|
139
|
+
docs,
|
|
140
|
+
drafts,
|
|
141
|
+
version: versionMetadata,
|
|
142
|
+
sidebarOptions: {
|
|
143
|
+
sidebarCollapsed: options.sidebarCollapsed,
|
|
144
|
+
sidebarCollapsible: options.sidebarCollapsible,
|
|
145
|
+
},
|
|
146
|
+
categoryLabelSlugger: createSlugger(),
|
|
147
|
+
});
|
|
99
148
|
|
|
100
|
-
|
|
101
|
-
const allDocIds = Object.keys(docsById);
|
|
149
|
+
const sidebarsUtils = createSidebarsUtils(sidebars);
|
|
102
150
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
versionMetadata,
|
|
106
|
-
});
|
|
107
|
-
sidebarsUtils.checkSidebarsDocIds({
|
|
108
|
-
allDocIds,
|
|
109
|
-
sidebarFilePath: versionMetadata.sidebarFilePath as string,
|
|
110
|
-
versionMetadata,
|
|
111
|
-
});
|
|
151
|
+
const docsById = createDocsByIdIndex(docs);
|
|
152
|
+
const allDocIds = Object.keys(docsById);
|
|
112
153
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
154
|
+
sidebarsUtils.checkLegacyVersionedSidebarNames({
|
|
155
|
+
sidebarFilePath: versionMetadata.sidebarFilePath as string,
|
|
156
|
+
versionMetadata,
|
|
157
|
+
});
|
|
158
|
+
sidebarsUtils.checkSidebarsDocIds({
|
|
159
|
+
allDocIds,
|
|
160
|
+
sidebarFilePath: versionMetadata.sidebarFilePath as string,
|
|
161
|
+
versionMetadata,
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
return {
|
|
165
|
+
...versionMetadata,
|
|
166
|
+
docs: addDocNavigation({
|
|
167
|
+
docs,
|
|
168
|
+
sidebarsUtils,
|
|
169
|
+
}),
|
|
170
|
+
drafts,
|
|
171
|
+
sidebars,
|
|
172
|
+
};
|
|
173
|
+
}
|
|
123
174
|
|
|
175
|
+
export async function loadVersion(
|
|
176
|
+
params: LoadVersionParams,
|
|
177
|
+
): Promise<LoadedVersion> {
|
|
124
178
|
try {
|
|
125
|
-
return await doLoadVersion();
|
|
179
|
+
return await doLoadVersion(params);
|
|
126
180
|
} catch (err) {
|
|
127
|
-
|
|
181
|
+
// TODO use error cause (but need to refactor many tests)
|
|
182
|
+
logger.error`Loading of version failed for version name=${params.versionMetadata.versionName}`;
|
|
128
183
|
throw err;
|
|
129
184
|
}
|
|
130
185
|
}
|
package/src/versions/version.ts
CHANGED
|
@@ -50,33 +50,47 @@ function getVersionEditUrls({
|
|
|
50
50
|
return {editUrl: undefined, editUrlLocalized: undefined};
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
|
|
54
|
-
const
|
|
55
|
-
? getDocsDirPathLocalized({
|
|
56
|
-
localizationDir: context.localizationDir,
|
|
57
|
-
versionName: CURRENT_VERSION_NAME,
|
|
58
|
-
pluginId: options.id,
|
|
59
|
-
})
|
|
60
|
-
: contentPathLocalized;
|
|
53
|
+
// Intermediate var just to please TS not narrowing to "string"
|
|
54
|
+
const editUrlOption = options.editUrl;
|
|
61
55
|
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
56
|
+
const getEditUrl = () => {
|
|
57
|
+
const editDirPath = options.editCurrentVersion ? options.path : contentPath;
|
|
58
|
+
|
|
59
|
+
return normalizeUrl([
|
|
60
|
+
editUrlOption,
|
|
61
|
+
posixPath(
|
|
62
|
+
path.relative(
|
|
63
|
+
context.siteDir,
|
|
64
|
+
path.resolve(context.siteDir, editDirPath),
|
|
65
|
+
),
|
|
66
|
+
),
|
|
67
|
+
]);
|
|
68
|
+
};
|
|
71
69
|
|
|
72
|
-
const
|
|
70
|
+
const getEditUrlLocalized = () => {
|
|
71
|
+
if (!contentPathLocalized) {
|
|
72
|
+
return undefined;
|
|
73
|
+
}
|
|
74
|
+
const editDirPathLocalized = options.editCurrentVersion
|
|
75
|
+
? getDocsDirPathLocalized({
|
|
76
|
+
localizationDir: context.localizationDir,
|
|
77
|
+
versionName: CURRENT_VERSION_NAME,
|
|
78
|
+
pluginId: options.id,
|
|
79
|
+
})
|
|
80
|
+
: contentPathLocalized;
|
|
73
81
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
82
|
+
return normalizeUrl([
|
|
83
|
+
editUrlOption,
|
|
84
|
+
posixPath(
|
|
85
|
+
path.relative(
|
|
86
|
+
context.siteDir,
|
|
87
|
+
path.resolve(context.siteDir, editDirPathLocalized),
|
|
88
|
+
),
|
|
89
|
+
),
|
|
90
|
+
]);
|
|
91
|
+
};
|
|
78
92
|
|
|
79
|
-
return {editUrl, editUrlLocalized};
|
|
93
|
+
return {editUrl: getEditUrl(), editUrlLocalized: getEditUrlLocalized()};
|
|
80
94
|
}
|
|
81
95
|
|
|
82
96
|
/**
|