@happyvertical/smrt-scanner 0.51.32 → 0.51.34
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/AGENTS.md +9 -0
- package/dist/agent-surface.d.ts +224 -0
- package/dist/agent-surface.d.ts.map +1 -0
- package/dist/cli.d.ts +21 -1
- package/dist/cli.d.ts.map +1 -0
- package/dist/discovery.d.ts +15 -0
- package/dist/discovery.d.ts.map +1 -0
- package/dist/index.d.ts +29 -2061
- package/dist/index.d.ts.map +1 -0
- package/dist/inheritance-resolver.d.ts +226 -0
- package/dist/inheritance-resolver.d.ts.map +1 -0
- package/dist/knowledge-discovery.d.ts +48 -0
- package/dist/knowledge-discovery.d.ts.map +1 -0
- package/dist/knowledge-graph.d.ts +113 -0
- package/dist/knowledge-graph.d.ts.map +1 -0
- package/dist/knowledge.d.ts +3 -0
- package/dist/knowledge.d.ts.map +1 -0
- package/dist/knowledge.js +301 -0
- package/dist/knowledge.js.map +1 -0
- package/dist/manifest-adapter.d.ts +297 -0
- package/dist/manifest-adapter.d.ts.map +1 -0
- package/dist/numeric-precision-lint.d.ts +94 -0
- package/dist/numeric-precision-lint.d.ts.map +1 -0
- package/dist/oxc-parser.d.ts +505 -0
- package/dist/oxc-parser.d.ts.map +1 -0
- package/dist/scanner.d.ts +266 -0
- package/dist/scanner.d.ts.map +1 -0
- package/dist/source-location.d.ts +22 -0
- package/dist/source-location.d.ts.map +1 -0
- package/dist/types.d.ts +497 -522
- package/dist/types.d.ts.map +1 -0
- package/dist/verify-completeness.d.ts +60 -0
- package/dist/verify-completeness.d.ts.map +1 -0
- package/package.json +6 -1
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OXC Scanner
|
|
3
|
+
*
|
|
4
|
+
* High-level scanner that orchestrates OXC parsing and inheritance resolution.
|
|
5
|
+
* Provides a simple API for scanning TypeScript files for SMRT classes.
|
|
6
|
+
*/
|
|
7
|
+
import type { ExternalManifest, OxcScannerOptions, ResolvedClassDefinition, ScanResults } from './types.js';
|
|
8
|
+
/**
|
|
9
|
+
* Prunes that always apply, on top of whatever `exclude` a caller passes.
|
|
10
|
+
*
|
|
11
|
+
* `exclude` replaces {@link DEFAULT_EXCLUDE} wholesale, so every caller that
|
|
12
|
+
* narrowed the excludes also silently reopened `node_modules` — and installed
|
|
13
|
+
* dependencies are never a project's own `@smrt()` sources. Dot directories are
|
|
14
|
+
* generated or tool state (`.git`, `.svelte-kit`, `.turbo`, `.vercel`, agent
|
|
15
|
+
* scratch) and are pruned for the same reason: nothing authored lives there.
|
|
16
|
+
* `**\/.*` keeps hidden FILES out of the result too, so turning `dot` on to
|
|
17
|
+
* make these prunes work does not quietly widen what gets scanned.
|
|
18
|
+
*
|
|
19
|
+
* These are load-bearing for termination, not just for speed. See
|
|
20
|
+
* {@link OxcScanner.discoverFiles}.
|
|
21
|
+
*/
|
|
22
|
+
/**
|
|
23
|
+
* High-performance TypeScript scanner that discovers `@smrt()`-decorated
|
|
24
|
+
* classes in a project's source files.
|
|
25
|
+
*
|
|
26
|
+
* Orchestrates the two-phase scan pipeline:
|
|
27
|
+
* 1. **Phase 1 — Parse** (`scan()`): uses OXC (Rust) to parse TypeScript files
|
|
28
|
+
* in parallel and extract raw class, field, method, and decorator metadata.
|
|
29
|
+
* 2. **Phase 2 — Resolve** (`resolve()`): walks inheritance chains, detects STI
|
|
30
|
+
* hierarchies, and merges fields from ancestor classes.
|
|
31
|
+
*
|
|
32
|
+
* The common path is {@link scanAndResolve} which runs both phases in sequence.
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```typescript
|
|
36
|
+
* import { OxcScanner } from '@happyvertical/smrt-scanner';
|
|
37
|
+
*
|
|
38
|
+
* const scanner = new OxcScanner({
|
|
39
|
+
* cwd: process.cwd(),
|
|
40
|
+
* include: ['src/**\/*.ts'],
|
|
41
|
+
* exclude: ['**\/*.test.ts'],
|
|
42
|
+
* });
|
|
43
|
+
*
|
|
44
|
+
* const { results, resolved } = await scanner.scanAndResolve();
|
|
45
|
+
* console.log(`Found ${resolved.length} SMRT classes in ${results.fileCount} files`);
|
|
46
|
+
* ```
|
|
47
|
+
*
|
|
48
|
+
* @see {@link OxcScannerOptions} for all available configuration options.
|
|
49
|
+
* @see {@link scanDirectory} for a one-liner convenience wrapper.
|
|
50
|
+
*/
|
|
51
|
+
export declare class OxcScanner {
|
|
52
|
+
private options;
|
|
53
|
+
private resolver;
|
|
54
|
+
private scanResults;
|
|
55
|
+
/**
|
|
56
|
+
* Create a new `OxcScanner` with the given options.
|
|
57
|
+
*
|
|
58
|
+
* All options are optional. By default the scanner targets every `.ts` and
|
|
59
|
+
* `.tsx` file under `process.cwd()`, excluding `node_modules`, `dist`,
|
|
60
|
+
* `build`, declaration files, and test files.
|
|
61
|
+
*
|
|
62
|
+
* @param options - Scanner configuration. See {@link OxcScannerOptions}.
|
|
63
|
+
*/
|
|
64
|
+
constructor(options?: OxcScannerOptions);
|
|
65
|
+
/**
|
|
66
|
+
* Phase 1 — Discover and parse TypeScript files using OXC.
|
|
67
|
+
*
|
|
68
|
+
* Uses `fast-glob` to enumerate matching files and then parses them in
|
|
69
|
+
* parallel with OXC (Rust). The raw class definitions are registered with
|
|
70
|
+
* the internal {@link InheritanceResolver} for use in the subsequent
|
|
71
|
+
* {@link resolve} call.
|
|
72
|
+
*
|
|
73
|
+
* @returns A {@link ScanResults} object containing all classes found, any
|
|
74
|
+
* parse errors, accumulated type aliases, SMRT import metadata, and
|
|
75
|
+
* aggregate timing information.
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* ```typescript
|
|
79
|
+
* const scanner = new OxcScanner({ cwd: '/project' });
|
|
80
|
+
* const results = await scanner.scan();
|
|
81
|
+
* console.log(`Parsed ${results.fileCount} files in ${results.totalParseTimeMs.toFixed(1)}ms`);
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
84
|
+
scan(): Promise<ScanResults>;
|
|
85
|
+
/**
|
|
86
|
+
* Phase 2 — Resolve inheritance chains for all scanned classes.
|
|
87
|
+
*
|
|
88
|
+
* Must be called after {@link scan}. Walks each class's extends chain,
|
|
89
|
+
* detects STI hierarchies, merges ancestor fields for STI subclasses, and
|
|
90
|
+
* marks framework base classes.
|
|
91
|
+
*
|
|
92
|
+
* @returns An array of {@link ResolvedClassDefinition} objects — one for
|
|
93
|
+
* every class that either carries `@smrt()` or extends a framework base
|
|
94
|
+
* class (`SmrtObject`, `SmrtClass`, `SmrtCollection`).
|
|
95
|
+
*
|
|
96
|
+
* @throws {Error} If called before {@link scan}.
|
|
97
|
+
*
|
|
98
|
+
* @see {@link scanAndResolve} to run both phases in one call.
|
|
99
|
+
*/
|
|
100
|
+
resolve(): ResolvedClassDefinition[];
|
|
101
|
+
/**
|
|
102
|
+
* Run both scan phases in a single call.
|
|
103
|
+
*
|
|
104
|
+
* Equivalent to calling `await scanner.scan()` followed by
|
|
105
|
+
* `scanner.resolve()`. This is the most common entry point for callers
|
|
106
|
+
* that want the fully-resolved manifest-ready data in one step.
|
|
107
|
+
*
|
|
108
|
+
* @returns An object with:
|
|
109
|
+
* - `results` — raw {@link ScanResults} from Phase 1.
|
|
110
|
+
* - `resolved` — array of {@link ResolvedClassDefinition} from Phase 2.
|
|
111
|
+
*
|
|
112
|
+
* @example
|
|
113
|
+
* ```typescript
|
|
114
|
+
* const scanner = new OxcScanner({ cwd: '/project/src' });
|
|
115
|
+
* const { results, resolved } = await scanner.scanAndResolve();
|
|
116
|
+
* // resolved is ready to pass to ManifestAdapter.toManifest()
|
|
117
|
+
* ```
|
|
118
|
+
*
|
|
119
|
+
* @see {@link ManifestAdapter} to convert `resolved` into a manifest JSON.
|
|
120
|
+
*/
|
|
121
|
+
scanAndResolve(): Promise<{
|
|
122
|
+
results: ScanResults;
|
|
123
|
+
resolved: ResolvedClassDefinition[];
|
|
124
|
+
}>;
|
|
125
|
+
/**
|
|
126
|
+
* Register an external package manifest for cross-package base class resolution.
|
|
127
|
+
*
|
|
128
|
+
* When a project class extends a class defined in an installed SMRT package,
|
|
129
|
+
* the resolver needs access to that package's class definitions to walk the
|
|
130
|
+
* full inheritance chain. Call this method with each external package's
|
|
131
|
+
* {@link ExternalManifest} before calling {@link scan} or {@link resolve}.
|
|
132
|
+
*
|
|
133
|
+
* @param manifest - The external manifest to register, including `packageName`,
|
|
134
|
+
* `packageVersion`, and a `classes` map keyed by class name.
|
|
135
|
+
*
|
|
136
|
+
* @see {@link ExternalManifest}
|
|
137
|
+
*/
|
|
138
|
+
addExternalManifest(manifest: ExternalManifest): void;
|
|
139
|
+
/**
|
|
140
|
+
* Scan all discovered files for @happyvertical/smrt-* imports.
|
|
141
|
+
* Returns a map of package name → Set of imported class names.
|
|
142
|
+
*
|
|
143
|
+
* Used for tree-shaking: only external objects that are actually imported
|
|
144
|
+
* in the project's source files will be included in the manifest.
|
|
145
|
+
*
|
|
146
|
+
* Must be called after scan() or as part of scanAndResolve().
|
|
147
|
+
*
|
|
148
|
+
* @example
|
|
149
|
+
* ```typescript
|
|
150
|
+
* const scanner = new OxcScanner({ cwd: process.cwd() });
|
|
151
|
+
* await scanner.scan();
|
|
152
|
+
* const imports = scanner.scanSmrtImports();
|
|
153
|
+
* // Map { '@happyvertical/smrt-profiles' => Set { 'Person', 'Organization' } }
|
|
154
|
+
* ```
|
|
155
|
+
*/
|
|
156
|
+
scanSmrtImports(): Map<string, Set<string>>;
|
|
157
|
+
/**
|
|
158
|
+
* Return aggregate statistics about the last scan.
|
|
159
|
+
*
|
|
160
|
+
* Can be called after {@link scan} has completed. Returns counts useful for
|
|
161
|
+
* diagnostics and the `--stats` CLI flag.
|
|
162
|
+
*
|
|
163
|
+
* @returns An object with:
|
|
164
|
+
* - `totalClasses` — total class declarations seen (including non-SMRT).
|
|
165
|
+
* - `smrtClasses` — classes with `@smrt()` decorator.
|
|
166
|
+
* - `stiClasses` — SMRT classes participating in an STI hierarchy.
|
|
167
|
+
* - `maxInheritanceDepth` — length of the deepest inheritance chain.
|
|
168
|
+
* - `fileCount` — number of files scanned.
|
|
169
|
+
* - `parseTimeMs` — total wall-clock parse time in milliseconds.
|
|
170
|
+
*/
|
|
171
|
+
getStats(): {
|
|
172
|
+
totalClasses: number;
|
|
173
|
+
smrtClasses: number;
|
|
174
|
+
stiClasses: number;
|
|
175
|
+
maxInheritanceDepth: number;
|
|
176
|
+
fileCount: number;
|
|
177
|
+
parseTimeMs: number;
|
|
178
|
+
};
|
|
179
|
+
/**
|
|
180
|
+
* Discover files to scan using fast-glob.
|
|
181
|
+
*
|
|
182
|
+
* Two settings here decide whether discovery terminates at all when the
|
|
183
|
+
* scanner is pointed at an application root rather than a package `src/`:
|
|
184
|
+
*
|
|
185
|
+
* - `dot: true`. Without it a `**` in an ignore pattern cannot cross a
|
|
186
|
+
* dot segment, so `**\/node_modules/**` prunes `node_modules` at the root
|
|
187
|
+
* but NOT `.svelte-kit/…/node_modules` or any other `node_modules` under a
|
|
188
|
+
* dot directory. Those subtrees were then walked in full and every entry
|
|
189
|
+
* discarded — unbounded work that could never produce a match.
|
|
190
|
+
* - `followSymbolicLinks: false`. pnpm materializes `node_modules` as a
|
|
191
|
+
* symlink graph with cycles, so a link-following walk revisits the same
|
|
192
|
+
* real directories once per path that reaches them.
|
|
193
|
+
*
|
|
194
|
+
* Together they were enough to exhaust a 4 GB heap on a consumer app that
|
|
195
|
+
* installs the published packages (#2275).
|
|
196
|
+
*
|
|
197
|
+
* Patterns are rewritten relative to `cwd` first. fast-glob matches `ignore`
|
|
198
|
+
* in whatever space the patterns use, so an absolute pattern would hand
|
|
199
|
+
* `**\/.*\/**` the project's own ancestors — a checkout under `~/.worktrees`
|
|
200
|
+
* or `~/.cache` would then match nothing at all, silently.
|
|
201
|
+
*/
|
|
202
|
+
private discoverFiles;
|
|
203
|
+
/**
|
|
204
|
+
* Find declarations in files the CLASS scan did not cover.
|
|
205
|
+
*
|
|
206
|
+
* The class `include` is routinely narrowed to where models live, but an
|
|
207
|
+
* intent sidecar lives beside its component. Without this pass those
|
|
208
|
+
* declarations would be missing from every artifact with no diagnostic — a
|
|
209
|
+
* silent omission, and in the shipped SvelteKit template's own layout at
|
|
210
|
+
* that. Files already parsed by the class scan are skipped so a declaration
|
|
211
|
+
* is never counted twice and cannot collide with itself.
|
|
212
|
+
*
|
|
213
|
+
* @param alreadyScanned - Absolute paths the class scan already parsed.
|
|
214
|
+
*/
|
|
215
|
+
private scanDeclarationsOutsideClassGlob;
|
|
216
|
+
/**
|
|
217
|
+
* Search `.svelte` files for declarations the scanner can never read.
|
|
218
|
+
*
|
|
219
|
+
* A `.svelte` file is not a TypeScript program and is never parsed here, so
|
|
220
|
+
* this pass produces diagnostics only — never an emitted entry. It exists
|
|
221
|
+
* because the alternative is silence: an intent declared inline in a
|
|
222
|
+
* component simply would not appear anywhere, with nothing to explain why.
|
|
223
|
+
*/
|
|
224
|
+
private scanSvelteDeclarations;
|
|
225
|
+
/**
|
|
226
|
+
* Record a declaring module as a `cwd`-relative POSIX path.
|
|
227
|
+
*
|
|
228
|
+
* Emitted entries land in checked-in artifacts, so an absolute path would
|
|
229
|
+
* make them machine-specific and a Windows separator would make them
|
|
230
|
+
* platform-specific — either one churns a snapshot that is supposed to prove
|
|
231
|
+
* two builds agree.
|
|
232
|
+
*/
|
|
233
|
+
private relativizeSourcePath;
|
|
234
|
+
/**
|
|
235
|
+
* Parse a single file with timing
|
|
236
|
+
*/
|
|
237
|
+
private parseFileWithTiming;
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Convenience wrapper that creates an {@link OxcScanner} for `dir` and runs
|
|
241
|
+
* both scan phases in a single call.
|
|
242
|
+
*
|
|
243
|
+
* @param dir - Directory to scan (resolved to an absolute path automatically).
|
|
244
|
+
* @param options - Scanner options, excluding `cwd` which is set from `dir`.
|
|
245
|
+
* See {@link OxcScannerOptions}.
|
|
246
|
+
* @returns An object with `results` ({@link ScanResults}) and `resolved`
|
|
247
|
+
* ({@link ResolvedClassDefinition}[]).
|
|
248
|
+
*
|
|
249
|
+
* @example
|
|
250
|
+
* ```typescript
|
|
251
|
+
* import { scanDirectory } from '@happyvertical/smrt-scanner';
|
|
252
|
+
*
|
|
253
|
+
* const { resolved } = await scanDirectory('src/', {
|
|
254
|
+
* include: ['**\/*.ts'],
|
|
255
|
+
* exclude: ['**\/*.test.ts'],
|
|
256
|
+
* });
|
|
257
|
+
* console.log(`Found ${resolved.length} SMRT classes`);
|
|
258
|
+
* ```
|
|
259
|
+
*
|
|
260
|
+
* @see {@link OxcScanner} for the full class API with more control.
|
|
261
|
+
*/
|
|
262
|
+
export declare function scanDirectory(dir: string, options?: Omit<OxcScannerOptions, 'cwd'>): Promise<{
|
|
263
|
+
results: ScanResults;
|
|
264
|
+
resolved: ResolvedClassDefinition[];
|
|
265
|
+
}>;
|
|
266
|
+
//# sourceMappingURL=scanner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../src/scanner.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAaH,OAAO,KAAK,EAEV,gBAAgB,EAEhB,iBAAiB,EACjB,uBAAuB,EACvB,WAAW,EACZ,MAAM,YAAY,CAAC;AA2DpB;;;;;;;;;;;;;GAaG;AACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,OAAO,CAA8B;IAC7C,OAAO,CAAC,QAAQ,CAAsB;IACtC,OAAO,CAAC,WAAW,CAA4B;IAE/C;;;;;;;;OAQG;gBACS,OAAO,GAAE,iBAAsB;IAwB3C;;;;;;;;;;;;;;;;;;OAkBG;IACG,IAAI,IAAI,OAAO,CAAC,WAAW,CAAC;IA8DlC;;;;;;;;;;;;;;OAcG;IACH,OAAO,IAAI,uBAAuB,EAAE;IAQpC;;;;;;;;;;;;;;;;;;;OAmBG;IACG,cAAc,IAAI,OAAO,CAAC;QAC9B,OAAO,EAAE,WAAW,CAAC;QACrB,QAAQ,EAAE,uBAAuB,EAAE,CAAC;KACrC,CAAC;IAOF;;;;;;;;;;;;OAYG;IACH,mBAAmB,CAAC,QAAQ,EAAE,gBAAgB,GAAG,IAAI;IAIrD;;;;;;;;;;;;;;;;OAgBG;IACH,eAAe,IAAI,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAwB3C;;;;;;;;;;;;;OAaG;IACH,QAAQ,IAAI;QACV,YAAY,EAAE,MAAM,CAAC;QACrB,WAAW,EAAE,MAAM,CAAC;QACpB,UAAU,EAAE,MAAM,CAAC;QACnB,mBAAmB,EAAE,MAAM,CAAC;QAC5B,SAAS,EAAE,MAAM,CAAC;QAClB,WAAW,EAAE,MAAM,CAAC;KACrB;IAUD;;;;;;;;;;;;;;;;;;;;;;OAsBG;YACW,aAAa;IAS3B;;;;;;;;;;;OAWG;YACW,gCAAgC;IAmC9C;;;;;;;OAOG;YACW,sBAAsB;IAoCpC;;;;;;;OAOG;IACH,OAAO,CAAC,oBAAoB;IAM5B;;OAEG;YACW,mBAAmB;CAIlC;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAsB,aAAa,CACjC,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,IAAI,CAAC,iBAAiB,EAAE,KAAK,CAAM,GAC3C,OAAO,CAAC;IACT,OAAO,EAAE,WAAW,CAAC;IACrB,QAAQ,EAAE,uBAAuB,EAAE,CAAC;CACrC,CAAC,CAOD"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Source-offset helpers shared by the OXC class parser and the agent-surface
|
|
3
|
+
* matcher.
|
|
4
|
+
*
|
|
5
|
+
* Lives in its own module so `agent-surface.ts` can resolve a diagnostic's
|
|
6
|
+
* line/column without importing `oxc-parser.ts`, which imports it back.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Extract line/column from offset in source text.
|
|
10
|
+
*
|
|
11
|
+
* Note: oxc-parser v0.108+ removed magicString, so this is computed manually.
|
|
12
|
+
*
|
|
13
|
+
* @param sourceText - Full source text the offset indexes into.
|
|
14
|
+
* @param offset - 0-based character offset.
|
|
15
|
+
* @returns 1-based line and column, or `undefined` when the offset is out of
|
|
16
|
+
* range.
|
|
17
|
+
*/
|
|
18
|
+
export declare function getLineColumn(sourceText: string, offset: number): {
|
|
19
|
+
line: number;
|
|
20
|
+
column: number;
|
|
21
|
+
} | undefined;
|
|
22
|
+
//# sourceMappingURL=source-location.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"source-location.d.ts","sourceRoot":"","sources":["../src/source-location.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAC3B,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,GACb;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAmB9C"}
|