@ddd-ts-kit/eslint-plugin 0.2.0 → 0.4.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.
Files changed (67) hide show
  1. package/README.md +6 -0
  2. package/dist/project/config.d.ts +2 -0
  3. package/dist/project/config.d.ts.map +1 -1
  4. package/dist/project/parse-config.d.ts.map +1 -1
  5. package/dist/project/parse-config.js +2 -0
  6. package/dist/project/parse-config.js.map +1 -1
  7. package/dist/rules/authz-declared.d.ts +1 -1
  8. package/dist/rules/authz-declared.d.ts.map +1 -1
  9. package/dist/rules/authz-declared.js +18 -0
  10. package/dist/rules/authz-declared.js.map +1 -1
  11. package/dist/rules/domain-no-generic-error.js +1 -1
  12. package/dist/rules/domain-no-generic-error.js.map +1 -1
  13. package/dist/rules/errors-constructor-not-public.d.ts +2 -0
  14. package/dist/rules/errors-constructor-not-public.d.ts.map +1 -0
  15. package/dist/rules/errors-constructor-not-public.js +41 -0
  16. package/dist/rules/errors-constructor-not-public.js.map +1 -0
  17. package/dist/rules/errors-factory-name.d.ts +4 -0
  18. package/dist/rules/errors-factory-name.d.ts.map +1 -0
  19. package/dist/rules/errors-factory-name.js +88 -0
  20. package/dist/rules/errors-factory-name.js.map +1 -0
  21. package/dist/rules/errors-through-factory.d.ts +2 -0
  22. package/dist/rules/errors-through-factory.d.ts.map +1 -0
  23. package/dist/rules/errors-through-factory.js +39 -0
  24. package/dist/rules/errors-through-factory.js.map +1 -0
  25. package/dist/rules/presentation-controller-delegates.d.ts +4 -0
  26. package/dist/rules/presentation-controller-delegates.d.ts.map +1 -0
  27. package/dist/rules/presentation-controller-delegates.js +85 -0
  28. package/dist/rules/presentation-controller-delegates.js.map +1 -0
  29. package/dist/rules/presentation-controller-shape.d.ts +4 -0
  30. package/dist/rules/presentation-controller-shape.d.ts.map +1 -0
  31. package/dist/rules/presentation-controller-shape.js +49 -0
  32. package/dist/rules/presentation-controller-shape.js.map +1 -0
  33. package/dist/rules/presentation-guard-at-the-edge.d.ts +4 -0
  34. package/dist/rules/presentation-guard-at-the-edge.d.ts.map +1 -0
  35. package/dist/rules/presentation-guard-at-the-edge.js +39 -0
  36. package/dist/rules/presentation-guard-at-the-edge.js.map +1 -0
  37. package/dist/rules/rules.d.ts.map +1 -1
  38. package/dist/rules/rules.js +12 -0
  39. package/dist/rules/rules.js.map +1 -1
  40. package/dist/support/declarations/declaration-reader.d.ts +1 -1
  41. package/dist/support/declarations/declaration-reader.d.ts.map +1 -1
  42. package/dist/support/declarations/declaration-reader.js +5 -2
  43. package/dist/support/declarations/declaration-reader.js.map +1 -1
  44. package/dist/support/declarations/declared-roles.d.ts.map +1 -1
  45. package/dist/support/declarations/declared-roles.js +4 -0
  46. package/dist/support/declarations/declared-roles.js.map +1 -1
  47. package/dist/support/errors/constant-case.d.ts +3 -0
  48. package/dist/support/errors/constant-case.d.ts.map +1 -0
  49. package/dist/support/errors/constant-case.js +6 -0
  50. package/dist/support/errors/constant-case.js.map +1 -0
  51. package/dist/support/errors/is-error-class.d.ts +4 -0
  52. package/dist/support/errors/is-error-class.d.ts.map +1 -0
  53. package/dist/support/errors/is-error-class.js +6 -0
  54. package/dist/support/errors/is-error-class.js.map +1 -0
  55. package/dist/support/errors/is-error-file.d.ts +4 -0
  56. package/dist/support/errors/is-error-file.d.ts.map +1 -0
  57. package/dist/support/errors/is-error-file.js +10 -0
  58. package/dist/support/errors/is-error-file.js.map +1 -0
  59. package/dist/version.d.ts +1 -1
  60. package/dist/version.js +1 -1
  61. package/docs/rules/errors-constructor-not-public.md +53 -0
  62. package/docs/rules/errors-factory-name.md +50 -0
  63. package/docs/rules/errors-through-factory.md +45 -0
  64. package/docs/rules/presentation-controller-delegates.md +57 -0
  65. package/docs/rules/presentation-controller-shape.md +50 -0
  66. package/docs/rules/presentation-guard-at-the-edge.md +55 -0
  67. package/package.json +1 -1
