@happyvertical/smrt-scanner 0.30.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/AGENTS.md +69 -0
- package/CLAUDE.md +1 -0
- package/LICENSE +7 -0
- package/README.md +77 -0
- package/bin/smrt-scan.js +26 -0
- package/dist/chunks/scanner-3K_xuVXN.js +2117 -0
- package/dist/chunks/scanner-3K_xuVXN.js.map +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +191 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +1408 -0
- package/dist/index.js +163 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +323 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +61 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,1408 @@
|
|
|
1
|
+
declare interface ArrayExpression extends BaseNode {
|
|
2
|
+
type: 'ArrayExpression';
|
|
3
|
+
elements: (Expression | SpreadElement | null)[];
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
declare interface ArrayPattern extends BaseNode {
|
|
7
|
+
type: 'ArrayPattern';
|
|
8
|
+
elements: (Pattern | null)[];
|
|
9
|
+
typeAnnotation?: TSTypeAnnotation;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
declare interface AssignmentPattern extends BaseNode {
|
|
13
|
+
type: 'AssignmentPattern';
|
|
14
|
+
left: Pattern;
|
|
15
|
+
right: Expression;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
declare interface BaseNode {
|
|
19
|
+
type: string;
|
|
20
|
+
loc?: SourceLocation;
|
|
21
|
+
range?: [number, number];
|
|
22
|
+
start?: number;
|
|
23
|
+
end?: number;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
declare interface BlockStatement extends BaseNode {
|
|
27
|
+
type: 'BlockStatement';
|
|
28
|
+
body: Statement[];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
declare interface CallExpression extends BaseNode {
|
|
32
|
+
type: 'CallExpression';
|
|
33
|
+
callee: Expression;
|
|
34
|
+
arguments: Expression[];
|
|
35
|
+
typeParameters?: TSTypeParameterInstantiation;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
declare interface ClassBody extends BaseNode {
|
|
39
|
+
type: 'ClassBody';
|
|
40
|
+
body: ClassElement[];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
declare interface ClassDeclaration extends BaseNode {
|
|
44
|
+
type: 'ClassDeclaration';
|
|
45
|
+
id: Identifier | null;
|
|
46
|
+
superClass: Expression | null;
|
|
47
|
+
superTypeParameters?: TSTypeParameterInstantiation;
|
|
48
|
+
body: ClassBody;
|
|
49
|
+
decorators?: Decorator[];
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
declare type ClassElement = PropertyDefinition | MethodDefinition_2 | any;
|
|
53
|
+
|
|
54
|
+
declare interface Decorator extends BaseNode {
|
|
55
|
+
type: 'Decorator';
|
|
56
|
+
expression: Expression;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
declare interface ExportDefaultDeclaration extends BaseNode {
|
|
60
|
+
type: 'ExportDefaultDeclaration';
|
|
61
|
+
declaration: Statement | Expression;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
declare interface ExportNamedDeclaration extends BaseNode {
|
|
65
|
+
type: 'ExportNamedDeclaration';
|
|
66
|
+
declaration: Statement | null;
|
|
67
|
+
specifiers: ExportSpecifier[];
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
declare interface ExportSpecifier extends BaseNode {
|
|
71
|
+
type: 'ExportSpecifier';
|
|
72
|
+
local: Identifier;
|
|
73
|
+
exported: Identifier;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
declare type Expression = Identifier | Literal | CallExpression | MemberExpression | ObjectExpression | ArrayExpression | NewExpression | any;
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Describes a pre-loaded manifest from an installed SMRT package, used by
|
|
80
|
+
* {@link InheritanceResolver} to resolve base classes that originate outside
|
|
81
|
+
* the local project source.
|
|
82
|
+
*
|
|
83
|
+
* Build tooling (e.g. the SMRT CLI / vitest plugin) loads each installed
|
|
84
|
+
* `@happyvertical/smrt-*` package's `manifest.json` and converts it into an
|
|
85
|
+
* `ExternalManifest` before passing it to the scanner.
|
|
86
|
+
*
|
|
87
|
+
* @see {@link OxcScannerOptions.externalManifests}
|
|
88
|
+
* @see {@link InheritanceResolver.addExternalManifest}
|
|
89
|
+
*/
|
|
90
|
+
export declare interface ExternalManifest {
|
|
91
|
+
/** npm package name, e.g. `'@happyvertical/smrt-profiles'`. */
|
|
92
|
+
packageName: string;
|
|
93
|
+
/** SemVer version string of the installed package. */
|
|
94
|
+
packageVersion: string;
|
|
95
|
+
/** All class definitions exported by the package, keyed by class name. */
|
|
96
|
+
classes: Map<string, RawClassDefinition>;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/* Excluded from this release type: extractSmrtImports */
|
|
100
|
+
|
|
101
|
+
declare interface FieldDefinition {
|
|
102
|
+
type: 'text' | 'decimal' | 'boolean' | 'integer' | 'datetime' | 'json' | 'foreignKey' | 'crossPackageRef' | 'oneToMany' | 'manyToMany' | 'meta';
|
|
103
|
+
required?: boolean;
|
|
104
|
+
default?: any;
|
|
105
|
+
min?: number;
|
|
106
|
+
max?: number;
|
|
107
|
+
maxLength?: number;
|
|
108
|
+
minLength?: number;
|
|
109
|
+
related?: string;
|
|
110
|
+
description?: string;
|
|
111
|
+
_meta?: Record<string, any>;
|
|
112
|
+
transient?: boolean;
|
|
113
|
+
/** Sensitive value — excluded from public serialization + where filtering. */
|
|
114
|
+
sensitive?: boolean;
|
|
115
|
+
/** Read-only over generated write surfaces — stripped from create/update bodies. */
|
|
116
|
+
readonly?: boolean;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Result produced by {@link ManifestAdapter.inferFieldType} for a single field.
|
|
121
|
+
*
|
|
122
|
+
* In addition to the inferred `type`, carries the `source` of the inference
|
|
123
|
+
* so callers can distinguish authoritative decorator-driven results from
|
|
124
|
+
* heuristic guesses and provide better diagnostics.
|
|
125
|
+
*
|
|
126
|
+
* @see {@link InferredFieldType} for valid `type` values.
|
|
127
|
+
* @see {@link ManifestAdapter.inferFieldType} for inference priority rules.
|
|
128
|
+
*/
|
|
129
|
+
export declare interface FieldTypeInference {
|
|
130
|
+
/** Inferred SMRT type */
|
|
131
|
+
type: InferredFieldType;
|
|
132
|
+
/** Related class for relationship types */
|
|
133
|
+
related?: string;
|
|
134
|
+
/** Default value if extractable */
|
|
135
|
+
defaultValue?: unknown;
|
|
136
|
+
/** Whether field is required */
|
|
137
|
+
required: boolean;
|
|
138
|
+
/** Inference source for debugging */
|
|
139
|
+
source: 'helper' | 'decorator' | 'annotation' | 'heuristic' | 'default';
|
|
140
|
+
/** Underlying type for meta fields (e.g., 'string' inside Meta<string>) */
|
|
141
|
+
underlyingType?: InferredFieldType;
|
|
142
|
+
/**
|
|
143
|
+
* Decorator-derived metadata that should be merged into the manifest
|
|
144
|
+
* field's `_meta` object. Used by `@crossPackageRef`, `@manyToMany`,
|
|
145
|
+
* `@meta` to carry options (`validate`, `through`, `indexed`, `idType`,
|
|
146
|
+
* etc.) that don't fit on the top-level FieldDefinition.
|
|
147
|
+
*/
|
|
148
|
+
_meta?: Record<string, unknown>;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Result from scanning a single file
|
|
153
|
+
*/
|
|
154
|
+
export declare interface FileScanResult {
|
|
155
|
+
/** Source file path */
|
|
156
|
+
filePath: string;
|
|
157
|
+
/** Classes found in file */
|
|
158
|
+
classes: RawClassDefinition[];
|
|
159
|
+
/** Scan errors */
|
|
160
|
+
errors: ScanError[];
|
|
161
|
+
/** Parse time in milliseconds */
|
|
162
|
+
parseTimeMs: number;
|
|
163
|
+
/** Type alias declarations found in file (name → resolved type string) */
|
|
164
|
+
typeAliases: Record<string, string>;
|
|
165
|
+
/** SMRT package imports found in file (package name → Set of imported class names) */
|
|
166
|
+
smrtImports?: Map<string, Set<string>>;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
declare interface FunctionExpression extends BaseNode {
|
|
170
|
+
type: 'FunctionExpression';
|
|
171
|
+
async: boolean;
|
|
172
|
+
params: Pattern[];
|
|
173
|
+
returnType?: TSTypeAnnotation;
|
|
174
|
+
body: BlockStatement;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
declare interface Identifier extends BaseNode {
|
|
178
|
+
type: 'Identifier';
|
|
179
|
+
name: string;
|
|
180
|
+
typeAnnotation?: TSTypeAnnotation;
|
|
181
|
+
optional?: boolean;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
declare interface ImportDeclaration extends BaseNode {
|
|
185
|
+
type: 'ImportDeclaration';
|
|
186
|
+
specifiers?: ImportSpecifierLike[];
|
|
187
|
+
source: Literal;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
declare interface ImportDefaultSpecifier extends BaseNode {
|
|
191
|
+
type: 'ImportDefaultSpecifier';
|
|
192
|
+
local: Identifier;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
declare interface ImportNamespaceSpecifier extends BaseNode {
|
|
196
|
+
type: 'ImportNamespaceSpecifier';
|
|
197
|
+
local: Identifier;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
declare interface ImportSpecifier extends BaseNode {
|
|
201
|
+
type: 'ImportSpecifier';
|
|
202
|
+
imported: Identifier;
|
|
203
|
+
local: Identifier;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
declare type ImportSpecifierLike = ImportSpecifier | ImportNamespaceSpecifier | ImportDefaultSpecifier;
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* The set of SMRT column types that the scanner can infer for a field.
|
|
210
|
+
*
|
|
211
|
+
* | Value | DB column type | Notes |
|
|
212
|
+
* |---|---|---|
|
|
213
|
+
* | `text` | `TEXT` / `VARCHAR` | Default for `string` and unknown types |
|
|
214
|
+
* | `integer` | `INTEGER` | `number` with `= 0` initialiser |
|
|
215
|
+
* | `decimal` | `DECIMAL` | `number` with `= 0.0` initialiser |
|
|
216
|
+
* | `boolean` | `BOOLEAN` | `boolean` annotation or literal initialiser |
|
|
217
|
+
* | `datetime` | `DATETIME` | `Date` annotation |
|
|
218
|
+
* | `json` | `JSON` / `TEXT` | Arrays, `Record<>`, object types |
|
|
219
|
+
* | `foreignKey` | `UUID` by default (FK column) | `@foreignKey(Class)` decorator |
|
|
220
|
+
* | `crossPackageRef` | `UUID` by default (no FK constraint) | `@crossPackageRef('@pkg:Class')` decorator |
|
|
221
|
+
* | `oneToMany` | — (virtual) | `@oneToMany(Class)` decorator |
|
|
222
|
+
* | `manyToMany` | — (virtual) | `@manyToMany(Class)` decorator |
|
|
223
|
+
* | `meta` | Stored in `_meta_data` | STI child field wrapped in `Meta<T>` |
|
|
224
|
+
* | `unknown` | — | Could not be determined |
|
|
225
|
+
*
|
|
226
|
+
* @see {@link FieldTypeInference} for the full inference result shape.
|
|
227
|
+
*/
|
|
228
|
+
export declare type InferredFieldType = 'text' | 'integer' | 'decimal' | 'boolean' | 'datetime' | 'json' | 'foreignKey' | 'crossPackageRef' | 'oneToMany' | 'manyToMany' | 'meta' | 'unknown';
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Resolves class inheritance chains and STI hierarchies from raw OXC scan output.
|
|
232
|
+
*
|
|
233
|
+
* After {@link OxcScanner} parses files, `InheritanceResolver` builds a
|
|
234
|
+
* class map from the raw definitions and walks each class's `extends` chain
|
|
235
|
+
* to produce fully-resolved {@link ResolvedClassDefinition} objects.
|
|
236
|
+
*
|
|
237
|
+
* Key responsibilities:
|
|
238
|
+
* - Walking extends chains across local classes and external package manifests.
|
|
239
|
+
* - Detecting which classes participate in STI (Single Table Inheritance).
|
|
240
|
+
* - Merging fields from ancestor classes for STI subclasses (base fields first).
|
|
241
|
+
* - Caching resolved chains to avoid repeated traversals.
|
|
242
|
+
*
|
|
243
|
+
* Framework base classes (`SmrtObject`, `SmrtClass`, `SmrtCollection`) are
|
|
244
|
+
* recognized without needing to appear in source files.
|
|
245
|
+
*
|
|
246
|
+
* @example
|
|
247
|
+
* ```typescript
|
|
248
|
+
* import { InheritanceResolver } from '@happyvertical/smrt-scanner';
|
|
249
|
+
*
|
|
250
|
+
* const resolver = new InheritanceResolver({ baseClasses: ['MyBaseClass'] });
|
|
251
|
+
* resolver.addClasses(rawClasses);
|
|
252
|
+
* const resolved = resolver.resolveAll();
|
|
253
|
+
* ```
|
|
254
|
+
*
|
|
255
|
+
* @see {@link OxcScanner} which owns and drives this resolver internally.
|
|
256
|
+
*/
|
|
257
|
+
export declare class InheritanceResolver {
|
|
258
|
+
/** Map of className -> RawClassDefinition */
|
|
259
|
+
private classMap;
|
|
260
|
+
/** External package manifests for cross-package resolution */
|
|
261
|
+
private externalManifests;
|
|
262
|
+
/** Known base classes (user-provided) */
|
|
263
|
+
private knownBaseClasses;
|
|
264
|
+
/** Cache of resolved inheritance chains */
|
|
265
|
+
private chainCache;
|
|
266
|
+
/**
|
|
267
|
+
* Create a new `InheritanceResolver`.
|
|
268
|
+
*
|
|
269
|
+
* @param options.baseClasses - Additional class names to treat as known
|
|
270
|
+
* framework base classes (beyond the built-in `SmrtObject`, `SmrtClass`,
|
|
271
|
+
* and `SmrtCollection`).
|
|
272
|
+
* @param options.externalManifests - Pre-loaded external package manifests
|
|
273
|
+
* keyed by package name, used for cross-package parent class resolution.
|
|
274
|
+
*/
|
|
275
|
+
constructor(options?: {
|
|
276
|
+
baseClasses?: string[];
|
|
277
|
+
externalManifests?: Map<string, ExternalManifest>;
|
|
278
|
+
});
|
|
279
|
+
/**
|
|
280
|
+
* Register raw class definitions from a scan pass.
|
|
281
|
+
*
|
|
282
|
+
* Adds each class to the internal class map by `className`. Calling this
|
|
283
|
+
* clears the inheritance chain cache so subsequent calls to
|
|
284
|
+
* {@link resolveAll} or {@link resolveInheritanceChain} reflect the new
|
|
285
|
+
* classes.
|
|
286
|
+
*
|
|
287
|
+
* @param classes - Array of {@link RawClassDefinition} objects from
|
|
288
|
+
* {@link ScanResults.classes}.
|
|
289
|
+
*/
|
|
290
|
+
addClasses(classes: RawClassDefinition[]): void;
|
|
291
|
+
/**
|
|
292
|
+
* Register an external package manifest for cross-package base class resolution.
|
|
293
|
+
*
|
|
294
|
+
* Clears the chain cache after registration so re-resolution picks up the
|
|
295
|
+
* new definitions.
|
|
296
|
+
*
|
|
297
|
+
* @param manifest - External package manifest providing class definitions
|
|
298
|
+
* that may appear as base classes in the local project.
|
|
299
|
+
*
|
|
300
|
+
* @see {@link ExternalManifest}
|
|
301
|
+
*/
|
|
302
|
+
addExternalManifest(manifest: ExternalManifest): void;
|
|
303
|
+
/**
|
|
304
|
+
* Resolve all registered classes and return fully-resolved definitions.
|
|
305
|
+
*
|
|
306
|
+
* A class is included in the output if it either:
|
|
307
|
+
* 1. Has an `@smrt()` decorator, or
|
|
308
|
+
* 2. Directly or transitively extends a framework base class
|
|
309
|
+
* (`SmrtObject`, `SmrtClass`, `SmrtCollection`) — this captures
|
|
310
|
+
* collection classes such as `class MeetingCollection extends
|
|
311
|
+
* SmrtCollection<Meeting>` that do not carry `@smrt()` themselves.
|
|
312
|
+
*
|
|
313
|
+
* @returns An array of {@link ResolvedClassDefinition} — one entry per
|
|
314
|
+
* eligible class, with inheritance chain, STI metadata, and merged fields
|
|
315
|
+
* populated.
|
|
316
|
+
*
|
|
317
|
+
* @see {@link resolve} to resolve a single class definition.
|
|
318
|
+
*/
|
|
319
|
+
resolveAll(): ResolvedClassDefinition[];
|
|
320
|
+
/**
|
|
321
|
+
* Check if a class extends a framework base class
|
|
322
|
+
* (SmrtObject, SmrtClass, or SmrtCollection)
|
|
323
|
+
*/
|
|
324
|
+
private extendsFrameworkBase;
|
|
325
|
+
/**
|
|
326
|
+
* Resolve a single raw class definition into a fully-resolved definition.
|
|
327
|
+
*
|
|
328
|
+
* Computes the inheritance chain, determines the effective table strategy,
|
|
329
|
+
* detects STI membership, and merges ancestor fields for STI classes.
|
|
330
|
+
*
|
|
331
|
+
* @param classDef - The raw class definition to resolve.
|
|
332
|
+
* @returns A {@link ResolvedClassDefinition} with all inherited metadata
|
|
333
|
+
* applied. The `packageName` field is left as `null` and must be set by
|
|
334
|
+
* the caller (e.g. {@link ManifestAdapter}).
|
|
335
|
+
*
|
|
336
|
+
* @see {@link resolveAll} to resolve every registered class at once.
|
|
337
|
+
*/
|
|
338
|
+
resolve(classDef: RawClassDefinition): ResolvedClassDefinition;
|
|
339
|
+
/**
|
|
340
|
+
* Resolve the full inheritance chain for a named class, from the root base
|
|
341
|
+
* class down to the named class itself.
|
|
342
|
+
*
|
|
343
|
+
* Results are memoised in an internal cache that is cleared whenever
|
|
344
|
+
* {@link addClasses} or {@link addExternalManifest} is called.
|
|
345
|
+
*
|
|
346
|
+
* @param className - Name of the class to resolve.
|
|
347
|
+
* @returns An ordered array of class names starting from the furthest
|
|
348
|
+
* ancestor and ending with `className`.
|
|
349
|
+
*
|
|
350
|
+
* @example
|
|
351
|
+
* ```typescript
|
|
352
|
+
* // Given: class Article extends Content, class Content extends SmrtObject
|
|
353
|
+
* resolver.resolveInheritanceChain('Article');
|
|
354
|
+
* // => ['SmrtObject', 'Content', 'Article']
|
|
355
|
+
* ```
|
|
356
|
+
*/
|
|
357
|
+
resolveInheritanceChain(className: string): string[];
|
|
358
|
+
/**
|
|
359
|
+
* Look up a class definition by name, searching in priority order:
|
|
360
|
+
* 1. Local classes added via {@link addClasses}.
|
|
361
|
+
* 2. External package manifests added via {@link addExternalManifest}.
|
|
362
|
+
* 3. Built-in framework base classes (`SmrtObject`, `SmrtClass`,
|
|
363
|
+
* `SmrtCollection`) — returns a minimal stub definition so chain walking
|
|
364
|
+
* can terminate cleanly.
|
|
365
|
+
*
|
|
366
|
+
* @param className - Class name to look up.
|
|
367
|
+
* @returns The {@link RawClassDefinition} if found, or `null` if the class
|
|
368
|
+
* is unknown to the resolver.
|
|
369
|
+
*/
|
|
370
|
+
findClassDefinition(className: string): RawClassDefinition | null;
|
|
371
|
+
/**
|
|
372
|
+
* Find the STI root class in a resolved inheritance chain.
|
|
373
|
+
*
|
|
374
|
+
* Walks the chain from base to leaf and returns the name of the first class
|
|
375
|
+
* whose `@smrt()` decorator explicitly declares `tableStrategy: 'sti'`.
|
|
376
|
+
*
|
|
377
|
+
* @param chain - Ordered inheritance chain (base → leaf) as returned by
|
|
378
|
+
* {@link resolveInheritanceChain}.
|
|
379
|
+
* @returns The class name of the STI root, or `null` if no class in the
|
|
380
|
+
* chain uses `tableStrategy: 'sti'`.
|
|
381
|
+
*/
|
|
382
|
+
findSTIBase(chain: string[]): string | null;
|
|
383
|
+
/**
|
|
384
|
+
* Determine the effective table strategy (`'sti'` or `'cti'`) for a class.
|
|
385
|
+
*
|
|
386
|
+
* Resolution order:
|
|
387
|
+
* 1. The class's own `@smrt({ tableStrategy })` declaration, if present.
|
|
388
|
+
* 2. The nearest ancestor that declares `tableStrategy: 'sti'` — STI is
|
|
389
|
+
* inherited automatically by all subclasses.
|
|
390
|
+
* 3. Defaults to `'cti'` if no STI ancestor is found.
|
|
391
|
+
*
|
|
392
|
+
* @param classDef - Raw class definition whose strategy is being determined.
|
|
393
|
+
* @param chain - Pre-resolved inheritance chain for `classDef` (base → leaf).
|
|
394
|
+
* @returns `'sti'` or `'cti'`.
|
|
395
|
+
*/
|
|
396
|
+
determineTableStrategy(classDef: RawClassDefinition, chain: string[]): 'sti' | 'cti';
|
|
397
|
+
/**
|
|
398
|
+
* Merge fields from all classes in an STI inheritance chain.
|
|
399
|
+
*
|
|
400
|
+
* Iterates from the root base class to the leaf class so that base class
|
|
401
|
+
* fields appear first in the returned array. If a field name is declared in
|
|
402
|
+
* both an ancestor and a descendant, the ancestor's definition takes
|
|
403
|
+
* precedence (first-seen wins), preserving the base-class column layout.
|
|
404
|
+
*
|
|
405
|
+
* @param chain - Ordered inheritance chain (base → leaf) as returned by
|
|
406
|
+
* {@link resolveInheritanceChain}.
|
|
407
|
+
* @returns A deduplicated, ordered array of {@link RawFieldDefinition}
|
|
408
|
+
* covering every field in the STI hierarchy.
|
|
409
|
+
*/
|
|
410
|
+
mergeFieldsForSTI(chain: string[]): RawFieldDefinition[];
|
|
411
|
+
/**
|
|
412
|
+
* Return all known descendants of a class.
|
|
413
|
+
*
|
|
414
|
+
* Useful for STI schema generation where the base table must accommodate
|
|
415
|
+
* columns from every subclass.
|
|
416
|
+
*
|
|
417
|
+
* @param className - The ancestor class name to search from.
|
|
418
|
+
* @returns An array of class names (local classes only) whose resolved
|
|
419
|
+
* inheritance chain includes `className`. Does not include `className`
|
|
420
|
+
* itself.
|
|
421
|
+
*/
|
|
422
|
+
getDescendants(className: string): string[];
|
|
423
|
+
/**
|
|
424
|
+
* Check whether a class participates in an STI hierarchy.
|
|
425
|
+
*
|
|
426
|
+
* @param className - Name of the class to check.
|
|
427
|
+
* @returns `true` if any class in the resolved inheritance chain declares
|
|
428
|
+
* `tableStrategy: 'sti'`, `false` otherwise.
|
|
429
|
+
*/
|
|
430
|
+
isSTIClass(className: string): boolean;
|
|
431
|
+
/**
|
|
432
|
+
* Return aggregate statistics about the classes registered with this resolver.
|
|
433
|
+
*
|
|
434
|
+
* @returns An object with:
|
|
435
|
+
* - `totalClasses` — total number of classes in the class map.
|
|
436
|
+
* - `smrtClasses` — classes that carry `@smrt()`.
|
|
437
|
+
* - `stiClasses` — `@smrt()` classes in an STI hierarchy.
|
|
438
|
+
* - `maxInheritanceDepth` — length of the deepest inheritance chain among
|
|
439
|
+
* `@smrt()` classes.
|
|
440
|
+
*/
|
|
441
|
+
getStats(): {
|
|
442
|
+
totalClasses: number;
|
|
443
|
+
smrtClasses: number;
|
|
444
|
+
stiClasses: number;
|
|
445
|
+
maxInheritanceDepth: number;
|
|
446
|
+
};
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
declare interface Literal extends BaseNode {
|
|
450
|
+
type: 'Literal';
|
|
451
|
+
value: string | number | boolean | null | RegExp | bigint;
|
|
452
|
+
raw?: string;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
/**
|
|
456
|
+
* Converts OXC scanner output into the smrt-core `SmartObjectManifest` format
|
|
457
|
+
* consumed by code generators, the Vitest plugin, and the SMRT CLI.
|
|
458
|
+
*
|
|
459
|
+
* The adapter handles field type inference (applying the `0` vs `0.0` integer /
|
|
460
|
+
* decimal heuristic), decorator interpretation (`@foreignKey`, `@oneToMany`,
|
|
461
|
+
* `@manyToMany`, `@field`), type alias resolution, STI `Meta<T>` unwrapping,
|
|
462
|
+
* static property capture (`uiSlots`, `adminRoutes`), and qualified name
|
|
463
|
+
* generation for namespace isolation across packages.
|
|
464
|
+
*
|
|
465
|
+
* @example
|
|
466
|
+
* ```typescript
|
|
467
|
+
* import { OxcScanner, ManifestAdapter } from '@happyvertical/smrt-scanner';
|
|
468
|
+
*
|
|
469
|
+
* const scanner = new OxcScanner({ cwd: process.cwd() });
|
|
470
|
+
* const { results, resolved } = await scanner.scanAndResolve();
|
|
471
|
+
*
|
|
472
|
+
* const adapter = new ManifestAdapter();
|
|
473
|
+
* const manifest = adapter.toManifest(resolved, {
|
|
474
|
+
* packageName: '@my-org/my-package',
|
|
475
|
+
* packageVersion: '1.0.0',
|
|
476
|
+
* typeAliases: results.typeAliases,
|
|
477
|
+
* });
|
|
478
|
+
* ```
|
|
479
|
+
*
|
|
480
|
+
* @see {@link OxcScanner} for producing the `ResolvedClassDefinition[]` input.
|
|
481
|
+
* @see {@link ResolvedClassDefinition} for the shape of each input element.
|
|
482
|
+
*/
|
|
483
|
+
export declare class ManifestAdapter {
|
|
484
|
+
private typeAliases;
|
|
485
|
+
private _aliasDepth?;
|
|
486
|
+
/**
|
|
487
|
+
* Convert an array of resolved class definitions into a `SmartObjectManifest`.
|
|
488
|
+
*
|
|
489
|
+
* Each class is converted to a `SmartObjectDefinition` via
|
|
490
|
+
* {@link toSmartObjectDefinition} and stored under its qualified name key
|
|
491
|
+
* (e.g. `@my-org/my-package:MyClass`) when `packageName` is provided, or
|
|
492
|
+
* under its lowercased class name otherwise.
|
|
493
|
+
*
|
|
494
|
+
* @param resolved - Resolved class definitions from {@link OxcScanner.resolve}
|
|
495
|
+
* or {@link OxcScanner.scanAndResolve}.
|
|
496
|
+
* @param options.packageName - npm package name used to generate qualified
|
|
497
|
+
* class names for namespace isolation across multi-package projects.
|
|
498
|
+
* @param options.packageVersion - Package version recorded in the manifest
|
|
499
|
+
* metadata.
|
|
500
|
+
* @param options.typeAliases - Map of type alias names to their resolved type
|
|
501
|
+
* strings (from {@link ScanResults.typeAliases}). Used to resolve custom
|
|
502
|
+
* types like `type Status = 'active' | 'inactive'` during field inference.
|
|
503
|
+
* @returns A complete `SmartObjectManifest` ready for serialisation.
|
|
504
|
+
*
|
|
505
|
+
* @example
|
|
506
|
+
* ```typescript
|
|
507
|
+
* const manifest = adapter.toManifest(resolved, {
|
|
508
|
+
* packageName: '@my-org/my-package',
|
|
509
|
+
* packageVersion: '1.0.0',
|
|
510
|
+
* typeAliases: results.typeAliases,
|
|
511
|
+
* });
|
|
512
|
+
* fs.writeFileSync('manifest.json', JSON.stringify(manifest, null, 2));
|
|
513
|
+
* ```
|
|
514
|
+
*/
|
|
515
|
+
toManifest(resolved: ResolvedClassDefinition[], options?: {
|
|
516
|
+
packageName?: string;
|
|
517
|
+
packageVersion?: string;
|
|
518
|
+
typeAliases?: Record<string, string>;
|
|
519
|
+
}): SmartObjectManifest;
|
|
520
|
+
/**
|
|
521
|
+
* Convert a single resolved class definition to a `SmartObjectDefinition`.
|
|
522
|
+
*
|
|
523
|
+
* Handles:
|
|
524
|
+
* - Static property capture (`uiSlots`, `adminRoutes`) with child-wins
|
|
525
|
+
* semantics for overridden statics.
|
|
526
|
+
* - Field conversion (non-static public fields only) via {@link convertField}.
|
|
527
|
+
* - Method conversion (public instance/static methods) via {@link convertMethod}.
|
|
528
|
+
* - Collection name pluralisation.
|
|
529
|
+
* - Qualified name generation when `packageName` is supplied.
|
|
530
|
+
*
|
|
531
|
+
* @param classDef - A fully-resolved class definition.
|
|
532
|
+
* @param options.packageName - Package name used to build the qualified class
|
|
533
|
+
* name (`@pkg:ClassName`).
|
|
534
|
+
* @param options.packageVersion - Package version (informational, stored in
|
|
535
|
+
* the definition).
|
|
536
|
+
* @returns A `SmartObjectDefinition` ready to be stored in a manifest.
|
|
537
|
+
*
|
|
538
|
+
* @see {@link toManifest} for the bulk conversion entry point.
|
|
539
|
+
*/
|
|
540
|
+
toSmartObjectDefinition(classDef: ResolvedClassDefinition, options?: {
|
|
541
|
+
packageName?: string;
|
|
542
|
+
packageVersion?: string;
|
|
543
|
+
}): SmartObjectDefinition;
|
|
544
|
+
/**
|
|
545
|
+
* Framework internal fields that should NOT be included in manifests
|
|
546
|
+
* These are SmrtObject internals used by the framework, not user-defined fields
|
|
547
|
+
*/
|
|
548
|
+
private static readonly FRAMEWORK_INTERNAL_FIELDS;
|
|
549
|
+
/**
|
|
550
|
+
* Convert a single raw field definition to a manifest `FieldDefinition`.
|
|
551
|
+
*
|
|
552
|
+
* Returns `null` for fields that should be omitted from the manifest:
|
|
553
|
+
* - `private` or `protected` fields.
|
|
554
|
+
* - Framework-internal fields (`_tableName`, `_db`, `_ai`, etc.).
|
|
555
|
+
*
|
|
556
|
+
* Delegates type inference to {@link inferFieldType} and applies additional
|
|
557
|
+
* post-processing:
|
|
558
|
+
* - Marks fields with `Function` type annotation as `transient`.
|
|
559
|
+
* - Marks fields with `@field({ transient: true })` decorator as `transient`.
|
|
560
|
+
* - Populates `_meta.underlyingType` for STI `Meta<T>` fields.
|
|
561
|
+
*
|
|
562
|
+
* @param field - Raw field definition from a scanned class.
|
|
563
|
+
* @returns A `FieldDefinition` for the manifest, or `null` if the field
|
|
564
|
+
* should be excluded.
|
|
565
|
+
*
|
|
566
|
+
* @see {@link inferFieldType} for the type inference logic.
|
|
567
|
+
*/
|
|
568
|
+
convertField(field: RawFieldDefinition): FieldDefinition | null;
|
|
569
|
+
/**
|
|
570
|
+
* Infer the SMRT field type and required flag from a raw field definition.
|
|
571
|
+
*
|
|
572
|
+
* Inference is attempted in the following priority order:
|
|
573
|
+
* 1. **Field helper call in initializer** — currently always returns `null`
|
|
574
|
+
* (field helpers removed); reserved for future use.
|
|
575
|
+
* 2. **Decorator** — `@foreignKey`, `@oneToMany`, `@manyToMany`, `@field({ type })`.
|
|
576
|
+
* 3. **Type annotation** — `string` → `text`, `number` with `0` vs `0.0`
|
|
577
|
+
* heuristic → `integer` / `decimal`, `boolean`, `Date` → `datetime`,
|
|
578
|
+
* arrays → `json`, `Record<>` / `object` → `json`, union types with
|
|
579
|
+
* `null`, inline string/number literal unions, `Meta<T>` wrapper,
|
|
580
|
+
* and type alias resolution (up to depth 5).
|
|
581
|
+
* 4. **Numeric literal without annotation** — `version = 1` → `integer`.
|
|
582
|
+
* 5. **Boolean literal without annotation** — `isRead = false` → `boolean`.
|
|
583
|
+
* 6. **Default** — falls back to `text`.
|
|
584
|
+
*
|
|
585
|
+
* @param field - The raw field definition to analyse.
|
|
586
|
+
* @returns A {@link FieldTypeInference} describing the inferred type,
|
|
587
|
+
* required flag, default value, related class name (for relationships),
|
|
588
|
+
* and the inference source for debugging.
|
|
589
|
+
*
|
|
590
|
+
* @see {@link FieldTypeInference} for the result shape.
|
|
591
|
+
* @see {@link InferredFieldType} for valid type values.
|
|
592
|
+
*/
|
|
593
|
+
inferFieldType(field: RawFieldDefinition): FieldTypeInference;
|
|
594
|
+
/**
|
|
595
|
+
* Infer type from field helper call (removed)
|
|
596
|
+
*
|
|
597
|
+
* Field helpers have been removed in favor of decorators and TypeScript types:
|
|
598
|
+
* - Use TypeScript types: name: string = '', price: number = 0.0
|
|
599
|
+
* - Use @field() decorator for constraints: @field({ required: true })
|
|
600
|
+
* - Use @foreignKey(), @oneToMany(), @manyToMany() decorators for relationships
|
|
601
|
+
*/
|
|
602
|
+
private inferFromHelper;
|
|
603
|
+
/**
|
|
604
|
+
* Infer type from field decorator
|
|
605
|
+
*/
|
|
606
|
+
private inferFromDecorator;
|
|
607
|
+
private extractFieldDecoratorOptions;
|
|
608
|
+
private parseFieldDecoratorOptions;
|
|
609
|
+
private normalizeFieldType;
|
|
610
|
+
/**
|
|
611
|
+
* Infer type from TypeScript type annotation
|
|
612
|
+
*/
|
|
613
|
+
private inferFromAnnotation;
|
|
614
|
+
/**
|
|
615
|
+
* Parse default value from initializer string
|
|
616
|
+
*/
|
|
617
|
+
private parseDefaultValue;
|
|
618
|
+
/**
|
|
619
|
+
* Convert a raw method definition to a manifest `MethodDefinition`.
|
|
620
|
+
*
|
|
621
|
+
* Returns `null` for `private` or `protected` methods, which are excluded
|
|
622
|
+
* from the manifest. Parameters are mapped to the manifest parameter shape
|
|
623
|
+
* and default values are parsed via `parseDefaultValue`.
|
|
624
|
+
*
|
|
625
|
+
* @param method - Raw method definition from a scanned class.
|
|
626
|
+
* @returns A manifest-compatible `MethodDefinition`, or `null` if the method
|
|
627
|
+
* should be excluded.
|
|
628
|
+
*/
|
|
629
|
+
convertMethod(method: RawMethodDefinition): MethodDefinition | null;
|
|
630
|
+
/**
|
|
631
|
+
* Simple pluralization for collection names.
|
|
632
|
+
*
|
|
633
|
+
* This produces the manifest's `collection` label only; the authoritative DDL
|
|
634
|
+
* table name is derived independently by core (`classnameToTablename` →
|
|
635
|
+
* the `pluralize` library), so this needs to stay self-consistent rather than
|
|
636
|
+
* cover every irregular plural. Note the `y → ies` rule fires only after a
|
|
637
|
+
* consonant, so vowel+y words pluralise correctly (`Day` → `days`, not
|
|
638
|
+
* `daies`).
|
|
639
|
+
*/
|
|
640
|
+
private pluralize;
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
declare interface MemberExpression extends BaseNode {
|
|
644
|
+
type: 'MemberExpression';
|
|
645
|
+
object: Expression;
|
|
646
|
+
property: Expression;
|
|
647
|
+
computed: boolean;
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
declare interface MethodDefinition {
|
|
651
|
+
name: string;
|
|
652
|
+
async: boolean;
|
|
653
|
+
parameters: Array<{
|
|
654
|
+
name: string;
|
|
655
|
+
type: string;
|
|
656
|
+
optional: boolean;
|
|
657
|
+
default?: any;
|
|
658
|
+
}>;
|
|
659
|
+
returnType: string;
|
|
660
|
+
description?: string;
|
|
661
|
+
isStatic: boolean;
|
|
662
|
+
isPublic: boolean;
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
declare interface MethodDefinition_2 extends BaseNode {
|
|
666
|
+
type: 'MethodDefinition';
|
|
667
|
+
key: Expression;
|
|
668
|
+
value: FunctionExpression;
|
|
669
|
+
kind: 'constructor' | 'method' | 'get' | 'set';
|
|
670
|
+
computed: boolean;
|
|
671
|
+
static: boolean;
|
|
672
|
+
accessibility?: 'public' | 'private' | 'protected';
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
declare interface NewExpression extends BaseNode {
|
|
676
|
+
type: 'NewExpression';
|
|
677
|
+
callee: Expression;
|
|
678
|
+
arguments: Expression[];
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
declare interface ObjectExpression extends BaseNode {
|
|
682
|
+
type: 'ObjectExpression';
|
|
683
|
+
properties: (Property | SpreadElement)[];
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
declare interface ObjectPattern extends BaseNode {
|
|
687
|
+
type: 'ObjectPattern';
|
|
688
|
+
properties: (Property | RestElement)[];
|
|
689
|
+
typeAnnotation?: TSTypeAnnotation;
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
/**
|
|
693
|
+
* High-performance TypeScript scanner that discovers `@smrt()`-decorated
|
|
694
|
+
* classes in a project's source files.
|
|
695
|
+
*
|
|
696
|
+
* Orchestrates the two-phase scan pipeline:
|
|
697
|
+
* 1. **Phase 1 — Parse** (`scan()`): uses OXC (Rust) to parse TypeScript files
|
|
698
|
+
* in parallel and extract raw class, field, method, and decorator metadata.
|
|
699
|
+
* 2. **Phase 2 — Resolve** (`resolve()`): walks inheritance chains, detects STI
|
|
700
|
+
* hierarchies, and merges fields from ancestor classes.
|
|
701
|
+
*
|
|
702
|
+
* The common path is {@link scanAndResolve} which runs both phases in sequence.
|
|
703
|
+
*
|
|
704
|
+
* @example
|
|
705
|
+
* ```typescript
|
|
706
|
+
* import { OxcScanner } from '@happyvertical/smrt-scanner';
|
|
707
|
+
*
|
|
708
|
+
* const scanner = new OxcScanner({
|
|
709
|
+
* cwd: process.cwd(),
|
|
710
|
+
* include: ['src/**\/*.ts'],
|
|
711
|
+
* exclude: ['**\/*.test.ts'],
|
|
712
|
+
* });
|
|
713
|
+
*
|
|
714
|
+
* const { results, resolved } = await scanner.scanAndResolve();
|
|
715
|
+
* console.log(`Found ${resolved.length} SMRT classes in ${results.fileCount} files`);
|
|
716
|
+
* ```
|
|
717
|
+
*
|
|
718
|
+
* @see {@link OxcScannerOptions} for all available configuration options.
|
|
719
|
+
* @see {@link scanDirectory} for a one-liner convenience wrapper.
|
|
720
|
+
*/
|
|
721
|
+
export declare class OxcScanner {
|
|
722
|
+
private options;
|
|
723
|
+
private resolver;
|
|
724
|
+
private scanResults;
|
|
725
|
+
/**
|
|
726
|
+
* Create a new `OxcScanner` with the given options.
|
|
727
|
+
*
|
|
728
|
+
* All options are optional. By default the scanner targets every `.ts` and
|
|
729
|
+
* `.tsx` file under `process.cwd()`, excluding `node_modules`, `dist`,
|
|
730
|
+
* `build`, declaration files, and test files.
|
|
731
|
+
*
|
|
732
|
+
* @param options - Scanner configuration. See {@link OxcScannerOptions}.
|
|
733
|
+
*/
|
|
734
|
+
constructor(options?: OxcScannerOptions);
|
|
735
|
+
/**
|
|
736
|
+
* Phase 1 — Discover and parse TypeScript files using OXC.
|
|
737
|
+
*
|
|
738
|
+
* Uses `fast-glob` to enumerate matching files and then parses them in
|
|
739
|
+
* parallel with OXC (Rust). The raw class definitions are registered with
|
|
740
|
+
* the internal {@link InheritanceResolver} for use in the subsequent
|
|
741
|
+
* {@link resolve} call.
|
|
742
|
+
*
|
|
743
|
+
* @returns A {@link ScanResults} object containing all classes found, any
|
|
744
|
+
* parse errors, accumulated type aliases, SMRT import metadata, and
|
|
745
|
+
* aggregate timing information.
|
|
746
|
+
*
|
|
747
|
+
* @example
|
|
748
|
+
* ```typescript
|
|
749
|
+
* const scanner = new OxcScanner({ cwd: '/project' });
|
|
750
|
+
* const results = await scanner.scan();
|
|
751
|
+
* console.log(`Parsed ${results.fileCount} files in ${results.totalParseTimeMs.toFixed(1)}ms`);
|
|
752
|
+
* ```
|
|
753
|
+
*/
|
|
754
|
+
scan(): Promise<ScanResults>;
|
|
755
|
+
/**
|
|
756
|
+
* Phase 2 — Resolve inheritance chains for all scanned classes.
|
|
757
|
+
*
|
|
758
|
+
* Must be called after {@link scan}. Walks each class's extends chain,
|
|
759
|
+
* detects STI hierarchies, merges ancestor fields for STI subclasses, and
|
|
760
|
+
* marks framework base classes.
|
|
761
|
+
*
|
|
762
|
+
* @returns An array of {@link ResolvedClassDefinition} objects — one for
|
|
763
|
+
* every class that either carries `@smrt()` or extends a framework base
|
|
764
|
+
* class (`SmrtObject`, `SmrtClass`, `SmrtCollection`).
|
|
765
|
+
*
|
|
766
|
+
* @throws {Error} If called before {@link scan}.
|
|
767
|
+
*
|
|
768
|
+
* @see {@link scanAndResolve} to run both phases in one call.
|
|
769
|
+
*/
|
|
770
|
+
resolve(): ResolvedClassDefinition[];
|
|
771
|
+
/**
|
|
772
|
+
* Run both scan phases in a single call.
|
|
773
|
+
*
|
|
774
|
+
* Equivalent to calling `await scanner.scan()` followed by
|
|
775
|
+
* `scanner.resolve()`. This is the most common entry point for callers
|
|
776
|
+
* that want the fully-resolved manifest-ready data in one step.
|
|
777
|
+
*
|
|
778
|
+
* @returns An object with:
|
|
779
|
+
* - `results` — raw {@link ScanResults} from Phase 1.
|
|
780
|
+
* - `resolved` — array of {@link ResolvedClassDefinition} from Phase 2.
|
|
781
|
+
*
|
|
782
|
+
* @example
|
|
783
|
+
* ```typescript
|
|
784
|
+
* const scanner = new OxcScanner({ cwd: '/project/src' });
|
|
785
|
+
* const { results, resolved } = await scanner.scanAndResolve();
|
|
786
|
+
* // resolved is ready to pass to ManifestAdapter.toManifest()
|
|
787
|
+
* ```
|
|
788
|
+
*
|
|
789
|
+
* @see {@link ManifestAdapter} to convert `resolved` into a manifest JSON.
|
|
790
|
+
*/
|
|
791
|
+
scanAndResolve(): Promise<{
|
|
792
|
+
results: ScanResults;
|
|
793
|
+
resolved: ResolvedClassDefinition[];
|
|
794
|
+
}>;
|
|
795
|
+
/**
|
|
796
|
+
* Register an external package manifest for cross-package base class resolution.
|
|
797
|
+
*
|
|
798
|
+
* When a project class extends a class defined in an installed SMRT package,
|
|
799
|
+
* the resolver needs access to that package's class definitions to walk the
|
|
800
|
+
* full inheritance chain. Call this method with each external package's
|
|
801
|
+
* {@link ExternalManifest} before calling {@link scan} or {@link resolve}.
|
|
802
|
+
*
|
|
803
|
+
* @param manifest - The external manifest to register, including `packageName`,
|
|
804
|
+
* `packageVersion`, and a `classes` map keyed by class name.
|
|
805
|
+
*
|
|
806
|
+
* @see {@link ExternalManifest}
|
|
807
|
+
*/
|
|
808
|
+
addExternalManifest(manifest: ExternalManifest): void;
|
|
809
|
+
/**
|
|
810
|
+
* Scan all discovered files for @happyvertical/smrt-* imports.
|
|
811
|
+
* Returns a map of package name → Set of imported class names.
|
|
812
|
+
*
|
|
813
|
+
* Used for tree-shaking: only external objects that are actually imported
|
|
814
|
+
* in the project's source files will be included in the manifest.
|
|
815
|
+
*
|
|
816
|
+
* Must be called after scan() or as part of scanAndResolve().
|
|
817
|
+
*
|
|
818
|
+
* @example
|
|
819
|
+
* ```typescript
|
|
820
|
+
* const scanner = new OxcScanner({ cwd: process.cwd() });
|
|
821
|
+
* await scanner.scan();
|
|
822
|
+
* const imports = scanner.scanSmrtImports();
|
|
823
|
+
* // Map { '@happyvertical/smrt-profiles' => Set { 'Person', 'Organization' } }
|
|
824
|
+
* ```
|
|
825
|
+
*/
|
|
826
|
+
scanSmrtImports(): Map<string, Set<string>>;
|
|
827
|
+
/**
|
|
828
|
+
* Return aggregate statistics about the last scan.
|
|
829
|
+
*
|
|
830
|
+
* Can be called after {@link scan} has completed. Returns counts useful for
|
|
831
|
+
* diagnostics and the `--stats` CLI flag.
|
|
832
|
+
*
|
|
833
|
+
* @returns An object with:
|
|
834
|
+
* - `totalClasses` — total class declarations seen (including non-SMRT).
|
|
835
|
+
* - `smrtClasses` — classes with `@smrt()` decorator.
|
|
836
|
+
* - `stiClasses` — SMRT classes participating in an STI hierarchy.
|
|
837
|
+
* - `maxInheritanceDepth` — length of the deepest inheritance chain.
|
|
838
|
+
* - `fileCount` — number of files scanned.
|
|
839
|
+
* - `parseTimeMs` — total wall-clock parse time in milliseconds.
|
|
840
|
+
*/
|
|
841
|
+
getStats(): {
|
|
842
|
+
totalClasses: number;
|
|
843
|
+
smrtClasses: number;
|
|
844
|
+
stiClasses: number;
|
|
845
|
+
maxInheritanceDepth: number;
|
|
846
|
+
fileCount: number;
|
|
847
|
+
parseTimeMs: number;
|
|
848
|
+
};
|
|
849
|
+
/**
|
|
850
|
+
* Discover files to scan using fast-glob
|
|
851
|
+
*/
|
|
852
|
+
private discoverFiles;
|
|
853
|
+
/**
|
|
854
|
+
* Parse a single file with timing
|
|
855
|
+
*/
|
|
856
|
+
private parseFileWithTiming;
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
/**
|
|
860
|
+
* Configuration options for {@link OxcScanner}.
|
|
861
|
+
*
|
|
862
|
+
* All fields are optional; reasonable defaults are applied when omitted.
|
|
863
|
+
*
|
|
864
|
+
* @see {@link OxcScanner}
|
|
865
|
+
*/
|
|
866
|
+
export declare interface OxcScannerOptions {
|
|
867
|
+
/** Glob patterns to include */
|
|
868
|
+
include?: string[];
|
|
869
|
+
/** Glob patterns to exclude */
|
|
870
|
+
exclude?: string[];
|
|
871
|
+
/** Base directory for scanning */
|
|
872
|
+
cwd?: string;
|
|
873
|
+
/** Path to tsconfig.json for module resolution */
|
|
874
|
+
tsconfig?: string;
|
|
875
|
+
/** Whether to follow imports to find base classes */
|
|
876
|
+
followImports?: boolean;
|
|
877
|
+
/** Known base classes (avoid resolution) */
|
|
878
|
+
baseClasses?: string[];
|
|
879
|
+
/** Include private methods in output */
|
|
880
|
+
includePrivateMethods?: boolean;
|
|
881
|
+
/** Include static methods in output */
|
|
882
|
+
includeStaticMethods?: boolean;
|
|
883
|
+
/** External package manifests for base class resolution */
|
|
884
|
+
externalManifests?: Map<string, ExternalManifest>;
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
/**
|
|
888
|
+
* Parse a single TypeScript file and extract SMRT class definitions.
|
|
889
|
+
*
|
|
890
|
+
* Reads the file from disk, runs oxc-parser on it, and returns all class
|
|
891
|
+
* definitions found, any parse errors, accumulated type aliases, and
|
|
892
|
+
* `@happyvertical/smrt-*` import metadata.
|
|
893
|
+
*
|
|
894
|
+
* @param filePath - Absolute path to the `.ts` or `.tsx` file to parse.
|
|
895
|
+
* @returns A {@link FileScanResult} containing classes, errors, type aliases,
|
|
896
|
+
* SMRT imports, and timing information for the file.
|
|
897
|
+
*
|
|
898
|
+
* @example
|
|
899
|
+
* ```typescript
|
|
900
|
+
* import { parseFile } from '@happyvertical/smrt-scanner';
|
|
901
|
+
*
|
|
902
|
+
* const result = parseFile('/project/src/models/Product.ts');
|
|
903
|
+
* console.log(result.classes.map((c) => c.className));
|
|
904
|
+
* // ['Product', 'ProductCollection']
|
|
905
|
+
* ```
|
|
906
|
+
*
|
|
907
|
+
* @see {@link parseSource} to parse a source string directly (e.g. in tests).
|
|
908
|
+
*/
|
|
909
|
+
export declare function parseFile(filePath: string): FileScanResult;
|
|
910
|
+
|
|
911
|
+
/**
|
|
912
|
+
* Parse TypeScript source text directly and extract SMRT class definitions.
|
|
913
|
+
*
|
|
914
|
+
* Identical to {@link parseFile} but accepts a source string instead of a
|
|
915
|
+
* file path. Primarily used in tests and tooling that constructs source
|
|
916
|
+
* programmatically.
|
|
917
|
+
*
|
|
918
|
+
* @param sourceText - Raw TypeScript source code to parse.
|
|
919
|
+
* @param filename - Virtual filename used to determine the parser language
|
|
920
|
+
* mode (`.ts`, `.tsx`, `.js`, `.jsx`) and to populate `filePath` fields in
|
|
921
|
+
* the result. Defaults to `'test.ts'`.
|
|
922
|
+
* @returns A {@link FileScanResult} containing classes, errors, type aliases,
|
|
923
|
+
* and SMRT import metadata extracted from the source text.
|
|
924
|
+
*
|
|
925
|
+
* @example
|
|
926
|
+
* ```typescript
|
|
927
|
+
* import { parseSource } from '@happyvertical/smrt-scanner';
|
|
928
|
+
*
|
|
929
|
+
* const src = `
|
|
930
|
+
* import { smrt } from '@happyvertical/smrt-core';
|
|
931
|
+
* @smrt()
|
|
932
|
+
* export class Widget extends SmrtObject {
|
|
933
|
+
* label: string = '';
|
|
934
|
+
* }
|
|
935
|
+
* `;
|
|
936
|
+
* const result = parseSource(src, 'Widget.ts');
|
|
937
|
+
* console.log(result.classes[0].className); // 'Widget'
|
|
938
|
+
* ```
|
|
939
|
+
*
|
|
940
|
+
* @see {@link parseFile} to parse a file from disk.
|
|
941
|
+
*/
|
|
942
|
+
export declare function parseSource(sourceText: string, filename?: string): FileScanResult;
|
|
943
|
+
|
|
944
|
+
declare type Pattern = Identifier | AssignmentPattern | RestElement | ObjectPattern | ArrayPattern | any;
|
|
945
|
+
|
|
946
|
+
declare interface Position {
|
|
947
|
+
line: number;
|
|
948
|
+
column: number;
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
declare interface Property extends BaseNode {
|
|
952
|
+
type: 'Property';
|
|
953
|
+
key: Expression;
|
|
954
|
+
value: Expression | Pattern;
|
|
955
|
+
kind: 'init' | 'get' | 'set';
|
|
956
|
+
method: boolean;
|
|
957
|
+
shorthand: boolean;
|
|
958
|
+
computed: boolean;
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
declare interface PropertyDefinition extends BaseNode {
|
|
962
|
+
type: 'PropertyDefinition';
|
|
963
|
+
key: Expression;
|
|
964
|
+
value: Expression | null;
|
|
965
|
+
computed: boolean;
|
|
966
|
+
static: boolean;
|
|
967
|
+
readonly?: boolean;
|
|
968
|
+
optional?: boolean;
|
|
969
|
+
accessibility?: 'public' | 'private' | 'protected';
|
|
970
|
+
typeAnnotation?: TSTypeAnnotation;
|
|
971
|
+
decorators?: Decorator[];
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
/**
|
|
975
|
+
* Qualified class name format: "@package/name:ClassName"
|
|
976
|
+
* Uniquely identifies classes across packages.
|
|
977
|
+
*/
|
|
978
|
+
declare type QualifiedClassName = `${string}:${string}`;
|
|
979
|
+
|
|
980
|
+
/**
|
|
981
|
+
* Type definitions for OXC-based SMRT scanner
|
|
982
|
+
*
|
|
983
|
+
* This module defines:
|
|
984
|
+
* 1. Raw types - Intermediate representation from OXC parsing (Phase 1)
|
|
985
|
+
* 2. Resolved types - After inheritance resolution (Phase 2)
|
|
986
|
+
* 3. Re-exports of smrt-core types for compatibility
|
|
987
|
+
*/
|
|
988
|
+
/**
|
|
989
|
+
* Raw class definition extracted from OXC AST
|
|
990
|
+
* Contains only syntactic information, no semantic resolution
|
|
991
|
+
*/
|
|
992
|
+
export declare interface RawClassDefinition {
|
|
993
|
+
/** Class name as declared in source */
|
|
994
|
+
className: string;
|
|
995
|
+
/** Absolute path to source file */
|
|
996
|
+
filePath: string;
|
|
997
|
+
/** Parent class name from extends clause (null if none) */
|
|
998
|
+
extendsClause: string | null;
|
|
999
|
+
/** Generic type argument from extends (e.g., "Meeting" from SmrtCollection<Meeting>) */
|
|
1000
|
+
extendsTypeArg: string | null;
|
|
1001
|
+
/** Parsed @smrt() decorator configuration object */
|
|
1002
|
+
decoratorConfig: RawDecoratorConfig | null;
|
|
1003
|
+
/** Has @smrt() decorator */
|
|
1004
|
+
hasSmartDecorator: boolean;
|
|
1005
|
+
/** Class properties/fields */
|
|
1006
|
+
fields: RawFieldDefinition[];
|
|
1007
|
+
/** Class methods */
|
|
1008
|
+
methods: RawMethodDefinition[];
|
|
1009
|
+
/** Start line in source file */
|
|
1010
|
+
startLine: number;
|
|
1011
|
+
/** End line in source file */
|
|
1012
|
+
endLine: number;
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
/**
|
|
1016
|
+
* Raw decorator information
|
|
1017
|
+
*/
|
|
1018
|
+
export declare interface RawDecorator {
|
|
1019
|
+
/** Decorator name (e.g., "field", "foreignKey") */
|
|
1020
|
+
name: string;
|
|
1021
|
+
/** Raw arguments as strings */
|
|
1022
|
+
arguments: string[];
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
/**
|
|
1026
|
+
* Raw @smrt() decorator configuration
|
|
1027
|
+
*/
|
|
1028
|
+
export declare interface RawDecoratorConfig {
|
|
1029
|
+
/** Table strategy: 'sti' | 'cti' */
|
|
1030
|
+
tableStrategy?: 'sti' | 'cti';
|
|
1031
|
+
/** Storage type for the generated id primary key */
|
|
1032
|
+
idType?: 'uuid' | 'text';
|
|
1033
|
+
/** Code-owned feature toggle declarations */
|
|
1034
|
+
features?: Record<string, {
|
|
1035
|
+
defaultEnabled: boolean;
|
|
1036
|
+
label?: string;
|
|
1037
|
+
description?: string;
|
|
1038
|
+
metadata?: Record<string, unknown>;
|
|
1039
|
+
}>;
|
|
1040
|
+
/** API configuration */
|
|
1041
|
+
api?: {
|
|
1042
|
+
include?: string[];
|
|
1043
|
+
exclude?: string[];
|
|
1044
|
+
};
|
|
1045
|
+
/** CLI configuration */
|
|
1046
|
+
cli?: boolean | {
|
|
1047
|
+
include?: string[];
|
|
1048
|
+
exclude?: string[];
|
|
1049
|
+
skipApiCheck?: boolean;
|
|
1050
|
+
http?: boolean;
|
|
1051
|
+
};
|
|
1052
|
+
/** MCP configuration */
|
|
1053
|
+
mcp?: {
|
|
1054
|
+
include?: string[];
|
|
1055
|
+
exclude?: string[];
|
|
1056
|
+
};
|
|
1057
|
+
/** Raw config object for unknown properties */
|
|
1058
|
+
[key: string]: unknown;
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
/**
|
|
1062
|
+
* Raw field definition from OXC AST
|
|
1063
|
+
*/
|
|
1064
|
+
export declare interface RawFieldDefinition {
|
|
1065
|
+
/** Field name */
|
|
1066
|
+
name: string;
|
|
1067
|
+
/** TypeScript type annotation as string (e.g., "string", "number", "Date") */
|
|
1068
|
+
typeAnnotation: string | null;
|
|
1069
|
+
/** Raw initializer expression as string */
|
|
1070
|
+
initializer: string | null;
|
|
1071
|
+
/** For numeric literals: whether it contains a decimal point */
|
|
1072
|
+
hasDecimalPoint: boolean;
|
|
1073
|
+
/** For numeric literals: the actual numeric value */
|
|
1074
|
+
numericValue: number | null;
|
|
1075
|
+
/** Decorators applied to this field */
|
|
1076
|
+
decorators: RawDecorator[];
|
|
1077
|
+
/** Whether field is optional (has ?) */
|
|
1078
|
+
optional: boolean;
|
|
1079
|
+
/** Whether field is static */
|
|
1080
|
+
isStatic: boolean;
|
|
1081
|
+
/** Whether field is readonly */
|
|
1082
|
+
readonly: boolean;
|
|
1083
|
+
/** Whether field is private/protected */
|
|
1084
|
+
accessibility: 'public' | 'private' | 'protected';
|
|
1085
|
+
/** Start line in source */
|
|
1086
|
+
line: number;
|
|
1087
|
+
}
|
|
1088
|
+
|
|
1089
|
+
/**
|
|
1090
|
+
* Raw method definition from OXC AST
|
|
1091
|
+
*/
|
|
1092
|
+
export declare interface RawMethodDefinition {
|
|
1093
|
+
/** Method name */
|
|
1094
|
+
name: string;
|
|
1095
|
+
/** Whether method is async */
|
|
1096
|
+
async: boolean;
|
|
1097
|
+
/** Whether method is static */
|
|
1098
|
+
isStatic: boolean;
|
|
1099
|
+
/** Accessibility modifier */
|
|
1100
|
+
accessibility: 'public' | 'private' | 'protected';
|
|
1101
|
+
/** Method parameters */
|
|
1102
|
+
parameters: RawParameterDefinition[];
|
|
1103
|
+
/** Return type annotation as string */
|
|
1104
|
+
returnType: string | null;
|
|
1105
|
+
/** JSDoc description if present */
|
|
1106
|
+
description: string | null;
|
|
1107
|
+
/** Start line in source */
|
|
1108
|
+
line: number;
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
/**
|
|
1112
|
+
* Raw parameter definition
|
|
1113
|
+
*/
|
|
1114
|
+
export declare interface RawParameterDefinition {
|
|
1115
|
+
/** Parameter name */
|
|
1116
|
+
name: string;
|
|
1117
|
+
/** Type annotation as string */
|
|
1118
|
+
type: string | null;
|
|
1119
|
+
/** Whether parameter is optional */
|
|
1120
|
+
optional: boolean;
|
|
1121
|
+
/** Default value as string */
|
|
1122
|
+
defaultValue: string | null;
|
|
1123
|
+
}
|
|
1124
|
+
|
|
1125
|
+
/**
|
|
1126
|
+
* Resolved class definition with inheritance chain
|
|
1127
|
+
*/
|
|
1128
|
+
export declare interface ResolvedClassDefinition extends RawClassDefinition {
|
|
1129
|
+
/** Full inheritance chain from base to this class */
|
|
1130
|
+
inheritanceChain: string[];
|
|
1131
|
+
/** STI base class name (if part of STI hierarchy) */
|
|
1132
|
+
stiBase: string | null;
|
|
1133
|
+
/** Effective table strategy (inherited or declared) */
|
|
1134
|
+
effectiveTableStrategy: 'sti' | 'cti';
|
|
1135
|
+
/** Whether this class uses STI (convenience boolean) */
|
|
1136
|
+
isSTI: boolean;
|
|
1137
|
+
/** Whether this class is a framework base class */
|
|
1138
|
+
isFrameworkBase: boolean;
|
|
1139
|
+
/** All fields including inherited (for STI) */
|
|
1140
|
+
allFields: RawFieldDefinition[];
|
|
1141
|
+
/** Package this class belongs to (if external) */
|
|
1142
|
+
packageName: string | null;
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1145
|
+
declare interface RestElement extends BaseNode {
|
|
1146
|
+
type: 'RestElement';
|
|
1147
|
+
argument: Pattern;
|
|
1148
|
+
typeAnnotation?: TSTypeAnnotation;
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1151
|
+
/**
|
|
1152
|
+
* Scan error
|
|
1153
|
+
*/
|
|
1154
|
+
export declare interface ScanError {
|
|
1155
|
+
/** Error message */
|
|
1156
|
+
message: string;
|
|
1157
|
+
/** Source file */
|
|
1158
|
+
filePath: string;
|
|
1159
|
+
/** Line number (1-based) */
|
|
1160
|
+
line?: number;
|
|
1161
|
+
/** Column number (1-based) */
|
|
1162
|
+
column?: number;
|
|
1163
|
+
/** Error severity */
|
|
1164
|
+
severity: 'error' | 'warning';
|
|
1165
|
+
}
|
|
1166
|
+
|
|
1167
|
+
/**
|
|
1168
|
+
* Result from scanning multiple files
|
|
1169
|
+
*/
|
|
1170
|
+
export declare interface ScanResults {
|
|
1171
|
+
/** All scanned files */
|
|
1172
|
+
files: FileScanResult[];
|
|
1173
|
+
/** All classes found (flattened) */
|
|
1174
|
+
classes: RawClassDefinition[];
|
|
1175
|
+
/** All errors (flattened) */
|
|
1176
|
+
errors: ScanError[];
|
|
1177
|
+
/** Total parse time in milliseconds */
|
|
1178
|
+
totalParseTimeMs: number;
|
|
1179
|
+
/** Number of files scanned */
|
|
1180
|
+
fileCount: number;
|
|
1181
|
+
/** Accumulated type aliases across all files */
|
|
1182
|
+
typeAliases: Record<string, string>;
|
|
1183
|
+
/** Accumulated SMRT package imports across all files (package name → Set of imported class names) */
|
|
1184
|
+
smrtImports?: Map<string, Set<string>>;
|
|
1185
|
+
}
|
|
1186
|
+
|
|
1187
|
+
declare interface SmartObjectConfig {
|
|
1188
|
+
tableStrategy?: 'sti' | 'cti';
|
|
1189
|
+
idType?: 'uuid' | 'text';
|
|
1190
|
+
features?: Record<string, {
|
|
1191
|
+
defaultEnabled: boolean;
|
|
1192
|
+
label?: string;
|
|
1193
|
+
description?: string;
|
|
1194
|
+
metadata?: Record<string, unknown>;
|
|
1195
|
+
}>;
|
|
1196
|
+
api?: {
|
|
1197
|
+
include?: string[];
|
|
1198
|
+
exclude?: string[];
|
|
1199
|
+
};
|
|
1200
|
+
cli?: boolean | {
|
|
1201
|
+
include?: string[];
|
|
1202
|
+
exclude?: string[];
|
|
1203
|
+
skipApiCheck?: boolean;
|
|
1204
|
+
http?: boolean;
|
|
1205
|
+
};
|
|
1206
|
+
mcp?: {
|
|
1207
|
+
include?: string[];
|
|
1208
|
+
exclude?: string[];
|
|
1209
|
+
};
|
|
1210
|
+
[key: string]: unknown;
|
|
1211
|
+
}
|
|
1212
|
+
|
|
1213
|
+
declare interface SmartObjectDefinition {
|
|
1214
|
+
name: string;
|
|
1215
|
+
className: string;
|
|
1216
|
+
qualifiedName?: QualifiedClassName;
|
|
1217
|
+
collection: string;
|
|
1218
|
+
filePath: string;
|
|
1219
|
+
packageName?: string;
|
|
1220
|
+
packageVersion?: string;
|
|
1221
|
+
importPath?: string;
|
|
1222
|
+
modulePath?: string;
|
|
1223
|
+
exportName?: string;
|
|
1224
|
+
collectionExportName?: string;
|
|
1225
|
+
fields: Record<string, FieldDefinition>;
|
|
1226
|
+
methods: Record<string, MethodDefinition>;
|
|
1227
|
+
decoratorConfig: SmartObjectConfig;
|
|
1228
|
+
extends?: string;
|
|
1229
|
+
extendsTypeArg?: string;
|
|
1230
|
+
staticProperties?: Record<string, any>;
|
|
1231
|
+
}
|
|
1232
|
+
|
|
1233
|
+
declare interface SmartObjectManifest {
|
|
1234
|
+
version: string;
|
|
1235
|
+
timestamp: number;
|
|
1236
|
+
packageName?: string;
|
|
1237
|
+
packageVersion?: string;
|
|
1238
|
+
objects: Record<string, SmartObjectDefinition>;
|
|
1239
|
+
moduleType?: string;
|
|
1240
|
+
smrtDependencies?: string[];
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1243
|
+
declare interface SourceLocation {
|
|
1244
|
+
start: Position;
|
|
1245
|
+
end: Position;
|
|
1246
|
+
}
|
|
1247
|
+
|
|
1248
|
+
declare interface SpreadElement extends BaseNode {
|
|
1249
|
+
type: 'SpreadElement';
|
|
1250
|
+
argument: Expression;
|
|
1251
|
+
}
|
|
1252
|
+
|
|
1253
|
+
declare type Statement = ClassDeclaration | ExportNamedDeclaration | ExportDefaultDeclaration | ImportDeclaration | any;
|
|
1254
|
+
|
|
1255
|
+
declare interface TSAnyKeyword extends BaseNode {
|
|
1256
|
+
type: 'TSAnyKeyword';
|
|
1257
|
+
}
|
|
1258
|
+
|
|
1259
|
+
declare interface TSArrayType extends BaseNode {
|
|
1260
|
+
type: 'TSArrayType';
|
|
1261
|
+
elementType: TSType;
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
declare interface TSBooleanKeyword extends BaseNode {
|
|
1265
|
+
type: 'TSBooleanKeyword';
|
|
1266
|
+
}
|
|
1267
|
+
|
|
1268
|
+
declare interface TSIndexSignature extends BaseNode {
|
|
1269
|
+
type: 'TSIndexSignature';
|
|
1270
|
+
parameters: Identifier[];
|
|
1271
|
+
typeAnnotation?: TSTypeAnnotation;
|
|
1272
|
+
}
|
|
1273
|
+
|
|
1274
|
+
declare interface TSMethodSignature extends BaseNode {
|
|
1275
|
+
type: 'TSMethodSignature';
|
|
1276
|
+
key: Expression;
|
|
1277
|
+
params: Pattern[];
|
|
1278
|
+
returnType?: TSTypeAnnotation;
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
declare interface TSNullKeyword extends BaseNode {
|
|
1282
|
+
type: 'TSNullKeyword';
|
|
1283
|
+
}
|
|
1284
|
+
|
|
1285
|
+
declare interface TSNumberKeyword extends BaseNode {
|
|
1286
|
+
type: 'TSNumberKeyword';
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1289
|
+
declare interface TSPropertySignature extends BaseNode {
|
|
1290
|
+
type: 'TSPropertySignature';
|
|
1291
|
+
key: Expression;
|
|
1292
|
+
typeAnnotation?: TSTypeAnnotation;
|
|
1293
|
+
optional?: boolean;
|
|
1294
|
+
readonly?: boolean;
|
|
1295
|
+
}
|
|
1296
|
+
|
|
1297
|
+
declare interface TSQualifiedName extends BaseNode {
|
|
1298
|
+
type: 'TSQualifiedName';
|
|
1299
|
+
left: Identifier | TSQualifiedName;
|
|
1300
|
+
right: Identifier;
|
|
1301
|
+
}
|
|
1302
|
+
|
|
1303
|
+
declare interface TSStringKeyword extends BaseNode {
|
|
1304
|
+
type: 'TSStringKeyword';
|
|
1305
|
+
}
|
|
1306
|
+
|
|
1307
|
+
declare type TSType = TSStringKeyword | TSNumberKeyword | TSBooleanKeyword | TSAnyKeyword | TSVoidKeyword | TSNullKeyword | TSUndefinedKeyword | TSTypeReference | TSArrayType | TSUnionType | TSTypeLiteral | any;
|
|
1308
|
+
|
|
1309
|
+
declare interface TSTypeAnnotation extends BaseNode {
|
|
1310
|
+
type: 'TSTypeAnnotation';
|
|
1311
|
+
typeAnnotation: TSType;
|
|
1312
|
+
}
|
|
1313
|
+
|
|
1314
|
+
declare type TSTypeElement = TSPropertySignature | TSMethodSignature | TSIndexSignature | any;
|
|
1315
|
+
|
|
1316
|
+
declare interface TSTypeLiteral extends BaseNode {
|
|
1317
|
+
type: 'TSTypeLiteral';
|
|
1318
|
+
members: TSTypeElement[];
|
|
1319
|
+
}
|
|
1320
|
+
|
|
1321
|
+
declare interface TSTypeParameterInstantiation extends BaseNode {
|
|
1322
|
+
type: 'TSTypeParameterInstantiation';
|
|
1323
|
+
params: TSType[];
|
|
1324
|
+
}
|
|
1325
|
+
|
|
1326
|
+
declare interface TSTypeReference extends BaseNode {
|
|
1327
|
+
type: 'TSTypeReference';
|
|
1328
|
+
typeName: Identifier | TSQualifiedName;
|
|
1329
|
+
typeParameters?: TSTypeParameterInstantiation;
|
|
1330
|
+
}
|
|
1331
|
+
|
|
1332
|
+
declare interface TSUndefinedKeyword extends BaseNode {
|
|
1333
|
+
type: 'TSUndefinedKeyword';
|
|
1334
|
+
}
|
|
1335
|
+
|
|
1336
|
+
declare interface TSUnionType extends BaseNode {
|
|
1337
|
+
type: 'TSUnionType';
|
|
1338
|
+
types: TSType[];
|
|
1339
|
+
}
|
|
1340
|
+
|
|
1341
|
+
declare interface TSVoidKeyword extends BaseNode {
|
|
1342
|
+
type: 'TSVoidKeyword';
|
|
1343
|
+
}
|
|
1344
|
+
|
|
1345
|
+
/**
|
|
1346
|
+
* Verify that `dist/manifest.json` contains every `@smrt()` object declared in
|
|
1347
|
+
* the package source. See module docs for the rationale and guarantees.
|
|
1348
|
+
*/
|
|
1349
|
+
export declare function verifyManifestCompleteness(options: VerifyManifestCompletenessOptions): Promise<VerifyManifestCompletenessResult>;
|
|
1350
|
+
|
|
1351
|
+
export declare interface VerifyManifestCompletenessOptions {
|
|
1352
|
+
/** Absolute or relative path to the package directory to verify. */
|
|
1353
|
+
packageDir: string;
|
|
1354
|
+
/** Source include globs (default mirrors the build). */
|
|
1355
|
+
include?: string[];
|
|
1356
|
+
/** Source exclude globs (default mirrors the build). */
|
|
1357
|
+
exclude?: string[];
|
|
1358
|
+
/** Package directory basenames to skip (default: framework infrastructure). */
|
|
1359
|
+
skipPackages?: string[];
|
|
1360
|
+
}
|
|
1361
|
+
|
|
1362
|
+
export declare interface VerifyManifestCompletenessResult {
|
|
1363
|
+
status: VerifyManifestStatus;
|
|
1364
|
+
packageName?: string;
|
|
1365
|
+
manifestPath?: string;
|
|
1366
|
+
/** Qualified object keys present in source but missing from the manifest. */
|
|
1367
|
+
missing: string[];
|
|
1368
|
+
/** Number of objects the source is expected to contribute. */
|
|
1369
|
+
expectedCount: number;
|
|
1370
|
+
/** Number of objects present in the published manifest. */
|
|
1371
|
+
distCount: number;
|
|
1372
|
+
/** Human-readable explanation for `skipped` / `missing-manifest`. */
|
|
1373
|
+
reason?: string;
|
|
1374
|
+
}
|
|
1375
|
+
|
|
1376
|
+
/**
|
|
1377
|
+
* Manifest completeness verification.
|
|
1378
|
+
*
|
|
1379
|
+
* Re-scans a package's `src/` with the same OXC scanner the build uses and
|
|
1380
|
+
* asserts that every `@smrt()`-decorated object (and its collection) is present
|
|
1381
|
+
* in the package's published `dist/manifest.json`. This is a publish-time guard:
|
|
1382
|
+
* downstream schema migration is manifest-driven, so a stale manifest that omits
|
|
1383
|
+
* an object means consumers can never create its table via `smrt db:migrate`.
|
|
1384
|
+
*
|
|
1385
|
+
* Root cause it guards against (issue #1483): `@happyvertical/smrt-jobs@0.27.41`
|
|
1386
|
+
* shipped a `dist/manifest.json` generated before `SmrtWorker` existed. The
|
|
1387
|
+
* source, exports, and `__smrt-register__` path were all correct, but the
|
|
1388
|
+
* published manifest had only 4 of 6 objects, so `_smrt_workers` was never
|
|
1389
|
+
* created and `TaskRunner.start()` threw on every consumer that upgraded.
|
|
1390
|
+
*
|
|
1391
|
+
* The check compares object-key SETS only. The downstream manifest-enrichment
|
|
1392
|
+
* passes (schema/validation/agent generation) mutate object entries but never
|
|
1393
|
+
* add or remove object keys, so the scanner + adapter object set is the source
|
|
1394
|
+
* of truth for "which objects the published manifest must contain". The
|
|
1395
|
+
* comparison is `expected ⊆ dist`: enrichment passes that add keys to `dist`
|
|
1396
|
+
* (e.g. STI children) never trigger a false failure.
|
|
1397
|
+
*
|
|
1398
|
+
* Parse errors are handled before the set comparison: a syntactically broken
|
|
1399
|
+
* source file drops its objects from `expected` AND `dist` symmetrically, which
|
|
1400
|
+
* a naive `expected ⊆ dist` would wave through as `ok`. The scan's
|
|
1401
|
+
* `severity:'error'` entries therefore short-circuit to a distinct `scan-error`
|
|
1402
|
+
* status so a broken source can never masquerade as a complete manifest.
|
|
1403
|
+
*
|
|
1404
|
+
* @see https://github.com/happyvertical/smrt/issues/1483
|
|
1405
|
+
*/
|
|
1406
|
+
export declare type VerifyManifestStatus = 'ok' | 'incomplete' | 'missing-manifest' | 'scan-error' | 'skipped';
|
|
1407
|
+
|
|
1408
|
+
export { }
|