@alveolus/arch 0.4.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
@@ -69,11 +69,16 @@ interface MemberProps {
69
69
  readonly kind: MemberKind;
70
70
  readonly visibility: Visibility;
71
71
  readonly isStatic: boolean;
72
+ readonly isReadonly: boolean;
72
73
  readonly isParameterProperty: boolean;
73
74
  readonly isCallable: boolean;
74
75
  readonly valueTypes: readonly ClassType[];
75
76
  readonly parameterTypes: readonly ClassType[];
76
77
  readonly returns: ReturnShape | undefined;
78
+ readonly holdsCollection: boolean;
79
+ readonly receivesFunction: boolean;
80
+ readonly erasedType: string | undefined;
81
+ readonly opaqueValue: string | undefined;
77
82
  }
78
83
  declare class Member {
79
84
  readonly name: string;
@@ -81,11 +86,16 @@ declare class Member {
81
86
  readonly kind: MemberKind;
82
87
  readonly visibility: Visibility;
83
88
  readonly isStatic: boolean;
89
+ readonly isReadonly: boolean;
84
90
  readonly isParameterProperty: boolean;
85
91
  readonly isCallable: boolean;
86
92
  readonly valueTypes: readonly ClassType[];
87
93
  readonly parameterTypes: readonly ClassType[];
88
94
  readonly returns: ReturnShape | undefined;
95
+ readonly holdsCollection: boolean;
96
+ readonly receivesFunction: boolean;
97
+ readonly erasedType: string | undefined;
98
+ readonly opaqueValue: string | undefined;
89
99
  constructor(props: MemberProps);
90
100
  get isPublicInstance(): boolean;
91
101
  get isField(): boolean;
@@ -119,8 +129,8 @@ declare class ClassDeclaration {
119
129
  }
120
130
  //#endregion
121
131
  //#region src/model/dependencies/dependency.d.ts
122
- type DependencyForm = "import" | "re-export" | "inline type" | "dynamic import" | "require" | "global";
123
- type TargetVisibility = "analysed" | "ignored" | "unresolved";
132
+ type DependencyForm = "import" | "re-export" | "inline type" | "dynamic import" | "require" | "reference" | "augmentation" | "dynamic load" | "global";
133
+ type TargetVisibility = "analysed" | "ignored" | "unresolved" | "dynamic";
124
134
  type DependencyTarget = {
125
135
  readonly kind: "file";
126
136
  readonly path: string;
@@ -140,6 +150,15 @@ declare class Dependency {
140
150
  isOnPackage(name: string): boolean;
141
151
  }
142
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
143
162
  //#region src/model/dependencies/global-use.d.ts
144
163
  type GlobalOrigin = "ecmascript" | "host";
145
164
  type GlobalEffect = "clock" | "randomness";
@@ -151,6 +170,28 @@ declare class GlobalUse {
151
170
  constructor(line: number, name: string, origin: GlobalOrigin, effect: GlobalEffect | undefined);
152
171
  }
153
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
182
+ //#region src/model/dependencies/wiring.d.ts
183
+ interface WiringLink {
184
+ readonly text: string;
185
+ readonly declaredIn: string | undefined;
186
+ readonly types: readonly ClassType[];
187
+ }
188
+ declare class Wiring {
189
+ readonly line: number;
190
+ readonly receiver: string;
191
+ readonly links: readonly WiringLink[];
192
+ constructor(line: number, receiver: string, links: readonly WiringLink[]);
193
+ }
194
+ //#endregion
154
195
  //#region src/model/statements/disable-comment.d.ts
155
196
  declare class DisableComment {
156
197
  readonly line: number;
@@ -185,6 +226,9 @@ interface SourceFileProps {
185
226
  readonly statements: readonly TopLevelStatement[];
186
227
  readonly throws: readonly Throw[];
187
228
  readonly globals: readonly GlobalUse[];
229
+ readonly globalChannels: readonly GlobalChannel[];
230
+ readonly wirings: readonly Wiring[];
231
+ readonly moduleReaches: readonly ModuleReach[];
188
232
  readonly disables: readonly DisableComment[];
189
233
  }
190
234
  declare class SourceFile {
@@ -194,6 +238,9 @@ declare class SourceFile {
194
238
  readonly statements: readonly TopLevelStatement[];
195
239
  readonly throws: readonly Throw[];
196
240
  readonly globals: readonly GlobalUse[];
241
+ readonly globalChannels: readonly GlobalChannel[];
242
+ readonly wirings: readonly Wiring[];
243
+ readonly moduleReaches: readonly ModuleReach[];
197
244
  readonly disables: readonly DisableComment[];
198
245
  private readonly lines;
199
246
  constructor(props: SourceFileProps);
@@ -261,7 +308,7 @@ interface Settings {
261
308
  //#endregion
262
309
  //#region src/architecture/paths/location.d.ts
263
310
  type Area = "context" | "shared-kernel" | "root" | "outside";
264
- type Unseen = "ignored" | "unresolved";
311
+ type Unseen = "ignored" | "unresolved" | "dynamic";
265
312
  interface LocationProps {
266
313
  readonly area: Area;
267
314
  readonly context?: string;
@@ -316,6 +363,15 @@ declare class BuildingBlocks {
316
363
  foldersOf(layer: "domain" | "application"): readonly string[];
317
364
  }
318
365
  //#endregion
366
+ //#region src/architecture/crossing.d.ts
367
+ interface Crossing {
368
+ readonly line: number;
369
+ readonly from: string;
370
+ readonly to: string;
371
+ readonly expression: string;
372
+ readonly isOpenHostService: boolean;
373
+ }
374
+ //#endregion
319
375
  //#region src/architecture/layers.d.ts
320
376
  declare class Layers {
321
377
  isLayer(name: string): name is Layer;
@@ -349,12 +405,15 @@ export declare class Architecture {
349
405
  private readonly shape;
350
406
  private readonly layout;
351
407
  private readonly locations;
408
+ private readonly crossings;
352
409
  constructor(project: Project$1, settings: Settings);
353
410
  get files(): readonly SourceFile[];
354
411
  get domainDependencies(): AllowedPackages;
355
412
  get applicationDependencies(): AllowedPackages;
356
413
  get contextMap(): ContextMap;
357
414
  locationOf(file: SourceFile): Location;
415
+ locationOfPath(path: string): Location;
416
+ crossingsIn(file: SourceFile): Crossing[];
358
417
  locationOfTarget(target: FileTarget$1): Location;
359
418
  shapeIssueOf(location: Location): ShapeIssue | undefined;
360
419
  relativePath(path: string): string;
@@ -418,7 +477,7 @@ declare class NoLooseDisableRule extends Rule<"tooling/no-loose-disable", Messag
418
477
  }
419
478
  //#endregion
420
479
  //#region src/rules/registry.d.ts
421
- declare const ruleIds: readonly ["strategic/no-cross-context-import", "strategic/no-leaky-host-service", "strategic/no-unmapped-context", "strategic/no-fat-shared-kernel", "layers/no-impure-domain", "layers/no-outward-import", "layers/no-portless-adapter", "layers/no-driving-shortcut", "tactical/no-aggregate-reference", "tactical/no-public-field", "tactical/no-foreign-command-dependency", "tactical/no-foreign-query-dependency", "tactical/no-stateful-service", "tactical/no-thrown-failure", "tactical/no-misplaced-class", "tactical/no-loose-code", "tooling/no-loose-disable"];
480
+ declare const ruleIds: readonly ["strategic/no-cross-context-import", "strategic/no-leaky-host-service", "strategic/no-unmapped-context", "strategic/no-fat-shared-kernel", "strategic/no-shared-state", "layers/no-impure-domain", "layers/no-outward-import", "layers/no-portless-adapter", "layers/no-driving-shortcut", "tactical/no-aggregate-reference", "tactical/no-public-field", "tactical/no-foreign-command-dependency", "tactical/no-foreign-query-dependency", "tactical/no-stateful-service", "tactical/no-thrown-failure", "tactical/no-misplaced-class", "tactical/no-loose-code", "tooling/no-loose-disable"];
422
481
  type RuleId = (typeof ruleIds)[number];
423
482
  export declare class RuleRegistry {
424
483
  readonly rules: readonly Rule<RuleId>[];
@@ -459,6 +518,7 @@ interface ImportScope {
459
518
  readonly projectDir: string;
460
519
  readonly rootDir: string;
461
520
  isIgnored(path: string): boolean;
521
+ readsWiring(path: string): boolean;
462
522
  }
463
523
  export declare abstract class Importer {
464
524
  abstract read(scope: ImportScope): Project$1;
@@ -469,9 +529,11 @@ export declare abstract class Importer {
469
529
  export declare class TsMorphImporter extends Importer {
470
530
  private readonly sources;
471
531
  private readonly classes;
532
+ private readonly types;
472
533
  private readonly statements;
473
534
  private readonly disables;
474
535
  private readonly throws;
536
+ private readonly globalChannels;
475
537
  constructor(sources: Project);
476
538
  static fromTsConfig(tsConfigFilePath: string): TsMorphImporter;
477
539
  resolves(packageName: string, scope: ImportScope): boolean;
@@ -617,10 +679,12 @@ export declare class Config implements CheckSettings {
617
679
  readonly contextMap: ContextMap;
618
680
  private readonly ignored;
619
681
  private readonly rules;
682
+ private readonly layout;
620
683
  constructor(config: AlveolusConfig, projectDir: string);
621
684
  private classifiedContexts;
622
685
  private validContextMap;
623
686
  isIgnored(path: string): boolean;
687
+ readsWiring(path: string): boolean;
624
688
  severityOf(rule: RuleId): Severity | "off";
625
689
  }
626
690
  //#endregion
@@ -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/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/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-DcFgskuN.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
 
@@ -313,7 +313,9 @@ may import it; it imports none of them.
313
313
  Each change to the shared kernel reaches every context. `Clock` and `IdGenerator` already come
314
314
  with `@alveolus/core`; only their adapters live here. An aggregate, a repository or a handler in
315
315
  the shared kernel is reported by
316
- [`strategic/no-fat-shared-kernel`](../rules/strategic/no-fat-shared-kernel.md).
316
+ [`strategic/no-fat-shared-kernel`](../rules/strategic/no-fat-shared-kernel.md), and a static field
317
+ that holds state, such as a registry of services, by
318
+ [`strategic/no-shared-state`](../rules/strategic/no-shared-state.md).
317
319
  :::
318
320
 
319
321
  ## See also
@@ -51,9 +51,10 @@ its own business. The "Applies to" line of each rule page says which it is.
51
51
 
52
52
  | Rule | Reports |
53
53
  | --- | --- |
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 composition root that re-exports. |
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
- | [`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. |
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, receives a function or returns an erased type, instead of speaking the published language. |
57
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. |
58
59
 
59
60
  ## Layers
@@ -120,12 +121,15 @@ The rules that check imports read every way a file can depend on another one, no
120
121
  `import … from`:
121
122
 
122
123
  ```ts
124
+ /// <reference path="../legacy/pool.ts" />
125
+ /// <reference types="pg" />
123
126
  import { Pool } from "pg";
124
127
  export { Pool } from "pg";
125
128
  type Pool = import("pg").Pool;
126
129
  const pg = await import("pg");
127
130
  const pg = require("pg");
128
131
  import pg = require("pg");
132
+ declare module "pg" { interface Pool { tenant: string } }
129
133
  ```
130
134
 
131
135
  A global declared by the project, in a `declare global` block, counts as an import of the file that
@@ -133,8 +137,17 @@ declares it.
133
137
 
134
138
  An import the analysis cannot see through counts as a file outside the project: one that does not
135
139
  resolve, such as a `.js` file without types, one whose path is computed at runtime, or one that is
136
- ignored, such as a test file. No layer imports it: only the composition root and the files at the
137
- root of `src/` may.
140
+ ignored, such as a test file. No file imports it, not even a composition root or a file at the
141
+ root of `src/`: a test file that re-exports another context would otherwise carry the import past
142
+ every rule.
143
+
144
+ Code loaded at runtime counts the same way, wherever it is: `node:module` (`createRequire`),
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" }`.
138
151
 
139
152
  ```
140
153
  src/ordering/domain/services/pricing.service.ts
@@ -40,8 +40,11 @@ Within the same context, or towards the shared kernel:
40
40
  | `published-language/` | Its own `published-language/`. From `@alveolus/core`, only `PublishedLanguage`, `IntegrationEvent` and `JsonValue`; other packages, such as a schema library, are fine. |
41
41
  | `driven/` | `domain/`, `application/`, `published-language/`, `driven/`, any package. |
42
42
  | `driving/` | `domain/`, `application/`, `published-language/`, `driving/`, any package. |
43
- | the composition root | Anything in its context and in the shared kernel. |
44
- | files at the root of `src/` | Composition roots, and each other. |
43
+ | the composition root | Anything in its context and in the shared kernel, any package. |
44
+ | files at the root of `src/` | Composition roots, each other, any package. |
45
+
46
+ No file imports a file the analysis does not see: ignored, unresolved, computed at runtime, or
47
+ outside the declared contexts and the shared kernel.
45
48
 
46
49
  No layer imports a composition root. The domain has its own rule,
47
50
  [`layers/no-impure-domain`](./no-impure-domain.md); imports from another context are checked by
@@ -100,7 +103,8 @@ The rule also reports:
100
103
  | Case | Message |
101
104
  | --- | --- |
102
105
  | A layer imports a composition root | `Imports … : only the composition root wires the layers.` |
103
- | A file at the root imports inside a context | `Files at the root import composition roots only, not ….` |
106
+ | A file at the root imports inside a context, or a file the analysis does not see | `Files at the root import composition roots only, not ….` |
107
+ | A composition root imports a file the analysis does not see | `The composition root imports src/ordering/wiring.fixture.ts (ignored by the analysis): it wires its own context and the shared kernel only.` |
104
108
  | Two composition roots in a context | `ordering has 2 composition roots (ordering.module.ts, pricing.module.ts): keep one, and move the rest into the layers.` |
105
109
  | The published language imports another name from core | `The published language imports … from @alveolus/core: only published-language types are allowed.` |
106
110
  | A name not allowed from a restricted package | `The application imports Controller from @nestjs/common: applicationDependencies only allows Injectable.` |
@@ -10,7 +10,7 @@ an anti-corruption layer or its composition root.
10
10
  <dl class="al-glance">
11
11
  <dt>Rule</dt><dd><code>strategic/no-cross-context-import</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>An import from another bounded context that is not its open host service, used where it may be</dd>
13
+ <dt>Reports</dt><dd>An import from another bounded context that is not its open host service, used where it may be; a value of another context given in the wiring that is not its open host service; an import of a file the analysis does not see</dd>
14
14
  <dt>Applies to</dt><dd>Every file of every bounded context, whatever its subdomain, and of the shared kernel</dd>
15
15
  <dt>Turn off</dt><dd><a href="#turn-it-off"><code>"strategic/no-cross-context-import": "off"</code></a></dd>
16
16
  </dl>
@@ -41,8 +41,36 @@ When a file of one bounded context imports a file of another one:
41
41
 
42
42
  The shared kernel imports no bounded context at all. Every context may import the shared kernel.
43
43
 
44
+ No file of a context or of the shared kernel imports a file the analysis does not see: ignored,
45
+ unresolved, computed at runtime, or outside the declared contexts and the shared kernel. Such a
46
+ file could re-export another context, and the rule could not tell which one. Code loaded at
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).
50
+
44
51
  Every form of import counts, see [Every import counts](../index.md#every-import-counts).
45
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
+
60
+ The wiring follows the same contract. In the composition roots and the files at the root of
61
+ `src/`, a value of one context given to another one, such as
62
+ `new OrderingModule({ prices: () => this.catalog.commands.changePrice })`, is an
63
+ `OpenHostService` of the giving context, or one of its methods. A handler, a repository or any
64
+ other class of its model is reported, even when the receiving side declares a type of the same
65
+ shape. Whether the receiving context may consume the giving one at all is checked by
66
+ [`strategic/no-unmapped-context`](./no-unmapped-context.md).
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
+
46
74
  ## What it reports
47
75
 
48
76
  ```
@@ -67,6 +95,32 @@ src/shared-kernel/domain/value-objects/money.value-object.ts
67
95
  bounded context, but imports
68
96
  src/catalog/domain/value-objects/currency.value-object.ts
69
97
  (catalog domain).
98
+
99
+ src/ordering/domain/services/pricing.service.ts
100
+ 1 error strategic/no-cross-context-import: Imports
101
+ src/ordering/domain/value-objects/product-id.fixture.ts (ignored by
102
+ the analysis): the analysis cannot tell which bounded context it
103
+ reaches; move the file into a bounded context or the shared kernel.
104
+
105
+ src/ordering/driven/memory/adapters/memory-prices.adapter.ts
106
+ 1 error strategic/no-cross-context-import: Loads code at runtime with
107
+ node:module: the analysis cannot tell which bounded context it
108
+ reaches; use a static import.
109
+
110
+ src/app.module.ts
111
+ 14 error strategic/no-cross-context-import: Gives
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.
70
124
  ```
71
125
 
72
126
  ## Fix it
@@ -119,7 +173,15 @@ bounded context. Move what it needs into the shared kernel, or keep it in the co
119
173
  - The rule checks what an anti-corruption layer imports, not what it does with it: an adapter that
120
174
  returns the open host service's answer as is, untranslated, is accepted. In review, the ACL
121
175
  should build values of its own context.
122
- - A file that matches `ignore` in `alveolus.config.ts` is not analysed at all.
176
+ - A file that matches `ignore` in `alveolus.config.ts` is not analysed at all, and no file of a
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.
183
+ - In the wiring, a value whose type is erased on the way, by a cast or a container token written
184
+ as a string, is not seen. In review, the composition root holds no cast.
123
185
  :::
124
186
 
125
187
  ## Turn it off
@@ -77,5 +77,6 @@ rules: { "strategic/no-fat-shared-kernel": "off" },
77
77
  ## See also
78
78
 
79
79
  - [Project layout: shared kernel](../../guide/project-layout.md#shared-kernel)
80
+ - [`strategic/no-shared-state`](./no-shared-state.md), no state in the shared kernel either
80
81
  - [`strategic/no-unmapped-context`](./no-unmapped-context.md), the other way contexts get tied
81
82
  - [Rules](../index.md), every rule by category
@@ -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
  :::