@docusaurus/plugin-content-docs 3.8.1 → 3.9.0-canary-6406

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
@@ -49,7 +49,7 @@ async function cliDocsVersionCommand(version, { id: pluginId, path: docsPath, si
49
49
  logger_1.default.info `Versioned docs will be created for the following locales: name=${i18n.locales}`;
50
50
  }
51
51
  await Promise.all(i18n.locales.map(async (locale) => {
52
- const localizationDir = path_1.default.resolve(siteDir, i18n.path, i18n.localeConfigs[locale].path);
52
+ const localizationDir = path_1.default.resolve(siteDir, i18n.path, (0, utils_1.getLocaleConfig)(i18n, locale).path);
53
53
  // Copy docs files.
54
54
  const docsDir = locale === i18n.defaultLocale
55
55
  ? path_1.default.resolve(siteDir, docsPath)
package/lib/docs.js CHANGED
@@ -103,7 +103,8 @@ async function doProcessDocMetadata({ docFile, versionMetadata, context, options
103
103
  });
104
104
  }
105
105
  else if (typeof options.editUrl === 'string') {
106
- const isLocalized = contentPath === versionMetadata.contentPathLocalized;
106
+ const isLocalized = typeof versionMetadata.contentPathLocalized !== 'undefined' &&
107
+ contentPath === versionMetadata.contentPathLocalized;
107
108
  const baseVersionEditUrl = isLocalized && options.editLocalizedFiles
108
109
  ? versionMetadata.editUrlLocalized
109
110
  : versionMetadata.editUrl;
package/lib/index.js CHANGED
@@ -11,7 +11,6 @@ exports.default = pluginContentDocs;
11
11
  const tslib_1 = require("tslib");
12
12
  const path_1 = tslib_1.__importDefault(require("path"));
13
13
  const fs_extra_1 = tslib_1.__importDefault(require("fs-extra"));
14
- const logger_1 = tslib_1.__importDefault(require("@docusaurus/logger"));
15
14
  const utils_1 = require("@docusaurus/utils");
16
15
  const utils_validation_1 = require("@docusaurus/utils-validation");
17
16
  const mdx_loader_1 = require("@docusaurus/mdx-loader");
@@ -30,6 +29,11 @@ const loadVersion_1 = require("./versions/loadVersion");
30
29
  // Problem documented here: https://github.com/facebook/docusaurus/pull/10934
31
30
  // TODO this is not a perfect solution, find better?
32
31
  async function createMdxLoaderDependencyFile({ dataDir, options, versionsMetadata, }) {
32
+ // Disabled for unit tests, the side effect produces infinite watch loops
33
+ // TODO find a better way :/
34
+ if (process.env.NODE_ENV === 'test') {
35
+ return undefined;
36
+ }
33
37
  const filePath = path_1.default.join(dataDir, '__mdx-loader-dependency.json');
34
38
  // the cache is invalidated whenever this file content changes
35
39
  const fileContent = {
@@ -94,16 +98,12 @@ async function pluginContentDocs(context, options) {
94
98
  markdownConfig: siteConfig.markdown,
95
99
  resolveMarkdownLink: ({ linkPathname, sourceFilePath }) => {
96
100
  const version = (0, version_1.getVersionFromSourceFilePath)(sourceFilePath, versionsMetadata);
97
- const permalink = (0, utils_1.resolveMarkdownLinkPathname)(linkPathname, {
101
+ return (0, utils_1.resolveMarkdownLinkPathname)(linkPathname, {
98
102
  sourceFilePath,
99
103
  sourceToPermalink: contentHelpers.sourceToPermalink,
100
104
  siteDir,
101
105
  contentPaths: version,
102
106
  });
103
- if (permalink === null) {
104
- logger_1.default.report(siteConfig.onBrokenMarkdownLinks) `Docs markdown link couldn't be resolved: (url=${linkPathname}) in source file path=${sourceFilePath} for version number=${version.versionName}`;
105
- }
106
- return permalink;
107
107
  },
108
108
  },
109
109
  });
package/lib/props.d.ts CHANGED
@@ -11,7 +11,7 @@ export declare function toSidebarDocItemLinkProp({ item, doc, }: {
11
11
  item: SidebarItemDoc;
12
12
  doc: Pick<DocMetadata, 'id' | 'title' | 'permalink' | 'unlisted' | 'frontMatter'>;
13
13
  }): PropSidebarItemLink;
14
- export declare function toSidebarsProp(loadedVersion: LoadedVersion): PropSidebars;
14
+ export declare function toSidebarsProp(loadedVersion: Pick<LoadedVersion, 'docs' | 'sidebars'>): PropSidebars;
15
15
  export declare function toVersionMetadataProp(pluginId: string, loadedVersion: LoadedVersion): PropVersionMetadata;
16
16
  export declare function toTagDocListProp({ allTagsPath, tag, docs, }: {
17
17
  allTagsPath: string;
package/lib/props.js CHANGED
@@ -15,13 +15,15 @@ const tslib_1 = require("tslib");
15
15
  const lodash_1 = tslib_1.__importDefault(require("lodash"));
16
16
  const docs_1 = require("./docs");
17
17
  function toSidebarDocItemLinkProp({ item, doc, }) {
18
- const { id, title, permalink, frontMatter: { sidebar_label: sidebarLabel, sidebar_custom_props: customProps, }, unlisted, } = doc;
18
+ const { id, title, permalink, frontMatter, unlisted } = doc;
19
19
  return {
20
20
  type: 'link',
21
- label: sidebarLabel ?? item.label ?? title,
21
+ ...(item.key && { key: item.key }),
22
22
  href: permalink,
23
- className: item.className,
24
- customProps: item.customProps ?? customProps,
23
+ // Front Matter data takes precedence over sidebars.json
24
+ label: frontMatter.sidebar_label ?? item.label ?? title,
25
+ className: frontMatter.sidebar_class_name ?? item.className,
26
+ customProps: frontMatter.sidebar_custom_props ?? item.customProps,
25
27
  docId: id,
26
28
  unlisted,
27
29
  };
@@ -171,6 +171,7 @@ Available doc IDs:
171
171
  ...(categoryMetadata?.description && {
172
172
  description: categoryMetadata?.description,
173
173
  }),
174
+ ...(categoryMetadata?.key && { key: categoryMetadata?.key }),
174
175
  ...(link && { link }),
175
176
  };
176
177
  }
@@ -53,10 +53,13 @@ function postProcessSidebarItem(item, params) {
53
53
  params.draftIds.has(category.link.id)) {
54
54
  return null;
55
55
  }
56
+ const { label, className, customProps } = category;
56
57
  return {
57
58
  type: 'doc',
58
- label: category.label,
59
59
  id: category.link.id,
60
+ label,
61
+ ...(className && { className }),
62
+ ...(customProps && { customProps }),
60
63
  };
61
64
  }
62
65
  // A non-collapsible category can't be collapsed!
@@ -13,6 +13,7 @@ type Expand<T extends {
13
13
  [P in keyof T]: T[P];
14
14
  };
15
15
  export type SidebarItemBase = {
16
+ key?: string;
16
17
  className?: string;
17
18
  customProps?: {
18
19
  [key: string]: unknown;
@@ -23,8 +24,9 @@ export type SidebarItemDoc = SidebarItemBase & {
23
24
  label?: string;
24
25
  id: string;
25
26
  /**
26
- * This is an internal marker. Items with labels defined in the config needs
27
- * to be translated with JSON
27
+ * This is an internal marker set during the sidebar normalization process.
28
+ * Docs with labels defined in the config need to be translated with JSON.
29
+ * Otherwise, it's preferable to translate the MDX doc title or front matter.
28
30
  */
29
31
  translatable?: true;
30
32
  };
@@ -136,6 +138,7 @@ export type PropSidebars = {
136
138
  };
137
139
  export type PropSidebarBreadcrumbsItem = PropSidebarItemLink | PropSidebarItemCategory;
138
140
  export type CategoryMetadataFile = {
141
+ key?: string;
139
142
  label?: string;
140
143
  position?: number;
141
144
  description?: string;
@@ -13,6 +13,7 @@ const utils_validation_1 = require("@docusaurus/utils-validation");
13
13
  // Config types are exposed to users for typechecking and we use the same type
14
14
  // in normalization
15
15
  const sidebarItemBaseSchema = utils_validation_1.Joi.object({
16
+ key: utils_validation_1.Joi.string(),
16
17
  className: utils_validation_1.Joi.string(),
17
18
  customProps: utils_validation_1.Joi.object().unknown(),
18
19
  });
@@ -132,6 +133,7 @@ function validateSidebars(sidebars) {
132
133
  });
133
134
  }
134
135
  const categoryMetadataFileSchema = utils_validation_1.Joi.object({
136
+ key: utils_validation_1.Joi.string(),
135
137
  label: utils_validation_1.Joi.string(),
136
138
  description: utils_validation_1.Joi.string(),
137
139
  position: utils_validation_1.Joi.number(),
@@ -11,6 +11,7 @@ exports.translateLoadedContent = translateLoadedContent;
11
11
  const tslib_1 = require("tslib");
12
12
  const lodash_1 = tslib_1.__importDefault(require("lodash"));
13
13
  const utils_1 = require("@docusaurus/utils");
14
+ const logger_1 = tslib_1.__importDefault(require("@docusaurus/logger"));
14
15
  const constants_1 = require("./constants");
15
16
  const utils_2 = require("./sidebars/utils");
16
17
  function getVersionFileName(versionName) {
@@ -21,12 +22,33 @@ function getVersionFileName(versionName) {
21
22
  // but it's for consistency with site/versioned_docs
22
23
  return `version-${versionName}`;
23
24
  }
25
+ function ensureNoSidebarDuplicateEntries(translationEntries) {
26
+ const grouped = lodash_1.default.groupBy(translationEntries, (entry) => entry[0]);
27
+ const duplicates = Object.entries(grouped).filter((entry) => entry[1].length > 1);
28
+ if (duplicates.length > 0) {
29
+ throw new Error(`Multiple docs sidebar items produce the same translation key.
30
+ - ${duplicates
31
+ .map(([translationKey, entries]) => {
32
+ return `${logger_1.default.code(translationKey)}: ${logger_1.default.num(entries.length)} duplicates found:\n - ${entries
33
+ .map((duplicate) => {
34
+ const desc = duplicate[1].description;
35
+ return `${logger_1.default.name(duplicate[1].message)} ${desc ? `(${logger_1.default.subdue(desc)})` : ''}`;
36
+ })
37
+ .join('\n - ')}`;
38
+ })
39
+ .join('\n\n- ')}
40
+
41
+ To avoid translation key conflicts, use the ${logger_1.default.code('key')} attribute on the sidebar items above to uniquely identify them.
42
+ `);
43
+ }
44
+ }
24
45
  function getSidebarTranslationFileContent(sidebar, sidebarName) {
25
46
  const categories = (0, utils_2.collectSidebarCategories)(sidebar);
26
- const categoryContent = Object.fromEntries(categories.flatMap((category) => {
47
+ const categoryEntries = categories.flatMap((category) => {
27
48
  const entries = [];
49
+ const categoryKey = category.key ?? category.label;
28
50
  entries.push([
29
- `sidebar.${sidebarName}.category.${category.label}`,
51
+ `sidebar.${sidebarName}.category.${categoryKey}`,
30
52
  {
31
53
  message: category.label,
32
54
  description: `The label for category ${category.label} in sidebar ${sidebarName}`,
@@ -35,7 +57,7 @@ function getSidebarTranslationFileContent(sidebar, sidebarName) {
35
57
  if (category.link?.type === 'generated-index') {
36
58
  if (category.link.title) {
37
59
  entries.push([
38
- `sidebar.${sidebarName}.category.${category.label}.link.generated-index.title`,
60
+ `sidebar.${sidebarName}.category.${categoryKey}.link.generated-index.title`,
39
61
  {
40
62
  message: category.link.title,
41
63
  description: `The generated-index page title for category ${category.label} in sidebar ${sidebarName}`,
@@ -44,7 +66,7 @@ function getSidebarTranslationFileContent(sidebar, sidebarName) {
44
66
  }
45
67
  if (category.link.description) {
46
68
  entries.push([
47
- `sidebar.${sidebarName}.category.${category.label}.link.generated-index.description`,
69
+ `sidebar.${sidebarName}.category.${categoryKey}.link.generated-index.description`,
48
70
  {
49
71
  message: category.link.description,
50
72
  description: `The generated-index page description for category ${category.label} in sidebar ${sidebarName}`,
@@ -53,26 +75,34 @@ function getSidebarTranslationFileContent(sidebar, sidebarName) {
53
75
  }
54
76
  }
55
77
  return entries;
56
- }));
78
+ });
57
79
  const links = (0, utils_2.collectSidebarLinks)(sidebar);
58
- const linksContent = Object.fromEntries(links.map((link) => [
59
- `sidebar.${sidebarName}.link.${link.label}`,
60
- {
61
- message: link.label,
62
- description: `The label for link ${link.label} in sidebar ${sidebarName}, linking to ${link.href}`,
63
- },
64
- ]));
80
+ const linksEntries = links.map((link) => {
81
+ const linkKey = link.key ?? link.label;
82
+ return [
83
+ `sidebar.${sidebarName}.link.${linkKey}`,
84
+ {
85
+ message: link.label,
86
+ description: `The label for link ${link.label} in sidebar ${sidebarName}, linking to ${link.href}`,
87
+ },
88
+ ];
89
+ });
65
90
  const docs = (0, utils_2.collectSidebarDocItems)(sidebar)
66
91
  .concat((0, utils_2.collectSidebarRefs)(sidebar))
67
92
  .filter((item) => item.translatable);
68
- const docLinksContent = Object.fromEntries(docs.map((doc) => [
69
- `sidebar.${sidebarName}.doc.${doc.label}`,
70
- {
71
- message: doc.label,
72
- description: `The label for the doc item ${doc.label} in sidebar ${sidebarName}, linking to the doc ${doc.id}`,
73
- },
74
- ]));
75
- return (0, utils_1.mergeTranslations)([categoryContent, linksContent, docLinksContent]);
93
+ const docLinksEntries = docs.map((doc) => {
94
+ const docKey = doc.key ?? doc.label;
95
+ return [
96
+ `sidebar.${sidebarName}.doc.${docKey}`,
97
+ {
98
+ message: doc.label,
99
+ description: `The label for the doc item ${doc.label} in sidebar ${sidebarName}, linking to the doc ${doc.id}`,
100
+ },
101
+ ];
102
+ });
103
+ const allEntries = [...categoryEntries, ...linksEntries, ...docLinksEntries];
104
+ ensureNoSidebarDuplicateEntries(allEntries);
105
+ return Object.fromEntries(allEntries);
76
106
  }
77
107
  function translateSidebar({ sidebar, sidebarName, sidebarsTranslations, }) {
78
108
  function transformSidebarCategoryLink(category) {
@@ -93,24 +123,27 @@ function translateSidebar({ sidebar, sidebarName, sidebarsTranslations, }) {
93
123
  return (0, utils_2.transformSidebarItems)(sidebar, (item) => {
94
124
  if (item.type === 'category') {
95
125
  const link = transformSidebarCategoryLink(item);
126
+ const categoryKey = item.key ?? item.label;
96
127
  return {
97
128
  ...item,
98
- label: sidebarsTranslations[`sidebar.${sidebarName}.category.${item.label}`]
129
+ label: sidebarsTranslations[`sidebar.${sidebarName}.category.${categoryKey}`]
99
130
  ?.message ?? item.label,
100
131
  ...(link && { link }),
101
132
  };
102
133
  }
103
134
  if (item.type === 'link') {
135
+ const linkKey = item.key ?? item.label;
104
136
  return {
105
137
  ...item,
106
- label: sidebarsTranslations[`sidebar.${sidebarName}.link.${item.label}`]
138
+ label: sidebarsTranslations[`sidebar.${sidebarName}.link.${linkKey}`]
107
139
  ?.message ?? item.label,
108
140
  };
109
141
  }
110
142
  if ((item.type === 'doc' || item.type === 'ref') && item.translatable) {
143
+ const docKey = item.key ?? item.label;
111
144
  return {
112
145
  ...item,
113
- label: sidebarsTranslations[`sidebar.${sidebarName}.doc.${item.label}`]
146
+ label: sidebarsTranslations[`sidebar.${sidebarName}.doc.${docKey}`]
114
147
  ?.message ?? item.label,
115
148
  };
116
149
  }
@@ -117,11 +117,14 @@ async function readVersionNames(siteDir, options) {
117
117
  */
118
118
  async function getVersionMetadataPaths({ versionName, context, options, }) {
119
119
  const isCurrent = versionName === constants_1.CURRENT_VERSION_NAME;
120
- const contentPathLocalized = getDocsDirPathLocalized({
121
- localizationDir: context.localizationDir,
122
- pluginId: options.id,
123
- versionName,
124
- });
120
+ const shouldTranslate = (0, utils_1.getLocaleConfig)(context.i18n).translate;
121
+ const contentPathLocalized = shouldTranslate
122
+ ? getDocsDirPathLocalized({
123
+ localizationDir: context.localizationDir,
124
+ pluginId: options.id,
125
+ versionName,
126
+ })
127
+ : undefined;
125
128
  const contentPath = isCurrent
126
129
  ? path_1.default.resolve(context.siteDir, options.path)
127
130
  : getVersionDocsDirPath(context.siteDir, options.id, versionName);
@@ -7,9 +7,11 @@
7
7
  import { type DocEnv } from '../docs';
8
8
  import type { LoadedVersion, PluginOptions, VersionMetadata } from '@docusaurus/plugin-content-docs';
9
9
  import type { LoadContext } from '@docusaurus/types';
10
- export declare function loadVersion({ context, options, versionMetadata, env, }: {
10
+ type LoadVersionParams = {
11
11
  context: LoadContext;
12
12
  options: PluginOptions;
13
13
  versionMetadata: VersionMetadata;
14
14
  env: DocEnv;
15
- }): Promise<LoadedVersion>;
15
+ };
16
+ export declare function loadVersion(params: LoadVersionParams): Promise<LoadedVersion>;
17
+ export {};
@@ -16,74 +16,111 @@ const logger_1 = tslib_1.__importDefault(require("@docusaurus/logger"));
16
16
  const docs_1 = require("../docs");
17
17
  const sidebars_1 = require("../sidebars");
18
18
  const utils_2 = require("../sidebars/utils");
19
- async function loadVersion({ context, options, versionMetadata, env, }) {
20
- const { siteDir } = context;
21
- async function loadVersionDocsBase(tagsFile) {
22
- const docFiles = await (0, docs_1.readVersionDocs)(versionMetadata, options);
23
- if (docFiles.length === 0) {
24
- throw new Error(`Docs version "${versionMetadata.versionName}" has no docs! At least one doc should exist at "${path_1.default.relative(siteDir, versionMetadata.contentPath)}".`);
25
- }
26
- function processVersionDoc(docFile) {
27
- return (0, docs_1.processDocMetadata)({
28
- docFile,
29
- versionMetadata,
30
- context,
31
- options,
32
- env,
33
- tagsFile,
34
- });
35
- }
36
- return Promise.all(docFiles.map(processVersionDoc));
19
+ function ensureNoDuplicateDocId(docs) {
20
+ const duplicatesById = lodash_1.default.chain(docs)
21
+ .sort((d1, d2) => {
22
+ // Need to sort because Globby order is non-deterministic
23
+ // TODO maybe we should create a deterministic glob utils?
24
+ // see https://github.com/sindresorhus/globby/issues/131
25
+ return d1.source.localeCompare(d2.source);
26
+ })
27
+ .groupBy((d) => d.id)
28
+ .pickBy((group) => group.length > 1)
29
+ .value();
30
+ const duplicateIdEntries = Object.entries(duplicatesById);
31
+ if (duplicateIdEntries.length) {
32
+ const idMessages = duplicateIdEntries
33
+ .map(([id, duplicateDocs]) => {
34
+ return logger_1.default.interpolate `- code=${id} found in number=${duplicateDocs.length} docs:
35
+ - ${duplicateDocs
36
+ .map((d) => (0, utils_1.aliasedSitePathToRelativePath)(d.source))
37
+ .join('\n - ')}`;
38
+ })
39
+ .join('\n\n');
40
+ const message = `The docs plugin found docs sharing the same id:
41
+ \n${idMessages}\n
42
+ Docs should have distinct ids.
43
+ In case of conflict, you can rename the docs file, or use the ${logger_1.default.code('id')} front matter to assign an explicit distinct id to each doc.
44
+ `;
45
+ throw new Error(message);
37
46
  }
38
- async function doLoadVersion() {
39
- const tagsFile = await (0, utils_validation_1.getTagsFile)({
40
- contentPaths: versionMetadata,
41
- tags: options.tags,
42
- });
43
- const docsBase = await loadVersionDocsBase(tagsFile);
44
- // TODO we only ever need draftIds in further code, not full draft items
45
- // To simplify and prevent mistakes, avoid exposing draft
46
- // replace draft=>draftIds in content loaded
47
- const [drafts, docs] = lodash_1.default.partition(docsBase, (doc) => doc.draft);
48
- const sidebars = await (0, sidebars_1.loadSidebars)(versionMetadata.sidebarFilePath, {
49
- sidebarItemsGenerator: options.sidebarItemsGenerator,
50
- numberPrefixParser: options.numberPrefixParser,
51
- docs,
52
- drafts,
53
- version: versionMetadata,
54
- sidebarOptions: {
55
- sidebarCollapsed: options.sidebarCollapsed,
56
- sidebarCollapsible: options.sidebarCollapsible,
57
- },
58
- categoryLabelSlugger: (0, utils_1.createSlugger)(),
59
- });
60
- const sidebarsUtils = (0, utils_2.createSidebarsUtils)(sidebars);
61
- const docsById = (0, docs_1.createDocsByIdIndex)(docs);
62
- const allDocIds = Object.keys(docsById);
63
- sidebarsUtils.checkLegacyVersionedSidebarNames({
64
- sidebarFilePath: versionMetadata.sidebarFilePath,
65
- versionMetadata,
66
- });
67
- sidebarsUtils.checkSidebarsDocIds({
68
- allDocIds,
69
- sidebarFilePath: versionMetadata.sidebarFilePath,
47
+ }
48
+ async function loadVersionDocsBase({ tagsFile, context, options, versionMetadata, env, }) {
49
+ const docFiles = await (0, docs_1.readVersionDocs)(versionMetadata, options);
50
+ if (docFiles.length === 0) {
51
+ throw new Error(`Docs version "${versionMetadata.versionName}" has no docs! At least one doc should exist at "${path_1.default.relative(context.siteDir, versionMetadata.contentPath)}".`);
52
+ }
53
+ function processVersionDoc(docFile) {
54
+ return (0, docs_1.processDocMetadata)({
55
+ docFile,
70
56
  versionMetadata,
57
+ context,
58
+ options,
59
+ env,
60
+ tagsFile,
71
61
  });
72
- return {
73
- ...versionMetadata,
74
- docs: (0, docs_1.addDocNavigation)({
75
- docs,
76
- sidebarsUtils,
77
- }),
78
- drafts,
79
- sidebars,
80
- };
81
62
  }
63
+ const docs = await Promise.all(docFiles.map(processVersionDoc));
64
+ ensureNoDuplicateDocId(docs);
65
+ return docs;
66
+ }
67
+ async function doLoadVersion({ context, options, versionMetadata, env, }) {
68
+ const tagsFile = await (0, utils_validation_1.getTagsFile)({
69
+ contentPaths: versionMetadata,
70
+ tags: options.tags,
71
+ });
72
+ const docsBase = await loadVersionDocsBase({
73
+ tagsFile,
74
+ context,
75
+ options,
76
+ versionMetadata,
77
+ env,
78
+ });
79
+ // TODO we only ever need draftIds in further code, not full draft items
80
+ // To simplify and prevent mistakes, avoid exposing draft
81
+ // replace draft=>draftIds in content loaded
82
+ const [drafts, docs] = lodash_1.default.partition(docsBase, (doc) => doc.draft);
83
+ const sidebars = await (0, sidebars_1.loadSidebars)(versionMetadata.sidebarFilePath, {
84
+ sidebarItemsGenerator: options.sidebarItemsGenerator,
85
+ numberPrefixParser: options.numberPrefixParser,
86
+ docs,
87
+ drafts,
88
+ version: versionMetadata,
89
+ sidebarOptions: {
90
+ sidebarCollapsed: options.sidebarCollapsed,
91
+ sidebarCollapsible: options.sidebarCollapsible,
92
+ },
93
+ categoryLabelSlugger: (0, utils_1.createSlugger)(),
94
+ });
95
+ const sidebarsUtils = (0, utils_2.createSidebarsUtils)(sidebars);
96
+ const docsById = (0, docs_1.createDocsByIdIndex)(docs);
97
+ const allDocIds = Object.keys(docsById);
98
+ sidebarsUtils.checkLegacyVersionedSidebarNames({
99
+ sidebarFilePath: versionMetadata.sidebarFilePath,
100
+ versionMetadata,
101
+ });
102
+ sidebarsUtils.checkSidebarsDocIds({
103
+ allDocIds,
104
+ sidebarFilePath: versionMetadata.sidebarFilePath,
105
+ versionMetadata,
106
+ });
107
+ return {
108
+ ...versionMetadata,
109
+ docs: (0, docs_1.addDocNavigation)({
110
+ docs,
111
+ sidebarsUtils,
112
+ }),
113
+ drafts,
114
+ sidebars,
115
+ };
116
+ }
117
+ async function loadVersion(params) {
82
118
  try {
83
- return await doLoadVersion();
119
+ return await doLoadVersion(params);
84
120
  }
85
121
  catch (err) {
86
- logger_1.default.error `Loading of version failed for version name=${versionMetadata.versionName}`;
122
+ // TODO use error cause (but need to refactor many tests)
123
+ logger_1.default.error `Loading of version failed for version name=${params.versionMetadata.versionName}`;
87
124
  throw err;
88
125
  }
89
126
  }
@@ -28,22 +28,32 @@ function getVersionEditUrls({ contentPath, contentPathLocalized, context, option
28
28
  if (!options.editUrl || typeof options.editUrl === 'function') {
29
29
  return { editUrl: undefined, editUrlLocalized: undefined };
30
30
  }
31
- const editDirPath = options.editCurrentVersion ? options.path : contentPath;
32
- const editDirPathLocalized = options.editCurrentVersion
33
- ? (0, files_1.getDocsDirPathLocalized)({
34
- localizationDir: context.localizationDir,
35
- versionName: constants_1.CURRENT_VERSION_NAME,
36
- pluginId: options.id,
37
- })
38
- : contentPathLocalized;
39
- const versionPathSegment = (0, utils_1.posixPath)(path_1.default.relative(context.siteDir, path_1.default.resolve(context.siteDir, editDirPath)));
40
- const versionPathSegmentLocalized = (0, utils_1.posixPath)(path_1.default.relative(context.siteDir, path_1.default.resolve(context.siteDir, editDirPathLocalized)));
41
- const editUrl = (0, utils_1.normalizeUrl)([options.editUrl, versionPathSegment]);
42
- const editUrlLocalized = (0, utils_1.normalizeUrl)([
43
- options.editUrl,
44
- versionPathSegmentLocalized,
45
- ]);
46
- return { editUrl, editUrlLocalized };
31
+ // Intermediate var just to please TS not narrowing to "string"
32
+ const editUrlOption = options.editUrl;
33
+ const getEditUrl = () => {
34
+ const editDirPath = options.editCurrentVersion ? options.path : contentPath;
35
+ return (0, utils_1.normalizeUrl)([
36
+ editUrlOption,
37
+ (0, utils_1.posixPath)(path_1.default.relative(context.siteDir, path_1.default.resolve(context.siteDir, editDirPath))),
38
+ ]);
39
+ };
40
+ const getEditUrlLocalized = () => {
41
+ if (!contentPathLocalized) {
42
+ return undefined;
43
+ }
44
+ const editDirPathLocalized = options.editCurrentVersion
45
+ ? (0, files_1.getDocsDirPathLocalized)({
46
+ localizationDir: context.localizationDir,
47
+ versionName: constants_1.CURRENT_VERSION_NAME,
48
+ pluginId: options.id,
49
+ })
50
+ : contentPathLocalized;
51
+ return (0, utils_1.normalizeUrl)([
52
+ editUrlOption,
53
+ (0, utils_1.posixPath)(path_1.default.relative(context.siteDir, path_1.default.resolve(context.siteDir, editDirPathLocalized))),
54
+ ]);
55
+ };
56
+ return { editUrl: getEditUrl(), editUrlLocalized: getEditUrlLocalized() };
47
57
  }
48
58
  /**
49
59
  * The default version banner depends on the version's relative position to the
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@docusaurus/plugin-content-docs",
3
- "version": "3.8.1",
3
+ "version": "3.9.0-canary-6406",
4
4
  "description": "Docs plugin for Docusaurus.",
5
5
  "main": "lib/index.js",
6
6
  "sideEffects": false,
@@ -35,15 +35,15 @@
35
35
  },
36
36
  "license": "MIT",
37
37
  "dependencies": {
38
- "@docusaurus/core": "3.8.1",
39
- "@docusaurus/logger": "3.8.1",
40
- "@docusaurus/mdx-loader": "3.8.1",
41
- "@docusaurus/module-type-aliases": "3.8.1",
42
- "@docusaurus/theme-common": "3.8.1",
43
- "@docusaurus/types": "3.8.1",
44
- "@docusaurus/utils": "3.8.1",
45
- "@docusaurus/utils-common": "3.8.1",
46
- "@docusaurus/utils-validation": "3.8.1",
38
+ "@docusaurus/core": "3.9.0-canary-6406",
39
+ "@docusaurus/logger": "3.9.0-canary-6406",
40
+ "@docusaurus/mdx-loader": "3.9.0-canary-6406",
41
+ "@docusaurus/module-type-aliases": "3.9.0-canary-6406",
42
+ "@docusaurus/theme-common": "3.9.0-canary-6406",
43
+ "@docusaurus/types": "3.9.0-canary-6406",
44
+ "@docusaurus/utils": "3.9.0-canary-6406",
45
+ "@docusaurus/utils-common": "3.9.0-canary-6406",
46
+ "@docusaurus/utils-validation": "3.9.0-canary-6406",
47
47
  "@types/react-router-config": "^5.0.7",
48
48
  "combine-promises": "^1.1.0",
49
49
  "fs-extra": "^11.1.1",
@@ -65,7 +65,7 @@
65
65
  "react-dom": "^18.0.0 || ^19.0.0"
66
66
  },
67
67
  "engines": {
68
- "node": ">=18.0"
68
+ "node": ">=20.0"
69
69
  },
70
- "gitHead": "fa8ae13e668fcbc0481ce10c0a734e2a5b397293"
70
+ "gitHead": "796441f4f831278ffc57971fabcd4c730da9e9d7"
71
71
  }
package/src/cli.ts CHANGED
@@ -8,7 +8,7 @@
8
8
  import fs from 'fs-extra';
9
9
  import path from 'path';
10
10
  import logger from '@docusaurus/logger';
11
- import {DEFAULT_PLUGIN_ID} from '@docusaurus/utils';
11
+ import {DEFAULT_PLUGIN_ID, getLocaleConfig} from '@docusaurus/utils';
12
12
  import {
13
13
  getVersionsFilePath,
14
14
  getVersionDocsDirPath,
@@ -89,7 +89,7 @@ async function cliDocsVersionCommand(
89
89
  const localizationDir = path.resolve(
90
90
  siteDir,
91
91
  i18n.path,
92
- i18n.localeConfigs[locale]!.path,
92
+ getLocaleConfig(i18n, locale).path,
93
93
  );
94
94
  // Copy docs files.
95
95
  const docsDir =
package/src/docs.ts CHANGED
@@ -196,7 +196,9 @@ async function doProcessDocMetadata({
196
196
  locale: context.i18n.currentLocale,
197
197
  });
198
198
  } else if (typeof options.editUrl === 'string') {
199
- const isLocalized = contentPath === versionMetadata.contentPathLocalized;
199
+ const isLocalized =
200
+ typeof versionMetadata.contentPathLocalized !== 'undefined' &&
201
+ contentPath === versionMetadata.contentPathLocalized;
200
202
  const baseVersionEditUrl =
201
203
  isLocalized && options.editLocalizedFiles
202
204
  ? versionMetadata.editUrlLocalized