@docusaurus/plugin-content-docs 2.0.0-beta.12faed89d → 2.0.0-beta.13

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.
Files changed (138) hide show
  1. package/lib/.tsbuildinfo +1 -1
  2. package/lib/categoryGeneratedIndex.d.ts +12 -0
  3. package/lib/categoryGeneratedIndex.js +37 -0
  4. package/lib/cli.d.ts +2 -2
  5. package/lib/cli.js +12 -34
  6. package/lib/client/docsClientUtils.d.ts +0 -3
  7. package/lib/client/docsClientUtils.js +19 -22
  8. package/lib/docFrontMatter.d.ts +1 -1
  9. package/lib/docFrontMatter.js +7 -3
  10. package/lib/docs.d.ts +25 -3
  11. package/lib/docs.js +125 -41
  12. package/lib/globalData.d.ts +1 -1
  13. package/lib/index.d.ts +1 -1
  14. package/lib/index.js +100 -131
  15. package/lib/lastUpdate.js +8 -9
  16. package/lib/markdown/index.d.ts +3 -6
  17. package/lib/markdown/index.js +3 -3
  18. package/lib/markdown/linkify.js +2 -2
  19. package/lib/numberPrefix.d.ts +1 -1
  20. package/lib/options.d.ts +3 -3
  21. package/lib/options.js +48 -11
  22. package/lib/props.d.ts +7 -2
  23. package/lib/props.js +60 -8
  24. package/lib/routes.d.ts +27 -0
  25. package/lib/routes.js +105 -0
  26. package/lib/{sidebarItemsGenerator.d.ts → sidebars/generator.d.ts} +5 -2
  27. package/lib/sidebars/generator.js +216 -0
  28. package/lib/sidebars/index.d.ts +15 -0
  29. package/lib/sidebars/index.js +73 -0
  30. package/lib/sidebars/normalization.d.ts +14 -0
  31. package/lib/sidebars/normalization.js +77 -0
  32. package/lib/sidebars/processor.d.ts +18 -0
  33. package/lib/sidebars/processor.js +85 -0
  34. package/lib/sidebars/types.d.ts +127 -0
  35. package/lib/sidebars/types.js +8 -0
  36. package/lib/sidebars/utils.d.ts +35 -0
  37. package/lib/sidebars/utils.js +228 -0
  38. package/lib/sidebars/validation.d.ts +10 -0
  39. package/lib/sidebars/validation.js +138 -0
  40. package/lib/slug.d.ts +4 -3
  41. package/lib/slug.js +27 -15
  42. package/lib/tags.d.ts +8 -0
  43. package/lib/tags.js +20 -0
  44. package/lib/theme/hooks/useDocs.js +21 -21
  45. package/lib/translations.d.ts +2 -2
  46. package/lib/translations.js +71 -29
  47. package/lib/types.d.ts +52 -63
  48. package/lib/versions.d.ts +3 -3
  49. package/lib/versions.js +41 -22
  50. package/package.json +20 -20
  51. package/src/__tests__/__fixtures__/simple-site/docs/_partials/somePartial.md +3 -0
  52. package/src/__tests__/__fixtures__/simple-site/docs/_partials/subfolder/somePartial.md +3 -0
  53. package/src/__tests__/__fixtures__/simple-site/docs/_somePartial.md +3 -0
  54. package/src/__tests__/__fixtures__/simple-site/docs/foo/baz.md +5 -0
  55. package/src/__tests__/__fixtures__/simple-site/docs/hello.md +2 -0
  56. package/src/__tests__/__fixtures__/simple-site/docs/rootAbsoluteSlug.md +2 -0
  57. package/src/__tests__/__fixtures__/simple-site/docs/rootRelativeSlug.md +2 -0
  58. package/src/__tests__/__fixtures__/simple-site/docs/rootResolvedSlug.md +2 -0
  59. package/src/__tests__/__fixtures__/simple-site/docs/rootTryToEscapeSlug.md +2 -0
  60. package/src/__tests__/__fixtures__/simple-site/sidebars.json +15 -1
  61. package/src/__tests__/__fixtures__/site-with-doc-label/docs/hello-1.md +1 -0
  62. package/src/__tests__/__fixtures__/versioned-site/docs/foo/bar.md +6 -0
  63. package/src/__tests__/__fixtures__/versioned-site/docs/hello.md +3 -0
  64. package/src/__tests__/__fixtures__/versioned-site/i18n/en/docusaurus-plugin-content-docs/version-1.0.0/hello.md +3 -0
  65. package/src/__tests__/__fixtures__/versioned-site/i18n/fr/docusaurus-plugin-content-docs/version-1.0.0/hello.md +3 -0
  66. package/src/__tests__/__fixtures__/versioned-site/versioned_docs/version-1.0.0/hello.md +3 -0
  67. package/src/__tests__/__fixtures__/versioned-site/versioned_docs/version-1.0.1/_partials/somePartial.md +3 -0
  68. package/src/__tests__/__fixtures__/versioned-site/versioned_docs/version-1.0.1/_partials/subfolder/somePartial.md +3 -0
  69. package/src/__tests__/__fixtures__/versioned-site/versioned_docs/version-1.0.1/_somePartial.md +3 -0
  70. package/src/__tests__/__fixtures__/versioned-site/versioned_docs/version-1.0.1/hello.md +3 -0
  71. package/src/__tests__/__fixtures__/versioned-site/versioned_sidebars/version-1.0.1-sidebars.json +2 -2
  72. package/src/__tests__/__snapshots__/cli.test.ts.snap +48 -73
  73. package/src/__tests__/__snapshots__/docs.test.ts.snap +140 -0
  74. package/src/__tests__/__snapshots__/index.test.ts.snap +745 -97
  75. package/src/__tests__/__snapshots__/translations.test.ts.snap +45 -15
  76. package/src/__tests__/cli.test.ts +15 -11
  77. package/src/__tests__/docFrontMatter.test.ts +160 -45
  78. package/src/__tests__/docs.test.ts +311 -150
  79. package/src/__tests__/index.test.ts +108 -66
  80. package/src/__tests__/lastUpdate.test.ts +1 -1
  81. package/src/__tests__/options.test.ts +48 -3
  82. package/src/__tests__/props.test.ts +62 -0
  83. package/src/__tests__/slug.test.ts +127 -20
  84. package/src/__tests__/translations.test.ts +7 -1
  85. package/src/__tests__/versions.test.ts +73 -70
  86. package/src/categoryGeneratedIndex.ts +57 -0
  87. package/src/cli.ts +8 -41
  88. package/src/client/docsClientUtils.ts +14 -26
  89. package/{types.d.ts → src/deps.d.ts} +0 -0
  90. package/src/docFrontMatter.ts +9 -4
  91. package/src/docs.ts +158 -32
  92. package/src/globalData.ts +6 -1
  93. package/src/index.ts +125 -169
  94. package/src/lastUpdate.ts +10 -13
  95. package/src/markdown/index.ts +8 -12
  96. package/src/numberPrefix.ts +5 -3
  97. package/src/options.ts +59 -14
  98. package/src/plugin-content-docs.d.ts +173 -40
  99. package/src/props.ts +90 -15
  100. package/src/routes.ts +173 -0
  101. package/src/{__tests__ → sidebars/__tests__}/__fixtures__/sidebars/sidebars-category-shorthand.js +0 -0
  102. package/src/{__tests__ → sidebars/__tests__}/__fixtures__/sidebars/sidebars-category-wrong-items.json +0 -0
  103. package/src/{__tests__ → sidebars/__tests__}/__fixtures__/sidebars/sidebars-category-wrong-label.json +0 -0
  104. package/src/{__tests__ → sidebars/__tests__}/__fixtures__/sidebars/sidebars-category.js +0 -0
  105. package/src/{__tests__ → sidebars/__tests__}/__fixtures__/sidebars/sidebars-collapsed-first-level.json +0 -0
  106. package/src/{__tests__ → sidebars/__tests__}/__fixtures__/sidebars/sidebars-collapsed.json +0 -0
  107. package/src/{__tests__ → sidebars/__tests__}/__fixtures__/sidebars/sidebars-doc-id-not-string.json +0 -0
  108. package/src/{__tests__ → sidebars/__tests__}/__fixtures__/sidebars/sidebars-first-level-not-category.js +0 -0
  109. package/src/{__tests__ → sidebars/__tests__}/__fixtures__/sidebars/sidebars-link-wrong-href.json +0 -0
  110. package/src/{__tests__ → sidebars/__tests__}/__fixtures__/sidebars/sidebars-link-wrong-label.json +0 -0
  111. package/src/{__tests__ → sidebars/__tests__}/__fixtures__/sidebars/sidebars-link.json +0 -0
  112. package/src/{__tests__ → sidebars/__tests__}/__fixtures__/sidebars/sidebars-unknown-type.json +0 -0
  113. package/src/{__tests__ → sidebars/__tests__}/__fixtures__/sidebars/sidebars-wrong-field.json +0 -0
  114. package/src/{__tests__ → sidebars/__tests__}/__fixtures__/sidebars/sidebars.json +0 -0
  115. package/src/{__tests__/__snapshots__/sidebars.test.ts.snap → sidebars/__tests__/__snapshots__/index.test.ts.snap} +36 -6
  116. package/src/{__tests__/sidebarItemsGenerator.test.ts → sidebars/__tests__/generator.test.ts} +143 -18
  117. package/src/sidebars/__tests__/index.test.ts +204 -0
  118. package/src/sidebars/__tests__/processor.test.ts +237 -0
  119. package/src/sidebars/__tests__/utils.test.ts +695 -0
  120. package/src/sidebars/__tests__/validation.test.ts +105 -0
  121. package/src/sidebars/generator.ts +310 -0
  122. package/src/sidebars/index.ts +94 -0
  123. package/src/sidebars/normalization.ts +112 -0
  124. package/src/sidebars/processor.ts +154 -0
  125. package/src/sidebars/types.ts +211 -0
  126. package/src/sidebars/utils.ts +329 -0
  127. package/src/sidebars/validation.ts +168 -0
  128. package/src/slug.ts +32 -17
  129. package/src/tags.ts +19 -0
  130. package/src/translations.ts +103 -47
  131. package/src/types.ts +64 -107
  132. package/src/versions.ts +59 -25
  133. package/lib/sidebarItemsGenerator.js +0 -211
  134. package/lib/sidebars.d.ts +0 -43
  135. package/lib/sidebars.js +0 -320
  136. package/src/__tests__/sidebars.test.ts +0 -639
  137. package/src/sidebarItemsGenerator.ts +0 -307
  138. package/src/sidebars.ts +0 -522
