mirror of
https://github.com/facebook/docusaurus.git
synced 2025-12-26 01:33:02 +00:00
Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
56410aa946 | ||
|
|
4ab5a93262 | ||
|
|
4a2200ace4 | ||
|
|
4fb67ef11b | ||
|
|
985a64ad22 | ||
|
|
c60387dbe8 | ||
|
|
c84d779627 | ||
|
|
de972142a8 | ||
|
|
7743aa6307 | ||
|
|
26d2b9a018 | ||
|
|
bb65b5c578 | ||
|
|
2ef40c2598 | ||
|
|
d88f248180 | ||
|
|
e4fc47bec2 | ||
|
|
e78a15eeba | ||
|
|
c751bc64ea | ||
|
|
d255389e48 |
|
|
@ -28,6 +28,7 @@
|
|||
"__snapshots__",
|
||||
"website/src/data/users.tsx",
|
||||
"website/src/data/tweets.tsx",
|
||||
"website/docusaurus.config.localized.json",
|
||||
"*.xyz",
|
||||
"*.docx",
|
||||
"versioned_docs",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "new.docusaurus.io",
|
||||
"version": "2.0.0-rc.1",
|
||||
"version": "2.4.3",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"start": "npx --package netlify-cli netlify dev"
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
set -euo pipefail
|
||||
|
||||
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"
|
||||
EXTRA_OPTS=""
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"version": "2.0.0-rc.1",
|
||||
"version": "2.4.3",
|
||||
"npmClient": "yarn",
|
||||
"useWorkspaces": true,
|
||||
"changelog": {
|
||||
|
|
@ -11,6 +11,7 @@
|
|||
"pr: performance": ":running_woman: Performance",
|
||||
"pr: polish": ":nail_care: Polish",
|
||||
"pr: documentation": ":memo: Documentation",
|
||||
"pr: dependencies": ":robot: Dependencies",
|
||||
"pr: maintenance": ":wrench: Maintenance"
|
||||
},
|
||||
"cacheDir": ".changelog"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "create-docusaurus",
|
||||
"version": "2.0.0-rc.1",
|
||||
"version": "2.4.3",
|
||||
"description": "Create Docusaurus apps easily.",
|
||||
"type": "module",
|
||||
"repository": {
|
||||
|
|
@ -22,8 +22,8 @@
|
|||
},
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@docusaurus/logger": "2.0.0-rc.1",
|
||||
"@docusaurus/utils": "2.0.0-rc.1",
|
||||
"@docusaurus/logger": "2.4.3",
|
||||
"@docusaurus/utils": "2.4.3",
|
||||
"commander": "^5.1.0",
|
||||
"fs-extra": "^10.1.0",
|
||||
"lodash": "^4.17.21",
|
||||
|
|
|
|||
|
|
@ -241,7 +241,7 @@ async function getSiteName(
|
|||
return true;
|
||||
}
|
||||
if (reqName) {
|
||||
const res = validateSiteName(reqName);
|
||||
const res = await validateSiteName(reqName);
|
||||
if (typeof res === 'string') {
|
||||
throw new Error(res);
|
||||
}
|
||||
|
|
@ -456,8 +456,10 @@ export default async function init(
|
|||
reqTemplate?: string,
|
||||
cliOptions: CLIOptions = {},
|
||||
): Promise<void> {
|
||||
const templates = await readTemplates();
|
||||
const siteName = await getSiteName(reqName, rootDir);
|
||||
const [templates, siteName] = await Promise.all([
|
||||
readTemplates(),
|
||||
getSiteName(reqName, rootDir),
|
||||
]);
|
||||
const dest = path.resolve(rootDir, siteName);
|
||||
const source = await getSource(reqTemplate, templates, cliOptions);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "docusaurus-2-classic-typescript-template",
|
||||
"version": "2.0.0-rc.1",
|
||||
"version": "2.4.3",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"docusaurus": "docusaurus",
|
||||
|
|
@ -15,8 +15,8 @@
|
|||
"typecheck": "tsc"
|
||||
},
|
||||
"dependencies": {
|
||||
"@docusaurus/core": "2.0.0-rc.1",
|
||||
"@docusaurus/preset-classic": "2.0.0-rc.1",
|
||||
"@docusaurus/core": "2.4.3",
|
||||
"@docusaurus/preset-classic": "2.4.3",
|
||||
"@mdx-js/react": "^1.6.22",
|
||||
"clsx": "^1.2.1",
|
||||
"prism-react-renderer": "^1.3.5",
|
||||
|
|
@ -24,7 +24,7 @@
|
|||
"react-dom": "^17.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@docusaurus/module-type-aliases": "2.0.0-rc.1",
|
||||
"@docusaurus/module-type-aliases": "2.4.3",
|
||||
"@tsconfig/docusaurus": "^1.0.5",
|
||||
"typescript": "^4.7.4"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -8,17 +8,22 @@ const darkCodeTheme = require('prism-react-renderer/themes/dracula');
|
|||
const config = {
|
||||
title: 'My Site',
|
||||
tagline: 'Dinosaurs are cool',
|
||||
url: 'https://your-docusaurus-test-site.com',
|
||||
baseUrl: '/',
|
||||
onBrokenLinks: 'throw',
|
||||
onBrokenMarkdownLinks: 'warn',
|
||||
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.
|
||||
// If you aren't using GitHub pages, you don't need these.
|
||||
organizationName: 'facebook', // Usually your GitHub org/user 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
|
||||
// metadata like html lang. For example, if your site is Chinese, you may want
|
||||
// to replace "en" with "zh-Hans".
|
||||
|
|
@ -56,6 +61,8 @@ const config = {
|
|||
themeConfig:
|
||||
/** @type {import('@docusaurus/preset-classic').ThemeConfig} */
|
||||
({
|
||||
// Replace with your project's social card
|
||||
image: 'img/docusaurus-social-card.jpg',
|
||||
navbar: {
|
||||
title: 'My Site',
|
||||
logo: {
|
||||
|
|
@ -64,8 +71,8 @@ const config = {
|
|||
},
|
||||
items: [
|
||||
{
|
||||
type: 'doc',
|
||||
docId: 'intro',
|
||||
type: 'docSidebar',
|
||||
sidebarId: 'tutorialSidebar',
|
||||
position: 'left',
|
||||
label: 'Tutorial',
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "docusaurus-2-classic-template",
|
||||
"version": "2.0.0-rc.1",
|
||||
"version": "2.4.3",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"docusaurus": "docusaurus",
|
||||
|
|
@ -14,8 +14,8 @@
|
|||
"write-heading-ids": "docusaurus write-heading-ids"
|
||||
},
|
||||
"dependencies": {
|
||||
"@docusaurus/core": "2.0.0-rc.1",
|
||||
"@docusaurus/preset-classic": "2.0.0-rc.1",
|
||||
"@docusaurus/core": "2.4.3",
|
||||
"@docusaurus/preset-classic": "2.4.3",
|
||||
"@mdx-js/react": "^1.6.22",
|
||||
"clsx": "^1.2.1",
|
||||
"prism-react-renderer": "^1.3.5",
|
||||
|
|
@ -23,7 +23,7 @@
|
|||
"react-dom": "^17.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@docusaurus/module-type-aliases": "2.0.0-rc.1"
|
||||
"@docusaurus/module-type-aliases": "2.4.3"
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
|
|
|
|||
|
|
@ -13,17 +13,22 @@
|
|||
const config = {
|
||||
title: 'My Site',
|
||||
tagline: 'The tagline of my site',
|
||||
url: 'https://your-docusaurus-test-site.com',
|
||||
baseUrl: '/',
|
||||
onBrokenLinks: 'throw',
|
||||
onBrokenMarkdownLinks: 'warn',
|
||||
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.
|
||||
// If you aren't using GitHub pages, you don't need these.
|
||||
organizationName: 'facebook', // Usually your GitHub org/user name.
|
||||
projectName: 'docusaurus', // Usually your repo name.
|
||||
|
||||
onBrokenLinks: 'throw',
|
||||
onBrokenMarkdownLinks: 'warn',
|
||||
|
||||
presets: [
|
||||
[
|
||||
'classic',
|
||||
|
|
@ -53,6 +58,7 @@ const config = {
|
|||
themeConfig:
|
||||
/** @type {import('@docusaurus/preset-classic').ThemeConfig} */
|
||||
({
|
||||
image: 'img/docusaurus-social-card.jpg',
|
||||
navbar: {
|
||||
title: 'My Meta Project',
|
||||
logo: {
|
||||
|
|
@ -61,8 +67,8 @@ const config = {
|
|||
},
|
||||
items: [
|
||||
{
|
||||
type: 'doc',
|
||||
docId: 'intro',
|
||||
type: 'docSidebar',
|
||||
sidebarId: 'tutorialSidebar',
|
||||
position: 'left',
|
||||
label: 'Tutorial',
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "docusaurus-2-facebook-template",
|
||||
"version": "2.0.0-rc.1",
|
||||
"version": "2.4.3",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"docusaurus": "docusaurus",
|
||||
|
|
@ -18,8 +18,8 @@
|
|||
"format:diff": "prettier --config .prettierrc --list-different \"**/*.{js,jsx,ts,tsx,md,mdx}\""
|
||||
},
|
||||
"dependencies": {
|
||||
"@docusaurus/core": "2.0.0-rc.1",
|
||||
"@docusaurus/preset-classic": "2.0.0-rc.1",
|
||||
"@docusaurus/core": "2.4.3",
|
||||
"@docusaurus/preset-classic": "2.4.3",
|
||||
"@mdx-js/react": "^1.6.22",
|
||||
"clsx": "^1.2.1",
|
||||
"react": "^17.0.2",
|
||||
|
|
|
|||
|
|
@ -25,10 +25,12 @@ module.exports = {
|
|||
// But you can create a sidebar manually
|
||||
/*
|
||||
tutorialSidebar: [
|
||||
'intro',
|
||||
'hello',
|
||||
{
|
||||
type: 'category',
|
||||
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?
|
||||
|
||||
- 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 [search bar](https://docusaurus.io/docs/search)
|
||||
- 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"
|
||||
module.exports = {
|
||||
tutorialSidebar: [
|
||||
'intro',
|
||||
// highlight-next-line
|
||||
'hello',
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Tutorial',
|
||||
// highlight-next-line
|
||||
items: ['hello'],
|
||||
items: ['tutorial-basics/create-a-document'],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -19,10 +19,12 @@ const sidebars = {
|
|||
// But you can create a sidebar manually
|
||||
/*
|
||||
tutorialSidebar: [
|
||||
'intro',
|
||||
'hello',
|
||||
{
|
||||
type: 'category',
|
||||
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",
|
||||
"version": "2.0.0-rc.1",
|
||||
"version": "2.4.3",
|
||||
"description": "Advanced cssnano preset for maximum optimization.",
|
||||
"main": "lib/index.js",
|
||||
"license": "MIT",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@docusaurus/logger",
|
||||
"version": "2.0.0-rc.1",
|
||||
"version": "2.4.3",
|
||||
"description": "An encapsulated logger for semantically formatting console messages.",
|
||||
"main": "./lib/index.js",
|
||||
"repository": {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@docusaurus/mdx-loader",
|
||||
"version": "2.0.0-rc.1",
|
||||
"version": "2.4.3",
|
||||
"description": "Docusaurus Loader for MDX",
|
||||
"main": "lib/index.js",
|
||||
"types": "lib/index.d.ts",
|
||||
|
|
@ -20,8 +20,8 @@
|
|||
"dependencies": {
|
||||
"@babel/parser": "^7.18.8",
|
||||
"@babel/traverse": "^7.18.8",
|
||||
"@docusaurus/logger": "2.0.0-rc.1",
|
||||
"@docusaurus/utils": "2.0.0-rc.1",
|
||||
"@docusaurus/logger": "2.4.3",
|
||||
"@docusaurus/utils": "2.4.3",
|
||||
"@mdx-js/mdx": "^1.6.22",
|
||||
"escape-html": "^1.0.3",
|
||||
"file-loader": "^6.2.0",
|
||||
|
|
@ -37,7 +37,7 @@
|
|||
"webpack": "^5.73.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@docusaurus/types": "2.0.0-rc.1",
|
||||
"@docusaurus/types": "2.4.3",
|
||||
"@types/escape-html": "^1.0.2",
|
||||
"@types/mdast": "^3.0.10",
|
||||
"@types/stringify-object": "^3.3.1",
|
||||
|
|
|
|||
|
|
@ -22,8 +22,10 @@ import toc from './remark/toc';
|
|||
import unwrapMdxCodeBlocks from './remark/unwrapMdxCodeBlocks';
|
||||
import transformImage from './remark/transformImage';
|
||||
import transformLinks from './remark/transformLinks';
|
||||
import mermaid from './remark/mermaid';
|
||||
|
||||
import transformAdmonitions from './remark/admonitions';
|
||||
import type {MarkdownConfig} from '@docusaurus/types';
|
||||
import type {LoaderContext} from 'webpack';
|
||||
import type {Processor, Plugin} from 'unified';
|
||||
import type {AdmonitionOptions} from './remark/admonitions';
|
||||
|
|
@ -61,6 +63,7 @@ export type MDXOptions = {
|
|||
};
|
||||
|
||||
export type Options = Partial<MDXOptions> & {
|
||||
markdownConfig: MarkdownConfig;
|
||||
staticDirs: string[];
|
||||
siteDir: string;
|
||||
isMDXPartial?: (filePath: string) => boolean;
|
||||
|
|
@ -71,7 +74,6 @@ export type Options = Partial<MDXOptions> & {
|
|||
frontMatter: {[key: string]: unknown};
|
||||
metadata: {[key: string]: unknown};
|
||||
}) => {[key: string]: unknown};
|
||||
filepath: string;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -171,6 +173,7 @@ export async function mdxLoader(
|
|||
...(reqOptions.beforeDefaultRemarkPlugins ?? []),
|
||||
...getAdmonitionsPlugins(reqOptions.admonitions ?? false),
|
||||
...DEFAULT_OPTIONS.remarkPlugins,
|
||||
...(reqOptions.markdownConfig.mermaid ? [mermaid] : []),
|
||||
[
|
||||
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>
|
||||
<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');
|
||||
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 keywords = Object.values(options.keywords).map(escapeRegExp).join('|');
|
||||
const nestingChar = escapeRegExp(options.tag.slice(0, 1));
|
||||
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
|
||||
// present and create tags for it
|
||||
|
|
@ -77,6 +88,11 @@ const plugin: Plugin = function plugin(
|
|||
];
|
||||
const food = [];
|
||||
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;
|
||||
// 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);
|
||||
food.push(line);
|
||||
newValue = newValue.slice(idx + 1);
|
||||
// the closing tag is NOT part of the content
|
||||
if (line.startsWith(options.tag)) {
|
||||
break;
|
||||
const nesting = nestingLevelRegex.exec(line);
|
||||
idx = newValue.indexOf(NEWLINE);
|
||||
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);
|
||||
idx = newValue.indexOf(NEWLINE);
|
||||
}
|
||||
|
||||
// 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",
|
||||
"version": "2.0.0-rc.1",
|
||||
"version": "2.4.3",
|
||||
"description": "A CLI tool to migrate from older versions of Docusaurus.",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
|
|
@ -24,8 +24,8 @@
|
|||
"dependencies": {
|
||||
"@babel/core": "^7.18.6",
|
||||
"@babel/preset-env": "^7.18.6",
|
||||
"@docusaurus/logger": "2.0.0-rc.1",
|
||||
"@docusaurus/utils": "2.0.0-rc.1",
|
||||
"@docusaurus/logger": "2.4.3",
|
||||
"@docusaurus/utils": "2.4.3",
|
||||
"@mapbox/hast-util-to-jsx": "^2.0.0",
|
||||
"color": "^4.2.3",
|
||||
"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": {
|
||||
"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": {
|
||||
"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": {
|
||||
"src": "img/docusaurus_monochrome.svg"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@docusaurus/module-type-aliases",
|
||||
"version": "2.0.0-rc.1",
|
||||
"version": "2.4.3",
|
||||
"description": "Docusaurus module type aliases.",
|
||||
"types": "./src/index.d.ts",
|
||||
"publishConfig": {
|
||||
|
|
@ -13,7 +13,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@docusaurus/react-loadable": "5.5.2",
|
||||
"@docusaurus/types": "2.0.0-rc.1",
|
||||
"@docusaurus/types": "2.4.3",
|
||||
"@types/history": "^4.7.11",
|
||||
"@types/react": "*",
|
||||
"@types/react-router-config": "*",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@docusaurus/plugin-client-redirects",
|
||||
"version": "2.0.0-rc.1",
|
||||
"version": "2.4.3",
|
||||
"description": "Client redirects plugin for Docusaurus.",
|
||||
"main": "lib/index.js",
|
||||
"types": "lib/index.d.ts",
|
||||
|
|
@ -18,18 +18,18 @@
|
|||
},
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@docusaurus/core": "2.0.0-rc.1",
|
||||
"@docusaurus/logger": "2.0.0-rc.1",
|
||||
"@docusaurus/utils": "2.0.0-rc.1",
|
||||
"@docusaurus/utils-common": "2.0.0-rc.1",
|
||||
"@docusaurus/utils-validation": "2.0.0-rc.1",
|
||||
"eta": "^1.12.3",
|
||||
"@docusaurus/core": "2.4.3",
|
||||
"@docusaurus/logger": "2.4.3",
|
||||
"@docusaurus/utils": "2.4.3",
|
||||
"@docusaurus/utils-common": "2.4.3",
|
||||
"@docusaurus/utils-validation": "2.4.3",
|
||||
"eta": "^2.0.0",
|
||||
"fs-extra": "^10.1.0",
|
||||
"lodash": "^4.17.21",
|
||||
"tslib": "^2.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@docusaurus/types": "2.0.0-rc.1"
|
||||
"@docusaurus/types": "2.4.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.4 || ^17.0.0",
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
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:
|
||||
- /this/path/does/not/exist2
|
||||
"You are trying to create client-side redirections to invalid paths.
|
||||
|
||||
These paths are redirected to but do not exist:
|
||||
- /this/path/does/not/exist2
|
||||
|
||||
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`] = `
|
||||
"Some created redirects are invalid:
|
||||
- {"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/" />
|
||||
</head>
|
||||
<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>
|
||||
</html>"
|
||||
`;
|
||||
|
|
@ -23,7 +23,7 @@ exports[`createRedirectPageContent works 1`] = `
|
|||
<link rel="canonical" href="https://docusaurus.io/" />
|
||||
</head>
|
||||
<script>
|
||||
window.location.href = 'https://docusaurus.io/';
|
||||
window.location.href = 'https://docusaurus.io/' + window.location.search + window.location.hash;
|
||||
</script>
|
||||
</html>"
|
||||
`;
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ exports[`toRedirectFiles creates appropriate metadata for empty baseUrl: fileCon
|
|||
<link rel="canonical" href="/abc" />
|
||||
</head>
|
||||
<script>
|
||||
window.location.href = '/abc';
|
||||
window.location.href = '/abc' + window.location.search + window.location.hash;
|
||||
</script>
|
||||
</html>",
|
||||
]
|
||||
|
|
@ -26,7 +26,7 @@ exports[`toRedirectFiles creates appropriate metadata for root baseUrl: fileCont
|
|||
<link rel="canonical" href="/abc" />
|
||||
</head>
|
||||
<script>
|
||||
window.location.href = '/abc';
|
||||
window.location.href = '/abc' + window.location.search + window.location.hash;
|
||||
</script>
|
||||
</html>",
|
||||
]
|
||||
|
|
@ -42,7 +42,7 @@ exports[`toRedirectFiles creates appropriate metadata trailingSlash=false: fileC
|
|||
<link rel="canonical" href="https://docusaurus.io/abc" />
|
||||
</head>
|
||||
<script>
|
||||
window.location.href = 'https://docusaurus.io/abc';
|
||||
window.location.href = 'https://docusaurus.io/abc' + window.location.search + window.location.hash;
|
||||
</script>
|
||||
</html>",
|
||||
"<!DOCTYPE html>
|
||||
|
|
@ -53,7 +53,7 @@ exports[`toRedirectFiles creates appropriate metadata trailingSlash=false: fileC
|
|||
<link rel="canonical" href="https://docusaurus.io/def.html" />
|
||||
</head>
|
||||
<script>
|
||||
window.location.href = 'https://docusaurus.io/def.html';
|
||||
window.location.href = 'https://docusaurus.io/def.html' + window.location.search + window.location.hash;
|
||||
</script>
|
||||
</html>",
|
||||
"<!DOCTYPE html>
|
||||
|
|
@ -64,7 +64,7 @@ exports[`toRedirectFiles creates appropriate metadata trailingSlash=false: fileC
|
|||
<link rel="canonical" href="https://docusaurus.io/" />
|
||||
</head>
|
||||
<script>
|
||||
window.location.href = 'https://docusaurus.io/';
|
||||
window.location.href = 'https://docusaurus.io/' + window.location.search + window.location.hash;
|
||||
</script>
|
||||
</html>",
|
||||
]
|
||||
|
|
@ -80,7 +80,7 @@ exports[`toRedirectFiles creates appropriate metadata trailingSlash=true: fileCo
|
|||
<link rel="canonical" href="https://docusaurus.io/abc" />
|
||||
</head>
|
||||
<script>
|
||||
window.location.href = 'https://docusaurus.io/abc';
|
||||
window.location.href = 'https://docusaurus.io/abc' + window.location.search + window.location.hash;
|
||||
</script>
|
||||
</html>",
|
||||
"<!DOCTYPE html>
|
||||
|
|
@ -91,7 +91,7 @@ exports[`toRedirectFiles creates appropriate metadata trailingSlash=true: fileCo
|
|||
<link rel="canonical" href="https://docusaurus.io/def.html" />
|
||||
</head>
|
||||
<script>
|
||||
window.location.href = 'https://docusaurus.io/def.html';
|
||||
window.location.href = 'https://docusaurus.io/def.html' + window.location.search + window.location.hash;
|
||||
</script>
|
||||
</html>",
|
||||
"<!DOCTYPE html>
|
||||
|
|
@ -102,7 +102,7 @@ exports[`toRedirectFiles creates appropriate metadata trailingSlash=true: fileCo
|
|||
<link rel="canonical" href="https://docusaurus.io/" />
|
||||
</head>
|
||||
<script>
|
||||
window.location.href = 'https://docusaurus.io/';
|
||||
window.location.href = 'https://docusaurus.io/' + window.location.search + window.location.hash;
|
||||
</script>
|
||||
</html>",
|
||||
]
|
||||
|
|
@ -118,7 +118,7 @@ exports[`toRedirectFiles creates appropriate metadata trailingSlash=undefined: f
|
|||
<link rel="canonical" href="https://docusaurus.io/abc" />
|
||||
</head>
|
||||
<script>
|
||||
window.location.href = 'https://docusaurus.io/abc';
|
||||
window.location.href = 'https://docusaurus.io/abc' + window.location.search + window.location.hash;
|
||||
</script>
|
||||
</html>",
|
||||
"<!DOCTYPE html>
|
||||
|
|
@ -129,7 +129,7 @@ exports[`toRedirectFiles creates appropriate metadata trailingSlash=undefined: f
|
|||
<link rel="canonical" href="https://docusaurus.io/def.html" />
|
||||
</head>
|
||||
<script>
|
||||
window.location.href = 'https://docusaurus.io/def.html';
|
||||
window.location.href = 'https://docusaurus.io/def.html' + window.location.search + window.location.hash;
|
||||
</script>
|
||||
</html>",
|
||||
"<!DOCTYPE html>
|
||||
|
|
@ -140,7 +140,7 @@ exports[`toRedirectFiles creates appropriate metadata trailingSlash=undefined: f
|
|||
<link rel="canonical" href="https://docusaurus.io/" />
|
||||
</head>
|
||||
<script>
|
||||
window.location.href = 'https://docusaurus.io/';
|
||||
window.location.href = 'https://docusaurus.io/' + window.location.search + window.location.hash;
|
||||
</script>
|
||||
</html>",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -220,6 +220,69 @@ describe('collectRedirects', () => {
|
|||
).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', () => {
|
||||
expect(
|
||||
collectRedirects(
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
import _ from 'lodash';
|
||||
import logger from '@docusaurus/logger';
|
||||
import {addTrailingSlash, removeTrailingSlash} from '@docusaurus/utils';
|
||||
import {applyTrailingSlash} from '@docusaurus/utils-common';
|
||||
import {
|
||||
createFromExtensionsRedirects,
|
||||
|
|
@ -80,16 +81,59 @@ function validateCollectedRedirects(
|
|||
|
||||
const allowedToPaths = pluginContext.relativeRoutesPaths;
|
||||
const toPaths = redirects.map((redirect) => redirect.to);
|
||||
const illegalToPaths = _.difference(toPaths, allowedToPaths);
|
||||
if (illegalToPaths.length > 0) {
|
||||
throw new Error(
|
||||
`You are trying to create client-side redirections to paths that do not exist:
|
||||
- ${illegalToPaths.join('\n- ')}
|
||||
const trailingSlashConfig = pluginContext.siteConfig.trailingSlash;
|
||||
// Key is the path, value is whether a valid toPath with a different trailing
|
||||
// slash exists; if the key doesn't exist it means it's valid
|
||||
const differByTrailSlash = new Map(toPaths.map((path) => [path, false]));
|
||||
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:
|
||||
- ${allowedToPaths.join('\n- ')}
|
||||
`,
|
||||
);
|
||||
`;
|
||||
}
|
||||
|
||||
throw new Error(message);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ export default `
|
|||
<link rel="canonical" href="<%= it.toUrl %>" />
|
||||
</head>
|
||||
<script>
|
||||
window.location.href = '<%= it.toUrl %>';
|
||||
window.location.href = '<%= it.toUrl %>' + window.location.search + window.location.hash;
|
||||
</script>
|
||||
</html>
|
||||
`;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@docusaurus/plugin-content-blog",
|
||||
"version": "2.0.0-rc.1",
|
||||
"version": "2.4.3",
|
||||
"description": "Blog plugin for Docusaurus.",
|
||||
"main": "lib/index.js",
|
||||
"types": "src/plugin-content-blog.d.ts",
|
||||
|
|
@ -18,13 +18,13 @@
|
|||
},
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@docusaurus/core": "2.0.0-rc.1",
|
||||
"@docusaurus/logger": "2.0.0-rc.1",
|
||||
"@docusaurus/mdx-loader": "2.0.0-rc.1",
|
||||
"@docusaurus/types": "2.0.0-rc.1",
|
||||
"@docusaurus/utils": "2.0.0-rc.1",
|
||||
"@docusaurus/utils-common": "2.0.0-rc.1",
|
||||
"@docusaurus/utils-validation": "2.0.0-rc.1",
|
||||
"@docusaurus/core": "2.4.3",
|
||||
"@docusaurus/logger": "2.4.3",
|
||||
"@docusaurus/mdx-loader": "2.4.3",
|
||||
"@docusaurus/types": "2.4.3",
|
||||
"@docusaurus/utils": "2.4.3",
|
||||
"@docusaurus/utils-common": "2.4.3",
|
||||
"@docusaurus/utils-validation": "2.4.3",
|
||||
"cheerio": "^1.0.0-rc.12",
|
||||
"feed": "^4.2.2",
|
||||
"fs-extra": "^10.1.0",
|
||||
|
|
@ -35,10 +35,6 @@
|
|||
"utility-types": "^3.10.0",
|
||||
"webpack": "^5.73.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@docusaurus/types": "2.0.0-beta.21",
|
||||
"escape-string-regexp": "^4.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^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();
|
||||
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.
|
||||
*/
|
||||
|
||||
import escapeStringRegexp from 'escape-string-regexp';
|
||||
import {escapeRegexp} from '@docusaurus/utils';
|
||||
import {validateBlogPostFrontMatter} from '../frontMatter';
|
||||
import type {BlogPostFrontMatter} from '@docusaurus/plugin-content-blog';
|
||||
|
||||
|
|
@ -57,7 +57,7 @@ function testField(params: {
|
|||
} catch (err) {
|
||||
// eslint-disable-next-line jest/no-conditional-expect
|
||||
expect((err as Error).message).toMatch(
|
||||
new RegExp(escapeStringRegexp(message)),
|
||||
new RegExp(escapeRegexp(message)),
|
||||
);
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
import path from 'path';
|
||||
import fs from 'fs-extra';
|
||||
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 {blogPostContainerID} from '@docusaurus/utils-common';
|
||||
import {load as cheerioLoad} from 'cheerio';
|
||||
|
|
@ -18,6 +18,7 @@ import type {
|
|||
PluginOptions,
|
||||
Author,
|
||||
BlogPost,
|
||||
BlogFeedItem,
|
||||
} from '@docusaurus/plugin-content-blog';
|
||||
|
||||
async function generateBlogFeed({
|
||||
|
|
@ -54,14 +55,39 @@ async function generateBlogFeed({
|
|||
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 {
|
||||
return {name: author.name, link: author.url, email: author.email};
|
||||
}
|
||||
|
||||
await Promise.all(
|
||||
return Promise.all(
|
||||
blogPosts.map(async (post) => {
|
||||
const {
|
||||
id,
|
||||
metadata: {
|
||||
title: metadataTitle,
|
||||
permalink,
|
||||
|
|
@ -79,10 +105,11 @@ async function generateBlogFeed({
|
|||
);
|
||||
const $ = cheerioLoad(content);
|
||||
|
||||
const feedItem: FeedItem = {
|
||||
const link = normalizeUrl([siteUrl, permalink]);
|
||||
const feedItem: BlogFeedItem = {
|
||||
title: metadataTitle,
|
||||
id,
|
||||
link: normalizeUrl([siteUrl, permalink]),
|
||||
id: link,
|
||||
link,
|
||||
date,
|
||||
description,
|
||||
// Atom feed demands the "term", while other feeds use "name"
|
||||
|
|
@ -99,9 +126,7 @@ async function generateBlogFeed({
|
|||
|
||||
return feedItem;
|
||||
}),
|
||||
).then((items) => items.forEach(feed.addItem));
|
||||
|
||||
return feed;
|
||||
);
|
||||
}
|
||||
|
||||
async function createBlogFeedFile({
|
||||
|
|
|
|||
|
|
@ -455,6 +455,7 @@ export default async function pluginContentBlog(
|
|||
(author) => author.imageURL,
|
||||
),
|
||||
}),
|
||||
markdownConfig: siteConfig.markdown,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -124,6 +124,7 @@ const PluginOptionSchema = Joi.object<PluginOptions>({
|
|||
.default(DEFAULT_OPTIONS.feedOptions.copyright),
|
||||
}),
|
||||
language: Joi.string(),
|
||||
createFeedItems: Joi.function(),
|
||||
}).default(DEFAULT_OPTIONS.feedOptions),
|
||||
authorsMapPath: Joi.string().default(DEFAULT_OPTIONS.authorsMapPath),
|
||||
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 {MDXOptions} from '@docusaurus/mdx-loader';
|
||||
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';
|
||||
|
||||
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
|
||||
* should be accessed through `frontMatter.image`.
|
||||
*/
|
||||
|
|
@ -255,6 +262,24 @@ declare module '@docusaurus/plugin-content-blog' {
|
|||
copyright: string;
|
||||
/** Language of the feed. */
|
||||
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;
|
||||
};
|
||||
|
||||
export type BlogFeedItem = FeedItem;
|
||||
|
||||
export type BlogPaginatedMetadata = {
|
||||
/** Title of the entire blog. */
|
||||
readonly blogTitle: string;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
{
|
||||
"name": "@docusaurus/plugin-content-docs",
|
||||
"version": "2.0.0-rc.1",
|
||||
"version": "2.4.3",
|
||||
"description": "Docs plugin for Docusaurus.",
|
||||
"main": "lib/index.js",
|
||||
"sideEffects": false,
|
||||
"exports": {
|
||||
"./lib/*": "./lib/*",
|
||||
"./src/*": "./src/*",
|
||||
"./client": {
|
||||
"type": "./lib/client/index.d.ts",
|
||||
|
|
@ -34,13 +35,13 @@
|
|||
},
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@docusaurus/core": "2.0.0-rc.1",
|
||||
"@docusaurus/logger": "2.0.0-rc.1",
|
||||
"@docusaurus/mdx-loader": "2.0.0-rc.1",
|
||||
"@docusaurus/module-type-aliases": "2.0.0-rc.1",
|
||||
"@docusaurus/types": "2.0.0-rc.1",
|
||||
"@docusaurus/utils": "2.0.0-rc.1",
|
||||
"@docusaurus/utils-validation": "2.0.0-rc.1",
|
||||
"@docusaurus/core": "2.4.3",
|
||||
"@docusaurus/logger": "2.4.3",
|
||||
"@docusaurus/mdx-loader": "2.4.3",
|
||||
"@docusaurus/module-type-aliases": "2.4.3",
|
||||
"@docusaurus/types": "2.4.3",
|
||||
"@docusaurus/utils": "2.4.3",
|
||||
"@docusaurus/utils-validation": "2.4.3",
|
||||
"@types/react-router-config": "^5.0.6",
|
||||
"combine-promises": "^1.1.0",
|
||||
"fs-extra": "^10.1.0",
|
||||
|
|
@ -52,11 +53,9 @@
|
|||
"webpack": "^5.73.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@docusaurus/types": "2.0.0-beta.21",
|
||||
"@types/js-yaml": "^4.0.5",
|
||||
"@types/picomatch": "^2.3.0",
|
||||
"commander": "^5.1.0",
|
||||
"escape-string-regexp": "^4.0.0",
|
||||
"picomatch": "^2.3.1",
|
||||
"shelljs": "^0.8.5"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -901,6 +901,7 @@ exports[`simple website content: data 1`] = `
|
|||
"label": "Next",
|
||||
"banner": null,
|
||||
"badge": false,
|
||||
"noIndex": false,
|
||||
"className": "docs-version-current",
|
||||
"isLast": true,
|
||||
"docsSidebars": {
|
||||
|
|
@ -2608,6 +2609,7 @@ exports[`versioned website (community) content: data 1`] = `
|
|||
"label": "1.0.0",
|
||||
"banner": null,
|
||||
"badge": true,
|
||||
"noIndex": false,
|
||||
"className": "docs-version-1.0.0",
|
||||
"isLast": true,
|
||||
"docsSidebars": {
|
||||
|
|
@ -2635,6 +2637,7 @@ exports[`versioned website (community) content: data 1`] = `
|
|||
"label": "Next",
|
||||
"banner": "unreleased",
|
||||
"badge": true,
|
||||
"noIndex": false,
|
||||
"className": "docs-version-current",
|
||||
"isLast": false,
|
||||
"docsSidebars": {
|
||||
|
|
@ -3477,6 +3480,7 @@ exports[`versioned website content: data 1`] = `
|
|||
"label": "1.0.0",
|
||||
"banner": "unmaintained",
|
||||
"badge": true,
|
||||
"noIndex": false,
|
||||
"className": "docs-version-1.0.0",
|
||||
"isLast": false,
|
||||
"docsSidebars": {
|
||||
|
|
@ -3544,6 +3548,7 @@ exports[`versioned website content: data 1`] = `
|
|||
"label": "1.0.1",
|
||||
"banner": null,
|
||||
"badge": true,
|
||||
"noIndex": true,
|
||||
"className": "docs-version-1.0.1",
|
||||
"isLast": true,
|
||||
"docsSidebars": {
|
||||
|
|
@ -3599,6 +3604,7 @@ exports[`versioned website content: data 1`] = `
|
|||
"label": "Next",
|
||||
"banner": "unreleased",
|
||||
"badge": true,
|
||||
"noIndex": false,
|
||||
"className": "docs-version-current",
|
||||
"isLast": false,
|
||||
"docsSidebars": {
|
||||
|
|
@ -3674,6 +3680,7 @@ exports[`versioned website content: data 1`] = `
|
|||
"label": "withSlugs",
|
||||
"banner": "unmaintained",
|
||||
"badge": true,
|
||||
"noIndex": false,
|
||||
"className": "docs-version-withSlugs",
|
||||
"isLast": false,
|
||||
"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(
|
||||
docFileSource: string,
|
||||
expectedMetadata: Optional<
|
||||
|
|
@ -172,7 +184,13 @@ function createTestUtils({
|
|||
};
|
||||
}
|
||||
|
||||
return {processDocFile, testMeta, testSlug, generateNavigation};
|
||||
return {
|
||||
processDocFile,
|
||||
getProcessDocFileError,
|
||||
testMeta,
|
||||
testSlug,
|
||||
generateNavigation,
|
||||
};
|
||||
}
|
||||
|
||||
describe('simple site', () => {
|
||||
|
|
@ -683,16 +701,21 @@ describe('simple site', () => {
|
|||
|
||||
it('docs with invalid id', async () => {
|
||||
const {defaultTestUtils} = await loadSite();
|
||||
await expect(async () =>
|
||||
defaultTestUtils.processDocFile(
|
||||
createFakeDocFile({
|
||||
source: 'some/fake/path',
|
||||
frontMatter: {
|
||||
id: 'Hello/world',
|
||||
},
|
||||
}),
|
||||
),
|
||||
).rejects.toThrowErrorMatchingInlineSnapshot(
|
||||
|
||||
const error = await defaultTestUtils.getProcessDocFileError(
|
||||
createFakeDocFile({
|
||||
source: 'some/fake/path',
|
||||
frontMatter: {
|
||||
id: 'Hello/world',
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
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."`,
|
||||
);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
* 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 type {DocFrontMatter} from '@docusaurus/plugin-content-docs';
|
||||
|
||||
|
|
@ -57,7 +57,7 @@ function testField(params: {
|
|||
} catch (err) {
|
||||
// eslint-disable-next-line jest/no-conditional-expect
|
||||
expect((err as Error).message).toMatch(
|
||||
new RegExp(escapeStringRegexp(message)),
|
||||
new RegExp(escapeRegexp(message)),
|
||||
);
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -362,6 +362,11 @@ describe('versioned website', () => {
|
|||
options: {
|
||||
routeBasePath,
|
||||
sidebarPath,
|
||||
versions: {
|
||||
'1.0.1': {
|
||||
noIndex: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
const plugin = await pluginContentDocs(context, options);
|
||||
|
|
|
|||
|
|
@ -76,6 +76,7 @@ describe('normalizeDocsPluginOptions', () => {
|
|||
version1: {
|
||||
path: 'hello',
|
||||
label: 'world',
|
||||
noIndex: true,
|
||||
},
|
||||
},
|
||||
sidebarCollapsible: false,
|
||||
|
|
|
|||
|
|
@ -316,7 +316,7 @@ async function doProcessDocMetadata({
|
|||
};
|
||||
}
|
||||
|
||||
export function processDocMetadata(args: {
|
||||
export async function processDocMetadata(args: {
|
||||
docFile: DocFile;
|
||||
versionMetadata: VersionMetadata;
|
||||
context: LoadContext;
|
||||
|
|
@ -324,10 +324,12 @@ export function processDocMetadata(args: {
|
|||
env: DocEnv;
|
||||
}): Promise<DocMetadataBase> {
|
||||
try {
|
||||
return doProcessDocMetadata(args);
|
||||
return await doProcessDocMetadata(args);
|
||||
} catch (err) {
|
||||
logger.error`Can't process doc metadata for doc at path path=${args.docFile.filePath} in version name=${args.versionMetadata.versionName}`;
|
||||
throw err;
|
||||
throw new Error(
|
||||
`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 {
|
||||
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 {
|
||||
test: /\.mdx?$/i,
|
||||
include: contentDirs
|
||||
// Trailing slash is important, see https://github.com/facebook/docusaurus/pull/3970
|
||||
.map(addTrailingPathSeparator),
|
||||
include: contentDirs,
|
||||
use: [
|
||||
getJSLoader({isServer}),
|
||||
{
|
||||
|
|
@ -375,6 +376,7 @@ export default async function pluginContentDocs(
|
|||
}) => ({
|
||||
image: frontMatter.image,
|
||||
}),
|
||||
markdownConfig: siteConfig.markdown,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ const VersionOptionsSchema = Joi.object({
|
|||
banner: Joi.string().equal('none', 'unreleased', 'unmaintained').optional(),
|
||||
badge: Joi.boolean().optional(),
|
||||
className: Joi.string().optional(),
|
||||
noIndex: Joi.boolean().optional(),
|
||||
});
|
||||
|
||||
const VersionsOptionsSchema = Joi.object()
|
||||
|
|
|
|||
|
|
@ -125,6 +125,25 @@ declare module '@docusaurus/plugin-content-docs' {
|
|||
// TODO support custom version banner?
|
||||
// {type: "error", content: "html content"}
|
||||
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 = {
|
||||
/**
|
||||
* 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. */
|
||||
includeCurrentVersion: boolean;
|
||||
/** Independent customization of each version's properties. */
|
||||
versions: {
|
||||
[versionName: string]: {
|
||||
/**
|
||||
* The base path of the version, will be appended to `baseUrl` +
|
||||
* `routeBasePath`.
|
||||
*/
|
||||
path?: string;
|
||||
/** The label of the version to be used in badges, dropdowns, etc. */
|
||||
label?: string;
|
||||
/** The banner to show at the top of a doc of that version. */
|
||||
banner?: 'none' | VersionBanner;
|
||||
/** Show a badge with the version label at the top of each doc. */
|
||||
badge?: boolean;
|
||||
/** Add a custom class name to the <html> element of each doc. */
|
||||
className?: string;
|
||||
};
|
||||
};
|
||||
versions: {[versionName: string]: VersionOptions};
|
||||
};
|
||||
export type SidebarOptions = {
|
||||
/**
|
||||
|
|
@ -263,6 +266,8 @@ declare module '@docusaurus/plugin-content-docs' {
|
|||
banner: VersionBanner | null;
|
||||
/** 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;
|
||||
/**
|
||||
|
|
@ -500,7 +505,7 @@ declare module '@docusaurus/plugin-content-docs' {
|
|||
|
||||
export type PropVersionMetadata = Pick<
|
||||
VersionMetadata,
|
||||
'label' | 'banner' | 'badge' | 'className' | 'isLast'
|
||||
'label' | 'banner' | 'badge' | 'className' | 'isLast' | 'noIndex'
|
||||
> & {
|
||||
/** ID of the docs plugin this version belongs to. */
|
||||
pluginId: string;
|
||||
|
|
|
|||
|
|
@ -142,6 +142,7 @@ export function toVersionMetadataProp(
|
|||
label: loadedVersion.label,
|
||||
banner: loadedVersion.banner,
|
||||
badge: loadedVersion.badge,
|
||||
noIndex: loadedVersion.noIndex,
|
||||
className: loadedVersion.className,
|
||||
isLast: loadedVersion.isLast,
|
||||
docsSidebars: toSidebarsProp(loadedVersion),
|
||||
|
|
|
|||
|
|
@ -86,6 +86,9 @@ exports[`DefaultSidebarItemsGenerator generates simple flat sidebar 1`] = `
|
|||
"type": "doc",
|
||||
},
|
||||
{
|
||||
"customProps": {
|
||||
"custom": "prop",
|
||||
},
|
||||
"id": "doc1",
|
||||
"label": "doc1 sidebar label",
|
||||
"type": "doc",
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@ describe('DefaultSidebarItemsGenerator', () => {
|
|||
sidebarPosition: 2,
|
||||
frontMatter: {
|
||||
sidebar_label: 'doc1 sidebar label',
|
||||
sidebar_custom_props: {custom: 'prop'},
|
||||
},
|
||||
title: '',
|
||||
unversionedId: 'doc1',
|
||||
|
|
|
|||
|
|
@ -138,7 +138,11 @@ Available doc IDs:
|
|||
): WithPosition<SidebarItemDoc> {
|
||||
const {
|
||||
sidebarPosition: position,
|
||||
frontMatter: {sidebar_label: label, sidebar_class_name: className},
|
||||
frontMatter: {
|
||||
sidebar_label: label,
|
||||
sidebar_class_name: className,
|
||||
sidebar_custom_props: customProps,
|
||||
},
|
||||
} = getDoc(id);
|
||||
return {
|
||||
type: 'doc',
|
||||
|
|
@ -149,6 +153,7 @@ Available doc IDs:
|
|||
// sidebar
|
||||
...(label !== undefined && {label}),
|
||||
...(className !== undefined && {className}),
|
||||
...(customProps !== undefined && {customProps}),
|
||||
};
|
||||
}
|
||||
function createCategoryItem(
|
||||
|
|
|
|||
|
|
@ -44,6 +44,8 @@ export type SidebarItemLink = SidebarItemBase & {
|
|||
type: 'link';
|
||||
href: string;
|
||||
label: string;
|
||||
autoAddBaseUrl?: boolean;
|
||||
description?: string;
|
||||
};
|
||||
|
||||
export type SidebarItemAutogenerated = SidebarItemBase & {
|
||||
|
|
@ -56,6 +58,7 @@ type SidebarItemCategoryBase = SidebarItemBase & {
|
|||
label: string;
|
||||
collapsed: boolean;
|
||||
collapsible: boolean;
|
||||
description?: string;
|
||||
};
|
||||
|
||||
export type SidebarItemCategoryLinkDoc = {type: 'doc'; id: string};
|
||||
|
|
|
|||
|
|
@ -59,9 +59,13 @@ const sidebarItemHtmlSchema = sidebarItemBaseSchema.append<SidebarItemHtml>({
|
|||
const sidebarItemLinkSchema = sidebarItemBaseSchema.append<SidebarItemLink>({
|
||||
type: 'link',
|
||||
href: URISchema.required(),
|
||||
autoAddBaseUrl: Joi.boolean(),
|
||||
label: Joi.string()
|
||||
.required()
|
||||
.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>()
|
||||
|
|
@ -115,6 +119,9 @@ const sidebarItemCategorySchema =
|
|||
collapsible: Joi.boolean().messages({
|
||||
'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', {
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ describe('readVersionsMetadata', () => {
|
|||
path: '/docs',
|
||||
banner: null,
|
||||
badge: false,
|
||||
noIndex: false,
|
||||
className: 'docs-version-current',
|
||||
};
|
||||
return {simpleSiteDir, defaultOptions, defaultContext, vCurrent};
|
||||
|
|
@ -218,6 +219,7 @@ describe('readVersionsMetadata', () => {
|
|||
path: '/docs/next',
|
||||
banner: 'unreleased',
|
||||
badge: true,
|
||||
noIndex: false,
|
||||
className: 'docs-version-current',
|
||||
};
|
||||
|
||||
|
|
@ -242,6 +244,7 @@ describe('readVersionsMetadata', () => {
|
|||
path: '/docs',
|
||||
banner: null,
|
||||
badge: true,
|
||||
noIndex: false,
|
||||
className: 'docs-version-1.0.1',
|
||||
};
|
||||
|
||||
|
|
@ -266,6 +269,7 @@ describe('readVersionsMetadata', () => {
|
|||
path: '/docs/1.0.0',
|
||||
banner: 'unmaintained',
|
||||
badge: true,
|
||||
noIndex: false,
|
||||
className: 'docs-version-1.0.0',
|
||||
};
|
||||
|
||||
|
|
@ -290,6 +294,7 @@ describe('readVersionsMetadata', () => {
|
|||
path: '/docs/withSlugs',
|
||||
banner: 'unmaintained',
|
||||
badge: true,
|
||||
noIndex: false,
|
||||
className: 'docs-version-withSlugs',
|
||||
};
|
||||
|
||||
|
|
@ -657,6 +662,7 @@ describe('readVersionsMetadata', () => {
|
|||
path: '/communityBasePath/next',
|
||||
banner: 'unreleased',
|
||||
badge: true,
|
||||
noIndex: false,
|
||||
className: 'docs-version-current',
|
||||
};
|
||||
|
||||
|
|
@ -681,6 +687,7 @@ describe('readVersionsMetadata', () => {
|
|||
path: '/communityBasePath',
|
||||
banner: null,
|
||||
badge: true,
|
||||
noIndex: false,
|
||||
className: 'docs-version-1.0.0',
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -122,6 +122,13 @@ export function getVersionBadge({
|
|||
return options.versions[versionName]?.badge ?? defaultVersionBadge;
|
||||
}
|
||||
|
||||
export function getVersionNoIndex({
|
||||
versionName,
|
||||
options,
|
||||
}: VersionContext): VersionMetadata['noIndex'] {
|
||||
return options.versions[versionName]?.noIndex ?? false;
|
||||
}
|
||||
|
||||
function getVersionClassName({
|
||||
versionName,
|
||||
options,
|
||||
|
|
@ -179,6 +186,7 @@ async function createVersionMetadata(
|
|||
label: getVersionLabel(context),
|
||||
banner: getVersionBanner(context),
|
||||
badge: getVersionBadge(context),
|
||||
noIndex: getVersionNoIndex(context),
|
||||
className: getVersionClassName(context),
|
||||
path: routePath,
|
||||
tagsPath: normalizeUrl([routePath, options.tagsBasePath]),
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@docusaurus/plugin-content-pages",
|
||||
"version": "2.0.0-rc.1",
|
||||
"version": "2.4.3",
|
||||
"description": "Pages plugin for Docusaurus.",
|
||||
"main": "lib/index.js",
|
||||
"types": "src/plugin-content-pages.d.ts",
|
||||
|
|
@ -18,18 +18,15 @@
|
|||
},
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@docusaurus/core": "2.0.0-rc.1",
|
||||
"@docusaurus/mdx-loader": "2.0.0-rc.1",
|
||||
"@docusaurus/types": "2.0.0-rc.1",
|
||||
"@docusaurus/utils": "2.0.0-rc.1",
|
||||
"@docusaurus/utils-validation": "2.0.0-rc.1",
|
||||
"@docusaurus/core": "2.4.3",
|
||||
"@docusaurus/mdx-loader": "2.4.3",
|
||||
"@docusaurus/types": "2.4.3",
|
||||
"@docusaurus/utils": "2.4.3",
|
||||
"@docusaurus/utils-validation": "2.4.3",
|
||||
"fs-extra": "^10.1.0",
|
||||
"tslib": "^2.4.0",
|
||||
"webpack": "^5.73.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@docusaurus/types": "2.0.0-beta.21"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^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`,
|
||||
);
|
||||
},
|
||||
markdownConfig: siteConfig.markdown,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@docusaurus/plugin-debug",
|
||||
"version": "2.0.0-rc.1",
|
||||
"version": "2.4.3",
|
||||
"description": "Debug plugin for Docusaurus.",
|
||||
"main": "lib/index.js",
|
||||
"types": "src/plugin-debug.d.ts",
|
||||
|
|
@ -20,16 +20,13 @@
|
|||
},
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@docusaurus/core": "2.0.0-rc.1",
|
||||
"@docusaurus/types": "2.0.0-rc.1",
|
||||
"@docusaurus/utils": "2.0.0-rc.1",
|
||||
"@docusaurus/core": "2.4.3",
|
||||
"@docusaurus/types": "2.4.3",
|
||||
"@docusaurus/utils": "2.4.3",
|
||||
"fs-extra": "^10.1.0",
|
||||
"react-json-view": "^1.21.3",
|
||||
"tslib": "^2.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@docusaurus/types": "2.0.0-beta.21"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.4 || ^17.0.0",
|
||||
"react-dom": "^16.8.4 || ^17.0.0"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@docusaurus/plugin-google-analytics",
|
||||
"version": "2.0.0-rc.1",
|
||||
"version": "2.4.3",
|
||||
"description": "Global analytics (analytics.js) plugin for Docusaurus.",
|
||||
"main": "lib/index.js",
|
||||
"types": "lib/index.d.ts",
|
||||
|
|
@ -18,14 +18,11 @@
|
|||
},
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@docusaurus/core": "2.0.0-rc.1",
|
||||
"@docusaurus/types": "2.0.0-rc.1",
|
||||
"@docusaurus/utils-validation": "2.0.0-rc.1",
|
||||
"@docusaurus/core": "2.4.3",
|
||||
"@docusaurus/types": "2.4.3",
|
||||
"@docusaurus/utils-validation": "2.4.3",
|
||||
"tslib": "^2.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@docusaurus/types": "2.0.0-beta.21"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.4 || ^17.0.0",
|
||||
"react-dom": "^16.8.4 || ^17.0.0"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@docusaurus/plugin-google-gtag",
|
||||
"version": "2.0.0-rc.1",
|
||||
"version": "2.4.3",
|
||||
"description": "Global Site Tag (gtag.js) plugin for Docusaurus.",
|
||||
"main": "lib/index.js",
|
||||
"types": "lib/index.d.ts",
|
||||
|
|
@ -18,14 +18,11 @@
|
|||
},
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@docusaurus/core": "2.0.0-rc.1",
|
||||
"@docusaurus/types": "2.0.0-rc.1",
|
||||
"@docusaurus/utils-validation": "2.0.0-rc.1",
|
||||
"@docusaurus/core": "2.4.3",
|
||||
"@docusaurus/types": "2.4.3",
|
||||
"@docusaurus/utils-validation": "2.4.3",
|
||||
"tslib": "^2.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@docusaurus/types": "2.0.0-beta.21"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^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.
|
||||
*/
|
||||
|
||||
import {Joi} from '@docusaurus/utils-validation';
|
||||
import type {
|
||||
LoadContext,
|
||||
Plugin,
|
||||
OptionValidationContext,
|
||||
ThemeConfig,
|
||||
ThemeConfigValidationContext,
|
||||
} from '@docusaurus/types';
|
||||
import type {LoadContext, Plugin} from '@docusaurus/types';
|
||||
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(
|
||||
context: LoadContext,
|
||||
options: PluginOptions,
|
||||
): Plugin {
|
||||
const {anonymizeIP, trackingID} = options;
|
||||
const isProd = process.env.NODE_ENV === 'production';
|
||||
|
||||
const firstTrackingId = options.trackingID[0];
|
||||
|
||||
return {
|
||||
name: 'docusaurus-plugin-google-gtag',
|
||||
|
||||
|
|
@ -60,7 +75,11 @@ export default function pluginGoogleGtag(
|
|||
tagName: 'script',
|
||||
attributes: {
|
||||
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 || [];
|
||||
function gtag(){dataLayer.push(arguments);}
|
||||
gtag('js', new Date());
|
||||
gtag('config', '${trackingID}', { ${
|
||||
anonymizeIP ? "'anonymize_ip': true" : ''
|
||||
} });`,
|
||||
${createConfigSnippets(options)};
|
||||
`,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
|
@ -79,27 +97,6 @@ export default function pluginGoogleGtag(
|
|||
};
|
||||
}
|
||||
|
||||
const pluginOptionsSchema = Joi.object<PluginOptions>({
|
||||
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 {validateThemeConfig, validateOptions} from './options';
|
||||
|
||||
export type {PluginOptions, Options};
|
||||
|
|
|
|||
|
|
@ -4,10 +4,58 @@
|
|||
* 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 {
|
||||
OptionValidationContext,
|
||||
ThemeConfig,
|
||||
ThemeConfigValidationContext,
|
||||
} from '@docusaurus/types';
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
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",
|
||||
"outDir": "lib"
|
||||
},
|
||||
"include": ["src/gtag.ts", "src/options.ts", "src/*.d.ts"],
|
||||
"include": ["src/gtag.ts", "src/*.d.ts"],
|
||||
"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.3",
|
||||
"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.3",
|
||||
"@docusaurus/types": "2.4.3",
|
||||
"@docusaurus/utils-validation": "2.4.3",
|
||||
"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",
|
||||
"version": "2.0.0-rc.1",
|
||||
"version": "2.4.3",
|
||||
"description": "Docusaurus Plugin to generate an almost ideal image (responsive, lazy-loading, and low quality placeholder).",
|
||||
"main": "lib/index.js",
|
||||
"types": "src/plugin-ideal-image.d.ts",
|
||||
|
|
@ -20,12 +20,12 @@
|
|||
},
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@docusaurus/core": "2.0.0-rc.1",
|
||||
"@docusaurus/lqip-loader": "2.0.0-rc.1",
|
||||
"@docusaurus/core": "2.4.3",
|
||||
"@docusaurus/lqip-loader": "2.4.3",
|
||||
"@docusaurus/responsive-loader": "^1.7.0",
|
||||
"@docusaurus/theme-translations": "2.0.0-rc.1",
|
||||
"@docusaurus/types": "2.0.0-rc.1",
|
||||
"@docusaurus/utils-validation": "2.0.0-rc.1",
|
||||
"@docusaurus/theme-translations": "2.4.3",
|
||||
"@docusaurus/types": "2.4.3",
|
||||
"@docusaurus/utils-validation": "2.4.3",
|
||||
"@endiliey/react-ideal-image": "^0.0.11",
|
||||
"react-waypoint": "^10.3.0",
|
||||
"sharp": "^0.30.7",
|
||||
|
|
@ -33,8 +33,7 @@
|
|||
"webpack": "^5.73.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@docusaurus/module-type-aliases": "2.0.0-rc.1",
|
||||
"@docusaurus/types": "2.0.0-beta.21",
|
||||
"@docusaurus/module-type-aliases": "2.4.3",
|
||||
"fs-extra": "^10.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
|
|
|
|||
|
|
@ -81,25 +81,19 @@ function getMessage(icon: IconKey, state: State) {
|
|||
}
|
||||
|
||||
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
|
||||
if (typeof img === 'string' || 'default' in img) {
|
||||
return (
|
||||
<img
|
||||
src={typeof img === 'string' ? img : img.default}
|
||||
className={className}
|
||||
alt={alt}
|
||||
{...props}
|
||||
/>
|
||||
// eslint-disable-next-line jsx-a11y/alt-text
|
||||
<img src={typeof img === 'string' ? img : img.default} {...propsRest} />
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<ReactIdealImage
|
||||
{...props}
|
||||
alt={alt}
|
||||
className={className}
|
||||
{...propsRest}
|
||||
height={img.src.height ?? 100}
|
||||
width={img.src.width ?? 100}
|
||||
placeholder={{lqip: img.preSrc}}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@docusaurus/plugin-pwa",
|
||||
"version": "2.0.0-rc.1",
|
||||
"version": "2.4.3",
|
||||
"description": "Docusaurus Plugin to add PWA support.",
|
||||
"main": "lib/index.js",
|
||||
"types": "src/plugin-pwa.d.ts",
|
||||
|
|
@ -22,12 +22,12 @@
|
|||
"dependencies": {
|
||||
"@babel/core": "^7.18.6",
|
||||
"@babel/preset-env": "^7.18.6",
|
||||
"@docusaurus/core": "2.0.0-rc.1",
|
||||
"@docusaurus/theme-common": "2.0.0-rc.1",
|
||||
"@docusaurus/theme-translations": "2.0.0-rc.1",
|
||||
"@docusaurus/types": "2.0.0-rc.1",
|
||||
"@docusaurus/utils": "2.0.0-rc.1",
|
||||
"@docusaurus/utils-validation": "2.0.0-rc.1",
|
||||
"@docusaurus/core": "2.4.3",
|
||||
"@docusaurus/theme-common": "2.4.3",
|
||||
"@docusaurus/theme-translations": "2.4.3",
|
||||
"@docusaurus/types": "2.4.3",
|
||||
"@docusaurus/utils": "2.4.3",
|
||||
"@docusaurus/utils-validation": "2.4.3",
|
||||
"babel-loader": "^8.2.5",
|
||||
"clsx": "^1.2.1",
|
||||
"core-js": "^3.23.3",
|
||||
|
|
@ -40,7 +40,7 @@
|
|||
"workbox-window": "^6.5.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@docusaurus/module-type-aliases": "2.0.0-rc.1",
|
||||
"@docusaurus/module-type-aliases": "2.4.3",
|
||||
"fs-extra": "^10.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@docusaurus/plugin-sitemap",
|
||||
"version": "2.0.0-rc.1",
|
||||
"version": "2.4.3",
|
||||
"description": "Simple sitemap generation plugin for Docusaurus.",
|
||||
"main": "lib/index.js",
|
||||
"types": "lib/index.d.ts",
|
||||
|
|
@ -18,19 +18,16 @@
|
|||
},
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@docusaurus/core": "2.0.0-rc.1",
|
||||
"@docusaurus/logger": "2.0.0-rc.1",
|
||||
"@docusaurus/types": "2.0.0-rc.1",
|
||||
"@docusaurus/utils": "2.0.0-rc.1",
|
||||
"@docusaurus/utils-common": "2.0.0-rc.1",
|
||||
"@docusaurus/utils-validation": "2.0.0-rc.1",
|
||||
"@docusaurus/core": "2.4.3",
|
||||
"@docusaurus/logger": "2.4.3",
|
||||
"@docusaurus/types": "2.4.3",
|
||||
"@docusaurus/utils": "2.4.3",
|
||||
"@docusaurus/utils-common": "2.4.3",
|
||||
"@docusaurus/utils-validation": "2.4.3",
|
||||
"fs-extra": "^10.1.0",
|
||||
"sitemap": "^7.1.1",
|
||||
"tslib": "^2.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@docusaurus/types": "2.0.0-beta.21"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.4 || ^17.0.0",
|
||||
"react-dom": "^16.8.4 || ^17.0.0"
|
||||
|
|
|
|||
|
|
@ -158,7 +158,10 @@ describe('createSitemap', () => {
|
|||
meta: {
|
||||
// @ts-expect-error: bad lib def
|
||||
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 {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(
|
||||
siteConfig: DocusaurusConfig,
|
||||
routesPaths: string[],
|
||||
|
|
@ -27,18 +61,15 @@ export default async function createSitemap(
|
|||
|
||||
const ignoreMatcher = createMatcher(ignorePatterns);
|
||||
|
||||
const includedRoutes = routesPaths.filter((route) => {
|
||||
if (route.endsWith('404.html') || ignoreMatcher(route)) {
|
||||
return false;
|
||||
}
|
||||
// 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) => tag.props.name === 'robots' && tag.props.content === 'noindex',
|
||||
function isRouteExcluded(route: string) {
|
||||
return (
|
||||
route.endsWith('404.html') ||
|
||||
ignoreMatcher(route) ||
|
||||
isNoIndexMetaRoute({head, route})
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
const includedRoutes = routesPaths.filter((route) => !isRouteExcluded(route));
|
||||
|
||||
if (includedRoutes.length === 0) {
|
||||
return null;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@docusaurus/preset-classic",
|
||||
"version": "2.0.0-rc.1",
|
||||
"version": "2.4.3",
|
||||
"description": "Classic preset for Docusaurus.",
|
||||
"main": "lib/index.js",
|
||||
"types": "lib/index.d.ts",
|
||||
|
|
@ -18,18 +18,19 @@
|
|||
},
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@docusaurus/core": "2.0.0-rc.1",
|
||||
"@docusaurus/plugin-content-blog": "2.0.0-rc.1",
|
||||
"@docusaurus/plugin-content-docs": "2.0.0-rc.1",
|
||||
"@docusaurus/plugin-content-pages": "2.0.0-rc.1",
|
||||
"@docusaurus/plugin-debug": "2.0.0-rc.1",
|
||||
"@docusaurus/plugin-google-analytics": "2.0.0-rc.1",
|
||||
"@docusaurus/plugin-google-gtag": "2.0.0-rc.1",
|
||||
"@docusaurus/plugin-sitemap": "2.0.0-rc.1",
|
||||
"@docusaurus/theme-classic": "2.0.0-rc.1",
|
||||
"@docusaurus/theme-common": "2.0.0-rc.1",
|
||||
"@docusaurus/theme-search-algolia": "2.0.0-rc.1",
|
||||
"@docusaurus/types": "2.0.0-rc.1"
|
||||
"@docusaurus/core": "2.4.3",
|
||||
"@docusaurus/plugin-content-blog": "2.4.3",
|
||||
"@docusaurus/plugin-content-docs": "2.4.3",
|
||||
"@docusaurus/plugin-content-pages": "2.4.3",
|
||||
"@docusaurus/plugin-debug": "2.4.3",
|
||||
"@docusaurus/plugin-google-analytics": "2.4.3",
|
||||
"@docusaurus/plugin-google-gtag": "2.4.3",
|
||||
"@docusaurus/plugin-google-tag-manager": "2.4.3",
|
||||
"@docusaurus/plugin-sitemap": "2.4.3",
|
||||
"@docusaurus/theme-classic": "2.4.3",
|
||||
"@docusaurus/theme-common": "2.4.3",
|
||||
"@docusaurus/theme-search-algolia": "2.4.3",
|
||||
"@docusaurus/types": "2.4.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.4 || ^17.0.0",
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ export default function preset(
|
|||
theme,
|
||||
googleAnalytics,
|
||||
gtag,
|
||||
googleTagManager,
|
||||
...rest
|
||||
} = opts;
|
||||
|
||||
|
|
@ -80,6 +81,14 @@ export default function preset(
|
|||
if (gtag) {
|
||||
plugins.push(makePluginConfig('@docusaurus/plugin-google-gtag', gtag));
|
||||
}
|
||||
if (googleTagManager) {
|
||||
plugins.push(
|
||||
makePluginConfig(
|
||||
'@docusaurus/plugin-google-tag-manager',
|
||||
googleTagManager,
|
||||
),
|
||||
);
|
||||
}
|
||||
if (isProd && sitemap !== false) {
|
||||
plugins.push(makePluginConfig('@docusaurus/plugin-sitemap', sitemap));
|
||||
}
|
||||
|
|
@ -87,7 +96,7 @@ export default function preset(
|
|||
throw new Error(
|
||||
`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 GAPluginOptions} from '@docusaurus/plugin-google-analytics';
|
||||
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 {ThemeConfig as BaseThemeConfig} from '@docusaurus/types';
|
||||
import type {UserThemeConfig as ClassicThemeConfig} from '@docusaurus/theme-common';
|
||||
|
|
@ -42,6 +43,7 @@ export type Options = {
|
|||
* is present.
|
||||
*/
|
||||
gtag?: GtagPluginOptions;
|
||||
googleTagManager?: GTMPluginOptions;
|
||||
};
|
||||
|
||||
export type ThemeConfig = BaseThemeConfig &
|
||||
|
|
|
|||
|
|
@ -63,3 +63,30 @@ module.exports = {
|
|||
| 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. |
|
||||
| `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",
|
||||
"version": "2.0.0-rc.1",
|
||||
"version": "2.4.3",
|
||||
"description": "Remark plugin for converting npm commands to Yarn commands as tabs.",
|
||||
"main": "lib/index.js",
|
||||
"publishConfig": {
|
||||
|
|
@ -17,8 +17,8 @@
|
|||
},
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"npm-to-yarn": "^1.0.1",
|
||||
"tslib": "^2.4.0",
|
||||
"npm-to-yarn": "^2.0.0",
|
||||
"tslib": "^2.4.1",
|
||||
"unist-util-visit": "^2.0.3"
|
||||
},
|
||||
"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