@ddd-ts-kit/eslint-plugin 0.8.0 → 0.10.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/README.md +6 -1
- package/dist/rules/event-sourcing-past-tense.d.ts +2 -0
- package/dist/rules/event-sourcing-past-tense.d.ts.map +1 -0
- package/dist/rules/event-sourcing-past-tense.js +52 -0
- package/dist/rules/event-sourcing-past-tense.js.map +1 -0
- package/dist/rules/event-sourcing-projection-never-appends.d.ts +3 -0
- package/dist/rules/event-sourcing-projection-never-appends.d.ts.map +1 -0
- package/dist/rules/event-sourcing-projection-never-appends.js +72 -0
- package/dist/rules/event-sourcing-projection-never-appends.js.map +1 -0
- package/dist/rules/event-sourcing-state-in-apply.d.ts +4 -0
- package/dist/rules/event-sourcing-state-in-apply.d.ts.map +1 -0
- package/dist/rules/event-sourcing-state-in-apply.js +81 -0
- package/dist/rules/event-sourcing-state-in-apply.js.map +1 -0
- package/dist/rules/event-sourcing-store-behind-repository.d.ts +2 -0
- package/dist/rules/event-sourcing-store-behind-repository.d.ts.map +1 -0
- package/dist/rules/event-sourcing-store-behind-repository.js +32 -0
- package/dist/rules/event-sourcing-store-behind-repository.js.map +1 -0
- package/dist/rules/event-sourcing-upcaster-required.d.ts +4 -0
- package/dist/rules/event-sourcing-upcaster-required.d.ts.map +1 -0
- package/dist/rules/event-sourcing-upcaster-required.js +96 -0
- package/dist/rules/event-sourcing-upcaster-required.js.map +1 -0
- package/dist/rules/rules.d.ts.map +1 -1
- package/dist/rules/rules.js +10 -0
- package/dist/rules/rules.js.map +1 -1
- package/dist/support/event-sourcing/fact-words.d.ts +6 -0
- package/dist/support/event-sourcing/fact-words.d.ts.map +1 -0
- package/dist/support/event-sourcing/fact-words.js +10 -0
- package/dist/support/event-sourcing/fact-words.js.map +1 -0
- package/dist/support/event-sourcing/is-aggregate-file.d.ts +4 -0
- package/dist/support/event-sourcing/is-aggregate-file.d.ts.map +1 -0
- package/dist/support/event-sourcing/is-aggregate-file.js +6 -0
- package/dist/support/event-sourcing/is-aggregate-file.js.map +1 -0
- package/dist/support/event-sourcing/is-event-sourced-class.d.ts +4 -0
- package/dist/support/event-sourcing/is-event-sourced-class.d.ts.map +1 -0
- package/dist/support/event-sourcing/is-event-sourced-class.js +8 -0
- package/dist/support/event-sourcing/is-event-sourced-class.js.map +1 -0
- package/dist/support/event-sourcing/is-past-fact.d.ts +3 -0
- package/dist/support/event-sourcing/is-past-fact.d.ts.map +1 -0
- package/dist/support/event-sourcing/is-past-fact.js +15 -0
- package/dist/support/event-sourcing/is-past-fact.js.map +1 -0
- package/dist/support/event-sourcing/is-past-participle.d.ts +3 -0
- package/dist/support/event-sourcing/is-past-participle.d.ts.map +1 -0
- package/dist/support/event-sourcing/is-past-participle.js +113 -0
- package/dist/support/event-sourcing/is-past-participle.js.map +1 -0
- package/dist/support/event-sourcing/kernel-names-listener.d.ts +6 -0
- package/dist/support/event-sourcing/kernel-names-listener.d.ts.map +1 -0
- package/dist/support/event-sourcing/kernel-names-listener.js +10 -0
- package/dist/support/event-sourcing/kernel-names-listener.js.map +1 -0
- package/dist/support/event-sourcing/unresolved-types.d.ts +7 -0
- package/dist/support/event-sourcing/unresolved-types.d.ts.map +1 -0
- package/dist/support/event-sourcing/unresolved-types.js +49 -0
- package/dist/support/event-sourcing/unresolved-types.js.map +1 -0
- package/dist/support/event-sourcing/words-of.d.ts +3 -0
- package/dist/support/event-sourcing/words-of.d.ts.map +1 -0
- package/dist/support/event-sourcing/words-of.js +9 -0
- package/dist/support/event-sourcing/words-of.js.map +1 -0
- package/dist/support/outside-concerns/outside-concern.d.ts.map +1 -1
- package/dist/support/outside-concerns/outside-concern.js +4 -0
- package/dist/support/outside-concerns/outside-concern.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/docs/rules/event-sourcing-past-tense.md +40 -0
- package/docs/rules/event-sourcing-projection-never-appends.md +49 -0
- package/docs/rules/event-sourcing-state-in-apply.md +51 -0
- package/docs/rules/event-sourcing-store-behind-repository.md +39 -0
- package/docs/rules/event-sourcing-upcaster-required.md +55 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -116,6 +116,11 @@ is an error whatever the configured limit). `strict` sets every rule to `error`.
|
|
|
116
116
|
| [`application/command-query-separation`](docs/rules/application-command-query-separation.md) | `ddd-ts-kit/application-command-query-separation` | nothing under `application/queries` calls `save`, `delete`, `publish` on a dependency | `warn` | custom |
|
|
117
117
|
| [`domain-events/dispatched-on-save`](docs/rules/domain-events-dispatched-on-save.md) | `ddd-ts-kit/domain-events-dispatched-on-save` | no `pullEvents()` in `application/` and `infrastructure/`; no `DomainEventDispatcher` imported, listed as a dependency or received by a constructor in `application/commands`, `application/queries` and a repository adapter | `error` | custom |
|
|
118
118
|
| [`domain-events/transactional-before-commit`](docs/rules/domain-events-transactional-before-commit.md) | `ddd-ts-kit/domain-events-transactional-before-commit` | a class carrying `@DomainEventHandler` without `phase: 'after-commit'` depends on no `Cache`, `Lock`, `RateLimiter`, `JobScheduler` or `EventBus` of the kernel and on nothing imported from `infrastructure/`, another context, the platform or a package other than `@ddd-ts-kit/kernel` and `@ddd-ts-kit/auth`; an after-commit handler does not depend on `IntegrationEventPublisher`. The adapters of an `application/ports/` port and the phase of an explicit-style handler are held by the CLI checker | `error` | custom |
|
|
119
|
+
| [`event-sourcing/state-in-apply`](docs/rules/event-sourcing-state-in-apply.md) | `ddd-ts-kit/event-sourcing-state-in-apply` | an event-sourced aggregate changes its state only in its apply methods (`apply<Fact>`, `restore`), and an apply method records no event | `error` | custom |
|
|
120
|
+
| [`event-sourcing/past-tense`](docs/rules/event-sourcing-past-tense.md) | `ddd-ts-kit/event-sourcing-past-tense` | the events an event-sourced aggregate imports from `domain/events/` are named in the past tense | `error` | custom |
|
|
121
|
+
| [`event-sourcing/store-behind-repository`](docs/rules/event-sourcing-store-behind-repository.md) | `ddd-ts-kit/event-sourcing-store-behind-repository` | no `EventStore`, `SnapshotStore`, `CheckpointStore`, `EventSourcedRepository`, `EventSerializer`, `CatchUpSubscription` in `domain/` and `application/`: the aggregate goes through its repository | `error` | custom |
|
|
122
|
+
| [`event-sourcing/projection-never-appends`](docs/rules/event-sourcing-projection-never-appends.md) | `ddd-ts-kit/event-sourcing-projection-never-appends` | a projection names no event store, and one fed by the store no repository: it never appends to a stream | `error` | custom |
|
|
123
|
+
| [`event-sourcing/upcaster-required`](docs/rules/event-sourcing-upcaster-required.md) | `ddd-ts-kit/event-sourcing-upcaster-required` | `defineStoredEvent` names the type of its data, declared in the file, and a version above 1 has an upcaster from each version below (the lock of recorded shapes: `ddd-ts-kit check`) | `error` | custom |
|
|
119
124
|
| [`test/no-mocks`](docs/rules/test-no-mocks.md) | `ddd-ts-kit/test-no-mocks` | no `vi.mock`, `vi.fn`, `vi.spyOn`, their `jest` twins or a mocking library in a context's tests | `warn` | custom |
|
|
120
125
|
| [`events/name-format`](docs/rules/events-name-format.md) | `ddd-ts-kit/events-name-format` | event names follow `<context>.<aggregate>.<fact>` in kebab-case | `error` | custom |
|
|
121
126
|
| [`events/outbox-required`](docs/rules/events-outbox-required.md) | `ddd-ts-kit/events-outbox-required` | no broker client and no concrete bus in `domain/` and `application/`; a publisher depends on the `IntegrationEventPublisher` port | `error` | custom |
|
|
@@ -258,7 +263,7 @@ Two tools, one set of ids, no overlap of authority.
|
|
|
258
263
|
|
|
259
264
|
| Concern | Authority | Why |
|
|
260
265
|
|---|---|---|
|
|
261
|
-
| imports and boundaries (`layer/*`, `context/published-language-only`, `context/declared-relationship`, `context/published-language-is-a-contract`), `purity/*`, `clean/*`, `test/no-mocks`, `events/name-format`, `domain/*`, `application/*`, the code side of `events/outbox-required`, `events/consumer-idempotent`, `context/extractable`, `authz/*`, `aspects/outside-in`, `tracing/platform-only`, `domain-events/dispatched-on-save`, `domain-events/transactional-before-commit` on a declared class, `standard/no-parallel-interface`, `declarations/role-declared`, `ports/*`, `scheduling/*` (but the uniqueness of job names) and `governance/recorded-deviation` | this plugin | it reads the syntax tree: no false positive from a string or a comment, shadowing and arrow functions are understood |
|
|
266
|
+
| imports and boundaries (`layer/*`, `context/published-language-only`, `context/declared-relationship`, `context/published-language-is-a-contract`), `purity/*`, `clean/*`, `test/no-mocks`, `events/name-format`, `domain/*`, `application/*`, the code side of `events/outbox-required`, `events/consumer-idempotent`, `context/extractable`, `authz/*`, `aspects/outside-in`, `tracing/platform-only`, `domain-events/dispatched-on-save`, `domain-events/transactional-before-commit` on a declared class, `event-sourcing/*` (but the lock of `event-sourcing/upcaster-required`), `standard/no-parallel-interface`, `declarations/role-declared`, `ports/*`, `scheduling/*` (but the uniqueness of job names) and `governance/recorded-deviation` | this plugin | it reads the syntax tree: no false positive from a string or a comment, shadowing and arrow functions are understood |
|
|
262
267
|
| the tree (`tree/closed`, `tree/context-doc`), names and files (`naming/*`, `test/spec-required`, `test/builder-required`), the language (`language/*`), the config (`config/*`, `context/no-cycle`), `events/defined-in-published-language`, `composition/only-in-module`, `declarations/barrel-current`, unique consumer names and job names, one declared class per role file, of `domain-events/transactional-before-commit` the adapters of an `application/ports/` port and the phase of an explicit-style handler, the config side of the ids above (`stack.events`, lowered severities, that a decision record exists) | `ddd-ts-kit check` | they judge the project, the glossary and files that are not sources; ESLint judges one source at a time |
|
|
263
268
|
| the real dependency graph (barrels, cycles, orphans, dev dependencies in production code) | dependency-cruiser, configured by the `.dependency-cruiser.cjs` that `ddd-ts-kit depcruise-config --write` generates from the config | it resolves modules instead of classifying paths |
|
|
264
269
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-sourcing-past-tense.d.ts","sourceRoot":"","sources":["../../src/rules/event-sourcing-past-tense.ts"],"names":[],"mappings":"AAQA,eAAO,MAAM,sBAAsB,wKA8CjC,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { AST_NODE_TYPES } from '@typescript-eslint/utils';
|
|
2
|
+
import { isAggregateFile } from '../support/event-sourcing/is-aggregate-file.js';
|
|
3
|
+
import { isEventSourcedClass } from '../support/event-sourcing/is-event-sourced-class.js';
|
|
4
|
+
import { factWords } from '../support/event-sourcing/fact-words.js';
|
|
5
|
+
import { isPastFact } from '../support/event-sourcing/is-past-fact.js';
|
|
6
|
+
import { importListener } from '../support/imports/import-listener.js';
|
|
7
|
+
import { defineRule } from '../support/rule/define-rule.js';
|
|
8
|
+
export const eventSourcingPastTense = defineRule({
|
|
9
|
+
id: 'event-sourcing/past-tense',
|
|
10
|
+
type: 'suggestion',
|
|
11
|
+
recommended: 'error',
|
|
12
|
+
description: 'The events an event-sourced aggregate imports from domain/events/ are named in the past tense: one word of the fact, the name after the aggregate, is a past participle that does not read as a command at its head.',
|
|
13
|
+
messages: {
|
|
14
|
+
presentTense: 'The event {{name}} is not named in the past tense. Name it after what happened (`InvoiceIssued`, `NoShowNoted`, `AmountWithdrawn`): a stored event is a fact replayed for years, a name in the present reads as a command.',
|
|
15
|
+
},
|
|
16
|
+
create({ file, report }) {
|
|
17
|
+
if (!isAggregateFile(file)) {
|
|
18
|
+
return {};
|
|
19
|
+
}
|
|
20
|
+
const events = [];
|
|
21
|
+
const aggregates = [];
|
|
22
|
+
return {
|
|
23
|
+
...importListener(file, ({ target, names }) => {
|
|
24
|
+
const fromEvents = target.kind === 'file' &&
|
|
25
|
+
target.location.area === 'context' &&
|
|
26
|
+
target.location.layer === 'domain' &&
|
|
27
|
+
target.location.inside[0] === 'events';
|
|
28
|
+
if (fromEvents) {
|
|
29
|
+
events.push(...names);
|
|
30
|
+
}
|
|
31
|
+
}),
|
|
32
|
+
ClassDeclaration(node) {
|
|
33
|
+
if (isEventSourcedClass(node) && node.id !== null) {
|
|
34
|
+
aggregates.push(node.id.name);
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
'Program:exit'() {
|
|
38
|
+
for (const imported of aggregates.length > 0 ? events : []) {
|
|
39
|
+
const name = localName(imported);
|
|
40
|
+
if (!isPastFact(factWords(name, aggregates))) {
|
|
41
|
+
report({ node: imported.node, messageId: 'presentTense', data: { name } });
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
/** The name the aggregate writes, as the checker reads it: the local one of a renamed import. */
|
|
49
|
+
function localName({ name, node }) {
|
|
50
|
+
return node.type === AST_NODE_TYPES.ImportSpecifier ? node.local.name : name;
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=event-sourcing-past-tense.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-sourcing-past-tense.js","sourceRoot":"","sources":["../../src/rules/event-sourcing-past-tense.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,gDAAgD,CAAC;AACjF,OAAO,EAAE,mBAAmB,EAAE,MAAM,qDAAqD,CAAC;AAC1F,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,UAAU,EAAE,MAAM,2CAA2C,CAAC;AACvE,OAAO,EAAE,cAAc,EAAqB,MAAM,uCAAuC,CAAC;AAC1F,OAAO,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AAE5D,MAAM,CAAC,MAAM,sBAAsB,GAAG,UAAU,CAAiB;IAC/D,EAAE,EAAE,2BAA2B;IAC/B,IAAI,EAAE,YAAY;IAClB,WAAW,EAAE,OAAO;IACpB,WAAW,EACT,sNAAsN;IACxN,QAAQ,EAAE;QACR,YAAY,EACV,4NAA4N;KAC/N;IACD,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE;QACrB,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC;YAC3B,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,MAAM,MAAM,GAAmB,EAAE,CAAC;QAClC,MAAM,UAAU,GAAa,EAAE,CAAC;QAEhC,OAAO;YACL,GAAG,cAAc,CAAC,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,EAAE;gBAC5C,MAAM,UAAU,GACd,MAAM,CAAC,IAAI,KAAK,MAAM;oBACtB,MAAM,CAAC,QAAQ,CAAC,IAAI,KAAK,SAAS;oBAClC,MAAM,CAAC,QAAQ,CAAC,KAAK,KAAK,QAAQ;oBAClC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,QAAQ,CAAC;gBAEzC,IAAI,UAAU,EAAE,CAAC;oBACf,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,CAAC;gBACxB,CAAC;YACH,CAAC,CAAC;YACF,gBAAgB,CAAC,IAAI;gBACnB,IAAI,mBAAmB,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,EAAE,KAAK,IAAI,EAAE,CAAC;oBAClD,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;gBAChC,CAAC;YACH,CAAC;YACD,cAAc;gBACZ,KAAK,MAAM,QAAQ,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;oBAC3D,MAAM,IAAI,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;oBAEjC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC,EAAE,CAAC;wBAC7C,MAAM,CAAC,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,EAAE,cAAc,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;oBAC7E,CAAC;gBACH,CAAC;YACH,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC,CAAC;AAEH,iGAAiG;AACjG,SAAS,SAAS,CAAC,EAAE,IAAI,EAAE,IAAI,EAAgB;IAC7C,OAAO,IAAI,CAAC,IAAI,KAAK,cAAc,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;AAC/E,CAAC"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { type TSESLint } from '@typescript-eslint/utils';
|
|
2
|
+
export declare const eventSourcingProjectionNeverAppends: TSESLint.RuleModule<"appends", [], import("../index.js").RuleDocs, TSESLint.RuleListener>;
|
|
3
|
+
//# sourceMappingURL=event-sourcing-projection-never-appends.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-sourcing-projection-never-appends.d.ts","sourceRoot":"","sources":["../../src/rules/event-sourcing-projection-never-appends.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,QAAQ,EAAiB,MAAM,0BAA0B,CAAC;AAQxF,eAAO,MAAM,mCAAmC,2FA6C9C,CAAC"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { AST_NODE_TYPES } from '@typescript-eslint/utils';
|
|
2
|
+
import { kernelNamesListener } from '../support/event-sourcing/kernel-names-listener.js';
|
|
3
|
+
import { importListener } from '../support/imports/import-listener.js';
|
|
4
|
+
import { defineRule } from '../support/rule/define-rule.js';
|
|
5
|
+
const APPENDING = new Set(['EventStore', 'EventSourcedRepository']);
|
|
6
|
+
export const eventSourcingProjectionNeverAppends = defineRule({
|
|
7
|
+
id: 'event-sourcing/projection-never-appends',
|
|
8
|
+
type: 'problem',
|
|
9
|
+
recommended: 'error',
|
|
10
|
+
description: 'A projection never appends to a stream: it names no event store, and a projection fed by the event store names no repository of domain/repositories/ either.',
|
|
11
|
+
messages: {
|
|
12
|
+
appends: 'The projection names {{name}}: it could append to a stream, and would append again at every rebuild. A projection writes its read model through its port; a fact worth keeping is decided by a command.',
|
|
13
|
+
},
|
|
14
|
+
create({ file, report }) {
|
|
15
|
+
const { location } = file;
|
|
16
|
+
if (location.area !== 'context' || file.isTest) {
|
|
17
|
+
return {};
|
|
18
|
+
}
|
|
19
|
+
const named = [];
|
|
20
|
+
const repositoryNames = [];
|
|
21
|
+
const listeners = [
|
|
22
|
+
kernelNamesListener(file, APPENDING, (imported) => named.push(imported)),
|
|
23
|
+
repositories(file, repositoryNames),
|
|
24
|
+
];
|
|
25
|
+
let declared = location.layer === 'application' && location.inside[0] === 'projections';
|
|
26
|
+
let storeFed = false;
|
|
27
|
+
return {
|
|
28
|
+
ImportDeclaration(node) {
|
|
29
|
+
listeners.forEach((listener) => listener.ImportDeclaration?.(node));
|
|
30
|
+
},
|
|
31
|
+
Decorator(node) {
|
|
32
|
+
declared ||= isProjectionDecorator(node);
|
|
33
|
+
storeFed ||= isProjectionDecorator(node) && feedsFromStore(node);
|
|
34
|
+
},
|
|
35
|
+
'Program:exit'() {
|
|
36
|
+
const appending = [...named, ...(storeFed ? repositoryNames : [])];
|
|
37
|
+
for (const { name, node } of declared ? appending : []) {
|
|
38
|
+
report({ node, messageId: 'appends', data: { name } });
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
/** Notes what the file imports from `domain/repositories/`. */
|
|
45
|
+
function repositories(file, named) {
|
|
46
|
+
return importListener(file, ({ target, names }) => {
|
|
47
|
+
const isRepository = target.kind === 'file' &&
|
|
48
|
+
target.location.area === 'context' &&
|
|
49
|
+
target.location.layer === 'domain' &&
|
|
50
|
+
target.location.inside[0] === 'repositories';
|
|
51
|
+
if (isRepository) {
|
|
52
|
+
named.push(...names);
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
/** `@Projection(name, { feed: 'event-store' })`: replayed from position zero at every rebuild. */
|
|
57
|
+
function feedsFromStore({ expression }) {
|
|
58
|
+
const options = expression.type === AST_NODE_TYPES.CallExpression ? expression.arguments[1] : undefined;
|
|
59
|
+
return (options?.type === AST_NODE_TYPES.ObjectExpression &&
|
|
60
|
+
options.properties.some((property) => property.type === AST_NODE_TYPES.Property &&
|
|
61
|
+
property.key.type === AST_NODE_TYPES.Identifier &&
|
|
62
|
+
property.key.name === 'feed' &&
|
|
63
|
+
property.value.type === AST_NODE_TYPES.Literal &&
|
|
64
|
+
property.value.value === 'event-store'));
|
|
65
|
+
}
|
|
66
|
+
function isProjectionDecorator(node) {
|
|
67
|
+
const { expression } = node;
|
|
68
|
+
return (expression.type === AST_NODE_TYPES.CallExpression &&
|
|
69
|
+
expression.callee.type === AST_NODE_TYPES.Identifier &&
|
|
70
|
+
expression.callee.name === 'Projection');
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=event-sourcing-projection-never-appends.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-sourcing-projection-never-appends.js","sourceRoot":"","sources":["../../src/rules/event-sourcing-projection-never-appends.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
type MessageId = 'outsideApply' | 'recordedInApply';
|
|
2
|
+
export declare const eventSourcingStateInApply: import("@typescript-eslint/utils/ts-eslint").RuleModule<MessageId, [], import("../index.js").RuleDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
|
3
|
+
export {};
|
|
4
|
+
//# sourceMappingURL=event-sourcing-state-in-apply.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-sourcing-state-in-apply.d.ts","sourceRoot":"","sources":["../../src/rules/event-sourcing-state-in-apply.ts"],"names":[],"mappings":"AAkCA,KAAK,SAAS,GAAG,cAAc,GAAG,iBAAiB,CAAC;AAEpD,eAAO,MAAM,yBAAyB,mKAiCpC,CAAC"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { AST_NODE_TYPES } from '@typescript-eslint/utils';
|
|
2
|
+
import { className } from '../support/classes/class-name.js';
|
|
3
|
+
import { enclosingMember } from '../support/classes/enclosing-member.js';
|
|
4
|
+
import { memberName } from '../support/classes/member-name.js';
|
|
5
|
+
import { isAggregateFile } from '../support/event-sourcing/is-aggregate-file.js';
|
|
6
|
+
import { isEventSourcedClass } from '../support/event-sourcing/is-event-sourced-class.js';
|
|
7
|
+
import { propertyName } from '../support/globals/property-name.js';
|
|
8
|
+
import { startsAtThis } from '../support/members/starts-at-this.js';
|
|
9
|
+
import { defineRule } from '../support/rule/define-rule.js';
|
|
10
|
+
const MUTATORS = new Set([
|
|
11
|
+
'push',
|
|
12
|
+
'pop',
|
|
13
|
+
'shift',
|
|
14
|
+
'unshift',
|
|
15
|
+
'splice',
|
|
16
|
+
'sort',
|
|
17
|
+
'reverse',
|
|
18
|
+
'fill',
|
|
19
|
+
'copyWithin',
|
|
20
|
+
'set',
|
|
21
|
+
'add',
|
|
22
|
+
'delete',
|
|
23
|
+
'clear',
|
|
24
|
+
]);
|
|
25
|
+
const APPLY = /^apply[A-Z]/;
|
|
26
|
+
export const eventSourcingStateInApply = defineRule({
|
|
27
|
+
id: 'event-sourcing/state-in-apply',
|
|
28
|
+
type: 'problem',
|
|
29
|
+
recommended: 'error',
|
|
30
|
+
description: 'An event-sourced aggregate changes its state only in its apply methods (`apply<Fact>`, `restore` for a snapshot), and an apply method records no event.',
|
|
31
|
+
messages: {
|
|
32
|
+
outsideApply: '{{method}} of the event-sourced aggregate {{className}} writes {{target}} outside an apply method. Record the event of what the command decided, `this.record(new <Fact>(...))`, and change the state in `apply<Fact>(event)`: a replay rebuilds only what the apply methods write.',
|
|
33
|
+
recordedInApply: 'The apply method {{method}} of {{className}} records an event: a replay would record it again. Record the follow-up fact from the command that decides it.',
|
|
34
|
+
},
|
|
35
|
+
create({ file, sourceCode, report }) {
|
|
36
|
+
if (!isAggregateFile(file)) {
|
|
37
|
+
return {};
|
|
38
|
+
}
|
|
39
|
+
const written = (node, target) => {
|
|
40
|
+
const judged = judgedAt(node);
|
|
41
|
+
if (judged !== undefined && !judged.applies && startsAtThis(target)) {
|
|
42
|
+
const data = { method: judged.method, className: judged.owner, target: sourceCode.getText(target) };
|
|
43
|
+
report({ node, messageId: 'outsideApply', data });
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
return {
|
|
47
|
+
AssignmentExpression: (node) => written(node, node.left),
|
|
48
|
+
UpdateExpression: (node) => written(node, node.argument),
|
|
49
|
+
CallExpression: (node) => called(node, written, report),
|
|
50
|
+
};
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
/** A mutating call writes what it is called on; `this.record(..)` in an apply method records again at each replay. */
|
|
54
|
+
function called(node, written, report) {
|
|
55
|
+
if (node.callee.type !== AST_NODE_TYPES.MemberExpression) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
const name = propertyName(node.callee) ?? '';
|
|
59
|
+
if (MUTATORS.has(name)) {
|
|
60
|
+
written(node, node.callee.object);
|
|
61
|
+
}
|
|
62
|
+
const judged = judgedAt(node);
|
|
63
|
+
if (name === 'record' && node.callee.object.type === AST_NODE_TYPES.ThisExpression && judged?.applies === true) {
|
|
64
|
+
report({ node, messageId: 'recordedInApply', data: { method: judged.method, className: judged.owner } });
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/** The method of an event-sourced class around the node, unless it is the constructor or a static method. */
|
|
68
|
+
function judgedAt(node) {
|
|
69
|
+
const site = enclosingMember(node);
|
|
70
|
+
if (site === undefined || !isEventSourcedClass(site.body.parent)) {
|
|
71
|
+
return undefined;
|
|
72
|
+
}
|
|
73
|
+
const { member } = site;
|
|
74
|
+
const isMethod = member.type === AST_NODE_TYPES.MethodDefinition;
|
|
75
|
+
if (!isMethod || member.static || member.kind === 'constructor') {
|
|
76
|
+
return undefined;
|
|
77
|
+
}
|
|
78
|
+
const method = memberName(member) ?? '';
|
|
79
|
+
return { method, owner: className(site.body.parent), applies: APPLY.test(method) || method === 'restore' };
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=event-sourcing-state-in-apply.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-sourcing-state-in-apply.js","sourceRoot":"","sources":["../../src/rules/event-sourcing-state-in-apply.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export declare const eventSourcingStoreBehindRepository: import("@typescript-eslint/utils/ts-eslint").RuleModule<"store", [], import("../index.js").RuleDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
|
2
|
+
//# sourceMappingURL=event-sourcing-store-behind-repository.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-sourcing-store-behind-repository.d.ts","sourceRoot":"","sources":["../../src/rules/event-sourcing-store-behind-repository.ts"],"names":[],"mappings":"AAaA,eAAO,MAAM,kCAAkC,iKAyB7C,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { kernelNamesListener } from '../support/event-sourcing/kernel-names-listener.js';
|
|
2
|
+
import { defineRule } from '../support/rule/define-rule.js';
|
|
3
|
+
const STORE_NAMES = new Set([
|
|
4
|
+
'EventStore',
|
|
5
|
+
'SnapshotStore',
|
|
6
|
+
'CheckpointStore',
|
|
7
|
+
'EventSourcedRepository',
|
|
8
|
+
'EventSerializer',
|
|
9
|
+
'CatchUpSubscription',
|
|
10
|
+
'InMemoryEventStore',
|
|
11
|
+
]);
|
|
12
|
+
export const eventSourcingStoreBehindRepository = defineRule({
|
|
13
|
+
id: 'event-sourcing/store-behind-repository',
|
|
14
|
+
type: 'problem',
|
|
15
|
+
recommended: 'error',
|
|
16
|
+
description: 'domain/ and application/ never name the event store, its snapshots, checkpoints, serializer or subscriptions: an event-sourced aggregate is loaded and saved through its repository port.',
|
|
17
|
+
messages: {
|
|
18
|
+
store: '{{name}} is named in {{layer}}/: the domain and the use cases never read the event store. Load and save the aggregate through its repository port; its adapter in infrastructure/persistence/ delegates to EventSourcedRepository, and a read across streams is a projection fed by the store.',
|
|
19
|
+
},
|
|
20
|
+
create({ file, report }) {
|
|
21
|
+
const { location } = file;
|
|
22
|
+
if (location.area !== 'context' ||
|
|
23
|
+
file.isTest ||
|
|
24
|
+
(location.layer !== 'domain' && location.layer !== 'application')) {
|
|
25
|
+
return {};
|
|
26
|
+
}
|
|
27
|
+
return kernelNamesListener(file, STORE_NAMES, ({ name, node }) => {
|
|
28
|
+
report({ node, messageId: 'store', data: { name, layer: location.layer } });
|
|
29
|
+
});
|
|
30
|
+
},
|
|
31
|
+
});
|
|
32
|
+
//# sourceMappingURL=event-sourcing-store-behind-repository.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-sourcing-store-behind-repository.js","sourceRoot":"","sources":["../../src/rules/event-sourcing-store-behind-repository.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,oDAAoD,CAAC;AACzF,OAAO,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AAE5D,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC;IAC1B,YAAY;IACZ,eAAe;IACf,iBAAiB;IACjB,wBAAwB;IACxB,iBAAiB;IACjB,qBAAqB;IACrB,oBAAoB;CACrB,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,kCAAkC,GAAG,UAAU,CAAU;IACpE,EAAE,EAAE,wCAAwC;IAC5C,IAAI,EAAE,SAAS;IACf,WAAW,EAAE,OAAO;IACpB,WAAW,EACT,2LAA2L;IAC7L,QAAQ,EAAE;QACR,KAAK,EACH,gSAAgS;KACnS;IACD,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE;QACrB,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC;QAE1B,IACE,QAAQ,CAAC,IAAI,KAAK,SAAS;YAC3B,IAAI,CAAC,MAAM;YACX,CAAC,QAAQ,CAAC,KAAK,KAAK,QAAQ,IAAI,QAAQ,CAAC,KAAK,KAAK,aAAa,CAAC,EACjE,CAAC;YACD,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,OAAO,mBAAmB,CAAC,IAAI,EAAE,WAAW,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE;YAC/D,MAAM,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAC9E,CAAC,CAAC,CAAC;IACL,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
type MessageId = 'unnamed' | 'undeclared' | 'unresolved' | 'missingUpcaster';
|
|
2
|
+
export declare const eventSourcingUpcasterRequired: import("@typescript-eslint/utils/ts-eslint").RuleModule<MessageId, [], import("../index.js").RuleDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
|
3
|
+
export {};
|
|
4
|
+
//# sourceMappingURL=event-sourcing-upcaster-required.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-sourcing-upcaster-required.d.ts","sourceRoot":"","sources":["../../src/rules/event-sourcing-upcaster-required.ts"],"names":[],"mappings":"AAIA,KAAK,SAAS,GAAG,SAAS,GAAG,YAAY,GAAG,YAAY,GAAG,iBAAiB,CAAC;AAQ7E,eAAO,MAAM,6BAA6B,mKA2CxC,CAAC"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { AST_NODE_TYPES } from '@typescript-eslint/utils';
|
|
2
|
+
import { unresolvedTypes } from '../support/event-sourcing/unresolved-types.js';
|
|
3
|
+
import { defineRule } from '../support/rule/define-rule.js';
|
|
4
|
+
export const eventSourcingUpcasterRequired = defineRule({
|
|
5
|
+
id: 'event-sourcing/upcaster-required',
|
|
6
|
+
type: 'problem',
|
|
7
|
+
recommended: 'error',
|
|
8
|
+
description: 'A stored event names the type of its data in `encode` and declares it, with every named type it reaches, in its codec file, and a version above 1 has an upcaster from each version below. The lock of recorded shapes is read by `ddd-ts-kit check`.',
|
|
9
|
+
messages: {
|
|
10
|
+
unnamed: 'The encode of {{eventClass}} does not name the type of the data it stores. Write the stored shape as a named type in this file and answer it: `encode: (event): InvoiceIssuedData => ({ ... })`.',
|
|
11
|
+
undeclared: '{{type}}, the data of {{eventClass}}, is not declared in this file. Declare it next to the events it stores: it is the stored shape, kept even when the domain event changes.',
|
|
12
|
+
unresolved: '{{name}}, reached by {{type}} of {{eventClass}}, is not declared in this file: a change of it would change the stored shape unseen. Declare its stored shape in the codec file too, mapped from the domain type in encode.',
|
|
13
|
+
missingUpcaster: '{{eventClass}} is stored in version {{version}} and has no upcaster from version {{from}}. Add `upcasters: { {{from}}: (data) => ({ ...data }) }`: events stored in version {{from}} are read through it.',
|
|
14
|
+
},
|
|
15
|
+
create({ report }) {
|
|
16
|
+
const declared = new Map();
|
|
17
|
+
const stored = [];
|
|
18
|
+
return {
|
|
19
|
+
TSInterfaceDeclaration: (node) => declared.set(node.id.name, node),
|
|
20
|
+
TSTypeAliasDeclaration: (node) => declared.set(node.id.name, node),
|
|
21
|
+
TSEnumDeclaration: (node) => declared.set(node.id.name, node),
|
|
22
|
+
CallExpression(node) {
|
|
23
|
+
const [type, spec] = node.arguments;
|
|
24
|
+
if (node.callee.type === AST_NODE_TYPES.Identifier &&
|
|
25
|
+
node.callee.name === 'defineStoredEvent' &&
|
|
26
|
+
type?.type === AST_NODE_TYPES.Identifier &&
|
|
27
|
+
spec?.type === AST_NODE_TYPES.ObjectExpression) {
|
|
28
|
+
stored.push({ node, eventClass: type.name, spec });
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
'Program:exit'() {
|
|
32
|
+
for (const event of stored) {
|
|
33
|
+
judge(event, declared, report);
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
function judge(event, declared, report) {
|
|
40
|
+
const { node, eventClass, spec } = event;
|
|
41
|
+
judgeShape(event, declared, report);
|
|
42
|
+
const version = numberOf(property(spec, 'version'));
|
|
43
|
+
const upcasters = upcasterKeys(property(spec, 'upcasters'));
|
|
44
|
+
for (let from = 1; from < (version ?? 1); from += 1) {
|
|
45
|
+
if (!upcasters.includes(from)) {
|
|
46
|
+
report({
|
|
47
|
+
node,
|
|
48
|
+
messageId: 'missingUpcaster',
|
|
49
|
+
data: { eventClass, version: String(version), from: String(from) },
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
/** The data type is named, declared in the file, and so is every named type it reaches. */
|
|
55
|
+
function judgeShape({ node, eventClass, spec }, declared, report) {
|
|
56
|
+
const type = payloadType(property(spec, 'encode'));
|
|
57
|
+
if (type === undefined) {
|
|
58
|
+
report({ node, messageId: 'unnamed', data: { eventClass } });
|
|
59
|
+
}
|
|
60
|
+
else if (!declared.has(type)) {
|
|
61
|
+
report({ node, messageId: 'undeclared', data: { eventClass, type } });
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
for (const name of unresolvedTypes(type, declared)) {
|
|
65
|
+
report({ node, messageId: 'unresolved', data: { eventClass, type, name } });
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
function property(spec, name) {
|
|
70
|
+
const found = spec.properties.find((candidate) => candidate.type === AST_NODE_TYPES.Property && keyOf(candidate.key) === name);
|
|
71
|
+
return found?.value;
|
|
72
|
+
}
|
|
73
|
+
function keyOf(key) {
|
|
74
|
+
if (key.type === AST_NODE_TYPES.Identifier) {
|
|
75
|
+
return key.name;
|
|
76
|
+
}
|
|
77
|
+
return key.type === AST_NODE_TYPES.Literal ? String(key.value) : undefined;
|
|
78
|
+
}
|
|
79
|
+
/** The name of the type an `encode` arrow, function or method declares as its return type. */
|
|
80
|
+
function payloadType(encode) {
|
|
81
|
+
const isFunction = encode?.type === AST_NODE_TYPES.ArrowFunctionExpression || encode?.type === AST_NODE_TYPES.FunctionExpression;
|
|
82
|
+
const annotation = isFunction ? encode.returnType?.typeAnnotation : undefined;
|
|
83
|
+
return annotation?.type === AST_NODE_TYPES.TSTypeReference && annotation.typeName.type === AST_NODE_TYPES.Identifier
|
|
84
|
+
? annotation.typeName.name
|
|
85
|
+
: undefined;
|
|
86
|
+
}
|
|
87
|
+
function numberOf(value) {
|
|
88
|
+
return value?.type === AST_NODE_TYPES.Literal && typeof value.value === 'number' ? value.value : undefined;
|
|
89
|
+
}
|
|
90
|
+
function upcasterKeys(value) {
|
|
91
|
+
if (value?.type !== AST_NODE_TYPES.ObjectExpression) {
|
|
92
|
+
return [];
|
|
93
|
+
}
|
|
94
|
+
return value.properties.flatMap((candidate) => candidate.type === AST_NODE_TYPES.Property ? [Number(keyOf(candidate.key))] : []);
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=event-sourcing-upcaster-required.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-sourcing-upcaster-required.js","sourceRoot":"","sources":["../../src/rules/event-sourcing-upcaster-required.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rules.d.ts","sourceRoot":"","sources":["../../src/rules/rules.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,KAAK,OAAO,EAAE,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"rules.d.ts","sourceRoot":"","sources":["../../src/rules/rules.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,KAAK,OAAO,EAAE,MAAM,4BAA4B,CAAC;AAkIlE,+HAA+H;AAC/H,eAAO,MAAM,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAEnD,CAAC"}
|
package/dist/rules/rules.js
CHANGED
|
@@ -23,6 +23,11 @@ import { domainAggregateEncapsulation } from './domain-aggregate-encapsulation.j
|
|
|
23
23
|
import { domainEventsDispatchedOnSave } from './domain-events-dispatched-on-save.js';
|
|
24
24
|
import { domainEventsTransactionalBeforeCommit } from './domain-events-transactional-before-commit.js';
|
|
25
25
|
import { domainNoGenericError } from './domain-no-generic-error.js';
|
|
26
|
+
import { eventSourcingPastTense } from './event-sourcing-past-tense.js';
|
|
27
|
+
import { eventSourcingProjectionNeverAppends } from './event-sourcing-projection-never-appends.js';
|
|
28
|
+
import { eventSourcingStateInApply } from './event-sourcing-state-in-apply.js';
|
|
29
|
+
import { eventSourcingStoreBehindRepository } from './event-sourcing-store-behind-repository.js';
|
|
30
|
+
import { eventSourcingUpcasterRequired } from './event-sourcing-upcaster-required.js';
|
|
26
31
|
import { errorsConstructorNotPublic } from './errors-constructor-not-public.js';
|
|
27
32
|
import { errorsFactoryName } from './errors-factory-name.js';
|
|
28
33
|
import { errorsThroughFactory } from './errors-through-factory.js';
|
|
@@ -85,6 +90,11 @@ const ALL = [
|
|
|
85
90
|
applicationCommandQuerySeparation,
|
|
86
91
|
domainEventsDispatchedOnSave,
|
|
87
92
|
domainEventsTransactionalBeforeCommit,
|
|
93
|
+
eventSourcingStateInApply,
|
|
94
|
+
eventSourcingPastTense,
|
|
95
|
+
eventSourcingStoreBehindRepository,
|
|
96
|
+
eventSourcingProjectionNeverAppends,
|
|
97
|
+
eventSourcingUpcasterRequired,
|
|
88
98
|
testNoMocks,
|
|
89
99
|
eventsNameFormat,
|
|
90
100
|
eventsOutboxRequired,
|
package/dist/rules/rules.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rules.js","sourceRoot":"","sources":["../../src/rules/rules.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"rules.js","sourceRoot":"","sources":["../../src/rules/rules.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The words of the fact an event names, after the name of its aggregate: `InvoiceIssued` of
|
|
3
|
+
* `Invoice` is `issued`. The whole name when it does not start with the name of an aggregate.
|
|
4
|
+
*/
|
|
5
|
+
export declare function factWords(eventName: string, aggregates: readonly string[]): string[];
|
|
6
|
+
//# sourceMappingURL=fact-words.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fact-words.d.ts","sourceRoot":"","sources":["../../../src/support/event-sourcing/fact-words.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,wBAAgB,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,EAAE,CAMpF"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { wordsOf } from './words-of.js';
|
|
2
|
+
/**
|
|
3
|
+
* The words of the fact an event names, after the name of its aggregate: `InvoiceIssued` of
|
|
4
|
+
* `Invoice` is `issued`. The whole name when it does not start with the name of an aggregate.
|
|
5
|
+
*/
|
|
6
|
+
export function factWords(eventName, aggregates) {
|
|
7
|
+
const owner = aggregates.find((aggregate) => eventName.startsWith(aggregate) && /^[A-Z]/.test(eventName.slice(aggregate.length)));
|
|
8
|
+
return wordsOf(owner === undefined ? eventName : eventName.slice(owner.length));
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=fact-words.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fact-words.js","sourceRoot":"","sources":["../../../src/support/event-sourcing/fact-words.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAExC;;;GAGG;AACH,MAAM,UAAU,SAAS,CAAC,SAAiB,EAAE,UAA6B;IACxE,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,CAC3B,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CACnG,CAAC;IAEF,OAAO,OAAO,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;AAClF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"is-aggregate-file.d.ts","sourceRoot":"","sources":["../../../src/support/event-sourcing/is-aggregate-file.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAE/D,8DAA8D;AAC9D,wBAAgB,eAAe,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAMzD"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** A production file of `domain/aggregates/` of a context. */
|
|
2
|
+
export function isAggregateFile(file) {
|
|
3
|
+
const { location } = file;
|
|
4
|
+
return (location.area === 'context' && !file.isTest && location.layer === 'domain' && location.inside[0] === 'aggregates');
|
|
5
|
+
}
|
|
6
|
+
//# sourceMappingURL=is-aggregate-file.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"is-aggregate-file.js","sourceRoot":"","sources":["../../../src/support/event-sourcing/is-aggregate-file.ts"],"names":[],"mappings":"AAEA,8DAA8D;AAC9D,MAAM,UAAU,eAAe,CAAC,IAAgB;IAC9C,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC;IAE1B,OAAO,CACL,QAAQ,CAAC,IAAI,KAAK,SAAS,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,QAAQ,CAAC,KAAK,KAAK,QAAQ,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,YAAY,CAClH,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type TSESTree } from '@typescript-eslint/utils';
|
|
2
|
+
/** Whether a class extends `EventSourcedAggregate` of the kernel, with or without type arguments. */
|
|
3
|
+
export declare function isEventSourcedClass(node: TSESTree.Node | undefined): boolean;
|
|
4
|
+
//# sourceMappingURL=is-event-sourced-class.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"is-event-sourced-class.d.ts","sourceRoot":"","sources":["../../../src/support/event-sourcing/is-event-sourced-class.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAEzE,qGAAqG;AACrG,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,GAAG,SAAS,GAAG,OAAO,CAM5E"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { AST_NODE_TYPES } from '@typescript-eslint/utils';
|
|
2
|
+
/** Whether a class extends `EventSourcedAggregate` of the kernel, with or without type arguments. */
|
|
3
|
+
export function isEventSourcedClass(node) {
|
|
4
|
+
return ((node?.type === AST_NODE_TYPES.ClassDeclaration || node?.type === AST_NODE_TYPES.ClassExpression) &&
|
|
5
|
+
node.superClass?.type === AST_NODE_TYPES.Identifier &&
|
|
6
|
+
node.superClass.name === 'EventSourcedAggregate');
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=is-event-sourced-class.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"is-event-sourced-class.js","sourceRoot":"","sources":["../../../src/support/event-sourcing/is-event-sourced-class.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAiB,MAAM,0BAA0B,CAAC;AAEzE,qGAAqG;AACrG,MAAM,UAAU,mBAAmB,CAAC,IAA+B;IACjE,OAAO,CACL,CAAC,IAAI,EAAE,IAAI,KAAK,cAAc,CAAC,gBAAgB,IAAI,IAAI,EAAE,IAAI,KAAK,cAAc,CAAC,eAAe,CAAC;QACjG,IAAI,CAAC,UAAU,EAAE,IAAI,KAAK,cAAc,CAAC,UAAU;QACnD,IAAI,CAAC,UAAU,CAAC,IAAI,KAAK,uBAAuB,CACjD,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"is-past-fact.d.ts","sourceRoot":"","sources":["../../../src/support/event-sourcing/is-past-fact.ts"],"names":[],"mappings":"AAYA,gHAAgH;AAChH,wBAAgB,UAAU,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAI5D"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { isPastParticiple } from './is-past-participle.js';
|
|
2
|
+
/**
|
|
3
|
+
* Past participles spelled like the imperative of their verb: at the head of a name they read as
|
|
4
|
+
* a command (`SetPrice`, `ReadInvoice`, `RunReport`), after a noun as a fact (`PriceSet`). The
|
|
5
|
+
* same list as the generator and the checker of the CLI, held equal by a test of the CLI.
|
|
6
|
+
*/
|
|
7
|
+
const READS_AS_COMMAND = new Set([
|
|
8
|
+
...['bid', 'bound', 'cast', 'come', 'become', 'cut', 'forecast', 'found', 'hit', 'left', 'put'],
|
|
9
|
+
...['quit', 'read', 'rerun', 'reset', 'run', 'set', 'shed', 'shut', 'split', 'spread'],
|
|
10
|
+
]);
|
|
11
|
+
/** Whether the words of the fact of an event, its name after its aggregate, read as something that happened. */
|
|
12
|
+
export function isPastFact(words) {
|
|
13
|
+
return words.some((word, index) => isPastParticiple(word) && !(index === 0 && READS_AS_COMMAND.has(word.toLowerCase())));
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=is-past-fact.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"is-past-fact.js","sourceRoot":"","sources":["../../../src/support/event-sourcing/is-past-fact.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAE3D;;;;GAIG;AACH,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC;IAC/B,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC;IAC/F,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,CAAC;CACvF,CAAC,CAAC;AAEH,gHAAgH;AAChH,MAAM,UAAU,UAAU,CAAC,KAAwB;IACjD,OAAO,KAAK,CAAC,IAAI,CACf,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,KAAK,CAAC,IAAI,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CACtG,CAAC;AACJ,CAAC"}
|