mirror of
https://github.com/facebook/docusaurus.git
synced 2025-06-19 03:02:30 +02:00
Merge branch 'main' into lex111/prism-styles-fouc
This commit is contained in:
commit
15fb0dacde
350 changed files with 1693 additions and 1301 deletions
30
.eslintrc.js
30
.eslintrc.js
|
@ -220,7 +220,35 @@ module.exports = {
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
'import/order': OFF,
|
'import/order': [
|
||||||
|
WARNING,
|
||||||
|
{
|
||||||
|
groups: [
|
||||||
|
'builtin',
|
||||||
|
'external',
|
||||||
|
'internal',
|
||||||
|
['parent', 'sibling', 'index'],
|
||||||
|
'type',
|
||||||
|
],
|
||||||
|
pathGroups: [
|
||||||
|
{pattern: '@jest/globals', group: 'builtin', position: 'before'},
|
||||||
|
{pattern: 'react', group: 'builtin', position: 'before'},
|
||||||
|
{pattern: 'fs-extra', group: 'builtin'},
|
||||||
|
{pattern: 'lodash', group: 'external', position: 'before'},
|
||||||
|
{pattern: 'clsx', group: 'external', position: 'before'},
|
||||||
|
// 'Bit weird to not use the `import/internal-regex` option, but this
|
||||||
|
// way, we can make `import type { Props } from "@theme/*"` appear
|
||||||
|
// before `import styles from "styles.module.css"`, which is what we
|
||||||
|
// always did. This should be removable once we stop using ambient
|
||||||
|
// module declarations for theme aliases.
|
||||||
|
{pattern: '@theme/**', group: 'internal'},
|
||||||
|
{pattern: '@site/**', group: 'internal'},
|
||||||
|
{pattern: '@theme-init/**', group: 'internal'},
|
||||||
|
{pattern: '@theme-original/**', group: 'internal'},
|
||||||
|
],
|
||||||
|
pathGroupsExcludedImportTypes: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
'import/prefer-default-export': OFF,
|
'import/prefer-default-export': OFF,
|
||||||
|
|
||||||
'jest/consistent-test-it': WARNING,
|
'jest/consistent-test-it': WARNING,
|
||||||
|
|
2
.github/dependabot.yml
vendored
2
.github/dependabot.yml
vendored
|
@ -6,4 +6,4 @@ updates:
|
||||||
interval: weekly
|
interval: weekly
|
||||||
open-pull-requests-limit: 99
|
open-pull-requests-limit: 99
|
||||||
labels:
|
labels:
|
||||||
- 'tag: dependencies'
|
- 'pr: dependencies'
|
||||||
|
|
4
.github/workflows/codeql-analysis.yml
vendored
4
.github/workflows/codeql-analysis.yml
vendored
|
@ -34,9 +34,9 @@ jobs:
|
||||||
uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # v3
|
uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # v3
|
||||||
|
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
uses: github/codeql-action/init@7502d6e991ca767d2db617bfd823a1ed925a0d59 # v2
|
uses: github/codeql-action/init@75b4f1c4669133dc294b06c2794e969efa2e5316 # v2
|
||||||
with:
|
with:
|
||||||
languages: ${{ matrix.language }}
|
languages: ${{ matrix.language }}
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
- name: Perform CodeQL Analysis
|
||||||
uses: github/codeql-action/analyze@7502d6e991ca767d2db617bfd823a1ed925a0d59 # v2
|
uses: github/codeql-action/analyze@75b4f1c4669133dc294b06c2794e969efa2e5316 # v2
|
||||||
|
|
5
.husky/pre-commit
vendored
5
.husky/pre-commit
vendored
|
@ -1,4 +1,7 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
. "$(dirname "$0")/_/husky.sh"
|
. "$(dirname "$0")/_/husky.sh"
|
||||||
|
|
||||||
yarn lint-staged --allow-empty
|
# Workaround of a mysterious bug in either lint-staged or husky.
|
||||||
|
# https://github.com/typicode/husky/issues/1134
|
||||||
|
# https://github.com/okonet/lint-staged/issues/693#issuecomment-1079759224
|
||||||
|
FORCE_COLOR=1 yarn lint-staged --allow-empty
|
||||||
|
|
|
@ -5,8 +5,8 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {Globby} from '@docusaurus/utils';
|
|
||||||
import fs from 'fs-extra';
|
import fs from 'fs-extra';
|
||||||
|
import {Globby} from '@docusaurus/utils';
|
||||||
|
|
||||||
type PackageJsonFile = {
|
type PackageJsonFile = {
|
||||||
file: string;
|
file: string;
|
||||||
|
|
|
@ -5,9 +5,8 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type {Handler} from '@netlify/functions';
|
|
||||||
|
|
||||||
import {createPlaygroundResponse} from '../functionUtils/playgroundUtils';
|
import {createPlaygroundResponse} from '../functionUtils/playgroundUtils';
|
||||||
|
import type {Handler} from '@netlify/functions';
|
||||||
|
|
||||||
export const handler: Handler = async function handler() {
|
export const handler: Handler = async function handler() {
|
||||||
return createPlaygroundResponse('codesandbox');
|
return createPlaygroundResponse('codesandbox');
|
||||||
|
|
|
@ -5,13 +5,12 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type {Handler} from '@netlify/functions';
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
readPlaygroundName,
|
readPlaygroundName,
|
||||||
createPlaygroundResponse,
|
createPlaygroundResponse,
|
||||||
createPlaygroundDocumentationResponse,
|
createPlaygroundDocumentationResponse,
|
||||||
} from '../functionUtils/playgroundUtils';
|
} from '../functionUtils/playgroundUtils';
|
||||||
|
import type {Handler} from '@netlify/functions';
|
||||||
|
|
||||||
export const handler: Handler = async (event) => {
|
export const handler: Handler = async (event) => {
|
||||||
const playgroundName = readPlaygroundName(event);
|
const playgroundName = readPlaygroundName(event);
|
||||||
|
|
|
@ -5,9 +5,8 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type {Handler} from '@netlify/functions';
|
|
||||||
|
|
||||||
import {createPlaygroundResponse} from '../functionUtils/playgroundUtils';
|
import {createPlaygroundResponse} from '../functionUtils/playgroundUtils';
|
||||||
|
import type {Handler} from '@netlify/functions';
|
||||||
|
|
||||||
export const handler: Handler = async function handler() {
|
export const handler: Handler = async function handler() {
|
||||||
return createPlaygroundResponse('stackblitz');
|
return createPlaygroundResponse('stackblitz');
|
||||||
|
|
|
@ -70,11 +70,22 @@ This local test step is optional because it will be run by the CI on your releas
|
||||||
|
|
||||||
### 3. Update the v2 changelog
|
### 3. Update the v2 changelog
|
||||||
|
|
||||||
The changelog uses GitHub labels to classify each pull request. Use the GitHub interface to assign each newly merged pull request to a GitHub label starting with `tag:`, otherwise the PR won't appear in the changelog.
|
The changelog uses GitHub labels to classify each pull request. Use the GitHub interface to assign each newly merged pull request to a GitHub label starting with `pr:`, otherwise the PR won't appear in the changelog.
|
||||||
|
|
||||||
[Check tags of all recently merged Pull-Requests](https://github.com/facebook/docusaurus/pulls?q=is%3Apr+sort%3Aupdated-desc+is%3Amerged+)
|
Not all labels will appear in the changelog—some are designed not to. However, you should **always** label each PR, so that before release, we can do a quick scan and confirm no PR is accidentally left out. Here's a search query (pity that GH doesn't have wildcard queries yet):
|
||||||
|
|
||||||
The `tag:` label prefix is for PRs only. Other labels are not used by the changelog tool, and it's not necessary to assign such labels to issues, only PRs.
|
```
|
||||||
|
is:pr is:merged sort:updated-desc -label:"pr: breaking change","pr: new feature","pr: bug fix","pr: performance","pr: polish","pr: documentation","pr: maintenance","pr: internal","pr: dependencies","pr: showcase"
|
||||||
|
```
|
||||||
|
|
||||||
|
[Check tags of all recently merged Pull-Requests](https://github.com/facebook/docusaurus/pulls?q=is%3Apr+is%3Amerged+sort%3Aupdated-desc+-label%3A%22pr%3A+breaking+change%22%2C%22pr%3A+new+feature%22%2C%22pr%3A+bug+fix%22%2C%22pr%3A+performance%22%2C%22pr%3A+polish%22%2C%22pr%3A+documentation%22%2C%22pr%3A+maintenance%22%2C%22pr%3A+internal%22%2C%22pr%3A+dependencies%22%2C%22pr%3A+showcase%22)
|
||||||
|
|
||||||
|
Some general principles about the labeling process:
|
||||||
|
|
||||||
|
- "Will an average user be interested in this entry?" Items like "improve test coverage", "upgrade dependencies" can probably be left out (we have `pr: internal` and `pr: dependencies` for this). However, "pin GitHub actions to an SHA", "add visual testing infrastructure", etc., albeit internal, could be interesting to the user, and can be included in the "maintenance" section.
|
||||||
|
- "Will this change have tangible impact on the user?" A common case is when a PR implements a feature X, then there are immediately follow-up PRs that fix bugs or polish feature X. These follow-up PRs don't necessarily have to be in the changelog, and even if they alter the API, they are not breaking changes, because to an average user bumping their version, they will only see the new feature X as a whole. Make the entries atomic.
|
||||||
|
|
||||||
|
The `pr:` label prefix is for PRs only. Other labels are not used by the changelog tool, and it's not necessary to assign such labels to issues, only PRs.
|
||||||
|
|
||||||
Generate a GitHub auth token by going to https://github.com/settings/tokens (the only permission needed is `public_repo`). Save the token somewhere for future reference.
|
Generate a GitHub auth token by going to https://github.com/settings/tokens (the only permission needed is `public_repo`). Save the token somewhere for future reference.
|
||||||
|
|
||||||
|
|
|
@ -5,12 +5,12 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import sharp from 'sharp';
|
|
||||||
import fs from 'fs-extra';
|
import fs from 'fs-extra';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import imageSize from 'image-size';
|
|
||||||
import {fileURLToPath} from 'url';
|
import {fileURLToPath} from 'url';
|
||||||
import logger from '@docusaurus/logger';
|
import logger from '@docusaurus/logger';
|
||||||
|
import sharp from 'sharp';
|
||||||
|
import imageSize from 'image-size';
|
||||||
|
|
||||||
const allImages = (
|
const allImages = (
|
||||||
await fs.readdir(new URL('../../website/src/data/showcase', import.meta.url))
|
await fs.readdir(new URL('../../website/src/data/showcase', import.meta.url))
|
||||||
|
|
8
jest/snapshotPathNormalizer.ts
vendored
8
jest/snapshotPathNormalizer.ts
vendored
|
@ -8,13 +8,13 @@
|
||||||
// Forked from https://github.com/tribou/jest-serializer-path/blob/master/lib/index.js
|
// Forked from https://github.com/tribou/jest-serializer-path/blob/master/lib/index.js
|
||||||
// Added some project-specific handlers
|
// Added some project-specific handlers
|
||||||
|
|
||||||
import _ from 'lodash';
|
|
||||||
import {escapePath} from '@docusaurus/utils';
|
|
||||||
import stripAnsi from 'strip-ansi';
|
|
||||||
import {version} from '@docusaurus/core/package.json';
|
|
||||||
import os from 'os';
|
import os from 'os';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
|
import _ from 'lodash';
|
||||||
|
import {escapePath} from '@docusaurus/utils';
|
||||||
|
import {version} from '@docusaurus/core/package.json';
|
||||||
|
import stripAnsi from 'strip-ansi';
|
||||||
|
|
||||||
export function print(
|
export function print(
|
||||||
val: unknown,
|
val: unknown,
|
||||||
|
|
14
lerna.json
14
lerna.json
|
@ -5,13 +5,13 @@
|
||||||
"changelog": {
|
"changelog": {
|
||||||
"repo": "facebook/docusaurus",
|
"repo": "facebook/docusaurus",
|
||||||
"labels": {
|
"labels": {
|
||||||
"tag: new feature": ":rocket: New Feature",
|
"pr: breaking change": ":boom: Breaking Change",
|
||||||
"tag: breaking change": ":boom: Breaking Change",
|
"pr: new feature": ":rocket: New Feature",
|
||||||
"tag: bug fix": ":bug: Bug Fix",
|
"pr: bug fix": ":bug: Bug Fix",
|
||||||
"tag: polish": ":nail_care: Polish",
|
"pr: performance": ":running_woman: Performance",
|
||||||
"tag: documentation": ":memo: Documentation",
|
"pr: polish": ":nail_care: Polish",
|
||||||
"tag: maintenance": ":wrench: Maintenance",
|
"pr: documentation": ":memo: Documentation",
|
||||||
"tag: performance": ":running_woman: Performance"
|
"pr: maintenance": ":wrench: Maintenance"
|
||||||
},
|
},
|
||||||
"cacheDir": ".changelog"
|
"cacheDir": ".changelog"
|
||||||
}
|
}
|
||||||
|
|
10
package.json
10
package.json
|
@ -63,8 +63,8 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@crowdin/cli": "^3.7.8",
|
"@crowdin/cli": "^3.7.8",
|
||||||
"@swc/core": "^1.2.178",
|
"@swc/core": "^1.2.181",
|
||||||
"@swc/jest": "^0.2.20",
|
"@swc/jest": "^0.2.21",
|
||||||
"@testing-library/react-hooks": "^8.0.0",
|
"@testing-library/react-hooks": "^8.0.0",
|
||||||
"@types/fs-extra": "^9.0.13",
|
"@types/fs-extra": "^9.0.13",
|
||||||
"@types/jest": "^27.5.0",
|
"@types/jest": "^27.5.0",
|
||||||
|
@ -76,8 +76,8 @@
|
||||||
"@types/react-test-renderer": "^18.0.0",
|
"@types/react-test-renderer": "^18.0.0",
|
||||||
"@types/semver": "^7.3.9",
|
"@types/semver": "^7.3.9",
|
||||||
"@types/shelljs": "^0.8.11",
|
"@types/shelljs": "^0.8.11",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.22.0",
|
"@typescript-eslint/eslint-plugin": "^5.23.0",
|
||||||
"@typescript-eslint/parser": "^5.22.0",
|
"@typescript-eslint/parser": "^5.23.0",
|
||||||
"concurrently": "^7.1.0",
|
"concurrently": "^7.1.0",
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
"cspell": "^5.20.0",
|
"cspell": "^5.20.0",
|
||||||
|
@ -91,7 +91,7 @@
|
||||||
"eslint-plugin-react": "^7.29.4",
|
"eslint-plugin-react": "^7.29.4",
|
||||||
"eslint-plugin-react-hooks": "^4.5.0",
|
"eslint-plugin-react-hooks": "^4.5.0",
|
||||||
"eslint-plugin-regexp": "^1.7.0",
|
"eslint-plugin-regexp": "^1.7.0",
|
||||||
"husky": "^7.0.4",
|
"husky": "^8.0.1",
|
||||||
"image-size": "^1.0.1",
|
"image-size": "^1.0.1",
|
||||||
"jest": "^28.1.0",
|
"jest": "^28.1.0",
|
||||||
"jest-environment-jsdom": "^28.1.0",
|
"jest-environment-jsdom": "^28.1.0",
|
||||||
|
|
|
@ -8,11 +8,11 @@
|
||||||
|
|
||||||
// @ts-check
|
// @ts-check
|
||||||
|
|
||||||
|
import path from 'path';
|
||||||
|
import {createRequire} from 'module';
|
||||||
import logger from '@docusaurus/logger';
|
import logger from '@docusaurus/logger';
|
||||||
import semver from 'semver';
|
import semver from 'semver';
|
||||||
import path from 'path';
|
|
||||||
import {program} from 'commander';
|
import {program} from 'commander';
|
||||||
import {createRequire} from 'module';
|
|
||||||
|
|
||||||
const packageJson = createRequire(import.meta.url)('../package.json');
|
const packageJson = createRequire(import.meta.url)('../package.json');
|
||||||
const requiredVersion = packageJson.engines.node;
|
const requiredVersion = packageJson.engines.node;
|
||||||
|
|
|
@ -5,39 +5,41 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import logger from '@docusaurus/logger';
|
|
||||||
import fs from 'fs-extra';
|
import fs from 'fs-extra';
|
||||||
import prompts, {type Choice} from 'prompts';
|
|
||||||
import path from 'path';
|
|
||||||
import shell from 'shelljs';
|
|
||||||
import _ from 'lodash';
|
|
||||||
import supportsColor from 'supports-color';
|
|
||||||
import {fileURLToPath} from 'url';
|
import {fileURLToPath} from 'url';
|
||||||
|
import path from 'path';
|
||||||
|
import _ from 'lodash';
|
||||||
|
import logger from '@docusaurus/logger';
|
||||||
|
import shell from 'shelljs';
|
||||||
|
import prompts, {type Choice} from 'prompts';
|
||||||
|
import supportsColor from 'supports-color';
|
||||||
|
|
||||||
const RecommendedTemplate = 'classic';
|
type CLIOptions = {
|
||||||
const TypeScriptTemplateSuffix = '-typescript';
|
packageManager?: PackageManager;
|
||||||
|
skipInstall?: boolean;
|
||||||
|
typescript?: boolean;
|
||||||
|
gitStrategy?: GitStrategy;
|
||||||
|
};
|
||||||
|
|
||||||
// Only used in the rare, rare case of running globally installed create +
|
// Only used in the rare, rare case of running globally installed create +
|
||||||
// using --skip-install. We need a default name to show the tip text
|
// using --skip-install. We need a default name to show the tip text
|
||||||
const DefaultPackageManager = 'npm';
|
const defaultPackageManager = 'npm';
|
||||||
|
|
||||||
const SupportedPackageManagers = {
|
const lockfileNames = {
|
||||||
npm: 'package-lock.json',
|
npm: 'package-lock.json',
|
||||||
yarn: 'yarn.lock',
|
yarn: 'yarn.lock',
|
||||||
pnpm: 'pnpm-lock.yaml',
|
pnpm: 'pnpm-lock.yaml',
|
||||||
};
|
};
|
||||||
|
|
||||||
type SupportedPackageManager = keyof typeof SupportedPackageManagers;
|
type PackageManager = keyof typeof lockfileNames;
|
||||||
|
|
||||||
const PackageManagersList = Object.keys(
|
const packageManagers = Object.keys(lockfileNames) as PackageManager[];
|
||||||
SupportedPackageManagers,
|
|
||||||
) as SupportedPackageManager[];
|
|
||||||
|
|
||||||
async function findPackageManagerFromLockFile(): Promise<
|
async function findPackageManagerFromLockFile(
|
||||||
SupportedPackageManager | undefined
|
rootDir: string,
|
||||||
> {
|
): Promise<PackageManager | undefined> {
|
||||||
for (const packageManager of PackageManagersList) {
|
for (const packageManager of packageManagers) {
|
||||||
const lockFilePath = path.resolve(SupportedPackageManagers[packageManager]);
|
const lockFilePath = path.join(rootDir, lockfileNames[packageManager]);
|
||||||
if (await fs.pathExists(lockFilePath)) {
|
if (await fs.pathExists(lockFilePath)) {
|
||||||
return packageManager;
|
return packageManager;
|
||||||
}
|
}
|
||||||
|
@ -45,15 +47,13 @@ async function findPackageManagerFromLockFile(): Promise<
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
function findPackageManagerFromUserAgent():
|
function findPackageManagerFromUserAgent(): PackageManager | undefined {
|
||||||
| SupportedPackageManager
|
return packageManagers.find((packageManager) =>
|
||||||
| undefined {
|
|
||||||
return PackageManagersList.find((packageManager) =>
|
|
||||||
process.env.npm_config_user_agent?.startsWith(packageManager),
|
process.env.npm_config_user_agent?.startsWith(packageManager),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function askForPackageManagerChoice(): Promise<SupportedPackageManager> {
|
async function askForPackageManagerChoice(): Promise<PackageManager> {
|
||||||
const hasYarn = shell.exec('yarn --version', {silent: true}).code === 0;
|
const hasYarn = shell.exec('yarn --version', {silent: true}).code === 0;
|
||||||
const hasPnpm = shell.exec('pnpm --version', {silent: true}).code === 0;
|
const hasPnpm = shell.exec('pnpm --version', {silent: true}).code === 0;
|
||||||
|
|
||||||
|
@ -65,67 +65,121 @@ async function askForPackageManagerChoice(): Promise<SupportedPackageManager> {
|
||||||
.map((p) => ({title: p, value: p}));
|
.map((p) => ({title: p, value: p}));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
await prompts({
|
await prompts(
|
||||||
type: 'select',
|
{
|
||||||
name: 'packageManager',
|
type: 'select',
|
||||||
message: 'Select a package manager...',
|
name: 'packageManager',
|
||||||
choices,
|
message: 'Select a package manager...',
|
||||||
})
|
choices,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
onCancel() {
|
||||||
|
logger.info`Falling back to name=${defaultPackageManager}`;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
).packageManager;
|
).packageManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getPackageManager(
|
async function getPackageManager(
|
||||||
packageManagerChoice: SupportedPackageManager | undefined,
|
dest: string,
|
||||||
skipInstall: boolean = false,
|
{packageManager, skipInstall}: CLIOptions,
|
||||||
): Promise<SupportedPackageManager> {
|
): Promise<PackageManager> {
|
||||||
if (
|
if (packageManager && !packageManagers.includes(packageManager)) {
|
||||||
packageManagerChoice &&
|
|
||||||
!PackageManagersList.includes(packageManagerChoice)
|
|
||||||
) {
|
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Invalid package manager choice ${packageManagerChoice}. Must be one of ${PackageManagersList.join(
|
`Invalid package manager choice ${packageManager}. Must be one of ${packageManagers.join(
|
||||||
', ',
|
', ',
|
||||||
)}`,
|
)}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
packageManagerChoice ??
|
// If dest already contains a lockfile (e.g. if using a local template), we
|
||||||
(await findPackageManagerFromLockFile()) ??
|
// always use that instead
|
||||||
|
(await findPackageManagerFromLockFile(dest)) ??
|
||||||
|
packageManager ??
|
||||||
|
(await findPackageManagerFromLockFile('.')) ??
|
||||||
findPackageManagerFromUserAgent() ??
|
findPackageManagerFromUserAgent() ??
|
||||||
// This only happens if the user has a global installation in PATH
|
// This only happens if the user has a global installation in PATH
|
||||||
(skipInstall ? DefaultPackageManager : askForPackageManagerChoice())
|
(skipInstall ? defaultPackageManager : askForPackageManagerChoice()) ??
|
||||||
|
defaultPackageManager
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function isValidGitRepoUrl(gitRepoUrl: string) {
|
const recommendedTemplate = 'classic';
|
||||||
return ['https://', 'git@'].some((item) => gitRepoUrl.startsWith(item));
|
const typeScriptTemplateSuffix = '-typescript';
|
||||||
}
|
const templatesDir = fileURLToPath(new URL('../templates', import.meta.url));
|
||||||
|
|
||||||
async function updatePkg(pkgPath: string, obj: {[key: string]: unknown}) {
|
type Template = {
|
||||||
const pkg = await fs.readJSON(pkgPath);
|
name: string;
|
||||||
const newPkg = Object.assign(pkg, obj);
|
path: string;
|
||||||
|
tsVariantPath: string | undefined;
|
||||||
|
};
|
||||||
|
|
||||||
await fs.outputFile(pkgPath, `${JSON.stringify(newPkg, null, 2)}\n`);
|
async function readTemplates(): Promise<Template[]> {
|
||||||
}
|
const dirContents = await fs.readdir(templatesDir);
|
||||||
|
const templates = await Promise.all(
|
||||||
async function readTemplates(templatesDir: string) {
|
dirContents
|
||||||
const templates = (await fs.readdir(templatesDir)).filter(
|
.filter(
|
||||||
(d) =>
|
(d) =>
|
||||||
!d.startsWith('.') &&
|
!d.startsWith('.') &&
|
||||||
!d.startsWith('README') &&
|
!d.startsWith('README') &&
|
||||||
!d.endsWith(TypeScriptTemplateSuffix) &&
|
!d.endsWith(typeScriptTemplateSuffix) &&
|
||||||
d !== 'shared',
|
d !== 'shared',
|
||||||
|
)
|
||||||
|
.map(async (name) => {
|
||||||
|
const tsVariantPath = path.join(
|
||||||
|
templatesDir,
|
||||||
|
`${name}${typeScriptTemplateSuffix}`,
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
name,
|
||||||
|
path: path.join(templatesDir, name),
|
||||||
|
tsVariantPath: (await fs.pathExists(tsVariantPath))
|
||||||
|
? tsVariantPath
|
||||||
|
: undefined,
|
||||||
|
};
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Classic should be first in list!
|
// Classic should be first in list!
|
||||||
return _.sortBy(templates, (t) => t !== RecommendedTemplate);
|
return _.sortBy(templates, (t) => t.name !== recommendedTemplate);
|
||||||
}
|
}
|
||||||
|
|
||||||
function createTemplateChoices(templates: string[]) {
|
async function copyTemplate(
|
||||||
function makeNameAndValueChoice(value: string): Choice {
|
template: Template,
|
||||||
|
dest: string,
|
||||||
|
typescript: boolean,
|
||||||
|
): Promise<void> {
|
||||||
|
await fs.copy(path.join(templatesDir, 'shared'), dest);
|
||||||
|
|
||||||
|
// TypeScript variants will copy duplicate resources like CSS & config from
|
||||||
|
// base template
|
||||||
|
if (typescript) {
|
||||||
|
await fs.copy(template.path, dest, {
|
||||||
|
filter: async (filePath) =>
|
||||||
|
(await fs.stat(filePath)).isDirectory() ||
|
||||||
|
path.extname(filePath) === '.css' ||
|
||||||
|
path.basename(filePath) === 'docusaurus.config.js',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
await fs.copy(typescript ? template.tsVariantPath! : template.path, dest, {
|
||||||
|
// Symlinks don't exist in published npm packages anymore, so this is only
|
||||||
|
// to prevent errors during local testing
|
||||||
|
filter: async (filePath) => !(await fs.lstat(filePath)).isSymbolicLink(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function createTemplateChoices(templates: Template[]): Choice[] {
|
||||||
|
function makeNameAndValueChoice(value: string | Template): Choice {
|
||||||
|
if (typeof value === 'string') {
|
||||||
|
return {title: value, value};
|
||||||
|
}
|
||||||
const title =
|
const title =
|
||||||
value === RecommendedTemplate ? `${value} (recommended)` : value;
|
value.name === recommendedTemplate
|
||||||
|
? `${value.name} (recommended)`
|
||||||
|
: value.name;
|
||||||
return {title, value};
|
return {title, value};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,55 +190,33 @@ function createTemplateChoices(templates: string[]) {
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTypeScriptBaseTemplate(template: string): string | undefined {
|
function isValidGitRepoUrl(gitRepoUrl: string): boolean {
|
||||||
if (template.endsWith(TypeScriptTemplateSuffix)) {
|
return ['https://', 'git@'].some((item) => gitRepoUrl.startsWith(item));
|
||||||
return template.replace(TypeScriptTemplateSuffix, '');
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function copyTemplate(
|
|
||||||
templatesDir: string,
|
|
||||||
template: string,
|
|
||||||
dest: string,
|
|
||||||
) {
|
|
||||||
await fs.copy(path.join(templatesDir, 'shared'), dest);
|
|
||||||
|
|
||||||
// TypeScript variants will copy duplicate resources like CSS & config from
|
|
||||||
// base template
|
|
||||||
const tsBaseTemplate = getTypeScriptBaseTemplate(template);
|
|
||||||
if (tsBaseTemplate) {
|
|
||||||
const tsBaseTemplatePath = path.resolve(templatesDir, tsBaseTemplate);
|
|
||||||
await fs.copy(tsBaseTemplatePath, dest, {
|
|
||||||
filter: async (filePath) =>
|
|
||||||
(await fs.stat(filePath)).isDirectory() ||
|
|
||||||
path.extname(filePath) === '.css' ||
|
|
||||||
path.basename(filePath) === 'docusaurus.config.js',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
await fs.copy(path.resolve(templatesDir, template), dest, {
|
|
||||||
// Symlinks don't exist in published npm packages anymore, so this is only
|
|
||||||
// to prevent errors during local testing
|
|
||||||
filter: async (filePath) => !(await fs.lstat(filePath)).isSymbolicLink(),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const gitStrategies = ['deep', 'shallow', 'copy', 'custom'] as const;
|
const gitStrategies = ['deep', 'shallow', 'copy', 'custom'] as const;
|
||||||
|
type GitStrategy = typeof gitStrategies[number];
|
||||||
|
|
||||||
async function getGitCommand(gitStrategy: typeof gitStrategies[number]) {
|
async function getGitCommand(gitStrategy: GitStrategy): Promise<string> {
|
||||||
switch (gitStrategy) {
|
switch (gitStrategy) {
|
||||||
case 'shallow':
|
case 'shallow':
|
||||||
case 'copy':
|
case 'copy':
|
||||||
return 'git clone --recursive --depth 1';
|
return 'git clone --recursive --depth 1';
|
||||||
case 'custom': {
|
case 'custom': {
|
||||||
const {command} = await prompts({
|
const {command} = await prompts(
|
||||||
type: 'text',
|
{
|
||||||
name: 'command',
|
type: 'text',
|
||||||
message:
|
name: 'command',
|
||||||
'Write your own git clone command. The repository URL and destination directory will be supplied. E.g. "git clone --depth 10"',
|
message:
|
||||||
});
|
'Write your own git clone command. The repository URL and destination directory will be supplied. E.g. "git clone --depth 10"',
|
||||||
return command;
|
},
|
||||||
|
{
|
||||||
|
onCancel() {
|
||||||
|
logger.info`Falling back to code=${'git clone'}`;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
return command ?? 'git clone';
|
||||||
}
|
}
|
||||||
case 'deep':
|
case 'deep':
|
||||||
default:
|
default:
|
||||||
|
@ -192,178 +224,273 @@ async function getGitCommand(gitStrategy: typeof gitStrategies[number]) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async function init(
|
async function getSiteName(
|
||||||
|
reqName: string | undefined,
|
||||||
rootDir: string,
|
rootDir: string,
|
||||||
siteName?: string,
|
): Promise<string> {
|
||||||
reqTemplate?: string,
|
async function validateSiteName(siteName: string) {
|
||||||
cliOptions: Partial<{
|
if (!siteName) {
|
||||||
packageManager: SupportedPackageManager;
|
return 'A website name is required.';
|
||||||
skipInstall: boolean;
|
}
|
||||||
typescript: boolean;
|
const dest = path.resolve(rootDir, siteName);
|
||||||
gitStrategy: typeof gitStrategies[number];
|
if (await fs.pathExists(dest)) {
|
||||||
}> = {},
|
return logger.interpolate`Directory already exists at path=${dest}!`;
|
||||||
): Promise<void> {
|
}
|
||||||
const templatesDir = fileURLToPath(new URL('../templates', import.meta.url));
|
return true;
|
||||||
const templates = await readTemplates(templatesDir);
|
}
|
||||||
const hasTS = (templateName: string) =>
|
if (reqName) {
|
||||||
fs.pathExists(
|
const res = validateSiteName(reqName);
|
||||||
path.join(templatesDir, `${templateName}${TypeScriptTemplateSuffix}`),
|
if (typeof res === 'string') {
|
||||||
);
|
throw new Error(res);
|
||||||
let name = siteName;
|
}
|
||||||
|
return reqName;
|
||||||
// Prompt if siteName is not passed from CLI.
|
}
|
||||||
if (!name) {
|
const {siteName} = await prompts(
|
||||||
const prompt = await prompts({
|
{
|
||||||
type: 'text',
|
type: 'text',
|
||||||
name: 'name',
|
name: 'siteName',
|
||||||
message: 'What should we name this site?',
|
message: 'What should we name this site?',
|
||||||
initial: 'website',
|
initial: 'website',
|
||||||
});
|
validate: validateSiteName,
|
||||||
name = prompt.name;
|
},
|
||||||
}
|
{
|
||||||
|
onCancel() {
|
||||||
if (!name) {
|
logger.error('A website name is required.');
|
||||||
logger.error('A website name is required.');
|
process.exit(1);
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
const dest = path.resolve(rootDir, name);
|
|
||||||
if (await fs.pathExists(dest)) {
|
|
||||||
logger.error`Directory already exists at path=${dest}!`;
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
let template = reqTemplate;
|
|
||||||
let useTS = cliOptions.typescript;
|
|
||||||
// Prompt if template is not provided from CLI.
|
|
||||||
if (!template) {
|
|
||||||
const templatePrompt = await prompts({
|
|
||||||
type: 'select',
|
|
||||||
name: 'template',
|
|
||||||
message: 'Select a template below...',
|
|
||||||
choices: createTemplateChoices(templates),
|
|
||||||
});
|
|
||||||
template = templatePrompt.template;
|
|
||||||
if (template && !useTS && (await hasTS(template))) {
|
|
||||||
const tsPrompt = await prompts({
|
|
||||||
type: 'confirm',
|
|
||||||
name: 'useTS',
|
|
||||||
message:
|
|
||||||
'This template is available in TypeScript. Do you want to use the TS variant?',
|
|
||||||
initial: false,
|
|
||||||
});
|
|
||||||
useTS = tsPrompt.useTS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let gitStrategy = cliOptions.gitStrategy ?? 'deep';
|
|
||||||
|
|
||||||
// If user choose Git repository, we'll prompt for the url.
|
|
||||||
if (template === 'Git repository') {
|
|
||||||
const repoPrompt = await prompts({
|
|
||||||
type: 'text',
|
|
||||||
name: 'gitRepoUrl',
|
|
||||||
validate: (url?: string) => {
|
|
||||||
if (url && isValidGitRepoUrl(url)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return logger.red('Invalid repository URL');
|
|
||||||
},
|
},
|
||||||
message: logger.interpolate`Enter a repository URL from GitHub, Bitbucket, GitLab, or any other public repo.
|
},
|
||||||
(e.g: url=${'https://github.com/ownerName/repoName.git'})`,
|
);
|
||||||
});
|
return siteName;
|
||||||
({gitStrategy} = await prompts({
|
}
|
||||||
type: 'select',
|
|
||||||
name: 'gitStrategy',
|
type Source =
|
||||||
message: 'How should we clone this repo?',
|
| {
|
||||||
choices: [
|
type: 'template';
|
||||||
{title: 'Deep clone: preserve full history', value: 'deep'},
|
template: Template;
|
||||||
{title: 'Shallow clone: clone with --depth=1', value: 'shallow'},
|
typescript: boolean;
|
||||||
{
|
}
|
||||||
title: 'Copy: do a shallow clone, but do not create a git repo',
|
| {
|
||||||
value: 'copy',
|
type: 'git';
|
||||||
},
|
url: string;
|
||||||
{title: 'Custom: enter your custom git clone command', value: 'custom'},
|
strategy: GitStrategy;
|
||||||
],
|
}
|
||||||
}));
|
| {
|
||||||
template = repoPrompt.gitRepoUrl;
|
type: 'local';
|
||||||
} else if (template === 'Local template') {
|
path: string;
|
||||||
const dirPrompt = await prompts({
|
};
|
||||||
type: 'text',
|
|
||||||
name: 'templateDir',
|
async function getSource(
|
||||||
validate: async (dir?: string) => {
|
reqTemplate: string | undefined,
|
||||||
if (dir) {
|
templates: Template[],
|
||||||
const fullDir = path.resolve(dir);
|
cliOptions: CLIOptions,
|
||||||
if (await fs.pathExists(fullDir)) {
|
): Promise<Source> {
|
||||||
|
if (reqTemplate) {
|
||||||
|
if (isValidGitRepoUrl(reqTemplate)) {
|
||||||
|
if (
|
||||||
|
cliOptions.gitStrategy &&
|
||||||
|
!gitStrategies.includes(cliOptions.gitStrategy)
|
||||||
|
) {
|
||||||
|
logger.error`Invalid git strategy: name=${
|
||||||
|
cliOptions.gitStrategy
|
||||||
|
}. Value must be one of ${gitStrategies.join(', ')}.`;
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
type: 'git',
|
||||||
|
url: reqTemplate,
|
||||||
|
strategy: cliOptions.gitStrategy ?? 'deep',
|
||||||
|
};
|
||||||
|
} else if (await fs.pathExists(path.resolve(reqTemplate))) {
|
||||||
|
return {
|
||||||
|
type: 'local',
|
||||||
|
path: path.resolve(reqTemplate),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const template = templates.find((t) => t.name === reqTemplate);
|
||||||
|
if (!template) {
|
||||||
|
logger.error('Invalid template.');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
if (cliOptions.typescript && !template.tsVariantPath) {
|
||||||
|
logger.error`Template name=${reqTemplate} doesn't provide the TypeScript variant.`;
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
type: 'template',
|
||||||
|
template,
|
||||||
|
typescript: cliOptions.typescript ?? false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const template = cliOptions.gitStrategy
|
||||||
|
? 'Git repository'
|
||||||
|
: (
|
||||||
|
await prompts(
|
||||||
|
{
|
||||||
|
type: 'select',
|
||||||
|
name: 'template',
|
||||||
|
message: 'Select a template below...',
|
||||||
|
choices: createTemplateChoices(templates),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
onCancel() {
|
||||||
|
logger.error('A choice is required.');
|
||||||
|
process.exit(1);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
).template;
|
||||||
|
if (template === 'Git repository') {
|
||||||
|
const {gitRepoUrl} = await prompts(
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
name: 'gitRepoUrl',
|
||||||
|
validate: (url?: string) => {
|
||||||
|
if (url && isValidGitRepoUrl(url)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return logger.red(
|
return logger.red('Invalid repository URL');
|
||||||
logger.interpolate`path=${fullDir} does not exist.`,
|
},
|
||||||
);
|
message: logger.interpolate`Enter a repository URL from GitHub, Bitbucket, GitLab, or any other public repo.
|
||||||
}
|
(e.g: url=${'https://github.com/ownerName/repoName.git'})`,
|
||||||
return logger.red('Please enter a valid path.');
|
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
onCancel() {
|
||||||
|
logger.error('A git repo URL is required.');
|
||||||
|
process.exit(1);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
let strategy = cliOptions.gitStrategy;
|
||||||
|
if (!strategy) {
|
||||||
|
({strategy} = await prompts(
|
||||||
|
{
|
||||||
|
type: 'select',
|
||||||
|
name: 'strategy',
|
||||||
|
message: 'How should we clone this repo?',
|
||||||
|
choices: [
|
||||||
|
{title: 'Deep clone: preserve full history', value: 'deep'},
|
||||||
|
{title: 'Shallow clone: clone with --depth=1', value: 'shallow'},
|
||||||
|
{
|
||||||
|
title: 'Copy: do a shallow clone, but do not create a git repo',
|
||||||
|
value: 'copy',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Custom: enter your custom git clone command',
|
||||||
|
value: 'custom',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
onCancel() {
|
||||||
|
logger.info`Falling back to name=${'deep'}`;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
));
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
type: 'git',
|
||||||
|
url: gitRepoUrl,
|
||||||
|
strategy: strategy ?? 'deep',
|
||||||
|
};
|
||||||
|
} else if (template === 'Local template') {
|
||||||
|
const {templateDir} = await prompts(
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
name: 'templateDir',
|
||||||
|
validate: async (dir?: string) => {
|
||||||
|
if (dir) {
|
||||||
|
const fullDir = path.resolve(dir);
|
||||||
|
if (await fs.pathExists(fullDir)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return logger.red(
|
||||||
|
logger.interpolate`path=${fullDir} does not exist.`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return logger.red('Please enter a valid path.');
|
||||||
|
},
|
||||||
|
message:
|
||||||
|
'Enter a local folder path, relative to the current working directory.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
onCancel() {
|
||||||
|
logger.error('A file path is required.');
|
||||||
|
process.exit(1);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
type: 'local',
|
||||||
|
path: templateDir,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
let useTS = cliOptions.typescript;
|
||||||
|
if (!useTS && template.tsVariantPath) {
|
||||||
|
({useTS} = await prompts({
|
||||||
|
type: 'confirm',
|
||||||
|
name: 'useTS',
|
||||||
message:
|
message:
|
||||||
'Enter a local folder path, relative to the current working directory.',
|
'This template is available in TypeScript. Do you want to use the TS variant?',
|
||||||
});
|
initial: false,
|
||||||
template = dirPrompt.templateDir;
|
}));
|
||||||
}
|
}
|
||||||
|
return {
|
||||||
|
type: 'template',
|
||||||
|
template,
|
||||||
|
typescript: useTS ?? false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if (!template) {
|
async function updatePkg(pkgPath: string, obj: {[key: string]: unknown}) {
|
||||||
logger.error('Template should not be empty');
|
const pkg = await fs.readJSON(pkgPath);
|
||||||
process.exit(1);
|
const newPkg = Object.assign(pkg, obj);
|
||||||
}
|
|
||||||
|
await fs.outputFile(pkgPath, `${JSON.stringify(newPkg, null, 2)}\n`);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default async function init(
|
||||||
|
rootDir: string,
|
||||||
|
reqName?: string,
|
||||||
|
reqTemplate?: string,
|
||||||
|
cliOptions: CLIOptions = {},
|
||||||
|
): Promise<void> {
|
||||||
|
const templates = await readTemplates();
|
||||||
|
const siteName = await getSiteName(reqName, rootDir);
|
||||||
|
const dest = path.resolve(rootDir, siteName);
|
||||||
|
const source = await getSource(reqTemplate, templates, cliOptions);
|
||||||
|
|
||||||
logger.info('Creating new Docusaurus project...');
|
logger.info('Creating new Docusaurus project...');
|
||||||
|
|
||||||
if (isValidGitRepoUrl(template)) {
|
if (source.type === 'git') {
|
||||||
logger.info`Cloning Git template url=${template}...`;
|
logger.info`Cloning Git template url=${source.url}...`;
|
||||||
if (!gitStrategies.includes(gitStrategy)) {
|
const command = await getGitCommand(source.strategy);
|
||||||
logger.error`Invalid git strategy: name=${gitStrategy}. Value must be one of ${gitStrategies.join(
|
if (shell.exec(`${command} ${source.url} ${dest}`).code !== 0) {
|
||||||
', ',
|
logger.error`Cloning Git template failed!`;
|
||||||
)}.`;
|
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
const command = await getGitCommand(gitStrategy);
|
if (source.strategy === 'copy') {
|
||||||
if (shell.exec(`${command} ${template} ${dest}`).code !== 0) {
|
|
||||||
logger.error`Cloning Git template name=${template} failed!`;
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
if (gitStrategy === 'copy') {
|
|
||||||
await fs.remove(path.join(dest, '.git'));
|
await fs.remove(path.join(dest, '.git'));
|
||||||
}
|
}
|
||||||
} else if (templates.includes(template)) {
|
} else if (source.type === 'template') {
|
||||||
// Docusaurus templates.
|
|
||||||
if (useTS) {
|
|
||||||
if (!(await hasTS(template))) {
|
|
||||||
logger.error`Template name=${template} doesn't provide the TypeScript variant.`;
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
template = `${template}${TypeScriptTemplateSuffix}`;
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
await copyTemplate(templatesDir, template, dest);
|
await copyTemplate(source.template, dest, source.typescript);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logger.error`Copying Docusaurus template name=${template} failed!`;
|
logger.error`Copying Docusaurus template name=${source.template.name} failed!`;
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
} else if (await fs.pathExists(path.resolve(template))) {
|
|
||||||
const templateDir = path.resolve(template);
|
|
||||||
try {
|
|
||||||
await fs.copy(templateDir, dest);
|
|
||||||
} catch (err) {
|
|
||||||
logger.error`Copying local template path=${templateDir} failed!`;
|
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
logger.error('Invalid template.');
|
try {
|
||||||
process.exit(1);
|
await fs.copy(source.path, dest);
|
||||||
|
} catch (err) {
|
||||||
|
logger.error`Copying local template path=${source.path} failed!`;
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update package.json info.
|
// Update package.json info.
|
||||||
try {
|
try {
|
||||||
await updatePkg(path.join(dest, 'package.json'), {
|
await updatePkg(path.join(dest, 'package.json'), {
|
||||||
name: _.kebabCase(name),
|
name: _.kebabCase(siteName),
|
||||||
version: '0.0.0',
|
version: '0.0.0',
|
||||||
private: true,
|
private: true,
|
||||||
});
|
});
|
||||||
|
@ -385,10 +512,7 @@ export default async function init(
|
||||||
|
|
||||||
// Display the most elegant way to cd.
|
// Display the most elegant way to cd.
|
||||||
const cdpath = path.relative('.', dest);
|
const cdpath = path.relative('.', dest);
|
||||||
const pkgManager = await getPackageManager(
|
const pkgManager = await getPackageManager(dest, cliOptions);
|
||||||
cliOptions.packageManager,
|
|
||||||
cliOptions.skipInstall,
|
|
||||||
);
|
|
||||||
if (!cliOptions.skipInstall) {
|
if (!cliOptions.skipInstall) {
|
||||||
shell.cd(dest);
|
shell.cd(dest);
|
||||||
logger.info`Installing dependencies with name=${pkgManager}...`;
|
logger.info`Installing dependencies with name=${pkgManager}...`;
|
||||||
|
@ -398,8 +522,8 @@ export default async function init(
|
||||||
{
|
{
|
||||||
env: {
|
env: {
|
||||||
...process.env,
|
...process.env,
|
||||||
// Force coloring the output, since the command is invoked,
|
// Force coloring the output, since the command is invoked by
|
||||||
// by shelljs which is not the interactive shell
|
// shelljs, which is not an interactive shell
|
||||||
...(supportsColor.stdout ? {FORCE_COLOR: '1'} : {}),
|
...(supportsColor.stdout ? {FORCE_COLOR: '1'} : {}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import Layout from '@theme/Layout';
|
|
||||||
import Link from '@docusaurus/Link';
|
import Link from '@docusaurus/Link';
|
||||||
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
||||||
import styles from './index.module.css';
|
import Layout from '@theme/Layout';
|
||||||
import HomepageFeatures from '@site/src/components/HomepageFeatures';
|
import HomepageFeatures from '@site/src/components/HomepageFeatures';
|
||||||
|
|
||||||
|
import styles from './index.module.css';
|
||||||
|
|
||||||
function HomepageHeader() {
|
function HomepageHeader() {
|
||||||
const {siteConfig} = useDocusaurusContext();
|
const {siteConfig} = useDocusaurusContext();
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import Layout from '@theme/Layout';
|
|
||||||
import Link from '@docusaurus/Link';
|
import Link from '@docusaurus/Link';
|
||||||
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
||||||
import styles from './index.module.css';
|
import Layout from '@theme/Layout';
|
||||||
import HomepageFeatures from '@site/src/components/HomepageFeatures';
|
import HomepageFeatures from '@site/src/components/HomepageFeatures';
|
||||||
|
|
||||||
|
import styles from './index.module.css';
|
||||||
|
|
||||||
function HomepageHeader() {
|
function HomepageHeader() {
|
||||||
const {siteConfig} = useDocusaurusContext();
|
const {siteConfig} = useDocusaurusContext();
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
"tslib": "^2.4.0",
|
"tslib": "^2.4.0",
|
||||||
"unist-util-visit": "^2.0.3",
|
"unist-util-visit": "^2.0.3",
|
||||||
"url-loader": "^4.1.1",
|
"url-loader": "^4.1.1",
|
||||||
"webpack": "^5.72.0"
|
"webpack": "^5.72.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@docusaurus/types": "2.0.0-beta.20",
|
"@docusaurus/types": "2.0.0-beta.20",
|
||||||
|
|
|
@ -6,21 +6,23 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import fs from 'fs-extra';
|
import fs from 'fs-extra';
|
||||||
import {createCompiler} from '@mdx-js/mdx';
|
|
||||||
import logger from '@docusaurus/logger';
|
import logger from '@docusaurus/logger';
|
||||||
import emoji from 'remark-emoji';
|
|
||||||
import {
|
import {
|
||||||
parseFrontMatter,
|
parseFrontMatter,
|
||||||
parseMarkdownContentTitle,
|
parseMarkdownContentTitle,
|
||||||
escapePath,
|
escapePath,
|
||||||
getFileLoaderUtils,
|
getFileLoaderUtils,
|
||||||
} from '@docusaurus/utils';
|
} from '@docusaurus/utils';
|
||||||
|
import {createCompiler} from '@mdx-js/mdx';
|
||||||
|
import emoji from 'remark-emoji';
|
||||||
import stringifyObject from 'stringify-object';
|
import stringifyObject from 'stringify-object';
|
||||||
|
|
||||||
import headings from './remark/headings';
|
import headings from './remark/headings';
|
||||||
import toc from './remark/toc';
|
import toc from './remark/toc';
|
||||||
import unwrapMdxCodeBlocks from './remark/unwrapMdxCodeBlocks';
|
import unwrapMdxCodeBlocks from './remark/unwrapMdxCodeBlocks';
|
||||||
import transformImage from './remark/transformImage';
|
import transformImage from './remark/transformImage';
|
||||||
import transformLinks from './remark/transformLinks';
|
import transformLinks from './remark/transformLinks';
|
||||||
|
|
||||||
import type {LoaderContext} from 'webpack';
|
import type {LoaderContext} from 'webpack';
|
||||||
import type {Processor, Plugin} from 'unified';
|
import type {Processor, Plugin} from 'unified';
|
||||||
|
|
||||||
|
@ -31,7 +33,7 @@ const {
|
||||||
const pragma = `
|
const pragma = `
|
||||||
/* @jsxRuntime classic */
|
/* @jsxRuntime classic */
|
||||||
/* @jsx mdx */
|
/* @jsx mdx */
|
||||||
/* @jsxFrag mdx.Fragment */
|
/* @jsxFrag React.Fragment */
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const DEFAULT_OPTIONS: MDXOptions = {
|
const DEFAULT_OPTIONS: MDXOptions = {
|
||||||
|
|
|
@ -6,13 +6,13 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {parse, type ParserOptions} from '@babel/parser';
|
import {parse, type ParserOptions} from '@babel/parser';
|
||||||
import type {Identifier} from '@babel/types';
|
|
||||||
import traverse from '@babel/traverse';
|
import traverse from '@babel/traverse';
|
||||||
import stringifyObject from 'stringify-object';
|
import stringifyObject from 'stringify-object';
|
||||||
import toString from 'mdast-util-to-string';
|
import toString from 'mdast-util-to-string';
|
||||||
import visit from 'unist-util-visit';
|
import visit from 'unist-util-visit';
|
||||||
import {toValue} from '../utils';
|
import {toValue} from '../utils';
|
||||||
|
|
||||||
|
import type {Identifier} from '@babel/types';
|
||||||
import type {TOCItem} from '../..';
|
import type {TOCItem} from '../..';
|
||||||
import type {Node, Parent} from 'unist';
|
import type {Node, Parent} from 'unist';
|
||||||
import type {Heading, Literal} from 'mdast';
|
import type {Heading, Literal} from 'mdast';
|
||||||
|
|
|
@ -5,6 +5,11 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import path from 'path';
|
||||||
|
import url from 'url';
|
||||||
|
import fs from 'fs-extra';
|
||||||
|
import {promisify} from 'util';
|
||||||
|
import logger from '@docusaurus/logger';
|
||||||
import {
|
import {
|
||||||
toMessageRelativeFilePath,
|
toMessageRelativeFilePath,
|
||||||
posixPath,
|
posixPath,
|
||||||
|
@ -13,15 +18,10 @@ import {
|
||||||
findAsyncSequential,
|
findAsyncSequential,
|
||||||
} from '@docusaurus/utils';
|
} from '@docusaurus/utils';
|
||||||
import visit from 'unist-util-visit';
|
import visit from 'unist-util-visit';
|
||||||
import path from 'path';
|
|
||||||
import url from 'url';
|
|
||||||
import fs from 'fs-extra';
|
|
||||||
import escapeHtml from 'escape-html';
|
import escapeHtml from 'escape-html';
|
||||||
import sizeOf from 'image-size';
|
import sizeOf from 'image-size';
|
||||||
import {promisify} from 'util';
|
|
||||||
import type {Transformer} from 'unified';
|
import type {Transformer} from 'unified';
|
||||||
import type {Image, Literal} from 'mdast';
|
import type {Image, Literal} from 'mdast';
|
||||||
import logger from '@docusaurus/logger';
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
loaders: {inlineMarkdownImageFileLoader},
|
loaders: {inlineMarkdownImageFileLoader},
|
||||||
|
|
|
@ -5,6 +5,9 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import path from 'path';
|
||||||
|
import url from 'url';
|
||||||
|
import fs from 'fs-extra';
|
||||||
import {
|
import {
|
||||||
toMessageRelativeFilePath,
|
toMessageRelativeFilePath,
|
||||||
posixPath,
|
posixPath,
|
||||||
|
@ -13,9 +16,6 @@ import {
|
||||||
findAsyncSequential,
|
findAsyncSequential,
|
||||||
} from '@docusaurus/utils';
|
} from '@docusaurus/utils';
|
||||||
import visit from 'unist-util-visit';
|
import visit from 'unist-util-visit';
|
||||||
import path from 'path';
|
|
||||||
import url from 'url';
|
|
||||||
import fs from 'fs-extra';
|
|
||||||
import escapeHtml from 'escape-html';
|
import escapeHtml from 'escape-html';
|
||||||
import {stringifyContent} from '../utils';
|
import {stringifyContent} from '../utils';
|
||||||
import type {Transformer} from 'unified';
|
import type {Transformer} from 'unified';
|
||||||
|
|
|
@ -8,11 +8,11 @@
|
||||||
|
|
||||||
// @ts-check
|
// @ts-check
|
||||||
|
|
||||||
|
import path from 'path';
|
||||||
|
import {createRequire} from 'module';
|
||||||
import logger from '@docusaurus/logger';
|
import logger from '@docusaurus/logger';
|
||||||
import semver from 'semver';
|
import semver from 'semver';
|
||||||
import cli from 'commander';
|
import cli from 'commander';
|
||||||
import path from 'path';
|
|
||||||
import {createRequire} from 'module';
|
|
||||||
|
|
||||||
const moduleRequire = createRequire(import.meta.url);
|
const moduleRequire = createRequire(import.meta.url);
|
||||||
const requiredVersion = moduleRequire('../package.json').engines.node;
|
const requiredVersion = moduleRequire('../package.json').engines.node;
|
||||||
|
|
|
@ -6,10 +6,10 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {jest} from '@jest/globals';
|
import {jest} from '@jest/globals';
|
||||||
import {migrateDocusaurusProject} from '../index';
|
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import fs from 'fs-extra';
|
import fs from 'fs-extra';
|
||||||
import {posixPath} from '@docusaurus/utils';
|
import {posixPath} from '@docusaurus/utils';
|
||||||
|
import {migrateDocusaurusProject} from '../index';
|
||||||
|
|
||||||
async function testMigration(siteDir: string, newDir: string) {
|
async function testMigration(siteDir: string, newDir: string) {
|
||||||
const writeMock = jest.spyOn(fs, 'outputFile').mockImplementation(() => {});
|
const writeMock = jest.spyOn(fs, 'outputFile').mockImplementation(() => {});
|
||||||
|
|
|
@ -5,22 +5,23 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import path from 'path';
|
||||||
import fs from 'fs-extra';
|
import fs from 'fs-extra';
|
||||||
import importFresh from 'import-fresh';
|
|
||||||
import logger from '@docusaurus/logger';
|
import logger from '@docusaurus/logger';
|
||||||
import {Globby} from '@docusaurus/utils';
|
import {Globby} from '@docusaurus/utils';
|
||||||
|
import importFresh from 'import-fresh';
|
||||||
import Color from 'color';
|
import Color from 'color';
|
||||||
|
|
||||||
|
import extractMetadata, {shouldQuotifyFrontMatter} from './frontMatter';
|
||||||
|
import migratePage from './transform';
|
||||||
|
import sanitizeMD from './sanitizeMD';
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
SidebarEntry,
|
SidebarEntry,
|
||||||
SidebarEntries,
|
SidebarEntries,
|
||||||
VersionOneConfig,
|
VersionOneConfig,
|
||||||
VersionTwoConfig,
|
VersionTwoConfig,
|
||||||
} from './types';
|
} from './types';
|
||||||
import extractMetadata, {shouldQuotifyFrontMatter} from './frontMatter';
|
|
||||||
import migratePage from './transform';
|
|
||||||
import sanitizeMD from './sanitizeMD';
|
|
||||||
import path from 'path';
|
|
||||||
|
|
||||||
const DOCUSAURUS_VERSION = (importFresh('../package.json') as {version: string})
|
const DOCUSAURUS_VERSION = (importFresh('../package.json') as {version: string})
|
||||||
.version;
|
.version;
|
||||||
|
|
|
@ -136,8 +136,8 @@ declare module '@docusaurus/ErrorBoundary' {
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module '@docusaurus/Head' {
|
declare module '@docusaurus/Head' {
|
||||||
import type {HelmetProps} from 'react-helmet-async';
|
|
||||||
import type {ReactNode} from 'react';
|
import type {ReactNode} from 'react';
|
||||||
|
import type {HelmetProps} from 'react-helmet-async';
|
||||||
|
|
||||||
export type Props = HelmetProps & {children: ReactNode};
|
export type Props = HelmetProps & {children: ReactNode};
|
||||||
|
|
||||||
|
|
|
@ -5,12 +5,12 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type {PluginContext} from '../types';
|
|
||||||
import collectRedirects from '../collectRedirects';
|
|
||||||
import {validateOptions} from '../options';
|
|
||||||
import {removeTrailingSlash} from '@docusaurus/utils';
|
import {removeTrailingSlash} from '@docusaurus/utils';
|
||||||
import {normalizePluginOptions} from '@docusaurus/utils-validation';
|
import {normalizePluginOptions} from '@docusaurus/utils-validation';
|
||||||
|
import collectRedirects from '../collectRedirects';
|
||||||
|
import {validateOptions} from '../options';
|
||||||
import type {Options} from '../options';
|
import type {Options} from '../options';
|
||||||
|
import type {PluginContext} from '../types';
|
||||||
|
|
||||||
function createTestPluginContext(
|
function createTestPluginContext(
|
||||||
options?: Options,
|
options?: Options,
|
||||||
|
|
|
@ -5,8 +5,8 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {validateOptions, DEFAULT_OPTIONS} from '../options';
|
|
||||||
import {normalizePluginOptions} from '@docusaurus/utils-validation';
|
import {normalizePluginOptions} from '@docusaurus/utils-validation';
|
||||||
|
import {validateOptions, DEFAULT_OPTIONS} from '../options';
|
||||||
import type {Options} from '../options';
|
import type {Options} from '../options';
|
||||||
|
|
||||||
function testValidate(options: Options) {
|
function testValidate(options: Options) {
|
||||||
|
|
|
@ -6,19 +6,18 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import type {PluginOptions, RedirectOption} from './options';
|
import logger from '@docusaurus/logger';
|
||||||
import type {PluginContext, RedirectMetadata} from './types';
|
import {
|
||||||
|
applyTrailingSlash,
|
||||||
|
type ApplyTrailingSlashParams,
|
||||||
|
} from '@docusaurus/utils-common';
|
||||||
import {
|
import {
|
||||||
createFromExtensionsRedirects,
|
createFromExtensionsRedirects,
|
||||||
createToExtensionsRedirects,
|
createToExtensionsRedirects,
|
||||||
} from './extensionRedirects';
|
} from './extensionRedirects';
|
||||||
import {validateRedirect} from './redirectValidation';
|
import {validateRedirect} from './redirectValidation';
|
||||||
import {
|
import type {PluginOptions, RedirectOption} from './options';
|
||||||
applyTrailingSlash,
|
import type {PluginContext, RedirectMetadata} from './types';
|
||||||
type ApplyTrailingSlashParams,
|
|
||||||
} from '@docusaurus/utils-common';
|
|
||||||
|
|
||||||
import logger from '@docusaurus/logger';
|
|
||||||
|
|
||||||
export default function collectRedirects(
|
export default function collectRedirects(
|
||||||
pluginContext: PluginContext,
|
pluginContext: PluginContext,
|
||||||
|
|
|
@ -5,9 +5,9 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import _ from 'lodash';
|
||||||
import * as eta from 'eta';
|
import * as eta from 'eta';
|
||||||
import redirectPageTemplate from './templates/redirectPage.template.html';
|
import redirectPageTemplate from './templates/redirectPage.template.html';
|
||||||
import _ from 'lodash';
|
|
||||||
|
|
||||||
const getCompiledRedirectPageTemplate = _.memoize(() =>
|
const getCompiledRedirectPageTemplate = _.memoize(() =>
|
||||||
eta.compile(redirectPageTemplate.trim()),
|
eta.compile(redirectPageTemplate.trim()),
|
||||||
|
|
|
@ -5,16 +5,15 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type {LoadContext, Plugin} from '@docusaurus/types';
|
import {removePrefix, addLeadingSlash} from '@docusaurus/utils';
|
||||||
import type {PluginContext, RedirectMetadata} from './types';
|
|
||||||
import type {PluginOptions, Options} from './options';
|
|
||||||
|
|
||||||
import collectRedirects from './collectRedirects';
|
import collectRedirects from './collectRedirects';
|
||||||
import writeRedirectFiles, {
|
import writeRedirectFiles, {
|
||||||
toRedirectFilesMetadata,
|
toRedirectFilesMetadata,
|
||||||
type RedirectFileMetadata,
|
type RedirectFileMetadata,
|
||||||
} from './writeRedirectFiles';
|
} from './writeRedirectFiles';
|
||||||
import {removePrefix, addLeadingSlash} from '@docusaurus/utils';
|
import type {LoadContext, Plugin} from '@docusaurus/types';
|
||||||
|
import type {PluginContext, RedirectMetadata} from './types';
|
||||||
|
import type {PluginOptions, Options} from './options';
|
||||||
|
|
||||||
export default function pluginClientRedirectsPages(
|
export default function pluginClientRedirectsPages(
|
||||||
context: LoadContext,
|
context: LoadContext,
|
||||||
|
|
|
@ -5,8 +5,8 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type {OptionValidationContext} from '@docusaurus/types';
|
|
||||||
import {Joi, PathnameSchema} from '@docusaurus/utils-validation';
|
import {Joi, PathnameSchema} from '@docusaurus/utils-validation';
|
||||||
|
import type {OptionValidationContext} from '@docusaurus/types';
|
||||||
|
|
||||||
export type RedirectOption = {
|
export type RedirectOption = {
|
||||||
to: string;
|
to: string;
|
||||||
|
|
|
@ -5,8 +5,8 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type {RedirectMetadata} from './types';
|
|
||||||
import {Joi, PathnameSchema} from '@docusaurus/utils-validation';
|
import {Joi, PathnameSchema} from '@docusaurus/utils-validation';
|
||||||
|
import type {RedirectMetadata} from './types';
|
||||||
|
|
||||||
const RedirectSchema = Joi.object<RedirectMetadata>({
|
const RedirectSchema = Joi.object<RedirectMetadata>({
|
||||||
from: PathnameSchema.required(),
|
from: PathnameSchema.required(),
|
||||||
|
|
|
@ -8,11 +8,12 @@
|
||||||
import fs from 'fs-extra';
|
import fs from 'fs-extra';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
|
import logger from '@docusaurus/logger';
|
||||||
|
import {normalizeUrl} from '@docusaurus/utils';
|
||||||
|
|
||||||
|
import createRedirectPageContent from './createRedirectPageContent';
|
||||||
|
|
||||||
import type {PluginContext, RedirectMetadata} from './types';
|
import type {PluginContext, RedirectMetadata} from './types';
|
||||||
import createRedirectPageContent from './createRedirectPageContent';
|
|
||||||
import {normalizeUrl} from '@docusaurus/utils';
|
|
||||||
import logger from '@docusaurus/logger';
|
|
||||||
|
|
||||||
export type WriteFilesPluginContext = Pick<PluginContext, 'baseUrl' | 'outDir'>;
|
export type WriteFilesPluginContext = Pick<PluginContext, 'baseUrl' | 'outDir'>;
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
"tslib": "^2.4.0",
|
"tslib": "^2.4.0",
|
||||||
"unist-util-visit": "^2.0.3",
|
"unist-util-visit": "^2.0.3",
|
||||||
"utility-types": "^3.10.0",
|
"utility-types": "^3.10.0",
|
||||||
"webpack": "^5.72.0"
|
"webpack": "^5.72.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@docusaurus/types": "2.0.0-beta.20",
|
"@docusaurus/types": "2.0.0-beta.20",
|
||||||
|
|
|
@ -5,13 +5,13 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import path from 'path';
|
||||||
import {
|
import {
|
||||||
type AuthorsMap,
|
type AuthorsMap,
|
||||||
getAuthorsMap,
|
getAuthorsMap,
|
||||||
getBlogPostAuthors,
|
getBlogPostAuthors,
|
||||||
validateAuthorsMap,
|
validateAuthorsMap,
|
||||||
} from '../authors';
|
} from '../authors';
|
||||||
import path from 'path';
|
|
||||||
|
|
||||||
describe('getBlogPostAuthors', () => {
|
describe('getBlogPostAuthors', () => {
|
||||||
it('can read no authors', () => {
|
it('can read no authors', () => {
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {jest} from '@jest/globals';
|
import {jest} from '@jest/globals';
|
||||||
|
import fs from 'fs-extra';
|
||||||
|
import path from 'path';
|
||||||
import {
|
import {
|
||||||
truncate,
|
truncate,
|
||||||
parseBlogFileName,
|
parseBlogFileName,
|
||||||
|
@ -14,13 +16,8 @@ import {
|
||||||
paginateBlogPosts,
|
paginateBlogPosts,
|
||||||
type LinkifyParams,
|
type LinkifyParams,
|
||||||
} from '../blogUtils';
|
} from '../blogUtils';
|
||||||
import fs from 'fs-extra';
|
import type {BlogBrokenMarkdownLink, BlogContentPaths} from '../types';
|
||||||
import path from 'path';
|
import type {BlogPost} from '@docusaurus/plugin-content-blog';
|
||||||
import type {
|
|
||||||
BlogBrokenMarkdownLink,
|
|
||||||
BlogContentPaths,
|
|
||||||
BlogPost,
|
|
||||||
} from '../types';
|
|
||||||
|
|
||||||
describe('truncate', () => {
|
describe('truncate', () => {
|
||||||
it('truncates texts', () => {
|
it('truncates texts', () => {
|
||||||
|
|
|
@ -8,11 +8,11 @@
|
||||||
import {jest} from '@jest/globals';
|
import {jest} from '@jest/globals';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import fs from 'fs-extra';
|
import fs from 'fs-extra';
|
||||||
|
import {DEFAULT_OPTIONS} from '../options';
|
||||||
|
import {generateBlogPosts} from '../blogUtils';
|
||||||
import {createBlogFeedFiles} from '../feed';
|
import {createBlogFeedFiles} from '../feed';
|
||||||
import type {LoadContext, I18n} from '@docusaurus/types';
|
import type {LoadContext, I18n} from '@docusaurus/types';
|
||||||
import type {BlogContentPaths} from '../types';
|
import type {BlogContentPaths} from '../types';
|
||||||
import {DEFAULT_OPTIONS} from '../options';
|
|
||||||
import {generateBlogPosts} from '../blogUtils';
|
|
||||||
import type {PluginOptions} from '@docusaurus/plugin-content-blog';
|
import type {PluginOptions} from '@docusaurus/plugin-content-blog';
|
||||||
|
|
||||||
const DefaultI18N: I18n = {
|
const DefaultI18N: I18n = {
|
||||||
|
|
|
@ -5,8 +5,8 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {validateBlogPostFrontMatter} from '../frontMatter';
|
|
||||||
import escapeStringRegexp from 'escape-string-regexp';
|
import escapeStringRegexp from 'escape-string-regexp';
|
||||||
|
import {validateBlogPostFrontMatter} from '../frontMatter';
|
||||||
import type {BlogPostFrontMatter} from '@docusaurus/plugin-content-blog';
|
import type {BlogPostFrontMatter} from '@docusaurus/plugin-content-blog';
|
||||||
|
|
||||||
// TODO this abstraction reduce verbosity but it makes it harder to debug
|
// TODO this abstraction reduce verbosity but it makes it harder to debug
|
||||||
|
|
|
@ -7,13 +7,13 @@
|
||||||
|
|
||||||
import {jest} from '@jest/globals';
|
import {jest} from '@jest/globals';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import pluginContentBlog from '../index';
|
|
||||||
import type {DocusaurusConfig, LoadContext, I18n} from '@docusaurus/types';
|
|
||||||
import {validateOptions} from '../options';
|
|
||||||
import type {BlogPost} from '../types';
|
|
||||||
import {normalizePluginOptions} from '@docusaurus/utils-validation';
|
import {normalizePluginOptions} from '@docusaurus/utils-validation';
|
||||||
import {posixPath, getFileCommitDate} from '@docusaurus/utils';
|
import {posixPath, getFileCommitDate} from '@docusaurus/utils';
|
||||||
|
import pluginContentBlog from '../index';
|
||||||
|
import {validateOptions} from '../options';
|
||||||
|
import type {DocusaurusConfig, LoadContext, I18n} from '@docusaurus/types';
|
||||||
import type {
|
import type {
|
||||||
|
BlogPost,
|
||||||
PluginOptions,
|
PluginOptions,
|
||||||
EditUrlFunction,
|
EditUrlFunction,
|
||||||
} from '@docusaurus/plugin-content-blog';
|
} from '@docusaurus/plugin-content-blog';
|
||||||
|
|
|
@ -5,8 +5,8 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {validateOptions, DEFAULT_OPTIONS} from '../options';
|
|
||||||
import {normalizePluginOptions} from '@docusaurus/utils-validation';
|
import {normalizePluginOptions} from '@docusaurus/utils-validation';
|
||||||
|
import {validateOptions, DEFAULT_OPTIONS} from '../options';
|
||||||
import type {Options} from '@docusaurus/plugin-content-blog';
|
import type {Options} from '@docusaurus/plugin-content-blog';
|
||||||
|
|
||||||
function testValidate(options: Options) {
|
function testValidate(options: Options) {
|
||||||
|
|
|
@ -5,11 +5,14 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type {BlogPost, BlogContent} from '../types';
|
import {updateTranslationFileMessages} from '@docusaurus/utils';
|
||||||
import {getTranslationFiles, translateContent} from '../translations';
|
import {getTranslationFiles, translateContent} from '../translations';
|
||||||
import {DEFAULT_OPTIONS} from '../options';
|
import {DEFAULT_OPTIONS} from '../options';
|
||||||
import {updateTranslationFileMessages} from '@docusaurus/utils';
|
import type {
|
||||||
import type {PluginOptions} from '@docusaurus/plugin-content-blog';
|
PluginOptions,
|
||||||
|
BlogPost,
|
||||||
|
BlogContent,
|
||||||
|
} from '@docusaurus/plugin-content-blog';
|
||||||
|
|
||||||
const sampleBlogOptions: PluginOptions = {
|
const sampleBlogOptions: PluginOptions = {
|
||||||
...DEFAULT_OPTIONS,
|
...DEFAULT_OPTIONS,
|
||||||
|
|
|
@ -5,9 +5,9 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type {BlogContentPaths} from './types';
|
|
||||||
import {getDataFileData} from '@docusaurus/utils';
|
import {getDataFileData} from '@docusaurus/utils';
|
||||||
import {Joi, URISchema} from '@docusaurus/utils-validation';
|
import {Joi, URISchema} from '@docusaurus/utils-validation';
|
||||||
|
import type {BlogContentPaths} from './types';
|
||||||
import type {
|
import type {
|
||||||
Author,
|
Author,
|
||||||
BlogPostFrontMatter,
|
BlogPostFrontMatter,
|
||||||
|
|
|
@ -7,9 +7,9 @@
|
||||||
|
|
||||||
import fs from 'fs-extra';
|
import fs from 'fs-extra';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import readingTime from 'reading-time';
|
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import type {BlogContentPaths, BlogMarkdownLoaderOptions} from './types';
|
import logger from '@docusaurus/logger';
|
||||||
|
import readingTime from 'reading-time';
|
||||||
import {
|
import {
|
||||||
parseMarkdownString,
|
parseMarkdownString,
|
||||||
normalizeUrl,
|
normalizeUrl,
|
||||||
|
@ -24,10 +24,9 @@ import {
|
||||||
getFileCommitDate,
|
getFileCommitDate,
|
||||||
getContentPathList,
|
getContentPathList,
|
||||||
} from '@docusaurus/utils';
|
} from '@docusaurus/utils';
|
||||||
import type {LoadContext} from '@docusaurus/types';
|
|
||||||
import {validateBlogPostFrontMatter} from './frontMatter';
|
import {validateBlogPostFrontMatter} from './frontMatter';
|
||||||
import {type AuthorsMap, getAuthorsMap, getBlogPostAuthors} from './authors';
|
import {type AuthorsMap, getAuthorsMap, getBlogPostAuthors} from './authors';
|
||||||
import logger from '@docusaurus/logger';
|
import type {LoadContext} from '@docusaurus/types';
|
||||||
import type {
|
import type {
|
||||||
PluginOptions,
|
PluginOptions,
|
||||||
ReadingTimeFunction,
|
ReadingTimeFunction,
|
||||||
|
@ -35,6 +34,7 @@ import type {
|
||||||
BlogTags,
|
BlogTags,
|
||||||
BlogPaginated,
|
BlogPaginated,
|
||||||
} from '@docusaurus/plugin-content-blog';
|
} from '@docusaurus/plugin-content-blog';
|
||||||
|
import type {BlogContentPaths, BlogMarkdownLoaderOptions} from './types';
|
||||||
|
|
||||||
export function truncate(fileString: string, truncateMarker: RegExp): string {
|
export function truncate(fileString: string, truncateMarker: RegExp): string {
|
||||||
return fileString.split(truncateMarker, 1).shift()!;
|
return fileString.split(truncateMarker, 1).shift()!;
|
||||||
|
|
|
@ -5,20 +5,20 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {Feed, type Author as FeedAuthor, type Item as FeedItem} from 'feed';
|
|
||||||
import {normalizeUrl, readOutputHTMLFile} from '@docusaurus/utils';
|
|
||||||
import {load as cheerioLoad} from 'cheerio';
|
|
||||||
import type {DocusaurusConfig} from '@docusaurus/types';
|
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import fs from 'fs-extra';
|
import fs from 'fs-extra';
|
||||||
|
import logger from '@docusaurus/logger';
|
||||||
|
import {Feed, type Author as FeedAuthor, type Item as FeedItem} from 'feed';
|
||||||
|
import {normalizeUrl, readOutputHTMLFile} from '@docusaurus/utils';
|
||||||
|
import {blogPostContainerID} from '@docusaurus/utils-common';
|
||||||
|
import {load as cheerioLoad} from 'cheerio';
|
||||||
|
import type {DocusaurusConfig} from '@docusaurus/types';
|
||||||
import type {
|
import type {
|
||||||
FeedType,
|
FeedType,
|
||||||
PluginOptions,
|
PluginOptions,
|
||||||
Author,
|
Author,
|
||||||
BlogPost,
|
BlogPost,
|
||||||
} from '@docusaurus/plugin-content-blog';
|
} from '@docusaurus/plugin-content-blog';
|
||||||
import {blogPostContainerID} from '@docusaurus/utils-common';
|
|
||||||
import logger from '@docusaurus/logger';
|
|
||||||
|
|
||||||
async function generateBlogFeed({
|
async function generateBlogFeed({
|
||||||
blogPosts,
|
blogPosts,
|
||||||
|
|
|
@ -6,8 +6,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import admonitions from 'remark-admonitions';
|
|
||||||
import footnoteIDFixer from './remark/footnoteIDFixer';
|
|
||||||
import {
|
import {
|
||||||
normalizeUrl,
|
normalizeUrl,
|
||||||
docuHash,
|
docuHash,
|
||||||
|
@ -23,17 +21,19 @@ import {
|
||||||
type TagsListItem,
|
type TagsListItem,
|
||||||
type TagModule,
|
type TagModule,
|
||||||
} from '@docusaurus/utils';
|
} from '@docusaurus/utils';
|
||||||
import {translateContent, getTranslationFiles} from './translations';
|
import admonitions from 'remark-admonitions';
|
||||||
|
|
||||||
import type {BlogContentPaths, BlogMarkdownLoaderOptions} from './types';
|
|
||||||
import type {LoadContext, Plugin, HtmlTags} from '@docusaurus/types';
|
|
||||||
import {
|
import {
|
||||||
generateBlogPosts,
|
generateBlogPosts,
|
||||||
getSourceToPermalink,
|
getSourceToPermalink,
|
||||||
getBlogTags,
|
getBlogTags,
|
||||||
paginateBlogPosts,
|
paginateBlogPosts,
|
||||||
} from './blogUtils';
|
} from './blogUtils';
|
||||||
|
import footnoteIDFixer from './remark/footnoteIDFixer';
|
||||||
|
import {translateContent, getTranslationFiles} from './translations';
|
||||||
import {createBlogFeedFiles} from './feed';
|
import {createBlogFeedFiles} from './feed';
|
||||||
|
|
||||||
|
import type {BlogContentPaths, BlogMarkdownLoaderOptions} from './types';
|
||||||
|
import type {LoadContext, Plugin, HtmlTags} from '@docusaurus/types';
|
||||||
import type {
|
import type {
|
||||||
PluginOptions,
|
PluginOptions,
|
||||||
BlogPostFrontMatter,
|
BlogPostFrontMatter,
|
||||||
|
|
|
@ -538,11 +538,11 @@ declare module '@theme/BlogTagsListPage' {
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module '@theme/BlogTagsPostsPage' {
|
declare module '@theme/BlogTagsPostsPage' {
|
||||||
|
import type {Content} from '@theme/BlogPostPage';
|
||||||
import type {
|
import type {
|
||||||
BlogSidebar,
|
BlogSidebar,
|
||||||
BlogPaginatedMetadata,
|
BlogPaginatedMetadata,
|
||||||
} from '@docusaurus/plugin-content-blog';
|
} from '@docusaurus/plugin-content-blog';
|
||||||
import type {Content} from '@theme/BlogPostPage';
|
|
||||||
import type {TagModule} from '@docusaurus/utils';
|
import type {TagModule} from '@docusaurus/utils';
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
|
|
|
@ -38,7 +38,7 @@
|
||||||
"remark-admonitions": "^1.2.1",
|
"remark-admonitions": "^1.2.1",
|
||||||
"tslib": "^2.4.0",
|
"tslib": "^2.4.0",
|
||||||
"utility-types": "^3.10.0",
|
"utility-types": "^3.10.0",
|
||||||
"webpack": "^5.72.0"
|
"webpack": "^5.72.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@docusaurus/module-type-aliases": "2.0.0-beta.20",
|
"@docusaurus/module-type-aliases": "2.0.0-beta.20",
|
||||||
|
|
Binary file not shown.
|
@ -8,6 +8,8 @@
|
||||||
import {jest} from '@jest/globals';
|
import {jest} from '@jest/globals';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import {loadContext} from '@docusaurus/core/src/server/index';
|
import {loadContext} from '@docusaurus/core/src/server/index';
|
||||||
|
import {createSlugger, posixPath, DEFAULT_PLUGIN_ID} from '@docusaurus/utils';
|
||||||
|
import {createSidebarsUtils} from '../sidebars/utils';
|
||||||
import {
|
import {
|
||||||
processDocMetadata,
|
processDocMetadata,
|
||||||
readVersionDocs,
|
readVersionDocs,
|
||||||
|
@ -17,8 +19,9 @@ import {
|
||||||
type DocEnv,
|
type DocEnv,
|
||||||
} from '../docs';
|
} from '../docs';
|
||||||
import {loadSidebars} from '../sidebars';
|
import {loadSidebars} from '../sidebars';
|
||||||
import type {Sidebars} from '../sidebars/types';
|
|
||||||
import {readVersionsMetadata} from '../versions';
|
import {readVersionsMetadata} from '../versions';
|
||||||
|
import {DEFAULT_OPTIONS} from '../options';
|
||||||
|
import type {Sidebars} from '../sidebars/types';
|
||||||
import type {DocFile} from '../types';
|
import type {DocFile} from '../types';
|
||||||
import type {
|
import type {
|
||||||
MetadataOptions,
|
MetadataOptions,
|
||||||
|
@ -29,10 +32,7 @@ import type {
|
||||||
PropNavigationLink,
|
PropNavigationLink,
|
||||||
} from '@docusaurus/plugin-content-docs';
|
} from '@docusaurus/plugin-content-docs';
|
||||||
import type {LoadContext} from '@docusaurus/types';
|
import type {LoadContext} from '@docusaurus/types';
|
||||||
import {DEFAULT_OPTIONS} from '../options';
|
|
||||||
import type {Optional} from 'utility-types';
|
import type {Optional} from 'utility-types';
|
||||||
import {createSlugger, posixPath, DEFAULT_PLUGIN_ID} from '@docusaurus/utils';
|
|
||||||
import {createSidebarsUtils} from '../sidebars/utils';
|
|
||||||
|
|
||||||
jest.setTimeout(15000);
|
jest.setTimeout(15000);
|
||||||
|
|
||||||
|
|
|
@ -5,9 +5,9 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import escapeStringRegexp from 'escape-string-regexp';
|
||||||
import {validateDocFrontMatter} from '../frontMatter';
|
import {validateDocFrontMatter} from '../frontMatter';
|
||||||
import type {DocFrontMatter} from '@docusaurus/plugin-content-docs';
|
import type {DocFrontMatter} from '@docusaurus/plugin-content-docs';
|
||||||
import escapeStringRegexp from 'escape-string-regexp';
|
|
||||||
|
|
||||||
function testField(params: {
|
function testField(params: {
|
||||||
prefix: string;
|
prefix: string;
|
||||||
|
|
|
@ -7,32 +7,27 @@
|
||||||
|
|
||||||
import {jest} from '@jest/globals';
|
import {jest} from '@jest/globals';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
import fs from 'fs-extra';
|
||||||
|
import _ from 'lodash';
|
||||||
import {isMatch} from 'picomatch';
|
import {isMatch} from 'picomatch';
|
||||||
import commander from 'commander';
|
import commander from 'commander';
|
||||||
import _ from 'lodash';
|
import webpack from 'webpack';
|
||||||
|
|
||||||
import fs from 'fs-extra';
|
|
||||||
import pluginContentDocs from '../index';
|
|
||||||
import {loadContext} from '@docusaurus/core/src/server/index';
|
import {loadContext} from '@docusaurus/core/src/server/index';
|
||||||
import {applyConfigureWebpack} from '@docusaurus/core/src/webpack/utils';
|
import {applyConfigureWebpack} from '@docusaurus/core/src/webpack/utils';
|
||||||
import type {RouteConfig} from '@docusaurus/types';
|
|
||||||
import {posixPath} from '@docusaurus/utils';
|
|
||||||
import {sortConfig} from '@docusaurus/core/src/server/plugins/routeConfig';
|
import {sortConfig} from '@docusaurus/core/src/server/plugins/routeConfig';
|
||||||
|
import {posixPath} from '@docusaurus/utils';
|
||||||
import * as cliDocs from '../cli';
|
|
||||||
import {validateOptions} from '../options';
|
|
||||||
import {normalizePluginOptions} from '@docusaurus/utils-validation';
|
import {normalizePluginOptions} from '@docusaurus/utils-validation';
|
||||||
import type {LoadedVersion} from '../types';
|
|
||||||
import type {
|
|
||||||
SidebarItem,
|
|
||||||
SidebarItemsGeneratorOption,
|
|
||||||
SidebarItemsGeneratorOptionArgs,
|
|
||||||
} from '../sidebars/types';
|
|
||||||
import {toSidebarsProp} from '../props';
|
|
||||||
|
|
||||||
import webpack from 'webpack';
|
import pluginContentDocs from '../index';
|
||||||
|
import {toSidebarsProp} from '../props';
|
||||||
import {DefaultSidebarItemsGenerator} from '../sidebars/generator';
|
import {DefaultSidebarItemsGenerator} from '../sidebars/generator';
|
||||||
import {DisabledSidebars} from '../sidebars';
|
import {DisabledSidebars} from '../sidebars';
|
||||||
|
import * as cliDocs from '../cli';
|
||||||
|
import {validateOptions} from '../options';
|
||||||
|
|
||||||
|
import type {RouteConfig} from '@docusaurus/types';
|
||||||
|
import type {LoadedVersion} from '@docusaurus/plugin-content-docs';
|
||||||
|
import type {SidebarItem, SidebarItemsGeneratorOption} from '../sidebars/types';
|
||||||
|
|
||||||
function findDocById(version: LoadedVersion, unversionedId: string) {
|
function findDocById(version: LoadedVersion, unversionedId: string) {
|
||||||
return version.docs.find((item) => item.unversionedId === unversionedId);
|
return version.docs.find((item) => item.unversionedId === unversionedId);
|
||||||
|
@ -768,14 +763,14 @@ describe('site with custom sidebar items generator', () => {
|
||||||
const customSidebarItemsGeneratorMock = jest.fn(async () => []);
|
const customSidebarItemsGeneratorMock = jest.fn(async () => []);
|
||||||
const {siteDir} = await loadSite(customSidebarItemsGeneratorMock);
|
const {siteDir} = await loadSite(customSidebarItemsGeneratorMock);
|
||||||
|
|
||||||
const generatorArg: SidebarItemsGeneratorOptionArgs =
|
const generatorArg: Parameters<SidebarItemsGeneratorOption>[0] =
|
||||||
customSidebarItemsGeneratorMock.mock.calls[0][0];
|
customSidebarItemsGeneratorMock.mock.calls[0][0];
|
||||||
|
|
||||||
// Make test pass even if docs are in different order and paths are
|
// Make test pass even if docs are in different order and paths are
|
||||||
// absolutes
|
// absolutes
|
||||||
function makeDeterministic(
|
function makeDeterministic(
|
||||||
arg: SidebarItemsGeneratorOptionArgs,
|
arg: Parameters<SidebarItemsGeneratorOption>[0],
|
||||||
): SidebarItemsGeneratorOptionArgs {
|
): Parameters<SidebarItemsGeneratorOption>[0] {
|
||||||
return {
|
return {
|
||||||
...arg,
|
...arg,
|
||||||
docs: _.orderBy(arg.docs, 'id'),
|
docs: _.orderBy(arg.docs, 'id'),
|
||||||
|
|
|
@ -5,11 +5,11 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {createTempRepo} from '@testing-utils/git';
|
|
||||||
import {jest} from '@jest/globals';
|
import {jest} from '@jest/globals';
|
||||||
import fs from 'fs-extra';
|
import fs from 'fs-extra';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import shell from 'shelljs';
|
import shell from 'shelljs';
|
||||||
|
import {createTempRepo} from '@testing-utils/git';
|
||||||
|
|
||||||
import {getFileLastUpdate} from '../lastUpdate';
|
import {getFileLastUpdate} from '../lastUpdate';
|
||||||
|
|
||||||
|
|
|
@ -5,14 +5,14 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {validateOptions, DEFAULT_OPTIONS} from '../options';
|
import {GlobExcludeDefault} from '@docusaurus/utils';
|
||||||
import {normalizePluginOptions} from '@docusaurus/utils-validation';
|
import {normalizePluginOptions} from '@docusaurus/utils-validation';
|
||||||
|
import {validateOptions, DEFAULT_OPTIONS} from '../options';
|
||||||
import {DefaultSidebarItemsGenerator} from '../sidebars/generator';
|
import {DefaultSidebarItemsGenerator} from '../sidebars/generator';
|
||||||
import {
|
import {
|
||||||
DefaultNumberPrefixParser,
|
DefaultNumberPrefixParser,
|
||||||
DisabledNumberPrefixParser,
|
DisabledNumberPrefixParser,
|
||||||
} from '../numberPrefix';
|
} from '../numberPrefix';
|
||||||
import {GlobExcludeDefault} from '@docusaurus/utils';
|
|
||||||
import type {Options} from '@docusaurus/plugin-content-docs';
|
import type {Options} from '@docusaurus/plugin-content-docs';
|
||||||
|
|
||||||
// The type of remark/rehype plugins can be function/object
|
// The type of remark/rehype plugins can be function/object
|
||||||
|
|
|
@ -5,14 +5,17 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type {LoadedContent, LoadedVersion} from '../types';
|
import {updateTranslationFileMessages} from '@docusaurus/utils';
|
||||||
import {CURRENT_VERSION_NAME} from '../constants';
|
import {CURRENT_VERSION_NAME} from '../constants';
|
||||||
import {
|
import {
|
||||||
getLoadedContentTranslationFiles,
|
getLoadedContentTranslationFiles,
|
||||||
translateLoadedContent,
|
translateLoadedContent,
|
||||||
} from '../translations';
|
} from '../translations';
|
||||||
import type {DocMetadata} from '@docusaurus/plugin-content-docs';
|
import type {
|
||||||
import {updateTranslationFileMessages} from '@docusaurus/utils';
|
DocMetadata,
|
||||||
|
LoadedContent,
|
||||||
|
LoadedVersion,
|
||||||
|
} from '@docusaurus/plugin-content-docs';
|
||||||
|
|
||||||
function createSampleDoc(doc: Pick<DocMetadata, 'id'>): DocMetadata {
|
function createSampleDoc(doc: Pick<DocMetadata, 'id'>): DocMetadata {
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -5,13 +5,13 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import {type SidebarsUtils, toNavigationLink} from './sidebars/utils';
|
||||||
|
import {createDocsByIdIndex} from './docs';
|
||||||
import type {
|
import type {
|
||||||
CategoryGeneratedIndexMetadata,
|
CategoryGeneratedIndexMetadata,
|
||||||
DocMetadataBase,
|
DocMetadataBase,
|
||||||
} from '@docusaurus/plugin-content-docs';
|
} from '@docusaurus/plugin-content-docs';
|
||||||
import type {SidebarItemCategoryWithGeneratedIndex} from './sidebars/types';
|
import type {SidebarItemCategoryWithGeneratedIndex} from './sidebars/types';
|
||||||
import {type SidebarsUtils, toNavigationLink} from './sidebars/utils';
|
|
||||||
import {createDocsByIdIndex} from './docs';
|
|
||||||
|
|
||||||
function getCategoryGeneratedIndexMetadata({
|
function getCategoryGeneratedIndexMetadata({
|
||||||
category,
|
category,
|
||||||
|
|
|
@ -5,6 +5,10 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import fs from 'fs-extra';
|
||||||
|
import path from 'path';
|
||||||
|
import logger from '@docusaurus/logger';
|
||||||
|
import {DEFAULT_PLUGIN_ID} from '@docusaurus/utils';
|
||||||
import {
|
import {
|
||||||
getVersionsFilePath,
|
getVersionsFilePath,
|
||||||
getVersionDocsDirPath,
|
getVersionDocsDirPath,
|
||||||
|
@ -12,13 +16,9 @@ import {
|
||||||
getDocsDirPathLocalized,
|
getDocsDirPathLocalized,
|
||||||
} from './versions/files';
|
} from './versions/files';
|
||||||
import {validateVersionName} from './versions/validation';
|
import {validateVersionName} from './versions/validation';
|
||||||
import fs from 'fs-extra';
|
|
||||||
import path from 'path';
|
|
||||||
import type {PluginOptions} from '@docusaurus/plugin-content-docs';
|
|
||||||
import {loadSidebarsFileUnsafe} from './sidebars';
|
import {loadSidebarsFileUnsafe} from './sidebars';
|
||||||
import {CURRENT_VERSION_NAME} from './constants';
|
import {CURRENT_VERSION_NAME} from './constants';
|
||||||
import {DEFAULT_PLUGIN_ID} from '@docusaurus/utils';
|
import type {PluginOptions} from '@docusaurus/plugin-content-docs';
|
||||||
import logger from '@docusaurus/logger';
|
|
||||||
import type {LoadContext} from '@docusaurus/types';
|
import type {LoadContext} from '@docusaurus/types';
|
||||||
|
|
||||||
async function createVersionedSidebarFile({
|
async function createVersionedSidebarFile({
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import _ from 'lodash';
|
||||||
import {
|
import {
|
||||||
getActivePlugin,
|
getActivePlugin,
|
||||||
getLatestVersion,
|
getLatestVersion,
|
||||||
|
@ -17,7 +18,6 @@ import type {
|
||||||
GlobalVersion,
|
GlobalVersion,
|
||||||
ActivePlugin,
|
ActivePlugin,
|
||||||
} from '@docusaurus/plugin-content-docs/client';
|
} from '@docusaurus/plugin-content-docs/client';
|
||||||
import _ from 'lodash';
|
|
||||||
|
|
||||||
describe('docsClientUtils', () => {
|
describe('docsClientUtils', () => {
|
||||||
it('getActivePlugin', () => {
|
it('getActivePlugin', () => {
|
||||||
|
|
|
@ -19,15 +19,12 @@ import {
|
||||||
Globby,
|
Globby,
|
||||||
normalizeFrontMatterTags,
|
normalizeFrontMatterTags,
|
||||||
} from '@docusaurus/utils';
|
} from '@docusaurus/utils';
|
||||||
import type {LoadContext} from '@docusaurus/types';
|
|
||||||
|
|
||||||
import {getFileLastUpdate} from './lastUpdate';
|
import {getFileLastUpdate} from './lastUpdate';
|
||||||
import type {DocFile} from './types';
|
|
||||||
import getSlug from './slug';
|
import getSlug from './slug';
|
||||||
import {CURRENT_VERSION_NAME} from './constants';
|
import {CURRENT_VERSION_NAME} from './constants';
|
||||||
import {stripPathNumberPrefixes} from './numberPrefix';
|
import {stripPathNumberPrefixes} from './numberPrefix';
|
||||||
import {validateDocFrontMatter} from './frontMatter';
|
import {validateDocFrontMatter} from './frontMatter';
|
||||||
import type {SidebarsUtils} from './sidebars/utils';
|
|
||||||
import {toDocNavigationLink, toNavigationLink} from './sidebars/utils';
|
import {toDocNavigationLink, toNavigationLink} from './sidebars/utils';
|
||||||
import type {
|
import type {
|
||||||
MetadataOptions,
|
MetadataOptions,
|
||||||
|
@ -41,6 +38,9 @@ import type {
|
||||||
DocFrontMatter,
|
DocFrontMatter,
|
||||||
LoadedVersion,
|
LoadedVersion,
|
||||||
} from '@docusaurus/plugin-content-docs';
|
} from '@docusaurus/plugin-content-docs';
|
||||||
|
import type {LoadContext} from '@docusaurus/types';
|
||||||
|
import type {SidebarsUtils} from './sidebars/utils';
|
||||||
|
import type {DocFile} from './types';
|
||||||
|
|
||||||
type LastUpdateOptions = Pick<
|
type LastUpdateOptions = Pick<
|
||||||
PluginOptions,
|
PluginOptions,
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import type {Sidebars} from './sidebars/types';
|
|
||||||
import {getMainDocId} from './docs';
|
import {getMainDocId} from './docs';
|
||||||
import type {FullVersion} from './types';
|
import type {FullVersion} from './types';
|
||||||
import type {
|
import type {
|
||||||
|
@ -18,6 +17,7 @@ import type {
|
||||||
GlobalSidebar,
|
GlobalSidebar,
|
||||||
GlobalDoc,
|
GlobalDoc,
|
||||||
} from '@docusaurus/plugin-content-docs/client';
|
} from '@docusaurus/plugin-content-docs/client';
|
||||||
|
import type {Sidebars} from './sidebars/types';
|
||||||
|
|
||||||
function toGlobalDataDoc(doc: DocMetadata): GlobalDoc {
|
function toGlobalDataDoc(doc: DocMetadata): GlobalDoc {
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -6,7 +6,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
import _ from 'lodash';
|
||||||
|
import logger from '@docusaurus/logger';
|
||||||
import {
|
import {
|
||||||
normalizeUrl,
|
normalizeUrl,
|
||||||
docuHash,
|
docuHash,
|
||||||
|
@ -19,20 +20,15 @@ import {
|
||||||
createSlugger,
|
createSlugger,
|
||||||
DEFAULT_PLUGIN_ID,
|
DEFAULT_PLUGIN_ID,
|
||||||
} from '@docusaurus/utils';
|
} from '@docusaurus/utils';
|
||||||
import type {LoadContext, Plugin} from '@docusaurus/types';
|
|
||||||
import {loadSidebars, resolveSidebarPathOption} from './sidebars';
|
import {loadSidebars, resolveSidebarPathOption} from './sidebars';
|
||||||
import {CategoryMetadataFilenamePattern} from './sidebars/generator';
|
import {CategoryMetadataFilenamePattern} from './sidebars/generator';
|
||||||
import type {DocEnv} from './docs';
|
import {
|
||||||
import {readVersionDocs, processDocMetadata, addDocNavigation} from './docs';
|
readVersionDocs,
|
||||||
|
processDocMetadata,
|
||||||
|
addDocNavigation,
|
||||||
|
type DocEnv,
|
||||||
|
} from './docs';
|
||||||
import {readVersionsMetadata} from './versions';
|
import {readVersionsMetadata} from './versions';
|
||||||
import type {
|
|
||||||
SourceToPermalink,
|
|
||||||
DocFile,
|
|
||||||
DocsMarkdownOption,
|
|
||||||
VersionTag,
|
|
||||||
FullVersion,
|
|
||||||
} from './types';
|
|
||||||
import type {RuleSetRule} from 'webpack';
|
|
||||||
import {cliDocsVersionCommand} from './cli';
|
import {cliDocsVersionCommand} from './cli';
|
||||||
import {VERSIONS_JSON_FILE} from './constants';
|
import {VERSIONS_JSON_FILE} from './constants';
|
||||||
import {toGlobalDataVersion} from './globalData';
|
import {toGlobalDataVersion} from './globalData';
|
||||||
|
@ -42,9 +38,10 @@ import {
|
||||||
translateLoadedContent,
|
translateLoadedContent,
|
||||||
getLoadedContentTranslationFiles,
|
getLoadedContentTranslationFiles,
|
||||||
} from './translations';
|
} from './translations';
|
||||||
import logger from '@docusaurus/logger';
|
|
||||||
import {getVersionTags} from './tags';
|
import {getVersionTags} from './tags';
|
||||||
import {createVersionRoutes} from './routes';
|
import {createVersionRoutes} from './routes';
|
||||||
|
import {createSidebarsUtils} from './sidebars/utils';
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
PropTagsListPage,
|
PropTagsListPage,
|
||||||
PluginOptions,
|
PluginOptions,
|
||||||
|
@ -54,8 +51,15 @@ import type {
|
||||||
LoadedContent,
|
LoadedContent,
|
||||||
LoadedVersion,
|
LoadedVersion,
|
||||||
} from '@docusaurus/plugin-content-docs';
|
} from '@docusaurus/plugin-content-docs';
|
||||||
import {createSidebarsUtils} from './sidebars/utils';
|
import type {LoadContext, Plugin} from '@docusaurus/types';
|
||||||
import _ from 'lodash';
|
import type {
|
||||||
|
SourceToPermalink,
|
||||||
|
DocFile,
|
||||||
|
DocsMarkdownOption,
|
||||||
|
VersionTag,
|
||||||
|
FullVersion,
|
||||||
|
} from './types';
|
||||||
|
import type {RuleSetRule} from 'webpack';
|
||||||
|
|
||||||
export default async function pluginContentDocs(
|
export default async function pluginContentDocs(
|
||||||
context: LoadContext,
|
context: LoadContext,
|
||||||
|
|
|
@ -9,13 +9,13 @@ import {jest} from '@jest/globals';
|
||||||
import fs from 'fs-extra';
|
import fs from 'fs-extra';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import {linkify} from '../linkify';
|
import {linkify} from '../linkify';
|
||||||
|
import {VERSIONED_DOCS_DIR, CURRENT_VERSION_NAME} from '../../constants';
|
||||||
import type {
|
import type {
|
||||||
DocsMarkdownOption,
|
DocsMarkdownOption,
|
||||||
SourceToPermalink,
|
SourceToPermalink,
|
||||||
DocBrokenMarkdownLink,
|
DocBrokenMarkdownLink,
|
||||||
} from '../../types';
|
} from '../../types';
|
||||||
import type {VersionMetadata} from '@docusaurus/plugin-content-docs';
|
import type {VersionMetadata} from '@docusaurus/plugin-content-docs';
|
||||||
import {VERSIONED_DOCS_DIR, CURRENT_VERSION_NAME} from '../../constants';
|
|
||||||
|
|
||||||
function createFakeVersion({
|
function createFakeVersion({
|
||||||
versionName,
|
versionName,
|
||||||
|
|
|
@ -5,8 +5,8 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type {DocsMarkdownOption} from '../types';
|
|
||||||
import {replaceMarkdownLinks, getContentPathList} from '@docusaurus/utils';
|
import {replaceMarkdownLinks, getContentPathList} from '@docusaurus/utils';
|
||||||
|
import type {DocsMarkdownOption} from '../types';
|
||||||
|
|
||||||
function getVersion(filePath: string, options: DocsMarkdownOption) {
|
function getVersion(filePath: string, options: DocsMarkdownOption) {
|
||||||
const versionFound = options.versionsMetadata.find((version) =>
|
const versionFound = options.versionsMetadata.find((version) =>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type {PluginOptions, Options} from '@docusaurus/plugin-content-docs';
|
import logger from '@docusaurus/logger';
|
||||||
import {
|
import {
|
||||||
Joi,
|
Joi,
|
||||||
RemarkPluginsSchema,
|
RemarkPluginsSchema,
|
||||||
|
@ -14,15 +14,14 @@ import {
|
||||||
URISchema,
|
URISchema,
|
||||||
} from '@docusaurus/utils-validation';
|
} from '@docusaurus/utils-validation';
|
||||||
import {GlobExcludeDefault} from '@docusaurus/utils';
|
import {GlobExcludeDefault} from '@docusaurus/utils';
|
||||||
|
|
||||||
import type {OptionValidationContext} from '@docusaurus/types';
|
|
||||||
import logger from '@docusaurus/logger';
|
|
||||||
import admonitions from 'remark-admonitions';
|
import admonitions from 'remark-admonitions';
|
||||||
import {DefaultSidebarItemsGenerator} from './sidebars/generator';
|
import {DefaultSidebarItemsGenerator} from './sidebars/generator';
|
||||||
import {
|
import {
|
||||||
DefaultNumberPrefixParser,
|
DefaultNumberPrefixParser,
|
||||||
DisabledNumberPrefixParser,
|
DisabledNumberPrefixParser,
|
||||||
} from './numberPrefix';
|
} from './numberPrefix';
|
||||||
|
import type {OptionValidationContext} from '@docusaurus/types';
|
||||||
|
import type {PluginOptions, Options} from '@docusaurus/plugin-content-docs';
|
||||||
|
|
||||||
export const DEFAULT_OPTIONS: Omit<PluginOptions, 'id' | 'sidebarPath'> = {
|
export const DEFAULT_OPTIONS: Omit<PluginOptions, 'id' | 'sidebarPath'> = {
|
||||||
path: 'docs', // Path to data on filesystem, relative to site dir.
|
path: 'docs', // Path to data on filesystem, relative to site dir.
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import _ from 'lodash';
|
||||||
|
import {createDocsByIdIndex} from './docs';
|
||||||
import type {VersionTag} from './types';
|
import type {VersionTag} from './types';
|
||||||
import type {
|
import type {
|
||||||
SidebarItemDoc,
|
SidebarItemDoc,
|
||||||
|
@ -24,8 +26,6 @@ import type {
|
||||||
DocMetadata,
|
DocMetadata,
|
||||||
LoadedVersion,
|
LoadedVersion,
|
||||||
} from '@docusaurus/plugin-content-docs';
|
} from '@docusaurus/plugin-content-docs';
|
||||||
import _ from 'lodash';
|
|
||||||
import {createDocsByIdIndex} from './docs';
|
|
||||||
|
|
||||||
export function toSidebarsProp(loadedVersion: LoadedVersion): PropSidebars {
|
export function toSidebarsProp(loadedVersion: LoadedVersion): PropSidebars {
|
||||||
const docsById = createDocsByIdIndex(loadedVersion.docs);
|
const docsById = createDocsByIdIndex(loadedVersion.docs);
|
||||||
|
|
|
@ -5,15 +5,15 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type {PluginContentLoadedActions, RouteConfig} from '@docusaurus/types';
|
import logger from '@docusaurus/logger';
|
||||||
import {docuHash, createSlugger} from '@docusaurus/utils';
|
import {docuHash, createSlugger} from '@docusaurus/utils';
|
||||||
|
import {toVersionMetadataProp} from './props';
|
||||||
|
import type {PluginContentLoadedActions, RouteConfig} from '@docusaurus/types';
|
||||||
import type {FullVersion} from './types';
|
import type {FullVersion} from './types';
|
||||||
import type {
|
import type {
|
||||||
CategoryGeneratedIndexMetadata,
|
CategoryGeneratedIndexMetadata,
|
||||||
DocMetadata,
|
DocMetadata,
|
||||||
} from '@docusaurus/plugin-content-docs';
|
} from '@docusaurus/plugin-content-docs';
|
||||||
import {toVersionMetadataProp} from './props';
|
|
||||||
import logger from '@docusaurus/logger';
|
|
||||||
|
|
||||||
export async function createCategoryGeneratedIndexRoutes({
|
export async function createCategoryGeneratedIndexRoutes({
|
||||||
version,
|
version,
|
||||||
|
|
|
@ -6,4 +6,5 @@ This part is very complicated and hard to navigate. Sidebars are loaded through
|
||||||
2. **Normalization**. The shorthands are expanded. This step is very lenient about the sidebars' shapes. Returns `NormalizedSidebars`.
|
2. **Normalization**. The shorthands are expanded. This step is very lenient about the sidebars' shapes. Returns `NormalizedSidebars`.
|
||||||
3. **Validation**. The normalized sidebars are validated. This step happens after normalization, because the normalized sidebars are easier to validate, and allows us to repeatedly validate & generate in the future.
|
3. **Validation**. The normalized sidebars are validated. This step happens after normalization, because the normalized sidebars are easier to validate, and allows us to repeatedly validate & generate in the future.
|
||||||
4. **Generation**. This step is done through the "processor" (naming is hard). The `autogenerated` items are unwrapped. In the future, steps 3 and 4 may be repeatedly done until all autogenerated items are unwrapped. Returns `ProcessedSidebars`.
|
4. **Generation**. This step is done through the "processor" (naming is hard). The `autogenerated` items are unwrapped. In the future, steps 3 and 4 may be repeatedly done until all autogenerated items are unwrapped. Returns `ProcessedSidebars`.
|
||||||
|
- **Important**: this step should only care about unwrapping autogenerated items, not filtering them, writing additional metadata, applying defaults, etc.—everything will be handled in the post-processor. Important because the generator is exposed to the end-user and we want it to be easy to be reasoned about.
|
||||||
5. **Post-processing**. Defaults are applied (collapsed states), category links are resolved, empty categories are flattened. Returns `Sidebars`.
|
5. **Post-processing**. Defaults are applied (collapsed states), category links are resolved, empty categories are flattened. Returns `Sidebars`.
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
{
|
||||||
|
"docs": [
|
||||||
|
{
|
||||||
|
"label": "Tutorials",
|
||||||
|
"type": "category",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"type": "autogenerated",
|
||||||
|
"dirName": "tutorials"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "index-only",
|
||||||
|
"type": "category",
|
||||||
|
"link": {
|
||||||
|
"type": "doc",
|
||||||
|
"id": "tutorials/tutorial-basics"
|
||||||
|
},
|
||||||
|
"items": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
{
|
||||||
|
"sidebar": [
|
||||||
|
"draft1",
|
||||||
|
{
|
||||||
|
"type": "category",
|
||||||
|
"label": "all drafts",
|
||||||
|
"items": [
|
||||||
|
"draft2",
|
||||||
|
"draft3"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "category",
|
||||||
|
"label": "all drafts",
|
||||||
|
"link": {
|
||||||
|
"type": "generated-index"
|
||||||
|
},
|
||||||
|
"items": [
|
||||||
|
"draft2",
|
||||||
|
"draft3"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "category",
|
||||||
|
"label": "all drafts",
|
||||||
|
"link": {
|
||||||
|
"type": "doc",
|
||||||
|
"id": "draft1"
|
||||||
|
},
|
||||||
|
"items": [
|
||||||
|
"draft2",
|
||||||
|
"draft3"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "category",
|
||||||
|
"label": "index not draft",
|
||||||
|
"link": {
|
||||||
|
"type": "doc",
|
||||||
|
"id": "not-draft"
|
||||||
|
},
|
||||||
|
"items": [
|
||||||
|
"draft2",
|
||||||
|
"draft3"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "category",
|
||||||
|
"label": "subitem not draft",
|
||||||
|
"link": {
|
||||||
|
"type": "doc",
|
||||||
|
"id": "draft1"
|
||||||
|
},
|
||||||
|
"items": [
|
||||||
|
"not-draft",
|
||||||
|
"draft3"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -1,5 +1,56 @@
|
||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`loadSidebars loads sidebars with index-only categories 1`] = `
|
||||||
|
{
|
||||||
|
"docs": [
|
||||||
|
{
|
||||||
|
"collapsed": true,
|
||||||
|
"collapsible": true,
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"id": "tutorials/tutorial-basics",
|
||||||
|
"label": "tutorial-basics",
|
||||||
|
"type": "doc",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"label": "Tutorials",
|
||||||
|
"link": undefined,
|
||||||
|
"type": "category",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "tutorials/tutorial-basics",
|
||||||
|
"label": "index-only",
|
||||||
|
"type": "doc",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`loadSidebars loads sidebars with interspersed draft items 1`] = `
|
||||||
|
{
|
||||||
|
"sidebar": [
|
||||||
|
{
|
||||||
|
"id": "not-draft",
|
||||||
|
"label": "index not draft",
|
||||||
|
"type": "doc",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"collapsed": true,
|
||||||
|
"collapsible": true,
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"id": "not-draft",
|
||||||
|
"type": "doc",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"label": "subitem not draft",
|
||||||
|
"link": undefined,
|
||||||
|
"type": "category",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`loadSidebars sidebars link 1`] = `
|
exports[`loadSidebars sidebars link 1`] = `
|
||||||
{
|
{
|
||||||
"docs": [
|
"docs": [
|
||||||
|
|
|
@ -60,14 +60,21 @@ exports[`postProcess corrects collapsed state inconsistencies 3`] = `
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`postProcess transforms category without subitems 1`] = `
|
exports[`postProcess filters draft items 1`] = `
|
||||||
{
|
{
|
||||||
"sidebar": [
|
"sidebar": [
|
||||||
{
|
{
|
||||||
"href": "version/generated/permalink",
|
"id": "another",
|
||||||
"label": "Category",
|
"label": "Category",
|
||||||
"type": "link",
|
"type": "doc",
|
||||||
},
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`postProcess transforms category without subitems 1`] = `
|
||||||
|
{
|
||||||
|
"sidebar": [
|
||||||
{
|
{
|
||||||
"id": "doc ID",
|
"id": "doc ID",
|
||||||
"label": "Category 2",
|
"label": "Category 2",
|
||||||
|
|
|
@ -7,9 +7,9 @@
|
||||||
|
|
||||||
import {jest} from '@jest/globals';
|
import {jest} from '@jest/globals';
|
||||||
import {DefaultSidebarItemsGenerator} from '../generator';
|
import {DefaultSidebarItemsGenerator} from '../generator';
|
||||||
import type {SidebarItemsGenerator} from '../types';
|
|
||||||
import {DefaultNumberPrefixParser} from '../../numberPrefix';
|
import {DefaultNumberPrefixParser} from '../../numberPrefix';
|
||||||
import {isCategoryIndex} from '../../docs';
|
import {isCategoryIndex} from '../../docs';
|
||||||
|
import type {SidebarItemsGenerator} from '../types';
|
||||||
|
|
||||||
describe('DefaultSidebarItemsGenerator', () => {
|
describe('DefaultSidebarItemsGenerator', () => {
|
||||||
function testDefaultSidebarItemsGenerator(
|
function testDefaultSidebarItemsGenerator(
|
||||||
|
|
|
@ -7,9 +7,10 @@
|
||||||
|
|
||||||
import {jest} from '@jest/globals';
|
import {jest} from '@jest/globals';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
import {createSlugger} from '@docusaurus/utils';
|
||||||
import {loadSidebars, DisabledSidebars} from '../index';
|
import {loadSidebars, DisabledSidebars} from '../index';
|
||||||
import type {SidebarProcessorParams} from '../types';
|
|
||||||
import {DefaultSidebarItemsGenerator} from '../generator';
|
import {DefaultSidebarItemsGenerator} from '../generator';
|
||||||
|
import type {SidebarProcessorParams} from '../types';
|
||||||
import type {DocMetadata} from '@docusaurus/plugin-content-docs';
|
import type {DocMetadata} from '@docusaurus/plugin-content-docs';
|
||||||
|
|
||||||
describe('loadSidebars', () => {
|
describe('loadSidebars', () => {
|
||||||
|
@ -27,6 +28,7 @@ describe('loadSidebars', () => {
|
||||||
],
|
],
|
||||||
drafts: [],
|
drafts: [],
|
||||||
version: {
|
version: {
|
||||||
|
path: 'version',
|
||||||
contentPath: path.join(fixtureDir, 'docs'),
|
contentPath: path.join(fixtureDir, 'docs'),
|
||||||
contentPathLocalized: path.join(fixtureDir, 'docs'),
|
contentPathLocalized: path.join(fixtureDir, 'docs'),
|
||||||
},
|
},
|
||||||
|
@ -124,6 +126,32 @@ describe('loadSidebars', () => {
|
||||||
expect(result).toMatchSnapshot();
|
expect(result).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('loads sidebars with index-only categories', async () => {
|
||||||
|
const sidebarPath = path.join(fixtureDir, 'sidebars-category-index.json');
|
||||||
|
const result = await loadSidebars(sidebarPath, {
|
||||||
|
...params,
|
||||||
|
docs: [
|
||||||
|
{
|
||||||
|
id: 'tutorials/tutorial-basics',
|
||||||
|
source: '@site/docs/tutorials/tutorial-basics/index.md',
|
||||||
|
sourceDirName: 'tutorials/tutorial-basics',
|
||||||
|
frontMatter: {},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
expect(result).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('loads sidebars with interspersed draft items', async () => {
|
||||||
|
const sidebarPath = path.join(fixtureDir, 'sidebars-drafts.json');
|
||||||
|
const result = await loadSidebars(sidebarPath, {
|
||||||
|
...params,
|
||||||
|
drafts: [{id: 'draft1'}, {id: 'draft2'}, {id: 'draft3'}],
|
||||||
|
categoryLabelSlugger: createSlugger(),
|
||||||
|
});
|
||||||
|
expect(result).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
it('duplicate category metadata files', async () => {
|
it('duplicate category metadata files', async () => {
|
||||||
const sidebarPath = path.join(
|
const sidebarPath = path.join(
|
||||||
fixtureDir,
|
fixtureDir,
|
||||||
|
|
|
@ -35,6 +35,7 @@ describe('postProcess', () => {
|
||||||
{
|
{
|
||||||
sidebarOptions: {sidebarCollapsed: true, sidebarCollapsible: true},
|
sidebarOptions: {sidebarCollapsed: true, sidebarCollapsible: true},
|
||||||
version: {path: 'version'},
|
version: {path: 'version'},
|
||||||
|
drafts: [],
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -54,6 +55,7 @@ describe('postProcess', () => {
|
||||||
{
|
{
|
||||||
sidebarOptions: {sidebarCollapsed: true, sidebarCollapsible: true},
|
sidebarOptions: {sidebarCollapsed: true, sidebarCollapsible: true},
|
||||||
version: {path: 'version'},
|
version: {path: 'version'},
|
||||||
|
drafts: [],
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}).toThrowErrorMatchingInlineSnapshot(
|
}).toThrowErrorMatchingInlineSnapshot(
|
||||||
|
@ -79,6 +81,7 @@ describe('postProcess', () => {
|
||||||
{
|
{
|
||||||
sidebarOptions: {sidebarCollapsed: true, sidebarCollapsible: true},
|
sidebarOptions: {sidebarCollapsed: true, sidebarCollapsible: true},
|
||||||
version: {path: 'version'},
|
version: {path: 'version'},
|
||||||
|
drafts: [],
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
).toMatchSnapshot();
|
).toMatchSnapshot();
|
||||||
|
@ -99,6 +102,7 @@ describe('postProcess', () => {
|
||||||
{
|
{
|
||||||
sidebarOptions: {sidebarCollapsed: false, sidebarCollapsible: false},
|
sidebarOptions: {sidebarCollapsed: false, sidebarCollapsible: false},
|
||||||
version: {path: 'version'},
|
version: {path: 'version'},
|
||||||
|
drafts: [],
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
).toMatchSnapshot();
|
).toMatchSnapshot();
|
||||||
|
@ -118,6 +122,37 @@ describe('postProcess', () => {
|
||||||
{
|
{
|
||||||
sidebarOptions: {sidebarCollapsed: true, sidebarCollapsible: false},
|
sidebarOptions: {sidebarCollapsed: true, sidebarCollapsible: false},
|
||||||
version: {path: 'version'},
|
version: {path: 'version'},
|
||||||
|
drafts: [],
|
||||||
|
},
|
||||||
|
),
|
||||||
|
).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('filters draft items', () => {
|
||||||
|
expect(
|
||||||
|
postProcessSidebars(
|
||||||
|
{
|
||||||
|
sidebar: [
|
||||||
|
{
|
||||||
|
type: 'category',
|
||||||
|
label: 'Category',
|
||||||
|
items: [{type: 'doc', id: 'foo'}],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'category',
|
||||||
|
label: 'Category',
|
||||||
|
link: {
|
||||||
|
type: 'doc',
|
||||||
|
id: 'another',
|
||||||
|
},
|
||||||
|
items: [{type: 'doc', id: 'foo'}],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
sidebarOptions: {sidebarCollapsed: true, sidebarCollapsible: true},
|
||||||
|
version: {path: 'version'},
|
||||||
|
drafts: [{id: 'foo', unversionedId: 'foo'}],
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
).toMatchSnapshot();
|
).toMatchSnapshot();
|
||||||
|
|
|
@ -6,7 +6,11 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {jest} from '@jest/globals';
|
import {jest} from '@jest/globals';
|
||||||
|
import {createSlugger} from '@docusaurus/utils';
|
||||||
import {processSidebars} from '../processor';
|
import {processSidebars} from '../processor';
|
||||||
|
import {DefaultSidebarItemsGenerator} from '../generator';
|
||||||
|
import {DefaultNumberPrefixParser} from '../../numberPrefix';
|
||||||
|
import {isCategoryIndex} from '../../docs';
|
||||||
import type {
|
import type {
|
||||||
SidebarItem,
|
SidebarItem,
|
||||||
SidebarItemsGenerator,
|
SidebarItemsGenerator,
|
||||||
|
@ -16,11 +20,7 @@ import type {
|
||||||
CategoryMetadataFile,
|
CategoryMetadataFile,
|
||||||
ProcessedSidebars,
|
ProcessedSidebars,
|
||||||
} from '../types';
|
} from '../types';
|
||||||
import {DefaultSidebarItemsGenerator} from '../generator';
|
|
||||||
import {createSlugger} from '@docusaurus/utils';
|
|
||||||
import type {VersionMetadata} from '@docusaurus/plugin-content-docs';
|
import type {VersionMetadata} from '@docusaurus/plugin-content-docs';
|
||||||
import {DefaultNumberPrefixParser} from '../../numberPrefix';
|
|
||||||
import {isCategoryIndex} from '../../docs';
|
|
||||||
|
|
||||||
describe('processSidebars', () => {
|
describe('processSidebars', () => {
|
||||||
function createStaticSidebarItemGenerator(
|
function createStaticSidebarItemGenerator(
|
||||||
|
|
|
@ -5,6 +5,11 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import path from 'path';
|
||||||
|
import _ from 'lodash';
|
||||||
|
import logger from '@docusaurus/logger';
|
||||||
|
import {addTrailingSlash} from '@docusaurus/utils';
|
||||||
|
import {createDocsByIdIndex, toCategoryIndexMatcherParam} from '../docs';
|
||||||
import type {
|
import type {
|
||||||
SidebarItemDoc,
|
SidebarItemDoc,
|
||||||
SidebarItemsGenerator,
|
SidebarItemsGenerator,
|
||||||
|
@ -13,11 +18,6 @@ import type {
|
||||||
NormalizedSidebarItem,
|
NormalizedSidebarItem,
|
||||||
SidebarItemCategoryLinkConfig,
|
SidebarItemCategoryLinkConfig,
|
||||||
} from './types';
|
} from './types';
|
||||||
import _ from 'lodash';
|
|
||||||
import {addTrailingSlash} from '@docusaurus/utils';
|
|
||||||
import logger from '@docusaurus/logger';
|
|
||||||
import path from 'path';
|
|
||||||
import {createDocsByIdIndex, toCategoryIndexMatcherParam} from '../docs';
|
|
||||||
|
|
||||||
const BreadcrumbSeparator = '/';
|
const BreadcrumbSeparator = '/';
|
||||||
|
|
||||||
|
|
|
@ -6,19 +6,19 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import fs from 'fs-extra';
|
import fs from 'fs-extra';
|
||||||
|
import path from 'path';
|
||||||
|
import _ from 'lodash';
|
||||||
|
import logger from '@docusaurus/logger';
|
||||||
|
import {Globby} from '@docusaurus/utils';
|
||||||
|
import Yaml from 'js-yaml';
|
||||||
|
import combinePromises from 'combine-promises';
|
||||||
import importFresh from 'import-fresh';
|
import importFresh from 'import-fresh';
|
||||||
import type {SidebarsConfig, Sidebars, SidebarProcessorParams} from './types';
|
|
||||||
import {validateSidebars, validateCategoryMetadataFile} from './validation';
|
import {validateSidebars, validateCategoryMetadataFile} from './validation';
|
||||||
import {normalizeSidebars} from './normalization';
|
import {normalizeSidebars} from './normalization';
|
||||||
import {processSidebars} from './processor';
|
import {processSidebars} from './processor';
|
||||||
import {postProcessSidebars} from './postProcessor';
|
import {postProcessSidebars} from './postProcessor';
|
||||||
import path from 'path';
|
|
||||||
import {Globby} from '@docusaurus/utils';
|
|
||||||
import logger from '@docusaurus/logger';
|
|
||||||
import type {PluginOptions} from '@docusaurus/plugin-content-docs';
|
import type {PluginOptions} from '@docusaurus/plugin-content-docs';
|
||||||
import Yaml from 'js-yaml';
|
import type {SidebarsConfig, Sidebars, SidebarProcessorParams} from './types';
|
||||||
import _ from 'lodash';
|
|
||||||
import combinePromises from 'combine-promises';
|
|
||||||
|
|
||||||
export const DefaultSidebars: SidebarsConfig = {
|
export const DefaultSidebars: SidebarsConfig = {
|
||||||
defaultSidebar: [
|
defaultSidebar: [
|
||||||
|
|
|
@ -5,6 +5,9 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import _ from 'lodash';
|
||||||
|
import logger from '@docusaurus/logger';
|
||||||
|
import {isCategoriesShorthand} from './utils';
|
||||||
import type {
|
import type {
|
||||||
NormalizedSidebarItem,
|
NormalizedSidebarItem,
|
||||||
NormalizedSidebar,
|
NormalizedSidebar,
|
||||||
|
@ -16,9 +19,6 @@ import type {
|
||||||
SidebarsConfig,
|
SidebarsConfig,
|
||||||
NormalizedSidebarItemCategory,
|
NormalizedSidebarItemCategory,
|
||||||
} from './types';
|
} from './types';
|
||||||
import {isCategoriesShorthand} from './utils';
|
|
||||||
import _ from 'lodash';
|
|
||||||
import logger from '@docusaurus/logger';
|
|
||||||
|
|
||||||
function normalizeCategoriesShorthand(
|
function normalizeCategoriesShorthand(
|
||||||
sidebar: SidebarCategoriesShorthand,
|
sidebar: SidebarCategoriesShorthand,
|
||||||
|
|
|
@ -5,7 +5,9 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import _ from 'lodash';
|
||||||
import {normalizeUrl} from '@docusaurus/utils';
|
import {normalizeUrl} from '@docusaurus/utils';
|
||||||
|
import {getDocIds} from '../docs';
|
||||||
import type {
|
import type {
|
||||||
SidebarItem,
|
SidebarItem,
|
||||||
Sidebars,
|
Sidebars,
|
||||||
|
@ -15,12 +17,18 @@ import type {
|
||||||
ProcessedSidebars,
|
ProcessedSidebars,
|
||||||
SidebarItemCategoryLink,
|
SidebarItemCategoryLink,
|
||||||
} from './types';
|
} from './types';
|
||||||
import _ from 'lodash';
|
|
||||||
|
type SidebarPostProcessorParams = SidebarProcessorParams & {
|
||||||
|
draftIds: Set<string>;
|
||||||
|
};
|
||||||
|
|
||||||
function normalizeCategoryLink(
|
function normalizeCategoryLink(
|
||||||
category: ProcessedSidebarItemCategory,
|
category: ProcessedSidebarItemCategory,
|
||||||
params: SidebarProcessorParams,
|
params: SidebarPostProcessorParams,
|
||||||
): SidebarItemCategoryLink | undefined {
|
): SidebarItemCategoryLink | undefined {
|
||||||
|
if (category.link?.type === 'doc' && params.draftIds.has(category.link.id)) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
if (category.link?.type === 'generated-index') {
|
if (category.link?.type === 'generated-index') {
|
||||||
// Default slug logic can be improved
|
// Default slug logic can be improved
|
||||||
const getDefaultSlug = () =>
|
const getDefaultSlug = () =>
|
||||||
|
@ -38,37 +46,42 @@ function normalizeCategoryLink(
|
||||||
|
|
||||||
function postProcessSidebarItem(
|
function postProcessSidebarItem(
|
||||||
item: ProcessedSidebarItem,
|
item: ProcessedSidebarItem,
|
||||||
params: SidebarProcessorParams,
|
params: SidebarPostProcessorParams,
|
||||||
): SidebarItem {
|
): SidebarItem | null {
|
||||||
if (item.type === 'category') {
|
if (item.type === 'category') {
|
||||||
|
// Fail-fast if there's actually no subitems, no because all subitems are
|
||||||
|
// drafts. This is likely a configuration mistake.
|
||||||
|
if (item.items.length === 0 && !item.link) {
|
||||||
|
throw new Error(
|
||||||
|
`Sidebar category ${item.label} has neither any subitem nor a link. This makes this item not able to link to anything.`,
|
||||||
|
);
|
||||||
|
}
|
||||||
const category = {
|
const category = {
|
||||||
...item,
|
...item,
|
||||||
collapsed: item.collapsed ?? params.sidebarOptions.sidebarCollapsed,
|
collapsed: item.collapsed ?? params.sidebarOptions.sidebarCollapsed,
|
||||||
collapsible: item.collapsible ?? params.sidebarOptions.sidebarCollapsible,
|
collapsible: item.collapsible ?? params.sidebarOptions.sidebarCollapsible,
|
||||||
link: normalizeCategoryLink(item, params),
|
link: normalizeCategoryLink(item, params),
|
||||||
items: item.items.map((subItem) =>
|
items: item.items
|
||||||
postProcessSidebarItem(subItem, params),
|
.map((subItem) => postProcessSidebarItem(subItem, params))
|
||||||
),
|
.filter((v): v is SidebarItem => Boolean(v)),
|
||||||
};
|
};
|
||||||
// If the current category doesn't have subitems, we render a normal link
|
// If the current category doesn't have subitems, we render a normal link
|
||||||
// instead.
|
// instead.
|
||||||
if (category.items.length === 0) {
|
if (category.items.length === 0) {
|
||||||
if (!category.link) {
|
// Doesn't make sense to render an empty generated index page, so we
|
||||||
throw new Error(
|
// filter the entire category out as well.
|
||||||
`Sidebar category ${item.label} has neither any subitem nor a link. This makes this item not able to link to anything.`,
|
if (
|
||||||
);
|
!category.link ||
|
||||||
|
category.link.type === 'generated-index' ||
|
||||||
|
params.draftIds.has(category.link.id)
|
||||||
|
) {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
return category.link.type === 'doc'
|
return {
|
||||||
? {
|
type: 'doc',
|
||||||
type: 'doc',
|
label: category.label,
|
||||||
label: category.label,
|
id: category.link.id,
|
||||||
id: category.link.id,
|
};
|
||||||
}
|
|
||||||
: {
|
|
||||||
type: 'link',
|
|
||||||
label: category.label,
|
|
||||||
href: category.link.permalink,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
// A non-collapsible category can't be collapsed!
|
// A non-collapsible category can't be collapsed!
|
||||||
if (category.collapsible === false) {
|
if (category.collapsible === false) {
|
||||||
|
@ -76,6 +89,12 @@ function postProcessSidebarItem(
|
||||||
}
|
}
|
||||||
return category;
|
return category;
|
||||||
}
|
}
|
||||||
|
if (
|
||||||
|
(item.type === 'doc' || item.type === 'ref') &&
|
||||||
|
params.draftIds.has(item.id)
|
||||||
|
) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,7 +102,11 @@ export function postProcessSidebars(
|
||||||
sidebars: ProcessedSidebars,
|
sidebars: ProcessedSidebars,
|
||||||
params: SidebarProcessorParams,
|
params: SidebarProcessorParams,
|
||||||
): Sidebars {
|
): Sidebars {
|
||||||
|
const draftIds = new Set(params.drafts.flatMap(getDocIds));
|
||||||
|
|
||||||
return _.mapValues(sidebars, (sidebar) =>
|
return _.mapValues(sidebars, (sidebar) =>
|
||||||
sidebar.map((item) => postProcessSidebarItem(item, params)),
|
sidebar
|
||||||
|
.map((item) => postProcessSidebarItem(item, {...params, draftIds}))
|
||||||
|
.filter((v): v is SidebarItem => Boolean(v)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,11 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import _ from 'lodash';
|
||||||
|
import combinePromises from 'combine-promises';
|
||||||
|
import {DefaultSidebarItemsGenerator} from './generator';
|
||||||
|
import {validateSidebars} from './validation';
|
||||||
|
import {isCategoryIndex} from '../docs';
|
||||||
import type {
|
import type {
|
||||||
DocMetadataBase,
|
DocMetadataBase,
|
||||||
VersionMetadata,
|
VersionMetadata,
|
||||||
|
@ -22,11 +27,6 @@ import type {
|
||||||
SidebarProcessorParams,
|
SidebarProcessorParams,
|
||||||
CategoryMetadataFile,
|
CategoryMetadataFile,
|
||||||
} from './types';
|
} from './types';
|
||||||
import {DefaultSidebarItemsGenerator} from './generator';
|
|
||||||
import {validateSidebars} from './validation';
|
|
||||||
import _ from 'lodash';
|
|
||||||
import combinePromises from 'combine-promises';
|
|
||||||
import {getDocIds, isCategoryIndex} from '../docs';
|
|
||||||
|
|
||||||
function toSidebarItemsGeneratorDoc(
|
function toSidebarItemsGeneratorDoc(
|
||||||
doc: DocMetadataBase,
|
doc: DocMetadataBase,
|
||||||
|
@ -55,8 +55,7 @@ async function processSidebar(
|
||||||
categoriesMetadata: {[filePath: string]: CategoryMetadataFile},
|
categoriesMetadata: {[filePath: string]: CategoryMetadataFile},
|
||||||
params: SidebarProcessorParams,
|
params: SidebarProcessorParams,
|
||||||
): Promise<ProcessedSidebar> {
|
): Promise<ProcessedSidebar> {
|
||||||
const {sidebarItemsGenerator, numberPrefixParser, docs, drafts, version} =
|
const {sidebarItemsGenerator, numberPrefixParser, docs, version} = params;
|
||||||
params;
|
|
||||||
|
|
||||||
// Just a minor lazy transformation optimization
|
// Just a minor lazy transformation optimization
|
||||||
const getSidebarItemsGeneratorDocsAndVersion = _.memoize(() => ({
|
const getSidebarItemsGeneratorDocsAndVersion = _.memoize(() => ({
|
||||||
|
@ -82,19 +81,6 @@ async function processSidebar(
|
||||||
return processItems(generatedItems);
|
return processItems(generatedItems);
|
||||||
}
|
}
|
||||||
|
|
||||||
const draftIds = new Set(drafts.flatMap(getDocIds));
|
|
||||||
|
|
||||||
const isDraftItem = (item: NormalizedSidebarItem): boolean => {
|
|
||||||
if (item.type === 'doc' || item.type === 'ref') {
|
|
||||||
return draftIds.has(item.id);
|
|
||||||
}
|
|
||||||
// If a category only contains draft items, it should be filtered entirely.
|
|
||||||
if (item.type === 'category') {
|
|
||||||
return item.items.every(isDraftItem);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
async function processItem(
|
async function processItem(
|
||||||
item: NormalizedSidebarItem,
|
item: NormalizedSidebarItem,
|
||||||
): Promise<ProcessedSidebarItem[]> {
|
): Promise<ProcessedSidebarItem[]> {
|
||||||
|
@ -102,7 +88,7 @@ async function processSidebar(
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
...item,
|
...item,
|
||||||
items: await processItems(item.items),
|
items: (await Promise.all(item.items.map(processItem))).flat(),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -115,9 +101,7 @@ async function processSidebar(
|
||||||
async function processItems(
|
async function processItems(
|
||||||
items: NormalizedSidebarItem[],
|
items: NormalizedSidebarItem[],
|
||||||
): Promise<ProcessedSidebarItem[]> {
|
): Promise<ProcessedSidebarItem[]> {
|
||||||
return (
|
return (await Promise.all(items.map(processItem))).flat();
|
||||||
await Promise.all(items.filter((i) => !isDraftItem(i)).map(processItem))
|
|
||||||
).flat();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const processedSidebar = await processItems(unprocessedSidebar);
|
const processedSidebar = await processItems(unprocessedSidebar);
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import _ from 'lodash';
|
||||||
|
import {toMessageRelativeFilePath} from '@docusaurus/utils';
|
||||||
import type {
|
import type {
|
||||||
Sidebars,
|
Sidebars,
|
||||||
Sidebar,
|
Sidebar,
|
||||||
|
@ -18,9 +20,6 @@ import type {
|
||||||
SidebarItemCategoryWithGeneratedIndex,
|
SidebarItemCategoryWithGeneratedIndex,
|
||||||
SidebarNavigationItem,
|
SidebarNavigationItem,
|
||||||
} from './types';
|
} from './types';
|
||||||
|
|
||||||
import _ from 'lodash';
|
|
||||||
import {toMessageRelativeFilePath} from '@docusaurus/utils';
|
|
||||||
import type {
|
import type {
|
||||||
DocMetadataBase,
|
DocMetadataBase,
|
||||||
PropNavigationLink,
|
PropNavigationLink,
|
||||||
|
|
|
@ -5,10 +5,10 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import _ from 'lodash';
|
||||||
import {groupTaggedItems} from '@docusaurus/utils';
|
import {groupTaggedItems} from '@docusaurus/utils';
|
||||||
import type {VersionTags} from './types';
|
import type {VersionTags} from './types';
|
||||||
import type {DocMetadata} from '@docusaurus/plugin-content-docs';
|
import type {DocMetadata} from '@docusaurus/plugin-content-docs';
|
||||||
import _ from 'lodash';
|
|
||||||
|
|
||||||
export function getVersionTags(docs: DocMetadata[]): VersionTags {
|
export function getVersionTags(docs: DocMetadata[]): VersionTags {
|
||||||
const groups = groupTaggedItems(docs, (doc) => doc.tags);
|
const groups = groupTaggedItems(docs, (doc) => doc.tags);
|
||||||
|
|
|
@ -5,6 +5,14 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import _ from 'lodash';
|
||||||
|
import {mergeTranslations} from '@docusaurus/utils';
|
||||||
|
import {CURRENT_VERSION_NAME} from './constants';
|
||||||
|
import {
|
||||||
|
collectSidebarCategories,
|
||||||
|
transformSidebarItems,
|
||||||
|
collectSidebarLinks,
|
||||||
|
} from './sidebars/utils';
|
||||||
import type {
|
import type {
|
||||||
LoadedVersion,
|
LoadedVersion,
|
||||||
LoadedContent,
|
LoadedContent,
|
||||||
|
@ -15,20 +23,11 @@ import type {
|
||||||
SidebarItemCategoryLink,
|
SidebarItemCategoryLink,
|
||||||
Sidebars,
|
Sidebars,
|
||||||
} from './sidebars/types';
|
} from './sidebars/types';
|
||||||
|
|
||||||
import _ from 'lodash';
|
|
||||||
import {
|
|
||||||
collectSidebarCategories,
|
|
||||||
transformSidebarItems,
|
|
||||||
collectSidebarLinks,
|
|
||||||
} from './sidebars/utils';
|
|
||||||
import type {
|
import type {
|
||||||
TranslationFileContent,
|
TranslationFileContent,
|
||||||
TranslationFile,
|
TranslationFile,
|
||||||
TranslationMessage,
|
TranslationMessage,
|
||||||
} from '@docusaurus/types';
|
} from '@docusaurus/types';
|
||||||
import {mergeTranslations} from '@docusaurus/utils';
|
|
||||||
import {CURRENT_VERSION_NAME} from './constants';
|
|
||||||
|
|
||||||
function getVersionFileName(versionName: string): string {
|
function getVersionFileName(versionName: string): string {
|
||||||
if (versionName === CURRENT_VERSION_NAME) {
|
if (versionName === CURRENT_VERSION_NAME) {
|
||||||
|
|
|
@ -7,9 +7,9 @@
|
||||||
|
|
||||||
import {jest} from '@jest/globals';
|
import {jest} from '@jest/globals';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
import {DEFAULT_PLUGIN_ID} from '@docusaurus/utils';
|
||||||
import {readVersionsMetadata} from '../index';
|
import {readVersionsMetadata} from '../index';
|
||||||
import {DEFAULT_OPTIONS} from '../../options';
|
import {DEFAULT_OPTIONS} from '../../options';
|
||||||
import {DEFAULT_PLUGIN_ID} from '@docusaurus/utils';
|
|
||||||
import type {I18n} from '@docusaurus/types';
|
import type {I18n} from '@docusaurus/types';
|
||||||
import type {
|
import type {
|
||||||
PluginOptions,
|
PluginOptions,
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import fs from 'fs-extra';
|
import fs from 'fs-extra';
|
||||||
|
import {getPluginI18nPath, DEFAULT_PLUGIN_ID} from '@docusaurus/utils';
|
||||||
import {
|
import {
|
||||||
VERSIONS_JSON_FILE,
|
VERSIONS_JSON_FILE,
|
||||||
VERSIONED_DOCS_DIR,
|
VERSIONED_DOCS_DIR,
|
||||||
|
@ -14,7 +15,6 @@ import {
|
||||||
CURRENT_VERSION_NAME,
|
CURRENT_VERSION_NAME,
|
||||||
} from '../constants';
|
} from '../constants';
|
||||||
import {validateVersionNames} from './validation';
|
import {validateVersionNames} from './validation';
|
||||||
import {getPluginI18nPath, DEFAULT_PLUGIN_ID} from '@docusaurus/utils';
|
|
||||||
import type {
|
import type {
|
||||||
PluginOptions,
|
PluginOptions,
|
||||||
VersionMetadata,
|
VersionMetadata,
|
||||||
|
|
|
@ -6,8 +6,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import {CURRENT_VERSION_NAME} from '../constants';
|
|
||||||
import {normalizeUrl, posixPath} from '@docusaurus/utils';
|
import {normalizeUrl, posixPath} from '@docusaurus/utils';
|
||||||
|
import {CURRENT_VERSION_NAME} from '../constants';
|
||||||
import {validateVersionsOptions} from './validation';
|
import {validateVersionsOptions} from './validation';
|
||||||
import {
|
import {
|
||||||
getDocsDirPathLocalized,
|
getDocsDirPathLocalized,
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
"fs-extra": "^10.1.0",
|
"fs-extra": "^10.1.0",
|
||||||
"remark-admonitions": "^1.2.1",
|
"remark-admonitions": "^1.2.1",
|
||||||
"tslib": "^2.4.0",
|
"tslib": "^2.4.0",
|
||||||
"webpack": "^5.72.0"
|
"webpack": "^5.72.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@docusaurus/types": "2.0.0-beta.20"
|
"@docusaurus/types": "2.0.0-beta.20"
|
||||||
|
|
|
@ -7,10 +7,10 @@
|
||||||
|
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import {loadContext} from '@docusaurus/core/lib/server';
|
import {loadContext} from '@docusaurus/core/lib/server';
|
||||||
|
import {normalizePluginOptions} from '@docusaurus/utils-validation';
|
||||||
|
|
||||||
import pluginContentPages from '../index';
|
import pluginContentPages from '../index';
|
||||||
import {validateOptions} from '../options';
|
import {validateOptions} from '../options';
|
||||||
import {normalizePluginOptions} from '@docusaurus/utils-validation';
|
|
||||||
|
|
||||||
describe('docusaurus-plugin-content-pages', () => {
|
describe('docusaurus-plugin-content-pages', () => {
|
||||||
it('loads simple pages', async () => {
|
it('loads simple pages', async () => {
|
||||||
|
|
|
@ -5,8 +5,8 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {validateOptions, DEFAULT_OPTIONS} from '../options';
|
|
||||||
import {normalizePluginOptions} from '@docusaurus/utils-validation';
|
import {normalizePluginOptions} from '@docusaurus/utils-validation';
|
||||||
|
import {validateOptions, DEFAULT_OPTIONS} from '../options';
|
||||||
import type {Options} from '@docusaurus/plugin-content-pages';
|
import type {Options} from '@docusaurus/plugin-content-pages';
|
||||||
|
|
||||||
function testValidate(options: Options) {
|
function testValidate(options: Options) {
|
||||||
|
|
|
@ -21,10 +21,10 @@ import {
|
||||||
DEFAULT_PLUGIN_ID,
|
DEFAULT_PLUGIN_ID,
|
||||||
parseMarkdownString,
|
parseMarkdownString,
|
||||||
} from '@docusaurus/utils';
|
} from '@docusaurus/utils';
|
||||||
import type {LoadContext, Plugin} from '@docusaurus/types';
|
|
||||||
import admonitions from 'remark-admonitions';
|
import admonitions from 'remark-admonitions';
|
||||||
import {validatePageFrontMatter} from './frontMatter';
|
import {validatePageFrontMatter} from './frontMatter';
|
||||||
|
|
||||||
|
import type {LoadContext, Plugin} from '@docusaurus/types';
|
||||||
import type {PagesContentPaths} from './types';
|
import type {PagesContentPaths} from './types';
|
||||||
import type {
|
import type {
|
||||||
PluginOptions,
|
PluginOptions,
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type {PluginOptions, Options} from '@docusaurus/plugin-content-pages';
|
|
||||||
import {
|
import {
|
||||||
Joi,
|
Joi,
|
||||||
RemarkPluginsSchema,
|
RemarkPluginsSchema,
|
||||||
|
@ -14,6 +13,7 @@ import {
|
||||||
} from '@docusaurus/utils-validation';
|
} from '@docusaurus/utils-validation';
|
||||||
import {GlobExcludeDefault} from '@docusaurus/utils';
|
import {GlobExcludeDefault} from '@docusaurus/utils';
|
||||||
import type {OptionValidationContext} from '@docusaurus/types';
|
import type {OptionValidationContext} from '@docusaurus/types';
|
||||||
|
import type {PluginOptions, Options} from '@docusaurus/plugin-content-pages';
|
||||||
|
|
||||||
export const DEFAULT_OPTIONS: PluginOptions = {
|
export const DEFAULT_OPTIONS: PluginOptions = {
|
||||||
path: 'src/pages', // Path to data on filesystem, relative to site dir.
|
path: 'src/pages', // Path to data on filesystem, relative to site dir.
|
||||||
|
|
|
@ -5,9 +5,9 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type {LoadContext, Plugin} from '@docusaurus/types';
|
|
||||||
import {docuHash, normalizeUrl, posixPath} from '@docusaurus/utils';
|
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
import {docuHash, normalizeUrl, posixPath} from '@docusaurus/utils';
|
||||||
|
import type {LoadContext, Plugin} from '@docusaurus/types';
|
||||||
|
|
||||||
export default function pluginDebug({
|
export default function pluginDebug({
|
||||||
siteConfig: {baseUrl},
|
siteConfig: {baseUrl},
|
||||||
|
|
|
@ -6,12 +6,10 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
||||||
import DebugLayout from '@theme/DebugLayout';
|
import DebugLayout from '@theme/DebugLayout';
|
||||||
import DebugJsonView from '@theme/DebugJsonView';
|
import DebugJsonView from '@theme/DebugJsonView';
|
||||||
|
|
||||||
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
|
||||||
|
|
||||||
export default function DebugMetadata(): JSX.Element {
|
export default function DebugMetadata(): JSX.Element {
|
||||||
const {siteConfig} = useDocusaurusContext();
|
const {siteConfig} = useDocusaurusContext();
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -6,10 +6,9 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import useGlobalData from '@docusaurus/useGlobalData';
|
||||||
import DebugLayout from '@theme/DebugLayout';
|
import DebugLayout from '@theme/DebugLayout';
|
||||||
import DebugJsonView from '@theme/DebugJsonView';
|
import DebugJsonView from '@theme/DebugJsonView';
|
||||||
import useGlobalData from '@docusaurus/useGlobalData';
|
|
||||||
|
|
||||||
export default function DebugMetadata(): JSX.Element {
|
export default function DebugMetadata(): JSX.Element {
|
||||||
const globalData = useGlobalData();
|
const globalData = useGlobalData();
|
||||||
|
|
|
@ -6,9 +6,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import DebugLayout from '@theme/DebugLayout';
|
|
||||||
import registry from '@generated/registry';
|
import registry from '@generated/registry';
|
||||||
|
import DebugLayout from '@theme/DebugLayout';
|
||||||
import styles from './styles.module.css';
|
import styles from './styles.module.css';
|
||||||
|
|
||||||
export default function DebugRegistry(): JSX.Element {
|
export default function DebugRegistry(): JSX.Element {
|
||||||
|
|
|
@ -6,10 +6,9 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import routes from '@generated/routes';
|
||||||
import DebugLayout from '@theme/DebugLayout';
|
import DebugLayout from '@theme/DebugLayout';
|
||||||
import DebugJsonView from '@theme/DebugJsonView';
|
import DebugJsonView from '@theme/DebugJsonView';
|
||||||
import routes from '@generated/routes';
|
|
||||||
import styles from './styles.module.css';
|
import styles from './styles.module.css';
|
||||||
|
|
||||||
export default function DebugRoutes(): JSX.Element {
|
export default function DebugRoutes(): JSX.Element {
|
||||||
|
|
|
@ -6,9 +6,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import DebugLayout from '@theme/DebugLayout';
|
|
||||||
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
||||||
|
import DebugLayout from '@theme/DebugLayout';
|
||||||
import styles from './styles.module.css';
|
import styles from './styles.module.css';
|
||||||
|
|
||||||
export default function DebugMetadata(): JSX.Element {
|
export default function DebugMetadata(): JSX.Element {
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
"react-waypoint": "^10.1.0",
|
"react-waypoint": "^10.1.0",
|
||||||
"sharp": "^0.30.4",
|
"sharp": "^0.30.4",
|
||||||
"tslib": "^2.4.0",
|
"tslib": "^2.4.0",
|
||||||
"webpack": "^5.72.0"
|
"webpack": "^5.72.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@docusaurus/module-type-aliases": "2.0.0-beta.20",
|
"@docusaurus/module-type-aliases": "2.0.0-beta.20",
|
||||||
|
|
|
@ -5,14 +5,14 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import {Joi} from '@docusaurus/utils-validation';
|
||||||
|
import {readDefaultCodeTranslationMessages} from '@docusaurus/theme-translations';
|
||||||
import type {
|
import type {
|
||||||
LoadContext,
|
LoadContext,
|
||||||
Plugin,
|
Plugin,
|
||||||
OptionValidationContext,
|
OptionValidationContext,
|
||||||
} from '@docusaurus/types';
|
} from '@docusaurus/types';
|
||||||
import type {PluginOptions} from '@docusaurus/plugin-ideal-image';
|
import type {PluginOptions} from '@docusaurus/plugin-ideal-image';
|
||||||
import {Joi} from '@docusaurus/utils-validation';
|
|
||||||
import {readDefaultCodeTranslationMessages} from '@docusaurus/theme-translations';
|
|
||||||
|
|
||||||
export default function pluginIdealImage(
|
export default function pluginIdealImage(
|
||||||
context: LoadContext,
|
context: LoadContext,
|
||||||
|
|
|
@ -29,10 +29,10 @@
|
||||||
"@docusaurus/utils-validation": "2.0.0-beta.20",
|
"@docusaurus/utils-validation": "2.0.0-beta.20",
|
||||||
"babel-loader": "^8.2.5",
|
"babel-loader": "^8.2.5",
|
||||||
"clsx": "^1.1.1",
|
"clsx": "^1.1.1",
|
||||||
"core-js": "^3.22.4",
|
"core-js": "^3.22.5",
|
||||||
"terser-webpack-plugin": "^5.3.1",
|
"terser-webpack-plugin": "^5.3.1",
|
||||||
"tslib": "^2.4.0",
|
"tslib": "^2.4.0",
|
||||||
"webpack": "^5.72.0",
|
"webpack": "^5.72.1",
|
||||||
"webpack-merge": "^5.8.0",
|
"webpack-merge": "^5.8.0",
|
||||||
"workbox-build": "^6.5.3",
|
"workbox-build": "^6.5.3",
|
||||||
"workbox-precaching": "^6.5.3",
|
"workbox-precaching": "^6.5.3",
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue