@docusaurus/plugin-content-docs 2.0.0-beta.1ab8aa0af → 2.0.0-beta.2
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/.tsbuildinfo +1 -4661
- package/lib/cli.js +15 -10
- package/lib/client/docsClientUtils.d.ts +1 -1
- package/lib/client/docsClientUtils.js +3 -10
- package/lib/docFrontMatter.d.ts +1 -14
- package/lib/docFrontMatter.js +3 -2
- package/lib/docs.d.ts +1 -1
- package/lib/docs.js +22 -12
- package/lib/index.js +38 -17
- package/lib/lastUpdate.js +6 -6
- package/lib/markdown/linkify.js +1 -1
- package/lib/options.js +1 -6
- package/lib/props.js +4 -3
- package/lib/sidebarItemsGenerator.js +3 -3
- package/lib/sidebars.d.ts +3 -2
- package/lib/sidebars.js +28 -17
- package/lib/slug.js +2 -2
- package/lib/types.d.ts +18 -5
- package/lib/versions.js +54 -22
- package/package.json +13 -12
- package/src/__tests__/__fixtures__/simple-site/docs/foo/baz.md +4 -1
- package/src/__tests__/__fixtures__/simple-site/docs/hello.md +1 -0
- package/src/__tests__/__snapshots__/index.test.ts.snap +22 -13
- package/src/__tests__/cli.test.ts +16 -16
- package/src/__tests__/docFrontMatter.test.ts +47 -7
- package/src/__tests__/docs.test.ts +8 -5
- package/src/__tests__/index.test.ts +52 -12
- package/src/__tests__/lastUpdate.test.ts +3 -2
- package/src/__tests__/options.test.ts +0 -1
- package/src/__tests__/sidebars.test.ts +9 -8
- package/src/__tests__/versions.test.ts +34 -11
- package/src/cli.ts +17 -11
- package/src/client/__tests__/docsClientUtils.test.ts +6 -7
- package/src/client/docsClientUtils.ts +6 -16
- package/src/docFrontMatter.ts +5 -17
- package/src/docs.ts +28 -10
- package/src/index.ts +58 -21
- package/src/lastUpdate.ts +10 -6
- package/src/markdown/linkify.ts +1 -1
- package/src/options.ts +1 -15
- package/src/plugin-content-docs.d.ts +21 -0
- package/src/props.ts +8 -3
- package/src/sidebarItemsGenerator.ts +3 -3
- package/src/sidebars.ts +52 -19
- package/src/slug.ts +2 -2
- package/src/types.ts +23 -7
- package/src/versions.ts +88 -27
package/src/cli.ts
CHANGED
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
UnprocessedSidebarItem,
|
|
18
18
|
UnprocessedSidebars,
|
|
19
19
|
} from './types';
|
|
20
|
-
import {loadSidebars} from './sidebars';
|
|
20
|
+
import {loadSidebars, resolveSidebarPathOption} from './sidebars';
|
|
21
21
|
import {DEFAULT_PLUGIN_ID} from '@docusaurus/core/lib/constants';
|
|
22
22
|
|
|
23
23
|
function createVersionedSidebarFile({
|
|
@@ -92,23 +92,23 @@ export function cliDocsVersionCommand(
|
|
|
92
92
|
// It wouldn't be very user-friendly to show a [default] log prefix,
|
|
93
93
|
// so we use [docs] instead of [default]
|
|
94
94
|
const pluginIdLogPrefix =
|
|
95
|
-
pluginId === DEFAULT_PLUGIN_ID ? '[docs]
|
|
95
|
+
pluginId === DEFAULT_PLUGIN_ID ? '[docs]' : `[${pluginId}]`;
|
|
96
96
|
|
|
97
97
|
if (!version) {
|
|
98
98
|
throw new Error(
|
|
99
|
-
`${pluginIdLogPrefix}
|
|
99
|
+
`${pluginIdLogPrefix}: no version tag specified! Pass the version you wish to create as an argument, for example: 1.0.0.`,
|
|
100
100
|
);
|
|
101
101
|
}
|
|
102
102
|
|
|
103
103
|
if (version.includes('/') || version.includes('\\')) {
|
|
104
104
|
throw new Error(
|
|
105
|
-
`${pluginIdLogPrefix}
|
|
105
|
+
`${pluginIdLogPrefix}: invalid version tag specified! Do not include slash (/) or backslash (\\). Try something like: 1.0.0.`,
|
|
106
106
|
);
|
|
107
107
|
}
|
|
108
108
|
|
|
109
109
|
if (version.length > 32) {
|
|
110
110
|
throw new Error(
|
|
111
|
-
`${pluginIdLogPrefix}
|
|
111
|
+
`${pluginIdLogPrefix}: invalid version tag specified! Length cannot exceed 32 characters. Try something like: 1.0.0.`,
|
|
112
112
|
);
|
|
113
113
|
}
|
|
114
114
|
|
|
@@ -117,13 +117,13 @@ export function cliDocsVersionCommand(
|
|
|
117
117
|
// eslint-disable-next-line no-control-regex
|
|
118
118
|
if (/[<>:"|?*\x00-\x1F]/g.test(version)) {
|
|
119
119
|
throw new Error(
|
|
120
|
-
`${pluginIdLogPrefix}
|
|
120
|
+
`${pluginIdLogPrefix}: invalid version tag specified! Please ensure its a valid pathname too. Try something like: 1.0.0.`,
|
|
121
121
|
);
|
|
122
122
|
}
|
|
123
123
|
|
|
124
124
|
if (/^\.\.?$/.test(version)) {
|
|
125
125
|
throw new Error(
|
|
126
|
-
`${pluginIdLogPrefix}
|
|
126
|
+
`${pluginIdLogPrefix}: invalid version tag specified! Do not name your version "." or "..". Try something like: 1.0.0.`,
|
|
127
127
|
);
|
|
128
128
|
}
|
|
129
129
|
|
|
@@ -137,7 +137,7 @@ export function cliDocsVersionCommand(
|
|
|
137
137
|
// Check if version already exists.
|
|
138
138
|
if (versions.includes(version)) {
|
|
139
139
|
throw new Error(
|
|
140
|
-
`${pluginIdLogPrefix}
|
|
140
|
+
`${pluginIdLogPrefix}: this version already exists! Use a version tag that does not already exist.`,
|
|
141
141
|
);
|
|
142
142
|
}
|
|
143
143
|
|
|
@@ -145,20 +145,26 @@ export function cliDocsVersionCommand(
|
|
|
145
145
|
|
|
146
146
|
// Copy docs files.
|
|
147
147
|
const docsDir = path.join(siteDir, docsPath);
|
|
148
|
+
|
|
148
149
|
if (fs.existsSync(docsDir) && fs.readdirSync(docsDir).length > 0) {
|
|
149
150
|
const versionedDir = getVersionedDocsDirPath(siteDir, pluginId);
|
|
150
151
|
const newVersionDir = path.join(versionedDir, `version-${version}`);
|
|
151
152
|
fs.copySync(docsDir, newVersionDir);
|
|
152
153
|
} else {
|
|
153
|
-
throw new Error(`${pluginIdLogPrefix}
|
|
154
|
+
throw new Error(`${pluginIdLogPrefix}: there is no docs to version!`);
|
|
154
155
|
}
|
|
155
156
|
|
|
156
|
-
createVersionedSidebarFile({
|
|
157
|
+
createVersionedSidebarFile({
|
|
158
|
+
siteDir,
|
|
159
|
+
pluginId,
|
|
160
|
+
version,
|
|
161
|
+
sidebarPath: resolveSidebarPathOption(siteDir, sidebarPath),
|
|
162
|
+
});
|
|
157
163
|
|
|
158
164
|
// Update versions.json file.
|
|
159
165
|
versions.unshift(version);
|
|
160
166
|
fs.ensureDirSync(path.dirname(versionsJSONFile));
|
|
161
167
|
fs.writeFileSync(versionsJSONFile, `${JSON.stringify(versions, null, 2)}\n`);
|
|
162
168
|
|
|
163
|
-
console.log(`${pluginIdLogPrefix}
|
|
169
|
+
console.log(`${pluginIdLogPrefix}: version ${version} created!`);
|
|
164
170
|
}
|
|
@@ -35,12 +35,12 @@ describe('docsClientUtils', () => {
|
|
|
35
35
|
expect(() =>
|
|
36
36
|
getActivePlugin(data, '/', {failfast: true}),
|
|
37
37
|
).toThrowErrorMatchingInlineSnapshot(
|
|
38
|
-
`"Can't find active docs plugin for pathname
|
|
38
|
+
`"Can't find active docs plugin for \\"/\\" pathname, while it was expected to be found. Maybe you tried to use a docs feature that can only be used on a docs-related page? Existing docs plugin paths are: /ios, /android"`,
|
|
39
39
|
);
|
|
40
40
|
expect(() =>
|
|
41
41
|
getActivePlugin(data, '/xyz', {failfast: true}),
|
|
42
42
|
).toThrowErrorMatchingInlineSnapshot(
|
|
43
|
-
`"Can't find active docs plugin for pathname
|
|
43
|
+
`"Can't find active docs plugin for \\"/xyz\\" pathname, while it was expected to be found. Maybe you tried to use a docs feature that can only be used on a docs-related page? Existing docs plugin paths are: /ios, /android"`,
|
|
44
44
|
);
|
|
45
45
|
|
|
46
46
|
const activePluginIos: ActivePlugin = {
|
|
@@ -350,14 +350,13 @@ describe('docsClientUtils', () => {
|
|
|
350
350
|
latestVersionSuggestion: version2,
|
|
351
351
|
});
|
|
352
352
|
|
|
353
|
-
// nothing to suggest, we are already on latest version
|
|
354
353
|
expect(getDocVersionSuggestions(data, '/docs/')).toEqual({
|
|
355
|
-
latestDocSuggestion:
|
|
356
|
-
latestVersionSuggestion:
|
|
354
|
+
latestDocSuggestion: version2.docs[0],
|
|
355
|
+
latestVersionSuggestion: version2,
|
|
357
356
|
});
|
|
358
357
|
expect(getDocVersionSuggestions(data, '/docs/doc2')).toEqual({
|
|
359
|
-
latestDocSuggestion:
|
|
360
|
-
latestVersionSuggestion:
|
|
358
|
+
latestDocSuggestion: version2.docs[1],
|
|
359
|
+
latestVersionSuggestion: version2,
|
|
361
360
|
});
|
|
362
361
|
|
|
363
362
|
expect(getDocVersionSuggestions(data, '/docs/version1/')).toEqual({
|
|
@@ -57,7 +57,7 @@ export function getActivePlugin(
|
|
|
57
57
|
|
|
58
58
|
if (!activePlugin && options.failfast) {
|
|
59
59
|
throw new Error(
|
|
60
|
-
`Can't find active docs plugin for
|
|
60
|
+
`Can't find active docs plugin for "${pathname}" pathname, while it was expected to be found. Maybe you tried to use a docs feature that can only be used on a docs-related page? Existing docs plugin paths are: ${Object.values(
|
|
61
61
|
allPluginDatas,
|
|
62
62
|
)
|
|
63
63
|
.map((plugin) => plugin.path)
|
|
@@ -140,10 +140,10 @@ export const getActiveDocContext = (
|
|
|
140
140
|
};
|
|
141
141
|
|
|
142
142
|
export type DocVersionSuggestions = {
|
|
143
|
+
// suggest the latest version
|
|
144
|
+
latestVersionSuggestion: GlobalVersion;
|
|
143
145
|
// suggest the same doc, in latest version (if exist)
|
|
144
146
|
latestDocSuggestion?: GlobalDoc;
|
|
145
|
-
// suggest the latest version
|
|
146
|
-
latestVersionSuggestion?: GlobalVersion;
|
|
147
147
|
};
|
|
148
148
|
|
|
149
149
|
export const getDocVersionSuggestions = (
|
|
@@ -152,17 +152,7 @@ export const getDocVersionSuggestions = (
|
|
|
152
152
|
): DocVersionSuggestions => {
|
|
153
153
|
const latestVersion = getLatestVersion(data);
|
|
154
154
|
const activeDocContext = getActiveDocContext(data, pathname);
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
const latestDocSuggestion: GlobalDoc | undefined = isNotOnLatestVersion
|
|
160
|
-
? activeDocContext?.alternateDocVersions[latestVersion.name]
|
|
161
|
-
: undefined;
|
|
162
|
-
|
|
163
|
-
const latestVersionSuggestion = isNotOnLatestVersion
|
|
164
|
-
? latestVersion
|
|
165
|
-
: undefined;
|
|
166
|
-
|
|
167
|
-
return {latestDocSuggestion, latestVersionSuggestion};
|
|
155
|
+
const latestDocSuggestion: GlobalDoc | undefined =
|
|
156
|
+
activeDocContext?.alternateDocVersions[latestVersion.name];
|
|
157
|
+
return {latestDocSuggestion, latestVersionSuggestion: latestVersion};
|
|
168
158
|
};
|
package/src/docFrontMatter.ts
CHANGED
|
@@ -9,23 +9,10 @@
|
|
|
9
9
|
|
|
10
10
|
import {
|
|
11
11
|
JoiFrontMatter as Joi, // Custom instance for frontmatter
|
|
12
|
+
URISchema,
|
|
12
13
|
validateFrontMatter,
|
|
13
14
|
} from '@docusaurus/utils-validation';
|
|
14
|
-
|
|
15
|
-
export type DocFrontMatter = {
|
|
16
|
-
id?: string;
|
|
17
|
-
title?: string;
|
|
18
|
-
hide_title?: boolean;
|
|
19
|
-
hide_table_of_contents?: boolean;
|
|
20
|
-
keywords?: string[];
|
|
21
|
-
image?: string;
|
|
22
|
-
description?: string;
|
|
23
|
-
slug?: string;
|
|
24
|
-
sidebar_label?: string;
|
|
25
|
-
sidebar_position?: number;
|
|
26
|
-
custom_edit_url?: string | null;
|
|
27
|
-
parse_number_prefixes?: boolean;
|
|
28
|
-
};
|
|
15
|
+
import {DocFrontMatter} from './types';
|
|
29
16
|
|
|
30
17
|
// NOTE: we don't add any default value on purpose here
|
|
31
18
|
// We don't want default values to magically appear in doc metadatas and props
|
|
@@ -37,12 +24,13 @@ const DocFrontMatterSchema = Joi.object<DocFrontMatter>({
|
|
|
37
24
|
hide_title: Joi.boolean(),
|
|
38
25
|
hide_table_of_contents: Joi.boolean(),
|
|
39
26
|
keywords: Joi.array().items(Joi.string().required()),
|
|
40
|
-
image:
|
|
27
|
+
image: URISchema,
|
|
41
28
|
description: Joi.string().allow(''), // see https://github.com/facebook/docusaurus/issues/4591#issuecomment-822372398
|
|
42
29
|
slug: Joi.string(),
|
|
43
30
|
sidebar_label: Joi.string(),
|
|
44
31
|
sidebar_position: Joi.number().min(0),
|
|
45
|
-
|
|
32
|
+
pagination_label: Joi.string(),
|
|
33
|
+
custom_edit_url: URISchema.allow('', null),
|
|
46
34
|
parse_number_prefixes: Joi.boolean(),
|
|
47
35
|
}).unknown();
|
|
48
36
|
|
package/src/docs.ts
CHANGED
|
@@ -32,6 +32,7 @@ import globby from 'globby';
|
|
|
32
32
|
import {getDocsDirPaths} from './versions';
|
|
33
33
|
import {stripPathNumberPrefixes} from './numberPrefix';
|
|
34
34
|
import {validateDocFrontMatter} from './docFrontMatter';
|
|
35
|
+
import chalk from 'chalk';
|
|
35
36
|
|
|
36
37
|
type LastUpdateOptions = Pick<
|
|
37
38
|
PluginOptions,
|
|
@@ -102,7 +103,7 @@ export async function readVersionDocs(
|
|
|
102
103
|
);
|
|
103
104
|
}
|
|
104
105
|
|
|
105
|
-
|
|
106
|
+
function doProcessDocMetadata({
|
|
106
107
|
docFile,
|
|
107
108
|
versionMetadata,
|
|
108
109
|
context,
|
|
@@ -125,11 +126,11 @@ export function processDocMetadata({
|
|
|
125
126
|
const frontMatter = validateDocFrontMatter(unsafeFrontMatter);
|
|
126
127
|
|
|
127
128
|
const {
|
|
128
|
-
sidebar_label: sidebarLabel,
|
|
129
129
|
custom_edit_url: customEditURL,
|
|
130
130
|
|
|
131
131
|
// Strip number prefixes by default (01-MyFolder/01-MyDoc.md => MyFolder/MyDoc) by default,
|
|
132
132
|
// but allow to disable this behavior with frontmatterr
|
|
133
|
+
// eslint-disable-next-line camelcase
|
|
133
134
|
parse_number_prefixes = true,
|
|
134
135
|
} = frontMatter;
|
|
135
136
|
|
|
@@ -144,13 +145,14 @@ export function processDocMetadata({
|
|
|
144
145
|
// ex: myDoc -> .
|
|
145
146
|
const sourceDirName = path.dirname(source);
|
|
146
147
|
|
|
148
|
+
// eslint-disable-next-line camelcase
|
|
147
149
|
const {filename: unprefixedFileName, numberPrefix} = parse_number_prefixes
|
|
148
150
|
? options.numberPrefixParser(sourceFileNameWithoutExtension)
|
|
149
151
|
: {filename: sourceFileNameWithoutExtension, numberPrefix: undefined};
|
|
150
152
|
|
|
151
153
|
const baseID: string = frontMatter.id ?? unprefixedFileName;
|
|
152
154
|
if (baseID.includes('/')) {
|
|
153
|
-
throw new Error(`Document id
|
|
155
|
+
throw new Error(`Document id "${baseID}" cannot include slash.`);
|
|
154
156
|
}
|
|
155
157
|
|
|
156
158
|
// For autogenerated sidebars, sidebar position can come from filename number prefix or frontmatter
|
|
@@ -172,6 +174,7 @@ export function processDocMetadata({
|
|
|
172
174
|
return undefined;
|
|
173
175
|
}
|
|
174
176
|
// Eventually remove the number prefixes from intermediate directories
|
|
177
|
+
// eslint-disable-next-line camelcase
|
|
175
178
|
return parse_number_prefixes
|
|
176
179
|
? stripPathNumberPrefixes(sourceDirName, options.numberPrefixParser)
|
|
177
180
|
: sourceDirName;
|
|
@@ -203,11 +206,9 @@ export function processDocMetadata({
|
|
|
203
206
|
numberPrefixParser: options.numberPrefixParser,
|
|
204
207
|
});
|
|
205
208
|
|
|
206
|
-
//
|
|
207
|
-
//
|
|
208
|
-
|
|
209
|
-
const headingTitle: string = contentTitle ?? frontMatter.title ?? baseID;
|
|
210
|
-
// const metaTitle: string = frontMatter.title ?? contentTitle ?? baseID;
|
|
209
|
+
// Note: the title is used by default for page title, sidebar label, pagination buttons...
|
|
210
|
+
// frontMatter.title should be used in priority over contentTitle (because it can contain markdown/JSX syntax)
|
|
211
|
+
const title: string = frontMatter.title ?? contentTitle ?? baseID;
|
|
211
212
|
|
|
212
213
|
const description: string = frontMatter.description ?? excerpt ?? '';
|
|
213
214
|
|
|
@@ -246,7 +247,7 @@ export function processDocMetadata({
|
|
|
246
247
|
unversionedId,
|
|
247
248
|
id,
|
|
248
249
|
isDocsHomePage,
|
|
249
|
-
title
|
|
250
|
+
title,
|
|
250
251
|
description,
|
|
251
252
|
source: aliasedSitePath(filePath, siteDir),
|
|
252
253
|
sourceDirName,
|
|
@@ -261,8 +262,25 @@ export function processDocMetadata({
|
|
|
261
262
|
lastUpdate.lastUpdatedAt * 1000,
|
|
262
263
|
)
|
|
263
264
|
: undefined,
|
|
264
|
-
sidebar_label: sidebarLabel,
|
|
265
265
|
sidebarPosition,
|
|
266
266
|
frontMatter,
|
|
267
267
|
};
|
|
268
268
|
}
|
|
269
|
+
|
|
270
|
+
export function processDocMetadata(args: {
|
|
271
|
+
docFile: DocFile;
|
|
272
|
+
versionMetadata: VersionMetadata;
|
|
273
|
+
context: LoadContext;
|
|
274
|
+
options: MetadataOptions;
|
|
275
|
+
}): DocMetadataBase {
|
|
276
|
+
try {
|
|
277
|
+
return doProcessDocMetadata(args);
|
|
278
|
+
} catch (e) {
|
|
279
|
+
console.error(
|
|
280
|
+
chalk.red(
|
|
281
|
+
`Can't process doc metadatas for doc at path "${args.docFile.filePath}" in version "${args.versionMetadata.versionName}"`,
|
|
282
|
+
),
|
|
283
|
+
);
|
|
284
|
+
throw e;
|
|
285
|
+
}
|
|
286
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -41,7 +41,7 @@ import {PermalinkToSidebar} from '@docusaurus/plugin-content-docs-types';
|
|
|
41
41
|
import {RuleSetRule} from 'webpack';
|
|
42
42
|
import {cliDocsVersionCommand} from './cli';
|
|
43
43
|
import {VERSIONS_JSON_FILE} from './constants';
|
|
44
|
-
import {flatten, keyBy, compact} from 'lodash';
|
|
44
|
+
import {flatten, keyBy, compact, mapValues} from 'lodash';
|
|
45
45
|
import {toGlobalDataVersion} from './globalData';
|
|
46
46
|
import {toVersionMetadataProp} from './props';
|
|
47
47
|
import {
|
|
@@ -49,6 +49,7 @@ import {
|
|
|
49
49
|
getLoadedContentTranslationFiles,
|
|
50
50
|
} from './translations';
|
|
51
51
|
import {CategoryMetadataFilenamePattern} from './sidebarItemsGenerator';
|
|
52
|
+
import chalk from 'chalk';
|
|
52
53
|
|
|
53
54
|
export default function pluginContentDocs(
|
|
54
55
|
context: LoadContext,
|
|
@@ -58,7 +59,6 @@ export default function pluginContentDocs(
|
|
|
58
59
|
|
|
59
60
|
const versionsMetadata = readVersionsMetadata({context, options});
|
|
60
61
|
|
|
61
|
-
const sourceToPermalink: SourceToPermalink = {};
|
|
62
62
|
const pluginId = options.id ?? DEFAULT_PLUGIN_ID;
|
|
63
63
|
|
|
64
64
|
const pluginDataDirRoot = path.join(
|
|
@@ -144,12 +144,12 @@ export default function pluginContentDocs(
|
|
|
144
144
|
const docFiles = await readVersionDocs(versionMetadata, options);
|
|
145
145
|
if (docFiles.length === 0) {
|
|
146
146
|
throw new Error(
|
|
147
|
-
`Docs version ${
|
|
147
|
+
`Docs version "${
|
|
148
148
|
versionMetadata.versionName
|
|
149
|
-
} has no docs! At least one doc should exist at
|
|
149
|
+
}" has no docs! At least one doc should exist at "${path.relative(
|
|
150
150
|
siteDir,
|
|
151
151
|
versionMetadata.contentPath,
|
|
152
|
-
)}
|
|
152
|
+
)}".`,
|
|
153
153
|
);
|
|
154
154
|
}
|
|
155
155
|
async function processVersionDoc(docFile: DocFile) {
|
|
@@ -163,7 +163,7 @@ export default function pluginContentDocs(
|
|
|
163
163
|
return Promise.all(docFiles.map(processVersionDoc));
|
|
164
164
|
}
|
|
165
165
|
|
|
166
|
-
async function
|
|
166
|
+
async function doLoadVersion(
|
|
167
167
|
versionMetadata: VersionMetadata,
|
|
168
168
|
): Promise<LoadedVersion> {
|
|
169
169
|
const unprocessedSidebars = loadSidebars(
|
|
@@ -189,7 +189,10 @@ export default function pluginContentDocs(
|
|
|
189
189
|
const sidebarsUtils = createSidebarsUtils(sidebars);
|
|
190
190
|
|
|
191
191
|
const validDocIds = Object.keys(docsBaseById);
|
|
192
|
-
sidebarsUtils.checkSidebarsDocIds(
|
|
192
|
+
sidebarsUtils.checkSidebarsDocIds(
|
|
193
|
+
validDocIds,
|
|
194
|
+
versionMetadata.sidebarFilePath as string,
|
|
195
|
+
);
|
|
193
196
|
|
|
194
197
|
// Add sidebar/next/previous to the docs
|
|
195
198
|
function addNavData(doc: DocMetadataBase): DocMetadata {
|
|
@@ -198,10 +201,16 @@ export default function pluginContentDocs(
|
|
|
198
201
|
previousId,
|
|
199
202
|
nextId,
|
|
200
203
|
} = sidebarsUtils.getDocNavigation(doc.id);
|
|
201
|
-
const toDocNavLink = (navDocId: string): DocNavLink =>
|
|
202
|
-
title
|
|
203
|
-
|
|
204
|
-
|
|
204
|
+
const toDocNavLink = (navDocId: string): DocNavLink => {
|
|
205
|
+
const {title, permalink, frontMatter} = docsBaseById[navDocId];
|
|
206
|
+
return {
|
|
207
|
+
title:
|
|
208
|
+
frontMatter.pagination_label ??
|
|
209
|
+
frontMatter.sidebar_label ??
|
|
210
|
+
title,
|
|
211
|
+
permalink,
|
|
212
|
+
};
|
|
213
|
+
};
|
|
205
214
|
return {
|
|
206
215
|
...doc,
|
|
207
216
|
sidebar: sidebarName,
|
|
@@ -215,12 +224,6 @@ export default function pluginContentDocs(
|
|
|
215
224
|
// sort to ensure consistent output for tests
|
|
216
225
|
docs.sort((a, b) => a.id.localeCompare(b.id));
|
|
217
226
|
|
|
218
|
-
// TODO annoying side effect!
|
|
219
|
-
Object.values(docs).forEach((loadedDoc) => {
|
|
220
|
-
const {source, permalink} = loadedDoc;
|
|
221
|
-
sourceToPermalink[source] = permalink;
|
|
222
|
-
});
|
|
223
|
-
|
|
224
227
|
// TODO really useful? replace with global state logic?
|
|
225
228
|
const permalinkToSidebar: PermalinkToSidebar = {};
|
|
226
229
|
Object.values(docs).forEach((doc) => {
|
|
@@ -258,6 +261,19 @@ export default function pluginContentDocs(
|
|
|
258
261
|
};
|
|
259
262
|
}
|
|
260
263
|
|
|
264
|
+
async function loadVersion(versionMetadata: VersionMetadata) {
|
|
265
|
+
try {
|
|
266
|
+
return await doLoadVersion(versionMetadata);
|
|
267
|
+
} catch (e) {
|
|
268
|
+
console.error(
|
|
269
|
+
chalk.red(
|
|
270
|
+
`Loading of version failed for version "${versionMetadata.versionName}"`,
|
|
271
|
+
),
|
|
272
|
+
);
|
|
273
|
+
throw e;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
261
277
|
return {
|
|
262
278
|
loadedVersions: await Promise.all(versionsMetadata.map(loadVersion)),
|
|
263
279
|
};
|
|
@@ -298,7 +314,7 @@ export default function pluginContentDocs(
|
|
|
298
314
|
return routes.sort((a, b) => a.path.localeCompare(b.path));
|
|
299
315
|
};
|
|
300
316
|
|
|
301
|
-
async function
|
|
317
|
+
async function doCreateVersionRoutes(loadedVersion: LoadedVersion) {
|
|
302
318
|
const versionMetadataPropPath = await createData(
|
|
303
319
|
`${docuHash(
|
|
304
320
|
`version-${loadedVersion.versionName}-metadata-prop`,
|
|
@@ -325,7 +341,20 @@ export default function pluginContentDocs(
|
|
|
325
341
|
});
|
|
326
342
|
}
|
|
327
343
|
|
|
328
|
-
|
|
344
|
+
async function createVersionRoutes(loadedVersion: LoadedVersion) {
|
|
345
|
+
try {
|
|
346
|
+
return await doCreateVersionRoutes(loadedVersion);
|
|
347
|
+
} catch (e) {
|
|
348
|
+
console.error(
|
|
349
|
+
chalk.red(
|
|
350
|
+
`Can't create version routes for version "${loadedVersion.versionName}"`,
|
|
351
|
+
),
|
|
352
|
+
);
|
|
353
|
+
throw e;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
await Promise.all(loadedVersions.map(createVersionRoutes));
|
|
329
358
|
|
|
330
359
|
setGlobalData<GlobalPluginData>({
|
|
331
360
|
path: normalizeUrl([baseUrl, options.routeBasePath]),
|
|
@@ -333,7 +362,7 @@ export default function pluginContentDocs(
|
|
|
333
362
|
});
|
|
334
363
|
},
|
|
335
364
|
|
|
336
|
-
configureWebpack(_config, isServer, utils) {
|
|
365
|
+
configureWebpack(_config, isServer, utils, content) {
|
|
337
366
|
const {getJSLoader} = utils;
|
|
338
367
|
const {
|
|
339
368
|
rehypePlugins,
|
|
@@ -342,9 +371,17 @@ export default function pluginContentDocs(
|
|
|
342
371
|
beforeDefaultRemarkPlugins,
|
|
343
372
|
} = options;
|
|
344
373
|
|
|
374
|
+
function getSourceToPermalink(): SourceToPermalink {
|
|
375
|
+
const allDocs = flatten(content.loadedVersions.map((v) => v.docs));
|
|
376
|
+
return mapValues(
|
|
377
|
+
keyBy(allDocs, (d) => d.source),
|
|
378
|
+
(d) => d.permalink,
|
|
379
|
+
);
|
|
380
|
+
}
|
|
381
|
+
|
|
345
382
|
const docsMarkdownOptions: DocsMarkdownOption = {
|
|
346
383
|
siteDir,
|
|
347
|
-
sourceToPermalink,
|
|
384
|
+
sourceToPermalink: getSourceToPermalink(),
|
|
348
385
|
versionsMetadata,
|
|
349
386
|
onBrokenMarkdownLink: (brokenMarkdownLink) => {
|
|
350
387
|
if (siteConfig.onBrokenMarkdownLinks === 'ignore') {
|
package/src/lastUpdate.ts
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
import shell from 'shelljs';
|
|
9
9
|
import execa from 'execa';
|
|
10
|
+
import path from 'path';
|
|
10
11
|
|
|
11
12
|
type FileLastUpdateData = {timestamp?: number; author?: string};
|
|
12
13
|
|
|
@@ -43,12 +44,15 @@ export async function getFileLastUpdate(
|
|
|
43
44
|
return null;
|
|
44
45
|
}
|
|
45
46
|
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
'
|
|
50
|
-
|
|
51
|
-
|
|
47
|
+
const fileBasename = path.basename(filePath);
|
|
48
|
+
const fileDirname = path.dirname(filePath);
|
|
49
|
+
const {stdout} = await execa(
|
|
50
|
+
'git',
|
|
51
|
+
['log', '-1', '--format=%ct, %an', fileBasename],
|
|
52
|
+
{
|
|
53
|
+
cwd: fileDirname,
|
|
54
|
+
},
|
|
55
|
+
);
|
|
52
56
|
return getTimestampAndAuthor(stdout);
|
|
53
57
|
} catch (error) {
|
|
54
58
|
console.error(error);
|
package/src/markdown/linkify.ts
CHANGED
|
@@ -17,7 +17,7 @@ function getVersion(filePath: string, options: DocsMarkdownOption) {
|
|
|
17
17
|
);
|
|
18
18
|
if (!versionFound) {
|
|
19
19
|
throw new Error(
|
|
20
|
-
`Unexpected
|
|
20
|
+
`Unexpected error: Markdown file at "${filePath}" does not belong to any docs version!`,
|
|
21
21
|
);
|
|
22
22
|
}
|
|
23
23
|
return versionFound;
|
package/src/options.ts
CHANGED
|
@@ -37,7 +37,6 @@ export const DEFAULT_OPTIONS: Omit<PluginOptions, 'id' | 'sidebarPath'> = {
|
|
|
37
37
|
showLastUpdateTime: false,
|
|
38
38
|
showLastUpdateAuthor: false,
|
|
39
39
|
admonitions: {},
|
|
40
|
-
excludeNextVersionDocs: false,
|
|
41
40
|
includeCurrentVersion: true,
|
|
42
41
|
disableVersioning: false,
|
|
43
42
|
lastVersion: undefined,
|
|
@@ -49,6 +48,7 @@ export const DEFAULT_OPTIONS: Omit<PluginOptions, 'id' | 'sidebarPath'> = {
|
|
|
49
48
|
const VersionOptionsSchema = Joi.object({
|
|
50
49
|
path: Joi.string().allow('').optional(),
|
|
51
50
|
label: Joi.string().optional(),
|
|
51
|
+
banner: Joi.string().equal('none', 'unreleased', 'unmaintained').optional(),
|
|
52
52
|
});
|
|
53
53
|
|
|
54
54
|
const VersionsOptionsSchema = Joi.object()
|
|
@@ -101,9 +101,6 @@ export const OptionsSchema = Joi.object({
|
|
|
101
101
|
showLastUpdateAuthor: Joi.bool().default(
|
|
102
102
|
DEFAULT_OPTIONS.showLastUpdateAuthor,
|
|
103
103
|
),
|
|
104
|
-
excludeNextVersionDocs: Joi.bool().default(
|
|
105
|
-
DEFAULT_OPTIONS.excludeNextVersionDocs,
|
|
106
|
-
),
|
|
107
104
|
includeCurrentVersion: Joi.bool().default(
|
|
108
105
|
DEFAULT_OPTIONS.includeCurrentVersion,
|
|
109
106
|
),
|
|
@@ -127,17 +124,6 @@ export function validateOptions({
|
|
|
127
124
|
);
|
|
128
125
|
}
|
|
129
126
|
|
|
130
|
-
if (typeof options.excludeNextVersionDocs !== 'undefined') {
|
|
131
|
-
console.log(
|
|
132
|
-
chalk.red(
|
|
133
|
-
`The docs plugin option excludeNextVersionDocs=${
|
|
134
|
-
options.excludeNextVersionDocs
|
|
135
|
-
} is deprecated. Use the includeCurrentVersion=${!options.excludeNextVersionDocs} option instead!"`,
|
|
136
|
-
),
|
|
137
|
-
);
|
|
138
|
-
options.includeCurrentVersion = !options.excludeNextVersionDocs;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
127
|
const normalizedOptions = validate(OptionsSchema, options);
|
|
142
128
|
|
|
143
129
|
if (normalizedOptions.admonitions) {
|
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
/* eslint-disable camelcase */
|
|
9
9
|
|
|
10
10
|
declare module '@docusaurus/plugin-content-docs-types' {
|
|
11
|
+
import type {VersionBanner} from './types';
|
|
12
|
+
|
|
11
13
|
export type PermalinkToSidebar = {
|
|
12
14
|
[permalink: string]: string;
|
|
13
15
|
};
|
|
@@ -16,6 +18,7 @@ declare module '@docusaurus/plugin-content-docs-types' {
|
|
|
16
18
|
pluginId: string;
|
|
17
19
|
version: string;
|
|
18
20
|
label: string;
|
|
21
|
+
banner: VersionBanner;
|
|
19
22
|
isLast: boolean;
|
|
20
23
|
docsSidebars: PropSidebars;
|
|
21
24
|
permalinkToSidebar: PermalinkToSidebar;
|
|
@@ -43,6 +46,11 @@ declare module '@docusaurus/plugin-content-docs-types' {
|
|
|
43
46
|
export type PropSidebars = {
|
|
44
47
|
[sidebarId: string]: PropSidebarItem[];
|
|
45
48
|
};
|
|
49
|
+
|
|
50
|
+
export type {
|
|
51
|
+
GlobalVersion as GlobalDataVersion,
|
|
52
|
+
GlobalDoc as GlobalDataDoc,
|
|
53
|
+
} from './types';
|
|
46
54
|
}
|
|
47
55
|
|
|
48
56
|
declare module '@theme/DocItem' {
|
|
@@ -78,10 +86,12 @@ declare module '@theme/DocItem' {
|
|
|
78
86
|
|
|
79
87
|
export type Props = {
|
|
80
88
|
readonly route: DocumentRoute;
|
|
89
|
+
readonly versionMetadata: PropVersionMetadata;
|
|
81
90
|
readonly content: {
|
|
82
91
|
readonly frontMatter: FrontMatter;
|
|
83
92
|
readonly metadata: Metadata;
|
|
84
93
|
readonly toc: readonly TOCItem[];
|
|
94
|
+
readonly contentTitle: string | undefined;
|
|
85
95
|
(): JSX.Element;
|
|
86
96
|
};
|
|
87
97
|
};
|
|
@@ -90,6 +100,17 @@ declare module '@theme/DocItem' {
|
|
|
90
100
|
export default DocItem;
|
|
91
101
|
}
|
|
92
102
|
|
|
103
|
+
declare module '@theme/DocVersionBanner' {
|
|
104
|
+
import type {PropVersionMetadata} from '@docusaurus/plugin-content-docs-types';
|
|
105
|
+
|
|
106
|
+
export type Props = {
|
|
107
|
+
readonly versionMetadata: PropVersionMetadata;
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const DocVersionBanner: (props: Props) => JSX.Element;
|
|
111
|
+
export default DocVersionBanner;
|
|
112
|
+
}
|
|
113
|
+
|
|
93
114
|
declare module '@theme/DocPage' {
|
|
94
115
|
import type {PropVersionMetadata} from '@docusaurus/plugin-content-docs-types';
|
|
95
116
|
import type {DocumentRoute} from '@theme/DocItem';
|
package/src/props.ts
CHANGED
|
@@ -27,13 +27,17 @@ export function toSidebarsProp(loadedVersion: LoadedVersion): PropSidebars {
|
|
|
27
27
|
|
|
28
28
|
if (!docMetadata) {
|
|
29
29
|
throw new Error(
|
|
30
|
-
`
|
|
31
|
-
Available document ids
|
|
30
|
+
`Invalid sidebars file. The document with id "${docId}" was used in the sidebar, but no document with this id could be found.
|
|
31
|
+
Available document ids are:
|
|
32
32
|
- ${Object.keys(docsById).sort().join('\n- ')}`,
|
|
33
33
|
);
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
const {
|
|
36
|
+
const {
|
|
37
|
+
title,
|
|
38
|
+
permalink,
|
|
39
|
+
frontMatter: {sidebar_label: sidebarLabel},
|
|
40
|
+
} = docMetadata;
|
|
37
41
|
|
|
38
42
|
return {
|
|
39
43
|
type: 'link',
|
|
@@ -70,6 +74,7 @@ export function toVersionMetadataProp(
|
|
|
70
74
|
pluginId,
|
|
71
75
|
version: loadedVersion.versionName,
|
|
72
76
|
label: loadedVersion.versionLabel,
|
|
77
|
+
banner: loadedVersion.versionBanner,
|
|
73
78
|
isLast: loadedVersion.isLast,
|
|
74
79
|
docsSidebars: toSidebarsProp(loadedVersion),
|
|
75
80
|
permalinkToSidebar: loadedVersion.permalinkToSidebar,
|