@@ -124,6 +124,7 @@ function unwrapExpression(expression: SyntaxNode): SyntaxNode {
124124function getStaticPropertyName ( property : SyntaxNode ) : string | undefined {
125125 if ( ! isSyntaxNode ( property . key ) ) return undefined
126126 const key = property . key
127+ if ( property . computed === true ) return getStaticString ( key )
127128 if ( key . type === 'Identifier' && typeof key . name === 'string' ) return key . name
128129 if ( key . type === 'StringLiteral' && typeof key . value === 'string' ) return key . value
129130 return undefined
@@ -1278,11 +1279,28 @@ function functionContainsInternalRoute(
12781279 return found
12791280}
12801281
1281- function getToolId ( object : SyntaxNode ) : string | undefined {
1282+ function resolveStaticStringExpression (
1283+ expression : SyntaxNode ,
1284+ resolver : SelfHopResolver ,
1285+ seen = new Set < string > ( )
1286+ ) : string | undefined {
1287+ const value = unwrapExpression ( expression )
1288+ const staticValue = getStaticString ( value )
1289+ if ( staticValue !== undefined ) return staticValue
1290+ if ( value . type !== 'Identifier' || typeof value . name !== 'string' ) return undefined
1291+ const key = `${ resolver . file } :static-string:${ value . name } `
1292+ if ( seen . has ( key ) ) return undefined
1293+ const binding = resolveScopedIdentifier ( value . name , resolver )
1294+ if ( ! binding ) return undefined
1295+ const nextSeen = new Set ( seen )
1296+ nextSeen . add ( key )
1297+ return resolveStaticStringExpression ( binding . expression , binding . resolver , nextSeen )
1298+ }
1299+
1300+ function getToolId ( object : SyntaxNode , resolver : SelfHopResolver ) : string | undefined {
12821301 const idProperty = getObjectProperty ( object , 'id' )
12831302 if ( ! idProperty || ! isSyntaxNode ( idProperty . value ) ) return undefined
1284- const value = unwrapExpression ( idProperty . value )
1285- return value . type === 'StringLiteral' && typeof value . value === 'string' ? value . value : undefined
1303+ return resolveStaticStringExpression ( idProperty . value , resolver )
12861304}
12871305
12881306interface ScopedExpression {
@@ -1531,11 +1549,15 @@ function getResolvedObjectProperties(
15311549 const lastIndex = endIndex ?? properties . length - 1
15321550 for ( let index = lastIndex ; index >= 0 ; index -= 1 ) {
15331551 const property = properties [ index ]
1534- if (
1535- ( property . type === 'ObjectProperty' || property . type === 'ObjectMethod' ) &&
1536- getStaticPropertyName ( property ) === name
1537- ) {
1538- return { properties : [ { property, request } ] , complete : true }
1552+ if ( property . type === 'ObjectProperty' || property . type === 'ObjectMethod' ) {
1553+ const propertyName = getStaticPropertyName ( property )
1554+ if ( propertyName === name ) {
1555+ return { properties : [ { property, request } ] , complete : true }
1556+ }
1557+ if ( property . computed === true && propertyName === undefined ) {
1558+ const earlier = getResolvedObjectProperties ( request , name , seen , index - 1 )
1559+ return { properties : earlier . properties , complete : false }
1560+ }
15391561 }
15401562 if ( property . type !== 'SpreadElement' || ! isSyntaxNode ( property . argument ) ) continue
15411563 const key = `${ request . resolver . file } :spread:${ property . start ?? index } :${ name } `
@@ -1582,8 +1604,10 @@ export function auditToolSelfHops(source: string, file = 'source.ts'): ToolSelfH
15821604
15831605 const visit = ( node : SyntaxNode ) => {
15841606 if ( node . type === 'ObjectExpression' ) {
1585- const toolId = getToolId ( node )
1586- if ( toolId ) {
1607+ const idProperty = getObjectProperty ( node , 'id' )
1608+ const toolId = idProperty ? getToolId ( node , resolver ) : undefined
1609+ const directRequestProperty = getObjectProperty ( node , 'request' )
1610+ if ( idProperty && ( toolId !== undefined || directRequestProperty ) ) {
15871611 const toolObject : ResolvedRequestObject = {
15881612 expression : node ,
15891613 resolver,
0 commit comments