mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-13 00:57:53 +02:00
feat(v2): core v2 i18n support + Docusaurus site Crowdin integration (#3325)
* docs i18n initial poc * docs i18n initial poc * docs i18n initial poc * docs i18n initial poc * crowdin-v2 attempt * fix source * use crowdin env variable * try to install crowdin on netlify * try to install crowdin on netlify * try to use crowdin jar directly * try to curl the crowdin jar * add java version cmd * try to run crowdin jar in netlify * fix translatedDocsDirPath * fix loadContext issue due to site baseUrl not being modified in generted config file * real validateLocalesFile * add locale option to deploy command * better LocalizationFile type * create util getPluginI18nPath * better core localization context loading code * More explicit VersionMetadata type for localized docs folders * Ability to translate blog posts with Crowdin! * blog: refactor markdown loader + report broken links + try to get linkify working better * upgrade crowdin config to upload all docs folder files except source code related files * try to support translated pages * make markdown pages translation work * add write-translations cli command template * fix site not reloaded with correct options * refactor a bit the read/write of @generated/i18n.json file * Add <Translate> + translate() API + use it on the docusaurus homepage * watch locale translation dir * early POC of adding babel parsing for translation extraction * fs.stat => pathExists * add install:fast script * TSC: noUnusedLocals false as it's already checked by eslint * POC of extracting translations from source code * minor typo * fix extracted key to code * initial docs extracted translations * stable plugin translations POC * add crowdin commands * quickfix for i18n deployment * POC of themeConfig translation * add ability to have localized site without path prefix * sidebar typo * refactor translation system to output multiple translation files * translate properly the docs plugin * improve theme classic translation * rework translation extractor to handle new Chrome I18n JSON format (include id/description) * writeTranslations: allow to pass locales cli arg * fix ThemeConfig TS issues * fix localizePath errors * temporary add write-translations to netlify deploy preview * complete example of french translated folder * update fr folder * remove all translations from repo * minor translation refactors * fix all docs-related tests * fix blog feed tests * fix last blog tests * refactor i18n context a bit, extract codeTranslations in an extra generated file * improve @generated/i18n type * fix some i18n todos * minor refactor * fix logo typing issue after merge * move i18n.json to siteConfig instead * try to fix windows CI build * fix config test * attempt to fix windows non-posix path * increase v1 minify css jest timeout due to flaky test * proper support for localizePath on windows * remove non-functional install:fast * docs, fix docsDirPathLocalized * fix Docs i18n / md linkify issues * ensure theme-classic swizzling will use "nextjs" sources (transpiled less aggressively, to make them human readable) * fix some snapshots * improve themeConfig translation code * refactor a bit getPluginI18nPath * readTranslationFileContent => ensure files are valid, fail fast * fix versions tests * add extractSourceCodeAstTranslations comments/resource links * ignore eslint: packages/docusaurus-theme-classic/lib-next/ * fix windows CI with cross-env * crowdin ignore .DS_Store * improve writeTranslations + add exhaustive tests for translations.ts * remove typo * Wire currentLocale to algolia search * improve i18n locale error * Add tests for translationsExtractor.ts * better code translation extraction regarding statically evaluable code * fix typo * fix typo * improve theme-classic transpilation * refactor + add i18n tests * typo * test new utils * add missing snapshots * fix snapshot * blog onBrokenMarkdownLink * add sidebars tests * theme-classic index should now use ES modules * tests for theme-classic translations * useless comment * add more translation tests * simplify/cleanup writeTranslations * try to fix Netlify fr deployment * blog: test translated md is used during feed generation * blog: better i18n tests regarding editUrl + md translation application * more i18n tests for docs plugin * more i18n tests for docs plugin * Add tests for pages i18n * polish docusaurus build i18n logs
This commit is contained in:
parent
85fe96d112
commit
3166fab307
107 changed files with 5447 additions and 649 deletions
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Team title translated
|
||||
---
|
||||
|
||||
Team current version (translated)
|
|
@ -0,0 +1 @@
|
|||
Hello `1.0.0` ! (translated)
|
|
@ -616,18 +616,6 @@ Object {
|
|||
|
||||
exports[`versioned website (community) content: data 1`] = `
|
||||
Object {
|
||||
"site-community-team-md-9d8.json": "{
|
||||
\\"unversionedId\\": \\"team\\",
|
||||
\\"id\\": \\"team\\",
|
||||
\\"isDocsHomePage\\": false,
|
||||
\\"title\\": \\"team\\",
|
||||
\\"description\\": \\"Team current version\\",
|
||||
\\"source\\": \\"@site/community/team.md\\",
|
||||
\\"slug\\": \\"/team\\",
|
||||
\\"permalink\\": \\"/community/next/team\\",
|
||||
\\"version\\": \\"current\\",
|
||||
\\"sidebar\\": \\"community\\"
|
||||
}",
|
||||
"site-community-versioned-docs-version-1-0-0-team-md-359.json": "{
|
||||
\\"unversionedId\\": \\"team\\",
|
||||
\\"id\\": \\"version-1.0.0/team\\",
|
||||
|
@ -639,6 +627,18 @@ Object {
|
|||
\\"permalink\\": \\"/community/team\\",
|
||||
\\"version\\": \\"1.0.0\\",
|
||||
\\"sidebar\\": \\"version-1.0.0/community\\"
|
||||
}",
|
||||
"site-i-18-n-en-docusaurus-plugin-content-docs-community-current-team-md-7e5.json": "{
|
||||
\\"unversionedId\\": \\"team\\",
|
||||
\\"id\\": \\"team\\",
|
||||
\\"isDocsHomePage\\": false,
|
||||
\\"title\\": \\"Team title translated\\",
|
||||
\\"description\\": \\"Team current version (translated)\\",
|
||||
\\"source\\": \\"@site/i18n/en/docusaurus-plugin-content-docs-community/current/team.md\\",
|
||||
\\"slug\\": \\"/team\\",
|
||||
\\"permalink\\": \\"/community/next/team\\",
|
||||
\\"version\\": \\"current\\",
|
||||
\\"sidebar\\": \\"community\\"
|
||||
}",
|
||||
"version-1-0-0-metadata-prop-608.json": "{
|
||||
\\"pluginId\\": \\"community\\",
|
||||
|
@ -667,7 +667,7 @@ Object {
|
|||
\\"community\\": [
|
||||
{
|
||||
\\"type\\": \\"link\\",
|
||||
\\"label\\": \\"team\\",
|
||||
\\"label\\": \\"Team title translated\\",
|
||||
\\"href\\": \\"/community/next/team\\"
|
||||
}
|
||||
]
|
||||
|
@ -734,7 +734,7 @@ Array [
|
|||
"component": "@theme/DocItem",
|
||||
"exact": true,
|
||||
"modules": Object {
|
||||
"content": "@site/community/team.md",
|
||||
"content": "@site/i18n/en/docusaurus-plugin-content-docs-community/current/team.md",
|
||||
},
|
||||
"path": "/community/next/team",
|
||||
},
|
||||
|
@ -930,6 +930,22 @@ Object {
|
|||
\\"slug\\": \\"/tryToEscapeSlug\\",
|
||||
\\"permalink\\": \\"/docs/next/tryToEscapeSlug\\",
|
||||
\\"version\\": \\"current\\"
|
||||
}",
|
||||
"site-i-18-n-en-docusaurus-plugin-content-docs-version-1-0-0-hello-md-fe5.json": "{
|
||||
\\"unversionedId\\": \\"hello\\",
|
||||
\\"id\\": \\"version-1.0.0/hello\\",
|
||||
\\"isDocsHomePage\\": true,
|
||||
\\"title\\": \\"hello\\",
|
||||
\\"description\\": \\"Hello 1.0.0 ! (translated)\\",
|
||||
\\"source\\": \\"@site/i18n/en/docusaurus-plugin-content-docs/version-1.0.0/hello.md\\",
|
||||
\\"slug\\": \\"/\\",
|
||||
\\"permalink\\": \\"/docs/1.0.0/\\",
|
||||
\\"version\\": \\"1.0.0\\",
|
||||
\\"sidebar\\": \\"version-1.0.0/docs\\",
|
||||
\\"previous\\": {
|
||||
\\"title\\": \\"baz\\",
|
||||
\\"permalink\\": \\"/docs/1.0.0/foo/baz\\"
|
||||
}
|
||||
}",
|
||||
"site-versioned-docs-version-1-0-0-foo-bar-md-7a6.json": "{
|
||||
\\"unversionedId\\": \\"foo/bar\\",
|
||||
|
@ -966,22 +982,6 @@ Object {
|
|||
\\"title\\": \\"hello\\",
|
||||
\\"permalink\\": \\"/docs/1.0.0/\\"
|
||||
}
|
||||
}",
|
||||
"site-versioned-docs-version-1-0-0-hello-md-3ef.json": "{
|
||||
\\"unversionedId\\": \\"hello\\",
|
||||
\\"id\\": \\"version-1.0.0/hello\\",
|
||||
\\"isDocsHomePage\\": true,
|
||||
\\"title\\": \\"hello\\",
|
||||
\\"description\\": \\"Hello 1.0.0 !\\",
|
||||
\\"source\\": \\"@site/versioned_docs/version-1.0.0/hello.md\\",
|
||||
\\"slug\\": \\"/\\",
|
||||
\\"permalink\\": \\"/docs/1.0.0/\\",
|
||||
\\"version\\": \\"1.0.0\\",
|
||||
\\"sidebar\\": \\"version-1.0.0/docs\\",
|
||||
\\"previous\\": {
|
||||
\\"title\\": \\"baz\\",
|
||||
\\"permalink\\": \\"/docs/1.0.0/foo/baz\\"
|
||||
}
|
||||
}",
|
||||
"site-versioned-docs-version-1-0-1-foo-bar-md-7a3.json": "{
|
||||
\\"unversionedId\\": \\"foo/bar\\",
|
||||
|
@ -1410,7 +1410,7 @@ Array [
|
|||
"component": "@theme/DocItem",
|
||||
"exact": true,
|
||||
"modules": Object {
|
||||
"content": "@site/versioned_docs/version-1.0.0/hello.md",
|
||||
"content": "@site/i18n/en/docusaurus-plugin-content-docs/version-1.0.0/hello.md",
|
||||
},
|
||||
"path": "/docs/1.0.0/",
|
||||
},
|
||||
|
|
|
@ -0,0 +1,487 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`getLoadedContentTranslationFiles should return translation files matching snapshot 1`] = `
|
||||
Array [
|
||||
Object {
|
||||
"content": Object {
|
||||
"sidebar.docs.category.Getting started": Object {
|
||||
"description": "The label for category Getting started in sidebar docs",
|
||||
"message": "Getting started",
|
||||
},
|
||||
"sidebar.docs.link.Link label": Object {
|
||||
"description": "The label for link Link label in sidebar docs, linking to https://facebook.com",
|
||||
"message": "Link label",
|
||||
},
|
||||
"version.label": Object {
|
||||
"description": "The label for version current",
|
||||
"message": "current label",
|
||||
},
|
||||
},
|
||||
"path": "current",
|
||||
},
|
||||
Object {
|
||||
"content": Object {
|
||||
"sidebar.docs.category.Getting started": Object {
|
||||
"description": "The label for category Getting started in sidebar docs",
|
||||
"message": "Getting started",
|
||||
},
|
||||
"sidebar.docs.link.Link label": Object {
|
||||
"description": "The label for link Link label in sidebar docs, linking to https://facebook.com",
|
||||
"message": "Link label",
|
||||
},
|
||||
"version.label": Object {
|
||||
"description": "The label for version 2.0.0",
|
||||
"message": "2.0.0 label",
|
||||
},
|
||||
},
|
||||
"path": "version-2.0.0",
|
||||
},
|
||||
Object {
|
||||
"content": Object {
|
||||
"sidebar.docs.category.Getting started": Object {
|
||||
"description": "The label for category Getting started in sidebar docs",
|
||||
"message": "Getting started",
|
||||
},
|
||||
"sidebar.docs.link.Link label": Object {
|
||||
"description": "The label for link Link label in sidebar docs, linking to https://facebook.com",
|
||||
"message": "Link label",
|
||||
},
|
||||
"version.label": Object {
|
||||
"description": "The label for version 1.0.0",
|
||||
"message": "1.0.0 label",
|
||||
},
|
||||
},
|
||||
"path": "version-1.0.0",
|
||||
},
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`translateLoadedContent should return translated loaded content matching snapshot 1`] = `
|
||||
Object {
|
||||
"loadedVersions": Array [
|
||||
Object {
|
||||
"docs": Array [
|
||||
Object {
|
||||
"description": "doc1 description",
|
||||
"editUrl": "any",
|
||||
"id": "doc1",
|
||||
"isDocsHomePage": false,
|
||||
"lastUpdatedAt": 0,
|
||||
"lastUpdatedBy": "any",
|
||||
"next": undefined,
|
||||
"permalink": "any",
|
||||
"previous": undefined,
|
||||
"sidebar_label": "doc1 title",
|
||||
"slug": "any",
|
||||
"source": "any",
|
||||
"title": "doc1 title",
|
||||
"unversionedId": "any",
|
||||
"version": "any",
|
||||
},
|
||||
Object {
|
||||
"description": "doc2 description",
|
||||
"editUrl": "any",
|
||||
"id": "doc2",
|
||||
"isDocsHomePage": false,
|
||||
"lastUpdatedAt": 0,
|
||||
"lastUpdatedBy": "any",
|
||||
"next": undefined,
|
||||
"permalink": "any",
|
||||
"previous": undefined,
|
||||
"sidebar_label": "doc2 title",
|
||||
"slug": "any",
|
||||
"source": "any",
|
||||
"title": "doc2 title",
|
||||
"unversionedId": "any",
|
||||
"version": "any",
|
||||
},
|
||||
Object {
|
||||
"description": "doc3 description",
|
||||
"editUrl": "any",
|
||||
"id": "doc3",
|
||||
"isDocsHomePage": false,
|
||||
"lastUpdatedAt": 0,
|
||||
"lastUpdatedBy": "any",
|
||||
"next": undefined,
|
||||
"permalink": "any",
|
||||
"previous": undefined,
|
||||
"sidebar_label": "doc3 title",
|
||||
"slug": "any",
|
||||
"source": "any",
|
||||
"title": "doc3 title",
|
||||
"unversionedId": "any",
|
||||
"version": "any",
|
||||
},
|
||||
Object {
|
||||
"description": "doc4 description",
|
||||
"editUrl": "any",
|
||||
"id": "doc4",
|
||||
"isDocsHomePage": false,
|
||||
"lastUpdatedAt": 0,
|
||||
"lastUpdatedBy": "any",
|
||||
"next": undefined,
|
||||
"permalink": "any",
|
||||
"previous": undefined,
|
||||
"sidebar_label": "doc4 title",
|
||||
"slug": "any",
|
||||
"source": "any",
|
||||
"title": "doc4 title",
|
||||
"unversionedId": "any",
|
||||
"version": "any",
|
||||
},
|
||||
Object {
|
||||
"description": "doc5 description",
|
||||
"editUrl": "any",
|
||||
"id": "doc5",
|
||||
"isDocsHomePage": false,
|
||||
"lastUpdatedAt": 0,
|
||||
"lastUpdatedBy": "any",
|
||||
"next": undefined,
|
||||
"permalink": "any",
|
||||
"previous": undefined,
|
||||
"sidebar_label": "doc5 title",
|
||||
"slug": "any",
|
||||
"source": "any",
|
||||
"title": "doc5 title",
|
||||
"unversionedId": "any",
|
||||
"version": "any",
|
||||
},
|
||||
],
|
||||
"docsDirPath": "any",
|
||||
"docsDirPathLocalized": "any",
|
||||
"isLast": true,
|
||||
"mainDocId": "",
|
||||
"permalinkToSidebar": Object {},
|
||||
"routePriority": undefined,
|
||||
"sidebarFilePath": "any",
|
||||
"sidebars": Object {
|
||||
"docs": Array [
|
||||
Object {
|
||||
"collapsed": false,
|
||||
"items": Array [
|
||||
Object {
|
||||
"id": "doc1",
|
||||
"type": "doc",
|
||||
},
|
||||
Object {
|
||||
"id": "doc2",
|
||||
"type": "doc",
|
||||
},
|
||||
Object {
|
||||
"href": "https://facebook.com",
|
||||
"label": "Link label (translated)",
|
||||
"type": "link",
|
||||
},
|
||||
Object {
|
||||
"id": "doc1",
|
||||
"type": "ref",
|
||||
},
|
||||
],
|
||||
"label": "Getting started (translated)",
|
||||
"type": "category",
|
||||
},
|
||||
Object {
|
||||
"id": "doc3",
|
||||
"type": "doc",
|
||||
},
|
||||
],
|
||||
"otherSidebar": Array [
|
||||
Object {
|
||||
"id": "doc4",
|
||||
"type": "doc",
|
||||
},
|
||||
Object {
|
||||
"id": "doc5",
|
||||
"type": "doc",
|
||||
},
|
||||
],
|
||||
},
|
||||
"versionLabel": "current label (translated)",
|
||||
"versionName": "current",
|
||||
"versionPath": "/docs/",
|
||||
},
|
||||
Object {
|
||||
"docs": Array [
|
||||
Object {
|
||||
"description": "doc1 description",
|
||||
"editUrl": "any",
|
||||
"id": "doc1",
|
||||
"isDocsHomePage": false,
|
||||
"lastUpdatedAt": 0,
|
||||
"lastUpdatedBy": "any",
|
||||
"next": undefined,
|
||||
"permalink": "any",
|
||||
"previous": undefined,
|
||||
"sidebar_label": "doc1 title",
|
||||
"slug": "any",
|
||||
"source": "any",
|
||||
"title": "doc1 title",
|
||||
"unversionedId": "any",
|
||||
"version": "any",
|
||||
},
|
||||
Object {
|
||||
"description": "doc2 description",
|
||||
"editUrl": "any",
|
||||
"id": "doc2",
|
||||
"isDocsHomePage": false,
|
||||
"lastUpdatedAt": 0,
|
||||
"lastUpdatedBy": "any",
|
||||
"next": undefined,
|
||||
"permalink": "any",
|
||||
"previous": undefined,
|
||||
"sidebar_label": "doc2 title",
|
||||
"slug": "any",
|
||||
"source": "any",
|
||||
"title": "doc2 title",
|
||||
"unversionedId": "any",
|
||||
"version": "any",
|
||||
},
|
||||
Object {
|
||||
"description": "doc3 description",
|
||||
"editUrl": "any",
|
||||
"id": "doc3",
|
||||
"isDocsHomePage": false,
|
||||
"lastUpdatedAt": 0,
|
||||
"lastUpdatedBy": "any",
|
||||
"next": undefined,
|
||||
"permalink": "any",
|
||||
"previous": undefined,
|
||||
"sidebar_label": "doc3 title",
|
||||
"slug": "any",
|
||||
"source": "any",
|
||||
"title": "doc3 title",
|
||||
"unversionedId": "any",
|
||||
"version": "any",
|
||||
},
|
||||
Object {
|
||||
"description": "doc4 description",
|
||||
"editUrl": "any",
|
||||
"id": "doc4",
|
||||
"isDocsHomePage": false,
|
||||
"lastUpdatedAt": 0,
|
||||
"lastUpdatedBy": "any",
|
||||
"next": undefined,
|
||||
"permalink": "any",
|
||||
"previous": undefined,
|
||||
"sidebar_label": "doc4 title",
|
||||
"slug": "any",
|
||||
"source": "any",
|
||||
"title": "doc4 title",
|
||||
"unversionedId": "any",
|
||||
"version": "any",
|
||||
},
|
||||
Object {
|
||||
"description": "doc5 description",
|
||||
"editUrl": "any",
|
||||
"id": "doc5",
|
||||
"isDocsHomePage": false,
|
||||
"lastUpdatedAt": 0,
|
||||
"lastUpdatedBy": "any",
|
||||
"next": undefined,
|
||||
"permalink": "any",
|
||||
"previous": undefined,
|
||||
"sidebar_label": "doc5 title",
|
||||
"slug": "any",
|
||||
"source": "any",
|
||||
"title": "doc5 title",
|
||||
"unversionedId": "any",
|
||||
"version": "any",
|
||||
},
|
||||
],
|
||||
"docsDirPath": "any",
|
||||
"docsDirPathLocalized": "any",
|
||||
"isLast": true,
|
||||
"mainDocId": "",
|
||||
"permalinkToSidebar": Object {},
|
||||
"routePriority": undefined,
|
||||
"sidebarFilePath": "any",
|
||||
"sidebars": Object {
|
||||
"docs": Array [
|
||||
Object {
|
||||
"collapsed": false,
|
||||
"items": Array [
|
||||
Object {
|
||||
"id": "doc1",
|
||||
"type": "doc",
|
||||
},
|
||||
Object {
|
||||
"id": "doc2",
|
||||
"type": "doc",
|
||||
},
|
||||
Object {
|
||||
"href": "https://facebook.com",
|
||||
"label": "Link label (translated)",
|
||||
"type": "link",
|
||||
},
|
||||
Object {
|
||||
"id": "doc1",
|
||||
"type": "ref",
|
||||
},
|
||||
],
|
||||
"label": "Getting started (translated)",
|
||||
"type": "category",
|
||||
},
|
||||
Object {
|
||||
"id": "doc3",
|
||||
"type": "doc",
|
||||
},
|
||||
],
|
||||
"otherSidebar": Array [
|
||||
Object {
|
||||
"id": "doc4",
|
||||
"type": "doc",
|
||||
},
|
||||
Object {
|
||||
"id": "doc5",
|
||||
"type": "doc",
|
||||
},
|
||||
],
|
||||
},
|
||||
"versionLabel": "2.0.0 label (translated)",
|
||||
"versionName": "2.0.0",
|
||||
"versionPath": "/docs/",
|
||||
},
|
||||
Object {
|
||||
"docs": Array [
|
||||
Object {
|
||||
"description": "doc1 description",
|
||||
"editUrl": "any",
|
||||
"id": "doc1",
|
||||
"isDocsHomePage": false,
|
||||
"lastUpdatedAt": 0,
|
||||
"lastUpdatedBy": "any",
|
||||
"next": undefined,
|
||||
"permalink": "any",
|
||||
"previous": undefined,
|
||||
"sidebar_label": "doc1 title",
|
||||
"slug": "any",
|
||||
"source": "any",
|
||||
"title": "doc1 title",
|
||||
"unversionedId": "any",
|
||||
"version": "any",
|
||||
},
|
||||
Object {
|
||||
"description": "doc2 description",
|
||||
"editUrl": "any",
|
||||
"id": "doc2",
|
||||
"isDocsHomePage": false,
|
||||
"lastUpdatedAt": 0,
|
||||
"lastUpdatedBy": "any",
|
||||
"next": undefined,
|
||||
"permalink": "any",
|
||||
"previous": undefined,
|
||||
"sidebar_label": "doc2 title",
|
||||
"slug": "any",
|
||||
"source": "any",
|
||||
"title": "doc2 title",
|
||||
"unversionedId": "any",
|
||||
"version": "any",
|
||||
},
|
||||
Object {
|
||||
"description": "doc3 description",
|
||||
"editUrl": "any",
|
||||
"id": "doc3",
|
||||
"isDocsHomePage": false,
|
||||
"lastUpdatedAt": 0,
|
||||
"lastUpdatedBy": "any",
|
||||
"next": undefined,
|
||||
"permalink": "any",
|
||||
"previous": undefined,
|
||||
"sidebar_label": "doc3 title",
|
||||
"slug": "any",
|
||||
"source": "any",
|
||||
"title": "doc3 title",
|
||||
"unversionedId": "any",
|
||||
"version": "any",
|
||||
},
|
||||
Object {
|
||||
"description": "doc4 description",
|
||||
"editUrl": "any",
|
||||
"id": "doc4",
|
||||
"isDocsHomePage": false,
|
||||
"lastUpdatedAt": 0,
|
||||
"lastUpdatedBy": "any",
|
||||
"next": undefined,
|
||||
"permalink": "any",
|
||||
"previous": undefined,
|
||||
"sidebar_label": "doc4 title",
|
||||
"slug": "any",
|
||||
"source": "any",
|
||||
"title": "doc4 title",
|
||||
"unversionedId": "any",
|
||||
"version": "any",
|
||||
},
|
||||
Object {
|
||||
"description": "doc5 description",
|
||||
"editUrl": "any",
|
||||
"id": "doc5",
|
||||
"isDocsHomePage": false,
|
||||
"lastUpdatedAt": 0,
|
||||
"lastUpdatedBy": "any",
|
||||
"next": undefined,
|
||||
"permalink": "any",
|
||||
"previous": undefined,
|
||||
"sidebar_label": "doc5 title",
|
||||
"slug": "any",
|
||||
"source": "any",
|
||||
"title": "doc5 title",
|
||||
"unversionedId": "any",
|
||||
"version": "any",
|
||||
},
|
||||
],
|
||||
"docsDirPath": "any",
|
||||
"docsDirPathLocalized": "any",
|
||||
"isLast": true,
|
||||
"mainDocId": "",
|
||||
"permalinkToSidebar": Object {},
|
||||
"routePriority": undefined,
|
||||
"sidebarFilePath": "any",
|
||||
"sidebars": Object {
|
||||
"docs": Array [
|
||||
Object {
|
||||
"collapsed": false,
|
||||
"items": Array [
|
||||
Object {
|
||||
"id": "doc1",
|
||||
"type": "doc",
|
||||
},
|
||||
Object {
|
||||
"id": "doc2",
|
||||
"type": "doc",
|
||||
},
|
||||
Object {
|
||||
"href": "https://facebook.com",
|
||||
"label": "Link label (translated)",
|
||||
"type": "link",
|
||||
},
|
||||
Object {
|
||||
"id": "doc1",
|
||||
"type": "ref",
|
||||
},
|
||||
],
|
||||
"label": "Getting started (translated)",
|
||||
"type": "category",
|
||||
},
|
||||
Object {
|
||||
"id": "doc3",
|
||||
"type": "doc",
|
||||
},
|
||||
],
|
||||
"otherSidebar": Array [
|
||||
Object {
|
||||
"id": "doc4",
|
||||
"type": "doc",
|
||||
},
|
||||
Object {
|
||||
"id": "doc5",
|
||||
"type": "doc",
|
||||
},
|
||||
],
|
||||
},
|
||||
"versionLabel": "1.0.0 label (translated)",
|
||||
"versionName": "1.0.0",
|
||||
"versionPath": "/docs/",
|
||||
},
|
||||
],
|
||||
}
|
||||
`;
|
|
@ -42,6 +42,7 @@ ${markdown}
|
|||
source,
|
||||
content,
|
||||
lastUpdate: {},
|
||||
filePath: source,
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -57,7 +58,7 @@ function createTestUtils({
|
|||
options: MetadataOptions;
|
||||
}) {
|
||||
async function readDoc(docFileSource: string) {
|
||||
return readDocFile(versionMetadata.docsDirPath, docFileSource, options);
|
||||
return readDocFile(versionMetadata, docFileSource, options);
|
||||
}
|
||||
function processDocFile(docFile: DocFile) {
|
||||
return processDocMetadata({
|
||||
|
@ -110,30 +111,41 @@ function createTestUtils({
|
|||
}
|
||||
|
||||
describe('simple site', () => {
|
||||
const siteDir = path.join(fixtureDir, 'simple-site');
|
||||
const context = loadContext(siteDir);
|
||||
const options = {
|
||||
id: DEFAULT_PLUGIN_ID,
|
||||
...DEFAULT_OPTIONS,
|
||||
};
|
||||
const versionsMetadata = readVersionsMetadata({
|
||||
context,
|
||||
options: {
|
||||
async function loadSite() {
|
||||
const siteDir = path.join(fixtureDir, 'simple-site');
|
||||
const context = await loadContext(siteDir);
|
||||
const options = {
|
||||
id: DEFAULT_PLUGIN_ID,
|
||||
...DEFAULT_OPTIONS,
|
||||
},
|
||||
});
|
||||
expect(versionsMetadata.length).toEqual(1);
|
||||
const [currentVersion] = versionsMetadata;
|
||||
};
|
||||
const versionsMetadata = readVersionsMetadata({
|
||||
context,
|
||||
options: {
|
||||
id: DEFAULT_PLUGIN_ID,
|
||||
...DEFAULT_OPTIONS,
|
||||
},
|
||||
});
|
||||
expect(versionsMetadata.length).toEqual(1);
|
||||
const [currentVersion] = versionsMetadata;
|
||||
|
||||
const defaultTestUtils = createTestUtils({
|
||||
siteDir,
|
||||
context,
|
||||
options,
|
||||
versionMetadata: currentVersion,
|
||||
});
|
||||
const defaultTestUtils = createTestUtils({
|
||||
siteDir,
|
||||
context,
|
||||
options,
|
||||
versionMetadata: currentVersion,
|
||||
});
|
||||
return {
|
||||
siteDir,
|
||||
context,
|
||||
options,
|
||||
versionsMetadata,
|
||||
defaultTestUtils,
|
||||
currentVersion,
|
||||
};
|
||||
}
|
||||
|
||||
test('readVersionDocs', async () => {
|
||||
const {options, currentVersion} = await loadSite();
|
||||
const docs = await readVersionDocs(currentVersion, options);
|
||||
expect(docs.map((doc) => doc.source).sort()).toEqual(
|
||||
[
|
||||
|
@ -155,6 +167,7 @@ describe('simple site', () => {
|
|||
});
|
||||
|
||||
test('normal docs', async () => {
|
||||
const {defaultTestUtils} = await loadSite();
|
||||
await defaultTestUtils.testMeta(path.join('foo', 'bar.md'), {
|
||||
version: 'current',
|
||||
id: 'foo/bar',
|
||||
|
@ -178,6 +191,8 @@ describe('simple site', () => {
|
|||
});
|
||||
|
||||
test('homePageId doc', async () => {
|
||||
const {siteDir, context, options, currentVersion} = await loadSite();
|
||||
|
||||
const testUtilsLocal = createTestUtils({
|
||||
siteDir,
|
||||
context,
|
||||
|
@ -198,6 +213,8 @@ describe('simple site', () => {
|
|||
});
|
||||
|
||||
test('homePageId doc nested', async () => {
|
||||
const {siteDir, context, options, currentVersion} = await loadSite();
|
||||
|
||||
const testUtilsLocal = createTestUtils({
|
||||
siteDir,
|
||||
context,
|
||||
|
@ -218,6 +235,8 @@ describe('simple site', () => {
|
|||
});
|
||||
|
||||
test('docs with editUrl', async () => {
|
||||
const {siteDir, context, options, currentVersion} = await loadSite();
|
||||
|
||||
const testUtilsLocal = createTestUtils({
|
||||
siteDir,
|
||||
context,
|
||||
|
@ -243,6 +262,8 @@ describe('simple site', () => {
|
|||
});
|
||||
|
||||
test('docs with custom editUrl & unrelated frontmatter', async () => {
|
||||
const {defaultTestUtils} = await loadSite();
|
||||
|
||||
await defaultTestUtils.testMeta('lorem.md', {
|
||||
version: 'current',
|
||||
id: 'lorem',
|
||||
|
@ -257,6 +278,8 @@ describe('simple site', () => {
|
|||
});
|
||||
|
||||
test('docs with last update time and author', async () => {
|
||||
const {siteDir, context, options, currentVersion} = await loadSite();
|
||||
|
||||
const testUtilsLocal = createTestUtils({
|
||||
siteDir,
|
||||
context,
|
||||
|
@ -284,6 +307,8 @@ describe('simple site', () => {
|
|||
});
|
||||
|
||||
test('docs with slugs', async () => {
|
||||
const {defaultTestUtils} = await loadSite();
|
||||
|
||||
await defaultTestUtils.testSlug(
|
||||
path.join('rootRelativeSlug.md'),
|
||||
'/docs/rootRelativeSlug',
|
||||
|
@ -319,7 +344,8 @@ describe('simple site', () => {
|
|||
);
|
||||
});
|
||||
|
||||
test('docs with invalid id', () => {
|
||||
test('docs with invalid id', async () => {
|
||||
const {defaultTestUtils} = await loadSite();
|
||||
expect(() => {
|
||||
defaultTestUtils.processDocFile(
|
||||
createFakeDocFile({
|
||||
|
@ -335,6 +361,8 @@ describe('simple site', () => {
|
|||
});
|
||||
|
||||
test('docs with slug on doc home', async () => {
|
||||
const {siteDir, context, options, currentVersion} = await loadSite();
|
||||
|
||||
const testUtilsLocal = createTestUtils({
|
||||
siteDir,
|
||||
context,
|
||||
|
@ -360,55 +388,71 @@ describe('simple site', () => {
|
|||
});
|
||||
|
||||
describe('versioned site', () => {
|
||||
const siteDir = path.join(fixtureDir, 'versioned-site');
|
||||
const context = loadContext(siteDir);
|
||||
const options = {
|
||||
id: DEFAULT_PLUGIN_ID,
|
||||
...DEFAULT_OPTIONS,
|
||||
};
|
||||
const versionsMetadata = readVersionsMetadata({
|
||||
context,
|
||||
options: {
|
||||
async function loadSite() {
|
||||
const siteDir = path.join(fixtureDir, 'versioned-site');
|
||||
const context = await loadContext(siteDir);
|
||||
const options = {
|
||||
id: DEFAULT_PLUGIN_ID,
|
||||
...DEFAULT_OPTIONS,
|
||||
},
|
||||
});
|
||||
expect(versionsMetadata.length).toEqual(4);
|
||||
const [
|
||||
currentVersion,
|
||||
version101,
|
||||
version100,
|
||||
versionWithSlugs,
|
||||
] = versionsMetadata;
|
||||
};
|
||||
const versionsMetadata = readVersionsMetadata({
|
||||
context,
|
||||
options: {
|
||||
id: DEFAULT_PLUGIN_ID,
|
||||
...DEFAULT_OPTIONS,
|
||||
},
|
||||
});
|
||||
expect(versionsMetadata.length).toEqual(4);
|
||||
const [
|
||||
currentVersion,
|
||||
version101,
|
||||
version100,
|
||||
versionWithSlugs,
|
||||
] = versionsMetadata;
|
||||
|
||||
const currentVersionTestUtils = createTestUtils({
|
||||
siteDir,
|
||||
context,
|
||||
options,
|
||||
versionMetadata: currentVersion,
|
||||
});
|
||||
const version101TestUtils = createTestUtils({
|
||||
siteDir,
|
||||
context,
|
||||
options,
|
||||
versionMetadata: version101,
|
||||
});
|
||||
const currentVersionTestUtils = createTestUtils({
|
||||
siteDir,
|
||||
context,
|
||||
options,
|
||||
versionMetadata: currentVersion,
|
||||
});
|
||||
const version101TestUtils = createTestUtils({
|
||||
siteDir,
|
||||
context,
|
||||
options,
|
||||
versionMetadata: version101,
|
||||
});
|
||||
|
||||
const version100TestUtils = createTestUtils({
|
||||
siteDir,
|
||||
context,
|
||||
options,
|
||||
versionMetadata: version100,
|
||||
});
|
||||
const version100TestUtils = createTestUtils({
|
||||
siteDir,
|
||||
context,
|
||||
options,
|
||||
versionMetadata: version100,
|
||||
});
|
||||
|
||||
const versionWithSlugsTestUtils = createTestUtils({
|
||||
siteDir,
|
||||
context,
|
||||
options,
|
||||
versionMetadata: versionWithSlugs,
|
||||
});
|
||||
const versionWithSlugsTestUtils = createTestUtils({
|
||||
siteDir,
|
||||
context,
|
||||
options,
|
||||
versionMetadata: versionWithSlugs,
|
||||
});
|
||||
|
||||
return {
|
||||
siteDir,
|
||||
context,
|
||||
options,
|
||||
versionsMetadata,
|
||||
currentVersionTestUtils,
|
||||
version101TestUtils,
|
||||
version100,
|
||||
version100TestUtils,
|
||||
versionWithSlugsTestUtils,
|
||||
};
|
||||
}
|
||||
|
||||
test('next docs', async () => {
|
||||
const {currentVersionTestUtils} = await loadSite();
|
||||
|
||||
await currentVersionTestUtils.testMeta(path.join('foo', 'bar.md'), {
|
||||
id: 'foo/bar',
|
||||
unversionedId: 'foo/bar',
|
||||
|
@ -432,6 +476,8 @@ describe('versioned site', () => {
|
|||
});
|
||||
|
||||
test('versioned docs', async () => {
|
||||
const {version101TestUtils, version100TestUtils} = await loadSite();
|
||||
|
||||
await version100TestUtils.testMeta(path.join('foo', 'bar.md'), {
|
||||
id: 'version-1.0.0/foo/bar',
|
||||
unversionedId: 'foo/bar',
|
||||
|
@ -449,8 +495,10 @@ describe('versioned site', () => {
|
|||
permalink: '/docs/1.0.0/hello',
|
||||
slug: '/hello',
|
||||
title: 'hello',
|
||||
description: 'Hello 1.0.0 !',
|
||||
description: 'Hello 1.0.0 ! (translated)',
|
||||
version: '1.0.0',
|
||||
source:
|
||||
'@site/i18n/en/docusaurus-plugin-content-docs/version-1.0.0/hello.md',
|
||||
});
|
||||
await version101TestUtils.testMeta(path.join('foo', 'bar.md'), {
|
||||
id: 'version-1.0.1/foo/bar',
|
||||
|
@ -475,6 +523,8 @@ describe('versioned site', () => {
|
|||
});
|
||||
|
||||
test('next doc slugs', async () => {
|
||||
const {currentVersionTestUtils} = await loadSite();
|
||||
|
||||
await currentVersionTestUtils.testSlug(
|
||||
path.join('slugs', 'absoluteSlug.md'),
|
||||
'/docs/next/absoluteSlug',
|
||||
|
@ -494,6 +544,8 @@ describe('versioned site', () => {
|
|||
});
|
||||
|
||||
test('versioned doc slugs', async () => {
|
||||
const {versionWithSlugsTestUtils} = await loadSite();
|
||||
|
||||
await versionWithSlugsTestUtils.testSlug(
|
||||
path.join('rootAbsoluteSlug.md'),
|
||||
'/docs/withSlugs/rootAbsoluteSlug',
|
||||
|
@ -528,4 +580,33 @@ describe('versioned site', () => {
|
|||
'/docs/withSlugs/tryToEscapeSlug',
|
||||
);
|
||||
});
|
||||
|
||||
test('translated doc with editUrl', async () => {
|
||||
const {siteDir, context, options, version100} = await loadSite();
|
||||
|
||||
const testUtilsLocal = createTestUtils({
|
||||
siteDir,
|
||||
context,
|
||||
options: {
|
||||
...options,
|
||||
editUrl: 'https://github.com/facebook/docusaurus/edit/master/website',
|
||||
},
|
||||
versionMetadata: version100,
|
||||
});
|
||||
|
||||
await testUtilsLocal.testMeta(path.join('hello.md'), {
|
||||
id: 'version-1.0.0/hello',
|
||||
unversionedId: 'hello',
|
||||
isDocsHomePage: false,
|
||||
permalink: '/docs/1.0.0/hello',
|
||||
slug: '/hello',
|
||||
title: 'hello',
|
||||
description: 'Hello 1.0.0 ! (translated)',
|
||||
version: '1.0.0',
|
||||
source:
|
||||
'@site/i18n/en/docusaurus-plugin-content-docs/version-1.0.0/hello.md',
|
||||
editUrl:
|
||||
'https://github.com/facebook/docusaurus/edit/master/website/i18n/en/docusaurus-plugin-content-docs/version-1.0.0/hello.md',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -106,7 +106,7 @@ Entries created:
|
|||
|
||||
test('site with wrong sidebar file', async () => {
|
||||
const siteDir = path.join(__dirname, '__fixtures__', 'simple-site');
|
||||
const context = loadContext(siteDir);
|
||||
const context = await loadContext(siteDir);
|
||||
const sidebarPath = path.join(siteDir, 'wrong-sidebars.json');
|
||||
const plugin = pluginContentDocs(
|
||||
context,
|
||||
|
@ -119,9 +119,9 @@ test('site with wrong sidebar file', async () => {
|
|||
|
||||
describe('empty/no docs website', () => {
|
||||
const siteDir = path.join(__dirname, '__fixtures__', 'empty-site');
|
||||
const context = loadContext(siteDir);
|
||||
|
||||
test('no files in docs folder', async () => {
|
||||
const context = await loadContext(siteDir);
|
||||
await fs.ensureDir(path.join(siteDir, 'docs'));
|
||||
const plugin = pluginContentDocs(
|
||||
context,
|
||||
|
@ -135,6 +135,7 @@ describe('empty/no docs website', () => {
|
|||
});
|
||||
|
||||
test('docs folder does not exist', async () => {
|
||||
const context = await loadContext(siteDir);
|
||||
expect(() =>
|
||||
pluginContentDocs(
|
||||
context,
|
||||
|
@ -149,20 +150,25 @@ describe('empty/no docs website', () => {
|
|||
});
|
||||
|
||||
describe('simple website', () => {
|
||||
const siteDir = path.join(__dirname, '__fixtures__', 'simple-site');
|
||||
const context = loadContext(siteDir);
|
||||
const sidebarPath = path.join(siteDir, 'sidebars.json');
|
||||
const plugin = pluginContentDocs(
|
||||
context,
|
||||
normalizePluginOptions(OptionsSchema, {
|
||||
path: 'docs',
|
||||
sidebarPath,
|
||||
homePageId: 'hello',
|
||||
}),
|
||||
);
|
||||
const pluginContentDir = path.join(context.generatedFilesDir, plugin.name);
|
||||
async function loadSite() {
|
||||
const siteDir = path.join(__dirname, '__fixtures__', 'simple-site');
|
||||
const context = await loadContext(siteDir);
|
||||
const sidebarPath = path.join(siteDir, 'sidebars.json');
|
||||
const plugin = pluginContentDocs(
|
||||
context,
|
||||
normalizePluginOptions(OptionsSchema, {
|
||||
path: 'docs',
|
||||
sidebarPath,
|
||||
homePageId: 'hello',
|
||||
}),
|
||||
);
|
||||
const pluginContentDir = path.join(context.generatedFilesDir, plugin.name);
|
||||
|
||||
test('extendCli - docsVersion', () => {
|
||||
return {siteDir, context, sidebarPath, plugin, pluginContentDir};
|
||||
}
|
||||
|
||||
test('extendCli - docsVersion', async () => {
|
||||
const {siteDir, sidebarPath, plugin} = await loadSite();
|
||||
const mock = jest
|
||||
.spyOn(cliDocs, 'cliDocsVersionCommand')
|
||||
.mockImplementation();
|
||||
|
@ -178,7 +184,9 @@ describe('simple website', () => {
|
|||
mock.mockRestore();
|
||||
});
|
||||
|
||||
test('getPathToWatch', () => {
|
||||
test('getPathToWatch', async () => {
|
||||
const {siteDir, plugin} = await loadSite();
|
||||
|
||||
const pathToWatch = plugin.getPathsToWatch!();
|
||||
const matchPattern = pathToWatch.map((filepath) =>
|
||||
posixPath(path.relative(siteDir, filepath)),
|
||||
|
@ -187,6 +195,7 @@ describe('simple website', () => {
|
|||
expect(matchPattern).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
"sidebars.json",
|
||||
"i18n/en/docusaurus-plugin-content-docs/current/**/*.{md,mdx}",
|
||||
"docs/**/*.{md,mdx}",
|
||||
]
|
||||
`);
|
||||
|
@ -203,6 +212,8 @@ describe('simple website', () => {
|
|||
});
|
||||
|
||||
test('configureWebpack', async () => {
|
||||
const {plugin} = await loadSite();
|
||||
|
||||
const config = applyConfigureWebpack(
|
||||
plugin.configureWebpack,
|
||||
{
|
||||
|
@ -219,6 +230,7 @@ describe('simple website', () => {
|
|||
});
|
||||
|
||||
test('content', async () => {
|
||||
const {siteDir, plugin, pluginContentDir} = await loadSite();
|
||||
const content = await plugin.loadContent!();
|
||||
expect(content.loadedVersions.length).toEqual(1);
|
||||
const [currentVersion] = content.loadedVersions;
|
||||
|
@ -287,22 +299,32 @@ describe('simple website', () => {
|
|||
});
|
||||
|
||||
describe('versioned website', () => {
|
||||
const siteDir = path.join(__dirname, '__fixtures__', 'versioned-site');
|
||||
const context = loadContext(siteDir);
|
||||
const sidebarPath = path.join(siteDir, 'sidebars.json');
|
||||
const routeBasePath = 'docs';
|
||||
const plugin = pluginContentDocs(
|
||||
context,
|
||||
normalizePluginOptions(OptionsSchema, {
|
||||
async function loadSite() {
|
||||
const siteDir = path.join(__dirname, '__fixtures__', 'versioned-site');
|
||||
const context = await loadContext(siteDir);
|
||||
const sidebarPath = path.join(siteDir, 'sidebars.json');
|
||||
const routeBasePath = 'docs';
|
||||
const plugin = pluginContentDocs(
|
||||
context,
|
||||
normalizePluginOptions(OptionsSchema, {
|
||||
routeBasePath,
|
||||
sidebarPath,
|
||||
homePageId: 'hello',
|
||||
}),
|
||||
);
|
||||
const pluginContentDir = path.join(context.generatedFilesDir, plugin.name);
|
||||
return {
|
||||
siteDir,
|
||||
context,
|
||||
routeBasePath,
|
||||
sidebarPath,
|
||||
homePageId: 'hello',
|
||||
}),
|
||||
);
|
||||
plugin,
|
||||
pluginContentDir,
|
||||
};
|
||||
}
|
||||
|
||||
const pluginContentDir = path.join(context.generatedFilesDir, plugin.name);
|
||||
|
||||
test('extendCli - docsVersion', () => {
|
||||
test('extendCli - docsVersion', async () => {
|
||||
const {siteDir, routeBasePath, sidebarPath, plugin} = await loadSite();
|
||||
const mock = jest
|
||||
.spyOn(cliDocs, 'cliDocsVersionCommand')
|
||||
.mockImplementation();
|
||||
|
@ -318,7 +340,8 @@ describe('versioned website', () => {
|
|||
mock.mockRestore();
|
||||
});
|
||||
|
||||
test('getPathToWatch', () => {
|
||||
test('getPathToWatch', async () => {
|
||||
const {siteDir, plugin} = await loadSite();
|
||||
const pathToWatch = plugin.getPathsToWatch!();
|
||||
const matchPattern = pathToWatch.map((filepath) =>
|
||||
posixPath(path.relative(siteDir, filepath)),
|
||||
|
@ -327,12 +350,16 @@ describe('versioned website', () => {
|
|||
expect(matchPattern).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
"sidebars.json",
|
||||
"i18n/en/docusaurus-plugin-content-docs/current/**/*.{md,mdx}",
|
||||
"docs/**/*.{md,mdx}",
|
||||
"versioned_sidebars/version-1.0.1-sidebars.json",
|
||||
"i18n/en/docusaurus-plugin-content-docs/version-1.0.1/**/*.{md,mdx}",
|
||||
"versioned_docs/version-1.0.1/**/*.{md,mdx}",
|
||||
"versioned_sidebars/version-1.0.0-sidebars.json",
|
||||
"i18n/en/docusaurus-plugin-content-docs/version-1.0.0/**/*.{md,mdx}",
|
||||
"versioned_docs/version-1.0.0/**/*.{md,mdx}",
|
||||
"versioned_sidebars/version-withSlugs-sidebars.json",
|
||||
"i18n/en/docusaurus-plugin-content-docs/version-withSlugs/**/*.{md,mdx}",
|
||||
"versioned_docs/version-withSlugs/**/*.{md,mdx}",
|
||||
]
|
||||
`);
|
||||
|
@ -369,6 +396,7 @@ describe('versioned website', () => {
|
|||
});
|
||||
|
||||
test('content', async () => {
|
||||
const {siteDir, plugin, pluginContentDir} = await loadSite();
|
||||
const content = await plugin.loadContent!();
|
||||
expect(content.loadedVersions.length).toEqual(4);
|
||||
const [
|
||||
|
@ -499,23 +527,41 @@ describe('versioned website', () => {
|
|||
});
|
||||
|
||||
describe('versioned website (community)', () => {
|
||||
const siteDir = path.join(__dirname, '__fixtures__', 'versioned-site');
|
||||
const context = loadContext(siteDir);
|
||||
const sidebarPath = path.join(siteDir, 'community_sidebars.json');
|
||||
const routeBasePath = 'community';
|
||||
const pluginId = 'community';
|
||||
const plugin = pluginContentDocs(
|
||||
context,
|
||||
normalizePluginOptions(OptionsSchema, {
|
||||
id: 'community',
|
||||
path: 'community',
|
||||
async function loadSite() {
|
||||
const siteDir = path.join(__dirname, '__fixtures__', 'versioned-site');
|
||||
const context = await loadContext(siteDir);
|
||||
const sidebarPath = path.join(siteDir, 'community_sidebars.json');
|
||||
const routeBasePath = 'community';
|
||||
const pluginId = 'community';
|
||||
const plugin = pluginContentDocs(
|
||||
context,
|
||||
normalizePluginOptions(OptionsSchema, {
|
||||
id: 'community',
|
||||
path: 'community',
|
||||
routeBasePath,
|
||||
sidebarPath,
|
||||
}),
|
||||
);
|
||||
const pluginContentDir = path.join(context.generatedFilesDir, plugin.name);
|
||||
return {
|
||||
siteDir,
|
||||
context,
|
||||
routeBasePath,
|
||||
sidebarPath,
|
||||
}),
|
||||
);
|
||||
const pluginContentDir = path.join(context.generatedFilesDir, plugin.name);
|
||||
pluginId,
|
||||
plugin,
|
||||
pluginContentDir,
|
||||
};
|
||||
}
|
||||
|
||||
test('extendCli - docsVersion', () => {
|
||||
test('extendCli - docsVersion', async () => {
|
||||
const {
|
||||
siteDir,
|
||||
routeBasePath,
|
||||
sidebarPath,
|
||||
pluginId,
|
||||
plugin,
|
||||
} = await loadSite();
|
||||
const mock = jest
|
||||
.spyOn(cliDocs, 'cliDocsVersionCommand')
|
||||
.mockImplementation();
|
||||
|
@ -531,7 +577,8 @@ describe('versioned website (community)', () => {
|
|||
mock.mockRestore();
|
||||
});
|
||||
|
||||
test('getPathToWatch', () => {
|
||||
test('getPathToWatch', async () => {
|
||||
const {siteDir, plugin} = await loadSite();
|
||||
const pathToWatch = plugin.getPathsToWatch!();
|
||||
const matchPattern = pathToWatch.map((filepath) =>
|
||||
posixPath(path.relative(siteDir, filepath)),
|
||||
|
@ -540,8 +587,10 @@ describe('versioned website (community)', () => {
|
|||
expect(matchPattern).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
"community_sidebars.json",
|
||||
"i18n/en/docusaurus-plugin-content-docs-community/current/**/*.{md,mdx}",
|
||||
"community/**/*.{md,mdx}",
|
||||
"community_versioned_sidebars/version-1.0.0-sidebars.json",
|
||||
"i18n/en/docusaurus-plugin-content-docs-community/version-1.0.0/**/*.{md,mdx}",
|
||||
"community_versioned_docs/version-1.0.0/**/*.{md,mdx}",
|
||||
]
|
||||
`);
|
||||
|
@ -568,6 +617,7 @@ describe('versioned website (community)', () => {
|
|||
});
|
||||
|
||||
test('content', async () => {
|
||||
const {siteDir, plugin, pluginContentDir} = await loadSite();
|
||||
const content = await plugin.loadContent!();
|
||||
expect(content.loadedVersions.length).toEqual(2);
|
||||
const [currentVersion, version100] = content.loadedVersions;
|
||||
|
@ -579,13 +629,17 @@ describe('versioned website (community)', () => {
|
|||
isDocsHomePage: false,
|
||||
permalink: '/community/next/team',
|
||||
slug: '/team',
|
||||
/*
|
||||
source: path.join(
|
||||
'@site',
|
||||
path.relative(siteDir, currentVersion.docsDirPath),
|
||||
'team.md',
|
||||
),
|
||||
title: 'team',
|
||||
description: 'Team current version',
|
||||
*/
|
||||
source:
|
||||
'@site/i18n/en/docusaurus-plugin-content-docs-community/current/team.md',
|
||||
title: 'Team title translated',
|
||||
description: 'Team current version (translated)',
|
||||
version: 'current',
|
||||
sidebar: 'community',
|
||||
});
|
||||
|
|
|
@ -11,6 +11,9 @@ import {
|
|||
collectSidebarDocItems,
|
||||
collectSidebarsDocIds,
|
||||
createSidebarsUtils,
|
||||
collectSidebarCategories,
|
||||
collectSidebarLinks,
|
||||
transformSidebarItems,
|
||||
} from '../sidebars';
|
||||
import {Sidebar, Sidebars} from '../types';
|
||||
|
||||
|
@ -163,7 +166,7 @@ describe('loadSidebars', () => {
|
|||
});
|
||||
|
||||
describe('collectSidebarDocItems', () => {
|
||||
test('can collect recursively', async () => {
|
||||
test('can collect docs', async () => {
|
||||
const sidebar: Sidebar = [
|
||||
{
|
||||
type: 'category',
|
||||
|
@ -213,7 +216,96 @@ describe('collectSidebarDocItems', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('collectSidebarsDocItems', () => {
|
||||
describe('collectSidebarCategories', () => {
|
||||
test('can collect categories', async () => {
|
||||
const sidebar: Sidebar = [
|
||||
{
|
||||
type: 'category',
|
||||
collapsed: false,
|
||||
label: 'Category1',
|
||||
items: [
|
||||
{
|
||||
type: 'category',
|
||||
collapsed: false,
|
||||
label: 'Subcategory 1',
|
||||
items: [{type: 'doc', id: 'doc1'}],
|
||||
},
|
||||
{
|
||||
type: 'category',
|
||||
collapsed: false,
|
||||
label: 'Subcategory 2',
|
||||
items: [
|
||||
{type: 'doc', id: 'doc2'},
|
||||
{
|
||||
type: 'category',
|
||||
collapsed: false,
|
||||
label: 'Sub sub category 1',
|
||||
items: [{type: 'doc', id: 'doc3'}],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'category',
|
||||
collapsed: false,
|
||||
label: 'Category2',
|
||||
items: [
|
||||
{type: 'doc', id: 'doc4'},
|
||||
{type: 'doc', id: 'doc5'},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
expect(
|
||||
collectSidebarCategories(sidebar).map((category) => category.label),
|
||||
).toEqual([
|
||||
'Category1',
|
||||
'Subcategory 1',
|
||||
'Subcategory 2',
|
||||
'Sub sub category 1',
|
||||
'Category2',
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('collectSidebarLinks', () => {
|
||||
test('can collect links', async () => {
|
||||
const sidebar: Sidebar = [
|
||||
{
|
||||
type: 'category',
|
||||
collapsed: false,
|
||||
label: 'Category1',
|
||||
items: [
|
||||
{
|
||||
type: 'link',
|
||||
href: 'https://google.com',
|
||||
label: 'Google',
|
||||
},
|
||||
{
|
||||
type: 'category',
|
||||
collapsed: false,
|
||||
label: 'Subcategory 2',
|
||||
items: [
|
||||
{
|
||||
type: 'link',
|
||||
href: 'https://facebook.com',
|
||||
label: 'Facebook',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
expect(collectSidebarLinks(sidebar).map((link) => link.href)).toEqual([
|
||||
'https://google.com',
|
||||
'https://facebook.com',
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('collectSidebarsDocIds', () => {
|
||||
test('can collect sidebars doc items', async () => {
|
||||
const sidebar1: Sidebar = [
|
||||
{
|
||||
|
@ -256,6 +348,95 @@ describe('collectSidebarsDocItems', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('transformSidebarItems', () => {
|
||||
test('can transform sidebar items', async () => {
|
||||
const sidebar: Sidebar = [
|
||||
{
|
||||
type: 'category',
|
||||
collapsed: false,
|
||||
label: 'Category1',
|
||||
items: [
|
||||
{
|
||||
type: 'category',
|
||||
collapsed: false,
|
||||
label: 'Subcategory 1',
|
||||
items: [{type: 'doc', id: 'doc1'}],
|
||||
},
|
||||
{
|
||||
type: 'category',
|
||||
collapsed: false,
|
||||
label: 'Subcategory 2',
|
||||
items: [
|
||||
{type: 'doc', id: 'doc2'},
|
||||
{
|
||||
type: 'category',
|
||||
collapsed: false,
|
||||
label: 'Sub sub category 1',
|
||||
items: [{type: 'doc', id: 'doc3'}],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'category',
|
||||
collapsed: false,
|
||||
label: 'Category2',
|
||||
items: [
|
||||
{type: 'doc', id: 'doc4'},
|
||||
{type: 'doc', id: 'doc5'},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
expect(
|
||||
transformSidebarItems(sidebar, (item) => {
|
||||
if (item.type === 'category') {
|
||||
return {...item, label: `MODIFIED LABEL: ${item.label}`};
|
||||
}
|
||||
return item;
|
||||
}),
|
||||
).toEqual([
|
||||
{
|
||||
type: 'category',
|
||||
collapsed: false,
|
||||
label: 'MODIFIED LABEL: Category1',
|
||||
items: [
|
||||
{
|
||||
type: 'category',
|
||||
collapsed: false,
|
||||
label: 'MODIFIED LABEL: Subcategory 1',
|
||||
items: [{type: 'doc', id: 'doc1'}],
|
||||
},
|
||||
{
|
||||
type: 'category',
|
||||
collapsed: false,
|
||||
label: 'MODIFIED LABEL: Subcategory 2',
|
||||
items: [
|
||||
{type: 'doc', id: 'doc2'},
|
||||
{
|
||||
type: 'category',
|
||||
collapsed: false,
|
||||
label: 'MODIFIED LABEL: Sub sub category 1',
|
||||
items: [{type: 'doc', id: 'doc3'}],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'category',
|
||||
collapsed: false,
|
||||
label: 'MODIFIED LABEL: Category2',
|
||||
items: [
|
||||
{type: 'doc', id: 'doc4'},
|
||||
{type: 'doc', id: 'doc5'},
|
||||
],
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('createSidebarsUtils', () => {
|
||||
const sidebar1: Sidebar = [
|
||||
{
|
||||
|
|
|
@ -0,0 +1,159 @@
|
|||
/**
|
||||
* 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 {LoadedContent, DocMetadata, LoadedVersion} from '../types';
|
||||
import {CURRENT_VERSION_NAME} from '../constants';
|
||||
import {
|
||||
getLoadedContentTranslationFiles,
|
||||
translateLoadedContent,
|
||||
} from '../translations';
|
||||
import {updateTranslationFileMessages} from '@docusaurus/utils';
|
||||
|
||||
function createSampleDoc(doc: Pick<DocMetadata, 'id'>): DocMetadata {
|
||||
return {
|
||||
editUrl: 'any',
|
||||
isDocsHomePage: false,
|
||||
lastUpdatedAt: 0,
|
||||
lastUpdatedBy: 'any',
|
||||
next: undefined,
|
||||
previous: undefined,
|
||||
permalink: 'any',
|
||||
slug: 'any',
|
||||
source: 'any',
|
||||
unversionedId: 'any',
|
||||
version: 'any',
|
||||
title: `${doc.id} title`,
|
||||
sidebar_label: `${doc.id} title`,
|
||||
description: `${doc.id} description`,
|
||||
...doc,
|
||||
};
|
||||
}
|
||||
|
||||
function createSampleVersion(
|
||||
version: Pick<LoadedVersion, 'versionName'>,
|
||||
): LoadedVersion {
|
||||
return {
|
||||
versionLabel: `${version.versionName} label`,
|
||||
versionPath: '/docs/',
|
||||
mainDocId: '',
|
||||
permalinkToSidebar: {},
|
||||
routePriority: undefined,
|
||||
sidebarFilePath: 'any',
|
||||
isLast: true,
|
||||
docsDirPath: 'any',
|
||||
docsDirPathLocalized: 'any',
|
||||
docs: [
|
||||
createSampleDoc({
|
||||
id: 'doc1',
|
||||
}),
|
||||
createSampleDoc({
|
||||
id: 'doc2',
|
||||
}),
|
||||
createSampleDoc({
|
||||
id: 'doc3',
|
||||
}),
|
||||
createSampleDoc({
|
||||
id: 'doc4',
|
||||
}),
|
||||
createSampleDoc({
|
||||
id: 'doc5',
|
||||
}),
|
||||
],
|
||||
sidebars: {
|
||||
docs: [
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Getting started',
|
||||
collapsed: false,
|
||||
items: [
|
||||
{
|
||||
type: 'doc',
|
||||
id: 'doc1',
|
||||
},
|
||||
{
|
||||
type: 'doc',
|
||||
id: 'doc2',
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
label: 'Link label',
|
||||
href: 'https://facebook.com',
|
||||
},
|
||||
{
|
||||
type: 'ref',
|
||||
id: 'doc1',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'doc',
|
||||
id: 'doc3',
|
||||
},
|
||||
],
|
||||
otherSidebar: [
|
||||
{
|
||||
type: 'doc',
|
||||
id: 'doc4',
|
||||
},
|
||||
{
|
||||
type: 'doc',
|
||||
id: 'doc5',
|
||||
},
|
||||
],
|
||||
},
|
||||
...version,
|
||||
};
|
||||
}
|
||||
|
||||
const SampleLoadedContent: LoadedContent = {
|
||||
loadedVersions: [
|
||||
createSampleVersion({
|
||||
versionName: CURRENT_VERSION_NAME,
|
||||
}),
|
||||
createSampleVersion({
|
||||
versionName: '2.0.0',
|
||||
}),
|
||||
createSampleVersion({
|
||||
versionName: '1.0.0',
|
||||
}),
|
||||
],
|
||||
};
|
||||
|
||||
function getSampleTranslationFiles() {
|
||||
return getLoadedContentTranslationFiles(SampleLoadedContent);
|
||||
}
|
||||
function getSampleTranslationFilesTranslated() {
|
||||
const translationFiles = getSampleTranslationFiles();
|
||||
return translationFiles.map((translationFile) =>
|
||||
updateTranslationFileMessages(
|
||||
translationFile,
|
||||
(message) => `${message} (translated)`,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
describe('getLoadedContentTranslationFiles', () => {
|
||||
test('should return translation files matching snapshot', async () => {
|
||||
expect(getSampleTranslationFiles()).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe('translateLoadedContent', () => {
|
||||
test('should not translate anything if translation files are untranslated', () => {
|
||||
const translationFiles = getSampleTranslationFiles();
|
||||
expect(
|
||||
translateLoadedContent(SampleLoadedContent, translationFiles),
|
||||
).toEqual(SampleLoadedContent);
|
||||
});
|
||||
|
||||
test('should return translated loaded content matching snapshot', () => {
|
||||
const translationFiles = getSampleTranslationFilesTranslated();
|
||||
expect(
|
||||
translateLoadedContent(SampleLoadedContent, translationFiles),
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
});
|
|
@ -14,7 +14,14 @@ import {
|
|||
} from '../versions';
|
||||
import {DEFAULT_OPTIONS} from '../options';
|
||||
import {DEFAULT_PLUGIN_ID} from '@docusaurus/core/lib/constants';
|
||||
import {VersionMetadata} from '../types';
|
||||
import {PluginOptions, VersionMetadata} from '../types';
|
||||
import {I18n} from '@docusaurus/types';
|
||||
|
||||
const DefaultI18N: I18n = {
|
||||
currentLocale: 'en',
|
||||
locales: ['en'],
|
||||
defaultLocale: 'en',
|
||||
};
|
||||
|
||||
describe('version paths', () => {
|
||||
test('getVersionedDocsDirPath', () => {
|
||||
|
@ -46,29 +53,39 @@ describe('version paths', () => {
|
|||
});
|
||||
|
||||
describe('simple site', () => {
|
||||
const simpleSiteDir = path.resolve(
|
||||
path.join(__dirname, '__fixtures__', 'simple-site'),
|
||||
);
|
||||
const defaultOptions = {
|
||||
id: DEFAULT_PLUGIN_ID,
|
||||
...DEFAULT_OPTIONS,
|
||||
};
|
||||
const defaultContext = {
|
||||
siteDir: simpleSiteDir,
|
||||
baseUrl: '/',
|
||||
};
|
||||
async function loadSite() {
|
||||
const simpleSiteDir = path.resolve(
|
||||
path.join(__dirname, '__fixtures__', 'simple-site'),
|
||||
);
|
||||
const defaultOptions: PluginOptions = {
|
||||
id: DEFAULT_PLUGIN_ID,
|
||||
...DEFAULT_OPTIONS,
|
||||
};
|
||||
const defaultContext = {
|
||||
siteDir: simpleSiteDir,
|
||||
baseUrl: '/',
|
||||
i18n: DefaultI18N,
|
||||
};
|
||||
|
||||
const vCurrent: VersionMetadata = {
|
||||
docsDirPath: path.join(simpleSiteDir, 'docs'),
|
||||
isLast: true,
|
||||
routePriority: -1,
|
||||
sidebarFilePath: path.join(simpleSiteDir, 'sidebars.json'),
|
||||
versionLabel: 'Next',
|
||||
versionName: 'current',
|
||||
versionPath: '/docs',
|
||||
};
|
||||
const vCurrent: VersionMetadata = {
|
||||
docsDirPath: path.join(simpleSiteDir, 'docs'),
|
||||
docsDirPathLocalized: path.join(
|
||||
simpleSiteDir,
|
||||
'i18n/en/docusaurus-plugin-content-docs/current',
|
||||
),
|
||||
isLast: true,
|
||||
routePriority: -1,
|
||||
sidebarFilePath: path.join(simpleSiteDir, 'sidebars.json'),
|
||||
versionLabel: 'Next',
|
||||
versionName: 'current',
|
||||
versionPath: '/docs',
|
||||
};
|
||||
return {simpleSiteDir, defaultOptions, defaultContext, vCurrent};
|
||||
}
|
||||
|
||||
test('readVersionsMetadata simple site', async () => {
|
||||
const {defaultOptions, defaultContext, vCurrent} = await loadSite();
|
||||
|
||||
test('readVersionsMetadata simple site', () => {
|
||||
const versionsMetadata = readVersionsMetadata({
|
||||
options: defaultOptions,
|
||||
context: defaultContext,
|
||||
|
@ -77,7 +94,9 @@ describe('simple site', () => {
|
|||
expect(versionsMetadata).toEqual([vCurrent]);
|
||||
});
|
||||
|
||||
test('readVersionsMetadata simple site with base url', () => {
|
||||
test('readVersionsMetadata simple site with base url', async () => {
|
||||
const {defaultOptions, defaultContext, vCurrent} = await loadSite();
|
||||
|
||||
const versionsMetadata = readVersionsMetadata({
|
||||
options: defaultOptions,
|
||||
context: {
|
||||
|
@ -94,7 +113,9 @@ describe('simple site', () => {
|
|||
]);
|
||||
});
|
||||
|
||||
test('readVersionsMetadata simple site with current version config', () => {
|
||||
test('readVersionsMetadata simple site with current version config', async () => {
|
||||
const {defaultOptions, defaultContext, vCurrent} = await loadSite();
|
||||
|
||||
const versionsMetadata = readVersionsMetadata({
|
||||
options: {
|
||||
...defaultOptions,
|
||||
|
@ -121,7 +142,9 @@ describe('simple site', () => {
|
|||
]);
|
||||
});
|
||||
|
||||
test('readVersionsMetadata simple site with unknown lastVersion should throw', () => {
|
||||
test('readVersionsMetadata simple site with unknown lastVersion should throw', async () => {
|
||||
const {defaultOptions, defaultContext} = await loadSite();
|
||||
|
||||
expect(() =>
|
||||
readVersionsMetadata({
|
||||
options: {...defaultOptions, lastVersion: 'unknownVersionName'},
|
||||
|
@ -132,7 +155,9 @@ describe('simple site', () => {
|
|||
);
|
||||
});
|
||||
|
||||
test('readVersionsMetadata simple site with unknown version configurations should throw', () => {
|
||||
test('readVersionsMetadata simple site with unknown version configurations should throw', async () => {
|
||||
const {defaultOptions, defaultContext} = await loadSite();
|
||||
|
||||
expect(() =>
|
||||
readVersionsMetadata({
|
||||
options: {
|
||||
|
@ -150,7 +175,9 @@ describe('simple site', () => {
|
|||
);
|
||||
});
|
||||
|
||||
test('readVersionsMetadata simple site with disableVersioning while single version should throw', () => {
|
||||
test('readVersionsMetadata simple site with disableVersioning while single version should throw', async () => {
|
||||
const {defaultOptions, defaultContext} = await loadSite();
|
||||
|
||||
expect(() =>
|
||||
readVersionsMetadata({
|
||||
options: {...defaultOptions, disableVersioning: true},
|
||||
|
@ -161,7 +188,9 @@ describe('simple site', () => {
|
|||
);
|
||||
});
|
||||
|
||||
test('readVersionsMetadata simple site without including current version should throw', () => {
|
||||
test('readVersionsMetadata simple site without including current version should throw', async () => {
|
||||
const {defaultOptions, defaultContext} = await loadSite();
|
||||
|
||||
expect(() =>
|
||||
readVersionsMetadata({
|
||||
options: {...defaultOptions, includeCurrentVersion: false},
|
||||
|
@ -174,71 +203,109 @@ describe('simple site', () => {
|
|||
});
|
||||
|
||||
describe('versioned site, pluginId=default', () => {
|
||||
const versionedSiteDir = path.resolve(
|
||||
path.join(__dirname, '__fixtures__', 'versioned-site'),
|
||||
);
|
||||
const defaultOptions = {
|
||||
id: DEFAULT_PLUGIN_ID,
|
||||
...DEFAULT_OPTIONS,
|
||||
};
|
||||
const defaultContext = {
|
||||
siteDir: versionedSiteDir,
|
||||
baseUrl: '/',
|
||||
};
|
||||
async function loadSite() {
|
||||
const versionedSiteDir = path.resolve(
|
||||
path.join(__dirname, '__fixtures__', 'versioned-site'),
|
||||
);
|
||||
const defaultOptions: PluginOptions = {
|
||||
id: DEFAULT_PLUGIN_ID,
|
||||
...DEFAULT_OPTIONS,
|
||||
};
|
||||
const defaultContext = {
|
||||
siteDir: versionedSiteDir,
|
||||
baseUrl: '/',
|
||||
i18n: DefaultI18N,
|
||||
};
|
||||
|
||||
const vCurrent: VersionMetadata = {
|
||||
docsDirPath: path.join(versionedSiteDir, 'docs'),
|
||||
isLast: false,
|
||||
routePriority: undefined,
|
||||
sidebarFilePath: path.join(versionedSiteDir, 'sidebars.json'),
|
||||
versionLabel: 'Next',
|
||||
versionName: 'current',
|
||||
versionPath: '/docs/next',
|
||||
};
|
||||
const vCurrent: VersionMetadata = {
|
||||
docsDirPath: path.join(versionedSiteDir, 'docs'),
|
||||
docsDirPathLocalized: path.join(
|
||||
versionedSiteDir,
|
||||
'i18n/en/docusaurus-plugin-content-docs/current',
|
||||
),
|
||||
isLast: false,
|
||||
routePriority: undefined,
|
||||
sidebarFilePath: path.join(versionedSiteDir, 'sidebars.json'),
|
||||
versionLabel: 'Next',
|
||||
versionName: 'current',
|
||||
versionPath: '/docs/next',
|
||||
};
|
||||
|
||||
const v101: VersionMetadata = {
|
||||
docsDirPath: path.join(versionedSiteDir, 'versioned_docs/version-1.0.1'),
|
||||
isLast: true,
|
||||
routePriority: -1,
|
||||
sidebarFilePath: path.join(
|
||||
const v101: VersionMetadata = {
|
||||
docsDirPath: path.join(versionedSiteDir, 'versioned_docs/version-1.0.1'),
|
||||
docsDirPathLocalized: path.join(
|
||||
versionedSiteDir,
|
||||
'i18n/en/docusaurus-plugin-content-docs/version-1.0.1',
|
||||
),
|
||||
isLast: true,
|
||||
routePriority: -1,
|
||||
sidebarFilePath: path.join(
|
||||
versionedSiteDir,
|
||||
'versioned_sidebars/version-1.0.1-sidebars.json',
|
||||
),
|
||||
versionLabel: '1.0.1',
|
||||
versionName: '1.0.1',
|
||||
versionPath: '/docs',
|
||||
};
|
||||
|
||||
const v100: VersionMetadata = {
|
||||
docsDirPath: path.join(versionedSiteDir, 'versioned_docs/version-1.0.0'),
|
||||
docsDirPathLocalized: path.join(
|
||||
versionedSiteDir,
|
||||
'i18n/en/docusaurus-plugin-content-docs/version-1.0.0',
|
||||
),
|
||||
isLast: false,
|
||||
routePriority: undefined,
|
||||
sidebarFilePath: path.join(
|
||||
versionedSiteDir,
|
||||
'versioned_sidebars/version-1.0.0-sidebars.json',
|
||||
),
|
||||
versionLabel: '1.0.0',
|
||||
versionName: '1.0.0',
|
||||
versionPath: '/docs/1.0.0',
|
||||
};
|
||||
|
||||
const vwithSlugs: VersionMetadata = {
|
||||
docsDirPath: path.join(
|
||||
versionedSiteDir,
|
||||
'versioned_docs/version-withSlugs',
|
||||
),
|
||||
docsDirPathLocalized: path.join(
|
||||
versionedSiteDir,
|
||||
'i18n/en/docusaurus-plugin-content-docs/version-withSlugs',
|
||||
),
|
||||
isLast: false,
|
||||
routePriority: undefined,
|
||||
sidebarFilePath: path.join(
|
||||
versionedSiteDir,
|
||||
'versioned_sidebars/version-withSlugs-sidebars.json',
|
||||
),
|
||||
versionLabel: 'withSlugs',
|
||||
versionName: 'withSlugs',
|
||||
versionPath: '/docs/withSlugs',
|
||||
};
|
||||
|
||||
return {
|
||||
versionedSiteDir,
|
||||
'versioned_sidebars/version-1.0.1-sidebars.json',
|
||||
),
|
||||
versionLabel: '1.0.1',
|
||||
versionName: '1.0.1',
|
||||
versionPath: '/docs',
|
||||
};
|
||||
defaultOptions,
|
||||
defaultContext,
|
||||
vCurrent,
|
||||
v101,
|
||||
v100,
|
||||
vwithSlugs,
|
||||
};
|
||||
}
|
||||
|
||||
const v100: VersionMetadata = {
|
||||
docsDirPath: path.join(versionedSiteDir, 'versioned_docs/version-1.0.0'),
|
||||
isLast: false,
|
||||
routePriority: undefined,
|
||||
sidebarFilePath: path.join(
|
||||
versionedSiteDir,
|
||||
'versioned_sidebars/version-1.0.0-sidebars.json',
|
||||
),
|
||||
versionLabel: '1.0.0',
|
||||
versionName: '1.0.0',
|
||||
versionPath: '/docs/1.0.0',
|
||||
};
|
||||
test('readVersionsMetadata versioned site', async () => {
|
||||
const {
|
||||
defaultOptions,
|
||||
defaultContext,
|
||||
vCurrent,
|
||||
v101,
|
||||
v100,
|
||||
vwithSlugs,
|
||||
} = await loadSite();
|
||||
|
||||
const vwithSlugs: VersionMetadata = {
|
||||
docsDirPath: path.join(
|
||||
versionedSiteDir,
|
||||
'versioned_docs/version-withSlugs',
|
||||
),
|
||||
isLast: false,
|
||||
routePriority: undefined,
|
||||
sidebarFilePath: path.join(
|
||||
versionedSiteDir,
|
||||
'versioned_sidebars/version-withSlugs-sidebars.json',
|
||||
),
|
||||
versionLabel: 'withSlugs',
|
||||
versionName: 'withSlugs',
|
||||
versionPath: '/docs/withSlugs',
|
||||
};
|
||||
|
||||
test('readVersionsMetadata versioned site', () => {
|
||||
const versionsMetadata = readVersionsMetadata({
|
||||
options: defaultOptions,
|
||||
context: defaultContext,
|
||||
|
@ -247,7 +314,15 @@ describe('versioned site, pluginId=default', () => {
|
|||
expect(versionsMetadata).toEqual([vCurrent, v101, v100, vwithSlugs]);
|
||||
});
|
||||
|
||||
test('readVersionsMetadata versioned site with includeCurrentVersion=false', () => {
|
||||
test('readVersionsMetadata versioned site with includeCurrentVersion=false', async () => {
|
||||
const {
|
||||
defaultOptions,
|
||||
defaultContext,
|
||||
v101,
|
||||
v100,
|
||||
vwithSlugs,
|
||||
} = await loadSite();
|
||||
|
||||
const versionsMetadata = readVersionsMetadata({
|
||||
options: {...defaultOptions, includeCurrentVersion: false},
|
||||
context: defaultContext,
|
||||
|
@ -261,7 +336,16 @@ describe('versioned site, pluginId=default', () => {
|
|||
]);
|
||||
});
|
||||
|
||||
test('readVersionsMetadata versioned site with version options', () => {
|
||||
test('readVersionsMetadata versioned site with version options', async () => {
|
||||
const {
|
||||
defaultOptions,
|
||||
defaultContext,
|
||||
vCurrent,
|
||||
v101,
|
||||
v100,
|
||||
vwithSlugs,
|
||||
} = await loadSite();
|
||||
|
||||
const versionsMetadata = readVersionsMetadata({
|
||||
options: {
|
||||
...defaultOptions,
|
||||
|
@ -297,7 +381,9 @@ describe('versioned site, pluginId=default', () => {
|
|||
]);
|
||||
});
|
||||
|
||||
test('readVersionsMetadata versioned site with onlyIncludeVersions option', () => {
|
||||
test('readVersionsMetadata versioned site with onlyIncludeVersions option', async () => {
|
||||
const {defaultOptions, defaultContext, v101, vwithSlugs} = await loadSite();
|
||||
|
||||
const versionsMetadata = readVersionsMetadata({
|
||||
options: {
|
||||
...defaultOptions,
|
||||
|
@ -310,7 +396,9 @@ describe('versioned site, pluginId=default', () => {
|
|||
expect(versionsMetadata).toEqual([v101, vwithSlugs]);
|
||||
});
|
||||
|
||||
test('readVersionsMetadata versioned site with disableVersioning', () => {
|
||||
test('readVersionsMetadata versioned site with disableVersioning', async () => {
|
||||
const {defaultOptions, defaultContext, vCurrent} = await loadSite();
|
||||
|
||||
const versionsMetadata = readVersionsMetadata({
|
||||
options: {...defaultOptions, disableVersioning: true},
|
||||
context: defaultContext,
|
||||
|
@ -321,7 +409,9 @@ describe('versioned site, pluginId=default', () => {
|
|||
]);
|
||||
});
|
||||
|
||||
test('readVersionsMetadata versioned site with all versions disabled', () => {
|
||||
test('readVersionsMetadata versioned site with all versions disabled', async () => {
|
||||
const {defaultOptions, defaultContext} = await loadSite();
|
||||
|
||||
expect(() =>
|
||||
readVersionsMetadata({
|
||||
options: {
|
||||
|
@ -336,7 +426,9 @@ describe('versioned site, pluginId=default', () => {
|
|||
);
|
||||
});
|
||||
|
||||
test('readVersionsMetadata versioned site with empty onlyIncludeVersions', () => {
|
||||
test('readVersionsMetadata versioned site with empty onlyIncludeVersions', async () => {
|
||||
const {defaultOptions, defaultContext} = await loadSite();
|
||||
|
||||
expect(() =>
|
||||
readVersionsMetadata({
|
||||
options: {
|
||||
|
@ -350,7 +442,9 @@ describe('versioned site, pluginId=default', () => {
|
|||
);
|
||||
});
|
||||
|
||||
test('readVersionsMetadata versioned site with unknown versions in onlyIncludeVersions', () => {
|
||||
test('readVersionsMetadata versioned site with unknown versions in onlyIncludeVersions', async () => {
|
||||
const {defaultOptions, defaultContext} = await loadSite();
|
||||
|
||||
expect(() =>
|
||||
readVersionsMetadata({
|
||||
options: {
|
||||
|
@ -364,7 +458,9 @@ describe('versioned site, pluginId=default', () => {
|
|||
);
|
||||
});
|
||||
|
||||
test('readVersionsMetadata versioned site with lastVersion not in onlyIncludeVersions', () => {
|
||||
test('readVersionsMetadata versioned site with lastVersion not in onlyIncludeVersions', async () => {
|
||||
const {defaultOptions, defaultContext} = await loadSite();
|
||||
|
||||
expect(() =>
|
||||
readVersionsMetadata({
|
||||
options: {
|
||||
|
@ -379,7 +475,9 @@ describe('versioned site, pluginId=default', () => {
|
|||
);
|
||||
});
|
||||
|
||||
test('readVersionsMetadata versioned site with invalid versions.json file', () => {
|
||||
test('readVersionsMetadata versioned site with invalid versions.json file', async () => {
|
||||
const {defaultOptions, defaultContext} = await loadSite();
|
||||
|
||||
const mock = jest.spyOn(JSON, 'parse').mockImplementationOnce(() => {
|
||||
return {
|
||||
invalid: 'json',
|
||||
|
@ -399,47 +497,62 @@ describe('versioned site, pluginId=default', () => {
|
|||
});
|
||||
|
||||
describe('versioned site, pluginId=community', () => {
|
||||
const versionedSiteDir = path.resolve(
|
||||
path.join(__dirname, '__fixtures__', 'versioned-site'),
|
||||
);
|
||||
const defaultOptions = {
|
||||
...DEFAULT_OPTIONS,
|
||||
id: 'community',
|
||||
path: 'community',
|
||||
routeBasePath: 'communityBasePath',
|
||||
};
|
||||
const defaultContext = {
|
||||
siteDir: versionedSiteDir,
|
||||
baseUrl: '/',
|
||||
};
|
||||
async function loadSite() {
|
||||
const versionedSiteDir = path.resolve(
|
||||
path.join(__dirname, '__fixtures__', 'versioned-site'),
|
||||
);
|
||||
const defaultOptions: PluginOptions = {
|
||||
...DEFAULT_OPTIONS,
|
||||
id: 'community',
|
||||
path: 'community',
|
||||
routeBasePath: 'communityBasePath',
|
||||
};
|
||||
const defaultContext = {
|
||||
siteDir: versionedSiteDir,
|
||||
baseUrl: '/',
|
||||
i18n: DefaultI18N,
|
||||
};
|
||||
|
||||
const vCurrent: VersionMetadata = {
|
||||
docsDirPath: path.join(versionedSiteDir, 'community'),
|
||||
isLast: false,
|
||||
routePriority: undefined,
|
||||
sidebarFilePath: path.join(versionedSiteDir, 'sidebars.json'),
|
||||
versionLabel: 'Next',
|
||||
versionName: 'current',
|
||||
versionPath: '/communityBasePath/next',
|
||||
};
|
||||
const vCurrent: VersionMetadata = {
|
||||
docsDirPath: path.join(versionedSiteDir, 'community'),
|
||||
docsDirPathLocalized: path.join(
|
||||
versionedSiteDir,
|
||||
'i18n/en/docusaurus-plugin-content-docs-community/current',
|
||||
),
|
||||
isLast: false,
|
||||
routePriority: undefined,
|
||||
sidebarFilePath: path.join(versionedSiteDir, 'sidebars.json'),
|
||||
versionLabel: 'Next',
|
||||
versionName: 'current',
|
||||
versionPath: '/communityBasePath/next',
|
||||
};
|
||||
|
||||
const v100: VersionMetadata = {
|
||||
docsDirPath: path.join(
|
||||
versionedSiteDir,
|
||||
'community_versioned_docs/version-1.0.0',
|
||||
),
|
||||
isLast: true,
|
||||
routePriority: -1,
|
||||
sidebarFilePath: path.join(
|
||||
versionedSiteDir,
|
||||
'community_versioned_sidebars/version-1.0.0-sidebars.json',
|
||||
),
|
||||
versionLabel: '1.0.0',
|
||||
versionName: '1.0.0',
|
||||
versionPath: '/communityBasePath',
|
||||
};
|
||||
const v100: VersionMetadata = {
|
||||
docsDirPath: path.join(
|
||||
versionedSiteDir,
|
||||
'community_versioned_docs/version-1.0.0',
|
||||
),
|
||||
docsDirPathLocalized: path.join(
|
||||
versionedSiteDir,
|
||||
'i18n/en/docusaurus-plugin-content-docs-community/version-1.0.0',
|
||||
),
|
||||
isLast: true,
|
||||
routePriority: -1,
|
||||
sidebarFilePath: path.join(
|
||||
versionedSiteDir,
|
||||
'community_versioned_sidebars/version-1.0.0-sidebars.json',
|
||||
),
|
||||
versionLabel: '1.0.0',
|
||||
versionName: '1.0.0',
|
||||
versionPath: '/communityBasePath',
|
||||
};
|
||||
|
||||
return {versionedSiteDir, defaultOptions, defaultContext, vCurrent, v100};
|
||||
}
|
||||
|
||||
test('readVersionsMetadata versioned site (community)', async () => {
|
||||
const {defaultOptions, defaultContext, vCurrent, v100} = await loadSite();
|
||||
|
||||
test('readVersionsMetadata versioned site (community)', () => {
|
||||
const versionsMetadata = readVersionsMetadata({
|
||||
options: defaultOptions,
|
||||
context: defaultContext,
|
||||
|
@ -448,7 +561,9 @@ describe('versioned site, pluginId=community', () => {
|
|||
expect(versionsMetadata).toEqual([vCurrent, v100]);
|
||||
});
|
||||
|
||||
test('readVersionsMetadata versioned site (community) with includeCurrentVersion=false', () => {
|
||||
test('readVersionsMetadata versioned site (community) with includeCurrentVersion=false', async () => {
|
||||
const {defaultOptions, defaultContext, v100} = await loadSite();
|
||||
|
||||
const versionsMetadata = readVersionsMetadata({
|
||||
options: {...defaultOptions, includeCurrentVersion: false},
|
||||
context: defaultContext,
|
||||
|
@ -460,7 +575,9 @@ describe('versioned site, pluginId=community', () => {
|
|||
]);
|
||||
});
|
||||
|
||||
test('readVersionsMetadata versioned site (community) with disableVersioning', () => {
|
||||
test('readVersionsMetadata versioned site (community) with disableVersioning', async () => {
|
||||
const {defaultOptions, defaultContext, vCurrent} = await loadSite();
|
||||
|
||||
const versionsMetadata = readVersionsMetadata({
|
||||
options: {...defaultOptions, disableVersioning: true},
|
||||
context: defaultContext,
|
||||
|
@ -476,7 +593,9 @@ describe('versioned site, pluginId=community', () => {
|
|||
]);
|
||||
});
|
||||
|
||||
test('readVersionsMetadata versioned site (community) with all versions disabled', () => {
|
||||
test('readVersionsMetadata versioned site (community) with all versions disabled', async () => {
|
||||
const {defaultOptions, defaultContext} = await loadSite();
|
||||
|
||||
expect(() =>
|
||||
readVersionsMetadata({
|
||||
options: {
|
||||
|
|
|
@ -12,6 +12,7 @@ import {
|
|||
normalizeUrl,
|
||||
getEditUrl,
|
||||
parseMarkdownString,
|
||||
getFolderContainingFile,
|
||||
} from '@docusaurus/utils';
|
||||
import {LoadContext} from '@docusaurus/types';
|
||||
|
||||
|
@ -27,6 +28,7 @@ import {
|
|||
import getSlug from './slug';
|
||||
import {CURRENT_VERSION_NAME} from './constants';
|
||||
import globby from 'globby';
|
||||
import {getDocsDirPaths} from './versions';
|
||||
|
||||
type LastUpdateOptions = Pick<
|
||||
PluginOptions,
|
||||
|
@ -61,16 +63,25 @@ async function readLastUpdateData(
|
|||
}
|
||||
|
||||
export async function readDocFile(
|
||||
docsDirPath: string,
|
||||
versionMetadata: Pick<
|
||||
VersionMetadata,
|
||||
'docsDirPath' | 'docsDirPathLocalized'
|
||||
>,
|
||||
source: string,
|
||||
options: LastUpdateOptions,
|
||||
): Promise<DocFile> {
|
||||
const filePath = path.join(docsDirPath, source);
|
||||
const folderPath = await getFolderContainingFile(
|
||||
getDocsDirPaths(versionMetadata),
|
||||
source,
|
||||
);
|
||||
|
||||
const filePath = path.join(folderPath, source);
|
||||
|
||||
const [content, lastUpdate] = await Promise.all([
|
||||
fs.readFile(filePath, 'utf-8'),
|
||||
readLastUpdateData(filePath, options),
|
||||
]);
|
||||
return {source, content, lastUpdate};
|
||||
return {source, content, lastUpdate, filePath};
|
||||
}
|
||||
|
||||
export async function readVersionDocs(
|
||||
|
@ -84,9 +95,7 @@ export async function readVersionDocs(
|
|||
cwd: versionMetadata.docsDirPath,
|
||||
});
|
||||
return Promise.all(
|
||||
sources.map((source) =>
|
||||
readDocFile(versionMetadata.docsDirPath, source, options),
|
||||
),
|
||||
sources.map((source) => readDocFile(versionMetadata, source, options)),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -101,10 +110,9 @@ export function processDocMetadata({
|
|||
context: LoadContext;
|
||||
options: MetadataOptions;
|
||||
}): DocMetadataBase {
|
||||
const {source, content, lastUpdate} = docFile;
|
||||
const {source, content, lastUpdate, filePath} = docFile;
|
||||
const {editUrl, homePageId} = options;
|
||||
const {siteDir} = context;
|
||||
const filePath = path.join(versionMetadata.docsDirPath, source);
|
||||
|
||||
// ex: api/myDoc -> api
|
||||
// ex: myDoc -> .
|
||||
|
|
|
@ -21,7 +21,7 @@ import {LoadContext, Plugin, RouteConfig} from '@docusaurus/types';
|
|||
|
||||
import {loadSidebars, createSidebarsUtils} from './sidebars';
|
||||
import {readVersionDocs, processDocMetadata} from './docs';
|
||||
import {readVersionsMetadata} from './versions';
|
||||
import {getDocsDirPaths, readVersionsMetadata} from './versions';
|
||||
|
||||
import {
|
||||
PluginOptions,
|
||||
|
@ -44,6 +44,10 @@ import {OptionsSchema} from './options';
|
|||
import {flatten, keyBy, compact} from 'lodash';
|
||||
import {toGlobalDataVersion} from './globalData';
|
||||
import {toVersionMetadataProp} from './props';
|
||||
import {
|
||||
translateLoadedContent,
|
||||
getLoadedContentTranslationFiles,
|
||||
} from './translations';
|
||||
|
||||
export default function pluginContentDocs(
|
||||
context: LoadContext,
|
||||
|
@ -99,6 +103,10 @@ export default function pluginContentDocs(
|
|||
});
|
||||
},
|
||||
|
||||
async getTranslationFiles() {
|
||||
return getLoadedContentTranslationFiles(await this.loadContent!());
|
||||
},
|
||||
|
||||
getClientModules() {
|
||||
const modules = [];
|
||||
if (options.admonitions) {
|
||||
|
@ -111,8 +119,12 @@ export default function pluginContentDocs(
|
|||
function getVersionPathsToWatch(version: VersionMetadata): string[] {
|
||||
return [
|
||||
version.sidebarFilePath,
|
||||
...options.include.map(
|
||||
(pattern) => `${version.docsDirPath}/${pattern}`,
|
||||
...flatten(
|
||||
options.include.map((pattern) =>
|
||||
getDocsDirPaths(version).map(
|
||||
(docsDirPath) => `${docsDirPath}/${pattern}`,
|
||||
),
|
||||
),
|
||||
),
|
||||
];
|
||||
}
|
||||
|
@ -235,6 +247,10 @@ export default function pluginContentDocs(
|
|||
};
|
||||
},
|
||||
|
||||
translateContent({content, translationFiles}) {
|
||||
return translateLoadedContent(content, translationFiles);
|
||||
},
|
||||
|
||||
async contentLoaded({content, actions}) {
|
||||
const {loadedVersions} = content;
|
||||
const {docLayoutComponent, docItemComponent} = options;
|
||||
|
@ -318,7 +334,6 @@ export default function pluginContentDocs(
|
|||
if (siteConfig.onBrokenMarkdownLinks === 'ignore') {
|
||||
return;
|
||||
}
|
||||
|
||||
reportMessage(
|
||||
`Docs markdown link couldn't be resolved: (${brokenMarkdownLink.link}) in ${brokenMarkdownLink.filePath} for version ${brokenMarkdownLink.version.versionName}`,
|
||||
siteConfig.onBrokenMarkdownLinks,
|
||||
|
@ -329,7 +344,7 @@ export default function pluginContentDocs(
|
|||
function createMDXLoaderRule(): RuleSetRule {
|
||||
return {
|
||||
test: /(\.mdx?)$/,
|
||||
include: versionsMetadata.map((vmd) => vmd.docsDirPath),
|
||||
include: flatten(versionsMetadata.map(getDocsDirPaths)),
|
||||
use: compact([
|
||||
getCacheLoader(isServer),
|
||||
getBabelLoader(isServer),
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
### localized doc
|
|
@ -8,3 +8,5 @@
|
|||
|
||||
- [doc1](doc1.md)
|
||||
- [doc2](./doc2.md)
|
||||
|
||||
- [doc-localized](./doc-localized.md)
|
||||
|
|
|
@ -35,6 +35,8 @@ exports[`transform to correct links 1`] = `
|
|||
|
||||
- [doc1](/docs/doc1)
|
||||
- [doc2](/docs/doc2)
|
||||
|
||||
- [doc-localized](/fr/doc-localized)
|
||||
"
|
||||
`;
|
||||
|
||||
|
|
|
@ -16,15 +16,21 @@ import {
|
|||
} from '../../types';
|
||||
import {VERSIONED_DOCS_DIR, CURRENT_VERSION_NAME} from '../../constants';
|
||||
|
||||
function createFakeVersion(
|
||||
versionName: string,
|
||||
docsDirPath: string,
|
||||
): VersionMetadata {
|
||||
function createFakeVersion({
|
||||
versionName,
|
||||
docsDirPath,
|
||||
docsDirPathLocalized,
|
||||
}: {
|
||||
versionName: string;
|
||||
docsDirPath: string;
|
||||
docsDirPathLocalized: string;
|
||||
}): VersionMetadata {
|
||||
return {
|
||||
versionName,
|
||||
versionLabel: 'Any',
|
||||
versionPath: 'any',
|
||||
docsDirPath,
|
||||
docsDirPathLocalized,
|
||||
sidebarFilePath: 'any',
|
||||
routePriority: undefined,
|
||||
isLast: false,
|
||||
|
@ -33,14 +39,29 @@ function createFakeVersion(
|
|||
|
||||
const siteDir = path.join(__dirname, '__fixtures__');
|
||||
|
||||
const versionCurrent = createFakeVersion(
|
||||
CURRENT_VERSION_NAME,
|
||||
path.join(siteDir, 'docs'),
|
||||
);
|
||||
const version100 = createFakeVersion(
|
||||
CURRENT_VERSION_NAME,
|
||||
path.join(siteDir, VERSIONED_DOCS_DIR, 'version-1.0.0'),
|
||||
);
|
||||
const versionCurrent = createFakeVersion({
|
||||
versionName: CURRENT_VERSION_NAME,
|
||||
docsDirPath: path.join(siteDir, 'docs'),
|
||||
docsDirPathLocalized: path.join(
|
||||
siteDir,
|
||||
'i18n',
|
||||
'fr',
|
||||
'docusaurus-plugin-content-docs',
|
||||
CURRENT_VERSION_NAME,
|
||||
),
|
||||
});
|
||||
|
||||
const version100 = createFakeVersion({
|
||||
versionName: '1.0.0',
|
||||
docsDirPath: path.join(siteDir, VERSIONED_DOCS_DIR, 'version-1.0.0'),
|
||||
docsDirPathLocalized: path.join(
|
||||
siteDir,
|
||||
'i18n',
|
||||
'fr',
|
||||
'docusaurus-plugin-content-docs',
|
||||
'version-1.0.0',
|
||||
),
|
||||
});
|
||||
|
||||
const sourceToPermalink: SourceToPermalink = {
|
||||
'@site/docs/doc1.md': '/docs/doc1',
|
||||
|
@ -50,6 +71,10 @@ const sourceToPermalink: SourceToPermalink = {
|
|||
'@site/versioned_docs/version-1.0.0/doc2.md': '/docs/1.0.0/doc2',
|
||||
'@site/versioned_docs/version-1.0.0/subdir/doc1.md':
|
||||
'/docs/1.0.0/subdir/doc1',
|
||||
|
||||
'@site/i18n/fr/docusaurus-plugin-content-docs/current/doc-localized.md':
|
||||
'/fr/doc-localized',
|
||||
'@site/docs/doc-localized': '/doc-localized',
|
||||
};
|
||||
|
||||
function createMarkdownOptions(
|
||||
|
@ -85,9 +110,11 @@ test('transform to correct links', () => {
|
|||
expect(transformedContent).toContain('](/docs/doc1');
|
||||
expect(transformedContent).toContain('](/docs/doc2');
|
||||
expect(transformedContent).toContain('](/docs/subdir/doc3');
|
||||
expect(transformedContent).toContain('](/fr/doc-localized');
|
||||
expect(transformedContent).not.toContain('](doc1.md)');
|
||||
expect(transformedContent).not.toContain('](./doc2.md)');
|
||||
expect(transformedContent).not.toContain('](subdir/doc3.md)');
|
||||
expect(transformedContent).not.toContain('](/doc-localized');
|
||||
expect(content).not.toEqual(transformedContent);
|
||||
});
|
||||
|
||||
|
|
|
@ -12,10 +12,13 @@ import {
|
|||
VersionMetadata,
|
||||
BrokenMarkdownLink,
|
||||
} from '../types';
|
||||
import {getDocsDirPaths} from '../versions';
|
||||
|
||||
function getVersion(filePath: string, options: DocsMarkdownOption) {
|
||||
const versionFound = options.versionsMetadata.find((version) =>
|
||||
filePath.startsWith(version.docsDirPath),
|
||||
getDocsDirPaths(version).some((docsDirPath) =>
|
||||
filePath.startsWith(docsDirPath),
|
||||
),
|
||||
);
|
||||
if (!versionFound) {
|
||||
throw new Error(
|
||||
|
@ -32,7 +35,7 @@ function replaceMarkdownLinks(
|
|||
options: DocsMarkdownOption,
|
||||
) {
|
||||
const {siteDir, sourceToPermalink, onBrokenMarkdownLink} = options;
|
||||
const {docsDirPath} = version;
|
||||
const {docsDirPath, docsDirPathLocalized} = version;
|
||||
|
||||
// Replace internal markdown linking (except in fenced blocks).
|
||||
let fencedBlock = false;
|
||||
|
@ -53,12 +56,15 @@ function replaceMarkdownLinks(
|
|||
while (mdMatch !== null) {
|
||||
// Replace it to correct html link.
|
||||
const mdLink = mdMatch[1];
|
||||
const targetSource = `${docsDirPath}/${mdLink}`;
|
||||
|
||||
const aliasedSource = (source: string) =>
|
||||
`@site/${path.relative(siteDir, source)}`;
|
||||
|
||||
const permalink =
|
||||
sourceToPermalink[aliasedSource(resolve(filePath, mdLink))] ||
|
||||
sourceToPermalink[aliasedSource(targetSource)];
|
||||
sourceToPermalink[aliasedSource(`${docsDirPathLocalized}/${mdLink}`)] ||
|
||||
sourceToPermalink[aliasedSource(`${docsDirPath}/${mdLink}`)];
|
||||
|
||||
if (permalink) {
|
||||
modifiedLine = modifiedLine.replace(mdLink, permalink);
|
||||
} else {
|
||||
|
|
|
@ -14,6 +14,8 @@ import {
|
|||
SidebarItemLink,
|
||||
SidebarItemDoc,
|
||||
Sidebar,
|
||||
SidebarItemCategory,
|
||||
SidebarItemType,
|
||||
} from './types';
|
||||
import {mapValues, flatten, difference} from 'lodash';
|
||||
import {getElementsAround} from '@docusaurus/utils';
|
||||
|
@ -213,25 +215,51 @@ export function loadSidebars(sidebarFilePath: string): Sidebars {
|
|||
return normalizeSidebars(sidebarJson);
|
||||
}
|
||||
|
||||
// traverse the sidebar tree in depth to find all doc items, in correct order
|
||||
export function collectSidebarDocItems(sidebar: Sidebar): SidebarItemDoc[] {
|
||||
function collectRecursive(item: SidebarItem): SidebarItemDoc[] {
|
||||
if (item.type === 'doc') {
|
||||
return [item];
|
||||
}
|
||||
if (item.type === 'category') {
|
||||
return flatten(item.items.map(collectRecursive));
|
||||
}
|
||||
// Refs and links should not be shown in navigation.
|
||||
if (item.type === 'ref' || item.type === 'link') {
|
||||
return [];
|
||||
}
|
||||
throw new Error(`unknown sidebar item type = ${item.type}`);
|
||||
function collectSidebarItemsOfType<
|
||||
Type extends SidebarItemType,
|
||||
Item extends SidebarItem & {type: SidebarItemType}
|
||||
>(type: Type, sidebar: Sidebar): Item[] {
|
||||
function collectRecursive(item: SidebarItem): Item[] {
|
||||
const currentItemsCollected: Item[] =
|
||||
item.type === type ? [item as Item] : [];
|
||||
|
||||
const childItemsCollected: Item[] =
|
||||
item.type === 'category' ? flatten(item.items.map(collectRecursive)) : [];
|
||||
|
||||
return [...currentItemsCollected, ...childItemsCollected];
|
||||
}
|
||||
|
||||
return flatten(sidebar.map(collectRecursive));
|
||||
}
|
||||
|
||||
export function collectSidebarDocItems(sidebar: Sidebar): SidebarItemDoc[] {
|
||||
return collectSidebarItemsOfType('doc', sidebar);
|
||||
}
|
||||
export function collectSidebarCategories(
|
||||
sidebar: Sidebar,
|
||||
): SidebarItemCategory[] {
|
||||
return collectSidebarItemsOfType('category', sidebar);
|
||||
}
|
||||
export function collectSidebarLinks(sidebar: Sidebar): SidebarItemLink[] {
|
||||
return collectSidebarItemsOfType('link', sidebar);
|
||||
}
|
||||
|
||||
export function transformSidebarItems(
|
||||
sidebar: Sidebar,
|
||||
updateFn: (item: SidebarItem) => SidebarItem,
|
||||
): Sidebar {
|
||||
function transformRecursive(item: SidebarItem): SidebarItem {
|
||||
if (item.type === 'category') {
|
||||
return updateFn({
|
||||
...item,
|
||||
items: item.items.map(transformRecursive),
|
||||
});
|
||||
}
|
||||
return updateFn(item);
|
||||
}
|
||||
return sidebar.map(transformRecursive);
|
||||
}
|
||||
|
||||
export function collectSidebarsDocIds(
|
||||
sidebars: Sidebars,
|
||||
): Record<string, string[]> {
|
||||
|
|
259
packages/docusaurus-plugin-content-docs/src/translations.ts
Normal file
259
packages/docusaurus-plugin-content-docs/src/translations.ts
Normal file
|
@ -0,0 +1,259 @@
|
|||
/**
|
||||
* 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 {
|
||||
LoadedVersion,
|
||||
Sidebar,
|
||||
LoadedContent,
|
||||
Sidebars,
|
||||
SidebarItem,
|
||||
} from './types';
|
||||
|
||||
import {chain, mapValues, flatten, keyBy} from 'lodash';
|
||||
import {
|
||||
collectSidebarCategories,
|
||||
transformSidebarItems,
|
||||
collectSidebarLinks,
|
||||
} from './sidebars';
|
||||
import {
|
||||
TranslationFileContent,
|
||||
TranslationFile,
|
||||
TranslationFiles,
|
||||
} from '@docusaurus/types';
|
||||
import {mergeTranslations} from '@docusaurus/utils';
|
||||
import {CURRENT_VERSION_NAME} from './constants';
|
||||
|
||||
function getVersionFileName(versionName: string): string {
|
||||
if (versionName === CURRENT_VERSION_NAME) {
|
||||
return versionName;
|
||||
} else {
|
||||
// I don't like this "version-" prefix,
|
||||
// but it's for consistency with site/versioned_docs
|
||||
return `version-${versionName}`;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO legacy, the sidebar name is like "version-2.0.0-alpha.66/docs"
|
||||
// input: "version-2.0.0-alpha.66/docs"
|
||||
// output: "docs"
|
||||
function getNormalizedSidebarName({
|
||||
versionName,
|
||||
sidebarName,
|
||||
}: {
|
||||
versionName: string;
|
||||
sidebarName: string;
|
||||
}): string {
|
||||
if (versionName === CURRENT_VERSION_NAME || !sidebarName.includes('/')) {
|
||||
return sidebarName;
|
||||
}
|
||||
const [, ...rest] = sidebarName.split('/');
|
||||
return rest.join('/');
|
||||
}
|
||||
|
||||
/*
|
||||
// Do we need to translate doc metadatas?
|
||||
// It seems translating frontmatter labels is good enough
|
||||
function getDocTranslations(doc: DocMetadata): TranslationFileContent {
|
||||
return {
|
||||
[`${doc.unversionedId}.title`]: {
|
||||
message: doc.title,
|
||||
description: `The title for doc with id=${doc.unversionedId}`,
|
||||
},
|
||||
...(doc.sidebar_label
|
||||
? {
|
||||
[`${doc.unversionedId}.sidebar_label`]: {
|
||||
message: doc.sidebar_label,
|
||||
description: `The sidebar label for doc with id=${doc.unversionedId}`,
|
||||
},
|
||||
}
|
||||
: undefined),
|
||||
};
|
||||
}
|
||||
function translateDoc(
|
||||
doc: DocMetadata,
|
||||
docsTranslations: TranslationFileContent,
|
||||
): DocMetadata {
|
||||
return {
|
||||
...doc,
|
||||
title: docsTranslations[`${doc.unversionedId}.title`]?.message ?? doc.title,
|
||||
sidebar_label:
|
||||
docsTranslations[`${doc.unversionedId}.sidebar_label`]?.message ??
|
||||
doc.sidebar_label,
|
||||
};
|
||||
}
|
||||
|
||||
function getDocsTranslations(version: LoadedVersion): TranslationFileContent {
|
||||
return mergeTranslations(version.docs.map(getDocTranslations));
|
||||
}
|
||||
function translateDocs(
|
||||
docs: DocMetadata[],
|
||||
docsTranslations: TranslationFileContent,
|
||||
): DocMetadata[] {
|
||||
return docs.map((doc) => translateDoc(doc, docsTranslations));
|
||||
}
|
||||
*/
|
||||
|
||||
function getSidebarTranslationFileContent(
|
||||
sidebar: Sidebar,
|
||||
sidebarName: string,
|
||||
): TranslationFileContent {
|
||||
const categories = collectSidebarCategories(sidebar);
|
||||
const categoryContent: TranslationFileContent = chain(categories)
|
||||
.keyBy((category) => `sidebar.${sidebarName}.category.${category.label}`)
|
||||
.mapValues((category) => ({
|
||||
message: category.label,
|
||||
description: `The label for category ${category.label} in sidebar ${sidebarName}`,
|
||||
}))
|
||||
.value();
|
||||
|
||||
const links = collectSidebarLinks(sidebar);
|
||||
const linksContent: TranslationFileContent = chain(links)
|
||||
.keyBy((link) => `sidebar.${sidebarName}.link.${link.label}`)
|
||||
.mapValues((link) => ({
|
||||
message: link.label,
|
||||
description: `The label for link ${link.label} in sidebar ${sidebarName}, linking to ${link.href}`,
|
||||
}))
|
||||
.value();
|
||||
|
||||
return mergeTranslations([categoryContent, linksContent]);
|
||||
}
|
||||
|
||||
function translateSidebar({
|
||||
sidebar,
|
||||
sidebarName,
|
||||
sidebarsTranslations,
|
||||
}: {
|
||||
sidebar: Sidebar;
|
||||
sidebarName: string;
|
||||
sidebarsTranslations: TranslationFileContent;
|
||||
}): Sidebar {
|
||||
return transformSidebarItems(
|
||||
sidebar,
|
||||
(item: SidebarItem): SidebarItem => {
|
||||
if (item.type === 'category') {
|
||||
return {
|
||||
...item,
|
||||
label:
|
||||
sidebarsTranslations[
|
||||
`sidebar.${sidebarName}.category.${item.label}`
|
||||
]?.message ?? item.label,
|
||||
};
|
||||
}
|
||||
if (item.type === 'link') {
|
||||
return {
|
||||
...item,
|
||||
label:
|
||||
sidebarsTranslations[`sidebar.${sidebarName}.link.${item.label}`]
|
||||
?.message ?? item.label,
|
||||
};
|
||||
}
|
||||
return item;
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
function getSidebarsTranslations(
|
||||
version: LoadedVersion,
|
||||
): TranslationFileContent {
|
||||
return mergeTranslations(
|
||||
Object.entries(version.sidebars).map(([sidebarName, sidebar]) => {
|
||||
const normalizedSidebarName = getNormalizedSidebarName({
|
||||
sidebarName,
|
||||
versionName: version.versionName,
|
||||
});
|
||||
return getSidebarTranslationFileContent(sidebar, normalizedSidebarName);
|
||||
}),
|
||||
);
|
||||
}
|
||||
function translateSidebars(
|
||||
version: LoadedVersion,
|
||||
sidebarsTranslations: TranslationFileContent,
|
||||
): Sidebars {
|
||||
return mapValues(version.sidebars, (sidebar, sidebarName) => {
|
||||
return translateSidebar({
|
||||
sidebar,
|
||||
sidebarName: getNormalizedSidebarName({
|
||||
sidebarName,
|
||||
versionName: version.versionName,
|
||||
}),
|
||||
sidebarsTranslations,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function getVersionTranslationFiles(version: LoadedVersion): TranslationFiles {
|
||||
const versionTranslations: TranslationFileContent = {
|
||||
'version.label': {
|
||||
message: version.versionLabel,
|
||||
description: `The label for version ${version.versionName}`,
|
||||
},
|
||||
};
|
||||
|
||||
const sidebarsTranslations: TranslationFileContent = getSidebarsTranslations(
|
||||
version,
|
||||
);
|
||||
|
||||
// const docsTranslations: TranslationFileContent = getDocsTranslations(version);
|
||||
|
||||
return [
|
||||
{
|
||||
path: getVersionFileName(version.versionName),
|
||||
content: mergeTranslations([
|
||||
versionTranslations,
|
||||
sidebarsTranslations,
|
||||
// docsTranslations,
|
||||
]),
|
||||
},
|
||||
];
|
||||
}
|
||||
function translateVersion(
|
||||
version: LoadedVersion,
|
||||
translationFiles: Record<string, TranslationFile>,
|
||||
): LoadedVersion {
|
||||
const versionTranslations =
|
||||
translationFiles[getVersionFileName(version.versionName)].content;
|
||||
return {
|
||||
...version,
|
||||
versionLabel: versionTranslations['version.label']?.message,
|
||||
sidebars: translateSidebars(version, versionTranslations),
|
||||
// docs: translateDocs(version.docs, versionTranslations),
|
||||
};
|
||||
}
|
||||
|
||||
function getVersionsTranslationFiles(
|
||||
versions: LoadedVersion[],
|
||||
): TranslationFiles {
|
||||
return flatten(versions.map(getVersionTranslationFiles));
|
||||
}
|
||||
function translateVersions(
|
||||
versions: LoadedVersion[],
|
||||
translationFiles: Record<string, TranslationFile>,
|
||||
): LoadedVersion[] {
|
||||
return versions.map((version) => translateVersion(version, translationFiles));
|
||||
}
|
||||
|
||||
export function getLoadedContentTranslationFiles(
|
||||
loadedContent: LoadedContent,
|
||||
): TranslationFiles {
|
||||
return getVersionsTranslationFiles(loadedContent.loadedVersions);
|
||||
}
|
||||
export function translateLoadedContent(
|
||||
loadedContent: LoadedContent,
|
||||
translationFiles: TranslationFile[],
|
||||
): LoadedContent {
|
||||
const translationFilesMap: Record<string, TranslationFile> = keyBy(
|
||||
translationFiles,
|
||||
(f) => f.path,
|
||||
);
|
||||
|
||||
return {
|
||||
loadedVersions: translateVersions(
|
||||
loadedContent.loadedVersions,
|
||||
translationFilesMap,
|
||||
),
|
||||
};
|
||||
}
|
|
@ -9,6 +9,7 @@
|
|||
/// <reference types="@docusaurus/module-type-aliases" />
|
||||
|
||||
export type DocFile = {
|
||||
filePath: string;
|
||||
source: string;
|
||||
content: string;
|
||||
lastUpdate: LastUpdateData;
|
||||
|
@ -21,7 +22,8 @@ export type VersionMetadata = {
|
|||
versionLabel: string; // Version 1.0.0
|
||||
versionPath: string; // /baseUrl/docs/1.0.0
|
||||
isLast: boolean;
|
||||
docsDirPath: string; // versioned_docs/1.0.0
|
||||
docsDirPath: string; // "versioned_docs/version-1.0.0"
|
||||
docsDirPathLocalized: string; // "i18n/fr/version-1.0.0/default"
|
||||
sidebarFilePath: string; // versioned_sidebars/1.0.0.json
|
||||
routePriority: number | undefined; // -1 for the latest docs
|
||||
};
|
||||
|
@ -91,6 +93,7 @@ export type SidebarItem =
|
|||
| SidebarItemCategory;
|
||||
|
||||
export type Sidebar = SidebarItem[];
|
||||
export type SidebarItemType = SidebarItem['type'];
|
||||
|
||||
export type Sidebars = Record<string, Sidebar>;
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ import {
|
|||
|
||||
import {DEFAULT_PLUGIN_ID} from '@docusaurus/core/lib/constants';
|
||||
import {LoadContext} from '@docusaurus/types';
|
||||
import {normalizeUrl} from '@docusaurus/utils';
|
||||
import {getPluginI18nPath, normalizeUrl} from '@docusaurus/utils';
|
||||
import {difference} from 'lodash';
|
||||
import chalk from 'chalk';
|
||||
|
||||
|
@ -137,9 +137,12 @@ function getVersionMetadataPaths({
|
|||
options,
|
||||
}: {
|
||||
versionName: string;
|
||||
context: Pick<LoadContext, 'siteDir'>;
|
||||
context: Pick<LoadContext, 'siteDir' | 'i18n'>;
|
||||
options: Pick<PluginOptions, 'id' | 'path' | 'sidebarPath'>;
|
||||
}): Pick<VersionMetadata, 'docsDirPath' | 'sidebarFilePath'> {
|
||||
}): Pick<
|
||||
VersionMetadata,
|
||||
'docsDirPath' | 'docsDirPathLocalized' | 'sidebarFilePath'
|
||||
> {
|
||||
const isCurrentVersion = versionName === CURRENT_VERSION_NAME;
|
||||
|
||||
const docsDirPath = isCurrentVersion
|
||||
|
@ -149,6 +152,18 @@ function getVersionMetadataPaths({
|
|||
`version-${versionName}`,
|
||||
);
|
||||
|
||||
const docsDirPathLocalized = getPluginI18nPath({
|
||||
siteDir: context.siteDir,
|
||||
locale: context.i18n.currentLocale,
|
||||
pluginName: 'docusaurus-plugin-content-docs',
|
||||
pluginId: options.id,
|
||||
subPaths: [
|
||||
versionName === CURRENT_VERSION_NAME
|
||||
? CURRENT_VERSION_NAME
|
||||
: `version-${versionName}`,
|
||||
],
|
||||
});
|
||||
|
||||
const sidebarFilePath = isCurrentVersion
|
||||
? path.resolve(context.siteDir, options.sidebarPath)
|
||||
: path.join(
|
||||
|
@ -156,7 +171,7 @@ function getVersionMetadataPaths({
|
|||
`version-${versionName}-sidebars.json`,
|
||||
);
|
||||
|
||||
return {docsDirPath, sidebarFilePath};
|
||||
return {docsDirPath, docsDirPathLocalized, sidebarFilePath};
|
||||
}
|
||||
|
||||
function createVersionMetadata({
|
||||
|
@ -167,13 +182,17 @@ function createVersionMetadata({
|
|||
}: {
|
||||
versionName: string;
|
||||
isLast: boolean;
|
||||
context: Pick<LoadContext, 'siteDir' | 'baseUrl'>;
|
||||
context: Pick<LoadContext, 'siteDir' | 'baseUrl' | 'i18n'>;
|
||||
options: Pick<
|
||||
PluginOptions,
|
||||
'id' | 'path' | 'sidebarPath' | 'routeBasePath' | 'versions'
|
||||
>;
|
||||
}): VersionMetadata {
|
||||
const {sidebarFilePath, docsDirPath} = getVersionMetadataPaths({
|
||||
const {
|
||||
sidebarFilePath,
|
||||
docsDirPath,
|
||||
docsDirPathLocalized,
|
||||
} = getVersionMetadataPaths({
|
||||
versionName,
|
||||
context,
|
||||
options,
|
||||
|
@ -210,6 +229,7 @@ function createVersionMetadata({
|
|||
routePriority,
|
||||
sidebarFilePath,
|
||||
docsDirPath,
|
||||
docsDirPathLocalized,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -322,7 +342,7 @@ export function readVersionsMetadata({
|
|||
context,
|
||||
options,
|
||||
}: {
|
||||
context: Pick<LoadContext, 'siteDir' | 'baseUrl'>;
|
||||
context: Pick<LoadContext, 'siteDir' | 'baseUrl' | 'i18n'>;
|
||||
options: Pick<
|
||||
PluginOptions,
|
||||
| 'id'
|
||||
|
@ -356,3 +376,15 @@ export function readVersionsMetadata({
|
|||
versionsMetadata.forEach(checkVersionMetadataPaths);
|
||||
return versionsMetadata;
|
||||
}
|
||||
|
||||
// order matter!
|
||||
// Read in priority the localized path, then the unlocalized one
|
||||
// We want the localized doc to "override" the unlocalized one
|
||||
export function getDocsDirPaths(
|
||||
versionMetadata: Pick<
|
||||
VersionMetadata,
|
||||
'docsDirPath' | 'docsDirPathLocalized'
|
||||
>,
|
||||
): [string, string] {
|
||||
return [versionMetadata.docsDirPathLocalized, versionMetadata.docsDirPath];
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue