mirror of
https://github.com/withastro/astro.git
synced 2024-12-16 21:46:22 -05:00
Improve regex performance (#11635)
This commit is contained in:
parent
74a093056d
commit
ea82b03cd6
23 changed files with 39 additions and 32 deletions
|
@ -111,6 +111,8 @@ export default [
|
|||
|
||||
// In some cases, using explicit letter-casing is more performant than the `i` flag
|
||||
'regexp/use-ignore-case': 'off',
|
||||
'regexp/prefer-regexp-exec': 'warn',
|
||||
'regexp/prefer-regexp-test': 'warn',
|
||||
},
|
||||
},
|
||||
|
||||
|
|
|
@ -88,7 +88,7 @@ test.describe('Error display', () => {
|
|||
expect(fileExists).toBeTruthy();
|
||||
|
||||
const fileContent = await astro.readFile(absoluteFileUrl);
|
||||
const lineNumber = absoluteFileLocation.match(/:(\d+):\d+$/)[1];
|
||||
const lineNumber = /:(\d+):\d+$/.exec(absoluteFileLocation)[1];
|
||||
const highlightedLine = fileContent.split('\n')[lineNumber - 1];
|
||||
expect(highlightedLine).toContain(`@use '../styles/inexistent' as *;`);
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@ export const onRequest = defineMiddleware(async (context, next) => {
|
|||
|
||||
// Heuristic: If body is null, Astro might've reset this for prerendering.
|
||||
if (import.meta.env.DEV && request.method === 'POST' && request.body === null) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn(
|
||||
yellow('[astro:actions]'),
|
||||
'POST requests should not be sent to prerendered pages. If you\'re using Actions, disable prerendering with `export const prerender = "false".'
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
/* eslint-disable @typescript-eslint/non-nullable-type-assertion-style */
|
||||
/* eslint-disable regexp/prefer-regexp-exec */
|
||||
import type { IImage, ISize } from './interface.ts'
|
||||
import { toUTF8String } from './utils.js'
|
||||
|
||||
|
|
|
@ -501,7 +501,7 @@ export class App {
|
|||
}
|
||||
|
||||
#getDefaultStatusCode(routeData: RouteData, pathname: string): number {
|
||||
if (!routeData.pattern.exec(pathname)) {
|
||||
if (!routeData.pattern.test(pathname)) {
|
||||
for (const fallbackRoute of routeData.fallbackRoutes) {
|
||||
if (fallbackRoute.pattern.test(pathname)) {
|
||||
return 302;
|
||||
|
|
|
@ -306,7 +306,7 @@ function getInvalidRouteSegmentError(
|
|||
route: RouteData,
|
||||
staticPath: GetStaticPathsItem
|
||||
): AstroError {
|
||||
const invalidParam = e.message.match(/^Expected "([^"]+)"/)?.[1];
|
||||
const invalidParam = /^Expected "([^"]+)"/.exec(e.message)?.[1];
|
||||
const received = invalidParam ? staticPath.params[invalidParam] : undefined;
|
||||
let hint =
|
||||
'Learn about dynamic routes at https://docs.astro.build/en/core-concepts/routing/#dynamic-routes';
|
||||
|
@ -421,7 +421,7 @@ async function generatePath(
|
|||
// always be rendered
|
||||
route.pathname !== '/' &&
|
||||
// Check if there is a translated page with the same path
|
||||
Object.values(options.allPages).some((val) => pathname.match(val.route.pattern))
|
||||
Object.values(options.allPages).some((val) => val.route.pattern.test(pathname))
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
@ -503,7 +503,7 @@ function getPrettyRouteName(route: RouteData): string {
|
|||
} else if (route.component.includes('node_modules/')) {
|
||||
// For routes from node_modules (usually injected by integrations),
|
||||
// prettify it by only grabbing the part after the last `node_modules/`
|
||||
return route.component.match(/.*node_modules\/(.+)/)?.[1] ?? route.component;
|
||||
return /.*node_modules\/(.+)/.exec(route.component)?.[1] ?? route.component;
|
||||
} else {
|
||||
return route.component;
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ export function enhanceViteSSRError({
|
|||
// Vite has a fairly generic error message when it fails to load a module, let's try to enhance it a bit
|
||||
// https://github.com/vitejs/vite/blob/ee7c28a46a6563d54b828af42570c55f16b15d2c/packages/vite/src/node/ssr/ssrModuleLoader.ts#L91
|
||||
let importName: string | undefined;
|
||||
if ((importName = safeError.message.match(/Failed to load url (.*?) \(resolved id:/)?.[1])) {
|
||||
if ((importName = /Failed to load url (.*?) \(resolved id:/.exec(safeError.message)?.[1])) {
|
||||
safeError.title = FailedToLoadModuleSSR.title;
|
||||
safeError.name = 'FailedToLoadModuleSSR';
|
||||
safeError.message = FailedToLoadModuleSSR.message(importName);
|
||||
|
@ -64,9 +64,10 @@ export function enhanceViteSSRError({
|
|||
// Vite throws a syntax error trying to parse MDX without a plugin.
|
||||
// Suggest installing the MDX integration if none is found.
|
||||
if (
|
||||
fileId &&
|
||||
!renderers?.find((r) => r.name === '@astrojs/mdx') &&
|
||||
safeError.message.match(/Syntax error/) &&
|
||||
fileId?.match(/\.mdx$/)
|
||||
/Syntax error/.test(safeError.message) &&
|
||||
/.mdx$/.test(fileId)
|
||||
) {
|
||||
safeError = new AstroError({
|
||||
...MdxIntegrationMissingError,
|
||||
|
@ -78,7 +79,7 @@ export function enhanceViteSSRError({
|
|||
|
||||
// Since Astro.glob is a wrapper around Vite's import.meta.glob, errors don't show accurate information, let's fix that
|
||||
if (/Invalid glob/.test(safeError.message)) {
|
||||
const globPattern = safeError.message.match(/glob: "(.+)" \(/)?.[1];
|
||||
const globPattern = /glob: "(.+)" \(/.exec(safeError.message)?.[1];
|
||||
|
||||
if (globPattern) {
|
||||
safeError.message = InvalidGlob.message(globPattern);
|
||||
|
|
|
@ -28,7 +28,7 @@ interface ConfigErrorEventPayload extends ErrorEventPayload {
|
|||
*/
|
||||
const ANONYMIZE_MESSAGE_REGEX = /^(?:\w| )+/;
|
||||
function anonymizeErrorMessage(msg: string): string | undefined {
|
||||
const matchedMessage = msg.match(ANONYMIZE_MESSAGE_REGEX);
|
||||
const matchedMessage = ANONYMIZE_MESSAGE_REGEX.exec(msg);
|
||||
if (!matchedMessage?.[0]) {
|
||||
return undefined;
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ export class DevToolbarRadioCheckbox extends HTMLElement {
|
|||
|
||||
set radioStyle(value) {
|
||||
if (!styles.includes(value)) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(`Invalid style: ${value}, expected one of ${styles.join(', ')}.`);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -542,6 +542,7 @@ async function transition(
|
|||
// This log doesn't make it worse than before, where we got error messages about uncaught exceptions, which can't be caught when the trigger was a click or history traversal.
|
||||
// Needs more investigation on root causes if errors still occur sporadically
|
||||
const err = e as Error;
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('[astro]', err.name, err.message, err.stack);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -126,7 +126,7 @@ describe('CSS ordering - import order', () => {
|
|||
|
||||
const content = await Promise.all(getLinks(html).map((href) => getLinkContent(href)));
|
||||
const css = content.map((c) => c.css).join('');
|
||||
assert.equal(css.match(/\.astro-jsx/).length, 1, '.astro-jsx class is duplicated');
|
||||
assert.equal(/\.astro-jsx/.exec(css).length, 1, '.astro-jsx class is duplicated');
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -92,8 +92,8 @@ describe('CSS production ordering', () => {
|
|||
assert.ok(content.length, 3, 'there are 3 stylesheets');
|
||||
const [, sharedStyles, pageStyles] = content;
|
||||
|
||||
assert.ok(sharedStyles.css.match(/red/));
|
||||
assert.ok(pageStyles.css.match(/#00f/));
|
||||
assert.ok(/red/.exec(sharedStyles.css));
|
||||
assert.ok(/#00f/.exec(pageStyles.css));
|
||||
});
|
||||
|
||||
it('CSS injected by injectScript comes first because of import order', async () => {
|
||||
|
|
|
@ -183,11 +183,12 @@ describe.skip('Solid component dev', { todo: 'Check why the test hangs.', skip:
|
|||
const createHydrationScriptRegex = (flags) => new RegExp(/_\$HY=/, flags);
|
||||
|
||||
function countHydrationScripts(/** @type {string} */ html) {
|
||||
// eslint-disable-next-line regexp/prefer-regexp-exec
|
||||
return html.match(createHydrationScriptRegex('g'))?.length ?? 0;
|
||||
}
|
||||
|
||||
function getFirstHydrationScriptLocation(/** @type {string} */ html) {
|
||||
return html.match(createHydrationScriptRegex())?.index;
|
||||
return createHydrationScriptRegex().exec(html)?.index;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -202,9 +203,10 @@ function countHydrationEvents(/** @type {string} */ html) {
|
|||
// Number of times a component was hydrated during rendering
|
||||
// We look for the hint "_$HY.r["
|
||||
|
||||
// eslint-disable-next-line regexp/prefer-regexp-exec
|
||||
return html.match(createHydrationEventRegex('g'))?.length ?? 0;
|
||||
}
|
||||
|
||||
function getFirstHydrationEventLocation(/** @type {string} */ html) {
|
||||
return html.match(createHydrationEventRegex())?.index;
|
||||
return createHydrationEventRegex().exec(html)?.index;
|
||||
}
|
||||
|
|
|
@ -118,7 +118,7 @@ describe('API routes in SSR', () => {
|
|||
|
||||
let count = 0;
|
||||
let exp = /set-cookie:/g;
|
||||
while (exp.exec(response)) {
|
||||
while (exp.test(response)) {
|
||||
count++;
|
||||
}
|
||||
|
||||
|
|
|
@ -84,7 +84,7 @@ async function verifyTemplate(tmpl: string, ref?: string) {
|
|||
const GIT_RE = /^(?<repo>[\w.-]+\/[\w.-]+)(?<subdir>[^#]+)?(?<ref>#[\w.-]+)?/;
|
||||
|
||||
function parseGitURI(input: string) {
|
||||
const m = input.match(GIT_RE)?.groups;
|
||||
const m = GIT_RE.exec(input)?.groups;
|
||||
if (!m) throw new Error(`Unable to parse "${input}"`);
|
||||
return {
|
||||
repo: m.repo,
|
||||
|
|
|
@ -492,6 +492,5 @@ describe('column queries', () => {
|
|||
|
||||
/** @param {string} query */
|
||||
function getTempTableName(query) {
|
||||
// eslint-disable-next-line regexp/no-unused-capturing-group
|
||||
return query.match(/Users_([a-z\d]+)/)?.[0];
|
||||
return /Users_[a-z\d]+/.exec(query)?.[0];
|
||||
}
|
||||
|
|
|
@ -163,8 +163,7 @@ describe('reference queries', () => {
|
|||
});
|
||||
});
|
||||
|
||||
/** @param {string | undefined} query */
|
||||
/** @param {string} query */
|
||||
function getTempTableName(query) {
|
||||
// eslint-disable-next-line regexp/no-unused-capturing-group
|
||||
return query.match(/User_([a-z\d]+)/)?.[0];
|
||||
return /User_[a-z\d]+/.exec(query)?.[0];
|
||||
}
|
||||
|
|
|
@ -245,7 +245,7 @@ function raiseValidationErrors({
|
|||
e.error.id !== 'variable-undefined' &&
|
||||
// Ignore missing partial errors.
|
||||
// We will resolve these in `resolvePartials`.
|
||||
!(e.error.id === 'attribute-value-invalid' && e.error.message.match(/^Partial .+ not found/))
|
||||
!(e.error.id === 'attribute-value-invalid' && /^Partial .+ not found/.test(e.error.message))
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -275,7 +275,7 @@ function getUsedTags(markdocAst: Node) {
|
|||
// This is our signal that a tag is being used!
|
||||
for (const { error } of validationErrors) {
|
||||
if (error.id === 'tag-undefined') {
|
||||
const [, tagName] = error.message.match(/Undefined tag: '(.*)'/) ?? [];
|
||||
const [, tagName] = /Undefined tag: '(.*)'/.exec(error.message) ?? [];
|
||||
tags.add(tagName);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ async function compile(mdxCode, options) {
|
|||
});
|
||||
const code = result.toString();
|
||||
// Capture the returned JSX code for testing
|
||||
const jsx = code.match(/return (.+);\n\}\nexport default function MDXContent/s)?.[1];
|
||||
const jsx = /return (.+);\n\}\nexport default function MDXContent/s.exec(code)?.[1];
|
||||
if (jsx == null) throw new Error('Could not find JSX code in compiled MDX');
|
||||
return dedent(jsx);
|
||||
}
|
||||
|
|
|
@ -52,7 +52,7 @@ export function createStaticHandler(app: NodeApp, options: Options) {
|
|||
break;
|
||||
case 'always':
|
||||
// trailing slash is not added to "subresources"
|
||||
if (!hasSlash && !urlPath.match(isSubresourceRegex)) {
|
||||
if (!hasSlash && !isSubresourceRegex.test(urlPath)) {
|
||||
pathname = urlPath + '/' + (urlQuery ? '?' + urlQuery : '');
|
||||
res.statusCode = 301;
|
||||
res.setHeader('Location', pathname);
|
||||
|
|
|
@ -24,7 +24,7 @@ export function toTSX(code: string, className: string): string {
|
|||
|
||||
if (scriptSetup) {
|
||||
const codeWithoutComments = scriptSetup.content.replace(/\/\/.*|\/\*[\s\S]*?\*\//g, '');
|
||||
const definePropsType = codeWithoutComments.match(/defineProps<([\s\S]+?)>\s?\(\)/);
|
||||
const definePropsType = /defineProps<([\s\S]+?)>\s?\(\)/.exec(codeWithoutComments);
|
||||
const propsGeneric = scriptSetup.attrs.generic;
|
||||
const propsGenericType = propsGeneric ? `<${propsGeneric}>` : '';
|
||||
|
||||
|
@ -41,7 +41,7 @@ export function toTSX(code: string, className: string): string {
|
|||
// TODO. Find a way to support generics when using defineProps without passing explicit types.
|
||||
// Right now something like this `defineProps({ prop: { type: Array as PropType<T[]> } })`
|
||||
// won't be correctly typed in Astro.
|
||||
const defineProps = codeWithoutComments.match(/defineProps\([\s\S]+?\)/);
|
||||
const defineProps = /defineProps\([\s\S]+?\)/.exec(codeWithoutComments);
|
||||
if (defineProps) {
|
||||
result = `
|
||||
import { defineProps } from 'vue';
|
||||
|
|
|
@ -43,14 +43,14 @@ export async function highlightCodeBlocks(tree: Root, highlighter: Highlighter)
|
|||
let languageMatch: RegExpMatchArray | null | undefined;
|
||||
let { className } = node.properties;
|
||||
if (typeof className === 'string') {
|
||||
languageMatch = className.match(languagePattern);
|
||||
languageMatch = languagePattern.exec(className);
|
||||
} else if (Array.isArray(className)) {
|
||||
for (const cls of className) {
|
||||
if (typeof cls !== 'string') {
|
||||
continue;
|
||||
}
|
||||
|
||||
languageMatch = cls.match(languagePattern);
|
||||
languageMatch = languagePattern.exec(cls);
|
||||
if (languageMatch) {
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ export function rehypeHeadingIds(): ReturnType<RehypePlugin> {
|
|||
if (node.type !== 'element') return;
|
||||
const { tagName } = node;
|
||||
if (tagName[0] !== 'h') return;
|
||||
const [, level] = tagName.match(/h([0-6])/) ?? [];
|
||||
const [, level] = /h([0-6])/.exec(tagName) ?? [];
|
||||
if (!level) return;
|
||||
const depth = Number.parseInt(level);
|
||||
|
||||
|
@ -30,7 +30,7 @@ export function rehypeHeadingIds(): ReturnType<RehypePlugin> {
|
|||
return;
|
||||
}
|
||||
if (child.type === 'raw') {
|
||||
if (child.value.match(/^\n?<.*>\n?$/)) {
|
||||
if (/^\n?<.*>\n?$/.test(child.value)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue