refactor: enforce named capture groups; clean up regexes (#6524)

* refactor: enforce named capture groups; clean up regexes

* fixes

* fix
This commit is contained in:
Joshua Chen 2022-02-01 17:43:15 +08:00 committed by GitHub
parent c56e6194b4
commit 1cefb643dd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
32 changed files with 80 additions and 77 deletions

View file

@ -100,6 +100,7 @@ module.exports = {
'no-restricted-syntax': WARNING, 'no-restricted-syntax': WARNING,
'no-unused-expressions': [WARNING, {allowTaggedTemplates: true}], 'no-unused-expressions': [WARNING, {allowTaggedTemplates: true}],
'prefer-destructuring': WARNING, 'prefer-destructuring': WARNING,
'prefer-named-capture-group': WARNING,
'prefer-template': WARNING, 'prefer-template': WARNING,
yoda: WARNING, yoda: WARNING,

View file

@ -59,7 +59,7 @@ export function shouldQuotifyFrontMatter([key, value]: [
if (key === 'tags') { if (key === 'tags') {
return false; return false;
} }
if (String(value).match(/^("|').+("|')$/)) { if (String(value).match(/^(?<quote>["']).+\1$/)) {
return false; return false;
} }
// title: !something needs quotes because otherwise it's a YAML tag. // title: !something needs quotes because otherwise it's a YAML tag.
@ -69,6 +69,6 @@ export function shouldQuotifyFrontMatter([key, value]: [
// TODO this is not ideal to have to maintain such a list of allowed chars // TODO this is not ideal to have to maintain such a list of allowed chars
// maybe we should quotify if gray-matter throws instead? // maybe we should quotify if gray-matter throws instead?
return !String(value).match( return !String(value).match(
/^([\w .\-sàáâãäåçèéêëìíîïðòóôõöùúûüýÿ!;,=+_?'`&#()[\]§%€$])+$/, /^[\w .\-sàáâãäåçèéêëìíîïðòóôõöùúûüýÿ!;,=+_?'`&#()[\]§%€$]+$/,
); );
} }

View file

@ -63,7 +63,7 @@ export function getBlogTags(blogPosts: BlogPost[]): BlogTags {
} }
const DATE_FILENAME_REGEX = const DATE_FILENAME_REGEX =
/^(?<folder>.*)(?<date>\d{4}[-/]\d{1,2}[-/]\d{1,2})[-/]?(?<text>.*?)(\/index)?.mdx?$/; /^(?<folder>.*)(?<date>\d{4}[-/]\d{1,2}[-/]\d{1,2})[-/]?(?<text>.*?)(?:\/index)?.mdx?$/;
type ParsedBlogFileName = { type ParsedBlogFileName = {
date: Date | undefined; date: Date | undefined;
@ -83,7 +83,7 @@ export function parseBlogFileName(
const slug = `/${slugDate}/${folder}${text}`; const slug = `/${slugDate}/${folder}${text}`;
return {date, text, slug}; return {date, text, slug};
} }
const text = blogSourceRelative.replace(/(\/index)?\.mdx?$/, ''); const text = blogSourceRelative.replace(/(?:\/index)?\.mdx?$/, '');
const slug = `/${text}`; const slug = `/${text}`;
return {date: undefined, text, slug}; return {date: undefined, text, slug};
} }

View file

@ -452,7 +452,7 @@ export default async function pluginContentBlog(
module: { module: {
rules: [ rules: [
{ {
test: /(\.mdx?)$/, test: /\.mdx?$/i,
include: contentDirs include: contentDirs
// Trailing slash is important, see https://github.com/facebook/docusaurus/pull/3970 // Trailing slash is important, see https://github.com/facebook/docusaurus/pull/3970
.map(addTrailingPathSeparator), .map(addTrailingPathSeparator),

View file

@ -20,7 +20,7 @@ export const DEFAULT_OPTIONS: PluginOptions = {
beforeDefaultRehypePlugins: [], beforeDefaultRehypePlugins: [],
beforeDefaultRemarkPlugins: [], beforeDefaultRemarkPlugins: [],
admonitions: {}, admonitions: {},
truncateMarker: /<!--\s*(truncate)\s*-->/, truncateMarker: /<!--\s*truncate\s*-->/,
rehypePlugins: [], rehypePlugins: [],
remarkPlugins: [], remarkPlugins: [],
showReadingTime: true, showReadingTime: true,

View file

@ -333,7 +333,7 @@ export default async function pluginContentDocs(
function createMDXLoaderRule(): RuleSetRule { function createMDXLoaderRule(): RuleSetRule {
const contentDirs = versionsMetadata.flatMap(getDocsDirPaths); const contentDirs = versionsMetadata.flatMap(getDocsDirPaths);
return { return {
test: /(\.mdx?)$/, test: /\.mdx?$/i,
include: contentDirs include: contentDirs
// Trailing slash is important, see https://github.com/facebook/docusaurus/pull/3970 // Trailing slash is important, see https://github.com/facebook/docusaurus/pull/3970
.map(addTrailingPathSeparator), .map(addTrailingPathSeparator),

View file

@ -10,7 +10,7 @@ import logger from '@docusaurus/logger';
type FileLastUpdateData = {timestamp?: number; author?: string}; type FileLastUpdateData = {timestamp?: number; author?: string};
const GIT_COMMIT_TIMESTAMP_AUTHOR_REGEX = /^(\d+),(.+)$/; const GIT_COMMIT_TIMESTAMP_AUTHOR_REGEX = /^(?<timestamp>\d+),(?<author>.+)$/;
let showedGitRequirementError = false; let showedGitRequirementError = false;
@ -25,10 +25,10 @@ export async function getFileLastUpdate(
return null; return null;
} }
const temp = str.match(GIT_COMMIT_TIMESTAMP_AUTHOR_REGEX); const temp = str.match(GIT_COMMIT_TIMESTAMP_AUTHOR_REGEX)?.groups;
return !temp || temp.length < 3 return temp
? null ? {timestamp: Number(temp.timestamp), author: temp.author}
: {timestamp: +temp[1], author: temp[2]}; : null;
} }
// Wrap in try/catch in case the shell commands fail // Wrap in try/catch in case the shell commands fail

View file

@ -11,14 +11,14 @@ import type {NumberPrefixParser} from '@docusaurus/plugin-content-docs';
const IgnoredPrefixPatterns = (() => { const IgnoredPrefixPatterns = (() => {
// ignore common date-like patterns: https://github.com/facebook/docusaurus/issues/4640 // ignore common date-like patterns: https://github.com/facebook/docusaurus/issues/4640
const DateLikePrefixRegex = const DateLikePrefixRegex =
/^((\d{2}|\d{4})[-_.]\d{2}([-_.](\d{2}|\d{4}))?)(.*)$/; /^(?:\d{2}|\d{4})[-_.]\d{2}(?:[-_.](?:\d{2}|\d{4}))?.*$/;
// ignore common versioning patterns: https://github.com/facebook/docusaurus/issues/4653 // ignore common versioning patterns: https://github.com/facebook/docusaurus/issues/4653
// note: we could try to parse float numbers in filenames but that is // note: we could try to parse float numbers in filenames but that is
// probably not worth it as a version such as "8.0" can be interpreted as both // probably not worth it as a version such as "8.0" can be interpreted as both
// a version and a float. User can configure her own NumberPrefixParser if // a version and a float. User can configure her own NumberPrefixParser if
// she wants 8.0 to be interpreted as a float // she wants 8.0 to be interpreted as a float
const VersionLikePrefixRegex = /^(\d+[-_.]\d+)(.*)$/; const VersionLikePrefixRegex = /^\d+[-_.]\d+.*$/;
return new RegExp( return new RegExp(
`${DateLikePrefixRegex.source}|${VersionLikePrefixRegex.source}`, `${DateLikePrefixRegex.source}|${VersionLikePrefixRegex.source}`,

View file

@ -36,7 +36,7 @@ const sidebarItemAutogeneratedSchema =
type: 'autogenerated', type: 'autogenerated',
dirName: Joi.string() dirName: Joi.string()
.required() .required()
.pattern(/^[^/](.*[^/])?$/) .pattern(/^[^/](?:.*[^/])?$/)
.message( .message(
'"dirName" must be a dir path relative to the docs folder root, and should not start or end with slash', '"dirName" must be a dir path relative to the docs folder root, and should not start or end with slash',
), ),

View file

@ -199,7 +199,7 @@ export default async function pluginContentPages(
module: { module: {
rules: [ rules: [
{ {
test: /(\.mdx?)$/, test: /\.mdx?$/i,
include: contentDirs include: contentDirs
// Trailing slash is important, see https://github.com/facebook/docusaurus/pull/3970 // Trailing slash is important, see https://github.com/facebook/docusaurus/pull/3970
.map(addTrailingPathSeparator), .map(addTrailingPathSeparator),

View file

@ -57,7 +57,7 @@ export default function pluginIdealImage(
module: { module: {
rules: [ rules: [
{ {
test: /\.(png|jpe?g|gif)$/i, test: /\.(?:png|jpe?g|gif)$/i,
use: [ use: [
require.resolve('@docusaurus/lqip-loader'), require.resolve('@docusaurus/lqip-loader'),
{ {

View file

@ -174,7 +174,7 @@ export default function pluginPWA(
rules: [ rules: [
{ {
test: swSourceFileTest, test: swSourceFileTest,
exclude: /(node_modules)/, exclude: /node_modules/,
use: getSWBabelLoader(), use: getSWBabelLoader(),
}, },
], ],

View file

@ -7,8 +7,8 @@
import rangeParser from 'parse-numeric-range'; import rangeParser from 'parse-numeric-range';
const codeBlockTitleRegex = /title=(["'])(.*?)\1/; const codeBlockTitleRegex = /title=(?<quote>["'])(?<title>.*?)\1/;
const highlightLinesRangeRegex = /{([\d,-]+)}/; const highlightLinesRangeRegex = /{(?<range>[\d,-]+)}/;
const commentTypes = ['js', 'jsBlock', 'jsx', 'python', 'html'] as const; const commentTypes = ['js', 'jsBlock', 'jsx', 'python', 'html'] as const;
type CommentType = typeof commentTypes[number]; type CommentType = typeof commentTypes[number];
@ -89,7 +89,7 @@ const magicCommentDirectiveRegex = (lang: string) => {
}; };
export function parseCodeBlockTitle(metastring?: string): string { export function parseCodeBlockTitle(metastring?: string): string {
return metastring?.match(codeBlockTitleRegex)?.[2] ?? ''; return metastring?.match(codeBlockTitleRegex)?.groups!.title ?? '';
} }
export function parseLanguage(className: string): string | undefined { export function parseLanguage(className: string): string | undefined {
@ -114,7 +114,8 @@ export function parseLines(
let code = content.replace(/\n$/, ''); let code = content.replace(/\n$/, '');
// Highlighted lines specified in props: don't parse the content // Highlighted lines specified in props: don't parse the content
if (metastring && highlightLinesRangeRegex.test(metastring)) { if (metastring && highlightLinesRangeRegex.test(metastring)) {
const highlightLinesRange = metastring.match(highlightLinesRangeRegex)![1]; const highlightLinesRange = metastring.match(highlightLinesRangeRegex)!
.groups!.range;
const highlightLines = rangeParser(highlightLinesRange) const highlightLines = rangeParser(highlightLinesRange)
.filter((n) => n > 0) .filter((n) => n > 0)
.map((n) => n - 1); .map((n) => n - 1);

View file

@ -116,7 +116,7 @@ describe('createExcerpt', () => {
export function ItemCol(props) { return <Item {...props} className={'col col--6 margin-bottom--lg'}/> }; export function ItemCol(props) { return <Item {...props} className={'col col--6 margin-bottom--lg'}/> };
Lorem **ipsum** dolor sit \`amet\`[^1], consectetur _adipiscing_ elit. [**Vestibulum**](https://wiktionary.org/wiki/vestibulum) ex urna[^bignote], ~molestie~ et sagittis ut, varius ac justo :wink:. Lorem **ipsum** dolor sit \`amet\`[^1], consectetur _adipiscing_ elit. [**Vestibulum**](https://wiktionary.org/wiki/vestibulum) ex urna[^bignote], ~~molestie~~ et sagittis ut, varius ac justo :wink:.
Nunc porttitor libero nec vulputate venenatis. Nam nec rhoncus mauris. Morbi tempus est et nibh maximus, tempus venenatis arcu lobortis. Nunc porttitor libero nec vulputate venenatis. Nam nec rhoncus mauris. Morbi tempus est et nibh maximus, tempus venenatis arcu lobortis.
`), `),

View file

@ -69,8 +69,8 @@ export async function generate(
} }
} }
const indexRE = /(^|.*\/)index\.(md|mdx|js|jsx|ts|tsx)$/i; const indexRE = /(?<dirname>^|.*\/)index\.(?:mdx?|jsx?|tsx?)$/i;
const extRE = /\.(md|mdx|js|jsx|ts|tsx)$/; const extRE = /\.(?:mdx?|jsx?|tsx?)$/;
/** /**
* Convert filepath to url path. * Convert filepath to url path.

View file

@ -67,11 +67,11 @@ export function replaceMarkdownLinks<T extends ContentPaths>({
// ink // ink
// [doc1]: doc1.md -> we replace this doc1.md with correct link // [doc1]: doc1.md -> we replace this doc1.md with correct link
const mdRegex = const mdRegex =
/(?:(?:\]\()|(?:\]:\s?))(?!https?:\/\/|@site\/)([^'")\]\s>]+\.mdx?)/g; /(?:(?:\]\()|(?:\]:\s?))(?!https?:\/\/|@site\/)(?<filename>[^'")\]\s>]+\.mdx?)/g;
let mdMatch = mdRegex.exec(modifiedLine); let mdMatch = mdRegex.exec(modifiedLine);
while (mdMatch !== null) { while (mdMatch !== null) {
// Replace it to correct html link. // Replace it to correct html link.
const mdLink = mdMatch[1]; const mdLink = mdMatch.groups!.filename;
const sourcesToTry = [ const sourcesToTry = [
path.resolve(path.dirname(filePath), decodeURIComponent(mdLink)), path.resolve(path.dirname(filePath), decodeURIComponent(mdLink)),

View file

@ -14,12 +14,12 @@ export function parseMarkdownHeadingId(heading: string): {
text: string; text: string;
id?: string; id?: string;
} { } {
const customHeadingIdRegex = /^(.*?)\s*\{#([\w-]+)\}$/; const customHeadingIdRegex = /^(?<text>.*?)\s*\{#(?<id>[\w-]+)\}$/;
const matches = customHeadingIdRegex.exec(heading); const matches = customHeadingIdRegex.exec(heading);
if (matches) { if (matches) {
return { return {
text: matches[1], text: matches.groups!.text,
id: matches[2], id: matches.groups!.id,
}; };
} }
return {text: heading, id: undefined}; return {text: heading, id: undefined};
@ -46,7 +46,7 @@ export function createExcerpt(fileString: string): string | undefined {
} }
// Skip import/export declaration. // Skip import/export declaration.
if (/^\s*?import\s.*(from.*)?;?|export\s.*{.*};?/.test(fileLine)) { if (/^(?:import|export)\s.*/.test(fileLine)) {
continue; continue;
} }
@ -71,25 +71,27 @@ export function createExcerpt(fileString: string): string | undefined {
// Remove HTML tags. // Remove HTML tags.
.replace(/<[^>]*>/g, '') .replace(/<[^>]*>/g, '')
// Remove Title headers // Remove Title headers
.replace(/^#\s*([^#]*)\s*#?/gm, '') .replace(/^#\s*[^#]*\s*#?/gm, '')
// Remove Markdown + ATX-style headers // Remove Markdown + ATX-style headers
.replace(/^#{1,6}\s*([^#]*)\s*(#{1,6})?/gm, '$1') .replace(/^#{1,6}\s*(?<text>[^#]*)\s*(?:#{1,6})?/gm, '$1')
// Remove emphasis and strikethroughs. // Remove emphasis.
.replace(/([*_~]{1,3})(\S.*?\S{0,1})\1/g, '$2') .replace(/(?<opening>[*_]{1,3})(?<text>.*?)\1/g, '$2')
// Remove strikethroughs.
.replace(/~~(?<text>\S.*\S)~~/g, '$1')
// Remove images. // Remove images.
.replace(/!\[(.*?)\][[(].*?[\])]/g, '$1') .replace(/!\[(?<alt>.*?)\][[(].*?[\])]/g, '$1')
// Remove footnotes. // Remove footnotes.
.replace(/\[\^.+?\](: .*?$)?/g, '') .replace(/\[\^.+?\](?:: .*?$)?/g, '')
// Remove inline links. // Remove inline links.
.replace(/\[(.*?)\][[(].*?[\])]/g, '$1') .replace(/\[(?<alt>.*?)\][[(].*?[\])]/g, '$1')
// Remove inline code. // Remove inline code.
.replace(/`(.+?)`/g, '$1') .replace(/`(?<text>.+?)`/g, '$1')
// Remove blockquotes. // Remove blockquotes.
.replace(/^\s{0,3}>\s?/g, '') .replace(/^\s{0,3}>\s?/g, '')
// Remove admonition definition. // Remove admonition definition.
.replace(/(:{3}.*)/, '') .replace(/:::.*/, '')
// Remove Emoji names within colons include preceding whitespace. // Remove Emoji names within colons include preceding whitespace.
.replace(/\s?(:(::|[^:\n])+:)/g, '') .replace(/\s?:(?:::|[^:\n])+:/g, '')
// Remove custom Markdown heading id. // Remove custom Markdown heading id.
.replace(/{#*[\w-]+}/, '') .replace(/{#*[\w-]+}/, '')
.trim(); .trim();
@ -134,9 +136,9 @@ export function parseMarkdownContentTitle(
const content = contentUntrimmed.trim(); const content = contentUntrimmed.trim();
const IMPORT_STATEMENT = const IMPORT_STATEMENT =
/import\s+(([\w*{}\s\n,]+)from\s+)?["'\s]([@\w/_.-]+)["'\s];?|\n/.source; /import\s+(?:[\w*{}\s\n,]+from\s+)?["'\s][@\w/_.-]+["'\s];?|\n/.source;
const REGULAR_TITLE = const REGULAR_TITLE =
/(?<pattern>#\s*(?<title>[^#\n{]*)+[ \t]*(?<suffix>({#*[\w-]+})|#)?\n*?)/ /(?<pattern>#\s*(?<title>[^#\n{]*)+[ \t]*(?<suffix>(?:{#*[\w-]+})|#)?\n*?)/
.source; .source;
const ALTERNATE_TITLE = /(?<pattern>\s*(?<title>[^\n]*)\s*\n[=]+)/.source; const ALTERNATE_TITLE = /(?<pattern>\s*(?<title>[^\n]*)\s*\n[=]+)/.source;

View file

@ -27,7 +27,7 @@ export function normalizeUrl(rawUrls: string[]): string {
// There must be two or three slashes in the file protocol, // There must be two or three slashes in the file protocol,
// two slashes in anything else. // two slashes in anything else.
const replacement = urls[0].match(/^file:\/\/\//) ? '$1:///' : '$1://'; const replacement = urls[0].match(/^file:\/\/\//) ? '$1:///' : '$1://';
urls[0] = urls[0].replace(/^([^/:]+):\/*/, replacement); urls[0] = urls[0].replace(/^(?<protocol>[^/:]+):\/*/, replacement);
for (let i = 0; i < urls.length; i += 1) { for (let i = 0; i < urls.length; i += 1) {
let component = urls[i]; let component = urls[i];
@ -70,14 +70,14 @@ export function normalizeUrl(rawUrls: string[]): string {
// except the possible first plain protocol part. // except the possible first plain protocol part.
// Remove trailing slash before parameters or hash. // Remove trailing slash before parameters or hash.
str = str.replace(/\/(\?|&|#[^!])/g, '$1'); str = str.replace(/\/(?<search>\?|&|#[^!])/g, '$1');
// Replace ? in parameters with &. // Replace ? in parameters with &.
const parts = str.split('?'); const parts = str.split('?');
str = parts.shift() + (parts.length > 0 ? '?' : '') + parts.join('&'); str = parts.shift() + (parts.length > 0 ? '?' : '') + parts.join('&');
// Dedupe forward slashes in the entire path, avoiding protocol slashes. // Dedupe forward slashes in the entire path, avoiding protocol slashes.
str = str.replace(/([^:/]\/)\/+/g, '$1'); str = str.replace(/(?<textBefore>[^:/]\/)\/+/g, '$1');
// Dedupe forward slashes at the beginning of the path. // Dedupe forward slashes at the beginning of the path.
str = str.replace(/^\/+/g, '/'); str = str.replace(/^\/+/g, '/');

View file

@ -79,12 +79,12 @@ export function getFileLoaderUtils(): FileLoaderUtils {
*/ */
images: () => ({ images: () => ({
use: [loaders.url({folder: 'images'})], use: [loaders.url({folder: 'images'})],
test: /\.(ico|jpg|jpeg|png|gif|webp)(\?.*)?$/, test: /\.(?:ico|jpe?g|png|gif|webp)(?:\?.*)?$/i,
}), }),
fonts: () => ({ fonts: () => ({
use: [loaders.url({folder: 'fonts'})], use: [loaders.url({folder: 'fonts'})],
test: /\.(woff|woff2|eot|ttf|otf)$/, test: /\.(?:woff2?|eot|ttf|otf)$/i,
}), }),
/** /**
@ -93,11 +93,11 @@ export function getFileLoaderUtils(): FileLoaderUtils {
*/ */
media: () => ({ media: () => ({
use: [loaders.url({folder: 'medias'})], use: [loaders.url({folder: 'medias'})],
test: /\.(mp4|webm|ogv|wav|mp3|m4a|aac|oga|flac)$/, test: /\.(?:mp4|webm|ogv|wav|mp3|m4a|aac|oga|flac)$/i,
}), }),
svg: () => ({ svg: () => ({
test: /\.svg?$/, test: /\.svg$/i,
oneOf: [ oneOf: [
{ {
use: [ use: [
@ -126,7 +126,7 @@ export function getFileLoaderUtils(): FileLoaderUtils {
// We don't want to use SVGR loader for non-React source code // We don't want to use SVGR loader for non-React source code
// ie we don't want to use SVGR for CSS files... // ie we don't want to use SVGR for CSS files...
issuer: { issuer: {
and: [/\.(ts|tsx|js|jsx|md|mdx)$/], and: [/\.(?:tsx?|jsx?|mdx?)$/i],
}, },
}, },
{ {
@ -137,7 +137,7 @@ export function getFileLoaderUtils(): FileLoaderUtils {
otherAssets: () => ({ otherAssets: () => ({
use: [loaders.file({folder: 'files'})], use: [loaders.file({folder: 'files'})],
test: /\.(pdf|doc|docx|xls|xlsx|zip|rar)$/, test: /\.(?:pdf|docx?|xlsx?|zip|rar)$/i,
}), }),
}; };

View file

@ -37,7 +37,7 @@ const canPreload = (routePath: string) =>
// Remove the last part containing the route hash // Remove the last part containing the route hash
// input: /blog/2018/12/14/Happy-First-Birthday-Slash-fe9 // input: /blog/2018/12/14/Happy-First-Birthday-Slash-fe9
// output: /blog/2018/12/14/Happy-First-Birthday-Slash // output: /blog/2018/12/14/Happy-First-Birthday-Slash
const removeRouteNameHash = (str: string) => str.replace(/(-[^-]+)$/, ''); const removeRouteNameHash = (str: string) => str.replace(/-[^-]+$/, '');
const getChunkNamesToLoad = (path: string): string[] => const getChunkNamesToLoad = (path: string): string[] =>
Object.entries(routesChunkNames) Object.entries(routesChunkNames)

View file

@ -6,7 +6,7 @@
*/ */
export function hasProtocol(url: string): boolean { export function hasProtocol(url: string): boolean {
return /^(\w*:|\/\/)/.test(url) === true; return /^(?:\w*:|\/\/)/.test(url) === true;
} }
export default function isInternalUrl(url?: string): boolean { export default function isInternalUrl(url?: string): boolean {

View file

@ -54,7 +54,7 @@ export default async function render(
${(e as Error).stack!}`; ${(e as Error).stack!}`;
const isNotDefinedErrorRegex = const isNotDefinedErrorRegex =
/(window|document|localStorage|navigator|alert|location|buffer|self) is not defined/i; /(?:window|document|localStorage|navigator|alert|location|buffer|self) is not defined/i;
if (isNotDefinedErrorRegex.test((e as Error).message)) { if (isNotDefinedErrorRegex.test((e as Error).message)) {
logger.info`It looks like you are using code that should run on the client-side only. logger.info`It looks like you are using code that should run on the client-side only.

View file

@ -66,7 +66,7 @@ export function hasSSHProtocol(sourceRepoUrl: string): boolean {
return false; return false;
} catch { } catch {
// Fails when there isn't a protocol // Fails when there isn't a protocol
return /^([\w-]+@)?[\w.-]+:[\w./_-]+(\.git)?/.test(sourceRepoUrl); // git@github.com:facebook/docusaurus.git return /^(?:[\w-]+@)?[\w.-]+:[\w./_-]+/.test(sourceRepoUrl); // git@github.com:facebook/docusaurus.git
} }
} }

View file

@ -50,8 +50,8 @@ export function getPluginNames(plugins: PluginConfig[]): string[] {
const formatComponentName = (componentName: string): string => const formatComponentName = (componentName: string): string =>
componentName componentName
.replace(/(\/|\\)index\.(js|tsx|ts|jsx)/, '') .replace(/[\\/]index\.(?:jsx?|tsx?)/, '')
.replace(/\.(js|tsx|ts|jsx)/, ''); .replace(/\.(?:jsx?|tsx?)/, '');
function readComponent(themePath: string) { function readComponent(themePath: string) {
function walk(dir: string): Array<string> { function walk(dir: string): Array<string> {

View file

@ -23,7 +23,7 @@ type Options = {
}; };
function unwrapMarkdownLinks(line: string): string { function unwrapMarkdownLinks(line: string): string {
return line.replace(/\[([^\]]+)\]\([^)]+\)/g, (match, p1) => p1); return line.replace(/\[(?<alt>[^\]]+)\]\([^)]+\)/g, (match, p1) => p1);
} }
function addHeadingId( function addHeadingId(

View file

@ -85,7 +85,7 @@ describe('loadConfig', () => {
'docusaurus.config.js', 'docusaurus.config.js',
); );
await expect(loadConfig(siteDir)).rejects.toThrowError( await expect(loadConfig(siteDir)).rejects.toThrowError(
/Config file at "(.*?)__fixtures__[/\\]nonExisting[/\\]docusaurus.config.js" not found.$/, /Config file at ".*?__fixtures__[/\\]nonExisting[/\\]docusaurus.config.js" not found.$/,
); );
}); });
}); });

View file

@ -260,7 +260,7 @@ function createMDXFallbackPlugin({
module: { module: {
rules: [ rules: [
{ {
test: /(\.mdx?)$/, test: /\.mdx?$/i,
exclude: getMDXFallbackExcludedPaths(), exclude: getMDXFallbackExcludedPaths(),
use: [ use: [
getJSLoader({isServer}), getJSLoader({isServer}),

View file

@ -14,7 +14,7 @@ export function getNamePatterns(
if (!moduleName.includes('/')) { if (!moduleName.includes('/')) {
return [`${moduleName}/docusaurus-${moduleType}`]; return [`${moduleName}/docusaurus-${moduleType}`];
} }
const [scope, packageName] = moduleName.split(/\/(.*)/); const [scope, packageName] = moduleName.split(/\/(?<rest>.*)/);
return [ return [
`${scope}/${packageName}`, `${scope}/${packageName}`,
`${scope}/docusaurus-${moduleType}-${packageName}`, `${scope}/docusaurus-${moduleType}-${packageName}`,

View file

@ -28,7 +28,7 @@ type RegistryMap = {
function indent(str: string) { function indent(str: string) {
const spaces = ' '; const spaces = ' ';
return `${spaces}${str.replace(/(\n)/g, `\n${spaces}`)}`; return `${spaces}${str.replace(/\n/g, `\n${spaces}`)}`;
} }
const createRouteCodeString = ({ const createRouteCodeString = ({

View file

@ -19,8 +19,8 @@ import {
import {loadPluginsThemeAliases} from '../server/themes'; import {loadPluginsThemeAliases} from '../server/themes';
import {md5Hash, getFileLoaderUtils} from '@docusaurus/utils'; import {md5Hash, getFileLoaderUtils} from '@docusaurus/utils';
const CSS_REGEX = /\.css$/; const CSS_REGEX = /\.css$/i;
const CSS_MODULE_REGEX = /\.module\.css$/; const CSS_MODULE_REGEX = /\.module\.css$/i;
export const clientDir = path.join(__dirname, '..', 'client'); export const clientDir = path.join(__dirname, '..', 'client');
const LibrariesToTranspile = [ const LibrariesToTranspile = [
@ -39,7 +39,7 @@ export function excludeJS(modulePath: string): boolean {
// Don't transpile node_modules except any docusaurus npm package // Don't transpile node_modules except any docusaurus npm package
return ( return (
/node_modules/.test(modulePath) && /node_modules/.test(modulePath) &&
!/(docusaurus)((?!node_modules).)*\.jsx?$/.test(modulePath) && !/docusaurus(?:(?!node_modules).)*\.jsx?$/.test(modulePath) &&
!LibrariesToTranspileRegex.test(modulePath) !LibrariesToTranspileRegex.test(modulePath)
); );
} }
@ -220,7 +220,7 @@ export function createBaseConfig(
fileLoaderUtils.rules.svg(), fileLoaderUtils.rules.svg(),
fileLoaderUtils.rules.otherAssets(), fileLoaderUtils.rules.otherAssets(),
{ {
test: /\.(j|t)sx?$/, test: /\.[jt]sx?$/i,
exclude: excludeJS, exclude: excludeJS,
use: [ use: [
getCustomizableJSLoader(siteConfig.webpack?.jsLoader)({ getCustomizableJSLoader(siteConfig.webpack?.jsLoader)({

View file

@ -29,27 +29,26 @@ async function lqipLoader(
let content = contentBuffer.toString('utf8'); let content = contentBuffer.toString('utf8');
const contentIsUrlExport = const contentIsUrlExport =
/^(?:export default|module.exports =) "data:(.*)base64,(.*)/.test(content); /^(?:export default|module.exports =) "data:.*base64,.*/.test(content);
const contentIsFileExport = /^(?:export default|module.exports =) (.*)/.test( const contentIsFileExport = /^(?:export default|module.exports =) .*/.test(
content, content,
); );
let source = ''; let source = '';
const SOURCE_CHUNK = 1;
if (contentIsUrlExport) { if (contentIsUrlExport) {
source = content.match(/^(?:export default|module.exports =) (.*)/)![ source = content.match(
SOURCE_CHUNK /^(?:export default|module.exports =) (?<source>.*)/,
]; )!.groups!.source;
} else { } else {
if (!contentIsFileExport) { if (!contentIsFileExport) {
// eslint-disable-next-line global-require, @typescript-eslint/no-var-requires // eslint-disable-next-line global-require, @typescript-eslint/no-var-requires
const fileLoader = require('file-loader'); const fileLoader = require('file-loader');
content = fileLoader.call(this, contentBuffer); content = fileLoader.call(this, contentBuffer);
} }
source = content.match(/^(?:export default|module.exports =) (.*);/)![ source = content.match(
SOURCE_CHUNK /^(?:export default|module.exports =) (?<source>.*);/,
]; )!.groups!.source;
} }
const outputPromises: [Promise<string> | null, Promise<string[]> | null] = [ const outputPromises: [Promise<string> | null, Promise<string[]> | null] = [

View file

@ -60,7 +60,7 @@ function processSection(section) {
}); });
} }
let hour = 20; let hour = 20;
const date = title.match(/ \((.*)\)/)[1]; const date = title.match(/ \((?<date>.*)\)/)?.groups.date;
while (publishTimes.has(`${date}T${hour}:00`)) { while (publishTimes.has(`${date}T${hour}:00`)) {
hour -= 1; hour -= 1;
} }