diff --git a/.github/workflows/build-perf.yml b/.github/workflows/build-perf.yml index 00dae13f92..8556205551 100644 --- a/.github/workflows/build-perf.yml +++ b/.github/workflows/build-perf.yml @@ -48,7 +48,7 @@ jobs: repo-token: ${{ secrets.GITHUB_TOKEN }} build-script: build:website:en clean-script: clear:website # see https://github.com/facebook/docusaurus/pull/6838 - pattern: '{website/build/assets/js/main*js,website/build/assets/css/styles*css,website/.docusaurus/globalData.json,website/build/index.html,website/build/blog/index.html,website/build/blog/**/introducing-docusaurus/*,website/build/docs/index.html,website/build/docs/installation/index.html,website/build/tests/docs/index.html,website/build/tests/docs/standalone/index.html}' + pattern: '{website/build/assets/js/main*js,website/build/assets/css/styles*css,website/.docusaurus/globalData.json,website/.docusaurus/registry.js,website/.docusaurus/routes.js,website/.docusaurus/routesChunkNames.json,website/.docusaurus/site-metadata.json,website/.docusaurus/codeTranslations.json,website/.docusaurus/i18n.json,website/.docusaurus/docusaurus.config.mjs,website/build/index.html,website/build/blog/index.html,website/build/blog/**/introducing-docusaurus/*,website/build/docs/index.html,website/build/docs/installation/index.html,website/build/tests/docs/index.html,website/build/tests/docs/standalone/index.html}' strip-hash: '\.([^;]\w{7})\.' minimum-change-threshold: 30 compression: none diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/translations.test.ts.snap b/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/translations.test.ts.snap index 2a19730b60..ecb579574d 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/translations.test.ts.snap +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/translations.test.ts.snap @@ -56,6 +56,7 @@ exports[`translateContent falls back when translation is incomplete 1`] = ` "source": "/blog/2021/06/19/hello", "tags": [], "title": "Hello", + "unlisted": false, }, }, ], @@ -99,6 +100,7 @@ exports[`translateContent returns translated loaded 1`] = ` "source": "/blog/2021/06/19/hello", "tags": [], "title": "Hello", + "unlisted": false, }, }, ], diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/translations.test.ts b/packages/docusaurus-plugin-content-blog/src/__tests__/translations.test.ts index 8de26a3fb0..97db9eac87 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/translations.test.ts +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/translations.test.ts @@ -34,6 +34,7 @@ const sampleBlogPosts: BlogPost[] = [ hasTruncateMarker: true, authors: [], frontMatter: {}, + unlisted: false, }, content: '', }, diff --git a/packages/docusaurus-plugin-content-blog/src/index.ts b/packages/docusaurus-plugin-content-blog/src/index.ts index dfc1f097f4..673bb373a1 100644 --- a/packages/docusaurus-plugin-content-blog/src/index.ts +++ b/packages/docusaurus-plugin-content-blog/src/index.ts @@ -11,7 +11,6 @@ import { normalizeUrl, docuHash, aliasedSitePath, - aliasedSitePathToRelativePath, getPluginI18nPath, posixPath, addTrailingPathSeparator, @@ -32,24 +31,17 @@ import footnoteIDFixer from './remark/footnoteIDFixer'; import {translateContent, getTranslationFiles} from './translations'; import {createBlogFeedFiles} from './feed'; -import {toTagProp, toTagsProp} from './props'; +import {createAllRoutes} from './routes'; import type {BlogContentPaths, BlogMarkdownLoaderOptions} from './types'; -import type { - LoadContext, - Plugin, - HtmlTags, - RouteMetadata, -} from '@docusaurus/types'; +import type {LoadContext, Plugin, HtmlTags} from '@docusaurus/types'; import type { PluginOptions, BlogPostFrontMatter, BlogPostMetadata, Assets, - BlogTag, BlogTags, BlogContent, BlogPaginated, - BlogMetadata, } from '@docusaurus/plugin-content-blog'; export default async function pluginContentBlog( @@ -80,6 +72,9 @@ export default async function pluginContentBlog( 'docusaurus-plugin-content-blog', ); const dataDir = path.join(pluginDataDirRoot, pluginId); + // TODO Docusaurus v4 breaking change + // module aliasing should be automatic + // we should never find local absolute FS paths in the codegen registry const aliasedSource = (source: string) => `~blog/${posixPath(path.relative(pluginDataDirRoot, source))}`; @@ -185,213 +180,14 @@ export default async function pluginContentBlog( }; }, - async contentLoaded({content: blogContents, actions}) { - const { - blogListComponent, - blogPostComponent, - blogTagsListComponent, - blogTagsPostsComponent, - blogArchiveComponent, - routeBasePath, - archiveBasePath, - blogTitle, - } = options; - - const {addRoute, createData} = actions; - const { - blogSidebarTitle, - blogPosts, - blogListPaginated, - blogTags, - blogTagsListPath, - } = blogContents; - - const listedBlogPosts = blogPosts.filter(shouldBeListed); - - const blogItemsToMetadata: {[postId: string]: BlogPostMetadata} = {}; - - const sidebarBlogPosts = - options.blogSidebarCount === 'ALL' - ? blogPosts - : blogPosts.slice(0, options.blogSidebarCount); - - function blogPostItemsModule(items: string[]) { - return items.map((postId) => { - const blogPostMetadata = blogItemsToMetadata[postId]!; - return { - content: { - __import: true, - path: blogPostMetadata.source, - query: { - truncated: true, - }, - }, - }; - }); - } - - if (archiveBasePath && listedBlogPosts.length) { - const archiveUrl = normalizeUrl([ - baseUrl, - routeBasePath, - archiveBasePath, - ]); - // Create a blog archive route - const archiveProp = await createData( - `${docuHash(archiveUrl)}.json`, - JSON.stringify({blogPosts: listedBlogPosts}, null, 2), - ); - addRoute({ - path: archiveUrl, - component: blogArchiveComponent, - exact: true, - modules: { - archive: aliasedSource(archiveProp), - }, - }); - } - - // This prop is useful to provide the blog list sidebar - const sidebarProp = await createData( - // Note that this created data path must be in sync with - // metadataPath provided to mdx-loader. - `blog-post-list-prop-${pluginId}.json`, - JSON.stringify( - { - title: blogSidebarTitle, - items: sidebarBlogPosts.map((blogPost) => ({ - title: blogPost.metadata.title, - permalink: blogPost.metadata.permalink, - unlisted: blogPost.metadata.unlisted, - })), - }, - null, - 2, - ), - ); - - const blogMetadata: BlogMetadata = { - blogBasePath: normalizeUrl([baseUrl, routeBasePath]), - blogTitle, - }; - const blogMetadataPath = await createData( - `blogMetadata-${pluginId}.json`, - JSON.stringify(blogMetadata, null, 2), - ); - - function createBlogPostRouteMetadata( - blogPostMeta: BlogPostMetadata, - ): RouteMetadata { - return { - sourceFilePath: aliasedSitePathToRelativePath(blogPostMeta.source), - lastUpdatedAt: blogPostMeta.lastUpdatedAt, - }; - } - - // Create routes for blog entries. - await Promise.all( - blogPosts.map(async (blogPost) => { - const {id, metadata} = blogPost; - await createData( - // Note that this created data path must be in sync with - // metadataPath provided to mdx-loader. - `${docuHash(metadata.source)}.json`, - JSON.stringify(metadata, null, 2), - ); - - addRoute({ - path: metadata.permalink, - component: blogPostComponent, - exact: true, - modules: { - sidebar: aliasedSource(sidebarProp), - content: metadata.source, - }, - metadata: createBlogPostRouteMetadata(metadata), - context: { - blogMetadata: aliasedSource(blogMetadataPath), - }, - }); - - blogItemsToMetadata[id] = metadata; - }), - ); - - // Create routes for blog's paginated list entries. - await Promise.all( - blogListPaginated.map(async (listPage) => { - const {metadata, items} = listPage; - const {permalink} = metadata; - const pageMetadataPath = await createData( - `${docuHash(permalink)}.json`, - JSON.stringify(metadata, null, 2), - ); - - addRoute({ - path: permalink, - component: blogListComponent, - exact: true, - modules: { - sidebar: aliasedSource(sidebarProp), - items: blogPostItemsModule(items), - metadata: aliasedSource(pageMetadataPath), - }, - }); - }), - ); - - // Tags. This is the last part so we early-return if there are no tags. - if (Object.keys(blogTags).length === 0) { - return; - } - - async function createTagsListPage() { - const tagsPropPath = await createData( - `${docuHash(`${blogTagsListPath}-tags`)}.json`, - JSON.stringify(toTagsProp({blogTags}), null, 2), - ); - addRoute({ - path: blogTagsListPath, - component: blogTagsListComponent, - exact: true, - modules: { - sidebar: aliasedSource(sidebarProp), - tags: aliasedSource(tagsPropPath), - }, - }); - } - - async function createTagPostsListPage(tag: BlogTag): Promise { - await Promise.all( - tag.pages.map(async (blogPaginated) => { - const {metadata, items} = blogPaginated; - const tagPropPath = await createData( - `${docuHash(metadata.permalink)}.json`, - JSON.stringify(toTagProp({tag, blogTagsListPath}), null, 2), - ); - - const listMetadataPath = await createData( - `${docuHash(metadata.permalink)}-list.json`, - JSON.stringify(metadata, null, 2), - ); - - addRoute({ - path: metadata.permalink, - component: blogTagsPostsComponent, - exact: true, - modules: { - sidebar: aliasedSource(sidebarProp), - items: blogPostItemsModule(items), - tag: aliasedSource(tagPropPath), - listMetadata: aliasedSource(listMetadataPath), - }, - }); - }), - ); - } - - await createTagsListPage(); - await Promise.all(Object.values(blogTags).map(createTagPostsListPage)); + async contentLoaded({content, actions}) { + await createAllRoutes({ + baseUrl, + content, + actions, + options, + aliasedSource, + }); }, translateContent({content, translationFiles}) { diff --git a/packages/docusaurus-plugin-content-blog/src/routes.ts b/packages/docusaurus-plugin-content-blog/src/routes.ts new file mode 100644 index 0000000000..a810ce13da --- /dev/null +++ b/packages/docusaurus-plugin-content-blog/src/routes.ts @@ -0,0 +1,263 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import _ from 'lodash'; +import { + normalizeUrl, + docuHash, + aliasedSitePathToRelativePath, +} from '@docusaurus/utils'; +import {shouldBeListed} from './blogUtils'; + +import {toTagProp, toTagsProp} from './props'; +import type { + PluginContentLoadedActions, + RouteConfig, + RouteMetadata, +} from '@docusaurus/types'; +import type { + BlogPostMetadata, + BlogTag, + BlogMetadata, + BlogContent, + PluginOptions, + BlogPost, + BlogSidebar, +} from '@docusaurus/plugin-content-blog'; + +type CreateAllRoutesParam = { + baseUrl: string; + content: BlogContent; + options: PluginOptions; + actions: PluginContentLoadedActions; + aliasedSource: (str: string) => string; +}; + +export async function createAllRoutes( + param: CreateAllRoutesParam, +): Promise { + const routes = await buildAllRoutes(param); + routes.forEach(param.actions.addRoute); +} + +export async function buildAllRoutes({ + baseUrl, + content, + actions, + options, + aliasedSource, +}: CreateAllRoutesParam): Promise { + const { + blogListComponent, + blogPostComponent, + blogTagsListComponent, + blogTagsPostsComponent, + blogArchiveComponent, + routeBasePath, + archiveBasePath, + blogTitle, + } = options; + const pluginId = options.id!; + const {createData} = actions; + const { + blogSidebarTitle, + blogPosts, + blogListPaginated, + blogTags, + blogTagsListPath, + } = content; + + const listedBlogPosts = blogPosts.filter(shouldBeListed); + + const blogPostsById = _.keyBy(blogPosts, (post) => post.id); + function getBlogPostById(id: string): BlogPost { + const blogPost = blogPostsById[id]; + if (!blogPost) { + throw new Error(`unexpected, can't find blog post id=${id}`); + } + return blogPost; + } + + const sidebarBlogPosts = + options.blogSidebarCount === 'ALL' + ? blogPosts + : blogPosts.slice(0, options.blogSidebarCount); + + async function createSidebarModule() { + const sidebar: BlogSidebar = { + title: blogSidebarTitle, + items: sidebarBlogPosts.map((blogPost) => ({ + title: blogPost.metadata.title, + permalink: blogPost.metadata.permalink, + unlisted: blogPost.metadata.unlisted, + })), + }; + const modulePath = await createData( + `blog-post-list-prop-${pluginId}.json`, + sidebar, + ); + return aliasedSource(modulePath); + } + + async function createBlogMetadataModule() { + const blogMetadata: BlogMetadata = { + blogBasePath: normalizeUrl([baseUrl, routeBasePath]), + blogTitle, + }; + const modulePath = await createData( + `blogMetadata-${pluginId}.json`, + blogMetadata, + ); + return aliasedSource(modulePath); + } + + // TODO we should have a parent blog route, + // and inject blog metadata + sidebar as a parent context + // unfortunately we can't have a parent route for blog yet + // because if both blog/docs are using routeBasePath /, + // React router config rendering doesn't support that well + const sidebarModulePath = await createSidebarModule(); + const blogMetadataModulePath = await createBlogMetadataModule(); + + function blogPostItemsModule(ids: string[]) { + return ids.map((id) => { + return { + content: { + __import: true, + path: getBlogPostById(id).metadata.source, + query: { + truncated: true, + }, + }, + }; + }); + } + + function createArchiveRoute(): RouteConfig[] { + if (archiveBasePath && listedBlogPosts.length) { + return [ + { + path: normalizeUrl([baseUrl, routeBasePath, archiveBasePath]), + component: blogArchiveComponent, + exact: true, + props: { + archive: {blogPosts: listedBlogPosts}, + }, + }, + ]; + } + return []; + } + + function createBlogPostRouteMetadata( + blogPostMeta: BlogPostMetadata, + ): RouteMetadata { + return { + sourceFilePath: aliasedSitePathToRelativePath(blogPostMeta.source), + lastUpdatedAt: blogPostMeta.lastUpdatedAt, + }; + } + + await Promise.all( + blogPosts.map(async (blogPost) => { + const {metadata} = blogPost; + await createData( + // Note that this created data path must be in sync with + // metadataPath provided to mdx-loader. + `${docuHash(metadata.source)}.json`, + metadata, + ); + }), + ); + + function createBlogPostRoute(blogPost: BlogPost): RouteConfig { + return { + path: blogPost.metadata.permalink, + component: blogPostComponent, + exact: true, + modules: { + sidebar: sidebarModulePath, + content: blogPost.metadata.source, + }, + metadata: createBlogPostRouteMetadata(blogPost.metadata), + context: { + blogMetadata: blogMetadataModulePath, + }, + }; + } + + function createBlogPostRoutes(): RouteConfig[] { + return blogPosts.map(createBlogPostRoute); + } + + function createBlogPostsPaginatedRoutes(): RouteConfig[] { + return blogListPaginated.map((paginated) => { + return { + path: paginated.metadata.permalink, + component: blogListComponent, + exact: true, + modules: { + sidebar: sidebarModulePath, + items: blogPostItemsModule(paginated.items), + }, + props: { + metadata: paginated.metadata, + }, + }; + }); + } + + function createTagsRoutes(): RouteConfig[] { + // Tags. This is the last part so we early-return if there are no tags. + if (Object.keys(blogTags).length === 0) { + return []; + } + + const tagsListRoute: RouteConfig = { + path: blogTagsListPath, + component: blogTagsListComponent, + exact: true, + modules: { + sidebar: sidebarModulePath, + }, + props: { + tags: toTagsProp({blogTags}), + }, + }; + + function createTagPaginatedRoutes(tag: BlogTag): RouteConfig[] { + return tag.pages.map((paginated) => { + return { + path: paginated.metadata.permalink, + component: blogTagsPostsComponent, + exact: true, + modules: { + sidebar: sidebarModulePath, + items: blogPostItemsModule(paginated.items), + }, + props: { + tag: toTagProp({tag, blogTagsListPath}), + listMetadata: paginated.metadata, + }, + }; + }); + } + + const tagsPaginatedRoutes: RouteConfig[] = Object.values(blogTags).flatMap( + createTagPaginatedRoutes, + ); + + return [tagsListRoute, ...tagsPaginatedRoutes]; + } + + return [ + ...createBlogPostRoutes(), + ...createBlogPostsPaginatedRoutes(), + ...createTagsRoutes(), + ...createArchiveRoute(), + ]; +} diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap index 9c88d8e20b..a19421255b 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap @@ -430,853 +430,630 @@ exports[`simple website content 5`] = ` exports[`simple website content: data 1`] = ` { - "category-docs-docs-category-slugs-0fe.json": "{ - "title": "Slugs", - "slug": "/category/slugs", - "permalink": "/docs/category/slugs", - "navigation": { - "previous": { - "title": "unlisted-category-doc", - "permalink": "/docs/unlisted-category/unlisted-category-doc" + "site-docs-custom-last-update-md-b8d.json": { + "description": "Custom last update", + "draft": false, + "editUrl": undefined, + "frontMatter": { + "last_update": { + "author": "Custom Author (processed by parseFrontMatter)", + "date": "1/1/2000", + }, + "title": "Custom Last Update", }, - "next": { - "title": "rootAbsoluteSlug", - "permalink": "/docs/rootAbsoluteSlug" - } - } -}", - "site-docs-custom-last-update-md-b8d.json": "{ - "id": "customLastUpdate", - "title": "Custom Last Update", - "description": "Custom last update", - "source": "@site/docs/customLastUpdate.md", - "sourceDirName": ".", - "slug": "/customLastUpdate", - "permalink": "/docs/customLastUpdate", - "draft": false, - "unlisted": false, - "tags": [], - "version": "current", - "frontMatter": { + "id": "customLastUpdate", + "lastUpdatedAt": undefined, + "lastUpdatedBy": undefined, + "next": undefined, + "permalink": "/docs/customLastUpdate", + "previous": undefined, + "sidebar": undefined, + "sidebarPosition": undefined, + "slug": "/customLastUpdate", + "source": "@site/docs/customLastUpdate.md", + "sourceDirName": ".", + "tags": [], "title": "Custom Last Update", - "last_update": { - "author": "Custom Author (processed by parseFrontMatter)", - "date": "1/1/2000" - } - } -}", - "site-docs-doc-draft-md-584.json": "{ - "id": "doc-draft", - "title": "doc-draft", - "description": "This is a draft document", - "source": "@site/docs/doc-draft.md", - "sourceDirName": ".", - "slug": "/doc-draft", - "permalink": "/docs/doc-draft", - "draft": false, - "unlisted": false, - "tags": [], - "version": "current", - "frontMatter": { - "draft": true - } -}", - "site-docs-doc-unlisted-md-80b.json": "{ - "id": "doc-unlisted", - "title": "doc-unlisted", - "description": "This is an unlisted document", - "source": "@site/docs/doc-unlisted.md", - "sourceDirName": ".", - "slug": "/doc-unlisted", - "permalink": "/docs/doc-unlisted", - "draft": false, - "unlisted": false, - "tags": [], - "version": "current", - "frontMatter": { - "unlisted": true + "unlisted": false, + "version": "current", }, - "sidebar": "docs", - "previous": { - "title": "Bar", - "permalink": "/docs/foo/bar" + "site-docs-doc-draft-md-584.json": { + "description": "This is a draft document", + "draft": false, + "editUrl": undefined, + "frontMatter": { + "draft": true, + }, + "id": "doc-draft", + "lastUpdatedAt": undefined, + "lastUpdatedBy": undefined, + "next": undefined, + "permalink": "/docs/doc-draft", + "previous": undefined, + "sidebar": undefined, + "sidebarPosition": undefined, + "slug": "/doc-draft", + "source": "@site/docs/doc-draft.md", + "sourceDirName": ".", + "tags": [], + "title": "doc-draft", + "unlisted": false, + "version": "current", }, - "next": { - "title": "baz pagination_label", - "permalink": "/docs/foo/bazSlug.html" - } -}", - "site-docs-doc-with-space-md-e90.json": "{ - "id": "doc with space", - "title": "Hoo hoo, if this path tricks you...", - "description": "", - "source": "@site/docs/doc with space.md", - "sourceDirName": ".", - "slug": "/doc with space", - "permalink": "/docs/doc with space", - "draft": false, - "unlisted": false, - "tags": [], - "version": "current", - "frontMatter": {} -}", - "site-docs-foo-bar-md-8c2.json": "{ - "id": "foo/bar", - "title": "Bar", - "description": "This is custom description", - "source": "@site/docs/foo/bar.md", - "sourceDirName": "foo", - "slug": "/foo/bar", - "permalink": "/docs/foo/bar", - "draft": false, - "unlisted": false, - "tags": [], - "version": "current", - "frontMatter": { - "id": "bar", - "title": "Bar", + "site-docs-doc-unlisted-md-80b.json": { + "description": "This is an unlisted document", + "draft": false, + "editUrl": undefined, + "frontMatter": { + "unlisted": true, + }, + "id": "doc-unlisted", + "lastUpdatedAt": undefined, + "lastUpdatedBy": undefined, + "next": { + "permalink": "/docs/foo/bazSlug.html", + "title": "baz pagination_label", + }, + "permalink": "/docs/doc-unlisted", + "previous": { + "permalink": "/docs/foo/bar", + "title": "Bar", + }, + "sidebar": "docs", + "sidebarPosition": undefined, + "slug": "/doc-unlisted", + "source": "@site/docs/doc-unlisted.md", + "sourceDirName": ".", + "tags": [], + "title": "doc-unlisted", + "unlisted": false, + "version": "current", + }, + "site-docs-doc-with-space-md-e90.json": { + "description": "", + "draft": false, + "editUrl": undefined, + "frontMatter": {}, + "id": "doc with space", + "lastUpdatedAt": undefined, + "lastUpdatedBy": undefined, + "next": undefined, + "permalink": "/docs/doc with space", + "previous": undefined, + "sidebar": undefined, + "sidebarPosition": undefined, + "slug": "/doc with space", + "source": "@site/docs/doc with space.md", + "sourceDirName": ".", + "tags": [], + "title": "Hoo hoo, if this path tricks you...", + "unlisted": false, + "version": "current", + }, + "site-docs-foo-bar-md-8c2.json": { "description": "This is custom description", - "pagination_next": null, - "pagination_prev": null - }, - "sidebar": "docs" -}", - "site-docs-foo-baz-md-a69.json": "{ - "id": "foo/baz", - "title": "baz", - "description": "Images", - "source": "@site/docs/foo/baz.md", - "sourceDirName": "foo", - "slug": "/foo/bazSlug.html", - "permalink": "/docs/foo/bazSlug.html", - "draft": false, - "unlisted": false, - "tags": [ - { - "label": "tag 1", - "permalink": "/docs/tags/tag-1" + "draft": false, + "editUrl": undefined, + "frontMatter": { + "description": "This is custom description", + "id": "bar", + "pagination_next": null, + "pagination_prev": null, + "title": "Bar", }, - { - "label": "tag 2", - "permalink": "/docs/tags/tag2-custom-permalink" - } - ], - "version": "current", - "frontMatter": { - "id": "baz", - "title": "baz", - "slug": "bazSlug.html", - "pagination_label": "baz pagination_label", - "tags": [ - "tag 1", - "tag-1", - { - "label": "tag 2", - "permalink": "tag2-custom-permalink" - } - ] + "id": "foo/bar", + "lastUpdatedAt": undefined, + "lastUpdatedBy": undefined, + "next": undefined, + "permalink": "/docs/foo/bar", + "previous": undefined, + "sidebar": "docs", + "sidebarPosition": undefined, + "slug": "/foo/bar", + "source": "@site/docs/foo/bar.md", + "sourceDirName": "foo", + "tags": [], + "title": "Bar", + "unlisted": false, + "version": "current", }, - "sidebar": "docs", - "previous": { - "title": "doc-unlisted", - "permalink": "/docs/doc-unlisted" - }, - "next": { - "title": "unlisted-category-index", - "permalink": "/docs/unlisted-category/" - } -}", - "site-docs-heading-as-title-md-c6d.json": "{ - "id": "headingAsTitle", - "title": "My heading as title", - "description": "", - "source": "@site/docs/headingAsTitle.md", - "sourceDirName": ".", - "slug": "/headingAsTitle", - "permalink": "/docs/headingAsTitle", - "draft": false, - "unlisted": false, - "tags": [], - "version": "current", - "frontMatter": {}, - "sidebar": "docs", - "previous": { - "title": "rootTryToEscapeSlug", - "permalink": "/docs/rootTryToEscapeSlug" - }, - "next": { - "title": "Hello sidebar_label", - "permalink": "/docs/" - } -}", - "site-docs-hello-md-9df.json": "{ - "id": "hello", - "title": "Hello, World !", - "description": "Hi, Endilie here :)", - "source": "@site/docs/hello.md", - "sourceDirName": ".", - "slug": "/", - "permalink": "/docs/", - "draft": false, - "unlisted": false, - "tags": [ - { - "label": "tag-1", - "permalink": "/docs/tags/tag-1" - }, - { - "label": "tag 3", - "permalink": "/docs/tags/tag-3" - } - ], - "version": "current", - "frontMatter": { - "id": "hello", - "title": "Hello, World !", - "sidebar_label": "Hello sidebar_label", - "tags": [ - "tag-1", - "tag 3" - ], - "slug": "/" - }, - "sidebar": "docs", - "previous": { - "title": "My heading as title", - "permalink": "/docs/headingAsTitle" - } -}", - "site-docs-ipsum-md-c61.json": "{ - "id": "ipsum", - "title": "ipsum", - "description": "Lorem ipsum.", - "source": "@site/docs/ipsum.md", - "sourceDirName": ".", - "slug": "/ipsum", - "permalink": "/docs/ipsum", - "draft": false, - "unlisted": false, - "editUrl": null, - "tags": [], - "version": "current", - "frontMatter": { - "custom_edit_url": null, - "pagination_next": "doc-unlisted" - }, - "next": { - "title": "doc-unlisted", - "permalink": "/docs/doc-unlisted" - } -}", - "site-docs-last-update-author-only-md-352.json": "{ - "id": "lastUpdateAuthorOnly", - "title": "Last Update Author Only", - "description": "Only custom author, so it will still use the date from Git", - "source": "@site/docs/lastUpdateAuthorOnly.md", - "sourceDirName": ".", - "slug": "/lastUpdateAuthorOnly", - "permalink": "/docs/lastUpdateAuthorOnly", - "draft": false, - "unlisted": false, - "tags": [], - "version": "current", - "frontMatter": { - "title": "Last Update Author Only", - "last_update": { - "author": "Custom Author (processed by parseFrontMatter)" - } - } -}", - "site-docs-last-update-date-only-md-987.json": "{ - "id": "lastUpdateDateOnly", - "title": "Last Update Date Only", - "description": "Only custom date, so it will still use the author from Git", - "source": "@site/docs/lastUpdateDateOnly.md", - "sourceDirName": ".", - "slug": "/lastUpdateDateOnly", - "permalink": "/docs/lastUpdateDateOnly", - "draft": false, - "unlisted": false, - "tags": [], - "version": "current", - "frontMatter": { - "title": "Last Update Date Only", - "last_update": { - "date": "1/1/2000" - } - } -}", - "site-docs-lorem-md-b27.json": "{ - "id": "lorem", - "title": "lorem", - "description": "Lorem ipsum.", - "source": "@site/docs/lorem.md", - "sourceDirName": ".", - "slug": "/lorem", - "permalink": "/docs/lorem", - "draft": false, - "unlisted": false, - "editUrl": "https://github.com/customUrl/docs/lorem.md", - "tags": [], - "version": "current", - "frontMatter": { - "custom_edit_url": "https://github.com/customUrl/docs/lorem.md", - "unrelated_front_matter": "won't be part of metadata" - } -}", - "site-docs-root-absolute-slug-md-db5.json": "{ - "id": "rootAbsoluteSlug", - "title": "rootAbsoluteSlug", - "description": "Lorem", - "source": "@site/docs/rootAbsoluteSlug.md", - "sourceDirName": ".", - "slug": "/rootAbsoluteSlug", - "permalink": "/docs/rootAbsoluteSlug", - "draft": false, - "unlisted": false, - "tags": [], - "version": "current", - "frontMatter": { - "slug": "/rootAbsoluteSlug", - "pagination_next": "headingAsTitle", - "pagination_prev": "foo/baz" - }, - "sidebar": "docs", - "previous": { - "title": "baz pagination_label", - "permalink": "/docs/foo/bazSlug.html" - }, - "next": { - "title": "My heading as title", - "permalink": "/docs/headingAsTitle" - } -}", - "site-docs-root-relative-slug-md-3dd.json": "{ - "id": "rootRelativeSlug", - "title": "rootRelativeSlug", - "description": "Lorem", - "source": "@site/docs/rootRelativeSlug.md", - "sourceDirName": ".", - "slug": "/rootRelativeSlug", - "permalink": "/docs/rootRelativeSlug", - "draft": false, - "unlisted": false, - "tags": [], - "version": "current", - "frontMatter": { - "slug": "rootRelativeSlug", - "pagination_next": "headingAsTitle", - "pagination_prev": "foo/baz" - }, - "sidebar": "docs", - "previous": { - "title": "baz pagination_label", - "permalink": "/docs/foo/bazSlug.html" - }, - "next": { - "title": "My heading as title", - "permalink": "/docs/headingAsTitle" - } -}", - "site-docs-root-resolved-slug-md-4d1.json": "{ - "id": "rootResolvedSlug", - "title": "rootResolvedSlug", - "description": "Lorem", - "source": "@site/docs/rootResolvedSlug.md", - "sourceDirName": ".", - "slug": "/hey/rootResolvedSlug", - "permalink": "/docs/hey/rootResolvedSlug", - "draft": false, - "unlisted": false, - "tags": [], - "version": "current", - "frontMatter": { - "slug": "./hey/ho/../rootResolvedSlug", - "pagination_next": "headingAsTitle", - "pagination_prev": "foo/baz" - }, - "sidebar": "docs", - "previous": { - "title": "baz pagination_label", - "permalink": "/docs/foo/bazSlug.html" - }, - "next": { - "title": "My heading as title", - "permalink": "/docs/headingAsTitle" - } -}", - "site-docs-root-try-to-escape-slug-md-9ee.json": "{ - "id": "rootTryToEscapeSlug", - "title": "rootTryToEscapeSlug", - "description": "Lorem", - "source": "@site/docs/rootTryToEscapeSlug.md", - "sourceDirName": ".", - "slug": "/rootTryToEscapeSlug", - "permalink": "/docs/rootTryToEscapeSlug", - "draft": false, - "unlisted": false, - "tags": [], - "version": "current", - "frontMatter": { - "slug": "../../../../../../../../rootTryToEscapeSlug", - "pagination_next": "headingAsTitle", - "pagination_prev": "foo/baz" - }, - "sidebar": "docs", - "previous": { - "title": "baz pagination_label", - "permalink": "/docs/foo/bazSlug.html" - }, - "next": { - "title": "My heading as title", - "permalink": "/docs/headingAsTitle" - } -}", - "site-docs-slugs-absolute-slug-md-4e8.json": "{ - "id": "slugs/absoluteSlug", - "title": "absoluteSlug", - "description": "Lorem", - "source": "@site/docs/slugs/absoluteSlug.md", - "sourceDirName": "slugs", - "slug": "/absoluteSlug", - "permalink": "/docs/absoluteSlug", - "draft": false, - "unlisted": false, - "tags": [], - "version": "current", - "frontMatter": { - "slug": "/absoluteSlug" - } -}", - "site-docs-slugs-relative-slug-md-d1c.json": "{ - "id": "slugs/relativeSlug", - "title": "relativeSlug", - "description": "Lorem", - "source": "@site/docs/slugs/relativeSlug.md", - "sourceDirName": "slugs", - "slug": "/slugs/relativeSlug", - "permalink": "/docs/slugs/relativeSlug", - "draft": false, - "unlisted": false, - "tags": [], - "version": "current", - "frontMatter": { - "slug": "relativeSlug" - } -}", - "site-docs-slugs-resolved-slug-md-02b.json": "{ - "id": "slugs/resolvedSlug", - "title": "resolvedSlug", - "description": "Lorem", - "source": "@site/docs/slugs/resolvedSlug.md", - "sourceDirName": "slugs", - "slug": "/slugs/hey/resolvedSlug", - "permalink": "/docs/slugs/hey/resolvedSlug", - "draft": false, - "unlisted": false, - "tags": [], - "version": "current", - "frontMatter": { - "slug": "./hey/ho/../resolvedSlug" - } -}", - "site-docs-slugs-try-to-escape-slug-md-70d.json": "{ - "id": "slugs/tryToEscapeSlug", - "title": "tryToEscapeSlug", - "description": "Lorem", - "source": "@site/docs/slugs/tryToEscapeSlug.md", - "sourceDirName": "slugs", - "slug": "/tryToEscapeSlug", - "permalink": "/docs/tryToEscapeSlug", - "draft": false, - "unlisted": false, - "tags": [], - "version": "current", - "frontMatter": { - "slug": "../../../../../../../../tryToEscapeSlug" - } -}", - "site-docs-unlisted-category-index-md-efa.json": "{ - "id": "unlisted-category/unlisted-category-index", - "title": "unlisted-category-index", - "description": "This is an unlisted category index", - "source": "@site/docs/unlisted-category/index.md", - "sourceDirName": "unlisted-category", - "slug": "/unlisted-category/", - "permalink": "/docs/unlisted-category/", - "draft": false, - "unlisted": false, - "tags": [], - "version": "current", - "frontMatter": { - "id": "unlisted-category-index", - "unlisted": true - }, - "sidebar": "docs", - "previous": { - "title": "baz pagination_label", - "permalink": "/docs/foo/bazSlug.html" - }, - "next": { - "title": "unlisted-category-doc", - "permalink": "/docs/unlisted-category/unlisted-category-doc" - } -}", - "site-docs-unlisted-category-unlisted-category-doc-md-bd6.json": "{ - "id": "unlisted-category/unlisted-category-doc", - "title": "unlisted-category-doc", - "description": "This is an unlisted category doc", - "source": "@site/docs/unlisted-category/unlisted-category-doc.md", - "sourceDirName": "unlisted-category", - "slug": "/unlisted-category/unlisted-category-doc", - "permalink": "/docs/unlisted-category/unlisted-category-doc", - "draft": false, - "unlisted": false, - "tags": [], - "version": "current", - "frontMatter": { - "id": "unlisted-category-doc", - "unlisted": true - }, - "sidebar": "docs", - "previous": { - "title": "unlisted-category-index", - "permalink": "/docs/unlisted-category/" - }, - "next": { - "title": "Slugs", - "permalink": "/docs/category/slugs" - } -}", - "tag-docs-tags-tag-1-b3f.json": "{ - "label": "tag 1", - "permalink": "/docs/tags/tag-1", - "allTagsPath": "/docs/tags", - "count": 2, - "items": [ - { - "id": "foo/baz", + "site-docs-foo-baz-md-a69.json": { + "description": "Images", + "draft": false, + "editUrl": undefined, + "frontMatter": { + "id": "baz", + "pagination_label": "baz pagination_label", + "slug": "bazSlug.html", + "tags": [ + "tag 1", + "tag-1", + { + "label": "tag 2", + "permalink": "tag2-custom-permalink", + }, + ], "title": "baz", - "description": "Images", - "permalink": "/docs/foo/bazSlug.html" }, - { - "id": "hello", - "title": "Hello, World !", - "description": "Hi, Endilie here :)", - "permalink": "/docs/" - } - ], - "unlisted": false -}", - "tag-docs-tags-tag-2-custom-permalink-825.json": "{ - "label": "tag 2", - "permalink": "/docs/tags/tag2-custom-permalink", - "allTagsPath": "/docs/tags", - "count": 1, - "items": [ - { - "id": "foo/baz", - "title": "baz", - "description": "Images", - "permalink": "/docs/foo/bazSlug.html" - } - ], - "unlisted": false -}", - "tag-docs-tags-tag-3-ab5.json": "{ - "label": "tag 3", - "permalink": "/docs/tags/tag-3", - "allTagsPath": "/docs/tags", - "count": 1, - "items": [ - { - "id": "hello", - "title": "Hello, World !", - "description": "Hi, Endilie here :)", - "permalink": "/docs/" - } - ], - "unlisted": false -}", - "tags-list-current-prop-15a.json": "[ - { - "label": "tag 1", - "permalink": "/docs/tags/tag-1", - "count": 2 - }, - { - "label": "tag 2", - "permalink": "/docs/tags/tag2-custom-permalink", - "count": 1 - }, - { - "label": "tag 3", - "permalink": "/docs/tags/tag-3", - "count": 1 - } -]", - "version-current-metadata-prop-751.json": "{ - "pluginId": "default", - "version": "current", - "label": "Next", - "banner": null, - "badge": false, - "noIndex": false, - "className": "docs-version-current", - "isLast": true, - "docsSidebars": { - "docs": [ + "id": "foo/baz", + "lastUpdatedAt": undefined, + "lastUpdatedBy": undefined, + "next": { + "permalink": "/docs/unlisted-category/", + "title": "unlisted-category-index", + }, + "permalink": "/docs/foo/bazSlug.html", + "previous": { + "permalink": "/docs/doc-unlisted", + "title": "doc-unlisted", + }, + "sidebar": "docs", + "sidebarPosition": undefined, + "slug": "/foo/bazSlug.html", + "source": "@site/docs/foo/baz.md", + "sourceDirName": "foo", + "tags": [ { - "type": "category", - "label": "Test", - "items": [ - { - "type": "category", - "label": "foo", - "items": [ - { - "type": "link", - "label": "Bar", - "href": "/docs/foo/bar", - "docId": "foo/bar", - "unlisted": false - }, - { - "type": "link", - "label": "doc-unlisted", - "href": "/docs/doc-unlisted", - "docId": "doc-unlisted", - "unlisted": false - }, - { - "type": "link", - "label": "baz", - "href": "/docs/foo/bazSlug.html", - "docId": "foo/baz", - "unlisted": false - } - ], - "collapsed": true, - "collapsible": true - }, - { - "type": "category", - "label": "Unlisted category", - "items": [ - { - "type": "link", - "label": "unlisted-category-doc", - "href": "/docs/unlisted-category/unlisted-category-doc", - "docId": "unlisted-category/unlisted-category-doc", - "unlisted": false - } - ], - "collapsed": true, - "collapsible": true, - "href": "/docs/unlisted-category/" - }, - { - "type": "category", - "label": "Slugs", - "items": [ - { - "type": "link", - "label": "rootAbsoluteSlug", - "href": "/docs/rootAbsoluteSlug", - "docId": "rootAbsoluteSlug", - "unlisted": false - }, - { - "type": "link", - "label": "rootRelativeSlug", - "href": "/docs/rootRelativeSlug", - "docId": "rootRelativeSlug", - "unlisted": false - }, - { - "type": "link", - "label": "rootResolvedSlug", - "href": "/docs/hey/rootResolvedSlug", - "docId": "rootResolvedSlug", - "unlisted": false - }, - { - "type": "link", - "label": "rootTryToEscapeSlug", - "href": "/docs/rootTryToEscapeSlug", - "docId": "rootTryToEscapeSlug", - "unlisted": false - } - ], - "collapsed": true, - "collapsible": true, - "href": "/docs/category/slugs" - }, - { - "type": "link", - "label": "My heading as title", - "href": "/docs/headingAsTitle", - "docId": "headingAsTitle", - "unlisted": false - }, - { - "type": "link", - "label": "GitHub", - "href": "https://github.com" - }, - { - "type": "link", - "label": "Hello sidebar_label", - "href": "/docs/", - "docId": "hello", - "unlisted": false - } - ], - "collapsed": true, - "collapsible": true + "label": "tag 1", + "permalink": "/docs/tags/tag-1", }, { - "type": "category", - "label": "Guides", - "items": [ - { - "type": "link", - "label": "Hello sidebar_label", - "href": "/docs/", - "docId": "hello", - "unlisted": false - } - ], - "collapsed": true, - "collapsible": true - } - ] + "label": "tag 2", + "permalink": "/docs/tags/tag2-custom-permalink", + }, + ], + "title": "baz", + "unlisted": false, + "version": "current", }, - "docs": { - "customLastUpdate": { - "id": "customLastUpdate", - "title": "Custom Last Update", - "description": "Custom last update" + "site-docs-heading-as-title-md-c6d.json": { + "description": "", + "draft": false, + "editUrl": undefined, + "frontMatter": {}, + "id": "headingAsTitle", + "lastUpdatedAt": undefined, + "lastUpdatedBy": undefined, + "next": { + "permalink": "/docs/", + "title": "Hello sidebar_label", }, - "doc with space": { - "id": "doc with space", - "title": "Hoo hoo, if this path tricks you...", - "description": "" - }, - "doc-draft": { - "id": "doc-draft", - "title": "doc-draft", - "description": "This is a draft document" - }, - "doc-unlisted": { - "id": "doc-unlisted", - "title": "doc-unlisted", - "description": "This is an unlisted document", - "sidebar": "docs" - }, - "foo/bar": { - "id": "foo/bar", - "title": "Bar", - "description": "This is custom description", - "sidebar": "docs" - }, - "foo/baz": { - "id": "foo/baz", - "title": "baz", - "description": "Images", - "sidebar": "docs" - }, - "headingAsTitle": { - "id": "headingAsTitle", - "title": "My heading as title", - "description": "", - "sidebar": "docs" - }, - "hello": { - "id": "hello", - "title": "Hello, World !", - "description": "Hi, Endilie here :)", - "sidebar": "docs" - }, - "ipsum": { - "id": "ipsum", - "title": "ipsum", - "description": "Lorem ipsum." - }, - "lastUpdateAuthorOnly": { - "id": "lastUpdateAuthorOnly", - "title": "Last Update Author Only", - "description": "Only custom author, so it will still use the date from Git" - }, - "lastUpdateDateOnly": { - "id": "lastUpdateDateOnly", - "title": "Last Update Date Only", - "description": "Only custom date, so it will still use the author from Git" - }, - "lorem": { - "id": "lorem", - "title": "lorem", - "description": "Lorem ipsum." - }, - "rootAbsoluteSlug": { - "id": "rootAbsoluteSlug", - "title": "rootAbsoluteSlug", - "description": "Lorem", - "sidebar": "docs" - }, - "rootRelativeSlug": { - "id": "rootRelativeSlug", - "title": "rootRelativeSlug", - "description": "Lorem", - "sidebar": "docs" - }, - "rootResolvedSlug": { - "id": "rootResolvedSlug", - "title": "rootResolvedSlug", - "description": "Lorem", - "sidebar": "docs" - }, - "rootTryToEscapeSlug": { - "id": "rootTryToEscapeSlug", + "permalink": "/docs/headingAsTitle", + "previous": { + "permalink": "/docs/rootTryToEscapeSlug", "title": "rootTryToEscapeSlug", - "description": "Lorem", - "sidebar": "docs" }, - "slugs/absoluteSlug": { - "id": "slugs/absoluteSlug", - "title": "absoluteSlug", - "description": "Lorem" + "sidebar": "docs", + "sidebarPosition": undefined, + "slug": "/headingAsTitle", + "source": "@site/docs/headingAsTitle.md", + "sourceDirName": ".", + "tags": [], + "title": "My heading as title", + "unlisted": false, + "version": "current", + }, + "site-docs-hello-md-9df.json": { + "description": "Hi, Endilie here :)", + "draft": false, + "editUrl": undefined, + "frontMatter": { + "id": "hello", + "sidebar_label": "Hello sidebar_label", + "slug": "/", + "tags": [ + "tag-1", + "tag 3", + ], + "title": "Hello, World !", }, - "slugs/relativeSlug": { - "id": "slugs/relativeSlug", - "title": "relativeSlug", - "description": "Lorem" + "id": "hello", + "lastUpdatedAt": undefined, + "lastUpdatedBy": undefined, + "next": undefined, + "permalink": "/docs/", + "previous": { + "permalink": "/docs/headingAsTitle", + "title": "My heading as title", }, - "slugs/resolvedSlug": { - "id": "slugs/resolvedSlug", - "title": "resolvedSlug", - "description": "Lorem" + "sidebar": "docs", + "sidebarPosition": undefined, + "slug": "/", + "source": "@site/docs/hello.md", + "sourceDirName": ".", + "tags": [ + { + "label": "tag-1", + "permalink": "/docs/tags/tag-1", + }, + { + "label": "tag 3", + "permalink": "/docs/tags/tag-3", + }, + ], + "title": "Hello, World !", + "unlisted": false, + "version": "current", + }, + "site-docs-ipsum-md-c61.json": { + "description": "Lorem ipsum.", + "draft": false, + "editUrl": null, + "frontMatter": { + "custom_edit_url": null, + "pagination_next": "doc-unlisted", }, - "slugs/tryToEscapeSlug": { - "id": "slugs/tryToEscapeSlug", - "title": "tryToEscapeSlug", - "description": "Lorem" + "id": "ipsum", + "lastUpdatedAt": undefined, + "lastUpdatedBy": undefined, + "next": { + "permalink": "/docs/doc-unlisted", + "title": "doc-unlisted", }, - "unlisted-category/unlisted-category-doc": { - "id": "unlisted-category/unlisted-category-doc", + "permalink": "/docs/ipsum", + "previous": undefined, + "sidebar": undefined, + "sidebarPosition": undefined, + "slug": "/ipsum", + "source": "@site/docs/ipsum.md", + "sourceDirName": ".", + "tags": [], + "title": "ipsum", + "unlisted": false, + "version": "current", + }, + "site-docs-last-update-author-only-md-352.json": { + "description": "Only custom author, so it will still use the date from Git", + "draft": false, + "editUrl": undefined, + "frontMatter": { + "last_update": { + "author": "Custom Author (processed by parseFrontMatter)", + }, + "title": "Last Update Author Only", + }, + "id": "lastUpdateAuthorOnly", + "lastUpdatedAt": undefined, + "lastUpdatedBy": undefined, + "next": undefined, + "permalink": "/docs/lastUpdateAuthorOnly", + "previous": undefined, + "sidebar": undefined, + "sidebarPosition": undefined, + "slug": "/lastUpdateAuthorOnly", + "source": "@site/docs/lastUpdateAuthorOnly.md", + "sourceDirName": ".", + "tags": [], + "title": "Last Update Author Only", + "unlisted": false, + "version": "current", + }, + "site-docs-last-update-date-only-md-987.json": { + "description": "Only custom date, so it will still use the author from Git", + "draft": false, + "editUrl": undefined, + "frontMatter": { + "last_update": { + "date": "1/1/2000", + }, + "title": "Last Update Date Only", + }, + "id": "lastUpdateDateOnly", + "lastUpdatedAt": undefined, + "lastUpdatedBy": undefined, + "next": undefined, + "permalink": "/docs/lastUpdateDateOnly", + "previous": undefined, + "sidebar": undefined, + "sidebarPosition": undefined, + "slug": "/lastUpdateDateOnly", + "source": "@site/docs/lastUpdateDateOnly.md", + "sourceDirName": ".", + "tags": [], + "title": "Last Update Date Only", + "unlisted": false, + "version": "current", + }, + "site-docs-lorem-md-b27.json": { + "description": "Lorem ipsum.", + "draft": false, + "editUrl": "https://github.com/customUrl/docs/lorem.md", + "frontMatter": { + "custom_edit_url": "https://github.com/customUrl/docs/lorem.md", + "unrelated_front_matter": "won't be part of metadata", + }, + "id": "lorem", + "lastUpdatedAt": undefined, + "lastUpdatedBy": undefined, + "next": undefined, + "permalink": "/docs/lorem", + "previous": undefined, + "sidebar": undefined, + "sidebarPosition": undefined, + "slug": "/lorem", + "source": "@site/docs/lorem.md", + "sourceDirName": ".", + "tags": [], + "title": "lorem", + "unlisted": false, + "version": "current", + }, + "site-docs-root-absolute-slug-md-db5.json": { + "description": "Lorem", + "draft": false, + "editUrl": undefined, + "frontMatter": { + "pagination_next": "headingAsTitle", + "pagination_prev": "foo/baz", + "slug": "/rootAbsoluteSlug", + }, + "id": "rootAbsoluteSlug", + "lastUpdatedAt": undefined, + "lastUpdatedBy": undefined, + "next": { + "permalink": "/docs/headingAsTitle", + "title": "My heading as title", + }, + "permalink": "/docs/rootAbsoluteSlug", + "previous": { + "permalink": "/docs/foo/bazSlug.html", + "title": "baz pagination_label", + }, + "sidebar": "docs", + "sidebarPosition": undefined, + "slug": "/rootAbsoluteSlug", + "source": "@site/docs/rootAbsoluteSlug.md", + "sourceDirName": ".", + "tags": [], + "title": "rootAbsoluteSlug", + "unlisted": false, + "version": "current", + }, + "site-docs-root-relative-slug-md-3dd.json": { + "description": "Lorem", + "draft": false, + "editUrl": undefined, + "frontMatter": { + "pagination_next": "headingAsTitle", + "pagination_prev": "foo/baz", + "slug": "rootRelativeSlug", + }, + "id": "rootRelativeSlug", + "lastUpdatedAt": undefined, + "lastUpdatedBy": undefined, + "next": { + "permalink": "/docs/headingAsTitle", + "title": "My heading as title", + }, + "permalink": "/docs/rootRelativeSlug", + "previous": { + "permalink": "/docs/foo/bazSlug.html", + "title": "baz pagination_label", + }, + "sidebar": "docs", + "sidebarPosition": undefined, + "slug": "/rootRelativeSlug", + "source": "@site/docs/rootRelativeSlug.md", + "sourceDirName": ".", + "tags": [], + "title": "rootRelativeSlug", + "unlisted": false, + "version": "current", + }, + "site-docs-root-resolved-slug-md-4d1.json": { + "description": "Lorem", + "draft": false, + "editUrl": undefined, + "frontMatter": { + "pagination_next": "headingAsTitle", + "pagination_prev": "foo/baz", + "slug": "./hey/ho/../rootResolvedSlug", + }, + "id": "rootResolvedSlug", + "lastUpdatedAt": undefined, + "lastUpdatedBy": undefined, + "next": { + "permalink": "/docs/headingAsTitle", + "title": "My heading as title", + }, + "permalink": "/docs/hey/rootResolvedSlug", + "previous": { + "permalink": "/docs/foo/bazSlug.html", + "title": "baz pagination_label", + }, + "sidebar": "docs", + "sidebarPosition": undefined, + "slug": "/hey/rootResolvedSlug", + "source": "@site/docs/rootResolvedSlug.md", + "sourceDirName": ".", + "tags": [], + "title": "rootResolvedSlug", + "unlisted": false, + "version": "current", + }, + "site-docs-root-try-to-escape-slug-md-9ee.json": { + "description": "Lorem", + "draft": false, + "editUrl": undefined, + "frontMatter": { + "pagination_next": "headingAsTitle", + "pagination_prev": "foo/baz", + "slug": "../../../../../../../../rootTryToEscapeSlug", + }, + "id": "rootTryToEscapeSlug", + "lastUpdatedAt": undefined, + "lastUpdatedBy": undefined, + "next": { + "permalink": "/docs/headingAsTitle", + "title": "My heading as title", + }, + "permalink": "/docs/rootTryToEscapeSlug", + "previous": { + "permalink": "/docs/foo/bazSlug.html", + "title": "baz pagination_label", + }, + "sidebar": "docs", + "sidebarPosition": undefined, + "slug": "/rootTryToEscapeSlug", + "source": "@site/docs/rootTryToEscapeSlug.md", + "sourceDirName": ".", + "tags": [], + "title": "rootTryToEscapeSlug", + "unlisted": false, + "version": "current", + }, + "site-docs-slugs-absolute-slug-md-4e8.json": { + "description": "Lorem", + "draft": false, + "editUrl": undefined, + "frontMatter": { + "slug": "/absoluteSlug", + }, + "id": "slugs/absoluteSlug", + "lastUpdatedAt": undefined, + "lastUpdatedBy": undefined, + "next": undefined, + "permalink": "/docs/absoluteSlug", + "previous": undefined, + "sidebar": undefined, + "sidebarPosition": undefined, + "slug": "/absoluteSlug", + "source": "@site/docs/slugs/absoluteSlug.md", + "sourceDirName": "slugs", + "tags": [], + "title": "absoluteSlug", + "unlisted": false, + "version": "current", + }, + "site-docs-slugs-relative-slug-md-d1c.json": { + "description": "Lorem", + "draft": false, + "editUrl": undefined, + "frontMatter": { + "slug": "relativeSlug", + }, + "id": "slugs/relativeSlug", + "lastUpdatedAt": undefined, + "lastUpdatedBy": undefined, + "next": undefined, + "permalink": "/docs/slugs/relativeSlug", + "previous": undefined, + "sidebar": undefined, + "sidebarPosition": undefined, + "slug": "/slugs/relativeSlug", + "source": "@site/docs/slugs/relativeSlug.md", + "sourceDirName": "slugs", + "tags": [], + "title": "relativeSlug", + "unlisted": false, + "version": "current", + }, + "site-docs-slugs-resolved-slug-md-02b.json": { + "description": "Lorem", + "draft": false, + "editUrl": undefined, + "frontMatter": { + "slug": "./hey/ho/../resolvedSlug", + }, + "id": "slugs/resolvedSlug", + "lastUpdatedAt": undefined, + "lastUpdatedBy": undefined, + "next": undefined, + "permalink": "/docs/slugs/hey/resolvedSlug", + "previous": undefined, + "sidebar": undefined, + "sidebarPosition": undefined, + "slug": "/slugs/hey/resolvedSlug", + "source": "@site/docs/slugs/resolvedSlug.md", + "sourceDirName": "slugs", + "tags": [], + "title": "resolvedSlug", + "unlisted": false, + "version": "current", + }, + "site-docs-slugs-try-to-escape-slug-md-70d.json": { + "description": "Lorem", + "draft": false, + "editUrl": undefined, + "frontMatter": { + "slug": "../../../../../../../../tryToEscapeSlug", + }, + "id": "slugs/tryToEscapeSlug", + "lastUpdatedAt": undefined, + "lastUpdatedBy": undefined, + "next": undefined, + "permalink": "/docs/tryToEscapeSlug", + "previous": undefined, + "sidebar": undefined, + "sidebarPosition": undefined, + "slug": "/tryToEscapeSlug", + "source": "@site/docs/slugs/tryToEscapeSlug.md", + "sourceDirName": "slugs", + "tags": [], + "title": "tryToEscapeSlug", + "unlisted": false, + "version": "current", + }, + "site-docs-unlisted-category-index-md-efa.json": { + "description": "This is an unlisted category index", + "draft": false, + "editUrl": undefined, + "frontMatter": { + "id": "unlisted-category-index", + "unlisted": true, + }, + "id": "unlisted-category/unlisted-category-index", + "lastUpdatedAt": undefined, + "lastUpdatedBy": undefined, + "next": { + "permalink": "/docs/unlisted-category/unlisted-category-doc", "title": "unlisted-category-doc", - "description": "This is an unlisted category doc", - "sidebar": "docs" }, - "unlisted-category/unlisted-category-index": { - "id": "unlisted-category/unlisted-category-index", + "permalink": "/docs/unlisted-category/", + "previous": { + "permalink": "/docs/foo/bazSlug.html", + "title": "baz pagination_label", + }, + "sidebar": "docs", + "sidebarPosition": undefined, + "slug": "/unlisted-category/", + "source": "@site/docs/unlisted-category/index.md", + "sourceDirName": "unlisted-category", + "tags": [], + "title": "unlisted-category-index", + "unlisted": false, + "version": "current", + }, + "site-docs-unlisted-category-unlisted-category-doc-md-bd6.json": { + "description": "This is an unlisted category doc", + "draft": false, + "editUrl": undefined, + "frontMatter": { + "id": "unlisted-category-doc", + "unlisted": true, + }, + "id": "unlisted-category/unlisted-category-doc", + "lastUpdatedAt": undefined, + "lastUpdatedBy": undefined, + "next": { + "permalink": "/docs/category/slugs", + "title": "Slugs", + }, + "permalink": "/docs/unlisted-category/unlisted-category-doc", + "previous": { + "permalink": "/docs/unlisted-category/", "title": "unlisted-category-index", - "description": "This is an unlisted category index", - "sidebar": "docs" - } - } -}", + }, + "sidebar": "docs", + "sidebarPosition": undefined, + "slug": "/unlisted-category/unlisted-category-doc", + "source": "@site/docs/unlisted-category/unlisted-category-doc.md", + "sourceDirName": "unlisted-category", + "tags": [], + "title": "unlisted-category-doc", + "unlisted": false, + "version": "current", + }, } `; @@ -1436,43 +1213,400 @@ exports[`simple website content: route config 1`] = ` { "component": "@theme/DocVersionRoot", "exact": false, - "modules": { - "version": "~docs/version-current-metadata-prop-751.json", - }, "path": "/docs", "priority": -1, + "props": { + "version": { + "badge": false, + "banner": null, + "className": "docs-version-current", + "docs": { + "customLastUpdate": { + "description": "Custom last update", + "id": "customLastUpdate", + "sidebar": undefined, + "title": "Custom Last Update", + }, + "doc with space": { + "description": "", + "id": "doc with space", + "sidebar": undefined, + "title": "Hoo hoo, if this path tricks you...", + }, + "doc-draft": { + "description": "This is a draft document", + "id": "doc-draft", + "sidebar": undefined, + "title": "doc-draft", + }, + "doc-unlisted": { + "description": "This is an unlisted document", + "id": "doc-unlisted", + "sidebar": "docs", + "title": "doc-unlisted", + }, + "foo/bar": { + "description": "This is custom description", + "id": "foo/bar", + "sidebar": "docs", + "title": "Bar", + }, + "foo/baz": { + "description": "Images", + "id": "foo/baz", + "sidebar": "docs", + "title": "baz", + }, + "headingAsTitle": { + "description": "", + "id": "headingAsTitle", + "sidebar": "docs", + "title": "My heading as title", + }, + "hello": { + "description": "Hi, Endilie here :)", + "id": "hello", + "sidebar": "docs", + "title": "Hello, World !", + }, + "ipsum": { + "description": "Lorem ipsum.", + "id": "ipsum", + "sidebar": undefined, + "title": "ipsum", + }, + "lastUpdateAuthorOnly": { + "description": "Only custom author, so it will still use the date from Git", + "id": "lastUpdateAuthorOnly", + "sidebar": undefined, + "title": "Last Update Author Only", + }, + "lastUpdateDateOnly": { + "description": "Only custom date, so it will still use the author from Git", + "id": "lastUpdateDateOnly", + "sidebar": undefined, + "title": "Last Update Date Only", + }, + "lorem": { + "description": "Lorem ipsum.", + "id": "lorem", + "sidebar": undefined, + "title": "lorem", + }, + "rootAbsoluteSlug": { + "description": "Lorem", + "id": "rootAbsoluteSlug", + "sidebar": "docs", + "title": "rootAbsoluteSlug", + }, + "rootRelativeSlug": { + "description": "Lorem", + "id": "rootRelativeSlug", + "sidebar": "docs", + "title": "rootRelativeSlug", + }, + "rootResolvedSlug": { + "description": "Lorem", + "id": "rootResolvedSlug", + "sidebar": "docs", + "title": "rootResolvedSlug", + }, + "rootTryToEscapeSlug": { + "description": "Lorem", + "id": "rootTryToEscapeSlug", + "sidebar": "docs", + "title": "rootTryToEscapeSlug", + }, + "slugs/absoluteSlug": { + "description": "Lorem", + "id": "slugs/absoluteSlug", + "sidebar": undefined, + "title": "absoluteSlug", + }, + "slugs/relativeSlug": { + "description": "Lorem", + "id": "slugs/relativeSlug", + "sidebar": undefined, + "title": "relativeSlug", + }, + "slugs/resolvedSlug": { + "description": "Lorem", + "id": "slugs/resolvedSlug", + "sidebar": undefined, + "title": "resolvedSlug", + }, + "slugs/tryToEscapeSlug": { + "description": "Lorem", + "id": "slugs/tryToEscapeSlug", + "sidebar": undefined, + "title": "tryToEscapeSlug", + }, + "unlisted-category/unlisted-category-doc": { + "description": "This is an unlisted category doc", + "id": "unlisted-category/unlisted-category-doc", + "sidebar": "docs", + "title": "unlisted-category-doc", + }, + "unlisted-category/unlisted-category-index": { + "description": "This is an unlisted category index", + "id": "unlisted-category/unlisted-category-index", + "sidebar": "docs", + "title": "unlisted-category-index", + }, + }, + "docsSidebars": { + "docs": [ + { + "collapsed": true, + "collapsible": true, + "items": [ + { + "collapsed": true, + "collapsible": true, + "items": [ + { + "className": undefined, + "customProps": undefined, + "docId": "foo/bar", + "href": "/docs/foo/bar", + "label": "Bar", + "type": "link", + "unlisted": false, + }, + { + "className": undefined, + "customProps": undefined, + "docId": "doc-unlisted", + "href": "/docs/doc-unlisted", + "label": "doc-unlisted", + "type": "link", + "unlisted": false, + }, + { + "className": undefined, + "customProps": undefined, + "docId": "foo/baz", + "href": "/docs/foo/bazSlug.html", + "label": "baz", + "type": "link", + "unlisted": false, + }, + ], + "label": "foo", + "type": "category", + }, + { + "collapsed": true, + "collapsible": true, + "href": "/docs/unlisted-category/", + "items": [ + { + "className": undefined, + "customProps": undefined, + "docId": "unlisted-category/unlisted-category-doc", + "href": "/docs/unlisted-category/unlisted-category-doc", + "label": "unlisted-category-doc", + "type": "link", + "unlisted": false, + }, + ], + "label": "Unlisted category", + "type": "category", + }, + { + "collapsed": true, + "collapsible": true, + "href": "/docs/category/slugs", + "items": [ + { + "className": undefined, + "customProps": undefined, + "docId": "rootAbsoluteSlug", + "href": "/docs/rootAbsoluteSlug", + "label": "rootAbsoluteSlug", + "type": "link", + "unlisted": false, + }, + { + "className": undefined, + "customProps": undefined, + "docId": "rootRelativeSlug", + "href": "/docs/rootRelativeSlug", + "label": "rootRelativeSlug", + "type": "link", + "unlisted": false, + }, + { + "className": undefined, + "customProps": undefined, + "docId": "rootResolvedSlug", + "href": "/docs/hey/rootResolvedSlug", + "label": "rootResolvedSlug", + "type": "link", + "unlisted": false, + }, + { + "className": undefined, + "customProps": undefined, + "docId": "rootTryToEscapeSlug", + "href": "/docs/rootTryToEscapeSlug", + "label": "rootTryToEscapeSlug", + "type": "link", + "unlisted": false, + }, + ], + "label": "Slugs", + "type": "category", + }, + { + "className": undefined, + "customProps": undefined, + "docId": "headingAsTitle", + "href": "/docs/headingAsTitle", + "label": "My heading as title", + "type": "link", + "unlisted": false, + }, + { + "href": "https://github.com", + "label": "GitHub", + "type": "link", + }, + { + "className": undefined, + "customProps": undefined, + "docId": "hello", + "href": "/docs/", + "label": "Hello sidebar_label", + "type": "link", + "unlisted": false, + }, + ], + "label": "Test", + "type": "category", + }, + { + "collapsed": true, + "collapsible": true, + "items": [ + { + "className": undefined, + "customProps": undefined, + "docId": "hello", + "href": "/docs/", + "label": "Hello sidebar_label", + "type": "link", + "unlisted": false, + }, + ], + "label": "Guides", + "type": "category", + }, + ], + }, + "isLast": true, + "label": "Next", + "noIndex": false, + "pluginId": "default", + "version": "current", + }, + }, "routes": [ { "component": "@theme/DocTagsListPage", "exact": true, - "modules": { - "tags": "~docs/tags-list-current-prop-15a.json", - }, "path": "/docs/tags", + "props": { + "tags": [ + { + "count": 2, + "label": "tag 1", + "permalink": "/docs/tags/tag-1", + }, + { + "count": 1, + "label": "tag 2", + "permalink": "/docs/tags/tag2-custom-permalink", + }, + { + "count": 1, + "label": "tag 3", + "permalink": "/docs/tags/tag-3", + }, + ], + }, }, { "component": "@theme/DocTagDocListPage", "exact": true, - "modules": { - "tag": "~docs/tag-docs-tags-tag-1-b3f.json", - }, "path": "/docs/tags/tag-1", + "props": { + "tag": { + "allTagsPath": "/docs/tags", + "count": 2, + "items": [ + { + "description": "Images", + "id": "foo/baz", + "permalink": "/docs/foo/bazSlug.html", + "title": "baz", + }, + { + "description": "Hi, Endilie here :)", + "id": "hello", + "permalink": "/docs/", + "title": "Hello, World !", + }, + ], + "label": "tag 1", + "permalink": "/docs/tags/tag-1", + "unlisted": false, + }, + }, }, { "component": "@theme/DocTagDocListPage", "exact": true, - "modules": { - "tag": "~docs/tag-docs-tags-tag-3-ab5.json", - }, "path": "/docs/tags/tag-3", + "props": { + "tag": { + "allTagsPath": "/docs/tags", + "count": 1, + "items": [ + { + "description": "Hi, Endilie here :)", + "id": "hello", + "permalink": "/docs/", + "title": "Hello, World !", + }, + ], + "label": "tag 3", + "permalink": "/docs/tags/tag-3", + "unlisted": false, + }, + }, }, { "component": "@theme/DocTagDocListPage", "exact": true, - "modules": { - "tag": "~docs/tag-docs-tags-tag-2-custom-permalink-825.json", - }, "path": "/docs/tags/tag2-custom-permalink", + "props": { + "tag": { + "allTagsPath": "/docs/tags", + "count": 1, + "items": [ + { + "description": "Images", + "id": "foo/baz", + "permalink": "/docs/foo/bazSlug.html", + "title": "baz", + }, + ], + "label": "tag 2", + "permalink": "/docs/tags/tag2-custom-permalink", + "unlisted": false, + }, + }, }, { "component": "@theme/DocRoot", @@ -1507,10 +1641,28 @@ exports[`simple website content: route config 1`] = ` { "component": "@theme/DocCategoryGeneratedIndexPage", "exact": true, - "modules": { - "categoryGeneratedIndex": "~docs/category-docs-docs-category-slugs-0fe.json", - }, "path": "/docs/category/slugs", + "props": { + "categoryGeneratedIndex": { + "description": undefined, + "image": undefined, + "keywords": undefined, + "navigation": { + "next": { + "permalink": "/docs/rootAbsoluteSlug", + "title": "rootAbsoluteSlug", + }, + "previous": { + "permalink": "/docs/unlisted-category/unlisted-category-doc", + "title": "unlisted-category-doc", + }, + }, + "permalink": "/docs/category/slugs", + "sidebar": "docs", + "slug": "/category/slugs", + "title": "Slugs", + }, + }, "sidebar": "docs", }, { @@ -2852,96 +3004,50 @@ exports[`versioned website (community) content: current version sidebars 1`] = ` exports[`versioned website (community) content: data 1`] = ` { - "site-community-versioned-docs-version-1-0-0-team-md-359.json": "{ - "id": "team", - "title": "team", - "description": "Team 1.0.0", - "source": "@site/community_versioned_docs/version-1.0.0/team.md", - "sourceDirName": ".", - "slug": "/team", - "permalink": "/community/team", - "draft": false, - "unlisted": false, - "tags": [], - "version": "1.0.0", - "frontMatter": {}, - "sidebar": "community" -}", - "site-i-18-n-en-docusaurus-plugin-content-docs-community-current-team-md-7e5.json": "{ - "id": "team", - "title": "Team title translated", - "description": "Team current version (translated)", - "source": "@site/i18n/en/docusaurus-plugin-content-docs-community/current/team.md", - "sourceDirName": ".", - "slug": "/team", - "permalink": "/community/next/team", - "draft": false, - "unlisted": false, - "tags": [], - "version": "current", - "frontMatter": { - "title": "Team title translated" + "site-community-versioned-docs-version-1-0-0-team-md-359.json": { + "description": "Team 1.0.0", + "draft": false, + "editUrl": undefined, + "frontMatter": {}, + "id": "team", + "lastUpdatedAt": undefined, + "lastUpdatedBy": undefined, + "next": undefined, + "permalink": "/community/team", + "previous": undefined, + "sidebar": "community", + "sidebarPosition": undefined, + "slug": "/team", + "source": "@site/community_versioned_docs/version-1.0.0/team.md", + "sourceDirName": ".", + "tags": [], + "title": "team", + "unlisted": false, + "version": "1.0.0", }, - "sidebar": "community" -}", - "version-1-0-0-metadata-prop-608.json": "{ - "pluginId": "community", - "version": "1.0.0", - "label": "1.0.0", - "banner": null, - "badge": true, - "noIndex": false, - "className": "docs-version-1.0.0", - "isLast": true, - "docsSidebars": { - "community": [ - { - "type": "link", - "label": "team", - "href": "/community/team", - "docId": "team", - "unlisted": false - } - ] - }, - "docs": { - "team": { - "id": "team", - "title": "team", - "description": "Team 1.0.0", - "sidebar": "community" - } - } -}", - "version-current-metadata-prop-751.json": "{ - "pluginId": "community", - "version": "current", - "label": "Next", - "banner": "unreleased", - "badge": true, - "noIndex": false, - "className": "docs-version-current", - "isLast": false, - "docsSidebars": { - "community": [ - { - "type": "link", - "label": "Team title translated", - "href": "/community/next/team", - "docId": "team", - "unlisted": false - } - ] - }, - "docs": { - "team": { - "id": "team", + "site-i-18-n-en-docusaurus-plugin-content-docs-community-current-team-md-7e5.json": { + "description": "Team current version (translated)", + "draft": false, + "editUrl": undefined, + "frontMatter": { "title": "Team title translated", - "description": "Team current version (translated)", - "sidebar": "community" - } - } -}", + }, + "id": "team", + "lastUpdatedAt": undefined, + "lastUpdatedBy": undefined, + "next": undefined, + "permalink": "/community/next/team", + "previous": undefined, + "sidebar": "community", + "sidebarPosition": undefined, + "slug": "/team", + "source": "@site/i18n/en/docusaurus-plugin-content-docs-community/current/team.md", + "sourceDirName": ".", + "tags": [], + "title": "Team title translated", + "unlisted": false, + "version": "current", + }, } `; @@ -3014,11 +3120,41 @@ exports[`versioned website (community) content: route config 1`] = ` { "component": "@theme/DocVersionRoot", "exact": false, - "modules": { - "version": "~docs/version-current-metadata-prop-751.json", - }, "path": "/community/next", "priority": undefined, + "props": { + "version": { + "badge": true, + "banner": "unreleased", + "className": "docs-version-current", + "docs": { + "team": { + "description": "Team current version (translated)", + "id": "team", + "sidebar": "community", + "title": "Team title translated", + }, + }, + "docsSidebars": { + "community": [ + { + "className": undefined, + "customProps": undefined, + "docId": "team", + "href": "/community/next/team", + "label": "Team title translated", + "type": "link", + "unlisted": false, + }, + ], + }, + "isLast": false, + "label": "Next", + "noIndex": false, + "pluginId": "community", + "version": "current", + }, + }, "routes": [ { "component": "@theme/DocRoot", @@ -3045,11 +3181,41 @@ exports[`versioned website (community) content: route config 1`] = ` { "component": "@theme/DocVersionRoot", "exact": false, - "modules": { - "version": "~docs/version-1-0-0-metadata-prop-608.json", - }, "path": "/community", "priority": -1, + "props": { + "version": { + "badge": true, + "banner": null, + "className": "docs-version-1.0.0", + "docs": { + "team": { + "description": "Team 1.0.0", + "id": "team", + "sidebar": "community", + "title": "team", + }, + }, + "docsSidebars": { + "community": [ + { + "className": undefined, + "customProps": undefined, + "docId": "team", + "href": "/community/team", + "label": "team", + "type": "link", + "unlisted": false, + }, + ], + }, + "isLast": true, + "label": "1.0.0", + "noIndex": false, + "pluginId": "community", + "version": "1.0.0", + }, + }, "routes": [ { "component": "@theme/DocRoot", @@ -3361,708 +3527,484 @@ exports[`versioned website content: current version sidebars 1`] = ` exports[`versioned website content: data 1`] = ` { - "site-docs-foo-bar-md-8c2.json": "{ - "id": "foo/bar", - "title": "bar", - "description": "This is next version of bar.", - "source": "@site/docs/foo/bar.md", - "sourceDirName": "foo", - "slug": "/foo/barSlug", - "permalink": "/docs/next/foo/barSlug", - "draft": false, - "unlisted": false, - "tags": [ - { - "label": "barTag 1", - "permalink": "/docs/next/tags/bar-tag-1" + "site-docs-foo-bar-md-8c2.json": { + "description": "This is next version of bar.", + "draft": false, + "editUrl": undefined, + "frontMatter": { + "slug": "barSlug", + "tags": [ + "barTag 1", + "barTag-2", + { + "label": "barTag 3", + "permalink": "barTag-3-permalink", + }, + ], }, - { - "label": "barTag-2", - "permalink": "/docs/next/tags/bar-tag-2" + "id": "foo/bar", + "lastUpdatedAt": undefined, + "lastUpdatedBy": undefined, + "next": { + "permalink": "/docs/next/", + "title": "hello", }, - { - "label": "barTag 3", - "permalink": "/docs/next/tags/barTag-3-permalink" - } - ], - "version": "current", - "frontMatter": { - "slug": "barSlug", + "permalink": "/docs/next/foo/barSlug", + "previous": undefined, + "sidebar": "docs", + "sidebarPosition": undefined, + "slug": "/foo/barSlug", + "source": "@site/docs/foo/bar.md", + "sourceDirName": "foo", "tags": [ - "barTag 1", - "barTag-2", + { + "label": "barTag 1", + "permalink": "/docs/next/tags/bar-tag-1", + }, + { + "label": "barTag-2", + "permalink": "/docs/next/tags/bar-tag-2", + }, { "label": "barTag 3", - "permalink": "barTag-3-permalink" - } - ] - }, - "sidebar": "docs", - "next": { - "title": "hello", - "permalink": "/docs/next/" - } -}", - "site-docs-hello-md-9df.json": "{ - "id": "hello", - "title": "hello", - "description": "Hello next !", - "source": "@site/docs/hello.md", - "sourceDirName": ".", - "slug": "/", - "permalink": "/docs/next/", - "draft": false, - "unlisted": false, - "tags": [], - "version": "current", - "frontMatter": { - "slug": "/" - }, - "sidebar": "docs", - "previous": { - "title": "bar", - "permalink": "/docs/next/foo/barSlug" - } -}", - "site-docs-slugs-absolute-slug-md-4e8.json": "{ - "id": "slugs/absoluteSlug", - "title": "absoluteSlug", - "description": "Lorem", - "source": "@site/docs/slugs/absoluteSlug.md", - "sourceDirName": "slugs", - "slug": "/absoluteSlug", - "permalink": "/docs/next/absoluteSlug", - "draft": false, - "unlisted": false, - "tags": [], - "version": "current", - "frontMatter": { - "slug": "/absoluteSlug" - } -}", - "site-docs-slugs-relative-slug-md-d1c.json": "{ - "id": "slugs/relativeSlug", - "title": "relativeSlug", - "description": "Lorem", - "source": "@site/docs/slugs/relativeSlug.md", - "sourceDirName": "slugs", - "slug": "/slugs/relativeSlug", - "permalink": "/docs/next/slugs/relativeSlug", - "draft": false, - "unlisted": false, - "tags": [], - "version": "current", - "frontMatter": { - "slug": "relativeSlug" - } -}", - "site-docs-slugs-resolved-slug-md-02b.json": "{ - "id": "slugs/resolvedSlug", - "title": "resolvedSlug", - "description": "Lorem", - "source": "@site/docs/slugs/resolvedSlug.md", - "sourceDirName": "slugs", - "slug": "/slugs/hey/resolvedSlug", - "permalink": "/docs/next/slugs/hey/resolvedSlug", - "draft": false, - "unlisted": false, - "tags": [], - "version": "current", - "frontMatter": { - "slug": "./hey/ho/../resolvedSlug" - } -}", - "site-docs-slugs-try-to-escape-slug-md-70d.json": "{ - "id": "slugs/tryToEscapeSlug", - "title": "tryToEscapeSlug", - "description": "Lorem", - "source": "@site/docs/slugs/tryToEscapeSlug.md", - "sourceDirName": "slugs", - "slug": "/tryToEscapeSlug", - "permalink": "/docs/next/tryToEscapeSlug", - "draft": false, - "unlisted": false, - "tags": [], - "version": "current", - "frontMatter": { - "slug": "../../../../../../../../tryToEscapeSlug" - } -}", - "site-i-18-n-en-docusaurus-plugin-content-docs-version-1-0-0-hello-md-fe5.json": "{ - "id": "hello", - "title": "hello", - "description": "Hello 1.0.0 ! (translated en)", - "source": "@site/i18n/en/docusaurus-plugin-content-docs/version-1.0.0/hello.md", - "sourceDirName": ".", - "slug": "/", - "permalink": "/docs/1.0.0/", - "draft": false, - "unlisted": false, - "tags": [], - "version": "1.0.0", - "frontMatter": { - "slug": "/" - }, - "sidebar": "docs", - "previous": { - "title": "baz", - "permalink": "/docs/1.0.0/foo/baz" - } -}", - "site-versioned-docs-version-1-0-0-foo-bar-md-7a6.json": "{ - "id": "foo/bar", - "title": "bar", - "description": "Bar 1.0.0 !", - "source": "@site/versioned_docs/version-1.0.0/foo/bar.md", - "sourceDirName": "foo", - "slug": "/foo/barSlug", - "permalink": "/docs/1.0.0/foo/barSlug", - "draft": false, - "unlisted": false, - "tags": [], - "version": "1.0.0", - "frontMatter": { - "slug": "barSlug" - }, - "sidebar": "docs", - "next": { - "title": "baz", - "permalink": "/docs/1.0.0/foo/baz" - } -}", - "site-versioned-docs-version-1-0-0-foo-baz-md-883.json": "{ - "id": "foo/baz", - "title": "baz", - "description": "Baz 1.0.0 ! This will be deleted in next subsequent versions.", - "source": "@site/versioned_docs/version-1.0.0/foo/baz.md", - "sourceDirName": "foo", - "slug": "/foo/baz", - "permalink": "/docs/1.0.0/foo/baz", - "draft": false, - "unlisted": false, - "tags": [], - "version": "1.0.0", - "frontMatter": {}, - "sidebar": "docs", - "previous": { - "title": "bar", - "permalink": "/docs/1.0.0/foo/barSlug" - }, - "next": { - "title": "hello", - "permalink": "/docs/1.0.0/" - } -}", - "site-versioned-docs-version-1-0-1-foo-bar-md-7a3.json": "{ - "id": "foo/bar", - "title": "bar", - "description": "Bar 1.0.1 !", - "source": "@site/versioned_docs/version-1.0.1/foo/bar.md", - "sourceDirName": "foo", - "slug": "/foo/bar", - "permalink": "/docs/foo/bar", - "draft": false, - "unlisted": false, - "tags": [], - "version": "1.0.1", - "frontMatter": {}, - "sidebar": "VersionedSideBarNameDoesNotMatter/docs", - "next": { - "title": "hello", - "permalink": "/docs/" - } -}", - "site-versioned-docs-version-1-0-1-hello-md-0c7.json": "{ - "id": "hello", - "title": "hello", - "description": "Hello 1.0.1 !", - "source": "@site/versioned_docs/version-1.0.1/hello.md", - "sourceDirName": ".", - "slug": "/", - "permalink": "/docs/", - "draft": false, - "unlisted": false, - "tags": [], - "version": "1.0.1", - "frontMatter": { - "slug": "/" - }, - "sidebar": "VersionedSideBarNameDoesNotMatter/docs", - "previous": { - "title": "bar", - "permalink": "/docs/foo/bar" - } -}", - "site-versioned-docs-version-with-slugs-root-absolute-slug-md-4d2.json": "{ - "id": "rootAbsoluteSlug", - "title": "rootAbsoluteSlug", - "description": "Lorem", - "source": "@site/versioned_docs/version-withSlugs/rootAbsoluteSlug.md", - "sourceDirName": ".", - "slug": "/rootAbsoluteSlug", - "permalink": "/docs/withSlugs/rootAbsoluteSlug", - "draft": false, - "unlisted": false, - "tags": [], - "version": "withSlugs", - "frontMatter": { - "slug": "/rootAbsoluteSlug" - }, - "sidebar": "docs" -}", - "site-versioned-docs-version-with-slugs-root-relative-slug-md-32a.json": "{ - "id": "rootRelativeSlug", - "title": "rootRelativeSlug", - "description": "Lorem", - "source": "@site/versioned_docs/version-withSlugs/rootRelativeSlug.md", - "sourceDirName": ".", - "slug": "/rootRelativeSlug", - "permalink": "/docs/withSlugs/rootRelativeSlug", - "draft": false, - "unlisted": false, - "tags": [], - "version": "withSlugs", - "frontMatter": { - "slug": "rootRelativeSlug" - } -}", - "site-versioned-docs-version-with-slugs-root-resolved-slug-md-aee.json": "{ - "id": "rootResolvedSlug", - "title": "rootResolvedSlug", - "description": "Lorem", - "source": "@site/versioned_docs/version-withSlugs/rootResolvedSlug.md", - "sourceDirName": ".", - "slug": "/hey/rootResolvedSlug", - "permalink": "/docs/withSlugs/hey/rootResolvedSlug", - "draft": false, - "unlisted": false, - "tags": [], - "version": "withSlugs", - "frontMatter": { - "slug": "./hey/ho/../rootResolvedSlug" - } -}", - "site-versioned-docs-version-with-slugs-root-try-to-escape-slug-md-b5d.json": "{ - "id": "rootTryToEscapeSlug", - "title": "rootTryToEscapeSlug", - "description": "Lorem", - "source": "@site/versioned_docs/version-withSlugs/rootTryToEscapeSlug.md", - "sourceDirName": ".", - "slug": "/rootTryToEscapeSlug", - "permalink": "/docs/withSlugs/rootTryToEscapeSlug", - "draft": false, - "unlisted": false, - "tags": [], - "version": "withSlugs", - "frontMatter": { - "slug": "../../../../../../../../rootTryToEscapeSlug" - } -}", - "site-versioned-docs-version-with-slugs-slugs-absolute-slug-md-47a.json": "{ - "id": "slugs/absoluteSlug", - "title": "absoluteSlug", - "description": "Lorem", - "source": "@site/versioned_docs/version-withSlugs/slugs/absoluteSlug.md", - "sourceDirName": "slugs", - "slug": "/absoluteSlug", - "permalink": "/docs/withSlugs/absoluteSlug", - "draft": false, - "unlisted": false, - "tags": [], - "version": "withSlugs", - "frontMatter": { - "slug": "/absoluteSlug" - } -}", - "site-versioned-docs-version-with-slugs-slugs-relative-slug-md-a95.json": "{ - "id": "slugs/relativeSlug", - "title": "relativeSlug", - "description": "Lorem", - "source": "@site/versioned_docs/version-withSlugs/slugs/relativeSlug.md", - "sourceDirName": "slugs", - "slug": "/slugs/relativeSlug", - "permalink": "/docs/withSlugs/slugs/relativeSlug", - "draft": false, - "unlisted": false, - "tags": [], - "version": "withSlugs", - "frontMatter": { - "slug": "relativeSlug" - } -}", - "site-versioned-docs-version-with-slugs-slugs-resolved-slug-md-5a1.json": "{ - "id": "slugs/resolvedSlug", - "title": "resolvedSlug", - "description": "Lorem", - "source": "@site/versioned_docs/version-withSlugs/slugs/resolvedSlug.md", - "sourceDirName": "slugs", - "slug": "/slugs/hey/resolvedSlug", - "permalink": "/docs/withSlugs/slugs/hey/resolvedSlug", - "draft": false, - "unlisted": false, - "tags": [], - "version": "withSlugs", - "frontMatter": { - "slug": "./hey/ho/../resolvedSlug" - } -}", - "site-versioned-docs-version-with-slugs-slugs-try-to-escape-slug-md-4e1.json": "{ - "id": "slugs/tryToEscapeSlug", - "title": "tryToEscapeSlug", - "description": "Lorem", - "source": "@site/versioned_docs/version-withSlugs/slugs/tryToEscapeSlug.md", - "sourceDirName": "slugs", - "slug": "/tryToEscapeSlug", - "permalink": "/docs/withSlugs/tryToEscapeSlug", - "draft": false, - "unlisted": false, - "tags": [], - "version": "withSlugs", - "frontMatter": { - "slug": "../../../../../../../../tryToEscapeSlug" - } -}", - "tag-docs-next-tags-bar-tag-1-a8f.json": "{ - "label": "barTag 1", - "permalink": "/docs/next/tags/bar-tag-1", - "allTagsPath": "/docs/next/tags", - "count": 1, - "items": [ - { - "id": "foo/bar", - "title": "bar", - "description": "This is next version of bar.", - "permalink": "/docs/next/foo/barSlug" - } - ], - "unlisted": false -}", - "tag-docs-next-tags-bar-tag-2-216.json": "{ - "label": "barTag-2", - "permalink": "/docs/next/tags/bar-tag-2", - "allTagsPath": "/docs/next/tags", - "count": 1, - "items": [ - { - "id": "foo/bar", - "title": "bar", - "description": "This is next version of bar.", - "permalink": "/docs/next/foo/barSlug" - } - ], - "unlisted": false -}", - "tag-docs-next-tags-bar-tag-3-permalink-94a.json": "{ - "label": "barTag 3", - "permalink": "/docs/next/tags/barTag-3-permalink", - "allTagsPath": "/docs/next/tags", - "count": 1, - "items": [ - { - "id": "foo/bar", - "title": "bar", - "description": "This is next version of bar.", - "permalink": "/docs/next/foo/barSlug" - } - ], - "unlisted": false -}", - "tags-list-current-prop-15a.json": "[ - { - "label": "barTag 1", - "permalink": "/docs/next/tags/bar-tag-1", - "count": 1 - }, - { - "label": "barTag-2", - "permalink": "/docs/next/tags/bar-tag-2", - "count": 1 - }, - { - "label": "barTag 3", - "permalink": "/docs/next/tags/barTag-3-permalink", - "count": 1 - } -]", - "version-1-0-0-metadata-prop-608.json": "{ - "pluginId": "default", - "version": "1.0.0", - "label": "1.0.0", - "banner": "unmaintained", - "badge": true, - "noIndex": false, - "className": "docs-version-1.0.0", - "isLast": false, - "docsSidebars": { - "docs": [ - { - "type": "category", - "label": "Test", - "items": [ - { - "type": "link", - "label": "bar", - "href": "/docs/1.0.0/foo/barSlug", - "docId": "foo/bar", - "unlisted": false - }, - { - "type": "link", - "label": "baz", - "href": "/docs/1.0.0/foo/baz", - "docId": "foo/baz", - "unlisted": false - } - ], - "collapsed": true, - "collapsible": true + "permalink": "/docs/next/tags/barTag-3-permalink", }, - { - "type": "category", - "label": "Guides", - "items": [ - { - "type": "link", - "label": "hello", - "href": "/docs/1.0.0/", - "docId": "hello", - "unlisted": false - } - ], - "collapsed": true, - "collapsible": true - } - ] + ], + "title": "bar", + "unlisted": false, + "version": "current", }, - "docs": { - "foo/bar": { - "id": "foo/bar", - "title": "bar", - "description": "Bar 1.0.0 !", - "sidebar": "docs" + "site-docs-hello-md-9df.json": { + "description": "Hello next !", + "draft": false, + "editUrl": undefined, + "frontMatter": { + "slug": "/", }, - "foo/baz": { - "id": "foo/baz", + "id": "hello", + "lastUpdatedAt": undefined, + "lastUpdatedBy": undefined, + "next": undefined, + "permalink": "/docs/next/", + "previous": { + "permalink": "/docs/next/foo/barSlug", + "title": "bar", + }, + "sidebar": "docs", + "sidebarPosition": undefined, + "slug": "/", + "source": "@site/docs/hello.md", + "sourceDirName": ".", + "tags": [], + "title": "hello", + "unlisted": false, + "version": "current", + }, + "site-docs-slugs-absolute-slug-md-4e8.json": { + "description": "Lorem", + "draft": false, + "editUrl": undefined, + "frontMatter": { + "slug": "/absoluteSlug", + }, + "id": "slugs/absoluteSlug", + "lastUpdatedAt": undefined, + "lastUpdatedBy": undefined, + "next": undefined, + "permalink": "/docs/next/absoluteSlug", + "previous": undefined, + "sidebar": undefined, + "sidebarPosition": undefined, + "slug": "/absoluteSlug", + "source": "@site/docs/slugs/absoluteSlug.md", + "sourceDirName": "slugs", + "tags": [], + "title": "absoluteSlug", + "unlisted": false, + "version": "current", + }, + "site-docs-slugs-relative-slug-md-d1c.json": { + "description": "Lorem", + "draft": false, + "editUrl": undefined, + "frontMatter": { + "slug": "relativeSlug", + }, + "id": "slugs/relativeSlug", + "lastUpdatedAt": undefined, + "lastUpdatedBy": undefined, + "next": undefined, + "permalink": "/docs/next/slugs/relativeSlug", + "previous": undefined, + "sidebar": undefined, + "sidebarPosition": undefined, + "slug": "/slugs/relativeSlug", + "source": "@site/docs/slugs/relativeSlug.md", + "sourceDirName": "slugs", + "tags": [], + "title": "relativeSlug", + "unlisted": false, + "version": "current", + }, + "site-docs-slugs-resolved-slug-md-02b.json": { + "description": "Lorem", + "draft": false, + "editUrl": undefined, + "frontMatter": { + "slug": "./hey/ho/../resolvedSlug", + }, + "id": "slugs/resolvedSlug", + "lastUpdatedAt": undefined, + "lastUpdatedBy": undefined, + "next": undefined, + "permalink": "/docs/next/slugs/hey/resolvedSlug", + "previous": undefined, + "sidebar": undefined, + "sidebarPosition": undefined, + "slug": "/slugs/hey/resolvedSlug", + "source": "@site/docs/slugs/resolvedSlug.md", + "sourceDirName": "slugs", + "tags": [], + "title": "resolvedSlug", + "unlisted": false, + "version": "current", + }, + "site-docs-slugs-try-to-escape-slug-md-70d.json": { + "description": "Lorem", + "draft": false, + "editUrl": undefined, + "frontMatter": { + "slug": "../../../../../../../../tryToEscapeSlug", + }, + "id": "slugs/tryToEscapeSlug", + "lastUpdatedAt": undefined, + "lastUpdatedBy": undefined, + "next": undefined, + "permalink": "/docs/next/tryToEscapeSlug", + "previous": undefined, + "sidebar": undefined, + "sidebarPosition": undefined, + "slug": "/tryToEscapeSlug", + "source": "@site/docs/slugs/tryToEscapeSlug.md", + "sourceDirName": "slugs", + "tags": [], + "title": "tryToEscapeSlug", + "unlisted": false, + "version": "current", + }, + "site-i-18-n-en-docusaurus-plugin-content-docs-version-1-0-0-hello-md-fe5.json": { + "description": "Hello 1.0.0 ! (translated en)", + "draft": false, + "editUrl": undefined, + "frontMatter": { + "slug": "/", + }, + "id": "hello", + "lastUpdatedAt": undefined, + "lastUpdatedBy": undefined, + "next": undefined, + "permalink": "/docs/1.0.0/", + "previous": { + "permalink": "/docs/1.0.0/foo/baz", "title": "baz", - "description": "Baz 1.0.0 ! This will be deleted in next subsequent versions.", - "sidebar": "docs" }, - "hello": { - "id": "hello", - "title": "hello", - "description": "Hello 1.0.0 ! (translated en)", - "sidebar": "docs" - } - } -}", - "version-1-0-1-metadata-prop-e87.json": "{ - "pluginId": "default", - "version": "1.0.1", - "label": "1.0.1", - "banner": null, - "badge": true, - "noIndex": true, - "className": "docs-version-1.0.1", - "isLast": true, - "docsSidebars": { - "VersionedSideBarNameDoesNotMatter/docs": [ - { - "type": "category", - "label": "Test", - "items": [ - { - "type": "link", - "label": "bar", - "href": "/docs/foo/bar", - "docId": "foo/bar", - "unlisted": false - } - ], - "collapsed": true, - "collapsible": true - }, - { - "type": "category", - "label": "Guides", - "items": [ - { - "type": "link", - "label": "hello", - "href": "/docs/", - "docId": "hello", - "unlisted": false - } - ], - "collapsed": true, - "collapsible": true - } - ] + "sidebar": "docs", + "sidebarPosition": undefined, + "slug": "/", + "source": "@site/i18n/en/docusaurus-plugin-content-docs/version-1.0.0/hello.md", + "sourceDirName": ".", + "tags": [], + "title": "hello", + "unlisted": false, + "version": "1.0.0", }, - "docs": { - "foo/bar": { - "id": "foo/bar", + "site-versioned-docs-version-1-0-0-foo-bar-md-7a6.json": { + "description": "Bar 1.0.0 !", + "draft": false, + "editUrl": undefined, + "frontMatter": { + "slug": "barSlug", + }, + "id": "foo/bar", + "lastUpdatedAt": undefined, + "lastUpdatedBy": undefined, + "next": { + "permalink": "/docs/1.0.0/foo/baz", + "title": "baz", + }, + "permalink": "/docs/1.0.0/foo/barSlug", + "previous": undefined, + "sidebar": "docs", + "sidebarPosition": undefined, + "slug": "/foo/barSlug", + "source": "@site/versioned_docs/version-1.0.0/foo/bar.md", + "sourceDirName": "foo", + "tags": [], + "title": "bar", + "unlisted": false, + "version": "1.0.0", + }, + "site-versioned-docs-version-1-0-0-foo-baz-md-883.json": { + "description": "Baz 1.0.0 ! This will be deleted in next subsequent versions.", + "draft": false, + "editUrl": undefined, + "frontMatter": {}, + "id": "foo/baz", + "lastUpdatedAt": undefined, + "lastUpdatedBy": undefined, + "next": { + "permalink": "/docs/1.0.0/", + "title": "hello", + }, + "permalink": "/docs/1.0.0/foo/baz", + "previous": { + "permalink": "/docs/1.0.0/foo/barSlug", "title": "bar", - "description": "Bar 1.0.1 !", - "sidebar": "VersionedSideBarNameDoesNotMatter/docs" }, - "hello": { - "id": "hello", - "title": "hello", - "description": "Hello 1.0.1 !", - "sidebar": "VersionedSideBarNameDoesNotMatter/docs" - } - } -}", - "version-current-metadata-prop-751.json": "{ - "pluginId": "default", - "version": "current", - "label": "Next", - "banner": "unreleased", - "badge": true, - "noIndex": false, - "className": "docs-version-current", - "isLast": false, - "docsSidebars": { - "docs": [ - { - "type": "category", - "label": "Test", - "items": [ - { - "type": "link", - "label": "bar", - "href": "/docs/next/foo/barSlug", - "docId": "foo/bar", - "unlisted": false - } - ], - "collapsed": true, - "collapsible": true - }, - { - "type": "category", - "label": "Guides", - "items": [ - { - "type": "link", - "label": "hello", - "href": "/docs/next/", - "docId": "hello", - "unlisted": false - } - ], - "collapsed": true, - "collapsible": true - } - ] + "sidebar": "docs", + "sidebarPosition": undefined, + "slug": "/foo/baz", + "source": "@site/versioned_docs/version-1.0.0/foo/baz.md", + "sourceDirName": "foo", + "tags": [], + "title": "baz", + "unlisted": false, + "version": "1.0.0", }, - "docs": { - "foo/bar": { - "id": "foo/bar", + "site-versioned-docs-version-1-0-1-foo-bar-md-7a3.json": { + "description": "Bar 1.0.1 !", + "draft": false, + "editUrl": undefined, + "frontMatter": {}, + "id": "foo/bar", + "lastUpdatedAt": undefined, + "lastUpdatedBy": undefined, + "next": { + "permalink": "/docs/", + "title": "hello", + }, + "permalink": "/docs/foo/bar", + "previous": undefined, + "sidebar": "VersionedSideBarNameDoesNotMatter/docs", + "sidebarPosition": undefined, + "slug": "/foo/bar", + "source": "@site/versioned_docs/version-1.0.1/foo/bar.md", + "sourceDirName": "foo", + "tags": [], + "title": "bar", + "unlisted": false, + "version": "1.0.1", + }, + "site-versioned-docs-version-1-0-1-hello-md-0c7.json": { + "description": "Hello 1.0.1 !", + "draft": false, + "editUrl": undefined, + "frontMatter": { + "slug": "/", + }, + "id": "hello", + "lastUpdatedAt": undefined, + "lastUpdatedBy": undefined, + "next": undefined, + "permalink": "/docs/", + "previous": { + "permalink": "/docs/foo/bar", "title": "bar", - "description": "This is next version of bar.", - "sidebar": "docs" }, - "hello": { - "id": "hello", - "title": "hello", - "description": "Hello next !", - "sidebar": "docs" - }, - "slugs/absoluteSlug": { - "id": "slugs/absoluteSlug", - "title": "absoluteSlug", - "description": "Lorem" - }, - "slugs/relativeSlug": { - "id": "slugs/relativeSlug", - "title": "relativeSlug", - "description": "Lorem" - }, - "slugs/resolvedSlug": { - "id": "slugs/resolvedSlug", - "title": "resolvedSlug", - "description": "Lorem" - }, - "slugs/tryToEscapeSlug": { - "id": "slugs/tryToEscapeSlug", - "title": "tryToEscapeSlug", - "description": "Lorem" - } - } -}", - "version-with-slugs-metadata-prop-2bf.json": "{ - "pluginId": "default", - "version": "withSlugs", - "label": "withSlugs", - "banner": "unmaintained", - "badge": true, - "noIndex": false, - "className": "docs-version-withSlugs", - "isLast": false, - "docsSidebars": { - "docs": [ - { - "type": "category", - "label": "Test", - "items": [ - { - "type": "link", - "label": "rootAbsoluteSlug", - "href": "/docs/withSlugs/rootAbsoluteSlug", - "docId": "rootAbsoluteSlug", - "unlisted": false - } - ], - "collapsed": true, - "collapsible": true - } - ] + "sidebar": "VersionedSideBarNameDoesNotMatter/docs", + "sidebarPosition": undefined, + "slug": "/", + "source": "@site/versioned_docs/version-1.0.1/hello.md", + "sourceDirName": ".", + "tags": [], + "title": "hello", + "unlisted": false, + "version": "1.0.1", }, - "docs": { - "rootAbsoluteSlug": { - "id": "rootAbsoluteSlug", - "title": "rootAbsoluteSlug", - "description": "Lorem", - "sidebar": "docs" + "site-versioned-docs-version-with-slugs-root-absolute-slug-md-4d2.json": { + "description": "Lorem", + "draft": false, + "editUrl": undefined, + "frontMatter": { + "slug": "/rootAbsoluteSlug", }, - "rootRelativeSlug": { - "id": "rootRelativeSlug", - "title": "rootRelativeSlug", - "description": "Lorem" + "id": "rootAbsoluteSlug", + "lastUpdatedAt": undefined, + "lastUpdatedBy": undefined, + "next": undefined, + "permalink": "/docs/withSlugs/rootAbsoluteSlug", + "previous": undefined, + "sidebar": "docs", + "sidebarPosition": undefined, + "slug": "/rootAbsoluteSlug", + "source": "@site/versioned_docs/version-withSlugs/rootAbsoluteSlug.md", + "sourceDirName": ".", + "tags": [], + "title": "rootAbsoluteSlug", + "unlisted": false, + "version": "withSlugs", + }, + "site-versioned-docs-version-with-slugs-root-relative-slug-md-32a.json": { + "description": "Lorem", + "draft": false, + "editUrl": undefined, + "frontMatter": { + "slug": "rootRelativeSlug", }, - "rootResolvedSlug": { - "id": "rootResolvedSlug", - "title": "rootResolvedSlug", - "description": "Lorem" + "id": "rootRelativeSlug", + "lastUpdatedAt": undefined, + "lastUpdatedBy": undefined, + "next": undefined, + "permalink": "/docs/withSlugs/rootRelativeSlug", + "previous": undefined, + "sidebar": undefined, + "sidebarPosition": undefined, + "slug": "/rootRelativeSlug", + "source": "@site/versioned_docs/version-withSlugs/rootRelativeSlug.md", + "sourceDirName": ".", + "tags": [], + "title": "rootRelativeSlug", + "unlisted": false, + "version": "withSlugs", + }, + "site-versioned-docs-version-with-slugs-root-resolved-slug-md-aee.json": { + "description": "Lorem", + "draft": false, + "editUrl": undefined, + "frontMatter": { + "slug": "./hey/ho/../rootResolvedSlug", }, - "rootTryToEscapeSlug": { - "id": "rootTryToEscapeSlug", - "title": "rootTryToEscapeSlug", - "description": "Lorem" + "id": "rootResolvedSlug", + "lastUpdatedAt": undefined, + "lastUpdatedBy": undefined, + "next": undefined, + "permalink": "/docs/withSlugs/hey/rootResolvedSlug", + "previous": undefined, + "sidebar": undefined, + "sidebarPosition": undefined, + "slug": "/hey/rootResolvedSlug", + "source": "@site/versioned_docs/version-withSlugs/rootResolvedSlug.md", + "sourceDirName": ".", + "tags": [], + "title": "rootResolvedSlug", + "unlisted": false, + "version": "withSlugs", + }, + "site-versioned-docs-version-with-slugs-root-try-to-escape-slug-md-b5d.json": { + "description": "Lorem", + "draft": false, + "editUrl": undefined, + "frontMatter": { + "slug": "../../../../../../../../rootTryToEscapeSlug", }, - "slugs/absoluteSlug": { - "id": "slugs/absoluteSlug", - "title": "absoluteSlug", - "description": "Lorem" + "id": "rootTryToEscapeSlug", + "lastUpdatedAt": undefined, + "lastUpdatedBy": undefined, + "next": undefined, + "permalink": "/docs/withSlugs/rootTryToEscapeSlug", + "previous": undefined, + "sidebar": undefined, + "sidebarPosition": undefined, + "slug": "/rootTryToEscapeSlug", + "source": "@site/versioned_docs/version-withSlugs/rootTryToEscapeSlug.md", + "sourceDirName": ".", + "tags": [], + "title": "rootTryToEscapeSlug", + "unlisted": false, + "version": "withSlugs", + }, + "site-versioned-docs-version-with-slugs-slugs-absolute-slug-md-47a.json": { + "description": "Lorem", + "draft": false, + "editUrl": undefined, + "frontMatter": { + "slug": "/absoluteSlug", }, - "slugs/relativeSlug": { - "id": "slugs/relativeSlug", - "title": "relativeSlug", - "description": "Lorem" + "id": "slugs/absoluteSlug", + "lastUpdatedAt": undefined, + "lastUpdatedBy": undefined, + "next": undefined, + "permalink": "/docs/withSlugs/absoluteSlug", + "previous": undefined, + "sidebar": undefined, + "sidebarPosition": undefined, + "slug": "/absoluteSlug", + "source": "@site/versioned_docs/version-withSlugs/slugs/absoluteSlug.md", + "sourceDirName": "slugs", + "tags": [], + "title": "absoluteSlug", + "unlisted": false, + "version": "withSlugs", + }, + "site-versioned-docs-version-with-slugs-slugs-relative-slug-md-a95.json": { + "description": "Lorem", + "draft": false, + "editUrl": undefined, + "frontMatter": { + "slug": "relativeSlug", }, - "slugs/resolvedSlug": { - "id": "slugs/resolvedSlug", - "title": "resolvedSlug", - "description": "Lorem" + "id": "slugs/relativeSlug", + "lastUpdatedAt": undefined, + "lastUpdatedBy": undefined, + "next": undefined, + "permalink": "/docs/withSlugs/slugs/relativeSlug", + "previous": undefined, + "sidebar": undefined, + "sidebarPosition": undefined, + "slug": "/slugs/relativeSlug", + "source": "@site/versioned_docs/version-withSlugs/slugs/relativeSlug.md", + "sourceDirName": "slugs", + "tags": [], + "title": "relativeSlug", + "unlisted": false, + "version": "withSlugs", + }, + "site-versioned-docs-version-with-slugs-slugs-resolved-slug-md-5a1.json": { + "description": "Lorem", + "draft": false, + "editUrl": undefined, + "frontMatter": { + "slug": "./hey/ho/../resolvedSlug", }, - "slugs/tryToEscapeSlug": { - "id": "slugs/tryToEscapeSlug", - "title": "tryToEscapeSlug", - "description": "Lorem" - } - } -}", + "id": "slugs/resolvedSlug", + "lastUpdatedAt": undefined, + "lastUpdatedBy": undefined, + "next": undefined, + "permalink": "/docs/withSlugs/slugs/hey/resolvedSlug", + "previous": undefined, + "sidebar": undefined, + "sidebarPosition": undefined, + "slug": "/slugs/hey/resolvedSlug", + "source": "@site/versioned_docs/version-withSlugs/slugs/resolvedSlug.md", + "sourceDirName": "slugs", + "tags": [], + "title": "resolvedSlug", + "unlisted": false, + "version": "withSlugs", + }, + "site-versioned-docs-version-with-slugs-slugs-try-to-escape-slug-md-4e1.json": { + "description": "Lorem", + "draft": false, + "editUrl": undefined, + "frontMatter": { + "slug": "../../../../../../../../tryToEscapeSlug", + }, + "id": "slugs/tryToEscapeSlug", + "lastUpdatedAt": undefined, + "lastUpdatedBy": undefined, + "next": undefined, + "permalink": "/docs/withSlugs/tryToEscapeSlug", + "previous": undefined, + "sidebar": undefined, + "sidebarPosition": undefined, + "slug": "/tryToEscapeSlug", + "source": "@site/versioned_docs/version-withSlugs/slugs/tryToEscapeSlug.md", + "sourceDirName": "slugs", + "tags": [], + "title": "tryToEscapeSlug", + "unlisted": false, + "version": "withSlugs", + }, } `; @@ -4256,11 +4198,87 @@ exports[`versioned website content: route config 1`] = ` { "component": "@theme/DocVersionRoot", "exact": false, - "modules": { - "version": "~docs/version-1-0-0-metadata-prop-608.json", - }, "path": "/docs/1.0.0", "priority": undefined, + "props": { + "version": { + "badge": true, + "banner": "unmaintained", + "className": "docs-version-1.0.0", + "docs": { + "foo/bar": { + "description": "Bar 1.0.0 !", + "id": "foo/bar", + "sidebar": "docs", + "title": "bar", + }, + "foo/baz": { + "description": "Baz 1.0.0 ! This will be deleted in next subsequent versions.", + "id": "foo/baz", + "sidebar": "docs", + "title": "baz", + }, + "hello": { + "description": "Hello 1.0.0 ! (translated en)", + "id": "hello", + "sidebar": "docs", + "title": "hello", + }, + }, + "docsSidebars": { + "docs": [ + { + "collapsed": true, + "collapsible": true, + "items": [ + { + "className": undefined, + "customProps": undefined, + "docId": "foo/bar", + "href": "/docs/1.0.0/foo/barSlug", + "label": "bar", + "type": "link", + "unlisted": false, + }, + { + "className": undefined, + "customProps": undefined, + "docId": "foo/baz", + "href": "/docs/1.0.0/foo/baz", + "label": "baz", + "type": "link", + "unlisted": false, + }, + ], + "label": "Test", + "type": "category", + }, + { + "collapsed": true, + "collapsible": true, + "items": [ + { + "className": undefined, + "customProps": undefined, + "docId": "hello", + "href": "/docs/1.0.0/", + "label": "hello", + "type": "link", + "unlisted": false, + }, + ], + "label": "Guides", + "type": "category", + }, + ], + }, + "isLast": false, + "label": "1.0.0", + "noIndex": false, + "pluginId": "default", + "version": "1.0.0", + }, + }, "routes": [ { "component": "@theme/DocRoot", @@ -4313,43 +4331,186 @@ exports[`versioned website content: route config 1`] = ` { "component": "@theme/DocVersionRoot", "exact": false, - "modules": { - "version": "~docs/version-current-metadata-prop-751.json", - }, "path": "/docs/next", "priority": undefined, + "props": { + "version": { + "badge": true, + "banner": "unreleased", + "className": "docs-version-current", + "docs": { + "foo/bar": { + "description": "This is next version of bar.", + "id": "foo/bar", + "sidebar": "docs", + "title": "bar", + }, + "hello": { + "description": "Hello next !", + "id": "hello", + "sidebar": "docs", + "title": "hello", + }, + "slugs/absoluteSlug": { + "description": "Lorem", + "id": "slugs/absoluteSlug", + "sidebar": undefined, + "title": "absoluteSlug", + }, + "slugs/relativeSlug": { + "description": "Lorem", + "id": "slugs/relativeSlug", + "sidebar": undefined, + "title": "relativeSlug", + }, + "slugs/resolvedSlug": { + "description": "Lorem", + "id": "slugs/resolvedSlug", + "sidebar": undefined, + "title": "resolvedSlug", + }, + "slugs/tryToEscapeSlug": { + "description": "Lorem", + "id": "slugs/tryToEscapeSlug", + "sidebar": undefined, + "title": "tryToEscapeSlug", + }, + }, + "docsSidebars": { + "docs": [ + { + "collapsed": true, + "collapsible": true, + "items": [ + { + "className": undefined, + "customProps": undefined, + "docId": "foo/bar", + "href": "/docs/next/foo/barSlug", + "label": "bar", + "type": "link", + "unlisted": false, + }, + ], + "label": "Test", + "type": "category", + }, + { + "collapsed": true, + "collapsible": true, + "items": [ + { + "className": undefined, + "customProps": undefined, + "docId": "hello", + "href": "/docs/next/", + "label": "hello", + "type": "link", + "unlisted": false, + }, + ], + "label": "Guides", + "type": "category", + }, + ], + }, + "isLast": false, + "label": "Next", + "noIndex": false, + "pluginId": "default", + "version": "current", + }, + }, "routes": [ { "component": "@theme/DocTagsListPage", "exact": true, - "modules": { - "tags": "~docs/tags-list-current-prop-15a.json", - }, "path": "/docs/next/tags", + "props": { + "tags": [ + { + "count": 1, + "label": "barTag 1", + "permalink": "/docs/next/tags/bar-tag-1", + }, + { + "count": 1, + "label": "barTag-2", + "permalink": "/docs/next/tags/bar-tag-2", + }, + { + "count": 1, + "label": "barTag 3", + "permalink": "/docs/next/tags/barTag-3-permalink", + }, + ], + }, }, { "component": "@theme/DocTagDocListPage", "exact": true, - "modules": { - "tag": "~docs/tag-docs-next-tags-bar-tag-1-a8f.json", - }, "path": "/docs/next/tags/bar-tag-1", + "props": { + "tag": { + "allTagsPath": "/docs/next/tags", + "count": 1, + "items": [ + { + "description": "This is next version of bar.", + "id": "foo/bar", + "permalink": "/docs/next/foo/barSlug", + "title": "bar", + }, + ], + "label": "barTag 1", + "permalink": "/docs/next/tags/bar-tag-1", + "unlisted": false, + }, + }, }, { "component": "@theme/DocTagDocListPage", "exact": true, - "modules": { - "tag": "~docs/tag-docs-next-tags-bar-tag-2-216.json", - }, "path": "/docs/next/tags/bar-tag-2", + "props": { + "tag": { + "allTagsPath": "/docs/next/tags", + "count": 1, + "items": [ + { + "description": "This is next version of bar.", + "id": "foo/bar", + "permalink": "/docs/next/foo/barSlug", + "title": "bar", + }, + ], + "label": "barTag-2", + "permalink": "/docs/next/tags/bar-tag-2", + "unlisted": false, + }, + }, }, { "component": "@theme/DocTagDocListPage", "exact": true, - "modules": { - "tag": "~docs/tag-docs-next-tags-bar-tag-3-permalink-94a.json", - }, "path": "/docs/next/tags/barTag-3-permalink", + "props": { + "tag": { + "allTagsPath": "/docs/next/tags", + "count": 1, + "items": [ + { + "description": "This is next version of bar.", + "id": "foo/bar", + "permalink": "/docs/next/foo/barSlug", + "title": "bar", + }, + ], + "label": "barTag 3", + "permalink": "/docs/next/tags/barTag-3-permalink", + "unlisted": false, + }, + }, }, { "component": "@theme/DocRoot", @@ -4437,11 +4598,91 @@ exports[`versioned website content: route config 1`] = ` { "component": "@theme/DocVersionRoot", "exact": false, - "modules": { - "version": "~docs/version-with-slugs-metadata-prop-2bf.json", - }, "path": "/docs/withSlugs", "priority": undefined, + "props": { + "version": { + "badge": true, + "banner": "unmaintained", + "className": "docs-version-withSlugs", + "docs": { + "rootAbsoluteSlug": { + "description": "Lorem", + "id": "rootAbsoluteSlug", + "sidebar": "docs", + "title": "rootAbsoluteSlug", + }, + "rootRelativeSlug": { + "description": "Lorem", + "id": "rootRelativeSlug", + "sidebar": undefined, + "title": "rootRelativeSlug", + }, + "rootResolvedSlug": { + "description": "Lorem", + "id": "rootResolvedSlug", + "sidebar": undefined, + "title": "rootResolvedSlug", + }, + "rootTryToEscapeSlug": { + "description": "Lorem", + "id": "rootTryToEscapeSlug", + "sidebar": undefined, + "title": "rootTryToEscapeSlug", + }, + "slugs/absoluteSlug": { + "description": "Lorem", + "id": "slugs/absoluteSlug", + "sidebar": undefined, + "title": "absoluteSlug", + }, + "slugs/relativeSlug": { + "description": "Lorem", + "id": "slugs/relativeSlug", + "sidebar": undefined, + "title": "relativeSlug", + }, + "slugs/resolvedSlug": { + "description": "Lorem", + "id": "slugs/resolvedSlug", + "sidebar": undefined, + "title": "resolvedSlug", + }, + "slugs/tryToEscapeSlug": { + "description": "Lorem", + "id": "slugs/tryToEscapeSlug", + "sidebar": undefined, + "title": "tryToEscapeSlug", + }, + }, + "docsSidebars": { + "docs": [ + { + "collapsed": true, + "collapsible": true, + "items": [ + { + "className": undefined, + "customProps": undefined, + "docId": "rootAbsoluteSlug", + "href": "/docs/withSlugs/rootAbsoluteSlug", + "label": "rootAbsoluteSlug", + "type": "link", + "unlisted": false, + }, + ], + "label": "Test", + "type": "category", + }, + ], + }, + "isLast": false, + "label": "withSlugs", + "noIndex": false, + "pluginId": "default", + "version": "withSlugs", + }, + }, "routes": [ { "component": "@theme/DocRoot", @@ -4552,11 +4793,72 @@ exports[`versioned website content: route config 1`] = ` { "component": "@theme/DocVersionRoot", "exact": false, - "modules": { - "version": "~docs/version-1-0-1-metadata-prop-e87.json", - }, "path": "/docs", "priority": -1, + "props": { + "version": { + "badge": true, + "banner": null, + "className": "docs-version-1.0.1", + "docs": { + "foo/bar": { + "description": "Bar 1.0.1 !", + "id": "foo/bar", + "sidebar": "VersionedSideBarNameDoesNotMatter/docs", + "title": "bar", + }, + "hello": { + "description": "Hello 1.0.1 !", + "id": "hello", + "sidebar": "VersionedSideBarNameDoesNotMatter/docs", + "title": "hello", + }, + }, + "docsSidebars": { + "VersionedSideBarNameDoesNotMatter/docs": [ + { + "collapsed": true, + "collapsible": true, + "items": [ + { + "className": undefined, + "customProps": undefined, + "docId": "foo/bar", + "href": "/docs/foo/bar", + "label": "bar", + "type": "link", + "unlisted": false, + }, + ], + "label": "Test", + "type": "category", + }, + { + "collapsed": true, + "collapsible": true, + "items": [ + { + "className": undefined, + "customProps": undefined, + "docId": "hello", + "href": "/docs/", + "label": "hello", + "type": "link", + "unlisted": false, + }, + ], + "label": "Guides", + "type": "category", + }, + ], + }, + "isLast": true, + "label": "1.0.1", + "noIndex": true, + "pluginId": "default", + "version": "1.0.1", + }, + }, "routes": [ { "component": "@theme/DocRoot", diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/index.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/index.test.ts index 1aca97041d..150ca37766 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/index.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/index.test.ts @@ -31,7 +31,6 @@ import type { Options, PluginOptions, PropSidebarItemLink, - PropSidebars, } from '@docusaurus/plugin-content-docs'; import type { SidebarItemsGeneratorOption, @@ -76,36 +75,11 @@ const createFakeActions = (contentDir: string) => { }, }; - // Query by prefix, because files have a hash at the end so it's not - // convenient to query by full filename - function getCreatedDataByPrefix(prefix: string) { - const entry = Object.entries(dataContainer).find(([key]) => - key.startsWith(prefix), - ); - if (!entry) { - throw new Error(`No created entry found for prefix "${prefix}". -Entries created: -- ${Object.keys(dataContainer).join('\n- ')} - `); - } - return JSON.parse(entry[1] as string) as PropSidebars; - } - // Extra fns useful for tests! const utils = { getGlobalData: () => globalDataContainer, getRouteConfigs: () => routeConfigs, - checkVersionMetadataPropCreated: (version: LoadedVersion | undefined) => { - if (!version) { - throw new Error('Version not found'); - } - const versionMetadataProp = getCreatedDataByPrefix( - `version-${_.kebabCase(version.versionName)}-metadata-prop`, - ); - expect(versionMetadataProp.docsSidebars).toEqual(toSidebarsProp(version)); - }, - expectSnapshot: () => { // Sort the route config like in src/server/plugins/index.ts for // consistent snapshot ordering @@ -335,11 +309,8 @@ describe('simple website', () => { await plugin.contentLoaded!({ content, actions, - allContent: {}, }); - utils.checkVersionMetadataPropCreated(currentVersion); - utils.expectSnapshot(); expect(utils.getGlobalData()).toMatchSnapshot(); @@ -464,14 +435,8 @@ describe('versioned website', () => { await plugin.contentLoaded!({ content, actions, - allContent: {}, }); - utils.checkVersionMetadataPropCreated(currentVersion); - utils.checkVersionMetadataPropCreated(version101); - utils.checkVersionMetadataPropCreated(version100); - utils.checkVersionMetadataPropCreated(versionWithSlugs); - utils.expectSnapshot(); }); }); @@ -569,12 +534,8 @@ describe('versioned website (community)', () => { await plugin.contentLoaded!({ content, actions, - allContent: {}, }); - utils.checkVersionMetadataPropCreated(currentVersion); - utils.checkVersionMetadataPropCreated(version100); - utils.expectSnapshot(); }); }); diff --git a/packages/docusaurus-plugin-content-docs/src/index.ts b/packages/docusaurus-plugin-content-docs/src/index.ts index 4cb9860595..18e43a7f65 100644 --- a/packages/docusaurus-plugin-content-docs/src/index.ts +++ b/packages/docusaurus-plugin-content-docs/src/index.ts @@ -73,6 +73,9 @@ export default async function pluginContentDocs( 'docusaurus-plugin-content-docs', ); const dataDir = path.join(pluginDataDirRoot, pluginId); + // TODO Docusaurus v4 breaking change + // module aliasing should be automatic + // we should never find local absolute FS paths in the codegen registry const aliasedSource = (source: string) => `~docs/${posixPath(path.relative(pluginDataDirRoot, source))}`; diff --git a/packages/docusaurus-plugin-content-docs/src/routes.ts b/packages/docusaurus-plugin-content-docs/src/routes.ts index cff90fc491..14c55f1540 100644 --- a/packages/docusaurus-plugin-content-docs/src/routes.ts +++ b/packages/docusaurus-plugin-content-docs/src/routes.ts @@ -9,7 +9,6 @@ import _ from 'lodash'; import logger from '@docusaurus/logger'; import { docuHash, - createSlugger, normalizeUrl, aliasedSitePathToRelativePath, } from '@docusaurus/utils'; @@ -29,7 +28,6 @@ import type { CategoryGeneratedIndexMetadata, DocMetadata, PluginOptions, - PropTagsListPage, } from '@docusaurus/plugin-content-docs'; function createDocRouteMetadata(docMeta: DocMetadata): RouteMetadata { @@ -41,36 +39,23 @@ function createDocRouteMetadata(docMeta: DocMetadata): RouteMetadata { async function buildVersionCategoryGeneratedIndexRoutes({ version, - actions, options, - aliasedSource, }: BuildVersionRoutesParam): Promise { - const slugs = createSlugger(); - async function buildCategoryGeneratedIndexRoute( categoryGeneratedIndex: CategoryGeneratedIndexMetadata, ): Promise { - const {sidebar, ...prop} = categoryGeneratedIndex; - - const propFileName = slugs.slug( - `${version.path}-${categoryGeneratedIndex.sidebar}-category-${categoryGeneratedIndex.title}`, - ); - - const propData = await actions.createData( - `${docuHash(`category/${propFileName}`)}.json`, - JSON.stringify(prop, null, 2), - ); - return { path: categoryGeneratedIndex.permalink, component: options.docCategoryGeneratedIndexComponent, exact: true, - modules: { - categoryGeneratedIndex: aliasedSource(propData), + props: { + categoryGeneratedIndex, }, // Same as doc, this sidebar route attribute permits to associate this // subpage to the given sidebar - ...(sidebar && {sidebar}), + ...(categoryGeneratedIndex.sidebar && { + sidebar: categoryGeneratedIndex.sidebar, + }), }; } @@ -90,7 +75,7 @@ async function buildVersionDocRoutes({ // Note that this created data path must be in sync with // metadataPath provided to mdx-loader. `${docuHash(doc.source)}.json`, - JSON.stringify(doc, null, 2), + doc, ); const docRoute: RouteConfig = { @@ -131,7 +116,7 @@ async function buildVersionSidebarRoute(param: BuildVersionRoutesParam) { async function buildVersionTagsRoutes( param: BuildVersionRoutesParam, ): Promise { - const {version, options, actions, aliasedSource} = param; + const {version, options} = param; const versionTags = getVersionTags(version.docs); async function buildTagsListRoute(): Promise { @@ -139,37 +124,27 @@ async function buildVersionTagsRoutes( if (Object.keys(versionTags).length === 0) { return null; } - const tagsProp: PropTagsListPage['tags'] = toTagsListTagsProp(versionTags); - const tagsPropPath = await actions.createData( - `${docuHash(`tags-list-${version.versionName}-prop`)}.json`, - JSON.stringify(tagsProp, null, 2), - ); return { path: version.tagsPath, exact: true, component: options.docTagsListComponent, - modules: { - tags: aliasedSource(tagsPropPath), + props: { + tags: toTagsListTagsProp(versionTags), }, }; } async function buildTagDocListRoute(tag: VersionTag): Promise { - const tagProps = toTagDocListProp({ - allTagsPath: version.tagsPath, - tag, - docs: version.docs, - }); - const tagPropPath = await actions.createData( - `${docuHash(`tag-${tag.permalink}`)}.json`, - JSON.stringify(tagProps, null, 2), - ); return { path: tag.permalink, component: options.docTagDocListComponent, exact: true, - modules: { - tag: aliasedSource(tagPropPath), + props: { + tag: toTagDocListProp({ + allTagsPath: version.tagsPath, + tag, + docs: version.docs, + }), }, }; } @@ -189,7 +164,7 @@ type BuildVersionRoutesParam = Omit & { async function buildVersionRoutes( param: BuildVersionRoutesParam, ): Promise { - const {version, actions, options, aliasedSource} = param; + const {version, options} = param; async function buildVersionSubRoutes() { const [sidebarRoute, tagsRoutes] = await Promise.all([ @@ -201,19 +176,15 @@ async function buildVersionRoutes( } async function doBuildVersionRoutes(): Promise { - const versionProp = toVersionMetadataProp(options.id, version); - const versionPropPath = await actions.createData( - `${docuHash(`version-${version.versionName}-metadata-prop`)}.json`, - JSON.stringify(versionProp, null, 2), - ); - const subRoutes = await buildVersionSubRoutes(); return { path: version.path, exact: false, component: options.docVersionRootComponent, - routes: subRoutes, - modules: { - version: aliasedSource(versionPropPath), + routes: await buildVersionSubRoutes(), + props: { + // TODO Docusaurus v4 breaking change? + // expose version metadata as route context instead of props + version: toVersionMetadataProp(options.id, version), }, priority: version.routePriority, }; diff --git a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/utils.test.ts b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/utils.test.ts index 5c69d9ed8a..dcc17131a5 100644 --- a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/utils.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/utils.test.ts @@ -719,6 +719,22 @@ describe('toDocNavigationLink', () => { } as PropNavigationLink); }); + it('with sidebar item label', () => { + expect( + toDocNavigationLink( + testDoc({ + title: 'Doc Title', + permalink: '/docPermalink', + frontMatter: {}, + }), + {sidebarItemLabel: 'Doc sidebar item label'}, + ), + ).toEqual({ + title: 'Doc sidebar item label', + permalink: '/docPermalink', + } as PropNavigationLink); + }); + it('with pagination_label + sidebar_label front matter', () => { expect( toDocNavigationLink( @@ -736,6 +752,24 @@ describe('toDocNavigationLink', () => { permalink: '/docPermalink', } as PropNavigationLink); }); + + it('with sidebar_label + sidebar item label', () => { + expect( + toDocNavigationLink( + testDoc({ + title: 'Doc Title', + permalink: '/docPermalink', + frontMatter: { + sidebar_label: 'sidebar_label', + }, + }), + {sidebarItemLabel: 'Doc sidebar item label'}, + ), + ).toEqual({ + title: 'sidebar_label', + permalink: '/docPermalink', + } as PropNavigationLink); + }); }); describe('toNavigationLink', () => { diff --git a/packages/docusaurus-plugin-content-docs/src/sidebars/utils.ts b/packages/docusaurus-plugin-content-docs/src/sidebars/utils.ts index e716be9ba0..2f785a0320 100644 --- a/packages/docusaurus-plugin-content-docs/src/sidebars/utils.ts +++ b/packages/docusaurus-plugin-content-docs/src/sidebars/utils.ts @@ -478,7 +478,10 @@ Available document ids are: }; } -export function toDocNavigationLink(doc: DocMetadataBase): PropNavigationLink { +export function toDocNavigationLink( + doc: DocMetadataBase, + options?: {sidebarItemLabel?: string | undefined}, +): PropNavigationLink { const { title, permalink, @@ -487,7 +490,11 @@ export function toDocNavigationLink(doc: DocMetadataBase): PropNavigationLink { sidebar_label: sidebarLabel, }, } = doc; - return {title: paginationLabel ?? sidebarLabel ?? title, permalink}; + return { + title: + paginationLabel ?? sidebarLabel ?? options?.sidebarItemLabel ?? title, + permalink, + }; } export function toNavigationLink( @@ -516,5 +523,7 @@ export function toNavigationLink( permalink: navigationItem.link.permalink, }; } - return toDocNavigationLink(getDocById(navigationItem.id)); + return toDocNavigationLink(getDocById(navigationItem.id), { + sidebarItemLabel: navigationItem?.label, + }); } diff --git a/packages/docusaurus-plugin-content-pages/src/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus-plugin-content-pages/src/__tests__/__snapshots__/index.test.ts.snap index fc5fa21967..bc9b5308c3 100644 --- a/packages/docusaurus-plugin-content-pages/src/__tests__/__snapshots__/index.test.ts.snap +++ b/packages/docusaurus-plugin-content-pages/src/__tests__/__snapshots__/index.test.ts.snap @@ -14,9 +14,12 @@ exports[`docusaurus-plugin-content-pages loads simple pages 1`] = ` }, { "description": "Markdown index page", + "editUrl": undefined, "frontMatter": { "custom_frontMatter": "added by parseFrontMatter", }, + "lastUpdatedAt": undefined, + "lastUpdatedBy": undefined, "permalink": "/hello/", "source": "@site/src/pages/hello/index.md", "title": "Index", @@ -25,11 +28,14 @@ exports[`docusaurus-plugin-content-pages loads simple pages 1`] = ` }, { "description": "my MDX page", + "editUrl": undefined, "frontMatter": { "custom_frontMatter": "added by parseFrontMatter", "description": "my MDX page", "title": "MDX page", }, + "lastUpdatedAt": undefined, + "lastUpdatedBy": undefined, "permalink": "/hello/mdxPage", "source": "@site/src/pages/hello/mdxPage.mdx", "title": "MDX page", @@ -43,9 +49,12 @@ exports[`docusaurus-plugin-content-pages loads simple pages 1`] = ` }, { "description": "translated Markdown page", + "editUrl": undefined, "frontMatter": { "custom_frontMatter": "added by parseFrontMatter", }, + "lastUpdatedAt": undefined, + "lastUpdatedBy": undefined, "permalink": "/hello/translatedMd", "source": "@site/src/pages/hello/translatedMd.md", "title": undefined, @@ -74,9 +83,12 @@ exports[`docusaurus-plugin-content-pages loads simple pages with french translat }, { "description": "Markdown index page", + "editUrl": undefined, "frontMatter": { "custom_frontMatter": "added by parseFrontMatter", }, + "lastUpdatedAt": undefined, + "lastUpdatedBy": undefined, "permalink": "/fr/hello/", "source": "@site/src/pages/hello/index.md", "title": "Index", @@ -85,11 +97,14 @@ exports[`docusaurus-plugin-content-pages loads simple pages with french translat }, { "description": "my MDX page", + "editUrl": undefined, "frontMatter": { "custom_frontMatter": "added by parseFrontMatter", "description": "my MDX page", "title": "MDX page", }, + "lastUpdatedAt": undefined, + "lastUpdatedBy": undefined, "permalink": "/fr/hello/mdxPage", "source": "@site/src/pages/hello/mdxPage.mdx", "title": "MDX page", @@ -103,9 +118,12 @@ exports[`docusaurus-plugin-content-pages loads simple pages with french translat }, { "description": "translated Markdown page (fr)", + "editUrl": undefined, "frontMatter": { "custom_frontMatter": "added by parseFrontMatter", }, + "lastUpdatedAt": undefined, + "lastUpdatedBy": undefined, "permalink": "/fr/hello/translatedMd", "source": "@site/i18n/fr/docusaurus-plugin-content-pages/hello/translatedMd.md", "title": undefined, @@ -119,3 +137,72 @@ exports[`docusaurus-plugin-content-pages loads simple pages with french translat }, ] `; + +exports[`docusaurus-plugin-content-pages loads simple pages with last update 1`] = ` +[ + { + "permalink": "/", + "source": "@site/src/pages/index.js", + "type": "jsx", + }, + { + "permalink": "/typescript", + "source": "@site/src/pages/typescript.tsx", + "type": "jsx", + }, + { + "description": "Markdown index page", + "editUrl": "url placeholder", + "frontMatter": { + "custom_frontMatter": "added by parseFrontMatter", + }, + "lastUpdatedAt": 1539502055000, + "lastUpdatedBy": "Author", + "permalink": "/hello/", + "source": "@site/src/pages/hello/index.md", + "title": "Index", + "type": "mdx", + "unlisted": false, + }, + { + "description": "my MDX page", + "editUrl": "url placeholder", + "frontMatter": { + "custom_frontMatter": "added by parseFrontMatter", + "description": "my MDX page", + "title": "MDX page", + }, + "lastUpdatedAt": 1539502055000, + "lastUpdatedBy": "Author", + "permalink": "/hello/mdxPage", + "source": "@site/src/pages/hello/mdxPage.mdx", + "title": "MDX page", + "type": "mdx", + "unlisted": false, + }, + { + "permalink": "/hello/translatedJs", + "source": "@site/src/pages/hello/translatedJs.js", + "type": "jsx", + }, + { + "description": "translated Markdown page", + "editUrl": "url placeholder", + "frontMatter": { + "custom_frontMatter": "added by parseFrontMatter", + }, + "lastUpdatedAt": 1539502055000, + "lastUpdatedBy": "Author", + "permalink": "/hello/translatedMd", + "source": "@site/src/pages/hello/translatedMd.md", + "title": undefined, + "type": "mdx", + "unlisted": false, + }, + { + "permalink": "/hello/world", + "source": "@site/src/pages/hello/world.js", + "type": "jsx", + }, +] +`; diff --git a/packages/docusaurus-plugin-content-pages/src/__tests__/index.test.ts b/packages/docusaurus-plugin-content-pages/src/__tests__/index.test.ts index 5527f11e5a..24870c77bc 100644 --- a/packages/docusaurus-plugin-content-pages/src/__tests__/index.test.ts +++ b/packages/docusaurus-plugin-content-pages/src/__tests__/index.test.ts @@ -46,4 +46,24 @@ describe('docusaurus-plugin-content-pages', () => { expect(pagesMetadata).toMatchSnapshot(); }); + + it('loads simple pages with last update', async () => { + const siteDir = path.join(__dirname, '__fixtures__', 'website'); + const context = await loadContext({siteDir}); + const plugin = pluginContentPages( + context, + validateOptions({ + validate: normalizePluginOptions, + options: { + path: 'src/pages', + editUrl: () => 'url placeholder', + showLastUpdateAuthor: true, + showLastUpdateTime: true, + }, + }), + ); + const pagesMetadata = await plugin.loadContent!(); + + expect(pagesMetadata).toMatchSnapshot(); + }); }); diff --git a/packages/docusaurus-plugin-content-pages/src/content.ts b/packages/docusaurus-plugin-content-pages/src/content.ts new file mode 100644 index 0000000000..769adbf459 --- /dev/null +++ b/packages/docusaurus-plugin-content-pages/src/content.ts @@ -0,0 +1,194 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import fs from 'fs-extra'; +import path from 'path'; +import { + encodePath, + fileToPath, + aliasedSitePath, + getFolderContainingFile, + Globby, + normalizeUrl, + parseMarkdownFile, + isUnlisted, + isDraft, + readLastUpdateData, + getEditUrl, + posixPath, + getPluginI18nPath, +} from '@docusaurus/utils'; +import {validatePageFrontMatter} from './frontMatter'; +import type {LoadContext} from '@docusaurus/types'; +import type {PagesContentPaths} from './types'; +import type { + PluginOptions, + Metadata, + LoadedContent, +} from '@docusaurus/plugin-content-pages'; + +export function createPagesContentPaths({ + context, + options, +}: { + context: LoadContext; + options: PluginOptions; +}): PagesContentPaths { + const {siteDir, localizationDir} = context; + return { + contentPath: path.resolve(siteDir, options.path), + contentPathLocalized: getPluginI18nPath({ + localizationDir, + pluginName: 'docusaurus-plugin-content-pages', + pluginId: options.id, + }), + }; +} + +export function getContentPathList(contentPaths: PagesContentPaths): string[] { + return [contentPaths.contentPathLocalized, contentPaths.contentPath]; +} + +const isMarkdownSource = (source: string) => + source.endsWith('.md') || source.endsWith('.mdx'); + +type LoadContentParams = { + context: LoadContext; + options: PluginOptions; + contentPaths: PagesContentPaths; +}; + +export async function loadPagesContent( + params: LoadContentParams, +): Promise { + const {options} = params; + + const pagesFiles = await Globby(params.options.include, { + cwd: params.contentPaths.contentPath, + ignore: options.exclude, + }); + + async function doProcessPageSourceFile(relativeSource: string) { + try { + return await processPageSourceFile(relativeSource, params); + } catch (err) { + throw new Error( + `Processing of page source file path=${relativeSource} failed.`, + {cause: err as Error}, + ); + } + } + + return (await Promise.all(pagesFiles.map(doProcessPageSourceFile))).filter( + (res): res is Metadata => { + return res !== undefined; + }, + ); +} + +async function processPageSourceFile( + relativeSource: string, + params: LoadContentParams, +): Promise { + const {context, options, contentPaths} = params; + const {siteConfig, baseUrl, siteDir, i18n} = context; + const {editUrl} = options; + + // Lookup in localized folder in priority + const contentPath = await getFolderContainingFile( + getContentPathList(contentPaths), + relativeSource, + ); + + const source = path.join(contentPath, relativeSource); + const aliasedSourcePath = aliasedSitePath(source, siteDir); + const permalink = normalizeUrl([ + baseUrl, + options.routeBasePath, + encodePath(fileToPath(relativeSource)), + ]); + if (!isMarkdownSource(relativeSource)) { + return { + type: 'jsx', + permalink, + source: aliasedSourcePath, + }; + } + + const content = await fs.readFile(source, 'utf-8'); + const { + frontMatter: unsafeFrontMatter, + contentTitle, + excerpt, + } = await parseMarkdownFile({ + filePath: source, + fileContent: content, + parseFrontMatter: siteConfig.markdown.parseFrontMatter, + }); + const frontMatter = validatePageFrontMatter(unsafeFrontMatter); + + const pagesDirPath = await getFolderContainingFile( + getContentPathList(contentPaths), + relativeSource, + ); + + const pagesSourceAbsolute = path.join(pagesDirPath, relativeSource); + + function getPagesEditUrl() { + const pagesPathRelative = path.relative( + pagesDirPath, + path.resolve(pagesSourceAbsolute), + ); + + if (typeof editUrl === 'function') { + return editUrl({ + pagesDirPath: posixPath(path.relative(siteDir, pagesDirPath)), + pagesPath: posixPath(pagesPathRelative), + permalink, + locale: i18n.currentLocale, + }); + } else if (typeof editUrl === 'string') { + const isLocalized = pagesDirPath === contentPaths.contentPathLocalized; + const fileContentPath = + isLocalized && options.editLocalizedFiles + ? contentPaths.contentPathLocalized + : contentPaths.contentPath; + + const contentPathEditUrl = normalizeUrl([ + editUrl, + posixPath(path.relative(siteDir, fileContentPath)), + ]); + + return getEditUrl(pagesPathRelative, contentPathEditUrl); + } + return undefined; + } + + const lastUpdatedData = await readLastUpdateData( + source, + options, + frontMatter.last_update, + ); + + if (isDraft({frontMatter})) { + return undefined; + } + const unlisted = isUnlisted({frontMatter}); + + return { + type: 'mdx', + permalink, + source: aliasedSourcePath, + title: frontMatter.title ?? contentTitle, + description: frontMatter.description ?? excerpt, + frontMatter, + lastUpdatedBy: lastUpdatedData.lastUpdatedBy, + lastUpdatedAt: lastUpdatedData.lastUpdatedAt, + editUrl: getPagesEditUrl(), + unlisted, + }; +} diff --git a/packages/docusaurus-plugin-content-pages/src/frontMatter.ts b/packages/docusaurus-plugin-content-pages/src/frontMatter.ts index b87907adbd..5a87b1a221 100644 --- a/packages/docusaurus-plugin-content-pages/src/frontMatter.ts +++ b/packages/docusaurus-plugin-content-pages/src/frontMatter.ts @@ -11,6 +11,7 @@ import { FrontMatterTOCHeadingLevels, ContentVisibilitySchema, URISchema, + FrontMatterLastUpdateSchema, } from '@docusaurus/utils-validation'; import type {PageFrontMatter} from '@docusaurus/plugin-content-pages'; @@ -24,6 +25,7 @@ const PageFrontMatterSchema = Joi.object({ wrapperClassName: Joi.string(), hide_table_of_contents: Joi.boolean(), ...FrontMatterTOCHeadingLevels, + last_update: FrontMatterLastUpdateSchema, }).concat(ContentVisibilitySchema); export function validatePageFrontMatter(frontMatter: { diff --git a/packages/docusaurus-plugin-content-pages/src/index.ts b/packages/docusaurus-plugin-content-pages/src/index.ts index 7fe81e83af..a9f7b34642 100644 --- a/packages/docusaurus-plugin-content-pages/src/index.ts +++ b/packages/docusaurus-plugin-content-pages/src/index.ts @@ -8,53 +8,32 @@ import fs from 'fs-extra'; import path from 'path'; import { - encodePath, - fileToPath, aliasedSitePath, - aliasedSitePathToRelativePath, docuHash, - getPluginI18nPath, - getFolderContainingFile, addTrailingPathSeparator, - Globby, createAbsoluteFilePathMatcher, - normalizeUrl, DEFAULT_PLUGIN_ID, - parseMarkdownFile, - isUnlisted, - isDraft, } from '@docusaurus/utils'; -import {validatePageFrontMatter} from './frontMatter'; -import type {LoadContext, Plugin, RouteMetadata} from '@docusaurus/types'; -import type {PagesContentPaths} from './types'; +import {createAllRoutes} from './routes'; +import { + createPagesContentPaths, + getContentPathList, + loadPagesContent, +} from './content'; +import type {LoadContext, Plugin} from '@docusaurus/types'; import type { PluginOptions, - Metadata, LoadedContent, PageFrontMatter, } from '@docusaurus/plugin-content-pages'; -export function getContentPathList(contentPaths: PagesContentPaths): string[] { - return [contentPaths.contentPathLocalized, contentPaths.contentPath]; -} - -const isMarkdownSource = (source: string) => - source.endsWith('.md') || source.endsWith('.mdx'); - export default function pluginContentPages( context: LoadContext, options: PluginOptions, ): Plugin { - const {siteConfig, siteDir, generatedFilesDir, localizationDir} = context; + const {siteConfig, siteDir, generatedFilesDir} = context; - const contentPaths: PagesContentPaths = { - contentPath: path.resolve(siteDir, options.path), - contentPathLocalized: getPluginI18nPath({ - localizationDir, - pluginName: 'docusaurus-plugin-content-pages', - pluginId: options.id, - }), - }; + const contentPaths = createPagesContentPaths({context, options}); const pluginDataDirRoot = path.join( generatedFilesDir, @@ -73,135 +52,17 @@ export default function pluginContentPages( }, async loadContent() { - const {include} = options; - if (!(await fs.pathExists(contentPaths.contentPath))) { return null; } - - const {baseUrl} = siteConfig; - const pagesFiles = await Globby(include, { - cwd: contentPaths.contentPath, - ignore: options.exclude, - }); - - async function processPageSourceFile( - relativeSource: string, - ): Promise { - // Lookup in localized folder in priority - const contentPath = await getFolderContainingFile( - getContentPathList(contentPaths), - relativeSource, - ); - - const source = path.join(contentPath, relativeSource); - const aliasedSourcePath = aliasedSitePath(source, siteDir); - const permalink = normalizeUrl([ - baseUrl, - options.routeBasePath, - encodePath(fileToPath(relativeSource)), - ]); - if (!isMarkdownSource(relativeSource)) { - return { - type: 'jsx', - permalink, - source: aliasedSourcePath, - }; - } - const content = await fs.readFile(source, 'utf-8'); - const { - frontMatter: unsafeFrontMatter, - contentTitle, - excerpt, - } = await parseMarkdownFile({ - filePath: source, - fileContent: content, - parseFrontMatter: siteConfig.markdown.parseFrontMatter, - }); - const frontMatter = validatePageFrontMatter(unsafeFrontMatter); - - if (isDraft({frontMatter})) { - return undefined; - } - const unlisted = isUnlisted({frontMatter}); - - return { - type: 'mdx', - permalink, - source: aliasedSourcePath, - title: frontMatter.title ?? contentTitle, - description: frontMatter.description ?? excerpt, - frontMatter, - unlisted, - }; - } - - async function doProcessPageSourceFile(relativeSource: string) { - try { - return await processPageSourceFile(relativeSource); - } catch (err) { - throw new Error( - `Processing of page source file path=${relativeSource} failed.`, - {cause: err as Error}, - ); - } - } - - return ( - await Promise.all(pagesFiles.map(doProcessPageSourceFile)) - ).filter(Boolean) as Metadata[]; + return loadPagesContent({context, options, contentPaths}); }, async contentLoaded({content, actions}) { if (!content) { return; } - - const {addRoute, createData} = actions; - - function createPageRouteMetadata(metadata: Metadata): RouteMetadata { - return { - sourceFilePath: aliasedSitePathToRelativePath(metadata.source), - // TODO add support for last updated date in the page plugin - // at least for Markdown files - // lastUpdatedAt: metadata.lastUpdatedAt, - lastUpdatedAt: undefined, - }; - } - - await Promise.all( - content.map(async (metadata) => { - const {permalink, source} = metadata; - const routeMetadata = createPageRouteMetadata(metadata); - if (metadata.type === 'mdx') { - await createData( - // Note that this created data path must be in sync with - // metadataPath provided to mdx-loader. - `${docuHash(metadata.source)}.json`, - JSON.stringify(metadata, null, 2), - ); - addRoute({ - path: permalink, - component: options.mdxPageComponent, - exact: true, - metadata: routeMetadata, - modules: { - content: source, - }, - }); - } else { - addRoute({ - path: permalink, - component: source, - exact: true, - metadata: routeMetadata, - modules: { - config: `@generated/docusaurus.config`, - }, - }); - } - }), - ); + await createAllRoutes({content, options, actions}); }, configureWebpack() { @@ -214,11 +75,6 @@ export default function pluginContentPages( } = options; const contentDirs = getContentPathList(contentPaths); return { - resolve: { - alias: { - '~pages': pluginDataDirRoot, - }, - }, module: { rules: [ { diff --git a/packages/docusaurus-plugin-content-pages/src/options.ts b/packages/docusaurus-plugin-content-pages/src/options.ts index 014f07f119..88c3201b30 100644 --- a/packages/docusaurus-plugin-content-pages/src/options.ts +++ b/packages/docusaurus-plugin-content-pages/src/options.ts @@ -11,6 +11,7 @@ import { RehypePluginsSchema, AdmonitionsSchema, RouteBasePathSchema, + URISchema, } from '@docusaurus/utils-validation'; import {GlobExcludeDefault} from '@docusaurus/utils'; import type {OptionValidationContext} from '@docusaurus/types'; @@ -27,6 +28,9 @@ export const DEFAULT_OPTIONS: PluginOptions = { beforeDefaultRehypePlugins: [], beforeDefaultRemarkPlugins: [], admonitions: true, + showLastUpdateTime: false, + showLastUpdateAuthor: false, + editLocalizedFiles: false, }; const PluginOptionSchema = Joi.object({ @@ -44,6 +48,12 @@ const PluginOptionSchema = Joi.object({ DEFAULT_OPTIONS.beforeDefaultRemarkPlugins, ), admonitions: AdmonitionsSchema.default(DEFAULT_OPTIONS.admonitions), + showLastUpdateTime: Joi.bool().default(DEFAULT_OPTIONS.showLastUpdateTime), + showLastUpdateAuthor: Joi.bool().default( + DEFAULT_OPTIONS.showLastUpdateAuthor, + ), + editUrl: Joi.alternatives().try(URISchema, Joi.function()), + editLocalizedFiles: Joi.boolean().default(DEFAULT_OPTIONS.editLocalizedFiles), }); export function validateOptions({ diff --git a/packages/docusaurus-plugin-content-pages/src/plugin-content-pages.d.ts b/packages/docusaurus-plugin-content-pages/src/plugin-content-pages.d.ts index f0a9230cde..1c7b037437 100644 --- a/packages/docusaurus-plugin-content-pages/src/plugin-content-pages.d.ts +++ b/packages/docusaurus-plugin-content-pages/src/plugin-content-pages.d.ts @@ -8,6 +8,7 @@ declare module '@docusaurus/plugin-content-pages' { import type {MDXOptions} from '@docusaurus/mdx-loader'; import type {LoadContext, Plugin} from '@docusaurus/types'; + import type {FrontMatterLastUpdate, LastUpdateData} from '@docusaurus/utils'; export type Assets = { image?: string; @@ -20,6 +21,10 @@ declare module '@docusaurus/plugin-content-pages' { include: string[]; exclude: string[]; mdxPageComponent: string; + showLastUpdateTime: boolean; + showLastUpdateAuthor: boolean; + editUrl?: string | EditUrlFunction; + editLocalizedFiles?: boolean; }; export type Options = Partial; @@ -35,6 +40,7 @@ declare module '@docusaurus/plugin-content-pages' { readonly toc_max_heading_level?: number; readonly draft?: boolean; readonly unlisted?: boolean; + readonly last_update?: FrontMatterLastUpdate; }; export type JSXPageMetadata = { @@ -43,16 +49,31 @@ declare module '@docusaurus/plugin-content-pages' { source: string; }; - export type MDXPageMetadata = { + export type MDXPageMetadata = LastUpdateData & { type: 'mdx'; permalink: string; source: string; frontMatter: PageFrontMatter & {[key: string]: unknown}; + editUrl?: string; title?: string; description?: string; unlisted: boolean; }; + export type EditUrlFunction = (editUrlParams: { + /** + * The root content directory containing this post file, relative to the + * site path. Usually the same as `options.path` but can be localized + */ + pagesDirPath: string; + /** Path to this pages file, relative to `pagesDirPath`. */ + pagesPath: string; + /** @see {@link PagesPostMetadata.permalink} */ + permalink: string; + /** Locale name. */ + locale: string; + }) => string | undefined; + export type Metadata = JSXPageMetadata | MDXPageMetadata; export type LoadedContent = Metadata[]; diff --git a/packages/docusaurus-plugin-content-pages/src/routes.ts b/packages/docusaurus-plugin-content-pages/src/routes.ts new file mode 100644 index 0000000000..2de677c45f --- /dev/null +++ b/packages/docusaurus-plugin-content-pages/src/routes.ts @@ -0,0 +1,89 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import {aliasedSitePathToRelativePath, docuHash} from '@docusaurus/utils'; +import type { + PluginContentLoadedActions, + RouteConfig, + RouteMetadata, +} from '@docusaurus/types'; +import type { + PluginOptions, + Metadata, + LoadedContent, + MDXPageMetadata, +} from '@docusaurus/plugin-content-pages'; + +type CreateAllRoutesParam = { + content: LoadedContent; + options: PluginOptions; + actions: PluginContentLoadedActions; +}; + +function createPageRouteMetadata(metadata: Metadata): RouteMetadata { + const lastUpdatedAt = + metadata.type === 'mdx' ? metadata.lastUpdatedAt : undefined; + return { + sourceFilePath: aliasedSitePathToRelativePath(metadata.source), + lastUpdatedAt, + }; +} + +export async function createAllRoutes( + param: CreateAllRoutesParam, +): Promise { + const routes = await buildAllRoutes(param); + routes.forEach(param.actions.addRoute); +} + +export async function buildAllRoutes({ + content, + actions, + options, +}: CreateAllRoutesParam): Promise { + const {createData} = actions; + + async function buildMDXPageRoute( + metadata: MDXPageMetadata, + ): Promise { + await createData( + // Note that this created data path must be in sync with + // metadataPath provided to mdx-loader. + `${docuHash(metadata.source)}.json`, + metadata, + ); + return { + path: metadata.permalink, + component: options.mdxPageComponent, + exact: true, + metadata: createPageRouteMetadata(metadata), + modules: { + content: metadata.source, + }, + }; + } + + async function buildJSXRoute(metadata: Metadata): Promise { + return { + path: metadata.permalink, + component: metadata.source, + exact: true, + metadata: createPageRouteMetadata(metadata), + modules: { + config: `@generated/docusaurus.config`, + }, + }; + } + + async function buildPageRoute(metadata: Metadata): Promise { + return metadata.type === 'mdx' + ? buildMDXPageRoute(metadata) + : buildJSXRoute(metadata); + } + + return Promise.all(content.map(buildPageRoute)); +} diff --git a/packages/docusaurus-plugin-debug/src/index.ts b/packages/docusaurus-plugin-debug/src/index.ts index cd27ebc549..af1a017de3 100644 --- a/packages/docusaurus-plugin-debug/src/index.ts +++ b/packages/docusaurus-plugin-debug/src/index.ts @@ -5,21 +5,12 @@ * LICENSE file in the root directory of this source tree. */ -import path from 'path'; -import {docuHash, normalizeUrl, posixPath} from '@docusaurus/utils'; +import {normalizeUrl} from '@docusaurus/utils'; import type {LoadContext, Plugin} from '@docusaurus/types'; export default function pluginDebug({ siteConfig: {baseUrl}, - generatedFilesDir, }: LoadContext): Plugin { - const pluginDataDirRoot = path.join( - generatedFilesDir, - 'docusaurus-plugin-debug', - ); - const aliasedSource = (source: string) => - `~debug/${posixPath(path.relative(pluginDataDirRoot, source))}`; - return { name: 'docusaurus-plugin-debug', @@ -30,14 +21,7 @@ export default function pluginDebug({ return '../src/theme'; }, - async allContentLoaded({actions: {createData, addRoute}, allContent}) { - const allContentPath = await createData( - // Note that this created data path must be in sync with - // metadataPath provided to mdx-loader. - `${docuHash('docusaurus-debug-allContent')}.json`, - JSON.stringify(allContent, null, 2), - ); - + async allContentLoaded({actions: {addRoute}, allContent}) { // Home is config (duplicate for now) addRoute({ path: normalizeUrl([baseUrl, '__docusaurus/debug']), @@ -73,8 +57,8 @@ export default function pluginDebug({ path: normalizeUrl([baseUrl, '__docusaurus/debug/content']), component: '@theme/DebugContent', exact: true, - modules: { - allContent: aliasedSource(allContentPath), + props: { + allContent, }, }); @@ -84,15 +68,5 @@ export default function pluginDebug({ exact: true, }); }, - - configureWebpack() { - return { - resolve: { - alias: { - '~debug': pluginDataDirRoot, - }, - }, - }; - }, }; } diff --git a/packages/docusaurus-theme-classic/src/theme/MDXPage/index.tsx b/packages/docusaurus-theme-classic/src/theme/MDXPage/index.tsx index c9222ad0b5..103dc3e69a 100644 --- a/packages/docusaurus-theme-classic/src/theme/MDXPage/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/MDXPage/index.tsx @@ -18,12 +18,21 @@ import TOC from '@theme/TOC'; import Unlisted from '@theme/Unlisted'; import type {Props} from '@theme/MDXPage'; +import EditMetaRow from '@theme/EditMetaRow'; import styles from './styles.module.css'; export default function MDXPage(props: Props): JSX.Element { const {content: MDXPageContent} = props; const { - metadata: {title, description, frontMatter, unlisted}, + metadata: { + title, + editUrl, + description, + frontMatter, + unlisted, + lastUpdatedBy, + lastUpdatedAt, + }, assets, } = MDXPageContent; const { @@ -33,6 +42,8 @@ export default function MDXPage(props: Props): JSX.Element { } = frontMatter; const image = assets.image ?? frontMatter.image; + const canDisplayEditMetaRow = !!(editUrl || lastUpdatedAt || lastUpdatedBy); + return ( + {canDisplayEditMetaRow && ( + + )} {!hideTableOfContents && MDXPageContent.toc.length > 0 && (
diff --git a/packages/docusaurus-theme-common/src/utils/ThemeClassNames.ts b/packages/docusaurus-theme-common/src/utils/ThemeClassNames.ts index 79cf8e2ae0..1cdcda3ce5 100644 --- a/packages/docusaurus-theme-common/src/utils/ThemeClassNames.ts +++ b/packages/docusaurus-theme-common/src/utils/ThemeClassNames.ts @@ -76,4 +76,7 @@ export const ThemeClassNames = { blogFooterTagsRow: 'theme-blog-footer-tags-row', blogFooterEditMetaRow: 'theme-blog-footer-edit-meta-row', }, + pages: { + pageFooterEditMetaRow: 'theme-pages-footer-edit-meta-row', + }, } as const; diff --git a/packages/docusaurus-types/src/context.d.ts b/packages/docusaurus-types/src/context.d.ts index 57481a9816..68c4f78d6e 100644 --- a/packages/docusaurus-types/src/context.d.ts +++ b/packages/docusaurus-types/src/context.d.ts @@ -7,7 +7,7 @@ import type {DocusaurusConfig} from './config'; import type {CodeTranslations, I18n} from './i18n'; import type {LoadedPlugin, PluginVersionInformation} from './plugin'; -import type {RouteConfig} from './routing'; +import type {PluginRouteConfig} from './routing'; export type DocusaurusContext = { siteConfig: DocusaurusConfig; @@ -57,7 +57,7 @@ export type Props = LoadContext & { preBodyTags: string; postBodyTags: string; siteMetadata: SiteMetadata; - routes: RouteConfig[]; + routes: PluginRouteConfig[]; routesPaths: string[]; plugins: LoadedPlugin[]; }; diff --git a/packages/docusaurus-types/src/index.d.ts b/packages/docusaurus-types/src/index.d.ts index ecc5810be3..a674464101 100644 --- a/packages/docusaurus-types/src/index.d.ts +++ b/packages/docusaurus-types/src/index.d.ts @@ -70,6 +70,7 @@ export { export { RouteConfig, + PluginRouteConfig, RouteMetadata, RouteContext, PluginRouteContext, diff --git a/packages/docusaurus-types/src/plugin.d.ts b/packages/docusaurus-types/src/plugin.d.ts index fddc9c4fa5..076a39354a 100644 --- a/packages/docusaurus-types/src/plugin.d.ts +++ b/packages/docusaurus-types/src/plugin.d.ts @@ -49,7 +49,7 @@ export type PluginVersionInformation = export type PluginContentLoadedActions = { addRoute: (config: RouteConfig) => void; - createData: (name: string, data: string) => Promise; + createData: (name: string, data: string | object) => Promise; setGlobalData: (data: unknown) => void; }; diff --git a/packages/docusaurus-types/src/routing.d.ts b/packages/docusaurus-types/src/routing.d.ts index b87eee9676..698797b7d1 100644 --- a/packages/docusaurus-types/src/routing.d.ts +++ b/packages/docusaurus-types/src/routing.d.ts @@ -6,6 +6,7 @@ */ import type {ParsedUrlQueryInput} from 'querystring'; +import type {PluginIdentifier} from './plugin'; /** * A "module" represents a unit of serialized data emitted from the plugin. It @@ -110,9 +111,23 @@ export type RouteConfig = { */ metadata?: RouteMetadata; /** - * Extra props; will be available on the client side. + * Optional props object; will be converted to a module and injected as props + * into the route component. */ - [propName: string]: unknown; + props?: {[propName: string]: unknown}; + /** + * Extra route attribute; will be available on the client side route object. + */ + [attributeName: string]: unknown; +}; + +export type PluginRouteConfig = RouteConfig & { + /** + * Routes are always created by Docusaurus plugins + * A plugin identifier is available at the top of a routing tree + * (child routes are implicitly created by the same plugin as their parent) + */ + plugin: PluginIdentifier; }; export type RouteContext = { diff --git a/packages/docusaurus/src/client/exports/ComponentCreator.tsx b/packages/docusaurus/src/client/exports/ComponentCreator.tsx index 33c0f4c90a..34b257877c 100644 --- a/packages/docusaurus/src/client/exports/ComponentCreator.tsx +++ b/packages/docusaurus/src/client/exports/ComponentCreator.tsx @@ -85,7 +85,8 @@ export default function ComponentCreator( const loadedModules = JSON.parse(JSON.stringify(chunkNames)) as { __comp?: React.ComponentType; __context?: RouteContext; - [propName: string]: unknown; + __props?: {[propName: string]: unknown}; + [attributeName: string]: unknown; }; Object.entries(loaded).forEach(([keyPath, loadedModule]) => { // JSON modules are also loaded as `{ default: ... }` (`import()` @@ -127,12 +128,18 @@ export default function ComponentCreator( delete loadedModules.__comp; const routeContext = loadedModules.__context!; delete loadedModules.__context; + const routeProps = loadedModules.__props; + delete loadedModules.__props; /* eslint-enable no-underscore-dangle */ // Is there any way to put this RouteContextProvider upper in the tree? return ( - + ); }, diff --git a/packages/docusaurus/src/server/codegen/codegen.ts b/packages/docusaurus/src/server/codegen/codegen.ts index 6945042682..d6df2de34e 100644 --- a/packages/docusaurus/src/server/codegen/codegen.ts +++ b/packages/docusaurus/src/server/codegen/codegen.ts @@ -16,7 +16,7 @@ import type { DocusaurusConfig, GlobalData, I18n, - RouteConfig, + PluginRouteConfig, SiteMetadata, } from '@docusaurus/types'; @@ -140,7 +140,7 @@ type CodegenParams = { i18n: I18n; codeTranslations: CodeTranslations; siteMetadata: SiteMetadata; - routes: RouteConfig[]; + routes: PluginRouteConfig[]; }; export async function generateSiteFiles(params: CodegenParams): Promise { diff --git a/packages/docusaurus/src/server/codegen/codegenRoutes.ts b/packages/docusaurus/src/server/codegen/codegenRoutes.ts index 8eee10d3f6..cb40afc585 100644 --- a/packages/docusaurus/src/server/codegen/codegenRoutes.ts +++ b/packages/docusaurus/src/server/codegen/codegenRoutes.ts @@ -6,6 +6,7 @@ */ import query from 'querystring'; +import path from 'path'; import _ from 'lodash'; import {docuHash, simpleHash, escapePath, generate} from '@docusaurus/utils'; import type { @@ -14,6 +15,8 @@ import type { RouteModules, ChunkNames, RouteChunkNames, + PluginRouteConfig, + PluginIdentifier, } from '@docusaurus/types'; type RoutesCode = { @@ -88,13 +91,13 @@ function serializeRouteConfig({ routeHash, exact, subroutesCodeStrings, - props, + attributes, }: { routePath: string; routeHash: string; exact?: boolean; subroutesCodeStrings?: string[]; - props: {[propName: string]: unknown}; + attributes: {[attributeName: string]: unknown}; }) { const parts = [ `path: '${routePath}'`, @@ -113,11 +116,11 @@ ${indent(subroutesCodeStrings.join(',\n'))} ); } - Object.entries(props).forEach(([propName, propValue]) => { + Object.entries(attributes).forEach(([attrName, attrValue]) => { const isIdentifier = - /^[$_\p{ID_Start}][$\u200c\u200d\p{ID_Continue}]*$/u.test(propName); - const key = isIdentifier ? propName : JSON.stringify(propName); - parts.push(`${key}: ${JSON.stringify(propValue)}`); + /^[$_\p{ID_Start}][$\u200c\u200d\p{ID_Continue}]*$/u.test(attrName); + const key = isIdentifier ? attrName : JSON.stringify(attrName); + parts.push(`${key}: ${JSON.stringify(attrValue)}`); }); return `{ @@ -201,7 +204,9 @@ function genRouteCode(routeConfig: RouteConfig, res: RoutesCode): string { priority, exact, metadata, - ...props + props, + plugin, + ...attributes } = routeConfig; if (typeof routePath !== 'string' || !component) { @@ -225,7 +230,7 @@ ${JSON.stringify(routeConfig)}`, routeHash, subroutesCodeStrings: subroutes?.map((r) => genRouteCode(r, res)), exact, - props, + attributes, }); } @@ -311,14 +316,134 @@ const genRoutes = ({ type GenerateRouteFilesParams = { generatedFilesDir: string; - routes: RouteConfig[]; + routes: PluginRouteConfig[]; baseUrl: string; }; -export async function generateRouteFiles({ +async function generateRoutePropModule({ + generatedFilesDir, + route, + plugin, +}: { + generatedFilesDir: string; + route: RouteConfig; + plugin: PluginIdentifier; +}) { + ensureNoPropsConflict(route); + + const moduleContent = JSON.stringify(route.props); + + // TODO we should aim to reduce this path length + // This adds bytes to the global module registry + const relativePath = path.posix.join( + plugin.name, + plugin.id, + 'p', + `${docuHash(route.path)}.json`, + ); + const modulePath = path.posix.join(generatedFilesDir, relativePath); + const aliasedPath = path.posix.join('@generated', relativePath); + + await generate(generatedFilesDir, modulePath, moduleContent); + return aliasedPath; +} + +function ensureNoPropsConflict(route: RouteConfig) { + if (!route.props && !route.modules) { + return; + } + const conflictingPropNames = _.intersection( + Object.keys(route.props ?? {}), + Object.keys(route.modules ?? {}), + ); + if (conflictingPropNames.length > 0) { + throw new Error( + `Route ${ + route.path + } has conflicting props declared using both route.modules and route.props APIs for keys: ${conflictingPropNames.join( + ', ', + )}\nThis is not permitted, otherwise one prop would override the over.`, + ); + } +} + +async function preprocessRouteProps({ + generatedFilesDir, + route, + plugin, +}: { + generatedFilesDir: string; + route: RouteConfig; + plugin: PluginIdentifier; +}): Promise { + const propsModulePathPromise = route.props + ? generateRoutePropModule({ + generatedFilesDir, + route, + plugin, + }) + : undefined; + + const subRoutesPromise = route.routes + ? Promise.all( + route.routes.map((subRoute: RouteConfig) => { + return preprocessRouteProps({ + generatedFilesDir, + route: subRoute, + plugin, + }); + }), + ) + : undefined; + + const [propsModulePath, subRoutes] = await Promise.all([ + propsModulePathPromise, + subRoutesPromise, + ]); + + const newRoute: RouteConfig = { + ...route, + modules: { + ...route.modules, + ...(propsModulePath && {__props: propsModulePath}), + }, + routes: subRoutes, + props: undefined, + }; + + return newRoute; +} + +// For convenience, it's possible to pass a "route.props" object +// This method converts the props object to a regular module +// and assigns it to route.modules.__props attribute +async function preprocessAllPluginsRoutesProps({ generatedFilesDir, routes, +}: { + generatedFilesDir: string; + routes: PluginRouteConfig[]; +}) { + return Promise.all( + routes.map((route) => { + return preprocessRouteProps({ + generatedFilesDir, + route, + plugin: route.plugin, + }); + }), + ); +} + +export async function generateRouteFiles({ + generatedFilesDir, + routes: initialRoutes, }: GenerateRouteFilesParams): Promise { + const routes = await preprocessAllPluginsRoutesProps({ + generatedFilesDir, + routes: initialRoutes, + }); + const {registry, routesChunkNames, routesConfig} = generateRoutesCode(routes); await Promise.all([ genRegistry({generatedFilesDir, registry}), diff --git a/packages/docusaurus/src/server/plugins/__tests__/plugins.test.ts b/packages/docusaurus/src/server/plugins/__tests__/plugins.test.ts index 3a5c65234a..1ec86de26f 100644 --- a/packages/docusaurus/src/server/plugins/__tests__/plugins.test.ts +++ b/packages/docusaurus/src/server/plugins/__tests__/plugins.test.ts @@ -119,12 +119,16 @@ describe('loadPlugins', () => { "data": { "someContext": "someContextPath", }, - "plugin": "/packages/docusaurus/src/server/plugins/__tests__/__fixtures__/site-with-plugin/.docusaurus/plugin-name/default/plugin-route-context-module-100.json", + "plugin": "@generated/plugin-name/default/__plugin.json", }, "modules": { "someModule": "someModulePath", }, "path": "/foo/", + "plugin": { + "id": "default", + "name": "plugin-name", + }, }, ] `); @@ -180,9 +184,13 @@ describe('loadPlugins', () => { { "component": "Comp", "context": { - "plugin": "/packages/docusaurus/src/server/plugins/__tests__/__fixtures__/site-with-plugin/.docusaurus/plugin-name/plugin-id/plugin-route-context-module-100.json", + "plugin": "@generated/plugin-name/plugin-id/__plugin.json", }, "path": "/foo/", + "plugin": { + "id": "plugin-id", + "name": "plugin-name", + }, }, ] `); @@ -275,23 +283,35 @@ describe('loadPlugins', () => { { "component": "Comp", "context": { - "plugin": "/packages/docusaurus/src/server/plugins/__tests__/__fixtures__/site-with-plugin/.docusaurus/plugin-name/default/plugin-route-context-module-100.json", + "plugin": "@generated/plugin-name/default/__plugin.json", }, "path": "/allContentLoadedRouteSingle/", + "plugin": { + "id": "default", + "name": "plugin-name", + }, }, { "component": "Comp", "context": { - "plugin": "/packages/docusaurus/src/server/plugins/__tests__/__fixtures__/site-with-plugin/.docusaurus/plugin-name/default/plugin-route-context-module-100.json", + "plugin": "@generated/plugin-name/default/__plugin.json", }, "path": "/contentLoadedRouteSingle/", + "plugin": { + "id": "default", + "name": "plugin-name", + }, }, { "component": "Comp", "context": { - "plugin": "/packages/docusaurus/src/server/plugins/__tests__/__fixtures__/site-with-plugin/.docusaurus/plugin-name/default/plugin-route-context-module-100.json", + "plugin": "@generated/plugin-name/default/__plugin.json", }, "path": "/allContentLoadedRouteParent/", + "plugin": { + "id": "default", + "name": "plugin-name", + }, "routes": [ { "component": "Comp", @@ -302,9 +322,13 @@ describe('loadPlugins', () => { { "component": "Comp", "context": { - "plugin": "/packages/docusaurus/src/server/plugins/__tests__/__fixtures__/site-with-plugin/.docusaurus/plugin-name/default/plugin-route-context-module-100.json", + "plugin": "@generated/plugin-name/default/__plugin.json", }, "path": "/contentLoadedRouteParent/", + "plugin": { + "id": "default", + "name": "plugin-name", + }, "routes": [ { "component": "Comp", @@ -386,23 +410,35 @@ describe('reloadPlugin', () => { { "component": "Comp", "context": { - "plugin": "/packages/docusaurus/src/server/plugins/__tests__/__fixtures__/site-with-plugin/.docusaurus/plugin-name/default/plugin-route-context-module-100.json", + "plugin": "@generated/plugin-name/default/__plugin.json", }, "path": "/allContentLoadedRouteSingle/", + "plugin": { + "id": "default", + "name": "plugin-name", + }, }, { "component": "Comp", "context": { - "plugin": "/packages/docusaurus/src/server/plugins/__tests__/__fixtures__/site-with-plugin/.docusaurus/plugin-name/default/plugin-route-context-module-100.json", + "plugin": "@generated/plugin-name/default/__plugin.json", }, "path": "/contentLoadedRouteSingle/", + "plugin": { + "id": "default", + "name": "plugin-name", + }, }, { "component": "Comp", "context": { - "plugin": "/packages/docusaurus/src/server/plugins/__tests__/__fixtures__/site-with-plugin/.docusaurus/plugin-name/default/plugin-route-context-module-100.json", + "plugin": "@generated/plugin-name/default/__plugin.json", }, "path": "/allContentLoadedRouteParent/", + "plugin": { + "id": "default", + "name": "plugin-name", + }, "routes": [ { "component": "Comp", @@ -413,9 +449,13 @@ describe('reloadPlugin', () => { { "component": "Comp", "context": { - "plugin": "/packages/docusaurus/src/server/plugins/__tests__/__fixtures__/site-with-plugin/.docusaurus/plugin-name/default/plugin-route-context-module-100.json", + "plugin": "@generated/plugin-name/default/__plugin.json", }, "path": "/contentLoadedRouteParent/", + "plugin": { + "id": "default", + "name": "plugin-name", + }, "routes": [ { "component": "Comp", @@ -502,23 +542,35 @@ describe('reloadPlugin', () => { { "component": "Comp", "context": { - "plugin": "/packages/docusaurus/src/server/plugins/__tests__/__fixtures__/site-with-plugin/.docusaurus/plugin-name-1/default/plugin-route-context-module-100.json", + "plugin": "@generated/plugin-name-1/default/__plugin.json", }, "path": "/allContentLoaded-route-initial/", + "plugin": { + "id": "default", + "name": "plugin-name-1", + }, }, { "component": "Comp", "context": { - "plugin": "/packages/docusaurus/src/server/plugins/__tests__/__fixtures__/site-with-plugin/.docusaurus/plugin-name-1/default/plugin-route-context-module-100.json", + "plugin": "@generated/plugin-name-1/default/__plugin.json", }, "path": "/contentLoaded-route-initial/", + "plugin": { + "id": "default", + "name": "plugin-name-1", + }, }, { "component": "Comp", "context": { - "plugin": "/packages/docusaurus/src/server/plugins/__tests__/__fixtures__/site-with-plugin/.docusaurus/plugin-name-2/default/plugin-route-context-module-100.json", + "plugin": "@generated/plugin-name-2/default/__plugin.json", }, "path": "/plugin-2-route/", + "plugin": { + "id": "default", + "name": "plugin-name-2", + }, }, ] `); @@ -542,23 +594,35 @@ describe('reloadPlugin', () => { { "component": "Comp", "context": { - "plugin": "/packages/docusaurus/src/server/plugins/__tests__/__fixtures__/site-with-plugin/.docusaurus/plugin-name-1/default/plugin-route-context-module-100.json", + "plugin": "@generated/plugin-name-1/default/__plugin.json", }, "path": "/allContentLoaded-route-reload/", + "plugin": { + "id": "default", + "name": "plugin-name-1", + }, }, { "component": "Comp", "context": { - "plugin": "/packages/docusaurus/src/server/plugins/__tests__/__fixtures__/site-with-plugin/.docusaurus/plugin-name-1/default/plugin-route-context-module-100.json", + "plugin": "@generated/plugin-name-1/default/__plugin.json", }, "path": "/contentLoaded-route-reload/", + "plugin": { + "id": "default", + "name": "plugin-name-1", + }, }, { "component": "Comp", "context": { - "plugin": "/packages/docusaurus/src/server/plugins/__tests__/__fixtures__/site-with-plugin/.docusaurus/plugin-name-2/default/plugin-route-context-module-100.json", + "plugin": "@generated/plugin-name-2/default/__plugin.json", }, "path": "/plugin-2-route/", + "plugin": { + "id": "default", + "name": "plugin-name-2", + }, }, ] `); diff --git a/packages/docusaurus/src/server/plugins/actions.ts b/packages/docusaurus/src/server/plugins/actions.ts index d9313cb4cc..123a98166b 100644 --- a/packages/docusaurus/src/server/plugins/actions.ts +++ b/packages/docusaurus/src/server/plugins/actions.ts @@ -6,7 +6,7 @@ */ import path from 'path'; -import {docuHash, generate} from '@docusaurus/utils'; +import {generate, posixPath} from '@docusaurus/utils'; import {applyRouteTrailingSlash} from './routeConfig'; import type { InitializedPlugin, @@ -38,17 +38,26 @@ export async function createPluginActionsUtils({ }): Promise { const pluginId = plugin.options.id; // Plugins data files are namespaced by pluginName/pluginId + + // TODO Docusaurus v4 breaking change + // module aliasing should be automatic + // we should never find local absolute FS paths in the codegen registry + const aliasedSource = (source: string) => + `@generated/${posixPath(path.relative(generatedFilesDir, source))}`; + + // TODO use @generated data dir here! + // The module registry should not contain absolute paths const dataDir = path.join(generatedFilesDir, plugin.name, pluginId); const pluginRouteContext: PluginRouteContext['plugin'] = { name: plugin.name, id: pluginId, }; - const pluginRouteContextModulePath = path.join( - dataDir, - `${docuHash('pluginRouteContextModule')}.json`, - ); + + const pluginRouteContextModulePath = path.join(dataDir, `__plugin.json`); + // TODO not ideal place to generate that file + // move to codegen step instead! await generate( '/', pluginRouteContextModulePath, @@ -69,13 +78,15 @@ export async function createPluginActionsUtils({ ...finalRouteConfig, context: { ...(finalRouteConfig.context && {data: finalRouteConfig.context}), - plugin: pluginRouteContextModulePath, + plugin: aliasedSource(pluginRouteContextModulePath), }, }); }, async createData(name, data) { const modulePath = path.join(dataDir, name); - await generate(dataDir, name, data); + const dataString = + typeof data === 'string' ? data : JSON.stringify(data, null, 2); + await generate(dataDir, name, dataString); return modulePath; }, setGlobalData(data) { diff --git a/packages/docusaurus/src/server/plugins/plugins.ts b/packages/docusaurus/src/server/plugins/plugins.ts index a5dbf26338..17e1b2d6c7 100644 --- a/packages/docusaurus/src/server/plugins/plugins.ts +++ b/packages/docusaurus/src/server/plugins/plugins.ts @@ -18,6 +18,7 @@ import { formatPluginName, getPluginByIdentifier, mergeGlobalData, + toPluginRoute, } from './pluginsUtils'; import type { LoadContext, @@ -27,6 +28,7 @@ import type { PluginIdentifier, LoadedPlugin, InitializedPlugin, + PluginRouteConfig, } from '@docusaurus/types'; async function translatePluginContent({ @@ -174,7 +176,10 @@ async function executePluginAllContentLoaded({ ); } -type AllContentLoadedResult = {routes: RouteConfig[]; globalData: GlobalData}; +type AllContentLoadedResult = { + routes: PluginRouteConfig[]; + globalData: GlobalData; +}; async function executeAllPluginsAllContentLoaded({ plugins, @@ -186,28 +191,32 @@ async function executeAllPluginsAllContentLoaded({ return PerfLogger.async(`allContentLoaded()`, async () => { const allContent = aggregateAllContent(plugins); - const routes: RouteConfig[] = []; - const globalData: GlobalData = {}; + const allRoutes: PluginRouteConfig[] = []; + const allGlobalData: GlobalData = {}; await Promise.all( plugins.map(async (plugin) => { - const {routes: pluginRoutes, globalData: pluginGlobalData} = + const {routes, globalData: pluginGlobalData} = await executePluginAllContentLoaded({ plugin, context, allContent, }); - routes.push(...pluginRoutes); + const pluginRoutes = routes.map((route) => + toPluginRoute({plugin, route}), + ); + + allRoutes.push(...pluginRoutes); if (pluginGlobalData !== undefined) { - globalData[plugin.name] ??= {}; - globalData[plugin.name]![plugin.options.id] = pluginGlobalData; + allGlobalData[plugin.name] ??= {}; + allGlobalData[plugin.name]![plugin.options.id] = pluginGlobalData; } }), ); - return {routes, globalData}; + return {routes: allRoutes, globalData: allGlobalData}; }); } @@ -221,7 +230,7 @@ function mergeResults({ plugins: LoadedPlugin[]; allContentLoadedResult: AllContentLoadedResult; }) { - const routes: RouteConfig[] = [ + const routes: PluginRouteConfig[] = [ ...aggregateRoutes(plugins), ...allContentLoadedResult.routes, ]; @@ -237,7 +246,7 @@ function mergeResults({ export type LoadPluginsResult = { plugins: LoadedPlugin[]; - routes: RouteConfig[]; + routes: PluginRouteConfig[]; globalData: GlobalData; }; diff --git a/packages/docusaurus/src/server/plugins/pluginsUtils.ts b/packages/docusaurus/src/server/plugins/pluginsUtils.ts index 4c756fd7fd..2b1ff68c20 100644 --- a/packages/docusaurus/src/server/plugins/pluginsUtils.ts +++ b/packages/docusaurus/src/server/plugins/pluginsUtils.ts @@ -13,6 +13,7 @@ import type { InitializedPlugin, LoadedPlugin, PluginIdentifier, + PluginRouteConfig, RouteConfig, } from '@docusaurus/types'; @@ -49,8 +50,22 @@ export function aggregateAllContent(loadedPlugins: LoadedPlugin[]): AllContent { .value(); } -export function aggregateRoutes(loadedPlugins: LoadedPlugin[]): RouteConfig[] { - return loadedPlugins.flatMap((p) => p.routes); +export function toPluginRoute({ + plugin, + route, +}: { + plugin: LoadedPlugin; + route: RouteConfig; +}): PluginRouteConfig { + return {plugin: {name: plugin.name, id: plugin.options.id}, ...route}; +} + +export function aggregateRoutes( + loadedPlugins: LoadedPlugin[], +): PluginRouteConfig[] { + return loadedPlugins.flatMap((plugin) => + plugin.routes.map((route) => toPluginRoute({plugin, route})), + ); } export function aggregateGlobalData(loadedPlugins: LoadedPlugin[]): GlobalData { diff --git a/packages/docusaurus/src/server/plugins/routeConfig.ts b/packages/docusaurus/src/server/plugins/routeConfig.ts index cd824f1f4b..6e0891bfd2 100644 --- a/packages/docusaurus/src/server/plugins/routeConfig.ts +++ b/packages/docusaurus/src/server/plugins/routeConfig.ts @@ -12,10 +12,10 @@ import { import type {RouteConfig} from '@docusaurus/types'; /** Recursively applies trailing slash config to all nested routes. */ -export function applyRouteTrailingSlash( - route: RouteConfig, +export function applyRouteTrailingSlash( + route: Route, params: ApplyTrailingSlashParams, -): RouteConfig { +): Route { return { ...route, path: applyTrailingSlash(route.path, params), diff --git a/website/_dogfooding/dogfooding.config.ts b/website/_dogfooding/dogfooding.config.ts index 3e57c13c36..ebb6b22885 100644 --- a/website/_dogfooding/dogfooding.config.ts +++ b/website/_dogfooding/dogfooding.config.ts @@ -90,6 +90,10 @@ export const dogfoodingPluginInstances: PluginConfig[] = [ id: 'pages-tests', path: '_dogfooding/_pages tests', routeBasePath: '/tests/pages', + showLastUpdateTime: true, + showLastUpdateAuthor: true, + editUrl: ({pagesPath}) => + `https://github.com/facebook/docusaurus/edit/main/website/_dogfooding/_pages tests/${pagesPath}`, } satisfies PageOptions, ], diff --git a/website/docs/api/plugins/plugin-content-pages.mdx b/website/docs/api/plugins/plugin-content-pages.mdx index 8894e7861b..266c929d5a 100644 --- a/website/docs/api/plugins/plugin-content-pages.mdx +++ b/website/docs/api/plugins/plugin-content-pages.mdx @@ -34,6 +34,8 @@ Accepted fields: | Name | Type | Default | Description | | --- | --- | --- | --- | | `path` | `string` | `'src/pages'` | Path to data on filesystem relative to site dir. Components in this directory will be automatically converted to pages. | +| `editUrl` | string \| [EditUrlFn](#EditUrlFn) | `undefined` | **Only for Markdown pages**. Base URL to edit your site. The final URL is computed by `editUrl + relativePostPath`. Using a function allows more nuanced control for each file. Omitting this variable entirely will disable edit links. | +| `editLocalizedFiles` | `boolean` | `false` | **Only for Markdown pages**. The edit URL will target the localized file, instead of the original unlocalized file. Ignored when `editUrl` is a function. | | `routeBasePath` | `string` | `'/'` | URL route for the pages section of your site. **DO NOT** include a trailing slash. | | `include` | `string[]` | `['**/*.{js,jsx,ts,tsx,md,mdx}']` | Matching files will be included and processed. | | `exclude` | `string[]` | _See example configuration_ | No route will be created for matching files. | @@ -42,11 +44,26 @@ Accepted fields: | `rehypePlugins` | `[]` | `any[]` | Rehype plugins passed to MDX. | | `beforeDefaultRemarkPlugins` | `any[]` | `[]` | Custom Remark plugins passed to MDX before the default Docusaurus Remark plugins. | | `beforeDefaultRehypePlugins` | `any[]` | `[]` | Custom Rehype plugins passed to MDX before the default Docusaurus Rehype plugins. | +| `showLastUpdateAuthor` | `boolean` | `false` | **Only for Markdown pages**. Whether to display the author who last updated the page. | +| `showLastUpdateTime` | `boolean` | `false` | **Only for Markdown pages**. Whether to display the last date the page post was updated. This requires access to git history during the build, so will not work correctly with shallow clones (a common default for CI systems). With GitHub `actions/checkout`, use`fetch-depth: 0`. | ```mdx-code-block ``` +### Types {#types} + +#### `EditUrlFn` {#EditUrlFn} + +```ts +type EditUrlFunction = (params: { + blogDirPath: string; + blogPath: string; + permalink: string; + locale: string; +}) => string | undefined; +``` + ### Example configuration {#ex-config} You can configure this plugin through preset options or plugin options. diff --git a/website/docs/guides/markdown-features/markdown-features-plugins.mdx b/website/docs/guides/markdown-features/markdown-features-plugins.mdx index a8ffb356a7..690a8d81bd 100644 --- a/website/docs/guides/markdown-features/markdown-features-plugins.mdx +++ b/website/docs/guides/markdown-features/markdown-features-plugins.mdx @@ -160,7 +160,7 @@ The writeup below is **not** meant to be a comprehensive guide to creating a plu For example, let's make a plugin that visits every `h2` heading and adds a `Section X. ` prefix. First, create your plugin source file anywhere—you can even publish it as a separate npm package and install it like explained above. We would put ours at `src/remark/section-prefix.js`. A remark/rehype plugin is just a function that receives the `options` and returns a `transformer` that operates on the AST. ```js "src/remark/section-prefix.js" -import visit from 'unist-util-visit'; +import {visit} from 'unist-util-visit'; const plugin = (options) => { const transformer = async (ast) => { diff --git a/website/docusaurus.config.ts b/website/docusaurus.config.ts index ebacd3e63c..c2adb15763 100644 --- a/website/docusaurus.config.ts +++ b/website/docusaurus.config.ts @@ -470,6 +470,14 @@ export default async function createConfigAsync() { } satisfies BlogOptions, pages: { remarkPlugins: [npm2yarn], + editUrl: ({locale, pagesPath}) => { + if (locale !== defaultLocale) { + return `https://crowdin.com/project/docusaurus-v2/${locale}`; + } + return `https://github.com/facebook/docusaurus/edit/main/website/src/pages/${pagesPath}`; + }, + showLastUpdateAuthor: true, + showLastUpdateTime: true, } satisfies PageOptions, theme: { customCss: [ diff --git a/website/src/plugins/featureRequests/FeatureRequestsPlugin.js b/website/src/plugins/featureRequests/FeatureRequestsPlugin.js index c4ba402df5..5031dca775 100644 --- a/website/src/plugins/featureRequests/FeatureRequestsPlugin.js +++ b/website/src/plugins/featureRequests/FeatureRequestsPlugin.js @@ -5,7 +5,8 @@ * LICENSE file in the root directory of this source tree. */ -import {normalizeUrl} from '@docusaurus/utils'; +import path from 'path'; +import {normalizeUrl, posixPath} from '@docusaurus/utils'; /** * @param {import('@docusaurus/types').LoadContext} context @@ -20,12 +21,21 @@ export default function FeatureRequestsPlugin(context) { 'paths.json', JSON.stringify(basePath), ); + + // TODO Docusaurus v4 breaking change + // module aliasing should be automatic + // we should never find local absolute FS paths in the codegen registry + const aliasedSource = (source) => + `@generated/${posixPath( + path.relative(context.generatedFilesDir, source), + )}`; + actions.addRoute({ path: basePath, exact: false, component: '@site/src/plugins/featureRequests/FeatureRequestsPage', modules: { - basePath: paths, + basePath: aliasedSource(paths), }, }); },