55 * This snapshot is used to track API changes between versions.
66 */
77
8+ import { execSync } from 'child_process'
89import * as fs from 'fs'
910import * as path from 'path'
1011import * as ts from 'typescript'
@@ -21,6 +22,60 @@ if (!fs.existsSync(filePath)) {
2122 process . exit ( 1 )
2223}
2324
25+ /**
26+ * Search for the declaration in source files
27+ * Returns {file, line} or null if not found
28+ */
29+ function findInSourceFiles ( declarationName , kind , sourceRoot = 'src' ) {
30+ const searchPattern = getSearchPattern ( declarationName , kind )
31+ if ( ! searchPattern ) return null
32+
33+ try {
34+ // Search for the declaration pattern in source files
35+ const result = execSync (
36+ `grep -rn "${ searchPattern } " ${ sourceRoot } --include="*.ts" --include="*.tsx" | head -1` ,
37+ { encoding : 'utf-8' , stdio : [ 'pipe' , 'pipe' , 'ignore' ] }
38+ ) . trim ( )
39+
40+ if ( result ) {
41+ // Parse grep output: filepath:line:content
42+ const match = result . match ( / ^ ( [ ^ : ] + ) : ( \d + ) : / )
43+ if ( match ) {
44+ return {
45+ file : match [ 1 ] ,
46+ line : parseInt ( match [ 2 ] , 10 )
47+ }
48+ }
49+ }
50+ } catch ( error ) {
51+ // grep returns non-zero exit code if no match found
52+ }
53+
54+ return null
55+ }
56+
57+ /**
58+ * Generate search pattern for finding declaration in source
59+ */
60+ function getSearchPattern ( name , kind ) {
61+ switch ( kind ) {
62+ case 'interface' :
63+ return `export interface ${ name } `
64+ case 'class' :
65+ return `export class ${ name } `
66+ case 'type' :
67+ return `export type ${ name } `
68+ case 'enum' :
69+ return `export enum ${ name } `
70+ case 'function' :
71+ return `export function ${ name } `
72+ case 'constant' :
73+ return `export const ${ name } `
74+ default :
75+ return null
76+ }
77+ }
78+
2479/**
2580 * Extract API surface from TypeScript definitions
2681 */
@@ -39,12 +94,15 @@ function extractApiSurface(sourceFile) {
3994 if ( ts . isTypeAliasDeclaration ( node ) && node . name ) {
4095 const name = node . name . text
4196 const { line } = sourceFile . getLineAndCharacterOfPosition ( node . getStart ( ) )
97+ const sourceLocation = findInSourceFiles ( name , 'type' )
4298 api . types [ name ] = {
4399 kind : 'type' ,
44100 name,
45101 text : node . getText ( sourceFile ) ,
46102 exported : hasExportModifier ( node ) ,
47- line : line + 1 // Convert to 1-indexed
103+ line : line + 1 , // Convert to 1-indexed
104+ sourceFile : sourceLocation ?. file ,
105+ sourceLine : sourceLocation ?. line
48106 }
49107 }
50108
@@ -75,6 +133,7 @@ function extractApiSurface(sourceFile) {
75133 }
76134 } )
77135
136+ const sourceLocation = findInSourceFiles ( name , 'interface' )
78137 api . interfaces [ name ] = {
79138 kind : 'interface' ,
80139 name,
@@ -87,7 +146,9 @@ function extractApiSurface(sourceFile) {
87146 )
88147 . flat ( )
89148 : [ ] ,
90- line : line + 1 // Convert to 1-indexed
149+ line : line + 1 , // Convert to 1-indexed
150+ sourceFile : sourceLocation ?. file ,
151+ sourceLine : sourceLocation ?. line
91152 }
92153 }
93154
@@ -102,19 +163,23 @@ function extractApiSurface(sourceFile) {
102163 : undefined
103164 } ) )
104165
166+ const sourceLocation = findInSourceFiles ( name , 'enum' )
105167 api . enums [ name ] = {
106168 kind : 'enum' ,
107169 name,
108170 members,
109171 exported : hasExportModifier ( node ) ,
110- line : line + 1 // Convert to 1-indexed
172+ line : line + 1 , // Convert to 1-indexed
173+ sourceFile : sourceLocation ?. file ,
174+ sourceLine : sourceLocation ?. line
111175 }
112176 }
113177
114178 // Extract functions
115179 if ( ts . isFunctionDeclaration ( node ) && node . name ) {
116180 const name = node . name . text
117181 const { line } = sourceFile . getLineAndCharacterOfPosition ( node . getStart ( ) )
182+ const sourceLocation = findInSourceFiles ( name , 'function' )
118183 api . functions [ name ] = {
119184 kind : 'function' ,
120185 name,
@@ -125,7 +190,9 @@ function extractApiSurface(sourceFile) {
125190 } ) ) ,
126191 returnType : node . type ? node . type . getText ( sourceFile ) : 'any' ,
127192 exported : hasExportModifier ( node ) ,
128- line : line + 1 // Convert to 1-indexed
193+ line : line + 1 , // Convert to 1-indexed
194+ sourceFile : sourceLocation ?. file ,
195+ sourceLine : sourceLocation ?. line
129196 }
130197 }
131198
@@ -159,6 +226,7 @@ function extractApiSurface(sourceFile) {
159226 }
160227 } )
161228
229+ const sourceLocation = findInSourceFiles ( name , 'class' )
162230 api . classes [ name ] = {
163231 kind : 'class' ,
164232 name,
@@ -172,7 +240,9 @@ function extractApiSurface(sourceFile) {
172240 )
173241 . flat ( )
174242 : [ ] ,
175- line : line + 1 // Convert to 1-indexed
243+ line : line + 1 , // Convert to 1-indexed
244+ sourceFile : sourceLocation ?. file ,
245+ sourceLine : sourceLocation ?. line
176246 }
177247 }
178248
@@ -182,12 +252,15 @@ function extractApiSurface(sourceFile) {
182252 node . declarationList . declarations . forEach ( ( decl ) => {
183253 if ( decl . name && ts . isIdentifier ( decl . name ) ) {
184254 const name = decl . name . text
255+ const sourceLocation = findInSourceFiles ( name , 'constant' )
185256 api . constants [ name ] = {
186257 kind : 'constant' ,
187258 name,
188259 type : decl . type ? decl . type . getText ( sourceFile ) : 'unknown' ,
189260 exported : hasExportModifier ( node ) ,
190- line : line + 1 // Convert to 1-indexed
261+ line : line + 1 , // Convert to 1-indexed
262+ sourceFile : sourceLocation ?. file ,
263+ sourceLine : sourceLocation ?. line
191264 }
192265 }
193266 } )
0 commit comments