mirror of
https://github.com/facebook/docusaurus.git
synced 2025-04-30 18:58:36 +02:00
Merge branch 'main' of github.com:facebook/docusaurus into lex111/filter-sidebar
This commit is contained in:
commit
2bc3b28cec
543 changed files with 11307 additions and 9410 deletions
|
@ -1,10 +1,33 @@
|
|||
{
|
||||
"name": "Docusaurus Dev Container",
|
||||
"image": "mcr.microsoft.com/vscode/devcontainers/typescript-node:14-buster",
|
||||
"image": "mcr.microsoft.com/vscode/devcontainers/base:ubuntu-20.04",
|
||||
"settings": {
|
||||
"terminal.integrated.shell.linux": "/bin/bash"
|
||||
"[typescript]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"editor.formatOnSave": true
|
||||
},
|
||||
"[json]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"editor.formatOnSave": true
|
||||
},
|
||||
"[jsonc]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"editor.formatOnSave": true
|
||||
}
|
||||
},
|
||||
"extensions": ["dbaeumer.vscode-eslint", "orta.vscode-jest"],
|
||||
"extensions": [
|
||||
"dbaeumer.vscode-eslint",
|
||||
"orta.vscode-jest",
|
||||
"esbenp.prettier-vscode",
|
||||
"streetsidesoftware.code-spell-checker"
|
||||
],
|
||||
"forwardPorts": [3000],
|
||||
"postCreateCommand": "yarn install"
|
||||
"containerUser": "vscode",
|
||||
"postCreateCommand": "yarn install",
|
||||
"waitFor": "postCreateCommand", // otherwise automated jest tests fail
|
||||
"features": {
|
||||
"node": {
|
||||
"version": "14"
|
||||
},
|
||||
"github-cli": "latest"
|
||||
}
|
||||
}
|
||||
|
|
13
.eslintrc.js
13
.eslintrc.js
|
@ -49,6 +49,7 @@ module.exports = {
|
|||
curly: [WARNING, 'all'],
|
||||
'global-require': WARNING,
|
||||
'lines-between-class-members': OFF,
|
||||
'max-classes-per-file': OFF,
|
||||
'max-len': [
|
||||
WARNING,
|
||||
{
|
||||
|
@ -201,7 +202,13 @@ module.exports = {
|
|||
'import/no-unresolved': [
|
||||
ERROR,
|
||||
{
|
||||
ignore: ['^@theme', '^@docusaurus', '^@generated', '^@site'],
|
||||
ignore: [
|
||||
'^@theme',
|
||||
'^@docusaurus',
|
||||
'^@generated',
|
||||
'^@site',
|
||||
'^@testing-utils',
|
||||
],
|
||||
},
|
||||
],
|
||||
'import/order': OFF,
|
||||
|
@ -262,6 +269,10 @@ module.exports = {
|
|||
ERROR,
|
||||
{'ts-expect-error': 'allow-with-description'},
|
||||
],
|
||||
'@typescript-eslint/consistent-indexed-object-style': [
|
||||
WARNING,
|
||||
'index-signature',
|
||||
],
|
||||
'@typescript-eslint/consistent-type-imports': [
|
||||
WARNING,
|
||||
{disallowTypeAnnotations: false},
|
||||
|
|
219
CHANGELOG.md
219
CHANGELOG.md
|
@ -1,5 +1,224 @@
|
|||
# Docusaurus 2 Changelog
|
||||
|
||||
## 2.0.0-beta.18 (2022-03-25)
|
||||
|
||||
#### :rocket: New Feature
|
||||
|
||||
- `docusaurus-mdx-loader`, `docusaurus-theme-classic`
|
||||
- [#6990](https://github.com/facebook/docusaurus/pull/6990) feat: lazy-load external images + ability to customize image display ([@slorber](https://github.com/slorber))
|
||||
- `docusaurus-module-type-aliases`, `docusaurus-plugin-content-docs`, `docusaurus-theme-classic`, `docusaurus-theme-common`, `docusaurus-types`, `docusaurus`
|
||||
- [#6933](https://github.com/facebook/docusaurus/pull/6933) feat(core,theme): useRouteContext + HtmlClassNameProvider ([@slorber](https://github.com/slorber))
|
||||
- `docusaurus-plugin-debug`, `docusaurus-plugin-google-analytics`, `docusaurus-plugin-google-gtag`, `docusaurus-plugin-ideal-image`, `docusaurus-plugin-pwa`, `docusaurus-theme-classic`, `docusaurus-theme-live-codeblock`, `docusaurus-theme-search-algolia`, `docusaurus-types`, `docusaurus`
|
||||
- [#6921](https://github.com/facebook/docusaurus/pull/6921) feat(core): allow plugin lifecycles to return relative paths ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `docusaurus-theme-classic`
|
||||
- [#6697](https://github.com/facebook/docusaurus/pull/6697) feat: add SEO microdata for doc breadcrumbs ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- [#6842](https://github.com/facebook/docusaurus/pull/6842) feat(theme-classic): MDXContent wrapper component ([@slorber](https://github.com/slorber))
|
||||
- `docusaurus-plugin-content-docs`
|
||||
- [#6780](https://github.com/facebook/docusaurus/pull/6780) feat(content-docs): allow custom props through _category_.json ([@taejs](https://github.com/taejs))
|
||||
|
||||
#### :boom: Breaking Change
|
||||
|
||||
- `docusaurus-plugin-content-docs`
|
||||
- [#6859](https://github.com/facebook/docusaurus/pull/6859) feat(content-docs): autogenerate category with linked doc metadata as fallback ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `docusaurus-theme-classic`
|
||||
- [#6989](https://github.com/facebook/docusaurus/pull/6989) refactor: extract MDX components ([@slorber](https://github.com/slorber))
|
||||
- `docusaurus-module-type-aliases`, `docusaurus-theme-classic`, `docusaurus-theme-common`, `docusaurus-theme-search-algolia`, `docusaurus`
|
||||
- [#6925](https://github.com/facebook/docusaurus/pull/6925) refactor(theme-{classic,common}): refactor site/page/search metadata + apply className on html element ([@slorber](https://github.com/slorber))
|
||||
- `docusaurus-theme-classic`, `docusaurus-theme-common`
|
||||
- [#6895](https://github.com/facebook/docusaurus/pull/6895) refactor(theme-{classic,common}): split navbar into smaller components + cleanup + swizzle config ([@slorber](https://github.com/slorber))
|
||||
- [#6930](https://github.com/facebook/docusaurus/pull/6930) refactor(theme-{classic,common}): refactor ColorModeToggle + useColorMode() hook ([@lex111](https://github.com/lex111))
|
||||
|
||||
#### :bug: Bug Fix
|
||||
|
||||
- `docusaurus`
|
||||
- [#6993](https://github.com/facebook/docusaurus/pull/6993) fix(core): prevent useBaseUrl returning /base/base when on /base ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- [#6936](https://github.com/facebook/docusaurus/pull/6936) fix: remove semicolon from HTML output ([@lex111](https://github.com/lex111))
|
||||
- [#6849](https://github.com/facebook/docusaurus/pull/6849) fix(cli): write-heading-id should not generate colliding slugs when not overwriting ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `docusaurus-theme-classic`
|
||||
- [#6983](https://github.com/facebook/docusaurus/pull/6983) fix(search): bump Infima, fix search issue due to broken CSS selector ([@slorber](https://github.com/slorber))
|
||||
- `docusaurus-utils-validation`
|
||||
- [#6977](https://github.com/facebook/docusaurus/pull/6977) fix(validation): allow non-object params to remark/rehype plugins ([@aloisklink](https://github.com/aloisklink))
|
||||
- `docusaurus-plugin-content-docs`, `docusaurus-utils`
|
||||
- [#6973](https://github.com/facebook/docusaurus/pull/6973) fix(content-docs): suppress git error on multiple occurrences ([@felipecrs](https://github.com/felipecrs))
|
||||
- `docusaurus-plugin-content-blog`
|
||||
- [#6947](https://github.com/facebook/docusaurus/pull/6947) fix(content-blog): only create archive route if there are blog posts ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- [#6918](https://github.com/facebook/docusaurus/pull/6918) fix(content-blog): remove double leading slash in blog-only paginated view ([@heowc](https://github.com/heowc))
|
||||
- `docusaurus-theme-search-algolia`
|
||||
- [#6888](https://github.com/facebook/docusaurus/pull/6888) fix(theme-algolia): declare content-docs as dependency ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `docusaurus-theme-translations`
|
||||
- [#6847](https://github.com/facebook/docusaurus/pull/6847) fix: minor Chinese translation fixes ([@rccttwd](https://github.com/rccttwd))
|
||||
|
||||
#### :nail_care: Polish
|
||||
|
||||
- `docusaurus-plugin-content-docs`
|
||||
- [#6859](https://github.com/facebook/docusaurus/pull/6859) feat(content-docs): autogenerate category with linked doc metadata as fallback ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- [#6887](https://github.com/facebook/docusaurus/pull/6887) fix(content-docs): give context about sidebar loading failure ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `docusaurus-plugin-content-docs`, `docusaurus-utils-validation`, `docusaurus`
|
||||
- [#6997](https://github.com/facebook/docusaurus/pull/6997) fix(validation): improve error messages for a few schemas ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `docusaurus-theme-classic`
|
||||
- [#6971](https://github.com/facebook/docusaurus/pull/6971) refactor: improve a11y of dropdown menu ([@lex111](https://github.com/lex111))
|
||||
- [#6987](https://github.com/facebook/docusaurus/pull/6987) refactor(theme-classic): cleanup of code blocks ([@lex111](https://github.com/lex111))
|
||||
- [#6950](https://github.com/facebook/docusaurus/pull/6950) refactor(theme-classic): clean up CSS of doc cards ([@lex111](https://github.com/lex111))
|
||||
- [#6994](https://github.com/facebook/docusaurus/pull/6994) refactor: better external link icon positioning ([@lex111](https://github.com/lex111))
|
||||
- [#6989](https://github.com/facebook/docusaurus/pull/6989) refactor: extract MDX components ([@slorber](https://github.com/slorber))
|
||||
- [#6985](https://github.com/facebook/docusaurus/pull/6985) refactor(theme-classic): remove span wrappers from layout links ([@lex111](https://github.com/lex111))
|
||||
- [#6986](https://github.com/facebook/docusaurus/pull/6986) fix(theme-classic): minor code copy button improvements ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- [#6964](https://github.com/facebook/docusaurus/pull/6964) refactor: replace text-based copy code button with icons ([@lex111](https://github.com/lex111))
|
||||
- [#6932](https://github.com/facebook/docusaurus/pull/6932) refactor(theme-classic): little breadcrumbs improvements ([@lex111](https://github.com/lex111))
|
||||
- [#6914](https://github.com/facebook/docusaurus/pull/6914) feat(theme-classic): set aria-expanded on expandable sidebar categories ([@pkowaluk](https://github.com/pkowaluk))
|
||||
- [#6844](https://github.com/facebook/docusaurus/pull/6844) refactor(theme-classic): split sidebar into smaller parts ([@slorber](https://github.com/slorber))
|
||||
- [#6846](https://github.com/facebook/docusaurus/pull/6846) refactor(theme-classic): consistently add span wrapper for layout links ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `docusaurus-plugin-content-blog`, `docusaurus-plugin-content-docs`, `docusaurus-theme-classic`, `docusaurus-utils-validation`, `docusaurus-utils`, `docusaurus`
|
||||
- [#6980](https://github.com/facebook/docusaurus/pull/6980) feat(utils): JSDoc for all APIs ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `docusaurus-theme-common`
|
||||
- [#6974](https://github.com/facebook/docusaurus/pull/6974) feat(theme-common): JSDoc for all APIs ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `docusaurus`
|
||||
- [#6784](https://github.com/facebook/docusaurus/pull/6784) feat(core): allow configureWebpack to return undefined ([@yorkie](https://github.com/yorkie))
|
||||
- [#6941](https://github.com/facebook/docusaurus/pull/6941) refactor(core): improve error message when a page has no default-export ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- [#6878](https://github.com/facebook/docusaurus/pull/6878) fix(core): ensure stable webpack theme aliases sorting ([@jrvidal](https://github.com/jrvidal))
|
||||
- [#6854](https://github.com/facebook/docusaurus/pull/6854) fix(core): fix swizzle legend typo ([@DigiPie](https://github.com/DigiPie))
|
||||
- [#6850](https://github.com/facebook/docusaurus/pull/6850) fix(core): make plugin lifecycles consistently bound to the plugin instance ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `docusaurus-plugin-content-blog`, `docusaurus-plugin-content-docs`, `docusaurus-utils`
|
||||
- [#6937](https://github.com/facebook/docusaurus/pull/6937) fix(content-docs): warn when files are not tracked ([@felipecrs](https://github.com/felipecrs))
|
||||
- `docusaurus-module-type-aliases`, `docusaurus-theme-classic`, `docusaurus-theme-common`, `docusaurus-theme-search-algolia`, `docusaurus`
|
||||
- [#6925](https://github.com/facebook/docusaurus/pull/6925) refactor(theme-{classic,common}): refactor site/page/search metadata + apply className on html element ([@slorber](https://github.com/slorber))
|
||||
- `docusaurus-theme-classic`, `docusaurus-theme-common`
|
||||
- [#6895](https://github.com/facebook/docusaurus/pull/6895) refactor(theme-{classic,common}): split navbar into smaller components + cleanup + swizzle config ([@slorber](https://github.com/slorber))
|
||||
- [#6930](https://github.com/facebook/docusaurus/pull/6930) refactor(theme-{classic,common}): refactor ColorModeToggle + useColorMode() hook ([@lex111](https://github.com/lex111))
|
||||
- [#6894](https://github.com/facebook/docusaurus/pull/6894) refactor(theme-classic): split theme footer into smaller components + swizzle config ([@slorber](https://github.com/slorber))
|
||||
- `docusaurus-types`, `docusaurus`
|
||||
- [#6929](https://github.com/facebook/docusaurus/pull/6929) refactor(core): minor routes type improvement ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `docusaurus-plugin-client-redirects`, `docusaurus-plugin-ideal-image`, `docusaurus-plugin-pwa`, `docusaurus-plugin-sitemap`
|
||||
- [#6928](https://github.com/facebook/docusaurus/pull/6928) chore(pwa, sitemap, client-redirects, ideal-image): JSDoc for types ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `docusaurus-plugin-content-blog`, `docusaurus-theme-classic`, `docusaurus-utils`
|
||||
- [#6922](https://github.com/facebook/docusaurus/pull/6922) refactor(content-blog): clean up type definitions; in-code documentation ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `docusaurus-theme-translations`
|
||||
- [#6781](https://github.com/facebook/docusaurus/pull/6781) feat(theme-translations): complete Russian translations ([@dragomano](https://github.com/dragomano))
|
||||
- [#6877](https://github.com/facebook/docusaurus/pull/6877) chore(theme-translations): complete Vietnamese translations ([@datlechin](https://github.com/datlechin))
|
||||
- `docusaurus-plugin-content-blog`
|
||||
- [#6909](https://github.com/facebook/docusaurus/pull/6909) refactor(content-blog): improve error message of authors map validation ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `create-docusaurus`
|
||||
- [#6860](https://github.com/facebook/docusaurus/pull/6860) fix(create): load entry file after node version checking ([@taejs](https://github.com/taejs))
|
||||
|
||||
#### :memo: Documentation
|
||||
|
||||
- Other
|
||||
- [#6988](https://github.com/facebook/docusaurus/pull/6988) docs: fix example admonition syntax ([@kaycebasques](https://github.com/kaycebasques))
|
||||
- [#6978](https://github.com/facebook/docusaurus/pull/6978) docs: npm run tsc -> npx tsc ([@jadonn](https://github.com/jadonn))
|
||||
- [#6952](https://github.com/facebook/docusaurus/pull/6952) docs: add K3ai to showcase ([@alefesta](https://github.com/alefesta))
|
||||
- [#6948](https://github.com/facebook/docusaurus/pull/6948) docs: add pdfme docs to showcase ([@hand-dot](https://github.com/hand-dot))
|
||||
- [#6943](https://github.com/facebook/docusaurus/pull/6943) docs: add SeaORM docs to showcase ([@billy1624](https://github.com/billy1624))
|
||||
- [#6926](https://github.com/facebook/docusaurus/pull/6926) docs: clarify the usage of slug ([@kaycebasques](https://github.com/kaycebasques))
|
||||
- [#6911](https://github.com/facebook/docusaurus/pull/6911) docs: add Reactive Button site to showcase ([@arifszn](https://github.com/arifszn))
|
||||
- [#6904](https://github.com/facebook/docusaurus/pull/6904) docs: update image for digital support services ([@PatelN123](https://github.com/PatelN123))
|
||||
- [#6892](https://github.com/facebook/docusaurus/pull/6892) docs: add EduLinks site to showcase ([@odarpi](https://github.com/odarpi))
|
||||
- [#6889](https://github.com/facebook/docusaurus/pull/6889) docs: editorial fixes ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- [#6883](https://github.com/facebook/docusaurus/pull/6883) docs(cli): add info about development on github codespaces ([@vedantmgoyal2009](https://github.com/vedantmgoyal2009))
|
||||
- [#6856](https://github.com/facebook/docusaurus/pull/6856) docs: add Reddit Image Fetcher site to showcase ([@arifszn](https://github.com/arifszn))
|
||||
- [#6875](https://github.com/facebook/docusaurus/pull/6875) docs: update TRPG Engine showcase ([@moonrailgun](https://github.com/moonrailgun))
|
||||
- [#6871](https://github.com/facebook/docusaurus/pull/6871) docs: mark clutch and gulp as open-source ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- [#6862](https://github.com/facebook/docusaurus/pull/6862) docs: update showcase data ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- [#6837](https://github.com/facebook/docusaurus/pull/6837) docs: add PcapPlusPlus to showcase ([@seladb](https://github.com/seladb))
|
||||
- [#6832](https://github.com/facebook/docusaurus/pull/6832) docs: add Spicetify site to showcase ([@afonsojramos](https://github.com/afonsojramos))
|
||||
- [#6830](https://github.com/facebook/docusaurus/pull/6830) docs: simplify imported code blocks syntax ([@nathan-contino-mongo](https://github.com/nathan-contino-mongo))
|
||||
- `docusaurus-types`
|
||||
- [#6881](https://github.com/facebook/docusaurus/pull/6881) docs: mention configureWebpack devServer return value ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `create-docusaurus`
|
||||
- [#6833](https://github.com/facebook/docusaurus/pull/6833) docs: make tutorial code block directly copyable ([@samgutentag](https://github.com/samgutentag))
|
||||
|
||||
#### :house: Internal
|
||||
|
||||
- `create-docusaurus`, `docusaurus-mdx-loader`, `docusaurus-migrate`, `docusaurus-module-type-aliases`, `docusaurus-plugin-client-redirects`, `docusaurus-plugin-content-blog`, `docusaurus-plugin-content-docs`, `docusaurus-plugin-content-pages`, `docusaurus-plugin-debug`, `docusaurus-plugin-google-gtag`, `docusaurus-plugin-ideal-image`, `docusaurus-remark-plugin-npm2yarn`, `docusaurus-theme-classic`, `docusaurus-theme-common`, `docusaurus-theme-search-algolia`, `docusaurus-theme-translations`, `docusaurus-types`, `docusaurus-utils-validation`, `docusaurus-utils`, `docusaurus`, `lqip-loader`
|
||||
- [#6995](https://github.com/facebook/docusaurus/pull/6995) refactor: ensure all types are using index signature instead of Record ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `create-docusaurus`, `docusaurus-cssnano-preset`, `docusaurus-plugin-pwa`, `docusaurus-theme-search-algolia`, `docusaurus-utils`, `docusaurus`, `lqip-loader`
|
||||
- [#6991](https://github.com/facebook/docusaurus/pull/6991) chore: upgrade dependencies ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `lqip-loader`
|
||||
- [#6992](https://github.com/facebook/docusaurus/pull/6992) refactor(lqip-loader): remove unused palette option ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `docusaurus`
|
||||
- [#6975](https://github.com/facebook/docusaurus/pull/6975) chore: update static-site-generator-webpack-plugin ([@slorber](https://github.com/slorber))
|
||||
- `stylelint-copyright`
|
||||
- [#6967](https://github.com/facebook/docusaurus/pull/6967) chore: publish stylelint-copyright again ([@slorber](https://github.com/slorber))
|
||||
- `docusaurus-plugin-client-redirects`, `docusaurus-plugin-content-blog`, `docusaurus-plugin-content-docs`, `docusaurus-plugin-content-pages`, `docusaurus-plugin-google-analytics`, `docusaurus-plugin-google-gtag`, `docusaurus-plugin-ideal-image`, `docusaurus-plugin-pwa`, `docusaurus-plugin-sitemap`, `docusaurus-theme-classic`, `docusaurus-theme-live-codeblock`, `docusaurus-theme-search-algolia`, `docusaurus-types`, `docusaurus-utils-validation`, `docusaurus`
|
||||
- [#6961](https://github.com/facebook/docusaurus/pull/6961) refactor: unify how validateOptions is handled ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `docusaurus-types`
|
||||
- [#6957](https://github.com/facebook/docusaurus/pull/6957) chore(types): remove querystring from dependencies ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `docusaurus-theme-common`, `docusaurus`
|
||||
- [#6956](https://github.com/facebook/docusaurus/pull/6956) test: improve test coverage; reorder theme-common files ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- [#6955](https://github.com/facebook/docusaurus/pull/6955) refactor(core): move browserContext and docusaurusContext out of client exports ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- [#6944](https://github.com/facebook/docusaurus/pull/6944) chore: migrate Jest and website to SWC ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `docusaurus-utils`
|
||||
- [#6951](https://github.com/facebook/docusaurus/pull/6951) test: fix Windows test for gitUtils ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `docusaurus-mdx-loader`, `docusaurus-migrate`, `docusaurus-plugin-client-redirects`, `docusaurus-plugin-content-blog`, `docusaurus-plugin-content-docs`, `docusaurus-plugin-content-pages`, `docusaurus-plugin-debug`, `docusaurus-plugin-pwa`, `docusaurus-theme-classic`, `docusaurus-theme-common`, `docusaurus-theme-translations`, `docusaurus-utils`, `docusaurus`, `stylelint-copyright`
|
||||
- [#6931](https://github.com/facebook/docusaurus/pull/6931) chore: tighten ESLint config ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `docusaurus-module-type-aliases`, `docusaurus-plugin-client-redirects`
|
||||
- [#6924](https://github.com/facebook/docusaurus/pull/6924) refactor(client-redirects): migrate validation to validateOptions lifecycle ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `create-docusaurus`, `docusaurus-cssnano-preset`, `docusaurus-mdx-loader`, `docusaurus-migrate`, `docusaurus-plugin-ideal-image`, `docusaurus-plugin-pwa`, `docusaurus-theme-classic`, `docusaurus-theme-search-algolia`, `docusaurus-utils`, `docusaurus`, `lqip-loader`
|
||||
- [#6916](https://github.com/facebook/docusaurus/pull/6916) chore: upgrade dependencies ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `create-docusaurus`, `docusaurus-plugin-content-docs`, `docusaurus-theme-translations`, `docusaurus-types`, `docusaurus-utils-validation`, `docusaurus-utils`, `docusaurus`, `stylelint-copyright`
|
||||
- [#6912](https://github.com/facebook/docusaurus/pull/6912) test: improve test coverage; multiple internal refactors ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- Other
|
||||
- [#6910](https://github.com/facebook/docusaurus/pull/6910) refactor: convert Jest infrastructure to TS ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- [#6838](https://github.com/facebook/docusaurus/pull/6838) fix(website): changelog plugin leads to CI bugs on release ([@slorber](https://github.com/slorber))
|
||||
- `docusaurus-logger`, `docusaurus-mdx-loader`, `docusaurus-migrate`, `docusaurus-plugin-client-redirects`, `docusaurus-plugin-content-blog`, `docusaurus-plugin-content-docs`, `docusaurus-plugin-content-pages`, `docusaurus-theme-classic`, `docusaurus-theme-common`, `docusaurus-utils`, `docusaurus`
|
||||
- [#6908](https://github.com/facebook/docusaurus/pull/6908) chore: do not print prototype in jest snapshot ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `docusaurus-migrate`, `docusaurus-plugin-content-docs`, `docusaurus-theme-common`, `docusaurus-utils-validation`, `docusaurus-utils`, `docusaurus`
|
||||
- [#6906](https://github.com/facebook/docusaurus/pull/6906) refactor: install eslint-plugin-regexp ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `docusaurus-mdx-loader`, `docusaurus-plugin-client-redirects`, `docusaurus-plugin-content-docs`, `docusaurus-theme-common`, `docusaurus-theme-search-algolia`, `docusaurus-utils`, `docusaurus`
|
||||
- [#6905](https://github.com/facebook/docusaurus/pull/6905) test: improve test coverage; properly test core client APIs ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `docusaurus-logger`, `docusaurus-mdx-loader`, `docusaurus-migrate`, `docusaurus-plugin-client-redirects`, `docusaurus-plugin-content-blog`, `docusaurus-plugin-content-docs`, `docusaurus-plugin-sitemap`, `docusaurus-remark-plugin-npm2yarn`, `docusaurus-theme-classic`, `docusaurus-theme-common`, `docusaurus-theme-live-codeblock`, `docusaurus-theme-translations`, `docusaurus-utils`, `docusaurus`
|
||||
- [#6903](https://github.com/facebook/docusaurus/pull/6903) chore: spell-check test files ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `docusaurus-migrate`, `docusaurus-module-type-aliases`, `docusaurus-plugin-client-redirects`, `docusaurus-plugin-content-blog`, `docusaurus-plugin-content-docs`, `docusaurus-theme-common`, `docusaurus-types`, `docusaurus-utils-common`, `docusaurus-utils`, `docusaurus`, `lqip-loader`
|
||||
- [#6902](https://github.com/facebook/docusaurus/pull/6902) test(theme-common): improve test coverage ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `docusaurus-cssnano-preset`, `docusaurus-logger`, `docusaurus-mdx-loader`, `docusaurus-migrate`, `docusaurus-plugin-client-redirects`, `docusaurus-plugin-content-blog`, `docusaurus-plugin-content-docs`, `docusaurus-plugin-content-pages`, `docusaurus-plugin-sitemap`, `docusaurus-remark-plugin-npm2yarn`, `docusaurus-theme-classic`, `docusaurus-theme-common`, `docusaurus-theme-live-codeblock`, `docusaurus-theme-search-algolia`, `docusaurus-theme-translations`, `docusaurus-utils-common`, `docusaurus-utils-validation`, `docusaurus-utils`, `docusaurus`, `lqip-loader`, `stylelint-copyright`
|
||||
- [#6900](https://github.com/facebook/docusaurus/pull/6900) test: enable a few jest eslint rules ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `docusaurus-logger`, `docusaurus-mdx-loader`, `docusaurus-migrate`, `docusaurus-plugin-content-blog`, `docusaurus-plugin-content-docs`, `docusaurus-theme-classic`, `docusaurus-theme-common`, `docusaurus-theme-translations`, `docusaurus-utils-validation`, `docusaurus-utils`, `docusaurus`, `lqip-loader`
|
||||
- [#6898](https://github.com/facebook/docusaurus/pull/6898) refactor: import jest as global; unify import style of some modules ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `docusaurus-theme-classic`, `docusaurus-theme-common`
|
||||
- [#6891](https://github.com/facebook/docusaurus/pull/6891) refactor(theme-classic): avoid using clsx class dict with CSS modules ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `docusaurus-migrate`, `docusaurus-plugin-client-redirects`, `docusaurus-plugin-content-blog`, `docusaurus-plugin-content-docs`, `docusaurus-theme-translations`, `docusaurus-utils`, `docusaurus`
|
||||
- [#6880](https://github.com/facebook/docusaurus/pull/6880) refactor: prefer fs.outputFile to ensureDir + writeFile ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `docusaurus-plugin-pwa`, `docusaurus-types`, `docusaurus`
|
||||
- [#6866](https://github.com/facebook/docusaurus/pull/6866) refactor: improve types ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `docusaurus-mdx-loader`, `docusaurus-plugin-client-redirects`, `docusaurus-plugin-content-blog`, `docusaurus-plugin-content-docs`, `docusaurus-plugin-content-pages`, `docusaurus-plugin-pwa`, `docusaurus-theme-classic`, `docusaurus-theme-common`, `docusaurus-types`, `docusaurus`, `lqip-loader`
|
||||
- [#6864](https://github.com/facebook/docusaurus/pull/6864) refactor: remove unnecessary default values normalized during validation ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `create-docusaurus`, `docusaurus-migrate`, `docusaurus`
|
||||
- [#6861](https://github.com/facebook/docusaurus/pull/6861) refactor: make JS executables included in the tsconfig for editor hints ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `docusaurus-plugin-content-blog`, `docusaurus-plugin-content-docs`, `docusaurus-types`, `docusaurus`
|
||||
- [#6857](https://github.com/facebook/docusaurus/pull/6857) test: improve test coverage ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- `docusaurus-logger`, `docusaurus-mdx-loader`, `docusaurus-migrate`, `docusaurus-plugin-content-blog`, `docusaurus-plugin-content-docs`, `docusaurus-remark-plugin-npm2yarn`, `docusaurus-theme-classic`, `docusaurus-theme-common`, `docusaurus-theme-search-algolia`, `docusaurus-utils-common`, `docusaurus-utils`, `docusaurus`, `lqip-loader`
|
||||
- [#6852](https://github.com/facebook/docusaurus/pull/6852) refactor: enable a few TS flags ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
|
||||
#### Committers: 28
|
||||
|
||||
- Afonso Jorge Ramos ([@afonsojramos](https://github.com/afonsojramos))
|
||||
- Alessandro Festa ([@alefesta](https://github.com/alefesta))
|
||||
- Alexey Pyltsyn ([@lex111](https://github.com/lex111))
|
||||
- Alois Klink ([@aloisklink](https://github.com/aloisklink))
|
||||
- Ariful Alam ([@arifszn](https://github.com/arifszn))
|
||||
- Begula ([@vedantmgoyal2009](https://github.com/vedantmgoyal2009))
|
||||
- Billy Chan ([@billy1624](https://github.com/billy1624))
|
||||
- Bugo ([@dragomano](https://github.com/dragomano))
|
||||
- Evan ([@DigiPie](https://github.com/DigiPie))
|
||||
- Felipe Santos ([@felipecrs](https://github.com/felipecrs))
|
||||
- Jadon N ([@jadonn](https://github.com/jadonn))
|
||||
- Joshua Chen ([@Josh-Cena](https://github.com/Josh-Cena))
|
||||
- Kayce Basques ([@kaycebasques](https://github.com/kaycebasques))
|
||||
- Kyohei Fukuda ([@hand-dot](https://github.com/hand-dot))
|
||||
- Nayan Patel ([@PatelN123](https://github.com/PatelN123))
|
||||
- Ngô Quốc Đạt ([@datlechin](https://github.com/datlechin))
|
||||
- Odarpi ([@odarpi](https://github.com/odarpi))
|
||||
- Pawel Kowaluk ([@pkowaluk](https://github.com/pkowaluk))
|
||||
- Roberto Vidal ([@jrvidal](https://github.com/jrvidal))
|
||||
- Sam Gutentag ([@samgutentag](https://github.com/samgutentag))
|
||||
- Sébastien Lorber ([@slorber](https://github.com/slorber))
|
||||
- Tsz W. TAM ([@rccttwd](https://github.com/rccttwd))
|
||||
- WonChul Heo ([@heowc](https://github.com/heowc))
|
||||
- Yorkie Liu ([@yorkie](https://github.com/yorkie))
|
||||
- [@seladb](https://github.com/seladb)
|
||||
- moonrailgun ([@moonrailgun](https://github.com/moonrailgun))
|
||||
- nate contino ([@nathan-contino-mongo](https://github.com/nathan-contino-mongo))
|
||||
- tae ([@taejs](https://github.com/taejs))
|
||||
|
||||
## 2.0.0-beta.17 (2022-03-03)
|
||||
|
||||
#### :rocket: New Feature
|
||||
|
|
|
@ -26,9 +26,11 @@ const PlaygroundDocumentationUrl = 'https://docusaurus.io/docs/playground';
|
|||
export type PlaygroundName = keyof typeof PlaygroundConfigs;
|
||||
|
||||
function isValidPlaygroundName(
|
||||
playgroundName: string,
|
||||
playgroundName: string | undefined,
|
||||
): playgroundName is PlaygroundName {
|
||||
return Object.keys(PlaygroundConfigs).includes(playgroundName);
|
||||
return (
|
||||
!!playgroundName && Object.keys(PlaygroundConfigs).includes(playgroundName)
|
||||
);
|
||||
}
|
||||
|
||||
export function createPlaygroundDocumentationResponse(): HandlerResponse {
|
||||
|
@ -54,10 +56,10 @@ export function createPlaygroundResponse(
|
|||
}
|
||||
|
||||
// Inspired by https://stackoverflow.com/a/3409200/82609
|
||||
function parseCookieString(cookieString: string): Record<string, string> {
|
||||
const result: Record<string, string> = {};
|
||||
function parseCookieString(cookieString: string): {[key: string]: string} {
|
||||
const result: {[key: string]: string} = {};
|
||||
cookieString.split(';').forEach((cookie) => {
|
||||
const [name, value] = cookie.split('=');
|
||||
const [name, value] = cookie.split('=') as [string, string];
|
||||
result[name.trim()] = decodeURI(value);
|
||||
});
|
||||
return result;
|
||||
|
@ -66,7 +68,7 @@ function parseCookieString(cookieString: string): Record<string, string> {
|
|||
export function readPlaygroundName(
|
||||
event: HandlerEvent,
|
||||
): PlaygroundName | undefined {
|
||||
const parsedCookie: Record<string, string> = event.headers.cookie
|
||||
const parsedCookie: {[key: string]: string} = event.headers.cookie
|
||||
? parseCookieString(event.headers.cookie)
|
||||
: {};
|
||||
const playgroundName: string | undefined = parsedCookie[CookieName];
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "new.docusaurus.io",
|
||||
"version": "2.0.0-beta.17",
|
||||
"version": "2.0.0-beta.18",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"start": "netlify dev"
|
||||
|
@ -9,6 +9,6 @@
|
|||
"@netlify/functions": "^1.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"netlify-cli": "^9.13.1"
|
||||
"netlify-cli": "^9.13.4"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,14 +41,14 @@ This is my **first Docusaurus document**!
|
|||
|
||||
It is also possible to create your sidebar explicitly in `sidebars.js`:
|
||||
|
||||
```diff title="sidebars.js"
|
||||
```js title="sidebars.js"
|
||||
module.exports = {
|
||||
tutorialSidebar: [
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Tutorial',
|
||||
- items: [...],
|
||||
+ items: ['hello'],
|
||||
// highlight-next-line
|
||||
items: ['hello'],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
|
|
@ -16,18 +16,18 @@
|
|||
"dev": "docusaurus start"
|
||||
},
|
||||
"dependencies": {
|
||||
"@docusaurus/core": "2.0.0-beta.17",
|
||||
"@docusaurus/preset-classic": "2.0.0-beta.17",
|
||||
"@docusaurus/core": "2.0.0-beta.18",
|
||||
"@docusaurus/preset-classic": "2.0.0-beta.18",
|
||||
"@mdx-js/react": "^1.6.22",
|
||||
"clsx": "^1.1.1",
|
||||
"prism-react-renderer": "^1.2.1",
|
||||
"react": "^17.0.1",
|
||||
"react-dom": "^17.0.1"
|
||||
"prism-react-renderer": "^1.3.1",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@docusaurus/module-type-aliases": "2.0.0-beta.17",
|
||||
"@tsconfig/docusaurus": "^1.0.4",
|
||||
"typescript": "^4.6.2"
|
||||
"@docusaurus/module-type-aliases": "2.0.0-beta.18",
|
||||
"@tsconfig/docusaurus": "^1.0.5",
|
||||
"typescript": "^4.6.3"
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -41,14 +41,14 @@ This is my **first Docusaurus document**!
|
|||
|
||||
It is also possible to create your sidebar explicitly in `sidebars.js`:
|
||||
|
||||
```diff title="sidebars.js"
|
||||
```js title="sidebars.js"
|
||||
module.exports = {
|
||||
tutorialSidebar: [
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Tutorial',
|
||||
- items: [...],
|
||||
+ items: ['hello'],
|
||||
// highlight-next-line
|
||||
items: ['hello'],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
|
|
@ -15,13 +15,13 @@
|
|||
"dev": "docusaurus start"
|
||||
},
|
||||
"dependencies": {
|
||||
"@docusaurus/core": "2.0.0-beta.17",
|
||||
"@docusaurus/preset-classic": "2.0.0-beta.17",
|
||||
"@docusaurus/core": "2.0.0-beta.18",
|
||||
"@docusaurus/preset-classic": "2.0.0-beta.18",
|
||||
"@mdx-js/react": "^1.6.22",
|
||||
"clsx": "^1.1.1",
|
||||
"prism-react-renderer": "^1.2.1",
|
||||
"react": "^17.0.1",
|
||||
"react-dom": "^17.0.1"
|
||||
"prism-react-renderer": "^1.3.1",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2"
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -41,14 +41,14 @@ This is my **first Docusaurus document**!
|
|||
|
||||
It is also possible to create your sidebar explicitly in `sidebars.js`:
|
||||
|
||||
```diff title="sidebars.js"
|
||||
```js title="sidebars.js"
|
||||
module.exports = {
|
||||
tutorialSidebar: [
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Tutorial',
|
||||
- items: [...],
|
||||
+ items: ['hello'],
|
||||
// highlight-next-line
|
||||
items: ['hello'],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
|
|
@ -19,25 +19,25 @@
|
|||
"dev": "docusaurus start"
|
||||
},
|
||||
"dependencies": {
|
||||
"@docusaurus/core": "2.0.0-beta.17",
|
||||
"@docusaurus/preset-classic": "2.0.0-beta.17",
|
||||
"@docusaurus/core": "2.0.0-beta.18",
|
||||
"@docusaurus/preset-classic": "2.0.0-beta.18",
|
||||
"@mdx-js/react": "^1.6.22",
|
||||
"clsx": "^1.1.1",
|
||||
"react": "^17.0.1",
|
||||
"react-dom": "^17.0.1"
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/eslint-parser": "^7.16.3",
|
||||
"eslint": "^8.8.0",
|
||||
"eslint-config-airbnb": "^19.0.0",
|
||||
"eslint-config-prettier": "^8.4.0",
|
||||
"@babel/eslint-parser": "^7.17.0",
|
||||
"eslint": "^8.11.0",
|
||||
"eslint-config-airbnb": "^19.0.4",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-header": "^3.1.1",
|
||||
"eslint-plugin-import": "^2.25.3",
|
||||
"eslint-plugin-import": "^2.25.4",
|
||||
"eslint-plugin-jsx-a11y": "^6.5.1",
|
||||
"eslint-plugin-react": "^7.29.2",
|
||||
"eslint-plugin-react": "^7.29.4",
|
||||
"eslint-plugin-react-hooks": "^4.3.0",
|
||||
"prettier": "^2.5.1",
|
||||
"stylelint": "^14.5.3"
|
||||
"prettier": "^2.6.0",
|
||||
"stylelint": "^14.6.0"
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -7,18 +7,23 @@
|
|||
|
||||
import {fileURLToPath} from 'url';
|
||||
|
||||
process.env.TZ = 'UTC';
|
||||
|
||||
const ignorePatterns = [
|
||||
'/node_modules/',
|
||||
'__fixtures__',
|
||||
'/testUtils.ts',
|
||||
'/packages/docusaurus/lib',
|
||||
'/packages/docusaurus-logger/lib',
|
||||
'/packages/docusaurus-utils/lib',
|
||||
'/packages/docusaurus-utils-common/lib',
|
||||
'/packages/docusaurus-utils-validation/lib',
|
||||
'/packages/docusaurus-plugin-content-blog/lib',
|
||||
'/packages/docusaurus-plugin-content-docs/lib',
|
||||
'/packages/docusaurus-plugin-content-pages/lib',
|
||||
'/packages/docusaurus-theme-classic/lib',
|
||||
'/packages/docusaurus-theme-classic/lib-next',
|
||||
'/packages/docusaurus-theme-common/lib',
|
||||
'/packages/docusaurus-migrate/lib',
|
||||
];
|
||||
|
||||
|
@ -28,7 +33,11 @@ export default {
|
|||
testURL: 'https://docusaurus.io/',
|
||||
testEnvironment: 'node',
|
||||
testPathIgnorePatterns: ignorePatterns,
|
||||
coveragePathIgnorePatterns: ignorePatterns,
|
||||
coveragePathIgnorePatterns: [
|
||||
...ignorePatterns,
|
||||
// We also ignore all package entry points
|
||||
'/packages/docusaurus-utils/src/index.ts',
|
||||
],
|
||||
transform: {
|
||||
'^.+\\.[jt]sx?$': '@swc/jest',
|
||||
},
|
||||
|
@ -38,8 +47,10 @@ export default {
|
|||
'^.+\\.(css|jpe?g|png|svg|webp)$': '<rootDir>/jest/emptyModule.ts',
|
||||
|
||||
// Using src instead of lib, so we always get fresh source
|
||||
'@docusaurus/(browserContext|BrowserOnly|ComponentCreator|constants|docusaurusContext|ExecutionEnvironment|Head|Interpolate|isInternalUrl|Link|Noop|renderRoutes|router|Translate|use.*)':
|
||||
'@docusaurus/(BrowserOnly|ComponentCreator|constants|ExecutionEnvironment|Head|Interpolate|isInternalUrl|Link|Noop|renderRoutes|router|Translate|use.*)':
|
||||
'@docusaurus/core/src/client/exports/$1',
|
||||
|
||||
// TODO create dedicated testing utility for mocking contexts
|
||||
// Maybe point to a fixture?
|
||||
'@generated/.*': '<rootDir>/jest/emptyModule.ts',
|
||||
// TODO use "projects" + multiple configs if we work on another theme?
|
||||
|
@ -49,8 +60,13 @@ export default {
|
|||
// Using src instead of lib, so we always get fresh source
|
||||
'@docusaurus/plugin-content-docs/client':
|
||||
'@docusaurus/plugin-content-docs/src/client/index.ts',
|
||||
|
||||
'@testing-utils/(.*)': '<rootDir>/jest/utils/$1.ts',
|
||||
},
|
||||
snapshotSerializers: ['<rootDir>/jest/snapshotPathNormalizer.ts'],
|
||||
snapshotSerializers: [
|
||||
'<rootDir>/jest/snapshotPathNormalizer.ts',
|
||||
'jest-serializer-react-helmet-async',
|
||||
],
|
||||
snapshotFormat: {
|
||||
printBasicPrototype: false,
|
||||
},
|
||||
|
|
4
jest/snapshotPathNormalizer.ts
vendored
4
jest/snapshotPathNormalizer.ts
vendored
|
@ -31,7 +31,7 @@ export function print(
|
|||
});
|
||||
return serialize(error);
|
||||
} else if (val && typeof val === 'object') {
|
||||
const normalizedValue = _.cloneDeep(val) as Record<string, unknown>;
|
||||
const normalizedValue = _.cloneDeep(val) as {[key: string]: unknown};
|
||||
|
||||
Object.keys(normalizedValue).forEach((key) => {
|
||||
normalizedValue[key] = normalizePaths(normalizedValue[key]);
|
||||
|
@ -46,7 +46,7 @@ export function test(val: unknown): boolean {
|
|||
(typeof val === 'object' &&
|
||||
val &&
|
||||
Object.keys(val).some((key) =>
|
||||
shouldUpdate((val as Record<string, unknown>)[key]),
|
||||
shouldUpdate((val as {[key: string]: unknown})[key]),
|
||||
)) ||
|
||||
// val.message is non-enumerable in an error
|
||||
(val instanceof Error && shouldUpdate(val.message)) ||
|
||||
|
|
63
jest/utils/git.ts
vendored
Normal file
63
jest/utils/git.ts
vendored
Normal file
|
@ -0,0 +1,63 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import fs from 'fs-extra';
|
||||
import os from 'os';
|
||||
import path from 'path';
|
||||
import shell from 'shelljs';
|
||||
|
||||
class Git {
|
||||
constructor(private dir: string) {
|
||||
const res = shell.exec('git init', {cwd: dir, silent: true});
|
||||
if (res.code !== 0) {
|
||||
throw new Error(`git init exited with code ${res.code}.
|
||||
stderr: ${res.stderr}
|
||||
stdout: ${res.stdout}`);
|
||||
}
|
||||
// Doesn't matter currently
|
||||
shell.exec('git config user.email "test@jc-verse.com"', {
|
||||
cwd: dir,
|
||||
silent: true,
|
||||
});
|
||||
shell.exec('git config user.name "Test"', {cwd: dir, silent: true});
|
||||
|
||||
shell.exec('git commit --allow-empty -m "First commit"', {
|
||||
cwd: dir,
|
||||
silent: true,
|
||||
});
|
||||
}
|
||||
commit(msg: string, date: string, author: string): void {
|
||||
const addRes = shell.exec('git add .', {cwd: this.dir, silent: true});
|
||||
const commitRes = shell.exec(
|
||||
`git commit -m "${msg}" --date "${date}T00:00:00Z" --author "${author}"`,
|
||||
{
|
||||
cwd: this.dir,
|
||||
env: {GIT_COMMITTER_DATE: `${date}T00:00:00Z`},
|
||||
silent: true,
|
||||
},
|
||||
);
|
||||
if (addRes.code !== 0) {
|
||||
throw new Error(`git add exited with code ${addRes.code}.
|
||||
stderr: ${addRes.stderr}
|
||||
stdout: ${addRes.stdout}`);
|
||||
}
|
||||
if (commitRes.code !== 0) {
|
||||
throw new Error(`git commit exited with code ${commitRes.code}.
|
||||
stderr: ${commitRes.stderr}
|
||||
stdout: ${commitRes.stdout}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This function is sync so the same mock repo can be shared across tests
|
||||
export function createTempRepo(): {repoDir: string; git: Git} {
|
||||
const repoDir = fs.mkdtempSync(path.join(os.tmpdir(), 'git-test-repo'));
|
||||
|
||||
const git = new Git(repoDir);
|
||||
|
||||
return {repoDir, git};
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"version": "2.0.0-beta.17",
|
||||
"version": "2.0.0-beta.18",
|
||||
"npmClient": "yarn",
|
||||
"useWorkspaces": true,
|
||||
"changelog": {
|
||||
|
|
31
package.json
31
package.json
|
@ -52,7 +52,7 @@
|
|||
"lint:spelling": "cspell \"**\" --no-progress",
|
||||
"lint:style": "stylelint \"**/*.css\"",
|
||||
"lerna": "lerna",
|
||||
"test": "cross-env TZ=UTC jest",
|
||||
"test": "jest",
|
||||
"test:build:website": "./admin/scripts/test-release.sh",
|
||||
"watch": "yarn lerna run --parallel watch",
|
||||
"clear": "(yarn workspace website clear || echo 'Failure while running docusaurus clear') && yarn lerna exec --ignore docusaurus yarn rimraf lib lib-next",
|
||||
|
@ -61,56 +61,57 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.17.6",
|
||||
"@babel/core": "^7.17.7",
|
||||
"@babel/core": "^7.17.8",
|
||||
"@babel/preset-typescript": "^7.16.7",
|
||||
"@crowdin/cli": "^3.7.8",
|
||||
"@swc/core": "^1.2.158",
|
||||
"@swc/core": "^1.2.160",
|
||||
"@swc/jest": "^0.2.20",
|
||||
"@testing-library/react-hooks": "^7.0.2",
|
||||
"@types/fs-extra": "^9.0.13",
|
||||
"@types/jest": "^27.4.1",
|
||||
"@types/lodash": "^4.14.180",
|
||||
"@types/node": "^17.0.21",
|
||||
"@types/node": "^17.0.23",
|
||||
"@types/prompts": "^2.0.14",
|
||||
"@types/react": "^17.0.40",
|
||||
"@types/react": "^17.0.43",
|
||||
"@types/react-dev-utils": "^9.0.10",
|
||||
"@types/react-test-renderer": "^17.0.1",
|
||||
"@types/semver": "^7.3.9",
|
||||
"@types/shelljs": "^0.8.11",
|
||||
"@typescript-eslint/eslint-plugin": "^5.15.0",
|
||||
"@typescript-eslint/parser": "^5.15.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.16.0",
|
||||
"@typescript-eslint/parser": "^5.16.0",
|
||||
"concurrently": "^7.0.0",
|
||||
"cross-env": "^7.0.3",
|
||||
"cspell": "^5.19.2",
|
||||
"cspell": "^5.19.3",
|
||||
"eslint": "^8.11.0",
|
||||
"eslint-config-airbnb": "^19.0.4",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-header": "^3.1.1",
|
||||
"eslint-plugin-import": "^2.25.4",
|
||||
"eslint-plugin-jest": "^26.1.1",
|
||||
"eslint-plugin-jest": "^26.1.3",
|
||||
"eslint-plugin-jsx-a11y": "^6.5.1",
|
||||
"eslint-plugin-react": "^7.29.4",
|
||||
"eslint-plugin-react-hooks": "^4.3.0",
|
||||
"eslint-plugin-regexp": "^1.5.1",
|
||||
"eslint-plugin-regexp": "^1.6.0",
|
||||
"husky": "^7.0.4",
|
||||
"image-size": "^1.0.1",
|
||||
"jest": "^27.5.1",
|
||||
"jest-serializer-react-helmet-async": "^1.0.21",
|
||||
"lerna": "^4.0.0",
|
||||
"lerna-changelog": "^2.2.0",
|
||||
"lint-staged": "^12.3.5",
|
||||
"netlify-cli": "^9.13.1",
|
||||
"lint-staged": "^12.3.7",
|
||||
"netlify-cli": "^9.13.4",
|
||||
"nodemon": "^2.0.15",
|
||||
"prettier": "^2.5.1",
|
||||
"prettier": "^2.6.0",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-test-renderer": "^17.0.2",
|
||||
"remark-parse": "^8.0.2",
|
||||
"rimraf": "^3.0.2",
|
||||
"sharp": "^0.30.3",
|
||||
"stylelint": "^14.5.3",
|
||||
"stylelint": "^14.6.0",
|
||||
"stylelint-config-prettier": "^9.0.3",
|
||||
"stylelint-config-standard": "^25.0.0",
|
||||
"typescript": "^4.6.2",
|
||||
"typescript": "^4.6.3",
|
||||
"unified": "^9.2.1"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "create-docusaurus",
|
||||
"version": "2.0.0-beta.17",
|
||||
"version": "2.0.0-beta.18",
|
||||
"description": "Create Docusaurus apps easily.",
|
||||
"type": "module",
|
||||
"repository": {
|
||||
|
@ -22,7 +22,7 @@
|
|||
},
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@docusaurus/logger": "2.0.0-beta.17",
|
||||
"@docusaurus/logger": "2.0.0-beta.18",
|
||||
"commander": "^5.1.0",
|
||||
"fs-extra": "^10.0.1",
|
||||
"lodash": "^4.17.21",
|
||||
|
|
|
@ -102,7 +102,7 @@ function isValidGitRepoUrl(gitRepoUrl: string) {
|
|||
return ['https://', 'git@'].some((item) => gitRepoUrl.startsWith(item));
|
||||
}
|
||||
|
||||
async function updatePkg(pkgPath: string, obj: Record<string, unknown>) {
|
||||
async function updatePkg(pkgPath: string, obj: {[key: string]: unknown}) {
|
||||
const content = await fs.readFile(pkgPath, 'utf-8');
|
||||
const pkg = JSON.parse(content);
|
||||
const newPkg = Object.assign(pkg, obj);
|
||||
|
@ -271,7 +271,7 @@ export default async function init(
|
|||
return logger.red('Invalid repository URL');
|
||||
},
|
||||
message: logger.interpolate`Enter a repository URL from GitHub, Bitbucket, GitLab, or any other public repo.
|
||||
(e.g: path=${'https://github.com/ownerName/repoName.git'})`,
|
||||
(e.g: url=${'https://github.com/ownerName/repoName.git'})`,
|
||||
});
|
||||
({gitStrategy} = await prompts({
|
||||
type: 'select',
|
||||
|
@ -318,7 +318,7 @@ export default async function init(
|
|||
logger.info('Creating new Docusaurus project...');
|
||||
|
||||
if (isValidGitRepoUrl(template)) {
|
||||
logger.info`Cloning Git template path=${template}...`;
|
||||
logger.info`Cloning Git template url=${template}...`;
|
||||
if (!gitStrategies.includes(gitStrategy)) {
|
||||
logger.error`Invalid git strategy: name=${gitStrategy}. Value must be one of ${gitStrategies.join(
|
||||
', ',
|
||||
|
@ -416,7 +416,7 @@ export default async function init(
|
|||
}
|
||||
|
||||
const useNpm = pkgManager === 'npm';
|
||||
logger.success`Created path=${cdpath}.`;
|
||||
logger.success`Created name=${cdpath}.`;
|
||||
logger.info`Inside that directory, you can run several commands:
|
||||
|
||||
code=${`${pkgManager} start`}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "docusaurus-2-classic-typescript-template",
|
||||
"version": "2.0.0-beta.17",
|
||||
"version": "2.0.0-beta.18",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"docusaurus": "docusaurus",
|
||||
|
@ -15,8 +15,8 @@
|
|||
"typecheck": "tsc"
|
||||
},
|
||||
"dependencies": {
|
||||
"@docusaurus/core": "2.0.0-beta.17",
|
||||
"@docusaurus/preset-classic": "2.0.0-beta.17",
|
||||
"@docusaurus/core": "2.0.0-beta.18",
|
||||
"@docusaurus/preset-classic": "2.0.0-beta.18",
|
||||
"@mdx-js/react": "^1.6.22",
|
||||
"clsx": "^1.1.1",
|
||||
"prism-react-renderer": "^1.3.1",
|
||||
|
@ -24,9 +24,9 @@
|
|||
"react-dom": "^17.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@docusaurus/module-type-aliases": "2.0.0-beta.17",
|
||||
"@docusaurus/module-type-aliases": "2.0.0-beta.18",
|
||||
"@tsconfig/docusaurus": "^1.0.5",
|
||||
"typescript": "^4.6.2"
|
||||
"typescript": "^4.6.3"
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "docusaurus-2-classic-template",
|
||||
"version": "2.0.0-beta.17",
|
||||
"version": "2.0.0-beta.18",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"docusaurus": "docusaurus",
|
||||
|
@ -14,11 +14,11 @@
|
|||
"write-heading-ids": "docusaurus write-heading-ids"
|
||||
},
|
||||
"dependencies": {
|
||||
"@docusaurus/core": "2.0.0-beta.17",
|
||||
"@docusaurus/preset-classic": "2.0.0-beta.17",
|
||||
"@docusaurus/core": "2.0.0-beta.18",
|
||||
"@docusaurus/preset-classic": "2.0.0-beta.18",
|
||||
"@mdx-js/react": "^1.6.22",
|
||||
"clsx": "^1.1.1",
|
||||
"prism-react-renderer": "^1.2.1",
|
||||
"prism-react-renderer": "^1.3.1",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2"
|
||||
},
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "docusaurus-2-facebook-template",
|
||||
"version": "2.0.0-beta.17",
|
||||
"version": "2.0.0-beta.18",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"docusaurus": "docusaurus",
|
||||
|
@ -18,8 +18,8 @@
|
|||
"format:diff": "prettier --config .prettierrc --list-different \"**/*.{js,jsx,ts,tsx,md,mdx}\""
|
||||
},
|
||||
"dependencies": {
|
||||
"@docusaurus/core": "2.0.0-beta.17",
|
||||
"@docusaurus/preset-classic": "2.0.0-beta.17",
|
||||
"@docusaurus/core": "2.0.0-beta.18",
|
||||
"@docusaurus/preset-classic": "2.0.0-beta.18",
|
||||
"@mdx-js/react": "^1.6.22",
|
||||
"clsx": "^1.1.1",
|
||||
"react": "^17.0.2",
|
||||
|
@ -35,8 +35,8 @@
|
|||
"eslint-plugin-jsx-a11y": "^6.5.1",
|
||||
"eslint-plugin-react": "^7.29.4",
|
||||
"eslint-plugin-react-hooks": "^4.3.0",
|
||||
"prettier": "^2.5.1",
|
||||
"stylelint": "^14.5.3"
|
||||
"prettier": "^2.6.0",
|
||||
"stylelint": "^14.6.0"
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@docusaurus/cssnano-preset",
|
||||
"version": "2.0.0-beta.17",
|
||||
"version": "2.0.0-beta.18",
|
||||
"description": "Advanced cssnano preset for maximum optimization.",
|
||||
"main": "index.js",
|
||||
"license": "MIT",
|
||||
|
@ -13,8 +13,8 @@
|
|||
"directory": "packages/docusaurus-cssnano-preset"
|
||||
},
|
||||
"dependencies": {
|
||||
"cssnano-preset-advanced": "^5.2.5",
|
||||
"postcss": "^8.4.8",
|
||||
"cssnano-preset-advanced": "^5.3.1",
|
||||
"postcss": "^8.4.12",
|
||||
"postcss-sort-media-queries": "^4.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
@ -8,7 +8,8 @@ It exports a single object as default export: `logger`. `logger` has the followi
|
|||
|
||||
- Some useful colors.
|
||||
- Formatters. These functions have the same signature as the formatters of `picocolors`. Note that their implementations are not guaranteed. You should only care about their semantics.
|
||||
- `path`: formats a file path or URL.
|
||||
- `path`: formats a file path.
|
||||
- `url`: formats a URL.
|
||||
- `id`: formats an identifier.
|
||||
- `code`: formats a code snippet.
|
||||
- `subdue`: subdues the text.
|
||||
|
@ -34,6 +35,7 @@ To buy anything, enter code=${'buy x'} where code=${'x'} is the item's name; to
|
|||
An embedded expression is optionally preceded by a flag in the form `%[a-z]+` (a percentage sign followed by a few lowercase letters). If it's not preceded by any flag, it's printed out as-is. Otherwise, it's formatted with one of the formatters:
|
||||
|
||||
- `path=`: `path`
|
||||
- `url=`: `url`
|
||||
- `name=`: `id`
|
||||
- `code=`: `code`
|
||||
- `subdue=`: `subdue`
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@docusaurus/logger",
|
||||
"version": "2.0.0-beta.17",
|
||||
"version": "2.0.0-beta.18",
|
||||
"description": "An encapsulated logger for semantically formatting console messages.",
|
||||
"main": "./lib/index.js",
|
||||
"repository": {
|
||||
|
|
|
@ -11,7 +11,12 @@ import logger from '../index';
|
|||
describe('formatters', () => {
|
||||
it('path', () => {
|
||||
// cSpell:ignore mhey
|
||||
expect(logger.path('hey')).toMatchInlineSnapshot(`"[36m[4mhey[24m[39m"`);
|
||||
expect(logger.path('hey')).toMatchInlineSnapshot(`"[36m[4m\\"hey\\"[24m[39m"`);
|
||||
});
|
||||
it('url', () => {
|
||||
expect(logger.url('https://docusaurus.io/')).toMatchInlineSnapshot(
|
||||
`"[36m[4mhttps://docusaurus.io/[24m[39m"`,
|
||||
);
|
||||
});
|
||||
it('id', () => {
|
||||
expect(logger.name('hey')).toMatchInlineSnapshot(`"[34m[1mhey[22m[39m"`);
|
||||
|
@ -40,8 +45,7 @@ describe('interpolate', () => {
|
|||
expect(
|
||||
logger.interpolate`The package at path=${'packages/docusaurus'} has number=${10} files. name=${'Babel'} is exported here subdue=${'(as a preset)'} that you can with code=${"require.resolve('@docusaurus/core/lib/babel/preset')"}`,
|
||||
).toMatchInlineSnapshot(
|
||||
// cSpell:ignore mpackages
|
||||
`"The package at [36m[4mpackages/docusaurus[24m[39m has [33m10[39m files. [34m[1mBabel[22m[39m is exported here [90m(as a preset)[39m that you can with [36m\`require.resolve('@docusaurus/core/lib/babel/preset')\`[39m"`,
|
||||
`"The package at [36m[4m\\"packages/docusaurus\\"[24m[39m has [33m10[39m files. [34m[1mBabel[22m[39m is exported here [90m(as a preset)[39m that you can with [36m\`require.resolve('@docusaurus/core/lib/babel/preset')\`[39m"`,
|
||||
);
|
||||
});
|
||||
it('interpolates arrays with flags', () => {
|
||||
|
|
|
@ -9,7 +9,8 @@ import chalk, {type Chalk} from 'chalk';
|
|||
|
||||
type InterpolatableValue = string | number | (string | number)[];
|
||||
|
||||
const path = (msg: unknown): string => chalk.cyan(chalk.underline(msg));
|
||||
const path = (msg: unknown): string => chalk.cyan(chalk.underline(`"${msg}"`));
|
||||
const url = (msg: unknown): string => chalk.cyan(chalk.underline(msg));
|
||||
const name = (msg: unknown): string => chalk.blue(chalk.bold(msg));
|
||||
const code = (msg: unknown): string => chalk.cyan(`\`${msg}\``);
|
||||
const subdue: Chalk = chalk.gray;
|
||||
|
@ -30,6 +31,8 @@ function interpolate(
|
|||
switch (flag[0]) {
|
||||
case 'path=':
|
||||
return path;
|
||||
case 'url=':
|
||||
return url;
|
||||
case 'number=':
|
||||
return num;
|
||||
case 'name=':
|
||||
|
@ -131,6 +134,7 @@ const logger = {
|
|||
bold: chalk.bold,
|
||||
dim: chalk.dim,
|
||||
path,
|
||||
url,
|
||||
name,
|
||||
code,
|
||||
subdue,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@docusaurus/mdx-loader",
|
||||
"version": "2.0.0-beta.17",
|
||||
"version": "2.0.0-beta.18",
|
||||
"description": "Docusaurus Loader for MDX",
|
||||
"main": "lib/index.js",
|
||||
"types": "src/mdx-loader.d.ts",
|
||||
|
@ -18,10 +18,10 @@
|
|||
},
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/parser": "^7.17.7",
|
||||
"@babel/parser": "^7.17.8",
|
||||
"@babel/traverse": "^7.17.3",
|
||||
"@docusaurus/logger": "2.0.0-beta.17",
|
||||
"@docusaurus/utils": "2.0.0-beta.17",
|
||||
"@docusaurus/logger": "2.0.0-beta.18",
|
||||
"@docusaurus/utils": "2.0.0-beta.18",
|
||||
"@mdx-js/mdx": "^1.6.22",
|
||||
"escape-html": "^1.0.3",
|
||||
"file-loader": "^6.2.0",
|
||||
|
@ -36,7 +36,7 @@
|
|||
"webpack": "^5.70.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@docusaurus/types": "2.0.0-beta.17",
|
||||
"@docusaurus/types": "2.0.0-beta.18",
|
||||
"@types/escape-html": "^1.0.1",
|
||||
"@types/mdast": "^3.0.10",
|
||||
"@types/stringify-object": "^3.3.1",
|
||||
|
|
|
@ -21,21 +21,21 @@ import toc from './remark/toc';
|
|||
import unwrapMdxCodeBlocks from './remark/unwrapMdxCodeBlocks';
|
||||
import transformImage from './remark/transformImage';
|
||||
import transformLinks from './remark/transformLinks';
|
||||
import type {RemarkAndRehypePluginOptions} from '@docusaurus/mdx-loader';
|
||||
import type {MDXOptions} from '@docusaurus/mdx-loader';
|
||||
import type {LoaderContext} from 'webpack';
|
||||
|
||||
const {
|
||||
loaders: {inlineMarkdownImageFileLoader},
|
||||
} = getFileLoaderUtils();
|
||||
|
||||
const DEFAULT_OPTIONS: RemarkAndRehypePluginOptions = {
|
||||
const DEFAULT_OPTIONS: MDXOptions = {
|
||||
rehypePlugins: [],
|
||||
remarkPlugins: [unwrapMdxCodeBlocks, emoji, headings, toc],
|
||||
beforeDefaultRemarkPlugins: [],
|
||||
beforeDefaultRehypePlugins: [],
|
||||
};
|
||||
|
||||
type Options = RemarkAndRehypePluginOptions & {
|
||||
type Options = MDXOptions & {
|
||||
staticDirs: string[];
|
||||
siteDir: string;
|
||||
isMDXPartial?: (filePath: string) => boolean;
|
||||
|
@ -43,9 +43,9 @@ type Options = RemarkAndRehypePluginOptions & {
|
|||
removeContentTitle?: boolean;
|
||||
metadataPath?: string | ((filePath: string) => string);
|
||||
createAssets?: (metadata: {
|
||||
frontMatter: Record<string, unknown>;
|
||||
metadata: Record<string, unknown>;
|
||||
}) => Record<string, unknown>;
|
||||
frontMatter: {[key: string]: unknown};
|
||||
metadata: {[key: string]: unknown};
|
||||
}) => {[key: string]: unknown};
|
||||
filepath: string;
|
||||
};
|
||||
|
||||
|
@ -72,7 +72,7 @@ async function readMetadataPath(metadataPath: string) {
|
|||
*
|
||||
* `{image: "./myImage.png"}` => `{image: require("./myImage.png")}`
|
||||
*/
|
||||
function createAssetsExportCode(assets: Record<string, unknown>) {
|
||||
function createAssetsExportCode(assets: {[key: string]: unknown}) {
|
||||
if (Object.keys(assets).length === 0) {
|
||||
return 'undefined';
|
||||
}
|
||||
|
|
|
@ -7,12 +7,12 @@
|
|||
|
||||
import type {Plugin} from 'unified';
|
||||
|
||||
export type RemarkOrRehypePlugin =
|
||||
export type MDXPlugin =
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
[Plugin<any[]>, Record<string, unknown>] | Plugin<any[]>;
|
||||
export type RemarkAndRehypePluginOptions = {
|
||||
remarkPlugins: RemarkOrRehypePlugin[];
|
||||
rehypePlugins: RemarkOrRehypePlugin[];
|
||||
beforeDefaultRemarkPlugins: RemarkOrRehypePlugin[];
|
||||
beforeDefaultRehypePlugins: RemarkOrRehypePlugin[];
|
||||
[Plugin<any[]>, any] | Plugin<any[]>;
|
||||
export type MDXOptions = {
|
||||
remarkPlugins: MDXPlugin[];
|
||||
rehypePlugins: MDXPlugin[];
|
||||
beforeDefaultRemarkPlugins: MDXPlugin[];
|
||||
beforeDefaultRehypePlugins: MDXPlugin[];
|
||||
};
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`transformImage plugin does not choke on invalid image 1`] = `
|
||||
"<img loading=\\"lazy\\" alt={\\"invalid image\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/invalid.png\\").default} />
|
||||
"<img alt={\\"invalid image\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/invalid.png\\").default} />
|
||||
"
|
||||
`;
|
||||
|
||||
|
@ -19,29 +19,29 @@ exports[`transformImage plugin pathname protocol 1`] = `
|
|||
exports[`transformImage plugin transform md images to <img /> 1`] = `
|
||||
"
|
||||
|
||||
<img loading=\\"lazy\\" src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/img.png\\").default} width=\\"200\\" height=\\"200\\" />
|
||||
<img src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/img.png\\").default} width=\\"200\\" height=\\"200\\" />
|
||||
|
||||
<img loading=\\"lazy\\" alt={\\"img\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/img.png\\").default} width=\\"200\\" height=\\"200\\" />
|
||||
<img alt={\\"img\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/img.png\\").default} width=\\"200\\" height=\\"200\\" />
|
||||
|
||||
<img loading=\\"lazy\\" alt={\\"img from second static folder\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static2/img2.png\\").default} width=\\"256\\" height=\\"82\\" />
|
||||
<img alt={\\"img from second static folder\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static2/img2.png\\").default} width=\\"256\\" height=\\"82\\" />
|
||||
|
||||
<img loading=\\"lazy\\" alt={\\"img from second static folder\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static2/img2.png\\").default} width=\\"256\\" height=\\"82\\" />
|
||||
<img alt={\\"img from second static folder\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static2/img2.png\\").default} width=\\"256\\" height=\\"82\\" />
|
||||
|
||||
<img loading=\\"lazy\\" alt={\\"img with URL encoded chars\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static2/img2 copy.png\\").default} width=\\"256\\" height=\\"82\\" />
|
||||
<img alt={\\"img with URL encoded chars\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static2/img2 copy.png\\").default} width=\\"256\\" height=\\"82\\" />
|
||||
|
||||
<img loading=\\"lazy\\" alt={\\"img\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/img.png\\").default} title=\\"Title\\" width=\\"200\\" height=\\"200\\" /> <img loading=\\"lazy\\" alt={\\"img\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/img.png\\").default} width=\\"200\\" height=\\"200\\" />
|
||||
<img alt={\\"img\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/img.png\\").default} title=\\"Title\\" width=\\"200\\" height=\\"200\\" /> <img alt={\\"img\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/img.png\\").default} width=\\"200\\" height=\\"200\\" />
|
||||
|
||||
<img loading=\\"lazy\\" alt={\\"img with "quotes"\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/img.png\\").default} title=\\"'Quoted' title\\" width=\\"200\\" height=\\"200\\" />
|
||||
<img alt={\\"img with "quotes"\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/img.png\\").default} title=\\"'Quoted' title\\" width=\\"200\\" height=\\"200\\" />
|
||||
|
||||
<img loading=\\"lazy\\" alt={\\"site alias\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/img.png\\").default} width=\\"200\\" height=\\"200\\" />
|
||||
<img alt={\\"site alias\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/img.png\\").default} width=\\"200\\" height=\\"200\\" />
|
||||
|
||||
<img loading=\\"lazy\\" alt={\\"img with hash\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/img.png\\").default + '#light'} width=\\"200\\" height=\\"200\\" />
|
||||
<img loading=\\"lazy\\" alt={\\"img with hash\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/img.png\\").default + '#dark'} width=\\"200\\" height=\\"200\\" />
|
||||
<img alt={\\"img with hash\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/img.png\\").default + '#light'} width=\\"200\\" height=\\"200\\" />
|
||||
<img alt={\\"img with hash\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/img.png\\").default + '#dark'} width=\\"200\\" height=\\"200\\" />
|
||||
|
||||
<img loading=\\"lazy\\" alt={\\"img with query\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/img.png?w=10\\").default} width=\\"200\\" height=\\"200\\" />
|
||||
<img loading=\\"lazy\\" alt={\\"img with query\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/img.png?w=10&h=10\\").default} width=\\"200\\" height=\\"200\\" />
|
||||
<img alt={\\"img with query\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/img.png?w=10\\").default} width=\\"200\\" height=\\"200\\" />
|
||||
<img alt={\\"img with query\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/img.png?w=10&h=10\\").default} width=\\"200\\" height=\\"200\\" />
|
||||
|
||||
<img loading=\\"lazy\\" alt={\\"img with both\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/img.png?w=10&h=10\\").default + '#light'} width=\\"200\\" height=\\"200\\" />
|
||||
<img alt={\\"img with both\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/img.png?w=10&h=10\\").default + '#light'} width=\\"200\\" height=\\"200\\" />
|
||||
|
||||
## Heading
|
||||
|
||||
|
|
|
@ -80,7 +80,7 @@ ${(err as Error).message}`;
|
|||
);
|
||||
|
||||
(jsxNode as Literal).type = 'jsx';
|
||||
jsxNode.value = `<img loading="lazy" ${alt}src={${src}}${title}${width}${height} />`;
|
||||
jsxNode.value = `<img ${alt}src={${src}}${title}${width}${height} />`;
|
||||
}
|
||||
|
||||
async function ensureImageFileExist(imagePath: string, sourceFilePath: string) {
|
||||
|
|
|
@ -46,7 +46,7 @@ exports[`transformAsset plugin transform md links to <a /> 1`] = `
|
|||
|
||||
<a target=\\"_blank\\" href={require('!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./static/staticAsset.pdf').default}>Just staticAsset.pdf</a>, and <a target=\\"_blank\\" href={require('!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./static/staticAsset.pdf').default}><strong>awesome</strong> staticAsset 2.pdf 'It is really "AWESOME"'</a>, but also <a target=\\"_blank\\" href={require('!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./static/staticAsset.pdf').default}>coded <code>staticAsset 3.pdf</code></a>
|
||||
|
||||
<a target=\\"_blank\\" href={require('!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./static/staticAssetImage.png').default}><img loading=\\"lazy\\" alt={\\"Clickable Docusaurus logo\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/staticAssetImage.png\\").default} width=\\"200\\" height=\\"200\\" /></a>
|
||||
<a target=\\"_blank\\" href={require('!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./static/staticAssetImage.png').default}><img alt={\\"Clickable Docusaurus logo\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/staticAssetImage.png\\").default} width=\\"200\\" height=\\"200\\" /></a>
|
||||
|
||||
<a target=\\"_blank\\" href={require('!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./asset.pdf').default}><span style={{color: \\"red\\"}}>Stylized link to asset file</span></a>
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@docusaurus/migrate",
|
||||
"version": "2.0.0-beta.17",
|
||||
"version": "2.0.0-beta.18",
|
||||
"description": "A CLI tool to migrate from older versions of Docusaurus.",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
|
@ -23,8 +23,8 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@babel/preset-env": "^7.16.11",
|
||||
"@docusaurus/logger": "2.0.0-beta.17",
|
||||
"@docusaurus/utils": "2.0.0-beta.17",
|
||||
"@docusaurus/logger": "2.0.0-beta.18",
|
||||
"@docusaurus/utils": "2.0.0-beta.18",
|
||||
"@mapbox/hast-util-to-jsx": "^2.0.0",
|
||||
"color": "^4.2.1",
|
||||
"commander": "^5.1.0",
|
||||
|
|
|
@ -67,7 +67,7 @@ ${
|
|||
type MigrationContext = {
|
||||
siteDir: string;
|
||||
newDir: string;
|
||||
deps: Record<string, string>;
|
||||
deps: {[key: string]: string};
|
||||
shouldMigrateMdFiles: boolean;
|
||||
shouldMigratePages: boolean;
|
||||
v1Config: VersionOneConfig;
|
||||
|
@ -83,7 +83,7 @@ export async function migrateDocusaurusProject(
|
|||
async function createMigrationContext(): Promise<MigrationContext> {
|
||||
const v1Config = importFresh(`${siteDir}/siteConfig`) as VersionOneConfig;
|
||||
logger.info('Starting migration from v1 to v2...');
|
||||
const deps: Record<string, string> = {
|
||||
const deps = {
|
||||
'@docusaurus/core': DOCUSAURUS_VERSION,
|
||||
'@docusaurus/preset-classic': DOCUSAURUS_VERSION,
|
||||
clsx: '^1.1.1',
|
||||
|
@ -206,7 +206,7 @@ export function createConfigFile({
|
|||
'v1Config' | 'siteDir' | 'newDir'
|
||||
>): VersionTwoConfig {
|
||||
const siteConfig = v1Config;
|
||||
const customConfigFields: Record<string, unknown> = {};
|
||||
const customConfigFields: {[key: string]: unknown} = {};
|
||||
// add fields that are unknown to v2 to customConfigFields
|
||||
Object.keys(siteConfig).forEach((key) => {
|
||||
const knownFields = [
|
||||
|
@ -564,7 +564,7 @@ async function migrateVersionedSidebar(
|
|||
};
|
||||
});
|
||||
return acc;
|
||||
}, {} as Record<string, Array<string | Record<string, unknown>>>);
|
||||
}, {} as {[key: string]: Array<string | {[key: string]: unknown}>});
|
||||
return topLevel;
|
||||
},
|
||||
{},
|
||||
|
@ -702,9 +702,9 @@ async function migrateLatestDocs(context: MigrationContext) {
|
|||
async function migratePackageFile(context: MigrationContext): Promise<void> {
|
||||
const {deps, siteDir, newDir} = context;
|
||||
const packageFile = importFresh(`${siteDir}/package.json`) as {
|
||||
scripts?: Record<string, string>;
|
||||
dependencies?: Record<string, string>;
|
||||
devDependencies?: Record<string, string>;
|
||||
scripts?: {[key: string]: string};
|
||||
dependencies?: {[key: string]: string};
|
||||
devDependencies?: {[key: string]: string};
|
||||
[otherKey: string]: unknown;
|
||||
};
|
||||
packageFile.scripts = {
|
||||
|
|
|
@ -33,8 +33,8 @@ export type SidebarEntry =
|
|||
|
||||
export type SidebarEntries = {
|
||||
[key: string]:
|
||||
| Record<string, unknown>
|
||||
| Array<Record<string, unknown> | string>;
|
||||
| {[key: string]: unknown}
|
||||
| Array<{[key: string]: unknown} | string>;
|
||||
};
|
||||
|
||||
export interface VersionTwoConfig {
|
||||
|
@ -58,7 +58,7 @@ export interface VersionTwoConfig {
|
|||
logo?: {
|
||||
src?: string;
|
||||
};
|
||||
items: Array<Record<string, unknown> | null>;
|
||||
items: Array<{[key: string]: unknown} | null>;
|
||||
};
|
||||
image?: string;
|
||||
footer: {
|
||||
|
@ -74,7 +74,7 @@ export interface VersionTwoConfig {
|
|||
src?: string;
|
||||
};
|
||||
};
|
||||
algolia?: Record<string, unknown>;
|
||||
algolia?: {[key: string]: unknown};
|
||||
};
|
||||
customFields: {
|
||||
[key: string]: unknown;
|
||||
|
@ -111,16 +111,16 @@ export type VersionOneConfig = {
|
|||
copyright?: string;
|
||||
editUrl?: string;
|
||||
customDocsPath?: string;
|
||||
users?: Array<Record<string, unknown>>;
|
||||
users?: Array<{[key: string]: unknown}>;
|
||||
disableHeaderTitle?: string;
|
||||
disableTitleTagline?: string;
|
||||
separateCss?: Array<Record<string, unknown>>;
|
||||
separateCss?: Array<{[key: string]: unknown}>;
|
||||
footerIcon?: string;
|
||||
translationRecruitingLink?: string;
|
||||
algolia?: Record<string, unknown>;
|
||||
algolia?: {[key: string]: unknown};
|
||||
gaTrackingId?: string;
|
||||
gaGtag?: boolean;
|
||||
highlight?: Record<string, unknown>;
|
||||
highlight?: {[key: string]: unknown};
|
||||
markdownPlugins?: Array<() => void>;
|
||||
scripts?: Array<{src: string; [key: string]: unknown} | string>;
|
||||
stylesheets?: Array<{href: string; [key: string]: unknown} | string>;
|
||||
|
@ -133,5 +133,5 @@ export type VersionOneConfig = {
|
|||
ogImage?: string;
|
||||
cleanUrl?: boolean;
|
||||
scrollToTop?: boolean;
|
||||
scrollToTopOptions?: Record<string, unknown>;
|
||||
scrollToTopOptions?: {[key: string]: unknown};
|
||||
};
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@docusaurus/module-type-aliases",
|
||||
"version": "2.0.0-beta.17",
|
||||
"version": "2.0.0-beta.18",
|
||||
"description": "Docusaurus module type aliases.",
|
||||
"types": "./src/index.d.ts",
|
||||
"publishConfig": {
|
||||
|
@ -12,7 +12,7 @@
|
|||
"directory": "packages/docusaurus-module-type-aliases"
|
||||
},
|
||||
"dependencies": {
|
||||
"@docusaurus/types": "2.0.0-beta.17",
|
||||
"@docusaurus/types": "2.0.0-beta.18",
|
||||
"@types/react": "*",
|
||||
"@types/react-router-config": "*",
|
||||
"@types/react-router-dom": "*",
|
||||
|
|
|
@ -20,9 +20,9 @@ declare module '@generated/docusaurus.config' {
|
|||
}
|
||||
|
||||
declare module '@generated/site-metadata' {
|
||||
import type {DocusaurusSiteMetadata} from '@docusaurus/types';
|
||||
import type {SiteMetadata} from '@docusaurus/types';
|
||||
|
||||
const siteMetadata: DocusaurusSiteMetadata;
|
||||
const siteMetadata: SiteMetadata;
|
||||
export = siteMetadata;
|
||||
}
|
||||
|
||||
|
@ -44,35 +44,26 @@ declare module '@generated/routes' {
|
|||
declare module '@generated/routesChunkNames' {
|
||||
import type {RouteChunksTree} from '@docusaurus/types';
|
||||
|
||||
const routesChunkNames: Record<string, RouteChunksTree>;
|
||||
const routesChunkNames: {[route: string]: RouteChunksTree};
|
||||
export = routesChunkNames;
|
||||
}
|
||||
|
||||
declare module '@generated/globalData' {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const globalData: Record<string, any>;
|
||||
import type {GlobalData} from '@docusaurus/types';
|
||||
|
||||
const globalData: GlobalData;
|
||||
export = globalData;
|
||||
}
|
||||
|
||||
declare module '@generated/i18n' {
|
||||
const i18n: {
|
||||
defaultLocale: string;
|
||||
locales: [string, ...string[]];
|
||||
currentLocale: string;
|
||||
localeConfigs: Record<
|
||||
string,
|
||||
{
|
||||
label: string;
|
||||
direction: string;
|
||||
htmlLang: string;
|
||||
}
|
||||
>;
|
||||
};
|
||||
import type {I18n} from '@docusaurus/types';
|
||||
|
||||
const i18n: I18n;
|
||||
export = i18n;
|
||||
}
|
||||
|
||||
declare module '@generated/codeTranslations' {
|
||||
const codeTranslations: Record<string, string>;
|
||||
const codeTranslations: {[msgId: string]: string};
|
||||
export = codeTranslations;
|
||||
}
|
||||
|
||||
|
@ -172,10 +163,9 @@ declare module '@docusaurus/Interpolate' {
|
|||
? Key | ExtractInterpolatePlaceholders<Rest>
|
||||
: never;
|
||||
|
||||
export type InterpolateValues<
|
||||
Str extends string,
|
||||
Value extends ReactNode,
|
||||
> = Record<ExtractInterpolatePlaceholders<Str>, Value>;
|
||||
export type InterpolateValues<Str extends string, Value extends ReactNode> = {
|
||||
[key in ExtractInterpolatePlaceholders<Str>]: Value;
|
||||
};
|
||||
|
||||
// If all the values are plain strings, interpolate returns a simple string
|
||||
export function interpolate<Str extends string>(
|
||||
|
@ -320,17 +310,18 @@ declare module '@docusaurus/renderRoutes' {
|
|||
}
|
||||
|
||||
declare module '@docusaurus/useGlobalData' {
|
||||
export function useAllPluginInstancesData<T = unknown>(
|
||||
pluginName: string,
|
||||
): Record<string, T>;
|
||||
import type {GlobalData} from '@docusaurus/types';
|
||||
|
||||
export function usePluginData<T = unknown>(
|
||||
export function useAllPluginInstancesData(
|
||||
pluginName: string,
|
||||
): GlobalData[string];
|
||||
|
||||
export function usePluginData(
|
||||
pluginName: string,
|
||||
pluginId?: string,
|
||||
): T;
|
||||
): GlobalData[string][string];
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export default function useGlobalData(): Record<string, any>;
|
||||
export default function useGlobalData(): GlobalData;
|
||||
}
|
||||
|
||||
declare module '*.svg' {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@docusaurus/plugin-client-redirects",
|
||||
"version": "2.0.0-beta.17",
|
||||
"version": "2.0.0-beta.18",
|
||||
"description": "Client redirects plugin for Docusaurus.",
|
||||
"main": "lib/index.js",
|
||||
"types": "src/plugin-client-redirects.d.ts",
|
||||
|
@ -18,18 +18,18 @@
|
|||
},
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@docusaurus/core": "2.0.0-beta.17",
|
||||
"@docusaurus/logger": "2.0.0-beta.17",
|
||||
"@docusaurus/utils": "2.0.0-beta.17",
|
||||
"@docusaurus/utils-common": "2.0.0-beta.17",
|
||||
"@docusaurus/utils-validation": "2.0.0-beta.17",
|
||||
"@docusaurus/core": "2.0.0-beta.18",
|
||||
"@docusaurus/logger": "2.0.0-beta.18",
|
||||
"@docusaurus/utils": "2.0.0-beta.18",
|
||||
"@docusaurus/utils-common": "2.0.0-beta.18",
|
||||
"@docusaurus/utils-validation": "2.0.0-beta.18",
|
||||
"eta": "^1.12.3",
|
||||
"fs-extra": "^10.0.1",
|
||||
"lodash": "^4.17.21",
|
||||
"tslib": "^2.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@docusaurus/types": "2.0.0-beta.17"
|
||||
"@docusaurus/types": "2.0.0-beta.18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.4 || ^17.0.0",
|
||||
|
|
|
@ -15,11 +15,14 @@ function testValidate(options: Options) {
|
|||
|
||||
describe('normalizePluginOptions', () => {
|
||||
it('returns default options for undefined user options', () => {
|
||||
expect(testValidate(undefined)).toEqual(DEFAULT_OPTIONS);
|
||||
expect(testValidate(undefined)).toEqual({
|
||||
...DEFAULT_OPTIONS,
|
||||
id: 'default',
|
||||
});
|
||||
});
|
||||
|
||||
it('returns default options for empty user options', () => {
|
||||
expect(testValidate(undefined)).toEqual(DEFAULT_OPTIONS);
|
||||
expect(testValidate({})).toEqual({...DEFAULT_OPTIONS, id: 'default'});
|
||||
});
|
||||
|
||||
it('overrides one default options with valid user options', () => {
|
||||
|
|
|
@ -13,7 +13,7 @@ const getCompiledRedirectPageTemplate = _.memoize(() =>
|
|||
eta.compile(redirectPageTemplate.trim()),
|
||||
);
|
||||
|
||||
function renderRedirectPageTemplate(data: Record<string, unknown>) {
|
||||
function renderRedirectPageTemplate(data: {toUrl: string}) {
|
||||
const compiled = getCompiledRedirectPageTemplate();
|
||||
return compiled(data, eta.defaultConfig);
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import type {LoadContext, Plugin, Props} from '@docusaurus/types';
|
||||
import type {LoadContext, Plugin} from '@docusaurus/types';
|
||||
import type {PluginContext, RedirectMetadata} from './types';
|
||||
import type {PluginOptions} from '@docusaurus/plugin-client-redirects';
|
||||
|
||||
|
@ -24,7 +24,7 @@ export default function pluginClientRedirectsPages(
|
|||
|
||||
return {
|
||||
name: 'docusaurus-plugin-client-redirects',
|
||||
async postBuild(props: Props) {
|
||||
async postBuild(props) {
|
||||
const pluginContext: PluginContext = {
|
||||
relativeRoutesPaths: props.routesPaths.map(
|
||||
(path) => `${addLeadingSlash(removePrefix(path, props.baseUrl))}`,
|
||||
|
|
|
@ -7,12 +7,10 @@
|
|||
|
||||
import type {
|
||||
PluginOptions,
|
||||
Options,
|
||||
RedirectOption,
|
||||
} from '@docusaurus/plugin-client-redirects';
|
||||
import type {
|
||||
OptionValidationContext,
|
||||
ValidationResult,
|
||||
} from '@docusaurus/types';
|
||||
import type {OptionValidationContext} from '@docusaurus/types';
|
||||
import {Joi, PathnameSchema} from '@docusaurus/utils-validation';
|
||||
|
||||
export const DEFAULT_OPTIONS: Partial<PluginOptions> = {
|
||||
|
@ -47,6 +45,6 @@ const UserOptionsSchema = Joi.object<PluginOptions>({
|
|||
export function validateOptions({
|
||||
validate,
|
||||
options: userOptions,
|
||||
}: OptionValidationContext<PluginOptions>): ValidationResult<PluginOptions> {
|
||||
}: OptionValidationContext<Options, PluginOptions>): PluginOptions {
|
||||
return validate(UserOptionsSchema, userOptions);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@docusaurus/plugin-content-blog",
|
||||
"version": "2.0.0-beta.17",
|
||||
"version": "2.0.0-beta.18",
|
||||
"description": "Blog plugin for Docusaurus.",
|
||||
"main": "lib/index.js",
|
||||
"types": "src/plugin-content-blog.d.ts",
|
||||
|
@ -18,12 +18,12 @@
|
|||
},
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@docusaurus/core": "2.0.0-beta.17",
|
||||
"@docusaurus/logger": "2.0.0-beta.17",
|
||||
"@docusaurus/mdx-loader": "2.0.0-beta.17",
|
||||
"@docusaurus/utils": "2.0.0-beta.17",
|
||||
"@docusaurus/utils-common": "2.0.0-beta.17",
|
||||
"@docusaurus/utils-validation": "2.0.0-beta.17",
|
||||
"@docusaurus/core": "2.0.0-beta.18",
|
||||
"@docusaurus/logger": "2.0.0-beta.18",
|
||||
"@docusaurus/mdx-loader": "2.0.0-beta.18",
|
||||
"@docusaurus/utils": "2.0.0-beta.18",
|
||||
"@docusaurus/utils-common": "2.0.0-beta.18",
|
||||
"@docusaurus/utils-validation": "2.0.0-beta.18",
|
||||
"cheerio": "^1.0.0-rc.10",
|
||||
"feed": "^4.2.2",
|
||||
"fs-extra": "^10.0.1",
|
||||
|
@ -35,7 +35,7 @@
|
|||
"webpack": "^5.70.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@docusaurus/types": "2.0.0-beta.17",
|
||||
"@docusaurus/types": "2.0.0-beta.18",
|
||||
"escape-string-regexp": "^4.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`validateOptions throws Error in case of invalid feed type 1`] = `"\\"feedOptions.type\\" does not match any of the allowed types"`;
|
||||
|
||||
exports[`validateOptions throws Error in case of invalid options 1`] = `"\\"postsPerPage\\" must be greater than or equal to 1"`;
|
|
@ -1,5 +0,0 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`blog plugin options schema throws Error in case of invalid feed type 1`] = `[ValidationError: "feedOptions.type" does not match any of the allowed types]`;
|
||||
|
||||
exports[`blog plugin options schema throws Error in case of invalid options 1`] = `[ValidationError: "postsPerPage" must be greater than or equal to 1]`;
|
|
@ -11,7 +11,7 @@ import fs from 'fs-extra';
|
|||
import {createBlogFeedFiles} from '../feed';
|
||||
import type {LoadContext, I18n} from '@docusaurus/types';
|
||||
import type {BlogContentPaths} from '../types';
|
||||
import {DEFAULT_OPTIONS} from '../pluginOptionSchema';
|
||||
import {DEFAULT_OPTIONS} from '../options';
|
||||
import {generateBlogPosts} from '../blogUtils';
|
||||
import type {PluginOptions} from '@docusaurus/plugin-content-blog';
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import {validateBlogPostFrontMatter} from '../blogFrontMatter';
|
||||
import {validateBlogPostFrontMatter} from '../frontMatter';
|
||||
import escapeStringRegexp from 'escape-string-regexp';
|
||||
import type {BlogPostFrontMatter} from '@docusaurus/plugin-content-blog';
|
||||
|
||||
|
@ -15,11 +15,11 @@ function testField(params: {
|
|||
fieldName: keyof BlogPostFrontMatter;
|
||||
validFrontMatters: BlogPostFrontMatter[];
|
||||
convertibleFrontMatter?: [
|
||||
ConvertibleFrontMatter: Record<string, unknown>,
|
||||
ConvertibleFrontMatter: {[key: string]: unknown},
|
||||
ConvertedFrontMatter: BlogPostFrontMatter,
|
||||
][];
|
||||
invalidFrontMatters?: [
|
||||
InvalidFrontMatter: Record<string, unknown>,
|
||||
InvalidFrontMatter: {[key: string]: unknown},
|
||||
ErrorMessage: string,
|
||||
][];
|
||||
}) {
|
|
@ -9,9 +9,9 @@ import {jest} from '@jest/globals';
|
|||
import path from 'path';
|
||||
import pluginContentBlog from '../index';
|
||||
import type {DocusaurusConfig, LoadContext, I18n} from '@docusaurus/types';
|
||||
import {PluginOptionSchema} from '../pluginOptionSchema';
|
||||
import {validateOptions} from '../options';
|
||||
import type {BlogPost} from '../types';
|
||||
import type {Joi} from '@docusaurus/utils-validation';
|
||||
import {normalizePluginOptions} from '@docusaurus/utils-validation';
|
||||
import {posixPath, getFileCommitDate} from '@docusaurus/utils';
|
||||
import type {
|
||||
PluginOptions,
|
||||
|
@ -47,18 +47,6 @@ function getI18n(locale: string): I18n {
|
|||
|
||||
const DefaultI18N: I18n = getI18n('en');
|
||||
|
||||
function validateAndNormalize(
|
||||
schema: Joi.ObjectSchema,
|
||||
options: Partial<PluginOptions>,
|
||||
) {
|
||||
const {value, error} = schema.validate(options);
|
||||
if (error) {
|
||||
throw error;
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
const PluginPath = 'blog';
|
||||
|
||||
const BaseEditUrl = 'https://baseEditUrl.com/edit';
|
||||
|
@ -81,11 +69,14 @@ const getPlugin = async (
|
|||
generatedFilesDir,
|
||||
i18n,
|
||||
} as LoadContext,
|
||||
validateAndNormalize(PluginOptionSchema, {
|
||||
path: PluginPath,
|
||||
editUrl: BaseEditUrl,
|
||||
...pluginOptions,
|
||||
}),
|
||||
validateOptions({
|
||||
validate: normalizePluginOptions,
|
||||
options: {
|
||||
path: PluginPath,
|
||||
editUrl: BaseEditUrl,
|
||||
...pluginOptions,
|
||||
},
|
||||
}) as PluginOptions,
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,160 @@
|
|||
/**
|
||||
* 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 {validateOptions, DEFAULT_OPTIONS} from '../options';
|
||||
import {normalizePluginOptions} from '@docusaurus/utils-validation';
|
||||
import type {Options} from '@docusaurus/plugin-content-blog';
|
||||
|
||||
function testValidate(options: Options) {
|
||||
return validateOptions({validate: normalizePluginOptions, options});
|
||||
}
|
||||
|
||||
// the type of remark/rehype plugins can be either function, object or array
|
||||
const markdownPluginsFunctionStub = () => {};
|
||||
const markdownPluginsObjectStub = {};
|
||||
|
||||
const defaultOptions = {...DEFAULT_OPTIONS, id: 'default'};
|
||||
|
||||
describe('validateOptions', () => {
|
||||
it('returns default options for undefined user options', () => {
|
||||
expect(testValidate(undefined)).toEqual(defaultOptions);
|
||||
});
|
||||
|
||||
it('returns default options for empty user options', () => {
|
||||
expect(testValidate({})).toEqual(defaultOptions);
|
||||
});
|
||||
|
||||
it('accepts correctly defined user options', () => {
|
||||
const userOptions = {
|
||||
...defaultOptions,
|
||||
feedOptions: {type: 'rss' as const, title: 'myTitle'},
|
||||
path: 'not_blog',
|
||||
routeBasePath: 'myBlog',
|
||||
postsPerPage: 5,
|
||||
include: ['api/*', 'docs/*'],
|
||||
};
|
||||
expect(testValidate(userOptions)).toEqual({
|
||||
...userOptions,
|
||||
feedOptions: {type: ['rss'], title: 'myTitle', copyright: ''},
|
||||
});
|
||||
});
|
||||
|
||||
it('accepts valid user options', () => {
|
||||
const userOptions = {
|
||||
...defaultOptions,
|
||||
routeBasePath: 'myBlog',
|
||||
beforeDefaultRemarkPlugins: [],
|
||||
beforeDefaultRehypePlugins: [markdownPluginsFunctionStub],
|
||||
remarkPlugins: [[markdownPluginsFunctionStub, {option1: '42'}]],
|
||||
rehypePlugins: [
|
||||
markdownPluginsObjectStub,
|
||||
[markdownPluginsFunctionStub, {option1: '42'}],
|
||||
],
|
||||
};
|
||||
expect(testValidate(userOptions)).toEqual(userOptions);
|
||||
});
|
||||
|
||||
it('throws Error in case of invalid options', () => {
|
||||
expect(() =>
|
||||
testValidate({
|
||||
path: 'not_blog',
|
||||
postsPerPage: -1,
|
||||
include: ['api/*', 'docs/*'],
|
||||
routeBasePath: 'not_blog',
|
||||
}),
|
||||
).toThrowErrorMatchingSnapshot();
|
||||
});
|
||||
|
||||
it('throws Error in case of invalid feed type', () => {
|
||||
expect(() =>
|
||||
testValidate({
|
||||
feedOptions: {
|
||||
type: 'none',
|
||||
},
|
||||
}),
|
||||
).toThrowErrorMatchingSnapshot();
|
||||
});
|
||||
|
||||
it('converts all feed type to array with other feed type', () => {
|
||||
expect(
|
||||
testValidate({
|
||||
feedOptions: {type: 'all'},
|
||||
}),
|
||||
).toEqual({
|
||||
...defaultOptions,
|
||||
feedOptions: {type: ['rss', 'atom', 'json'], copyright: ''},
|
||||
});
|
||||
});
|
||||
|
||||
it('accepts null type and return same', () => {
|
||||
expect(
|
||||
testValidate({
|
||||
feedOptions: {type: null},
|
||||
}),
|
||||
).toEqual({
|
||||
...defaultOptions,
|
||||
feedOptions: {type: null},
|
||||
});
|
||||
});
|
||||
|
||||
it('contains array with rss + atom for missing feed type', () => {
|
||||
expect(
|
||||
testValidate({
|
||||
feedOptions: {},
|
||||
}),
|
||||
).toEqual(defaultOptions);
|
||||
});
|
||||
|
||||
it('has array with rss + atom, title for missing feed type', () => {
|
||||
expect(
|
||||
testValidate({
|
||||
feedOptions: {title: 'title'},
|
||||
}),
|
||||
).toEqual({
|
||||
...defaultOptions,
|
||||
feedOptions: {type: ['rss', 'atom'], title: 'title', copyright: ''},
|
||||
});
|
||||
});
|
||||
|
||||
it('accepts 0 sidebar count', () => {
|
||||
const userOptions = {blogSidebarCount: 0};
|
||||
expect(testValidate(userOptions)).toEqual({
|
||||
...defaultOptions,
|
||||
...userOptions,
|
||||
});
|
||||
});
|
||||
|
||||
it('accepts "ALL" sidebar count', () => {
|
||||
const userOptions = {blogSidebarCount: 'ALL' as const};
|
||||
expect(testValidate(userOptions)).toEqual({
|
||||
...defaultOptions,
|
||||
...userOptions,
|
||||
});
|
||||
});
|
||||
|
||||
it('rejects "abcdef" sidebar count', () => {
|
||||
const userOptions = {blogSidebarCount: 'abcdef'};
|
||||
expect(() => testValidate(userOptions)).toThrowErrorMatchingInlineSnapshot(
|
||||
`"\\"blogSidebarCount\\" must be one of [ALL, number]"`,
|
||||
);
|
||||
});
|
||||
|
||||
it('accepts "all posts" sidebar title', () => {
|
||||
const userOptions = {blogSidebarTitle: 'all posts'};
|
||||
expect(testValidate(userOptions)).toEqual({
|
||||
...defaultOptions,
|
||||
...userOptions,
|
||||
});
|
||||
});
|
||||
|
||||
it('rejects 42 sidebar title', () => {
|
||||
const userOptions = {blogSidebarTitle: 42};
|
||||
expect(() => testValidate(userOptions)).toThrowErrorMatchingInlineSnapshot(
|
||||
`"\\"blogSidebarTitle\\" must be a string"`,
|
||||
);
|
||||
});
|
||||
});
|
|
@ -1,152 +0,0 @@
|
|||
/**
|
||||
* 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 {PluginOptionSchema, DEFAULT_OPTIONS} from '../pluginOptionSchema';
|
||||
|
||||
// the type of remark/rehype plugins can be either function, object or array
|
||||
const markdownPluginsFunctionStub = () => {};
|
||||
const markdownPluginsObjectStub = {};
|
||||
|
||||
describe('blog plugin options schema', () => {
|
||||
it('normalizes options', () => {
|
||||
const {value, error} = PluginOptionSchema.validate({});
|
||||
expect(value).toEqual(DEFAULT_OPTIONS);
|
||||
expect(error).toBeUndefined();
|
||||
});
|
||||
|
||||
it('accepts correctly defined user options', () => {
|
||||
const userOptions = {
|
||||
...DEFAULT_OPTIONS,
|
||||
feedOptions: {type: 'rss', title: 'myTitle'},
|
||||
path: 'not_blog',
|
||||
routeBasePath: 'myBlog',
|
||||
postsPerPage: 5,
|
||||
include: ['api/*', 'docs/*'],
|
||||
};
|
||||
const {value, error} = PluginOptionSchema.validate(userOptions);
|
||||
expect(value).toEqual({
|
||||
...userOptions,
|
||||
feedOptions: {type: ['rss'], title: 'myTitle', copyright: ''},
|
||||
});
|
||||
expect(error).toBeUndefined();
|
||||
});
|
||||
|
||||
it('accepts valid user options', async () => {
|
||||
const userOptions = {
|
||||
...DEFAULT_OPTIONS,
|
||||
routeBasePath: 'myBlog',
|
||||
beforeDefaultRemarkPlugins: [],
|
||||
beforeDefaultRehypePlugins: [markdownPluginsFunctionStub],
|
||||
remarkPlugins: [[markdownPluginsFunctionStub, {option1: '42'}]],
|
||||
rehypePlugins: [
|
||||
markdownPluginsObjectStub,
|
||||
[markdownPluginsFunctionStub, {option1: '42'}],
|
||||
],
|
||||
};
|
||||
const {value, error} = PluginOptionSchema.validate(userOptions);
|
||||
expect(value).toEqual(userOptions);
|
||||
expect(error).toBeUndefined();
|
||||
});
|
||||
|
||||
it('throws Error in case of invalid options', () => {
|
||||
const {error} = PluginOptionSchema.validate({
|
||||
path: 'not_blog',
|
||||
postsPerPage: -1,
|
||||
include: ['api/*', 'docs/*'],
|
||||
routeBasePath: 'not_blog',
|
||||
});
|
||||
|
||||
expect(error).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('throws Error in case of invalid feed type', () => {
|
||||
const {error} = PluginOptionSchema.validate({
|
||||
feedOptions: {
|
||||
type: 'none',
|
||||
},
|
||||
});
|
||||
|
||||
expect(error).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('converts all feed type to array with other feed type', () => {
|
||||
const {value} = PluginOptionSchema.validate({
|
||||
feedOptions: {type: 'all'},
|
||||
});
|
||||
expect(value).toEqual({
|
||||
...DEFAULT_OPTIONS,
|
||||
feedOptions: {type: ['rss', 'atom', 'json'], copyright: ''},
|
||||
});
|
||||
});
|
||||
|
||||
it('accepts null type and return same', () => {
|
||||
const {value, error} = PluginOptionSchema.validate({
|
||||
feedOptions: {type: null},
|
||||
});
|
||||
expect(value).toEqual({
|
||||
...DEFAULT_OPTIONS,
|
||||
feedOptions: {type: null},
|
||||
});
|
||||
expect(error).toBeUndefined();
|
||||
});
|
||||
|
||||
it('contains array with rss + atom for missing feed type', () => {
|
||||
const {value} = PluginOptionSchema.validate({
|
||||
feedOptions: {},
|
||||
});
|
||||
expect(value).toEqual(DEFAULT_OPTIONS);
|
||||
});
|
||||
|
||||
it('has array with rss + atom, title for missing feed type', () => {
|
||||
const {value} = PluginOptionSchema.validate({
|
||||
feedOptions: {title: 'title'},
|
||||
});
|
||||
expect(value).toEqual({
|
||||
...DEFAULT_OPTIONS,
|
||||
feedOptions: {type: ['rss', 'atom'], title: 'title', copyright: ''},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('blog sidebar', () => {
|
||||
it('accepts 0 sidebar count', () => {
|
||||
const userOptions = {blogSidebarCount: 0};
|
||||
const {value, error} = PluginOptionSchema.validate(userOptions);
|
||||
expect(value).toEqual({...DEFAULT_OPTIONS, ...userOptions});
|
||||
expect(error).toBeUndefined();
|
||||
});
|
||||
|
||||
it('accepts "ALL" sidebar count', () => {
|
||||
const userOptions = {blogSidebarCount: 'ALL'};
|
||||
const {value, error} = PluginOptionSchema.validate(userOptions);
|
||||
expect(value).toEqual({...DEFAULT_OPTIONS, ...userOptions});
|
||||
expect(error).toBeUndefined();
|
||||
});
|
||||
|
||||
it('rejects "abcdef" sidebar count', () => {
|
||||
const userOptions = {blogSidebarCount: 'abcdef'};
|
||||
const {error} = PluginOptionSchema.validate(userOptions);
|
||||
expect(error).toMatchInlineSnapshot(
|
||||
`[ValidationError: "blogSidebarCount" must be one of [ALL, number]]`,
|
||||
);
|
||||
});
|
||||
|
||||
it('accepts "all posts" sidebar title', () => {
|
||||
const userOptions = {blogSidebarTitle: 'all posts'};
|
||||
const {value, error} = PluginOptionSchema.validate(userOptions);
|
||||
expect(value).toEqual({...DEFAULT_OPTIONS, ...userOptions});
|
||||
expect(error).toBeUndefined();
|
||||
});
|
||||
|
||||
it('rejects 42 sidebar title', () => {
|
||||
const userOptions = {blogSidebarTitle: 42};
|
||||
const {error} = PluginOptionSchema.validate(userOptions);
|
||||
expect(error).toMatchInlineSnapshot(
|
||||
`[ValidationError: "blogSidebarTitle" must be a string]`,
|
||||
);
|
||||
});
|
||||
});
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
import type {BlogPost, BlogContent} from '../types';
|
||||
import {getTranslationFiles, translateContent} from '../translations';
|
||||
import {DEFAULT_OPTIONS} from '../pluginOptionSchema';
|
||||
import {DEFAULT_OPTIONS} from '../options';
|
||||
import {updateTranslationFileMessages} from '@docusaurus/utils';
|
||||
import type {PluginOptions} from '@docusaurus/plugin-content-blog';
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ import type {
|
|||
BlogPostFrontMatterAuthors,
|
||||
} from '@docusaurus/plugin-content-blog';
|
||||
|
||||
export type AuthorsMap = Record<string, Author>;
|
||||
export type AuthorsMap = {[authorKey: string]: Author};
|
||||
|
||||
const AuthorsMapSchema = Joi.object<AuthorsMap>()
|
||||
.pattern(
|
||||
|
|
|
@ -31,7 +31,7 @@ import {
|
|||
getContentPathList,
|
||||
} from '@docusaurus/utils';
|
||||
import type {LoadContext} from '@docusaurus/types';
|
||||
import {validateBlogPostFrontMatter} from './blogFrontMatter';
|
||||
import {validateBlogPostFrontMatter} from './frontMatter';
|
||||
import {type AuthorsMap, getAuthorsMap, getBlogPostAuthors} from './authors';
|
||||
import logger from '@docusaurus/logger';
|
||||
import type {
|
||||
|
@ -43,9 +43,9 @@ export function truncate(fileString: string, truncateMarker: RegExp): string {
|
|||
return fileString.split(truncateMarker, 1).shift()!;
|
||||
}
|
||||
|
||||
export function getSourceToPermalink(
|
||||
blogPosts: BlogPost[],
|
||||
): Record<string, string> {
|
||||
export function getSourceToPermalink(blogPosts: BlogPost[]): {
|
||||
[aliasedPath: string]: string;
|
||||
} {
|
||||
return Object.fromEntries(
|
||||
blogPosts.map(({metadata: {source, permalink}}) => [source, permalink]),
|
||||
);
|
||||
|
@ -247,7 +247,7 @@ async function processBlogSourceFile(
|
|||
});
|
||||
return result.date;
|
||||
} catch (err) {
|
||||
logger.error(err);
|
||||
logger.warn(err);
|
||||
return (await fs.stat(blogSourceAbsolute)).birthtime;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
declare module 'remark-admonitions' {
|
||||
type Options = Record<string, unknown>;
|
||||
type Options = {[key: string]: unknown};
|
||||
|
||||
const plugin: (options?: Options) => void;
|
||||
export = plugin;
|
||||
|
|
|
@ -9,7 +9,6 @@ import {Feed, type Author as FeedAuthor, type Item as FeedItem} from 'feed';
|
|||
import type {BlogPost} from './types';
|
||||
import {
|
||||
normalizeUrl,
|
||||
posixPath,
|
||||
mapAsyncSequential,
|
||||
readOutputHTMLFile,
|
||||
} from '@docusaurus/utils';
|
||||
|
@ -128,10 +127,7 @@ async function createBlogFeedFile({
|
|||
}
|
||||
})();
|
||||
try {
|
||||
await fs.outputFile(
|
||||
posixPath(path.join(generatePath, feedPath)),
|
||||
feedContent,
|
||||
);
|
||||
await fs.outputFile(path.join(generatePath, feedPath), feedContent);
|
||||
} catch (err) {
|
||||
throw new Error(`Generating ${feedType} feed failed: ${err}.`);
|
||||
}
|
||||
|
|
|
@ -74,8 +74,8 @@ const BlogFrontMatterSchema = Joi.object<BlogPostFrontMatter>({
|
|||
'{#label} blog frontMatter field is deprecated. Please use {#alternative} instead.',
|
||||
});
|
||||
|
||||
export function validateBlogPostFrontMatter(
|
||||
frontMatter: Record<string, unknown>,
|
||||
): BlogPostFrontMatter {
|
||||
export function validateBlogPostFrontMatter(frontMatter: {
|
||||
[key: string]: unknown;
|
||||
}): BlogPostFrontMatter {
|
||||
return validateFrontMatter(frontMatter, BlogFrontMatterSchema);
|
||||
}
|
|
@ -30,14 +30,7 @@ import type {
|
|||
BlogContentPaths,
|
||||
BlogMarkdownLoaderOptions,
|
||||
} from './types';
|
||||
import {PluginOptionSchema} from './pluginOptionSchema';
|
||||
import type {
|
||||
LoadContext,
|
||||
Plugin,
|
||||
HtmlTags,
|
||||
OptionValidationContext,
|
||||
ValidationResult,
|
||||
} from '@docusaurus/types';
|
||||
import type {LoadContext, Plugin, HtmlTags} from '@docusaurus/types';
|
||||
import {
|
||||
generateBlogPosts,
|
||||
getSourceToPermalink,
|
||||
|
@ -212,14 +205,14 @@ export default async function pluginContentBlog(
|
|||
blogTagsListPath,
|
||||
} = blogContents;
|
||||
|
||||
const blogItemsToMetadata: Record<string, BlogPostMetadata> = {};
|
||||
const blogItemsToMetadata: {[postId: string]: BlogPostMetadata} = {};
|
||||
|
||||
const sidebarBlogPosts =
|
||||
options.blogSidebarCount === 'ALL'
|
||||
? blogPosts
|
||||
: blogPosts.slice(0, options.blogSidebarCount);
|
||||
|
||||
if (archiveBasePath) {
|
||||
if (archiveBasePath && blogPosts.length) {
|
||||
const archiveUrl = normalizeUrl([
|
||||
baseUrl,
|
||||
routeBasePath,
|
||||
|
@ -323,7 +316,7 @@ export default async function pluginContentBlog(
|
|||
return;
|
||||
}
|
||||
|
||||
const tagsModule: Record<string, TagModule> = Object.fromEntries(
|
||||
const tagsModule: {[tagName: string]: TagModule} = Object.fromEntries(
|
||||
Object.entries(blogTags).map(([, tag]) => {
|
||||
const tagModule: TagModule = {
|
||||
allTagsPath: blogTagsListPath,
|
||||
|
@ -572,10 +565,4 @@ export default async function pluginContentBlog(
|
|||
};
|
||||
}
|
||||
|
||||
export function validateOptions({
|
||||
validate,
|
||||
options,
|
||||
}: OptionValidationContext<PluginOptions>): ValidationResult<PluginOptions> {
|
||||
const validatedOptions = validate(PluginOptionSchema, options);
|
||||
return validatedOptions;
|
||||
}
|
||||
export {validateOptions} from './options';
|
||||
|
|
|
@ -13,7 +13,8 @@ import {
|
|||
URISchema,
|
||||
} from '@docusaurus/utils-validation';
|
||||
import {GlobExcludeDefault} from '@docusaurus/utils';
|
||||
import type {PluginOptions} from '@docusaurus/plugin-content-blog';
|
||||
import type {PluginOptions, Options} from '@docusaurus/plugin-content-blog';
|
||||
import type {OptionValidationContext} from '@docusaurus/types';
|
||||
|
||||
export const DEFAULT_OPTIONS: PluginOptions = {
|
||||
feedOptions: {type: ['rss', 'atom'], copyright: ''},
|
||||
|
@ -46,7 +47,7 @@ export const DEFAULT_OPTIONS: PluginOptions = {
|
|||
sortPosts: 'descending',
|
||||
};
|
||||
|
||||
export const PluginOptionSchema = Joi.object<PluginOptions>({
|
||||
const PluginOptionSchema = Joi.object<PluginOptions>({
|
||||
path: Joi.string().default(DEFAULT_OPTIONS.path),
|
||||
archiveBasePath: Joi.string()
|
||||
.default(DEFAULT_OPTIONS.archiveBasePath)
|
||||
|
@ -125,4 +126,15 @@ export const PluginOptionSchema = Joi.object<PluginOptions>({
|
|||
sortPosts: Joi.string()
|
||||
.valid('descending', 'ascending')
|
||||
.default(DEFAULT_OPTIONS.sortPosts),
|
||||
});
|
||||
}).default(DEFAULT_OPTIONS);
|
||||
|
||||
export function validateOptions({
|
||||
validate,
|
||||
options,
|
||||
}: OptionValidationContext<Options, PluginOptions>): PluginOptions {
|
||||
const validatedOptions = validate(
|
||||
PluginOptionSchema,
|
||||
options,
|
||||
) as PluginOptions;
|
||||
return validatedOptions;
|
||||
}
|
|
@ -6,8 +6,8 @@
|
|||
*/
|
||||
|
||||
declare module '@docusaurus/plugin-content-blog' {
|
||||
import type {RemarkAndRehypePluginOptions} from '@docusaurus/mdx-loader';
|
||||
import type {FrontMatterTag} from '@docusaurus/utils';
|
||||
import type {MDXOptions} from '@docusaurus/mdx-loader';
|
||||
import type {FrontMatterTag, Tag} from '@docusaurus/utils';
|
||||
import type {Overwrite} from 'utility-types';
|
||||
|
||||
export interface Assets {
|
||||
|
@ -81,10 +81,7 @@ declare module '@docusaurus/plugin-content-blog' {
|
|||
* @see {@link BlogPostMetadata.tags}
|
||||
*/
|
||||
tags?: FrontMatterTag[];
|
||||
/**
|
||||
* Custom slug appended after /<baseUrl>/<routeBasePath>/
|
||||
* @see {@link BlogPostMetadata.slug}
|
||||
*/
|
||||
/** Custom slug appended after `/<baseUrl>/<routeBasePath>/` */
|
||||
slug?: string;
|
||||
/**
|
||||
* Marks the post as draft and excludes it from the production build.
|
||||
|
@ -130,25 +127,18 @@ declare module '@docusaurus/plugin-content-blog' {
|
|||
/** @deprecated v1 legacy */
|
||||
authorImageURL?: string;
|
||||
|
||||
/**
|
||||
* @see {@link BlogPostMetadata.image}
|
||||
*/
|
||||
/** Used in the head meta. Should use `assets.image` in priority. */
|
||||
image?: string;
|
||||
/**
|
||||
* Used in the head meta
|
||||
*/
|
||||
/** Used in the head meta. */
|
||||
keywords?: string[];
|
||||
/**
|
||||
* Hide the right TOC
|
||||
*/
|
||||
/** Hide the right TOC. */
|
||||
hide_table_of_contents?: boolean;
|
||||
/**
|
||||
* Minimum TOC heading level
|
||||
* Minimum TOC heading level. Must be between 2 and 6 and lower or equal to
|
||||
* the max value.
|
||||
*/
|
||||
toc_min_heading_level?: number;
|
||||
/**
|
||||
* Maximum TOC heading level
|
||||
*/
|
||||
/** Maximum TOC heading level. Must be between 2 and 6. */
|
||||
toc_max_heading_level?: number;
|
||||
};
|
||||
|
||||
|
@ -175,9 +165,7 @@ declare module '@docusaurus/plugin-content-blog' {
|
|||
| (string | BlogPostFrontMatterAuthor)[];
|
||||
|
||||
export type BlogPostMetadata = {
|
||||
/**
|
||||
* Path to the Markdown source, with `@site` alias.
|
||||
*/
|
||||
/** Path to the Markdown source, with `@site` alias. */
|
||||
readonly source: string;
|
||||
/**
|
||||
* Used to generate the page h1 heading, tab title, and pagination title.
|
||||
|
@ -193,9 +181,7 @@ declare module '@docusaurus/plugin-content-blog' {
|
|||
* render the date regardless of the existence of `Intl.DateTimeFormat`.
|
||||
*/
|
||||
readonly formattedDate: string;
|
||||
/**
|
||||
* Full link including base URL.
|
||||
*/
|
||||
/** Full link including base URL. */
|
||||
readonly permalink: string;
|
||||
/**
|
||||
* Description used in the meta. Could be an empty string (empty content)
|
||||
|
@ -229,17 +215,10 @@ declare module '@docusaurus/plugin-content-blog' {
|
|||
* `assets.authorsImageUrls` on client side.
|
||||
*/
|
||||
readonly authors: Author[];
|
||||
/**
|
||||
* Front matter, as-is.
|
||||
*/
|
||||
readonly frontMatter: BlogPostFrontMatter & Record<string, unknown>;
|
||||
/**
|
||||
* Tags, normalized.
|
||||
*/
|
||||
readonly tags: readonly {
|
||||
readonly label: string;
|
||||
readonly permalink: string;
|
||||
}[];
|
||||
/** Front matter, as-is. */
|
||||
readonly frontMatter: BlogPostFrontMatter & {[key: string]: unknown};
|
||||
/** Tags, normalized. */
|
||||
readonly tags: Tag[];
|
||||
};
|
||||
/**
|
||||
* @returns The edit URL that's directly plugged into metadata.
|
||||
|
@ -250,17 +229,11 @@ declare module '@docusaurus/plugin-content-blog' {
|
|||
* site path. Usually the same as `options.path` but can be localized
|
||||
*/
|
||||
blogDirPath: string;
|
||||
/**
|
||||
* Path to this post file, relative to `blogDirPath`
|
||||
*/
|
||||
/** Path to this post file, relative to `blogDirPath`. */
|
||||
blogPath: string;
|
||||
/**
|
||||
* @see {@link BlogPostMetadata.permalink}
|
||||
*/
|
||||
/** @see {@link BlogPostMetadata.permalink} */
|
||||
permalink: string;
|
||||
/**
|
||||
* Locale name.
|
||||
*/
|
||||
/** Locale name. */
|
||||
locale: string;
|
||||
}) => string | undefined;
|
||||
|
||||
|
@ -301,7 +274,7 @@ declare module '@docusaurus/plugin-content-blog' {
|
|||
/** Markdown content. */
|
||||
content: string;
|
||||
/** Front matter. */
|
||||
frontMatter?: BlogPostFrontMatter & Record<string, unknown>;
|
||||
frontMatter?: BlogPostFrontMatter & {[key: string]: unknown};
|
||||
/** Options accepted by ngryman/reading-time. */
|
||||
options?: ReadingTimeOptions;
|
||||
}) => number;
|
||||
|
@ -325,7 +298,7 @@ declare module '@docusaurus/plugin-content-blog' {
|
|||
/**
|
||||
* Plugin options after normalization.
|
||||
*/
|
||||
export type PluginOptions = RemarkAndRehypePluginOptions & {
|
||||
export type PluginOptions = MDXOptions & {
|
||||
/** Plugin ID. */
|
||||
id?: string;
|
||||
/**
|
||||
|
@ -402,7 +375,7 @@ declare module '@docusaurus/plugin-content-blog' {
|
|||
* unlocalized file. Ignored when `editUrl` is a function.
|
||||
*/
|
||||
editLocalizedFiles?: boolean;
|
||||
admonitions: Record<string, unknown>;
|
||||
admonitions: {[key: string]: unknown};
|
||||
/** Path to the authors map file, relative to the blog content directory. */
|
||||
authorsMapPath: string;
|
||||
/** A callback to customize the reading time number displayed. */
|
||||
|
@ -545,7 +518,7 @@ declare module '@theme/BlogTagsListPage' {
|
|||
/** Blog sidebar. */
|
||||
readonly sidebar: BlogSidebar;
|
||||
/** A map from tag names to the full tag module. */
|
||||
readonly tags: Readonly<Record<string, TagModule>>;
|
||||
readonly tags: Readonly<{[tagName: string]: TagModule}>;
|
||||
}
|
||||
|
||||
export default function BlogTagsListPage(props: Props): JSX.Element;
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
import type {BlogContent, BlogPaginated} from './types';
|
||||
import type {TranslationFileContent, TranslationFiles} from '@docusaurus/types';
|
||||
import type {TranslationFileContent, TranslationFile} from '@docusaurus/types';
|
||||
import type {PluginOptions} from '@docusaurus/plugin-content-blog';
|
||||
|
||||
function translateListPage(
|
||||
|
@ -27,7 +27,7 @@ function translateListPage(
|
|||
});
|
||||
}
|
||||
|
||||
export function getTranslationFiles(options: PluginOptions): TranslationFiles {
|
||||
export function getTranslationFiles(options: PluginOptions): TranslationFile[] {
|
||||
return [
|
||||
{
|
||||
path: 'options',
|
||||
|
@ -51,7 +51,7 @@ export function getTranslationFiles(options: PluginOptions): TranslationFiles {
|
|||
|
||||
export function translateContent(
|
||||
content: BlogContent,
|
||||
translationFiles: TranslationFiles,
|
||||
translationFiles: TranslationFile[],
|
||||
): BlogContent {
|
||||
const {content: optionsTranslations} = translationFiles[0]!;
|
||||
return {
|
||||
|
|
|
@ -5,10 +5,7 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import type {
|
||||
BrokenMarkdownLink,
|
||||
ContentPaths,
|
||||
} from '@docusaurus/utils/lib/markdownLinks';
|
||||
import type {BrokenMarkdownLink, ContentPaths} from '@docusaurus/utils';
|
||||
import type {BlogPostMetadata} from '@docusaurus/plugin-content-blog';
|
||||
import type {Metadata as BlogPaginatedMetadata} from '@theme/BlogListPage';
|
||||
|
||||
|
@ -53,6 +50,6 @@ export type BlogMarkdownLoaderOptions = {
|
|||
siteDir: string;
|
||||
contentPaths: BlogContentPaths;
|
||||
truncateMarker: RegExp;
|
||||
sourceToPermalink: Record<string, string>;
|
||||
sourceToPermalink: {[aliasedPath: string]: string};
|
||||
onBrokenMarkdownLink: (brokenMarkdownLink: BlogBrokenMarkdownLink) => void;
|
||||
};
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@docusaurus/plugin-content-docs",
|
||||
"version": "2.0.0-beta.17",
|
||||
"version": "2.0.0-beta.18",
|
||||
"description": "Docs plugin for Docusaurus.",
|
||||
"main": "lib/index.js",
|
||||
"exports": {
|
||||
|
@ -23,11 +23,11 @@
|
|||
},
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@docusaurus/core": "2.0.0-beta.17",
|
||||
"@docusaurus/logger": "2.0.0-beta.17",
|
||||
"@docusaurus/mdx-loader": "2.0.0-beta.17",
|
||||
"@docusaurus/utils": "2.0.0-beta.17",
|
||||
"@docusaurus/utils-validation": "2.0.0-beta.17",
|
||||
"@docusaurus/core": "2.0.0-beta.18",
|
||||
"@docusaurus/logger": "2.0.0-beta.18",
|
||||
"@docusaurus/mdx-loader": "2.0.0-beta.18",
|
||||
"@docusaurus/utils": "2.0.0-beta.18",
|
||||
"@docusaurus/utils-validation": "2.0.0-beta.18",
|
||||
"combine-promises": "^1.1.0",
|
||||
"fs-extra": "^10.0.1",
|
||||
"import-fresh": "^3.3.0",
|
||||
|
@ -39,8 +39,8 @@
|
|||
"webpack": "^5.70.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@docusaurus/module-type-aliases": "2.0.0-beta.17",
|
||||
"@docusaurus/types": "2.0.0-beta.17",
|
||||
"@docusaurus/module-type-aliases": "2.0.0-beta.18",
|
||||
"@docusaurus/types": "2.0.0-beta.18",
|
||||
"@types/js-yaml": "^4.0.5",
|
||||
"@types/picomatch": "^2.3.0",
|
||||
"commander": "^5.1.0",
|
||||
|
|
|
@ -1407,6 +1407,7 @@ exports[`site with custom sidebar items generator sidebarItemsGenerator is calle
|
|||
"sidebarPosition": 0,
|
||||
"source": "@site/docs/3-API/01_Core APIs/0 --- Client API.md",
|
||||
"sourceDirName": "3-API/01_Core APIs",
|
||||
"title": "Client API",
|
||||
"unversionedId": "API/Core APIs/Client API",
|
||||
},
|
||||
{
|
||||
|
@ -1415,6 +1416,7 @@ exports[`site with custom sidebar items generator sidebarItemsGenerator is calle
|
|||
"sidebarPosition": 1,
|
||||
"source": "@site/docs/3-API/01_Core APIs/1 --- Server API.md",
|
||||
"sourceDirName": "3-API/01_Core APIs",
|
||||
"title": "Server API",
|
||||
"unversionedId": "API/Core APIs/Server API",
|
||||
},
|
||||
{
|
||||
|
@ -1423,6 +1425,7 @@ exports[`site with custom sidebar items generator sidebarItemsGenerator is calle
|
|||
"sidebarPosition": 0,
|
||||
"source": "@site/docs/3-API/02_Extension APIs/0. Plugin API.md",
|
||||
"sourceDirName": "3-API/02_Extension APIs",
|
||||
"title": "Plugin API",
|
||||
"unversionedId": "API/Extension APIs/Plugin API",
|
||||
},
|
||||
{
|
||||
|
@ -1431,6 +1434,7 @@ exports[`site with custom sidebar items generator sidebarItemsGenerator is calle
|
|||
"sidebarPosition": 1,
|
||||
"source": "@site/docs/3-API/02_Extension APIs/1. Theme API.md",
|
||||
"sourceDirName": "3-API/02_Extension APIs",
|
||||
"title": "Theme API",
|
||||
"unversionedId": "API/Extension APIs/Theme API",
|
||||
},
|
||||
{
|
||||
|
@ -1439,6 +1443,7 @@ exports[`site with custom sidebar items generator sidebarItemsGenerator is calle
|
|||
"sidebarPosition": 3,
|
||||
"source": "@site/docs/3-API/03_api-end.md",
|
||||
"sourceDirName": "3-API",
|
||||
"title": "API End",
|
||||
"unversionedId": "API/api-end",
|
||||
},
|
||||
{
|
||||
|
@ -1447,6 +1452,7 @@ exports[`site with custom sidebar items generator sidebarItemsGenerator is calle
|
|||
"sidebarPosition": 0,
|
||||
"source": "@site/docs/3-API/00_api-overview.md",
|
||||
"sourceDirName": "3-API",
|
||||
"title": "API Overview",
|
||||
"unversionedId": "API/api-overview",
|
||||
},
|
||||
{
|
||||
|
@ -1458,6 +1464,7 @@ exports[`site with custom sidebar items generator sidebarItemsGenerator is calle
|
|||
"sidebarPosition": 1,
|
||||
"source": "@site/docs/Guides/z-guide1.md",
|
||||
"sourceDirName": "Guides",
|
||||
"title": "Guide 1",
|
||||
"unversionedId": "Guides/guide1",
|
||||
},
|
||||
{
|
||||
|
@ -1468,6 +1475,7 @@ exports[`site with custom sidebar items generator sidebarItemsGenerator is calle
|
|||
"sidebarPosition": 2,
|
||||
"source": "@site/docs/Guides/02-guide2.md",
|
||||
"sourceDirName": "Guides",
|
||||
"title": "Guide 2",
|
||||
"unversionedId": "Guides/guide2",
|
||||
},
|
||||
{
|
||||
|
@ -1479,6 +1487,7 @@ exports[`site with custom sidebar items generator sidebarItemsGenerator is calle
|
|||
"sidebarPosition": 2.5,
|
||||
"source": "@site/docs/Guides/0-guide2.5.md",
|
||||
"sourceDirName": "Guides",
|
||||
"title": "Guide 2.5",
|
||||
"unversionedId": "Guides/guide2.5",
|
||||
},
|
||||
{
|
||||
|
@ -1490,6 +1499,7 @@ exports[`site with custom sidebar items generator sidebarItemsGenerator is calle
|
|||
"sidebarPosition": 3,
|
||||
"source": "@site/docs/Guides/guide3.md",
|
||||
"sourceDirName": "Guides",
|
||||
"title": "Guide 3",
|
||||
"unversionedId": "Guides/guide3",
|
||||
},
|
||||
{
|
||||
|
@ -1500,6 +1510,7 @@ exports[`site with custom sidebar items generator sidebarItemsGenerator is calle
|
|||
"sidebarPosition": undefined,
|
||||
"source": "@site/docs/Guides/a-guide4.md",
|
||||
"sourceDirName": "Guides",
|
||||
"title": "Guide 4",
|
||||
"unversionedId": "Guides/guide4",
|
||||
},
|
||||
{
|
||||
|
@ -1510,6 +1521,7 @@ exports[`site with custom sidebar items generator sidebarItemsGenerator is calle
|
|||
"sidebarPosition": undefined,
|
||||
"source": "@site/docs/Guides/b-guide5.md",
|
||||
"sourceDirName": "Guides",
|
||||
"title": "Guide 5",
|
||||
"unversionedId": "Guides/guide5",
|
||||
},
|
||||
{
|
||||
|
@ -1518,6 +1530,7 @@ exports[`site with custom sidebar items generator sidebarItemsGenerator is calle
|
|||
"sidebarPosition": 0,
|
||||
"source": "@site/docs/0-getting-started.md",
|
||||
"sourceDirName": ".",
|
||||
"title": "Getting Started",
|
||||
"unversionedId": "getting-started",
|
||||
},
|
||||
{
|
||||
|
@ -1526,6 +1539,7 @@ exports[`site with custom sidebar items generator sidebarItemsGenerator is calle
|
|||
"sidebarPosition": 1,
|
||||
"source": "@site/docs/1-installation.md",
|
||||
"sourceDirName": ".",
|
||||
"title": "Installation",
|
||||
"unversionedId": "installation",
|
||||
},
|
||||
],
|
||||
|
@ -1535,10 +1549,6 @@ exports[`site with custom sidebar items generator sidebarItemsGenerator is calle
|
|||
"type": "autogenerated",
|
||||
},
|
||||
"numberPrefixParser": [Function],
|
||||
"options": {
|
||||
"sidebarCollapsed": true,
|
||||
"sidebarCollapsible": true,
|
||||
},
|
||||
"version": {
|
||||
"contentPath": "docs",
|
||||
"versionName": "current",
|
||||
|
|
|
@ -169,7 +169,9 @@ exports[`translateLoadedContent returns translated loaded content 1`] = `
|
|||
},
|
||||
],
|
||||
"isLast": true,
|
||||
"label": "current label (translated)",
|
||||
"mainDocId": "",
|
||||
"path": "/docs/",
|
||||
"routePriority": undefined,
|
||||
"sidebarFilePath": "any",
|
||||
"sidebars": {
|
||||
|
@ -221,9 +223,7 @@ exports[`translateLoadedContent returns translated loaded content 1`] = `
|
|||
},
|
||||
],
|
||||
},
|
||||
"versionLabel": "current label (translated)",
|
||||
"versionName": "current",
|
||||
"versionPath": "/docs/",
|
||||
},
|
||||
{
|
||||
"contentPath": "any",
|
||||
|
@ -311,7 +311,9 @@ exports[`translateLoadedContent returns translated loaded content 1`] = `
|
|||
},
|
||||
],
|
||||
"isLast": true,
|
||||
"label": "2.0.0 label (translated)",
|
||||
"mainDocId": "",
|
||||
"path": "/docs/",
|
||||
"routePriority": undefined,
|
||||
"sidebarFilePath": "any",
|
||||
"sidebars": {
|
||||
|
@ -363,9 +365,7 @@ exports[`translateLoadedContent returns translated loaded content 1`] = `
|
|||
},
|
||||
],
|
||||
},
|
||||
"versionLabel": "2.0.0 label (translated)",
|
||||
"versionName": "2.0.0",
|
||||
"versionPath": "/docs/",
|
||||
},
|
||||
{
|
||||
"contentPath": "any",
|
||||
|
@ -453,7 +453,9 @@ exports[`translateLoadedContent returns translated loaded content 1`] = `
|
|||
},
|
||||
],
|
||||
"isLast": true,
|
||||
"label": "1.0.0 label (translated)",
|
||||
"mainDocId": "",
|
||||
"path": "/docs/",
|
||||
"routePriority": undefined,
|
||||
"sidebarFilePath": "any",
|
||||
"sidebars": {
|
||||
|
@ -505,9 +507,7 @@ exports[`translateLoadedContent returns translated loaded content 1`] = `
|
|||
},
|
||||
],
|
||||
},
|
||||
"versionLabel": "1.0.0 label (translated)",
|
||||
"versionName": "1.0.0",
|
||||
"versionPath": "/docs/",
|
||||
},
|
||||
],
|
||||
}
|
||||
|
|
|
@ -181,7 +181,7 @@ describe('docsVersion', () => {
|
|||
DEFAULT_OPTIONS,
|
||||
),
|
||||
).rejects.toThrowErrorMatchingInlineSnapshot(
|
||||
`"[docs]: there is no docs to version!"`,
|
||||
`"[docs]: no docs found in <PROJECT_ROOT>/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/empty-site/docs."`,
|
||||
);
|
||||
});
|
||||
|
||||
|
|
|
@ -18,16 +18,14 @@ import {
|
|||
import {loadSidebars} from '../sidebars';
|
||||
import type {Sidebars} from '../sidebars/types';
|
||||
import {readVersionsMetadata} from '../versions';
|
||||
import type {
|
||||
DocFile,
|
||||
DocMetadataBase,
|
||||
VersionMetadata,
|
||||
DocNavLink,
|
||||
} from '../types';
|
||||
import type {DocFile} from '../types';
|
||||
import type {
|
||||
MetadataOptions,
|
||||
PluginOptions,
|
||||
EditUrlFunction,
|
||||
DocMetadataBase,
|
||||
VersionMetadata,
|
||||
PropNavigationLink,
|
||||
} from '@docusaurus/plugin-content-docs';
|
||||
import type {LoadContext} from '@docusaurus/types';
|
||||
import {DEFAULT_OPTIONS} from '../options';
|
||||
|
@ -43,7 +41,7 @@ const createFakeDocFile = ({
|
|||
markdown = 'some markdown content',
|
||||
}: {
|
||||
source: string;
|
||||
frontMatter?: Record<string, string>;
|
||||
frontMatter?: {[key: string]: string};
|
||||
markdown?: string;
|
||||
}): DocFile => {
|
||||
const content = `---
|
||||
|
@ -123,7 +121,11 @@ function createTestUtils({
|
|||
}
|
||||
|
||||
async function generateNavigation(docFiles: DocFile[]): Promise<{
|
||||
pagination: {prev?: DocNavLink; next?: DocNavLink; id: string}[];
|
||||
pagination: {
|
||||
prev?: PropNavigationLink;
|
||||
next?: PropNavigationLink;
|
||||
id: string;
|
||||
}[];
|
||||
sidebars: Sidebars;
|
||||
}> {
|
||||
const rawDocs = docFiles.map((docFile) =>
|
||||
|
@ -166,7 +168,7 @@ describe('simple site', () => {
|
|||
loadSiteOptions: {options: Partial<PluginOptions>} = {options: {}},
|
||||
) {
|
||||
const siteDir = path.join(fixtureDir, 'simple-site');
|
||||
const context = await loadContext(siteDir);
|
||||
const context = await loadContext({siteDir});
|
||||
const options = {
|
||||
id: DEFAULT_PLUGIN_ID,
|
||||
...DEFAULT_OPTIONS,
|
||||
|
@ -521,7 +523,8 @@ describe('versioned site', () => {
|
|||
},
|
||||
) {
|
||||
const siteDir = path.join(fixtureDir, 'versioned-site');
|
||||
const context = await loadContext(siteDir, {
|
||||
const context = await loadContext({
|
||||
siteDir,
|
||||
locale: loadSiteOptions.locale,
|
||||
});
|
||||
const options = {
|
||||
|
|
|
@ -5,19 +5,19 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import {validateDocFrontMatter} from '../docFrontMatter';
|
||||
import type {DocFrontMatter} from '../types';
|
||||
import {validateDocFrontMatter} from '../frontMatter';
|
||||
import type {DocFrontMatter} from '@docusaurus/plugin-content-docs';
|
||||
import escapeStringRegexp from 'escape-string-regexp';
|
||||
|
||||
function testField(params: {
|
||||
prefix: string;
|
||||
validFrontMatters: DocFrontMatter[];
|
||||
convertibleFrontMatter?: [
|
||||
ConvertibleFrontMatter: Record<string, unknown>,
|
||||
ConvertibleFrontMatter: {[key: string]: unknown},
|
||||
ConvertedFrontMatter: DocFrontMatter,
|
||||
][];
|
||||
invalidFrontMatters?: [
|
||||
InvalidFrontMatter: Record<string, unknown>,
|
||||
InvalidFrontMatter: {[key: string]: unknown},
|
||||
ErrorMessage: string,
|
||||
][];
|
||||
}) {
|
|
@ -12,9 +12,9 @@ describe('toGlobalDataVersion', () => {
|
|||
expect(
|
||||
toGlobalDataVersion({
|
||||
versionName: 'current',
|
||||
versionLabel: 'Label',
|
||||
label: 'Label',
|
||||
isLast: true,
|
||||
versionPath: '/current',
|
||||
path: '/current',
|
||||
mainDocId: 'main',
|
||||
docs: [
|
||||
{
|
||||
|
@ -86,9 +86,9 @@ describe('toGlobalDataVersion', () => {
|
|||
sidebar: 'tutorial',
|
||||
},
|
||||
],
|
||||
versionBanner: 'unreleased',
|
||||
versionBadge: true,
|
||||
versionClassName: 'current-cls',
|
||||
banner: 'unreleased',
|
||||
badge: true,
|
||||
className: 'current-cls',
|
||||
tagsPath: '/current/tags',
|
||||
contentPath: '',
|
||||
contentPathLocalized: '',
|
||||
|
|
|
@ -17,10 +17,10 @@ import {loadContext} from '@docusaurus/core/src/server/index';
|
|||
import {applyConfigureWebpack} from '@docusaurus/core/src/webpack/utils';
|
||||
import type {RouteConfig} from '@docusaurus/types';
|
||||
import {posixPath, DEFAULT_PLUGIN_ID} from '@docusaurus/utils';
|
||||
import {sortConfig} from '@docusaurus/core/src/server/plugins';
|
||||
import {sortConfig} from '@docusaurus/core/src/server/plugins/routeConfig';
|
||||
|
||||
import * as cliDocs from '../cli';
|
||||
import {OptionsSchema} from '../options';
|
||||
import {validateOptions} from '../options';
|
||||
import {normalizePluginOptions} from '@docusaurus/utils-validation';
|
||||
import type {LoadedVersion} from '../types';
|
||||
import type {
|
||||
|
@ -52,7 +52,7 @@ Available ids are:\n- ${version.docs.map((d) => d.unversionedId).join('\n- ')}`,
|
|||
|
||||
const createFakeActions = (contentDir: string) => {
|
||||
const routeConfigs: RouteConfig[] = [];
|
||||
const dataContainer: Record<string, unknown> = {};
|
||||
const dataContainer: {[key: string]: unknown} = {};
|
||||
const globalDataContainer: {pluginName?: {pluginId: unknown}} = {};
|
||||
|
||||
const actions = {
|
||||
|
@ -115,12 +115,15 @@ Entries created:
|
|||
describe('sidebar', () => {
|
||||
it('site with wrong sidebar content', async () => {
|
||||
const siteDir = path.join(__dirname, '__fixtures__', 'simple-site');
|
||||
const context = await loadContext(siteDir);
|
||||
const context = await loadContext({siteDir});
|
||||
const sidebarPath = path.join(siteDir, 'wrong-sidebars.json');
|
||||
const plugin = await pluginContentDocs(
|
||||
context,
|
||||
normalizePluginOptions(OptionsSchema, {
|
||||
sidebarPath,
|
||||
validateOptions({
|
||||
validate: normalizePluginOptions,
|
||||
options: {
|
||||
sidebarPath,
|
||||
},
|
||||
}),
|
||||
);
|
||||
await expect(plugin.loadContent!()).rejects.toThrowErrorMatchingSnapshot();
|
||||
|
@ -128,13 +131,16 @@ describe('sidebar', () => {
|
|||
|
||||
it('site with wrong sidebar file path', async () => {
|
||||
const siteDir = path.join(__dirname, '__fixtures__', 'site-with-doc-label');
|
||||
const context = await loadContext(siteDir);
|
||||
const context = await loadContext({siteDir});
|
||||
|
||||
await expect(async () => {
|
||||
const plugin = await pluginContentDocs(
|
||||
context,
|
||||
normalizePluginOptions(OptionsSchema, {
|
||||
sidebarPath: 'wrong-path-sidebar.json',
|
||||
validateOptions({
|
||||
validate: normalizePluginOptions,
|
||||
options: {
|
||||
sidebarPath: 'wrong-path-sidebar.json',
|
||||
},
|
||||
}),
|
||||
);
|
||||
await plugin.loadContent!();
|
||||
|
@ -149,11 +155,14 @@ describe('sidebar', () => {
|
|||
|
||||
it('site with undefined sidebar', async () => {
|
||||
const siteDir = path.join(__dirname, '__fixtures__', 'site-with-doc-label');
|
||||
const context = await loadContext(siteDir);
|
||||
const context = await loadContext({siteDir});
|
||||
const plugin = await pluginContentDocs(
|
||||
context,
|
||||
normalizePluginOptions(OptionsSchema, {
|
||||
sidebarPath: undefined,
|
||||
validateOptions({
|
||||
validate: normalizePluginOptions,
|
||||
options: {
|
||||
sidebarPath: undefined,
|
||||
},
|
||||
}),
|
||||
);
|
||||
const result = await plugin.loadContent!();
|
||||
|
@ -164,11 +173,14 @@ describe('sidebar', () => {
|
|||
|
||||
it('site with disabled sidebar', async () => {
|
||||
const siteDir = path.join(__dirname, '__fixtures__', 'site-with-doc-label');
|
||||
const context = await loadContext(siteDir);
|
||||
const context = await loadContext({siteDir});
|
||||
const plugin = await pluginContentDocs(
|
||||
context,
|
||||
normalizePluginOptions(OptionsSchema, {
|
||||
sidebarPath: false,
|
||||
validateOptions({
|
||||
validate: normalizePluginOptions,
|
||||
options: {
|
||||
sidebarPath: false,
|
||||
},
|
||||
}),
|
||||
);
|
||||
const result = await plugin.loadContent!();
|
||||
|
@ -182,11 +194,11 @@ describe('empty/no docs website', () => {
|
|||
const siteDir = path.join(__dirname, '__fixtures__', 'empty-site');
|
||||
|
||||
it('no files in docs folder', async () => {
|
||||
const context = await loadContext(siteDir);
|
||||
const context = await loadContext({siteDir});
|
||||
await fs.ensureDir(path.join(siteDir, 'docs'));
|
||||
const plugin = await pluginContentDocs(
|
||||
context,
|
||||
normalizePluginOptions(OptionsSchema, {}),
|
||||
validateOptions({validate: normalizePluginOptions, options: {}}),
|
||||
);
|
||||
await expect(
|
||||
plugin.loadContent!(),
|
||||
|
@ -196,12 +208,15 @@ describe('empty/no docs website', () => {
|
|||
});
|
||||
|
||||
it('docs folder does not exist', async () => {
|
||||
const context = await loadContext(siteDir);
|
||||
const context = await loadContext({siteDir});
|
||||
await expect(
|
||||
pluginContentDocs(
|
||||
context,
|
||||
normalizePluginOptions(OptionsSchema, {
|
||||
path: `path/does/not/exist`,
|
||||
validateOptions({
|
||||
validate: normalizePluginOptions,
|
||||
options: {
|
||||
path: 'path/does/not/exist',
|
||||
},
|
||||
}),
|
||||
),
|
||||
).rejects.toThrowErrorMatchingInlineSnapshot(
|
||||
|
@ -213,13 +228,16 @@ describe('empty/no docs website', () => {
|
|||
describe('simple website', () => {
|
||||
async function loadSite() {
|
||||
const siteDir = path.join(__dirname, '__fixtures__', 'simple-site');
|
||||
const context = await loadContext(siteDir);
|
||||
const context = await loadContext({siteDir});
|
||||
const sidebarPath = path.join(siteDir, 'sidebars.json');
|
||||
const plugin = await pluginContentDocs(
|
||||
context,
|
||||
normalizePluginOptions(OptionsSchema, {
|
||||
path: 'docs',
|
||||
sidebarPath,
|
||||
validateOptions({
|
||||
validate: normalizePluginOptions,
|
||||
options: {
|
||||
path: 'docs',
|
||||
sidebarPath,
|
||||
},
|
||||
}),
|
||||
);
|
||||
const pluginContentDir = path.join(context.generatedFilesDir, plugin.name);
|
||||
|
@ -323,14 +341,17 @@ describe('simple website', () => {
|
|||
describe('versioned website', () => {
|
||||
async function loadSite() {
|
||||
const siteDir = path.join(__dirname, '__fixtures__', 'versioned-site');
|
||||
const context = await loadContext(siteDir);
|
||||
const context = await loadContext({siteDir});
|
||||
const sidebarPath = path.join(siteDir, 'sidebars.json');
|
||||
const routeBasePath = 'docs';
|
||||
const plugin = await pluginContentDocs(
|
||||
context,
|
||||
normalizePluginOptions(OptionsSchema, {
|
||||
routeBasePath,
|
||||
sidebarPath,
|
||||
validateOptions({
|
||||
validate: normalizePluginOptions,
|
||||
options: {
|
||||
routeBasePath,
|
||||
sidebarPath,
|
||||
},
|
||||
}),
|
||||
);
|
||||
const pluginContentDir = path.join(context.generatedFilesDir, plugin.name);
|
||||
|
@ -449,17 +470,20 @@ describe('versioned website', () => {
|
|||
describe('versioned website (community)', () => {
|
||||
async function loadSite() {
|
||||
const siteDir = path.join(__dirname, '__fixtures__', 'versioned-site');
|
||||
const context = await loadContext(siteDir);
|
||||
const context = await loadContext({siteDir});
|
||||
const sidebarPath = path.join(siteDir, 'community_sidebars.json');
|
||||
const routeBasePath = 'community';
|
||||
const pluginId = 'community';
|
||||
const plugin = await pluginContentDocs(
|
||||
context,
|
||||
normalizePluginOptions(OptionsSchema, {
|
||||
id: 'community',
|
||||
path: 'community',
|
||||
routeBasePath,
|
||||
sidebarPath,
|
||||
validateOptions({
|
||||
validate: normalizePluginOptions,
|
||||
options: {
|
||||
id: 'community',
|
||||
path: 'community',
|
||||
routeBasePath,
|
||||
sidebarPath,
|
||||
},
|
||||
}),
|
||||
);
|
||||
const pluginContentDir = path.join(context.generatedFilesDir, plugin.name);
|
||||
|
@ -554,13 +578,16 @@ describe('versioned website (community)', () => {
|
|||
describe('site with doc label', () => {
|
||||
async function loadSite() {
|
||||
const siteDir = path.join(__dirname, '__fixtures__', 'site-with-doc-label');
|
||||
const context = await loadContext(siteDir);
|
||||
const context = await loadContext({siteDir});
|
||||
const sidebarPath = path.join(siteDir, 'sidebars.json');
|
||||
const plugin = await pluginContentDocs(
|
||||
context,
|
||||
normalizePluginOptions(OptionsSchema, {
|
||||
path: 'docs',
|
||||
sidebarPath,
|
||||
validateOptions({
|
||||
validate: normalizePluginOptions,
|
||||
options: {
|
||||
path: 'docs',
|
||||
sidebarPath,
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
|
@ -593,11 +620,14 @@ describe('site with full autogenerated sidebar', () => {
|
|||
'__fixtures__',
|
||||
'site-with-autogenerated-sidebar',
|
||||
);
|
||||
const context = await loadContext(siteDir);
|
||||
const context = await loadContext({siteDir});
|
||||
const plugin = await pluginContentDocs(
|
||||
context,
|
||||
normalizePluginOptions(OptionsSchema, {
|
||||
path: 'docs',
|
||||
validateOptions({
|
||||
validate: normalizePluginOptions,
|
||||
options: {
|
||||
path: 'docs',
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
|
@ -645,17 +675,20 @@ describe('site with partial autogenerated sidebars', () => {
|
|||
'__fixtures__',
|
||||
'site-with-autogenerated-sidebar',
|
||||
);
|
||||
const context = await loadContext(siteDir, {});
|
||||
const context = await loadContext({siteDir});
|
||||
const plugin = await pluginContentDocs(
|
||||
context,
|
||||
normalizePluginOptions(OptionsSchema, {
|
||||
path: 'docs',
|
||||
sidebarPath: path.join(
|
||||
__dirname,
|
||||
'__fixtures__',
|
||||
'site-with-autogenerated-sidebar',
|
||||
'partialAutogeneratedSidebars.js',
|
||||
),
|
||||
validateOptions({
|
||||
validate: normalizePluginOptions,
|
||||
options: {
|
||||
path: 'docs',
|
||||
sidebarPath: path.join(
|
||||
__dirname,
|
||||
'__fixtures__',
|
||||
'site-with-autogenerated-sidebar',
|
||||
'partialAutogeneratedSidebars.js',
|
||||
),
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
|
@ -698,17 +731,20 @@ describe('site with partial autogenerated sidebars 2 (fix #4638)', () => {
|
|||
'__fixtures__',
|
||||
'site-with-autogenerated-sidebar',
|
||||
);
|
||||
const context = await loadContext(siteDir, {});
|
||||
const context = await loadContext({siteDir});
|
||||
const plugin = await pluginContentDocs(
|
||||
context,
|
||||
normalizePluginOptions(OptionsSchema, {
|
||||
path: 'docs',
|
||||
sidebarPath: path.join(
|
||||
__dirname,
|
||||
'__fixtures__',
|
||||
'site-with-autogenerated-sidebar',
|
||||
'partialAutogeneratedSidebars2.js',
|
||||
),
|
||||
validateOptions({
|
||||
validate: normalizePluginOptions,
|
||||
options: {
|
||||
path: 'docs',
|
||||
sidebarPath: path.join(
|
||||
__dirname,
|
||||
'__fixtures__',
|
||||
'site-with-autogenerated-sidebar',
|
||||
'partialAutogeneratedSidebars2.js',
|
||||
),
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
|
@ -732,12 +768,15 @@ describe('site with custom sidebar items generator', () => {
|
|||
'__fixtures__',
|
||||
'site-with-autogenerated-sidebar',
|
||||
);
|
||||
const context = await loadContext(siteDir);
|
||||
const context = await loadContext({siteDir});
|
||||
const plugin = await pluginContentDocs(
|
||||
context,
|
||||
normalizePluginOptions(OptionsSchema, {
|
||||
path: 'docs',
|
||||
sidebarItemsGenerator,
|
||||
validateOptions({
|
||||
validate: normalizePluginOptions,
|
||||
options: {
|
||||
path: 'docs',
|
||||
sidebarItemsGenerator,
|
||||
},
|
||||
}),
|
||||
);
|
||||
const content = (await plugin.loadContent?.())!;
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import {createTempRepo} from '@testing-utils/git';
|
||||
import {jest} from '@jest/globals';
|
||||
import fs from 'fs-extra';
|
||||
import path from 'path';
|
||||
|
@ -47,7 +48,7 @@ describe('getFileLastUpdate', () => {
|
|||
|
||||
it('non-existing file', async () => {
|
||||
const consoleMock = jest
|
||||
.spyOn(console, 'error')
|
||||
.spyOn(console, 'warn')
|
||||
.mockImplementation(() => {});
|
||||
const nonExistingFileName = '.nonExisting';
|
||||
const nonExistingFilePath = path.join(
|
||||
|
@ -65,13 +66,40 @@ describe('getFileLastUpdate', () => {
|
|||
consoleMock.mockRestore();
|
||||
});
|
||||
|
||||
it('temporary created file that has no git timestamp', async () => {
|
||||
const tempFilePath = path.join(__dirname, '__fixtures__', '.temp');
|
||||
it('temporary created file that is not tracked by git', async () => {
|
||||
const consoleMock = jest
|
||||
.spyOn(console, 'warn')
|
||||
.mockImplementation(() => {});
|
||||
const {repoDir} = createTempRepo();
|
||||
const tempFilePath = path.join(repoDir, 'file.md');
|
||||
await fs.writeFile(tempFilePath, 'Lorem ipsum :)');
|
||||
await expect(getFileLastUpdate(tempFilePath)).resolves.toBeNull();
|
||||
expect(consoleMock).toHaveBeenCalledTimes(1);
|
||||
expect(consoleMock).toHaveBeenLastCalledWith(
|
||||
expect.stringMatching(/not tracked by git./),
|
||||
);
|
||||
await fs.unlink(tempFilePath);
|
||||
});
|
||||
|
||||
it('multiple files not tracked by git', async () => {
|
||||
const consoleMock = jest
|
||||
.spyOn(console, 'warn')
|
||||
.mockImplementation(() => {});
|
||||
const {repoDir} = createTempRepo();
|
||||
const tempFilePath1 = path.join(repoDir, 'file1.md');
|
||||
const tempFilePath2 = path.join(repoDir, 'file2.md');
|
||||
await fs.writeFile(tempFilePath1, 'Lorem ipsum :)');
|
||||
await fs.writeFile(tempFilePath2, 'Lorem ipsum :)');
|
||||
await expect(getFileLastUpdate(tempFilePath1)).resolves.toBeNull();
|
||||
await expect(getFileLastUpdate(tempFilePath2)).resolves.toBeNull();
|
||||
expect(consoleMock).toHaveBeenCalledTimes(1);
|
||||
expect(consoleMock).toHaveBeenLastCalledWith(
|
||||
expect.stringMatching(/not tracked by git./),
|
||||
);
|
||||
await fs.unlink(tempFilePath1);
|
||||
await fs.unlink(tempFilePath2);
|
||||
});
|
||||
|
||||
it('git does not exist', async () => {
|
||||
const mock = jest.spyOn(shell, 'which').mockImplementationOnce(() => null);
|
||||
const consoleMock = jest
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import {OptionsSchema, DEFAULT_OPTIONS, validateOptions} from '../options';
|
||||
import {validateOptions, DEFAULT_OPTIONS} from '../options';
|
||||
import {normalizePluginOptions} from '@docusaurus/utils-validation';
|
||||
import {DefaultSidebarItemsGenerator} from '../sidebars/generator';
|
||||
import {
|
||||
|
@ -13,27 +13,26 @@ import {
|
|||
DisabledNumberPrefixParser,
|
||||
} from '../numberPrefix';
|
||||
import {GlobExcludeDefault} from '@docusaurus/utils';
|
||||
import type {PluginOptions} from '@docusaurus/plugin-content-docs';
|
||||
import type {Options} from '@docusaurus/plugin-content-docs';
|
||||
|
||||
// the type of remark/rehype plugins is function
|
||||
const markdownPluginsFunctionStub = () => {};
|
||||
const markdownPluginsObjectStub = {};
|
||||
|
||||
function testValidateOptions(options: Partial<PluginOptions>) {
|
||||
return validateOptions({
|
||||
options: {
|
||||
...DEFAULT_OPTIONS,
|
||||
...options,
|
||||
},
|
||||
validate: normalizePluginOptions,
|
||||
});
|
||||
function testValidate(options: Options) {
|
||||
return validateOptions({validate: normalizePluginOptions, options});
|
||||
}
|
||||
|
||||
const defaultOptions = {
|
||||
...DEFAULT_OPTIONS,
|
||||
id: 'default',
|
||||
// The admonitions plugin is automatically added. Not really worth testing
|
||||
remarkPlugins: expect.any(Array),
|
||||
};
|
||||
|
||||
describe('normalizeDocsPluginOptions', () => {
|
||||
it('returns default options for undefined user options', async () => {
|
||||
const {value, error} = await OptionsSchema.validate({});
|
||||
expect(value).toEqual(DEFAULT_OPTIONS);
|
||||
expect(error).toBeUndefined();
|
||||
expect(testValidate({})).toEqual(defaultOptions);
|
||||
});
|
||||
|
||||
it('accepts correctly defined user options', async () => {
|
||||
|
@ -77,14 +76,15 @@ describe('normalizeDocsPluginOptions', () => {
|
|||
sidebarCollapsible: false,
|
||||
sidebarCollapsed: false,
|
||||
};
|
||||
const {value, error} = await OptionsSchema.validate(userOptions);
|
||||
expect(value).toEqual(userOptions);
|
||||
expect(error).toBeUndefined();
|
||||
expect(testValidate(userOptions)).toEqual({
|
||||
...defaultOptions,
|
||||
...userOptions,
|
||||
remarkPlugins: [...userOptions.remarkPlugins, expect.any(Array)],
|
||||
});
|
||||
});
|
||||
|
||||
it('accepts correctly defined remark and rehype plugin options', async () => {
|
||||
const userOptions = {
|
||||
...DEFAULT_OPTIONS,
|
||||
beforeDefaultRemarkPlugins: [],
|
||||
beforeDefaultRehypePlugins: [markdownPluginsFunctionStub],
|
||||
remarkPlugins: [[markdownPluginsFunctionStub, {option1: '42'}]],
|
||||
|
@ -93,85 +93,73 @@ describe('normalizeDocsPluginOptions', () => {
|
|||
[markdownPluginsFunctionStub, {option1: '42'}],
|
||||
],
|
||||
};
|
||||
const {value, error} = await OptionsSchema.validate(userOptions);
|
||||
expect(value).toEqual(userOptions);
|
||||
expect(error).toBeUndefined();
|
||||
expect(testValidate(userOptions)).toEqual({
|
||||
...defaultOptions,
|
||||
...userOptions,
|
||||
remarkPlugins: [...userOptions.remarkPlugins, expect.any(Array)],
|
||||
});
|
||||
});
|
||||
|
||||
it('accepts admonitions false', async () => {
|
||||
const admonitionsFalse = {
|
||||
...DEFAULT_OPTIONS,
|
||||
admonitions: false,
|
||||
};
|
||||
const {value, error} = OptionsSchema.validate(admonitionsFalse);
|
||||
expect(value).toEqual(admonitionsFalse);
|
||||
expect(error).toBeUndefined();
|
||||
});
|
||||
|
||||
it('accepts numberPrefixParser function', () => {
|
||||
function customNumberPrefixParser() {}
|
||||
expect(
|
||||
normalizePluginOptions(OptionsSchema, {
|
||||
...DEFAULT_OPTIONS,
|
||||
numberPrefixParser: customNumberPrefixParser,
|
||||
}),
|
||||
).toEqual({
|
||||
...DEFAULT_OPTIONS,
|
||||
id: 'default',
|
||||
numberPrefixParser: customNumberPrefixParser,
|
||||
});
|
||||
});
|
||||
|
||||
it('accepts numberPrefixParser false', () => {
|
||||
expect(
|
||||
normalizePluginOptions(OptionsSchema, {
|
||||
...DEFAULT_OPTIONS,
|
||||
numberPrefixParser: false,
|
||||
}),
|
||||
).toEqual({
|
||||
...DEFAULT_OPTIONS,
|
||||
id: 'default',
|
||||
numberPrefixParser: DisabledNumberPrefixParser,
|
||||
});
|
||||
});
|
||||
|
||||
it('accepts numberPrefixParser true', () => {
|
||||
expect(
|
||||
normalizePluginOptions(OptionsSchema, {
|
||||
...DEFAULT_OPTIONS,
|
||||
numberPrefixParser: true,
|
||||
}),
|
||||
).toEqual({
|
||||
...DEFAULT_OPTIONS,
|
||||
id: 'default',
|
||||
numberPrefixParser: DefaultNumberPrefixParser,
|
||||
expect(testValidate(admonitionsFalse)).toEqual({
|
||||
...defaultOptions,
|
||||
...admonitionsFalse,
|
||||
});
|
||||
});
|
||||
|
||||
it('rejects admonitions true', async () => {
|
||||
const admonitionsTrue = {
|
||||
...DEFAULT_OPTIONS,
|
||||
admonitions: true,
|
||||
};
|
||||
const {error} = OptionsSchema.validate(admonitionsTrue);
|
||||
expect(error).toMatchInlineSnapshot(
|
||||
`[ValidationError: "admonitions" contains an invalid value]`,
|
||||
expect(() =>
|
||||
testValidate(admonitionsTrue),
|
||||
).toThrowErrorMatchingInlineSnapshot(
|
||||
`"\\"admonitions\\" contains an invalid value"`,
|
||||
);
|
||||
});
|
||||
|
||||
it('accepts numberPrefixParser function', () => {
|
||||
function customNumberPrefixParser() {}
|
||||
expect(
|
||||
testValidate({numberPrefixParser: customNumberPrefixParser}),
|
||||
).toEqual({
|
||||
...defaultOptions,
|
||||
numberPrefixParser: customNumberPrefixParser,
|
||||
});
|
||||
});
|
||||
|
||||
it('accepts numberPrefixParser false', () => {
|
||||
expect(testValidate({numberPrefixParser: false})).toEqual({
|
||||
...defaultOptions,
|
||||
numberPrefixParser: DisabledNumberPrefixParser,
|
||||
});
|
||||
});
|
||||
|
||||
it('accepts numberPrefixParser true', () => {
|
||||
expect(testValidate({numberPrefixParser: true})).toEqual({
|
||||
...defaultOptions,
|
||||
numberPrefixParser: DefaultNumberPrefixParser,
|
||||
});
|
||||
});
|
||||
|
||||
it('rejects invalid remark plugin options', () => {
|
||||
expect(() => {
|
||||
normalizePluginOptions(OptionsSchema, {
|
||||
expect(() =>
|
||||
testValidate({
|
||||
remarkPlugins: [[{option1: '42'}, markdownPluginsFunctionStub]],
|
||||
});
|
||||
}).toThrowErrorMatchingInlineSnapshot(
|
||||
`"\\"remarkPlugins[0]\\" does not match any of the allowed types"`,
|
||||
);
|
||||
}),
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"\\"remarkPlugins[0]\\" does not look like a valid MDX plugin config. A plugin config entry should be one of:
|
||||
- A tuple, like \`[require(\\"rehype-katex\\"), { strict: false }]\`, or
|
||||
- A simple module, like \`require(\\"remark-math\\")\`"
|
||||
`);
|
||||
});
|
||||
|
||||
it('rejects invalid rehype plugin options', () => {
|
||||
expect(() => {
|
||||
normalizePluginOptions(OptionsSchema, {
|
||||
expect(() =>
|
||||
testValidate({
|
||||
rehypePlugins: [
|
||||
[
|
||||
markdownPluginsFunctionStub,
|
||||
|
@ -179,61 +167,53 @@ describe('normalizeDocsPluginOptions', () => {
|
|||
markdownPluginsFunctionStub,
|
||||
],
|
||||
],
|
||||
});
|
||||
}).toThrowErrorMatchingInlineSnapshot(
|
||||
`"\\"rehypePlugins[0]\\" does not match any of the allowed types"`,
|
||||
);
|
||||
}),
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"\\"rehypePlugins[0]\\" does not look like a valid MDX plugin config. A plugin config entry should be one of:
|
||||
- A tuple, like \`[require(\\"rehype-katex\\"), { strict: false }]\`, or
|
||||
- A simple module, like \`require(\\"remark-math\\")\`"
|
||||
`);
|
||||
});
|
||||
|
||||
it('rejects bad path inputs', () => {
|
||||
expect(() => {
|
||||
normalizePluginOptions(OptionsSchema, {
|
||||
path: 2,
|
||||
});
|
||||
}).toThrowErrorMatchingInlineSnapshot(`"\\"path\\" must be a string"`);
|
||||
expect(() => testValidate({path: 2})).toThrowErrorMatchingInlineSnapshot(
|
||||
`"\\"path\\" must be a string"`,
|
||||
);
|
||||
});
|
||||
|
||||
it('rejects bad include inputs', () => {
|
||||
expect(() => {
|
||||
normalizePluginOptions(OptionsSchema, {
|
||||
include: '**/*.{md,mdx}',
|
||||
});
|
||||
}).toThrowErrorMatchingInlineSnapshot(`"\\"include\\" must be an array"`);
|
||||
expect(() =>
|
||||
testValidate({include: '**/*.{md,mdx}'}),
|
||||
).toThrowErrorMatchingInlineSnapshot(`"\\"include\\" must be an array"`);
|
||||
});
|
||||
|
||||
it('rejects bad showLastUpdateTime inputs', () => {
|
||||
expect(() => {
|
||||
normalizePluginOptions(OptionsSchema, {
|
||||
showLastUpdateTime: 'true',
|
||||
});
|
||||
}).toThrowErrorMatchingInlineSnapshot(
|
||||
expect(() =>
|
||||
testValidate({showLastUpdateTime: 'true'}),
|
||||
).toThrowErrorMatchingInlineSnapshot(
|
||||
`"\\"showLastUpdateTime\\" must be a boolean"`,
|
||||
);
|
||||
});
|
||||
|
||||
it('rejects bad remarkPlugins input', () => {
|
||||
expect(() => {
|
||||
normalizePluginOptions(OptionsSchema, {
|
||||
remarkPlugins: 'remark-math',
|
||||
});
|
||||
}).toThrowErrorMatchingInlineSnapshot(
|
||||
expect(() =>
|
||||
testValidate({remarkPlugins: 'remark-math'}),
|
||||
).toThrowErrorMatchingInlineSnapshot(
|
||||
`"\\"remarkPlugins\\" must be an array"`,
|
||||
);
|
||||
});
|
||||
|
||||
it('rejects bad lastVersion', () => {
|
||||
expect(() => {
|
||||
normalizePluginOptions(OptionsSchema, {
|
||||
lastVersion: false,
|
||||
});
|
||||
}).toThrowErrorMatchingInlineSnapshot(
|
||||
expect(() =>
|
||||
testValidate({lastVersion: false}),
|
||||
).toThrowErrorMatchingInlineSnapshot(
|
||||
`"\\"lastVersion\\" must be a string"`,
|
||||
);
|
||||
});
|
||||
|
||||
it('rejects bad versions', () => {
|
||||
expect(() => {
|
||||
normalizePluginOptions(OptionsSchema, {
|
||||
expect(() =>
|
||||
testValidate({
|
||||
versions: {
|
||||
current: {
|
||||
hey: 3,
|
||||
|
@ -243,32 +223,29 @@ describe('normalizeDocsPluginOptions', () => {
|
|||
label: 'world',
|
||||
},
|
||||
},
|
||||
});
|
||||
}).toThrowErrorMatchingInlineSnapshot(
|
||||
}),
|
||||
).toThrowErrorMatchingInlineSnapshot(
|
||||
`"\\"versions.current.hey\\" is not allowed"`,
|
||||
);
|
||||
});
|
||||
|
||||
it('handles sidebarCollapsed option inconsistencies', () => {
|
||||
expect(
|
||||
testValidateOptions({
|
||||
...DEFAULT_OPTIONS,
|
||||
testValidate({
|
||||
sidebarCollapsible: true,
|
||||
sidebarCollapsed: undefined,
|
||||
}).sidebarCollapsed,
|
||||
).toBe(true);
|
||||
|
||||
expect(
|
||||
testValidateOptions({
|
||||
...DEFAULT_OPTIONS,
|
||||
testValidate({
|
||||
sidebarCollapsible: false,
|
||||
sidebarCollapsed: undefined,
|
||||
}).sidebarCollapsed,
|
||||
).toBe(false);
|
||||
|
||||
expect(
|
||||
testValidateOptions({
|
||||
...DEFAULT_OPTIONS,
|
||||
testValidate({
|
||||
sidebarCollapsible: false,
|
||||
sidebarCollapsed: true,
|
||||
}).sidebarCollapsed,
|
||||
|
|
|
@ -16,7 +16,7 @@ describe('toTagDocListProp', () => {
|
|||
|
||||
it('works', () => {
|
||||
const tag: Tag = {
|
||||
name: 'tag1',
|
||||
label: 'tag1',
|
||||
permalink: '/tag1',
|
||||
docIds: ['id1', 'id3'],
|
||||
};
|
||||
|
@ -54,7 +54,7 @@ describe('toTagDocListProp', () => {
|
|||
|
||||
expect(result).toEqual({
|
||||
allTagsPath,
|
||||
name: tag.name,
|
||||
name: tag.label,
|
||||
permalink: tag.permalink,
|
||||
docs: [doc3, doc1], // docs sorted by title, ignore "id5" absence
|
||||
});
|
||||
|
|
|
@ -5,12 +5,13 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import type {LoadedContent, DocMetadata, LoadedVersion} from '../types';
|
||||
import type {LoadedContent, LoadedVersion} from '../types';
|
||||
import {CURRENT_VERSION_NAME} from '../constants';
|
||||
import {
|
||||
getLoadedContentTranslationFiles,
|
||||
translateLoadedContent,
|
||||
} from '../translations';
|
||||
import type {DocMetadata} from '@docusaurus/plugin-content-docs';
|
||||
import {updateTranslationFileMessages} from '@docusaurus/utils';
|
||||
|
||||
function createSampleDoc(doc: Pick<DocMetadata, 'id'>): DocMetadata {
|
||||
|
@ -36,8 +37,8 @@ function createSampleVersion(
|
|||
version: Pick<LoadedVersion, 'versionName'>,
|
||||
): LoadedVersion {
|
||||
return {
|
||||
versionLabel: `${version.versionName} label`,
|
||||
versionPath: '/docs/',
|
||||
label: `${version.versionName} label`,
|
||||
path: '/docs/',
|
||||
mainDocId: '',
|
||||
routePriority: undefined,
|
||||
sidebarFilePath: 'any',
|
||||
|
@ -45,21 +46,11 @@ function createSampleVersion(
|
|||
contentPath: 'any',
|
||||
contentPathLocalized: 'any',
|
||||
docs: [
|
||||
createSampleDoc({
|
||||
id: 'doc1',
|
||||
}),
|
||||
createSampleDoc({
|
||||
id: 'doc2',
|
||||
}),
|
||||
createSampleDoc({
|
||||
id: 'doc3',
|
||||
}),
|
||||
createSampleDoc({
|
||||
id: 'doc4',
|
||||
}),
|
||||
createSampleDoc({
|
||||
id: 'doc5',
|
||||
}),
|
||||
createSampleDoc({id: 'doc1'}),
|
||||
createSampleDoc({id: 'doc2'}),
|
||||
createSampleDoc({id: 'doc3'}),
|
||||
createSampleDoc({id: 'doc4'}),
|
||||
createSampleDoc({id: 'doc5'}),
|
||||
],
|
||||
sidebars: {
|
||||
docs: [
|
||||
|
|
|
@ -15,9 +15,11 @@ import {
|
|||
} from '../versions';
|
||||
import {DEFAULT_OPTIONS} from '../options';
|
||||
import {DEFAULT_PLUGIN_ID} from '@docusaurus/utils';
|
||||
import type {VersionMetadata} from '../types';
|
||||
import type {I18n} from '@docusaurus/types';
|
||||
import type {PluginOptions} from '@docusaurus/plugin-content-docs';
|
||||
import type {
|
||||
PluginOptions,
|
||||
VersionMetadata,
|
||||
} from '@docusaurus/plugin-content-docs';
|
||||
|
||||
const DefaultI18N: I18n = {
|
||||
currentLocale: 'en',
|
||||
|
@ -85,12 +87,12 @@ describe('readVersionsMetadata', () => {
|
|||
routePriority: -1,
|
||||
sidebarFilePath: undefined,
|
||||
tagsPath: '/docs/tags',
|
||||
versionLabel: 'Next',
|
||||
label: 'Next',
|
||||
versionName: 'current',
|
||||
versionPath: '/docs',
|
||||
versionBanner: null,
|
||||
versionBadge: false,
|
||||
versionClassName: 'docs-version-current',
|
||||
path: '/docs',
|
||||
banner: null,
|
||||
badge: false,
|
||||
className: 'docs-version-current',
|
||||
};
|
||||
return {simpleSiteDir, defaultOptions, defaultContext, vCurrent};
|
||||
}
|
||||
|
@ -120,7 +122,7 @@ describe('readVersionsMetadata', () => {
|
|||
expect(versionsMetadata).toEqual([
|
||||
{
|
||||
...vCurrent,
|
||||
versionPath: '/myBaseUrl/docs',
|
||||
path: '/myBaseUrl/docs',
|
||||
tagsPath: '/myBaseUrl/docs/tags',
|
||||
},
|
||||
]);
|
||||
|
@ -148,13 +150,13 @@ describe('readVersionsMetadata', () => {
|
|||
expect(versionsMetadata).toEqual([
|
||||
{
|
||||
...vCurrent,
|
||||
versionPath: '/myBaseUrl/docs/current-path',
|
||||
versionLabel: 'current-label',
|
||||
path: '/myBaseUrl/docs/current-path',
|
||||
label: 'current-label',
|
||||
routePriority: undefined,
|
||||
sidebarFilePath: undefined,
|
||||
tagsPath: '/myBaseUrl/docs/current-path/tags',
|
||||
versionEditUrl: undefined,
|
||||
versionEditUrlLocalized: undefined,
|
||||
editUrl: undefined,
|
||||
editUrlLocalized: undefined,
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
@ -245,12 +247,12 @@ describe('readVersionsMetadata', () => {
|
|||
routePriority: undefined,
|
||||
sidebarFilePath: path.join(versionedSiteDir, 'sidebars.json'),
|
||||
tagsPath: '/docs/next/tags',
|
||||
versionLabel: 'Next',
|
||||
label: 'Next',
|
||||
versionName: 'current',
|
||||
versionPath: '/docs/next',
|
||||
versionBanner: 'unreleased',
|
||||
versionBadge: true,
|
||||
versionClassName: 'docs-version-current',
|
||||
path: '/docs/next',
|
||||
banner: 'unreleased',
|
||||
badge: true,
|
||||
className: 'docs-version-current',
|
||||
};
|
||||
|
||||
const v101: VersionMetadata = {
|
||||
|
@ -269,12 +271,12 @@ describe('readVersionsMetadata', () => {
|
|||
'versioned_sidebars/version-1.0.1-sidebars.json',
|
||||
),
|
||||
tagsPath: '/docs/tags',
|
||||
versionLabel: '1.0.1',
|
||||
label: '1.0.1',
|
||||
versionName: '1.0.1',
|
||||
versionPath: '/docs',
|
||||
versionBanner: null,
|
||||
versionBadge: true,
|
||||
versionClassName: 'docs-version-1.0.1',
|
||||
path: '/docs',
|
||||
banner: null,
|
||||
badge: true,
|
||||
className: 'docs-version-1.0.1',
|
||||
};
|
||||
|
||||
const v100: VersionMetadata = {
|
||||
|
@ -293,12 +295,12 @@ describe('readVersionsMetadata', () => {
|
|||
'versioned_sidebars/version-1.0.0-sidebars.json',
|
||||
),
|
||||
tagsPath: '/docs/1.0.0/tags',
|
||||
versionLabel: '1.0.0',
|
||||
label: '1.0.0',
|
||||
versionName: '1.0.0',
|
||||
versionPath: '/docs/1.0.0',
|
||||
versionBanner: 'unmaintained',
|
||||
versionBadge: true,
|
||||
versionClassName: 'docs-version-1.0.0',
|
||||
path: '/docs/1.0.0',
|
||||
banner: 'unmaintained',
|
||||
badge: true,
|
||||
className: 'docs-version-1.0.0',
|
||||
};
|
||||
|
||||
const vWithSlugs: VersionMetadata = {
|
||||
|
@ -317,12 +319,12 @@ describe('readVersionsMetadata', () => {
|
|||
'versioned_sidebars/version-withSlugs-sidebars.json',
|
||||
),
|
||||
tagsPath: '/docs/withSlugs/tags',
|
||||
versionLabel: 'withSlugs',
|
||||
label: 'withSlugs',
|
||||
versionName: 'withSlugs',
|
||||
versionPath: '/docs/withSlugs',
|
||||
versionBanner: 'unmaintained',
|
||||
versionBadge: true,
|
||||
versionClassName: 'docs-version-withSlugs',
|
||||
path: '/docs/withSlugs',
|
||||
banner: 'unmaintained',
|
||||
badge: true,
|
||||
className: 'docs-version-withSlugs',
|
||||
};
|
||||
|
||||
return {
|
||||
|
@ -393,27 +395,27 @@ describe('readVersionsMetadata', () => {
|
|||
{
|
||||
...vCurrent,
|
||||
tagsPath: '/docs/current-path/tags',
|
||||
versionPath: '/docs/current-path',
|
||||
versionBanner: 'unmaintained',
|
||||
versionBadge: false,
|
||||
versionClassName: 'custom-current-className',
|
||||
path: '/docs/current-path',
|
||||
banner: 'unmaintained',
|
||||
badge: false,
|
||||
className: 'custom-current-className',
|
||||
},
|
||||
{
|
||||
...v101,
|
||||
isLast: false,
|
||||
routePriority: undefined,
|
||||
tagsPath: '/docs/1.0.1/tags',
|
||||
versionPath: '/docs/1.0.1',
|
||||
versionBanner: 'unreleased',
|
||||
path: '/docs/1.0.1',
|
||||
banner: 'unreleased',
|
||||
},
|
||||
{
|
||||
...v100,
|
||||
isLast: true,
|
||||
routePriority: -1,
|
||||
tagsPath: '/docs/tags',
|
||||
versionLabel: '1.0.0-label',
|
||||
versionPath: '/docs',
|
||||
versionBanner: 'unreleased',
|
||||
label: '1.0.0-label',
|
||||
path: '/docs',
|
||||
banner: 'unreleased',
|
||||
},
|
||||
vWithSlugs,
|
||||
]);
|
||||
|
@ -434,30 +436,30 @@ describe('readVersionsMetadata', () => {
|
|||
expect(versionsMetadata).toEqual([
|
||||
{
|
||||
...vCurrent,
|
||||
versionEditUrl:
|
||||
editUrl:
|
||||
'https://github.com/facebook/docusaurus/edit/main/website/docs',
|
||||
versionEditUrlLocalized:
|
||||
editUrlLocalized:
|
||||
'https://github.com/facebook/docusaurus/edit/main/website/i18n/en/docusaurus-plugin-content-docs/current',
|
||||
},
|
||||
{
|
||||
...v101,
|
||||
versionEditUrl:
|
||||
editUrl:
|
||||
'https://github.com/facebook/docusaurus/edit/main/website/versioned_docs/version-1.0.1',
|
||||
versionEditUrlLocalized:
|
||||
editUrlLocalized:
|
||||
'https://github.com/facebook/docusaurus/edit/main/website/i18n/en/docusaurus-plugin-content-docs/version-1.0.1',
|
||||
},
|
||||
{
|
||||
...v100,
|
||||
versionEditUrl:
|
||||
editUrl:
|
||||
'https://github.com/facebook/docusaurus/edit/main/website/versioned_docs/version-1.0.0',
|
||||
versionEditUrlLocalized:
|
||||
editUrlLocalized:
|
||||
'https://github.com/facebook/docusaurus/edit/main/website/i18n/en/docusaurus-plugin-content-docs/version-1.0.0',
|
||||
},
|
||||
{
|
||||
...vWithSlugs,
|
||||
versionEditUrl:
|
||||
editUrl:
|
||||
'https://github.com/facebook/docusaurus/edit/main/website/versioned_docs/version-withSlugs',
|
||||
versionEditUrlLocalized:
|
||||
editUrlLocalized:
|
||||
'https://github.com/facebook/docusaurus/edit/main/website/i18n/en/docusaurus-plugin-content-docs/version-withSlugs',
|
||||
},
|
||||
]);
|
||||
|
@ -479,30 +481,30 @@ describe('readVersionsMetadata', () => {
|
|||
expect(versionsMetadata).toEqual([
|
||||
{
|
||||
...vCurrent,
|
||||
versionEditUrl:
|
||||
editUrl:
|
||||
'https://github.com/facebook/docusaurus/edit/main/website/docs',
|
||||
versionEditUrlLocalized:
|
||||
editUrlLocalized:
|
||||
'https://github.com/facebook/docusaurus/edit/main/website/i18n/en/docusaurus-plugin-content-docs/current',
|
||||
},
|
||||
{
|
||||
...v101,
|
||||
versionEditUrl:
|
||||
editUrl:
|
||||
'https://github.com/facebook/docusaurus/edit/main/website/docs',
|
||||
versionEditUrlLocalized:
|
||||
editUrlLocalized:
|
||||
'https://github.com/facebook/docusaurus/edit/main/website/i18n/en/docusaurus-plugin-content-docs/current',
|
||||
},
|
||||
{
|
||||
...v100,
|
||||
versionEditUrl:
|
||||
editUrl:
|
||||
'https://github.com/facebook/docusaurus/edit/main/website/docs',
|
||||
versionEditUrlLocalized:
|
||||
editUrlLocalized:
|
||||
'https://github.com/facebook/docusaurus/edit/main/website/i18n/en/docusaurus-plugin-content-docs/current',
|
||||
},
|
||||
{
|
||||
...vWithSlugs,
|
||||
versionEditUrl:
|
||||
editUrl:
|
||||
'https://github.com/facebook/docusaurus/edit/main/website/docs',
|
||||
versionEditUrlLocalized:
|
||||
editUrlLocalized:
|
||||
'https://github.com/facebook/docusaurus/edit/main/website/i18n/en/docusaurus-plugin-content-docs/current',
|
||||
},
|
||||
]);
|
||||
|
@ -538,9 +540,9 @@ describe('readVersionsMetadata', () => {
|
|||
isLast: true,
|
||||
routePriority: -1,
|
||||
tagsPath: '/docs/tags',
|
||||
versionPath: '/docs',
|
||||
versionBanner: null,
|
||||
versionBadge: false,
|
||||
path: '/docs',
|
||||
banner: null,
|
||||
badge: false,
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
@ -679,12 +681,12 @@ describe('readVersionsMetadata', () => {
|
|||
routePriority: undefined,
|
||||
sidebarFilePath: path.join(versionedSiteDir, 'sidebars.json'),
|
||||
tagsPath: '/communityBasePath/next/tags',
|
||||
versionLabel: 'Next',
|
||||
label: 'Next',
|
||||
versionName: 'current',
|
||||
versionPath: '/communityBasePath/next',
|
||||
versionBanner: 'unreleased',
|
||||
versionBadge: true,
|
||||
versionClassName: 'docs-version-current',
|
||||
path: '/communityBasePath/next',
|
||||
banner: 'unreleased',
|
||||
badge: true,
|
||||
className: 'docs-version-current',
|
||||
};
|
||||
|
||||
const v100: VersionMetadata = {
|
||||
|
@ -703,12 +705,12 @@ describe('readVersionsMetadata', () => {
|
|||
'community_versioned_sidebars/version-1.0.0-sidebars.json',
|
||||
),
|
||||
tagsPath: '/communityBasePath/tags',
|
||||
versionLabel: '1.0.0',
|
||||
label: '1.0.0',
|
||||
versionName: '1.0.0',
|
||||
versionPath: '/communityBasePath',
|
||||
versionBanner: null,
|
||||
versionBadge: true,
|
||||
versionClassName: 'docs-version-1.0.0',
|
||||
path: '/communityBasePath',
|
||||
banner: null,
|
||||
badge: true,
|
||||
className: 'docs-version-1.0.0',
|
||||
};
|
||||
|
||||
return {versionedSiteDir, defaultOptions, defaultContext, vCurrent, v100};
|
||||
|
@ -735,7 +737,7 @@ describe('readVersionsMetadata', () => {
|
|||
|
||||
expect(versionsMetadata).toEqual([
|
||||
// vCurrent removed
|
||||
{...v100, versionBadge: false},
|
||||
{...v100, badge: false},
|
||||
]);
|
||||
});
|
||||
|
||||
|
@ -753,9 +755,9 @@ describe('readVersionsMetadata', () => {
|
|||
isLast: true,
|
||||
routePriority: -1,
|
||||
tagsPath: '/communityBasePath/tags',
|
||||
versionPath: '/communityBasePath',
|
||||
versionBanner: null,
|
||||
versionBadge: false,
|
||||
path: '/communityBasePath',
|
||||
banner: null,
|
||||
badge: false,
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
|
|
@ -5,7 +5,10 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import type {CategoryGeneratedIndexMetadata, DocMetadataBase} from './types';
|
||||
import type {
|
||||
CategoryGeneratedIndexMetadata,
|
||||
DocMetadataBase,
|
||||
} from '@docusaurus/plugin-content-docs';
|
||||
import type {SidebarItemCategoryWithGeneratedIndex} from './sidebars/types';
|
||||
import {type SidebarsUtils, toNavigationLink} from './sidebars/utils';
|
||||
import {createDocsByIdIndex} from './docs';
|
||||
|
@ -17,7 +20,7 @@ function getCategoryGeneratedIndexMetadata({
|
|||
}: {
|
||||
category: SidebarItemCategoryWithGeneratedIndex;
|
||||
sidebarsUtils: SidebarsUtils;
|
||||
docsById: Record<string, DocMetadataBase>;
|
||||
docsById: {[docId: string]: DocMetadataBase};
|
||||
}): CategoryGeneratedIndexMetadata {
|
||||
const {sidebarName, previous, next} =
|
||||
sidebarsUtils.getCategoryGeneratedIndexNavigation(category.link.permalink);
|
||||
|
@ -29,8 +32,10 @@ function getCategoryGeneratedIndexMetadata({
|
|||
slug: category.link.slug,
|
||||
permalink: category.link.permalink,
|
||||
sidebar: sidebarName!,
|
||||
previous: toNavigationLink(previous, docsById),
|
||||
next: toNavigationLink(next, docsById),
|
||||
navigation: {
|
||||
previous: toNavigationLink(previous, docsById),
|
||||
next: toNavigationLink(next, docsById),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -117,7 +117,7 @@ export async function cliDocsVersionCommand(
|
|||
const {path: docsPath, sidebarPath} = options;
|
||||
|
||||
// Copy docs files.
|
||||
const docsDir = path.join(siteDir, docsPath);
|
||||
const docsDir = path.resolve(siteDir, docsPath);
|
||||
|
||||
if (
|
||||
(await fs.pathExists(docsDir)) &&
|
||||
|
@ -127,7 +127,7 @@ export async function cliDocsVersionCommand(
|
|||
const newVersionDir = path.join(versionedDir, `version-${version}`);
|
||||
await fs.copy(docsDir, newVersionDir);
|
||||
} else {
|
||||
throw new Error(`${pluginIdLogPrefix}: there is no docs to version!`);
|
||||
throw new Error(`${pluginIdLogPrefix}: no docs found in ${docsDir}.`);
|
||||
}
|
||||
|
||||
await createVersionedSidebarFile({
|
||||
|
|
|
@ -21,7 +21,7 @@ import _ from 'lodash';
|
|||
|
||||
describe('docsClientUtils', () => {
|
||||
it('getActivePlugin', () => {
|
||||
const data: Record<string, GlobalPluginData> = {
|
||||
const data: {[key: string]: GlobalPluginData} = {
|
||||
pluginIosId: {
|
||||
path: '/ios',
|
||||
versions: [],
|
||||
|
|
|
@ -23,11 +23,11 @@ import type {
|
|||
// ie the docs of that plugin are currently browsed
|
||||
// it is useful to support multiple docs plugin instances
|
||||
export function getActivePlugin(
|
||||
allPluginDatas: Record<string, GlobalPluginData>,
|
||||
allPluginData: {[pluginId: string]: GlobalPluginData},
|
||||
pathname: string,
|
||||
options: GetActivePluginOptions = {},
|
||||
): ActivePlugin | undefined {
|
||||
const activeEntry = Object.entries(allPluginDatas)
|
||||
const activeEntry = Object.entries(allPluginData)
|
||||
// Route sorting: '/android/foo' should match '/android' instead of '/'
|
||||
.sort((a, b) => b[1].path.localeCompare(a[1].path))
|
||||
.find(
|
||||
|
@ -46,7 +46,7 @@ export function getActivePlugin(
|
|||
if (!activePlugin && options.failfast) {
|
||||
throw new Error(
|
||||
`Can't find active docs plugin for "${pathname}" pathname, while it was expected to be found. Maybe you tried to use a docs feature that can only be used on a docs-related page? Existing docs plugin paths are: ${Object.values(
|
||||
allPluginDatas,
|
||||
allPluginData,
|
||||
)
|
||||
.map((plugin) => plugin.path)
|
||||
.join(', ')}`,
|
||||
|
|
|
@ -31,7 +31,7 @@ const StableEmptyObject = {};
|
|||
// Not using useAllPluginInstancesData() because in blog-only mode, docs hooks
|
||||
// are still used by the theme. We need a fail-safe fallback when the docs
|
||||
// plugin is not in use
|
||||
export const useAllDocsData = (): Record<string, GlobalPluginData> =>
|
||||
export const useAllDocsData = (): {[pluginId: string]: GlobalPluginData} =>
|
||||
useGlobalData()['docusaurus-plugin-content-docs'] ?? StableEmptyObject;
|
||||
|
||||
export const useDocsData = (pluginId: string | undefined): GlobalPluginData =>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
declare module 'remark-admonitions' {
|
||||
type Options = Record<string, unknown>;
|
||||
type Options = {[key: string]: unknown};
|
||||
|
||||
const plugin: (options?: Options) => void;
|
||||
export = plugin;
|
||||
|
|
|
@ -12,6 +12,7 @@ import {
|
|||
aliasedSitePath,
|
||||
getEditUrl,
|
||||
getFolderContainingFile,
|
||||
getContentPathList,
|
||||
normalizeUrl,
|
||||
parseMarkdownString,
|
||||
posixPath,
|
||||
|
@ -21,27 +22,22 @@ import {
|
|||
import type {LoadContext} from '@docusaurus/types';
|
||||
|
||||
import {getFileLastUpdate} from './lastUpdate';
|
||||
import type {
|
||||
DocFile,
|
||||
DocMetadataBase,
|
||||
DocMetadata,
|
||||
DocNavLink,
|
||||
LastUpdateData,
|
||||
VersionMetadata,
|
||||
LoadedVersion,
|
||||
} from './types';
|
||||
import type {DocFile, LoadedVersion} from './types';
|
||||
import getSlug from './slug';
|
||||
import {CURRENT_VERSION_NAME} from './constants';
|
||||
import {getDocsDirPaths} from './versions';
|
||||
import {stripPathNumberPrefixes} from './numberPrefix';
|
||||
import {validateDocFrontMatter} from './docFrontMatter';
|
||||
import {validateDocFrontMatter} from './frontMatter';
|
||||
import type {SidebarsUtils} from './sidebars/utils';
|
||||
import {toDocNavigationLink, toNavigationLink} from './sidebars/utils';
|
||||
import type {
|
||||
MetadataOptions,
|
||||
PluginOptions,
|
||||
CategoryIndexMatcher,
|
||||
CategoryIndexMatcherParam,
|
||||
DocMetadataBase,
|
||||
DocMetadata,
|
||||
PropNavigationLink,
|
||||
LastUpdateData,
|
||||
VersionMetadata,
|
||||
} from '@docusaurus/plugin-content-docs';
|
||||
|
||||
type LastUpdateOptions = Pick<
|
||||
|
@ -85,7 +81,7 @@ export async function readDocFile(
|
|||
options: LastUpdateOptions,
|
||||
): Promise<DocFile> {
|
||||
const contentPath = await getFolderContainingFile(
|
||||
getDocsDirPaths(versionMetadata),
|
||||
getContentPathList(versionMetadata),
|
||||
source,
|
||||
);
|
||||
|
||||
|
@ -213,7 +209,7 @@ function doProcessDocMetadata({
|
|||
|
||||
const description: string = frontMatter.description ?? excerpt ?? '';
|
||||
|
||||
const permalink = normalizeUrl([versionMetadata.versionPath, docSlug]);
|
||||
const permalink = normalizeUrl([versionMetadata.path, docSlug]);
|
||||
|
||||
function getDocEditUrl() {
|
||||
const relativeFilePath = path.relative(contentPath, filePath);
|
||||
|
@ -232,8 +228,8 @@ function doProcessDocMetadata({
|
|||
const isLocalized = contentPath === versionMetadata.contentPathLocalized;
|
||||
const baseVersionEditUrl =
|
||||
isLocalized && options.editLocalizedFiles
|
||||
? versionMetadata.versionEditUrlLocalized
|
||||
: versionMetadata.versionEditUrl;
|
||||
? versionMetadata.editUrlLocalized
|
||||
: versionMetadata.editUrl;
|
||||
return getEditUrl(relativeFilePath, baseVersionEditUrl);
|
||||
}
|
||||
return undefined;
|
||||
|
@ -304,7 +300,7 @@ export function addDocNavigation(
|
|||
const toNavigationLinkByDocId = (
|
||||
docId: string | null | undefined,
|
||||
type: 'prev' | 'next',
|
||||
): DocNavLink | undefined => {
|
||||
): PropNavigationLink | undefined => {
|
||||
if (!docId) {
|
||||
return undefined;
|
||||
}
|
||||
|
@ -401,7 +397,7 @@ export function toCategoryIndexMatcherParam({
|
|||
}: Pick<
|
||||
DocMetadataBase,
|
||||
'source' | 'sourceDirName'
|
||||
>): CategoryIndexMatcherParam {
|
||||
>): Parameters<CategoryIndexMatcher>[0] {
|
||||
// source + sourceDirName are always posix-style
|
||||
return {
|
||||
fileName: path.posix.parse(source).name,
|
||||
|
@ -424,7 +420,7 @@ export function getDocIds(doc: DocMetadataBase): [string, string] {
|
|||
// to "id")
|
||||
export function createDocsByIdIndex<
|
||||
Doc extends {id: string; unversionedId: string},
|
||||
>(docs: Doc[]): Record<string, Doc> {
|
||||
>(docs: Doc[]): {[docId: string]: Doc} {
|
||||
return Object.fromEntries(
|
||||
docs.flatMap((doc) => [
|
||||
[doc.unversionedId, doc],
|
||||
|
|
|
@ -12,7 +12,7 @@ import {
|
|||
FrontMatterTOCHeadingLevels,
|
||||
validateFrontMatter,
|
||||
} from '@docusaurus/utils-validation';
|
||||
import type {DocFrontMatter} from './types';
|
||||
import type {DocFrontMatter} from '@docusaurus/plugin-content-docs';
|
||||
|
||||
// NOTE: we don't add any default value on purpose here
|
||||
// We don't want default values to magically appear in doc metadata and props
|
||||
|
@ -41,8 +41,8 @@ const DocFrontMatterSchema = Joi.object<DocFrontMatter>({
|
|||
...FrontMatterTOCHeadingLevels,
|
||||
}).unknown();
|
||||
|
||||
export function validateDocFrontMatter(
|
||||
frontMatter: Record<string, unknown>,
|
||||
): DocFrontMatter {
|
||||
export function validateDocFrontMatter(frontMatter: {
|
||||
[key: string]: unknown;
|
||||
}): DocFrontMatter {
|
||||
return validateFrontMatter(frontMatter, DocFrontMatterSchema);
|
||||
}
|
|
@ -8,11 +8,11 @@
|
|||
import _ from 'lodash';
|
||||
import type {Sidebars} from './sidebars/types';
|
||||
import {createSidebarsUtils} from './sidebars/utils';
|
||||
import type {LoadedVersion} from './types';
|
||||
import type {
|
||||
CategoryGeneratedIndexMetadata,
|
||||
DocMetadata,
|
||||
LoadedVersion,
|
||||
} from './types';
|
||||
} from '@docusaurus/plugin-content-docs';
|
||||
import type {
|
||||
GlobalVersion,
|
||||
GlobalSidebar,
|
||||
|
@ -40,7 +40,7 @@ function toGlobalDataGeneratedIndex(
|
|||
function toGlobalSidebars(
|
||||
sidebars: Sidebars,
|
||||
version: LoadedVersion,
|
||||
): Record<string, GlobalSidebar> {
|
||||
): {[sidebarId: string]: GlobalSidebar} {
|
||||
const {getFirstLink} = createSidebarsUtils(sidebars);
|
||||
return _.mapValues(sidebars, (sidebar, sidebarId) => {
|
||||
const firstLink = getFirstLink(sidebarId);
|
||||
|
@ -65,9 +65,9 @@ function toGlobalSidebars(
|
|||
export function toGlobalDataVersion(version: LoadedVersion): GlobalVersion {
|
||||
return {
|
||||
name: version.versionName,
|
||||
label: version.versionLabel,
|
||||
label: version.label,
|
||||
isLast: version.isLast,
|
||||
path: version.versionPath,
|
||||
path: version.path,
|
||||
mainDocId: version.mainDocId,
|
||||
docs: version.docs
|
||||
.map(toGlobalDataDoc)
|
||||
|
|
|
@ -11,6 +11,7 @@ import {
|
|||
normalizeUrl,
|
||||
docuHash,
|
||||
aliasedSitePath,
|
||||
getContentPathList,
|
||||
reportMessage,
|
||||
posixPath,
|
||||
addTrailingPathSeparator,
|
||||
|
@ -27,18 +28,14 @@ import {
|
|||
addDocNavigation,
|
||||
getMainDocId,
|
||||
} from './docs';
|
||||
import {getDocsDirPaths, readVersionsMetadata} from './versions';
|
||||
|
||||
import {readVersionsMetadata} from './versions';
|
||||
import type {
|
||||
LoadedContent,
|
||||
SourceToPermalink,
|
||||
DocMetadataBase,
|
||||
VersionMetadata,
|
||||
LoadedVersion,
|
||||
DocFile,
|
||||
DocsMarkdownOption,
|
||||
VersionTag,
|
||||
DocFrontMatter,
|
||||
} from './types';
|
||||
import type {RuleSetRule} from 'webpack';
|
||||
import {cliDocsVersionCommand} from './cli';
|
||||
|
@ -55,8 +52,10 @@ import {createVersionRoutes} from './routes';
|
|||
import type {
|
||||
PropTagsListPage,
|
||||
PluginOptions,
|
||||
DocMetadataBase,
|
||||
VersionMetadata,
|
||||
DocFrontMatter,
|
||||
} from '@docusaurus/plugin-content-docs';
|
||||
import type {GlobalPluginData} from '@docusaurus/plugin-content-docs/client';
|
||||
import {createSidebarsUtils} from './sidebars/utils';
|
||||
import {getCategoryGeneratedIndexMetadataList} from './categoryGeneratedIndex';
|
||||
|
||||
|
@ -115,7 +114,7 @@ export default async function pluginContentDocs(
|
|||
function getVersionPathsToWatch(version: VersionMetadata): string[] {
|
||||
const result = [
|
||||
...options.include.flatMap((pattern) =>
|
||||
getDocsDirPaths(version).map(
|
||||
getContentPathList(version).map(
|
||||
(docsDirPath) => `${docsDirPath}/${pattern}`,
|
||||
),
|
||||
),
|
||||
|
@ -229,7 +228,7 @@ export default async function pluginContentDocs(
|
|||
const tagsProp: PropTagsListPage['tags'] = Object.values(
|
||||
versionTags,
|
||||
).map((tagValue) => ({
|
||||
name: tagValue.name,
|
||||
name: tagValue.label,
|
||||
permalink: tagValue.permalink,
|
||||
count: tagValue.docIds.length,
|
||||
}));
|
||||
|
@ -293,7 +292,7 @@ export default async function pluginContentDocs(
|
|||
// TODO tags should be a sub route of the version route
|
||||
await Promise.all(loadedVersions.map(createVersionTagsRoutes));
|
||||
|
||||
setGlobalData<GlobalPluginData>({
|
||||
setGlobalData({
|
||||
path: normalizeUrl([baseUrl, options.routeBasePath]),
|
||||
versions: loadedVersions.map(toGlobalDataVersion),
|
||||
breadcrumbs,
|
||||
|
@ -332,7 +331,7 @@ export default async function pluginContentDocs(
|
|||
};
|
||||
|
||||
function createMDXLoaderRule(): RuleSetRule {
|
||||
const contentDirs = versionsMetadata.flatMap(getDocsDirPaths);
|
||||
const contentDirs = versionsMetadata.flatMap(getContentPathList);
|
||||
return {
|
||||
test: /\.mdx?$/i,
|
||||
include: contentDirs
|
||||
|
|
|
@ -6,15 +6,18 @@
|
|||
*/
|
||||
|
||||
import logger from '@docusaurus/logger';
|
||||
import {getFileCommitDate, GitNotFoundError} from '@docusaurus/utils';
|
||||
|
||||
type FileLastUpdateData = {timestamp?: number; author?: string};
|
||||
import {
|
||||
getFileCommitDate,
|
||||
FileNotTrackedError,
|
||||
GitNotFoundError,
|
||||
} from '@docusaurus/utils';
|
||||
|
||||
let showedGitRequirementError = false;
|
||||
let showedFileNotTrackedError = false;
|
||||
|
||||
export async function getFileLastUpdate(
|
||||
filePath?: string,
|
||||
): Promise<FileLastUpdateData | null> {
|
||||
): Promise<{timestamp: number; author: string} | null> {
|
||||
if (!filePath) {
|
||||
return null;
|
||||
}
|
||||
|
@ -28,11 +31,20 @@ export async function getFileLastUpdate(
|
|||
});
|
||||
return {timestamp: result.timestamp, author: result.author};
|
||||
} catch (err) {
|
||||
if (err instanceof GitNotFoundError && !showedGitRequirementError) {
|
||||
logger.warn('Sorry, the docs plugin last update options require Git.');
|
||||
showedGitRequirementError = true;
|
||||
if (err instanceof GitNotFoundError) {
|
||||
if (!showedGitRequirementError) {
|
||||
logger.warn('Sorry, the docs plugin last update options require Git.');
|
||||
showedGitRequirementError = true;
|
||||
}
|
||||
} else if (err instanceof FileNotTrackedError) {
|
||||
if (!showedFileNotTrackedError) {
|
||||
logger.warn(
|
||||
'Cannot infer the update date for some files, as they are not tracked by git.',
|
||||
);
|
||||
showedFileNotTrackedError = true;
|
||||
}
|
||||
} else {
|
||||
logger.error(err);
|
||||
logger.warn(err);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -12,9 +12,9 @@ import {linkify} from '../linkify';
|
|||
import type {
|
||||
DocsMarkdownOption,
|
||||
SourceToPermalink,
|
||||
VersionMetadata,
|
||||
BrokenMarkdownLink,
|
||||
DocBrokenMarkdownLink,
|
||||
} from '../../types';
|
||||
import type {VersionMetadata} from '@docusaurus/plugin-content-docs';
|
||||
import {VERSIONED_DOCS_DIR, CURRENT_VERSION_NAME} from '../../constants';
|
||||
|
||||
function createFakeVersion({
|
||||
|
@ -156,22 +156,22 @@ describe('linkify', () => {
|
|||
filePath: doc5,
|
||||
link: 'docNotExist1.md',
|
||||
contentPaths: versionCurrent,
|
||||
} as BrokenMarkdownLink);
|
||||
} as DocBrokenMarkdownLink);
|
||||
expect(onBrokenMarkdownLink).toHaveBeenNthCalledWith(2, {
|
||||
filePath: doc5,
|
||||
link: './docNotExist2.mdx',
|
||||
contentPaths: versionCurrent,
|
||||
} as BrokenMarkdownLink);
|
||||
} as DocBrokenMarkdownLink);
|
||||
expect(onBrokenMarkdownLink).toHaveBeenNthCalledWith(3, {
|
||||
filePath: doc5,
|
||||
link: '../docNotExist3.mdx',
|
||||
contentPaths: versionCurrent,
|
||||
} as BrokenMarkdownLink);
|
||||
} as DocBrokenMarkdownLink);
|
||||
expect(onBrokenMarkdownLink).toHaveBeenNthCalledWith(4, {
|
||||
filePath: doc5,
|
||||
link: './subdir/docNotExist4.md',
|
||||
contentPaths: versionCurrent,
|
||||
} as BrokenMarkdownLink);
|
||||
} as DocBrokenMarkdownLink);
|
||||
});
|
||||
|
||||
it('transforms absolute links in versioned docs', async () => {
|
||||
|
|
|
@ -6,12 +6,11 @@
|
|||
*/
|
||||
|
||||
import type {DocsMarkdownOption} from '../types';
|
||||
import {getDocsDirPaths} from '../versions';
|
||||
import {replaceMarkdownLinks} from '@docusaurus/utils';
|
||||
import {replaceMarkdownLinks, getContentPathList} from '@docusaurus/utils';
|
||||
|
||||
function getVersion(filePath: string, options: DocsMarkdownOption) {
|
||||
const versionFound = options.versionsMetadata.find((version) =>
|
||||
getDocsDirPaths(version).some((docsDirPath) =>
|
||||
getContentPathList(version).some((docsDirPath) =>
|
||||
filePath.startsWith(docsDirPath),
|
||||
),
|
||||
);
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import type {PluginOptions} from '@docusaurus/plugin-content-docs';
|
||||
import type {PluginOptions, Options} from '@docusaurus/plugin-content-docs';
|
||||
import {
|
||||
Joi,
|
||||
RemarkPluginsSchema,
|
||||
|
@ -15,10 +15,7 @@ import {
|
|||
} from '@docusaurus/utils-validation';
|
||||
import {GlobExcludeDefault} from '@docusaurus/utils';
|
||||
|
||||
import type {
|
||||
OptionValidationContext,
|
||||
ValidationResult,
|
||||
} from '@docusaurus/types';
|
||||
import type {OptionValidationContext} from '@docusaurus/types';
|
||||
import logger from '@docusaurus/logger';
|
||||
import admonitions from 'remark-admonitions';
|
||||
import {DefaultSidebarItemsGenerator} from './sidebars/generator';
|
||||
|
@ -70,7 +67,7 @@ const VersionsOptionsSchema = Joi.object()
|
|||
.pattern(Joi.string().required(), VersionOptionsSchema)
|
||||
.default(DEFAULT_OPTIONS.versions);
|
||||
|
||||
export const OptionsSchema = Joi.object({
|
||||
const OptionsSchema = Joi.object<PluginOptions>({
|
||||
path: Joi.string().default(DEFAULT_OPTIONS.path),
|
||||
editUrl: Joi.alternatives().try(URISchema, Joi.function()),
|
||||
editCurrentVersion: Joi.boolean().default(DEFAULT_OPTIONS.editCurrentVersion),
|
||||
|
@ -80,6 +77,7 @@ export const OptionsSchema = Joi.object({
|
|||
// .allow('') ""
|
||||
.default(DEFAULT_OPTIONS.routeBasePath),
|
||||
tagsBasePath: Joi.string().default(DEFAULT_OPTIONS.tagsBasePath),
|
||||
// @ts-expect-error: deprecated
|
||||
homePageId: Joi.any().forbidden().messages({
|
||||
'any.unknown':
|
||||
'The docs plugin option homePageId is not supported anymore. To make a doc the "home", please add "slug: /" in its front matter. See: https://docusaurus.io/docs/next/docs-introduction#home-page-docs',
|
||||
|
@ -146,7 +144,7 @@ export const OptionsSchema = Joi.object({
|
|||
export function validateOptions({
|
||||
validate,
|
||||
options: userOptions,
|
||||
}: OptionValidationContext<PluginOptions>): ValidationResult<PluginOptions> {
|
||||
}: OptionValidationContext<Options, PluginOptions>): PluginOptions {
|
||||
let options = userOptions;
|
||||
|
||||
if (options.sidebarCollapsible === false) {
|
||||
|
@ -168,7 +166,7 @@ export function validateOptions({
|
|||
}
|
||||
}
|
||||
|
||||
const normalizedOptions = validate(OptionsSchema, options);
|
||||
const normalizedOptions = validate(OptionsSchema, options) as PluginOptions;
|
||||
|
||||
if (normalizedOptions.admonitions) {
|
||||
normalizedOptions.remarkPlugins = normalizedOptions.remarkPlugins.concat([
|
||||
|
|
|
@ -6,18 +6,25 @@
|
|||
*/
|
||||
|
||||
declare module '@docusaurus/plugin-content-docs' {
|
||||
import type {RemarkAndRehypePluginOptions} from '@docusaurus/mdx-loader';
|
||||
import type {MDXOptions} from '@docusaurus/mdx-loader';
|
||||
import type {ContentPaths, Tag, FrontMatterTag} from '@docusaurus/utils';
|
||||
import type {Required} from 'utility-types';
|
||||
|
||||
export interface Assets {
|
||||
image?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom callback for parsing number prefixes from file/folder names.
|
||||
*/
|
||||
export type NumberPrefixParser = (filename: string) => {
|
||||
/** file name without number prefix, without any other modification. */
|
||||
filename: string;
|
||||
/** The number prefix. Can be float, integer, negative, or anything. */
|
||||
numberPrefix?: number;
|
||||
};
|
||||
|
||||
export type CategoryIndexMatcherParam = {
|
||||
export type CategoryIndexMatcher = (param: {
|
||||
/** The file name, without extension */
|
||||
fileName: string;
|
||||
/**
|
||||
|
@ -27,113 +34,447 @@ declare module '@docusaurus/plugin-content-docs' {
|
|||
directories: string[];
|
||||
/** The extension, with a leading dot */
|
||||
extension: string;
|
||||
};
|
||||
export type CategoryIndexMatcher = (
|
||||
param: CategoryIndexMatcherParam,
|
||||
) => boolean;
|
||||
}) => boolean;
|
||||
|
||||
export type EditUrlFunction = (editUrlParams: {
|
||||
/** Name of the version. */
|
||||
version: string;
|
||||
/**
|
||||
* Path of the version's root content path, relative to the site directory.
|
||||
* Usually the same as `options.path` but can be localized or versioned.
|
||||
*/
|
||||
versionDocsDirPath: string;
|
||||
/** Path of the doc file, relative to `versionDocsDirPath`. */
|
||||
docPath: string;
|
||||
/** @see {@link DocMetadata.permalink} */
|
||||
permalink: string;
|
||||
/** Locale name. */
|
||||
locale: string;
|
||||
}) => string | undefined;
|
||||
|
||||
export type MetadataOptions = {
|
||||
/**
|
||||
* URL route for the docs section of your site. **DO NOT** include a
|
||||
* trailing slash. Use `/` for shipping docs without base path.
|
||||
*/
|
||||
routeBasePath: string;
|
||||
/**
|
||||
* Base URL to edit your site. The final URL is computed by `editUrl +
|
||||
* relativeDocPath`. Using a function allows more nuanced control for each
|
||||
* file. Omitting this variable entirely will disable edit links.
|
||||
*/
|
||||
editUrl?: string | EditUrlFunction;
|
||||
/**
|
||||
* The edit URL will always target the current version doc instead of older
|
||||
* versions. Ignored when `editUrl` is a function.
|
||||
*/
|
||||
editCurrentVersion: boolean;
|
||||
/**
|
||||
* The edit URL will target the localized file, instead of the original
|
||||
* unlocalized file. Ignored when `editUrl` is a function.
|
||||
*/
|
||||
editLocalizedFiles: boolean;
|
||||
/** Whether to display the last date the doc was updated. */
|
||||
showLastUpdateTime?: boolean;
|
||||
/** Whether to display the author who last updated the doc. */
|
||||
showLastUpdateAuthor?: boolean;
|
||||
/**
|
||||
* Custom parsing logic to extract number prefixes from file names. Use
|
||||
* `false` to disable this behavior and leave the docs untouched, and `true`
|
||||
* to use the default parser.
|
||||
*
|
||||
* @param filename One segment of the path, without any slashes.
|
||||
* @see https://docusaurus.io/docs/sidebar#using-number-prefixes
|
||||
*/
|
||||
numberPrefixParser: NumberPrefixParser;
|
||||
/** Enable or disable the breadcrumbs on doc pages. */
|
||||
breadcrumbs: boolean;
|
||||
};
|
||||
|
||||
export type PathOptions = {
|
||||
/**
|
||||
* Path to the docs content directory on the file system, relative to site
|
||||
* directory.
|
||||
*/
|
||||
path: string;
|
||||
/**
|
||||
* Path to sidebar configuration. Use `false` to disable sidebars, or
|
||||
* `undefined` to create a fully autogenerated sidebar.
|
||||
*/
|
||||
sidebarPath?: string | false | undefined;
|
||||
};
|
||||
|
||||
// TODO support custom version banner?
|
||||
// {type: "error", content: "html content"}
|
||||
export type VersionBanner = 'unreleased' | 'unmaintained';
|
||||
export type VersionOptions = {
|
||||
path?: string;
|
||||
label?: string;
|
||||
banner?: 'none' | VersionBanner;
|
||||
badge?: boolean;
|
||||
className?: string;
|
||||
};
|
||||
export type VersionsOptions = {
|
||||
/**
|
||||
* The version navigated to in priority and displayed by default for docs
|
||||
* navbar items.
|
||||
*
|
||||
* @see https://docusaurus.io/docs/versioning#terminology
|
||||
*/
|
||||
lastVersion?: string;
|
||||
versions: Record<string, VersionOptions>;
|
||||
/** Only include a subset of all available versions. */
|
||||
onlyIncludeVersions?: string[];
|
||||
/**
|
||||
* Explicitly disable versioning even when multiple versions exist. This
|
||||
* will make the site only include the current version. Will error if
|
||||
* `includeCurrentVersion: false` and `disableVersioning: true`.
|
||||
*/
|
||||
disableVersioning: boolean;
|
||||
/** Include the current version of your docs. */
|
||||
includeCurrentVersion: boolean;
|
||||
/** Independent customization of each version's properties. */
|
||||
versions: {
|
||||
[versionName: string]: {
|
||||
/**
|
||||
* The base path of the version, will be appended to `baseUrl` +
|
||||
* `routeBasePath`.
|
||||
*/
|
||||
path?: string;
|
||||
/** The label of the version to be used in badges, dropdowns, etc. */
|
||||
label?: string;
|
||||
/** The banner to show at the top of a doc of that version. */
|
||||
banner?: 'none' | VersionBanner;
|
||||
/** Show a badge with the version label at the top of each doc. */
|
||||
badge?: boolean;
|
||||
/** Add a custom class name to the <html> element of each doc. */
|
||||
className?: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
export type SidebarOptions = {
|
||||
/**
|
||||
* Whether sidebar categories are collapsible by default.
|
||||
*
|
||||
* @see https://docusaurus.io/docs/sidebar#collapsible-categories
|
||||
*/
|
||||
sidebarCollapsible: boolean;
|
||||
/**
|
||||
* Whether sidebar categories are collapsed by default.
|
||||
*
|
||||
* @see https://docusaurus.io/docs/sidebar#expanded-categories-by-default
|
||||
*/
|
||||
sidebarCollapsed: boolean;
|
||||
};
|
||||
|
||||
export type PluginOptions = MetadataOptions &
|
||||
PathOptions &
|
||||
VersionsOptions &
|
||||
RemarkAndRehypePluginOptions &
|
||||
MDXOptions &
|
||||
SidebarOptions & {
|
||||
/** Plugin ID. */
|
||||
id: string;
|
||||
/**
|
||||
* Array of glob patterns matching Markdown files to be built, relative to
|
||||
* the content path.
|
||||
*/
|
||||
include: string[];
|
||||
/**
|
||||
* Array of glob patterns matching Markdown files to be excluded. Serves
|
||||
* as refinement based on the `include` option.
|
||||
*/
|
||||
exclude: string[];
|
||||
/**
|
||||
* Root layout component of each doc page. Provides the version data
|
||||
* context, and is not unmounted when switching docs.
|
||||
*/
|
||||
docLayoutComponent: string;
|
||||
/** Main doc container, with TOC, pagination, etc. */
|
||||
docItemComponent: string;
|
||||
/** Root component of the "docs containing tag X" page. */
|
||||
docTagDocListComponent: string;
|
||||
/** Root component of the tags list page */
|
||||
docTagsListComponent: string;
|
||||
/** Root component of the generated category index page. */
|
||||
docCategoryGeneratedIndexComponent: string;
|
||||
admonitions: Record<string, unknown>;
|
||||
disableVersioning: boolean;
|
||||
includeCurrentVersion: boolean;
|
||||
admonitions: {[key: string]: unknown};
|
||||
sidebarItemsGenerator: import('./sidebars/types').SidebarItemsGeneratorOption;
|
||||
/**
|
||||
* URL route for the tags section of your doc version. Will be appended to
|
||||
* `routeBasePath`. **DO NOT** include a trailing slash.
|
||||
*/
|
||||
tagsBasePath: string;
|
||||
};
|
||||
export type Options = Partial<PluginOptions>;
|
||||
export type SidebarsConfig = import('./sidebars/types').SidebarsConfig;
|
||||
|
||||
export type VersionMetadata = ContentPaths & {
|
||||
/** A name like `1.0.0`. Acquired from `versions.json`. */
|
||||
versionName: string;
|
||||
/** Like `Version 1.0.0`. Can be configured through `versions.label`. */
|
||||
label: string;
|
||||
/**
|
||||
* Version's base path in the form of `/<baseUrl>/<routeBasePath>/1.0.0`.
|
||||
* Can be configured through `versions.path`.
|
||||
*/
|
||||
path: string;
|
||||
/** Tags base path in the form of `<versionPath>/tags`. */
|
||||
tagsPath: string;
|
||||
/**
|
||||
* The base URL to which the doc file path will be appended. Will be
|
||||
* `undefined` if `editUrl` is `undefined` or a function.
|
||||
*/
|
||||
editUrl?: string | undefined;
|
||||
/**
|
||||
* The base URL to which the localized doc file path will be appended. Will
|
||||
* be `undefined` if `editUrl` is `undefined` or a function.
|
||||
*/
|
||||
editUrlLocalized?: string | undefined;
|
||||
/**
|
||||
* "unmaintained" is the version before latest; "unreleased" is the version
|
||||
* after latest. `null` is the latest version without a banner. Can be
|
||||
* configured with `versions.banner`: `banner: "none"` will be transformed
|
||||
* to `null` here.
|
||||
*/
|
||||
banner: VersionBanner | null;
|
||||
/** Show a badge with the version label at the top of each doc. */
|
||||
badge: boolean;
|
||||
/** Add a custom class name to the <html> element of each doc. */
|
||||
className: string;
|
||||
/**
|
||||
* Whether this version is the "last" version. Can be configured with
|
||||
* `lastVersion` option.
|
||||
*/
|
||||
isLast: boolean;
|
||||
/**
|
||||
* Like `versioned_sidebars/1.0.0.json`. Versioned sidebars file may be
|
||||
* nonexistent since we don't create empty files.
|
||||
*/
|
||||
sidebarFilePath: string | false | undefined;
|
||||
/**
|
||||
* Will be -1 for the latest docs, and `undefined` for everything else.
|
||||
* Because `/docs/foo` should always be after `/docs/<versionName>/foo`.
|
||||
*/
|
||||
routePriority: number | undefined;
|
||||
};
|
||||
|
||||
export type DocFrontMatter = {
|
||||
/**
|
||||
* The last part of the doc ID (will be refactored in the future to be the
|
||||
* full ID instead)
|
||||
* @see {@link DocMetadata.id}
|
||||
*/
|
||||
id?: string;
|
||||
/**
|
||||
* Will override the default title collected from h1 heading.
|
||||
* @see {@link DocMetadata.title}
|
||||
*/
|
||||
title?: string;
|
||||
/**
|
||||
* Front matter tags, unnormalized.
|
||||
* @see {@link DocMetadata.tags}
|
||||
*/
|
||||
tags?: FrontMatterTag[];
|
||||
/**
|
||||
* If there isn't a Markdown h1 heading (which, if there is, we don't
|
||||
* remove), this front matter will cause the front matter title to not be
|
||||
* displayed in the doc page.
|
||||
*/
|
||||
hide_title?: boolean;
|
||||
/** Hide the TOC on the right. */
|
||||
hide_table_of_contents?: boolean;
|
||||
/** Used in the head meta. */
|
||||
keywords?: string[];
|
||||
/** Used in the head meta. Should use `assets.image` in priority. */
|
||||
image?: string;
|
||||
/**
|
||||
* Will override the default excerpt.
|
||||
* @see {@link DocMetadata.description}
|
||||
*/
|
||||
description?: string;
|
||||
/**
|
||||
* Custom slug appended after /<baseUrl>/<routeBasePath>/<versionPath>
|
||||
* @see {@link DocMetadata.slug}
|
||||
*/
|
||||
slug?: string;
|
||||
/** Customizes the sidebar label for this doc. Will default to its title. */
|
||||
sidebar_label?: string;
|
||||
/**
|
||||
* Controls the position of a doc inside the generated sidebar slice when
|
||||
* using autogenerated sidebar items.
|
||||
*
|
||||
* @see https://docusaurus.io/docs/sidebar#autogenerated-sidebar-metadata
|
||||
*/
|
||||
sidebar_position?: number;
|
||||
/**
|
||||
* Gives the corresponding sidebar label a special class name when using
|
||||
* autogenerated sidebars.
|
||||
*/
|
||||
sidebar_class_name?: string;
|
||||
/**
|
||||
* Will be propagated to the final sidebars data structure. Useful if you
|
||||
* have swizzled sidebar-related code or simply querying doc data through
|
||||
* sidebars.
|
||||
*/
|
||||
sidebar_custom_props?: {[key: string]: unknown};
|
||||
/**
|
||||
* Changes the sidebar association of the current doc. Use `null` to make
|
||||
* the current doc not associated to any sidebar.
|
||||
*/
|
||||
displayed_sidebar?: string | null;
|
||||
/**
|
||||
* Customizes the pagination label for this doc. Will default to the sidebar
|
||||
* label.
|
||||
*/
|
||||
pagination_label?: string;
|
||||
/** Overrides the default URL computed for this doc. */
|
||||
custom_edit_url?: string | null;
|
||||
/**
|
||||
* Whether number prefix parsing is disabled on this doc.
|
||||
* @see https://docusaurus.io/docs/sidebar#using-number-prefixes
|
||||
*/
|
||||
parse_number_prefixes?: boolean;
|
||||
/**
|
||||
* Minimum TOC heading level. Must be between 2 and 6 and lower or equal to
|
||||
* the max value.
|
||||
*/
|
||||
toc_min_heading_level?: number;
|
||||
/** Maximum TOC heading level. Must be between 2 and 6. */
|
||||
toc_max_heading_level?: number;
|
||||
/**
|
||||
* The ID of the documentation you want the "Next" pagination to link to.
|
||||
* Use `null` to disable showing "Next" for this page.
|
||||
* @see {@link DocMetadata.next}
|
||||
*/
|
||||
pagination_next?: string | null;
|
||||
/**
|
||||
* The ID of the documentation you want the "Previous" pagination to link
|
||||
* to. Use `null` to disable showing "Previous" for this page.
|
||||
* @see {@link DocMetadata.prev}
|
||||
*/
|
||||
pagination_prev?: string | null;
|
||||
};
|
||||
|
||||
export type LastUpdateData = {
|
||||
/** A timestamp in **seconds**, directly acquired from `git log`. */
|
||||
lastUpdatedAt?: number;
|
||||
/** `lastUpdatedAt` formatted as a date according to the current locale. */
|
||||
formattedLastUpdatedAt?: string;
|
||||
/** The author's name directly acquired from `git log`. */
|
||||
lastUpdatedBy?: string;
|
||||
};
|
||||
|
||||
export type DocMetadataBase = LastUpdateData & {
|
||||
// TODO
|
||||
/**
|
||||
* Legacy versioned ID. Will be refactored in the future to be unversioned.
|
||||
*/
|
||||
id: string;
|
||||
// TODO
|
||||
/**
|
||||
* Unversioned ID. Should be preferred everywhere over `id` until the latter
|
||||
* is refactored.
|
||||
*/
|
||||
unversionedId: string;
|
||||
/** The name of the version this doc belongs to. */
|
||||
version: string;
|
||||
/**
|
||||
* Used to generate the page h1 heading, tab title, and pagination title.
|
||||
*/
|
||||
title: string;
|
||||
/**
|
||||
* Description used in the meta. Could be an empty string (empty content)
|
||||
*/
|
||||
description: string;
|
||||
/** Path to the Markdown source, with `@site` alias. */
|
||||
source: string;
|
||||
/**
|
||||
* Posix path relative to the content path. Can be `"."`.
|
||||
* e.g. "folder/subfolder/subsubfolder"
|
||||
*/
|
||||
sourceDirName: string;
|
||||
/** `permalink` without base URL or version path. */
|
||||
slug: string;
|
||||
/** Full URL to this doc, with base URL and version path. */
|
||||
permalink: string;
|
||||
/**
|
||||
* Position in an autogenerated sidebar slice, acquired through front matter
|
||||
* or number prefix.
|
||||
*/
|
||||
sidebarPosition?: number;
|
||||
/**
|
||||
* Acquired from the options; can be customized with front matter.
|
||||
* `custom_edit_url` will always lead to it being null, but you should treat
|
||||
* `undefined` and `null` as equivalent.
|
||||
*/
|
||||
editUrl?: string | null;
|
||||
/** Tags, normalized. */
|
||||
tags: Tag[];
|
||||
/** Front matter, as-is. */
|
||||
frontMatter: DocFrontMatter & {[key: string]: unknown};
|
||||
};
|
||||
|
||||
export type DocMetadata = DocMetadataBase &
|
||||
PropNavigation & {
|
||||
/** Name of the sidebar this doc is associated with. */
|
||||
sidebar?: string;
|
||||
};
|
||||
|
||||
export type CategoryGeneratedIndexMetadata = Required<
|
||||
Omit<
|
||||
import('./sidebars/types').SidebarItemCategoryLinkGeneratedIndex,
|
||||
'type'
|
||||
>,
|
||||
'title'
|
||||
> & {
|
||||
navigation: PropNavigation;
|
||||
/**
|
||||
* Name of the sidebar this doc is associated with. Unlike
|
||||
* `DocMetadata.sidebar`, this will always be defined, because a generated
|
||||
* index can only be generated from a category.
|
||||
*/
|
||||
sidebar: string;
|
||||
};
|
||||
|
||||
export type PropNavigationLink = {
|
||||
readonly title: string;
|
||||
readonly permalink: string;
|
||||
};
|
||||
export type PropNavigation = {
|
||||
/**
|
||||
* Used in pagination. Content is just a subset of another doc's metadata.
|
||||
*/
|
||||
readonly previous?: PropNavigationLink;
|
||||
/**
|
||||
* Used in pagination. Content is just a subset of another doc's metadata.
|
||||
*/
|
||||
readonly next?: PropNavigationLink;
|
||||
};
|
||||
|
||||
export type PropVersionDoc = import('./sidebars/types').PropVersionDoc;
|
||||
export type PropVersionDocs = import('./sidebars/types').PropVersionDocs;
|
||||
export type PropVersionDoc = Pick<
|
||||
DocMetadata,
|
||||
'id' | 'title' | 'description' | 'sidebar'
|
||||
>;
|
||||
|
||||
export type PropVersionMetadata = {
|
||||
export type PropVersionDocs = {
|
||||
[docId: string]: PropVersionDoc;
|
||||
};
|
||||
|
||||
export type PropVersionMetadata = Pick<
|
||||
VersionMetadata,
|
||||
'label' | 'banner' | 'badge' | 'className' | 'isLast'
|
||||
> & {
|
||||
/** ID of the docs plugin this version belongs to. */
|
||||
pluginId: string;
|
||||
/** Name of this version. */
|
||||
version: string;
|
||||
label: string;
|
||||
banner: VersionBanner | null;
|
||||
badge: boolean;
|
||||
className: string;
|
||||
isLast: boolean;
|
||||
/** Sidebars contained in this version. */
|
||||
docsSidebars: PropSidebars;
|
||||
/** Docs contained in this version. */
|
||||
docs: PropVersionDocs;
|
||||
};
|
||||
|
||||
export type PropCategoryGeneratedIndex = {
|
||||
title: string;
|
||||
description?: string;
|
||||
image?: string;
|
||||
keywords?: string | readonly string[];
|
||||
slug: string;
|
||||
permalink: string;
|
||||
navigation: PropNavigation;
|
||||
};
|
||||
export type PropCategoryGeneratedIndex = Omit<
|
||||
CategoryGeneratedIndexMetadata,
|
||||
'sidebar'
|
||||
>;
|
||||
|
||||
export type PropSidebarItemLink =
|
||||
import('./sidebars/types').PropSidebarItemLink;
|
||||
export type PropSidebarItemHtml =
|
||||
import('./sidebars/types').PropSidebarItemHtml;
|
||||
export type PropSidebarItemCategory =
|
||||
import('./sidebars/types').PropSidebarItemCategory;
|
||||
export type PropSidebarItem = import('./sidebars/types').PropSidebarItem;
|
||||
|
@ -167,9 +508,10 @@ declare module '@docusaurus/plugin-content-docs' {
|
|||
declare module '@theme/DocItem' {
|
||||
import type {TOCItem} from '@docusaurus/types';
|
||||
import type {
|
||||
PropNavigationLink,
|
||||
PropVersionMetadata,
|
||||
Assets,
|
||||
DocMetadata,
|
||||
DocFrontMatter,
|
||||
} from '@docusaurus/plugin-content-docs';
|
||||
|
||||
export type DocumentRoute = {
|
||||
|
@ -179,41 +521,12 @@ declare module '@theme/DocItem' {
|
|||
readonly sidebar?: string;
|
||||
};
|
||||
|
||||
export type FrontMatter = {
|
||||
readonly id: string;
|
||||
readonly title: string;
|
||||
readonly image?: string;
|
||||
readonly keywords?: readonly string[];
|
||||
readonly hide_title?: boolean;
|
||||
readonly hide_table_of_contents?: boolean;
|
||||
readonly toc_min_heading_level?: number;
|
||||
readonly toc_max_heading_level?: number;
|
||||
};
|
||||
|
||||
export type Metadata = {
|
||||
readonly unversionedId?: string;
|
||||
readonly description?: string;
|
||||
readonly title?: string;
|
||||
readonly permalink?: string;
|
||||
readonly editUrl?: string;
|
||||
readonly lastUpdatedAt?: number;
|
||||
readonly formattedLastUpdatedAt?: string;
|
||||
readonly lastUpdatedBy?: string;
|
||||
readonly version?: string;
|
||||
readonly previous?: PropNavigationLink;
|
||||
readonly next?: PropNavigationLink;
|
||||
readonly tags: readonly {
|
||||
readonly label: string;
|
||||
readonly permalink: string;
|
||||
}[];
|
||||
};
|
||||
|
||||
export interface Props {
|
||||
readonly route: DocumentRoute;
|
||||
readonly versionMetadata: PropVersionMetadata;
|
||||
readonly content: {
|
||||
readonly frontMatter: FrontMatter;
|
||||
readonly metadata: Metadata;
|
||||
readonly frontMatter: DocFrontMatter;
|
||||
readonly metadata: DocMetadata;
|
||||
readonly toc: readonly TOCItem[];
|
||||
readonly contentTitle: string | undefined;
|
||||
readonly assets: Assets;
|
||||
|
@ -273,6 +586,40 @@ declare module '@theme/DocPage' {
|
|||
export default function DocPage(props: Props): JSX.Element;
|
||||
}
|
||||
|
||||
declare module '@theme/DocPage/Layout' {
|
||||
import type {ReactNode} from 'react';
|
||||
|
||||
export interface Props {
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
export default function DocPageLayout(props: Props): JSX.Element;
|
||||
}
|
||||
|
||||
declare module '@theme/DocPage/Layout/Aside' {
|
||||
import type {Dispatch, SetStateAction} from 'react';
|
||||
import type {PropSidebar} from '@docusaurus/plugin-content-docs';
|
||||
|
||||
export interface Props {
|
||||
sidebar: PropSidebar;
|
||||
hiddenSidebarContainer: boolean;
|
||||
setHiddenSidebarContainer: Dispatch<SetStateAction<boolean>>;
|
||||
}
|
||||
|
||||
export default function DocPageLayoutAside(props: Props): JSX.Element;
|
||||
}
|
||||
|
||||
declare module '@theme/DocPage/Layout/Main' {
|
||||
import type {ReactNode} from 'react';
|
||||
|
||||
export interface Props {
|
||||
hiddenSidebarContainer: boolean;
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
export default function DocPageLayoutMain(props: Props): JSX.Element;
|
||||
}
|
||||
|
||||
// TODO until TS supports exports field... hope it's in 4.6
|
||||
declare module '@docusaurus/plugin-content-docs/client' {
|
||||
export type ActivePlugin = {
|
||||
|
@ -282,7 +629,7 @@ declare module '@docusaurus/plugin-content-docs/client' {
|
|||
export type ActiveDocContext = {
|
||||
activeVersion?: GlobalVersion;
|
||||
activeDoc?: GlobalDoc;
|
||||
alternateDocVersions: Record<string, GlobalDoc>;
|
||||
alternateDocVersions: {[versionName: string]: GlobalDoc};
|
||||
};
|
||||
export type GlobalDoc = {
|
||||
id: string;
|
||||
|
@ -297,16 +644,14 @@ declare module '@docusaurus/plugin-content-docs/client' {
|
|||
path: string;
|
||||
mainDocId: string; // home doc (if docs homepage configured), or first doc
|
||||
docs: GlobalDoc[];
|
||||
sidebars?: Record<string, GlobalSidebar>;
|
||||
};
|
||||
|
||||
export type GlobalSidebarLink = {
|
||||
label: string;
|
||||
path: string;
|
||||
sidebars?: {[sidebarId: string]: GlobalSidebar};
|
||||
};
|
||||
|
||||
export type GlobalSidebar = {
|
||||
link?: GlobalSidebarLink;
|
||||
link?: {
|
||||
label: string;
|
||||
path: string;
|
||||
};
|
||||
// ... we may add other things here later
|
||||
};
|
||||
export type GlobalPluginData = {
|
||||
|
@ -322,7 +667,7 @@ declare module '@docusaurus/plugin-content-docs/client' {
|
|||
};
|
||||
export type GetActivePluginOptions = {failfast?: boolean}; // use fail-fast option if you know for sure one plugin instance is active
|
||||
|
||||
export const useAllDocsData: () => Record<string, GlobalPluginData>;
|
||||
export const useAllDocsData: () => {[pluginId: string]: GlobalPluginData};
|
||||
export const useDocsData: (pluginId?: string) => GlobalPluginData;
|
||||
export const useActivePlugin: (
|
||||
options?: GetActivePluginOptions,
|
||||
|
|
|
@ -5,13 +5,12 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import type {LoadedVersion, VersionTag, DocMetadata} from './types';
|
||||
import type {LoadedVersion, VersionTag} from './types';
|
||||
import type {
|
||||
SidebarItemDoc,
|
||||
SidebarItem,
|
||||
SidebarItemCategory,
|
||||
SidebarItemCategoryLink,
|
||||
PropVersionDocs,
|
||||
} from './sidebars/types';
|
||||
import type {
|
||||
PropSidebars,
|
||||
|
@ -21,6 +20,8 @@ import type {
|
|||
PropTagDocList,
|
||||
PropTagDocListDoc,
|
||||
PropSidebarItemLink,
|
||||
PropVersionDocs,
|
||||
DocMetadata,
|
||||
} from '@docusaurus/plugin-content-docs';
|
||||
import _ from 'lodash';
|
||||
import {createDocsByIdIndex} from './docs';
|
||||
|
@ -119,10 +120,10 @@ export function toVersionMetadataProp(
|
|||
return {
|
||||
pluginId,
|
||||
version: loadedVersion.versionName,
|
||||
label: loadedVersion.versionLabel,
|
||||
banner: loadedVersion.versionBanner,
|
||||
badge: loadedVersion.versionBadge,
|
||||
className: loadedVersion.versionClassName,
|
||||
label: loadedVersion.label,
|
||||
banner: loadedVersion.banner,
|
||||
badge: loadedVersion.badge,
|
||||
className: loadedVersion.className,
|
||||
isLast: loadedVersion.isLast,
|
||||
docsSidebars: toSidebarsProp(loadedVersion),
|
||||
docs: toVersionDocsProp(loadedVersion),
|
||||
|
@ -153,7 +154,7 @@ export function toTagDocListProp({
|
|||
}
|
||||
|
||||
return {
|
||||
name: tag.name,
|
||||
name: tag.label,
|
||||
permalink: tag.permalink,
|
||||
docs: toDocListProp(),
|
||||
allTagsPath,
|
||||
|
|
|
@ -7,12 +7,11 @@
|
|||
|
||||
import type {PluginContentLoadedActions, RouteConfig} from '@docusaurus/types';
|
||||
import {docuHash, createSlugger} from '@docusaurus/utils';
|
||||
import type {LoadedVersion} from './types';
|
||||
import type {
|
||||
CategoryGeneratedIndexMetadata,
|
||||
DocMetadata,
|
||||
LoadedVersion,
|
||||
} from './types';
|
||||
import type {PropCategoryGeneratedIndex} from '@docusaurus/plugin-content-docs';
|
||||
} from '@docusaurus/plugin-content-docs';
|
||||
import {toVersionMetadataProp} from './props';
|
||||
import logger from '@docusaurus/logger';
|
||||
|
||||
|
@ -32,42 +31,19 @@ export async function createCategoryGeneratedIndexRoutes({
|
|||
async function createCategoryGeneratedIndexRoute(
|
||||
categoryGeneratedIndex: CategoryGeneratedIndexMetadata,
|
||||
): Promise<RouteConfig> {
|
||||
const {
|
||||
sidebar,
|
||||
title,
|
||||
description,
|
||||
slug,
|
||||
permalink,
|
||||
previous,
|
||||
next,
|
||||
image,
|
||||
keywords,
|
||||
} = categoryGeneratedIndex;
|
||||
const {sidebar, ...prop} = categoryGeneratedIndex;
|
||||
|
||||
const propFileName = slugs.slug(
|
||||
`${version.versionPath}-${categoryGeneratedIndex.sidebar}-category-${categoryGeneratedIndex.title}`,
|
||||
`${version.path}-${categoryGeneratedIndex.sidebar}-category-${categoryGeneratedIndex.title}`,
|
||||
);
|
||||
|
||||
const prop: PropCategoryGeneratedIndex = {
|
||||
title,
|
||||
description,
|
||||
slug,
|
||||
permalink,
|
||||
image,
|
||||
keywords,
|
||||
navigation: {
|
||||
previous,
|
||||
next,
|
||||
},
|
||||
};
|
||||
|
||||
const propData = await actions.createData(
|
||||
`${docuHash(`category/${propFileName}`)}.json`,
|
||||
JSON.stringify(prop, null, 2),
|
||||
);
|
||||
|
||||
return {
|
||||
path: permalink,
|
||||
path: categoryGeneratedIndex.permalink,
|
||||
component: docCategoryGeneratedIndexComponent,
|
||||
exact: true,
|
||||
modules: {
|
||||
|
@ -162,7 +138,7 @@ export async function createVersionRoutes({
|
|||
}
|
||||
|
||||
actions.addRoute({
|
||||
path: version.versionPath,
|
||||
path: version.path,
|
||||
// allow matching /docs/* as well
|
||||
exact: false,
|
||||
// main docs component (DocPage)
|
||||
|
|
|
@ -116,7 +116,7 @@ exports[`DefaultSidebarItemsGenerator generates subfolder sidebar 1`] = `
|
|||
"type": "doc",
|
||||
},
|
||||
],
|
||||
"label": "subsubsubfolder3 (_category_.json label)",
|
||||
"label": "Subsubsubfolder category label",
|
||||
"link": {
|
||||
"id": "doc1",
|
||||
"type": "doc",
|
||||
|
|
|
@ -234,7 +234,7 @@ describe('DefaultSidebarItemsGenerator', () => {
|
|||
},
|
||||
'subfolder/subsubfolder/subsubsubfolder3': {
|
||||
position: 1,
|
||||
label: 'subsubsubfolder3 (_category_.json label)',
|
||||
// This item's label is defined from the index doc instead
|
||||
link: {
|
||||
type: 'doc',
|
||||
id: 'doc1', // This is a "fully-qualified" ID that can't be found locally
|
||||
|
@ -246,6 +246,7 @@ describe('DefaultSidebarItemsGenerator', () => {
|
|||
id: 'doc1',
|
||||
source: 'doc1.md',
|
||||
sourceDirName: 'subfolder/subsubfolder',
|
||||
title: 'Subsubsubfolder category label',
|
||||
sidebarPosition: undefined,
|
||||
frontMatter: {},
|
||||
},
|
||||
|
|
|
@ -34,7 +34,7 @@ describe('postProcess', () => {
|
|||
},
|
||||
{
|
||||
sidebarOptions: {sidebarCollapsed: true, sidebarCollapsible: true},
|
||||
version: {versionPath: 'version'},
|
||||
version: {path: 'version'},
|
||||
},
|
||||
);
|
||||
|
||||
|
@ -53,7 +53,7 @@ describe('postProcess', () => {
|
|||
},
|
||||
{
|
||||
sidebarOptions: {sidebarCollapsed: true, sidebarCollapsible: true},
|
||||
version: {versionPath: 'version'},
|
||||
version: {path: 'version'},
|
||||
},
|
||||
);
|
||||
}).toThrowErrorMatchingInlineSnapshot(
|
||||
|
@ -78,7 +78,7 @@ describe('postProcess', () => {
|
|||
|
||||
{
|
||||
sidebarOptions: {sidebarCollapsed: true, sidebarCollapsible: true},
|
||||
version: {versionPath: 'version'},
|
||||
version: {path: 'version'},
|
||||
},
|
||||
),
|
||||
).toMatchSnapshot();
|
||||
|
@ -98,7 +98,7 @@ describe('postProcess', () => {
|
|||
|
||||
{
|
||||
sidebarOptions: {sidebarCollapsed: false, sidebarCollapsible: false},
|
||||
version: {versionPath: 'version'},
|
||||
version: {path: 'version'},
|
||||
},
|
||||
),
|
||||
).toMatchSnapshot();
|
||||
|
@ -117,7 +117,7 @@ describe('postProcess', () => {
|
|||
|
||||
{
|
||||
sidebarOptions: {sidebarCollapsed: true, sidebarCollapsible: false},
|
||||
version: {versionPath: 'version'},
|
||||
version: {path: 'version'},
|
||||
},
|
||||
),
|
||||
).toMatchSnapshot();
|
||||
|
|
|
@ -18,7 +18,7 @@ import type {
|
|||
} from '../types';
|
||||
import {DefaultSidebarItemsGenerator} from '../generator';
|
||||
import {createSlugger} from '@docusaurus/utils';
|
||||
import type {VersionMetadata} from '../../types';
|
||||
import type {VersionMetadata} from '@docusaurus/plugin-content-docs';
|
||||
import {DefaultNumberPrefixParser} from '../../numberPrefix';
|
||||
import {isCategoryIndex} from '../../docs';
|
||||
|
||||
|
@ -57,7 +57,7 @@ describe('processSidebars', () => {
|
|||
|
||||
async function testProcessSidebars(
|
||||
unprocessedSidebars: NormalizedSidebars,
|
||||
categoriesMetadata: Record<string, CategoryMetadataFile> = {},
|
||||
categoriesMetadata: {[filePath: string]: CategoryMetadataFile} = {},
|
||||
paramsOverrides: Partial<SidebarProcessorParams> = {},
|
||||
) {
|
||||
return processSidebars(unprocessedSidebars, categoriesMetadata, {
|
||||
|
@ -142,7 +142,6 @@ describe('processSidebars', () => {
|
|||
},
|
||||
numberPrefixParser: DefaultNumberPrefixParser,
|
||||
isCategoryIndex,
|
||||
options: params.sidebarOptions,
|
||||
});
|
||||
expect(StaticSidebarItemsGenerator).toHaveBeenCalledWith({
|
||||
defaultSidebarItemsGenerator: DefaultSidebarItemsGenerator,
|
||||
|
@ -154,7 +153,6 @@ describe('processSidebars', () => {
|
|||
},
|
||||
numberPrefixParser: DefaultNumberPrefixParser,
|
||||
isCategoryIndex,
|
||||
options: params.sidebarOptions,
|
||||
});
|
||||
expect(StaticSidebarItemsGenerator).toHaveBeenCalledWith({
|
||||
defaultSidebarItemsGenerator: DefaultSidebarItemsGenerator,
|
||||
|
@ -166,7 +164,6 @@ describe('processSidebars', () => {
|
|||
},
|
||||
numberPrefixParser: DefaultNumberPrefixParser,
|
||||
isCategoryIndex,
|
||||
options: params.sidebarOptions,
|
||||
});
|
||||
|
||||
expect(processedSidebar).toEqual({
|
||||
|
|
|
@ -16,7 +16,10 @@ import {
|
|||
toNavigationLink,
|
||||
} from '../utils';
|
||||
import type {Sidebar, Sidebars} from '../types';
|
||||
import type {DocMetadataBase, DocNavLink} from '../../types';
|
||||
import type {
|
||||
DocMetadataBase,
|
||||
PropNavigationLink,
|
||||
} from '@docusaurus/plugin-content-docs';
|
||||
|
||||
describe('createSidebarsUtils', () => {
|
||||
const sidebar1: Sidebar = [
|
||||
|
@ -618,7 +621,7 @@ describe('toDocNavigationLink', () => {
|
|||
).toEqual({
|
||||
title: 'Doc Title',
|
||||
permalink: '/docPermalink',
|
||||
} as DocNavLink);
|
||||
} as PropNavigationLink);
|
||||
});
|
||||
|
||||
it('with pagination_label front matter', () => {
|
||||
|
@ -635,7 +638,7 @@ describe('toDocNavigationLink', () => {
|
|||
).toEqual({
|
||||
title: 'pagination_label',
|
||||
permalink: '/docPermalink',
|
||||
} as DocNavLink);
|
||||
} as PropNavigationLink);
|
||||
});
|
||||
|
||||
it('with sidebar_label front matter', () => {
|
||||
|
@ -652,7 +655,7 @@ describe('toDocNavigationLink', () => {
|
|||
).toEqual({
|
||||
title: 'sidebar_label',
|
||||
permalink: '/docPermalink',
|
||||
} as DocNavLink);
|
||||
} as PropNavigationLink);
|
||||
});
|
||||
|
||||
it('with pagination_label + sidebar_label front matter', () => {
|
||||
|
@ -670,7 +673,7 @@ describe('toDocNavigationLink', () => {
|
|||
).toEqual({
|
||||
title: 'pagination_label',
|
||||
permalink: '/docPermalink',
|
||||
} as DocNavLink);
|
||||
} as PropNavigationLink);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -680,7 +683,7 @@ describe('toNavigationLink', () => {
|
|||
return {...data, frontMatter: {}} as DocMetadataBase;
|
||||
}
|
||||
|
||||
const docsById: Record<string, DocMetadataBase> = {
|
||||
const docsById: {[docId: string]: DocMetadataBase} = {
|
||||
doc1: testDoc({
|
||||
title: 'Doc 1',
|
||||
permalink: '/doc1',
|
||||
|
|
|
@ -14,7 +14,7 @@ import type {
|
|||
SidebarItemCategoryLinkConfig,
|
||||
} from './types';
|
||||
import _ from 'lodash';
|
||||
import {addTrailingSlash, posixPath} from '@docusaurus/utils';
|
||||
import {addTrailingSlash} from '@docusaurus/utils';
|
||||
import logger from '@docusaurus/logger';
|
||||
import path from 'path';
|
||||
import {createDocsByIdIndex, toCategoryIndexMatcherParam} from '../docs';
|
||||
|
@ -157,10 +157,7 @@ Available doc IDs:
|
|||
folderName: string,
|
||||
): WithPosition<NormalizedSidebarItemCategory> {
|
||||
const categoryMetadata =
|
||||
categoriesMetadata[posixPath(path.join(autogenDir, fullPath))];
|
||||
const className = categoryMetadata?.className;
|
||||
const customProps = categoryMetadata?.customProps;
|
||||
const {filename, numberPrefix} = numberPrefixParser(folderName);
|
||||
categoriesMetadata[path.posix.join(autogenDir, fullPath)];
|
||||
const allItems = Object.entries(dir).map(([key, content]) =>
|
||||
dirToItem(content, key, `${fullPath}/${key}`),
|
||||
);
|
||||
|
@ -184,41 +181,65 @@ Available doc IDs:
|
|||
});
|
||||
}
|
||||
|
||||
function getCategoryLinkedDocId(): string | undefined {
|
||||
const link = categoryMetadata?.link;
|
||||
if (link !== undefined) {
|
||||
if (link && link.type === 'doc') {
|
||||
return findDocByLocalId(link.id)?.id || getDoc(link.id).id;
|
||||
// In addition to the ID, this function also retrieves metadata of the
|
||||
// linked doc that could be used as fallback values for category metadata
|
||||
function getCategoryLinkedDocMetadata():
|
||||
| {
|
||||
id: string;
|
||||
position?: number;
|
||||
label?: string;
|
||||
customProps?: {[key: string]: unknown};
|
||||
className?: string;
|
||||
}
|
||||
| undefined {
|
||||
const link = categoryMetadata?.link;
|
||||
if (link !== undefined && link?.type !== 'doc') {
|
||||
// If a link is explicitly specified, we won't apply conventions
|
||||
return undefined;
|
||||
}
|
||||
// Apply default convention to pick index.md, README.md or
|
||||
// <categoryName>.md as the category doc
|
||||
return findConventionalCategoryDocLink()?.id;
|
||||
const id = link
|
||||
? findDocByLocalId(link.id)?.id ?? getDoc(link.id).id
|
||||
: findConventionalCategoryDocLink()?.id;
|
||||
if (!id) {
|
||||
return undefined;
|
||||
}
|
||||
const doc = getDoc(id);
|
||||
return {
|
||||
id,
|
||||
position: doc.sidebarPosition,
|
||||
label: doc.frontMatter.sidebar_label ?? doc.title,
|
||||
customProps: doc.frontMatter.sidebar_custom_props,
|
||||
className: doc.frontMatter.sidebar_class_name,
|
||||
};
|
||||
}
|
||||
|
||||
const categoryLinkedDocId = getCategoryLinkedDocId();
|
||||
|
||||
const categoryLinkedDoc = getCategoryLinkedDocMetadata();
|
||||
const link: SidebarItemCategoryLinkConfig | null | undefined =
|
||||
categoryLinkedDocId
|
||||
categoryLinkedDoc
|
||||
? {
|
||||
type: 'doc',
|
||||
id: categoryLinkedDocId, // We "remap" a potentially "local id" to a "qualified id"
|
||||
id: categoryLinkedDoc.id, // We "remap" a potentially "local id" to a "qualified id"
|
||||
}
|
||||
: categoryMetadata?.link;
|
||||
|
||||
// If a doc is linked, remove it from the category subItems
|
||||
const items = allItems.filter(
|
||||
(item) => !(item.type === 'doc' && item.id === categoryLinkedDocId),
|
||||
(item) => !(item.type === 'doc' && item.id === categoryLinkedDoc?.id),
|
||||
);
|
||||
|
||||
const className =
|
||||
categoryMetadata?.className ?? categoryLinkedDoc?.className;
|
||||
const customProps =
|
||||
categoryMetadata?.customProps ?? categoryLinkedDoc?.customProps;
|
||||
const {filename, numberPrefix} = numberPrefixParser(folderName);
|
||||
|
||||
return {
|
||||
type: 'category',
|
||||
label: categoryMetadata?.label ?? filename,
|
||||
label: categoryMetadata?.label ?? categoryLinkedDoc?.label ?? filename,
|
||||
collapsible: categoryMetadata?.collapsible,
|
||||
collapsed: categoryMetadata?.collapsed,
|
||||
position: categoryMetadata?.position ?? numberPrefix,
|
||||
position:
|
||||
categoryMetadata?.position ??
|
||||
categoryLinkedDoc?.position ??
|
||||
numberPrefix,
|
||||
source: folderName,
|
||||
...(customProps !== undefined && {customProps}),
|
||||
...(className !== undefined && {className}),
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue