@zipbul/gildash 0.2.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.ko.md +454 -0
- package/README.md +65 -0
- package/dist/index.js +4 -4
- package/dist/index.js.map +6 -6
- package/dist/src/gildash.d.ts +34 -1
- package/dist/src/index.d.ts +2 -0
- package/dist/src/parser/types.d.ts +18 -0
- package/dist/src/search/symbol-search.d.ts +3 -0
- package/dist/src/store/repositories/file.repository.d.ts +12 -0
- package/dist/src/store/repositories/symbol.repository.d.ts +1 -0
- package/package.json +6 -4
package/README.ko.md
ADDED
|
@@ -0,0 +1,454 @@
|
|
|
1
|
+
# @zipbul/gildash
|
|
2
|
+
|
|
3
|
+
[English](./README.md) | **한국어**
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@zipbul/gildash)
|
|
6
|
+
[](https://github.com/zipbul/gildash/actions/workflows/ci.yml)
|
|
7
|
+
[](./LICENSE)
|
|
8
|
+
|
|
9
|
+
**Bun 네이티브** TypeScript 코드 인덱서.
|
|
10
|
+
심볼 추출, 파일 간 관계 추적, 의존성 그래프 구축을 하나의 로컬 SQLite 데이터베이스로 제공합니다.
|
|
11
|
+
|
|
12
|
+
<br>
|
|
13
|
+
|
|
14
|
+
## ✨ 주요 기능
|
|
15
|
+
|
|
16
|
+
- **심볼 추출** — 함수, 클래스, 변수, 타입, 인터페이스, 열거형, 프로퍼티를 AST 수준에서 추출
|
|
17
|
+
- **관계 분석** — `import`, `calls`, `extends`, `implements` 관계를 파일 간에 추적
|
|
18
|
+
- **전문 검색** — SQLite FTS5 기반 심볼 이름 전문 검색
|
|
19
|
+
- **의존성 그래프** — 방향 import 그래프로 순환 감지 및 전이적(transitive) 영향도 분석
|
|
20
|
+
- **증분 인덱싱** — `@parcel/watcher` 기반 파일 변경 감지, 변경된 파일만 재인덱싱
|
|
21
|
+
- **멀티 프로세스 안전** — owner/reader 역할 분리로 단일 writer 보장
|
|
22
|
+
|
|
23
|
+
<br>
|
|
24
|
+
|
|
25
|
+
## 📋 요구사항
|
|
26
|
+
|
|
27
|
+
- **Bun** v1.3 이상
|
|
28
|
+
- 지원 확장자: `.ts`, `.mts`, `.cts`
|
|
29
|
+
|
|
30
|
+
<br>
|
|
31
|
+
|
|
32
|
+
## 📦 설치
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
bun add @zipbul/gildash
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
<br>
|
|
39
|
+
|
|
40
|
+
## 🚀 빠른 시작
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
import { Gildash } from '@zipbul/gildash';
|
|
44
|
+
|
|
45
|
+
// 인덱서 열기 — 최초 실행 시 전체 인덱싱 자동 수행, 이후 파일 변경을 감시
|
|
46
|
+
const ledger = await Gildash.open({
|
|
47
|
+
projectRoot: '/absolute/path/to/project',
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
// 심볼 검색
|
|
51
|
+
const hits = ledger.searchSymbols({ text: 'UserService', kind: 'class' });
|
|
52
|
+
|
|
53
|
+
// 정확한 이름 매칭
|
|
54
|
+
const exact = ledger.searchSymbols({ text: 'UserService', exact: true });
|
|
55
|
+
|
|
56
|
+
// 의존성 그래프 조회
|
|
57
|
+
const deps = ledger.getDependencies('src/app.ts');
|
|
58
|
+
const affected = await ledger.getAffected(['src/utils.ts']);
|
|
59
|
+
const cyclic = await ledger.hasCycle();
|
|
60
|
+
|
|
61
|
+
// 파일 정보 및 심볼 조회
|
|
62
|
+
const fileInfo = ledger.getFileInfo('src/app.ts');
|
|
63
|
+
const symbols = ledger.getSymbolsByFile('src/app.ts');
|
|
64
|
+
|
|
65
|
+
// 캐시된 AST 조회
|
|
66
|
+
const ast = ledger.getParsedAst('/absolute/path/to/src/app.ts');
|
|
67
|
+
|
|
68
|
+
await ledger.close();
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
<br>
|
|
72
|
+
|
|
73
|
+
## 🔍 API 개요
|
|
74
|
+
|
|
75
|
+
| 메서드 | 반환 타입 | 설명 |
|
|
76
|
+
|--------|-----------|------|
|
|
77
|
+
| `searchSymbols(query)` | `SymbolSearchResult[]` | FTS5 전문 검색 + 필터 조합. `exact` 옵션 지원 |
|
|
78
|
+
| `searchRelations(query)` | `CodeRelation[]` | 파일/심볼/관계 유형 필터 |
|
|
79
|
+
| `getDependencies(filePath, project?)` | `string[]` | 이 파일이 import하는 파일 목록 |
|
|
80
|
+
| `getDependents(filePath, project?)` | `string[]` | 이 파일을 import하는 파일 목록 |
|
|
81
|
+
| `getAffected(changedFiles, project?)` | `Promise<string[]>` | 변경 파일의 전이적 영향 범위 |
|
|
82
|
+
| `hasCycle(project?)` | `Promise<boolean>` | 순환 의존성 감지 |
|
|
83
|
+
| `reindex()` | `Promise<IndexResult>` | 강제 전체 재인덱싱 |
|
|
84
|
+
| `onIndexed(callback)` | `() => void` | 인덱싱 완료 이벤트 구독 |
|
|
85
|
+
| `parseSource(filePath, src)` | `ParsedFile` | 파일 파싱 후 AST 캐시 |
|
|
86
|
+
| `extractSymbols(parsed)` | `ExtractedSymbol[]` | 파싱된 파일에서 심볼 추출 |
|
|
87
|
+
| `extractRelations(parsed)` | `CodeRelation[]` | 파싱된 파일에서 관계 추출 |
|
|
88
|
+
| `getParsedAst(filePath)` | `ParsedFile \| undefined` | 캐시된 AST 조회 |
|
|
89
|
+
| `getFileInfo(filePath, project?)` | `FileRecord \| null` | 인덱싱된 파일 메타데이터 조회 |
|
|
90
|
+
| `getSymbolsByFile(filePath, project?)` | `SymbolSearchResult[]` | 특정 파일의 모든 심볼 조회 |
|
|
91
|
+
| `projects` | `ProjectBoundary[]` | 감지된 프로젝트 경계 (모노레포) |
|
|
92
|
+
| `getStats(project?)` | `SymbolStats` | 심볼 통계 |
|
|
93
|
+
| `close()` | `Promise<void>` | 인덱서 종료 |
|
|
94
|
+
|
|
95
|
+
<br>
|
|
96
|
+
|
|
97
|
+
## ⚙️ API 레퍼런스
|
|
98
|
+
|
|
99
|
+
### `Gildash.open(options)`
|
|
100
|
+
|
|
101
|
+
인덱서 인스턴스를 생성합니다. 최초 실행 시 전체 인덱싱을 수행하고, 이후 파일 변경을 감시합니다.
|
|
102
|
+
|
|
103
|
+
```ts
|
|
104
|
+
const ledger = await Gildash.open({
|
|
105
|
+
projectRoot: '/absolute/path', // 필수. 절대 경로
|
|
106
|
+
extensions: ['.ts', '.mts', '.cts'], // 선택. 인덱싱 대상 확장자
|
|
107
|
+
ignorePatterns: ['dist', 'vendor'], // 선택. 무시할 디렉토리/패턴
|
|
108
|
+
parseCacheCapacity: 500, // 선택. 파싱 캐시 크기
|
|
109
|
+
});
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
| 옵션 | 타입 | 기본값 | 설명 |
|
|
113
|
+
|------|------|--------|------|
|
|
114
|
+
| `projectRoot` | `string` | — | 프로젝트 루트 절대 경로 **(필수)** |
|
|
115
|
+
| `extensions` | `string[]` | `['.ts', '.mts', '.cts']` | 인덱싱 대상 파일 확장자 |
|
|
116
|
+
| `ignorePatterns` | `string[]` | `[]` | 무시할 경로 패턴 |
|
|
117
|
+
| `parseCacheCapacity` | `number` | `500` | LRU 파싱 캐시 최대 크기 |
|
|
118
|
+
| `logger` | `Logger` | `console` | 커스텀 로거 (`{ error(...args): void }`) |
|
|
119
|
+
|
|
120
|
+
**반환**: `Promise<Gildash>`
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
### `ledger.close()`
|
|
125
|
+
|
|
126
|
+
인덱서를 종료합니다. watcher 중지, DB 연결 해제, 시그널 핸들러 제거를 수행합니다.
|
|
127
|
+
|
|
128
|
+
```ts
|
|
129
|
+
await ledger.close();
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
**반환**: `Promise<void>`
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
### `ledger.searchSymbols(query)`
|
|
137
|
+
|
|
138
|
+
심볼을 검색합니다. FTS5 전문 검색과 필터를 조합할 수 있습니다.
|
|
139
|
+
|
|
140
|
+
```ts
|
|
141
|
+
// 이름으로 검색
|
|
142
|
+
const results = ledger.searchSymbols({ text: 'handleClick' });
|
|
143
|
+
|
|
144
|
+
// 정확한 이름 매칭 (FTS prefix가 아닌 완전 일치)
|
|
145
|
+
const exact = ledger.searchSymbols({ text: 'UserService', exact: true });
|
|
146
|
+
|
|
147
|
+
// 종류 + export 여부 필터
|
|
148
|
+
const classes = ledger.searchSymbols({
|
|
149
|
+
kind: 'class',
|
|
150
|
+
isExported: true,
|
|
151
|
+
limit: 50,
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
// 파일 경로 필터
|
|
155
|
+
const inFile = ledger.searchSymbols({
|
|
156
|
+
filePath: 'src/services/user.ts',
|
|
157
|
+
});
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
| 필드 | 타입 | 설명 |
|
|
161
|
+
|------|------|------|
|
|
162
|
+
| `text` | `string?` | FTS5 전문 검색 쿼리 |
|
|
163
|
+
| `exact` | `boolean?` | `true`이면 `text`를 정확한 이름으로 매칭 (FTS prefix 아님) |
|
|
164
|
+
| `kind` | `SymbolKind?` | `'function'` \| `'method'` \| `'class'` \| `'variable'` \| `'type'` \| `'interface'` \| `'enum'` \| `'property'` |
|
|
165
|
+
| `filePath` | `string?` | 특정 파일 경로 필터 |
|
|
166
|
+
| `isExported` | `boolean?` | export 여부 필터 |
|
|
167
|
+
| `project` | `string?` | 프로젝트 이름 (모노레포 지원) |
|
|
168
|
+
| `limit` | `number?` | 최대 결과 수 |
|
|
169
|
+
|
|
170
|
+
**반환**: `SymbolSearchResult[]`
|
|
171
|
+
|
|
172
|
+
```ts
|
|
173
|
+
interface SymbolSearchResult {
|
|
174
|
+
id: number;
|
|
175
|
+
filePath: string;
|
|
176
|
+
kind: SymbolKind;
|
|
177
|
+
name: string;
|
|
178
|
+
span: {
|
|
179
|
+
start: { line: number; column: number };
|
|
180
|
+
end: { line: number; column: number };
|
|
181
|
+
};
|
|
182
|
+
isExported: boolean;
|
|
183
|
+
signature: string | null;
|
|
184
|
+
fingerprint: string | null;
|
|
185
|
+
detail: Record<string, unknown>;
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
### `ledger.searchRelations(query)`
|
|
192
|
+
|
|
193
|
+
파일/심볼 간 관계를 검색합니다.
|
|
194
|
+
|
|
195
|
+
```ts
|
|
196
|
+
// 특정 파일이 import하는 관계
|
|
197
|
+
const imports = ledger.searchRelations({
|
|
198
|
+
srcFilePath: 'src/app.ts',
|
|
199
|
+
type: 'imports',
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
// 특정 심볼을 호출하는 관계
|
|
203
|
+
const callers = ledger.searchRelations({
|
|
204
|
+
dstSymbolName: 'processOrder',
|
|
205
|
+
type: 'calls',
|
|
206
|
+
});
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
| 필드 | 타입 | 설명 |
|
|
210
|
+
|------|------|------|
|
|
211
|
+
| `srcFilePath` | `string?` | 출발 파일 경로 |
|
|
212
|
+
| `srcSymbolName` | `string?` | 출발 심볼 이름 |
|
|
213
|
+
| `dstFilePath` | `string?` | 도착 파일 경로 |
|
|
214
|
+
| `dstSymbolName` | `string?` | 도착 심볼 이름 |
|
|
215
|
+
| `type` | `'imports'` \| `'calls'` \| `'extends'` \| `'implements'`? | 관계 유형 |
|
|
216
|
+
| `project` | `string?` | 프로젝트 이름 |
|
|
217
|
+
| `limit` | `number?` | 최대 결과 수 |
|
|
218
|
+
|
|
219
|
+
**반환**: `CodeRelation[]`
|
|
220
|
+
|
|
221
|
+
```ts
|
|
222
|
+
interface CodeRelation {
|
|
223
|
+
type: 'imports' | 'calls' | 'extends' | 'implements';
|
|
224
|
+
srcFilePath: string;
|
|
225
|
+
srcSymbolName: string | null; // null = 모듈 레벨
|
|
226
|
+
dstFilePath: string;
|
|
227
|
+
dstSymbolName: string | null;
|
|
228
|
+
metaJson?: string;
|
|
229
|
+
}
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
### `ledger.getDependencies(filePath, project?)`
|
|
235
|
+
|
|
236
|
+
특정 파일이 import하는 파일 목록을 반환합니다.
|
|
237
|
+
|
|
238
|
+
```ts
|
|
239
|
+
const deps = ledger.getDependencies('src/app.ts');
|
|
240
|
+
// → ['src/utils.ts', 'src/config.ts', ...]
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
**반환**: `string[]`
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
### `ledger.getDependents(filePath, project?)`
|
|
248
|
+
|
|
249
|
+
특정 파일을 import하는 파일 목록을 반환합니다.
|
|
250
|
+
|
|
251
|
+
```ts
|
|
252
|
+
const dependents = ledger.getDependents('src/utils.ts');
|
|
253
|
+
// → ['src/app.ts', 'src/services/user.ts', ...]
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
**반환**: `string[]`
|
|
257
|
+
|
|
258
|
+
---
|
|
259
|
+
|
|
260
|
+
### `ledger.getAffected(changedFiles, project?)`
|
|
261
|
+
|
|
262
|
+
변경된 파일들의 영향을 받는 모든 파일을 전이적(transitive)으로 계산합니다.
|
|
263
|
+
|
|
264
|
+
```ts
|
|
265
|
+
const affected = await ledger.getAffected(['src/utils.ts']);
|
|
266
|
+
// → ['src/app.ts', 'src/services/user.ts', 'src/main.ts', ...]
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
**반환**: `Promise<string[]>`
|
|
270
|
+
|
|
271
|
+
---
|
|
272
|
+
|
|
273
|
+
### `ledger.hasCycle(project?)`
|
|
274
|
+
|
|
275
|
+
프로젝트의 import 그래프에 순환 의존성이 있는지 검사합니다.
|
|
276
|
+
|
|
277
|
+
```ts
|
|
278
|
+
const cyclic = await ledger.hasCycle();
|
|
279
|
+
if (cyclic) {
|
|
280
|
+
console.warn('순환 의존성이 감지되었습니다');
|
|
281
|
+
}
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
**반환**: `Promise<boolean>`
|
|
285
|
+
|
|
286
|
+
---
|
|
287
|
+
|
|
288
|
+
### `ledger.reindex()`
|
|
289
|
+
|
|
290
|
+
수동으로 전체 재인덱싱을 수행합니다. owner 역할에서만 사용 가능합니다.
|
|
291
|
+
|
|
292
|
+
```ts
|
|
293
|
+
const result = await ledger.reindex();
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
**반환**: `Promise<IndexResult>`
|
|
297
|
+
|
|
298
|
+
---
|
|
299
|
+
|
|
300
|
+
### `ledger.onIndexed(callback)`
|
|
301
|
+
|
|
302
|
+
인덱싱 완료 이벤트를 구독합니다.
|
|
303
|
+
|
|
304
|
+
```ts
|
|
305
|
+
const unsubscribe = ledger.onIndexed((result) => {
|
|
306
|
+
console.log(`인덱싱 완료: ${result.indexedFiles}개 파일`);
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
// 구독 해제
|
|
310
|
+
unsubscribe();
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
**반환**: `() => void` (구독 해제 함수)
|
|
314
|
+
|
|
315
|
+
---
|
|
316
|
+
|
|
317
|
+
### `ledger.projects`
|
|
318
|
+
|
|
319
|
+
감지된 프로젝트 경계 목록을 반환합니다 (모노레포에서 여러 프로젝트 감지).
|
|
320
|
+
|
|
321
|
+
```ts
|
|
322
|
+
const boundaries = ledger.projects;
|
|
323
|
+
// → [{ project: 'my-app', root: '/path/to/project' }, ...]
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
**타입**: `ProjectBoundary[]`
|
|
327
|
+
|
|
328
|
+
---
|
|
329
|
+
|
|
330
|
+
### `ledger.getStats(project?)`
|
|
331
|
+
|
|
332
|
+
심볼 통계를 반환합니다.
|
|
333
|
+
|
|
334
|
+
```ts
|
|
335
|
+
const stats = ledger.getStats();
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
**반환**: `SymbolStats`
|
|
339
|
+
|
|
340
|
+
---
|
|
341
|
+
|
|
342
|
+
### `ledger.parseSource(filePath, sourceText)`
|
|
343
|
+
|
|
344
|
+
파일을 파싱하여 AST를 반환합니다. 결과는 내부 캐시에 저장됩니다.
|
|
345
|
+
|
|
346
|
+
```ts
|
|
347
|
+
const parsed = ledger.parseSource('/path/to/file.ts', sourceCode);
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
**반환**: `ParsedFile`
|
|
351
|
+
|
|
352
|
+
---
|
|
353
|
+
|
|
354
|
+
### `ledger.extractSymbols(parsed)`
|
|
355
|
+
|
|
356
|
+
파싱된 파일에서 심볼을 추출합니다.
|
|
357
|
+
|
|
358
|
+
```ts
|
|
359
|
+
const symbols = ledger.extractSymbols(parsed);
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
**반환**: `ExtractedSymbol[]`
|
|
363
|
+
|
|
364
|
+
---
|
|
365
|
+
|
|
366
|
+
### `ledger.extractRelations(parsed)`
|
|
367
|
+
|
|
368
|
+
파싱된 파일에서 관계를 추출합니다.
|
|
369
|
+
|
|
370
|
+
```ts
|
|
371
|
+
const relations = ledger.extractRelations(parsed);
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
**반환**: `CodeRelation[]`
|
|
375
|
+
|
|
376
|
+
---
|
|
377
|
+
|
|
378
|
+
### `ledger.getParsedAst(filePath)`
|
|
379
|
+
|
|
380
|
+
내부 LRU 캐시에서 이전에 파싱된 AST를 조회합니다.
|
|
381
|
+
|
|
382
|
+
파일이 아직 파싱되지 않았거나 캐시에서 제거된 경우 `undefined`를 반환합니다.
|
|
383
|
+
반환된 객체는 내부 캐시와 공유됩니다 — **읽기 전용**으로 취급하세요.
|
|
384
|
+
|
|
385
|
+
```ts
|
|
386
|
+
const ast = ledger.getParsedAst('/absolute/path/to/src/app.ts');
|
|
387
|
+
if (ast) {
|
|
388
|
+
console.log(ast.program.body.length, '개의 AST 노드');
|
|
389
|
+
}
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
**반환**: `ParsedFile | undefined`
|
|
393
|
+
|
|
394
|
+
---
|
|
395
|
+
|
|
396
|
+
### `ledger.getFileInfo(filePath, project?)`
|
|
397
|
+
|
|
398
|
+
인덱싱된 파일의 메타데이터를 조회합니다.
|
|
399
|
+
|
|
400
|
+
content hash, mtime, size 등이 포함된 `FileRecord`를 반환합니다.
|
|
401
|
+
파일이 아직 인덱싱되지 않은 경우 `null`을 반환합니다.
|
|
402
|
+
|
|
403
|
+
```ts
|
|
404
|
+
const info = ledger.getFileInfo('src/app.ts');
|
|
405
|
+
if (!isErr(info) && info !== null) {
|
|
406
|
+
console.log(`해시: ${info.contentHash}, 크기: ${info.size}`);
|
|
407
|
+
}
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
**반환**: `Result<FileRecord | null, GildashError>`
|
|
411
|
+
|
|
412
|
+
---
|
|
413
|
+
|
|
414
|
+
### `ledger.getSymbolsByFile(filePath, project?)`
|
|
415
|
+
|
|
416
|
+
특정 파일에 선언된 모든 심볼을 조회합니다. `searchSymbols`에 `filePath` 필터를 적용한 편의 래퍼입니다.
|
|
417
|
+
|
|
418
|
+
```ts
|
|
419
|
+
const symbols = ledger.getSymbolsByFile('src/app.ts');
|
|
420
|
+
if (!isErr(symbols)) {
|
|
421
|
+
for (const sym of symbols) {
|
|
422
|
+
console.log(`${sym.kind}: ${sym.name}`);
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
**반환**: `Result<SymbolSearchResult[], GildashError>`
|
|
428
|
+
|
|
429
|
+
<br>
|
|
430
|
+
|
|
431
|
+
## 🏗 아키텍처
|
|
432
|
+
|
|
433
|
+
```
|
|
434
|
+
Gildash (파사드)
|
|
435
|
+
├── Parser — oxc-parser 기반 TypeScript AST 파싱
|
|
436
|
+
├── Extractor — 심볼/관계 추출 (imports, calls, heritage)
|
|
437
|
+
├── Store — bun:sqlite + drizzle-orm (files, symbols, relations, FTS5)
|
|
438
|
+
├── Indexer — 변경 감지 → 파싱 → 추출 → 저장 파이프라인
|
|
439
|
+
├── Search — 심볼 검색, 관계 검색, 의존성 그래프
|
|
440
|
+
└── Watcher — @parcel/watcher + owner/reader 역할 관리
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
### Owner/Reader 패턴
|
|
444
|
+
|
|
445
|
+
동일 SQLite DB를 여러 프로세스가 공유할 때, 단일 writer를 보장합니다.
|
|
446
|
+
|
|
447
|
+
- **Owner** — watcher 실행, 인덱싱 수행, heartbeat 전송 (30초 간격)
|
|
448
|
+
- **Reader** — 읽기 전용 접근, 60초 간격으로 owner 상태 확인; owner가 stale 상태가 되면 reader 중 하나가 owner로 승격
|
|
449
|
+
|
|
450
|
+
<br>
|
|
451
|
+
|
|
452
|
+
## 📄 라이선스
|
|
453
|
+
|
|
454
|
+
[MIT](./LICENSE) © [zipbul](https://github.com/zipbul)
|
package/README.md
CHANGED
|
@@ -52,6 +52,9 @@ const hits = ledger.searchSymbols({
|
|
|
52
52
|
isExported: true,
|
|
53
53
|
});
|
|
54
54
|
|
|
55
|
+
// Exact name match (not FTS prefix)
|
|
56
|
+
const exact = ledger.searchSymbols({ text: 'UserService', exact: true });
|
|
57
|
+
|
|
55
58
|
// Find what a file imports
|
|
56
59
|
const deps = ledger.getDependencies('src/app.ts');
|
|
57
60
|
|
|
@@ -63,6 +66,13 @@ if (await ledger.hasCycle()) {
|
|
|
63
66
|
console.warn('Circular dependency detected');
|
|
64
67
|
}
|
|
65
68
|
|
|
69
|
+
// File metadata & symbols
|
|
70
|
+
const fileInfo = ledger.getFileInfo('src/app.ts');
|
|
71
|
+
const symbols = ledger.getSymbolsByFile('src/app.ts');
|
|
72
|
+
|
|
73
|
+
// Cached AST lookup
|
|
74
|
+
const ast = ledger.getParsedAst('/absolute/path/to/src/app.ts');
|
|
75
|
+
|
|
66
76
|
// Subscribe to index-complete events
|
|
67
77
|
const unsubscribe = ledger.onIndexed((result) => {
|
|
68
78
|
console.log(`Indexed ${result.indexedFiles} files in ${result.durationMs}ms`);
|
|
@@ -129,6 +139,9 @@ Search symbols by name (FTS5 full-text), kind, file path, and/or export status.
|
|
|
129
139
|
// Full-text search
|
|
130
140
|
const results = ledger.searchSymbols({ text: 'handleClick' });
|
|
131
141
|
|
|
142
|
+
// Exact name match (not FTS prefix)
|
|
143
|
+
const exact = ledger.searchSymbols({ text: 'UserService', exact: true });
|
|
144
|
+
|
|
132
145
|
// Filter by kind + export status
|
|
133
146
|
const classes = ledger.searchSymbols({
|
|
134
147
|
kind: 'class',
|
|
@@ -147,6 +160,7 @@ const inFile = ledger.searchSymbols({
|
|
|
147
160
|
| Field | Type | Description |
|
|
148
161
|
|-------|------|-------------|
|
|
149
162
|
| `text` | `string?` | FTS5 full-text search query |
|
|
163
|
+
| `exact` | `boolean?` | When `true`, `text` is treated as an exact name match (not FTS prefix) |
|
|
150
164
|
| `kind` | `SymbolKind?` | `'function'` \| `'method'` \| `'class'` \| `'variable'` \| `'type'` \| `'interface'` \| `'enum'` \| `'property'` |
|
|
151
165
|
| `filePath` | `string?` | Filter by file path |
|
|
152
166
|
| `isExported` | `boolean?` | Filter by export status |
|
|
@@ -391,6 +405,57 @@ Returns `CodeRelation[]`
|
|
|
391
405
|
|
|
392
406
|
---
|
|
393
407
|
|
|
408
|
+
### `ledger.getParsedAst(filePath)`
|
|
409
|
+
|
|
410
|
+
Retrieves a previously-parsed AST from the internal LRU cache.
|
|
411
|
+
|
|
412
|
+
Returns `undefined` if the file has not been parsed or was evicted from the cache.
|
|
413
|
+
The returned object is shared with the internal cache — treat it as **read-only**.
|
|
414
|
+
|
|
415
|
+
```ts
|
|
416
|
+
const ast = ledger.getParsedAst('/absolute/path/to/src/app.ts');
|
|
417
|
+
if (ast) {
|
|
418
|
+
console.log(ast.program.body.length, 'AST nodes');
|
|
419
|
+
}
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
Returns `ParsedFile | undefined`
|
|
423
|
+
|
|
424
|
+
---
|
|
425
|
+
|
|
426
|
+
### `ledger.getFileInfo(filePath, project?)`
|
|
427
|
+
|
|
428
|
+
Retrieves metadata for an indexed file, including content hash, mtime, and size.
|
|
429
|
+
Returns `null` if the file has not been indexed yet.
|
|
430
|
+
|
|
431
|
+
```ts
|
|
432
|
+
const info = ledger.getFileInfo('src/app.ts');
|
|
433
|
+
if (!isErr(info) && info !== null) {
|
|
434
|
+
console.log(`Hash: ${info.contentHash}, Size: ${info.size}`);
|
|
435
|
+
}
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
Returns `Result<FileRecord | null, GildashError>`
|
|
439
|
+
|
|
440
|
+
---
|
|
441
|
+
|
|
442
|
+
### `ledger.getSymbolsByFile(filePath, project?)`
|
|
443
|
+
|
|
444
|
+
Lists all symbols declared in a specific file. Convenience wrapper around `searchSymbols` with a `filePath` filter.
|
|
445
|
+
|
|
446
|
+
```ts
|
|
447
|
+
const symbols = ledger.getSymbolsByFile('src/app.ts');
|
|
448
|
+
if (!isErr(symbols)) {
|
|
449
|
+
for (const sym of symbols) {
|
|
450
|
+
console.log(`${sym.kind}: ${sym.name}`);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
Returns `Result<SymbolSearchResult[], GildashError>`
|
|
456
|
+
|
|
457
|
+
---
|
|
458
|
+
|
|
394
459
|
### `ledger.close()`
|
|
395
460
|
|
|
396
461
|
Graceful shutdown. Stops the watcher, releases the database, and removes signal handlers.
|