Skip to content

Commit be05917

Browse files
fix: move regex literals to module scope to fix e18e/prefer-static-regex lint errors
Extracts inline regex patterns from inside functions to module-level constants across 38 files to avoid unnecessary re-compilation on every call. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 1a8e2d3 commit be05917

38 files changed

Lines changed: 182 additions & 89 deletions

File tree

examples/better-auth/server/drizzle/schema/book.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import { v7 as uuidv7 } from 'uuid'
44
import { user } from './auth'
55
import { customTimestamp } from './shared'
66

7+
const FOUR_DIGIT_YEAR_RE = /^\d{4}$/
8+
79
// Book table - Demonstrates user ownership with Better Auth
810
export const book = pgTable('book', {
911
id: uuid().primaryKey().$defaultFn(uuidv7),
@@ -30,7 +32,7 @@ export const insertBookSchema = createInsertSchema(book, {
3032
title: schema => schema.min(1, 'Title is required'),
3133
author: schema => schema.min(1, 'Author is required'),
3234
isbn: schema => schema.length(13, 'ISBN must be 13 characters').optional(),
33-
publishedYear: schema => schema.regex(/^\d{4}$/, 'Year must be 4 digits').optional(),
35+
publishedYear: schema => schema.regex(FOUR_DIGIT_YEAR_RE, 'Year must be 4 digits').optional(),
3436
}).omit({ userId: true }) // userId is auto-assigned in resolvers
3537

3638
export const selectBookSchema = createSelectSchema(book)

examples/drizzle-orm/server/drizzle/schema/book.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import { createInsertSchema, createSelectSchema } from 'drizzle-zod'
33
import { v7 as uuidv7 } from 'uuid'
44
import { customTimestamp } from './shared'
55

6+
const FOUR_DIGIT_YEAR_RE = /^\d{4}$/
7+
68
// Book table - Simple example with a single table
79
export const book = pgTable('book', {
810
id: uuid().primaryKey().$defaultFn(uuidv7),
@@ -24,7 +26,7 @@ export const insertBookSchema = createInsertSchema(book, {
2426
title: schema => schema.min(1, 'Title is required'),
2527
author: schema => schema.min(1, 'Author is required'),
2628
isbn: schema => schema.length(13, 'ISBN must be 13 characters').optional(),
27-
publishedYear: schema => schema.regex(/^\d{4}$/, 'Year must be 4 digits').optional(),
29+
publishedYear: schema => schema.regex(FOUR_DIGIT_YEAR_RE, 'Year must be 4 digits').optional(),
2830
})
2931

3032
export const selectBookSchema = createSelectSchema(book)

playgrounds/nitro/server/graphql/directives/format.directive.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ import { getDirective, MapperKind, mapSchema } from '@graphql-tools/utils'
22
import { defaultFieldResolver } from 'graphql'
33
import { defineDirective } from 'nitro-graphql/define'
44

5+
const UPPERCASE_LETTER_RE = /([A-Z])/g
6+
const UNDERSCORE_LOWERCASE_RE = /_([a-z])/g
7+
const LEADING_UNDERSCORE_RE = /^_/
8+
59
/**
610
* @format directive - Apply multiple formatting operations
711
*
@@ -57,10 +61,10 @@ export const formatDirective = defineDirective({
5761
result = result.charAt(0).toUpperCase() + result.slice(1).toLowerCase()
5862
break
5963
case 'SNAKE_CASE':
60-
result = result.replace(/([A-Z])/g, '_$1').toLowerCase().replace(/^_/, '')
64+
result = result.replace(UPPERCASE_LETTER_RE, '_$1').toLowerCase().replace(LEADING_UNDERSCORE_RE, '')
6165
break
6266
case 'CAMEL_CASE':
63-
result = result.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase())
67+
result = result.replace(UNDERSCORE_LOWERCASE_RE, (_, letter) => letter.toUpperCase())
6468
break
6569
}
6670
}

playgrounds/nitro/server/graphql/directives/list.directive.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ export const listDirective = defineDirective({
8383

8484
// Apply sort
8585
if (listDirective.sort && result.length > 0) {
86-
result = [...result].sort((a, b) => {
86+
result = result.toSorted((a, b) => {
8787
const aVal = a?.[listDirective.sort]
8888
const bVal = b?.[listDirective.sort]
8989

@@ -97,7 +97,7 @@ export const listDirective = defineDirective({
9797

9898
// Apply reverse
9999
if (listDirective.reverse) {
100-
result = [...result].reverse()
100+
result = result.toReversed()
101101
}
102102

103103
// Apply max limit

playgrounds/subscriptions/server/graphql/chat.resolver.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import {
1212
withFilter,
1313
} from 'nitro-graphql/define'
1414

15+
const WHITESPACE_RE = /\s+/g
16+
1517
// Define topic types for type-safe PubSub
1618
interface ChatTopics {
1719
'message:added': Message
@@ -53,7 +55,7 @@ export const chatQueries = defineQuery({
5355
},
5456

5557
channels: () => {
56-
return Array.from(channels.values())
58+
return [...channels.values()]
5759
},
5860
})
5961

@@ -81,7 +83,7 @@ export const chatMutations = defineMutation({
8183

8284
createChannel: async (_, { name }) => {
8385
const channel: Channel = {
84-
id: name.toLowerCase().replace(/\s+/g, '-'),
86+
id: name.toLowerCase().replace(WHITESPACE_RE, '-'),
8587
name,
8688
createdAt: new Date().toISOString(),
8789
}

src/cli/commands/generate.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ import { buildGraphQLSchema } from '../../core/schema'
2121
import { existsSync_, mkdirSync_, onSignal, readFileSync_, writeFileSync_ } from '../../core/utils/runtime'
2222

2323
const logger = consola.withTag(LOG_TAG)
24+
const NODE_MODULES_RE = /node_modules/
25+
const DOT_GIT_RE = /\.git/
2426

2527
/**
2628
* Create ScanContext from CLI context
@@ -302,8 +304,8 @@ async function watchAndRegenerate(
302304
ignoreInitial: true,
303305
ignored: [
304306
...ctx.config.ignore || [],
305-
/node_modules/,
306-
/\.git/,
307+
NODE_MODULES_RE,
308+
DOT_GIT_RE,
307309
],
308310
persistent: true,
309311
})

src/cli/commands/init.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import { basename, join, relative, resolve } from 'pathe'
1212
import { LOG_TAG } from '../../core/constants'
1313

1414
const logger = consola.withTag(LOG_TAG)
15+
const NON_ALPHANUMERIC_HYPHEN_RE = /[^a-z0-9-]/gi
16+
const LEADING_TRAILING_HYPHENS_RE = /^-+|-+$/g
1517

1618
/**
1719
* Available templates from the examples directory
@@ -121,8 +123,8 @@ export async function initFromTemplate(
121123
try {
122124
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'))
123125
const slug = basename(projectName)
124-
.replace(/[^a-z0-9-]/gi, '-')
125-
.replace(/^-+|-+$/g, '')
126+
.replace(NON_ALPHANUMERIC_HYPHEN_RE, '-')
127+
.replace(LEADING_TRAILING_HYPHENS_RE, '')
126128
.toLowerCase()
127129

128130
packageJson.name = slug || 'my-graphql-app'

src/cli/server/debug-handler.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ async function collectDebugInfo(ctx: CLIContext): Promise<DebugInfo> {
4646
// Process resolver files for display
4747
const resolverFiles = resolversResult.items.map((r) => {
4848
const parts = r.specifier.split('/')
49-
const fileName = parts[parts.length - 1] || r.specifier
49+
const fileName = parts.at(-1) || r.specifier
5050

5151
return {
5252
file: fileName,

src/core/codegen/runtime.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@
66
import type { ScannedResolver } from '../types'
77
import { relative } from 'pathe'
88

9+
const TS_EXTENSION_RE = /\.ts$/
10+
const BACKTICK_RE = /`/g
11+
const DOLLAR_SIGN_RE = /\$/g
12+
913
/**
1014
* Generate resolver module code
1115
* Outputs Nitro-compatible format with { resolver: ... } wrapper
@@ -26,7 +30,7 @@ export const resolvers = []
2630

2731
for (const resolver of resolvers) {
2832
// Calculate relative path from baseDir to resolver file
29-
const relativePath = relative(baseDir, resolver.specifier).replace(/\.ts$/, '')
33+
const relativePath = relative(baseDir, resolver.specifier).replace(TS_EXTENSION_RE, '')
3034

3135
// Get all export names
3236
const exportNames = resolver.imports.map(i => i.name)
@@ -62,7 +66,7 @@ ${reexports.join('\n')}
6266
*/
6367
export function generateSchemaModule(schemaString: string): string {
6468
// Escape backticks in schema string
65-
const escapedSchema = schemaString.replace(/`/g, '\\`').replace(/\$/g, '\\$')
69+
const escapedSchema = schemaString.replace(BACKTICK_RE, '\\`').replace(DOLLAR_SIGN_RE, '\\$')
6670

6771
return `// Auto-generated by nitro-graphql - do not edit
6872
export const schemaString = \`

src/core/debug/template.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ export interface DebugInfo {
3939
virtualModules: Record<string, string>
4040
}
4141

42+
const HTML_SPECIAL_CHARS_RE = /[&<>"']/g
43+
const DOUBLE_QUOTE_RE = /"/g
44+
4245
/**
4346
* Escape HTML special characters
4447
*/
@@ -50,7 +53,7 @@ export function escapeHtml(text: string): string {
5053
'"': '&quot;',
5154
'\'': '&#039;',
5255
}
53-
return text.replace(/[&<>"']/g, m => map[m] || m)
56+
return text.replace(HTML_SPECIAL_CHARS_RE, m => map[m] || m)
5457
}
5558

5659
/**
@@ -189,7 +192,7 @@ function renderVirtualModules(virtualModules: Record<string, string>): string {
189192
</div>
190193
<button
191194
onclick="event.stopPropagation(); navigator.clipboard.writeText(this.getAttribute('data-code')); this.textContent = '✓ Copied!'; setTimeout(() => this.textContent = 'Copy', 1000)"
192-
data-code="${escapeHtml(code).replace(/"/g, '&quot;')}"
195+
data-code="${escapeHtml(code).replace(DOUBLE_QUOTE_RE, '&quot;')}"
193196
class="text-xs px-3 py-1.5 bg-slate-800 hover:bg-slate-700 text-slate-300 rounded border border-slate-600/50 transition-colors"
194197
>
195198
Copy

0 commit comments

Comments
 (0)