@@ -11,6 +11,8 @@ import type {
1111 FnRefBinding ,
1212 ForOfBinding ,
1313 Import ,
14+ ObjectPropBinding ,
15+ ObjectRestParamBinding ,
1416 ParamBinding ,
1517 SpreadArgBinding ,
1618 SubDeclaration ,
@@ -332,6 +334,8 @@ function extractSymbolsQuery(tree: TreeSitterTree, query: TreeSitterQuery): Extr
332334 const spreadArgBindings : SpreadArgBinding [ ] = [ ] ;
333335 const forOfBindings : ForOfBinding [ ] = [ ] ;
334336 const arrayCallbackBindings : ArrayCallbackBinding [ ] = [ ] ;
337+ const objectRestParamBindings : ObjectRestParamBinding [ ] = [ ] ;
338+ const objectPropBindings : ObjectPropBinding [ ] = [ ] ;
335339
336340 const matches = query . matches ( tree . rootNode ) ;
337341
@@ -373,6 +377,10 @@ function extractSymbolsQuery(tree: TreeSitterTree, query: TreeSitterQuery): Extr
373377 // Extract definitions from destructured bindings (query patterns don't match object_pattern)
374378 extractDestructuredBindingsWalk ( tree . rootNode , definitions ) ;
375379
380+ // Phase 8.3f: Extract object-rest parameter and object-property bindings
381+ extractObjectRestParamBindingsWalk ( tree . rootNode , objectRestParamBindings ) ;
382+ extractObjectPropBindingsWalk ( tree . rootNode , objectPropBindings ) ;
383+
376384 // Phase 8.5: collect all `new X()` constructor names for RTA instantiation tracking
377385 const newExpressions : string [ ] = [ ] ;
378386 extractNewExpressionsWalk ( tree . rootNode , newExpressions ) ;
@@ -392,6 +400,8 @@ function extractSymbolsQuery(tree: TreeSitterTree, query: TreeSitterQuery): Extr
392400 spreadArgBindings,
393401 forOfBindings,
394402 arrayCallbackBindings,
403+ objectRestParamBindings,
404+ objectPropBindings,
395405 newExpressions,
396406 } ;
397407}
@@ -629,6 +639,8 @@ function extractSymbolsWalk(tree: TreeSitterTree): ExtractorOutput {
629639 spreadArgBindings : [ ] ,
630640 forOfBindings : [ ] ,
631641 arrayCallbackBindings : [ ] ,
642+ objectRestParamBindings : [ ] ,
643+ objectPropBindings : [ ] ,
632644 } ;
633645
634646 walkJavaScriptNode ( tree . rootNode , ctx ) ;
@@ -657,6 +669,9 @@ function extractSymbolsWalk(tree: TreeSitterTree): ExtractorOutput {
657669 ctx . arrayCallbackBindings ! ,
658670 ctx . fnRefBindings ! ,
659671 ) ;
672+ // Phase 8.3f: Extract object-rest parameter and object-property bindings
673+ extractObjectRestParamBindingsWalk ( tree . rootNode , ctx . objectRestParamBindings ! ) ;
674+ extractObjectPropBindingsWalk ( tree . rootNode , ctx . objectPropBindings ! ) ;
660675 // Phase 8.5: collect all `new X()` constructor names for RTA instantiation tracking
661676 const newExpressions : string [ ] = [ ] ;
662677 extractNewExpressionsWalk ( tree . rootNode , newExpressions ) ;
@@ -1871,6 +1886,101 @@ function extractSpreadForOfWalk(
18711886 walk ( rootNode , 0 ) ;
18721887}
18731888
1889+ /**
1890+ * Phase 8.3f: collect object-rest parameter bindings.
1891+ *
1892+ * `function f({ a, ...rest }) {}` → `{ callee: "f", restName: "rest", argIndex: 0 }`
1893+ *
1894+ * Enables resolving `rest.prop()` when a known object is passed as that parameter.
1895+ */
1896+ function extractObjectRestParamBindingsWalk (
1897+ rootNode : TreeSitterNode ,
1898+ bindings : ObjectRestParamBinding [ ] ,
1899+ ) : void {
1900+ function walk ( node : TreeSitterNode , depth : number ) : void {
1901+ if ( depth >= MAX_WALK_DEPTH ) return ;
1902+ const t = node . type ;
1903+ if ( t === 'function_declaration' || t === 'function_expression' || t === 'arrow_function' ) {
1904+ const nameNode = node . childForFieldName ( 'name' ) ;
1905+ const funcName = nameNode ?. text ;
1906+ if ( funcName ) {
1907+ const paramsNode =
1908+ node . childForFieldName ( 'parameters' ) || findChild ( node , 'formal_parameters' ) ;
1909+ if ( paramsNode ) {
1910+ let argIndex = 0 ;
1911+ for ( let i = 0 ; i < paramsNode . childCount ; i ++ ) {
1912+ const param = paramsNode . child ( i ) ;
1913+ if ( ! param ) continue ;
1914+ const pt = param . type ;
1915+ if ( pt === ',' || pt === '(' || pt === ')' ) continue ;
1916+ if ( pt === 'object_pattern' ) {
1917+ for ( let j = 0 ; j < param . childCount ; j ++ ) {
1918+ const child = param . child ( j ) ;
1919+ if ( ! child ) continue ;
1920+ if ( child . type !== 'rest_pattern' && child . type !== 'rest_element' ) continue ;
1921+ const restNameNode = child . child ( 1 ) ?? child . childForFieldName ( 'name' ) ;
1922+ if ( restNameNode ?. type === 'identifier' ) {
1923+ bindings . push ( { callee : funcName , restName : restNameNode . text , argIndex } ) ;
1924+ }
1925+ }
1926+ }
1927+ argIndex ++ ;
1928+ }
1929+ }
1930+ }
1931+ }
1932+ for ( let i = 0 ; i < node . childCount ; i ++ ) {
1933+ walk ( node . child ( i ) ! , depth + 1 ) ;
1934+ }
1935+ }
1936+ walk ( rootNode , 0 ) ;
1937+ }
1938+
1939+ /**
1940+ * Phase 8.3f: collect object-property bindings from object literals.
1941+ *
1942+ * `const obj = { e4 }` → `{ objectName: "obj", propName: "e4", valueName: "e4" }`
1943+ * `const obj = { e1: fn }` → `{ objectName: "obj", propName: "e1", valueName: "fn" }`
1944+ *
1945+ * Only tracks shorthand and `key: identifier` pairs; skips function literals.
1946+ */
1947+ function extractObjectPropBindingsWalk (
1948+ rootNode : TreeSitterNode ,
1949+ bindings : ObjectPropBinding [ ] ,
1950+ ) : void {
1951+ function walk ( node : TreeSitterNode , depth : number ) : void {
1952+ if ( depth >= MAX_WALK_DEPTH ) return ;
1953+ if ( node . type === 'variable_declarator' ) {
1954+ const nameN = node . childForFieldName ( 'name' ) ;
1955+ const valueN = node . childForFieldName ( 'value' ) ;
1956+ if ( nameN ?. type === 'identifier' && valueN ?. type === 'object' ) {
1957+ const objectName = nameN . text ;
1958+ for ( let i = 0 ; i < valueN . childCount ; i ++ ) {
1959+ const child = valueN . child ( i ) ;
1960+ if ( ! child ) continue ;
1961+ if ( child . type === 'shorthand_property_identifier' ) {
1962+ bindings . push ( { objectName, propName : child . text , valueName : child . text } ) ;
1963+ } else if ( child . type === 'pair' ) {
1964+ const keyN = child . childForFieldName ( 'key' ) ;
1965+ const valN = child . childForFieldName ( 'value' ) ;
1966+ if (
1967+ keyN ?. type === 'property_identifier' &&
1968+ valN ?. type === 'identifier' &&
1969+ ! BUILTIN_GLOBALS . has ( valN . text )
1970+ ) {
1971+ bindings . push ( { objectName, propName : keyN . text , valueName : valN . text } ) ;
1972+ }
1973+ }
1974+ }
1975+ }
1976+ }
1977+ for ( let i = 0 ; i < node . childCount ; i ++ ) {
1978+ walk ( node . child ( i ) ! , depth + 1 ) ;
1979+ }
1980+ }
1981+ walk ( rootNode , 0 ) ;
1982+ }
1983+
18741984function extractReceiverName ( objNode : TreeSitterNode | null ) : string | undefined {
18751985 if ( ! objNode ) return undefined ;
18761986 const t = objNode . type ;
0 commit comments