@docusaurus/plugin-content-docs 2.0.0-beta.8e9b829d9 → 2.0.0-beta.9

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 (103) hide show
  1. package/lib/.tsbuildinfo +1 -1
  2. package/lib/cli.d.ts +1 -1
  3. package/lib/cli.js +18 -23
  4. package/lib/client/docsClientUtils.d.ts +0 -3
  5. package/lib/client/docsClientUtils.js +10 -7
  6. package/lib/docFrontMatter.js +6 -2
  7. package/lib/docs.d.ts +3 -1
  8. package/lib/docs.js +76 -25
  9. package/lib/index.js +70 -77
  10. package/lib/lastUpdate.js +4 -4
  11. package/lib/markdown/index.d.ts +3 -6
  12. package/lib/markdown/index.js +3 -3
  13. package/lib/markdown/linkify.js +2 -2
  14. package/lib/options.js +12 -4
  15. package/lib/props.d.ts +7 -2
  16. package/lib/props.js +26 -3
  17. package/lib/{sidebarItemsGenerator.d.ts → sidebars/generator.d.ts} +2 -1
  18. package/lib/sidebars/generator.js +174 -0
  19. package/lib/sidebars/index.d.ts +14 -0
  20. package/lib/sidebars/index.js +64 -0
  21. package/lib/sidebars/normalization.d.ts +9 -0
  22. package/lib/sidebars/normalization.js +58 -0
  23. package/lib/sidebars/processor.d.ts +16 -0
  24. package/lib/sidebars/processor.js +70 -0
  25. package/lib/sidebars/types.d.ts +87 -0
  26. package/lib/sidebars/types.js +13 -0
  27. package/lib/sidebars/utils.d.ts +22 -0
  28. package/lib/sidebars/utils.js +101 -0
  29. package/lib/sidebars/validation.d.ts +8 -0
  30. package/lib/sidebars/validation.js +102 -0
  31. package/lib/slug.js +4 -4
  32. package/lib/tags.d.ts +8 -0
  33. package/lib/tags.js +22 -0
  34. package/lib/theme/hooks/useDocs.js +21 -21
  35. package/lib/translations.d.ts +1 -1
  36. package/lib/translations.js +13 -13
  37. package/lib/types.d.ts +29 -61
  38. package/lib/versions.d.ts +1 -1
  39. package/lib/versions.js +40 -20
  40. package/package.json +15 -14
  41. package/src/__tests__/__fixtures__/simple-site/docs/foo/baz.md +5 -0
  42. package/src/__tests__/__fixtures__/simple-site/docs/hello.md +1 -0
  43. package/src/__tests__/__fixtures__/simple-site/docs/rootAbsoluteSlug.md +2 -0
  44. package/src/__tests__/__fixtures__/simple-site/docs/rootRelativeSlug.md +2 -0
  45. package/src/__tests__/__fixtures__/simple-site/docs/rootResolvedSlug.md +2 -0
  46. package/src/__tests__/__fixtures__/simple-site/docs/rootTryToEscapeSlug.md +2 -0
  47. package/src/__tests__/__fixtures__/simple-site/sidebars.json +15 -1
  48. package/src/__tests__/__fixtures__/versioned-site/docs/foo/bar.md +6 -0
  49. package/src/__tests__/__snapshots__/cli.test.ts.snap +28 -0
  50. package/src/__tests__/__snapshots__/docs.test.ts.snap +140 -0
  51. package/src/__tests__/__snapshots__/index.test.ts.snap +426 -25
  52. package/src/__tests__/docFrontMatter.test.ts +160 -45
  53. package/src/__tests__/docs.test.ts +167 -21
  54. package/src/__tests__/index.test.ts +53 -27
  55. package/src/__tests__/options.test.ts +4 -1
  56. package/src/__tests__/props.test.ts +62 -0
  57. package/src/__tests__/versions.test.ts +68 -63
  58. package/src/cli.ts +23 -30
  59. package/src/client/docsClientUtils.ts +1 -12
  60. package/src/docFrontMatter.ts +7 -2
  61. package/src/docs.ts +88 -9
  62. package/src/index.ts +77 -91
  63. package/src/markdown/index.ts +8 -12
  64. package/src/numberPrefix.ts +4 -2
  65. package/src/options.ts +13 -1
  66. package/src/plugin-content-docs.d.ts +107 -32
  67. package/src/props.ts +41 -5
  68. package/src/{__tests__ → sidebars/__tests__}/__fixtures__/sidebars/sidebars-category-shorthand.js +0 -0
  69. package/src/{__tests__ → sidebars/__tests__}/__fixtures__/sidebars/sidebars-category-wrong-items.json +0 -0
  70. package/src/{__tests__ → sidebars/__tests__}/__fixtures__/sidebars/sidebars-category-wrong-label.json +0 -0
  71. package/src/{__tests__ → sidebars/__tests__}/__fixtures__/sidebars/sidebars-category.js +0 -0
  72. package/src/{__tests__ → sidebars/__tests__}/__fixtures__/sidebars/sidebars-collapsed-first-level.json +0 -0
  73. package/src/{__tests__ → sidebars/__tests__}/__fixtures__/sidebars/sidebars-collapsed.json +0 -0
  74. package/src/{__tests__ → sidebars/__tests__}/__fixtures__/sidebars/sidebars-doc-id-not-string.json +0 -0
  75. package/src/{__tests__ → sidebars/__tests__}/__fixtures__/sidebars/sidebars-first-level-not-category.js +0 -0
  76. package/src/{__tests__ → sidebars/__tests__}/__fixtures__/sidebars/sidebars-link-wrong-href.json +0 -0
  77. package/src/{__tests__ → sidebars/__tests__}/__fixtures__/sidebars/sidebars-link-wrong-label.json +0 -0
  78. package/src/{__tests__ → sidebars/__tests__}/__fixtures__/sidebars/sidebars-link.json +0 -0
  79. package/src/{__tests__ → sidebars/__tests__}/__fixtures__/sidebars/sidebars-unknown-type.json +0 -0
  80. package/src/{__tests__ → sidebars/__tests__}/__fixtures__/sidebars/sidebars-wrong-field.json +0 -0
  81. package/src/{__tests__ → sidebars/__tests__}/__fixtures__/sidebars/sidebars.json +0 -0
  82. package/src/{__tests__/__snapshots__/sidebars.test.ts.snap → sidebars/__tests__/__snapshots__/index.test.ts.snap} +6 -6
  83. package/src/{__tests__/sidebarItemsGenerator.test.ts → sidebars/__tests__/generator.test.ts} +2 -2
  84. package/src/sidebars/__tests__/index.test.ts +202 -0
  85. package/src/sidebars/__tests__/processor.test.ts +148 -0
  86. package/src/sidebars/__tests__/utils.test.ts +395 -0
  87. package/src/sidebars/generator.ts +253 -0
  88. package/src/sidebars/index.ts +84 -0
  89. package/src/sidebars/normalization.ts +88 -0
  90. package/src/sidebars/processor.ts +124 -0
  91. package/src/sidebars/types.ts +156 -0
  92. package/src/sidebars/utils.ts +146 -0
  93. package/src/sidebars/validation.ts +124 -0
  94. package/src/tags.ts +21 -0
  95. package/src/translations.ts +26 -36
  96. package/src/types.ts +35 -101
  97. package/src/versions.ts +51 -21
  98. package/lib/sidebarItemsGenerator.js +0 -215
  99. package/lib/sidebars.d.ts +0 -45
  100. package/lib/sidebars.js +0 -354
  101. package/src/__tests__/sidebars.test.ts +0 -746
  102. package/src/sidebarItemsGenerator.ts +0 -315
  103. package/src/sidebars.ts +0 -589
@@ -0,0 +1,124 @@
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 {Joi, URISchema} from '@docusaurus/utils-validation';
9
+ import {
10
+ SidebarItemConfig,
11
+ SidebarCategoriesShorthand,
12
+ SidebarItemBase,
13
+ SidebarItemAutogenerated,
14
+ SidebarItemDoc,
15
+ SidebarItemLink,
16
+ SidebarItemCategoryConfig,
17
+ SidebarsConfig,
18
+ isCategoriesShorthand,
19
+ } from './types';
20
+
21
+ const sidebarItemBaseSchema = Joi.object<SidebarItemBase>({
22
+ className: Joi.string(),
23
+ customProps: Joi.object().unknown(),
24
+ });
25
+
26
+ const sidebarItemAutogeneratedSchema =
27
+ sidebarItemBaseSchema.append<SidebarItemAutogenerated>({
28
+ type: 'autogenerated',
29
+ dirName: Joi.string()
30
+ .required()
31
+ .pattern(/^[^/](.*[^/])?$/)
32
+ .message(
33
+ '"dirName" must be a dir path relative to the docs folder root, and should not start or end with slash',
34
+ ),
35
+ });
36
+
37
+ const sidebarItemDocSchema = sidebarItemBaseSchema.append<SidebarItemDoc>({
38
+ type: Joi.string().valid('doc', 'ref').required(),
39
+ id: Joi.string().required(),
40
+ label: Joi.string(),
41
+ });
42
+
43
+ const sidebarItemLinkSchema = sidebarItemBaseSchema.append<SidebarItemLink>({
44
+ type: 'link',
45
+ href: URISchema.required(),
46
+ label: Joi.string()
47
+ .required()
48
+ .messages({'any.unknown': '"label" must be a string'}),
49
+ });
50
+
51
+ const sidebarItemCategorySchema =
52
+ sidebarItemBaseSchema.append<SidebarItemCategoryConfig>({
53
+ type: 'category',
54
+ label: Joi.string()
55
+ .required()
56
+ .messages({'any.unknown': '"label" must be a string'}),
57
+ // TODO: Joi doesn't allow mutual recursion. See https://github.com/sideway/joi/issues/2611
58
+ items: Joi.array()
59
+ .required()
60
+ .messages({'any.unknown': '"items" must be an array'}), // .items(Joi.link('#sidebarItemSchema')),
61
+ collapsed: Joi.boolean().messages({
62
+ 'any.unknown': '"collapsed" must be a boolean',
63
+ }),
64
+ collapsible: Joi.boolean().messages({
65
+ 'any.unknown': '"collapsible" must be a boolean',
66
+ }),
67
+ });
68
+
69
+ const sidebarItemSchema: Joi.Schema<SidebarItemConfig> = Joi.object()
70
+ .when('.type', {
71
+ switch: [
72
+ {is: 'link', then: sidebarItemLinkSchema},
73
+ {
74
+ is: Joi.string().valid('doc', 'ref').required(),
75
+ then: sidebarItemDocSchema,
76
+ },
77
+ {is: 'autogenerated', then: sidebarItemAutogeneratedSchema},
78
+ {is: 'category', then: sidebarItemCategorySchema},
79
+ {
80
+ is: 'subcategory',
81
+ then: Joi.forbidden().messages({
82
+ 'any.unknown':
83
+ 'Docusaurus v2: "subcategory" has been renamed as "category".',
84
+ }),
85
+ },
86
+ {
87
+ is: Joi.string().required(),
88
+ then: Joi.forbidden().messages({
89
+ 'any.unknown': 'Unknown sidebar item type "{.type}".',
90
+ }),
91
+ },
92
+ ],
93
+ })
94
+ .id('sidebarItemSchema');
95
+
96
+ function validateSidebarItem(item: unknown): asserts item is SidebarItemConfig {
97
+ if (typeof item === 'string') {
98
+ return;
99
+ }
100
+ // TODO: remove once with proper Joi support
101
+ // Because we can't use Joi to validate nested items (see above), we do it manually
102
+ if (isCategoriesShorthand(item as SidebarItemConfig)) {
103
+ Object.values(item as SidebarCategoriesShorthand).forEach((category) =>
104
+ category.forEach(validateSidebarItem),
105
+ );
106
+ } else {
107
+ Joi.assert(item, sidebarItemSchema);
108
+ if ((item as SidebarItemCategoryConfig).type === 'category') {
109
+ (item as SidebarItemCategoryConfig).items.forEach(validateSidebarItem);
110
+ }
111
+ }
112
+ }
113
+
114
+ export function validateSidebars(
115
+ sidebars: unknown,
116
+ ): asserts sidebars is SidebarsConfig {
117
+ Object.values(sidebars as SidebarsConfig).forEach((sidebar) => {
118
+ if (Array.isArray(sidebar)) {
119
+ sidebar.forEach(validateSidebarItem);
120
+ } else {
121
+ validateSidebarItem(sidebar);
122
+ }
123
+ });
124
+ }
package/src/tags.ts ADDED
@@ -0,0 +1,21 @@
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 {groupTaggedItems} from '@docusaurus/utils';
9
+ import {VersionTags, DocMetadata} from './types';
10
+ import {mapValues} from 'lodash';
11
+
12
+ export function getVersionTags(docs: DocMetadata[]): VersionTags {
13
+ const groups = groupTaggedItems(docs, (doc) => doc.tags);
14
+ return mapValues(groups, (group) => {
15
+ return {
16
+ name: group.tag.label,
17
+ docIds: group.items.map((item) => item.id),
18
+ permalink: group.tag.permalink,
19
+ };
20
+ });
21
+ }
@@ -5,20 +5,15 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
 
8
- import {
9
- LoadedVersion,
10
- Sidebar,
11
- LoadedContent,
12
- Sidebars,
13
- SidebarItem,
14
- } from './types';
8
+ import type {LoadedVersion, LoadedContent} from './types';
9
+ import type {Sidebar, Sidebars} from './sidebars/types';
15
10
 
16
- import {chain, mapValues, flatten, keyBy} from 'lodash';
11
+ import {chain, mapValues, keyBy} from 'lodash';
17
12
  import {
18
13
  collectSidebarCategories,
19
14
  transformSidebarItems,
20
15
  collectSidebarLinks,
21
- } from './sidebars';
16
+ } from './sidebars/utils';
22
17
  import {
23
18
  TranslationFileContent,
24
19
  TranslationFile,
@@ -131,29 +126,25 @@ function translateSidebar({
131
126
  sidebarName: string;
132
127
  sidebarsTranslations: TranslationFileContent;
133
128
  }): Sidebar {
134
- return transformSidebarItems(
135
- sidebar,
136
- (item: SidebarItem): SidebarItem => {
137
- if (item.type === 'category') {
138
- return {
139
- ...item,
140
- label:
141
- sidebarsTranslations[
142
- `sidebar.${sidebarName}.category.${item.label}`
143
- ]?.message ?? item.label,
144
- };
145
- }
146
- if (item.type === 'link') {
147
- return {
148
- ...item,
149
- label:
150
- sidebarsTranslations[`sidebar.${sidebarName}.link.${item.label}`]
151
- ?.message ?? item.label,
152
- };
153
- }
154
- return item;
155
- },
156
- );
129
+ return transformSidebarItems(sidebar, (item) => {
130
+ if (item.type === 'category') {
131
+ return {
132
+ ...item,
133
+ label:
134
+ sidebarsTranslations[`sidebar.${sidebarName}.category.${item.label}`]
135
+ ?.message ?? item.label,
136
+ };
137
+ }
138
+ if (item.type === 'link') {
139
+ return {
140
+ ...item,
141
+ label:
142
+ sidebarsTranslations[`sidebar.${sidebarName}.link.${item.label}`]
143
+ ?.message ?? item.label,
144
+ };
145
+ }
146
+ return item;
147
+ });
157
148
  }
158
149
 
159
150
  function getSidebarsTranslations(
@@ -193,9 +184,8 @@ function getVersionTranslationFiles(version: LoadedVersion): TranslationFiles {
193
184
  },
194
185
  };
195
186
 
196
- const sidebarsTranslations: TranslationFileContent = getSidebarsTranslations(
197
- version,
198
- );
187
+ const sidebarsTranslations: TranslationFileContent =
188
+ getSidebarsTranslations(version);
199
189
 
200
190
  // const docsTranslations: TranslationFileContent = getDocsTranslations(version);
201
191
 
@@ -227,7 +217,7 @@ function translateVersion(
227
217
  function getVersionsTranslationFiles(
228
218
  versions: LoadedVersion[],
229
219
  ): TranslationFiles {
230
- return flatten(versions.map(getVersionTranslationFiles));
220
+ return versions.flatMap(getVersionTranslationFiles);
231
221
  }
232
222
  function translateVersions(
233
223
  versions: LoadedVersion[],
package/src/types.ts CHANGED
@@ -5,14 +5,15 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
 
8
- // eslint-disable-next-line spaced-comment
9
8
  /// <reference types="@docusaurus/module-type-aliases" />
10
9
 
11
10
  import type {RemarkAndRehypePluginOptions} from '@docusaurus/mdx-loader';
12
- import {
11
+ import type {Tag, FrontMatterTag} from '@docusaurus/utils';
12
+ import type {
13
13
  BrokenMarkdownLink as IBrokenMarkdownLink,
14
14
  ContentPaths,
15
15
  } from '@docusaurus/utils/lib/markdownLinks';
16
+ import type {SidebarItemsGeneratorOption, Sidebars} from './sidebars/types';
16
17
 
17
18
  export type DocFile = {
18
19
  contentPath: string; // /!\ may be localized
@@ -28,9 +29,12 @@ export type VersionMetadata = ContentPaths & {
28
29
  versionName: VersionName; // 1.0.0
29
30
  versionLabel: string; // Version 1.0.0
30
31
  versionPath: string; // /baseUrl/docs/1.0.0
32
+ tagsPath: string;
31
33
  versionEditUrl?: string | undefined;
32
34
  versionEditUrlLocalized?: string | undefined;
33
- versionBanner: VersionBanner;
35
+ versionBanner: VersionBanner | null;
36
+ versionBadge: boolean;
37
+ versionClassName: string;
34
38
  isLast: boolean;
35
39
  sidebarFilePath: string | false | undefined; // versioned_sidebars/1.0.0.json
36
40
  routePriority: number | undefined; // -1 for the latest docs
@@ -61,12 +65,14 @@ export type PathOptions = {
61
65
  };
62
66
 
63
67
  // TODO support custom version banner? {type: "error", content: "html content"}
64
- export type VersionBanner = 'none' | 'unreleased' | 'unmaintained';
68
+ export type VersionBanner = 'unreleased' | 'unmaintained';
65
69
 
66
70
  export type VersionOptions = {
67
71
  path?: string;
68
72
  label?: string;
69
- banner?: VersionBanner;
73
+ banner?: 'none' | VersionBanner;
74
+ badge?: boolean;
75
+ className?: string;
70
76
  };
71
77
 
72
78
  export type VersionsOptions = {
@@ -90,105 +96,15 @@ export type PluginOptions = MetadataOptions &
90
96
  exclude: string[];
91
97
  docLayoutComponent: string;
92
98
  docItemComponent: string;
99
+ docTagDocListComponent: string;
100
+ docTagsListComponent: string;
93
101
  admonitions: Record<string, unknown>;
94
102
  disableVersioning: boolean;
95
103
  includeCurrentVersion: boolean;
96
104
  sidebarItemsGenerator: SidebarItemsGeneratorOption;
105
+ tagsBasePath: string;
97
106
  };
98
107
 
99
- export type SidebarItemBase = {
100
- customProps?: Record<string, unknown>;
101
- };
102
-
103
- export type SidebarItemDoc = SidebarItemBase & {
104
- type: 'doc' | 'ref';
105
- label?: string;
106
- id: string;
107
- };
108
-
109
- export type SidebarItemLink = SidebarItemBase & {
110
- type: 'link';
111
- href: string;
112
- label: string;
113
- };
114
-
115
- export type SidebarItemCategory = SidebarItemBase & {
116
- type: 'category';
117
- label: string;
118
- items: SidebarItem[];
119
- collapsed: boolean;
120
- collapsible: boolean;
121
- };
122
-
123
- export type UnprocessedSidebarItemAutogenerated = {
124
- type: 'autogenerated';
125
- dirName: string;
126
- };
127
-
128
- export type UnprocessedSidebarItemCategory = SidebarItemBase & {
129
- type: 'category';
130
- label: string;
131
- items: UnprocessedSidebarItem[];
132
- collapsed: boolean;
133
- collapsible: boolean;
134
- };
135
-
136
- export type UnprocessedSidebarItem =
137
- | SidebarItemDoc
138
- | SidebarItemLink
139
- | UnprocessedSidebarItemCategory
140
- | UnprocessedSidebarItemAutogenerated;
141
-
142
- export type UnprocessedSidebar = UnprocessedSidebarItem[];
143
- export type UnprocessedSidebars = Record<string, UnprocessedSidebar>;
144
-
145
- export type SidebarItem =
146
- | SidebarItemDoc
147
- | SidebarItemLink
148
- | SidebarItemCategory;
149
-
150
- export type Sidebar = SidebarItem[];
151
- export type SidebarItemType = SidebarItem['type'];
152
- export type Sidebars = Record<string, Sidebar>;
153
-
154
- // Reduce API surface for options.sidebarItemsGenerator
155
- // The user-provided generator fn should receive only a subset of metadatas
156
- // A change to any of these metadatas can be considered as a breaking change
157
- export type SidebarItemsGeneratorDoc = Pick<
158
- DocMetadataBase,
159
- 'id' | 'frontMatter' | 'source' | 'sourceDirName' | 'sidebarPosition'
160
- >;
161
- export type SidebarItemsGeneratorVersion = Pick<
162
- VersionMetadata,
163
- 'versionName' | 'contentPath'
164
- >;
165
-
166
- export type SidebarItemsGeneratorArgs = {
167
- item: UnprocessedSidebarItemAutogenerated;
168
- version: SidebarItemsGeneratorVersion;
169
- docs: SidebarItemsGeneratorDoc[];
170
- numberPrefixParser: NumberPrefixParser;
171
- options: SidebarOptions;
172
- };
173
- export type SidebarItemsGenerator = (
174
- generatorArgs: SidebarItemsGeneratorArgs,
175
- ) => Promise<SidebarItem[]>;
176
-
177
- // Also inject the default generator to conveniently wrap/enhance/sort the default sidebar gen logic
178
- // see https://github.com/facebook/docusaurus/issues/4640#issuecomment-822292320
179
- export type SidebarItemsGeneratorOptionArgs = {
180
- defaultSidebarItemsGenerator: SidebarItemsGenerator;
181
- } & SidebarItemsGeneratorArgs;
182
- export type SidebarItemsGeneratorOption = (
183
- generatorArgs: SidebarItemsGeneratorOptionArgs,
184
- ) => Promise<SidebarItem[]>;
185
-
186
- export type OrderMetadata = {
187
- previous?: string;
188
- next?: string;
189
- sidebar?: string;
190
- };
191
-
192
108
  export type LastUpdateData = {
193
109
  lastUpdatedAt?: number;
194
110
  formattedLastUpdatedAt?: string;
@@ -200,6 +116,7 @@ export type DocFrontMatter = {
200
116
  /* eslint-disable camelcase */
201
117
  id?: string;
202
118
  title?: string;
119
+ tags?: FrontMatterTag[];
203
120
  hide_title?: boolean;
204
121
  hide_table_of_contents?: boolean;
205
122
  keywords?: string[];
@@ -208,9 +125,14 @@ export type DocFrontMatter = {
208
125
  slug?: string;
209
126
  sidebar_label?: string;
210
127
  sidebar_position?: number;
128
+ sidebar_class_name?: string;
211
129
  pagination_label?: string;
212
130
  custom_edit_url?: string | null;
213
131
  parse_number_prefixes?: boolean;
132
+ toc_min_heading_level?: number;
133
+ toc_max_heading_level?: number;
134
+ pagination_next?: string | null;
135
+ pagination_prev?: string | null;
214
136
  /* eslint-enable camelcase */
215
137
  };
216
138
 
@@ -227,6 +149,7 @@ export type DocMetadataBase = LastUpdateData & {
227
149
  permalink: string;
228
150
  sidebarPosition?: number;
229
151
  editUrl?: string | null;
152
+ tags: Tag[];
230
153
  frontMatter: DocFrontMatter & Record<string, unknown>;
231
154
  };
232
155
 
@@ -244,6 +167,16 @@ export type DocMetadata = DocMetadataBase & {
244
167
  export type SourceToPermalink = {
245
168
  [source: string]: string;
246
169
  };
170
+
171
+ export type VersionTag = {
172
+ name: string; // normalized name/label of the tag
173
+ docIds: string[]; // all doc ids having this tag
174
+ permalink: string; // pathname of the tag
175
+ };
176
+ export type VersionTags = {
177
+ [key: string]: VersionTag;
178
+ };
179
+
247
180
  export type LoadedVersion = VersionMetadata & {
248
181
  versionPath: string;
249
182
  mainDocId: string;
@@ -284,6 +217,7 @@ export type DocsMarkdownOption = {
284
217
  onBrokenMarkdownLink: (brokenMarkdownLink: BrokenMarkdownLink) => void;
285
218
  };
286
219
 
287
- export type NumberPrefixParser = (
288
- filename: string,
289
- ) => {filename: string; numberPrefix?: number};
220
+ export type NumberPrefixParser = (filename: string) => {
221
+ filename: string;
222
+ numberPrefix?: number;
223
+ };
package/src/versions.ts CHANGED
@@ -264,10 +264,10 @@ function getDefaultVersionBanner({
264
264
  versionName: string;
265
265
  versionNames: string[];
266
266
  lastVersionName: string;
267
- }): VersionBanner {
267
+ }): VersionBanner | null {
268
268
  // Current version: good, no banner
269
269
  if (versionName === lastVersionName) {
270
- return 'none';
270
+ return null;
271
271
  }
272
272
  // Upcoming versions: unreleased banner
273
273
  else if (
@@ -291,17 +291,45 @@ function getVersionBanner({
291
291
  versionNames: string[];
292
292
  lastVersionName: string;
293
293
  options: Pick<PluginOptions, 'versions'>;
294
- }): VersionBanner {
295
- const versionOptionBanner = options.versions[versionName]?.banner;
294
+ }): VersionBanner | null {
295
+ const versionBannerOption = options.versions[versionName]?.banner;
296
+ if (versionBannerOption) {
297
+ return versionBannerOption === 'none' ? null : versionBannerOption;
298
+ }
299
+ return getDefaultVersionBanner({
300
+ versionName,
301
+ versionNames,
302
+ lastVersionName,
303
+ });
304
+ }
296
305
 
297
- return (
298
- versionOptionBanner ??
299
- getDefaultVersionBanner({
300
- versionName,
301
- versionNames,
302
- lastVersionName,
303
- })
304
- );
306
+ function getVersionBadge({
307
+ versionName,
308
+ versionNames,
309
+ options,
310
+ }: {
311
+ versionName: string;
312
+ versionNames: string[];
313
+ options: Pick<PluginOptions, 'versions'>;
314
+ }): boolean {
315
+ const versionBadgeOption = options.versions[versionName]?.badge;
316
+ // If site is not versioned or only one version is included
317
+ // we don't show the version badge by default
318
+ // See https://github.com/facebook/docusaurus/issues/3362
319
+ const versionBadgeDefault = versionNames.length !== 1;
320
+ return versionBadgeOption ?? versionBadgeDefault;
321
+ }
322
+
323
+ function getVersionClassName({
324
+ versionName,
325
+ options,
326
+ }: {
327
+ versionName: string;
328
+ options: Pick<PluginOptions, 'versions'>;
329
+ }): string {
330
+ const versionClassNameOption = options.versions[versionName]?.className;
331
+ const versionClassNameDefault = `docs-version-${versionName}`;
332
+ return versionClassNameOption ?? versionClassNameDefault;
305
333
  }
306
334
 
307
335
  function createVersionMetadata({
@@ -321,20 +349,14 @@ function createVersionMetadata({
321
349
  | 'path'
322
350
  | 'sidebarPath'
323
351
  | 'routeBasePath'
352
+ | 'tagsBasePath'
324
353
  | 'versions'
325
354
  | 'editUrl'
326
355
  | 'editCurrentVersion'
327
356
  >;
328
357
  }): VersionMetadata {
329
- const {
330
- sidebarFilePath,
331
- contentPath,
332
- contentPathLocalized,
333
- } = getVersionMetadataPaths({
334
- versionName,
335
- context,
336
- options,
337
- });
358
+ const {sidebarFilePath, contentPath, contentPathLocalized} =
359
+ getVersionMetadataPaths({versionName, context, options});
338
360
 
339
361
  const isLast = versionName === lastVersionName;
340
362
 
@@ -370,10 +392,15 @@ function createVersionMetadata({
370
392
  // Because /docs/:route` should always be after `/docs/versionName/:route`.
371
393
  const routePriority = versionPathPart === '' ? -1 : undefined;
372
394
 
395
+ // the path that will be used to refer the docs tags
396
+ // example below will be using /docs/tags
397
+ const tagsPath = normalizeUrl([versionPath, options.tagsBasePath]);
398
+
373
399
  return {
374
400
  versionName,
375
401
  versionLabel,
376
402
  versionPath,
403
+ tagsPath,
377
404
  versionEditUrl: versionEditUrls?.versionEditUrl,
378
405
  versionEditUrlLocalized: versionEditUrls?.versionEditUrlLocalized,
379
406
  versionBanner: getVersionBanner({
@@ -382,6 +409,8 @@ function createVersionMetadata({
382
409
  lastVersionName,
383
410
  options,
384
411
  }),
412
+ versionBadge: getVersionBadge({versionName, versionNames, options}),
413
+ versionClassName: getVersionClassName({versionName, options}),
385
414
  isLast,
386
415
  routePriority,
387
416
  sidebarFilePath,
@@ -526,6 +555,7 @@ export function readVersionsMetadata({
526
555
  | 'path'
527
556
  | 'sidebarPath'
528
557
  | 'routeBasePath'
558
+ | 'tagsBasePath'
529
559
  | 'includeCurrentVersion'
530
560
  | 'disableVersioning'
531
561
  | 'lastVersion'