@zipbul/gildash 0.3.0 → 0.4.0
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/LICENSE +1 -1
- package/README.ko.md +234 -290
- package/README.md +337 -341
- package/dist/index.js +6 -4
- package/dist/index.js.map +15 -14
- package/dist/migrations/0001_add_line_count.sql +1 -0
- package/dist/migrations/meta/_journal.json +7 -0
- package/dist/src/extractor/types.d.ts +5 -1
- package/dist/src/gildash.d.ts +379 -3
- package/dist/src/index.d.ts +3 -1
- package/dist/src/indexer/index-coordinator.d.ts +21 -0
- package/dist/src/search/dependency-graph.d.ts +28 -0
- package/dist/src/search/index.d.ts +2 -0
- package/dist/src/search/pattern-search.d.ts +30 -0
- package/dist/src/search/symbol-search.d.ts +12 -0
- package/dist/src/store/repositories/file.repository.d.ts +2 -0
- package/dist/src/store/repositories/symbol.repository.d.ts +2 -0
- package/dist/src/store/schema.d.ts +17 -0
- package/package.json +2 -1
package/README.ko.md
CHANGED
|
@@ -6,19 +6,34 @@
|
|
|
6
6
|
[](https://github.com/zipbul/gildash/actions/workflows/ci.yml)
|
|
7
7
|
[](./LICENSE)
|
|
8
8
|
|
|
9
|
-
**Bun 네이티브** TypeScript 코드
|
|
10
|
-
|
|
9
|
+
**Bun 네이티브** TypeScript 코드 인텔리전스 엔진.
|
|
10
|
+
|
|
11
|
+
gildash는 TypeScript 코드베이스를 로컬 SQLite 데이터베이스에 인덱싱하여, 심볼 검색 · 파일 간 관계 추적 · 의존성 그래프 분석 · 구조적 패턴 매칭을 제공합니다. 파일 변경을 감시하며 증분(incremental) 재인덱싱을 자동으로 수행합니다.
|
|
12
|
+
|
|
13
|
+
## 💡 왜 gildash인가?
|
|
14
|
+
|
|
15
|
+
| 문제 | gildash의 해결 방식 |
|
|
16
|
+
|------|---------------------|
|
|
17
|
+
| "이 모듈을 바꾸면 어디가 깨지지?" | 방향 import 그래프 + 전이적(transitive) 영향도 분석 |
|
|
18
|
+
| "순환 의존성이 있나?" | 전체 import 그래프에서 순환 감지 |
|
|
19
|
+
| "이 심볼이 실제로 어디서 정의된 거지?" | re-export 체인을 따라가 원본 소스까지 추적 |
|
|
20
|
+
| "사용되지 않는 export는?" | 프로젝트 전체에서 미사용 export 탐지 |
|
|
21
|
+
| "모든 `console.log(...)` 호출을 찾아줘" | [ast-grep](https://ast-grep.github.io/) 기반 AST 레벨 구조적 패턴 검색 |
|
|
11
22
|
|
|
12
23
|
<br>
|
|
13
24
|
|
|
14
25
|
## ✨ 주요 기능
|
|
15
26
|
|
|
16
|
-
- **심볼 추출** — 함수, 클래스, 변수, 타입, 인터페이스, 열거형, 프로퍼티를 AST 수준에서 추출
|
|
17
|
-
- **관계 분석** — `import`, `calls`, `extends`, `implements` 관계를 파일 간에 추적
|
|
18
|
-
- **전문 검색** — SQLite FTS5 기반 심볼 이름 전문 검색
|
|
19
|
-
- **의존성 그래프** — 방향 import 그래프로 순환
|
|
27
|
+
- **심볼 추출** — 함수, 클래스, 변수, 타입, 인터페이스, 열거형, 프로퍼티를 [oxc-parser](https://oxc.rs) AST 수준에서 추출
|
|
28
|
+
- **관계 분석** — `import`, `re-exports`, `type-references`, `calls`, `extends`, `implements` 관계를 파일 간에 추적
|
|
29
|
+
- **전문 검색** — SQLite FTS5 기반 심볼 이름 전문 검색 + 정확 일치(exact), 정규식(regex), 데코레이터(decorator) 필터
|
|
30
|
+
- **의존성 그래프** — 방향 import 그래프로 순환 감지, 전이적(transitive) 영향도 분석, 내부 캐싱
|
|
31
|
+
- **구조적 패턴 매칭** — [@ast-grep/napi](https://ast-grep.github.io/) 기반 AST 레벨 코드 검색
|
|
20
32
|
- **증분 인덱싱** — `@parcel/watcher` 기반 파일 변경 감지, 변경된 파일만 재인덱싱
|
|
33
|
+
- **심볼 레벨 diff** — `IndexResult`의 `changedSymbols`로 인덱싱 사이클 당 추가/수정/삭제된 심볼 추적
|
|
21
34
|
- **멀티 프로세스 안전** — owner/reader 역할 분리로 단일 writer 보장
|
|
35
|
+
- **스캔 전용 모드** — `watchMode: false`로 파일 워처 없이 1회성 인덱싱
|
|
36
|
+
- **외부 패키지 인덱싱** — `node_modules`의 `.d.ts` 타입 선언 인덱싱
|
|
22
37
|
|
|
23
38
|
<br>
|
|
24
39
|
|
|
@@ -35,396 +50,325 @@
|
|
|
35
50
|
bun add @zipbul/gildash
|
|
36
51
|
```
|
|
37
52
|
|
|
53
|
+
> **피어 의존성** — [`@zipbul/result`](https://www.npmjs.com/package/@zipbul/result)가 필요합니다. 모든 public 메서드는 `Result<T, GildashError>`를 반환합니다.
|
|
54
|
+
|
|
38
55
|
<br>
|
|
39
56
|
|
|
40
57
|
## 🚀 빠른 시작
|
|
41
58
|
|
|
42
59
|
```ts
|
|
43
60
|
import { Gildash } from '@zipbul/gildash';
|
|
61
|
+
import { isErr } from '@zipbul/result';
|
|
44
62
|
|
|
45
|
-
//
|
|
63
|
+
// 1. 열기 — 최초 실행 시 전체 .ts 파일 인덱싱, 이후 파일 변경 감시
|
|
46
64
|
const ledger = await Gildash.open({
|
|
47
65
|
projectRoot: '/absolute/path/to/project',
|
|
48
66
|
});
|
|
49
67
|
|
|
50
|
-
// 심볼
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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');
|
|
68
|
+
// 2. 검색 — 이름으로 심볼 찾기
|
|
69
|
+
const result = ledger.searchSymbols({ text: 'UserService', kind: 'class' });
|
|
70
|
+
if (!isErr(result)) {
|
|
71
|
+
result.forEach(s => console.log(`${s.name} → ${s.filePath}`));
|
|
72
|
+
}
|
|
67
73
|
|
|
74
|
+
// 3. 종료 — 리소스 해제
|
|
68
75
|
await ledger.close();
|
|
69
76
|
```
|
|
70
77
|
|
|
71
|
-
|
|
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>` | 인덱서 종료 |
|
|
78
|
+
프로젝트 탐색(모노레포 지원), 증분 재인덱싱, 멀티 프로세스 안전 모두 자동으로 처리됩니다.
|
|
94
79
|
|
|
95
80
|
<br>
|
|
96
81
|
|
|
97
|
-
##
|
|
82
|
+
## 📖 사용 가이드
|
|
98
83
|
|
|
99
|
-
###
|
|
84
|
+
### 심볼 검색
|
|
100
85
|
|
|
101
|
-
|
|
86
|
+
인덱싱된 심볼을 FTS5 전문 검색, 정확 일치, 정규식, 데코레이터 필터로 검색합니다.
|
|
102
87
|
|
|
103
88
|
```ts
|
|
104
|
-
|
|
105
|
-
|
|
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>`
|
|
89
|
+
// 전문 검색 (FTS5 접두사 매칭)
|
|
90
|
+
const hits = ledger.searchSymbols({ text: 'handle' });
|
|
133
91
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
### `ledger.searchSymbols(query)`
|
|
137
|
-
|
|
138
|
-
심볼을 검색합니다. FTS5 전문 검색과 필터를 조합할 수 있습니다.
|
|
92
|
+
// 정확한 이름 매칭
|
|
93
|
+
const exact = ledger.searchSymbols({ text: 'UserService', exact: true });
|
|
139
94
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
const results = ledger.searchSymbols({ text: 'handleClick' });
|
|
95
|
+
// 정규식 패턴
|
|
96
|
+
const handlers = ledger.searchSymbols({ regex: '^handle.*Click$' });
|
|
143
97
|
|
|
144
|
-
//
|
|
145
|
-
const
|
|
98
|
+
// 데코레이터 필터
|
|
99
|
+
const injectables = ledger.searchSymbols({ decorator: 'Injectable' });
|
|
146
100
|
|
|
147
|
-
//
|
|
148
|
-
const
|
|
101
|
+
// 필터 조합
|
|
102
|
+
const exportedClasses = ledger.searchSymbols({
|
|
149
103
|
kind: 'class',
|
|
150
104
|
isExported: true,
|
|
151
105
|
limit: 50,
|
|
152
106
|
});
|
|
153
|
-
|
|
154
|
-
// 파일 경로 필터
|
|
155
|
-
const inFile = ledger.searchSymbols({
|
|
156
|
-
filePath: 'src/services/user.ts',
|
|
157
|
-
});
|
|
158
107
|
```
|
|
159
108
|
|
|
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
|
-
파일/심볼 간 관계를 검색합니다.
|
|
109
|
+
`searchRelations()`로 파일 간 관계를 검색할 수 있습니다:
|
|
194
110
|
|
|
195
111
|
```ts
|
|
196
|
-
|
|
197
|
-
const
|
|
198
|
-
srcFilePath: 'src/app.ts',
|
|
199
|
-
type: 'imports',
|
|
200
|
-
});
|
|
201
|
-
|
|
202
|
-
// 특정 심볼을 호출하는 관계
|
|
203
|
-
const callers = ledger.searchRelations({
|
|
204
|
-
dstSymbolName: 'processOrder',
|
|
205
|
-
type: 'calls',
|
|
206
|
-
});
|
|
112
|
+
const imports = ledger.searchRelations({ srcFilePath: 'src/app.ts', type: 'imports' });
|
|
113
|
+
const callers = ledger.searchRelations({ dstSymbolName: 'processOrder', type: 'calls' });
|
|
207
114
|
```
|
|
208
115
|
|
|
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
|
-
```
|
|
116
|
+
모노레포 프로젝트에서는 `searchAllSymbols()`와 `searchAllRelations()`로 전체 프로젝트를 검색합니다.
|
|
231
117
|
|
|
232
118
|
---
|
|
233
119
|
|
|
234
|
-
###
|
|
120
|
+
### 의존성 분석
|
|
235
121
|
|
|
236
|
-
|
|
122
|
+
import 그래프 분석, 순환 감지, 변경 영향 범위 계산을 수행합니다.
|
|
237
123
|
|
|
238
124
|
```ts
|
|
125
|
+
// 직접 import / importer 목록
|
|
239
126
|
const deps = ledger.getDependencies('src/app.ts');
|
|
240
|
-
|
|
241
|
-
```
|
|
127
|
+
const importers = ledger.getDependents('src/utils.ts');
|
|
242
128
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
---
|
|
129
|
+
// 전이적 영향 — 파일 변경 시 어떤 파일이 영향을 받는가?
|
|
130
|
+
const affected = await ledger.getAffected(['src/utils.ts']);
|
|
246
131
|
|
|
247
|
-
|
|
132
|
+
// 전체 import 그래프 (인접 리스트)
|
|
133
|
+
const graph = await ledger.getImportGraph();
|
|
248
134
|
|
|
249
|
-
|
|
135
|
+
// 전이적 의존성 (전방 BFS)
|
|
136
|
+
const transitive = await ledger.getTransitiveDependencies('src/app.ts');
|
|
250
137
|
|
|
251
|
-
|
|
252
|
-
const
|
|
253
|
-
|
|
138
|
+
// 순환 의존성 감지
|
|
139
|
+
const hasCycles = await ledger.hasCycle();
|
|
140
|
+
const cyclePaths = await ledger.getCyclePaths();
|
|
254
141
|
```
|
|
255
142
|
|
|
256
|
-
**반환**: `string[]`
|
|
257
|
-
|
|
258
143
|
---
|
|
259
144
|
|
|
260
|
-
###
|
|
145
|
+
### 코드 품질 분석
|
|
261
146
|
|
|
262
|
-
|
|
147
|
+
미사용 export 감지, 모듈 인터페이스 조회, 결합도 측정을 수행합니다.
|
|
263
148
|
|
|
264
149
|
```ts
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
```
|
|
268
|
-
|
|
269
|
-
**반환**: `Promise<string[]>`
|
|
150
|
+
// 미사용 export — 어디에서도 import되지 않은 exported 심볼
|
|
151
|
+
const dead = ledger.getDeadExports();
|
|
270
152
|
|
|
271
|
-
|
|
153
|
+
// 파일 통계 — 라인 수, 심볼 수, 파일 크기
|
|
154
|
+
const stats = ledger.getFileStats('src/app.ts');
|
|
272
155
|
|
|
273
|
-
|
|
156
|
+
// Fan-in / Fan-out 결합도 메트릭
|
|
157
|
+
const fan = await ledger.getFanMetrics('src/app.ts');
|
|
274
158
|
|
|
275
|
-
|
|
159
|
+
// 모듈 공개 인터페이스 — 모든 exported 심볼과 메타데이터
|
|
160
|
+
const iface = ledger.getModuleInterface('src/services/user.ts');
|
|
276
161
|
|
|
277
|
-
|
|
278
|
-
const
|
|
279
|
-
if (cyclic) {
|
|
280
|
-
console.warn('순환 의존성이 감지되었습니다');
|
|
281
|
-
}
|
|
162
|
+
// 상세 심볼 정보 — 멤버, jsDoc, 데코레이터, 타입 정보
|
|
163
|
+
const full = ledger.getFullSymbol('UserService', 'src/services/user.ts');
|
|
282
164
|
```
|
|
283
165
|
|
|
284
|
-
**반환**: `Promise<boolean>`
|
|
285
|
-
|
|
286
166
|
---
|
|
287
167
|
|
|
288
|
-
###
|
|
168
|
+
### 패턴 매칭 & 추적
|
|
289
169
|
|
|
290
|
-
|
|
170
|
+
AST 구조로 코드를 검색하고, re-export 체인을 통해 심볼 원본을 추적합니다.
|
|
291
171
|
|
|
292
172
|
```ts
|
|
293
|
-
|
|
294
|
-
|
|
173
|
+
// 구조적 패턴 검색 (ast-grep 문법)
|
|
174
|
+
const logs = await ledger.findPattern('console.log($$$)');
|
|
175
|
+
const hooks = await ledger.findPattern('useState($A)', {
|
|
176
|
+
filePaths: ['src/components/App.tsx'],
|
|
177
|
+
});
|
|
295
178
|
|
|
296
|
-
|
|
179
|
+
// re-export 체인 추적 — 심볼이 실제로 정의된 위치 찾기
|
|
180
|
+
const resolved = ledger.resolveSymbol('MyComponent', 'src/index.ts');
|
|
297
181
|
|
|
298
|
-
|
|
182
|
+
// 상속 체인 — extends/implements 트리 순회
|
|
183
|
+
const tree = await ledger.getHeritageChain('UserService', 'src/services/user.ts');
|
|
184
|
+
```
|
|
299
185
|
|
|
300
|
-
|
|
186
|
+
<br>
|
|
187
|
+
|
|
188
|
+
## 🔧 스캔 전용 모드
|
|
301
189
|
|
|
302
|
-
|
|
190
|
+
CI 파이프라인이나 1회성 분석에서는 파일 워처를 비활성화합니다:
|
|
303
191
|
|
|
304
192
|
```ts
|
|
305
|
-
const
|
|
306
|
-
|
|
193
|
+
const ledger = await Gildash.open({
|
|
194
|
+
projectRoot: '/path/to/project',
|
|
195
|
+
watchMode: false, // 워처 없음, heartbeat 없음
|
|
307
196
|
});
|
|
308
197
|
|
|
309
|
-
//
|
|
310
|
-
unsubscribe();
|
|
311
|
-
```
|
|
312
|
-
|
|
313
|
-
**반환**: `() => void` (구독 해제 함수)
|
|
198
|
+
// ... 쿼리 실행 ...
|
|
314
199
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
### `ledger.projects`
|
|
318
|
-
|
|
319
|
-
감지된 프로젝트 경계 목록을 반환합니다 (모노레포에서 여러 프로젝트 감지).
|
|
320
|
-
|
|
321
|
-
```ts
|
|
322
|
-
const boundaries = ledger.projects;
|
|
323
|
-
// → [{ project: 'my-app', root: '/path/to/project' }, ...]
|
|
200
|
+
await ledger.close({ cleanup: true }); // DB 파일까지 삭제
|
|
324
201
|
```
|
|
325
202
|
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
---
|
|
203
|
+
<br>
|
|
329
204
|
|
|
330
|
-
|
|
205
|
+
## ❌ 에러 처리
|
|
331
206
|
|
|
332
|
-
|
|
207
|
+
모든 public 메서드는 [`@zipbul/result`](https://www.npmjs.com/package/@zipbul/result)의 `Result<T, GildashError>`를 반환합니다. `isErr()`로 에러를 분기합니다:
|
|
333
208
|
|
|
334
209
|
```ts
|
|
335
|
-
|
|
210
|
+
import { isErr } from '@zipbul/result';
|
|
211
|
+
|
|
212
|
+
const result = ledger.searchSymbols({ text: 'foo' });
|
|
213
|
+
if (isErr(result)) {
|
|
214
|
+
console.error(result.data.type, result.data.message);
|
|
215
|
+
} else {
|
|
216
|
+
console.log(`${result.length}개 심볼 발견`);
|
|
217
|
+
}
|
|
336
218
|
```
|
|
337
219
|
|
|
338
|
-
|
|
220
|
+
<br>
|
|
339
221
|
|
|
340
|
-
|
|
222
|
+
## ⚙️ 설정
|
|
341
223
|
|
|
342
|
-
### `
|
|
224
|
+
### `Gildash.open(options)`
|
|
343
225
|
|
|
344
|
-
|
|
226
|
+
| 옵션 | 타입 | 기본값 | 설명 |
|
|
227
|
+
|------|------|--------|------|
|
|
228
|
+
| `projectRoot` | `string` | — | 프로젝트 루트 절대 경로 **(필수)** |
|
|
229
|
+
| `extensions` | `string[]` | `['.ts', '.mts', '.cts']` | 인덱싱 대상 파일 확장자 |
|
|
230
|
+
| `ignorePatterns` | `string[]` | `[]` | 무시할 글로브 패턴 |
|
|
231
|
+
| `parseCacheCapacity` | `number` | `500` | LRU 파싱 캐시 최대 크기 |
|
|
232
|
+
| `logger` | `Logger` | `console` | 커스텀 로거 (`{ error(...args): void }`) |
|
|
233
|
+
| `watchMode` | `boolean` | `true` | `false`이면 파일 워처 비활성화 (스캔 전용 모드) |
|
|
345
234
|
|
|
346
|
-
|
|
347
|
-
const parsed = ledger.parseSource('/path/to/file.ts', sourceCode);
|
|
348
|
-
```
|
|
235
|
+
**반환**: `Promise<Gildash>` (`Result`로 래핑됨)
|
|
349
236
|
|
|
350
|
-
|
|
237
|
+
<br>
|
|
351
238
|
|
|
352
|
-
|
|
239
|
+
## 🔍 API 레퍼런스
|
|
353
240
|
|
|
354
|
-
###
|
|
241
|
+
### 검색
|
|
355
242
|
|
|
356
|
-
|
|
243
|
+
| 메서드 | 반환 타입 | 설명 |
|
|
244
|
+
|--------|-----------|------|
|
|
245
|
+
| `searchSymbols(query)` | `Result<SymbolSearchResult[]>` | FTS5 전문검색 + exact/regex/decorator 필터 |
|
|
246
|
+
| `searchRelations(query)` | `Result<CodeRelation[]>` | 파일, 심볼, 관계 유형 필터 |
|
|
247
|
+
| `searchAllSymbols(query)` | `Result<SymbolSearchResult[]>` | 전체 프로젝트 심볼 검색 |
|
|
248
|
+
| `searchAllRelations(query)` | `Result<CodeRelation[]>` | 전체 프로젝트 관계 검색 |
|
|
249
|
+
| `listIndexedFiles(project?)` | `Result<FileRecord[]>` | 인덱싱된 파일 목록 |
|
|
250
|
+
| `getSymbolsByFile(filePath)` | `Result<SymbolSearchResult[]>` | 단일 파일의 모든 심볼 |
|
|
357
251
|
|
|
358
|
-
|
|
359
|
-
const symbols = ledger.extractSymbols(parsed);
|
|
360
|
-
```
|
|
252
|
+
### 의존성 그래프
|
|
361
253
|
|
|
362
|
-
|
|
254
|
+
| 메서드 | 반환 타입 | 설명 |
|
|
255
|
+
|--------|-----------|------|
|
|
256
|
+
| `getDependencies(filePath)` | `Result<string[]>` | `filePath`가 import하는 파일 목록 |
|
|
257
|
+
| `getDependents(filePath)` | `Result<string[]>` | `filePath`를 import하는 파일 목록 |
|
|
258
|
+
| `getAffected(changedFiles)` | `Promise<Result<string[]>>` | 전이적 영향 범위 |
|
|
259
|
+
| `hasCycle(project?)` | `Promise<Result<boolean>>` | 순환 의존성 감지 |
|
|
260
|
+
| `getCyclePaths(project?)` | `Promise<Result<string[][]>>` | 모든 순환 경로 |
|
|
261
|
+
| `getImportGraph(project?)` | `Promise<Result<Map>>` | 전체 인접 리스트 |
|
|
262
|
+
| `getTransitiveDependencies(filePath)` | `Promise<Result<string[]>>` | 전방 전이적 BFS |
|
|
363
263
|
|
|
364
|
-
|
|
264
|
+
### 분석
|
|
365
265
|
|
|
366
|
-
|
|
266
|
+
| 메서드 | 반환 타입 | 설명 |
|
|
267
|
+
|--------|-----------|------|
|
|
268
|
+
| `getDeadExports(project?, opts?)` | `Result<Array>` | 미사용 exported 심볼 |
|
|
269
|
+
| `getFullSymbol(name, filePath)` | `Result<FullSymbol>` | 멤버, jsDoc, 데코레이터, 타입 정보 |
|
|
270
|
+
| `getFileStats(filePath)` | `Result<FileStats>` | 라인 수, 심볼 수, 파일 크기 |
|
|
271
|
+
| `getFanMetrics(filePath)` | `Promise<Result<FanMetrics>>` | fan-in/fan-out 결합도 |
|
|
272
|
+
| `getModuleInterface(filePath)` | `Result<ModuleInterface>` | 공개 export와 메타데이터 |
|
|
273
|
+
| `getInternalRelations(filePath)` | `Result<CodeRelation[]>` | 파일 내부 관계 |
|
|
274
|
+
| `diffSymbols(before, after)` | `SymbolDiff` | 스냅샷 diff (추가/삭제/수정) |
|
|
367
275
|
|
|
368
|
-
|
|
276
|
+
### 고급
|
|
369
277
|
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
278
|
+
| 메서드 | 반환 타입 | 설명 |
|
|
279
|
+
|--------|-----------|------|
|
|
280
|
+
| `findPattern(pattern, opts?)` | `Promise<Result<PatternMatch[]>>` | AST 구조적 검색 (ast-grep) |
|
|
281
|
+
| `resolveSymbol(name, filePath)` | `Result<ResolvedSymbol>` | re-export 체인을 따라 원본 추적 |
|
|
282
|
+
| `getHeritageChain(name, filePath)` | `Promise<Result<HeritageNode>>` | extends/implements 트리 |
|
|
283
|
+
| `indexExternalPackages(packages)` | `Promise<Result<IndexResult[]>>` | `node_modules`의 `.d.ts` 인덱싱 |
|
|
284
|
+
| `batchParse(filePaths)` | `Promise<Result<Map>>` | 다중 파일 동시 파싱 |
|
|
373
285
|
|
|
374
|
-
|
|
286
|
+
### 라이프사이클 & 저수준
|
|
375
287
|
|
|
376
|
-
|
|
288
|
+
| 메서드 | 반환 타입 | 설명 |
|
|
289
|
+
|--------|-----------|------|
|
|
290
|
+
| `reindex()` | `Promise<Result<IndexResult>>` | 강제 전체 재인덱싱 (owner만 가능) |
|
|
291
|
+
| `onIndexed(callback)` | `() => void` | 인덱싱 완료 이벤트 구독 |
|
|
292
|
+
| `parseSource(filePath, src)` | `Result<ParsedFile>` | 단일 파일 파싱 & 캐시 |
|
|
293
|
+
| `extractSymbols(parsed)` | `Result<ExtractedSymbol[]>` | 파싱된 AST에서 심볼 추출 |
|
|
294
|
+
| `extractRelations(parsed)` | `Result<CodeRelation[]>` | 파싱된 AST에서 관계 추출 |
|
|
295
|
+
| `getParsedAst(filePath)` | `ParsedFile \| undefined` | 캐시된 AST 조회 (읽기 전용) |
|
|
296
|
+
| `getFileInfo(filePath)` | `Result<FileRecord \| null>` | 파일 메타데이터 (해시, mtime, 크기) |
|
|
297
|
+
| `getStats(project?)` | `Result<SymbolStats>` | 심볼/파일 통계 |
|
|
298
|
+
| `projects` | `ProjectBoundary[]` | 탐지된 프로젝트 경계 |
|
|
299
|
+
| `close(opts?)` | `Promise<Result<void>>` | 종료 (`{ cleanup: true }`로 DB 삭제 가능) |
|
|
300
|
+
|
|
301
|
+
<br>
|
|
377
302
|
|
|
378
|
-
|
|
303
|
+
<details>
|
|
304
|
+
<summary><strong>타입 정의</strong></summary>
|
|
379
305
|
|
|
380
|
-
|
|
306
|
+
상세 TypeScript 타입 정의는 영문 README를 참고하세요 → [README.md — Type Definitions](./README.md#type-definitions)
|
|
381
307
|
|
|
382
|
-
|
|
383
|
-
반환된 객체는 내부 캐시와 공유됩니다 — **읽기 전용**으로 취급하세요.
|
|
308
|
+
주요 타입 요약:
|
|
384
309
|
|
|
385
310
|
```ts
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
311
|
+
interface SymbolSearchQuery {
|
|
312
|
+
text?: string; // FTS5 전문 검색
|
|
313
|
+
exact?: boolean; // 정확한 이름 일치
|
|
314
|
+
kind?: SymbolKind; // 심볼 종류 필터
|
|
315
|
+
filePath?: string; // 파일 경로 필터
|
|
316
|
+
isExported?: boolean; // export 여부
|
|
317
|
+
project?: string; // 프로젝트 이름
|
|
318
|
+
limit?: number; // 최대 결과 수 (기본값: 100)
|
|
319
|
+
decorator?: string; // 데코레이터 이름 필터
|
|
320
|
+
regex?: string; // 정규식 패턴 필터
|
|
389
321
|
}
|
|
390
|
-
```
|
|
391
322
|
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
323
|
+
interface CodeRelation {
|
|
324
|
+
type: 'imports' | 'type-references' | 're-exports' | 'calls' | 'extends' | 'implements';
|
|
325
|
+
srcFilePath: string;
|
|
326
|
+
srcSymbolName: string | null;
|
|
327
|
+
dstFilePath: string;
|
|
328
|
+
dstSymbolName: string | null;
|
|
329
|
+
meta?: Record<string, unknown>;
|
|
330
|
+
}
|
|
399
331
|
|
|
400
|
-
|
|
401
|
-
|
|
332
|
+
interface IndexResult {
|
|
333
|
+
indexedFiles: number;
|
|
334
|
+
removedFiles: number;
|
|
335
|
+
totalSymbols: number;
|
|
336
|
+
totalRelations: number;
|
|
337
|
+
durationMs: number;
|
|
338
|
+
changedFiles: string[];
|
|
339
|
+
deletedFiles: string[];
|
|
340
|
+
failedFiles: string[];
|
|
341
|
+
changedSymbols: {
|
|
342
|
+
added: Array<{ name: string; filePath: string; kind: string }>;
|
|
343
|
+
modified: Array<{ name: string; filePath: string; kind: string }>;
|
|
344
|
+
removed: Array<{ name: string; filePath: string; kind: string }>;
|
|
345
|
+
};
|
|
346
|
+
}
|
|
402
347
|
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
348
|
+
interface GildashError {
|
|
349
|
+
type: GildashErrorType;
|
|
350
|
+
message: string;
|
|
351
|
+
cause?: unknown;
|
|
407
352
|
}
|
|
408
353
|
```
|
|
409
354
|
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
---
|
|
413
|
-
|
|
414
|
-
### `ledger.getSymbolsByFile(filePath, project?)`
|
|
355
|
+
</details>
|
|
415
356
|
|
|
416
|
-
|
|
357
|
+
<br>
|
|
417
358
|
|
|
418
|
-
|
|
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
|
-
```
|
|
359
|
+
## ⚠️ 에러 타입
|
|
426
360
|
|
|
427
|
-
|
|
361
|
+
| 타입 | 발생 시점 |
|
|
362
|
+
|------|----------|
|
|
363
|
+
| `watcher` | 파일 워처 시작/중지 실패 |
|
|
364
|
+
| `parse` | AST 파싱 실패 |
|
|
365
|
+
| `extract` | 심볼/관계 추출 실패 |
|
|
366
|
+
| `index` | 인덱싱 파이프라인 실패 |
|
|
367
|
+
| `store` | DB 연산 실패 |
|
|
368
|
+
| `search` | 검색 쿼리 실패 |
|
|
369
|
+
| `closed` | 종료된 인스턴스에서 연산 시도 |
|
|
370
|
+
| `validation` | 잘못된 입력 (e.g. `node_modules`에 패키지 없음) |
|
|
371
|
+
| `close` | 종료 중 에러 |
|
|
428
372
|
|
|
429
373
|
<br>
|
|
430
374
|
|
|
@@ -433,19 +377,19 @@ if (!isErr(symbols)) {
|
|
|
433
377
|
```
|
|
434
378
|
Gildash (파사드)
|
|
435
379
|
├── Parser — oxc-parser 기반 TypeScript AST 파싱
|
|
436
|
-
├── Extractor — 심볼/관계 추출 (imports, calls, heritage)
|
|
437
|
-
├── Store — bun:sqlite + drizzle-orm (files
|
|
438
|
-
├── Indexer — 변경
|
|
439
|
-
├── Search —
|
|
380
|
+
├── Extractor — 심볼/관계 추출 (imports, re-exports, type-refs, calls, heritage)
|
|
381
|
+
├── Store — bun:sqlite + drizzle-orm (files · symbols · relations · FTS5)
|
|
382
|
+
├── Indexer — 파일 변경 → 파싱 → 추출 → 저장 파이프라인, 심볼 레벨 diff
|
|
383
|
+
├── Search — FTS + regex + decorator 검색, 관계 쿼리, 의존성 그래프, ast-grep
|
|
440
384
|
└── Watcher — @parcel/watcher + owner/reader 역할 관리
|
|
441
385
|
```
|
|
442
386
|
|
|
443
387
|
### Owner/Reader 패턴
|
|
444
388
|
|
|
445
|
-
동일 SQLite DB를 여러 프로세스가 공유할 때, 단일 writer를
|
|
389
|
+
동일 SQLite DB를 여러 프로세스가 공유할 때, 단일 writer를 보장합니다:
|
|
446
390
|
|
|
447
|
-
- **Owner** —
|
|
448
|
-
- **Reader** — 읽기 전용
|
|
391
|
+
- **Owner** — 파일 워처 실행, 인덱싱 수행, 30초 간격으로 heartbeat 전송
|
|
392
|
+
- **Reader** — 읽기 전용 접근; 60초 간격으로 owner 상태 확인, owner가 stale 상태가 되면 reader 중 하나가 owner로 승격
|
|
449
393
|
|
|
450
394
|
<br>
|
|
451
395
|
|