Skip to content

Commit 98ed124

Browse files
snomiaoclaude
andcommitted
[feat] Add source file location discovery to API snapshot tool
Enhance snapshot-api.js to discover source file locations for exported declarations using grep search. This enables mapping from generated .d.ts declarations back to their original source files. For each declaration, the tool now searches the src directory for: - export interface <Name> - export class <Name> - export type <Name> - export enum <Name> - export function <Name> - export const <Name> The source file path and line number are stored in the snapshot for use in generating accurate GitHub permalinks in the changelog. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent e933b5c commit 98ed124

File tree

1 file changed

+79
-6
lines changed

1 file changed

+79
-6
lines changed

scripts/snapshot-api.js

Lines changed: 79 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
* This snapshot is used to track API changes between versions.
66
*/
77

8+
import { execSync } from 'child_process'
89
import * as fs from 'fs'
910
import * as path from 'path'
1011
import * 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

Comments
 (0)