@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.
@@ -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 { }