@mnemonica/tactica 0.3.15 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -41,6 +41,8 @@ npm install --save-dev @mnemonica/tactica
41
41
 
42
42
  `mnemonica` is a peer dependency (>= 1.0.1).
43
43
 
44
+ Tactica bundles its own TypeScript compiler (6.x) as a regular dependency, so it installs and runs regardless of the TypeScript version your project uses — including TypeScript 7, whose npm package no longer exposes the classic compiler API. Your `tsconfig.json` is only ever *parsed* (never emitted), so TS5-era options like `baseUrl` keep working even though TS6 marks them deprecated.
45
+
44
46
  ## Usage
45
47
 
46
48
  ### CLI
@@ -251,7 +253,7 @@ These usage shapes are recognized and attributed within the existing output cont
251
253
  - **`call(entity, Ctor, ...)` / `apply(entity, Ctor, args)`** — the mnemonica construction exports (import-aware: only actual `'mnemonica'` imports or members of a tracked module-object alias match; userland `call`/`apply` never do). The Ctor argument (arg 1) records an `instantiation`, and the result variable binds to the Ctor's type (runtime `InstanceResult<Merge<E, T>>` approximated by T). **Decorated classes resolve as the Ctor** through the same graph tiers — `@decorate() class C` is a known type, so `call(parent, C)` records and binds; an undecorated plain class has no graph entry, so the call binds nothing and records no usage (never a bare name). The free-call `decorate(Class)` form is not tracked (tactica recognizes the `@decorate` decorator syntax only).
252
254
  - **`bind(entity, Ctor)`** — records no usage (it constructs nothing); the bound variable binds to the Ctor's type. Invoking the bound function later (`f(...)`, including `await f(...)`) is not followed.
253
255
 
