@@ -26,6 +26,10 @@ import path from 'node:path';
2626
2727const EXCLUDED_STATEMENTS = new Set ( [ 'BreakStatement' , 'LabeledStatement' , 'ContinueStatement' ] ) ;
2828
29+ // Cheap prefilter: any meaningful JS statement must contain at least one of these characters,
30+ // or be an import/export with a string literal (side-effect imports have no punctuation)
31+ const CODE_CHAR_PATTERN = / [ ; { } ( ) = < > ] | \b i m p o r t \s + [ ' " ] | \b e x p o r t \s / ;
32+
2933const recognizer = new CodeRecognizer ( 0.9 , new JavaScriptFootPrint ( ) ) ;
3034
3135interface GroupComment {
@@ -113,36 +117,38 @@ export const rule: Rule.RuleModule = {
113117 } ,
114118} ;
115119
116- function isExpressionExclusion ( statement : estree . Node , code : SourceCode ) {
120+ function isExpressionExclusion ( statement : estree . Node , value : string , program : AST . Program ) {
117121 if ( statement . type === 'ExpressionStatement' ) {
118122 const expression = statement . expression ;
119123 if (
120124 expression . type === 'Identifier' ||
121125 expression . type === 'SequenceExpression' ||
122126 isUnaryPlusOrMinus ( expression ) ||
123- isExcludedLiteral ( expression ) ||
124- ! code . getLastToken ( statement , token => token . value === ';' )
127+ isExcludedLiteral ( expression )
125128 ) {
126129 return true ;
127130 }
131+ // Only construct SourceCode when we need getLastToken
132+ const code = new SourceCode ( value , program ) ;
133+ return ! code . getLastToken ( statement , token => token . value === ';' ) ;
128134 }
129135 return false ;
130136}
131137
132- function isExclusion ( parsedBody : Array < estree . Node > , code : SourceCode ) {
138+ function isExclusion ( parsedBody : Array < estree . Node > , value : string , program : AST . Program ) {
133139 if ( parsedBody . length === 1 ) {
134140 const singleStatement = parsedBody [ 0 ] ;
135141 return (
136142 EXCLUDED_STATEMENTS . has ( singleStatement . type ) ||
137143 isReturnThrowExclusion ( singleStatement ) ||
138- isExpressionExclusion ( singleStatement , code )
144+ isExpressionExclusion ( singleStatement , value , program )
139145 ) ;
140146 }
141147 return false ;
142148}
143149
144150function containsCode ( value : string , context : Rule . RuleContext ) {
145- if ( ! couldBeJsCode ( value ) || ! context . languageOptions . parser ) {
151+ if ( ! CODE_CHAR_PATTERN . test ( value ) || ! couldBeJsCode ( value ) || ! context . languageOptions . parser ) {
146152 return false ;
147153 }
148154
@@ -158,28 +164,32 @@ function containsCode(value: string, context: Rule.RuleContext) {
158164 context . languageOptions ?. parserOptions ?. parser ?? context . languageOptions ?. parser ;
159165 const result =
160166 'parse' in parser ? parser . parse ( value , options ) : parser . parseForESLint ( value , options ) . ast ;
161- const parseResult = new SourceCode ( value , result as AST . Program ) ;
162- return parseResult . ast . body . length > 0 && ! isExclusion ( parseResult . ast . body , parseResult ) ;
167+ const program = result as AST . Program ;
168+ return program . body . length > 0 && ! isExclusion ( program . body , value , program ) ;
163169 } catch {
164170 return false ;
165171 }
166172}
167173
168174function couldBeJsCode ( input : string ) : boolean {
169- return recognizer . extractCodeLines ( input . split ( '\n' ) ) . length > 0 ;
175+ return input . split ( '\n' ) . some ( line => recognizer . recognition ( line ) >= recognizer . threshold ) ;
170176}
171177
172178function injectMissingBraces ( value : string ) {
173- const openCurlyBraceNum = ( value . match ( / { / g) ?? [ ] ) . length ;
174- const closeCurlyBraceNum = ( value . match ( / } / g) ?? [ ] ) . length ;
175- const missingBraces = openCurlyBraceNum - closeCurlyBraceNum ;
176- if ( missingBraces > 0 ) {
177- return value + '}' . repeat ( missingBraces ) ;
178- } else if ( missingBraces < 0 ) {
179- return '{' . repeat ( - missingBraces ) + value ;
180- } else {
181- return value ;
179+ let balance = 0 ;
180+ for ( let i = 0 ; i < value . length ; i ++ ) {
181+ if ( value [ i ] === '{' ) {
182+ balance ++ ;
183+ } else if ( value [ i ] === '}' ) {
184+ balance -- ;
185+ }
186+ }
187+ if ( balance > 0 ) {
188+ return value + '}' . repeat ( balance ) ;
189+ } else if ( balance < 0 ) {
190+ return '{' . repeat ( - balance ) + value ;
182191 }
192+ return value ;
183193}
184194
185195function getCommentLocation ( nodes : TSESTree . Comment [ ] ) {
0 commit comments