@@ -76,6 +76,8 @@ const BANNED_PATTERNS: Array<{
7676 suggestion : string
7777 /** Restricts the pattern to matching files; unrestricted patterns apply everywhere. */
7878 appliesTo ?: ( rel : string , content : string ) => boolean
79+ /** Cheap literal test that gates a backreference-heavy pattern, which is slow over every file. */
80+ prefilter ?: RegExp
7981} > = [
8082 // Randomness / ID generation — global property access that import bans miss
8183 {
@@ -116,6 +118,7 @@ const BANNED_PATTERNS: Array<{
116118 / \b ( [ \w . ] + ) \s + i n s t a n c e o f \s + E r r o r \s * \? \s * \1\s * : \s * n e w \s + E r r o r \( \s * S t r i n g \( \s * \1\s * \) \s * \) / g,
117119 description : 'e instanceof Error ? e : new Error(String(e))' ,
118120 suggestion : 'toError(e) from @sim/utils/errors' ,
121+ prefilter : / n e w \s + E r r o r \( \s * S t r i n g \( / ,
119122 } ,
120123 {
121124 pattern :
@@ -139,12 +142,14 @@ const BANNED_PATTERNS: Array<{
139142 pattern :
140143 / \b ( [ \w . ] + ) \. l e n g t h \s * > \s * ( [ \w . ] + ) \s * \? \s * (?: ` \$ \{ \1\. (?: s l i c e | s u b s t r i n g ) \( \s * 0 \s * , \s * \2\s * \) \} [ ^ ` $ ] * ` | \1\. (?: s l i c e | s u b s t r i n g ) \( \s * 0 \s * , \s * \2\s * \) \s * \+ \s * (?: ' [ ^ ' ] * ' | " [ ^ " ] * " | \w + ) ) \s * : \s * \1\b (? ! \. ) / g,
141144 description : 's.length > n ? s.slice(0, n) + suffix : s' ,
145+ prefilter : / \. (?: s l i c e | s u b s t r i n g ) \( \s * 0 \s * , [ ^ ) ] * \) \s * (?: \} | \+ ) / ,
142146 suggestion : "truncate(s, n, suffix?) from @sim/utils/string (suffix defaults to '...')" ,
143147 } ,
144148 {
145149 pattern :
146150 / \b ( [ \w . ] + ) \. l e n g t h \s * < = \s * ( [ \w . ] + ) \s * \? \s * \1\s * : \s * (?: ` \$ \{ \1\. (?: s l i c e | s u b s t r i n g ) \( \s * 0 \s * , \s * \2\s * \) \} [ ^ ` $ ] * ` | \1\. (?: s l i c e | s u b s t r i n g ) \( \s * 0 \s * , \s * \2\s * \) \s * \+ \s * (?: ' [ ^ ' ] * ' | " [ ^ " ] * " | \w + ) ) / g,
147151 description : 's.length <= n ? s : s.slice(0, n) + suffix' ,
152+ prefilter : / \. (?: s l i c e | s u b s t r i n g ) \( \s * 0 \s * , [ ^ ) ] * \) \s * (?: \} | \+ ) / ,
148153 suggestion : "truncate(s, n, suffix?) from @sim/utils/string (suffix defaults to '...')" ,
149154 } ,
150155 {
@@ -166,7 +171,8 @@ const BANNED_PATTERNS: Array<{
166171 } ,
167172 {
168173 pattern :
169- / (?< = [ \s ' " ` ] | ^ ) ( (?: [ \w - ] + : ) * ) (?: h - ( \[ [ ^ \] \s ] + \] | [ \d . ] + | p x | f u l l | s c r e e n | a u t o | f i t | m i n | m a x ) \s + \1w - \2| w - ( \[ [ ^ \] \s ] + \] | [ \d . ] + | p x | f u l l | s c r e e n | a u t o | f i t | m i n | m a x ) \s + \1h - \3) (? = [ \s ' " ` ] | $ ) / gm,
174+ / (?: ^ | [ \t ' " ` ] ) ( (?: [ \w - ] + : ) * ) (?: h - ( \[ [ ^ \] \s ] + \] | [ \d . ] + | p x | f u l l | s c r e e n | a u t o | f i t | m i n | m a x ) \s + \1w - \2| w - ( \[ [ ^ \] \s ] + \] | [ \d . ] + | p x | f u l l | s c r e e n | a u t o | f i t | m i n | m a x ) \s + \1h - \3) (? = [ \s ' " ` ] | $ ) / gm,
175+ prefilter : / [ h w ] - \S + \s + (?: [ \w - ] + : ) * [ h w ] - / ,
170176 description : 'h-N w-N with equal N' ,
171177 suggestion : 'size-N (Tailwind) — e.g. `size-4`, `size-full`' ,
172178 } ,
@@ -260,8 +266,9 @@ async function main() {
260266 suggestion : string
261267 } > = [ ]
262268
263- for ( const { pattern, description, suggestion, appliesTo } of BANNED_PATTERNS ) {
269+ for ( const { pattern, description, suggestion, appliesTo, prefilter } of BANNED_PATTERNS ) {
264270 if ( appliesTo && ! appliesTo ( rel , content ) ) continue
271+ if ( prefilter && ! prefilter . test ( content ) ) continue
265272 pattern . lastIndex = 0
266273 for ( let match = pattern . exec ( content ) ; match !== null ; match = pattern . exec ( content ) ) {
267274 matches . push ( { index : match . index , description, suggestion } )
0 commit comments