@docusaurus/plugin-content-docs 0.0.0-4238 → 0.0.0-4243

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 (62) 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.js +5 -23
  5. package/lib/docs.d.ts +22 -2
  6. package/lib/docs.js +71 -29
  7. package/lib/index.js +34 -62
  8. package/lib/options.js +2 -0
  9. package/lib/props.js +35 -6
  10. package/lib/routes.d.ts +27 -0
  11. package/lib/routes.js +105 -0
  12. package/lib/sidebars/generator.d.ts +2 -1
  13. package/lib/sidebars/generator.js +55 -13
  14. package/lib/sidebars/index.d.ts +5 -4
  15. package/lib/sidebars/index.js +18 -9
  16. package/lib/sidebars/normalization.d.ts +8 -3
  17. package/lib/sidebars/normalization.js +36 -17
  18. package/lib/sidebars/processor.d.ts +5 -3
  19. package/lib/sidebars/processor.js +33 -18
  20. package/lib/sidebars/types.d.ts +43 -2
  21. package/lib/sidebars/utils.d.ts +18 -6
  22. package/lib/sidebars/utils.js +149 -24
  23. package/lib/sidebars/validation.d.ts +2 -0
  24. package/lib/sidebars/validation.js +44 -8
  25. package/lib/slug.d.ts +4 -3
  26. package/lib/slug.js +26 -14
  27. package/lib/translations.js +51 -7
  28. package/lib/types.d.ts +18 -3
  29. package/package.json +8 -8
  30. package/src/__tests__/__fixtures__/versioned-site/versioned_sidebars/version-1.0.1-sidebars.json +2 -2
  31. package/src/__tests__/__snapshots__/cli.test.ts.snap +48 -106
  32. package/src/__tests__/__snapshots__/index.test.ts.snap +279 -28
  33. package/src/__tests__/__snapshots__/translations.test.ts.snap +45 -0
  34. package/src/__tests__/docs.test.ts +122 -7
  35. package/src/__tests__/index.test.ts +27 -1
  36. package/src/__tests__/options.test.ts +2 -0
  37. package/src/__tests__/slug.test.ts +127 -20
  38. package/src/__tests__/translations.test.ts +7 -0
  39. package/src/categoryGeneratedIndex.ts +57 -0
  40. package/src/cli.ts +5 -35
  41. package/src/docs.ts +103 -45
  42. package/src/index.ts +55 -93
  43. package/src/options.ts +4 -0
  44. package/src/plugin-content-docs.d.ts +71 -8
  45. package/src/props.ts +48 -9
  46. package/src/routes.ts +173 -0
  47. package/src/sidebars/__tests__/__snapshots__/index.test.ts.snap +21 -6
  48. package/src/sidebars/__tests__/generator.test.ts +105 -1
  49. package/src/sidebars/__tests__/index.test.ts +26 -24
  50. package/src/sidebars/__tests__/processor.test.ts +110 -19
  51. package/src/sidebars/__tests__/utils.test.ts +320 -20
  52. package/src/sidebars/__tests__/validation.test.ts +105 -0
  53. package/src/sidebars/generator.ts +82 -19
  54. package/src/sidebars/index.ts +23 -13
  55. package/src/sidebars/normalization.ts +47 -23
  56. package/src/sidebars/processor.ts +57 -27
  57. package/src/sidebars/types.ts +64 -3
  58. package/src/sidebars/utils.ts +217 -42
  59. package/src/sidebars/validation.ts +52 -8
  60. package/src/slug.ts +32 -17
  61. package/src/translations.ts +74 -8
  62. package/src/types.ts +22 -5
@@ -8,11 +8,12 @@
8
8
  import fs from 'fs-extra';
9
9
  import importFresh from 'import-fresh';
10
10
  import type {SidebarsConfig, Sidebars, NormalizedSidebars} from './types';
11
- import type {PluginOptions} from '../types';
11
+ import type {NormalizeSidebarsParams, PluginOptions} from '../types';
12
12
  import {validateSidebars} from './validation';
