mirror of
https://github.com/facebook/docusaurus.git
synced 2025-12-28 20:52:48 +00:00
Compare commits
23 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
60be18cee9 | ||
|
|
0265d17b8e | ||
|
|
c702aa6201 | ||
|
|
6aab42ed56 | ||
|
|
7832f6b302 | ||
|
|
8404fbeda5 | ||
|
|
dea538d082 | ||
|
|
4ab5a93262 | ||
|
|
4a2200ace4 | ||
|
|
4fb67ef11b | ||
|
|
985a64ad22 | ||
|
|
c60387dbe8 | ||
|
|
c84d779627 | ||
|
|
de972142a8 | ||
|
|
7743aa6307 | ||
|
|
26d2b9a018 | ||
|
|
bb65b5c578 | ||
|
|
2ef40c2598 | ||
|
|
d88f248180 | ||
|
|
e4fc47bec2 | ||
|
|
e78a15eeba | ||
|
|
c751bc64ea | ||
|
|
d255389e48 |
|
|
@ -28,6 +28,7 @@
|
||||||
"__snapshots__",
|
"__snapshots__",
|
||||||
"website/src/data/users.tsx",
|
"website/src/data/users.tsx",
|
||||||
"website/src/data/tweets.tsx",
|
"website/src/data/tweets.tsx",
|
||||||
|
"website/docusaurus.config.localized.json",
|
||||||
"*.xyz",
|
"*.xyz",
|
||||||
"*.docx",
|
"*.docx",
|
||||||
"versioned_docs",
|
"versioned_docs",
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "new.docusaurus.io",
|
"name": "new.docusaurus.io",
|
||||||
"version": "2.0.0-rc.1",
|
"version": "2.4.2",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "npx --package netlify-cli netlify dev"
|
"start": "npx --package netlify-cli netlify dev"
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
CUSTOM_REGISTRY_URL="http://localhost:4873"
|
CUSTOM_REGISTRY_URL="http://localhost:4873"
|
||||||
NEW_VERSION="$(node -p "require('./packages/docusaurus/package.json').version").NEW"
|
NEW_VERSION="$(node -p "require('./packages/docusaurus/package.json').version")-NEW"
|
||||||
CONTAINER_NAME="verdaccio"
|
CONTAINER_NAME="verdaccio"
|
||||||
EXTRA_OPTS=""
|
EXTRA_OPTS=""
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"version": "2.0.0-rc.1",
|
"version": "2.4.2",
|
||||||
"npmClient": "yarn",
|
"npmClient": "yarn",
|
||||||
"useWorkspaces": true,
|
"useWorkspaces": true,
|
||||||
"changelog": {
|
"changelog": {
|
||||||
|
|
@ -11,6 +11,7 @@
|
||||||
"pr: performance": ":running_woman: Performance",
|
"pr: performance": ":running_woman: Performance",
|
||||||
"pr: polish": ":nail_care: Polish",
|
"pr: polish": ":nail_care: Polish",
|
||||||
"pr: documentation": ":memo: Documentation",
|
"pr: documentation": ":memo: Documentation",
|
||||||
|
"pr: dependencies": ":robot: Dependencies",
|
||||||
"pr: maintenance": ":wrench: Maintenance"
|
"pr: maintenance": ":wrench: Maintenance"
|
||||||
},
|
},
|
||||||
"cacheDir": ".changelog"
|
"cacheDir": ".changelog"
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "create-docusaurus",
|
"name": "create-docusaurus",
|
||||||
"version": "2.0.0-rc.1",
|
"version": "2.4.2",
|
||||||
"description": "Create Docusaurus apps easily.",
|
"description": "Create Docusaurus apps easily.",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
@ -22,8 +22,8 @@
|
||||||
},
|
},
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docusaurus/logger": "2.0.0-rc.1",
|
"@docusaurus/logger": "2.4.2",
|
||||||
"@docusaurus/utils": "2.0.0-rc.1",
|
"@docusaurus/utils": "2.4.2",
|
||||||
"commander": "^5.1.0",
|
"commander": "^5.1.0",
|
||||||
"fs-extra": "^10.1.0",
|
"fs-extra": "^10.1.0",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
|
|
|
||||||
|
|
@ -241,7 +241,7 @@ async function getSiteName(
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (reqName) {
|
if (reqName) {
|
||||||
const res = validateSiteName(reqName);
|
const res = await validateSiteName(reqName);
|
||||||
if (typeof res === 'string') {
|
if (typeof res === 'string') {
|
||||||
throw new Error(res);
|
throw new Error(res);
|
||||||
}
|
}
|
||||||
|
|
@ -456,8 +456,10 @@ export default async function init(
|
||||||
reqTemplate?: string,
|
reqTemplate?: string,
|
||||||
cliOptions: CLIOptions = {},
|
cliOptions: CLIOptions = {},
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const templates = await readTemplates();
|
const [templates, siteName] = await Promise.all([
|
||||||
const siteName = await getSiteName(reqName, rootDir);
|
readTemplates(),
|
||||||
|
getSiteName(reqName, rootDir),
|
||||||
|
]);
|
||||||
const dest = path.resolve(rootDir, siteName);
|
const dest = path.resolve(rootDir, siteName);
|
||||||
const source = await getSource(reqTemplate, templates, cliOptions);
|
const source = await getSource(reqTemplate, templates, cliOptions);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "docusaurus-2-classic-typescript-template",
|
"name": "docusaurus-2-classic-typescript-template",
|
||||||
"version": "2.0.0-rc.1",
|
"version": "2.4.2",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"docusaurus": "docusaurus",
|
"docusaurus": "docusaurus",
|
||||||
|
|
@ -15,8 +15,8 @@
|
||||||
"typecheck": "tsc"
|
"typecheck": "tsc"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docusaurus/core": "2.0.0-rc.1",
|
"@docusaurus/core": "2.4.2",
|
||||||
"@docusaurus/preset-classic": "2.0.0-rc.1",
|
"@docusaurus/preset-classic": "2.4.2",
|
||||||
"@mdx-js/react": "^1.6.22",
|
"@mdx-js/react": "^1.6.22",
|
||||||
"clsx": "^1.2.1",
|
"clsx": "^1.2.1",
|
||||||
"prism-react-renderer": "^1.3.5",
|
"prism-react-renderer": "^1.3.5",
|
||||||
|
|
@ -24,7 +24,7 @@
|
||||||
"react-dom": "^17.0.2"
|
"react-dom": "^17.0.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@docusaurus/module-type-aliases": "2.0.0-rc.1",
|
"@docusaurus/module-type-aliases": "2.4.2",
|
||||||
"@tsconfig/docusaurus": "^1.0.5",
|
"@tsconfig/docusaurus": "^1.0.5",
|
||||||
"typescript": "^4.7.4"
|
"typescript": "^4.7.4"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -8,17 +8,22 @@ const darkCodeTheme = require('prism-react-renderer/themes/dracula');
|
||||||
const config = {
|
const config = {
|
||||||
title: 'My Site',
|
title: 'My Site',
|
||||||
tagline: 'Dinosaurs are cool',
|
tagline: 'Dinosaurs are cool',
|
||||||
url: 'https://your-docusaurus-test-site.com',
|
|
||||||
baseUrl: '/',
|
|
||||||
onBrokenLinks: 'throw',
|
|
||||||
onBrokenMarkdownLinks: 'warn',
|
|
||||||
favicon: 'img/favicon.ico',
|
favicon: 'img/favicon.ico',
|
||||||
|
|
||||||
|
// Set the production url of your site here
|
||||||
|
url: 'https://your-docusaurus-test-site.com',
|
||||||
|
// Set the /<baseUrl>/ pathname under which your site is served
|
||||||
|
// For GitHub pages deployment, it is often '/<projectName>/'
|
||||||
|
baseUrl: '/',
|
||||||
|
|
||||||
// GitHub pages deployment config.
|
// GitHub pages deployment config.
|
||||||
// If you aren't using GitHub pages, you don't need these.
|
// If you aren't using GitHub pages, you don't need these.
|
||||||
organizationName: 'facebook', // Usually your GitHub org/user name.
|
organizationName: 'facebook', // Usually your GitHub org/user name.
|
||||||
projectName: 'docusaurus', // Usually your repo name.
|
projectName: 'docusaurus', // Usually your repo name.
|
||||||
|
|
||||||
|
onBrokenLinks: 'throw',
|
||||||
|
onBrokenMarkdownLinks: 'warn',
|
||||||
|
|
||||||
// Even if you don't use internalization, you can use this field to set useful
|
// Even if you don't use internalization, you can use this field to set useful
|
||||||
// metadata like html lang. For example, if your site is Chinese, you may want
|
// metadata like html lang. For example, if your site is Chinese, you may want
|
||||||
// to replace "en" with "zh-Hans".
|
// to replace "en" with "zh-Hans".
|
||||||
|
|
@ -56,6 +61,8 @@ const config = {
|
||||||
themeConfig:
|
themeConfig:
|
||||||
/** @type {import('@docusaurus/preset-classic').ThemeConfig} */
|
/** @type {import('@docusaurus/preset-classic').ThemeConfig} */
|
||||||
({
|
({
|
||||||
|
// Replace with your project's social card
|
||||||
|
image: 'img/docusaurus-social-card.jpg',
|
||||||
navbar: {
|
navbar: {
|
||||||
title: 'My Site',
|
title: 'My Site',
|
||||||
logo: {
|
logo: {
|
||||||
|
|
@ -64,8 +71,8 @@ const config = {
|
||||||
},
|
},
|
||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
type: 'doc',
|
type: 'docSidebar',
|
||||||
docId: 'intro',
|
sidebarId: 'tutorialSidebar',
|
||||||
position: 'left',
|
position: 'left',
|
||||||
label: 'Tutorial',
|
label: 'Tutorial',
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "docusaurus-2-classic-template",
|
"name": "docusaurus-2-classic-template",
|
||||||
"version": "2.0.0-rc.1",
|
"version": "2.4.2",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"docusaurus": "docusaurus",
|
"docusaurus": "docusaurus",
|
||||||
|
|
@ -14,8 +14,8 @@
|
||||||
"write-heading-ids": "docusaurus write-heading-ids"
|
"write-heading-ids": "docusaurus write-heading-ids"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docusaurus/core": "2.0.0-rc.1",
|
"@docusaurus/core": "2.4.2",
|
||||||
"@docusaurus/preset-classic": "2.0.0-rc.1",
|
"@docusaurus/preset-classic": "2.4.2",
|
||||||
"@mdx-js/react": "^1.6.22",
|
"@mdx-js/react": "^1.6.22",
|
||||||
"clsx": "^1.2.1",
|
"clsx": "^1.2.1",
|
||||||
"prism-react-renderer": "^1.3.5",
|
"prism-react-renderer": "^1.3.5",
|
||||||
|
|
@ -23,7 +23,7 @@
|
||||||
"react-dom": "^17.0.2"
|
"react-dom": "^17.0.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@docusaurus/module-type-aliases": "2.0.0-rc.1"
|
"@docusaurus/module-type-aliases": "2.4.2"
|
||||||
},
|
},
|
||||||
"browserslist": {
|
"browserslist": {
|
||||||
"production": [
|
"production": [
|
||||||
|
|
|
||||||
|
|
@ -13,17 +13,22 @@
|
||||||
const config = {
|
const config = {
|
||||||
title: 'My Site',
|
title: 'My Site',
|
||||||
tagline: 'The tagline of my site',
|
tagline: 'The tagline of my site',
|
||||||
url: 'https://your-docusaurus-test-site.com',
|
|
||||||
baseUrl: '/',
|
|
||||||
onBrokenLinks: 'throw',
|
|
||||||
onBrokenMarkdownLinks: 'warn',
|
|
||||||
favicon: 'img/favicon.ico',
|
favicon: 'img/favicon.ico',
|
||||||
|
|
||||||
|
// Set the production url of your site here
|
||||||
|
url: 'https://your-docusaurus-test-site.com',
|
||||||
|
// Set the /<baseUrl>/ pathname under which your site is served
|
||||||
|
// For GitHub pages deployment, it is often '/<projectName>/'
|
||||||
|
baseUrl: '/',
|
||||||
|
|
||||||
// GitHub pages deployment config.
|
// GitHub pages deployment config.
|
||||||
// If you aren't using GitHub pages, you don't need these.
|
// If you aren't using GitHub pages, you don't need these.
|
||||||
organizationName: 'facebook', // Usually your GitHub org/user name.
|
organizationName: 'facebook', // Usually your GitHub org/user name.
|
||||||
projectName: 'docusaurus', // Usually your repo name.
|
projectName: 'docusaurus', // Usually your repo name.
|
||||||
|
|
||||||
|
onBrokenLinks: 'throw',
|
||||||
|
onBrokenMarkdownLinks: 'warn',
|
||||||
|
|
||||||
presets: [
|
presets: [
|
||||||
[
|
[
|
||||||
'classic',
|
'classic',
|
||||||
|
|
@ -53,6 +58,7 @@ const config = {
|
||||||
themeConfig:
|
themeConfig:
|
||||||
/** @type {import('@docusaurus/preset-classic').ThemeConfig} */
|
/** @type {import('@docusaurus/preset-classic').ThemeConfig} */
|
||||||
({
|
({
|
||||||
|
image: 'img/docusaurus-social-card.jpg',
|
||||||
navbar: {
|
navbar: {
|
||||||
title: 'My Meta Project',
|
title: 'My Meta Project',
|
||||||
logo: {
|
logo: {
|
||||||
|
|
@ -61,8 +67,8 @@ const config = {
|
||||||
},
|
},
|
||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
type: 'doc',
|
type: 'docSidebar',
|
||||||
docId: 'intro',
|
sidebarId: 'tutorialSidebar',
|
||||||
position: 'left',
|
position: 'left',
|
||||||
label: 'Tutorial',
|
label: 'Tutorial',
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "docusaurus-2-facebook-template",
|
"name": "docusaurus-2-facebook-template",
|
||||||
"version": "2.0.0-rc.1",
|
"version": "2.4.2",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"docusaurus": "docusaurus",
|
"docusaurus": "docusaurus",
|
||||||
|
|
@ -18,8 +18,8 @@
|
||||||
"format:diff": "prettier --config .prettierrc --list-different \"**/*.{js,jsx,ts,tsx,md,mdx}\""
|
"format:diff": "prettier --config .prettierrc --list-different \"**/*.{js,jsx,ts,tsx,md,mdx}\""
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docusaurus/core": "2.0.0-rc.1",
|
"@docusaurus/core": "2.4.2",
|
||||||
"@docusaurus/preset-classic": "2.0.0-rc.1",
|
"@docusaurus/preset-classic": "2.4.2",
|
||||||
"@mdx-js/react": "^1.6.22",
|
"@mdx-js/react": "^1.6.22",
|
||||||
"clsx": "^1.2.1",
|
"clsx": "^1.2.1",
|
||||||
"react": "^17.0.2",
|
"react": "^17.0.2",
|
||||||
|
|
|
||||||
|
|
@ -25,10 +25,12 @@ module.exports = {
|
||||||
// But you can create a sidebar manually
|
// But you can create a sidebar manually
|
||||||
/*
|
/*
|
||||||
tutorialSidebar: [
|
tutorialSidebar: [
|
||||||
|
'intro',
|
||||||
|
'hello',
|
||||||
{
|
{
|
||||||
type: 'category',
|
type: 'category',
|
||||||
label: 'Tutorial',
|
label: 'Tutorial',
|
||||||
items: ['hello'],
|
items: ['tutorial-basics/create-a-document'],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,9 @@ Anything **unclear** or **buggy** in this tutorial? [Please report it!](https://
|
||||||
|
|
||||||
## What's next?
|
## What's next?
|
||||||
|
|
||||||
- Read the [official documentation](https://docusaurus.io/).
|
- Read the [official documentation](https://docusaurus.io/)
|
||||||
|
- Modify your site configuration with [`docusaurus.config.js`](https://docusaurus.io/docs/api/docusaurus-config)
|
||||||
|
- Add navbar and footer items with [`themeConfig`](https://docusaurus.io/docs/api/themes/configuration)
|
||||||
- Add a custom [Design and Layout](https://docusaurus.io/docs/styling-layout)
|
- Add a custom [Design and Layout](https://docusaurus.io/docs/styling-layout)
|
||||||
- Add a [search bar](https://docusaurus.io/docs/search)
|
- Add a [search bar](https://docusaurus.io/docs/search)
|
||||||
- Find inspirations in the [Docusaurus showcase](https://docusaurus.io/showcase)
|
- Find inspirations in the [Docusaurus showcase](https://docusaurus.io/showcase)
|
||||||
|
|
|
||||||
|
|
@ -44,11 +44,13 @@ It is also possible to create your sidebar explicitly in `sidebars.js`:
|
||||||
```js title="sidebars.js"
|
```js title="sidebars.js"
|
||||||
module.exports = {
|
module.exports = {
|
||||||
tutorialSidebar: [
|
tutorialSidebar: [
|
||||||
|
'intro',
|
||||||
|
// highlight-next-line
|
||||||
|
'hello',
|
||||||
{
|
{
|
||||||
type: 'category',
|
type: 'category',
|
||||||
label: 'Tutorial',
|
label: 'Tutorial',
|
||||||
// highlight-next-line
|
items: ['tutorial-basics/create-a-document'],
|
||||||
items: ['hello'],
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,11 @@ You can use absolute paths to reference images in the static directory (`static/
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
You can reference images relative to the current file as well, as shown in [the extra guides](../tutorial-extras/manage-docs-versions.md).
|
You can reference images relative to the current file as well. This is particularly useful to colocate images close to the Markdown files using them:
|
||||||
|
|
||||||
|
```md
|
||||||
|

|
||||||
|
```
|
||||||
|
|
||||||
## Code Blocks
|
## Code Blocks
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,10 +19,12 @@ const sidebars = {
|
||||||
// But you can create a sidebar manually
|
// But you can create a sidebar manually
|
||||||
/*
|
/*
|
||||||
tutorialSidebar: [
|
tutorialSidebar: [
|
||||||
|
'intro',
|
||||||
|
'hello',
|
||||||
{
|
{
|
||||||
type: 'category',
|
type: 'category',
|
||||||
label: 'Tutorial',
|
label: 'Tutorial',
|
||||||
items: ['hello'],
|
items: ['tutorial-basics/create-a-document'],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
BIN
packages/create-docusaurus/templates/shared/static/img/docusaurus-social-card.jpg
vendored
Normal file
BIN
packages/create-docusaurus/templates/shared/static/img/docusaurus-social-card.jpg
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 54 KiB |
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@docusaurus/cssnano-preset",
|
"name": "@docusaurus/cssnano-preset",
|
||||||
"version": "2.0.0-rc.1",
|
"version": "2.4.2",
|
||||||
"description": "Advanced cssnano preset for maximum optimization.",
|
"description": "Advanced cssnano preset for maximum optimization.",
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@docusaurus/logger",
|
"name": "@docusaurus/logger",
|
||||||
"version": "2.0.0-rc.1",
|
"version": "2.4.2",
|
||||||
"description": "An encapsulated logger for semantically formatting console messages.",
|
"description": "An encapsulated logger for semantically formatting console messages.",
|
||||||
"main": "./lib/index.js",
|
"main": "./lib/index.js",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@docusaurus/mdx-loader",
|
"name": "@docusaurus/mdx-loader",
|
||||||
"version": "2.0.0-rc.1",
|
"version": "2.4.2",
|
||||||
"description": "Docusaurus Loader for MDX",
|
"description": "Docusaurus Loader for MDX",
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"types": "lib/index.d.ts",
|
"types": "lib/index.d.ts",
|
||||||
|
|
@ -20,8 +20,8 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/parser": "^7.18.8",
|
"@babel/parser": "^7.18.8",
|
||||||
"@babel/traverse": "^7.18.8",
|
"@babel/traverse": "^7.18.8",
|
||||||
"@docusaurus/logger": "2.0.0-rc.1",
|
"@docusaurus/logger": "2.4.2",
|
||||||
"@docusaurus/utils": "2.0.0-rc.1",
|
"@docusaurus/utils": "2.4.2",
|
||||||
"@mdx-js/mdx": "^1.6.22",
|
"@mdx-js/mdx": "^1.6.22",
|
||||||
"escape-html": "^1.0.3",
|
"escape-html": "^1.0.3",
|
||||||
"file-loader": "^6.2.0",
|
"file-loader": "^6.2.0",
|
||||||
|
|
@ -37,7 +37,7 @@
|
||||||
"webpack": "^5.73.0"
|
"webpack": "^5.73.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@docusaurus/types": "2.0.0-rc.1",
|
"@docusaurus/types": "2.4.2",
|
||||||
"@types/escape-html": "^1.0.2",
|
"@types/escape-html": "^1.0.2",
|
||||||
"@types/mdast": "^3.0.10",
|
"@types/mdast": "^3.0.10",
|
||||||
"@types/stringify-object": "^3.3.1",
|
"@types/stringify-object": "^3.3.1",
|
||||||
|
|
|
||||||
|
|
@ -22,8 +22,10 @@ import toc from './remark/toc';
|
||||||
import unwrapMdxCodeBlocks from './remark/unwrapMdxCodeBlocks';
|
import unwrapMdxCodeBlocks from './remark/unwrapMdxCodeBlocks';
|
||||||
import transformImage from './remark/transformImage';
|
import transformImage from './remark/transformImage';
|
||||||
import transformLinks from './remark/transformLinks';
|
import transformLinks from './remark/transformLinks';
|
||||||
|
import mermaid from './remark/mermaid';
|
||||||
|
|
||||||
import transformAdmonitions from './remark/admonitions';
|
import transformAdmonitions from './remark/admonitions';
|
||||||
|
import type {MarkdownConfig} from '@docusaurus/types';
|
||||||
import type {LoaderContext} from 'webpack';
|
import type {LoaderContext} from 'webpack';
|
||||||
import type {Processor, Plugin} from 'unified';
|
import type {Processor, Plugin} from 'unified';
|
||||||
import type {AdmonitionOptions} from './remark/admonitions';
|
import type {AdmonitionOptions} from './remark/admonitions';
|
||||||
|
|
@ -61,6 +63,7 @@ export type MDXOptions = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Options = Partial<MDXOptions> & {
|
export type Options = Partial<MDXOptions> & {
|
||||||
|
markdownConfig: MarkdownConfig;
|
||||||
staticDirs: string[];
|
staticDirs: string[];
|
||||||
siteDir: string;
|
siteDir: string;
|
||||||
isMDXPartial?: (filePath: string) => boolean;
|
isMDXPartial?: (filePath: string) => boolean;
|
||||||
|
|
@ -71,7 +74,6 @@ export type Options = Partial<MDXOptions> & {
|
||||||
frontMatter: {[key: string]: unknown};
|
frontMatter: {[key: string]: unknown};
|
||||||
metadata: {[key: string]: unknown};
|
metadata: {[key: string]: unknown};
|
||||||
}) => {[key: string]: unknown};
|
}) => {[key: string]: unknown};
|
||||||
filepath: string;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -171,6 +173,7 @@ export async function mdxLoader(
|
||||||
...(reqOptions.beforeDefaultRemarkPlugins ?? []),
|
...(reqOptions.beforeDefaultRemarkPlugins ?? []),
|
||||||
...getAdmonitionsPlugins(reqOptions.admonitions ?? false),
|
...getAdmonitionsPlugins(reqOptions.admonitions ?? false),
|
||||||
...DEFAULT_OPTIONS.remarkPlugins,
|
...DEFAULT_OPTIONS.remarkPlugins,
|
||||||
|
...(reqOptions.markdownConfig.mermaid ? [mermaid] : []),
|
||||||
[
|
[
|
||||||
transformImage,
|
transformImage,
|
||||||
{
|
{
|
||||||
|
|
|
||||||
10
packages/docusaurus-mdx-loader/src/remark/admonitions/__tests__/__fixtures__/nesting.md
generated
Normal file
10
packages/docusaurus-mdx-loader/src/remark/admonitions/__tests__/__fixtures__/nesting.md
generated
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
Test nested Admonitions
|
||||||
|
|
||||||
|
::::info **Weather**
|
||||||
|
On nice days, you can enjoy skiing in the mountains.
|
||||||
|
|
||||||
|
:::danger *Storms*
|
||||||
|
Take care of snowstorms...
|
||||||
|
:::
|
||||||
|
|
||||||
|
::::
|
||||||
|
|
@ -42,3 +42,8 @@ exports[`admonitions remark plugin interpolation 1`] = `
|
||||||
"<p>Test admonition with interpolated title/body</p>
|
"<p>Test admonition with interpolated title/body</p>
|
||||||
<admonition type="tip"><mdxAdmonitionTitle>My <code>interpolated</code> <strong>title</strong> <button style={{color: "red"}} onClick={() => alert("click")}>test</mdxAdmonitionTitle><p><code>body</code> <strong>interpolated</strong> content</p></admonition>"
|
<admonition type="tip"><mdxAdmonitionTitle>My <code>interpolated</code> <strong>title</strong> <button style={{color: "red"}} onClick={() => alert("click")}>test</mdxAdmonitionTitle><p><code>body</code> <strong>interpolated</strong> content</p></admonition>"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`admonitions remark plugin nesting 1`] = `
|
||||||
|
"<p>Test nested Admonitions</p>
|
||||||
|
<admonition type="info"><mdxAdmonitionTitle><strong>Weather</strong></mdxAdmonitionTitle><p>On nice days, you can enjoy skiing in the mountains.</p><admonition type="danger"><mdxAdmonitionTitle><em>Storms</em></mdxAdmonitionTitle><p>Take care of snowstorms...</p></admonition></admonition>"
|
||||||
|
`;
|
||||||
|
|
|
||||||
|
|
@ -50,4 +50,9 @@ describe('admonitions remark plugin', () => {
|
||||||
const result = await processFixture('interpolation');
|
const result = await processFixture('interpolation');
|
||||||
expect(result).toMatchSnapshot();
|
expect(result).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('nesting', async () => {
|
||||||
|
const result = await processFixture('nesting');
|
||||||
|
expect(result).toMatchSnapshot();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -52,9 +52,20 @@ const plugin: Plugin = function plugin(
|
||||||
const options = normalizeOptions(optionsInput);
|
const options = normalizeOptions(optionsInput);
|
||||||
|
|
||||||
const keywords = Object.values(options.keywords).map(escapeRegExp).join('|');
|
const keywords = Object.values(options.keywords).map(escapeRegExp).join('|');
|
||||||
|
const nestingChar = escapeRegExp(options.tag.slice(0, 1));
|
||||||
const tag = escapeRegExp(options.tag);
|
const tag = escapeRegExp(options.tag);
|
||||||
const regex = new RegExp(`${tag}(${keywords})(?: *(.*))?\n`);
|
|
||||||
const escapeTag = new RegExp(escapeRegExp(`\\${options.tag}`), 'g');
|
// resolve th nesting level of an opening tag
|
||||||
|
// ::: -> 0, :::: -> 1, ::::: -> 2 ...
|
||||||
|
const nestingLevelRegex = new RegExp(
|
||||||
|
`^${tag}(?<nestingLevel>${nestingChar}*)`,
|
||||||
|
);
|
||||||
|
|
||||||
|
const regex = new RegExp(`${tag}${nestingChar}*(${keywords})(?: *(.*))?\n`);
|
||||||
|
const escapeTag = new RegExp(
|
||||||
|
escapeRegExp(`\\${options.tag}${options.tag.slice(0, 1)}*`),
|
||||||
|
'g',
|
||||||
|
);
|
||||||
|
|
||||||
// The tokenizer is called on blocks to determine if there is an admonition
|
// The tokenizer is called on blocks to determine if there is an admonition
|
||||||
// present and create tags for it
|
// present and create tags for it
|
||||||
|
|
@ -77,6 +88,11 @@ const plugin: Plugin = function plugin(
|
||||||
];
|
];
|
||||||
const food = [];
|
const food = [];
|
||||||
const content = [];
|
const content = [];
|
||||||
|
// get the nesting level of the opening tag
|
||||||
|
const openingLevel =
|
||||||
|
nestingLevelRegex.exec(opening)!.groups!.nestingLevel!.length;
|
||||||
|
// used as a stack to keep track of nested admonitions
|
||||||
|
const nestingLevels: number[] = [openingLevel];
|
||||||
|
|
||||||
let newValue = value;
|
let newValue = value;
|
||||||
// consume lines until a closing tag
|
// consume lines until a closing tag
|
||||||
|
|
@ -88,12 +104,32 @@ const plugin: Plugin = function plugin(
|
||||||
next !== -1 ? newValue.slice(idx + 1, next) : newValue.slice(idx + 1);
|
next !== -1 ? newValue.slice(idx + 1, next) : newValue.slice(idx + 1);
|
||||||
food.push(line);
|
food.push(line);
|
||||||
newValue = newValue.slice(idx + 1);
|
newValue = newValue.slice(idx + 1);
|
||||||
// the closing tag is NOT part of the content
|
const nesting = nestingLevelRegex.exec(line);
|
||||||
if (line.startsWith(options.tag)) {
|
idx = newValue.indexOf(NEWLINE);
|
||||||
break;
|
if (!nesting) {
|
||||||
|
content.push(line);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const tagLevel = nesting.groups!.nestingLevel!.length;
|
||||||
|
// first level
|
||||||
|
if (nestingLevels.length === 0) {
|
||||||
|
nestingLevels.push(tagLevel);
|
||||||
|
content.push(line);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const currentLevel = nestingLevels[nestingLevels.length - 1]!;
|
||||||
|
if (tagLevel < currentLevel) {
|
||||||
|
// entering a nested admonition block
|
||||||
|
nestingLevels.push(tagLevel);
|
||||||
|
} else if (tagLevel === currentLevel) {
|
||||||
|
// closing a nested admonition block
|
||||||
|
nestingLevels.pop();
|
||||||
|
// the closing tag is NOT part of the content
|
||||||
|
if (nestingLevels.length === 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
content.push(line);
|
content.push(line);
|
||||||
idx = newValue.indexOf(NEWLINE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// consume the processed tag and replace escape sequences
|
// consume the processed tag and replace escape sequences
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`mermaid remark plugin does nothing if there's no mermaid code block 1`] = `
|
||||||
|
"
|
||||||
|
|
||||||
|
|
||||||
|
const layoutProps = {
|
||||||
|
|
||||||
|
};
|
||||||
|
const MDXLayout = "wrapper"
|
||||||
|
export default function MDXContent({
|
||||||
|
components,
|
||||||
|
...props
|
||||||
|
}) {
|
||||||
|
return <MDXLayout {...layoutProps} {...props} components={components} mdxType="MDXLayout">
|
||||||
|
<h1>{\`Heading 1\`}</h1>
|
||||||
|
<p>{\`No Mermaid diagram :(\`}</p>
|
||||||
|
<pre><code parentName="pre" {...{
|
||||||
|
"className": "language-js"
|
||||||
|
}}>{\`this is not mermaid
|
||||||
|
\`}</code></pre>
|
||||||
|
</MDXLayout>;
|
||||||
|
}
|
||||||
|
|
||||||
|
;
|
||||||
|
MDXContent.isMDXComponent = true;"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`mermaid remark plugin works for basic mermaid code blocks 1`] = `
|
||||||
|
"
|
||||||
|
|
||||||
|
|
||||||
|
const layoutProps = {
|
||||||
|
|
||||||
|
};
|
||||||
|
const MDXLayout = "wrapper"
|
||||||
|
export default function MDXContent({
|
||||||
|
components,
|
||||||
|
...props
|
||||||
|
}) {
|
||||||
|
return <MDXLayout {...layoutProps} {...props} components={components} mdxType="MDXLayout">
|
||||||
|
<h1>{\`Heading 1\`}</h1>
|
||||||
|
<mermaid {...{
|
||||||
|
"value": "graph TD;/n A-->B;/n A-->C;/n B-->D;/n C-->D;"
|
||||||
|
}}></mermaid>
|
||||||
|
</MDXLayout>;
|
||||||
|
}
|
||||||
|
|
||||||
|
;
|
||||||
|
MDXContent.isMDXComponent = true;"
|
||||||
|
`;
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
/**
|
||||||
|
* 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 {createCompiler} from '@mdx-js/mdx';
|
||||||
|
import mermaid from '..';
|
||||||
|
|
||||||
|
describe('mermaid remark plugin', () => {
|
||||||
|
function createTestCompiler() {
|
||||||
|
return createCompiler({
|
||||||
|
remarkPlugins: [mermaid],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
it("does nothing if there's no mermaid code block", async () => {
|
||||||
|
const mdxCompiler = createTestCompiler();
|
||||||
|
const result = await mdxCompiler.process(
|
||||||
|
`# Heading 1
|
||||||
|
|
||||||
|
No Mermaid diagram :(
|
||||||
|
|
||||||
|
\`\`\`js
|
||||||
|
this is not mermaid
|
||||||
|
\`\`\`
|
||||||
|
`,
|
||||||
|
);
|
||||||
|
expect(result.contents).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('works for basic mermaid code blocks', async () => {
|
||||||
|
const mdxCompiler = createTestCompiler();
|
||||||
|
const result = await mdxCompiler.process(`# Heading 1
|
||||||
|
|
||||||
|
\`\`\`mermaid
|
||||||
|
graph TD;
|
||||||
|
A-->B;
|
||||||
|
A-->C;
|
||||||
|
B-->D;
|
||||||
|
C-->D;
|
||||||
|
\`\`\``);
|
||||||
|
expect(result.contents).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
/**
|
||||||
|
* 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 visit from 'unist-util-visit';
|
||||||
|
import type {Transformer} from 'unified';
|
||||||
|
import type {Code} from 'mdast';
|
||||||
|
|
||||||
|
// TODO: this plugin shouldn't be in the core MDX loader
|
||||||
|
// After we allow plugins to provide Remark/Rehype plugins (see
|
||||||
|
// https://github.com/facebook/docusaurus/issues/6370), this should be provided
|
||||||
|
// by theme-mermaid itself
|
||||||
|
export default function plugin(): Transformer {
|
||||||
|
return (root) => {
|
||||||
|
visit(root, 'code', (node: Code, index, parent) => {
|
||||||
|
if (node.lang === 'mermaid') {
|
||||||
|
parent!.children.splice(index, 1, {
|
||||||
|
type: 'mermaidCodeBlock',
|
||||||
|
data: {
|
||||||
|
hName: 'mermaid',
|
||||||
|
hProperties: {
|
||||||
|
value: node.value,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@docusaurus/migrate",
|
"name": "@docusaurus/migrate",
|
||||||
"version": "2.0.0-rc.1",
|
"version": "2.4.2",
|
||||||
"description": "A CLI tool to migrate from older versions of Docusaurus.",
|
"description": "A CLI tool to migrate from older versions of Docusaurus.",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
|
|
@ -24,8 +24,8 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/core": "^7.18.6",
|
"@babel/core": "^7.18.6",
|
||||||
"@babel/preset-env": "^7.18.6",
|
"@babel/preset-env": "^7.18.6",
|
||||||
"@docusaurus/logger": "2.0.0-rc.1",
|
"@docusaurus/logger": "2.4.2",
|
||||||
"@docusaurus/utils": "2.0.0-rc.1",
|
"@docusaurus/utils": "2.4.2",
|
||||||
"@mapbox/hast-util-to-jsx": "^2.0.0",
|
"@mapbox/hast-util-to-jsx": "^2.0.0",
|
||||||
"color": "^4.2.3",
|
"color": "^4.2.3",
|
||||||
"commander": "^5.1.0",
|
"commander": "^5.1.0",
|
||||||
|
|
|
||||||
|
|
@ -120,7 +120,7 @@ exports[`migration CLI migrates complex website: write 1`] = `
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"copyright": "Copyright © 2022 Facebook Inc.",
|
"copyright": "Copyright © 2023 Facebook Inc.",
|
||||||
"logo": {
|
"logo": {
|
||||||
"src": "img/docusaurus_monochrome.svg"
|
"src": "img/docusaurus_monochrome.svg"
|
||||||
}
|
}
|
||||||
|
|
@ -303,7 +303,7 @@ exports[`migration CLI migrates missing versions: write 1`] = `
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"copyright": "Copyright © 2022 Facebook Inc.",
|
"copyright": "Copyright © 2023 Facebook Inc.",
|
||||||
"logo": {
|
"logo": {
|
||||||
"src": "img/docusaurus_monochrome.svg"
|
"src": "img/docusaurus_monochrome.svg"
|
||||||
}
|
}
|
||||||
|
|
@ -483,7 +483,7 @@ exports[`migration CLI migrates simple website: write 1`] = `
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"copyright": "Copyright © 2022 Facebook Inc.",
|
"copyright": "Copyright © 2023 Facebook Inc.",
|
||||||
"logo": {
|
"logo": {
|
||||||
"src": "img/docusaurus_monochrome.svg"
|
"src": "img/docusaurus_monochrome.svg"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@docusaurus/module-type-aliases",
|
"name": "@docusaurus/module-type-aliases",
|
||||||
"version": "2.0.0-rc.1",
|
"version": "2.4.2",
|
||||||
"description": "Docusaurus module type aliases.",
|
"description": "Docusaurus module type aliases.",
|
||||||
"types": "./src/index.d.ts",
|
"types": "./src/index.d.ts",
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
|
|
@ -13,7 +13,7 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docusaurus/react-loadable": "5.5.2",
|
"@docusaurus/react-loadable": "5.5.2",
|
||||||
"@docusaurus/types": "2.0.0-rc.1",
|
"@docusaurus/types": "2.4.2",
|
||||||
"@types/history": "^4.7.11",
|
"@types/history": "^4.7.11",
|
||||||
"@types/react": "*",
|
"@types/react": "*",
|
||||||
"@types/react-router-config": "*",
|
"@types/react-router-config": "*",
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@docusaurus/plugin-client-redirects",
|
"name": "@docusaurus/plugin-client-redirects",
|
||||||
"version": "2.0.0-rc.1",
|
"version": "2.4.2",
|
||||||
"description": "Client redirects plugin for Docusaurus.",
|
"description": "Client redirects plugin for Docusaurus.",
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"types": "lib/index.d.ts",
|
"types": "lib/index.d.ts",
|
||||||
|
|
@ -18,18 +18,18 @@
|
||||||
},
|
},
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docusaurus/core": "2.0.0-rc.1",
|
"@docusaurus/core": "2.4.2",
|
||||||
"@docusaurus/logger": "2.0.0-rc.1",
|
"@docusaurus/logger": "2.4.2",
|
||||||
"@docusaurus/utils": "2.0.0-rc.1",
|
"@docusaurus/utils": "2.4.2",
|
||||||
"@docusaurus/utils-common": "2.0.0-rc.1",
|
"@docusaurus/utils-common": "2.4.2",
|
||||||
"@docusaurus/utils-validation": "2.0.0-rc.1",
|
"@docusaurus/utils-validation": "2.4.2",
|
||||||
"eta": "^1.12.3",
|
"eta": "^2.0.0",
|
||||||
"fs-extra": "^10.1.0",
|
"fs-extra": "^10.1.0",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"tslib": "^2.4.0"
|
"tslib": "^2.4.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@docusaurus/types": "2.0.0-rc.1"
|
"@docusaurus/types": "2.4.2"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": "^16.8.4 || ^17.0.0",
|
"react": "^16.8.4 || ^17.0.0",
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`collectRedirects throw if plugin option redirects contain invalid to paths 1`] = `
|
exports[`collectRedirects throw if plugin option redirects contain invalid to paths 1`] = `
|
||||||
"You are trying to create client-side redirections to paths that do not exist:
|
"You are trying to create client-side redirections to invalid paths.
|
||||||
- /this/path/does/not/exist2
|
|
||||||
|
These paths are redirected to but do not exist:
|
||||||
- /this/path/does/not/exist2
|
- /this/path/does/not/exist2
|
||||||
|
|
||||||
Valid paths you can redirect to:
|
Valid paths you can redirect to:
|
||||||
|
|
@ -12,6 +13,22 @@ Valid paths you can redirect to:
|
||||||
"
|
"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`collectRedirects throw if plugin option redirects contain to paths with mismatching trailing slash 1`] = `
|
||||||
|
"You are trying to create client-side redirections to invalid paths.
|
||||||
|
|
||||||
|
These paths do exist, but because you have explicitly set trailingSlash=false, you need to write the path without trailing slash:
|
||||||
|
- /someExistingPath/
|
||||||
|
"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`collectRedirects throw if plugin option redirects contain to paths with mismatching trailing slash 2`] = `
|
||||||
|
"You are trying to create client-side redirections to invalid paths.
|
||||||
|
|
||||||
|
These paths do exist, but because you have explicitly set trailingSlash=true, you need to write the path with trailing slash:
|
||||||
|
- /someExistingPath
|
||||||
|
"
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`collectRedirects throws if redirect creator creates array of array redirect 1`] = `
|
exports[`collectRedirects throws if redirect creator creates array of array redirect 1`] = `
|
||||||
"Some created redirects are invalid:
|
"Some created redirects are invalid:
|
||||||
- {"from":["/fromPath"],"to":"/"} => Validation error: "from" must be a string
|
- {"from":["/fromPath"],"to":"/"} => Validation error: "from" must be a string
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ exports[`createRedirectPageContent encodes uri special chars 1`] = `
|
||||||
<link rel="canonical" href="https://docusaurus.io/gr/%CF%83%CE%B5%CE%BB%CE%B9%CE%B4%CE%B1%CF%82/" />
|
<link rel="canonical" href="https://docusaurus.io/gr/%CF%83%CE%B5%CE%BB%CE%B9%CE%B4%CE%B1%CF%82/" />
|
||||||
</head>
|
</head>
|
||||||
<script>
|
<script>
|
||||||
window.location.href = 'https://docusaurus.io/gr/%CF%83%CE%B5%CE%BB%CE%B9%CE%B4%CE%B1%CF%82/';
|
window.location.href = 'https://docusaurus.io/gr/%CF%83%CE%B5%CE%BB%CE%B9%CE%B4%CE%B1%CF%82/' + window.location.search + window.location.hash;
|
||||||
</script>
|
</script>
|
||||||
</html>"
|
</html>"
|
||||||
`;
|
`;
|
||||||
|
|
@ -23,7 +23,7 @@ exports[`createRedirectPageContent works 1`] = `
|
||||||
<link rel="canonical" href="https://docusaurus.io/" />
|
<link rel="canonical" href="https://docusaurus.io/" />
|
||||||
</head>
|
</head>
|
||||||
<script>
|
<script>
|
||||||
window.location.href = 'https://docusaurus.io/';
|
window.location.href = 'https://docusaurus.io/' + window.location.search + window.location.hash;
|
||||||
</script>
|
</script>
|
||||||
</html>"
|
</html>"
|
||||||
`;
|
`;
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ exports[`toRedirectFiles creates appropriate metadata for empty baseUrl: fileCon
|
||||||
<link rel="canonical" href="/abc" />
|
<link rel="canonical" href="/abc" />
|
||||||
</head>
|
</head>
|
||||||
<script>
|
<script>
|
||||||
window.location.href = '/abc';
|
window.location.href = '/abc' + window.location.search + window.location.hash;
|
||||||
</script>
|
</script>
|
||||||
</html>",
|
</html>",
|
||||||
]
|
]
|
||||||
|
|
@ -26,7 +26,7 @@ exports[`toRedirectFiles creates appropriate metadata for root baseUrl: fileCont
|
||||||
<link rel="canonical" href="/abc" />
|
<link rel="canonical" href="/abc" />
|
||||||
</head>
|
</head>
|
||||||
<script>
|
<script>
|
||||||
window.location.href = '/abc';
|
window.location.href = '/abc' + window.location.search + window.location.hash;
|
||||||
</script>
|
</script>
|
||||||
</html>",
|
</html>",
|
||||||
]
|
]
|
||||||
|
|
@ -42,7 +42,7 @@ exports[`toRedirectFiles creates appropriate metadata trailingSlash=false: fileC
|
||||||
<link rel="canonical" href="https://docusaurus.io/abc" />
|
<link rel="canonical" href="https://docusaurus.io/abc" />
|
||||||
</head>
|
</head>
|
||||||
<script>
|
<script>
|
||||||
window.location.href = 'https://docusaurus.io/abc';
|
window.location.href = 'https://docusaurus.io/abc' + window.location.search + window.location.hash;
|
||||||
</script>
|
</script>
|
||||||
</html>",
|
</html>",
|
||||||
"<!DOCTYPE html>
|
"<!DOCTYPE html>
|
||||||
|
|
@ -53,7 +53,7 @@ exports[`toRedirectFiles creates appropriate metadata trailingSlash=false: fileC
|
||||||
<link rel="canonical" href="https://docusaurus.io/def.html" />
|
<link rel="canonical" href="https://docusaurus.io/def.html" />
|
||||||
</head>
|
</head>
|
||||||
<script>
|
<script>
|
||||||
window.location.href = 'https://docusaurus.io/def.html';
|
window.location.href = 'https://docusaurus.io/def.html' + window.location.search + window.location.hash;
|
||||||
</script>
|
</script>
|
||||||
</html>",
|
</html>",
|
||||||
"<!DOCTYPE html>
|
"<!DOCTYPE html>
|
||||||
|
|
@ -64,7 +64,7 @@ exports[`toRedirectFiles creates appropriate metadata trailingSlash=false: fileC
|
||||||
<link rel="canonical" href="https://docusaurus.io/" />
|
<link rel="canonical" href="https://docusaurus.io/" />
|
||||||
</head>
|
</head>
|
||||||
<script>
|
<script>
|
||||||
window.location.href = 'https://docusaurus.io/';
|
window.location.href = 'https://docusaurus.io/' + window.location.search + window.location.hash;
|
||||||
</script>
|
</script>
|
||||||
</html>",
|
</html>",
|
||||||
]
|
]
|
||||||
|
|
@ -80,7 +80,7 @@ exports[`toRedirectFiles creates appropriate metadata trailingSlash=true: fileCo
|
||||||
<link rel="canonical" href="https://docusaurus.io/abc" />
|
<link rel="canonical" href="https://docusaurus.io/abc" />
|
||||||
</head>
|
</head>
|
||||||
<script>
|
<script>
|
||||||
window.location.href = 'https://docusaurus.io/abc';
|
window.location.href = 'https://docusaurus.io/abc' + window.location.search + window.location.hash;
|
||||||
</script>
|
</script>
|
||||||
</html>",
|
</html>",
|
||||||
"<!DOCTYPE html>
|
"<!DOCTYPE html>
|
||||||
|
|
@ -91,7 +91,7 @@ exports[`toRedirectFiles creates appropriate metadata trailingSlash=true: fileCo
|
||||||
<link rel="canonical" href="https://docusaurus.io/def.html" />
|
<link rel="canonical" href="https://docusaurus.io/def.html" />
|
||||||
</head>
|
</head>
|
||||||
<script>
|
<script>
|
||||||
window.location.href = 'https://docusaurus.io/def.html';
|
window.location.href = 'https://docusaurus.io/def.html' + window.location.search + window.location.hash;
|
||||||
</script>
|
</script>
|
||||||
</html>",
|
</html>",
|
||||||
"<!DOCTYPE html>
|
"<!DOCTYPE html>
|
||||||
|
|
@ -102,7 +102,7 @@ exports[`toRedirectFiles creates appropriate metadata trailingSlash=true: fileCo
|
||||||
<link rel="canonical" href="https://docusaurus.io/" />
|
<link rel="canonical" href="https://docusaurus.io/" />
|
||||||
</head>
|
</head>
|
||||||
<script>
|
<script>
|
||||||
window.location.href = 'https://docusaurus.io/';
|
window.location.href = 'https://docusaurus.io/' + window.location.search + window.location.hash;
|
||||||
</script>
|
</script>
|
||||||
</html>",
|
</html>",
|
||||||
]
|
]
|
||||||
|
|
@ -118,7 +118,7 @@ exports[`toRedirectFiles creates appropriate metadata trailingSlash=undefined: f
|
||||||
<link rel="canonical" href="https://docusaurus.io/abc" />
|
<link rel="canonical" href="https://docusaurus.io/abc" />
|
||||||
</head>
|
</head>
|
||||||
<script>
|
<script>
|
||||||
window.location.href = 'https://docusaurus.io/abc';
|
window.location.href = 'https://docusaurus.io/abc' + window.location.search + window.location.hash;
|
||||||
</script>
|
</script>
|
||||||
</html>",
|
</html>",
|
||||||
"<!DOCTYPE html>
|
"<!DOCTYPE html>
|
||||||
|
|
@ -129,7 +129,7 @@ exports[`toRedirectFiles creates appropriate metadata trailingSlash=undefined: f
|
||||||
<link rel="canonical" href="https://docusaurus.io/def.html" />
|
<link rel="canonical" href="https://docusaurus.io/def.html" />
|
||||||
</head>
|
</head>
|
||||||
<script>
|
<script>
|
||||||
window.location.href = 'https://docusaurus.io/def.html';
|
window.location.href = 'https://docusaurus.io/def.html' + window.location.search + window.location.hash;
|
||||||
</script>
|
</script>
|
||||||
</html>",
|
</html>",
|
||||||
"<!DOCTYPE html>
|
"<!DOCTYPE html>
|
||||||
|
|
@ -140,7 +140,7 @@ exports[`toRedirectFiles creates appropriate metadata trailingSlash=undefined: f
|
||||||
<link rel="canonical" href="https://docusaurus.io/" />
|
<link rel="canonical" href="https://docusaurus.io/" />
|
||||||
</head>
|
</head>
|
||||||
<script>
|
<script>
|
||||||
window.location.href = 'https://docusaurus.io/';
|
window.location.href = 'https://docusaurus.io/' + window.location.search + window.location.hash;
|
||||||
</script>
|
</script>
|
||||||
</html>",
|
</html>",
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -220,6 +220,69 @@ describe('collectRedirects', () => {
|
||||||
).toThrowErrorMatchingSnapshot();
|
).toThrowErrorMatchingSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('tolerates mismatched trailing slash if option is undefined', () => {
|
||||||
|
expect(
|
||||||
|
collectRedirects(
|
||||||
|
createTestPluginContext(
|
||||||
|
{
|
||||||
|
redirects: [
|
||||||
|
{
|
||||||
|
from: '/someLegacyPath',
|
||||||
|
to: '/somePath',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
['/', '/somePath/'],
|
||||||
|
{trailingSlash: undefined},
|
||||||
|
),
|
||||||
|
undefined,
|
||||||
|
),
|
||||||
|
).toEqual([
|
||||||
|
{
|
||||||
|
from: '/someLegacyPath',
|
||||||
|
to: '/somePath',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('throw if plugin option redirects contain to paths with mismatching trailing slash', () => {
|
||||||
|
expect(() =>
|
||||||
|
collectRedirects(
|
||||||
|
createTestPluginContext(
|
||||||
|
{
|
||||||
|
redirects: [
|
||||||
|
{
|
||||||
|
from: '/someLegacyPath',
|
||||||
|
to: '/someExistingPath/',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
['/', '/someExistingPath', '/anotherExistingPath'],
|
||||||
|
{trailingSlash: false},
|
||||||
|
),
|
||||||
|
undefined,
|
||||||
|
),
|
||||||
|
).toThrowErrorMatchingSnapshot();
|
||||||
|
|
||||||
|
expect(() =>
|
||||||
|
collectRedirects(
|
||||||
|
createTestPluginContext(
|
||||||
|
{
|
||||||
|
redirects: [
|
||||||
|
{
|
||||||
|
from: '/someLegacyPath',
|
||||||
|
to: '/someExistingPath',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
['/', '/someExistingPath/', '/anotherExistingPath/'],
|
||||||
|
{trailingSlash: true},
|
||||||
|
),
|
||||||
|
undefined,
|
||||||
|
),
|
||||||
|
).toThrowErrorMatchingSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
it('collects redirects with custom redirect creator', () => {
|
it('collects redirects with custom redirect creator', () => {
|
||||||
expect(
|
expect(
|
||||||
collectRedirects(
|
collectRedirects(
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import logger from '@docusaurus/logger';
|
import logger from '@docusaurus/logger';
|
||||||
|
import {addTrailingSlash, removeTrailingSlash} from '@docusaurus/utils';
|
||||||
import {applyTrailingSlash} from '@docusaurus/utils-common';
|
import {applyTrailingSlash} from '@docusaurus/utils-common';
|
||||||
import {
|
import {
|
||||||
createFromExtensionsRedirects,
|
createFromExtensionsRedirects,
|
||||||
|
|
@ -80,16 +81,59 @@ function validateCollectedRedirects(
|
||||||
|
|
||||||
const allowedToPaths = pluginContext.relativeRoutesPaths;
|
const allowedToPaths = pluginContext.relativeRoutesPaths;
|
||||||
const toPaths = redirects.map((redirect) => redirect.to);
|
const toPaths = redirects.map((redirect) => redirect.to);
|
||||||
const illegalToPaths = _.difference(toPaths, allowedToPaths);
|
const trailingSlashConfig = pluginContext.siteConfig.trailingSlash;
|
||||||
if (illegalToPaths.length > 0) {
|
// Key is the path, value is whether a valid toPath with a different trailing
|
||||||
throw new Error(
|
// slash exists; if the key doesn't exist it means it's valid
|
||||||
`You are trying to create client-side redirections to paths that do not exist:
|
const differByTrailSlash = new Map(toPaths.map((path) => [path, false]));
|
||||||
- ${illegalToPaths.join('\n- ')}
|
allowedToPaths.forEach((toPath) => {
|
||||||
|
if (differByTrailSlash.has(toPath)) {
|
||||||
|
differByTrailSlash.delete(toPath);
|
||||||
|
} else if (differByTrailSlash.has(removeTrailingSlash(toPath))) {
|
||||||
|
if (trailingSlashConfig === true) {
|
||||||
|
differByTrailSlash.set(removeTrailingSlash(toPath), true);
|
||||||
|
} else {
|
||||||
|
differByTrailSlash.delete(removeTrailingSlash(toPath));
|
||||||
|
}
|
||||||
|
} else if (differByTrailSlash.has(addTrailingSlash(toPath))) {
|
||||||
|
if (trailingSlashConfig === false) {
|
||||||
|
differByTrailSlash.set(addTrailingSlash(toPath), true);
|
||||||
|
} else {
|
||||||
|
differByTrailSlash.delete(addTrailingSlash(toPath));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (differByTrailSlash.size > 0) {
|
||||||
|
console.log(differByTrailSlash);
|
||||||
|
const errors = Array.from(differByTrailSlash.entries());
|
||||||
|
|
||||||
|
let message =
|
||||||
|
'You are trying to create client-side redirections to invalid paths.\n';
|
||||||
|
|
||||||
|
const [trailingSlashIssues, invalidPaths] = _.partition(
|
||||||
|
errors,
|
||||||
|
([, differ]) => differ,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (trailingSlashIssues.length) {
|
||||||
|
message += `
|
||||||
|
These paths do exist, but because you have explicitly set trailingSlash=${trailingSlashConfig}, you need to write the path ${
|
||||||
|
trailingSlashConfig ? 'with trailing slash' : 'without trailing slash'
|
||||||
|
}:
|
||||||
|
- ${trailingSlashIssues.map(([p]) => p).join('\n- ')}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (invalidPaths.length) {
|
||||||
|
message += `
|
||||||
|
These paths are redirected to but do not exist:
|
||||||
|
- ${invalidPaths.map(([p]) => p).join('\n- ')}
|
||||||
|
|
||||||
Valid paths you can redirect to:
|
Valid paths you can redirect to:
|
||||||
- ${allowedToPaths.join('\n- ')}
|
- ${allowedToPaths.join('\n- ')}
|
||||||
`,
|
`;
|
||||||
);
|
}
|
||||||
|
|
||||||
|
throw new Error(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ export default `
|
||||||
<link rel="canonical" href="<%= it.toUrl %>" />
|
<link rel="canonical" href="<%= it.toUrl %>" />
|
||||||
</head>
|
</head>
|
||||||
<script>
|
<script>
|
||||||
window.location.href = '<%= it.toUrl %>';
|
window.location.href = '<%= it.toUrl %>' + window.location.search + window.location.hash;
|
||||||
</script>
|
</script>
|
||||||
</html>
|
</html>
|
||||||
`;
|
`;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@docusaurus/plugin-content-blog",
|
"name": "@docusaurus/plugin-content-blog",
|
||||||
"version": "2.0.0-rc.1",
|
"version": "2.4.2",
|
||||||
"description": "Blog plugin for Docusaurus.",
|
"description": "Blog plugin for Docusaurus.",
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"types": "src/plugin-content-blog.d.ts",
|
"types": "src/plugin-content-blog.d.ts",
|
||||||
|
|
@ -18,13 +18,13 @@
|
||||||
},
|
},
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docusaurus/core": "2.0.0-rc.1",
|
"@docusaurus/core": "2.4.2",
|
||||||
"@docusaurus/logger": "2.0.0-rc.1",
|
"@docusaurus/logger": "2.4.2",
|
||||||
"@docusaurus/mdx-loader": "2.0.0-rc.1",
|
"@docusaurus/mdx-loader": "2.4.2",
|
||||||
"@docusaurus/types": "2.0.0-rc.1",
|
"@docusaurus/types": "2.4.2",
|
||||||
"@docusaurus/utils": "2.0.0-rc.1",
|
"@docusaurus/utils": "2.4.2",
|
||||||
"@docusaurus/utils-common": "2.0.0-rc.1",
|
"@docusaurus/utils-common": "2.4.2",
|
||||||
"@docusaurus/utils-validation": "2.0.0-rc.1",
|
"@docusaurus/utils-validation": "2.4.2",
|
||||||
"cheerio": "^1.0.0-rc.12",
|
"cheerio": "^1.0.0-rc.12",
|
||||||
"feed": "^4.2.2",
|
"feed": "^4.2.2",
|
||||||
"fs-extra": "^10.1.0",
|
"fs-extra": "^10.1.0",
|
||||||
|
|
@ -35,10 +35,6 @@
|
||||||
"utility-types": "^3.10.0",
|
"utility-types": "^3.10.0",
|
||||||
"webpack": "^5.73.0"
|
"webpack": "^5.73.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
|
||||||
"@docusaurus/types": "2.0.0-beta.21",
|
|
||||||
"escape-string-regexp": "^4.0.0"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": "^16.8.4 || ^17.0.0",
|
"react": "^16.8.4 || ^17.0.0",
|
||||||
"react-dom": "^16.8.4 || ^17.0.0"
|
"react-dom": "^16.8.4 || ^17.0.0"
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -143,4 +143,56 @@ describe.each(['atom', 'rss', 'json'])('%s', (feedType) => {
|
||||||
).toMatchSnapshot();
|
).toMatchSnapshot();
|
||||||
fsMock.mockClear();
|
fsMock.mockClear();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('filters to the first two entries', async () => {
|
||||||
|
const siteDir = path.join(__dirname, '__fixtures__', 'website');
|
||||||
|
const outDir = path.join(siteDir, 'build-snap');
|
||||||
|
const siteConfig = {
|
||||||
|
title: 'Hello',
|
||||||
|
baseUrl: '/myBaseUrl/',
|
||||||
|
url: 'https://docusaurus.io',
|
||||||
|
favicon: 'image/favicon.ico',
|
||||||
|
};
|
||||||
|
|
||||||
|
// Build is quite difficult to mock, so we built the blog beforehand and
|
||||||
|
// copied the output to the fixture...
|
||||||
|
await testGenerateFeeds(
|
||||||
|
{
|
||||||
|
siteDir,
|
||||||
|
siteConfig,
|
||||||
|
i18n: DefaultI18N,
|
||||||
|
outDir,
|
||||||
|
} as LoadContext,
|
||||||
|
{
|
||||||
|
path: 'blog',
|
||||||
|
routeBasePath: 'blog',
|
||||||
|
tagsBasePath: 'tags',
|
||||||
|
authorsMapPath: 'authors.yml',
|
||||||
|
include: DEFAULT_OPTIONS.include,
|
||||||
|
exclude: DEFAULT_OPTIONS.exclude,
|
||||||
|
feedOptions: {
|
||||||
|
type: [feedType],
|
||||||
|
copyright: 'Copyright',
|
||||||
|
createFeedItems: async (params) => {
|
||||||
|
const {blogPosts, defaultCreateFeedItems, ...rest} = params;
|
||||||
|
const blogPostsFiltered = blogPosts.filter(
|
||||||
|
(item, index) => index < 2,
|
||||||
|
);
|
||||||
|
return defaultCreateFeedItems({
|
||||||
|
blogPosts: blogPostsFiltered,
|
||||||
|
...rest,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
readingTime: ({content, defaultReadingTime}) =>
|
||||||
|
defaultReadingTime({content}),
|
||||||
|
truncateMarker: /<!--\s*truncate\s*-->/,
|
||||||
|
} as PluginOptions,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
fsMock.mock.calls.map((call) => call[1] as string),
|
||||||
|
).toMatchSnapshot();
|
||||||
|
fsMock.mockClear();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import escapeStringRegexp from 'escape-string-regexp';
|
import {escapeRegexp} from '@docusaurus/utils';
|
||||||
import {validateBlogPostFrontMatter} from '../frontMatter';
|
import {validateBlogPostFrontMatter} from '../frontMatter';
|
||||||
import type {BlogPostFrontMatter} from '@docusaurus/plugin-content-blog';
|
import type {BlogPostFrontMatter} from '@docusaurus/plugin-content-blog';
|
||||||
|
|
||||||
|
|
@ -57,7 +57,7 @@ function testField(params: {
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// eslint-disable-next-line jest/no-conditional-expect
|
// eslint-disable-next-line jest/no-conditional-expect
|
||||||
expect((err as Error).message).toMatch(
|
expect((err as Error).message).toMatch(
|
||||||
new RegExp(escapeStringRegexp(message)),
|
new RegExp(escapeRegexp(message)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import fs from 'fs-extra';
|
import fs from 'fs-extra';
|
||||||
import logger from '@docusaurus/logger';
|
import logger from '@docusaurus/logger';
|
||||||
import {Feed, type Author as FeedAuthor, type Item as FeedItem} from 'feed';
|
import {Feed, type Author as FeedAuthor} from 'feed';
|
||||||
import {normalizeUrl, readOutputHTMLFile} from '@docusaurus/utils';
|
import {normalizeUrl, readOutputHTMLFile} from '@docusaurus/utils';
|
||||||
import {blogPostContainerID} from '@docusaurus/utils-common';
|
import {blogPostContainerID} from '@docusaurus/utils-common';
|
||||||
import {load as cheerioLoad} from 'cheerio';
|
import {load as cheerioLoad} from 'cheerio';
|
||||||
|
|
@ -18,6 +18,7 @@ import type {
|
||||||
PluginOptions,
|
PluginOptions,
|
||||||
Author,
|
Author,
|
||||||
BlogPost,
|
BlogPost,
|
||||||
|
BlogFeedItem,
|
||||||
} from '@docusaurus/plugin-content-blog';
|
} from '@docusaurus/plugin-content-blog';
|
||||||
|
|
||||||
async function generateBlogFeed({
|
async function generateBlogFeed({
|
||||||
|
|
@ -54,14 +55,39 @@ async function generateBlogFeed({
|
||||||
copyright: feedOptions.copyright,
|
copyright: feedOptions.copyright,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const createFeedItems =
|
||||||
|
options.feedOptions.createFeedItems ?? defaultCreateFeedItems;
|
||||||
|
|
||||||
|
const feedItems = await createFeedItems({
|
||||||
|
blogPosts,
|
||||||
|
siteConfig,
|
||||||
|
outDir,
|
||||||
|
defaultCreateFeedItems,
|
||||||
|
});
|
||||||
|
|
||||||
|
feedItems.forEach(feed.addItem);
|
||||||
|
|
||||||
|
return feed;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function defaultCreateFeedItems({
|
||||||
|
blogPosts,
|
||||||
|
siteConfig,
|
||||||
|
outDir,
|
||||||
|
}: {
|
||||||
|
blogPosts: BlogPost[];
|
||||||
|
siteConfig: DocusaurusConfig;
|
||||||
|
outDir: string;
|
||||||
|
}): Promise<BlogFeedItem[]> {
|
||||||
|
const {url: siteUrl} = siteConfig;
|
||||||
|
|
||||||
function toFeedAuthor(author: Author): FeedAuthor {
|
function toFeedAuthor(author: Author): FeedAuthor {
|
||||||
return {name: author.name, link: author.url, email: author.email};
|
return {name: author.name, link: author.url, email: author.email};
|
||||||
}
|
}
|
||||||
|
|
||||||
await Promise.all(
|
return Promise.all(
|
||||||
blogPosts.map(async (post) => {
|
blogPosts.map(async (post) => {
|
||||||
const {
|
const {
|
||||||
id,
|
|
||||||
metadata: {
|
metadata: {
|
||||||
title: metadataTitle,
|
title: metadataTitle,
|
||||||
permalink,
|
permalink,
|
||||||
|
|
@ -79,10 +105,11 @@ async function generateBlogFeed({
|
||||||
);
|
);
|
||||||
const $ = cheerioLoad(content);
|
const $ = cheerioLoad(content);
|
||||||
|
|
||||||
const feedItem: FeedItem = {
|
const link = normalizeUrl([siteUrl, permalink]);
|
||||||
|
const feedItem: BlogFeedItem = {
|
||||||
title: metadataTitle,
|
title: metadataTitle,
|
||||||
id,
|
id: link,
|
||||||
link: normalizeUrl([siteUrl, permalink]),
|
link,
|
||||||
date,
|
date,
|
||||||
description,
|
description,
|
||||||
// Atom feed demands the "term", while other feeds use "name"
|
// Atom feed demands the "term", while other feeds use "name"
|
||||||
|
|
@ -99,9 +126,7 @@ async function generateBlogFeed({
|
||||||
|
|
||||||
return feedItem;
|
return feedItem;
|
||||||
}),
|
}),
|
||||||
).then((items) => items.forEach(feed.addItem));
|
);
|
||||||
|
|
||||||
return feed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function createBlogFeedFile({
|
async function createBlogFeedFile({
|
||||||
|
|
|
||||||
|
|
@ -455,6 +455,7 @@ export default async function pluginContentBlog(
|
||||||
(author) => author.imageURL,
|
(author) => author.imageURL,
|
||||||
),
|
),
|
||||||
}),
|
}),
|
||||||
|
markdownConfig: siteConfig.markdown,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -124,6 +124,7 @@ const PluginOptionSchema = Joi.object<PluginOptions>({
|
||||||
.default(DEFAULT_OPTIONS.feedOptions.copyright),
|
.default(DEFAULT_OPTIONS.feedOptions.copyright),
|
||||||
}),
|
}),
|
||||||
language: Joi.string(),
|
language: Joi.string(),
|
||||||
|
createFeedItems: Joi.function(),
|
||||||
}).default(DEFAULT_OPTIONS.feedOptions),
|
}).default(DEFAULT_OPTIONS.feedOptions),
|
||||||
authorsMapPath: Joi.string().default(DEFAULT_OPTIONS.authorsMapPath),
|
authorsMapPath: Joi.string().default(DEFAULT_OPTIONS.authorsMapPath),
|
||||||
readingTime: Joi.function().default(() => DEFAULT_OPTIONS.readingTime),
|
readingTime: Joi.function().default(() => DEFAULT_OPTIONS.readingTime),
|
||||||
|
|
|
||||||
|
|
@ -9,12 +9,19 @@ declare module '@docusaurus/plugin-content-blog' {
|
||||||
import type {LoadedMDXContent} from '@docusaurus/mdx-loader';
|
import type {LoadedMDXContent} from '@docusaurus/mdx-loader';
|
||||||
import type {MDXOptions} from '@docusaurus/mdx-loader';
|
import type {MDXOptions} from '@docusaurus/mdx-loader';
|
||||||
import type {FrontMatterTag, Tag} from '@docusaurus/utils';
|
import type {FrontMatterTag, Tag} from '@docusaurus/utils';
|
||||||
import type {Plugin, LoadContext} from '@docusaurus/types';
|
import type {DocusaurusConfig, Plugin, LoadContext} from '@docusaurus/types';
|
||||||
|
import type {Item as FeedItem} from 'feed';
|
||||||
import type {Overwrite} from 'utility-types';
|
import type {Overwrite} from 'utility-types';
|
||||||
|
|
||||||
export type Assets = {
|
export type Assets = {
|
||||||
/**
|
/**
|
||||||
* If `metadata.image` is a collocated image path, this entry will be the
|
* If `metadata.yarn workspace website typecheck
|
||||||
|
4
|
||||||
|
yarn workspace v1.22.19yarn workspace website typecheck
|
||||||
|
4
|
||||||
|
yarn workspace v1.22.19yarn workspace website typecheck
|
||||||
|
4
|
||||||
|
yarn workspace v1.22.19image` is a collocated image path, this entry will be the
|
||||||
* bundler-generated image path. Otherwise, it's empty, and the image URL
|
* bundler-generated image path. Otherwise, it's empty, and the image URL
|
||||||
* should be accessed through `frontMatter.image`.
|
* should be accessed through `frontMatter.image`.
|
||||||
*/
|
*/
|
||||||
|
|
@ -255,6 +262,24 @@ declare module '@docusaurus/plugin-content-blog' {
|
||||||
copyright: string;
|
copyright: string;
|
||||||
/** Language of the feed. */
|
/** Language of the feed. */
|
||||||
language?: string;
|
language?: string;
|
||||||
|
/** Allow control over the construction of BlogFeedItems */
|
||||||
|
createFeedItems?: CreateFeedItemsFn;
|
||||||
|
};
|
||||||
|
|
||||||
|
type DefaultCreateFeedItemsParams = {
|
||||||
|
blogPosts: BlogPost[];
|
||||||
|
siteConfig: DocusaurusConfig;
|
||||||
|
outDir: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type CreateFeedItemsFn = (
|
||||||
|
params: CreateFeedItemsParams,
|
||||||
|
) => Promise<BlogFeedItem[]>;
|
||||||
|
|
||||||
|
type CreateFeedItemsParams = DefaultCreateFeedItemsParams & {
|
||||||
|
defaultCreateFeedItems: (
|
||||||
|
params: DefaultCreateFeedItemsParams,
|
||||||
|
) => Promise<BlogFeedItem[]>;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -436,6 +461,8 @@ declare module '@docusaurus/plugin-content-blog' {
|
||||||
content: string;
|
content: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type BlogFeedItem = FeedItem;
|
||||||
|
|
||||||
export type BlogPaginatedMetadata = {
|
export type BlogPaginatedMetadata = {
|
||||||
/** Title of the entire blog. */
|
/** Title of the entire blog. */
|
||||||
readonly blogTitle: string;
|
readonly blogTitle: string;
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
{
|
{
|
||||||
"name": "@docusaurus/plugin-content-docs",
|
"name": "@docusaurus/plugin-content-docs",
|
||||||
"version": "2.0.0-rc.1",
|
"version": "2.4.2",
|
||||||
"description": "Docs plugin for Docusaurus.",
|
"description": "Docs plugin for Docusaurus.",
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
"exports": {
|
"exports": {
|
||||||
|
"./lib/*": "./lib/*",
|
||||||
"./src/*": "./src/*",
|
"./src/*": "./src/*",
|
||||||
"./client": {
|
"./client": {
|
||||||
"type": "./lib/client/index.d.ts",
|
"type": "./lib/client/index.d.ts",
|
||||||
|
|
@ -34,13 +35,13 @@
|
||||||
},
|
},
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docusaurus/core": "2.0.0-rc.1",
|
"@docusaurus/core": "2.4.2",
|
||||||
"@docusaurus/logger": "2.0.0-rc.1",
|
"@docusaurus/logger": "2.4.2",
|
||||||
"@docusaurus/mdx-loader": "2.0.0-rc.1",
|
"@docusaurus/mdx-loader": "2.4.2",
|
||||||
"@docusaurus/module-type-aliases": "2.0.0-rc.1",
|
"@docusaurus/module-type-aliases": "2.4.2",
|
||||||
"@docusaurus/types": "2.0.0-rc.1",
|
"@docusaurus/types": "2.4.2",
|
||||||
"@docusaurus/utils": "2.0.0-rc.1",
|
"@docusaurus/utils": "2.4.2",
|
||||||
"@docusaurus/utils-validation": "2.0.0-rc.1",
|
"@docusaurus/utils-validation": "2.4.2",
|
||||||
"@types/react-router-config": "^5.0.6",
|
"@types/react-router-config": "^5.0.6",
|
||||||
"combine-promises": "^1.1.0",
|
"combine-promises": "^1.1.0",
|
||||||
"fs-extra": "^10.1.0",
|
"fs-extra": "^10.1.0",
|
||||||
|
|
@ -52,11 +53,9 @@
|
||||||
"webpack": "^5.73.0"
|
"webpack": "^5.73.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@docusaurus/types": "2.0.0-beta.21",
|
|
||||||
"@types/js-yaml": "^4.0.5",
|
"@types/js-yaml": "^4.0.5",
|
||||||
"@types/picomatch": "^2.3.0",
|
"@types/picomatch": "^2.3.0",
|
||||||
"commander": "^5.1.0",
|
"commander": "^5.1.0",
|
||||||
"escape-string-regexp": "^4.0.0",
|
|
||||||
"picomatch": "^2.3.1",
|
"picomatch": "^2.3.1",
|
||||||
"shelljs": "^0.8.5"
|
"shelljs": "^0.8.5"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -901,6 +901,7 @@ exports[`simple website content: data 1`] = `
|
||||||
"label": "Next",
|
"label": "Next",
|
||||||
"banner": null,
|
"banner": null,
|
||||||
"badge": false,
|
"badge": false,
|
||||||
|
"noIndex": false,
|
||||||
"className": "docs-version-current",
|
"className": "docs-version-current",
|
||||||
"isLast": true,
|
"isLast": true,
|
||||||
"docsSidebars": {
|
"docsSidebars": {
|
||||||
|
|
@ -2608,6 +2609,7 @@ exports[`versioned website (community) content: data 1`] = `
|
||||||
"label": "1.0.0",
|
"label": "1.0.0",
|
||||||
"banner": null,
|
"banner": null,
|
||||||
"badge": true,
|
"badge": true,
|
||||||
|
"noIndex": false,
|
||||||
"className": "docs-version-1.0.0",
|
"className": "docs-version-1.0.0",
|
||||||
"isLast": true,
|
"isLast": true,
|
||||||
"docsSidebars": {
|
"docsSidebars": {
|
||||||
|
|
@ -2635,6 +2637,7 @@ exports[`versioned website (community) content: data 1`] = `
|
||||||
"label": "Next",
|
"label": "Next",
|
||||||
"banner": "unreleased",
|
"banner": "unreleased",
|
||||||
"badge": true,
|
"badge": true,
|
||||||
|
"noIndex": false,
|
||||||
"className": "docs-version-current",
|
"className": "docs-version-current",
|
||||||
"isLast": false,
|
"isLast": false,
|
||||||
"docsSidebars": {
|
"docsSidebars": {
|
||||||
|
|
@ -3477,6 +3480,7 @@ exports[`versioned website content: data 1`] = `
|
||||||
"label": "1.0.0",
|
"label": "1.0.0",
|
||||||
"banner": "unmaintained",
|
"banner": "unmaintained",
|
||||||
"badge": true,
|
"badge": true,
|
||||||
|
"noIndex": false,
|
||||||
"className": "docs-version-1.0.0",
|
"className": "docs-version-1.0.0",
|
||||||
"isLast": false,
|
"isLast": false,
|
||||||
"docsSidebars": {
|
"docsSidebars": {
|
||||||
|
|
@ -3544,6 +3548,7 @@ exports[`versioned website content: data 1`] = `
|
||||||
"label": "1.0.1",
|
"label": "1.0.1",
|
||||||
"banner": null,
|
"banner": null,
|
||||||
"badge": true,
|
"badge": true,
|
||||||
|
"noIndex": true,
|
||||||
"className": "docs-version-1.0.1",
|
"className": "docs-version-1.0.1",
|
||||||
"isLast": true,
|
"isLast": true,
|
||||||
"docsSidebars": {
|
"docsSidebars": {
|
||||||
|
|
@ -3599,6 +3604,7 @@ exports[`versioned website content: data 1`] = `
|
||||||
"label": "Next",
|
"label": "Next",
|
||||||
"banner": "unreleased",
|
"banner": "unreleased",
|
||||||
"badge": true,
|
"badge": true,
|
||||||
|
"noIndex": false,
|
||||||
"className": "docs-version-current",
|
"className": "docs-version-current",
|
||||||
"isLast": false,
|
"isLast": false,
|
||||||
"docsSidebars": {
|
"docsSidebars": {
|
||||||
|
|
@ -3674,6 +3680,7 @@ exports[`versioned website content: data 1`] = `
|
||||||
"label": "withSlugs",
|
"label": "withSlugs",
|
||||||
"banner": "unmaintained",
|
"banner": "unmaintained",
|
||||||
"badge": true,
|
"badge": true,
|
||||||
|
"noIndex": false,
|
||||||
"className": "docs-version-withSlugs",
|
"className": "docs-version-withSlugs",
|
||||||
"isLast": false,
|
"isLast": false,
|
||||||
"docsSidebars": {
|
"docsSidebars": {
|
||||||
|
|
|
||||||
|
|
@ -93,6 +93,18 @@ function createTestUtils({
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Makes it easier to assert failure cases
|
||||||
|
async function getProcessDocFileError(
|
||||||
|
docFileArg: DocFile | string,
|
||||||
|
): Promise<Error> {
|
||||||
|
try {
|
||||||
|
await processDocFile(docFileArg);
|
||||||
|
return new Error("unexpected: getProcessDocFileError didn't crash");
|
||||||
|
} catch (e) {
|
||||||
|
return e as Error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function testMeta(
|
async function testMeta(
|
||||||
docFileSource: string,
|
docFileSource: string,
|
||||||
expectedMetadata: Optional<
|
expectedMetadata: Optional<
|
||||||
|
|
@ -172,7 +184,13 @@ function createTestUtils({
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return {processDocFile, testMeta, testSlug, generateNavigation};
|
return {
|
||||||
|
processDocFile,
|
||||||
|
getProcessDocFileError,
|
||||||
|
testMeta,
|
||||||
|
testSlug,
|
||||||
|
generateNavigation,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('simple site', () => {
|
describe('simple site', () => {
|
||||||
|
|
@ -683,16 +701,21 @@ describe('simple site', () => {
|
||||||
|
|
||||||
it('docs with invalid id', async () => {
|
it('docs with invalid id', async () => {
|
||||||
const {defaultTestUtils} = await loadSite();
|
const {defaultTestUtils} = await loadSite();
|
||||||
await expect(async () =>
|
|
||||||
defaultTestUtils.processDocFile(
|
const error = await defaultTestUtils.getProcessDocFileError(
|
||||||
createFakeDocFile({
|
createFakeDocFile({
|
||||||
source: 'some/fake/path',
|
source: 'some/fake/path',
|
||||||
frontMatter: {
|
frontMatter: {
|
||||||
id: 'Hello/world',
|
id: 'Hello/world',
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
),
|
);
|
||||||
).rejects.toThrowErrorMatchingInlineSnapshot(
|
|
||||||
|
expect(error.message).toMatchInlineSnapshot(
|
||||||
|
`"Can't process doc metadata for doc at path path=some/fake/path in version name=current"`,
|
||||||
|
);
|
||||||
|
expect(error.cause).toBeDefined();
|
||||||
|
expect(error.cause!.message).toMatchInlineSnapshot(
|
||||||
`"Document id "Hello/world" cannot include slash."`,
|
`"Document id "Hello/world" cannot include slash."`,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import escapeStringRegexp from 'escape-string-regexp';
|
import {escapeRegexp} from '@docusaurus/utils';
|
||||||
import {validateDocFrontMatter} from '../frontMatter';
|
import {validateDocFrontMatter} from '../frontMatter';
|
||||||
import type {DocFrontMatter} from '@docusaurus/plugin-content-docs';
|
import type {DocFrontMatter} from '@docusaurus/plugin-content-docs';
|
||||||
|
|
||||||
|
|
@ -57,7 +57,7 @@ function testField(params: {
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// eslint-disable-next-line jest/no-conditional-expect
|
// eslint-disable-next-line jest/no-conditional-expect
|
||||||
expect((err as Error).message).toMatch(
|
expect((err as Error).message).toMatch(
|
||||||
new RegExp(escapeStringRegexp(message)),
|
new RegExp(escapeRegexp(message)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -362,6 +362,11 @@ describe('versioned website', () => {
|
||||||
options: {
|
options: {
|
||||||
routeBasePath,
|
routeBasePath,
|
||||||
sidebarPath,
|
sidebarPath,
|
||||||
|
versions: {
|
||||||
|
'1.0.1': {
|
||||||
|
noIndex: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const plugin = await pluginContentDocs(context, options);
|
const plugin = await pluginContentDocs(context, options);
|
||||||
|
|
|
||||||
|
|
@ -76,6 +76,7 @@ describe('normalizeDocsPluginOptions', () => {
|
||||||
version1: {
|
version1: {
|
||||||
path: 'hello',
|
path: 'hello',
|
||||||
label: 'world',
|
label: 'world',
|
||||||
|
noIndex: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
sidebarCollapsible: false,
|
sidebarCollapsible: false,
|
||||||
|
|
|
||||||
|
|
@ -316,7 +316,7 @@ async function doProcessDocMetadata({
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function processDocMetadata(args: {
|
export async function processDocMetadata(args: {
|
||||||
docFile: DocFile;
|
docFile: DocFile;
|
||||||
versionMetadata: VersionMetadata;
|
versionMetadata: VersionMetadata;
|
||||||
context: LoadContext;
|
context: LoadContext;
|
||||||
|
|
@ -324,10 +324,12 @@ export function processDocMetadata(args: {
|
||||||
env: DocEnv;
|
env: DocEnv;
|
||||||
}): Promise<DocMetadataBase> {
|
}): Promise<DocMetadataBase> {
|
||||||
try {
|
try {
|
||||||
return doProcessDocMetadata(args);
|
return await doProcessDocMetadata(args);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logger.error`Can't process doc metadata for doc at path path=${args.docFile.filePath} in version name=${args.versionMetadata.versionName}`;
|
throw new Error(
|
||||||
throw err;
|
`Can't process doc metadata for doc at path path=${args.docFile.filePath} in version name=${args.versionMetadata.versionName}`,
|
||||||
|
{cause: err as Error},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -336,12 +336,13 @@ export default async function pluginContentDocs(
|
||||||
};
|
};
|
||||||
|
|
||||||
function createMDXLoaderRule(): RuleSetRule {
|
function createMDXLoaderRule(): RuleSetRule {
|
||||||
const contentDirs = versionsMetadata.flatMap(getContentPathList);
|
const contentDirs = versionsMetadata
|
||||||
|
.flatMap(getContentPathList)
|
||||||
|
// Trailing slash is important, see https://github.com/facebook/docusaurus/pull/3970
|
||||||
|
.map(addTrailingPathSeparator);
|
||||||
return {
|
return {
|
||||||
test: /\.mdx?$/i,
|
test: /\.mdx?$/i,
|
||||||
include: contentDirs
|
include: contentDirs,
|
||||||
// Trailing slash is important, see https://github.com/facebook/docusaurus/pull/3970
|
|
||||||
.map(addTrailingPathSeparator),
|
|
||||||
use: [
|
use: [
|
||||||
getJSLoader({isServer}),
|
getJSLoader({isServer}),
|
||||||
{
|
{
|
||||||
|
|
@ -375,6 +376,7 @@ export default async function pluginContentDocs(
|
||||||
}) => ({
|
}) => ({
|
||||||
image: frontMatter.image,
|
image: frontMatter.image,
|
||||||
}),
|
}),
|
||||||
|
markdownConfig: siteConfig.markdown,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,7 @@ const VersionOptionsSchema = Joi.object({
|
||||||
banner: Joi.string().equal('none', 'unreleased', 'unmaintained').optional(),
|
banner: Joi.string().equal('none', 'unreleased', 'unmaintained').optional(),
|
||||||
badge: Joi.boolean().optional(),
|
badge: Joi.boolean().optional(),
|
||||||
className: Joi.string().optional(),
|
className: Joi.string().optional(),
|
||||||
|
noIndex: Joi.boolean().optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const VersionsOptionsSchema = Joi.object()
|
const VersionsOptionsSchema = Joi.object()
|
||||||
|
|
|
||||||
|
|
@ -125,6 +125,25 @@ declare module '@docusaurus/plugin-content-docs' {
|
||||||
// TODO support custom version banner?
|
// TODO support custom version banner?
|
||||||
// {type: "error", content: "html content"}
|
// {type: "error", content: "html content"}
|
||||||
export type VersionBanner = 'unreleased' | 'unmaintained';
|
export type VersionBanner = 'unreleased' | 'unmaintained';
|
||||||
|
|
||||||
|
export type VersionOptions = {
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
/** Prevents search engines from indexing this version */
|
||||||
|
noIndex?: boolean;
|
||||||
|
/** Add a custom class name to the <html> element of each doc. */
|
||||||
|
className?: string;
|
||||||
|
};
|
||||||
|
|
||||||
export type VersionsOptions = {
|
export type VersionsOptions = {
|
||||||
/**
|
/**
|
||||||
* The version navigated to in priority and displayed by default for docs
|
* The version navigated to in priority and displayed by default for docs
|
||||||
|
|
@ -144,23 +163,7 @@ declare module '@docusaurus/plugin-content-docs' {
|
||||||
/** Include the current version of your docs. */
|
/** Include the current version of your docs. */
|
||||||
includeCurrentVersion: boolean;
|
includeCurrentVersion: boolean;
|
||||||
/** Independent customization of each version's properties. */
|
/** Independent customization of each version's properties. */
|
||||||
versions: {
|
versions: {[versionName: string]: VersionOptions};
|
||||||
[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 = {
|
export type SidebarOptions = {
|
||||||
/**
|
/**
|
||||||
|
|
@ -263,6 +266,8 @@ declare module '@docusaurus/plugin-content-docs' {
|
||||||
banner: VersionBanner | null;
|
banner: VersionBanner | null;
|
||||||
/** Show a badge with the version label at the top of each doc. */
|
/** Show a badge with the version label at the top of each doc. */
|
||||||
badge: boolean;
|
badge: boolean;
|
||||||
|
/** Prevents search engines from indexing this version */
|
||||||
|
noIndex: boolean;
|
||||||
/** Add a custom class name to the <html> element of each doc. */
|
/** Add a custom class name to the <html> element of each doc. */
|
||||||
className: string;
|
className: string;
|
||||||
/**
|
/**
|
||||||
|
|
@ -500,7 +505,7 @@ declare module '@docusaurus/plugin-content-docs' {
|
||||||
|
|
||||||
export type PropVersionMetadata = Pick<
|
export type PropVersionMetadata = Pick<
|
||||||
VersionMetadata,
|
VersionMetadata,
|
||||||
'label' | 'banner' | 'badge' | 'className' | 'isLast'
|
'label' | 'banner' | 'badge' | 'className' | 'isLast' | 'noIndex'
|
||||||
> & {
|
> & {
|
||||||
/** ID of the docs plugin this version belongs to. */
|
/** ID of the docs plugin this version belongs to. */
|
||||||
pluginId: string;
|
pluginId: string;
|
||||||
|
|
|
||||||
|
|
@ -142,6 +142,7 @@ export function toVersionMetadataProp(
|
||||||
label: loadedVersion.label,
|
label: loadedVersion.label,
|
||||||
banner: loadedVersion.banner,
|
banner: loadedVersion.banner,
|
||||||
badge: loadedVersion.badge,
|
badge: loadedVersion.badge,
|
||||||
|
noIndex: loadedVersion.noIndex,
|
||||||
className: loadedVersion.className,
|
className: loadedVersion.className,
|
||||||
isLast: loadedVersion.isLast,
|
isLast: loadedVersion.isLast,
|
||||||
docsSidebars: toSidebarsProp(loadedVersion),
|
docsSidebars: toSidebarsProp(loadedVersion),
|
||||||
|
|
|
||||||
|
|
@ -86,6 +86,9 @@ exports[`DefaultSidebarItemsGenerator generates simple flat sidebar 1`] = `
|
||||||
"type": "doc",
|
"type": "doc",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"customProps": {
|
||||||
|
"custom": "prop",
|
||||||
|
},
|
||||||
"id": "doc1",
|
"id": "doc1",
|
||||||
"label": "doc1 sidebar label",
|
"label": "doc1 sidebar label",
|
||||||
"type": "doc",
|
"type": "doc",
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,7 @@ describe('DefaultSidebarItemsGenerator', () => {
|
||||||
sidebarPosition: 2,
|
sidebarPosition: 2,
|
||||||
frontMatter: {
|
frontMatter: {
|
||||||
sidebar_label: 'doc1 sidebar label',
|
sidebar_label: 'doc1 sidebar label',
|
||||||
|
sidebar_custom_props: {custom: 'prop'},
|
||||||
},
|
},
|
||||||
title: '',
|
title: '',
|
||||||
unversionedId: 'doc1',
|
unversionedId: 'doc1',
|
||||||
|
|
|
||||||
|
|
@ -138,7 +138,11 @@ Available doc IDs:
|
||||||
): WithPosition<SidebarItemDoc> {
|
): WithPosition<SidebarItemDoc> {
|
||||||
const {
|
const {
|
||||||
sidebarPosition: position,
|
sidebarPosition: position,
|
||||||
frontMatter: {sidebar_label: label, sidebar_class_name: className},
|
frontMatter: {
|
||||||
|
sidebar_label: label,
|
||||||
|
sidebar_class_name: className,
|
||||||
|
sidebar_custom_props: customProps,
|
||||||
|
},
|
||||||
} = getDoc(id);
|
} = getDoc(id);
|
||||||
return {
|
return {
|
||||||
type: 'doc',
|
type: 'doc',
|
||||||
|
|
@ -149,6 +153,7 @@ Available doc IDs:
|
||||||
// sidebar
|
// sidebar
|
||||||
...(label !== undefined && {label}),
|
...(label !== undefined && {label}),
|
||||||
...(className !== undefined && {className}),
|
...(className !== undefined && {className}),
|
||||||
|
...(customProps !== undefined && {customProps}),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
function createCategoryItem(
|
function createCategoryItem(
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,8 @@ export type SidebarItemLink = SidebarItemBase & {
|
||||||
type: 'link';
|
type: 'link';
|
||||||
href: string;
|
href: string;
|
||||||
label: string;
|
label: string;
|
||||||
|
autoAddBaseUrl?: boolean;
|
||||||
|
description?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type SidebarItemAutogenerated = SidebarItemBase & {
|
export type SidebarItemAutogenerated = SidebarItemBase & {
|
||||||
|
|
@ -56,6 +58,7 @@ type SidebarItemCategoryBase = SidebarItemBase & {
|
||||||
label: string;
|
label: string;
|
||||||
collapsed: boolean;
|
collapsed: boolean;
|
||||||
collapsible: boolean;
|
collapsible: boolean;
|
||||||
|
description?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type SidebarItemCategoryLinkDoc = {type: 'doc'; id: string};
|
export type SidebarItemCategoryLinkDoc = {type: 'doc'; id: string};
|
||||||
|
|
|
||||||
|
|
@ -59,9 +59,13 @@ const sidebarItemHtmlSchema = sidebarItemBaseSchema.append<SidebarItemHtml>({
|
||||||
const sidebarItemLinkSchema = sidebarItemBaseSchema.append<SidebarItemLink>({
|
const sidebarItemLinkSchema = sidebarItemBaseSchema.append<SidebarItemLink>({
|
||||||
type: 'link',
|
type: 'link',
|
||||||
href: URISchema.required(),
|
href: URISchema.required(),
|
||||||
|
autoAddBaseUrl: Joi.boolean(),
|
||||||
label: Joi.string()
|
label: Joi.string()
|
||||||
.required()
|
.required()
|
||||||
.messages({'any.unknown': '"label" must be a string'}),
|
.messages({'any.unknown': '"label" must be a string'}),
|
||||||
|
description: Joi.string().optional().messages({
|
||||||
|
'any.unknown': '"description" must be a string',
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const sidebarItemCategoryLinkSchema = Joi.object<SidebarItemCategoryLink>()
|
const sidebarItemCategoryLinkSchema = Joi.object<SidebarItemCategoryLink>()
|
||||||
|
|
@ -115,6 +119,9 @@ const sidebarItemCategorySchema =
|
||||||
collapsible: Joi.boolean().messages({
|
collapsible: Joi.boolean().messages({
|
||||||
'any.unknown': '"collapsible" must be a boolean',
|
'any.unknown': '"collapsible" must be a boolean',
|
||||||
}),
|
}),
|
||||||
|
description: Joi.string().optional().messages({
|
||||||
|
'any.unknown': '"description" must be a string',
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const sidebarItemSchema = Joi.object<SidebarItemConfig>().when('.type', {
|
const sidebarItemSchema = Joi.object<SidebarItemConfig>().when('.type', {
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,7 @@ describe('readVersionsMetadata', () => {
|
||||||
path: '/docs',
|
path: '/docs',
|
||||||
banner: null,
|
banner: null,
|
||||||
badge: false,
|
badge: false,
|
||||||
|
noIndex: false,
|
||||||
className: 'docs-version-current',
|
className: 'docs-version-current',
|
||||||
};
|
};
|
||||||
return {simpleSiteDir, defaultOptions, defaultContext, vCurrent};
|
return {simpleSiteDir, defaultOptions, defaultContext, vCurrent};
|
||||||
|
|
@ -218,6 +219,7 @@ describe('readVersionsMetadata', () => {
|
||||||
path: '/docs/next',
|
path: '/docs/next',
|
||||||
banner: 'unreleased',
|
banner: 'unreleased',
|
||||||
badge: true,
|
badge: true,
|
||||||
|
noIndex: false,
|
||||||
className: 'docs-version-current',
|
className: 'docs-version-current',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -242,6 +244,7 @@ describe('readVersionsMetadata', () => {
|
||||||
path: '/docs',
|
path: '/docs',
|
||||||
banner: null,
|
banner: null,
|
||||||
badge: true,
|
badge: true,
|
||||||
|
noIndex: false,
|
||||||
className: 'docs-version-1.0.1',
|
className: 'docs-version-1.0.1',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -266,6 +269,7 @@ describe('readVersionsMetadata', () => {
|
||||||
path: '/docs/1.0.0',
|
path: '/docs/1.0.0',
|
||||||
banner: 'unmaintained',
|
banner: 'unmaintained',
|
||||||
badge: true,
|
badge: true,
|
||||||
|
noIndex: false,
|
||||||
className: 'docs-version-1.0.0',
|
className: 'docs-version-1.0.0',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -290,6 +294,7 @@ describe('readVersionsMetadata', () => {
|
||||||
path: '/docs/withSlugs',
|
path: '/docs/withSlugs',
|
||||||
banner: 'unmaintained',
|
banner: 'unmaintained',
|
||||||
badge: true,
|
badge: true,
|
||||||
|
noIndex: false,
|
||||||
className: 'docs-version-withSlugs',
|
className: 'docs-version-withSlugs',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -657,6 +662,7 @@ describe('readVersionsMetadata', () => {
|
||||||
path: '/communityBasePath/next',
|
path: '/communityBasePath/next',
|
||||||
banner: 'unreleased',
|
banner: 'unreleased',
|
||||||
badge: true,
|
badge: true,
|
||||||
|
noIndex: false,
|
||||||
className: 'docs-version-current',
|
className: 'docs-version-current',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -681,6 +687,7 @@ describe('readVersionsMetadata', () => {
|
||||||
path: '/communityBasePath',
|
path: '/communityBasePath',
|
||||||
banner: null,
|
banner: null,
|
||||||
badge: true,
|
badge: true,
|
||||||
|
noIndex: false,
|
||||||
className: 'docs-version-1.0.0',
|
className: 'docs-version-1.0.0',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -122,6 +122,13 @@ export function getVersionBadge({
|
||||||
return options.versions[versionName]?.badge ?? defaultVersionBadge;
|
return options.versions[versionName]?.badge ?? defaultVersionBadge;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getVersionNoIndex({
|
||||||
|
versionName,
|
||||||
|
options,
|
||||||
|
}: VersionContext): VersionMetadata['noIndex'] {
|
||||||
|
return options.versions[versionName]?.noIndex ?? false;
|
||||||
|
}
|
||||||
|
|
||||||
function getVersionClassName({
|
function getVersionClassName({
|
||||||
versionName,
|
versionName,
|
||||||
options,
|
options,
|
||||||
|
|
@ -179,6 +186,7 @@ async function createVersionMetadata(
|
||||||
label: getVersionLabel(context),
|
label: getVersionLabel(context),
|
||||||
banner: getVersionBanner(context),
|
banner: getVersionBanner(context),
|
||||||
badge: getVersionBadge(context),
|
badge: getVersionBadge(context),
|
||||||
|
noIndex: getVersionNoIndex(context),
|
||||||
className: getVersionClassName(context),
|
className: getVersionClassName(context),
|
||||||
path: routePath,
|
path: routePath,
|
||||||
tagsPath: normalizeUrl([routePath, options.tagsBasePath]),
|
tagsPath: normalizeUrl([routePath, options.tagsBasePath]),
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@docusaurus/plugin-content-pages",
|
"name": "@docusaurus/plugin-content-pages",
|
||||||
"version": "2.0.0-rc.1",
|
"version": "2.4.2",
|
||||||
"description": "Pages plugin for Docusaurus.",
|
"description": "Pages plugin for Docusaurus.",
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"types": "src/plugin-content-pages.d.ts",
|
"types": "src/plugin-content-pages.d.ts",
|
||||||
|
|
@ -18,18 +18,15 @@
|
||||||
},
|
},
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docusaurus/core": "2.0.0-rc.1",
|
"@docusaurus/core": "2.4.2",
|
||||||
"@docusaurus/mdx-loader": "2.0.0-rc.1",
|
"@docusaurus/mdx-loader": "2.4.2",
|
||||||
"@docusaurus/types": "2.0.0-rc.1",
|
"@docusaurus/types": "2.4.2",
|
||||||
"@docusaurus/utils": "2.0.0-rc.1",
|
"@docusaurus/utils": "2.4.2",
|
||||||
"@docusaurus/utils-validation": "2.0.0-rc.1",
|
"@docusaurus/utils-validation": "2.4.2",
|
||||||
"fs-extra": "^10.1.0",
|
"fs-extra": "^10.1.0",
|
||||||
"tslib": "^2.4.0",
|
"tslib": "^2.4.0",
|
||||||
"webpack": "^5.73.0"
|
"webpack": "^5.73.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
|
||||||
"@docusaurus/types": "2.0.0-beta.21"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": "^16.8.4 || ^17.0.0",
|
"react": "^16.8.4 || ^17.0.0",
|
||||||
"react-dom": "^16.8.4 || ^17.0.0"
|
"react-dom": "^16.8.4 || ^17.0.0"
|
||||||
|
|
|
||||||
|
|
@ -211,6 +211,7 @@ export default function pluginContentPages(
|
||||||
`${docuHash(aliasedSource)}.json`,
|
`${docuHash(aliasedSource)}.json`,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
markdownConfig: siteConfig.markdown,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@docusaurus/plugin-debug",
|
"name": "@docusaurus/plugin-debug",
|
||||||
"version": "2.0.0-rc.1",
|
"version": "2.4.2",
|
||||||
"description": "Debug plugin for Docusaurus.",
|
"description": "Debug plugin for Docusaurus.",
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"types": "src/plugin-debug.d.ts",
|
"types": "src/plugin-debug.d.ts",
|
||||||
|
|
@ -20,16 +20,13 @@
|
||||||
},
|
},
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docusaurus/core": "2.0.0-rc.1",
|
"@docusaurus/core": "2.4.2",
|
||||||
"@docusaurus/types": "2.0.0-rc.1",
|
"@docusaurus/types": "2.4.2",
|
||||||
"@docusaurus/utils": "2.0.0-rc.1",
|
"@docusaurus/utils": "2.4.2",
|
||||||
"fs-extra": "^10.1.0",
|
"fs-extra": "^10.1.0",
|
||||||
"react-json-view": "^1.21.3",
|
"react-json-view": "^1.21.3",
|
||||||
"tslib": "^2.4.0"
|
"tslib": "^2.4.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
|
||||||
"@docusaurus/types": "2.0.0-beta.21"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": "^16.8.4 || ^17.0.0",
|
"react": "^16.8.4 || ^17.0.0",
|
||||||
"react-dom": "^16.8.4 || ^17.0.0"
|
"react-dom": "^16.8.4 || ^17.0.0"
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@docusaurus/plugin-google-analytics",
|
"name": "@docusaurus/plugin-google-analytics",
|
||||||
"version": "2.0.0-rc.1",
|
"version": "2.4.2",
|
||||||
"description": "Global analytics (analytics.js) plugin for Docusaurus.",
|
"description": "Global analytics (analytics.js) plugin for Docusaurus.",
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"types": "lib/index.d.ts",
|
"types": "lib/index.d.ts",
|
||||||
|
|
@ -18,14 +18,11 @@
|
||||||
},
|
},
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docusaurus/core": "2.0.0-rc.1",
|
"@docusaurus/core": "2.4.2",
|
||||||
"@docusaurus/types": "2.0.0-rc.1",
|
"@docusaurus/types": "2.4.2",
|
||||||
"@docusaurus/utils-validation": "2.0.0-rc.1",
|
"@docusaurus/utils-validation": "2.4.2",
|
||||||
"tslib": "^2.4.0"
|
"tslib": "^2.4.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
|
||||||
"@docusaurus/types": "2.0.0-beta.21"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": "^16.8.4 || ^17.0.0",
|
"react": "^16.8.4 || ^17.0.0",
|
||||||
"react-dom": "^16.8.4 || ^17.0.0"
|
"react-dom": "^16.8.4 || ^17.0.0"
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@docusaurus/plugin-google-gtag",
|
"name": "@docusaurus/plugin-google-gtag",
|
||||||
"version": "2.0.0-rc.1",
|
"version": "2.4.2",
|
||||||
"description": "Global Site Tag (gtag.js) plugin for Docusaurus.",
|
"description": "Global Site Tag (gtag.js) plugin for Docusaurus.",
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"types": "lib/index.d.ts",
|
"types": "lib/index.d.ts",
|
||||||
|
|
@ -18,14 +18,11 @@
|
||||||
},
|
},
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docusaurus/core": "2.0.0-rc.1",
|
"@docusaurus/core": "2.4.2",
|
||||||
"@docusaurus/types": "2.0.0-rc.1",
|
"@docusaurus/types": "2.4.2",
|
||||||
"@docusaurus/utils-validation": "2.0.0-rc.1",
|
"@docusaurus/utils-validation": "2.4.2",
|
||||||
"tslib": "^2.4.0"
|
"tslib": "^2.4.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
|
||||||
"@docusaurus/types": "2.0.0-beta.21"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": "^16.8.4 || ^17.0.0",
|
"react": "^16.8.4 || ^17.0.0",
|
||||||
"react-dom": "^16.8.4 || ^17.0.0"
|
"react-dom": "^16.8.4 || ^17.0.0"
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,156 @@
|
||||||
|
/**
|
||||||
|
* 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 {normalizePluginOptions} from '@docusaurus/utils-validation';
|
||||||
|
import {
|
||||||
|
validateOptions,
|
||||||
|
type PluginOptions,
|
||||||
|
type Options,
|
||||||
|
DEFAULT_OPTIONS,
|
||||||
|
} from '../options';
|
||||||
|
import type {Validate} from '@docusaurus/types';
|
||||||
|
|
||||||
|
function testValidateOptions(options: Options) {
|
||||||
|
return validateOptions({
|
||||||
|
validate: normalizePluginOptions as Validate<Options, PluginOptions>,
|
||||||
|
options,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function validationResult(options: Options) {
|
||||||
|
return {
|
||||||
|
id: 'default',
|
||||||
|
...DEFAULT_OPTIONS,
|
||||||
|
...options,
|
||||||
|
trackingID:
|
||||||
|
typeof options.trackingID === 'string'
|
||||||
|
? [options.trackingID]
|
||||||
|
: options.trackingID,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const MinimalConfig: Options = {
|
||||||
|
trackingID: 'G-XYZ12345',
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('validateOptions', () => {
|
||||||
|
it('throws for undefined options', () => {
|
||||||
|
expect(
|
||||||
|
// @ts-expect-error: TS should error
|
||||||
|
() => testValidateOptions(undefined),
|
||||||
|
).toThrowErrorMatchingInlineSnapshot(`""trackingID" is required"`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('throws for null options', () => {
|
||||||
|
expect(
|
||||||
|
// @ts-expect-error: TS should error
|
||||||
|
() => testValidateOptions(null),
|
||||||
|
).toThrowErrorMatchingInlineSnapshot(`""value" must be of type object"`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('throws for empty object options', () => {
|
||||||
|
expect(
|
||||||
|
// @ts-expect-error: TS should error
|
||||||
|
() => testValidateOptions({}),
|
||||||
|
).toThrowErrorMatchingInlineSnapshot(`""trackingID" is required"`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('throws for number options', () => {
|
||||||
|
expect(
|
||||||
|
// @ts-expect-error: TS should error
|
||||||
|
() => testValidateOptions(42),
|
||||||
|
).toThrowErrorMatchingInlineSnapshot(`""value" must be of type object"`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('throws for null trackingID', () => {
|
||||||
|
expect(
|
||||||
|
// @ts-expect-error: TS should error
|
||||||
|
() => testValidateOptions({trackingID: null}),
|
||||||
|
).toThrowErrorMatchingInlineSnapshot(
|
||||||
|
`""trackingID" does not match any of the allowed types"`,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('throws for number trackingID', () => {
|
||||||
|
expect(
|
||||||
|
// @ts-expect-error: TS should error
|
||||||
|
() => testValidateOptions({trackingID: 42}),
|
||||||
|
).toThrowErrorMatchingInlineSnapshot(
|
||||||
|
`""trackingID" does not match any of the allowed types"`,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('throws for empty trackingID', () => {
|
||||||
|
expect(() =>
|
||||||
|
testValidateOptions({trackingID: ''}),
|
||||||
|
).toThrowErrorMatchingInlineSnapshot(
|
||||||
|
`""trackingID" does not match any of the allowed types"`,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('accepts minimal config', () => {
|
||||||
|
expect(testValidateOptions(MinimalConfig)).toEqual(
|
||||||
|
validationResult(MinimalConfig),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('accepts anonymizeIP', () => {
|
||||||
|
const config: Options = {
|
||||||
|
...MinimalConfig,
|
||||||
|
anonymizeIP: true,
|
||||||
|
};
|
||||||
|
expect(testValidateOptions(config)).toEqual(validationResult(config));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('accepts single trackingID', () => {
|
||||||
|
const config: Options = {
|
||||||
|
trackingID: 'G-ABCDEF123',
|
||||||
|
};
|
||||||
|
expect(testValidateOptions(config)).toEqual(validationResult(config));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('accepts multiple trackingIDs', () => {
|
||||||
|
const config: Options = {
|
||||||
|
trackingID: ['G-ABCDEF123', 'UA-XYZ456789'],
|
||||||
|
};
|
||||||
|
expect(testValidateOptions(config)).toEqual(validationResult(config));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('throws for empty trackingID arrays', () => {
|
||||||
|
const config: Options = {
|
||||||
|
// @ts-expect-error: TS should error
|
||||||
|
trackingID: [],
|
||||||
|
};
|
||||||
|
expect(() =>
|
||||||
|
testValidateOptions(config),
|
||||||
|
).toThrowErrorMatchingInlineSnapshot(
|
||||||
|
`""trackingID" does not match any of the allowed types"`,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('throws for sparse trackingID arrays', () => {
|
||||||
|
const config: Options = {
|
||||||
|
// @ts-expect-error: TS should error
|
||||||
|
trackingID: ['G-ABCDEF123', null, 'UA-XYZ456789'],
|
||||||
|
};
|
||||||
|
expect(() =>
|
||||||
|
testValidateOptions(config),
|
||||||
|
).toThrowErrorMatchingInlineSnapshot(
|
||||||
|
`""trackingID" does not match any of the allowed types"`,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('throws for bad trackingID arrays', () => {
|
||||||
|
const config: Options = {
|
||||||
|
// @ts-expect-error: TS should error
|
||||||
|
trackingID: ['G-ABCDEF123', 42],
|
||||||
|
};
|
||||||
|
expect(() =>
|
||||||
|
testValidateOptions(config),
|
||||||
|
).toThrowErrorMatchingInlineSnapshot(
|
||||||
|
`""trackingID" does not match any of the allowed types"`,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -5,23 +5,38 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {Joi} from '@docusaurus/utils-validation';
|
import type {LoadContext, Plugin} from '@docusaurus/types';
|
||||||
import type {
|
|
||||||
LoadContext,
|
|
||||||
Plugin,
|
|
||||||
OptionValidationContext,
|
|
||||||
ThemeConfig,
|
|
||||||
ThemeConfigValidationContext,
|
|
||||||
} from '@docusaurus/types';
|
|
||||||
import type {PluginOptions, Options} from './options';
|
import type {PluginOptions, Options} from './options';
|
||||||
|
|
||||||
|
function createConfigSnippet({
|
||||||
|
trackingID,
|
||||||
|
anonymizeIP,
|
||||||
|
}: {
|
||||||
|
trackingID: string;
|
||||||
|
anonymizeIP: boolean;
|
||||||
|
}): string {
|
||||||
|
return `gtag('config', '${trackingID}', { ${
|
||||||
|
anonymizeIP ? "'anonymize_ip': true" : ''
|
||||||
|
} });`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createConfigSnippets({
|
||||||
|
trackingID: trackingIDArray,
|
||||||
|
anonymizeIP,
|
||||||
|
}: PluginOptions): string {
|
||||||
|
return trackingIDArray
|
||||||
|
.map((trackingID) => createConfigSnippet({trackingID, anonymizeIP}))
|
||||||
|
.join('\n');
|
||||||
|
}
|
||||||
|
|
||||||
export default function pluginGoogleGtag(
|
export default function pluginGoogleGtag(
|
||||||
context: LoadContext,
|
context: LoadContext,
|
||||||
options: PluginOptions,
|
options: PluginOptions,
|
||||||
): Plugin {
|
): Plugin {
|
||||||
const {anonymizeIP, trackingID} = options;
|
|
||||||
const isProd = process.env.NODE_ENV === 'production';
|
const isProd = process.env.NODE_ENV === 'production';
|
||||||
|
|
||||||
|
const firstTrackingId = options.trackingID[0];
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name: 'docusaurus-plugin-google-gtag',
|
name: 'docusaurus-plugin-google-gtag',
|
||||||
|
|
||||||
|
|
@ -60,7 +75,11 @@ export default function pluginGoogleGtag(
|
||||||
tagName: 'script',
|
tagName: 'script',
|
||||||
attributes: {
|
attributes: {
|
||||||
async: true,
|
async: true,
|
||||||
src: `https://www.googletagmanager.com/gtag/js?id=${trackingID}`,
|
// We only include the first tracking id here because google says
|
||||||
|
// we shouldn't install multiple tags/scripts on the same page
|
||||||
|
// Instead we should load one script and use n * gtag("config",id)
|
||||||
|
// See https://developers.google.com/tag-platform/gtagjs/install#add-products
|
||||||
|
src: `https://www.googletagmanager.com/gtag/js?id=${firstTrackingId}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -69,9 +88,8 @@ export default function pluginGoogleGtag(
|
||||||
window.dataLayer = window.dataLayer || [];
|
window.dataLayer = window.dataLayer || [];
|
||||||
function gtag(){dataLayer.push(arguments);}
|
function gtag(){dataLayer.push(arguments);}
|
||||||
gtag('js', new Date());
|
gtag('js', new Date());
|
||||||
gtag('config', '${trackingID}', { ${
|
${createConfigSnippets(options)};
|
||||||
anonymizeIP ? "'anonymize_ip': true" : ''
|
`,
|
||||||
} });`,
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
@ -79,27 +97,6 @@ export default function pluginGoogleGtag(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const pluginOptionsSchema = Joi.object<PluginOptions>({
|
export {validateThemeConfig, validateOptions} from './options';
|
||||||
trackingID: Joi.string().required(),
|
|
||||||
anonymizeIP: Joi.boolean().default(false),
|
|
||||||
});
|
|
||||||
|
|
||||||
export function validateOptions({
|
|
||||||
validate,
|
|
||||||
options,
|
|
||||||
}: OptionValidationContext<Options, PluginOptions>): PluginOptions {
|
|
||||||
return validate(pluginOptionsSchema, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function validateThemeConfig({
|
|
||||||
themeConfig,
|
|
||||||
}: ThemeConfigValidationContext<ThemeConfig>): ThemeConfig {
|
|
||||||
if ('gtag' in themeConfig) {
|
|
||||||
throw new Error(
|
|
||||||
'The "gtag" field in themeConfig should now be specified as option for plugin-google-gtag. More information at https://github.com/facebook/docusaurus/pull/5832.',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return themeConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type {PluginOptions, Options};
|
export type {PluginOptions, Options};
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,58 @@
|
||||||
* This source code is licensed under the MIT license found in the
|
* This source code is licensed under the MIT license found in the
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
import {Joi} from '@docusaurus/utils-validation';
|
||||||
|
import type {
|
||||||
|
OptionValidationContext,
|
||||||
|
ThemeConfig,
|
||||||
|
ThemeConfigValidationContext,
|
||||||
|
} from '@docusaurus/types';
|
||||||
|
|
||||||
export type PluginOptions = {
|
export type PluginOptions = {
|
||||||
trackingID: string;
|
trackingID: [string, ...string[]];
|
||||||
|
// TODO deprecate anonymizeIP after June 2023
|
||||||
|
// "In Google Analytics 4, IP masking is not necessary
|
||||||
|
// since IP addresses are not logged or stored."
|
||||||
|
// https://support.google.com/analytics/answer/2763052?hl=en
|
||||||
anonymizeIP: boolean;
|
anonymizeIP: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Options = Partial<PluginOptions>;
|
export type Options = {
|
||||||
|
trackingID: string | [string, ...string[]];
|
||||||
|
anonymizeIP?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const DEFAULT_OPTIONS: Partial<PluginOptions> = {
|
||||||
|
anonymizeIP: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
const pluginOptionsSchema = Joi.object<PluginOptions>({
|
||||||
|
// We normalize trackingID as a string[]
|
||||||
|
trackingID: Joi.alternatives()
|
||||||
|
.try(
|
||||||
|
Joi.alternatives().conditional(Joi.string().required(), {
|
||||||
|
then: Joi.custom((val: boolean) => [val]),
|
||||||
|
}),
|
||||||
|
Joi.array().items(Joi.string().required()),
|
||||||
|
)
|
||||||
|
.required(),
|
||||||
|
anonymizeIP: Joi.boolean().default(DEFAULT_OPTIONS.anonymizeIP),
|
||||||
|
});
|
||||||
|
|
||||||
|
export function validateOptions({
|
||||||
|
validate,
|
||||||
|
options,
|
||||||
|
}: OptionValidationContext<Options, PluginOptions>): PluginOptions {
|
||||||
|
return validate(pluginOptionsSchema, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function validateThemeConfig({
|
||||||
|
themeConfig,
|
||||||
|
}: ThemeConfigValidationContext<ThemeConfig>): ThemeConfig {
|
||||||
|
if ('gtag' in themeConfig) {
|
||||||
|
throw new Error(
|
||||||
|
'The "gtag" field in themeConfig should now be specified as option for plugin-google-gtag. More information at https://github.com/facebook/docusaurus/pull/5832.',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return themeConfig;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,6 @@
|
||||||
"rootDir": "src",
|
"rootDir": "src",
|
||||||
"outDir": "lib"
|
"outDir": "lib"
|
||||||
},
|
},
|
||||||
"include": ["src/gtag.ts", "src/options.ts", "src/*.d.ts"],
|
"include": ["src/gtag.ts", "src/*.d.ts"],
|
||||||
"exclude": ["**/__tests__/**"]
|
"exclude": ["**/__tests__/**"]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
.tsbuildinfo*
|
||||||
|
tsconfig*
|
||||||
|
__tests__
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
# `@docusaurus/plugin-google-tag-manager`
|
||||||
|
|
||||||
|
Google Tag Manager plugin for Docusaurus.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
See [plugin-google-tag-manager documentation](https://docusaurus.io/docs/api/plugins/@docusaurus/plugin-google-tag-manager).
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
{
|
||||||
|
"name": "@docusaurus/plugin-google-tag-manager",
|
||||||
|
"version": "2.4.2",
|
||||||
|
"description": "Google Tag Manager (gtm.js) plugin for Docusaurus.",
|
||||||
|
"main": "lib/index.js",
|
||||||
|
"types": "lib/index.d.ts",
|
||||||
|
"publishConfig": {
|
||||||
|
"access": "public"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"build": "tsc --build",
|
||||||
|
"watch": "tsc --build --watch"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/facebook/docusaurus.git",
|
||||||
|
"directory": "packages/docusaurus-plugin-google-tag-manager"
|
||||||
|
},
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@docusaurus/core": "2.4.2",
|
||||||
|
"@docusaurus/types": "2.4.2",
|
||||||
|
"@docusaurus/utils-validation": "2.4.2",
|
||||||
|
"tslib": "^2.4.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^16.8.4 || ^17.0.0",
|
||||||
|
"react-dom": "^16.8.4 || ^17.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16.14"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,78 @@
|
||||||
|
/**
|
||||||
|
* 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 {Joi} from '@docusaurus/utils-validation';
|
||||||
|
import type {
|
||||||
|
LoadContext,
|
||||||
|
Plugin,
|
||||||
|
OptionValidationContext,
|
||||||
|
} from '@docusaurus/types';
|
||||||
|
import type {PluginOptions, Options} from './options';
|
||||||
|
|
||||||
|
export default function pluginGoogleAnalytics(
|
||||||
|
context: LoadContext,
|
||||||
|
options: PluginOptions,
|
||||||
|
): Plugin {
|
||||||
|
const {containerId} = options;
|
||||||
|
const isProd = process.env.NODE_ENV === 'production';
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: 'docusaurus-plugin-google-tag-manager',
|
||||||
|
|
||||||
|
contentLoaded({actions}) {
|
||||||
|
actions.setGlobalData(options);
|
||||||
|
},
|
||||||
|
|
||||||
|
injectHtmlTags() {
|
||||||
|
if (!isProd) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
preBodyTags: [
|
||||||
|
{
|
||||||
|
tagName: 'noscript',
|
||||||
|
innerHTML: `<iframe src="https://www.googletagmanager.com/ns.html?id=${containerId}" height="0" width="0" style="display:none;visibility:hidden"></iframe>`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
headTags: [
|
||||||
|
{
|
||||||
|
tagName: 'link',
|
||||||
|
attributes: {
|
||||||
|
rel: 'preconnect',
|
||||||
|
href: 'https://www.googletagmanager.com',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tagName: 'script',
|
||||||
|
innerHTML: `window.dataLayer = window.dataLayer || [];`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tagName: 'script',
|
||||||
|
innerHTML: `(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
|
||||||
|
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
|
||||||
|
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
|
||||||
|
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
|
||||||
|
})(window,document,'script','dataLayer','${containerId}');`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const pluginOptionsSchema = Joi.object<PluginOptions>({
|
||||||
|
containerId: Joi.string().required(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export function validateOptions({
|
||||||
|
validate,
|
||||||
|
options,
|
||||||
|
}: OptionValidationContext<Options, PluginOptions>): PluginOptions {
|
||||||
|
return validate(pluginOptionsSchema, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
export type {PluginOptions, Options};
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export type PluginOptions = {
|
||||||
|
containerId: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Options = Partial<PluginOptions>;
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/// <reference types="@docusaurus/module-type-aliases" />
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
{
|
||||||
|
"extends": "../../tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"noEmit": false,
|
||||||
|
"composite": true,
|
||||||
|
"incremental": true,
|
||||||
|
"tsBuildInfoFile": "./lib/.tsbuildinfo-client",
|
||||||
|
"module": "esnext",
|
||||||
|
"target": "esnext",
|
||||||
|
"rootDir": "src",
|
||||||
|
"outDir": "lib"
|
||||||
|
},
|
||||||
|
"include": ["src/*.d.ts"],
|
||||||
|
"exclude": ["**/__tests__/**"]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
{
|
||||||
|
"extends": "../../tsconfig.json",
|
||||||
|
"references": [{"path": "./tsconfig.client.json"}],
|
||||||
|
"compilerOptions": {
|
||||||
|
"noEmit": false,
|
||||||
|
"incremental": true,
|
||||||
|
"tsBuildInfoFile": "./lib/.tsbuildinfo",
|
||||||
|
"rootDir": "src",
|
||||||
|
"outDir": "lib"
|
||||||
|
},
|
||||||
|
"include": ["src"],
|
||||||
|
"exclude": ["**/__tests__/**"]
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@docusaurus/plugin-ideal-image",
|
"name": "@docusaurus/plugin-ideal-image",
|
||||||
"version": "2.0.0-rc.1",
|
"version": "2.4.2",
|
||||||
"description": "Docusaurus Plugin to generate an almost ideal image (responsive, lazy-loading, and low quality placeholder).",
|
"description": "Docusaurus Plugin to generate an almost ideal image (responsive, lazy-loading, and low quality placeholder).",
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"types": "src/plugin-ideal-image.d.ts",
|
"types": "src/plugin-ideal-image.d.ts",
|
||||||
|
|
@ -20,12 +20,12 @@
|
||||||
},
|
},
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docusaurus/core": "2.0.0-rc.1",
|
"@docusaurus/core": "2.4.2",
|
||||||
"@docusaurus/lqip-loader": "2.0.0-rc.1",
|
"@docusaurus/lqip-loader": "2.4.2",
|
||||||
"@docusaurus/responsive-loader": "^1.7.0",
|
"@docusaurus/responsive-loader": "^1.7.0",
|
||||||
"@docusaurus/theme-translations": "2.0.0-rc.1",
|
"@docusaurus/theme-translations": "2.4.2",
|
||||||
"@docusaurus/types": "2.0.0-rc.1",
|
"@docusaurus/types": "2.4.2",
|
||||||
"@docusaurus/utils-validation": "2.0.0-rc.1",
|
"@docusaurus/utils-validation": "2.4.2",
|
||||||
"@endiliey/react-ideal-image": "^0.0.11",
|
"@endiliey/react-ideal-image": "^0.0.11",
|
||||||
"react-waypoint": "^10.3.0",
|
"react-waypoint": "^10.3.0",
|
||||||
"sharp": "^0.30.7",
|
"sharp": "^0.30.7",
|
||||||
|
|
@ -33,8 +33,7 @@
|
||||||
"webpack": "^5.73.0"
|
"webpack": "^5.73.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@docusaurus/module-type-aliases": "2.0.0-rc.1",
|
"@docusaurus/module-type-aliases": "2.4.2",
|
||||||
"@docusaurus/types": "2.0.0-beta.21",
|
|
||||||
"fs-extra": "^10.1.0"
|
"fs-extra": "^10.1.0"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
|
|
|
||||||
|
|
@ -81,25 +81,19 @@ function getMessage(icon: IconKey, state: State) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function IdealImage(props: Props): JSX.Element {
|
export default function IdealImage(props: Props): JSX.Element {
|
||||||
const {alt, className, img} = props;
|
const {img, ...propsRest} = props;
|
||||||
|
|
||||||
// In dev env just use regular img with original file
|
// In dev env just use regular img with original file
|
||||||
if (typeof img === 'string' || 'default' in img) {
|
if (typeof img === 'string' || 'default' in img) {
|
||||||
return (
|
return (
|
||||||
<img
|
// eslint-disable-next-line jsx-a11y/alt-text
|
||||||
src={typeof img === 'string' ? img : img.default}
|
<img src={typeof img === 'string' ? img : img.default} {...propsRest} />
|
||||||
className={className}
|
|
||||||
alt={alt}
|
|
||||||
{...props}
|
|
||||||
/>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ReactIdealImage
|
<ReactIdealImage
|
||||||
{...props}
|
{...propsRest}
|
||||||
alt={alt}
|
|
||||||
className={className}
|
|
||||||
height={img.src.height ?? 100}
|
height={img.src.height ?? 100}
|
||||||
width={img.src.width ?? 100}
|
width={img.src.width ?? 100}
|
||||||
placeholder={{lqip: img.preSrc}}
|
placeholder={{lqip: img.preSrc}}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@docusaurus/plugin-pwa",
|
"name": "@docusaurus/plugin-pwa",
|
||||||
"version": "2.0.0-rc.1",
|
"version": "2.4.2",
|
||||||
"description": "Docusaurus Plugin to add PWA support.",
|
"description": "Docusaurus Plugin to add PWA support.",
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"types": "src/plugin-pwa.d.ts",
|
"types": "src/plugin-pwa.d.ts",
|
||||||
|
|
@ -22,12 +22,12 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/core": "^7.18.6",
|
"@babel/core": "^7.18.6",
|
||||||
"@babel/preset-env": "^7.18.6",
|
"@babel/preset-env": "^7.18.6",
|
||||||
"@docusaurus/core": "2.0.0-rc.1",
|
"@docusaurus/core": "2.4.2",
|
||||||
"@docusaurus/theme-common": "2.0.0-rc.1",
|
"@docusaurus/theme-common": "2.4.2",
|
||||||
"@docusaurus/theme-translations": "2.0.0-rc.1",
|
"@docusaurus/theme-translations": "2.4.2",
|
||||||
"@docusaurus/types": "2.0.0-rc.1",
|
"@docusaurus/types": "2.4.2",
|
||||||
"@docusaurus/utils": "2.0.0-rc.1",
|
"@docusaurus/utils": "2.4.2",
|
||||||
"@docusaurus/utils-validation": "2.0.0-rc.1",
|
"@docusaurus/utils-validation": "2.4.2",
|
||||||
"babel-loader": "^8.2.5",
|
"babel-loader": "^8.2.5",
|
||||||
"clsx": "^1.2.1",
|
"clsx": "^1.2.1",
|
||||||
"core-js": "^3.23.3",
|
"core-js": "^3.23.3",
|
||||||
|
|
@ -40,7 +40,7 @@
|
||||||
"workbox-window": "^6.5.3"
|
"workbox-window": "^6.5.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@docusaurus/module-type-aliases": "2.0.0-rc.1",
|
"@docusaurus/module-type-aliases": "2.4.2",
|
||||||
"fs-extra": "^10.1.0"
|
"fs-extra": "^10.1.0"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@docusaurus/plugin-sitemap",
|
"name": "@docusaurus/plugin-sitemap",
|
||||||
"version": "2.0.0-rc.1",
|
"version": "2.4.2",
|
||||||
"description": "Simple sitemap generation plugin for Docusaurus.",
|
"description": "Simple sitemap generation plugin for Docusaurus.",
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"types": "lib/index.d.ts",
|
"types": "lib/index.d.ts",
|
||||||
|
|
@ -18,19 +18,16 @@
|
||||||
},
|
},
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docusaurus/core": "2.0.0-rc.1",
|
"@docusaurus/core": "2.4.2",
|
||||||
"@docusaurus/logger": "2.0.0-rc.1",
|
"@docusaurus/logger": "2.4.2",
|
||||||
"@docusaurus/types": "2.0.0-rc.1",
|
"@docusaurus/types": "2.4.2",
|
||||||
"@docusaurus/utils": "2.0.0-rc.1",
|
"@docusaurus/utils": "2.4.2",
|
||||||
"@docusaurus/utils-common": "2.0.0-rc.1",
|
"@docusaurus/utils-common": "2.4.2",
|
||||||
"@docusaurus/utils-validation": "2.0.0-rc.1",
|
"@docusaurus/utils-validation": "2.4.2",
|
||||||
"fs-extra": "^10.1.0",
|
"fs-extra": "^10.1.0",
|
||||||
"sitemap": "^7.1.1",
|
"sitemap": "^7.1.1",
|
||||||
"tslib": "^2.4.0"
|
"tslib": "^2.4.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
|
||||||
"@docusaurus/types": "2.0.0-beta.21"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": "^16.8.4 || ^17.0.0",
|
"react": "^16.8.4 || ^17.0.0",
|
||||||
"react-dom": "^16.8.4 || ^17.0.0"
|
"react-dom": "^16.8.4 || ^17.0.0"
|
||||||
|
|
|
||||||
|
|
@ -158,7 +158,10 @@ describe('createSitemap', () => {
|
||||||
meta: {
|
meta: {
|
||||||
// @ts-expect-error: bad lib def
|
// @ts-expect-error: bad lib def
|
||||||
toComponent: () => [
|
toComponent: () => [
|
||||||
React.createElement('meta', {name: 'robots', content: 'noindex'}),
|
React.createElement('meta', {
|
||||||
|
name: 'robots',
|
||||||
|
content: 'NoFolloW, NoiNDeX',
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,40 @@ import type {DocusaurusConfig} from '@docusaurus/types';
|
||||||
import type {HelmetServerState} from 'react-helmet-async';
|
import type {HelmetServerState} from 'react-helmet-async';
|
||||||
import type {PluginOptions} from './options';
|
import type {PluginOptions} from './options';
|
||||||
|
|
||||||
|
function isNoIndexMetaRoute({
|
||||||
|
head,
|
||||||
|
route,
|
||||||
|
}: {
|
||||||
|
head: {[location: string]: HelmetServerState};
|
||||||
|
route: string;
|
||||||
|
}) {
|
||||||
|
const isNoIndexMetaTag = ({
|
||||||
|
name,
|
||||||
|
content,
|
||||||
|
}: {
|
||||||
|
name?: string;
|
||||||
|
content?: string;
|
||||||
|
}): boolean => {
|
||||||
|
if (!name || !content) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
// meta name is not case-sensitive
|
||||||
|
name.toLowerCase() === 'robots' &&
|
||||||
|
// Robots directives are not case-sensitive
|
||||||
|
content.toLowerCase().includes('noindex')
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// https://github.com/staylor/react-helmet-async/pull/167
|
||||||
|
const meta = head[route]?.meta.toComponent() as unknown as
|
||||||
|
| ReactElement<{name?: string; content?: string}>[]
|
||||||
|
| undefined;
|
||||||
|
return meta?.some((tag) =>
|
||||||
|
isNoIndexMetaTag({name: tag.props.name, content: tag.props.content}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export default async function createSitemap(
|
export default async function createSitemap(
|
||||||
siteConfig: DocusaurusConfig,
|
siteConfig: DocusaurusConfig,
|
||||||
routesPaths: string[],
|
routesPaths: string[],
|
||||||
|
|
@ -27,18 +61,15 @@ export default async function createSitemap(
|
||||||
|
|
||||||
const ignoreMatcher = createMatcher(ignorePatterns);
|
const ignoreMatcher = createMatcher(ignorePatterns);
|
||||||
|
|
||||||
const includedRoutes = routesPaths.filter((route) => {
|
function isRouteExcluded(route: string) {
|
||||||
if (route.endsWith('404.html') || ignoreMatcher(route)) {
|
return (
|
||||||
return false;
|
route.endsWith('404.html') ||
|
||||||
}
|
ignoreMatcher(route) ||
|
||||||
// https://github.com/staylor/react-helmet-async/pull/167
|
isNoIndexMetaRoute({head, route})
|
||||||
const meta = head[route]?.meta.toComponent() as unknown as
|
|
||||||
| ReactElement<{name?: string; content?: string}>[]
|
|
||||||
| undefined;
|
|
||||||
return !meta?.some(
|
|
||||||
(tag) => tag.props.name === 'robots' && tag.props.content === 'noindex',
|
|
||||||
);
|
);
|
||||||
});
|
}
|
||||||
|
|
||||||
|
const includedRoutes = routesPaths.filter((route) => !isRouteExcluded(route));
|
||||||
|
|
||||||
if (includedRoutes.length === 0) {
|
if (includedRoutes.length === 0) {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@docusaurus/preset-classic",
|
"name": "@docusaurus/preset-classic",
|
||||||
"version": "2.0.0-rc.1",
|
"version": "2.4.2",
|
||||||
"description": "Classic preset for Docusaurus.",
|
"description": "Classic preset for Docusaurus.",
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"types": "lib/index.d.ts",
|
"types": "lib/index.d.ts",
|
||||||
|
|
@ -18,18 +18,19 @@
|
||||||
},
|
},
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docusaurus/core": "2.0.0-rc.1",
|
"@docusaurus/core": "2.4.2",
|
||||||
"@docusaurus/plugin-content-blog": "2.0.0-rc.1",
|
"@docusaurus/plugin-content-blog": "2.4.2",
|
||||||
"@docusaurus/plugin-content-docs": "2.0.0-rc.1",
|
"@docusaurus/plugin-content-docs": "2.4.2",
|
||||||
"@docusaurus/plugin-content-pages": "2.0.0-rc.1",
|
"@docusaurus/plugin-content-pages": "2.4.2",
|
||||||
"@docusaurus/plugin-debug": "2.0.0-rc.1",
|
"@docusaurus/plugin-debug": "2.4.2",
|
||||||
"@docusaurus/plugin-google-analytics": "2.0.0-rc.1",
|
"@docusaurus/plugin-google-analytics": "2.4.2",
|
||||||
"@docusaurus/plugin-google-gtag": "2.0.0-rc.1",
|
"@docusaurus/plugin-google-gtag": "2.4.2",
|
||||||
"@docusaurus/plugin-sitemap": "2.0.0-rc.1",
|
"@docusaurus/plugin-google-tag-manager": "2.4.2",
|
||||||
"@docusaurus/theme-classic": "2.0.0-rc.1",
|
"@docusaurus/plugin-sitemap": "2.4.2",
|
||||||
"@docusaurus/theme-common": "2.0.0-rc.1",
|
"@docusaurus/theme-classic": "2.4.2",
|
||||||
"@docusaurus/theme-search-algolia": "2.0.0-rc.1",
|
"@docusaurus/theme-common": "2.4.2",
|
||||||
"@docusaurus/types": "2.0.0-rc.1"
|
"@docusaurus/theme-search-algolia": "2.4.2",
|
||||||
|
"@docusaurus/types": "2.4.2"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": "^16.8.4 || ^17.0.0",
|
"react": "^16.8.4 || ^17.0.0",
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,7 @@ export default function preset(
|
||||||
theme,
|
theme,
|
||||||
googleAnalytics,
|
googleAnalytics,
|
||||||
gtag,
|
gtag,
|
||||||
|
googleTagManager,
|
||||||
...rest
|
...rest
|
||||||
} = opts;
|
} = opts;
|
||||||
|
|
||||||
|
|
@ -80,6 +81,14 @@ export default function preset(
|
||||||
if (gtag) {
|
if (gtag) {
|
||||||
plugins.push(makePluginConfig('@docusaurus/plugin-google-gtag', gtag));
|
plugins.push(makePluginConfig('@docusaurus/plugin-google-gtag', gtag));
|
||||||
}
|
}
|
||||||
|
if (googleTagManager) {
|
||||||
|
plugins.push(
|
||||||
|
makePluginConfig(
|
||||||
|
'@docusaurus/plugin-google-tag-manager',
|
||||||
|
googleTagManager,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
if (isProd && sitemap !== false) {
|
if (isProd && sitemap !== false) {
|
||||||
plugins.push(makePluginConfig('@docusaurus/plugin-sitemap', sitemap));
|
plugins.push(makePluginConfig('@docusaurus/plugin-sitemap', sitemap));
|
||||||
}
|
}
|
||||||
|
|
@ -87,7 +96,7 @@ export default function preset(
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Unrecognized keys ${Object.keys(rest).join(
|
`Unrecognized keys ${Object.keys(rest).join(
|
||||||
', ',
|
', ',
|
||||||
)} found in preset-classic configuration. The allowed keys are debug, docs, blog, pages, sitemap, theme, googleAnalytics, gtag. Check the documentation: https://docusaurus.io/docs/presets#docusauruspreset-classic for more information on how to configure individual plugins.`,
|
)} found in preset-classic configuration. The allowed keys are debug, docs, blog, pages, sitemap, theme, googleAnalytics, gtag, and googleTagManager. Check the documentation: https://docusaurus.io/docs/using-plugins#docusauruspreset-classic for more information on how to configure individual plugins.`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import type {Options as PagesPluginOptions} from '@docusaurus/plugin-content-pag
|
||||||
import type {Options as SitemapPluginOptions} from '@docusaurus/plugin-sitemap';
|
import type {Options as SitemapPluginOptions} from '@docusaurus/plugin-sitemap';
|
||||||
import type {Options as GAPluginOptions} from '@docusaurus/plugin-google-analytics';
|
import type {Options as GAPluginOptions} from '@docusaurus/plugin-google-analytics';
|
||||||
import type {Options as GtagPluginOptions} from '@docusaurus/plugin-google-gtag';
|
import type {Options as GtagPluginOptions} from '@docusaurus/plugin-google-gtag';
|
||||||
|
import type {Options as GTMPluginOptions} from '@docusaurus/plugin-google-tag-manager';
|
||||||
import type {Options as ThemeOptions} from '@docusaurus/theme-classic';
|
import type {Options as ThemeOptions} from '@docusaurus/theme-classic';
|
||||||
import type {ThemeConfig as BaseThemeConfig} from '@docusaurus/types';
|
import type {ThemeConfig as BaseThemeConfig} from '@docusaurus/types';
|
||||||
import type {UserThemeConfig as ClassicThemeConfig} from '@docusaurus/theme-common';
|
import type {UserThemeConfig as ClassicThemeConfig} from '@docusaurus/theme-common';
|
||||||
|
|
@ -42,6 +43,7 @@ export type Options = {
|
||||||
* is present.
|
* is present.
|
||||||
*/
|
*/
|
||||||
gtag?: GtagPluginOptions;
|
gtag?: GtagPluginOptions;
|
||||||
|
googleTagManager?: GTMPluginOptions;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ThemeConfig = BaseThemeConfig &
|
export type ThemeConfig = BaseThemeConfig &
|
||||||
|
|
|
||||||
|
|
@ -63,3 +63,30 @@ module.exports = {
|
||||||
| Property | Type | Default | Description |
|
| Property | Type | Default | Description |
|
||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| `sync` | `boolean` | `false` | Syncing tab choices (Yarn and npm). See https://docusaurus.io/docs/markdown-features/#syncing-tab-choices for details. |
|
| `sync` | `boolean` | `false` | Syncing tab choices (Yarn and npm). See https://docusaurus.io/docs/markdown-features/#syncing-tab-choices for details. |
|
||||||
|
| `converters` | `array` | `'yarn'`, `'pnpm'` | The list of converters to use. The order of the converters is important, as the first converter will be used as the default choice. |
|
||||||
|
|
||||||
|
## Custom converters
|
||||||
|
|
||||||
|
In case you want to convert npm commands to something else than `yarn` or `pnpm`, you can use custom converters:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
type CustomConverter = [name: string, cb: (npmCode: string) => string];
|
||||||
|
```
|
||||||
|
|
||||||
|
```ts
|
||||||
|
{
|
||||||
|
remarkPlugins: [
|
||||||
|
[
|
||||||
|
require('@docusaurus/remark-plugin-npm2yarn'),
|
||||||
|
{
|
||||||
|
sync: true,
|
||||||
|
converters: [
|
||||||
|
'yarn',
|
||||||
|
'pnpm',
|
||||||
|
['Turbo', (code) => code.replace(/npm/g, 'turbo')],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@docusaurus/remark-plugin-npm2yarn",
|
"name": "@docusaurus/remark-plugin-npm2yarn",
|
||||||
"version": "2.0.0-rc.1",
|
"version": "2.4.2",
|
||||||
"description": "Remark plugin for converting npm commands to Yarn commands as tabs.",
|
"description": "Remark plugin for converting npm commands to Yarn commands as tabs.",
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
|
|
@ -17,8 +17,8 @@
|
||||||
},
|
},
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"npm-to-yarn": "^1.0.1",
|
"npm-to-yarn": "^2.0.0",
|
||||||
"tslib": "^2.4.0",
|
"tslib": "^2.4.1",
|
||||||
"unist-util-visit": "^2.0.3"
|
"unist-util-visit": "^2.0.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|
|
||||||
16
packages/docusaurus-remark-plugin-npm2yarn/src/__tests__/__fixtures__/conversion-test.md
generated
Normal file
16
packages/docusaurus-remark-plugin-npm2yarn/src/__tests__/__fixtures__/conversion-test.md
generated
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
```bash npm2yarn
|
||||||
|
npm run xxx -- --arg
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash npm2yarn
|
||||||
|
npm install package
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash npm2yarn
|
||||||
|
npm remove package-name
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash npm2yarn
|
||||||
|
npm init docusaurus
|
||||||
|
npm init docusaurus@latest my-website classic
|
||||||
|
```
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue