@c4a/extract 0.5.29-beta.18
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.md +154 -0
- package/bin/c4a-extract-code.js +14383 -0
- package/index.js +16455 -0
- package/package.json +13 -0
- package/wasm/tree-sitter-tsx.wasm +0 -0
- package/wasm/tree-sitter-typescript.wasm +0 -0
- package/wasm/tree-sitter.wasm +0 -0
package/README.md
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
# @c4a/extract
|
|
2
|
+
|
|
3
|
+
Code extraction framework: plugin protocol, registry, digest generation, and shared parsing infrastructure.
|
|
4
|
+
|
|
5
|
+
## Role in the monorepo
|
|
6
|
+
|
|
7
|
+
Defines the standard extraction protocol (`ExtractionPlugin` interface) and provides:
|
|
8
|
+
- Plugin registry for language-specific extraction plugins
|
|
9
|
+
- ExtractionResult v2 schema (SymbolInfo + RelationInfo)
|
|
10
|
+
- Digest generation (exported/internal symbol partitioning) and symbol diff
|
|
11
|
+
- Shared Tree-sitter parsing and file scanning utilities
|
|
12
|
+
|
|
13
|
+
**Depends on:** `core`
|
|
14
|
+
**Depended on by:** `extract-ts`, `daemon`, `api`, `e2e`
|
|
15
|
+
|
|
16
|
+
## Key exports
|
|
17
|
+
|
|
18
|
+
### Plugin protocol
|
|
19
|
+
|
|
20
|
+
- `ExtractionPlugin` — interface that language plugins implement
|
|
21
|
+
- `ExtractionPluginRegistry` — register/resolve plugins by source manifest
|
|
22
|
+
- `FileSystem` — abstraction for file access (plugins don't touch disk directly)
|
|
23
|
+
- `SourceInfo` / `ManifestInfo` — source metadata passed to `canHandle`/`detectEntries`
|
|
24
|
+
- `EntryDetectionResult` — package info + entry files (supports monorepo recursion via `subPackages`)
|
|
25
|
+
- `PatternDetectionResult` — framework pattern detection (endpoints, implicit deps)
|
|
26
|
+
|
|
27
|
+
### Types (ExtractionResult v2)
|
|
28
|
+
|
|
29
|
+
- `ExtractionResult` — standard output format: `{ version: "2", meta, package, files, symbols, relations, stats }`
|
|
30
|
+
- `SymbolInfo` — extracted symbol: name, kind, visibility, file, line, members, params, returnType, etc.
|
|
31
|
+
- `RelationInfo` — extracted relation: type, from, to, grounding, confidence, source
|
|
32
|
+
|
|
33
|
+
### Digest & diff
|
|
34
|
+
|
|
35
|
+
- `generateDigest(result)` — ExtractionResult -> DigestData (exported/internal symbol partitioning)
|
|
36
|
+
- `generateSymbolDiff(current, previous)` — compare two digests, output `{ added, removed }`
|
|
37
|
+
- `DigestData` / `SymbolDiff` types
|
|
38
|
+
|
|
39
|
+
### Shared utilities
|
|
40
|
+
|
|
41
|
+
- `initParser()` / `parseFile()` — Tree-sitter parser initialization and per-file AST parsing
|
|
42
|
+
- `scanSourceFiles()` / `detectModules()` / `detectModuleAt()` — file system scanning and module detection
|
|
43
|
+
- `getGitCommitHash()` — reads the current git commit hash
|
|
44
|
+
- `detectTechStack()` — identifies languages and frameworks in a repository
|
|
45
|
+
|
|
46
|
+
## Writing a language plugin
|
|
47
|
+
|
|
48
|
+
To add support for a new language (e.g., Python), create a new package `@c4a/extract-python` that implements `ExtractionPlugin`:
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
import type {
|
|
52
|
+
ExtractionPlugin,
|
|
53
|
+
ExtractionResult,
|
|
54
|
+
EntryDetectionResult,
|
|
55
|
+
FileSystem,
|
|
56
|
+
ManifestInfo,
|
|
57
|
+
SourceInfo,
|
|
58
|
+
EntryFile,
|
|
59
|
+
} from "@c4a/extract";
|
|
60
|
+
|
|
61
|
+
export class PythonPlugin implements ExtractionPlugin {
|
|
62
|
+
readonly id = "c4a-extract-python";
|
|
63
|
+
readonly languages = ["python"];
|
|
64
|
+
readonly packageManagers = ["pip"];
|
|
65
|
+
|
|
66
|
+
canHandle(source: SourceInfo): boolean {
|
|
67
|
+
// Return true if this source has a pyproject.toml or setup.py
|
|
68
|
+
return source.manifests.some(
|
|
69
|
+
(m) => m.type === "pyproject.toml",
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
async detectEntries(
|
|
74
|
+
manifest: ManifestInfo,
|
|
75
|
+
fs: FileSystem,
|
|
76
|
+
): Promise<EntryDetectionResult> {
|
|
77
|
+
// Parse pyproject.toml to find package name, kind, entry points
|
|
78
|
+
// Return: { package: { name, kind, language }, entries: [...] }
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async extractSymbols(
|
|
82
|
+
entries: EntryFile[],
|
|
83
|
+
fs: FileSystem,
|
|
84
|
+
): Promise<ExtractionResult> {
|
|
85
|
+
// Use Tree-sitter with Python grammar to parse AST
|
|
86
|
+
// Extract SymbolInfo[] (functions, classes, etc.)
|
|
87
|
+
// Extract RelationInfo[] (imports, inheritance, etc.)
|
|
88
|
+
// Return ExtractionResult v2
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Plugin interface
|
|
94
|
+
|
|
95
|
+
| Method | When called | Returns |
|
|
96
|
+
|--------|------------|---------|
|
|
97
|
+
| `canHandle(source)` | Registry resolves which plugin handles a source | `boolean` |
|
|
98
|
+
| `detectEntries(manifest, fs)` | Layer 0: identify package info + entry files | `EntryDetectionResult` |
|
|
99
|
+
| `extractSymbols(entries, fs)` | Layer 1: AST parsing + symbol extraction | `ExtractionResult` |
|
|
100
|
+
| `detectPatterns?(fs)` | Layer 2 (optional): framework-specific patterns | `PatternDetectionResult` |
|
|
101
|
+
|
|
102
|
+
### Registration
|
|
103
|
+
|
|
104
|
+
Plugins are currently registered statically in the daemon:
|
|
105
|
+
|
|
106
|
+
```typescript
|
|
107
|
+
import { ExtractionPluginRegistry } from "@c4a/extract";
|
|
108
|
+
import { TypeScriptPlugin } from "@c4a/extract-ts";
|
|
109
|
+
|
|
110
|
+
const registry = new ExtractionPluginRegistry();
|
|
111
|
+
registry.register(new TypeScriptPlugin());
|
|
112
|
+
|
|
113
|
+
const plugin = registry.resolve(sourceInfo);
|
|
114
|
+
if (plugin) {
|
|
115
|
+
const entries = await plugin.detectEntries(manifest, fs);
|
|
116
|
+
const result = await plugin.extractSymbols(entries.entries, fs);
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### FileSystem abstraction
|
|
121
|
+
|
|
122
|
+
Plugins access files through the `FileSystem` interface, not directly via `node:fs`. This enables future API-based file loading without changing plugin code.
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
interface FileSystem {
|
|
126
|
+
readFile(path: string): Promise<string>;
|
|
127
|
+
readdir(path: string): Promise<string[]>;
|
|
128
|
+
exists(path: string): Promise<boolean>;
|
|
129
|
+
readJson<T = unknown>(path: string): Promise<T>;
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### ExtractionResult v2 format
|
|
134
|
+
|
|
135
|
+
```typescript
|
|
136
|
+
{
|
|
137
|
+
version: "2",
|
|
138
|
+
meta: { extractedAt, pluginId, commitHash, language },
|
|
139
|
+
package: { name, kind, language },
|
|
140
|
+
files: [{ path, language, lines }],
|
|
141
|
+
symbols: SymbolInfo[], // exported + internal
|
|
142
|
+
relations: RelationInfo[], // imports, calls, type refs, etc.
|
|
143
|
+
stats: { files, lines, exportedSymbols, internalSymbols, relations },
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Development
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
bun run --filter @c4a/extract build
|
|
151
|
+
bun run --filter @c4a/extract typecheck
|
|
152
|
+
bun run --filter @c4a/extract test
|
|
153
|
+
bun run --filter @c4a/extract lint
|
|
154
|
+
```
|