13
13
  import {normalizeSidebars} from './normalization';
14
- import {processSidebars, SidebarProcessorProps} from './processor';
14
+ import {processSidebars, SidebarProcessorParams} from './processor';
15
15
  import path from 'path';
16
+ import {createSlugger} from '@docusaurus/utils';
16
17
 
17
18
  export const DefaultSidebars: SidebarsConfig = {
18
19
  defaultSidebar: [
@@ -36,7 +37,7 @@ export function resolveSidebarPathOption(
36
37
  : sidebarPathOption;
37
38
  }
38
39
 
39
- function loadSidebarFile(
40
+ function loadSidebarsFileUnsafe(
40
41
  sidebarFilePath: string | false | undefined,
41
42
  ): SidebarsConfig {
42
43
  // false => no sidebars
@@ -60,25 +61,34 @@ function loadSidebarFile(
60
61
  return importFresh(sidebarFilePath);
61
62
  }
62
63
 
63
- export function loadUnprocessedSidebars(
64
+ export function loadSidebarsFile(
64
65
  sidebarFilePath: string | false | undefined,
65
- options: SidebarProcessorProps['options'],
66
- ): NormalizedSidebars {
67
- const sidebarsConfig = loadSidebarFile(sidebarFilePath);
66
+ ): SidebarsConfig {
67
+ const sidebarsConfig = loadSidebarsFileUnsafe(sidebarFilePath);
68
68
  validateSidebars(sidebarsConfig);
69
+ return sidebarsConfig;
70
+ }
69
71
 
70
- const normalizedSidebars = normalizeSidebars(sidebarsConfig, options);
71
- return normalizedSidebars;
72
+ export function loadNormalizedSidebars(
73
+ sidebarFilePath: string | false | undefined,
74
+ params: NormalizeSidebarsParams,
75
+ ): NormalizedSidebars {
76
+ return normalizeSidebars(loadSidebarsFile(sidebarFilePath), params);
72
77
  }
73
78
 
74
79
  // Note: sidebarFilePath must be absolute, use resolveSidebarPathOption
75
80
  export async function loadSidebars(
76
81
  sidebarFilePath: string | false | undefined,
77
- options: SidebarProcessorProps,
82
+ options: SidebarProcessorParams,
78
83
  ): Promise<Sidebars> {
79
- const unprocessedSidebars = loadUnprocessedSidebars(
84
+ const normalizeSidebarsParams: NormalizeSidebarsParams = {
85
+ ...options.sidebarOptions,
86
+ version: options.version,
87
+ categoryLabelSlugger: createSlugger(),
88
+ };
89
+ const normalizedSidebars = loadNormalizedSidebars(
80
90
  sidebarFilePath,
81
- options.options,
91
+ normalizeSidebarsParams,
82
92
  );
83
- return processSidebars(unprocessedSidebars, options);
93
+ return processSidebars(normalizedSidebars, options);
84
94
  }
@@ -5,7 +5,7 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
 
8
- import type {SidebarOptions} from '../types';
8
+ import type {NormalizeSidebarsParams, SidebarOptions} from '../types';
9
9
  import type {
10
10
  NormalizedSidebarItem,
11
11
  NormalizedSidebar,
@@ -15,9 +15,31 @@ import type {
15
15
  SidebarItemConfig,
16
16
  SidebarConfig,
17
17
  SidebarsConfig,
18
+ SidebarItemCategoryLink,
19
+ NormalizedSidebarItemCategory,
18
20
  } from './types';
19
- import {mapValues} from 'lodash';
20
21
  import {isCategoriesShorthand} from './utils';
22
+ import {mapValues} from 'lodash';
23
+ import {normalizeUrl} from '@docusaurus/utils';
24
+
25
+ function normalizeCategoryLink(
26
+ category: SidebarItemCategoryConfig,
27
+ params: NormalizeSidebarsParams,
28
+ ): SidebarItemCategoryLink | undefined {
29
+ if (category.link?.type === 'generated-index') {
30
+ // default slug logic can be improved
31
+ const getDefaultSlug = () =>
32
+ `/category/${params.categoryLabelSlugger.slug(category.label)}`;
33
+ const slug = category.link.slug ?? getDefaultSlug();
34
+ const permalink = normalizeUrl([params.version.versionPath, slug]);
35
+ return {
36
+ ...category.link,
37
+ slug,
38
+ permalink,
39
+ };
40
+ }
41
+ return category.link;
42
+ }
21
43
 
22
44
  function normalizeCategoriesShorthand(
23
45
  sidebar: SidebarCategoriesShorthand,
@@ -36,9 +58,9 @@ function normalizeCategoriesShorthand(
36
58
  * Normalizes recursively item and all its children. Ensures that at the end
37
59
  * each item will be an object with the corresponding type.
38
60
  */
39
- function normalizeItem(
61
+ export function normalizeItem(
40
62
  item: SidebarItemConfig,
41
- options: SidebarOptions,
63
+ options: NormalizeSidebarsParams,
42
64
  ): NormalizedSidebarItem[] {
43
65
  if (typeof item === 'string') {
44
66
  return [
@@ -49,40 +71,42 @@ function normalizeItem(
49
71
  ];
50
72
  }
51
73
  if (isCategoriesShorthand(item)) {
52
- return normalizeCategoriesShorthand(item, options).flatMap((subitem) =>
53
- normalizeItem(subitem, options),
74
+ return normalizeCategoriesShorthand(item, options).flatMap((subItem) =>
75
+ normalizeItem(subItem, options),
54
76
  );
55
77
  }
56
- return item.type === 'category'
57
- ? [
58
- {
59
- ...item,
60
- items: item.items.flatMap((subItem) =>
61
- normalizeItem(subItem, options),
62
- ),
63
- collapsible: item.collapsible ?? options.sidebarCollapsible,
64
- collapsed: item.collapsed ?? options.sidebarCollapsed,
65
- },
66
- ]
67
- : [item];
78
+ if (item.type === 'category') {
79
+ const link = normalizeCategoryLink(item, options);
80
+ const normalizedCategory: NormalizedSidebarItemCategory = {
81
+ ...item,
82
+ link,
83
+ items: (item.items ?? []).flatMap((subItem) =>
84
+ normalizeItem(subItem, options),
85
+ ),
86
+ collapsible: item.collapsible ?? options.sidebarCollapsible,
87
+ collapsed: item.collapsed ?? options.sidebarCollapsed,
88
+ };
89
+ return [normalizedCategory];
90
+ }
91
+ return [item];
68
92
  }
69
93
 
70
94
  function normalizeSidebar(
71
95
  sidebar: SidebarConfig,
72
- options: SidebarOptions,
96
+ options: NormalizeSidebarsParams,
73
97
  ): NormalizedSidebar {
74
98
  const normalizedSidebar = Array.isArray(sidebar)
75
99
  ? sidebar
76
100
  : normalizeCategoriesShorthand(sidebar, options);
77
101
 
78
- return normalizedSidebar.flatMap((subitem) =>
79
- normalizeItem(subitem, options),
102
+ return normalizedSidebar.flatMap((subItem) =>
103
+ normalizeItem(subItem, options),
80
104
  );
81
105
  }
82
106
 
83
107
  export function normalizeSidebars(
84
108
  sidebars: SidebarsConfig,
85
- options: SidebarOptions,
109
+ params: NormalizeSidebarsParams,
86
110
  ): NormalizedSidebars {
87
- return mapValues(sidebars, (subitem) => normalizeSidebar(subitem, options));
111
+ return mapValues(sidebars, (items) => normalizeSidebar(items, params));
88
112
  }
@@ -21,18 +21,24 @@ import type {
21
21
  SidebarItemsGeneratorOption,
22
22
  SidebarItemsGeneratorDoc,
23
23
  SidebarItemsGeneratorVersion,
24
+ NormalizedSidebarItemCategory,
25
+ SidebarItemCategory,
26
+ SidebarItemAutogenerated,
24
27
  } from './types';
25
28
  import {transformSidebarItems} from './utils';
26
29
  import {DefaultSidebarItemsGenerator} from './generator';
27
30
  import {mapValues, memoize, pick} from 'lodash';
28
31
  import combinePromises from 'combine-promises';
32
+ import {normalizeItem} from './normalization';
33
+ import {Slugger} from '@docusaurus/utils';
29
34
 
30
- export type SidebarProcessorProps = {
35
+ export type SidebarProcessorParams = {
31
36
  sidebarItemsGenerator: SidebarItemsGeneratorOption;
32
37
  numberPrefixParser: NumberPrefixParser;
33
38
  docs: DocMetadataBase[];
34
39
  version: VersionMetadata;
35
- options: SidebarOptions;
40
+ categoryLabelSlugger: Slugger;
41
+ sidebarOptions: SidebarOptions;
36
42
  };
37
43
 
38
44
  function toSidebarItemsGeneratorDoc(
@@ -40,6 +46,7 @@ function toSidebarItemsGeneratorDoc(
40
46
  ): SidebarItemsGeneratorDoc {
41
47
  return pick(doc, [
42
48
  'id',
49
+ 'unversionedId',
43
50
  'frontMatter',
44
51
  'source',
45
52
  'sourceDirName',
@@ -56,48 +63,71 @@ function toSidebarItemsGeneratorVersion(
56
63
  // Handle the generation of autogenerated sidebar items and other post-processing checks
57
64
  async function processSidebar(
58
65
  unprocessedSidebar: NormalizedSidebar,
59
- {
66
+ params: SidebarProcessorParams,
67
+ ): Promise<Sidebar> {
68
+ const {
60
69
  sidebarItemsGenerator,
61
70
  numberPrefixParser,
62
71
  docs,
63
72
  version,
64
- options,
65
- }: SidebarProcessorProps,
66
- ): Promise<Sidebar> {
73
+ sidebarOptions,
74
+ } = params;
75
+
67
76
  // Just a minor lazy transformation optimization
68
77
  const getSidebarItemsGeneratorDocsAndVersion = memoize(() => ({
69
78
  docs: docs.map(toSidebarItemsGeneratorDoc),
70
79
  version: toSidebarItemsGeneratorVersion(version),
71
80
  }));
72
81
 
73
- async function handleAutoGeneratedItems(
82
+ async function processCategoryItem(
83
+ item: NormalizedSidebarItemCategory,
84
+ ): Promise<SidebarItemCategory> {
85
+ return {
86
+ ...item,
87
+ items: (await Promise.all(item.items.map(processItem))).flat(),
88
+ };
89
+ }
90
+
91
+ async function processAutoGeneratedItem(
92
+ item: SidebarItemAutogenerated,
93
+ ): Promise<SidebarItem[]> {
94
+ // TODO the returned type can't be trusted in practice (generator can be user-provided)
95
+ const generatedItems = await sidebarItemsGenerator({
96
+ item,
97
+ numberPrefixParser,
98
+ defaultSidebarItemsGenerator: DefaultSidebarItemsGenerator,
99
+ ...getSidebarItemsGeneratorDocsAndVersion(),
100
+ options: sidebarOptions,
101
+ });
102
+ // TODO validate generated items: user can generate bad items
103
+
104
+ const generatedItemsNormalized = generatedItems.flatMap((generatedItem) =>
105
+ normalizeItem(generatedItem, {...params, ...sidebarOptions}),
106
+ );
107
+
108
+ // Process again... weird but sidebar item generated might generate some auto-generated items?
109
+ return processItems(generatedItemsNormalized);
110
+ }
111
+
112
+ async function processItem(
74
113
  item: NormalizedSidebarItem,
75
114
  ): Promise<SidebarItem[]> {
76
115
  if (item.type === 'category') {
77
- return [
78
- {
79
- ...item,
80
- items: (
81
- await Promise.all(item.items.map(handleAutoGeneratedItems))
82
- ).flat(),
83
- },
84
- ];
116
+ return [await processCategoryItem(item)];
85
117
  }
86
118
  if (item.type === 'autogenerated') {
87
- return sidebarItemsGenerator({
88
- item,
89
- numberPrefixParser,
90
- defaultSidebarItemsGenerator: DefaultSidebarItemsGenerator,
91
- ...getSidebarItemsGeneratorDocsAndVersion(),
92
- options,
93
- });
119
+ return processAutoGeneratedItem(item);
94
120
  }
95
121
  return [item];
96
122
  }
97
123
 
98
- const processedSidebar = (
99
- await Promise.all(unprocessedSidebar.map(handleAutoGeneratedItems))
100
- ).flat();
124
+ async function processItems(
125
+ items: NormalizedSidebarItem[],
126
+ ): Promise<SidebarItem[]> {
127
+ return (await Promise.all(items.map(processItem))).flat();
128
+ }
129
+
130
+ const processedSidebar = await processItems(unprocessedSidebar);
101
131
 
102
132
  const fixSidebarItemInconsistencies = (item: SidebarItem): SidebarItem => {
103
133
  // A non-collapsible category can't be collapsed!
@@ -114,11 +144,11 @@ async function processSidebar(
114
144
 
115
145
  export async function processSidebars(
116
146
  unprocessedSidebars: NormalizedSidebars,
117
- props: SidebarProcessorProps,
147
+ params: SidebarProcessorParams,
118
148
  ): Promise<Sidebars> {
119
149
  return combinePromises(
120
150
  mapValues(unprocessedSidebars, (unprocessedSidebar) =>
121
- processSidebar(unprocessedSidebar, props),
151
+ processSidebar(unprocessedSidebar, params),
122
152
  ),
123
153
  );
124
154
  }
@@ -12,6 +12,7 @@ import type {
12
12
  NumberPrefixParser,
13
13
  SidebarOptions,
14
14
  } from '../types';
15
+ import {Required} from 'utility-types';
15
16
 
16
17
  // Makes all properties visible when hovering over the type
17
18
  type Expand<T extends Record<string, unknown>> = {[P in keyof T]: T[P]};
@@ -45,10 +46,35 @@ type SidebarItemCategoryBase = SidebarItemBase & {
45
46
  collapsible: boolean;
46
47
  };
47
48
 
49
+ export type SidebarItemCategoryLinkDoc = {type: 'doc'; id: string};
50
+
51
+ export type SidebarItemCategoryLinkGeneratedIndexConfig = {
52
+ type: 'generated-index';
53
+ slug?: string;
54
+ title?: string;
55
+ description?: string;
56
+ };
57
+ export type SidebarItemCategoryLinkGeneratedIndex = {
58
+ type: 'generated-index';
59
+ slug: string;
60
+ permalink: string;
61
+ title?: string;
62
+ description?: string;
63
+ };
64
+
65
+ export type SidebarItemCategoryLinkConfig =
66
+ | SidebarItemCategoryLinkDoc
67
+ | SidebarItemCategoryLinkGeneratedIndexConfig;
68
+
69
+ export type SidebarItemCategoryLink =
70
+ | SidebarItemCategoryLinkDoc
71
+ | SidebarItemCategoryLinkGeneratedIndex;
72
+
48
73
  // The user-given configuration in sidebars.js, before normalization
49
74
  export type SidebarItemCategoryConfig = Expand<
50
75
  Optional<SidebarItemCategoryBase, 'collapsed' | 'collapsible'> & {
51
76
  items: SidebarItemConfig[];
77
+ link?: SidebarItemCategoryLinkConfig;
52
78
  }
53
79
  >;
54
80
 
@@ -73,6 +99,7 @@ export type SidebarsConfig = {
73
99
  export type NormalizedSidebarItemCategory = Expand<
74
100
  SidebarItemCategoryBase & {
75
101
  items: NormalizedSidebarItem[];
102
+ link?: SidebarItemCategoryLink;
76
103
  }
77
104
  >;
78
105
 
@@ -90,14 +117,25 @@ export type NormalizedSidebars = {
90
117
  export type SidebarItemCategory = Expand<
91
118
  SidebarItemCategoryBase & {
92
119
  items: SidebarItem[];
120
+ link?: SidebarItemCategoryLink;
93
121
  }
94
122
  >;
95
123
 
124
+ export type SidebarItemCategoryWithLink = Required<SidebarItemCategory, 'link'>;
125
+
126
+ export type SidebarItemCategoryWithGeneratedIndex =
127
+ SidebarItemCategoryWithLink & {link: SidebarItemCategoryLinkGeneratedIndex};
128
+
96
129
  export type SidebarItem =
97
130
  | SidebarItemDoc
98
131
  | SidebarItemLink
99
132
  | SidebarItemCategory;
100
133
 
134
+ // A sidebar item that is part of the previous/next ordered navigation
135
+ export type SidebarNavigationItem =
136
+ | SidebarItemDoc
137
+ | SidebarItemCategoryWithLink;
138
+
101
139
  export type Sidebar = SidebarItem[];
102
140
  export type SidebarItemType = SidebarItem['type'];
103
141
  export type Sidebars = {
@@ -108,21 +146,42 @@ export type Sidebars = {
108
146
  export type PropSidebarItemCategory = Expand<
109
147
  SidebarItemCategoryBase & {
110
148
  items: PropSidebarItem[];
149
+ href?: string;
111
150
  }
112
151
  >;
113
152
 
114
- export type PropSidebarItem = SidebarItemLink | PropSidebarItemCategory;
153
+ // we may want to use a union type in props instead of this generic link?
154
+ export type PropSidebarItemLink = SidebarItemLink & {
155
+ docId?: string;
156
+ };
157
+
158
+ export type PropSidebarItem = PropSidebarItemLink | PropSidebarItemCategory;
115
159
  export type PropSidebar = PropSidebarItem[];
116
160
  export type PropSidebars = {
117
161
  [sidebarId: string]: PropSidebar;
118
162
  };
119
163
 
164
+ export type PropVersionDoc = {
165
+ id: string;
166
+ title: string;
167
+ description?: string;
168
+ sidebar?: string;
169
+ };
170
+ export type PropVersionDocs = {
171
+ [docId: string]: PropVersionDoc;
172
+ };
173
+
120
174
  // Reduce API surface for options.sidebarItemsGenerator
121
175
  // The user-provided generator fn should receive only a subset of metadata
122
176
  // A change to any of these metadata can be considered as a breaking change
123
177
  export type SidebarItemsGeneratorDoc = Pick<
124
178
  DocMetadataBase,
125
- 'id' | 'frontMatter' | 'source' | 'sourceDirName' | 'sidebarPosition'
179
+ | 'id'
180
+ | 'unversionedId'
181
+ | 'frontMatter'
182
+ | 'source'
183
+ | 'sourceDirName'
184
+ | 'sidebarPosition'
126
185
  >;
127
186
  export type SidebarItemsGeneratorVersion = Pick<
128
187
  VersionMetadata,
@@ -138,7 +197,9 @@ export type SidebarItemsGeneratorArgs = {
138
197
  };
139
198
  export type SidebarItemsGenerator = (
140
199
  generatorArgs: SidebarItemsGeneratorArgs,
141
- ) => Promise<SidebarItem[]>;
200
+ ) => // TODO TS issue: the generator can generate un-normalized items!
201
+ Promise<SidebarItem[]>;
202
+ // Promise<SidebarItemConfig[]>;
142
203
 
143
204
  // Also inject the default generator to conveniently wrap/enhance/sort the default sidebar gen logic
144
205
  // see https://github.com/facebook/docusaurus/issues/4640#issuecomment-822292320