254
- Two boundaries stay deliberate: bindings surface only for references lexically AFTER the binding statement (a binding made inside a constructor body is not yet visible to that same handler's property extraction), and the mechanism distinction (`new` vs fork vs call) is not carried in the outputs — fork/clone/merge record as plain `instantiation` entries, byte-indistinguishable from `new`, until the deferred mechanism-kind contract revision lands. Consumers counting constructions should expect fork sites among them.
256
+ Three boundaries stay deliberate: bindings surface only for references lexically AFTER the binding statement (a binding made inside a constructor body is not yet visible to that same handler's property extraction); a construction nested inside a class or function body of the initializer does not bind the outer variable (`const X = define('X', class { m = new Map() })` binds X to the defined type, never to `Map` — scope boundaries are not crossed); and the mechanism distinction (`new` vs fork vs call) is not carried in the outputs — fork/clone/merge record as plain `instantiation` entries, byte-indistinguishable from `new`, until the deferred mechanism-kind contract revision lands. Consumers counting constructions should expect fork sites among them.
255
257
 
256
258
  ### Builder pattern on the imported module object
257
259
 
@@ -359,7 +361,7 @@ Tactica then emits:
359
361
  - Prefixed instance types in `.tactica/types.ts`, e.g. `AppCollectionRegistry_UserType` and `AppCollectionRegistry_UserType_AdminType`.
360
362
  - A `declare module '<relative path to this file>'` block in `.tactica/registry.ts` that augments `AppCollectionRegistry` with `'UserType'` and `'UserType.AdminType'` entries.
361
363
 
362
- Once `.tactica/registry.ts` is part of your `tsc` compilation, `AppCollection.lookup('UserType')` and `AppCollection.lookup('UserType.AdminType')` are fully typed.
364
+ Once `.tactica/registry.ts` is part of your `tsc` compilation, `AppCollection.lookup('UserType')` and `AppCollection.lookup('UserType.AdminType')` are fully typed. Constructor-relative lookups resolve too: a variable bound to `AppCollection.lookup('UserType')` resolves `.lookup('AdminType')` relative-first (the type's own subtypes, then the collection root) — the same law as for default-collection types.
363
365
 
364
366
  Custom collections also support `decorate()` for root types:
365
367
 
@@ -473,7 +475,7 @@ The analyzer infers property types from constructor bodies and class members. Su
473
475
  | `this.x = []` / `new Array()` | `Array<…>` |
474
476
  | `this.x = {}` | `object` |
475
477
  | `this.x = new Date()` | `Date` |
476
- | `this.x = new Map()` / `new Set()` | `Map<…>` / `Set<…>` |
478
+ | `this.x = new Map()` / `new Set()` | `Map<unknown, unknown>` / `Set<unknown>` — a bare generic is never emitted (TS2314); explicit arguments survive: `new Map<string, number>()` → `Map<string, number>` |
477
479
  | `this.x = Date.now()` | `number` |
478
480
  | `this.x = parseInt(…)` / `parseFloat(…)` | `number` |
479
481
  | `this.x = String(…)` / `Number(…)` / `Boolean(…)` | `string` / `number` / `boolean` |
@@ -907,7 +909,7 @@ Deliberate approximations (name-based, no type checker): namespace imports count
907
909
  1. **Parse** — load `tsconfig.json`, build a `ts.Program`, walk each source file's AST.
908
910
  2. **Detect** — find `define()` and `@decorate()` calls, plus `lookup` lookups, `new` expressions, and EDS / flow patterns.
909
911
  3. **Graph** — build a Trie of types in `TypeGraphImpl`, with parent links via the chain of `.define()` calls and `@decorate(Parent)` references.
910
- 4. **Generate** — emit `types.ts`, `registry.ts`, `index.ts` (default mode) or `index.d.ts` (legacy mode), plus `definitions.json`, `usages.json` (with `holderScopeId`), `flow.json`, `instrumentation.json`, `modules.json`, `scopes.json`, `hierarchy.json`/`hierarchy.txt`, and optionally `eds.json`.
912
+ 4. **Generate** — emit `types.ts`, `registry.ts`, `index.ts` (default mode) or `index.d.ts` (legacy mode), plus `definitions.json`, `usages.json` (with `holderScopeId`), `flow.json`, `instrumentation.json`, `modules.json`, `scopes.json`, `hierarchy.json`/`hierarchy.txt`, `collections.json`, and optionally `eds.json`.
911
913
  5. **Write** — files land in the output directory (default `.tactica/`).
912
914
 
913
915
  ```
package/lib/analyzer.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as ts from 'typescript';
2
- import { AnalyzeResult, DefinitionInfo, UsageInfo, EDSInfo, FlowInfo, InstrumentationPoint, ResolutionError } from './types';
2
+ import { AnalyzeResult, DefinitionInfo, UsageInfo, EDSInfo, FlowInfo, InstrumentationPoint, ResolutionError, CollectionManifestEntry } from './types';
3
3
  import { TypeGraphImpl } from './graph';
4
4
  import { TacticaPlugin } from './plugins';
5
5
  /**
@@ -73,6 +73,14 @@ export declare class MnemonicaAnalyzer {
73
73
  * Get collected definitions
74
74
  */
75
75
  getDefinitions(): Map<string, DefinitionInfo>;
76
+ /**
77
+ * The collections.json manifest: one entry per minted collection, in
78
+ * minting order, preceded by the default-collection entry whenever
79
+ * default-collection types exist. The default entry has no id/location
80
+ * (there is no call site — unprefixed fullPaths are its identity) and
81
+ * its registry interface is the global TypeRegistry.
82
+ */
83
+ getCollectionsManifest(): CollectionManifestEntry[];
76
84
  /**
77
85
  * Get collected usages
78
86
  */
@@ -251,6 +259,14 @@ export declare class MnemonicaAnalyzer {
251
259
  */
252
260
  private expandReferencedTypeDeclaration;
253
261
  private expandReferencedTypeDeclarationInner;
262
+ /**
263
+ * Emitted instance-type alias for a graph node — the name types.ts /
264
+ * registry.ts actually declare. Option B collection types carry their
265
+ * registry interface prefix; collection types WITHOUT a registry
266
+ * interface are never emitted, so no valid alias exists for them
267
+ * (undefined — callers degrade to `unknown`, never a bare name).
268
+ */
269
+ private getEmittedInstanceTypeName;
254
270
  /**
255
271
  * Resolve a simple (non-qualified) type reference: import-aware
256
272
  * declaration expansion first, then the InstanceType<typeof X> pattern,
@@ -403,9 +419,14 @@ export declare class MnemonicaAnalyzer {
403
419
  */
404
420
  private extractRegistryInterfaceName;
405
421
  /**
406
- * Get the registry interface name for a collection id.
422
+ * Stamp a node with its collection's emission info: the Option B registry
423
+ * interface name and the collection's home file — the module the generated
424
+ * augmentation must target (the interface is confirmed declared there).
425
+ * A type's own sourceFile is NOT the target: multi-file collections define
426
+ * types across many modules while the interface lives at the
427
+ * createTypesCollection() call site.
407
428
  */
408
- private getRegistryInterfaceName;
429
+ private applyCollectionEmissionInfo;
409
430
  /**
410
431
  * Check if an expression is a createTypesCollection() call.
411
432
  * Handles: