@docusaurus/plugin-content-docs 3.0.0-alpha.0 → 3.0.0-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/cli.js CHANGED
@@ -21,7 +21,7 @@ async function createVersionedSidebarFile({ siteDir, pluginId, sidebarPath, vers
21
21
  // Note: we don't need the sidebars file to be normalized: it's ok to let
22
22
  // plugin option changes to impact older, versioned sidebars
23
23
  // We don't validate here, assuming the user has already built the version
24
- const sidebars = await (0, sidebars_1.loadSidebarsFileUnsafe)(sidebarPath);
24
+ const sidebars = await (0, sidebars_1.loadSidebarsFile)(sidebarPath);
25
25
  // Do not create a useless versioned sidebars file if sidebars file is empty
26
26
  // or sidebars are disabled/false)
27
27
  const shouldCreateVersionedSidebarFile = Object.keys(sidebars).length > 0;
package/lib/docs.d.ts CHANGED
@@ -18,10 +18,9 @@ export declare function processDocMetadata(args: {
18
18
  options: MetadataOptions;
19
19
  env: DocEnv;
20
20
  }): Promise<DocMetadataBase>;
21
- export declare function addDocNavigation({ docs, sidebarsUtils, sidebarFilePath, }: {
21
+ export declare function addDocNavigation({ docs, sidebarsUtils, }: {
22
22
  docs: DocMetadataBase[];
23
23
  sidebarsUtils: SidebarsUtils;
24
- sidebarFilePath: string;
25
24
  }): LoadedVersion['docs'];
26
25
  /**
27
26
  * The "main doc" is the "version entry point"
@@ -40,10 +39,8 @@ export declare const isCategoryIndex: CategoryIndexMatcher;
40
39
  * `'autogenerated', '.md', ['sidebar', 'guides']`
41
40
  */
42
41
  export declare function toCategoryIndexMatcherParam({ source, sourceDirName, }: Pick<DocMetadataBase, 'source' | 'sourceDirName'>): Parameters<CategoryIndexMatcher>[0];
43
- export declare function getDocIds(doc: DocMetadataBase): [string, string];
44
42
  export declare function createDocsByIdIndex<Doc extends {
45
43
  id: string;
46
- unversionedId: string;
47
44
  }>(docs: Doc[]): {
48
45
  [docId: string]: Doc;
49
46
  };
package/lib/docs.js CHANGED
@@ -6,15 +6,15 @@
6
6
  * LICENSE file in the root directory of this source tree.
7
7
  */
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.createDocsByIdIndex = exports.getDocIds = exports.toCategoryIndexMatcherParam = exports.isCategoryIndex = exports.getMainDocId = exports.addDocNavigation = exports.processDocMetadata = exports.readVersionDocs = exports.readDocFile = void 0;
9
+ exports.createDocsByIdIndex = exports.toCategoryIndexMatcherParam = exports.isCategoryIndex = exports.getMainDocId = exports.addDocNavigation = exports.processDocMetadata = exports.readVersionDocs = exports.readDocFile = void 0;
10
10
  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
+ const lodash_1 = tslib_1.__importDefault(require("lodash"));
13
14
  const logger_1 = tslib_1.__importDefault(require("@docusaurus/logger"));
14
15
  const utils_1 = require("@docusaurus/utils");
15
16
  const lastUpdate_1 = require("./lastUpdate");
16
17
  const slug_1 = tslib_1.__importDefault(require("./slug"));
17
- const constants_1 = require("./constants");
18
18
  const numberPrefix_1 = require("./numberPrefix");
19
19
  const frontMatter_1 = require("./frontMatter");
20
20
  const utils_2 = require("./sidebars/utils");
@@ -90,12 +90,6 @@ async function doProcessDocMetadata({ docFile, versionMetadata, context, options
90
90
  // prefix or front matter
91
91
  const sidebarPosition = frontMatter.sidebar_position ?? numberPrefix;
92
92
  // TODO legacy retrocompatibility
93
- // The same doc in 2 distinct version could keep the same id,
94
- // we just need to namespace the data by version
95
- const versionIdPrefix = versionMetadata.versionName === constants_1.CURRENT_VERSION_NAME
96
- ? undefined
97
- : `version-${versionMetadata.versionName}`;
98
- // TODO legacy retrocompatibility
99
93
  // I think it's bad to affect the front matter id with the dirname?
100
94
  function computeDirNameIdPrefix() {
101
95
  if (sourceDirName === '.') {
@@ -106,12 +100,7 @@ async function doProcessDocMetadata({ docFile, versionMetadata, context, options
106
100
  ? (0, numberPrefix_1.stripPathNumberPrefixes)(sourceDirName, options.numberPrefixParser)
107
101
  : sourceDirName;
108
102
  }
109
- const unversionedId = [computeDirNameIdPrefix(), baseID]
110
- .filter(Boolean)
111
- .join('/');
112
- // TODO is versioning the id very useful in practice?
113
- // legacy versioned id, requires a breaking change to modify this
114
- const id = [versionIdPrefix, unversionedId].filter(Boolean).join('/');
103
+ const id = [computeDirNameIdPrefix(), baseID].filter(Boolean).join('/');
115
104
  const docSlug = (0, slug_1.default)({
116
105
  baseID,
117
106
  source,
@@ -168,7 +157,6 @@ async function doProcessDocMetadata({ docFile, versionMetadata, context, options
168
157
  // Adding properties to object after instantiation will cause hidden
169
158
  // class transitions.
170
159
  return {
171
- unversionedId,
172
160
  id,
173
161
  title,
174
162
  description,
@@ -202,15 +190,13 @@ exports.processDocMetadata = processDocMetadata;
202
190
  function getUnlistedIds(docs) {
203
191
  return new Set(docs.filter((doc) => doc.unlisted).map((doc) => doc.id));
204
192
  }
205
- function addDocNavigation({ docs, sidebarsUtils, sidebarFilePath, }) {
193
+ function addDocNavigation({ docs, sidebarsUtils, }) {
206
194
  const docsById = createDocsByIdIndex(docs);
207
195
  const unlistedIds = getUnlistedIds(docs);
208
- sidebarsUtils.checkSidebarsDocIds(docs.flatMap(getDocIds), sidebarFilePath);
209
196
  // Add sidebar/next/previous to the docs
210
197
  function addNavData(doc) {
211
198
  const navigation = sidebarsUtils.getDocNavigation({
212
- unversionedId: doc.unversionedId,
213
- versionedId: doc.id,
199
+ docId: doc.id,
214
200
  displayedSidebar: doc.frontMatter.displayed_sidebar,
215
201
  unlistedIds,
216
202
  });
@@ -258,12 +244,11 @@ function getMainDocId({ docs, sidebarsUtils, }) {
258
244
  return versionHomeDoc;
259
245
  }
260
246
  else if (firstDocIdOfFirstSidebar) {
261
- return docs.find((doc) => doc.id === firstDocIdOfFirstSidebar ||
262
- doc.unversionedId === firstDocIdOfFirstSidebar);
247
+ return docs.find((doc) => doc.id === firstDocIdOfFirstSidebar);
263
248
  }
264
249
  return docs[0];
265
250
  }
266
- return getMainDoc().unversionedId;
251
+ return getMainDoc().id;
267
252
  }
268
253
  exports.getMainDocId = getMainDocId;
269
254
  // By convention, Docusaurus considers some docs are "indexes":
@@ -298,22 +283,8 @@ function toCategoryIndexMatcherParam({ source, sourceDirName, }) {
298
283
  };
299
284
  }
300
285
  exports.toCategoryIndexMatcherParam = toCategoryIndexMatcherParam;
301
- // Return both doc ids
302
- // TODO legacy retro-compatibility due to old versioned sidebars using
303
- // versioned doc ids ("id" should be removed & "versionedId" should be renamed
304
- // to "id")
305
- function getDocIds(doc) {
306
- return [doc.unversionedId, doc.id];
307
- }
308
- exports.getDocIds = getDocIds;
309
- // Docs are indexed by both versioned and unversioned ids at the same time
310
- // TODO legacy retro-compatibility due to old versioned sidebars using
311
- // versioned doc ids ("id" should be removed & "versionedId" should be renamed
312
- // to "id")
286
+ // Docs are indexed by their id
313
287
  function createDocsByIdIndex(docs) {
314
- return Object.fromEntries(docs.flatMap((doc) => [
315
- [doc.unversionedId, doc],
316
- [doc.id, doc],
317
- ]));
288
+ return lodash_1.default.keyBy(docs, (d) => d.id);
318
289
  }
319
290
  exports.createDocsByIdIndex = createDocsByIdIndex;
package/lib/globalData.js CHANGED
@@ -12,7 +12,7 @@ const lodash_1 = tslib_1.__importDefault(require("lodash"));
12
12
  const docs_1 = require("./docs");
13
13
  function toGlobalDataDoc(doc) {
14
14
  return {
15
- id: doc.unversionedId,
15
+ id: doc.id,
16
16
  path: doc.permalink,
17
17
  // optimize global data size: do not add unlisted: false/undefined
18
18
  ...(doc.unlisted && { unlisted: doc.unlisted }),
@@ -37,7 +37,7 @@ function toGlobalSidebars(sidebars, version) {
37
37
  link: {
38
38
  path: firstLink.type === 'generated-index'
39
39
  ? firstLink.permalink
40
- : version.docs.find((doc) => doc.id === firstLink.id || doc.unversionedId === firstLink.id).permalink,
40
+ : version.docs.find((doc) => doc.id === firstLink.id).permalink,
41
41
  label: firstLink.label,
42
42
  },
43
43
  };
@@ -53,7 +53,7 @@ function toGlobalDataVersion(version) {
53
53
  docs: version.docs
54
54
  .map(toGlobalDataDoc)
55
55
  .concat(version.categoryGeneratedIndices.map(toGlobalDataGeneratedIndex)),
56
- draftIds: version.drafts.map((doc) => doc.unversionedId),
56
+ draftIds: version.drafts.map((doc) => doc.id),
57
57
  sidebars: toGlobalSidebars(version.sidebars, version),
58
58
  };
59
59
  }
package/lib/index.js CHANGED
@@ -103,12 +103,22 @@ async function pluginContentDocs(context, options) {
103
103
  categoryLabelSlugger: (0, utils_1.createSlugger)(),
104
104
  });
105
105
  const sidebarsUtils = (0, utils_2.createSidebarsUtils)(sidebars);
106
+ const docsById = (0, docs_1.createDocsByIdIndex)(docs);
107
+ const allDocIds = Object.keys(docsById);
108
+ sidebarsUtils.checkLegacyVersionedSidebarNames({
109
+ sidebarFilePath: versionMetadata.sidebarFilePath,
110
+ versionMetadata,
111
+ });
112
+ sidebarsUtils.checkSidebarsDocIds({
113
+ allDocIds,
114
+ sidebarFilePath: versionMetadata.sidebarFilePath,
115
+ versionMetadata,
116
+ });
106
117
  return {
107
118
  ...versionMetadata,
108
119
  docs: (0, docs_1.addDocNavigation)({
109
120
  docs,
110
121
  sidebarsUtils,
111
- sidebarFilePath: versionMetadata.sidebarFilePath,
112
122
  }),
113
123
  drafts,
114
124
  sidebars,
package/lib/props.d.ts CHANGED
@@ -9,7 +9,7 @@ import type { SidebarItemDoc } from './sidebars/types';
9
9
  import type { PropSidebars, PropVersionMetadata, PropTagDocList, PropTagsListPage, PropSidebarItemLink, DocMetadata, LoadedVersion } from '@docusaurus/plugin-content-docs';
10
10
  export declare function toSidebarDocItemLinkProp({ item, doc, }: {
11
11
  item: SidebarItemDoc;
12
- doc: Pick<DocMetadata, 'id' | 'title' | 'permalink' | 'unlisted' | 'frontMatter' | 'unversionedId'>;
12
+ doc: Pick<DocMetadata, 'id' | 'title' | 'permalink' | 'unlisted' | 'frontMatter'>;
13
13
  }): PropSidebarItemLink;
14
14
  export declare function toSidebarsProp(loadedVersion: LoadedVersion): PropSidebars;
15
15
  export declare function toVersionMetadataProp(pluginId: string, loadedVersion: LoadedVersion): PropVersionMetadata;
package/lib/props.js CHANGED
@@ -11,14 +11,14 @@ const tslib_1 = require("tslib");
11
11
  const lodash_1 = tslib_1.__importDefault(require("lodash"));
12
12
  const docs_1 = require("./docs");
13
13
  function toSidebarDocItemLinkProp({ item, doc, }) {
14
- const { title, permalink, frontMatter: { sidebar_label: sidebarLabel, sidebar_custom_props: customProps, }, unlisted, unversionedId, } = doc;
14
+ const { id, title, permalink, frontMatter: { sidebar_label: sidebarLabel, sidebar_custom_props: customProps, }, unlisted, } = doc;
15
15
  return {
16
16
  type: 'link',
17
17
  label: sidebarLabel ?? item.label ?? title,
18
18
  href: permalink,
19
19
  className: item.className,
20
20
  customProps: item.customProps ?? customProps,
21
- docId: unversionedId,
21
+ docId: id,
22
22
  unlisted,
23
23
  };
24
24
  }
@@ -95,9 +95,9 @@ Available document ids are:
95
95
  exports.toSidebarsProp = toSidebarsProp;
96
96
  function toVersionDocsProp(loadedVersion) {
97
97
  return Object.fromEntries(loadedVersion.docs.map((doc) => [
98
- doc.unversionedId,
98
+ doc.id,
99
99
  {
100
- id: doc.unversionedId,
100
+ id: doc.id,
101
101
  title: doc.title,
102
102
  description: doc.description,
103
103
  sidebar: doc.sidebar,
@@ -91,7 +91,7 @@ Available doc IDs:
91
91
  */
92
92
  function generateSidebar(fsModel) {
93
93
  function createDocItem(id, fullPath, fileName) {
94
- const { sidebarPosition: position, frontMatter: { sidebar_label: label, sidebar_class_name: className }, } = getDoc(id);
94
+ const { sidebarPosition: position, frontMatter: { sidebar_label: label, sidebar_class_name: className, sidebar_custom_props: customProps, }, } = getDoc(id);
95
95
  return {
96
96
  type: 'doc',
97
97
  id,
@@ -101,6 +101,7 @@ Available doc IDs:
101
101
  // sidebar
102
102
  ...(label !== undefined && { label }),
103
103
  ...(className !== undefined && { className }),
104
+ ...(customProps !== undefined && { customProps }),
104
105
  };
105
106
  }
106
107
  function createCategoryItem(dir, fullPath, folderName) {
@@ -9,5 +9,5 @@ import type { SidebarsConfig, Sidebars, SidebarProcessorParams } from './types';
9
9
  export declare const DefaultSidebars: SidebarsConfig;
10
10
  export declare const DisabledSidebars: SidebarsConfig;
11
11
  export declare function resolveSidebarPathOption(siteDir: string, sidebarPathOption: PluginOptions['sidebarPath']): PluginOptions['sidebarPath'];
12
- export declare function loadSidebarsFileUnsafe(sidebarFilePath: string | false | undefined): Promise<SidebarsConfig>;
12
+ export declare function loadSidebarsFile(sidebarFilePath: string | false | undefined): Promise<SidebarsConfig>;
13
13
  export declare function loadSidebars(sidebarFilePath: string | false | undefined, options: SidebarProcessorParams): Promise<Sidebars>;
@@ -6,7 +6,7 @@
6
6
  * LICENSE file in the root directory of this source tree.
7
7
  */
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.loadSidebars = exports.loadSidebarsFileUnsafe = exports.resolveSidebarPathOption = exports.DisabledSidebars = exports.DefaultSidebars = void 0;
9
+ exports.loadSidebars = exports.loadSidebarsFile = exports.resolveSidebarPathOption = exports.DisabledSidebars = exports.DefaultSidebars = void 0;
10
10
  const tslib_1 = require("tslib");
11
11
  const fs_extra_1 = tslib_1.__importDefault(require("fs-extra"));
12
12
  const path_1 = tslib_1.__importDefault(require("path"));
@@ -15,7 +15,6 @@ const logger_1 = tslib_1.__importDefault(require("@docusaurus/logger"));
15
15
  const utils_1 = require("@docusaurus/utils");
16
16
  const js_yaml_1 = tslib_1.__importDefault(require("js-yaml"));
17
17
  const combine_promises_1 = tslib_1.__importDefault(require("combine-promises"));
18
- const import_fresh_1 = tslib_1.__importDefault(require("import-fresh"));
19
18
  const validation_1 = require("./validation");
20
19
  const normalization_1 = require("./normalization");
21
20
  const processor_1 = require("./processor");
@@ -72,9 +71,16 @@ async function loadSidebarsFileUnsafe(sidebarFilePath) {
72
71
  return exports.DisabledSidebars;
73
72
  }
74
73
  // We don't want sidebars to be cached because of hot reloading.
75
- return (0, import_fresh_1.default)(sidebarFilePath);
74
+ const module = await (0, utils_1.loadFreshModule)(sidebarFilePath);
75
+ // TODO unsafe, need to refactor and improve validation
76
+ return module;
76
77
  }
77
- exports.loadSidebarsFileUnsafe = loadSidebarsFileUnsafe;
78
+ async function loadSidebarsFile(sidebarFilePath) {
79
+ const sidebars = await loadSidebarsFileUnsafe(sidebarFilePath);
80
+ // TODO unsafe, need to refactor and improve validation
81
+ return sidebars;
82
+ }
83
+ exports.loadSidebarsFile = loadSidebarsFile;
78
84
  async function loadSidebars(sidebarFilePath, options) {
79
85
  try {
80
86
  const sidebarsConfig = await loadSidebarsFileUnsafe(sidebarFilePath);
@@ -10,7 +10,6 @@ exports.postProcessSidebars = void 0;
10
10
  const tslib_1 = require("tslib");
11
11
  const lodash_1 = tslib_1.__importDefault(require("lodash"));
12
12
  const utils_1 = require("@docusaurus/utils");
13
- const docs_1 = require("../docs");
14
13
  function normalizeCategoryLink(category, params) {
15
14
  if (category.link?.type === 'doc' && params.draftIds.has(category.link.id)) {
16
15
  return undefined;
@@ -73,7 +72,7 @@ function postProcessSidebarItem(item, params) {
73
72
  return item;
74
73
  }
75
74
  function postProcessSidebars(sidebars, params) {
76
- const draftIds = new Set(params.drafts.flatMap(docs_1.getDocIds));
75
+ const draftIds = new Set(params.drafts.map((d) => d.id));
77
76
  return lodash_1.default.mapValues(sidebars, (sidebar) => sidebar
78
77
  .map((item) => postProcessSidebarItem(item, { ...params, draftIds }))
79
78
  .filter((v) => Boolean(v)));
@@ -16,7 +16,6 @@ const docs_1 = require("../docs");
16
16
  function toSidebarItemsGeneratorDoc(doc) {
17
17
  return lodash_1.default.pick(doc, [
18
18
  'id',
19
- 'unversionedId',
20
19
  'title',
21
20
  'frontMatter',
22
21
  'source',
@@ -146,7 +146,7 @@ export type CategoryMetadataFile = {
146
146
  [key: string]: unknown;
147
147
  };
148
148
  };
149
- export type SidebarItemsGeneratorDoc = Pick<DocMetadataBase, 'id' | 'unversionedId' | 'title' | 'frontMatter' | 'source' | 'sourceDirName' | 'sidebarPosition'>;
149
+ export type SidebarItemsGeneratorDoc = Pick<DocMetadataBase, 'id' | 'title' | 'frontMatter' | 'source' | 'sourceDirName' | 'sidebarPosition'>;
150
150
  export type SidebarItemsGeneratorVersion = Pick<VersionMetadata, 'versionName' | 'contentPath'>;
151
151
  export type SidebarItemsGeneratorArgs = {
152
152
  /** The sidebar item with type "autogenerated" to be transformed. */
@@ -5,7 +5,7 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
  import type { Sidebars, Sidebar, SidebarItem, SidebarItemCategory, SidebarItemLink, SidebarItemDoc, SidebarCategoriesShorthand, SidebarItemConfig, SidebarItemCategoryWithGeneratedIndex, SidebarNavigationItem } from './types';
8
- import type { DocMetadataBase, PropNavigationLink } from '@docusaurus/plugin-content-docs';
8
+ import type { DocMetadataBase, PropNavigationLink, VersionMetadata } from '@docusaurus/plugin-content-docs';
9
9
  export declare function isCategoriesShorthand(item: SidebarItemConfig): item is SidebarCategoriesShorthand;
10
10
  export declare function transformSidebarItems(sidebar: Sidebar, updateFn: (item: SidebarItem) => SidebarItem): Sidebar;
11
11
  export declare function collectSidebarDocItems(sidebar: Sidebar): SidebarItemDoc[];
@@ -30,8 +30,7 @@ export type SidebarsUtils = {
30
30
  getFirstDocIdOfFirstSidebar: () => string | undefined;
31
31
  getSidebarNameByDocId: (docId: string) => string | undefined;
32
32
  getDocNavigation: (params: {
33
- unversionedId: string;
34
- versionedId: string;
33
+ docId: string;
35
34
  displayedSidebar: string | null | undefined;
36
35
  unlistedIds: Set<string>;
37
36
  }) => SidebarNavigation;
@@ -51,7 +50,15 @@ export type SidebarsUtils = {
51
50
  permalink: string;
52
51
  label: string;
53
52
  } | undefined;
54
- checkSidebarsDocIds: (validDocIds: string[], sidebarFilePath: string) => void;
53
+ checkLegacyVersionedSidebarNames: ({ versionMetadata, }: {
54
+ sidebarFilePath: string;
55
+ versionMetadata: VersionMetadata;
56
+ }) => void;
57
+ checkSidebarsDocIds: ({ allDocIds, sidebarFilePath, versionMetadata, }: {
58
+ allDocIds: string[];
59
+ sidebarFilePath: string;
60
+ versionMetadata: VersionMetadata;
61
+ }) => void;
55
62
  };
56
63
  export declare function createSidebarsUtils(sidebars: Sidebars): SidebarsUtils;
57
64
  export declare function toDocNavigationLink(doc: DocMetadataBase): PropNavigationLink;
@@ -110,16 +110,10 @@ function createSidebarsUtils(sidebars) {
110
110
  next: undefined,
111
111
  };
112
112
  }
113
- function getDocNavigation({ unversionedId, versionedId, displayedSidebar, unlistedIds, }) {
114
- // TODO legacy id retro-compatibility!
115
- let docId = unversionedId;
116
- let sidebarName = displayedSidebar === undefined
113
+ function getDocNavigation({ docId, displayedSidebar, unlistedIds, }) {
114
+ const sidebarName = displayedSidebar === undefined
117
115
  ? getSidebarNameByDocId(docId)
118
116
  : displayedSidebar;
119
- if (sidebarName === undefined) {
120
- docId = versionedId;
121
- sidebarName = getSidebarNameByDocId(docId);
122
- }
123
117
  if (!sidebarName) {
124
118
  return emptySidebarNavigation();
125
119
  }
@@ -186,16 +180,73 @@ function createSidebarsUtils(sidebars) {
186
180
  next: navigationItems[currentItemIndex + 1],
187
181
  };
188
182
  }
189
- function checkSidebarsDocIds(validDocIds, sidebarFilePath) {
183
+ // TODO remove in Docusaurus v4
184
+ function getLegacyVersionedPrefix(versionMetadata) {
185
+ return `version-${versionMetadata.versionName}/`;
186
+ }
187
+ // In early v2, sidebar names used to be versioned
188
+ // example: "version-2.0.0-alpha.66/my-sidebar-name"
189
+ // In v3 it's not the case anymore and we throw an error to explain
190
+ // TODO remove in Docusaurus v4
191
+ function checkLegacyVersionedSidebarNames({ versionMetadata, sidebarFilePath, }) {
192
+ const illegalPrefix = getLegacyVersionedPrefix(versionMetadata);
193
+ const legacySidebarNames = Object.keys(sidebars).filter((sidebarName) => sidebarName.startsWith(illegalPrefix));
194
+ if (legacySidebarNames.length > 0) {
195
+ throw new Error(`Invalid sidebar file at "${(0, utils_1.toMessageRelativeFilePath)(sidebarFilePath)}".
196
+ These legacy versioned sidebar names are not supported anymore in Docusaurus v3:
197
+ - ${legacySidebarNames.sort().join('\n- ')}
198
+
199
+ The sidebar names you should now use are:
200
+ - ${legacySidebarNames
201
+ .sort()
202
+ .map((legacyName) => legacyName.split('/').splice(1).join('/'))
203
+ .join('\n- ')}
204
+
205
+ Please remove the "${illegalPrefix}" prefix from your versioned sidebar file.
206
+ This breaking change is documented on Docusaurus v3 release notes: https://docusaurus.io/blog/releases/3.0
207
+ `);
208
+ }
209
+ }
210
+ // throw a better error message for Docusaurus v3 breaking change
211
+ // TODO this can be removed in Docusaurus v4
212
+ function handleLegacyVersionedDocIds({ invalidDocIds, sidebarFilePath, versionMetadata, }) {
213
+ const illegalPrefix = getLegacyVersionedPrefix(versionMetadata);
214
+ // In older v2.0 alpha/betas, versioned docs had a legacy versioned prefix
215
+ // Example: "version-1.4/my-doc-id"
216
+ //
217
+ const legacyVersionedDocIds = invalidDocIds.filter((docId) => docId.startsWith(illegalPrefix));
218
+ if (legacyVersionedDocIds.length > 0) {
219
+ throw new Error(`Invalid sidebar file at "${(0, utils_1.toMessageRelativeFilePath)(sidebarFilePath)}".
220
+ These legacy versioned document ids are not supported anymore in Docusaurus v3:
221
+ - ${legacyVersionedDocIds.sort().join('\n- ')}
222
+
223
+ The document ids you should now use are:
224
+ - ${legacyVersionedDocIds
225
+ .sort()
226
+ .map((legacyId) => legacyId.split('/').splice(1).join('/'))
227
+ .join('\n- ')}
228
+
229
+ Please remove the "${illegalPrefix}" prefix from your versioned sidebar file.
230
+ This breaking change is documented on Docusaurus v3 release notes: https://docusaurus.io/blog/releases/3.0
231
+ `);
232
+ }
233
+ }
234
+ function checkSidebarsDocIds({ allDocIds, sidebarFilePath, versionMetadata, }) {
190
235
  const allSidebarDocIds = Object.values(sidebarNameToDocIds).flat();
191
- const invalidSidebarDocIds = lodash_1.default.difference(allSidebarDocIds, validDocIds);
192
- if (invalidSidebarDocIds.length > 0) {
236
+ const invalidDocIds = lodash_1.default.difference(allSidebarDocIds, allDocIds);
237
+ if (invalidDocIds.length > 0) {
238
+ handleLegacyVersionedDocIds({
239
+ invalidDocIds,
240
+ sidebarFilePath,
241
+ versionMetadata,
242
+ });
193
243
  throw new Error(`Invalid sidebar file at "${(0, utils_1.toMessageRelativeFilePath)(sidebarFilePath)}".
194
244
  These sidebar document ids do not exist:
195
- - ${invalidSidebarDocIds.sort().join('\n- ')}
245
+ - ${invalidDocIds.sort().join('\n- ')}
196
246
 
197
247
  Available document ids are:
198
- - ${lodash_1.default.uniq(validDocIds).sort().join('\n- ')}`);
248
+ - ${lodash_1.default.uniq(allDocIds).sort().join('\n- ')}
249
+ `);
199
250
  }
200
251
  }
201
252
  function getFirstLink(sidebar) {
@@ -237,6 +288,7 @@ Available document ids are:
237
288
  getDocNavigation,
238
289
  getCategoryGeneratedIndexList,
239
290
  getCategoryGeneratedIndexNavigation,
291
+ checkLegacyVersionedSidebarNames,
240
292
  checkSidebarsDocIds,
241
293
  getFirstLink: (id) => getFirstLink(sidebars[id]),
242
294
  };
@@ -20,16 +20,6 @@ function getVersionFileName(versionName) {
20
20
  // but it's for consistency with site/versioned_docs
21
21
  return `version-${versionName}`;
22
22
  }
23
- // TODO legacy, the sidebar name is like "version-2.0.0-alpha.66/docs"
24
- // input: "version-2.0.0-alpha.66/docs"
25
- // output: "docs"
26
- function getNormalizedSidebarName({ versionName, sidebarName, }) {
27
- if (versionName === constants_1.CURRENT_VERSION_NAME || !sidebarName.includes('/')) {
28
- return sidebarName;
29
- }
30
- const [, ...rest] = sidebarName.split('/');
31
- return rest.join('/');
32
- }
33
23
  function getSidebarTranslationFileContent(sidebar, sidebarName) {
34
24
  const categories = (0, utils_2.collectSidebarCategories)(sidebar);
35
25
  const categoryContent = Object.fromEntries(categories.flatMap((category) => {
@@ -127,21 +117,12 @@ function translateSidebar({ sidebar, sidebarName, sidebarsTranslations, }) {
127
117
  });
128
118
  }
129
119
  function getSidebarsTranslations(version) {
130
- return (0, utils_1.mergeTranslations)(Object.entries(version.sidebars).map(([sidebarName, sidebar]) => {
131
- const normalizedSidebarName = getNormalizedSidebarName({
132
- sidebarName,
133
- versionName: version.versionName,
134
- });
135
- return getSidebarTranslationFileContent(sidebar, normalizedSidebarName);
136
- }));
120
+ return (0, utils_1.mergeTranslations)(Object.entries(version.sidebars).map(([sidebarName, sidebar]) => getSidebarTranslationFileContent(sidebar, sidebarName)));
137
121
  }
138
122
  function translateSidebars(version, sidebarsTranslations) {
139
123
  return lodash_1.default.mapValues(version.sidebars, (sidebar, sidebarName) => translateSidebar({
140
124
  sidebar,
141
- sidebarName: getNormalizedSidebarName({
142
- sidebarName,
143
- versionName: version.versionName,
144
- }),
125
+ sidebarName,
145
126
  sidebarsTranslations,
146
127
  }));
147
128
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@docusaurus/plugin-content-docs",
3
- "version": "3.0.0-alpha.0",
3
+ "version": "3.0.0-rc.0",
4
4
  "description": "Docs plugin for Docusaurus.",
5
5
  "main": "lib/index.js",
6
6
  "sideEffects": false,
@@ -35,22 +35,21 @@
35
35
  },
36
36
  "license": "MIT",
37
37
  "dependencies": {
38
- "@docusaurus/core": "3.0.0-alpha.0",
39
- "@docusaurus/logger": "3.0.0-alpha.0",
40
- "@docusaurus/mdx-loader": "3.0.0-alpha.0",
41
- "@docusaurus/module-type-aliases": "3.0.0-alpha.0",
42
- "@docusaurus/types": "3.0.0-alpha.0",
43
- "@docusaurus/utils": "3.0.0-alpha.0",
44
- "@docusaurus/utils-validation": "3.0.0-alpha.0",
45
- "@types/react-router-config": "^5.0.6",
38
+ "@docusaurus/core": "3.0.0-rc.0",
39
+ "@docusaurus/logger": "3.0.0-rc.0",
40
+ "@docusaurus/mdx-loader": "3.0.0-rc.0",
41
+ "@docusaurus/module-type-aliases": "3.0.0-rc.0",
42
+ "@docusaurus/types": "3.0.0-rc.0",
43
+ "@docusaurus/utils": "3.0.0-rc.0",
44
+ "@docusaurus/utils-validation": "3.0.0-rc.0",
45
+ "@types/react-router-config": "^5.0.7",
46
46
  "combine-promises": "^1.1.0",
47
- "fs-extra": "^11.1.0",
48
- "import-fresh": "^3.3.0",
47
+ "fs-extra": "^11.1.1",
49
48
  "js-yaml": "^4.1.0",
50
49
  "lodash": "^4.17.21",
51
- "tslib": "^2.5.0",
50
+ "tslib": "^2.6.0",
52
51
  "utility-types": "^3.10.0",
53
- "webpack": "^5.76.0"
52
+ "webpack": "^5.88.1"
54
53
  },
55
54
  "devDependencies": {
56
55
  "@types/js-yaml": "^4.0.5",
@@ -64,7 +63,7 @@
64
63
  "react-dom": "^18.0.0"
65
64
  },
66
65
  "engines": {
67
- "node": ">=16.14"
66
+ "node": ">=18.0"
68
67
  },
69
- "gitHead": "7327f7ff880ed97ad7855744e59c9c55d467a950"
68
+ "gitHead": "e66dfe04d2972edce66f431908470c61340f8ffc"
70
69
  }
package/src/cli.ts CHANGED
@@ -17,7 +17,7 @@ import {
17
17
  readVersionsFile,
18
18
  } from './versions/files';
19
19
  import {validateVersionName} from './versions/validation';
20
- import {loadSidebarsFileUnsafe} from './sidebars';
20
+ import {loadSidebarsFile} from './sidebars';
21
21
  import {CURRENT_VERSION_NAME} from './constants';
22
22
  import type {PluginOptions} from '@docusaurus/plugin-content-docs';
23
23
  import type {LoadContext} from '@docusaurus/types';
@@ -37,7 +37,7 @@ async function createVersionedSidebarFile({
37
37
  // Note: we don't need the sidebars file to be normalized: it's ok to let
38
38
  // plugin option changes to impact older, versioned sidebars
39
39
  // We don't validate here, assuming the user has already built the version
40
- const sidebars = await loadSidebarsFileUnsafe(sidebarPath);
40
+ const sidebars = await loadSidebarsFile(sidebarPath);
41
41
 
42
42
  // Do not create a useless versioned sidebars file if sidebars file is empty
43
43
  // or sidebars are disabled/false)
package/src/docs.ts CHANGED
@@ -7,6 +7,7 @@
7
7
 
8
8
  import path from 'path';
9
9
  import fs from 'fs-extra';
10
+ import _ from 'lodash';
10
11
  import logger from '@docusaurus/logger';
11
12
  import {
12
13
  aliasedSitePath,
@@ -24,7 +25,6 @@ import {
24
25
 
25
26
  import {getFileLastUpdate} from './lastUpdate';
26
27
  import getSlug from './slug';
27
- import {CURRENT_VERSION_NAME} from './constants';
28
28
  import {stripPathNumberPrefixes} from './numberPrefix';
29
29
  import {validateDocFrontMatter} from './frontMatter';
30
30
  import {toDocNavigationLink, toNavigationLink} from './sidebars/utils';
@@ -188,14 +188,6 @@ async function doProcessDocMetadata({
188
188
  const sidebarPosition: number | undefined =
189
189
  frontMatter.sidebar_position ?? numberPrefix;
190
190
 
191
- // TODO legacy retrocompatibility
192
- // The same doc in 2 distinct version could keep the same id,
193
- // we just need to namespace the data by version
194
- const versionIdPrefix =
195
- versionMetadata.versionName === CURRENT_VERSION_NAME
196
- ? undefined
197
- : `version-${versionMetadata.versionName}`;
198
-
199
191
  // TODO legacy retrocompatibility
200
192
  // I think it's bad to affect the front matter id with the dirname?
201
193
  function computeDirNameIdPrefix() {
@@ -208,13 +200,7 @@ async function doProcessDocMetadata({
208
200
  : sourceDirName;
209
201
  }
210
202
 
211
- const unversionedId = [computeDirNameIdPrefix(), baseID]
212
- .filter(Boolean)
213
- .join('/');
214
-
215
- // TODO is versioning the id very useful in practice?
216
- // legacy versioned id, requires a breaking change to modify this
217
- const id = [versionIdPrefix, unversionedId].filter(Boolean).join('/');
203
+ const id = [computeDirNameIdPrefix(), baseID].filter(Boolean).join('/');
218
204
 
219
205
  const docSlug = getSlug({
220
206
  baseID,
@@ -281,7 +267,6 @@ async function doProcessDocMetadata({
281
267
  // Adding properties to object after instantiation will cause hidden
282
268
  // class transitions.
283
269
  return {
284
- unversionedId,
285
270
  id,
286
271
  title,
287
272
  description,
@@ -332,22 +317,17 @@ function getUnlistedIds(docs: DocMetadataBase[]): Set<string> {
332
317
  export function addDocNavigation({
333
318
  docs,
334
319
  sidebarsUtils,
335
- sidebarFilePath,
336
320
  }: {
337
321
  docs: DocMetadataBase[];
338
322
  sidebarsUtils: SidebarsUtils;
339
- sidebarFilePath: string;
340
323
  }): LoadedVersion['docs'] {
341
324
  const docsById = createDocsByIdIndex(docs);
342
325
  const unlistedIds = getUnlistedIds(docs);
343
326
 
344
- sidebarsUtils.checkSidebarsDocIds(docs.flatMap(getDocIds), sidebarFilePath);
345
-
346
327
  // Add sidebar/next/previous to the docs
347
328
  function addNavData(doc: DocMetadataBase): DocMetadata {
348
329
  const navigation = sidebarsUtils.getDocNavigation({
349
- unversionedId: doc.unversionedId,
350
- versionedId: doc.id,
330
+ docId: doc.id,
351
331
  displayedSidebar: doc.frontMatter.displayed_sidebar,
352
332
  unlistedIds,
353
333
  });
@@ -412,16 +392,12 @@ export function getMainDocId({
412
392
  if (versionHomeDoc) {
413
393
  return versionHomeDoc;
414
394
  } else if (firstDocIdOfFirstSidebar) {
415
- return docs.find(
416
- (doc) =>
417
- doc.id === firstDocIdOfFirstSidebar ||
418
- doc.unversionedId === firstDocIdOfFirstSidebar,
419
- )!;
395
+ return docs.find((doc) => doc.id === firstDocIdOfFirstSidebar)!;
420
396
  }
421
397
  return docs[0]!;
422
398
  }
423
399
 
424
- return getMainDoc().unversionedId;
400
+ return getMainDoc().id;
425
401
  }
426
402
 
427
403
  // By convention, Docusaurus considers some docs are "indexes":
@@ -465,25 +441,9 @@ export function toCategoryIndexMatcherParam({
465
441
  };
466
442
  }
467
443
 
468
- // Return both doc ids
469
- // TODO legacy retro-compatibility due to old versioned sidebars using
470
- // versioned doc ids ("id" should be removed & "versionedId" should be renamed
471
- // to "id")
472
- export function getDocIds(doc: DocMetadataBase): [string, string] {
473
- return [doc.unversionedId, doc.id];
474
- }
475
-
476
- // Docs are indexed by both versioned and unversioned ids at the same time
477
- // TODO legacy retro-compatibility due to old versioned sidebars using
478
- // versioned doc ids ("id" should be removed & "versionedId" should be renamed
479
- // to "id")
480
- export function createDocsByIdIndex<
481
- Doc extends {id: string; unversionedId: string},
482
- >(docs: Doc[]): {[docId: string]: Doc} {
483
- return Object.fromEntries(
484
- docs.flatMap((doc) => [
485
- [doc.unversionedId, doc],
486
- [doc.id, doc],
487
- ]),
488
- );
444
+ // Docs are indexed by their id
445
+ export function createDocsByIdIndex<Doc extends {id: string}>(
446
+ docs: Doc[],
447
+ ): {[docId: string]: Doc} {
448
+ return _.keyBy(docs, (d) => d.id);
489
449
  }
package/src/globalData.ts CHANGED
@@ -21,7 +21,7 @@ import type {Sidebars} from './sidebars/types';
21
21
 
22
22
  function toGlobalDataDoc(doc: DocMetadata): GlobalDoc {
23
23
  return {
24
- id: doc.unversionedId,
24
+ id: doc.id,
25
25
  path: doc.permalink,
26
26
 
27
27
  // optimize global data size: do not add unlisted: false/undefined
@@ -56,10 +56,7 @@ function toGlobalSidebars(
56
56
  path:
57
57
  firstLink.type === 'generated-index'
58
58
  ? firstLink.permalink
59
- : version.docs.find(
60
- (doc) =>
61
- doc.id === firstLink.id || doc.unversionedId === firstLink.id,
62
- )!.permalink,
59
+ : version.docs.find((doc) => doc.id === firstLink.id)!.permalink,
63
60
  label: firstLink.label,
64
61
  },
65
62
  };
@@ -76,7 +73,7 @@ export function toGlobalDataVersion(version: FullVersion): GlobalVersion {
76
73
  docs: version.docs
77
74
  .map(toGlobalDataDoc)
78
75
  .concat(version.categoryGeneratedIndices.map(toGlobalDataGeneratedIndex)),
79
- draftIds: version.drafts.map((doc) => doc.unversionedId),
76
+ draftIds: version.drafts.map((doc) => doc.id),
80
77
  sidebars: toGlobalSidebars(version.sidebars, version),
81
78
  };
82
79
  }
package/src/index.ts CHANGED
@@ -26,6 +26,7 @@ import {
26
26
  processDocMetadata,
27
27
  addDocNavigation,
28
28
  type DocEnv,
29
+ createDocsByIdIndex,
29
30
  } from './docs';
30
31
  import {readVersionsMetadata, toFullVersion} from './versions';
31
32
  import {cliDocsVersionCommand} from './cli';
@@ -179,12 +180,24 @@ export default async function pluginContentDocs(
179
180
 
180
181
  const sidebarsUtils = createSidebarsUtils(sidebars);
181
182
 
183
+ const docsById = createDocsByIdIndex(docs);
184
+ const allDocIds = Object.keys(docsById);
185
+
186
+ sidebarsUtils.checkLegacyVersionedSidebarNames({
187
+ sidebarFilePath: versionMetadata.sidebarFilePath as string,
188
+ versionMetadata,
189
+ });
190
+ sidebarsUtils.checkSidebarsDocIds({
191
+ allDocIds,
192
+ sidebarFilePath: versionMetadata.sidebarFilePath as string,
193
+ versionMetadata,
194
+ });
195
+
182
196
  return {
183
197
  ...versionMetadata,
184
198
  docs: addDocNavigation({
185
199
  docs,
186
200
  sidebarsUtils,
187
- sidebarFilePath: versionMetadata.sidebarFilePath as string,
188
201
  }),
189
202
  drafts,
190
203
  sidebars,
@@ -414,17 +414,11 @@ declare module '@docusaurus/plugin-content-docs' {
414
414
  };
415
415
 
416
416
  export type DocMetadataBase = LastUpdateData & {
417
- // TODO
418
417
  /**
419
- * Legacy versioned ID. Will be refactored in the future to be unversioned.
418
+ * The document id.
419
+ * Multiple documents can have the same id, when in different versions.
420
420
  */
421
421
  id: string;
422
- // TODO
423
- /**
424
- * Unversioned ID. Should be preferred everywhere over `id` until the latter
425
- * is refactored.
426
- */
427
- unversionedId: string;
428
422
  /** The name of the version this doc belongs to. */
429
423
  version: string;
430
424
  /**
package/src/props.ts CHANGED
@@ -35,10 +35,11 @@ export function toSidebarDocItemLinkProp({
35
35
  item: SidebarItemDoc;
36
36
  doc: Pick<
37
37
  DocMetadata,
38
- 'id' | 'title' | 'permalink' | 'unlisted' | 'frontMatter' | 'unversionedId'
38
+ 'id' | 'title' | 'permalink' | 'unlisted' | 'frontMatter'
39
39
  >;
40
40
  }): PropSidebarItemLink {
41
41
  const {
42
+ id,
42
43
  title,
43
44
  permalink,
44
45
  frontMatter: {
@@ -46,7 +47,6 @@ export function toSidebarDocItemLinkProp({
46
47
  sidebar_custom_props: customProps,
47
48
  },
48
49
  unlisted,
49
- unversionedId,
50
50
  } = doc;
51
51
  return {
52
52
  type: 'link',
@@ -54,7 +54,7 @@ export function toSidebarDocItemLinkProp({
54
54
  href: permalink,
55
55
  className: item.className,
56
56
  customProps: item.customProps ?? customProps,
57
- docId: unversionedId,
57
+ docId: id,
58
58
  unlisted,
59
59
  };
60
60
  }
@@ -151,9 +151,9 @@ Available document ids are:
151
151
  function toVersionDocsProp(loadedVersion: LoadedVersion): PropVersionDocs {
152
152
  return Object.fromEntries(
153
153
  loadedVersion.docs.map((doc) => [
154
- doc.unversionedId,
154
+ doc.id,
155
155
  {
156
- id: doc.unversionedId,
156
+ id: doc.id,
157
157
  title: doc.title,
158
158
  description: doc.description,
159
159
  sidebar: doc.sidebar,
@@ -138,7 +138,11 @@ Available doc IDs:
138
138
  ): WithPosition<SidebarItemDoc> {
139
139
  const {
140
140
  sidebarPosition: position,
141
- frontMatter: {sidebar_label: label, sidebar_class_name: className},
141
+ frontMatter: {
142
+ sidebar_label: label,
143
+ sidebar_class_name: className,
144
+ sidebar_custom_props: customProps,
145
+ },
142
146
  } = getDoc(id);
143
147
  return {
144
148
  type: 'doc',
@@ -149,6 +153,7 @@ Available doc IDs:
149
153
  // sidebar
150
154
  ...(label !== undefined && {label}),
151
155
  ...(className !== undefined && {className}),
156
+ ...(customProps !== undefined && {customProps}),
152
157
  };
153
158
  }
154
159
  function createCategoryItem(
@@ -9,10 +9,9 @@ import fs from 'fs-extra';
9
9
  import path from 'path';
10
10
  import _ from 'lodash';
11
11
  import logger from '@docusaurus/logger';
12
- import {Globby} from '@docusaurus/utils';
12
+ import {loadFreshModule, Globby} from '@docusaurus/utils';
13
13
  import Yaml from 'js-yaml';
14
14
  import combinePromises from 'combine-promises';
15
- import importFresh from 'import-fresh';
16
15
  import {validateSidebars, validateCategoryMetadataFile} from './validation';
17
16
  import {normalizeSidebars} from './normalization';
18
17
  import {processSidebars} from './processor';
@@ -68,7 +67,7 @@ async function readCategoriesMetadata(contentPath: string) {
68
67
  );
69
68
  }
70
69
 
71
- export async function loadSidebarsFileUnsafe(
70
+ async function loadSidebarsFileUnsafe(
72
71
  sidebarFilePath: string | false | undefined,
73
72
  ): Promise<SidebarsConfig> {
74
73
  // false => no sidebars
@@ -89,7 +88,19 @@ export async function loadSidebarsFileUnsafe(
89
88
  }
90
89
 
91
90
  // We don't want sidebars to be cached because of hot reloading.
92
- return importFresh(sidebarFilePath);
91
+ const module = await loadFreshModule(sidebarFilePath);
92
+
93
+ // TODO unsafe, need to refactor and improve validation
94
+ return module as SidebarsConfig;
95
+ }
96
+
97
+ export async function loadSidebarsFile(
98
+ sidebarFilePath: string | false | undefined,
99
+ ): Promise<SidebarsConfig> {
100
+ const sidebars = await loadSidebarsFileUnsafe(sidebarFilePath);
101
+
102
+ // TODO unsafe, need to refactor and improve validation
103
+ return sidebars as SidebarsConfig;
93
104
  }
94
105
 
95
106
  export async function loadSidebars(
@@ -7,7 +7,6 @@
7
7
 
8
8
  import _ from 'lodash';
9
9
  import {normalizeUrl} from '@docusaurus/utils';
10
- import {getDocIds} from '../docs';
11
10
  import type {
12
11
  SidebarItem,
13
12
  Sidebars,
@@ -102,7 +101,7 @@ export function postProcessSidebars(
102
101
  sidebars: ProcessedSidebars,
103
102
  params: SidebarProcessorParams,
104
103
  ): Sidebars {
105
- const draftIds = new Set(params.drafts.flatMap(getDocIds));
104
+ const draftIds = new Set(params.drafts.map((d) => d.id));
106
105
 
107
106
  return _.mapValues(sidebars, (sidebar) =>
108
107
  sidebar
@@ -33,7 +33,6 @@ function toSidebarItemsGeneratorDoc(
33
33
  ): SidebarItemsGeneratorDoc {
34
34
  return _.pick(doc, [
35
35
  'id',
36
- 'unversionedId',
37
36
  'title',
38
37
  'frontMatter',
39
38
  'source',
@@ -235,7 +235,6 @@ export type CategoryMetadataFile = {
235
235
  export type SidebarItemsGeneratorDoc = Pick<
236
236
  DocMetadataBase,
237
237
  | 'id'
238
- | 'unversionedId'
239
238
  | 'title'
240
239
  | 'frontMatter'
241
240
  | 'source'
@@ -23,6 +23,7 @@ import type {
23
23
  import type {
24
24
  DocMetadataBase,
25
25
  PropNavigationLink,
26
+ VersionMetadata,
26
27
  } from '@docusaurus/plugin-content-docs';
27
28
 
28
29
  export function isCategoriesShorthand(
@@ -136,8 +137,7 @@ export type SidebarsUtils = {
136
137
  getFirstDocIdOfFirstSidebar: () => string | undefined;
137
138
  getSidebarNameByDocId: (docId: string) => string | undefined;
138
139
  getDocNavigation: (params: {
139
- unversionedId: string;
140
- versionedId: string;
140
+ docId: string;
141
141
  displayedSidebar: string | null | undefined;
142
142
  unlistedIds: Set<string>;
143
143
  }) => SidebarNavigation;
@@ -163,7 +163,22 @@ export type SidebarsUtils = {
163
163
  }
164
164
  | undefined;
165
165
 
166
- checkSidebarsDocIds: (validDocIds: string[], sidebarFilePath: string) => void;
166
+ checkLegacyVersionedSidebarNames: ({
167
+ versionMetadata,
168
+ }: {
169
+ sidebarFilePath: string;
170
+ versionMetadata: VersionMetadata;
171
+ }) => void;
172
+
173
+ checkSidebarsDocIds: ({
174
+ allDocIds,
175
+ sidebarFilePath,
176
+ versionMetadata,
177
+ }: {
178
+ allDocIds: string[];
179
+ sidebarFilePath: string;
180
+ versionMetadata: VersionMetadata;
181
+ }) => void;
167
182
  };
168
183
 
169
184
  export function createSidebarsUtils(sidebars: Sidebars): SidebarsUtils {
@@ -194,26 +209,18 @@ export function createSidebarsUtils(sidebars: Sidebars): SidebarsUtils {
194
209
  }
195
210
 
196
211
  function getDocNavigation({
197
- unversionedId,
198
- versionedId,
212
+ docId,
199
213
  displayedSidebar,
200
214
  unlistedIds,
201
215
  }: {
202
- unversionedId: string;
203
- versionedId: string;
216
+ docId: string;
204
217
  displayedSidebar: string | null | undefined;
205
218
  unlistedIds: Set<string>;
206
219
  }): SidebarNavigation {
207
- // TODO legacy id retro-compatibility!
208
- let docId = unversionedId;
209
- let sidebarName =
220
+ const sidebarName =
210
221
  displayedSidebar === undefined
211
222
  ? getSidebarNameByDocId(docId)
212
223
  : displayedSidebar;
213
- if (sidebarName === undefined) {
214
- docId = versionedId;
215
- sidebarName = getSidebarNameByDocId(docId);
216
- }
217
224
 
218
225
  if (!sidebarName) {
219
226
  return emptySidebarNavigation();
@@ -303,19 +310,115 @@ export function createSidebarsUtils(sidebars: Sidebars): SidebarsUtils {
303
310
  };
304
311
  }
305
312
 
306
- function checkSidebarsDocIds(validDocIds: string[], sidebarFilePath: string) {
313
+ // TODO remove in Docusaurus v4
314
+ function getLegacyVersionedPrefix(versionMetadata: VersionMetadata): string {
315
+ return `version-${versionMetadata.versionName}/`;
316
+ }
317
+
318
+ // In early v2, sidebar names used to be versioned
319
+ // example: "version-2.0.0-alpha.66/my-sidebar-name"
320
+ // In v3 it's not the case anymore and we throw an error to explain
321
+ // TODO remove in Docusaurus v4
322
+ function checkLegacyVersionedSidebarNames({
323
+ versionMetadata,
324
+ sidebarFilePath,
325
+ }: {
326
+ versionMetadata: VersionMetadata;
327
+ sidebarFilePath: string;
328
+ }): void {
329
+ const illegalPrefix = getLegacyVersionedPrefix(versionMetadata);
330
+ const legacySidebarNames = Object.keys(sidebars).filter((sidebarName) =>
331
+ sidebarName.startsWith(illegalPrefix),
332
+ );
333
+ if (legacySidebarNames.length > 0) {
334
+ throw new Error(
335
+ `Invalid sidebar file at "${toMessageRelativeFilePath(
336
+ sidebarFilePath,
337
+ )}".
338
+ These legacy versioned sidebar names are not supported anymore in Docusaurus v3:
339
+ - ${legacySidebarNames.sort().join('\n- ')}
340
+
341
+ The sidebar names you should now use are:
342
+ - ${legacySidebarNames
343
+ .sort()
344
+ .map((legacyName) => legacyName.split('/').splice(1).join('/'))
345
+ .join('\n- ')}
346
+
347
+ Please remove the "${illegalPrefix}" prefix from your versioned sidebar file.
348
+ This breaking change is documented on Docusaurus v3 release notes: https://docusaurus.io/blog/releases/3.0
349
+ `,
350
+ );
351
+ }
352
+ }
353
+
354
+ // throw a better error message for Docusaurus v3 breaking change
355
+ // TODO this can be removed in Docusaurus v4
356
+ function handleLegacyVersionedDocIds({
357
+ invalidDocIds,
358
+ sidebarFilePath,
359
+ versionMetadata,
360
+ }: {
361
+ invalidDocIds: string[];
362
+ sidebarFilePath: string;
363
+ versionMetadata: VersionMetadata;
364
+ }) {
365
+ const illegalPrefix = getLegacyVersionedPrefix(versionMetadata);
366
+
367
+ // In older v2.0 alpha/betas, versioned docs had a legacy versioned prefix
368
+ // Example: "version-1.4/my-doc-id"
369
+ //
370
+ const legacyVersionedDocIds = invalidDocIds.filter((docId) =>
371
+ docId.startsWith(illegalPrefix),
372
+ );
373
+ if (legacyVersionedDocIds.length > 0) {
374
+ throw new Error(
375
+ `Invalid sidebar file at "${toMessageRelativeFilePath(
376
+ sidebarFilePath,
377
+ )}".
378
+ These legacy versioned document ids are not supported anymore in Docusaurus v3:
379
+ - ${legacyVersionedDocIds.sort().join('\n- ')}
380
+
381
+ The document ids you should now use are:
382
+ - ${legacyVersionedDocIds
383
+ .sort()
384
+ .map((legacyId) => legacyId.split('/').splice(1).join('/'))
385
+ .join('\n- ')}
386
+
387
+ Please remove the "${illegalPrefix}" prefix from your versioned sidebar file.
388
+ This breaking change is documented on Docusaurus v3 release notes: https://docusaurus.io/blog/releases/3.0
389
+ `,
390
+ );
391
+ }
392
+ }
393
+
394
+ function checkSidebarsDocIds({
395
+ allDocIds,
396
+ sidebarFilePath,
397
+ versionMetadata,
398
+ }: {
399
+ allDocIds: string[];
400
+ sidebarFilePath: string;
401
+ versionMetadata: VersionMetadata;
402
+ }) {
307
403
  const allSidebarDocIds = Object.values(sidebarNameToDocIds).flat();
308
- const invalidSidebarDocIds = _.difference(allSidebarDocIds, validDocIds);
309
- if (invalidSidebarDocIds.length > 0) {
404
+ const invalidDocIds = _.difference(allSidebarDocIds, allDocIds);
405
+
406
+ if (invalidDocIds.length > 0) {
407
+ handleLegacyVersionedDocIds({
408
+ invalidDocIds,
409
+ sidebarFilePath,
410
+ versionMetadata,
411
+ });
310
412
  throw new Error(
311
413
  `Invalid sidebar file at "${toMessageRelativeFilePath(
312
414
  sidebarFilePath,
313
415
  )}".
314
416
  These sidebar document ids do not exist:
315
- - ${invalidSidebarDocIds.sort().join('\n- ')}
417
+ - ${invalidDocIds.sort().join('\n- ')}
316
418
 
317
419
  Available document ids are:
318
- - ${_.uniq(validDocIds).sort().join('\n- ')}`,
420
+ - ${_.uniq(allDocIds).sort().join('\n- ')}
421
+ `,
319
422
  );
320
423
  }
321
424
  }
@@ -369,6 +472,7 @@ Available document ids are:
369
472
  getDocNavigation,
370
473
  getCategoryGeneratedIndexList,
371
474
  getCategoryGeneratedIndexNavigation,
475
+ checkLegacyVersionedSidebarNames,
372
476
  checkSidebarsDocIds,
373
477
  getFirstLink: (id) => getFirstLink(sidebars[id]!),
374
478
  };
@@ -40,23 +40,6 @@ function getVersionFileName(versionName: string): string {
40
40
  return `version-${versionName}`;
41
41
  }
42
42
 
43
- // TODO legacy, the sidebar name is like "version-2.0.0-alpha.66/docs"
44
- // input: "version-2.0.0-alpha.66/docs"
45
- // output: "docs"
46
- function getNormalizedSidebarName({
47
- versionName,
48
- sidebarName,
49
- }: {
50
- versionName: string;
51
- sidebarName: string;
52
- }): string {
53
- if (versionName === CURRENT_VERSION_NAME || !sidebarName.includes('/')) {
54
- return sidebarName;
55
- }
56
- const [, ...rest] = sidebarName.split('/');
57
- return rest.join('/');
58
- }
59
-
60
43
  function getSidebarTranslationFileContent(
61
44
  sidebar: Sidebar,
62
45
  sidebarName: string,
@@ -199,13 +182,9 @@ function getSidebarsTranslations(
199
182
  version: LoadedVersion,
200
183
  ): TranslationFileContent {
201
184
  return mergeTranslations(
202
- Object.entries(version.sidebars).map(([sidebarName, sidebar]) => {
203
- const normalizedSidebarName = getNormalizedSidebarName({
204
- sidebarName,
205
- versionName: version.versionName,
206
- });
207
- return getSidebarTranslationFileContent(sidebar, normalizedSidebarName);
208
- }),
185
+ Object.entries(version.sidebars).map(([sidebarName, sidebar]) =>
186
+ getSidebarTranslationFileContent(sidebar, sidebarName),
187
+ ),
209
188
  );
210
189
  }
211
190
  function translateSidebars(
@@ -215,10 +194,7 @@ function translateSidebars(
215
194
  return _.mapValues(version.sidebars, (sidebar, sidebarName) =>
216
195
  translateSidebar({
217
196
  sidebar,
218
- sidebarName: getNormalizedSidebarName({
219
- sidebarName,
220
- versionName: version.versionName,
221
- }),
197
+ sidebarName,
222
198
  sidebarsTranslations,
223
199
  }),
224
200
  );