@alveolus/arch 0.5.0 → 0.6.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/dist/index.d.mts CHANGED
@@ -76,6 +76,9 @@ interface MemberProps {
76
76
  readonly parameterTypes: readonly ClassType[];
77
77
  readonly returns: ReturnShape | undefined;
78
78
  readonly holdsCollection: boolean;
79
+ readonly receivesFunction: boolean;
80
+ readonly erasedType: string | undefined;
81
+ readonly opaqueValue: string | undefined;
79
82
  }
80
83
  declare class Member {
81
84
  readonly name: string;
@@ -90,6 +93,9 @@ declare class Member {
90
93
  readonly parameterTypes: readonly ClassType[];
91
94
  readonly returns: ReturnShape | undefined;
92
95
  readonly holdsCollection: boolean;
96
+ readonly receivesFunction: boolean;
97
+ readonly erasedType: string | undefined;
98
+ readonly opaqueValue: string | undefined;
93
99
  constructor(props: MemberProps);
94
100
  get isPublicInstance(): boolean;
95
101
  get isField(): boolean;
@@ -144,6 +150,15 @@ declare class Dependency {
144
150
  isOnPackage(name: string): boolean;
145
151
  }
146
152
  //#endregion
153
+ //#region src/model/dependencies/global-channel.d.ts
154
+ type GlobalAccess = "reads" | "writes";
155
+ declare class GlobalChannel {
156
+ readonly line: number;
157
+ readonly name: string;
158
+ readonly access: GlobalAccess;
159
+ constructor(line: number, name: string, access: GlobalAccess);
160
+ }
161
+ //#endregion
147
162
  //#region src/model/dependencies/global-use.d.ts
148
163
  type GlobalOrigin = "ecmascript" | "host";
149
164
  type GlobalEffect = "clock" | "randomness";
@@ -155,6 +170,15 @@ declare class GlobalUse {
155
170
  constructor(line: number, name: string, origin: GlobalOrigin, effect: GlobalEffect | undefined);
156
171
  }
157
172
  //#endregion
173
+ //#region src/model/dependencies/module-reach.d.ts
174
+ declare class ModuleReach {
175
+ readonly line: number;
176
+ readonly expression: string;
177
+ readonly means: string;
178
+ readonly module: ClassType;
179
+ constructor(line: number, expression: string, means: string, module: ClassType);
180
+ }
181
+ //#endregion
158
182
  //#region src/model/dependencies/wiring.d.ts
159
183
  interface WiringLink {
160
184
  readonly text: string;
@@ -202,7 +226,9 @@ interface SourceFileProps {
202
226
  readonly statements: readonly TopLevelStatement[];
203
227
  readonly throws: readonly Throw[];
204
228
  readonly globals: readonly GlobalUse[];
229
+ readonly globalChannels: readonly GlobalChannel[];
205
230
  readonly wirings: readonly Wiring[];
231
+ readonly moduleReaches: readonly ModuleReach[];
206
232
  readonly disables: readonly DisableComment[];
207
233
  }
208
234
  declare class SourceFile {
@@ -212,7 +238,9 @@ declare class SourceFile {
212
238
  readonly statements: readonly TopLevelStatement[];
213
239
  readonly throws: readonly Throw[];
214
240
  readonly globals: readonly GlobalUse[];
241
+ readonly globalChannels: readonly GlobalChannel[];
215
242
  readonly wirings: readonly Wiring[];
243
+ readonly moduleReaches: readonly ModuleReach[];
216
244
  readonly disables: readonly DisableComment[];
217
245
  private readonly lines;
218
246
  constructor(props: SourceFileProps);
@@ -505,6 +533,7 @@ export declare class TsMorphImporter extends Importer {
505
533
  private readonly statements;
506
534
  private readonly disables;
507
535
  private readonly throws;
536
+ private readonly globalChannels;
508
537
  constructor(sources: Project);
509
538
  static fromTsConfig(tsConfigFilePath: string): TsMorphImporter;
510
539
  resolves(packageName: string, scope: ImportScope): boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":["Project","FileTarget","Project","Project","MorphProject","Project"],"sources":["../src/architecture/allowed-packages.ts","../src/conventions/core-api.ts","../src/conventions/layers.ts","../src/conventions/building-blocks.ts","../src/model/classes/named-type.ts","../src/model/classes/class-type.ts","../src/model/classes/heritage.ts","../src/model/classes/return-shape.ts","../src/model/classes/member.ts","../src/model/classes/class-declaration.ts","../src/model/dependencies/dependency.ts","../src/model/dependencies/global-use.ts","../src/model/dependencies/wiring.ts","../src/model/statements/disable-comment.ts","../src/model/statements/throw.ts","../src/model/statements/top-level-statement.ts","../src/model/source-file.ts","../src/model/project.ts","../src/architecture/core-api.ts","../src/architecture/context-map.ts","../src/architecture/settings.ts","../src/architecture/paths/location.ts","../src/architecture/paths/place.ts","../src/architecture/building-blocks.ts","../src/architecture/crossing.ts","../src/architecture/layers.ts","../src/architecture/paths/layer-shape.ts","../src/architecture/architecture.ts","../src/rules/framework/finding.ts","../src/rules/framework/wording.ts","../src/rules/framework/rule.ts","../src/rules/tooling/no-loose-disable.rule.ts","../src/rules/registry.ts","../src/check/violation.ts","../src/check/baseline.ts","../src/importer/importer.ts","../src/importer/ts-morph/ts-morph-importer.ts","../src/check/checker.ts","../src/check/report.ts","../src/docs/page.ts","../src/docs/docs.ts","../src/cli/cli.ts","../src/config/alveolus-config.ts","../src/config/config.ts","../src/config/config-loader.ts","../src/config/define-config.ts","../src/init/init.ts"],"mappings":"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"}
1
+ {"version":3,"file":"index.d.mts","names":["Project","FileTarget","Project","Project","MorphProject","Project"],"sources":["../src/architecture/allowed-packages.ts","../src/conventions/core-api.ts","../src/conventions/layers.ts","../src/conventions/building-blocks.ts","../src/model/classes/named-type.ts","../src/model/classes/class-type.ts","../src/model/classes/heritage.ts","../src/model/classes/return-shape.ts","../src/model/classes/member.ts","../src/model/classes/class-declaration.ts","../src/model/dependencies/dependency.ts","../src/model/dependencies/global-channel.ts","../src/model/dependencies/global-use.ts","../src/model/dependencies/module-reach.ts","../src/model/dependencies/wiring.ts","../src/model/statements/disable-comment.ts","../src/model/statements/throw.ts","../src/model/statements/top-level-statement.ts","../src/model/source-file.ts","../src/model/project.ts","../src/architecture/core-api.ts","../src/architecture/context-map.ts","../src/architecture/settings.ts","../src/architecture/paths/location.ts","../src/architecture/paths/place.ts","../src/architecture/building-blocks.ts","../src/architecture/crossing.ts","../src/architecture/layers.ts","../src/architecture/paths/layer-shape.ts","../src/architecture/architecture.ts","../src/rules/framework/finding.ts","../src/rules/framework/wording.ts","../src/rules/framework/rule.ts","../src/rules/tooling/no-loose-disable.rule.ts","../src/rules/registry.ts","../src/check/violation.ts","../src/check/baseline.ts","../src/importer/importer.ts","../src/importer/ts-morph/ts-morph-importer.ts","../src/check/checker.ts","../src/check/report.ts","../src/docs/page.ts","../src/docs/docs.ts","../src/cli/cli.ts","../src/config/alveolus-config.ts","../src/config/config.ts","../src/config/config-loader.ts","../src/config/define-config.ts","../src/init/init.ts"],"mappings":"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"}
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { a as TsMorphImporter, c as Config, d as RuleRegistry, f as Rule, h as Baseline, i as Init, l as Report, m as AllowedPackages, n as Page, o as Importer, p as Architecture, r as Cli, s as ConfigLoader, t as Docs, u as Checker } from "./docs-B1Tzkjrn.mjs";
1
+ import { a as TsMorphImporter, c as Config, d as RuleRegistry, f as Rule, h as Baseline, i as Init, l as Report, m as AllowedPackages, n as Page, o as Importer, p as Architecture, r as Cli, s as ConfigLoader, t as Docs, u as Checker } from "./docs-B6M9DxTM.mjs";
2
2
  //#region src/config/define-config.ts
3
3
  function defineConfig(config) {
4
4
  return config;
@@ -265,7 +265,7 @@ npx alveolus arch check
265
265
 
266
266
  <div class="al-cards">
267
267
  <div class="al-card"><span class="al-card-title"><a href="../../rules/strategic/no-cross-context-import"><code>strategic/no-cross-context-import</code></a></span>Another context imports this class, and nothing else of the catalog.</div>
268
- <div class="al-card"><span class="al-card-title"><a href="../../rules/strategic/no-leaky-host-service"><code>strategic/no-leaky-host-service</code></a></span>It answers in the published language, never with a class of the catalog.</div>
268
+ <div class="al-card"><span class="al-card-title"><a href="../../rules/strategic/no-leaky-host-service"><code>strategic/no-leaky-host-service</code></a></span>It answers in the published language, never with a class of the catalog or an untyped result, and it receives data, never a callback.</div>
269
269
  <div class="al-card"><span class="al-card-title"><a href="../../rules/tactical/no-misplaced-class"><code>tactical/no-misplaced-class</code></a></span>It stays under <code>driving/</code>.</div>
270
270
  </div>
271
271
 
@@ -54,7 +54,7 @@ its own business. The "Applies to" line of each rule page says which it is.
54
54
  | [`strategic/no-cross-context-import`](./strategic/no-cross-context-import.md) | An import from another bounded context that is not its open host service, a file the analysis does not see, a composition root that re-exports. |
55
55
  | [`strategic/no-fat-shared-kernel`](./strategic/no-fat-shared-kernel.md) | An aggregate, a repository or a handler in the shared kernel. |
56
56
  | [`strategic/no-shared-state`](./strategic/no-shared-state.md) | A static field of the shared kernel that holds state. |
57
- | [`strategic/no-leaky-host-service`](./strategic/no-leaky-host-service.md) | An open host service that exposes a class of its context instead of the published language. |
57
+ | [`strategic/no-leaky-host-service`](./strategic/no-leaky-host-service.md) | An open host service that exposes a class of its context, receives a function or returns an erased type, instead of speaking the published language. |
58
58
  | [`strategic/no-unmapped-context`](./strategic/no-unmapped-context.md) | A context consuming one the context map does not allow, or two contexts that depend on each other. |
59
59
 
60
60
  ## Layers
@@ -142,8 +142,12 @@ root of `src/`: a test file that re-exports another context would otherwise carr
142
142
  every rule.
143
143
 
144
144
  Code loaded at runtime counts the same way, wherever it is: `node:module` (`createRequire`),
145
- `node:vm`, `module.require`, `process.getBuiltinModule`, `eval`, `Function` and `new Function`.
146
- To read a JSON file, import it: `import pkg from "../package.json" with { type: "json" }`.
145
+ `node:vm`, `module.require`, `process.getBuiltinModule`, `eval` and the `Function` constructor.
146
+ They are recognised by their type as well as by their name: an alias of `Function` or `eval`, the
147
+ `constructor` of a function (`(() => 0).constructor`, the `AsyncFunction` constructor),
148
+ `Reflect.construct(Function, …)`, and a lookup on `globalThis` whose key is computed, such as
149
+ `Reflect.get(globalThis, name)`. To read a JSON file, import it:
150
+ `import pkg from "../package.json" with { type: "json" }`.
147
151
 
148
152
  ```
149
153
  src/ordering/domain/services/pricing.service.ts
@@ -44,18 +44,33 @@ The shared kernel imports no bounded context at all. Every context may import th
44
44
  No file of a context or of the shared kernel imports a file the analysis does not see: ignored,
45
45
  unresolved, computed at runtime, or outside the declared contexts and the shared kernel. Such a
46
46
  file could re-export another context, and the rule could not tell which one. Code loaded at
47
- runtime, with `createRequire`, `eval`, `new Function` or `node:vm`, is reported the same way.
47
+ runtime, with `createRequire`, `eval`, the `Function` constructor or `node:vm`, is reported the
48
+ same way, whether it is named or reached through its type, see
49
+ [Every import counts](../index.md#every-import-counts).
48
50
 
49
51
  Every form of import counts, see [Every import counts](../index.md#every-import-counts).
50
52
 
53
+ The global object is no channel either. Writing or reading a name of `globalThis`, `global`,
54
+ `window` or `self` that no file declares is reported, wherever it is written: an assignment,
55
+ `Reflect.set`, `Reflect.get`, `Object.assign`, `Object.defineProperty`, or `(globalThis as any).x`.
56
+ A name the library declares, such as a polyfill of `globalThis.crypto` or a read of `fetch`, is
57
+ fine, and a global the project declares with `declare global` counts as an import of the file that
58
+ declares it.
59
+
51
60
  The wiring follows the same contract. In the composition roots and the files at the root of
52
61
  `src/`, a value of one context given to another one, such as
53
- `new LedgerModule({ redemptions: () => this.emoney.commands.requestRedemption })`, is an
62
+ `new OrderingModule({ prices: () => this.catalog.commands.changePrice })`, is an
54
63
  `OpenHostService` of the giving context, or one of its methods. A handler, a repository or any
55
64
  other class of its model is reported, even when the receiving side declares a type of the same
56
65
  shape. Whether the receiving context may consume the giving one at all is checked by
57
66
  [`strategic/no-unmapped-context`](./no-unmapped-context.md).
58
67
 
68
+ So that what crosses can be seen, a module of another context is read by its properties
69
+ (`this.catalog.api`), or handed whole to the constructor of another module
70
+ (`new OrderingModule(this.catalog)`). Any other way into it is reported: brackets
71
+ (`this.catalog["commands"]`), `Reflect.get`, a spread, destructuring, or passing it to a function,
72
+ such as a helper of `src/` or `get` from lodash, that could hand back anything.
73
+
59
74
  ## What it reports
60
75
 
61
76
  ```
@@ -94,9 +109,18 @@ src/ordering/driven/memory/adapters/memory-prices.adapter.ts
94
109
 
95
110
  src/app.module.ts
96
111
  14 error strategic/no-cross-context-import: Gives
97
- this.emoney.commands.requestRedemption, from emoney, to ledger: only
98
- an OpenHostService of another bounded context may cross, in an import
99
- or in the wiring.
112
+ this.catalog.commands.changePrice, from catalog, to ordering: only an
113
+ OpenHostService of another bounded context may cross, in an import or
114
+ in the wiring.
115
+ 21 error strategic/no-cross-context-import: Reaches into this.catalog
116
+ with Reflect.get: in the wiring, a module of another context is read
117
+ by its properties, so that what crosses can be seen.
118
+
119
+ src/catalog/catalog.module.ts
120
+ 18 error strategic/no-cross-context-import: Writes
121
+ globalThis.catalog:prices, which no file declares: two contexts can
122
+ meet there without the context map showing it. Integrate through an
123
+ open host service, or publish an integration event.
100
124
  ```
101
125
 
102
126
  ## Fix it
@@ -151,6 +175,11 @@ bounded context. Move what it needs into the shared kernel, or keep it in the co
151
175
  should build values of its own context.
152
176
  - A file that matches `ignore` in `alveolus.config.ts` is not analysed at all, and no file of a
153
177
  context may import it. Review a change to `ignore` as you would review a rule turned off.
178
+ - A loader reached through a value typed `any` that is neither a `constructor` nor a lookup on
179
+ `globalThis`, such as `(loaders as any).run(code)`, is not recognised. In review, `any` around a
180
+ call is a question to ask.
181
+ - In the wiring, a module chosen by a condition (`flag ? this.catalog : this.ordering`) and then
182
+ reached into is not recognised as a module: its type is a union.
154
183
  - In the wiring, a value whose type is erased on the way, by a cast or a container token written
155
184
  as a string, is not seen. In review, the composition root holds no cast.
156
185
  :::
@@ -1,16 +1,16 @@
1
1
  ---
2
- description: "Architecture rule: an open host service speaks the published language, and never exposes a class of its bounded context."
2
+ description: "Architecture rule: an open host service speaks the published language: it never exposes a class of its bounded context, never receives a function and never returns an erased type."
3
3
  ---
4
4
 
5
5
  # no-leaky-host-service
6
6
 
7
- An open host service speaks the published language: no class of its context appears in what it
8
- offers.
7
+ An open host service speaks the published language: data in, data out. No class of its context
8
+ appears in what it offers, it receives no function, and what it returns has a type.
9
9
 
10
10
  <dl class="al-glance">
11
11
  <dt>Rule</dt><dd><code>strategic/no-leaky-host-service</code></dd>
12
12
  <dt>Category</dt><dd><a href="/rules/#strategic">Strategic</a>: what crosses a bounded context</dd>
13
- <dt>Reports</dt><dd>A class of the project in the parameters, results, properties or getters of an open host service</dd>
13
+ <dt>Reports</dt><dd>A class of the project in the parameters, results, properties or getters of an open host service; a function among its parameters; <code>unknown</code>, <code>any</code> or <code>object</code> as a result</dd>
14
14
  <dt>Applies to</dt><dd>Every class that implements <code>OpenHostService</code></dd>
15
15
  <dt>Turn off</dt><dd><a href="#turn-it-off"><code>"strategic/no-leaky-host-service": "off"</code></a></dd>
16
16
  </dl>
@@ -39,6 +39,13 @@ parameters and its result, followed into generics, `Promise`, arrays and object
39
39
  | A class of an installed package | ✅ |
40
40
  | Any other class of the project: an aggregate, an entity, a value object, an identifier, a domain event | ❌ |
41
41
 
42
+ Its parameters carry data, never behaviour: a function is reported wherever it sits, as a
43
+ parameter, a property of an object parameter (`{ onSettled: () => void }`), an item of an array or
44
+ a method of an interface it receives. A class, such as `Date` or `AbortSignal`, is not a function.
45
+
46
+ Its results have a type: `unknown`, `any` and `object`, alone or in a `Promise`, are reported. A
47
+ parameter may be `unknown`, for a payload the service validates.
48
+
42
49
  The constructor and private members are left out: they wire the service, other contexts never see
43
50
  them.
44
51
 
@@ -49,6 +56,13 @@ src/catalog/driving/in-process/catalog-api.ts
49
56
  6 error strategic/no-leaky-host-service: CatalogApi.product exposes
50
57
  Product, an AggregateRoot of catalog: an open host service speaks
51
58
  the published language.
59
+ 9 error strategic/no-leaky-host-service: CatalogApi.onRestockNeeded
60
+ receives a function: an open host service receives data, never
61
+ behaviour, or the upstream context ends up running code of another
62
+ one. To let another context react, publish an integration event.
63
+ 12 error strategic/no-leaky-host-service: CatalogApi.inspect returns
64
+ unknown: an open host service returns a type of its published
65
+ language, so that what leaves the context can be seen.
52
66
  ```
53
67
 
54
68
  ## Fix it
@@ -79,12 +93,51 @@ export class CatalogApi implements OpenHostService {
79
93
 
80
94
  </div>
81
95
 
96
+ ### Publish an event instead of taking a callback
97
+
98
+ So that the upstream context never runs code of another one, it does not accept a callback to call
99
+ when something happens: it publishes an integration event, and the downstream context subscribes
100
+ to it. The context map then says the truth: the downstream context consumes the upstream one, not
101
+ the other way round.
102
+
103
+ <div class="al-compare">
104
+
105
+ ```ts [❌ Avoid: src/catalog/driving/in-process/catalog-api.ts]
106
+ export class CatalogApi implements OpenHostService {
107
+ onRestockNeeded(callback: RestockCallback): void {
108
+ this.handlers.connect(callback);
109
+ }
110
+ }
111
+ ```
112
+
113
+ ```ts [✅ Prefer: src/catalog/application/translators/catalog-events.translator.ts]
114
+ export class CatalogEventsTranslator extends EventTranslator<
115
+ RestockNeeded,
116
+ RestockNeededRepresentation
117
+ > {
118
+ protected readonly source = "catalog";
119
+
120
+ translate(event: RestockNeeded, context: IntegrationEventContext) {
121
+ return this.wrap(event, context, {
122
+ payload: { productId: event.productId.value, quantity: event.quantity },
123
+ type: "catalog.restock-needed",
124
+ version: 1,
125
+ });
126
+ }
127
+ }
128
+ ```
129
+
130
+ </div>
131
+
82
132
  ## Limits
83
133
 
84
134
  ::: warning What the rule cannot see
85
- - What a method returns as `unknown`, `any` or a plain object typed by hand with the fields of the
86
- aggregate: the rule follows classes. In review, a method of an open host service returns a type of
135
+ - A plain object typed by hand with the fields of the aggregate: the rule follows classes and
136
+ erased types, not shapes. In review, a method of an open host service returns a type of
87
137
  `published-language/`.
138
+ - A function smuggled through a parameter typed `unknown`: parameters may be `unknown`, for a
139
+ payload to validate, so the rule cannot tell. In review, an `unknown` parameter is parsed, never
140
+ called.
88
141
  - A DTO class of the context is a leak too, on purpose: the published language is made of types,
89
142
  not classes.
90
143
  :::
@@ -17,10 +17,10 @@ by every context at once: a channel between them that no import and no context m
17
17
 
18
18
  ## Why
19
19
 
20
- Ledger needs to create a redemption in e-money, and the context map says ledger consumes nothing.
21
- Someone adds a `ServiceRegistry` to the shared kernel: e-money registers its handler under a name,
22
- ledger resolves it. No file of ledger imports e-money, every import rule passes, and ledger now
23
- depends on e-money in a way nobody decided.
20
+ The catalog needs to cancel the orders of a withdrawn product, and the context map says the
21
+ catalog consumes nothing. Someone adds a `ServiceRegistry` to the shared kernel: ordering registers
22
+ its handler under a name, the catalog resolves it. No file of the catalog imports ordering, every
23
+ import rule passes, and the catalog now depends on ordering in a way nobody decided.
24
24
 
25
25
  ::: tip The fix
26
26
  Contexts talk through an [open host service](../../core/strategic/open-host-services.md), consumed
@@ -39,14 +39,24 @@ Every static field of a class in the shared kernel:
39
39
  | `static readonly ZERO = new Money({ amount: 0 })` | ✅ |
40
40
  | `static readonly PRECISION = 2` | ✅ |
41
41
  | `static readonly CURRENCIES: readonly string[] = ["EUR"]`, a `ReadonlyMap`, a `ReadonlySet` | ✅ |
42
+ | `static readonly NONE = new CustomerId("")`: an identifier | ✅ |
43
+ | `static readonly RATE = new Decimal("1.1")`: a class of a package listed in `domainDependencies` | ✅ |
42
44
  | `static count = 0`: without `readonly` | ❌ |
43
45
  | `static readonly services = new Map()`: a `Map`, a `Set`, a `WeakMap`, a `WeakSet` | ❌ |
44
46
  | `static readonly names: string[] = []`: an array that is not `readonly` | ❌ |
45
47
  | `static readonly byId: Record<string, Handler> = {}`: an index signature | ❌ |
46
48
  | `static readonly options = { strict: true }`: an object literal | ❌ |
49
+ | `static readonly shared = new ServiceDirectory()`: a class that is not a value, such as a singleton | ❌ |
50
+ | `static readonly bus = new EventEmitter()`: a class of a package outside `domainDependencies` | ❌ |
51
+ | `static readonly resolve = makeResolver()`: a function, which can close over any state | ❌ |
47
52
 
48
- Instance fields are not checked: an adapter of the shared kernel may hold its own state, each
49
- context builds its own instance.
53
+ A static field holds a value: a primitive, a value object, an identifier, a class of a package
54
+ listed in `domainDependencies`, or a `readonly` collection of them. Static methods are not fields:
55
+ `static of(amount: number)` is fine.
56
+
57
+ Instance fields are not checked: an adapter of the shared kernel may hold its own state. When each
58
+ context builds its own instance, nobody else reaches it; when the composition root at the root of
59
+ `src/` hands the same instance to two contexts, it is a channel, see [Limits](#limits).
50
60
 
51
61
  Module-level state, such as `let current` or `const services = new Map()` at the top of a file, is
52
62
  reported by [`tactical/no-loose-code`](../tactical/no-loose-code.md).
@@ -59,6 +69,12 @@ src/shared-kernel/driven/memory/registry/service-registry.ts
59
69
  collection in a static field: every context reaches the same one, a
60
70
  channel the context map does not show. The shared kernel shares a
61
71
  model, not state: integrate through an open host service.
72
+ 3 error strategic/no-shared-state: ServiceRegistry.shared holds a
73
+ ServiceRegistry in a static field, which can keep state every context
74
+ reaches, a channel the context map does not show. A static field of
75
+ the shared kernel holds a value: a primitive, a value object, an
76
+ identifier, a class of domainDependencies, or a readonly collection
77
+ of them.
62
78
  ```
63
79
 
64
80
  ## Fix it
@@ -74,17 +90,27 @@ anti-corruption layer. The composition root passes the service; no registry is n
74
90
  So that a constant cannot become a channel, make it `readonly` and give it an immutable type: a
75
91
  value object, a primitive, a `readonly` array, a `ReadonlyMap`.
76
92
 
93
+ ### Build services in the composition root
94
+
95
+ So that every context gets the instance the composition root decides, a clock, a bus or a
96
+ directory is built there and passed to the constructors that need it, not kept in a static
97
+ `instance` field.
98
+
77
99
  ## Limits
78
100
 
79
101
  ::: warning What the rule cannot see
80
- - A `static readonly` field typed by a class whose instances can change, such as
81
- `static readonly bus = new EventEmitter()`, passes: the rule reads the type of the field, not
82
- what its class does. In review, a static field of the shared kernel holds a value, never a
83
- service.
102
+ - A value object or a class of `domainDependencies` is trusted to be immutable: a value object
103
+ that keeps a `Map` in a private field passes. In review, a value object changes by returning a
104
+ new one.
84
105
  - A `Readonly<Record<…>>` counts as a collection, because it has an index signature: use a
85
106
  `ReadonlyMap` for a constant dictionary.
107
+ - An instance handed to two contexts by the composition root at the root of `src/` is not checked:
108
+ the database and the outbox are shared that way on purpose, and a registry passed the same way
109
+ goes unseen. In review, the root passes the same instance to several contexts only for the
110
+ infrastructure every context needs: the database, the outbox, the clock.
86
111
  - State held outside the shared kernel is not checked: a package with a global container, such as
87
- the default container of a dependency injection library, or a write to `globalThis`.
112
+ the default container of a dependency injection library. A name of `globalThis` that no file
113
+ declares is reported by [`strategic/no-cross-context-import`](./no-cross-context-import.md).
88
114
  :::
89
115
 
90
116
  ## Turn it off
@@ -47,15 +47,15 @@ Imports of the shared kernel are not consumptions: every context may import it.
47
47
 
48
48
  A context can consume another one without importing it: `app.module.ts` sees every module, and
49
49
  can hand a value of one context to another. Ledger declares a port, its adapter calls whatever it
50
- is given, and the root composition gives it a handler of e-money:
50
+ is given, and the root composition gives it a handler of payments:
51
51
 
52
52
  ```ts [src/app.module.ts]
53
53
  this.ledger = new LedgerModule({
54
- redemptions: () => this.emoney.commands.requestRedemption,
54
+ transfers: () => this.payments.commands.settleTransfer,
55
55
  });
56
56
  ```
57
57
 
58
- No file of ledger imports e-money, yet ledger now consumes it. In the composition roots and the
58
+ No file of ledger imports payments, yet ledger now consumes it. In the composition roots and the
59
59
  files at the root of `src/`, every value given to a class, a function or a field of one context
60
60
  (an argument, a property of an object, the body of an arrow function, an assignment, a variable
61
61
  typed by that context) is read: when it comes from another context, by where it is declared or by
@@ -68,16 +68,18 @@ from it is.
68
68
  ```
69
69
  src/ledger/driven/payments/adapters/payment-status.adapter.ts
70
70
  2 error strategic/no-unmapped-context: ledger consumes payments, which the
71
- context map does not allow: reverse the dependency, or if ledger
72
- really is downstream of payments, add payments to
73
- contextMap.ledger.consumes.
71
+ context map does not allow: reverse the dependency with an
72
+ integration event that ledger publishes and payments subscribes to,
73
+ not with a callback; or if ledger really is downstream of payments,
74
+ add payments to contextMap.ledger.consumes.
74
75
 
75
76
  src/app.module.ts
76
77
  14 error strategic/no-unmapped-context: ledger receives
77
- this.emoney.commands.requestRedemption from emoney here, which the
78
- context map does not allow: reverse the dependency, or if ledger
79
- really is downstream of emoney, add emoney to
80
- contextMap.ledger.consumes.
78
+ this.payments.commands.settleTransfer from payments here, which the
79
+ context map does not allow: reverse the dependency with an
80
+ integration event that ledger publishes and payments subscribes to,
81
+ not with a callback; or if ledger really is downstream of payments,
82
+ add payments to contextMap.ledger.consumes.
81
83
  ```
82
84
 
83
85
  A map that would allow it is refused before the check:
@@ -117,6 +119,10 @@ So that `Ledger` stays upstream, it does not ask `Payments` anything: it publish
117
119
  `TransferSettled` in its [published language](../../core/strategic/published-language.md), and
118
120
  `Payments` reacts to it.
119
121
 
122
+ A callback is not a reversal. `Ledger` calling a function that `Payments` registered on its open
123
+ host service still runs code of `Payments` when `Ledger` decides: the dependency is the same, only
124
+ hidden from the map. An event carries data, and `Ledger` does not know who reacts.
125
+
120
126
  ## Limits
121
127
 
122
128
  ::: warning What the rule cannot see
@@ -125,7 +131,7 @@ So that `Ledger` stays upstream, it does not ask `Payments` anything: it publish
125
131
  another context is an import of its open host service.
126
132
  - A value whose type is erased on the way: a cast (`as unknown as Handler`, `any`) in the
127
133
  composition root, or a container token written as a string, such as NestJS
128
- `{ provide: "redemptions", useFactory: … }`. In review, the composition root holds no cast, and
134
+ `{ provide: "transfers", useFactory: … }`. In review, the composition root holds no cast, and
129
135
  a token is the abstract class of a port.
130
136
  - With the rule off, the wiring is no longer checked against the map, even though
131
137
  [`strategic/no-cross-context-import`](./no-cross-context-import.md) still checks what crosses.
package/package.json CHANGED
@@ -48,7 +48,7 @@
48
48
  },
49
49
  "sideEffects": false,
50
50
  "type": "module",
51
- "version": "0.5.0",
51
+ "version": "0.6.0",
52
52
  "scripts": {
53
53
  "build": "tsdown && biome check --write package.json",
54
54
  "typecheck": "tsc -p tsconfig.json"