@docusaurus/plugin-content-docs 3.1.1 → 3.2.1

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.
@@ -13,9 +13,16 @@ const StableEmptyObject = {};
13
13
  // In blog-only mode, docs hooks are still used by the theme. We need a fail-
14
14
  // safe fallback when the docs plugin is not in use
15
15
  export const useAllDocsData = () => useAllPluginInstancesData('docusaurus-plugin-content-docs') ?? StableEmptyObject;
16
- export const useDocsData = (pluginId) => usePluginData('docusaurus-plugin-content-docs', pluginId, {
17
- failfast: true,
18
- });
16
+ export const useDocsData = (pluginId) => {
17
+ try {
18
+ return usePluginData('docusaurus-plugin-content-docs', pluginId, {
19
+ failfast: true,
20
+ });
21
+ }
22
+ catch (error) {
23
+ throw new Error(`You are using a feature of the Docusaurus docs plugin, but this plugin does not seem to be enabled${pluginId === 'Default' ? '' : ` (pluginId=${pluginId}`}`, { cause: error });
24
+ }
25
+ };
19
26
  // TODO this feature should be provided by docusaurus core
20
27
  export function useActivePlugin(options = {}) {
21
28
  const data = useAllDocsData();
package/lib/docs.js CHANGED
@@ -11,44 +11,11 @@ const tslib_1 = require("tslib");
11
11
  const path_1 = tslib_1.__importDefault(require("path"));
12
12
  const fs_extra_1 = tslib_1.__importDefault(require("fs-extra"));
13
13
  const lodash_1 = tslib_1.__importDefault(require("lodash"));
14
- const logger_1 = tslib_1.__importDefault(require("@docusaurus/logger"));
15
14
  const utils_1 = require("@docusaurus/utils");
16
- const lastUpdate_1 = require("./lastUpdate");
15
+ const frontMatter_1 = require("./frontMatter");
17
16
  const slug_1 = tslib_1.__importDefault(require("./slug"));
18
17
  const numberPrefix_1 = require("./numberPrefix");
19
- const frontMatter_1 = require("./frontMatter");
20
18
  const utils_2 = require("./sidebars/utils");
21
- async function readLastUpdateData(filePath, options, lastUpdateFrontMatter) {
22
- const { showLastUpdateAuthor, showLastUpdateTime } = options;
23
- if (showLastUpdateAuthor || showLastUpdateTime) {
24
- const frontMatterTimestamp = lastUpdateFrontMatter?.date
25
- ? new Date(lastUpdateFrontMatter.date).getTime() / 1000
26
- : undefined;
27
- if (lastUpdateFrontMatter?.author && lastUpdateFrontMatter.date) {
28
- return {
29
- lastUpdatedAt: frontMatterTimestamp,
30
- lastUpdatedBy: lastUpdateFrontMatter.author,
31
- };
32
- }
33
- // Use fake data in dev for faster development.
34
- const fileLastUpdateData = process.env.NODE_ENV === 'production'
35
- ? await (0, lastUpdate_1.getFileLastUpdate)(filePath)
36
- : {
37
- author: 'Author',
38
- timestamp: 1539502055,
39
- };
40
- const { author, timestamp } = fileLastUpdateData ?? {};
41
- return {
42
- lastUpdatedBy: showLastUpdateAuthor
43
- ? lastUpdateFrontMatter?.author ?? author
44
- : undefined,
45
- lastUpdatedAt: showLastUpdateTime
46
- ? frontMatterTimestamp ?? timestamp
47
- : undefined,
48
- };
49
- }
50
- return {};
51
- }
52
19
  async function readDocFile(versionMetadata, source) {
53
20
  const contentPath = await (0, utils_1.getFolderContainingFile)((0, utils_1.getContentPathList)(versionMetadata), source);
54
21
  const filePath = path_1.default.join(contentPath, source);
@@ -66,7 +33,7 @@ async function readVersionDocs(versionMetadata, options) {
66
33
  exports.readVersionDocs = readVersionDocs;
67
34
  async function doProcessDocMetadata({ docFile, versionMetadata, context, options, env, }) {
68
35
  const { source, content, contentPath, filePath } = docFile;
69
- const { siteDir, i18n, siteConfig: { markdown: { parseFrontMatter }, }, } = context;
36
+ const { siteDir, siteConfig: { markdown: { parseFrontMatter }, }, } = context;
70
37
  const { frontMatter: unsafeFrontMatter, contentTitle, excerpt, } = await (0, utils_1.parseMarkdownFile)({
71
38
  filePath,
72
39
  fileContent: content,
@@ -78,7 +45,7 @@ async function doProcessDocMetadata({ docFile, versionMetadata, context, options
78
45
  // (01-MyFolder/01-MyDoc.md => MyFolder/MyDoc)
79
46
  // but allow to disable this behavior with front matter
80
47
  parse_number_prefixes: parseNumberPrefixes = true, last_update: lastUpdateFrontMatter, } = frontMatter;
81
- const lastUpdate = await readLastUpdateData(filePath, options, lastUpdateFrontMatter);
48
+ const lastUpdate = await (0, utils_1.readLastUpdateData)(filePath, options, lastUpdateFrontMatter);
82
49
  // E.g. api/plugins/myDoc -> myDoc; myDoc -> myDoc
83
50
  const sourceFileNameWithoutExtension = path_1.default.basename(source, path_1.default.extname(source));
84
51
  // E.g. api/plugins/myDoc -> api/plugins; myDoc -> .
@@ -141,21 +108,6 @@ async function doProcessDocMetadata({ docFile, versionMetadata, context, options
141
108
  }
142
109
  const draft = (0, utils_1.isDraft)({ env, frontMatter });
143
110
  const unlisted = (0, utils_1.isUnlisted)({ env, frontMatter });
144
- const formatDate = (locale, date, calendar) => {
145
- try {
146
- return new Intl.DateTimeFormat(locale, {
147
- day: 'numeric',
148
- month: 'short',
149
- year: 'numeric',
150
- timeZone: 'UTC',
151
- calendar,
152
- }).format(date);
153
- }
154
- catch (err) {
155
- logger_1.default.error `Can't format docs lastUpdatedAt date "${String(date)}"`;
156
- throw err;
157
- }
158
- };
159
111
  // Assign all of object properties during instantiation (if possible) for
160
112
  // NodeJS optimization.
161
113
  // Adding properties to object after instantiation will cause hidden
@@ -175,9 +127,6 @@ async function doProcessDocMetadata({ docFile, versionMetadata, context, options
175
127
  version: versionMetadata.versionName,
176
128
  lastUpdatedBy: lastUpdate.lastUpdatedBy,
177
129
  lastUpdatedAt: lastUpdate.lastUpdatedAt,
178
- formattedLastUpdatedAt: lastUpdate.lastUpdatedAt
179
- ? formatDate(i18n.currentLocale, new Date(lastUpdate.lastUpdatedAt * 1000), i18n.localeConfigs[i18n.currentLocale].calendar)
180
- : undefined,
181
130
  sidebarPosition,
182
131
  frontMatter,
183
132
  };
@@ -1,10 +1,5 @@
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
1
  import type { DocFrontMatter } from '@docusaurus/plugin-content-docs';
2
+ export declare const DocFrontMatterSchema: import("joi").ObjectSchema<DocFrontMatter>;
8
3
  export declare function validateDocFrontMatter(frontMatter: {
9
4
  [key: string]: unknown;
10
5
  }): DocFrontMatter;
@@ -1,19 +1,18 @@
1
1
  "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.validateDocFrontMatter = exports.DocFrontMatterSchema = void 0;
2
4
  /**
3
5
  * Copyright (c) Facebook, Inc. and its affiliates.
4
6
  *
5
7
  * This source code is licensed under the MIT license found in the
6
8
  * LICENSE file in the root directory of this source tree.
7
9
  */
8
- Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.validateDocFrontMatter = void 0;
10
10
  const utils_validation_1 = require("@docusaurus/utils-validation");
11
- const FrontMatterLastUpdateErrorMessage = '{{#label}} does not look like a valid front matter FileChange object. Please use a FileChange object (with an author and/or date).';
12
11
  // NOTE: we don't add any default value on purpose here
13
12
  // We don't want default values to magically appear in doc metadata and props
14
13
  // While the user did not provide those values explicitly
15
14
  // We use default values in code instead
16
- const DocFrontMatterSchema = utils_validation_1.JoiFrontMatter.object({
15
+ exports.DocFrontMatterSchema = utils_validation_1.JoiFrontMatter.object({
17
16
  id: utils_validation_1.JoiFrontMatter.string(),
18
17
  // See https://github.com/facebook/docusaurus/issues/4591#issuecomment-822372398
19
18
  title: utils_validation_1.JoiFrontMatter.string().allow(''),
@@ -36,19 +35,11 @@ const DocFrontMatterSchema = utils_validation_1.JoiFrontMatter.object({
36
35
  pagination_next: utils_validation_1.JoiFrontMatter.string().allow(null),
37
36
  pagination_prev: utils_validation_1.JoiFrontMatter.string().allow(null),
38
37
  ...utils_validation_1.FrontMatterTOCHeadingLevels,
39
- last_update: utils_validation_1.JoiFrontMatter.object({
40
- author: utils_validation_1.JoiFrontMatter.string(),
41
- date: utils_validation_1.JoiFrontMatter.date().raw(),
42
- })
43
- .or('author', 'date')
44
- .messages({
45
- 'object.missing': FrontMatterLastUpdateErrorMessage,
46
- 'object.base': FrontMatterLastUpdateErrorMessage,
47
- }),
38
+ last_update: utils_validation_1.FrontMatterLastUpdateSchema,
48
39
  })
49
40
  .unknown()
50
41
  .concat(utils_validation_1.ContentVisibilitySchema);
51
42
  function validateDocFrontMatter(frontMatter) {
52
- return (0, utils_validation_1.validateFrontMatter)(frontMatter, DocFrontMatterSchema);
43
+ return (0, utils_validation_1.validateFrontMatter)(frontMatter, exports.DocFrontMatterSchema);
53
44
  }
54
45
  exports.validateDocFrontMatter = validateDocFrontMatter;
package/lib/routes.js CHANGED
@@ -13,6 +13,12 @@ const logger_1 = tslib_1.__importDefault(require("@docusaurus/logger"));
13
13
  const utils_1 = require("@docusaurus/utils");
14
14
  const props_1 = require("./props");
15
15
  const tags_1 = require("./tags");
16
+ function createDocRouteMetadata(docMeta) {
17
+ return {
18
+ sourceFilePath: (0, utils_1.aliasedSitePathToRelativePath)(docMeta.source),
19
+ lastUpdatedAt: docMeta.lastUpdatedAt,
20
+ };
21
+ }
16
22
  async function buildVersionCategoryGeneratedIndexRoutes({ version, actions, options, aliasedSource, }) {
17
23
  const slugs = (0, utils_1.createSlugger)();
18
24
  async function buildCategoryGeneratedIndexRoute(categoryGeneratedIndex) {
@@ -34,23 +40,24 @@ async function buildVersionCategoryGeneratedIndexRoutes({ version, actions, opti
34
40
  return Promise.all(version.categoryGeneratedIndices.map(buildCategoryGeneratedIndexRoute));
35
41
  }
36
42
  async function buildVersionDocRoutes({ version, actions, options, }) {
37
- return Promise.all(version.docs.map(async (metadataItem) => {
43
+ return Promise.all(version.docs.map(async (doc) => {
38
44
  await actions.createData(
39
45
  // Note that this created data path must be in sync with
40
46
  // metadataPath provided to mdx-loader.
41
- `${(0, utils_1.docuHash)(metadataItem.source)}.json`, JSON.stringify(metadataItem, null, 2));
47
+ `${(0, utils_1.docuHash)(doc.source)}.json`, JSON.stringify(doc, null, 2));
42
48
  const docRoute = {
43
- path: metadataItem.permalink,
49
+ path: doc.permalink,
44
50
  component: options.docItemComponent,
45
51
  exact: true,
46
52
  modules: {
47
- content: metadataItem.source,
53
+ content: doc.source,
48
54
  },
55
+ metadata: createDocRouteMetadata(doc),
49
56
  // Because the parent (DocRoot) comp need to access it easily
50
57
  // This permits to render the sidebar once without unmount/remount when
51
58
  // navigating (and preserve sidebar state)
52
- ...(metadataItem.sidebar && {
53
- sidebar: metadataItem.sidebar,
59
+ ...(doc.sidebar && {
60
+ sidebar: doc.sidebar,
54
61
  }),
55
62
  };
56
63
  return docRoute;
@@ -11,7 +11,7 @@ const tslib_1 = require("tslib");
11
11
  const path_1 = tslib_1.__importDefault(require("path"));
12
12
  const lodash_1 = tslib_1.__importDefault(require("lodash"));
13
13
  const logger_1 = tslib_1.__importDefault(require("@docusaurus/logger"));
14
- const utils_1 = require("@docusaurus/utils");
14
+ const utils_common_1 = require("@docusaurus/utils-common");
15
15
  const docs_1 = require("../docs");
16
16
  const BreadcrumbSeparator = '/';
17
17
  // Just an alias to the make code more explicit
@@ -45,7 +45,7 @@ Available doc IDs:
45
45
  autogenDir === '.' ||
46
46
  // Autogen dir is not . and doc is in subfolder
47
47
  // "api/myDoc" startsWith "api/" (note "api2/myDoc" is not included)
48
- doc.sourceDirName.startsWith((0, utils_1.addTrailingSlash)(autogenDir)));
48
+ doc.sourceDirName.startsWith((0, utils_common_1.addTrailingSlash)(autogenDir)));
49
49
  }
50
50
  const docs = allDocs.filter(isInAutogeneratedDir);
51
51
  if (docs.length === 0) {
@@ -66,7 +66,7 @@ Available doc IDs:
66
66
  return autogenDir === doc.sourceDirName
67
67
  ? []
68
68
  : doc.sourceDirName
69
- .replace((0, utils_1.addTrailingSlash)(autogenDir), '')
69
+ .replace((0, utils_common_1.addTrailingSlash)(autogenDir), '')
70
70
  .split(BreadcrumbSeparator);
71
71
  }
72
72
  const treeRoot = {};
package/lib/slug.js CHANGED
@@ -7,6 +7,7 @@
7
7
  */
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
9
  const utils_1 = require("@docusaurus/utils");
10
+ const utils_common_1 = require("@docusaurus/utils-common");
10
11
  const numberPrefix_1 = require("./numberPrefix");
11
12
  const docs_1 = require("./docs");
12
13
  function getSlug({ baseID, frontMatterSlug, source, sourceDirName, stripDirNumberPrefixes = true, numberPrefixParser = numberPrefix_1.DefaultNumberPrefixParser, }) {
@@ -16,7 +17,7 @@ function getSlug({ baseID, frontMatterSlug, source, sourceDirName, stripDirNumbe
16
17
  : sourceDirName;
17
18
  const resolveDirname = sourceDirName === '.'
18
19
  ? '/'
19
- : (0, utils_1.addLeadingSlash)((0, utils_1.addTrailingSlash)(dirNameStripped));
20
+ : (0, utils_common_1.addLeadingSlash)((0, utils_common_1.addTrailingSlash)(dirNameStripped));
20
21
  return resolveDirname;
21
22
  }
22
23
  function computeSlug() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@docusaurus/plugin-content-docs",
3
- "version": "3.1.1",
3
+ "version": "3.2.1",
4
4
  "description": "Docs plugin for Docusaurus.",
5
5
  "main": "lib/index.js",
6
6
  "sideEffects": false,
@@ -35,13 +35,14 @@
35
35
  },
36
36
  "license": "MIT",
37
37
  "dependencies": {
38
- "@docusaurus/core": "3.1.1",
39
- "@docusaurus/logger": "3.1.1",
40
- "@docusaurus/mdx-loader": "3.1.1",
41
- "@docusaurus/module-type-aliases": "3.1.1",
42
- "@docusaurus/types": "3.1.1",
43
- "@docusaurus/utils": "3.1.1",
44
- "@docusaurus/utils-validation": "3.1.1",
38
+ "@docusaurus/core": "3.2.1",
39
+ "@docusaurus/logger": "3.2.1",
40
+ "@docusaurus/mdx-loader": "3.2.1",
41
+ "@docusaurus/module-type-aliases": "3.2.1",
42
+ "@docusaurus/types": "3.2.1",
43
+ "@docusaurus/utils": "3.2.1",
44
+ "@docusaurus/utils-common": "3.2.1",
45
+ "@docusaurus/utils-validation": "3.2.1",
45
46
  "@types/react-router-config": "^5.0.7",
46
47
  "combine-promises": "^1.1.0",
47
48
  "fs-extra": "^11.1.1",
@@ -65,5 +66,5 @@
65
66
  "engines": {
66
67
  "node": ">=18.0"
67
68
  },
68
- "gitHead": "8017f6a6776ba1bd7065e630a52fe2c2654e2f1b"
69
+ "gitHead": "f268e15264e208e6faf26117258162e988b53773"
69
70
  }
@@ -86,10 +86,20 @@ export const useAllDocsData = (): {[pluginId: string]: GlobalPluginData} =>
86
86
  }
87
87
  | undefined) ?? StableEmptyObject;
88
88
 
89
- export const useDocsData = (pluginId: string | undefined): GlobalPluginData =>
90
- usePluginData('docusaurus-plugin-content-docs', pluginId, {
91
- failfast: true,
92
- }) as GlobalPluginData;
89
+ export const useDocsData = (pluginId: string | undefined): GlobalPluginData => {
90
+ try {
91
+ return usePluginData('docusaurus-plugin-content-docs', pluginId, {
92
+ failfast: true,
93
+ }) as GlobalPluginData;
94
+ } catch (error) {
95
+ throw new Error(
96
+ `You are using a feature of the Docusaurus docs plugin, but this plugin does not seem to be enabled${
97
+ pluginId === 'Default' ? '' : ` (pluginId=${pluginId}`
98
+ }`,
99
+ {cause: error as Error},
100
+ );
101
+ }
102
+ };
93
103
 
94
104
  // TODO this feature should be provided by docusaurus core
95
105
  export function useActivePlugin(
package/src/docs.ts CHANGED
@@ -8,7 +8,6 @@
8
8
  import path from 'path';
9
9
  import fs from 'fs-extra';
10
10
  import _ from 'lodash';
11
- import logger from '@docusaurus/logger';
12
11
  import {
13
12
  aliasedSitePath,
14
13
  getEditUrl,
@@ -21,12 +20,11 @@ import {
21
20
  normalizeFrontMatterTags,
22
21
  isUnlisted,
23
22
  isDraft,
23
+ readLastUpdateData,
24
24
  } from '@docusaurus/utils';
25
-
26
- import {getFileLastUpdate} from './lastUpdate';
25
+ import {validateDocFrontMatter} from './frontMatter';
27
26
  import getSlug from './slug';
28
27
  import {stripPathNumberPrefixes} from './numberPrefix';
29
- import {validateDocFrontMatter} from './frontMatter';
30
28
  import {toDocNavigationLink, toNavigationLink} from './sidebars/utils';
31
29
  import type {
32
30
  MetadataOptions,
@@ -35,61 +33,13 @@ import type {
35
33
  DocMetadataBase,
36
34
  DocMetadata,
37
35
  PropNavigationLink,
38
- LastUpdateData,
39
36
  VersionMetadata,
40
37
  LoadedVersion,
41
- FileChange,
42
38
  } from '@docusaurus/plugin-content-docs';
43
39
  import type {LoadContext} from '@docusaurus/types';
44
40
  import type {SidebarsUtils} from './sidebars/utils';
45
41
  import type {DocFile} from './types';
46
42
 
47
- type LastUpdateOptions = Pick<
48
- PluginOptions,
49
- 'showLastUpdateAuthor' | 'showLastUpdateTime'
50
- >;
51
-
52
- async function readLastUpdateData(
53
- filePath: string,
54
- options: LastUpdateOptions,
55
- lastUpdateFrontMatter: FileChange | undefined,
56
- ): Promise<LastUpdateData> {
57
- const {showLastUpdateAuthor, showLastUpdateTime} = options;
58
- if (showLastUpdateAuthor || showLastUpdateTime) {
59
- const frontMatterTimestamp = lastUpdateFrontMatter?.date
60
- ? new Date(lastUpdateFrontMatter.date).getTime() / 1000
61
- : undefined;
62
-
63
- if (lastUpdateFrontMatter?.author && lastUpdateFrontMatter.date) {
64
- return {
65
- lastUpdatedAt: frontMatterTimestamp,
66
- lastUpdatedBy: lastUpdateFrontMatter.author,
67
- };
68
- }
69
-
70
- // Use fake data in dev for faster development.
71
- const fileLastUpdateData =
72
- process.env.NODE_ENV === 'production'
73
- ? await getFileLastUpdate(filePath)
74
- : {
75
- author: 'Author',
76
- timestamp: 1539502055,
77
- };
78
- const {author, timestamp} = fileLastUpdateData ?? {};
79
-
80
- return {
81
- lastUpdatedBy: showLastUpdateAuthor
82
- ? lastUpdateFrontMatter?.author ?? author
83
- : undefined,
84
- lastUpdatedAt: showLastUpdateTime
85
- ? frontMatterTimestamp ?? timestamp
86
- : undefined,
87
- };
88
- }
89
-
90
- return {};
91
- }
92
-
93
43
  export async function readDocFile(
94
44
  versionMetadata: Pick<
95
45
  VersionMetadata,
@@ -142,7 +92,6 @@ async function doProcessDocMetadata({
142
92
  const {source, content, contentPath, filePath} = docFile;
143
93
  const {
144
94
  siteDir,
145
- i18n,
146
95
  siteConfig: {
147
96
  markdown: {parseFrontMatter},
148
97
  },
@@ -257,21 +206,6 @@ async function doProcessDocMetadata({
257
206
  const draft = isDraft({env, frontMatter});
258
207
  const unlisted = isUnlisted({env, frontMatter});
259
208
 
260
- const formatDate = (locale: string, date: Date, calendar: string): string => {
261
- try {
262
- return new Intl.DateTimeFormat(locale, {
263
- day: 'numeric',
264
- month: 'short',
265
- year: 'numeric',
266
- timeZone: 'UTC',
267
- calendar,
268
- }).format(date);
269
- } catch (err) {
270
- logger.error`Can't format docs lastUpdatedAt date "${String(date)}"`;
271
- throw err;
272
- }
273
- };
274
-
275
209
  // Assign all of object properties during instantiation (if possible) for
276
210
  // NodeJS optimization.
277
211
  // Adding properties to object after instantiation will cause hidden
@@ -291,13 +225,6 @@ async function doProcessDocMetadata({
291
225
  version: versionMetadata.versionName,
292
226
  lastUpdatedBy: lastUpdate.lastUpdatedBy,
293
227
  lastUpdatedAt: lastUpdate.lastUpdatedAt,
294
- formattedLastUpdatedAt: lastUpdate.lastUpdatedAt
295
- ? formatDate(
296
- i18n.currentLocale,
297
- new Date(lastUpdate.lastUpdatedAt * 1000),
298
- i18n.localeConfigs[i18n.currentLocale]!.calendar,
299
- )
300
- : undefined,
301
228
  sidebarPosition,
302
229
  frontMatter,
303
230
  };
@@ -4,7 +4,6 @@
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
-
8
7
  import {
9
8
  JoiFrontMatter as Joi, // Custom instance for front matter
10
9
  URISchema,
@@ -12,17 +11,15 @@ import {
12
11
  FrontMatterTOCHeadingLevels,
13
12
  validateFrontMatter,
14
13
  ContentVisibilitySchema,
14
+ FrontMatterLastUpdateSchema,
15
15
  } from '@docusaurus/utils-validation';
16
16
  import type {DocFrontMatter} from '@docusaurus/plugin-content-docs';
17
17
 
18
- const FrontMatterLastUpdateErrorMessage =
19
- '{{#label}} does not look like a valid front matter FileChange object. Please use a FileChange object (with an author and/or date).';
20
-
21
18
  // NOTE: we don't add any default value on purpose here
22
19
  // We don't want default values to magically appear in doc metadata and props
23
20
  // While the user did not provide those values explicitly
24
21
  // We use default values in code instead
25
- const DocFrontMatterSchema = Joi.object<DocFrontMatter>({
22
+ export const DocFrontMatterSchema = Joi.object<DocFrontMatter>({
26
23
  id: Joi.string(),
27
24
  // See https://github.com/facebook/docusaurus/issues/4591#issuecomment-822372398
28
25
  title: Joi.string().allow(''),
@@ -45,15 +42,7 @@ const DocFrontMatterSchema = Joi.object<DocFrontMatter>({
45
42
  pagination_next: Joi.string().allow(null),
46
43
  pagination_prev: Joi.string().allow(null),
47
44
  ...FrontMatterTOCHeadingLevels,
48
- last_update: Joi.object({
49
- author: Joi.string(),
50
- date: Joi.date().raw(),
51
- })
52
- .or('author', 'date')
53
- .messages({
54
- 'object.missing': FrontMatterLastUpdateErrorMessage,
55
- 'object.base': FrontMatterLastUpdateErrorMessage,
56
- }),
45
+ last_update: FrontMatterLastUpdateSchema,
57
46
  })
58
47
  .unknown()
59
48
  .concat(ContentVisibilitySchema);
@@ -16,6 +16,8 @@ declare module '@docusaurus/plugin-content-docs' {
16
16
  TagsListItem,
17
17
  TagModule,
18
18
  Tag,
19
+ FrontMatterLastUpdate,
20
+ LastUpdateData,
19
21
  } from '@docusaurus/utils';
20
22
  import type {Plugin, LoadContext} from '@docusaurus/types';
21
23
  import type {Overwrite, Required} from 'utility-types';
@@ -24,14 +26,6 @@ declare module '@docusaurus/plugin-content-docs' {
24
26
  image?: string;
25
27
  };
26
28
 
27
- export type FileChange = {
28
- author?: string;
29
- /** Date can be any
30
- * [parsable date string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/parse).
31
- */
32
- date?: Date | string;
33
- };
34
-
35
29
  /**
36
30
  * Custom callback for parsing number prefixes from file/folder names.
37
31
  */
@@ -93,9 +87,9 @@ declare module '@docusaurus/plugin-content-docs' {
93
87
  */
94
88
  editLocalizedFiles: boolean;
95
89
  /** Whether to display the last date the doc was updated. */
96
- showLastUpdateTime?: boolean;
90
+ showLastUpdateTime: boolean;
97
91
  /** Whether to display the author who last updated the doc. */
98
- showLastUpdateAuthor?: boolean;
92
+ showLastUpdateAuthor: boolean;
99
93
  /**
100
94
  * Custom parsing logic to extract number prefixes from file names. Use
101
95
  * `false` to disable this behavior and leave the docs untouched, and `true`
@@ -401,16 +395,7 @@ declare module '@docusaurus/plugin-content-docs' {
401
395
  /** Should this doc be accessible but hidden in production builds? */
402
396
  unlisted?: boolean;
403
397
  /** Allows overriding the last updated author and/or date. */
404
- last_update?: FileChange;
405
- };
406
-
407
- export type LastUpdateData = {
408
- /** A timestamp in **seconds**, directly acquired from `git log`. */
409
- lastUpdatedAt?: number;
410
- /** `lastUpdatedAt` formatted as a date according to the current locale. */
411
- formattedLastUpdatedAt?: string;
412
- /** The author's name directly acquired from `git log`. */
413
- lastUpdatedBy?: string;
398
+ last_update?: FrontMatterLastUpdate;
414
399
  };
415
400
 
416
401
  export type DocMetadataBase = LastUpdateData & {
package/src/routes.ts CHANGED
@@ -7,21 +7,38 @@
7
7
 
8
8
  import _ from 'lodash';
9
9
  import logger from '@docusaurus/logger';
10
- import {docuHash, createSlugger, normalizeUrl} from '@docusaurus/utils';
10
+ import {
11
+ docuHash,
12
+ createSlugger,
13
+ normalizeUrl,
14
+ aliasedSitePathToRelativePath,
15
+ } from '@docusaurus/utils';
11
16
  import {
12
17
  toTagDocListProp,
13
18
  toTagsListTagsProp,
14
19
  toVersionMetadataProp,
15
20
  } from './props';
16
21
  import {getVersionTags} from './tags';
17
- import type {PluginContentLoadedActions, RouteConfig} from '@docusaurus/types';
22
+ import type {
23
+ PluginContentLoadedActions,
24
+ RouteConfig,
25
+ RouteMetadata,
26
+ } from '@docusaurus/types';
18
27
  import type {FullVersion, VersionTag} from './types';
19
28
  import type {
20
29
  CategoryGeneratedIndexMetadata,
30
+ DocMetadata,
21
31
  PluginOptions,
22
32
  PropTagsListPage,
23
33
  } from '@docusaurus/plugin-content-docs';
24
34
 
35
+ function createDocRouteMetadata(docMeta: DocMetadata): RouteMetadata {
36
+ return {
37
+ sourceFilePath: aliasedSitePathToRelativePath(docMeta.source),
38
+ lastUpdatedAt: docMeta.lastUpdatedAt,
39
+ };
40
+ }
41
+
25
42
  async function buildVersionCategoryGeneratedIndexRoutes({
26
43
  version,
27
44
  actions,
@@ -68,26 +85,27 @@ async function buildVersionDocRoutes({
68
85
  options,
69
86
  }: BuildVersionRoutesParam): Promise<RouteConfig[]> {
70
87
  return Promise.all(
71
- version.docs.map(async (metadataItem) => {
88
+ version.docs.map(async (doc) => {
72
89
  await actions.createData(
73
90
  // Note that this created data path must be in sync with
74
91
  // metadataPath provided to mdx-loader.
75
- `${docuHash(metadataItem.source)}.json`,
76
- JSON.stringify(metadataItem, null, 2),
92
+ `${docuHash(doc.source)}.json`,
93
+ JSON.stringify(doc, null, 2),
77
94
  );
78
95
 
79
96
  const docRoute: RouteConfig = {
80
- path: metadataItem.permalink,
97
+ path: doc.permalink,
81
98
  component: options.docItemComponent,
82
99
  exact: true,
83
100
  modules: {
84
- content: metadataItem.source,
101
+ content: doc.source,
85
102
  },
103
+ metadata: createDocRouteMetadata(doc),
86
104
  // Because the parent (DocRoot) comp need to access it easily
87
105
  // This permits to render the sidebar once without unmount/remount when
88
106
  // navigating (and preserve sidebar state)
89
- ...(metadataItem.sidebar && {
90
- sidebar: metadataItem.sidebar,
107
+ ...(doc.sidebar && {
108
+ sidebar: doc.sidebar,
91
109
  }),
92
110
  };
93
111
 
@@ -8,7 +8,7 @@
8
8
  import path from 'path';
9
9
  import _ from 'lodash';
10
10
  import logger from '@docusaurus/logger';
11
- import {addTrailingSlash} from '@docusaurus/utils';
11
+ import {addTrailingSlash} from '@docusaurus/utils-common';
12
12
  import {createDocsByIdIndex, toCategoryIndexMatcherParam} from '../docs';
13
13
  import type {
14
14
  SidebarItemDoc,
package/src/slug.ts CHANGED
@@ -5,12 +5,8 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
 
8
- import {
9
- addLeadingSlash,
10
- addTrailingSlash,
11
- isValidPathname,
12
- resolvePathname,
13
- } from '@docusaurus/utils';
8
+ import {isValidPathname, resolvePathname} from '@docusaurus/utils';
9
+ import {addLeadingSlash, addTrailingSlash} from '@docusaurus/utils-common';
14
10
  import {
15
11
  DefaultNumberPrefixParser,
16
12
  stripPathNumberPrefixes,
@@ -1,10 +0,0 @@
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
- export declare function getFileLastUpdate(filePath: string): Promise<{
8
- timestamp: number;
9
- author: string;
10
- } | null>;
package/lib/lastUpdate.js DELETED
@@ -1,47 +0,0 @@
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.getFileLastUpdate = void 0;
10
- const tslib_1 = require("tslib");
11
- const logger_1 = tslib_1.__importDefault(require("@docusaurus/logger"));
12
- const utils_1 = require("@docusaurus/utils");
13
- let showedGitRequirementError = false;
14
- let showedFileNotTrackedError = false;
15
- async function getFileLastUpdate(filePath) {
16
- if (!filePath) {
17
- return null;
18
- }
19
- // Wrap in try/catch in case the shell commands fail
20
- // (e.g. project doesn't use Git, etc).
21
- try {
22
- const result = (0, utils_1.getFileCommitDate)(filePath, {
23
- age: 'newest',
24
- includeAuthor: true,
25
- });
26
- return { timestamp: result.timestamp, author: result.author };
27
- }
28
- catch (err) {
29
- if (err instanceof utils_1.GitNotFoundError) {
30
- if (!showedGitRequirementError) {
31
- logger_1.default.warn('Sorry, the docs plugin last update options require Git.');
32
- showedGitRequirementError = true;
33
- }
34
- }
35
- else if (err instanceof utils_1.FileNotTrackedError) {
36
- if (!showedFileNotTrackedError) {
37
- logger_1.default.warn('Cannot infer the update date for some files, as they are not tracked by git.');
38
- showedFileNotTrackedError = true;
39
- }
40
- }
41
- else {
42
- logger_1.default.warn(err);
43
- }
44
- return null;
45
- }
46
- }
47
- exports.getFileLastUpdate = getFileLastUpdate;
package/src/lastUpdate.ts DELETED
@@ -1,51 +0,0 @@
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 logger from '@docusaurus/logger';
9
- import {
10
- getFileCommitDate,
11
- FileNotTrackedError,
12
- GitNotFoundError,
13
- } from '@docusaurus/utils';
14
-
15
- let showedGitRequirementError = false;
16
- let showedFileNotTrackedError = false;
17
-
18
- export async function getFileLastUpdate(
19
- filePath: string,
20
- ): Promise<{timestamp: number; author: string} | null> {
21
- if (!filePath) {
22
- return null;
23
- }
24
-
25
- // Wrap in try/catch in case the shell commands fail
26
- // (e.g. project doesn't use Git, etc).
27
- try {
28
- const result = getFileCommitDate(filePath, {
29
- age: 'newest',
30
- includeAuthor: true,
31
- });
32
- return {timestamp: result.timestamp, author: result.author};
33
- } catch (err) {
34
- if (err instanceof GitNotFoundError) {
35
- if (!showedGitRequirementError) {
36
- logger.warn('Sorry, the docs plugin last update options require Git.');
37
- showedGitRequirementError = true;
38
- }
39
- } else if (err instanceof FileNotTrackedError) {
40
- if (!showedFileNotTrackedError) {
41
- logger.warn(
42
- 'Cannot infer the update date for some files, as they are not tracked by git.',
43
- );
44
- showedFileNotTrackedError = true;
45
- }
46
- } else {
47
- logger.warn(err);
48
- }
49
- return null;
50
- }
51
- }