File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -144,6 +144,22 @@ describe('extractApiCalls', () => {
144144 const call = single ( "fetch('/u')" )
145145 expect ( call . hasErrorHandler ) . toBe ( false )
146146 } )
147+
148+ it ( 'does not throw for await fetch inside async function (regression)' , ( ) => {
149+ const source = `
150+ export async function loadItems() {
151+ const res = await fetch('/api/items', { headers: { Accept: 'application/json' } });
152+ const body = await res.json().catch(() => ({}));
153+ return body;
154+ }
155+ `
156+ const calls = extract ( source )
157+ expect ( calls . length ) . toBeGreaterThanOrEqual ( 1 )
158+ const fetchCall = calls . find ( ( c ) => c . caller === 'fetch' )
159+ expect ( fetchCall ) . toBeDefined ( )
160+ expect ( fetchCall ! . url ) . toBe ( '/api/items' )
161+ expect ( fetchCall ! . hasErrorHandler ) . toBe ( false )
162+ } )
147163 } )
148164
149165 describe ( 'known false positives' , ( ) => {
Original file line number Diff line number Diff line change @@ -497,12 +497,12 @@ function isInsideTryCatch(node: ts.Node): boolean {
497497}
498498
499499function hasCatchChain ( node : ts . CallExpression ) : boolean {
500- // Walk up property access chains: fetch(...). then(...).catch(...)
501- for ( let current : ts . Node = node ; ; current = current . parent ) {
502- const parent = current . parent
503-
504- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- SourceFile has no parent
505- if ( ! parent ) return false
500+ // Walk up from node; check whether any ancestor is a .catch / . then(_, reject) chain.
501+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- AST root may lack a parent
502+ for ( let parent = node . parent ; parent ; parent = parent . parent ) {
503+ if ( ts . isSourceFile ( parent ) ) {
504+ return false
505+ }
506506
507507 if ( ts . isPropertyAccessExpression ( parent ) && parent . name . text === 'catch' ) {
508508 return true
@@ -522,9 +522,9 @@ function hasCatchChain(node: ts.CallExpression): boolean {
522522 if ( ts . isExpressionStatement ( parent ) || ts . isVariableDeclaration ( parent ) ) {
523523 return false
524524 }
525-
526- current = parent
527525 }
526+
527+ return false
528528}
529529
530530function getLocation ( node : ts . Node , sourceFile : ts . SourceFile ) : SourceLocation {
Original file line number Diff line number Diff line change @@ -147,9 +147,10 @@ export async function scan(config: ScanConfig): Promise<ScanResult> {
147147 allApiCalls . push ( ...calls )
148148 } catch ( cause ) {
149149 filesErrored ++
150+ const detail = cause instanceof Error ? cause . message : String ( cause )
150151 diagnostics . push ( {
151152 kind : 'parse-error' ,
152- message : `Failed to parse ${ file . relativePath } ` ,
153+ message : `Failed to parse ${ file . relativePath } : ${ detail } ` ,
153154 file : file . absolutePath ,
154155 cause : cause instanceof Error ? cause : new Error ( String ( cause ) ) ,
155156 } )
You can’t perform that action at this time.
0 commit comments