package/src/index.ts CHANGED
@@ -7,10 +7,6 @@
7
7
 
8
8
  import path from 'path';
9
9
 
10
- import {
11
- STATIC_DIR_NAME,
12
- DEFAULT_PLUGIN_ID,
13
- } from '@docusaurus/core/lib/constants';
14
10
  import {
15
11
  normalizeUrl,
16
12
  docuHash,
@@ -18,10 +14,19 @@ import {
18
14
  reportMessage,
19
15
  posixPath,
20
16
  addTrailingPathSeparator,
17
+ createAbsoluteFilePathMatcher,
18
+ createSlugger,
19
+ DEFAULT_PLUGIN_ID,
21
20
  } from '@docusaurus/utils';
22
- import {LoadContext, Plugin, RouteConfig} from '@docusaurus/types';
23
- import {loadSidebars, createSidebarsUtils, processSidebars} from './sidebars';
24
- import {readVersionDocs, processDocMetadata} from './docs';
21
+ import type {LoadContext, Plugin} from '@docusaurus/types';
22
+ import {loadSidebars} from './sidebars';
23
+ import {CategoryMetadataFilenamePattern} from './sidebars/generator';
24
+ import {
25
+ readVersionDocs,
26
+ processDocMetadata,
27
+ addDocNavigation,
28
+ getMainDocId,
29
+ } from './docs';
25
30
  import {getDocsDirPaths, readVersionsMetadata} from './versions';
26
31
 
27
32
  import {
@@ -29,26 +34,29 @@ import {
29
34
  LoadedContent,
30
35
  SourceToPermalink,
31
36
  DocMetadataBase,
32
- DocMetadata,
33
37
  GlobalPluginData,
34
38
  VersionMetadata,
35
- DocNavLink,
36
39
  LoadedVersion,
37
40
  DocFile,
38
41
  DocsMarkdownOption,
42
+ VersionTag,
39
43
  } from './types';
40
- import {RuleSetRule} from 'webpack';
44
+ import type {RuleSetRule} from 'webpack';
41
45
  import {cliDocsVersionCommand} from './cli';
42
46
  import {VERSIONS_JSON_FILE} from './constants';
43
- import {flatten, keyBy, compact, mapValues} from 'lodash';
47
+ import {keyBy, mapValues} from 'lodash';
44
48
  import {toGlobalDataVersion} from './globalData';
45
- import {toVersionMetadataProp} from './props';
49
+ import {toTagDocListProp} from './props';
46
50
  import {
47
51
  translateLoadedContent,
48
52
  getLoadedContentTranslationFiles,
49
53
  } from './translations';
50
- import {CategoryMetadataFilenamePattern} from './sidebarItemsGenerator';
51
54
  import chalk from 'chalk';
55
+ import {getVersionTags} from './tags';
56
+ import {createVersionRoutes} from './routes';
57
+ import type {PropTagsListPage} from '@docusaurus/plugin-content-docs';
58
+ import {createSidebarsUtils} from './sidebars/utils';
59
+ import {getCategoryGeneratedIndexMetadataList} from './categoryGeneratedIndex';
52
60
 
53
61
  export default function pluginContentDocs(
54
62
  context: LoadContext,
@@ -99,6 +107,8 @@ export default function pluginContentDocs(
99
107
  cliDocsVersionCommand(version, siteDir, pluginId, {
100
108
  path: options.path,
101
109
  sidebarPath: options.sidebarPath,
110
+ sidebarCollapsed: options.sidebarCollapsed,
111
+ sidebarCollapsible: options.sidebarCollapsible,
102
112
  });
103
113
  });
104
114
  },
@@ -107,22 +117,12 @@ export default function pluginContentDocs(
107
117
  return getLoadedContentTranslationFiles(content);
108
118
  },
109
119
 
110
- getClientModules() {
111
- const modules = [];
112
- if (options.admonitions) {
113
- modules.push(require.resolve('remark-admonitions/styles/infima.css'));
114
- }
115
- return modules;
116
- },
117
-
118
120
  getPathsToWatch() {
119
121
  function getVersionPathsToWatch(version: VersionMetadata): string[] {
120
122
  const result = [
121
- ...flatten(
122
- options.include.map((pattern) =>
123
- getDocsDirPaths(version).map(
124
- (docsDirPath) => `${docsDirPath}/${pattern}`,
125
- ),
123
+ ...options.include.flatMap((pattern) =>
124
+ getDocsDirPaths(version).map(
125
+ (docsDirPath) => `${docsDirPath}/${pattern}`,
126
126
  ),
127
127
  ),
128
128
  `${version.contentPath}/**/${CategoryMetadataFilenamePattern}`,
@@ -133,7 +133,7 @@ export default function pluginContentDocs(
133
133
  return result;
134
134
  }
135
135
 
136
- return flatten(versionsMetadata.map(getVersionPathsToWatch));
136
+ return versionsMetadata.flatMap(getVersionPathsToWatch);
137
137
  },
138
138
 
139
139
  async loadContent() {
@@ -165,89 +165,37 @@ export default function pluginContentDocs(
165
165
  async function doLoadVersion(
166
166
  versionMetadata: VersionMetadata,
167
167
  ): Promise<LoadedVersion> {
168
- const unprocessedSidebars = loadSidebars(
169
- versionMetadata.sidebarFilePath,
170
- );
171
-
172
- const docsBase: DocMetadataBase[] = await loadVersionDocsBase(
168
+ const docs: DocMetadataBase[] = await loadVersionDocsBase(
173
169
  versionMetadata,
174
170
  );
175
- const docsBaseById: Record<string, DocMetadataBase> = keyBy(
176
- docsBase,
177
- (doc) => doc.id,
178
- );
179
171
 
180
- const sidebars = await processSidebars({
172
+ const sidebars = await loadSidebars(versionMetadata.sidebarFilePath, {
181
173
  sidebarItemsGenerator: options.sidebarItemsGenerator,
182
174
  numberPrefixParser: options.numberPrefixParser,
183
- unprocessedSidebars,
184
- docs: docsBase,
175
+ docs,
185
176
  version: versionMetadata,
177
+ sidebarOptions: {
178
+ sidebarCollapsed: options.sidebarCollapsed,
179
+ sidebarCollapsible: options.sidebarCollapsible,
180
+ },
181
+ categoryLabelSlugger: createSlugger(),
186
182
  });
187
183
 
188
184
  const sidebarsUtils = createSidebarsUtils(sidebars);
189
185
 
190
- const validDocIds = Object.keys(docsBaseById);
191
- sidebarsUtils.checkSidebarsDocIds(
192
- validDocIds,
193
- versionMetadata.sidebarFilePath as string,
194
- );
195
-
196
- // Add sidebar/next/previous to the docs
197
- function addNavData(doc: DocMetadataBase): DocMetadata {
198
- const {
199
- sidebarName,
200
- previousId,
201
- nextId,
202
- } = sidebarsUtils.getDocNavigation(doc.id);
203
- const toDocNavLink = (navDocId: string): DocNavLink => {
204
- const {title, permalink, frontMatter} = docsBaseById[navDocId];
205
- return {
206
- title:
207
- frontMatter.pagination_label ??
208
- frontMatter.sidebar_label ??
209
- title,
210
- permalink,
211
- };
212
- };
213
- return {
214
- ...doc,
215
- sidebar: sidebarName,
216
- previous: previousId ? toDocNavLink(previousId) : undefined,
217
- next: nextId ? toDocNavLink(nextId) : undefined,
218
- };
219
- }
220
-
221
- const docs = docsBase.map(addNavData);
222
-
223
- // sort to ensure consistent output for tests
224
- docs.sort((a, b) => a.id.localeCompare(b.id));
225
-
226
- // The "main doc" is the "version entry point"
227
- // We browse this doc by clicking on a version:
228
- // - the "home" doc (at '/docs/')
229
- // - the first doc of the first sidebar
230
- // - a random doc (if no docs are in any sidebar... edge case)
231
- function getMainDoc(): DocMetadata {
232
- const versionHomeDoc = docs.find(
233
- (doc) =>
234
- doc.unversionedId === options.homePageId || doc.slug === '/',
235
- );
236
- const firstDocIdOfFirstSidebar = sidebarsUtils.getFirstDocIdOfFirstSidebar();
237
- if (versionHomeDoc) {
238
- return versionHomeDoc;
239
- } else if (firstDocIdOfFirstSidebar) {
240
- return docs.find((doc) => doc.id === firstDocIdOfFirstSidebar)!;
241
- } else {
242
- return docs[0];
243
- }
244
- }
245
-
246
186
  return {
247
187
  ...versionMetadata,
248
- mainDocId: getMainDoc().unversionedId,
188
+ docs: addDocNavigation(
189
+ docs,
190
+ sidebarsUtils,
191
+ versionMetadata.sidebarFilePath as string,
192
+ ),
249
193
  sidebars,
250
- docs: docs.map(addNavData),
194
+ mainDocId: getMainDocId({docs, sidebarsUtils}),
195
+ categoryGeneratedIndices: getCategoryGeneratedIndexMetadataList({
196
+ docs,
197
+ sidebarsUtils,
198
+ }),
251
199
  };
252
200
  }
253
201
 
@@ -275,84 +223,84 @@ export default function pluginContentDocs(
275
223
 
276
224
  async contentLoaded({content, actions}) {
277
225
  const {loadedVersions} = content;
278
- const {docLayoutComponent, docItemComponent} = options;
226
+ const {
227
+ docLayoutComponent,
228
+ docItemComponent,
229
+ docCategoryGeneratedIndexComponent,
230
+ } = options;
279
231
  const {addRoute, createData, setGlobalData} = actions;
280
232
 
281
- const createDocRoutes = async (
282
- docs: DocMetadata[],
283
- ): Promise<RouteConfig[]> => {
284
- const routes = await Promise.all(
285
- docs.map(async (metadataItem) => {
286
- await createData(
287
- // Note that this created data path must be in sync with
288
- // metadataPath provided to mdx-loader.
289
- `${docuHash(metadataItem.source)}.json`,
290
- JSON.stringify(metadataItem, null, 2),
233
+ async function createVersionTagsRoutes(version: LoadedVersion) {
234
+ const versionTags = getVersionTags(version.docs);
235
+
236
+ // TODO tags should be a sub route of the version route
237
+ async function createTagsListPage() {
238
+ const tagsProp: PropTagsListPage['tags'] = Object.values(
239
+ versionTags,
240
+ ).map((tagValue) => ({
241
+ name: tagValue.name,
242
+ permalink: tagValue.permalink,
243
+ count: tagValue.docIds.length,
244
+ }));
245
+
246
+ // Only create /tags page if there are tags.
247
+ if (Object.keys(tagsProp).length > 0) {
248
+ const tagsPropPath = await createData(
249
+ `${docuHash(`tags-list-${version.versionName}-prop`)}.json`,
250
+ JSON.stringify(tagsProp, null, 2),
291
251
  );
292
-
293
- const docRoute: RouteConfig = {
294
- path: metadataItem.permalink,
295
- component: docItemComponent,
252
+ addRoute({
253
+ path: version.tagsPath,
296
254
  exact: true,
255
+ component: options.docTagsListComponent,
297
256
  modules: {
298
- content: metadataItem.source,
257
+ tags: aliasedSource(tagsPropPath),
299
258
  },
300
- // Because the parent (DocPage) comp need to access it easily
301
- // This permits to render the sidebar once without unmount/remount when navigating (and preserve sidebar state)
302
- ...(metadataItem.sidebar && {
303
- sidebar: metadataItem.sidebar,
304
- }),
305
- };
306
-
307
- return docRoute;
308
- }),
309
- );
310
-
311
- return routes.sort((a, b) => a.path.localeCompare(b.path));
312
- };
313
-
314
- async function doCreateVersionRoutes(
315
- loadedVersion: LoadedVersion,
316
- ): Promise<void> {
317
- const versionMetadata = toVersionMetadataProp(pluginId, loadedVersion);
318
- const versionMetadataPropPath = await createData(
319
- `${docuHash(
320
- `version-${loadedVersion.versionName}-metadata-prop`,
321
- )}.json`,
322
- JSON.stringify(versionMetadata, null, 2),
323
- );
324
-
325
- addRoute({
326
- path: loadedVersion.versionPath,
327
- // allow matching /docs/* as well
328
- exact: false,
329
- // main docs component (DocPage)
330
- component: docLayoutComponent,
331
- // sub-routes for each doc
332
- routes: await createDocRoutes(loadedVersion.docs),
333
- modules: {
334
- versionMetadata: aliasedSource(versionMetadataPropPath),
335
- },
336
- priority: loadedVersion.routePriority,
337
- });
338
- }
259
+ });
260
+ }
261
+ }
339
262
 
340
- async function createVersionRoutes(
341
- loadedVersion: LoadedVersion,
342
- ): Promise<void> {
343
- try {
344
- return await doCreateVersionRoutes(loadedVersion);
345
- } catch (e) {
346
- console.error(
347
- chalk.red(
348
- `Can't create version routes for version "${loadedVersion.versionName}"`,
349
- ),
263
+ // TODO tags should be a sub route of the version route
264
+ async function createTagDocListPage(tag: VersionTag) {
265
+ const tagProps = toTagDocListProp({
266
+ allTagsPath: version.tagsPath,
267
+ tag,
268
+ docs: version.docs,
269
+ });
270
+ const tagPropPath = await createData(
271
+ `${docuHash(`tag-${tag.permalink}`)}.json`,
272
+ JSON.stringify(tagProps, null, 2),
350
273
  );
351
- throw e;
274
+ addRoute({
275
+ path: tag.permalink,
276
+ component: options.docTagDocListComponent,
277
+ exact: true,
278
+ modules: {
279
+ tag: aliasedSource(tagPropPath),
280
+ },
281
+ });
352
282
  }
283
+
284
+ await createTagsListPage();
285
+ await Promise.all(Object.values(versionTags).map(createTagDocListPage));
353
286
  }
354
287
 
355
- await Promise.all(loadedVersions.map(createVersionRoutes));
288
+ await Promise.all(
289
+ loadedVersions.map((loadedVersion) =>
290
+ createVersionRoutes({
291
+ loadedVersion,
292
+ docItemComponent,
293
+ docLayoutComponent,
294
+ docCategoryGeneratedIndexComponent,
295
+ pluginId,
296
+ aliasedSource,
297
+ actions,
298
+ }),
299
+ ),
300
+ );
301
+
302
+ // TODO tags should be a sub route of the version route
303
+ await Promise.all(loadedVersions.map(createVersionTagsRoutes));
356
304
 
357
305
  setGlobalData<GlobalPluginData>({
358
306
  path: normalizeUrl([baseUrl, options.routeBasePath]),
@@ -370,7 +318,7 @@ export default function pluginContentDocs(
370
318
  } = options;
371
319
 
372
320
  function getSourceToPermalink(): SourceToPermalink {
373
- const allDocs = flatten(content.loadedVersions.map((v) => v.docs));
321
+ const allDocs = content.loadedVersions.flatMap((v) => v.docs);
374
322
  return mapValues(
375
323
  keyBy(allDocs, (d) => d.source),
376
324
  (d) => d.permalink,
@@ -393,12 +341,13 @@ export default function pluginContentDocs(
393
341
  };
394
342
 
395
343
  function createMDXLoaderRule(): RuleSetRule {
344
+ const contentDirs = versionsMetadata.flatMap(getDocsDirPaths);
396
345
  return {
397
346
  test: /(\.mdx?)$/,
398
- include: flatten(versionsMetadata.map(getDocsDirPaths))
347
+ include: contentDirs
399
348
  // Trailing slash is important, see https://github.com/facebook/docusaurus/pull/3970
400
349
  .map(addTrailingPathSeparator),
401
- use: compact([
350
+ use: [
402
351
  getJSLoader({isServer}),
403
352
  {
404
353
  loader: require.resolve('@docusaurus/mdx-loader'),
@@ -407,7 +356,14 @@ export default function pluginContentDocs(
407
356
  rehypePlugins,
408
357
  beforeDefaultRehypePlugins,
409
358
  beforeDefaultRemarkPlugins,
410
- staticDir: path.join(siteDir, STATIC_DIR_NAME),
359
+ staticDirs: siteConfig.staticDirectories.map((dir) =>
360
+ path.resolve(siteDir, dir),
361
+ ),
362
+ siteDir,
363
+ isMDXPartial: createAbsoluteFilePathMatcher(
364
+ options.exclude,
365
+ contentDirs,
366
+ ),
411
367
  metadataPath: (mdxPath: string) => {
412
368
  // Note that metadataPath must be the same/in-sync as
413
369
  // the path from createData for each MDX.
@@ -420,7 +376,7 @@ export default function pluginContentDocs(
420
376
  loader: path.resolve(__dirname, './markdown/index.js'),
421
377
  options: docsMarkdownOptions,
422
378
  },
423
- ]),
379
+ ].filter(Boolean),
424
380
  };
425
381
  }
426
382
 
package/src/lastUpdate.ts CHANGED
@@ -6,12 +6,10 @@
6
6
  */
7
7
 
8
8
  import shell from 'shelljs';
9
- import execa from 'execa';
10
- import path from 'path';
11
9
 
12
10
  type FileLastUpdateData = {timestamp?: number; author?: string};
13
11
 
14
- const GIT_COMMIT_TIMESTAMP_AUTHOR_REGEX = /^(\d+), (.+)$/;
12
+ const GIT_COMMIT_TIMESTAMP_AUTHOR_REGEX = /^(\d+),(.+)$/;
15
13
 
16
14
  let showedGitRequirementError = false;
17
15
 
@@ -44,16 +42,15 @@ export async function getFileLastUpdate(
44
42
  return null;
45
43
  }
46
44
 
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
- );
56
- return getTimestampAndAuthor(stdout);
45
+ const result = shell.exec(`git log -1 --format=%ct,%an ${filePath}`, {
46
+ silent: true,
47
+ });
48
+ if (result.code !== 0) {
49
+ throw new Error(
50
+ `Retrieval of git history failed at ${filePath} with exit code ${result.code}: ${result.stderr}`,
51
+ );
52
+ }
53
+ return getTimestampAndAuthor(result.stdout.trim());
57
54
  } catch (error) {
58
55
  console.error(error);
59
56
  }
@@ -7,20 +7,16 @@
7
7
 
8
8
  import {linkify} from './linkify';
9
9
  import {DocsMarkdownOption} from '../types';
10
+ import type {LoaderContext} from 'webpack';
10
11
 
11
- // TODO temporary until Webpack5 export this type
12
- // see https://github.com/webpack/webpack/issues/11630
13
- interface Loader extends Function {
14
- (this: any, source: string): string | Buffer | void | undefined;
15
- }
16
-
17
- const markdownLoader: Loader = function (source) {
18
- const fileString = source as string;
12
+ export default function markdownLoader(
13
+ this: LoaderContext<DocsMarkdownOption>,
14
+ source: string,
15
+ ): void {
16
+ const fileString = source;
19
17
  const callback = this.async();
20
- const options = this.getOptions() as DocsMarkdownOption;
18
+ const options = this.getOptions();
21
19
  return (
22
20
  callback && callback(null, linkify(fileString, this.resourcePath, options))
23
21
  );
24
- };
25
-
26
- export default markdownLoader;
22
+ }
@@ -5,12 +5,13 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
 
8
- import {NumberPrefixParser} from './types';
8
+ import type {NumberPrefixParser} from './types';
9
9
 
10
10
  // Best-effort to avoid parsing some patterns as number prefix
11
11
  const IgnoredPrefixPatterns = (function () {
12
12
  // ignore common date-like patterns: https://github.com/facebook/docusaurus/issues/4640
13
- const DateLikePrefixRegex = /^((\d{2}|\d{4})[-_.]\d{2}([-_.](\d{2}|\d{4}))?)(.*)$/;
13
+ const DateLikePrefixRegex =
14
+ /^((\d{2}|\d{4})[-_.]\d{2}([-_.](\d{2}|\d{4}))?)(.*)$/;
14
15
 
15
16
  // ignore common versioning patterns: https://github.com/facebook/docusaurus/issues/4653
16
17
  // note: we could try to parse float numbers in filenames but that is probably not worth it
@@ -23,7 +24,8 @@ const IgnoredPrefixPatterns = (function () {
23
24
  );
24
25
  })();
25
26
 
26
- const NumberPrefixRegex = /^(?<numberPrefix>\d+)(?<separator>\s*[-_.]+\s*)(?<suffix>.*)$/;
27
+ const NumberPrefixRegex =
28
+ /^(?<numberPrefix>\d+)(?<separator>\s*[-_.]+\s*)(?<suffix>.*)$/;
27
29
 
28
30
  // 0-myDoc => {filename: myDoc, numberPrefix: 0}
29
31
  // 003 - myDoc => {filename: myDoc, numberPrefix: 3}
package/src/options.ts CHANGED
@@ -4,7 +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
- import {PluginOptions} from './types';
7
+
8
+ import type {PluginOptions} from './types';
8
9
  import {
9
10
  Joi,
10
11
  RemarkPluginsSchema,
@@ -12,10 +13,15 @@ import {
12
13
  AdmonitionsSchema,
13
14
  URISchema,
14
15
  } from '@docusaurus/utils-validation';
15
- import {OptionValidationContext, ValidationResult} from '@docusaurus/types';
16
+ import {GlobExcludeDefault} from '@docusaurus/utils';
17
+
18
+ import type {
19
+ OptionValidationContext,
20
+ ValidationResult,
21
+ } from '@docusaurus/types';
16
22
  import chalk from 'chalk';
17
23
  import admonitions from 'remark-admonitions';
18
- import {DefaultSidebarItemsGenerator} from './sidebarItemsGenerator';
24
+ import {DefaultSidebarItemsGenerator} from './sidebars/generator';
19
25
  import {
20
26
  DefaultNumberPrefixParser,
21
27
  DisabledNumberPrefixParser,
@@ -24,12 +30,16 @@ import {
24
30
  export const DEFAULT_OPTIONS: Omit<PluginOptions, 'id' | 'sidebarPath'> = {
25
31
  path: 'docs', // Path to data on filesystem, relative to site dir.
26
32
  routeBasePath: 'docs', // URL Route.
27
- homePageId: undefined, // TODO remove soon, deprecated
33
+ tagsBasePath: 'tags', // URL Tags Route.
28
34
  include: ['**/*.{md,mdx}'], // Extensions to include.
35
+ exclude: GlobExcludeDefault,
29
36
  sidebarItemsGenerator: DefaultSidebarItemsGenerator,
30
37
  numberPrefixParser: DefaultNumberPrefixParser,
31
38
  docLayoutComponent: '@theme/DocPage',
32
39
  docItemComponent: '@theme/DocItem',
40
+ docTagDocListComponent: '@theme/DocTagDocListPage',
41
+ docTagsListComponent: '@theme/DocTagsListPage',
42
+ docCategoryGeneratedIndexComponent: '@theme/DocCategoryGeneratedIndexPage',
33
43
  remarkPlugins: [],
34
44
  rehypePlugins: [],
35
45
  beforeDefaultRemarkPlugins: [],
@@ -43,12 +53,16 @@ export const DEFAULT_OPTIONS: Omit<PluginOptions, 'id' | 'sidebarPath'> = {
43
53
  versions: {},
44
54
  editCurrentVersion: false,
45
55
  editLocalizedFiles: false,
56
+ sidebarCollapsible: true,
57
+ sidebarCollapsed: true,
46
58
  };
47
59
 
48
60
  const VersionOptionsSchema = Joi.object({
49
61
  path: Joi.string().allow('').optional(),
50
62
  label: Joi.string().optional(),
51
63
  banner: Joi.string().equal('none', 'unreleased', 'unmaintained').optional(),
64
+ badge: Joi.boolean().optional(),
65
+ className: Joi.string().optional(),
52
66
  });
53
67
 
54
68
  const VersionsOptionsSchema = Joi.object()
@@ -64,8 +78,14 @@ export const OptionsSchema = Joi.object({
64
78
  // '' not allowed, see https://github.com/facebook/docusaurus/issues/3374
65
79
  // .allow('') ""
66
80
  .default(DEFAULT_OPTIONS.routeBasePath),
67
- homePageId: Joi.string().optional(),
81
+ tagsBasePath: Joi.string().default(DEFAULT_OPTIONS.tagsBasePath),
82
+ homePageId: Joi.any().forbidden().messages({
83
+ 'any.unknown':
84
+ 'The docs plugin option homePageId is not supported anymore. To make a doc the "home", please add "slug: /" in its front matter. See: https://docusaurus.io/docs/next/docs-introduction#home-page-docs',
85
+ }),
86
+
68
87
  include: Joi.array().items(Joi.string()).default(DEFAULT_OPTIONS.include),
88
+ exclude: Joi.array().items(Joi.string()).default(DEFAULT_OPTIONS.exclude),
69
89
  sidebarPath: Joi.alternatives().try(
70
90
  Joi.boolean().invalid(true),
71
91
  Joi.string(),
@@ -73,6 +93,8 @@ export const OptionsSchema = Joi.object({
73
93
  sidebarItemsGenerator: Joi.function().default(
74
94
  () => DEFAULT_OPTIONS.sidebarItemsGenerator,
75
95
  ),
96
+ sidebarCollapsible: Joi.boolean().default(DEFAULT_OPTIONS.sidebarCollapsible),
97
+ sidebarCollapsed: Joi.boolean().default(DEFAULT_OPTIONS.sidebarCollapsed),
76
98
  numberPrefixParser: Joi.alternatives()
77
99
  .try(
78
100
  Joi.function(),
@@ -86,6 +108,15 @@ export const OptionsSchema = Joi.object({
86
108
  .default(() => DEFAULT_OPTIONS.numberPrefixParser),
87
109
  docLayoutComponent: Joi.string().default(DEFAULT_OPTIONS.docLayoutComponent),
88
110
  docItemComponent: Joi.string().default(DEFAULT_OPTIONS.docItemComponent),
111
+ docTagsListComponent: Joi.string().default(
112
+ DEFAULT_OPTIONS.docTagsListComponent,
113
+ ),
114
+ docTagDocListComponent: Joi.string().default(
115
+ DEFAULT_OPTIONS.docTagDocListComponent,
116
+ ),
117
+ docCategoryGeneratedIndexComponent: Joi.string().default(
118
+ DEFAULT_OPTIONS.docCategoryGeneratedIndexComponent,
119
+ ),
89
120
  remarkPlugins: RemarkPluginsSchema.default(DEFAULT_OPTIONS.remarkPlugins),
90
121
  rehypePlugins: RehypePluginsSchema.default(DEFAULT_OPTIONS.rehypePlugins),
91
122
  beforeDefaultRemarkPlugins: RemarkPluginsSchema.default(
@@ -112,16 +143,30 @@ export const OptionsSchema = Joi.object({
112
143
 
113
144
  export function validateOptions({
114
145
  validate,
115
- options,
146
+ options: userOptions,
116
147
  }: OptionValidationContext<PluginOptions>): ValidationResult<PluginOptions> {
117
- // TODO remove homePageId before end of 2020
118
- // "slug: /" is better because the home doc can be different across versions
119
- if (options.homePageId) {
120
- console.log(
121
- chalk.red(
122
- `The docs plugin option homePageId=${options.homePageId} is deprecated. To make a doc the "home", prefer frontmatter: "slug: /"`,
123
- ),
124
- );
148
+ let options = userOptions;
149
+
150
+ if (options.sidebarCollapsible === false) {
151
+ // When sidebarCollapsible=false and sidebarCollapsed=undefined, we don't want to have the inconsistency warning
152
+ // We let options.sidebarCollapsible become the default value for options.sidebarCollapsed
153
+ if (typeof options.sidebarCollapsed === 'undefined') {
154
+ options = {
155
+ ...options,
156
+ sidebarCollapsed: false,
157
+ };
158
+ }
159
+ if (options.sidebarCollapsed) {
160
+ console.warn(
161
+ chalk.yellow(
162
+ 'The docs plugin config is inconsistent. It does not make sense to use sidebarCollapsible=false and sidebarCollapsed=true at the same time. sidebarCollapsed=false will be ignored.',
163
+ ),
164
+ );
165
+ options = {
166
+ ...options,
167
+ sidebarCollapsed: false,
168
+ };
169
+ }
125
170
  }
126
171
 
127
172
  const normalizedOptions = validate(OptionsSchema, options);