@docusaurus/plugin-content-pages 3.2.0 → 3.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/content.d.ts +22 -0
- package/lib/content.js +120 -0
- package/lib/frontMatter.d.ts +1 -0
- package/lib/frontMatter.js +1 -0
- package/lib/index.d.ts +1 -2
- package/lib/index.js +9 -116
- package/lib/options.d.ts +1 -0
- package/lib/options.js +10 -3
- package/lib/routes.d.ts +17 -0
- package/lib/routes.js +58 -0
- package/package.json +7 -7
- package/src/content.ts +194 -0
- package/src/frontMatter.ts +2 -0
- package/src/index.ts +11 -155
- package/src/options.ts +10 -0
- package/src/plugin-content-pages.d.ts +22 -1
- package/src/routes.ts +89 -0
package/lib/content.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
/// <reference path="../src/plugin-content-pages.d.ts" />
|
|
8
|
+
import type { LoadContext } from '@docusaurus/types';
|
|
9
|
+
import type { PagesContentPaths } from './types';
|
|
10
|
+
import type { PluginOptions, LoadedContent } from '@docusaurus/plugin-content-pages';
|
|
11
|
+
export declare function createPagesContentPaths({ context, options, }: {
|
|
12
|
+
context: LoadContext;
|
|
13
|
+
options: PluginOptions;
|
|
14
|
+
}): PagesContentPaths;
|
|
15
|
+
export declare function getContentPathList(contentPaths: PagesContentPaths): string[];
|
|
16
|
+
type LoadContentParams = {
|
|
17
|
+
context: LoadContext;
|
|
18
|
+
options: PluginOptions;
|
|
19
|
+
contentPaths: PagesContentPaths;
|
|
20
|
+
};
|
|
21
|
+
export declare function loadPagesContent(params: LoadContentParams): Promise<LoadedContent>;
|
|
22
|
+
export {};
|
package/lib/content.js
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.loadPagesContent = exports.getContentPathList = exports.createPagesContentPaths = void 0;
|
|
10
|
+
const tslib_1 = require("tslib");
|
|
11
|
+
const fs_extra_1 = tslib_1.__importDefault(require("fs-extra"));
|
|
12
|
+
const path_1 = tslib_1.__importDefault(require("path"));
|
|
13
|
+
const utils_1 = require("@docusaurus/utils");
|
|
14
|
+
const frontMatter_1 = require("./frontMatter");
|
|
15
|
+
function createPagesContentPaths({ context, options, }) {
|
|
16
|
+
const { siteDir, localizationDir } = context;
|
|
17
|
+
return {
|
|
18
|
+
contentPath: path_1.default.resolve(siteDir, options.path),
|
|
19
|
+
contentPathLocalized: (0, utils_1.getPluginI18nPath)({
|
|
20
|
+
localizationDir,
|
|
21
|
+
pluginName: 'docusaurus-plugin-content-pages',
|
|
22
|
+
pluginId: options.id,
|
|
23
|
+
}),
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
exports.createPagesContentPaths = createPagesContentPaths;
|
|
27
|
+
function getContentPathList(contentPaths) {
|
|
28
|
+
return [contentPaths.contentPathLocalized, contentPaths.contentPath];
|
|
29
|
+
}
|
|
30
|
+
exports.getContentPathList = getContentPathList;
|
|
31
|
+
const isMarkdownSource = (source) => source.endsWith('.md') || source.endsWith('.mdx');
|
|
32
|
+
async function loadPagesContent(params) {
|
|
33
|
+
const { options } = params;
|
|
34
|
+
const pagesFiles = await (0, utils_1.Globby)(params.options.include, {
|
|
35
|
+
cwd: params.contentPaths.contentPath,
|
|
36
|
+
ignore: options.exclude,
|
|
37
|
+
});
|
|
38
|
+
async function doProcessPageSourceFile(relativeSource) {
|
|
39
|
+
try {
|
|
40
|
+
return await processPageSourceFile(relativeSource, params);
|
|
41
|
+
}
|
|
42
|
+
catch (err) {
|
|
43
|
+
throw new Error(`Processing of page source file path=${relativeSource} failed.`, { cause: err });
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return (await Promise.all(pagesFiles.map(doProcessPageSourceFile))).filter((res) => {
|
|
47
|
+
return res !== undefined;
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
exports.loadPagesContent = loadPagesContent;
|
|
51
|
+
async function processPageSourceFile(relativeSource, params) {
|
|
52
|
+
const { context, options, contentPaths } = params;
|
|
53
|
+
const { siteConfig, baseUrl, siteDir, i18n } = context;
|
|
54
|
+
const { editUrl } = options;
|
|
55
|
+
// Lookup in localized folder in priority
|
|
56
|
+
const contentPath = await (0, utils_1.getFolderContainingFile)(getContentPathList(contentPaths), relativeSource);
|
|
57
|
+
const source = path_1.default.join(contentPath, relativeSource);
|
|
58
|
+
const aliasedSourcePath = (0, utils_1.aliasedSitePath)(source, siteDir);
|
|
59
|
+
const permalink = (0, utils_1.normalizeUrl)([
|
|
60
|
+
baseUrl,
|
|
61
|
+
options.routeBasePath,
|
|
62
|
+
(0, utils_1.encodePath)((0, utils_1.fileToPath)(relativeSource)),
|
|
63
|
+
]);
|
|
64
|
+
if (!isMarkdownSource(relativeSource)) {
|
|
65
|
+
return {
|
|
66
|
+
type: 'jsx',
|
|
67
|
+
permalink,
|
|
68
|
+
source: aliasedSourcePath,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
const content = await fs_extra_1.default.readFile(source, 'utf-8');
|
|
72
|
+
const { frontMatter: unsafeFrontMatter, contentTitle, excerpt, } = await (0, utils_1.parseMarkdownFile)({
|
|
73
|
+
filePath: source,
|
|
74
|
+
fileContent: content,
|
|
75
|
+
parseFrontMatter: siteConfig.markdown.parseFrontMatter,
|
|
76
|
+
});
|
|
77
|
+
const frontMatter = (0, frontMatter_1.validatePageFrontMatter)(unsafeFrontMatter);
|
|
78
|
+
const pagesDirPath = await (0, utils_1.getFolderContainingFile)(getContentPathList(contentPaths), relativeSource);
|
|
79
|
+
const pagesSourceAbsolute = path_1.default.join(pagesDirPath, relativeSource);
|
|
80
|
+
function getPagesEditUrl() {
|
|
81
|
+
const pagesPathRelative = path_1.default.relative(pagesDirPath, path_1.default.resolve(pagesSourceAbsolute));
|
|
82
|
+
if (typeof editUrl === 'function') {
|
|
83
|
+
return editUrl({
|
|
84
|
+
pagesDirPath: (0, utils_1.posixPath)(path_1.default.relative(siteDir, pagesDirPath)),
|
|
85
|
+
pagesPath: (0, utils_1.posixPath)(pagesPathRelative),
|
|
86
|
+
permalink,
|
|
87
|
+
locale: i18n.currentLocale,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
else if (typeof editUrl === 'string') {
|
|
91
|
+
const isLocalized = pagesDirPath === contentPaths.contentPathLocalized;
|
|
92
|
+
const fileContentPath = isLocalized && options.editLocalizedFiles
|
|
93
|
+
? contentPaths.contentPathLocalized
|
|
94
|
+
: contentPaths.contentPath;
|
|
95
|
+
const contentPathEditUrl = (0, utils_1.normalizeUrl)([
|
|
96
|
+
editUrl,
|
|
97
|
+
(0, utils_1.posixPath)(path_1.default.relative(siteDir, fileContentPath)),
|
|
98
|
+
]);
|
|
99
|
+
return (0, utils_1.getEditUrl)(pagesPathRelative, contentPathEditUrl);
|
|
100
|
+
}
|
|
101
|
+
return undefined;
|
|
102
|
+
}
|
|
103
|
+
const lastUpdatedData = await (0, utils_1.readLastUpdateData)(source, options, frontMatter.last_update);
|
|
104
|
+
if ((0, utils_1.isDraft)({ frontMatter })) {
|
|
105
|
+
return undefined;
|
|
106
|
+
}
|
|
107
|
+
const unlisted = (0, utils_1.isUnlisted)({ frontMatter });
|
|
108
|
+
return {
|
|
109
|
+
type: 'mdx',
|
|
110
|
+
permalink,
|
|
111
|
+
source: aliasedSourcePath,
|
|
112
|
+
title: frontMatter.title ?? contentTitle,
|
|
113
|
+
description: frontMatter.description ?? excerpt,
|
|
114
|
+
frontMatter,
|
|
115
|
+
lastUpdatedBy: lastUpdatedData.lastUpdatedBy,
|
|
116
|
+
lastUpdatedAt: lastUpdatedData.lastUpdatedAt,
|
|
117
|
+
editUrl: getPagesEditUrl(),
|
|
118
|
+
unlisted,
|
|
119
|
+
};
|
|
120
|
+
}
|
package/lib/frontMatter.d.ts
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* This source code is licensed under the MIT license found in the
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
|
+
/// <reference path="../src/plugin-content-pages.d.ts" />
|
|
7
8
|
import type { PageFrontMatter } from '@docusaurus/plugin-content-pages';
|
|
8
9
|
export declare function validatePageFrontMatter(frontMatter: {
|
|
9
10
|
[key: string]: unknown;
|
package/lib/frontMatter.js
CHANGED
|
@@ -18,6 +18,7 @@ const PageFrontMatterSchema = utils_validation_1.Joi.object({
|
|
|
18
18
|
wrapperClassName: utils_validation_1.Joi.string(),
|
|
19
19
|
hide_table_of_contents: utils_validation_1.Joi.boolean(),
|
|
20
20
|
...utils_validation_1.FrontMatterTOCHeadingLevels,
|
|
21
|
+
last_update: utils_validation_1.FrontMatterLastUpdateSchema,
|
|
21
22
|
}).concat(utils_validation_1.ContentVisibilitySchema);
|
|
22
23
|
function validatePageFrontMatter(frontMatter) {
|
|
23
24
|
return (0, utils_validation_1.validateFrontMatter)(frontMatter, PageFrontMatterSchema);
|
package/lib/index.d.ts
CHANGED
|
@@ -4,9 +4,8 @@
|
|
|
4
4
|
* This source code is licensed under the MIT license found in the
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
|
+
/// <reference path="../src/plugin-content-pages.d.ts" />
|
|
7
8
|
import type { LoadContext, Plugin } from '@docusaurus/types';
|
|
8
|
-
import type { PagesContentPaths } from './types';
|
|
9
9
|
import type { PluginOptions, LoadedContent } from '@docusaurus/plugin-content-pages';
|
|
10
|
-
export declare function getContentPathList(contentPaths: PagesContentPaths): string[];
|
|
11
10
|
export default function pluginContentPages(context: LoadContext, options: PluginOptions): Plugin<LoadedContent | null>;
|
|
12
11
|
export { validateOptions } from './options';
|
package/lib/index.js
CHANGED
|
@@ -6,147 +6,40 @@
|
|
|
6
6
|
* LICENSE file in the root directory of this source tree.
|
|
7
7
|
*/
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
-
exports.validateOptions =
|
|
9
|
+
exports.validateOptions = void 0;
|
|
10
10
|
const tslib_1 = require("tslib");
|
|
11
11
|
const fs_extra_1 = tslib_1.__importDefault(require("fs-extra"));
|
|
12
12
|
const path_1 = tslib_1.__importDefault(require("path"));
|
|
13
13
|
const utils_1 = require("@docusaurus/utils");
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
return [contentPaths.contentPathLocalized, contentPaths.contentPath];
|
|
17
|
-
}
|
|
18
|
-
exports.getContentPathList = getContentPathList;
|
|
19
|
-
const isMarkdownSource = (source) => source.endsWith('.md') || source.endsWith('.mdx');
|
|
14
|
+
const routes_1 = require("./routes");
|
|
15
|
+
const content_1 = require("./content");
|
|
20
16
|
function pluginContentPages(context, options) {
|
|
21
|
-
const { siteConfig, siteDir, generatedFilesDir
|
|
22
|
-
const contentPaths = {
|
|
23
|
-
contentPath: path_1.default.resolve(siteDir, options.path),
|
|
24
|
-
contentPathLocalized: (0, utils_1.getPluginI18nPath)({
|
|
25
|
-
localizationDir,
|
|
26
|
-
pluginName: 'docusaurus-plugin-content-pages',
|
|
27
|
-
pluginId: options.id,
|
|
28
|
-
}),
|
|
29
|
-
};
|
|
17
|
+
const { siteConfig, siteDir, generatedFilesDir } = context;
|
|
18
|
+
const contentPaths = (0, content_1.createPagesContentPaths)({ context, options });
|
|
30
19
|
const pluginDataDirRoot = path_1.default.join(generatedFilesDir, 'docusaurus-plugin-content-pages');
|
|
31
20
|
const dataDir = path_1.default.join(pluginDataDirRoot, options.id ?? utils_1.DEFAULT_PLUGIN_ID);
|
|
32
21
|
return {
|
|
33
22
|
name: 'docusaurus-plugin-content-pages',
|
|
34
23
|
getPathsToWatch() {
|
|
35
24
|
const { include } = options;
|
|
36
|
-
return getContentPathList(contentPaths).flatMap((contentPath) => include.map((pattern) => `${contentPath}/${pattern}`));
|
|
25
|
+
return (0, content_1.getContentPathList)(contentPaths).flatMap((contentPath) => include.map((pattern) => `${contentPath}/${pattern}`));
|
|
37
26
|
},
|
|
38
27
|
async loadContent() {
|
|
39
|
-
const { include } = options;
|
|
40
28
|
if (!(await fs_extra_1.default.pathExists(contentPaths.contentPath))) {
|
|
41
29
|
return null;
|
|
42
30
|
}
|
|
43
|
-
|
|
44
|
-
const pagesFiles = await (0, utils_1.Globby)(include, {
|
|
45
|
-
cwd: contentPaths.contentPath,
|
|
46
|
-
ignore: options.exclude,
|
|
47
|
-
});
|
|
48
|
-
async function processPageSourceFile(relativeSource) {
|
|
49
|
-
// Lookup in localized folder in priority
|
|
50
|
-
const contentPath = await (0, utils_1.getFolderContainingFile)(getContentPathList(contentPaths), relativeSource);
|
|
51
|
-
const source = path_1.default.join(contentPath, relativeSource);
|
|
52
|
-
const aliasedSourcePath = (0, utils_1.aliasedSitePath)(source, siteDir);
|
|
53
|
-
const permalink = (0, utils_1.normalizeUrl)([
|
|
54
|
-
baseUrl,
|
|
55
|
-
options.routeBasePath,
|
|
56
|
-
(0, utils_1.encodePath)((0, utils_1.fileToPath)(relativeSource)),
|
|
57
|
-
]);
|
|
58
|
-
if (!isMarkdownSource(relativeSource)) {
|
|
59
|
-
return {
|
|
60
|
-
type: 'jsx',
|
|
61
|
-
permalink,
|
|
62
|
-
source: aliasedSourcePath,
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
const content = await fs_extra_1.default.readFile(source, 'utf-8');
|
|
66
|
-
const { frontMatter: unsafeFrontMatter, contentTitle, excerpt, } = await (0, utils_1.parseMarkdownFile)({
|
|
67
|
-
filePath: source,
|
|
68
|
-
fileContent: content,
|
|
69
|
-
parseFrontMatter: siteConfig.markdown.parseFrontMatter,
|
|
70
|
-
});
|
|
71
|
-
const frontMatter = (0, frontMatter_1.validatePageFrontMatter)(unsafeFrontMatter);
|
|
72
|
-
if ((0, utils_1.isDraft)({ frontMatter })) {
|
|
73
|
-
return undefined;
|
|
74
|
-
}
|
|
75
|
-
const unlisted = (0, utils_1.isUnlisted)({ frontMatter });
|
|
76
|
-
return {
|
|
77
|
-
type: 'mdx',
|
|
78
|
-
permalink,
|
|
79
|
-
source: aliasedSourcePath,
|
|
80
|
-
title: frontMatter.title ?? contentTitle,
|
|
81
|
-
description: frontMatter.description ?? excerpt,
|
|
82
|
-
frontMatter,
|
|
83
|
-
unlisted,
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
async function doProcessPageSourceFile(relativeSource) {
|
|
87
|
-
try {
|
|
88
|
-
return await processPageSourceFile(relativeSource);
|
|
89
|
-
}
|
|
90
|
-
catch (err) {
|
|
91
|
-
throw new Error(`Processing of page source file path=${relativeSource} failed.`, { cause: err });
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
return (await Promise.all(pagesFiles.map(doProcessPageSourceFile))).filter(Boolean);
|
|
31
|
+
return (0, content_1.loadPagesContent)({ context, options, contentPaths });
|
|
95
32
|
},
|
|
96
33
|
async contentLoaded({ content, actions }) {
|
|
97
34
|
if (!content) {
|
|
98
35
|
return;
|
|
99
36
|
}
|
|
100
|
-
|
|
101
|
-
function createPageRouteMetadata(metadata) {
|
|
102
|
-
return {
|
|
103
|
-
sourceFilePath: (0, utils_1.aliasedSitePathToRelativePath)(metadata.source),
|
|
104
|
-
// TODO add support for last updated date in the page plugin
|
|
105
|
-
// at least for Markdown files
|
|
106
|
-
// lastUpdatedAt: metadata.lastUpdatedAt,
|
|
107
|
-
lastUpdatedAt: undefined,
|
|
108
|
-
};
|
|
109
|
-
}
|
|
110
|
-
await Promise.all(content.map(async (metadata) => {
|
|
111
|
-
const { permalink, source } = metadata;
|
|
112
|
-
const routeMetadata = createPageRouteMetadata(metadata);
|
|
113
|
-
if (metadata.type === 'mdx') {
|
|
114
|
-
await createData(
|
|
115
|
-
// Note that this created data path must be in sync with
|
|
116
|
-
// metadataPath provided to mdx-loader.
|
|
117
|
-
`${(0, utils_1.docuHash)(metadata.source)}.json`, JSON.stringify(metadata, null, 2));
|
|
118
|
-
addRoute({
|
|
119
|
-
path: permalink,
|
|
120
|
-
component: options.mdxPageComponent,
|
|
121
|
-
exact: true,
|
|
122
|
-
metadata: routeMetadata,
|
|
123
|
-
modules: {
|
|
124
|
-
content: source,
|
|
125
|
-
},
|
|
126
|
-
});
|
|
127
|
-
}
|
|
128
|
-
else {
|
|
129
|
-
addRoute({
|
|
130
|
-
path: permalink,
|
|
131
|
-
component: source,
|
|
132
|
-
exact: true,
|
|
133
|
-
metadata: routeMetadata,
|
|
134
|
-
modules: {
|
|
135
|
-
config: `@generated/docusaurus.config`,
|
|
136
|
-
},
|
|
137
|
-
});
|
|
138
|
-
}
|
|
139
|
-
}));
|
|
37
|
+
await (0, routes_1.createAllRoutes)({ content, options, actions });
|
|
140
38
|
},
|
|
141
39
|
configureWebpack() {
|
|
142
40
|
const { admonitions, rehypePlugins, remarkPlugins, beforeDefaultRehypePlugins, beforeDefaultRemarkPlugins, } = options;
|
|
143
|
-
const contentDirs = getContentPathList(contentPaths);
|
|
41
|
+
const contentDirs = (0, content_1.getContentPathList)(contentPaths);
|
|
144
42
|
return {
|
|
145
|
-
resolve: {
|
|
146
|
-
alias: {
|
|
147
|
-
'~pages': pluginDataDirRoot,
|
|
148
|
-
},
|
|
149
|
-
},
|
|
150
43
|
module: {
|
|
151
44
|
rules: [
|
|
152
45
|
{
|
package/lib/options.d.ts
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* This source code is licensed under the MIT license found in the
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
|
+
/// <reference path="../src/plugin-content-pages.d.ts" />
|
|
7
8
|
import type { OptionValidationContext } from '@docusaurus/types';
|
|
8
9
|
import type { PluginOptions, Options } from '@docusaurus/plugin-content-pages';
|
|
9
10
|
export declare const DEFAULT_OPTIONS: PluginOptions;
|
package/lib/options.js
CHANGED
|
@@ -10,9 +10,9 @@ exports.validateOptions = exports.DEFAULT_OPTIONS = void 0;
|
|
|
10
10
|
const utils_validation_1 = require("@docusaurus/utils-validation");
|
|
11
11
|
const utils_1 = require("@docusaurus/utils");
|
|
12
12
|
exports.DEFAULT_OPTIONS = {
|
|
13
|
-
path: 'src/pages',
|
|
14
|
-
routeBasePath: '/',
|
|
15
|
-
include: ['**/*.{js,jsx,ts,tsx,md,mdx}'],
|
|
13
|
+
path: 'src/pages', // Path to data on filesystem, relative to site dir.
|
|
14
|
+
routeBasePath: '/', // URL Route.
|
|
15
|
+
include: ['**/*.{js,jsx,ts,tsx,md,mdx}'], // Extensions to include.
|
|
16
16
|
exclude: utils_1.GlobExcludeDefault,
|
|
17
17
|
mdxPageComponent: '@theme/MDXPage',
|
|
18
18
|
remarkPlugins: [],
|
|
@@ -20,6 +20,9 @@ exports.DEFAULT_OPTIONS = {
|
|
|
20
20
|
beforeDefaultRehypePlugins: [],
|
|
21
21
|
beforeDefaultRemarkPlugins: [],
|
|
22
22
|
admonitions: true,
|
|
23
|
+
showLastUpdateTime: false,
|
|
24
|
+
showLastUpdateAuthor: false,
|
|
25
|
+
editLocalizedFiles: false,
|
|
23
26
|
};
|
|
24
27
|
const PluginOptionSchema = utils_validation_1.Joi.object({
|
|
25
28
|
path: utils_validation_1.Joi.string().default(exports.DEFAULT_OPTIONS.path),
|
|
@@ -32,6 +35,10 @@ const PluginOptionSchema = utils_validation_1.Joi.object({
|
|
|
32
35
|
beforeDefaultRehypePlugins: utils_validation_1.RehypePluginsSchema.default(exports.DEFAULT_OPTIONS.beforeDefaultRehypePlugins),
|
|
33
36
|
beforeDefaultRemarkPlugins: utils_validation_1.RemarkPluginsSchema.default(exports.DEFAULT_OPTIONS.beforeDefaultRemarkPlugins),
|
|
34
37
|
admonitions: utils_validation_1.AdmonitionsSchema.default(exports.DEFAULT_OPTIONS.admonitions),
|
|
38
|
+
showLastUpdateTime: utils_validation_1.Joi.bool().default(exports.DEFAULT_OPTIONS.showLastUpdateTime),
|
|
39
|
+
showLastUpdateAuthor: utils_validation_1.Joi.bool().default(exports.DEFAULT_OPTIONS.showLastUpdateAuthor),
|
|
40
|
+
editUrl: utils_validation_1.Joi.alternatives().try(utils_validation_1.URISchema, utils_validation_1.Joi.function()),
|
|
41
|
+
editLocalizedFiles: utils_validation_1.Joi.boolean().default(exports.DEFAULT_OPTIONS.editLocalizedFiles),
|
|
35
42
|
});
|
|
36
43
|
function validateOptions({ validate, options, }) {
|
|
37
44
|
const validatedOptions = validate(PluginOptionSchema, options);
|
package/lib/routes.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
/// <reference path="../src/plugin-content-pages.d.ts" />
|
|
8
|
+
import type { PluginContentLoadedActions, RouteConfig } from '@docusaurus/types';
|
|
9
|
+
import type { PluginOptions, LoadedContent } from '@docusaurus/plugin-content-pages';
|
|
10
|
+
type CreateAllRoutesParam = {
|
|
11
|
+
content: LoadedContent;
|
|
12
|
+
options: PluginOptions;
|
|
13
|
+
actions: PluginContentLoadedActions;
|
|
14
|
+
};
|
|
15
|
+
export declare function createAllRoutes(param: CreateAllRoutesParam): Promise<void>;
|
|
16
|
+
export declare function buildAllRoutes({ content, actions, options, }: CreateAllRoutesParam): Promise<RouteConfig[]>;
|
|
17
|
+
export {};
|
package/lib/routes.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.buildAllRoutes = exports.createAllRoutes = void 0;
|
|
10
|
+
const utils_1 = require("@docusaurus/utils");
|
|
11
|
+
function createPageRouteMetadata(metadata) {
|
|
12
|
+
const lastUpdatedAt = metadata.type === 'mdx' ? metadata.lastUpdatedAt : undefined;
|
|
13
|
+
return {
|
|
14
|
+
sourceFilePath: (0, utils_1.aliasedSitePathToRelativePath)(metadata.source),
|
|
15
|
+
lastUpdatedAt,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
async function createAllRoutes(param) {
|
|
19
|
+
const routes = await buildAllRoutes(param);
|
|
20
|
+
routes.forEach(param.actions.addRoute);
|
|
21
|
+
}
|
|
22
|
+
exports.createAllRoutes = createAllRoutes;
|
|
23
|
+
async function buildAllRoutes({ content, actions, options, }) {
|
|
24
|
+
const { createData } = actions;
|
|
25
|
+
async function buildMDXPageRoute(metadata) {
|
|
26
|
+
await createData(
|
|
27
|
+
// Note that this created data path must be in sync with
|
|
28
|
+
// metadataPath provided to mdx-loader.
|
|
29
|
+
`${(0, utils_1.docuHash)(metadata.source)}.json`, metadata);
|
|
30
|
+
return {
|
|
31
|
+
path: metadata.permalink,
|
|
32
|
+
component: options.mdxPageComponent,
|
|
33
|
+
exact: true,
|
|
34
|
+
metadata: createPageRouteMetadata(metadata),
|
|
35
|
+
modules: {
|
|
36
|
+
content: metadata.source,
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
async function buildJSXRoute(metadata) {
|
|
41
|
+
return {
|
|
42
|
+
path: metadata.permalink,
|
|
43
|
+
component: metadata.source,
|
|
44
|
+
exact: true,
|
|
45
|
+
metadata: createPageRouteMetadata(metadata),
|
|
46
|
+
modules: {
|
|
47
|
+
config: `@generated/docusaurus.config`,
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
async function buildPageRoute(metadata) {
|
|
52
|
+
return metadata.type === 'mdx'
|
|
53
|
+
? buildMDXPageRoute(metadata)
|
|
54
|
+
: buildJSXRoute(metadata);
|
|
55
|
+
}
|
|
56
|
+
return Promise.all(content.map(buildPageRoute));
|
|
57
|
+
}
|
|
58
|
+
exports.buildAllRoutes = buildAllRoutes;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@docusaurus/plugin-content-pages",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.3.0",
|
|
4
4
|
"description": "Pages plugin for Docusaurus.",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "src/plugin-content-pages.d.ts",
|
|
@@ -18,11 +18,11 @@
|
|
|
18
18
|
},
|
|
19
19
|
"license": "MIT",
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@docusaurus/core": "3.
|
|
22
|
-
"@docusaurus/mdx-loader": "3.
|
|
23
|
-
"@docusaurus/types": "3.
|
|
24
|
-
"@docusaurus/utils": "3.
|
|
25
|
-
"@docusaurus/utils-validation": "3.
|
|
21
|
+
"@docusaurus/core": "3.3.0",
|
|
22
|
+
"@docusaurus/mdx-loader": "3.3.0",
|
|
23
|
+
"@docusaurus/types": "3.3.0",
|
|
24
|
+
"@docusaurus/utils": "3.3.0",
|
|
25
|
+
"@docusaurus/utils-validation": "3.3.0",
|
|
26
26
|
"fs-extra": "^11.1.1",
|
|
27
27
|
"tslib": "^2.6.0",
|
|
28
28
|
"webpack": "^5.88.1"
|
|
@@ -34,5 +34,5 @@
|
|
|
34
34
|
"engines": {
|
|
35
35
|
"node": ">=18.0"
|
|
36
36
|
},
|
|
37
|
-
"gitHead": "
|
|
37
|
+
"gitHead": "2ec4e078b5ca0c57f2cc04f2fe564d524bb5e858"
|
|
38
38
|
}
|
package/src/content.ts
ADDED
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import fs from 'fs-extra';
|
|
9
|
+
import path from 'path';
|
|
10
|
+
import {
|
|
11
|
+
encodePath,
|
|
12
|
+
fileToPath,
|
|
13
|
+
aliasedSitePath,
|
|
14
|
+
getFolderContainingFile,
|
|
15
|
+
Globby,
|
|
16
|
+
normalizeUrl,
|
|
17
|
+
parseMarkdownFile,
|
|
18
|
+
isUnlisted,
|
|
19
|
+
isDraft,
|
|
20
|
+
readLastUpdateData,
|
|
21
|
+
getEditUrl,
|
|
22
|
+
posixPath,
|
|
23
|
+
getPluginI18nPath,
|
|
24
|
+
} from '@docusaurus/utils';
|
|
25
|
+
import {validatePageFrontMatter} from './frontMatter';
|
|
26
|
+
import type {LoadContext} from '@docusaurus/types';
|
|
27
|
+
import type {PagesContentPaths} from './types';
|
|
28
|
+
import type {
|
|
29
|
+
PluginOptions,
|
|
30
|
+
Metadata,
|
|
31
|
+
LoadedContent,
|
|
32
|
+
} from '@docusaurus/plugin-content-pages';
|
|
33
|
+
|
|
34
|
+
export function createPagesContentPaths({
|
|
35
|
+
context,
|
|
36
|
+
options,
|
|
37
|
+
}: {
|
|
38
|
+
context: LoadContext;
|
|
39
|
+
options: PluginOptions;
|
|
40
|
+
}): PagesContentPaths {
|
|
41
|
+
const {siteDir, localizationDir} = context;
|
|
42
|
+
return {
|
|
43
|
+
contentPath: path.resolve(siteDir, options.path),
|
|
44
|
+
contentPathLocalized: getPluginI18nPath({
|
|
45
|
+
localizationDir,
|
|
46
|
+
pluginName: 'docusaurus-plugin-content-pages',
|
|
47
|
+
pluginId: options.id,
|
|
48
|
+
}),
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function getContentPathList(contentPaths: PagesContentPaths): string[] {
|
|
53
|
+
return [contentPaths.contentPathLocalized, contentPaths.contentPath];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const isMarkdownSource = (source: string) =>
|
|
57
|
+
source.endsWith('.md') || source.endsWith('.mdx');
|
|
58
|
+
|
|
59
|
+
type LoadContentParams = {
|
|
60
|
+
context: LoadContext;
|
|
61
|
+
options: PluginOptions;
|
|
62
|
+
contentPaths: PagesContentPaths;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export async function loadPagesContent(
|
|
66
|
+
params: LoadContentParams,
|
|
67
|
+
): Promise<LoadedContent> {
|
|
68
|
+
const {options} = params;
|
|
69
|
+
|
|
70
|
+
const pagesFiles = await Globby(params.options.include, {
|
|
71
|
+
cwd: params.contentPaths.contentPath,
|
|
72
|
+
ignore: options.exclude,
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
async function doProcessPageSourceFile(relativeSource: string) {
|
|
76
|
+
try {
|
|
77
|
+
return await processPageSourceFile(relativeSource, params);
|
|
78
|
+
} catch (err) {
|
|
79
|
+
throw new Error(
|
|
80
|
+
`Processing of page source file path=${relativeSource} failed.`,
|
|
81
|
+
{cause: err as Error},
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return (await Promise.all(pagesFiles.map(doProcessPageSourceFile))).filter(
|
|
87
|
+
(res): res is Metadata => {
|
|
88
|
+
return res !== undefined;
|
|
89
|
+
},
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
async function processPageSourceFile(
|
|
94
|
+
relativeSource: string,
|
|
95
|
+
params: LoadContentParams,
|
|
96
|
+
): Promise<Metadata | undefined> {
|
|
97
|
+
const {context, options, contentPaths} = params;
|
|
98
|
+
const {siteConfig, baseUrl, siteDir, i18n} = context;
|
|
99
|
+
const {editUrl} = options;
|
|
100
|
+
|
|
101
|
+
// Lookup in localized folder in priority
|
|
102
|
+
const contentPath = await getFolderContainingFile(
|
|
103
|
+
getContentPathList(contentPaths),
|
|
104
|
+
relativeSource,
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
const source = path.join(contentPath, relativeSource);
|
|
108
|
+
const aliasedSourcePath = aliasedSitePath(source, siteDir);
|
|
109
|
+
const permalink = normalizeUrl([
|
|
110
|
+
baseUrl,
|
|
111
|
+
options.routeBasePath,
|
|
112
|
+
encodePath(fileToPath(relativeSource)),
|
|
113
|
+
]);
|
|
114
|
+
if (!isMarkdownSource(relativeSource)) {
|
|
115
|
+
return {
|
|
116
|
+
type: 'jsx',
|
|
117
|
+
permalink,
|
|
118
|
+
source: aliasedSourcePath,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const content = await fs.readFile(source, 'utf-8');
|
|
123
|
+
const {
|
|
124
|
+
frontMatter: unsafeFrontMatter,
|
|
125
|
+
contentTitle,
|
|
126
|
+
excerpt,
|
|
127
|
+
} = await parseMarkdownFile({
|
|
128
|
+
filePath: source,
|
|
129
|
+
fileContent: content,
|
|
130
|
+
parseFrontMatter: siteConfig.markdown.parseFrontMatter,
|
|
131
|
+
});
|
|
132
|
+
const frontMatter = validatePageFrontMatter(unsafeFrontMatter);
|
|
133
|
+
|
|
134
|
+
const pagesDirPath = await getFolderContainingFile(
|
|
135
|
+
getContentPathList(contentPaths),
|
|
136
|
+
relativeSource,
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
const pagesSourceAbsolute = path.join(pagesDirPath, relativeSource);
|
|
140
|
+
|
|
141
|
+
function getPagesEditUrl() {
|
|
142
|
+
const pagesPathRelative = path.relative(
|
|
143
|
+
pagesDirPath,
|
|
144
|
+
path.resolve(pagesSourceAbsolute),
|
|
145
|
+
);
|
|
146
|
+
|
|
147
|
+
if (typeof editUrl === 'function') {
|
|
148
|
+
return editUrl({
|
|
149
|
+
pagesDirPath: posixPath(path.relative(siteDir, pagesDirPath)),
|
|
150
|
+
pagesPath: posixPath(pagesPathRelative),
|
|
151
|
+
permalink,
|
|
152
|
+
locale: i18n.currentLocale,
|
|
153
|
+
});
|
|
154
|
+
} else if (typeof editUrl === 'string') {
|
|
155
|
+
const isLocalized = pagesDirPath === contentPaths.contentPathLocalized;
|
|
156
|
+
const fileContentPath =
|
|
157
|
+
isLocalized && options.editLocalizedFiles
|
|
158
|
+
? contentPaths.contentPathLocalized
|
|
159
|
+
: contentPaths.contentPath;
|
|
160
|
+
|
|
161
|
+
const contentPathEditUrl = normalizeUrl([
|
|
162
|
+
editUrl,
|
|
163
|
+
posixPath(path.relative(siteDir, fileContentPath)),
|
|
164
|
+
]);
|
|
165
|
+
|
|
166
|
+
return getEditUrl(pagesPathRelative, contentPathEditUrl);
|
|
167
|
+
}
|
|
168
|
+
return undefined;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const lastUpdatedData = await readLastUpdateData(
|
|
172
|
+
source,
|
|
173
|
+
options,
|
|
174
|
+
frontMatter.last_update,
|
|
175
|
+
);
|
|
176
|
+
|
|
177
|
+
if (isDraft({frontMatter})) {
|
|
178
|
+
return undefined;
|
|
179
|
+
}
|
|
180
|
+
const unlisted = isUnlisted({frontMatter});
|
|
181
|
+
|
|
182
|
+
return {
|
|
183
|
+
type: 'mdx',
|
|
184
|
+
permalink,
|
|
185
|
+
source: aliasedSourcePath,
|
|
186
|
+
title: frontMatter.title ?? contentTitle,
|
|
187
|
+
description: frontMatter.description ?? excerpt,
|
|
188
|
+
frontMatter,
|
|
189
|
+
lastUpdatedBy: lastUpdatedData.lastUpdatedBy,
|
|
190
|
+
lastUpdatedAt: lastUpdatedData.lastUpdatedAt,
|
|
191
|
+
editUrl: getPagesEditUrl(),
|
|
192
|
+
unlisted,
|
|
193
|
+
};
|
|
194
|
+
}
|
package/src/frontMatter.ts
CHANGED
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
FrontMatterTOCHeadingLevels,
|
|
12
12
|
ContentVisibilitySchema,
|
|
13
13
|
URISchema,
|
|
14
|
+
FrontMatterLastUpdateSchema,
|
|
14
15
|
} from '@docusaurus/utils-validation';
|
|
15
16
|
import type {PageFrontMatter} from '@docusaurus/plugin-content-pages';
|
|
16
17
|
|
|
@@ -24,6 +25,7 @@ const PageFrontMatterSchema = Joi.object<PageFrontMatter>({
|
|
|
24
25
|
wrapperClassName: Joi.string(),
|
|
25
26
|
hide_table_of_contents: Joi.boolean(),
|
|
26
27
|
...FrontMatterTOCHeadingLevels,
|
|
28
|
+
last_update: FrontMatterLastUpdateSchema,
|
|
27
29
|
}).concat(ContentVisibilitySchema);
|
|
28
30
|
|
|
29
31
|
export function validatePageFrontMatter(frontMatter: {
|
package/src/index.ts
CHANGED
|
@@ -8,53 +8,32 @@
|
|
|
8
8
|
import fs from 'fs-extra';
|
|
9
9
|
import path from 'path';
|
|
10
10
|
import {
|
|
11
|
-
encodePath,
|
|
12
|
-
fileToPath,
|
|
13
11
|
aliasedSitePath,
|
|
14
|
-
aliasedSitePathToRelativePath,
|
|
15
12
|
docuHash,
|
|
16
|
-
getPluginI18nPath,
|
|
17
|
-
getFolderContainingFile,
|
|
18
13
|
addTrailingPathSeparator,
|
|
19
|
-
Globby,
|
|
20
14
|
createAbsoluteFilePathMatcher,
|
|
21
|
-
normalizeUrl,
|
|
22
15
|
DEFAULT_PLUGIN_ID,
|
|
23
|
-
parseMarkdownFile,
|
|
24
|
-
isUnlisted,
|
|
25
|
-
isDraft,
|
|
26
16
|
} from '@docusaurus/utils';
|
|
27
|
-
import {
|
|
28
|
-
import
|
|
29
|
-
|
|
17
|
+
import {createAllRoutes} from './routes';
|
|
18
|
+
import {
|
|
19
|
+
createPagesContentPaths,
|
|
20
|
+
getContentPathList,
|
|
21
|
+
loadPagesContent,
|
|
22
|
+
} from './content';
|
|
23
|
+
import type {LoadContext, Plugin} from '@docusaurus/types';
|
|
30
24
|
import type {
|
|
31
25
|
PluginOptions,
|
|
32
|
-
Metadata,
|
|
33
26
|
LoadedContent,
|
|
34
27
|
PageFrontMatter,
|
|
35
28
|
} from '@docusaurus/plugin-content-pages';
|
|
36
29
|
|
|
37
|
-
export function getContentPathList(contentPaths: PagesContentPaths): string[] {
|
|
38
|
-
return [contentPaths.contentPathLocalized, contentPaths.contentPath];
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const isMarkdownSource = (source: string) =>
|
|
42
|
-
source.endsWith('.md') || source.endsWith('.mdx');
|
|
43
|
-
|
|
44
30
|
export default function pluginContentPages(
|
|
45
31
|
context: LoadContext,
|
|
46
32
|
options: PluginOptions,
|
|
47
33
|
): Plugin<LoadedContent | null> {
|
|
48
|
-
const {siteConfig, siteDir, generatedFilesDir
|
|
34
|
+
const {siteConfig, siteDir, generatedFilesDir} = context;
|
|
49
35
|
|
|
50
|
-
const contentPaths
|
|
51
|
-
contentPath: path.resolve(siteDir, options.path),
|
|
52
|
-
contentPathLocalized: getPluginI18nPath({
|
|
53
|
-
localizationDir,
|
|
54
|
-
pluginName: 'docusaurus-plugin-content-pages',
|
|
55
|
-
pluginId: options.id,
|
|
56
|
-
}),
|
|
57
|
-
};
|
|
36
|
+
const contentPaths = createPagesContentPaths({context, options});
|
|
58
37
|
|
|
59
38
|
const pluginDataDirRoot = path.join(
|
|
60
39
|
generatedFilesDir,
|
|
@@ -73,135 +52,17 @@ export default function pluginContentPages(
|
|
|
73
52
|
},
|
|
74
53
|
|
|
75
54
|
async loadContent() {
|
|
76
|
-
const {include} = options;
|
|
77
|
-
|
|
78
55
|
if (!(await fs.pathExists(contentPaths.contentPath))) {
|
|
79
56
|
return null;
|
|
80
57
|
}
|
|
81
|
-
|
|
82
|
-
const {baseUrl} = siteConfig;
|
|
83
|
-
const pagesFiles = await Globby(include, {
|
|
84
|
-
cwd: contentPaths.contentPath,
|
|
85
|
-
ignore: options.exclude,
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
async function processPageSourceFile(
|
|
89
|
-
relativeSource: string,
|
|
90
|
-
): Promise<Metadata | undefined> {
|
|
91
|
-
// Lookup in localized folder in priority
|
|
92
|
-
const contentPath = await getFolderContainingFile(
|
|
93
|
-
getContentPathList(contentPaths),
|
|
94
|
-
relativeSource,
|
|
95
|
-
);
|
|
96
|
-
|
|
97
|
-
const source = path.join(contentPath, relativeSource);
|
|
98
|
-
const aliasedSourcePath = aliasedSitePath(source, siteDir);
|
|
99
|
-
const permalink = normalizeUrl([
|
|
100
|
-
baseUrl,
|
|
101
|
-
options.routeBasePath,
|
|
102
|
-
encodePath(fileToPath(relativeSource)),
|
|
103
|
-
]);
|
|
104
|
-
if (!isMarkdownSource(relativeSource)) {
|
|
105
|
-
return {
|
|
106
|
-
type: 'jsx',
|
|
107
|
-
permalink,
|
|
108
|
-
source: aliasedSourcePath,
|
|
109
|
-
};
|
|
110
|
-
}
|
|
111
|
-
const content = await fs.readFile(source, 'utf-8');
|
|
112
|
-
const {
|
|
113
|
-
frontMatter: unsafeFrontMatter,
|
|
114
|
-
contentTitle,
|
|
115
|
-
excerpt,
|
|
116
|
-
} = await parseMarkdownFile({
|
|
117
|
-
filePath: source,
|
|
118
|
-
fileContent: content,
|
|
119
|
-
parseFrontMatter: siteConfig.markdown.parseFrontMatter,
|
|
120
|
-
});
|
|
121
|
-
const frontMatter = validatePageFrontMatter(unsafeFrontMatter);
|
|
122
|
-
|
|
123
|
-
if (isDraft({frontMatter})) {
|
|
124
|
-
return undefined;
|
|
125
|
-
}
|
|
126
|
-
const unlisted = isUnlisted({frontMatter});
|
|
127
|
-
|
|
128
|
-
return {
|
|
129
|
-
type: 'mdx',
|
|
130
|
-
permalink,
|
|
131
|
-
source: aliasedSourcePath,
|
|
132
|
-
title: frontMatter.title ?? contentTitle,
|
|
133
|
-
description: frontMatter.description ?? excerpt,
|
|
134
|
-
frontMatter,
|
|
135
|
-
unlisted,
|
|
136
|
-
};
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
async function doProcessPageSourceFile(relativeSource: string) {
|
|
140
|
-
try {
|
|
141
|
-
return await processPageSourceFile(relativeSource);
|
|
142
|
-
} catch (err) {
|
|
143
|
-
throw new Error(
|
|
144
|
-
`Processing of page source file path=${relativeSource} failed.`,
|
|
145
|
-
{cause: err as Error},
|
|
146
|
-
);
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
return (
|
|
151
|
-
await Promise.all(pagesFiles.map(doProcessPageSourceFile))
|
|
152
|
-
).filter(Boolean) as Metadata[];
|
|
58
|
+
return loadPagesContent({context, options, contentPaths});
|
|
153
59
|
},
|
|
154
60
|
|
|
155
61
|
async contentLoaded({content, actions}) {
|
|
156
62
|
if (!content) {
|
|
157
63
|
return;
|
|
158
64
|
}
|
|
159
|
-
|
|
160
|
-
const {addRoute, createData} = actions;
|
|
161
|
-
|
|
162
|
-
function createPageRouteMetadata(metadata: Metadata): RouteMetadata {
|
|
163
|
-
return {
|
|
164
|
-
sourceFilePath: aliasedSitePathToRelativePath(metadata.source),
|
|
165
|
-
// TODO add support for last updated date in the page plugin
|
|
166
|
-
// at least for Markdown files
|
|
167
|
-
// lastUpdatedAt: metadata.lastUpdatedAt,
|
|
168
|
-
lastUpdatedAt: undefined,
|
|
169
|
-
};
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
await Promise.all(
|
|
173
|
-
content.map(async (metadata) => {
|
|
174
|
-
const {permalink, source} = metadata;
|
|
175
|
-
const routeMetadata = createPageRouteMetadata(metadata);
|
|
176
|
-
if (metadata.type === 'mdx') {
|
|
177
|
-
await createData(
|
|
178
|
-
// Note that this created data path must be in sync with
|
|
179
|
-
// metadataPath provided to mdx-loader.
|
|
180
|
-
`${docuHash(metadata.source)}.json`,
|
|
181
|
-
JSON.stringify(metadata, null, 2),
|
|
182
|
-
);
|
|
183
|
-
addRoute({
|
|
184
|
-
path: permalink,
|
|
185
|
-
component: options.mdxPageComponent,
|
|
186
|
-
exact: true,
|
|
187
|
-
metadata: routeMetadata,
|
|
188
|
-
modules: {
|
|
189
|
-
content: source,
|
|
190
|
-
},
|
|
191
|
-
});
|
|
192
|
-
} else {
|
|
193
|
-
addRoute({
|
|
194
|
-
path: permalink,
|
|
195
|
-
component: source,
|
|
196
|
-
exact: true,
|
|
197
|
-
metadata: routeMetadata,
|
|
198
|
-
modules: {
|
|
199
|
-
config: `@generated/docusaurus.config`,
|
|
200
|
-
},
|
|
201
|
-
});
|
|
202
|
-
}
|
|
203
|
-
}),
|
|
204
|
-
);
|
|
65
|
+
await createAllRoutes({content, options, actions});
|
|
205
66
|
},
|
|
206
67
|
|
|
207
68
|
configureWebpack() {
|
|
@@ -214,11 +75,6 @@ export default function pluginContentPages(
|
|
|
214
75
|
} = options;
|
|
215
76
|
const contentDirs = getContentPathList(contentPaths);
|
|
216
77
|
return {
|
|
217
|
-
resolve: {
|
|
218
|
-
alias: {
|
|
219
|
-
'~pages': pluginDataDirRoot,
|
|
220
|
-
},
|
|
221
|
-
},
|
|
222
78
|
module: {
|
|
223
79
|
rules: [
|
|
224
80
|
{
|
package/src/options.ts
CHANGED
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
RehypePluginsSchema,
|
|
12
12
|
AdmonitionsSchema,
|
|
13
13
|
RouteBasePathSchema,
|
|
14
|
+
URISchema,
|
|
14
15
|
} from '@docusaurus/utils-validation';
|
|
15
16
|
import {GlobExcludeDefault} from '@docusaurus/utils';
|
|
16
17
|
import type {OptionValidationContext} from '@docusaurus/types';
|
|
@@ -27,6 +28,9 @@ export const DEFAULT_OPTIONS: PluginOptions = {
|
|
|
27
28
|
beforeDefaultRehypePlugins: [],
|
|
28
29
|
beforeDefaultRemarkPlugins: [],
|
|
29
30
|
admonitions: true,
|
|
31
|
+
showLastUpdateTime: false,
|
|
32
|
+
showLastUpdateAuthor: false,
|
|
33
|
+
editLocalizedFiles: false,
|
|
30
34
|
};
|
|
31
35
|
|
|
32
36
|
const PluginOptionSchema = Joi.object<PluginOptions>({
|
|
@@ -44,6 +48,12 @@ const PluginOptionSchema = Joi.object<PluginOptions>({
|
|
|
44
48
|
DEFAULT_OPTIONS.beforeDefaultRemarkPlugins,
|
|
45
49
|
),
|
|
46
50
|
admonitions: AdmonitionsSchema.default(DEFAULT_OPTIONS.admonitions),
|
|
51
|
+
showLastUpdateTime: Joi.bool().default(DEFAULT_OPTIONS.showLastUpdateTime),
|
|
52
|
+
showLastUpdateAuthor: Joi.bool().default(
|
|
53
|
+
DEFAULT_OPTIONS.showLastUpdateAuthor,
|
|
54
|
+
),
|
|
55
|
+
editUrl: Joi.alternatives().try(URISchema, Joi.function()),
|
|
56
|
+
editLocalizedFiles: Joi.boolean().default(DEFAULT_OPTIONS.editLocalizedFiles),
|
|
47
57
|
});
|
|
48
58
|
|
|
49
59
|
export function validateOptions({
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
declare module '@docusaurus/plugin-content-pages' {
|
|
9
9
|
import type {MDXOptions} from '@docusaurus/mdx-loader';
|
|
10
10
|
import type {LoadContext, Plugin} from '@docusaurus/types';
|
|
11
|
+
import type {FrontMatterLastUpdate, LastUpdateData} from '@docusaurus/utils';
|
|
11
12
|
|
|
12
13
|
export type Assets = {
|
|
13
14
|
image?: string;
|
|
@@ -20,6 +21,10 @@ declare module '@docusaurus/plugin-content-pages' {
|
|
|
20
21
|
include: string[];
|
|
21
22
|
exclude: string[];
|
|
22
23
|
mdxPageComponent: string;
|
|
24
|
+
showLastUpdateTime: boolean;
|
|
25
|
+
showLastUpdateAuthor: boolean;
|
|
26
|
+
editUrl?: string | EditUrlFunction;
|
|
27
|
+
editLocalizedFiles?: boolean;
|
|
23
28
|
};
|
|
24
29
|
|
|
25
30
|
export type Options = Partial<PluginOptions>;
|
|
@@ -35,6 +40,7 @@ declare module '@docusaurus/plugin-content-pages' {
|
|
|
35
40
|
readonly toc_max_heading_level?: number;
|
|
36
41
|
readonly draft?: boolean;
|
|
37
42
|
readonly unlisted?: boolean;
|
|
43
|
+
readonly last_update?: FrontMatterLastUpdate;
|
|
38
44
|
};
|
|
39
45
|
|
|
40
46
|
export type JSXPageMetadata = {
|
|
@@ -43,16 +49,31 @@ declare module '@docusaurus/plugin-content-pages' {
|
|
|
43
49
|
source: string;
|
|
44
50
|
};
|
|
45
51
|
|
|
46
|
-
export type MDXPageMetadata = {
|
|
52
|
+
export type MDXPageMetadata = LastUpdateData & {
|
|
47
53
|
type: 'mdx';
|
|
48
54
|
permalink: string;
|
|
49
55
|
source: string;
|
|
50
56
|
frontMatter: PageFrontMatter & {[key: string]: unknown};
|
|
57
|
+
editUrl?: string;
|
|
51
58
|
title?: string;
|
|
52
59
|
description?: string;
|
|
53
60
|
unlisted: boolean;
|
|
54
61
|
};
|
|
55
62
|
|
|
63
|
+
export type EditUrlFunction = (editUrlParams: {
|
|
64
|
+
/**
|
|
65
|
+
* The root content directory containing this post file, relative to the
|
|
66
|
+
* site path. Usually the same as `options.path` but can be localized
|
|
67
|
+
*/
|
|
68
|
+
pagesDirPath: string;
|
|
69
|
+
/** Path to this pages file, relative to `pagesDirPath`. */
|
|
70
|
+
pagesPath: string;
|
|
71
|
+
/** @see {@link PagesPostMetadata.permalink} */
|
|
72
|
+
permalink: string;
|
|
73
|
+
/** Locale name. */
|
|
74
|
+
locale: string;
|
|
75
|
+
}) => string | undefined;
|
|
76
|
+
|
|
56
77
|
export type Metadata = JSXPageMetadata | MDXPageMetadata;
|
|
57
78
|
|
|
58
79
|
export type LoadedContent = Metadata[];
|
package/src/routes.ts
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import {aliasedSitePathToRelativePath, docuHash} from '@docusaurus/utils';
|
|
9
|
+
import type {
|
|
10
|
+
PluginContentLoadedActions,
|
|
11
|
+
RouteConfig,
|
|
12
|
+
RouteMetadata,
|
|
13
|
+
} from '@docusaurus/types';
|
|
14
|
+
import type {
|
|
15
|
+
PluginOptions,
|
|
16
|
+
Metadata,
|
|
17
|
+
LoadedContent,
|
|
18
|
+
MDXPageMetadata,
|
|
19
|
+
} from '@docusaurus/plugin-content-pages';
|
|
20
|
+
|
|
21
|
+
type CreateAllRoutesParam = {
|
|
22
|
+
content: LoadedContent;
|
|
23
|
+
options: PluginOptions;
|
|
24
|
+
actions: PluginContentLoadedActions;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
function createPageRouteMetadata(metadata: Metadata): RouteMetadata {
|
|
28
|
+
const lastUpdatedAt =
|
|
29
|
+
metadata.type === 'mdx' ? metadata.lastUpdatedAt : undefined;
|
|
30
|
+
return {
|
|
31
|
+
sourceFilePath: aliasedSitePathToRelativePath(metadata.source),
|
|
32
|
+
lastUpdatedAt,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export async function createAllRoutes(
|
|
37
|
+
param: CreateAllRoutesParam,
|
|
38
|
+
): Promise<void> {
|
|
39
|
+
const routes = await buildAllRoutes(param);
|
|
40
|
+
routes.forEach(param.actions.addRoute);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export async function buildAllRoutes({
|
|
44
|
+
content,
|
|
45
|
+
actions,
|
|
46
|
+
options,
|
|
47
|
+
}: CreateAllRoutesParam): Promise<RouteConfig[]> {
|
|
48
|
+
const {createData} = actions;
|
|
49
|
+
|
|
50
|
+
async function buildMDXPageRoute(
|
|
51
|
+
metadata: MDXPageMetadata,
|
|
52
|
+
): Promise<RouteConfig> {
|
|
53
|
+
await createData(
|
|
54
|
+
// Note that this created data path must be in sync with
|
|
55
|
+
// metadataPath provided to mdx-loader.
|
|
56
|
+
`${docuHash(metadata.source)}.json`,
|
|
57
|
+
metadata,
|
|
58
|
+
);
|
|
59
|
+
return {
|
|
60
|
+
path: metadata.permalink,
|
|
61
|
+
component: options.mdxPageComponent,
|
|
62
|
+
exact: true,
|
|
63
|
+
metadata: createPageRouteMetadata(metadata),
|
|
64
|
+
modules: {
|
|
65
|
+
content: metadata.source,
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async function buildJSXRoute(metadata: Metadata): Promise<RouteConfig> {
|
|
71
|
+
return {
|
|
72
|
+
path: metadata.permalink,
|
|
73
|
+
component: metadata.source,
|
|
74
|
+
exact: true,
|
|
75
|
+
metadata: createPageRouteMetadata(metadata),
|
|
76
|
+
modules: {
|
|
77
|
+
config: `@generated/docusaurus.config`,
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
async function buildPageRoute(metadata: Metadata): Promise<RouteConfig> {
|
|
83
|
+
return metadata.type === 'mdx'
|
|
84
|
+
? buildMDXPageRoute(metadata)
|
|
85
|
+
: buildJSXRoute(metadata);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return Promise.all(content.map(buildPageRoute));
|
|
89
|
+
}
|