@@ -0,0 +1,4 @@
1
+ type MessageId = 'reachesInside' | 'reachesName';
2
+ export declare const presentationGuardAtTheEdge: import("@typescript-eslint/utils/ts-eslint").RuleModule<MessageId, [], import("../index.js").RuleDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
3
+ export {};
4
+ //# sourceMappingURL=presentation-guard-at-the-edge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"presentation-guard-at-the-edge.d.ts","sourceRoot":"","sources":["../../src/rules/presentation-guard-at-the-edge.ts"],"names":[],"mappings":"AAGA,KAAK,SAAS,GAAG,eAAe,GAAG,aAAa,CAAC;AAMjD,eAAO,MAAM,0BAA0B,mKAyCrC,CAAC"}
@@ -0,0 +1,39 @@
1
+ import { AST_NODE_TYPES } from '@typescript-eslint/utils';
2
+ import { defineRule } from '../support/rule/define-rule.js';
3
+ const INSIDE = /(?:^|\/)(domain|infrastructure)\//;
4
+ /** What a guard has no business holding, by the name it is imported under. */
5
+ const FORBIDDEN_NAME = /(?:Repository|UnitOfWork)$|^CommandBus$/;
6
+ export const presentationGuardAtTheEdge = defineRule({
7
+ id: 'presentation/guard-at-the-edge',
8
+ type: 'problem',
9
+ recommended: 'error',
10
+ description: 'A guard controls the caller at the edge and nothing else: a `*.guard.ts` file imports nothing from `domain/` or `infrastructure/`, no repository, no unit of work and no command bus.',
11
+ messages: {
12
+ reachesInside: 'This guard imports "{{specifier}}", from {{layer}}/. A guard reads the caller and the request: the role, the tenant, a key, a parameter of the path. A right that depends on an element of the model is a permission of the use case (`@Requires`, a policy), held for every caller of the use case, a job and an event handler included. Remove the import and move the decision there.',
13
+ reachesName: 'This guard imports {{name}}. A guard never loads an aggregate and never changes anything: what needs {{name}} is a decision of the use case (`@Requires`, a policy). A guard may ask a port of application/ports a question about the caller, and nothing more.',
14
+ },
15
+ create({ file, report }) {
16
+ if (file.isTest || !file.path.endsWith('.guard.ts')) {
17
+ return {};
18
+ }
19
+ return {
20
+ ImportDeclaration(node) {
21
+ const specifier = node.source.value;
22
+ const layer = INSIDE.exec(specifier)?.[1];
23
+ if (layer !== undefined) {
24
+ report({ node, messageId: 'reachesInside', data: { specifier, layer } });
25
+ return;
26
+ }
27
+ for (const imported of node.specifiers) {
28
+ const name = imported.type === AST_NODE_TYPES.ImportSpecifier && imported.imported.type === AST_NODE_TYPES.Identifier
29
+ ? imported.imported.name
30
+ : imported.local.name;
31
+ if (FORBIDDEN_NAME.test(name)) {
32
+ report({ node: imported, messageId: 'reachesName', data: { name } });
33
+ }
34
+ }
35
+ },
36
+ };
37
+ },
38
+ });
39
+ //# sourceMappingURL=presentation-guard-at-the-edge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"presentation-guard-at-the-edge.js","sourceRoot":"","sources":["../../src/rules/presentation-guard-at-the-edge.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AAI5D,MAAM,MAAM,GAAG,mCAAmC,CAAC;AACnD,8EAA8E;AAC9E,MAAM,cAAc,GAAG,yCAAyC,CAAC;AAEjE,MAAM,CAAC,MAAM,0BAA0B,GAAG,UAAU,CAAY;IAC9D,EAAE,EAAE,gCAAgC;IACpC,IAAI,EAAE,SAAS;IACf,WAAW,EAAE,OAAO;IACpB,WAAW,EACT,uLAAuL;IACzL,QAAQ,EAAE;QACR,aAAa,EACX,0XAA0X;QAC5X,WAAW,EACT,iQAAiQ;KACpQ;IACD,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE;QACrB,IAAI,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;YACpD,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,OAAO;YACL,iBAAiB,CAAC,IAAI;gBACpB,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC;gBACpC,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;gBAE1C,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;oBACxB,MAAM,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,eAAe,EAAE,IAAI,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;oBAEzE,OAAO;gBACT,CAAC;gBAED,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;oBACvC,MAAM,IAAI,GACR,QAAQ,CAAC,IAAI,KAAK,cAAc,CAAC,eAAe,IAAI,QAAQ,CAAC,QAAQ,CAAC,IAAI,KAAK,cAAc,CAAC,UAAU;wBACtG,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI;wBACxB,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC;oBAE1B,IAAI,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;wBAC9B,MAAM,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,aAAa,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;oBACvE,CAAC;gBACH,CAAC;YACH,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC,CAAC"}
@@ -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;AAwGlE,+HAA+H;AAC/H,eAAO,MAAM,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAEnD,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;AAoHlE,+HAA+H;AAC/H,eAAO,MAAM,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAEnD,CAAC"}
@@ -23,6 +23,9 @@ 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 { errorsConstructorNotPublic } from './errors-constructor-not-public.js';
27
+ import { errorsFactoryName } from './errors-factory-name.js';
28
+ import { errorsThroughFactory } from './errors-through-factory.js';
26
29
  import { domainValueObjectImmutability } from './domain-value-object-immutability.js';
27
30
  import { eventsConsumerIdempotent } from './events-consumer-idempotent.js';
28
31
  import { eventsNameFormat } from './events-name-format.js';
@@ -38,6 +41,9 @@ import { portsImplementsNeverExtends } from './ports-implements-never-extends.js
38
41
  import { portsNoConcreteDependency } from './ports-no-concrete-dependency.js';
39
42
  import { portsNoTokenConstant } from './ports-no-token-constant.js';
40
43
  import { portsValueImport } from './ports-value-import.js';
44
+ import { presentationControllerDelegates } from './presentation-controller-delegates.js';
45
+ import { presentationControllerShape } from './presentation-controller-shape.js';
46
+ import { presentationGuardAtTheEdge } from './presentation-guard-at-the-edge.js';
41
47
  import { purityNoAmbientRandomness, purityNoEnvironment, purityNoSystemClock } from './purity.js';
42
48
  import { schedulingJobName } from './scheduling-job-name.js';
43
49
  import { schedulingJobTriggersUseCase } from './scheduling-job-triggers-use-case.js';
