From 50fdb2f55d9061900336e94c94f14798ccdf69c1 Mon Sep 17 00:00:00 2001 From: Dan Lynch Date: Wed, 5 Aug 2026 22:38:57 +0000 Subject: [PATCH] perf(transform): reuse compiled schema regexes and skip absent schemas --- packages/transform/src/transform.ts | 64 ++++++++++++++++++++++++----- 1 file changed, 54 insertions(+), 10 deletions(-) diff --git a/packages/transform/src/transform.ts b/packages/transform/src/transform.ts index 56ca556e..00f6f711 100644 --- a/packages/transform/src/transform.ts +++ b/packages/transform/src/transform.ts @@ -292,7 +292,8 @@ export function transformSchemaRefsInString( // References embedded in opaque strings carry no object identity, so only // whole-schema (schema-level default) routes can be applied here. for (const [oldSchema, newSchema] of schemaLevelMap(schemaMapping)) { - const pattern = new RegExp(`(?(); + +function cachedRegExp(source: string, flags: string): RegExp { + const key = `${flags}\u0000${source}`; + let re = regExpCache.get(key); + if (!re) { + re = new RegExp(source, flags); + regExpCache.set(key, re); + } + return re; +} + +const escapeRegexpCache = new Map(); + +function cachedEscapeRegexp(str: string): string { + let escaped = escapeRegexpCache.get(str); + if (escaped === undefined) { + escaped = escapeRegexp(str); + escapeRegexpCache.set(str, escaped); + } + return escaped; +} + /** * Extract pgpm header comments from the beginning of SQL content. */ @@ -1148,7 +1187,7 @@ export function transformComments( result.schemasFound.add(schema); - const pathPattern = new RegExp(`(schemas/)${escapeRegexp(schema)}(/|$)`, 'g'); + const pathPattern = cachedRegExp(`(schemas/)${cachedEscapeRegexp(schema)}(/|$)`, 'g'); const before = newPath; newPath = newPath.replace(pathPattern, `$1${newName}$2`); @@ -1173,14 +1212,17 @@ export function transformVerifyCalls( const schemas = Array.from(schemaMapping.keys()).sort((a, b) => b.length - a.length); let newContent = content; + // The pattern needs the schema name spelled out, case-insensitively. + let lowerContent = content.toLowerCase(); for (const schema of schemas) { const newName = schemaMapping.get(schema); if (!newName) continue; + if (!lowerContent.includes(schema.toLowerCase())) continue; - const escapedSchema = escapeRegexp(schema); + const escapedSchema = cachedEscapeRegexp(schema); - const verifyPattern = new RegExp( + const verifyPattern = cachedRegExp( `(verify_(?:function|table|trigger|type|domain|view|index|constraint|schema|policy|table_grant|function_grant|sequence_grant|type_grant)\\s*\\(\\s*')${escapedSchema}(\\.|'\\s*\\))`, 'gi' ); @@ -1189,6 +1231,7 @@ export function transformVerifyCalls( newContent = newContent.replace(verifyPattern, `$1${newName}$2`); if (newContent !== before) { + lowerContent = newContent.toLowerCase(); result.schemasFound.add(schema); result.schemasTransformed.set(schema, newName); } @@ -1212,10 +1255,11 @@ export function transformJsonStringValues( for (const schema of schemas) { const newName = schemaMapping.get(schema); if (!newName) continue; + if (!newContent.includes(schema)) continue; - const escapedSchema = escapeRegexp(schema); + const escapedSchema = cachedEscapeRegexp(schema); - const jsonValuePattern = new RegExp( + const jsonValuePattern = cachedRegExp( `(:")${escapedSchema}(")`, 'g' );