Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve regex performance #11635

Merged
merged 1 commit into from
Aug 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -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',
},
},

Expand Down
2 changes: 1 addition & 1 deletion packages/astro/e2e/errors.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 *;`);

Expand Down
1 change: 1 addition & 0 deletions packages/astro/src/actions/runtime/middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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".'
Expand Down
Original file line number Diff line number Diff line change
@@ -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'

Expand Down
2 changes: 1 addition & 1 deletion packages/astro/src/core/app/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
6 changes: 3 additions & 3 deletions packages/astro/src/core/build/generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
}
Expand Down
9 changes: 5 additions & 4 deletions packages/astro/src/core/errors/dev/vite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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,
Expand All @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion packages/astro/src/events/error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
1 change: 1 addition & 0 deletions packages/astro/src/transitions/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
Expand Down
2 changes: 1 addition & 1 deletion packages/astro/test/css-order-import.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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');
});
});

Expand Down
4 changes: 2 additions & 2 deletions packages/astro/test/css-order.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 () => {
Expand Down
6 changes: 4 additions & 2 deletions packages/astro/test/solid-component.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

/**
Expand All @@ -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;
}
2 changes: 1 addition & 1 deletion packages/astro/test/ssr-api-route.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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++;
}

Expand Down
2 changes: 1 addition & 1 deletion packages/create-astro/src/actions/verify.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
3 changes: 1 addition & 2 deletions packages/db/test/unit/column-queries.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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];
}
5 changes: 2 additions & 3 deletions packages/db/test/unit/reference-queries.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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];
}
4 changes: 2 additions & 2 deletions packages/integrations/markdoc/src/content-entry-type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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))
);
});

Expand Down Expand Up @@ -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);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
2 changes: 1 addition & 1 deletion packages/integrations/node/src/serve-static.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
4 changes: 2 additions & 2 deletions packages/integrations/vue/src/editor.cts
Original file line number Diff line number Diff line change
Expand Up @@ -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}>` : '';

Expand All @@ -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';
Expand Down
4 changes: 2 additions & 2 deletions packages/markdown/remark/src/highlight.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
4 changes: 2 additions & 2 deletions packages/markdown/remark/src/rehype-collect-headings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand All @@ -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;
}
}
Expand Down
Loading