@@ -68,6 +74,9 @@ const ALL = [
68
74
  domainAggregateEncapsulation,
69
75
  domainValueObjectImmutability,
70
76
  domainNoGenericError,
77
+ errorsThroughFactory,
78
+ errorsConstructorNotPublic,
79
+ errorsFactoryName,
71
80
  applicationHandlerShape,
72
81
  applicationCommandQuerySeparation,
73
82
  domainEventsDispatchedOnSave,
@@ -95,6 +104,9 @@ const ALL = [
95
104
  schedulingJobName,
96
105
  importsAliasOnly,
97
106
  importsExtension,
107
+ presentationControllerShape,
108
+ presentationControllerDelegates,
109
+ presentationGuardAtTheEdge,
98
110
  ];
99
111
  /** Keyed by ESLint name: the id of docs/ARCHITECTURE.md with its slash replaced by a dash, or the name of a companion rule. */
100
112
  export const rules = Object.fromEntries(ALL.map((rule) => [docsOf(rule).name, rule]));
@@ -1 +1 @@
1
- {"version":3,"file":"rules.js","sourceRoot":"","sources":["../../src/rules/rules.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAgB,MAAM,4BAA4B,CAAC;AAClE,OAAO,EAAE,iCAAiC,EAAE,MAAM,2CAA2C,CAAC;AAC9F,OAAO,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AACzE,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACnE,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,uBAAuB,EAAE,MAAM,kCAAkC,CAAC;AAC3E,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AACvE,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EACL,2BAA2B,EAC3B,mCAAmC,EACnC,4BAA4B,GAC7B,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,gCAAgC,EAAE,MAAM,yCAAyC,CAAC;AAC3F,OAAO,EAAE,wBAAwB,EAAE,MAAM,iCAAiC,CAAC;AAC3E,OAAO,EAAE,4BAA4B,EAAE,MAAM,qCAAqC,CAAC;AACnF,OAAO,EAAE,4BAA4B,EAAE,MAAM,uCAAuC,CAAC;AACrF,OAAO,EAAE,qCAAqC,EAAE,MAAM,gDAAgD,CAAC;AACvG,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,EAAE,6BAA6B,EAAE,MAAM,uCAAuC,CAAC;AACtF,OAAO,EAAE,wBAAwB,EAAE,MAAM,iCAAiC,CAAC;AAC3E,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACnE,OAAO,EAAE,2BAA2B,EAAE,MAAM,oCAAoC,CAAC;AACjF,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AACvE,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,iCAAiC,EAAE,iCAAiC,EAAE,MAAM,qBAAqB,CAAC;AAC3G,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,2BAA2B,EAAE,MAAM,qCAAqC,CAAC;AAClF,OAAO,EAAE,yBAAyB,EAAE,MAAM,mCAAmC,CAAC;AAC9E,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,yBAAyB,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClG,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,4BAA4B,EAAE,MAAM,uCAAuC,CAAC;AACrF,OAAO,EAAE,2BAA2B,EAAE,MAAM,qCAAqC,CAAC;AAClF,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAEjE,MAAM,GAAG,GAAG;IACV,iBAAiB;IACjB,sBAAsB;IACtB,iCAAiC;IACjC,iCAAiC;IACjC,4BAA4B;IAC5B,2BAA2B;IAC3B,mCAAmC;IACnC,mBAAmB;IACnB,yBAAyB;IACzB,mBAAmB;IACnB,aAAa;IACb,iBAAiB;IACjB,oBAAoB;IACpB,mBAAmB;IACnB,uBAAuB;IACvB,mBAAmB;IACnB,kBAAkB;IAClB,kBAAkB;IAClB,qBAAqB;IACrB,aAAa;IACb,4BAA4B;IAC5B,6BAA6B;IAC7B,oBAAoB;IACpB,uBAAuB;IACvB,iCAAiC;IACjC,4BAA4B;IAC5B,qCAAqC;IACrC,WAAW;IACX,gBAAgB;IAChB,oBAAoB;IACpB,wBAAwB;IACxB,kBAAkB;IAClB,aAAa;IACb,kBAAkB;IAClB,kBAAkB;IAClB,gBAAgB;IAChB,mBAAmB;IACnB,2BAA2B;IAC3B,2BAA2B;IAC3B,wBAAwB;IACxB,gCAAgC;IAChC,kBAAkB;IAClB,2BAA2B;IAC3B,oBAAoB;IACpB,yBAAyB;IACzB,gBAAgB;IAChB,4BAA4B;IAC5B,iBAAiB;IACjB,gBAAgB;IAChB,gBAAgB;CACjB,CAAC;AAEF,+HAA+H;AAC/H,MAAM,CAAC,MAAM,KAAK,GAAsC,MAAM,CAAC,WAAW,CACxE,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAC7C,CAAC"}
1
+ {"version":3,"file":"rules.js","sourceRoot":"","sources":["../../src/rules/rules.ts"],"names":[],"mappings":"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"}
@@ -12,7 +12,7 @@ export interface Declaration {
12
12
  export type DeclarationReader = (node: ClassNode) => Declaration[];
13
13
  /**
14
14
  * Reads the declarations of the classes of one program. A decorator counts when its name is
15
- * imported from the declarations entry of the kernel in that program: `{ Repository }`, an alias
15
+ * imported from the declarations entry of the kernel, or from `@ddd-ts-kit/http` for the edge, in that program: `{ Repository }`, an alias
16
16
  * `{ Repository as Repo }` or a namespace `declarations.Repository`.
17
17
  */
18
18
  export declare function declarationReader(program: TSESTree.Program): DeclarationReader;
@@ -1 +1 @@
1
- {"version":3,"file":"declaration-reader.d.ts","sourceRoot":"","sources":["../../../src/support/declarations/declaration-reader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AACzE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAI1D,qEAAqE;AACrE,eAAO,MAAM,kBAAkB,oCAAoC,CAAC;AAIpE,0FAA0F;AAC1F,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,SAAS,CAAC;IAClC,oDAAoD;IACpD,QAAQ,CAAC,SAAS,EAAE,SAAS,QAAQ,CAAC,sBAAsB,EAAE,CAAC;CAChE;AAED,MAAM,MAAM,iBAAiB,GAAG,CAAC,IAAI,EAAE,SAAS,KAAK,WAAW,EAAE,CAAC;AAEnE;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,QAAQ,CAAC,OAAO,GAAG,iBAAiB,CAoC9E"}
1
+ {"version":3,"file":"declaration-reader.d.ts","sourceRoot":"","sources":["../../../src/support/declarations/declaration-reader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AACzE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAI1D,qEAAqE;AACrE,eAAO,MAAM,kBAAkB,oCAAoC,CAAC;AAOpE,0FAA0F;AAC1F,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,SAAS,CAAC;IAClC,oDAAoD;IACpD,QAAQ,CAAC,SAAS,EAAE,SAAS,QAAQ,CAAC,sBAAsB,EAAE,CAAC;CAChE;AAED,MAAM,MAAM,iBAAiB,GAAG,CAAC,IAAI,EAAE,SAAS,KAAK,WAAW,EAAE,CAAC;AAEnE;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,QAAQ,CAAC,OAAO,GAAG,iBAAiB,CAsC9E"}
@@ -3,14 +3,17 @@ import { propertyName } from '../globals/property-name.js';
3
3
  import { DECLARED_ROLES } from './declared-roles.js';
4
4
  /** The entry of the kernel that holds the declaration decorators. */
5
5
  export const DECLARATIONS_ENTRY = '@ddd-ts-kit/kernel/declarations';
6
+ /** The entry the decorators of the edge come from: a controller, a guard, a request mapper, a serializer. */
7
+ const EDGE_ENTRY = '@ddd-ts-kit/http';
6
8
  const DECLARATION_DECORATORS = new Set(DECLARED_ROLES.flatMap((role) => role.decorators));
7
9
  /**
8
10
  * Reads the declarations of the classes of one program. A decorator counts when its name is
9
- * imported from the declarations entry of the kernel in that program: `{ Repository }`, an alias
11
+ * imported from the declarations entry of the kernel, or from `@ddd-ts-kit/http` for the edge, in that program: `{ Repository }`, an alias
10
12
  * `{ Repository as Repo }` or a namespace `declarations.Repository`.
11
13
  */
12
14
  export function declarationReader(program) {
13
- const imports = program.body.filter((statement) => statement.type === AST_NODE_TYPES.ImportDeclaration && statement.source.value === DECLARATIONS_ENTRY);
15
+ const imports = program.body.filter((statement) => statement.type === AST_NODE_TYPES.ImportDeclaration &&
16
+ (statement.source.value === DECLARATIONS_ENTRY || statement.source.value === EDGE_ENTRY));
14
17
  const specifiers = imports.flatMap((statement) => statement.type === AST_NODE_TYPES.ImportDeclaration ? statement.specifiers : []);
15
18
  const named = new Map(specifiers.flatMap(namedDeclaration));
16
19
  const namespaces = new Set(specifiers
@@ -1 +1 @@
1
- {"version":3,"file":"declaration-reader.js","sourceRoot":"","sources":["../../../src/support/declarations/declaration-reader.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"declaration-reader.js","sourceRoot":"","sources":["../../../src/support/declarations/declaration-reader.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"declared-roles.d.ts","sourceRoot":"","sources":["../../../src/support/declarations/declared-roles.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD,uFAAuF;AACvF,eAAO,MAAM,cAAc,EAAE,SAAS,YAAY,EAkBjD,CAAC"}
1
+ {"version":3,"file":"declared-roles.d.ts","sourceRoot":"","sources":["../../../src/support/declarations/declared-roles.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD,uFAAuF;AACvF,eAAO,MAAM,cAAc,EAAE,SAAS,YAAY,EAsBjD,CAAC"}
@@ -17,5 +17,9 @@ export const DECLARED_ROLES = [
17
17
  { suffix: 'repository', folders: ['infrastructure/persistence'], decorators: ['Repository'] },
18
18
  { suffix: 'gateway', folders: ['infrastructure'], decorators: ['Gateway'] },
19
19
  { suffix: 'adapter', folders: ['infrastructure'], decorators: ['Adapter'] },
20
+ { suffix: 'controller', folders: ['presentation/http'], decorators: ['Controller'] },
21
+ { suffix: 'guard', folders: ['presentation/http'], decorators: ['Guard'] },
22
+ { suffix: 'mapper', folders: ['presentation/http'], decorators: ['RequestMapper'] },
23
+ { suffix: 'serializer', folders: ['presentation/http'], decorators: ['Serializer'] },
20
24
  ];
21
25
  //# sourceMappingURL=declared-roles.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"declared-roles.js","sourceRoot":"","sources":["../../../src/support/declarations/declared-roles.ts"],"names":[],"mappings":"AAEA,uFAAuF;AACvF,MAAM,CAAC,MAAM,cAAc,GAA4B;IACrD,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,sBAAsB,CAAC,EAAE,UAAU,EAAE,CAAC,UAAU,EAAE,QAAQ,CAAC,EAAE;IAC5F,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,qBAAqB,CAAC,EAAE,UAAU,EAAE,CAAC,UAAU,EAAE,QAAQ,CAAC,EAAE;IACzF,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,sBAAsB,CAAC,EAAE,UAAU,EAAE,CAAC,gBAAgB,CAAC,EAAE;IACxF,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,qBAAqB,CAAC,EAAE,UAAU,EAAE,CAAC,cAAc,CAAC,EAAE;IACrF;QACE,MAAM,EAAE,qBAAqB;QAC7B,OAAO,EAAE,CAAC,kCAAkC,CAAC;QAC7C,UAAU,EAAE,CAAC,yBAAyB,CAAC;KACxC;IACD,EAAE,MAAM,EAAE,eAAe,EAAE,OAAO,EAAE,CAAC,4BAA4B,CAAC,EAAE,UAAU,EAAE,CAAC,oBAAoB,CAAC,EAAE;IACxG,EAAE,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC,oCAAoC,CAAC,EAAE,UAAU,EAAE,CAAC,oBAAoB,CAAC,EAAE;IAC5G,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,2BAA2B,CAAC,EAAE,UAAU,EAAE,CAAC,QAAQ,CAAC,EAAE;IACpF,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,wBAAwB,CAAC,EAAE,UAAU,EAAE,CAAC,WAAW,CAAC,EAAE;IACjF,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,CAAC,yBAAyB,CAAC,EAAE,UAAU,EAAE,CAAC,YAAY,CAAC,EAAE;IAC1F,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,CAAC,4BAA4B,CAAC,EAAE,UAAU,EAAE,CAAC,YAAY,CAAC,EAAE;IAC7F,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,gBAAgB,CAAC,EAAE,UAAU,EAAE,CAAC,SAAS,CAAC,EAAE;IAC3E,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,gBAAgB,CAAC,EAAE,UAAU,EAAE,CAAC,SAAS,CAAC,EAAE;CAC5E,CAAC"}
1
+ {"version":3,"file":"declared-roles.js","sourceRoot":"","sources":["../../../src/support/declarations/declared-roles.ts"],"names":[],"mappings":"AAEA,uFAAuF;AACvF,MAAM,CAAC,MAAM,cAAc,GAA4B;IACrD,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,sBAAsB,CAAC,EAAE,UAAU,EAAE,CAAC,UAAU,EAAE,QAAQ,CAAC,EAAE;IAC5F,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,qBAAqB,CAAC,EAAE,UAAU,EAAE,CAAC,UAAU,EAAE,QAAQ,CAAC,EAAE;IACzF,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,sBAAsB,CAAC,EAAE,UAAU,EAAE,CAAC,gBAAgB,CAAC,EAAE;IACxF,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,qBAAqB,CAAC,EAAE,UAAU,EAAE,CAAC,cAAc,CAAC,EAAE;IACrF;QACE,MAAM,EAAE,qBAAqB;QAC7B,OAAO,EAAE,CAAC,kCAAkC,CAAC;QAC7C,UAAU,EAAE,CAAC,yBAAyB,CAAC;KACxC;IACD,EAAE,MAAM,EAAE,eAAe,EAAE,OAAO,EAAE,CAAC,4BAA4B,CAAC,EAAE,UAAU,EAAE,CAAC,oBAAoB,CAAC,EAAE;IACxG,EAAE,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC,oCAAoC,CAAC,EAAE,UAAU,EAAE,CAAC,oBAAoB,CAAC,EAAE;IAC5G,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,2BAA2B,CAAC,EAAE,UAAU,EAAE,CAAC,QAAQ,CAAC,EAAE;IACpF,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,wBAAwB,CAAC,EAAE,UAAU,EAAE,CAAC,WAAW,CAAC,EAAE;IACjF,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,CAAC,yBAAyB,CAAC,EAAE,UAAU,EAAE,CAAC,YAAY,CAAC,EAAE;IAC1F,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,CAAC,4BAA4B,CAAC,EAAE,UAAU,EAAE,CAAC,YAAY,CAAC,EAAE;IAC7F,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,gBAAgB,CAAC,EAAE,UAAU,EAAE,CAAC,SAAS,CAAC,EAAE;IAC3E,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,gBAAgB,CAAC,EAAE,UAAU,EAAE,CAAC,SAAS,CAAC,EAAE;IAC3E,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,CAAC,mBAAmB,CAAC,EAAE,UAAU,EAAE,CAAC,YAAY,CAAC,EAAE;IACpF,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,mBAAmB,CAAC,EAAE,UAAU,EAAE,CAAC,OAAO,CAAC,EAAE;IAC1E,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,mBAAmB,CAAC,EAAE,UAAU,EAAE,CAAC,eAAe,CAAC,EAAE;IACnF,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,CAAC,mBAAmB,CAAC,EAAE,UAAU,EAAE,CAAC,YAAY,CAAC,EAAE;CACrF,CAAC"}
@@ -0,0 +1,3 @@
1
+ /** `slotTaken` and `SlotTaken` both read `SLOT_TAKEN`. */
2
+ export declare function constantCase(name: string): string;
3
+ //# sourceMappingURL=constant-case.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constant-case.d.ts","sourceRoot":"","sources":["../../../src/support/errors/constant-case.ts"],"names":[],"mappings":"AAEA,0DAA0D;AAC1D,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEjD"}
@@ -0,0 +1,6 @@
1
+ import { splitWords } from '../words/split-words.js';
2
+ /** `slotTaken` and `SlotTaken` both read `SLOT_TAKEN`. */
3
+ export function constantCase(name) {
4
+ return splitWords(name).join('_').toUpperCase();
5
+ }
6
+ //# sourceMappingURL=constant-case.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constant-case.js","sourceRoot":"","sources":["../../../src/support/errors/constant-case.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAErD,0DAA0D;AAC1D,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC;AAClD,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { ClassNode } from '../classes/class-name.js';
2
+ /** A class of an error file that extends something: `ConceptError`, `DomainError`, or a base of the project. */
3
+ export declare function isErrorClass(node: ClassNode): boolean;
4
+ //# sourceMappingURL=is-error-class.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"is-error-class.d.ts","sourceRoot":"","sources":["../../../src/support/errors/is-error-class.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAE1D,gHAAgH;AAChH,wBAAgB,YAAY,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,CAErD"}
@@ -0,0 +1,6 @@
1
+ import { AST_NODE_TYPES } from '@typescript-eslint/utils';
2
+ /** A class of an error file that extends something: `ConceptError`, `DomainError`, or a base of the project. */
3
+ export function isErrorClass(node) {
4
+ return node.superClass?.type === AST_NODE_TYPES.Identifier;
5
+ }
6
+ //# sourceMappingURL=is-error-class.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"is-error-class.js","sourceRoot":"","sources":["../../../src/support/errors/is-error-class.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAG1D,gHAAgH;AAChH,MAAM,UAAU,YAAY,CAAC,IAAe;IAC1C,OAAO,IAAI,CAAC,UAAU,EAAE,IAAI,KAAK,cAAc,CAAC,UAAU,CAAC;AAC7D,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { LintedFile } from '../../project/linted-file.js';
2
+ /** A production file of `domain/errors/` of a context, in a project that builds its refusals through factories. */
3
+ export declare function isErrorFile(file: LintedFile): boolean;
4
+ //# sourceMappingURL=is-error-file.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"is-error-file.d.ts","sourceRoot":"","sources":["../../../src/support/errors/is-error-file.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAE/D,mHAAmH;AACnH,wBAAgB,WAAW,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAUrD"}
@@ -0,0 +1,10 @@
1
+ /** A production file of `domain/errors/` of a context, in a project that builds its refusals through factories. */
2
+ export function isErrorFile(file) {
3
+ const { location } = file;
4
+ return (file.config.stack.refusals === 'factories' &&
5
+ location.area === 'context' &&
6
+ location.layer === 'domain' &&
7
+ location.inside[0] === 'errors' &&
8
+ !file.isTest);
9
+ }
10
+ //# sourceMappingURL=is-error-file.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"is-error-file.js","sourceRoot":"","sources":["../../../src/support/errors/is-error-file.ts"],"names":[],"mappings":"AAEA,mHAAmH;AACnH,MAAM,UAAU,WAAW,CAAC,IAAgB;IAC1C,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC;IAE1B,OAAO,CACL,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,KAAK,WAAW;QAC1C,QAAQ,CAAC,IAAI,KAAK,SAAS;QAC3B,QAAQ,CAAC,KAAK,KAAK,QAAQ;QAC3B,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,QAAQ;QAC/B,CAAC,IAAI,CAAC,MAAM,CACb,CAAC;AACJ,CAAC"}
package/dist/version.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export declare const VERSION = "0.2.0";
1
+ export declare const VERSION = "0.4.0";
2
2
  //# sourceMappingURL=version.d.ts.map
package/dist/version.js CHANGED
@@ -1,2 +1,2 @@
1
- export const VERSION = '0.2.0';
1
+ export const VERSION = '0.4.0';
2
2
  //# sourceMappingURL=version.js.map
@@ -0,0 +1,53 @@
1
+ # ddd-ts-kit/errors-constructor-not-public
2
+
3
+ Architecture id: `errors/constructor-not-public`. Default severity: `error` in `recommended`, `error` in `strict`.
4
+
5
+ Applies to: the production files of `domain/errors/` of a context, in a project whose config says `"stack.refusals": "factories"`.
6
+
7
+ ## Why
8
+
9
+ A public constructor lets any caller build a refusal with a code and a message of its own. `ConceptError` of `@ddd-ts-kit/kernel` has a protected constructor, and a class that extends it declares none: a refusal then exists only through a static factory.
10
+
11
+ ## Reported
12
+
13
+ - a class that extends another one and declares a public constructor
14
+ - a class that extends `DomainError` and declares no constructor: it inherits a public one
15
+
16
+ An abstract class is not judged.
17
+
18
+ Incorrect:
19
+
20
+ ```ts
21
+ export class SlotTakenError extends DomainError {
22
+ readonly code = 'SLOT_TAKEN';
23
+
24
+ constructor(calendarId: string) {
25
+ super(`The slot on calendar ${calendarId} is already held.`);
26
+ }
27
+ }
28
+ ```
29
+
30
+ Correct:
31
+
32
+ ```ts
33
+ export class AppointmentError extends ConceptError {
34
+ static slotTaken(calendarId: string) {
35
+ return AppointmentError.refusal('SLOT_TAKEN', `The slot on calendar ${calendarId} is already held.`, { calendarId });
36
+ }
37
+ }
38
+ ```
39
+
40
+ ## Options
41
+
42
+ None.
43
+
44
+ `rules."errors/constructor-not-public"` in `ddd-ts-kit.config.json` set to `off` silences the rule, and `// ddd-ts-kit-disable-next-line errors/constructor-not-public -- <reason>` silences one line, exactly as for `ddd-ts-kit check`.
45
+
46
+ ## Limits
47
+
48
+ - A class that extends a base of the project and declares no constructor is trusted: the visibility it inherits is in another file.
49
+ - Nothing is fixed: making a constructor private breaks every `new` of the class. `ddd-ts-kit error-factories` moves a project to factories as a whole.
50
+
51
+ ## With the CLI checker
52
+
53
+ Held by this plugin alone: the shape of a class needs a syntax tree.
@@ -0,0 +1,50 @@
1
+ # ddd-ts-kit/errors-factory-name
2
+
3
+ Architecture id: `errors/factory-name`. Default severity: `error` in `recommended`, `error` in `strict`.
4
+
5
+ Applies to: the production files of `domain/errors/` of a context, in a project whose config says `"stack.refusals": "factories"`.
6
+
7
+ ## Why
8
+
9
+ The factory is read by the developer who refuses, the code by the client, the mapper, the audit trail and the tests. They must meet the same words, and those words are the business's: `slotTaken` and `SLOT_TAKEN`, never `create` and `BOOKING_FAILED`.
10
+
11
+ ## Reported
12
+
13
+ A factory is a public static method of an error class that calls `refusal(...)`.
14
+
15
+ - a name that says an error is built and not which rule refused: `create`, `make`, `of`, `from`, `build`, `new`, `error`, `failure`, `fail`, `refusal`, `refuse`, or a name holding a digit (`error1`)
16
+ - a code that is not a string literal, or not in constant case
17
+ - a code that is not the name of the factory in constant case, alone or with the name of the concept before or after it: `AppointmentError.notFound` sets `NOT_FOUND`, `APPOINTMENT_NOT_FOUND` or `NOT_FOUND_APPOINTMENT`
18
+
19
+ Incorrect:
20
+
21
+ ```ts
22
+ static slotTaken(calendarId: string) {
23
+ return AppointmentError.refusal('BOOKING_FAILED', 'The slot is already held.', { calendarId });
24
+ }
25
+ ```
26
+
27
+ Correct:
28
+
29
+ ```ts
30
+ static slotTaken(calendarId: string) {
31
+ return AppointmentError.refusal('SLOT_TAKEN', 'The slot is already held.', { calendarId });
32
+ }
33
+ ```
34
+
35
+ ## Options
36
+
37
+ None.
38
+
39
+ `rules."errors/factory-name"` in `ddd-ts-kit.config.json` set to `off` silences the rule, and `// ddd-ts-kit-disable-next-line errors/factory-name -- <reason>` silences one line, exactly as for `ddd-ts-kit check`.
40
+
41
+ A code already published under other words cannot change: rename the factory after it, or keep the name and silence that line with the reason.
42
+
43
+ ## Limits
44
+
45
+ - Whether a name is a business phrase cannot be decided by a tool: only the names that are certainly not are refused. `language/glossary-term` holds the name of the class.
46
+ - The first `refusal(...)` call of the method is the one read.
47
+
48
+ ## With the CLI checker
49
+
50
+ Held by this plugin alone. That a code is unique in its context is `errors/code-unique`, held by the checker.
@@ -0,0 +1,45 @@
1
+ # ddd-ts-kit/errors-through-factory
2
+
3
+ Architecture id: `errors/through-factory`. Default severity: `error` in `recommended`, `error` in `strict`.
4
+
5
+ Applies to: every file of a context, tests included, in a project whose config says `"stack.refusals": "factories"`. A config without the key was written when an error was a class built with `new`: nothing is reported there.
6
+
7
+ ## Why
8
+
9
+ The code that refuses reads as a sentence, and the refusals of one concept live in one class: `throw AppointmentError.slotTaken(calendar.id, slot.startsAt)`. The factory writes the code, the message and the facts once. A `new` outside the class is a refusal whose code and message are whatever the caller wrote.
10
+
11
+ ## Reported
12
+
13
+ - `new X(...)` where `X` is imported from a file of `domain/errors/`
14
+
15
+ Incorrect:
16
+
17
+ ```ts
18
+ import { SlotTakenError } from '@/contexts/scheduling/domain/errors/slot-taken.error';
19
+
20
+ throw new SlotTakenError(calendar.id, slot.startsAt);
21
+ ```
22
+
23
+ Correct:
24
+
25
+ ```ts
26
+ import { AppointmentError } from '@/contexts/scheduling/domain/errors/appointment.error';
27
+
28
+ throw AppointmentError.slotTaken(calendar.id, slot.startsAt);
29
+ ```
30
+
31
+ ## Options
32
+
33
+ None.
34
+
35
+ `rules."errors/through-factory"` in `ddd-ts-kit.config.json` set to `off` silences the rule, and `// ddd-ts-kit-disable-next-line errors/through-factory -- <reason>` silences one line, exactly as for `ddd-ts-kit check`.
36
+
37
+ ## Limits
38
+
39
+ - An error class is known by where it is imported from: a class declared elsewhere than `domain/errors/` is not seen (`naming/suffix` keeps errors there).
40
+ - The errors of the kit (`NotFoundError`, `InvariantViolation`, `ValidationError`...) are each one refusal with a fixed code and stay built with `new`.
41
+ - Nothing is fixed: which factory replaces a constructor is a decision. `ddd-ts-kit error-factories` writes the plan of a migration and applies it.
42
+
43
+ ## With the CLI checker
44
+
45
+ Held by this plugin alone: the checker lists the rule and judges nothing. The compiler refuses the same thing once the class extends `ConceptError`, whose constructor is protected.
@@ -0,0 +1,57 @@
1
+ # ddd-ts-kit/presentation-controller-delegates
2
+
3
+ Architecture id: `presentation/controller-delegates` (added by this plugin). Default severity: `error` in `recommended`, `error` in `strict`.
4
+
5
+ Applies to: `*.controller.ts` files of a context whose class carries `@Controller` of `@ddd-ts-kit/http`.
6
+
7
+ ## Why
8
+
9
+ A controller holds no business logic, and the way to keep it so is to give it nothing to decide with. What it may be given is the bus of its method, a request mapper and a serializer. With a repository, a port or a domain service in its constructor, a rule would be written at the edge, where a job or an event handler calling the same use case does not pass.
10
+
11
+ ## Reported
12
+
13
+ - a constructor parameter typed by anything else than `CommandBus`, `QueryBus`, a class named `*Mapper` or a class named `*Serializer`
14
+ - a `POST`, `PUT`, `PATCH` or `DELETE` controller given the `QueryBus`, and a `GET` or `HEAD` controller given the `CommandBus`
15
+ - a controller that is not given the bus of its method
16
+
17
+ Incorrect:
18
+
19
+ ```ts
20
+ @Controller({ group: InvoicesRoutes, method: 'GET', path: '/:invoiceId', summary: 'Get invoice', response: { status: 200, body: answer } })
21
+ export class GetInvoiceController {
22
+ constructor(
23
+ private readonly commands: CommandBus,
24
+ private readonly invoices: InvoiceRepository,
25
+ ) {}
26
+ }
27
+ ```
28
+
29
+ Correct:
30
+
31
+ ```ts
32
+ @Controller({ group: InvoicesRoutes, method: 'GET', path: '/:invoiceId', summary: 'Get invoice', response: { status: 200, body: answer } })
33
+ export class GetInvoiceController {
34
+ constructor(
35
+ private readonly queries: QueryBus,
36
+ private readonly serializer: GetInvoiceSerializer,
37
+ ) {}
38
+ }
39
+ ```
40
+
41
+ ## Details
42
+
43
+ The method is read from the string literal of the declaration; a declaration built elsewhere is judged on its dependencies only. A controller without a constructor is reported for the missing bus.
44
+
45
+ ## Options
46
+
47
+ None.
48
+
49
+ `rules."presentation/controller-delegates"` in `ddd-ts-kit.config.json` set to `off` silences the rule, and `// ddd-ts-kit-disable-next-line presentation/controller-delegates -- <reason>` silences one line, exactly as for `ddd-ts-kit check`.
50
+
51
+ ## Limits
52
+
53
+ - The body of `handle` is not read: a controller that computes in `handle` what a use case should decide is not seen. The dependencies it would need for anything serious are.
54
+
55
+ ## With the CLI checker
56
+
57
+ New with this plugin: the CLI checker has no equivalent, because the constructor of a class needs a syntax tree.
@@ -0,0 +1,50 @@
1
+ # ddd-ts-kit/presentation-controller-shape
2
+
3
+ Architecture id: `presentation/controller-shape` (added by this plugin). Default severity: `error` in `recommended`, `error` in `strict`.
4
+
5
+ Applies to: `*.controller.ts` files whose class carries `@Controller` of `@ddd-ts-kit/http`.
6
+
7
+ ## Why
8
+
9
+ A controller is one route: one class, called by the pipeline through `handle`. The class is found by the name of its file, read in one sitting, and its declaration is the single statement of the route. A second public method is a second route hiding in the first, or a translation that belongs to a request mapper or a serializer.
10
+
11
+ ## Reported
12
+
13
+ - a second exported class in the file of a controller
14
+ - a controller class without a public `handle`
15
+ - any other public method or function property, static ones included
16
+
17
+ Incorrect:
18
+
19
+ ```ts
20
+ @Controller({ group: InvoicesRoutes, method: 'POST', path: '/', summary: 'Issue invoice', response: { status: 201, body: accepted } })
21
+ export class IssueInvoiceController {
22
+ async execute(request: HttpRequest): Promise<IssueInvoiceAccepted> {}
23
+ totalOf(body: IssueInvoiceBody): number {}
24
+ }
25
+ ```
26
+
27
+ Correct:
28
+
29
+ ```ts
30
+ @Controller({ group: InvoicesRoutes, method: 'POST', path: '/', summary: 'Issue invoice', body, response: { status: 201, body: accepted } })
31
+ export class IssueInvoiceController {
32
+ constructor(private readonly commands: CommandBus) {}
33
+
34
+ async handle(request: HttpRequest<{ body: IssueInvoiceBody }>): Promise<IssueInvoiceAccepted> {}
35
+ }
36
+ ```
37
+
38
+ ## Details
39
+
40
+ A `*.controller.ts` file that declares no controller of the kit, such as a NestJS controller written by hand, is not judged. Types, interfaces, constants and functions that are not exported may stand next to the class. That `handle` receives what the declaration validates and returns what it declares is checked by the compiler, on the decorator.
41
+
42
+ ## Options
43
+
44
+ None.
45
+
46
+ `rules."presentation/controller-shape"` in `ddd-ts-kit.config.json` set to `off` silences the rule, and `// ddd-ts-kit-disable-next-line presentation/controller-shape -- <reason>` silences one line, exactly as for `ddd-ts-kit check`.
47
+
48
+ ## With the CLI checker
49
+
50
+ New with this plugin: the CLI checker has no equivalent, because the shape of a class needs a syntax tree.
@@ -0,0 +1,55 @@
1
+ # ddd-ts-kit/presentation-guard-at-the-edge
2
+
3
+ Architecture id: `presentation/guard-at-the-edge` (added by this plugin). Default severity: `error` in `recommended`, `error` in `strict`.
4
+
5
+ Applies to: every `*.guard.ts` file, in a context or in the platform.
6
+
7
+ ## Why
8
+
9
+ A guard is a control at the edge over a set of routes: is the caller authenticated, does it hold a role, does the tenant of its token match the one of the path, is the key of the request known. A business permission is another thing: it depends on the element (who owns this appointment, is this invoice still a draft) and it is declared on the use case with `@Requires`, so that a job or an event handler sending the same command is held to the same right. A guard that loads an aggregate decides a permission at the one door where not every caller passes.
10
+
11
+ ## Reported
12
+
13
+ - an import from `domain/` or `infrastructure/`, of any context
14
+ - an imported name ending in `Repository` or `UnitOfWork`
15
+ - an import of `CommandBus`
16
+
17
+ Incorrect:
18
+
19
+ ```ts
20
+ import { AppointmentRepository } from '@/contexts/scheduling/domain/repositories/appointment.repository';
21
+
22
+ @Guard()
23
+ export class OwnAppointmentGuard implements Guard {
24
+ constructor(private readonly appointments: AppointmentRepository) {}
25
+ }
26
+ ```
27
+
28
+ Correct:
29
+
30
+ ```ts
31
+ @Guard()
32
+ export class SameClinicGuard implements Guard {
33
+ readonly documents = { errors: ['FORBIDDEN'] };
34
+
35
+ check({ actor, params }: GuardRequest): void {
36
+ if (actor.tenantId !== params['clinicId']) {
37
+ throw new ForbiddenError('The caller belongs to another clinic');
38
+ }
39
+ }
40
+ }
41
+ ```
42
+
43
+ ## Details
44
+
45
+ A guard may depend on a port of `application/ports/` that answers a question about the caller, such as whether an API key exists: the port is the checkable line, an aggregate behind it is not seen.
46
+
47
+ ## Options
48
+
49
+ None.
50
+
51
+ `rules."presentation/guard-at-the-edge"` in `ddd-ts-kit.config.json` set to `off` silences the rule, and `// ddd-ts-kit-disable-next-line presentation/guard-at-the-edge -- <reason>` silences one line, exactly as for `ddd-ts-kit check`.
52
+
53
+ ## With the CLI checker
54
+
55
+ New with this plugin: the CLI checker has no equivalent.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ddd-ts-kit/eslint-plugin",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "description": "AST-accurate ESLint rules for DDD and Clean Architecture in TypeScript: layer and context isolation, domain purity, clean code ordering.",
5
5
  "license": "MIT",
6
6
  "repository": {