@docusaurus/plugin-content-docs 3.3.2 → 3.4.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/docs.d.ts CHANGED
@@ -5,6 +5,7 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
  /// <reference path="../src/plugin-content-docs.d.ts" />
8
+ import type { TagsFile } from '@docusaurus/utils';
8
9
  import type { MetadataOptions, PluginOptions, CategoryIndexMatcher, DocMetadataBase, VersionMetadata, LoadedVersion } from '@docusaurus/plugin-content-docs';
9
10
  import type { LoadContext } from '@docusaurus/types';
10
11
  import type { SidebarsUtils } from './sidebars/utils';
@@ -18,6 +19,7 @@ export declare function processDocMetadata(args: {
18
19
  context: LoadContext;
19
20
  options: MetadataOptions;
20
21
  env: DocEnv;
22
+ tagsFile: TagsFile | null;
21
23
  }): Promise<DocMetadataBase>;
22
24
  export declare function addDocNavigation({ docs, sidebarsUtils, }: {
23
25
  docs: DocMetadataBase[];
package/lib/docs.js CHANGED
@@ -31,7 +31,7 @@ async function readVersionDocs(versionMetadata, options) {
31
31
  return Promise.all(sources.map((source) => readDocFile(versionMetadata, source)));
32
32
  }
33
33
  exports.readVersionDocs = readVersionDocs;
34
- async function doProcessDocMetadata({ docFile, versionMetadata, context, options, env, }) {
34
+ async function doProcessDocMetadata({ docFile, versionMetadata, context, options, env, tagsFile, }) {
35
35
  const { source, content, contentPath, filePath } = docFile;
36
36
  const { siteDir, siteConfig: { markdown: { parseFrontMatter }, }, } = context;
37
37
  const { frontMatter: unsafeFrontMatter, contentTitle, excerpt, } = await (0, utils_1.parseMarkdownFile)({
@@ -108,6 +108,13 @@ async function doProcessDocMetadata({ docFile, versionMetadata, context, options
108
108
  }
109
109
  const draft = (0, utils_1.isDraft)({ env, frontMatter });
110
110
  const unlisted = (0, utils_1.isUnlisted)({ env, frontMatter });
111
+ const tags = (0, utils_1.normalizeTags)({
112
+ options,
113
+ source,
114
+ frontMatterTags: frontMatter.tags,
115
+ tagsBaseRoutePath: versionMetadata.tagsPath,
116
+ tagsFile,
117
+ });
111
118
  // Assign all of object properties during instantiation (if possible) for
112
119
  // NodeJS optimization.
113
120
  // Adding properties to object after instantiation will cause hidden
@@ -123,7 +130,7 @@ async function doProcessDocMetadata({ docFile, versionMetadata, context, options
123
130
  draft,
124
131
  unlisted,
125
132
  editUrl: customEditURL !== undefined ? customEditURL : getDocEditUrl(),
126
- tags: (0, utils_1.normalizeFrontMatterTags)(versionMetadata.tagsPath, frontMatter.tags),
133
+ tags,
127
134
  version: versionMetadata.versionName,
128
135
  lastUpdatedBy: lastUpdate.lastUpdatedBy,
129
136
  lastUpdatedAt: lastUpdate.lastUpdatedAt,
package/lib/index.js CHANGED
@@ -12,6 +12,7 @@ const path_1 = tslib_1.__importDefault(require("path"));
12
12
  const lodash_1 = tslib_1.__importDefault(require("lodash"));
13
13
  const logger_1 = tslib_1.__importDefault(require("@docusaurus/logger"));
14
14
  const utils_1 = require("@docusaurus/utils");
15
+ const utils_validation_1 = require("@docusaurus/utils-validation");
15
16
  const sidebars_1 = require("./sidebars");
16
17
  const generator_1 = require("./sidebars/generator");
17
18
  const docs_1 = require("./docs");
@@ -22,6 +23,25 @@ const globalData_1 = require("./globalData");
22
23
  const translations_1 = require("./translations");
23
24
  const routes_1 = require("./routes");
24
25
  const utils_2 = require("./sidebars/utils");
26
+ // TODO this is bad, we should have a better way to do this (new lifecycle?)
27
+ // The source to permalink is currently a mutable map passed to the mdx loader
28
+ // for link resolution
29
+ // see https://github.com/facebook/docusaurus/pull/10185
30
+ function createSourceToPermalinkHelper() {
31
+ const sourceToPermalink = new Map();
32
+ function computeSourceToPermalink(content) {
33
+ const allDocs = content.loadedVersions.flatMap((v) => v.docs);
34
+ return new Map(allDocs.map(({ source, permalink }) => [source, permalink]));
35
+ }
36
+ // Mutable map update :/
37
+ function update(content) {
38
+ sourceToPermalink.clear();
39
+ computeSourceToPermalink(content).forEach((value, key) => {
40
+ sourceToPermalink.set(key, value);
41
+ });
42
+ }
43
+ return { get: () => sourceToPermalink, update };
44
+ }
25
45
  async function pluginContentDocs(context, options) {
26
46
  const { siteDir, generatedFilesDir, baseUrl, siteConfig } = context;
27
47
  // Mutate options to resolve sidebar path according to siteDir
@@ -36,6 +56,7 @@ async function pluginContentDocs(context, options) {
36
56
  const aliasedSource = (source) => `~docs/${(0, utils_1.posixPath)(path_1.default.relative(pluginDataDirRoot, source))}`;
37
57
  // TODO env should be injected into all plugins
38
58
  const env = process.env.NODE_ENV;
59
+ const sourceToPermalinkHelper = createSourceToPermalinkHelper();
39
60
  return {
40
61
  name: 'docusaurus-plugin-content-docs',
41
62
  extendCli(cli) {
@@ -61,6 +82,10 @@ async function pluginContentDocs(context, options) {
61
82
  function getVersionPathsToWatch(version) {
62
83
  const result = [
63
84
  ...options.include.flatMap((pattern) => (0, utils_1.getContentPathList)(version).map((docsDirPath) => `${docsDirPath}/${pattern}`)),
85
+ ...(0, utils_validation_1.getTagsFilePathsToWatch)({
86
+ contentPaths: version,
87
+ tags: options.tags,
88
+ }),
64
89
  `${version.contentPath}/**/${generator_1.CategoryMetadataFilenamePattern}`,
65
90
  ];
66
91
  if (typeof version.sidebarFilePath === 'string') {
@@ -71,7 +96,7 @@ async function pluginContentDocs(context, options) {
71
96
  return versionsMetadata.flatMap(getVersionPathsToWatch);
72
97
  },
73
98
  async loadContent() {
74
- async function loadVersionDocsBase(versionMetadata) {
99
+ async function loadVersionDocsBase(versionMetadata, tagsFile) {
75
100
  const docFiles = await (0, docs_1.readVersionDocs)(versionMetadata, options);
76
101
  if (docFiles.length === 0) {
77
102
  throw new Error(`Docs version "${versionMetadata.versionName}" has no docs! At least one doc should exist at "${path_1.default.relative(siteDir, versionMetadata.contentPath)}".`);
@@ -83,12 +108,17 @@ async function pluginContentDocs(context, options) {
83
108
  context,
84
109
  options,
85
110
  env,
111
+ tagsFile,
86
112
  });
87
113
  }
88
114
  return Promise.all(docFiles.map(processVersionDoc));
89
115
  }
90
116
  async function doLoadVersion(versionMetadata) {
91
- const docsBase = await loadVersionDocsBase(versionMetadata);
117
+ const tagsFile = await (0, utils_validation_1.getTagsFile)({
118
+ contentPaths: versionMetadata,
119
+ tags: options.tags,
120
+ });
121
+ const docsBase = await loadVersionDocsBase(versionMetadata, tagsFile);
92
122
  // TODO we only ever need draftIds in further code, not full draft items
93
123
  // To simplify and prevent mistakes, avoid exposing draft
94
124
  // replace draft=>draftIds in content loaded
@@ -144,6 +174,7 @@ async function pluginContentDocs(context, options) {
144
174
  return (0, translations_1.translateLoadedContent)(content, translationFiles);
145
175
  },
146
176
  async contentLoaded({ content, actions }) {
177
+ sourceToPermalinkHelper.update(content);
147
178
  const versions = content.loadedVersions.map(versions_1.toFullVersion);
148
179
  await (0, routes_1.createAllRoutes)({
149
180
  baseUrl,
@@ -160,57 +191,49 @@ async function pluginContentDocs(context, options) {
160
191
  },
161
192
  configureWebpack(_config, isServer, utils, content) {
162
193
  const { rehypePlugins, remarkPlugins, beforeDefaultRehypePlugins, beforeDefaultRemarkPlugins, } = options;
163
- function getSourceToPermalink() {
164
- const allDocs = content.loadedVersions.flatMap((v) => v.docs);
165
- return Object.fromEntries(allDocs.map(({ source, permalink }) => [source, permalink]));
166
- }
167
- const docsMarkdownOptions = {
168
- siteDir,
169
- sourceToPermalink: getSourceToPermalink(),
170
- versionsMetadata,
171
- onBrokenMarkdownLink: (brokenMarkdownLink) => {
172
- logger_1.default.report(siteConfig.onBrokenMarkdownLinks) `Docs markdown link couldn't be resolved: (url=${brokenMarkdownLink.link}) in path=${brokenMarkdownLink.filePath} for version number=${brokenMarkdownLink.contentPaths.versionName}`;
173
- },
174
- };
175
- function createMDXLoaderRule() {
176
- const contentDirs = versionsMetadata
177
- .flatMap(utils_1.getContentPathList)
178
- // Trailing slash is important, see https://github.com/facebook/docusaurus/pull/3970
179
- .map(utils_1.addTrailingPathSeparator);
194
+ const contentDirs = versionsMetadata
195
+ .flatMap(utils_1.getContentPathList)
196
+ // Trailing slash is important, see https://github.com/facebook/docusaurus/pull/3970
197
+ .map(utils_1.addTrailingPathSeparator);
198
+ function createMDXLoader() {
199
+ const loaderOptions = {
200
+ admonitions: options.admonitions,
201
+ remarkPlugins,
202
+ rehypePlugins,
203
+ beforeDefaultRehypePlugins,
204
+ beforeDefaultRemarkPlugins,
205
+ staticDirs: siteConfig.staticDirectories.map((dir) => path_1.default.resolve(siteDir, dir)),
206
+ siteDir,
207
+ isMDXPartial: (0, utils_1.createAbsoluteFilePathMatcher)(options.exclude, contentDirs),
208
+ metadataPath: (mdxPath) => {
209
+ // Note that metadataPath must be the same/in-sync as
210
+ // the path from createData for each MDX.
211
+ const aliasedPath = (0, utils_1.aliasedSitePath)(mdxPath, siteDir);
212
+ return path_1.default.join(dataDir, `${(0, utils_1.docuHash)(aliasedPath)}.json`);
213
+ },
214
+ // Assets allow to convert some relative images paths to
215
+ // require(...) calls
216
+ createAssets: ({ frontMatter }) => ({
217
+ image: frontMatter.image,
218
+ }),
219
+ markdownConfig: siteConfig.markdown,
220
+ resolveMarkdownLink: ({ linkPathname, sourceFilePath }) => {
221
+ const version = (0, versions_1.getVersionFromSourceFilePath)(sourceFilePath, content.loadedVersions);
222
+ const permalink = (0, utils_1.resolveMarkdownLinkPathname)(linkPathname, {
223
+ sourceFilePath,
224
+ sourceToPermalink: sourceToPermalinkHelper.get(),
225
+ siteDir,
226
+ contentPaths: version,
227
+ });
228
+ if (permalink === null) {
229
+ 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}`;
230
+ }
231
+ return permalink;
232
+ },
233
+ };
180
234
  return {
181
- test: /\.mdx?$/i,
182
- include: contentDirs,
183
- use: [
184
- {
185
- loader: require.resolve('@docusaurus/mdx-loader'),
186
- options: {
187
- admonitions: options.admonitions,
188
- remarkPlugins,
189
- rehypePlugins,
190
- beforeDefaultRehypePlugins,
191
- beforeDefaultRemarkPlugins,
192
- staticDirs: siteConfig.staticDirectories.map((dir) => path_1.default.resolve(siteDir, dir)),
193
- siteDir,
194
- isMDXPartial: (0, utils_1.createAbsoluteFilePathMatcher)(options.exclude, contentDirs),
195
- metadataPath: (mdxPath) => {
196
- // Note that metadataPath must be the same/in-sync as
197
- // the path from createData for each MDX.
198
- const aliasedPath = (0, utils_1.aliasedSitePath)(mdxPath, siteDir);
199
- return path_1.default.join(dataDir, `${(0, utils_1.docuHash)(aliasedPath)}.json`);
200
- },
201
- // Assets allow to convert some relative images paths to
202
- // require(...) calls
203
- createAssets: ({ frontMatter, }) => ({
204
- image: frontMatter.image,
205
- }),
206
- markdownConfig: siteConfig.markdown,
207
- },
208
- },
209
- {
210
- loader: path_1.default.resolve(__dirname, './markdown/index.js'),
211
- options: docsMarkdownOptions,
212
- },
213
- ].filter(Boolean),
235
+ loader: require.resolve('@docusaurus/mdx-loader'),
236
+ options: loaderOptions,
214
237
  };
215
238
  }
216
239
  return {
@@ -225,7 +248,13 @@ async function pluginContentDocs(context, options) {
225
248
  },
226
249
  },
227
250
  module: {
228
- rules: [createMDXLoaderRule()],
251
+ rules: [
252
+ {
253
+ test: /\.mdx?$/i,
254
+ include: contentDirs,
255
+ use: [createMDXLoader()],
256
+ },
257
+ ],
229
258
  },
230
259
  };
231
260
  },
package/lib/options.js CHANGED
@@ -44,6 +44,8 @@ exports.DEFAULT_OPTIONS = {
44
44
  sidebarCollapsible: true,
45
45
  sidebarCollapsed: true,
46
46
  breadcrumbs: true,
47
+ onInlineTags: 'warn',
48
+ tags: undefined,
47
49
  };
48
50
  const VersionOptionsSchema = utils_validation_1.Joi.object({
49
51
  path: utils_validation_1.Joi.string().allow('').optional(),
@@ -100,6 +102,13 @@ const OptionsSchema = utils_validation_1.Joi.object({
100
102
  lastVersion: utils_validation_1.Joi.string().optional(),
101
103
  versions: VersionsOptionsSchema,
102
104
  breadcrumbs: utils_validation_1.Joi.bool().default(exports.DEFAULT_OPTIONS.breadcrumbs),
105
+ onInlineTags: utils_validation_1.Joi.string()
106
+ .equal('ignore', 'log', 'warn', 'throw')
107
+ .default(exports.DEFAULT_OPTIONS.onInlineTags),
108
+ tags: utils_validation_1.Joi.string()
109
+ .disallow('')
110
+ .allow(null, false)
111
+ .default(() => exports.DEFAULT_OPTIONS.tags),
103
112
  });
104
113
  function validateOptions({ validate, options: userOptions, }) {
105
114
  let options = userOptions;
package/lib/props.js CHANGED
@@ -134,6 +134,7 @@ function toTagDocListProp({ allTagsPath, tag, docs, }) {
134
134
  return {
135
135
  label: tag.label,
136
136
  permalink: tag.permalink,
137
+ description: tag.description,
137
138
  allTagsPath,
138
139
  count: tag.docIds.length,
139
140
  items: toDocListProp(),
@@ -147,6 +148,7 @@ function toTagsListTagsProp(versionTags) {
147
148
  .map((tagValue) => ({
148
149
  label: tagValue.label,
149
150
  permalink: tagValue.permalink,
151
+ description: tagValue.description,
150
152
  count: tagValue.docIds.length,
151
153
  }));
152
154
  }
package/lib/routes.js CHANGED
@@ -12,7 +12,6 @@ const lodash_1 = tslib_1.__importDefault(require("lodash"));
12
12
  const logger_1 = tslib_1.__importDefault(require("@docusaurus/logger"));
13
13
  const utils_1 = require("@docusaurus/utils");
14
14
  const props_1 = require("./props");
15
- const tags_1 = require("./tags");
16
15
  function createDocRouteMetadata(docMeta) {
17
16
  return {
18
17
  sourceFilePath: (0, utils_1.aliasedSitePathToRelativePath)(docMeta.source),
@@ -74,12 +73,30 @@ async function buildVersionSidebarRoute(param) {
74
73
  routes: subRoutes,
75
74
  };
76
75
  }
76
+ function getVersionTags(docs) {
77
+ const groups = (0, utils_1.groupTaggedItems)(docs, (doc) => doc.tags);
78
+ return lodash_1.default.mapValues(groups, ({ tag, items: tagDocs }) => {
79
+ const tagVisibility = (0, utils_1.getTagVisibility)({
80
+ items: tagDocs,
81
+ isUnlisted: (item) => item.unlisted,
82
+ });
83
+ return {
84
+ inline: tag.inline,
85
+ label: tag.label,
86
+ permalink: tag.permalink,
87
+ description: tag.description,
88
+ docIds: tagVisibility.listedItems.map((item) => item.id),
89
+ unlisted: tagVisibility.unlisted,
90
+ };
91
+ });
92
+ }
77
93
  async function buildVersionTagsRoutes(param) {
78
94
  const { version, options } = param;
79
- const versionTags = (0, tags_1.getVersionTags)(version.docs);
95
+ const versionTags = getVersionTags(version.docs);
80
96
  async function buildTagsListRoute() {
97
+ const tags = (0, props_1.toTagsListTagsProp)(versionTags);
81
98
  // Don't create a tags list page if there's no tag
82
- if (Object.keys(versionTags).length === 0) {
99
+ if (tags.length === 0) {
83
100
  return null;
84
101
  }
85
102
  return {
@@ -87,7 +104,7 @@ async function buildVersionTagsRoutes(param) {
87
104
  exact: true,
88
105
  component: options.docTagsListComponent,
89
106
  props: {
90
- tags: (0, props_1.toTagsListTagsProp)(versionTags),
107
+ tags,
91
108
  },
92
109
  };
93
110
  }
package/lib/types.d.ts CHANGED
@@ -5,8 +5,8 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
  /// <reference path="../src/plugin-content-docs.d.ts" />
8
- import type { BrokenMarkdownLink, Tag } from '@docusaurus/utils';
9
- import type { VersionMetadata, LoadedVersion, CategoryGeneratedIndexMetadata } from '@docusaurus/plugin-content-docs';
8
+ import type { TagMetadata } from '@docusaurus/utils';
9
+ import type { LoadedVersion, CategoryGeneratedIndexMetadata } from '@docusaurus/plugin-content-docs';
10
10
  import type { SidebarsUtils } from './sidebars/utils';
11
11
  export type DocFile = {
12
12
  contentPath: string;
@@ -14,10 +14,7 @@ export type DocFile = {
14
14
  source: string;
15
15
  content: string;
16
16
  };
17
- export type SourceToPermalink = {
18
- [source: string]: string;
19
- };
20
- export type VersionTag = Tag & {
17
+ export type VersionTag = TagMetadata & {
21
18
  /** All doc ids having this tag. */
22
19
  docIds: string[];
23
20
  unlisted: boolean;
@@ -29,10 +26,3 @@ export type FullVersion = LoadedVersion & {
29
26
  sidebarsUtils: SidebarsUtils;
30
27
  categoryGeneratedIndices: CategoryGeneratedIndexMetadata[];
31
28
  };
32
- export type DocBrokenMarkdownLink = BrokenMarkdownLink<VersionMetadata>;
33
- export type DocsMarkdownOption = {
34
- versionsMetadata: VersionMetadata[];
35
- siteDir: string;
36
- sourceToPermalink: SourceToPermalink;
37
- onBrokenMarkdownLink: (brokenMarkdownLink: DocBrokenMarkdownLink) => void;
38
- };
@@ -38,3 +38,4 @@ export declare function readVersionsMetadata({ context, options, }: {
38
38
  options: PluginOptions;
39
39
  }): Promise<VersionMetadata[]>;
40
40
  export declare function toFullVersion(version: LoadedVersion): FullVersion;
41
+ export declare function getVersionFromSourceFilePath(filePath: string, versionsMetadata: VersionMetadata[]): VersionMetadata;
@@ -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.toFullVersion = exports.readVersionsMetadata = exports.filterVersions = exports.getVersionNoIndex = exports.getVersionBadge = exports.getVersionBanner = exports.getDefaultVersionBanner = void 0;
9
+ exports.getVersionFromSourceFilePath = exports.toFullVersion = exports.readVersionsMetadata = exports.filterVersions = exports.getVersionNoIndex = exports.getVersionBadge = exports.getVersionBanner = exports.getDefaultVersionBanner = void 0;
10
10
  const tslib_1 = require("tslib");
11
11
  const path_1 = tslib_1.__importDefault(require("path"));
12
12
  const utils_1 = require("@docusaurus/utils");
@@ -171,3 +171,11 @@ function toFullVersion(version) {
171
171
  };
172
172
  }
173
173
  exports.toFullVersion = toFullVersion;
174
+ function getVersionFromSourceFilePath(filePath, versionsMetadata) {
175
+ const versionFound = versionsMetadata.find((version) => (0, utils_1.getContentPathList)(version).some((docsDirPath) => filePath.startsWith(docsDirPath)));
176
+ if (!versionFound) {
177
+ throw new Error(`Unexpected error: file at "${filePath}" does not belong to any docs version!`);
178
+ }
179
+ return versionFound;
180
+ }
181
+ exports.getVersionFromSourceFilePath = getVersionFromSourceFilePath;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@docusaurus/plugin-content-docs",
3
- "version": "3.3.2",
3
+ "version": "3.4.0",
4
4
  "description": "Docs plugin for Docusaurus.",
5
5
  "main": "lib/index.js",
6
6
  "sideEffects": false,
@@ -35,14 +35,14 @@
35
35
  },
36
36
  "license": "MIT",
37
37
  "dependencies": {
38
- "@docusaurus/core": "3.3.2",
39
- "@docusaurus/logger": "3.3.2",
40
- "@docusaurus/mdx-loader": "3.3.2",
41
- "@docusaurus/module-type-aliases": "3.3.2",
42
- "@docusaurus/types": "3.3.2",
43
- "@docusaurus/utils": "3.3.2",
44
- "@docusaurus/utils-common": "3.3.2",
45
- "@docusaurus/utils-validation": "3.3.2",
38
+ "@docusaurus/core": "3.4.0",
39
+ "@docusaurus/logger": "3.4.0",
40
+ "@docusaurus/mdx-loader": "3.4.0",
41
+ "@docusaurus/module-type-aliases": "3.4.0",
42
+ "@docusaurus/types": "3.4.0",
43
+ "@docusaurus/utils": "3.4.0",
44
+ "@docusaurus/utils-common": "3.4.0",
45
+ "@docusaurus/utils-validation": "3.4.0",
46
46
  "@types/react-router-config": "^5.0.7",
47
47
  "combine-promises": "^1.1.0",
48
48
  "fs-extra": "^11.1.1",
@@ -66,5 +66,5 @@
66
66
  "engines": {
67
67
  "node": ">=18.0"
68
68
  },
69
- "gitHead": "bc638d674bfbde1e254ef306697f47e764b5e107"
69
+ "gitHead": "49e9a2143274a8dd795659b417b470bc42abbd6e"
70
70
  }
package/src/docs.ts CHANGED
@@ -17,15 +17,16 @@ import {
17
17
  parseMarkdownFile,
18
18
  posixPath,
19
19
  Globby,
20
- normalizeFrontMatterTags,
21
20
  isUnlisted,
22
21
  isDraft,
23
22
  readLastUpdateData,
23
+ normalizeTags,
24
24
  } from '@docusaurus/utils';
25
25
  import {validateDocFrontMatter} from './frontMatter';
26
26
  import getSlug from './slug';
27
27
  import {stripPathNumberPrefixes} from './numberPrefix';
28
28
  import {toDocNavigationLink, toNavigationLink} from './sidebars/utils';
29
+ import type {TagsFile} from '@docusaurus/utils';
29
30
  import type {
30
31
  MetadataOptions,
31
32
  PluginOptions,
@@ -82,12 +83,14 @@ async function doProcessDocMetadata({
82
83
  context,
83
84
  options,
84
85
  env,
86
+ tagsFile,
85
87
  }: {
86
88
  docFile: DocFile;
87
89
  versionMetadata: VersionMetadata;
88
90
  context: LoadContext;
89
91
  options: MetadataOptions;
90
92
  env: DocEnv;
93
+ tagsFile: TagsFile | null;
91
94
  }): Promise<DocMetadataBase> {
92
95
  const {source, content, contentPath, filePath} = docFile;
93
96
  const {
@@ -206,6 +209,14 @@ async function doProcessDocMetadata({
206
209
  const draft = isDraft({env, frontMatter});
207
210
  const unlisted = isUnlisted({env, frontMatter});
208
211
 
212
+ const tags = normalizeTags({
213
+ options,
214
+ source,
215
+ frontMatterTags: frontMatter.tags,
216
+ tagsBaseRoutePath: versionMetadata.tagsPath,
217
+ tagsFile,
218
+ });
219
+
209
220
  // Assign all of object properties during instantiation (if possible) for
210
221
  // NodeJS optimization.
211
222
  // Adding properties to object after instantiation will cause hidden
@@ -221,7 +232,7 @@ async function doProcessDocMetadata({
221
232
  draft,
222
233
  unlisted,
223
234
  editUrl: customEditURL !== undefined ? customEditURL : getDocEditUrl(),
224
- tags: normalizeFrontMatterTags(versionMetadata.tagsPath, frontMatter.tags),
235
+ tags,
225
236
  version: versionMetadata.versionName,
226
237
  lastUpdatedBy: lastUpdate.lastUpdatedBy,
227
238
  lastUpdatedAt: lastUpdate.lastUpdatedAt,
@@ -236,6 +247,7 @@ export async function processDocMetadata(args: {
236
247
  context: LoadContext;
237
248
  options: MetadataOptions;
238
249
  env: DocEnv;
250
+ tagsFile: TagsFile | null;
239
251
  }): Promise<DocMetadataBase> {
240
252
  try {
241
253
  return await doProcessDocMetadata(args);
package/src/index.ts CHANGED
@@ -17,8 +17,15 @@ import {
17
17
  addTrailingPathSeparator,
18
18
  createAbsoluteFilePathMatcher,
19
19
  createSlugger,
20
+ resolveMarkdownLinkPathname,
20
21
  DEFAULT_PLUGIN_ID,
22
+ type SourceToPermalink,
23
+ type TagsFile,
21
24
  } from '@docusaurus/utils';
25
+ import {
26
+ getTagsFile,
27
+ getTagsFilePathsToWatch,
28
+ } from '@docusaurus/utils-validation';
22
29
  import {loadSidebars, resolveSidebarPathOption} from './sidebars';
23
30
  import {CategoryMetadataFilenamePattern} from './sidebars/generator';
24
31
  import {
@@ -28,7 +35,11 @@ import {
28
35
  type DocEnv,
29
36
  createDocsByIdIndex,
30
37
  } from './docs';
31
- import {readVersionsMetadata, toFullVersion} from './versions';
38
+ import {
39
+ getVersionFromSourceFilePath,
40
+ readVersionsMetadata,
41
+ toFullVersion,
42
+ } from './versions';
32
43
  import {cliDocsVersionCommand} from './cli';
33
44
  import {VERSIONS_JSON_FILE} from './constants';
34
45
  import {toGlobalDataVersion} from './globalData';
@@ -38,6 +49,7 @@ import {
38
49
  } from './translations';
39
50
  import {createAllRoutes} from './routes';
40
51
  import {createSidebarsUtils} from './sidebars/utils';
52
+ import type {Options as MDXLoaderOptions} from '@docusaurus/mdx-loader';
41
53
 
42
54
  import type {
43
55
  PluginOptions,
@@ -48,13 +60,31 @@ import type {
48
60
  LoadedVersion,
49
61
  } from '@docusaurus/plugin-content-docs';
50
62
  import type {LoadContext, Plugin} from '@docusaurus/types';
51
- import type {
52
- SourceToPermalink,
53
- DocFile,
54
- DocsMarkdownOption,
55
- FullVersion,
56
- } from './types';
57
- import type {RuleSetRule} from 'webpack';
63
+ import type {DocFile, FullVersion} from './types';
64
+ import type {RuleSetUseItem} from 'webpack';
65
+
66
+ // TODO this is bad, we should have a better way to do this (new lifecycle?)
67
+ // The source to permalink is currently a mutable map passed to the mdx loader
68
+ // for link resolution
69
+ // see https://github.com/facebook/docusaurus/pull/10185
70
+ function createSourceToPermalinkHelper() {
71
+ const sourceToPermalink: SourceToPermalink = new Map();
72
+
73
+ function computeSourceToPermalink(content: LoadedContent): SourceToPermalink {
74
+ const allDocs = content.loadedVersions.flatMap((v) => v.docs);
75
+ return new Map(allDocs.map(({source, permalink}) => [source, permalink]));
76
+ }
77
+
78
+ // Mutable map update :/
79
+ function update(content: LoadedContent): void {
80
+ sourceToPermalink.clear();
81
+ computeSourceToPermalink(content).forEach((value, key) => {
82
+ sourceToPermalink.set(key, value);
83
+ });
84
+ }
85
+
86
+ return {get: () => sourceToPermalink, update};
87
+ }
58
88
 
59
89
  export default async function pluginContentDocs(
60
90
  context: LoadContext,
@@ -82,6 +112,8 @@ export default async function pluginContentDocs(
82
112
  // TODO env should be injected into all plugins
83
113
  const env = process.env.NODE_ENV as DocEnv;
84
114
 
115
+ const sourceToPermalinkHelper = createSourceToPermalinkHelper();
116
+
85
117
  return {
86
118
  name: 'docusaurus-plugin-content-docs',
87
119
 
@@ -118,6 +150,10 @@ export default async function pluginContentDocs(
118
150
  (docsDirPath) => `${docsDirPath}/${pattern}`,
119
151
  ),
120
152
  ),
153
+ ...getTagsFilePathsToWatch({
154
+ contentPaths: version,
155
+ tags: options.tags,
156
+ }),
121
157
  `${version.contentPath}/**/${CategoryMetadataFilenamePattern}`,
122
158
  ];
123
159
  if (typeof version.sidebarFilePath === 'string') {
@@ -132,6 +168,7 @@ export default async function pluginContentDocs(
132
168
  async loadContent() {
133
169
  async function loadVersionDocsBase(
134
170
  versionMetadata: VersionMetadata,
171
+ tagsFile: TagsFile | null,
135
172
  ): Promise<DocMetadataBase[]> {
136
173
  const docFiles = await readVersionDocs(versionMetadata, options);
137
174
  if (docFiles.length === 0) {
@@ -151,6 +188,7 @@ export default async function pluginContentDocs(
151
188
  context,
152
189
  options,
153
190
  env,
191
+ tagsFile,
154
192
  });
155
193
  }
156
194
  return Promise.all(docFiles.map(processVersionDoc));
@@ -159,8 +197,14 @@ export default async function pluginContentDocs(
159
197
  async function doLoadVersion(
160
198
  versionMetadata: VersionMetadata,
161
199
  ): Promise<LoadedVersion> {
200
+ const tagsFile = await getTagsFile({
201
+ contentPaths: versionMetadata,
202
+ tags: options.tags,
203
+ });
204
+
162
205
  const docsBase: DocMetadataBase[] = await loadVersionDocsBase(
163
206
  versionMetadata,
207
+ tagsFile,
164
208
  );
165
209
 
166
210
  // TODO we only ever need draftIds in further code, not full draft items
@@ -226,6 +270,8 @@ export default async function pluginContentDocs(
226
270
  },
227
271
 
228
272
  async contentLoaded({content, actions}) {
273
+ sourceToPermalinkHelper.update(content);
274
+
229
275
  const versions: FullVersion[] = content.loadedVersions.map(toFullVersion);
230
276
 
231
277
  await createAllRoutes({
@@ -251,72 +297,61 @@ export default async function pluginContentDocs(
251
297
  beforeDefaultRemarkPlugins,
252
298
  } = options;
253
299
 
254
- function getSourceToPermalink(): SourceToPermalink {
255
- const allDocs = content.loadedVersions.flatMap((v) => v.docs);
256
- return Object.fromEntries(
257
- allDocs.map(({source, permalink}) => [source, permalink]),
258
- );
259
- }
260
-
261
- const docsMarkdownOptions: DocsMarkdownOption = {
262
- siteDir,
263
- sourceToPermalink: getSourceToPermalink(),
264
- versionsMetadata,
265
- onBrokenMarkdownLink: (brokenMarkdownLink) => {
266
- logger.report(
267
- siteConfig.onBrokenMarkdownLinks,
268
- )`Docs markdown link couldn't be resolved: (url=${brokenMarkdownLink.link}) in path=${brokenMarkdownLink.filePath} for version number=${brokenMarkdownLink.contentPaths.versionName}`;
269
- },
270
- };
300
+ const contentDirs = versionsMetadata
301
+ .flatMap(getContentPathList)
302
+ // Trailing slash is important, see https://github.com/facebook/docusaurus/pull/3970
303
+ .map(addTrailingPathSeparator);
304
+
305
+ function createMDXLoader(): RuleSetUseItem {
306
+ const loaderOptions: MDXLoaderOptions = {
307
+ admonitions: options.admonitions,
308
+ remarkPlugins,
309
+ rehypePlugins,
310
+ beforeDefaultRehypePlugins,
311
+ beforeDefaultRemarkPlugins,
312
+ staticDirs: siteConfig.staticDirectories.map((dir) =>
313
+ path.resolve(siteDir, dir),
314
+ ),
315
+ siteDir,
316
+ isMDXPartial: createAbsoluteFilePathMatcher(
317
+ options.exclude,
318
+ contentDirs,
319
+ ),
320
+ metadataPath: (mdxPath: string) => {
321
+ // Note that metadataPath must be the same/in-sync as
322
+ // the path from createData for each MDX.
323
+ const aliasedPath = aliasedSitePath(mdxPath, siteDir);
324
+ return path.join(dataDir, `${docuHash(aliasedPath)}.json`);
325
+ },
326
+ // Assets allow to convert some relative images paths to
327
+ // require(...) calls
328
+ createAssets: ({frontMatter}: {frontMatter: DocFrontMatter}) => ({
329
+ image: frontMatter.image,
330
+ }),
331
+ markdownConfig: siteConfig.markdown,
332
+ resolveMarkdownLink: ({linkPathname, sourceFilePath}) => {
333
+ const version = getVersionFromSourceFilePath(
334
+ sourceFilePath,
335
+ content.loadedVersions,
336
+ );
337
+ const permalink = resolveMarkdownLinkPathname(linkPathname, {
338
+ sourceFilePath,
339
+ sourceToPermalink: sourceToPermalinkHelper.get(),
340
+ siteDir,
341
+ contentPaths: version,
342
+ });
343
+ if (permalink === null) {
344
+ logger.report(
345
+ siteConfig.onBrokenMarkdownLinks,
346
+ )`Docs markdown link couldn't be resolved: (url=${linkPathname}) in source file path=${sourceFilePath} for version number=${version.versionName}`;
347
+ }
348
+ return permalink;
349
+ },
350
+ };
271
351
 
272
- function createMDXLoaderRule(): RuleSetRule {
273
- const contentDirs = versionsMetadata
274
- .flatMap(getContentPathList)
275
- // Trailing slash is important, see https://github.com/facebook/docusaurus/pull/3970
276
- .map(addTrailingPathSeparator);
277
352
  return {
278
- test: /\.mdx?$/i,
279
- include: contentDirs,
280
- use: [
281
- {
282
- loader: require.resolve('@docusaurus/mdx-loader'),
283
- options: {
284
- admonitions: options.admonitions,
285
- remarkPlugins,
286
- rehypePlugins,
287
- beforeDefaultRehypePlugins,
288
- beforeDefaultRemarkPlugins,
289
- staticDirs: siteConfig.staticDirectories.map((dir) =>
290
- path.resolve(siteDir, dir),
291
- ),
292
- siteDir,
293
- isMDXPartial: createAbsoluteFilePathMatcher(
294
- options.exclude,
295
- contentDirs,
296
- ),
297
- metadataPath: (mdxPath: string) => {
298
- // Note that metadataPath must be the same/in-sync as
299
- // the path from createData for each MDX.
300
- const aliasedPath = aliasedSitePath(mdxPath, siteDir);
301
- return path.join(dataDir, `${docuHash(aliasedPath)}.json`);
302
- },
303
- // Assets allow to convert some relative images paths to
304
- // require(...) calls
305
- createAssets: ({
306
- frontMatter,
307
- }: {
308
- frontMatter: DocFrontMatter;
309
- }) => ({
310
- image: frontMatter.image,
311
- }),
312
- markdownConfig: siteConfig.markdown,
313
- },
314
- },
315
- {
316
- loader: path.resolve(__dirname, './markdown/index.js'),
317
- options: docsMarkdownOptions,
318
- },
319
- ].filter(Boolean),
353
+ loader: require.resolve('@docusaurus/mdx-loader'),
354
+ options: loaderOptions,
320
355
  };
321
356
  }
322
357
 
@@ -333,7 +368,13 @@ export default async function pluginContentDocs(
333
368
  },
334
369
  },
335
370
  module: {
336
- rules: [createMDXLoaderRule()],
371
+ rules: [
372
+ {
373
+ test: /\.mdx?$/i,
374
+ include: contentDirs,
375
+ use: [createMDXLoader()],
376
+ },
377
+ ],
337
378
  },
338
379
  };
339
380
  },
package/src/options.ts CHANGED
@@ -54,6 +54,8 @@ export const DEFAULT_OPTIONS: Omit<PluginOptions, 'id' | 'sidebarPath'> = {
54
54
  sidebarCollapsible: true,
55
55
  sidebarCollapsed: true,
56
56
  breadcrumbs: true,
57
+ onInlineTags: 'warn',
58
+ tags: undefined,
57
59
  };
58
60
 
59
61
  const VersionOptionsSchema = Joi.object({
@@ -140,6 +142,13 @@ const OptionsSchema = Joi.object<PluginOptions>({
140
142
  lastVersion: Joi.string().optional(),
141
143
  versions: VersionsOptionsSchema,
142
144
  breadcrumbs: Joi.bool().default(DEFAULT_OPTIONS.breadcrumbs),
145
+ onInlineTags: Joi.string()
146
+ .equal('ignore', 'log', 'warn', 'throw')
147
+ .default(DEFAULT_OPTIONS.onInlineTags),
148
+ tags: Joi.string()
149
+ .disallow('')
150
+ .allow(null, false)
151
+ .default(() => DEFAULT_OPTIONS.tags),
143
152
  });
144
153
 
145
154
  export function validateOptions({
@@ -15,9 +15,10 @@ declare module '@docusaurus/plugin-content-docs' {
15
15
  FrontMatterTag,
16
16
  TagsListItem,
17
17
  TagModule,
18
- Tag,
19
18
  FrontMatterLastUpdate,
20
19
  LastUpdateData,
20
+ TagMetadata,
21
+ TagsPluginOptions,
21
22
  } from '@docusaurus/utils';
22
23
  import type {Plugin, LoadContext} from '@docusaurus/types';
23
24
  import type {Overwrite, Required} from 'utility-types';
@@ -64,7 +65,7 @@ declare module '@docusaurus/plugin-content-docs' {
64
65
  locale: string;
65
66
  }) => string | undefined;
66
67
 
67
- export type MetadataOptions = {
68
+ export type MetadataOptions = TagsPluginOptions & {
68
69
  /**
69
70
  * URL route for the docs section of your site. **DO NOT** include a
70
71
  * trailing slash. Use `/` for shipping docs without base path.
@@ -446,7 +447,7 @@ declare module '@docusaurus/plugin-content-docs' {
446
447
  */
447
448
  editUrl?: string | null;
448
449
  /** Tags, normalized. */
449
- tags: Tag[];
450
+ tags: TagMetadata[];
450
451
  /** Front matter, as-is. */
451
452
  frontMatter: DocFrontMatter & {[key: string]: unknown};
452
453
  };
package/src/props.ts CHANGED
@@ -206,6 +206,7 @@ export function toTagDocListProp({
206
206
  return {
207
207
  label: tag.label,
208
208
  permalink: tag.permalink,
209
+ description: tag.description,
209
210
  allTagsPath,
210
211
  count: tag.docIds.length,
211
212
  items: toDocListProp(),
@@ -221,6 +222,7 @@ export function toTagsListTagsProp(
221
222
  .map((tagValue) => ({
222
223
  label: tagValue.label,
223
224
  permalink: tagValue.permalink,
225
+ description: tagValue.description,
224
226
  count: tagValue.docIds.length,
225
227
  }));
226
228
  }
package/src/routes.ts CHANGED
@@ -11,19 +11,20 @@ import {
11
11
  docuHash,
12
12
  normalizeUrl,
13
13
  aliasedSitePathToRelativePath,
14
+ groupTaggedItems,
15
+ getTagVisibility,
14
16
  } from '@docusaurus/utils';
15
17
  import {
16
18
  toTagDocListProp,
17
19
  toTagsListTagsProp,
18
20
  toVersionMetadataProp,
19
21
  } from './props';
20
- import {getVersionTags} from './tags';
21
22
  import type {
22
23
  PluginContentLoadedActions,
23
24
  RouteConfig,
24
25
  RouteMetadata,
25
26
  } from '@docusaurus/types';
26
- import type {FullVersion, VersionTag} from './types';
27
+ import type {FullVersion, VersionTag, VersionTags} from './types';
27
28
  import type {
28
29
  CategoryGeneratedIndexMetadata,
29
30
  DocMetadata,
@@ -112,6 +113,23 @@ async function buildVersionSidebarRoute(param: BuildVersionRoutesParam) {
112
113
  routes: subRoutes,
113
114
  };
114
115
  }
116
+ function getVersionTags(docs: DocMetadata[]): VersionTags {
117
+ const groups = groupTaggedItems(docs, (doc) => doc.tags);
118
+ return _.mapValues(groups, ({tag, items: tagDocs}) => {
119
+ const tagVisibility = getTagVisibility({
120
+ items: tagDocs,
121
+ isUnlisted: (item) => item.unlisted,
122
+ });
123
+ return {
124
+ inline: tag.inline,
125
+ label: tag.label,
126
+ permalink: tag.permalink,
127
+ description: tag.description,
128
+ docIds: tagVisibility.listedItems.map((item) => item.id),
129
+ unlisted: tagVisibility.unlisted,
130
+ };
131
+ });
132
+ }
115
133
 
116
134
  async function buildVersionTagsRoutes(
117
135
  param: BuildVersionRoutesParam,
@@ -120,8 +138,9 @@ async function buildVersionTagsRoutes(
120
138
  const versionTags = getVersionTags(version.docs);
121
139
 
122
140
  async function buildTagsListRoute(): Promise<RouteConfig | null> {
141
+ const tags = toTagsListTagsProp(versionTags);
123
142
  // Don't create a tags list page if there's no tag
124
- if (Object.keys(versionTags).length === 0) {
143
+ if (tags.length === 0) {
125
144
  return null;
126
145
  }
127
146
  return {
@@ -129,7 +148,7 @@ async function buildVersionTagsRoutes(
129
148
  exact: true,
130
149
  component: options.docTagsListComponent,
131
150
  props: {
132
- tags: toTagsListTagsProp(versionTags),
151
+ tags,
133
152
  },
134
153
  };
135
154
  }
package/src/types.ts CHANGED
@@ -5,9 +5,8 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
 
8
- import type {BrokenMarkdownLink, Tag} from '@docusaurus/utils';
8
+ import type {TagMetadata} from '@docusaurus/utils';
9
9
  import type {
10
- VersionMetadata,
11
10
  LoadedVersion,
12
11
  CategoryGeneratedIndexMetadata,
13
12
  } from '@docusaurus/plugin-content-docs';
@@ -20,11 +19,7 @@ export type DocFile = {
20
19
  content: string;
21
20
  };
22
21
 
23
- export type SourceToPermalink = {
24
- [source: string]: string;
25
- };
26
-
27
- export type VersionTag = Tag & {
22
+ export type VersionTag = TagMetadata & {
28
23
  /** All doc ids having this tag. */
29
24
  docIds: string[];
30
25
  unlisted: boolean;
@@ -37,12 +32,3 @@ export type FullVersion = LoadedVersion & {
37
32
  sidebarsUtils: SidebarsUtils;
38
33
  categoryGeneratedIndices: CategoryGeneratedIndexMetadata[];
39
34
  };
40
-
41
- export type DocBrokenMarkdownLink = BrokenMarkdownLink<VersionMetadata>;
42
-
43
- export type DocsMarkdownOption = {
44
- versionsMetadata: VersionMetadata[];
45
- siteDir: string;
46
- sourceToPermalink: SourceToPermalink;
47
- onBrokenMarkdownLink: (brokenMarkdownLink: DocBrokenMarkdownLink) => void;
48
- };
@@ -6,7 +6,7 @@
6
6
  */
7
7
 
8
8
  import path from 'path';
9
- import {normalizeUrl, posixPath} from '@docusaurus/utils';
9
+ import {getContentPathList, normalizeUrl, posixPath} from '@docusaurus/utils';
10
10
  import {CURRENT_VERSION_NAME} from '../constants';
11
11
  import {validateVersionsOptions} from './validation';
12
12
  import {
@@ -268,3 +268,20 @@ export function toFullVersion(version: LoadedVersion): FullVersion {
268
268
  }),
269
269
  };
270
270
  }
271
+
272
+ export function getVersionFromSourceFilePath(
273
+ filePath: string,
274
+ versionsMetadata: VersionMetadata[],
275
+ ): VersionMetadata {
276
+ const versionFound = versionsMetadata.find((version) =>
277
+ getContentPathList(version).some((docsDirPath) =>
278
+ filePath.startsWith(docsDirPath),
279
+ ),
280
+ );
281
+ if (!versionFound) {
282
+ throw new Error(
283
+ `Unexpected error: file at "${filePath}" does not belong to any docs version!`,
284
+ );
285
+ }
286
+ return versionFound;
287
+ }
@@ -1,9 +0,0 @@
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
- import type { DocsMarkdownOption } from '../types';
8
- import type { LoaderContext } from 'webpack';
9
- export default function markdownLoader(this: LoaderContext<DocsMarkdownOption>, source: string): void;
@@ -1,16 +0,0 @@
1
- "use strict";
2
- /**
3
- * Copyright (c) Facebook, Inc. and its affiliates.
4
- *
5
- * This source code is licensed under the MIT license found in the
6
- * LICENSE file in the root directory of this source tree.
7
- */
8
- Object.defineProperty(exports, "__esModule", { value: true });
9
- const linkify_1 = require("./linkify");
10
- function markdownLoader(source) {
11
- const fileString = source;
12
- const callback = this.async();
13
- const options = this.getOptions();
14
- return callback(null, (0, linkify_1.linkify)(fileString, this.resourcePath, options));
15
- }
16
- exports.default = markdownLoader;
@@ -1,8 +0,0 @@
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
- import type { DocsMarkdownOption } from '../types';
8
- export declare function linkify(fileString: string, filePath: string, options: DocsMarkdownOption): string;
@@ -1,34 +0,0 @@
1
- "use strict";
2
- /**
3
- * Copyright (c) Facebook, Inc. and its affiliates.
4
- *
5
- * This source code is licensed under the MIT license found in the
6
- * LICENSE file in the root directory of this source tree.
7
- */
8
- Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.linkify = void 0;
10
- const utils_1 = require("@docusaurus/utils");
11
- function getVersion(filePath, options) {
12
- const versionFound = options.versionsMetadata.find((version) => (0, utils_1.getContentPathList)(version).some((docsDirPath) => filePath.startsWith(docsDirPath)));
13
- // At this point, this should never happen, because the MDX loaders' paths are
14
- // literally using the version content paths; but if we allow sourcing content
15
- // from outside the docs directory (through the `include` option, for example;
16
- // is there a compelling use-case?), this would actually be testable
17
- if (!versionFound) {
18
- throw new Error(`Unexpected error: Markdown file at "${filePath}" does not belong to any docs version!`);
19
- }
20
- return versionFound;
21
- }
22
- function linkify(fileString, filePath, options) {
23
- const { siteDir, sourceToPermalink, onBrokenMarkdownLink } = options;
24
- const { newContent, brokenMarkdownLinks } = (0, utils_1.replaceMarkdownLinks)({
25
- siteDir,
26
- fileString,
27
- filePath,
28
- contentPaths: getVersion(filePath, options),
29
- sourceToPermalink,
30
- });
31
- brokenMarkdownLinks.forEach((l) => onBrokenMarkdownLink(l));
32
- return newContent;
33
- }
34
- exports.linkify = linkify;
package/lib/tags.d.ts DELETED
@@ -1,10 +0,0 @@
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
- /// <reference path="../src/plugin-content-docs.d.ts" />
8
- import type { VersionTags } from './types';
9
- import type { DocMetadata } from '@docusaurus/plugin-content-docs';
10
- export declare function getVersionTags(docs: DocMetadata[]): VersionTags;
package/lib/tags.js DELETED
@@ -1,28 +0,0 @@
1
- "use strict";
2
- /**
3
- * Copyright (c) Facebook, Inc. and its affiliates.
4
- *
5
- * This source code is licensed under the MIT license found in the
6
- * LICENSE file in the root directory of this source tree.
7
- */
8
- Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.getVersionTags = void 0;
10
- const tslib_1 = require("tslib");
11
- const lodash_1 = tslib_1.__importDefault(require("lodash"));
12
- const utils_1 = require("@docusaurus/utils");
13
- function getVersionTags(docs) {
14
- const groups = (0, utils_1.groupTaggedItems)(docs, (doc) => doc.tags);
15
- return lodash_1.default.mapValues(groups, ({ tag, items: tagDocs }) => {
16
- const tagVisibility = (0, utils_1.getTagVisibility)({
17
- items: tagDocs,
18
- isUnlisted: (item) => item.unlisted,
19
- });
20
- return {
21
- label: tag.label,
22
- docIds: tagVisibility.listedItems.map((item) => item.id),
23
- permalink: tag.permalink,
24
- unlisted: tagVisibility.unlisted,
25
- };
26
- });
27
- }
28
- exports.getVersionTags = getVersionTags;
@@ -1,20 +0,0 @@
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 {linkify} from './linkify';
9
- import type {DocsMarkdownOption} from '../types';
10
- import type {LoaderContext} from 'webpack';
11
-
12
- export default function markdownLoader(
13
- this: LoaderContext<DocsMarkdownOption>,
14
- source: string,
15
- ): void {
16
- const fileString = source;
17
- const callback = this.async();
18
- const options = this.getOptions();
19
- return callback(null, linkify(fileString, this.resourcePath, options));
20
- }
@@ -1,47 +0,0 @@
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 {replaceMarkdownLinks, getContentPathList} from '@docusaurus/utils';
9
- import type {DocsMarkdownOption} from '../types';
10
-
11
- function getVersion(filePath: string, options: DocsMarkdownOption) {
12
- const versionFound = options.versionsMetadata.find((version) =>
13
- getContentPathList(version).some((docsDirPath) =>
14
- filePath.startsWith(docsDirPath),
15
- ),
16
- );
17
- // At this point, this should never happen, because the MDX loaders' paths are
18
- // literally using the version content paths; but if we allow sourcing content
19
- // from outside the docs directory (through the `include` option, for example;
20
- // is there a compelling use-case?), this would actually be testable
21
- if (!versionFound) {
22
- throw new Error(
23
- `Unexpected error: Markdown file at "${filePath}" does not belong to any docs version!`,
24
- );
25
- }
26
- return versionFound;
27
- }
28
-
29
- export function linkify(
30
- fileString: string,
31
- filePath: string,
32
- options: DocsMarkdownOption,
33
- ): string {
34
- const {siteDir, sourceToPermalink, onBrokenMarkdownLink} = options;
35
-
36
- const {newContent, brokenMarkdownLinks} = replaceMarkdownLinks({
37
- siteDir,
38
- fileString,
39
- filePath,
40
- contentPaths: getVersion(filePath, options),
41
- sourceToPermalink,
42
- });
43
-
44
- brokenMarkdownLinks.forEach((l) => onBrokenMarkdownLink(l));
45
-
46
- return newContent;
47
- }
package/src/tags.ts DELETED
@@ -1,27 +0,0 @@
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 _ from 'lodash';
9
- import {getTagVisibility, groupTaggedItems} from '@docusaurus/utils';
10
- import type {VersionTags} from './types';
11
- import type {DocMetadata} from '@docusaurus/plugin-content-docs';
12
-
13
- export function getVersionTags(docs: DocMetadata[]): VersionTags {
14
- const groups = groupTaggedItems(docs, (doc) => doc.tags);
15
- return _.mapValues(groups, ({tag, items: tagDocs}) => {
16
- const tagVisibility = getTagVisibility({
17
- items: tagDocs,
18
- isUnlisted: (item) => item.unlisted,
19
- });
20
- return {
21
- label: tag.label,
22
- docIds: tagVisibility.listedItems.map((item) => item.id),
23
- permalink: tag.permalink,
24
- unlisted: tagVisibility.unlisted,
25
- };
26
- });
27
- }