summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Bjorn Lu <bjornlu.dev@gmail.com> 2024-08-07 16:01:23 +0800
committerGravatar GitHub <noreply@github.com> 2024-08-07 16:01:23 +0800
commitea82b03cd6d40c6bd541046f2f9aedfed058ff4f (patch)
tree620fbe169215cba926d7f6376a8b75cb7c12c8e3
parent74a093056df99b2714ecc30fc2c36e88778dd9ce (diff)
downloadastro-ea82b03cd6d40c6bd541046f2f9aedfed058ff4f.tar.gz
astro-ea82b03cd6d40c6bd541046f2f9aedfed058ff4f.tar.zst
astro-ea82b03cd6d40c6bd541046f2f9aedfed058ff4f.zip
Improve regex performance (#11635)
-rw-r--r--eslint.config.js2
-rw-r--r--packages/astro/e2e/errors.test.js2
-rw-r--r--packages/astro/src/actions/runtime/middleware.ts1
-rw-r--r--packages/astro/src/assets/utils/vendor/image-size/types/svg.ts1
-rw-r--r--packages/astro/src/core/app/index.ts2
-rw-r--r--packages/astro/src/core/build/generate.ts6
-rw-r--r--packages/astro/src/core/errors/dev/vite.ts9
-rw-r--r--packages/astro/src/events/error.ts2
-rw-r--r--packages/astro/src/runtime/client/dev-toolbar/ui-library/radio-checkbox.ts1
-rw-r--r--packages/astro/src/transitions/router.ts1
-rw-r--r--packages/astro/test/css-order-import.test.js2
-rw-r--r--packages/astro/test/css-order.test.js4
-rw-r--r--packages/astro/test/solid-component.test.js6
-rw-r--r--packages/astro/test/ssr-api-route.test.js2
-rw-r--r--packages/create-astro/src/actions/verify.ts2
-rw-r--r--packages/db/test/unit/column-queries.test.js3
-rw-r--r--packages/db/test/unit/reference-queries.test.js5
-rw-r--r--packages/integrations/markdoc/src/content-entry-type.ts4
-rw-r--r--packages/integrations/mdx/test/units/rehype-optimize-static.test.js2
-rw-r--r--packages/integrations/node/src/serve-static.ts2
-rw-r--r--packages/integrations/vue/src/editor.cts4
-rw-r--r--packages/markdown/remark/src/highlight.ts4
-rw-r--r--packages/markdown/remark/src/rehype-collect-headings.ts4
23 files changed, 39 insertions, 32 deletions
diff --git a/eslint.config.js b/eslint.config.js
index ab7efa3df..f12bf49d1 100644
--- a/eslint.config.js
+++ b/eslint.config.js
@@ -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',
},
},
diff --git a/packages/astro/e2e/errors.test.js b/packages/astro/e2e/errors.test.js
index 2f1358548..9087ac484 100644
--- a/packages/astro/e2e/errors.test.js
+++ b/packages/astro/e2e/errors.test.js
@@ -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 *;`);
diff --git a/packages/astro/src/actions/runtime/middleware.ts b/packages/astro/src/actions/runtime/middleware.ts
index 2cc1b1e28..3d430b04a 100644
--- a/packages/astro/src/actions/runtime/middleware.ts
+++ b/packages/astro/src/actions/runtime/middleware.ts
@@ -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".'
diff --git a/packages/astro/src/assets/utils/vendor/image-size/types/svg.ts b/packages/astro/src/assets/utils/vendor/image-size/types/svg.ts
index 11baaf6d2..a0099d0a0 100644
--- a/packages/astro/src/assets/utils/vendor/image-size/types/svg.ts
+++ b/packages/astro/src/assets/utils/vendor/image-size/types/svg.ts
@@ -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'
diff --git a/packages/astro/src/core/app/index.ts b/packages/astro/src/core/app/index.ts
index a2b1d4f2e..42027098f 100644
--- a/packages/astro/src/core/app/index.ts
+++ b/packages/astro/src/core/app/index.ts
@@ -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;
diff --git a/packages/astro/src/core/build/generate.ts b/packages/astro/src/core/build/generate.ts
index de98093c7..e3fca6120 100644
--- a/packages/astro/src/core/build/generate.ts
+++ b/packages/astro/src/core/build/generate.ts
@@ -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;
}
diff --git a/packages/astro/src/core/errors/dev/vite.ts b/packages/astro/src/core/errors/dev/vite.ts
index 1612754d0..b63d696f5 100644
--- a/packages/astro/src/core/errors/dev/vite.ts
+++ b/packages/astro/src/core/errors/dev/vite.ts
@@ -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);
diff --git a/packages/astro/src/events/error.ts b/packages/astro/src/events/error.ts
index 8b8e9767e..77de088c5 100644
--- a/packages/astro/src/events/error.ts
+++ b/packages/astro/src/events/error.ts
@@ -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;
}
diff --git a/packages/astro/src/runtime/client/dev-toolbar/ui-library/radio-checkbox.ts b/packages/astro/src/runtime/client/dev-toolbar/ui-library/radio-checkbox.ts
index a223bf1a8..79508cc69 100644
--- a/packages/astro/src/runtime/client/dev-toolbar/ui-library/radio-checkbox.ts
+++ b/packages/astro/src/runtime/client/dev-toolbar/ui-library/radio-checkbox.ts
@@ -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;
}
diff --git a/packages/astro/src/transitions/router.ts b/packages/astro/src/transitions/router.ts
index b5e1a2235..673eb4eb2 100644
--- a/packages/astro/src/transitions/router.ts
+++ b/packages/astro/src/transitions/router.ts
@@ -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);
}
}
diff --git a/packages/astro/test/css-order-import.test.js b/packages/astro/test/css-order-import.test.js
index d8ee74a1d..b64125d70 100644
--- a/packages/astro/test/css-order-import.test.js
+++ b/packages/astro/test/css-order-import.test.js
@@ -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');
});
});
diff --git a/packages/astro/test/css-order.test.js b/packages/astro/test/css-order.test.js
index ee2992a31..4c1b41cfc 100644
--- a/packages/astro/test/css-order.test.js
+++ b/packages/astro/test/css-order.test.js
@@ -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 () => {
diff --git a/packages/astro/test/solid-component.test.js b/packages/astro/test/solid-component.test.js
index bd2c4f64f..3d0eb3161 100644
--- a/packages/astro/test/solid-component.test.js
+++ b/packages/astro/test/solid-component.test.js
@@ -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;
}
diff --git a/packages/astro/test/ssr-api-route.test.js b/packages/astro/test/ssr-api-route.test.js
index 4c2e796e1..6c5d1ad09 100644
--- a/packages/astro/test/ssr-api-route.test.js
+++ b/packages/astro/test/ssr-api-route.test.js
@@ -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++;
}
diff --git a/packages/create-astro/src/actions/verify.ts b/packages/create-astro/src/actions/verify.ts
index a6c9cc7e1..605b6959d 100644
--- a/packages/create-astro/src/actions/verify.ts
+++ b/packages/create-astro/src/actions/verify.ts
@@ -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,
diff --git a/packages/db/test/unit/column-queries.test.js b/packages/db/test/unit/column-queries.test.js
index ebb865670..bd59fd458 100644
--- a/packages/db/test/unit/column-queries.test.js
+++ b/packages/db/test/unit/column-queries.test.js
@@ -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];
}
diff --git a/packages/db/test/unit/reference-queries.test.js b/packages/db/test/unit/reference-queries.test.js
index 791344146..3a457192f 100644
--- a/packages/db/test/unit/reference-queries.test.js
+++ b/packages/db/test/unit/reference-queries.test.js
@@ -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];
}
diff --git a/packages/integrations/markdoc/src/content-entry-type.ts b/packages/integrations/markdoc/src/content-entry-type.ts
index 8fc4bd77c..bd19e1ccd 100644
--- a/packages/integrations/markdoc/src/content-entry-type.ts
+++ b/packages/integrations/markdoc/src/content-entry-type.ts
@@ -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);
}
}
diff --git a/packages/integrations/mdx/test/units/rehype-optimize-static.test.js b/packages/integrations/mdx/test/units/rehype-optimize-static.test.js
index 132f3849f..675bc3478 100644
--- a/packages/integrations/mdx/test/units/rehype-optimize-static.test.js
+++ b/packages/integrations/mdx/test/units/rehype-optimize-static.test.js
@@ -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);
}
diff --git a/packages/integrations/node/src/serve-static.ts b/packages/integrations/node/src/serve-static.ts
index 0ec129d9f..8256c588e 100644
--- a/packages/integrations/node/src/serve-static.ts
+++ b/packages/integrations/node/src/serve-static.ts
@@ -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);
diff --git a/packages/integrations/vue/src/editor.cts b/packages/integrations/vue/src/editor.cts
index d4f10aab6..64b34b45b 100644
--- a/packages/integrations/vue/src/editor.cts
+++ b/packages/integrations/vue/src/editor.cts
@@ -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';
diff --git a/packages/markdown/remark/src/highlight.ts b/packages/markdown/remark/src/highlight.ts
index 41ec8880b..ef1a734ba 100644
--- a/packages/markdown/remark/src/highlight.ts
+++ b/packages/markdown/remark/src/highlight.ts
@@ -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;
}
diff --git a/packages/markdown/remark/src/rehype-collect-headings.ts b/packages/markdown/remark/src/rehype-collect-headings.ts
index 862400545..3bff443e2 100644
--- a/packages/markdown/remark/src/rehype-collect-headings.ts
+++ b/packages/markdown/remark/src/rehype-collect-headings.ts
@@ -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;
}
}