feat(v2): onBrokenMarkdownLinks config (#3658)

* refactor(v2): move `reportMessage` from `core/src/server/utils` to `utils` package

* feat(v2): handle broken markdown links by using onBrokenLinks prop from siteconfig

* feat(v2): add a new site config prop called `onBrokenMarkdownLinks`

works like onBrokenLinks, but only for markdown links

* feat(v2): add `onBrokenMarkdownLinks` to API docs

* some changes regarding test issues after adding `onBrokenMarkdownLink`

* Update website/versioned_docs/version-2.0.0-alpha.66/api/docusaurus.config.js.md

Co-authored-by: Sébastien Lorber <slorber@users.noreply.github.com>
This commit is contained in:
iAmir 2020-10-31 20:34:56 +03:30 committed by GitHub
parent 52e7511869
commit 8f2d898f22
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 71 additions and 38 deletions

View file

@ -4,6 +4,7 @@ module.exports = {
url: 'https://your-docusaurus-test-site.com',
baseUrl: '/',
onBrokenLinks: 'throw',
onBrokenMarkdownLinks: 'warn',
favicon: 'img/favicon.ico',
organizationName: 'facebook', // Usually your GitHub org/user name.
projectName: 'docusaurus', // Usually your repo name.

View file

@ -4,6 +4,7 @@ module.exports = {
url: 'https://your-docusaurus-test-site.com',
baseUrl: '/',
onBrokenLinks: 'throw',
onBrokenMarkdownLinks: 'warn',
favicon: 'img/favicon.ico',
organizationName: 'facebook', // Usually your GitHub org/user name.
projectName: 'docusaurus', // Usually your repo name.

View file

@ -13,6 +13,7 @@ module.exports = {
url: 'https://your-docusaurus-test-site.com',
baseUrl: '/',
onBrokenLinks: 'throw',
onBrokenMarkdownLinks: 'warn',
favicon: 'img/favicon.ico',
organizationName: 'facebook', // Usually your GitHub org/user name.
projectName: 'docusaurus', // Usually your repo name.

View file

@ -31,6 +31,7 @@ module.exports = {
facebookAppId: '199138890728411',
},
onBrokenLinks: 'log',
onBrokenMarkdownLinks: 'log',
presets: [
[
'@docusaurus/preset-classic',

View file

@ -302,6 +302,7 @@ export function createConfigFile({
favicon: siteConfig.favicon ?? '',
customFields: customConfigFields,
onBrokenLinks: 'log',
onBrokenMarkdownLinks: 'log',
presets: [
[
'@docusaurus/preset-classic',

View file

@ -38,6 +38,7 @@ export interface VersionTwoConfig {
noIndex?: boolean;
githubHost?: string;
onBrokenLinks: string;
onBrokenMarkdownLinks: string;
plugins: Array<[string, {[key: string]: any}]>;
themes?: [];
presets: [[string, ClassicPresetEntries]];

View file

@ -11,7 +11,12 @@ import {
STATIC_DIR_NAME,
DEFAULT_PLUGIN_ID,
} from '@docusaurus/core/lib/constants';
import {normalizeUrl, docuHash, aliasedSitePath} from '@docusaurus/utils';
import {
normalizeUrl,
docuHash,
aliasedSitePath,
reportMessage,
} from '@docusaurus/utils';
import {LoadContext, Plugin, RouteConfig} from '@docusaurus/types';
import {loadSidebars, createSidebarsUtils} from './sidebars';
@ -39,13 +44,12 @@ import {OptionsSchema} from './options';
import {flatten, keyBy, compact} from 'lodash';
import {toGlobalDataVersion} from './globalData';
import {toVersionMetadataProp} from './props';
import chalk from 'chalk';
export default function pluginContentDocs(
context: LoadContext,
options: PluginOptions,
): Plugin<LoadedContent, typeof OptionsSchema> {
const {siteDir, generatedFilesDir, baseUrl} = context;
const {siteDir, generatedFilesDir, baseUrl, siteConfig} = context;
const versionsMetadata = readVersionsMetadata({context, options});
@ -311,11 +315,13 @@ export default function pluginContentDocs(
sourceToPermalink,
versionsMetadata,
onBrokenMarkdownLink: (brokenMarkdownLink) => {
// TODO make this warning configurable?
console.warn(
chalk.yellow(
`Docs markdown link couldn't be resolved: (${brokenMarkdownLink.link}) in ${brokenMarkdownLink.filePath} for version ${brokenMarkdownLink.version.versionName}`,
),
if (siteConfig.onBrokenMarkdownLinks === 'ignore') {
return;
}
reportMessage(
`Docs markdown link couldn't be resolved: (${brokenMarkdownLink.link}) in ${brokenMarkdownLink.filePath} for version ${brokenMarkdownLink.version.versionName}`,
siteConfig.onBrokenMarkdownLinks,
);
},
};

View file

@ -21,6 +21,7 @@ export interface DocusaurusConfig {
title: string;
url: string;
onBrokenLinks: ReportingSeverity;
onBrokenMarkdownLinks: ReportingSeverity;
onDuplicateRoutes: ReportingSeverity;
noIndex: boolean;
organizationName?: string;

View file

@ -18,6 +18,8 @@
},
"license": "MIT",
"dependencies": {
"@docusaurus/types": "^2.0.0-alpha.66",
"chalk": "^3.0.0",
"escape-string-regexp": "^2.0.0",
"fs-extra": "^8.1.0",
"gray-matter": "^4.0.2",

View file

@ -5,6 +5,7 @@
* LICENSE file in the root directory of this source tree.
*/
import chalk from 'chalk';
import path from 'path';
import matter from 'gray-matter';
import {createHash} from 'crypto';
@ -13,6 +14,7 @@ import kebabCase from 'lodash.kebabcase';
import escapeStringRegexp from 'escape-string-regexp';
import fs from 'fs-extra';
import {URL} from 'url';
import {ReportingSeverity} from '@docusaurus/types';
// @ts-expect-error: no typedefs :s
import resolvePathnameUnsafe from 'resolve-pathname';
@ -436,3 +438,28 @@ export function getElementsAround<T extends unknown>(
const next = aroundIndex === max ? undefined : array[aroundIndex + 1];
return {previous, next};
}
export function reportMessage(
message: string,
reportingSeverity: ReportingSeverity,
): void {
switch (reportingSeverity) {
case 'ignore':
break;
case 'log':
console.log(chalk.bold.blue('info ') + chalk.blue(message));
break;
case 'warn':
console.warn(chalk.bold.yellow('warn ') + chalk.yellow(message));
break;
case 'error':
console.error(chalk.bold.red('error ') + chalk.red(message));
break;
case 'throw':
throw new Error(message);
default:
throw new Error(
`unexpected reportingSeverity value: ${reportingSeverity}`,
);
}
}

View file

@ -22,6 +22,7 @@ Object {
"favicon": "img/docusaurus.ico",
"noIndex": false,
"onBrokenLinks": "throw",
"onBrokenMarkdownLinks": "warn",
"onDuplicateRoutes": "warn",
"organizationName": "endiliey",
"plugins": Array [

View file

@ -10,8 +10,8 @@ import resolvePathname from 'resolve-pathname';
import fs from 'fs-extra';
import {mapValues, pickBy, flatten, countBy} from 'lodash';
import {RouteConfig, ReportingSeverity} from '@docusaurus/types';
import {removePrefix, removeSuffix} from '@docusaurus/utils';
import {getAllFinalRoutes, reportMessage} from './utils';
import {removePrefix, removeSuffix, reportMessage} from '@docusaurus/utils';
import {getAllFinalRoutes} from './utils';
import path from 'path';
function toReactRouterRoutes(routes: RouteConfig[]): RRRouteConfig[] {

View file

@ -17,6 +17,7 @@ import {
export const DEFAULT_CONFIG: Pick<
DocusaurusConfig,
| 'onBrokenLinks'
| 'onBrokenMarkdownLinks'
| 'onDuplicateRoutes'
| 'plugins'
| 'themes'
@ -27,6 +28,7 @@ export const DEFAULT_CONFIG: Pick<
| 'noIndex'
> = {
onBrokenLinks: 'throw',
onBrokenMarkdownLinks: 'warn',
onDuplicateRoutes: 'warn',
plugins: [],
themes: [],
@ -64,6 +66,9 @@ const ConfigSchema = Joi.object({
onBrokenLinks: Joi.string()
.equal('ignore', 'log', 'warn', 'error', 'throw')
.default(DEFAULT_CONFIG.onBrokenLinks),
onBrokenMarkdownLinks: Joi.string()
.equal('ignore', 'log', 'warn', 'error', 'throw')
.default(DEFAULT_CONFIG.onBrokenMarkdownLinks),
onDuplicateRoutes: Joi.string()
.equal('ignore', 'log', 'warn', 'error', 'throw')
.default(DEFAULT_CONFIG.onDuplicateRoutes),

View file

@ -5,7 +5,8 @@
* LICENSE file in the root directory of this source tree.
*/
import {RouteConfig, ReportingSeverity} from '@docusaurus/types';
import {getAllFinalRoutes, reportMessage} from './utils';
import {reportMessage} from '@docusaurus/utils';
import {getAllFinalRoutes} from './utils';
export function getAllDuplicateRoutes(
pluginsRouteConfigs: RouteConfig[],

View file

@ -4,9 +4,8 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import chalk from 'chalk';
import flatMap from 'lodash.flatmap';
import {RouteConfig, ReportingSeverity} from '@docusaurus/types';
import {RouteConfig} from '@docusaurus/types';
// Recursively get the final routes (routes with no subroutes)
export function getAllFinalRoutes(routeConfig: RouteConfig[]): RouteConfig[] {
@ -15,28 +14,3 @@ export function getAllFinalRoutes(routeConfig: RouteConfig[]): RouteConfig[] {
}
return flatMap(routeConfig, getFinalRoutes);
}
export function reportMessage(
message: string,
reportingSeverity: ReportingSeverity,
): void {
switch (reportingSeverity) {
case 'ignore':
break;
case 'log':
console.log(chalk.bold.blue('info ') + chalk.blue(message));
break;
case 'warn':
console.warn(chalk.bold.yellow('warn ') + chalk.yellow(message));
break;
case 'error':
console.error(chalk.bold.red('error ') + chalk.red(message));
break;
case 'throw':
throw new Error(message);
default:
throw new Error(
`unexpected reportingSeverity value: ${reportingSeverity}`,
);
}
}

View file

@ -108,6 +108,14 @@ The broken links detection is only available for a production build (`docusaurus
:::
### `onBrokenMarkdownLinks`
- Type: `'ignore' | 'log' | 'warn' | 'error' | 'throw'`
The behavior of Docusaurus, when it detects any broken markdown link.
By default, it prints a warning, to let you know about your broken markdown link, but you can change this security if needed.
### `onDuplicateRoutes`
- Type: `'ignore' | 'log' | 'warn' | 'error' | 'throw'`

View file

@ -13,6 +13,7 @@ module.exports = {
baseUrl: '/blog-only/',
url: 'https://v2.docusaurus.io',
onBrokenLinks: 'throw',
onBrokenMarkdownLinks: 'warn',
favicon: 'img/docusaurus.ico',
themes: ['@docusaurus/theme-live-codeblock'],
plugins: [],

View file

@ -49,6 +49,7 @@ module.exports = {
baseUrl,
url: 'https://v2.docusaurus.io',
onBrokenLinks: isVersioningDisabled ? 'warn' : 'throw',
onBrokenMarkdownLinks: 'warn',
favicon: 'img/docusaurus.ico',
customFields: {
description: