xdbc 1.0.217 → 1.0.219

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 (120) hide show
  1. package/.gitattributes +16 -8
  2. package/.vscode/settings.json +3 -3
  3. package/.vscode/tasks.json +23 -23
  4. package/ASSESSMENT.md +249 -0
  5. package/README.md +538 -408
  6. package/__tests__/DBC/AE.test.ts +62 -62
  7. package/__tests__/DBC/ARRAY.test.ts +91 -91
  8. package/__tests__/DBC/DEFINED.test.ts +53 -53
  9. package/__tests__/DBC/DOM.test.ts +786 -0
  10. package/__tests__/DBC/Decorators.test.ts +367 -367
  11. package/__tests__/DBC/EQ.test.ts +13 -13
  12. package/__tests__/DBC/GREATER.test.ts +31 -31
  13. package/__tests__/DBC/HasAttribute.test.ts +60 -60
  14. package/__tests__/DBC/IF.test.ts +62 -62
  15. package/__tests__/DBC/INSTANCE.test.ts +13 -13
  16. package/__tests__/DBC/JSON.OP.test.ts +47 -47
  17. package/__tests__/DBC/JSON.Parse.test.ts +17 -17
  18. package/__tests__/DBC/OR.test.ts +14 -14
  19. package/__tests__/DBC/PLAIN_OBJECT.test.ts +109 -109
  20. package/__tests__/DBC/REGEX.test.ts +17 -17
  21. package/__tests__/DBC/TYPE.test.ts +13 -13
  22. package/__tests__/DBC/UNDEFINED.test.ts +45 -45
  23. package/__tests__/DBC/ZOD.test.ts +54 -54
  24. package/__tests__/DBC/onInfringement.test.ts +262 -0
  25. package/biome.json +45 -40
  26. package/dist/DBC/AE.js +172 -0
  27. package/dist/DBC/ARR/PLAIN_OBJECT.d.ts +0 -3
  28. package/dist/DBC/ARR/PLAIN_OBJECT.js +95 -0
  29. package/dist/DBC/ARRAY.d.ts +0 -3
  30. package/dist/DBC/ARRAY.js +90 -0
  31. package/dist/DBC/COMPARISON/GREATER.js +21 -0
  32. package/dist/DBC/COMPARISON/GREATER_OR_EQUAL.js +21 -0
  33. package/dist/DBC/COMPARISON/LESS.js +21 -0
  34. package/dist/DBC/COMPARISON/LESS_OR_EQUAL.js +21 -0
  35. package/dist/DBC/COMPARISON.js +98 -0
  36. package/dist/DBC/DEFINED.js +87 -0
  37. package/dist/DBC/DOM.d.ts +123 -0
  38. package/dist/DBC/DOM.js +362 -0
  39. package/dist/DBC/EQ/DIFFERENT.js +34 -0
  40. package/dist/DBC/EQ.js +101 -0
  41. package/dist/DBC/GREATER.js +99 -0
  42. package/dist/DBC/HasAttribute.js +101 -0
  43. package/dist/DBC/IF.js +96 -0
  44. package/dist/DBC/INSTANCE.js +122 -0
  45. package/dist/DBC/JSON.OP.js +120 -0
  46. package/dist/DBC/JSON.Parse.js +104 -0
  47. package/dist/DBC/OR.js +125 -0
  48. package/dist/DBC/REGEX.js +136 -0
  49. package/dist/DBC/TYPE.js +112 -0
  50. package/dist/DBC/UNDEFINED.js +87 -0
  51. package/dist/DBC/ZOD.js +99 -0
  52. package/dist/DBC.d.ts +18 -4
  53. package/dist/DBC.js +645 -0
  54. package/dist/Demo.d.ts +10 -0
  55. package/dist/Demo.js +713 -0
  56. package/dist/Test.html +18 -0
  57. package/dist/bundle.js +6140 -405
  58. package/dist/index.d.ts +22 -0
  59. package/dist/index.html +18 -0
  60. package/dist/index.js +22 -0
  61. package/docs/assets/highlight.css +22 -22
  62. package/docs/assets/icons.js +17 -17
  63. package/docs/assets/main.js +60 -60
  64. package/docs/assets/style.css +1640 -1640
  65. package/docs/classes/DBC.DBC.html +98 -98
  66. package/docs/classes/DBC_AE.AE.html +160 -160
  67. package/docs/classes/DBC_EQ.EQ.html +131 -131
  68. package/docs/classes/DBC_GREATER.GREATER.html +139 -139
  69. package/docs/classes/DBC_INSTANCE.INSTANCE.html +130 -130
  70. package/docs/classes/DBC_JSON.OP.JSON_OP.html +138 -138
  71. package/docs/classes/DBC_JSON.Parse.JSON_Parse.html +129 -129
  72. package/docs/classes/DBC_OR.OR.html +137 -137
  73. package/docs/classes/DBC_REGEX.REGEX.html +136 -136
  74. package/docs/classes/DBC_TYPE.TYPE.html +130 -130
  75. package/docs/classes/Demo.Demo.html +14 -14
  76. package/docs/hierarchy.html +1 -1
  77. package/docs/index.html +1 -1
  78. package/docs/modules/DBC.html +1 -1
  79. package/docs/modules/DBC_AE.html +1 -1
  80. package/docs/modules/DBC_EQ.html +1 -1
  81. package/docs/modules/DBC_GREATER.html +1 -1
  82. package/docs/modules/DBC_INSTANCE.html +1 -1
  83. package/docs/modules/DBC_JSON.OP.html +1 -1
  84. package/docs/modules/DBC_JSON.Parse.html +1 -1
  85. package/docs/modules/DBC_OR.html +1 -1
  86. package/docs/modules/DBC_REGEX.html +1 -1
  87. package/docs/modules/DBC_TYPE.html +1 -1
  88. package/docs/modules/Demo.html +1 -1
  89. package/jest.config.js +32 -32
  90. package/package.json +71 -55
  91. package/src/DBC/AE.ts +269 -288
  92. package/src/DBC/ARR/PLAIN_OBJECT.ts +122 -133
  93. package/src/DBC/ARRAY.ts +117 -127
  94. package/src/DBC/COMPARISON/GREATER.ts +41 -46
  95. package/src/DBC/COMPARISON/GREATER_OR_EQUAL.ts +41 -45
  96. package/src/DBC/COMPARISON/LESS.ts +41 -45
  97. package/src/DBC/COMPARISON/LESS_OR_EQUAL.ts +41 -45
  98. package/src/DBC/COMPARISON.ts +149 -159
  99. package/src/DBC/DEFINED.ts +117 -122
  100. package/src/DBC/DOM.ts +453 -0
  101. package/src/DBC/EQ/DIFFERENT.ts +51 -57
  102. package/src/DBC/EQ.ts +154 -163
  103. package/src/DBC/HasAttribute.ts +149 -154
  104. package/src/DBC/IF.ts +173 -179
  105. package/src/DBC/INSTANCE.ts +168 -171
  106. package/src/DBC/JSON.OP.ts +178 -186
  107. package/src/DBC/JSON.Parse.ts +150 -157
  108. package/src/DBC/OR.ts +183 -187
  109. package/src/DBC/REGEX.ts +195 -196
  110. package/src/DBC/TYPE.ts +142 -149
  111. package/src/DBC/UNDEFINED.ts +115 -117
  112. package/src/DBC/ZOD.ts +130 -135
  113. package/src/DBC.ts +902 -904
  114. package/src/Demo.ts +537 -404
  115. package/src/index.ts +22 -0
  116. package/tsconfig.json +18 -18
  117. package/tsconfig.test.json +7 -7
  118. package/typedoc.json +16 -16
  119. package/webpack.config.js +27 -27
  120. package/Assessment.md +0 -507
package/README.md CHANGED
@@ -1,408 +1,538 @@
1
- <p align="center">
2
- <img src="https://img.shields.io/npm/v/xdbc?style=flat-square" alt="npm version" />
3
- <img src="https://img.shields.io/npm/l/xdbc?style=flat-square" alt="license" />
4
- <img src="https://img.shields.io/npm/dt/xdbc?style=flat-square" alt="downloads" />
5
- <img src="https://img.shields.io/badge/TypeScript-5.x-blue?style=flat-square&logo=typescript" alt="TypeScript" />
6
- <img src="https://img.shields.io/badge/decorators-stage%203-green?style=flat-square" alt="decorators" />
7
- <img src="https://img.shields.io/badge/optimized%20for-VS%20Code-007acc?style=flat-square&logo=visualstudiocode" alt="VS Code" />
8
- </p>
9
-
10
- # XDBC — e**X**plicit **D**esign **b**y **C**ontract for TypeScript
11
-
12
- > A decorator-based Design by Contract framework that enforces preconditions, postconditions, and invariants through TypeScript metadata — delivering precise, self-documenting, and verifiable component contracts.
13
-
14
- ---
15
-
16
- ## At a Glance
17
-
18
- | Approach | With XDBC | Without XDBC |
19
- |---|---|---|
20
- | **Parameter validation** | <pre>@DBC.ParamvalueProvider<br>method(@REGEX.PRE(/^\.*XDBC.\*$/i) input: string[]) {<br> ...<br>}</pre> | <pre>method(input: string[]) {<br> input.forEach((el, i) => {<br> console.assert(/^.\*XDBC.\*$/i.test(el), "error");<br> });<br> ...<br>}</pre> |
21
- | **Field invariant** | <pre>@REGEX.INVARIANT(/^.\*XDBC.\*$/i)<br>public field = "XDBC";</pre> | <pre>get field(): string { return this._field; }<br>set field(v: string) {<br> console.assert(/^.\*XDBC.\*$/i.test(v), "error");<br> this._field = v;<br>}</pre> |
22
- | **Return validation** | <pre>@REGEX.POST(/^XDBC$/i)<br>method(input: unknown): string {<br> ...<br> return result;<br>}</pre> | <pre>method(input: unknown): string {<br> ...<br> if (!/^XDBC$/i.test(result)) {<br> throw new Error("error");<br> }<br> return result;<br>}</pre> |
23
-
24
- Contract violations produce structured, actionable diagnostics:
25
-
26
- ```
27
- [ XDBC Infringement [ From "method" in "MyClass": [ Parameter-value "+1d,+5d,-x10y"
28
- of the 1st parameter did not fulfill one of it's contracts: Violating-Arrayelement at
29
- index 2. Value has to comply to regular expression "/^(?i:(NOW)|([+-]\d+[dmy]))$/i"]]]
30
- ```
31
-
32
- ---
33
-
34
- ## Table of Contents
35
-
36
- - [What is Design by Contract?](#what-is-design-by-contract)
37
- - [Why XDBC?](#why-xdbc)
38
- - [Installation](#installation)
39
- - [Quick Start](#quick-start)
40
- - [Contracts Reference](#contracts-reference)
41
- - [Core Concepts](#core-concepts)
42
- - [Advanced Features](#advanced-features)
43
- - [Configuration](#configuration)
44
- - [API Documentation](#api-documentation)
45
- - [Contributing](#contributing)
46
- - [License](#license)
47
-
48
- ---
49
-
50
- ## What is Design by Contract?
51
-
52
- [Design by Contract (DbC)](https://en.wikipedia.org/wiki/Design_by_contract) is a software engineering methodology that defines formal, precise, and verifiable interface specifications for software components. Each component's contract comprises:
53
-
54
- | Element | Purpose |
55
- |---|---|
56
- | **Preconditions** | Conditions that must hold true *before* a method executes |
57
- | **Postconditions** | Guarantees that must hold true *after* a method returns |
58
- | **Invariants** | Properties that must remain true *throughout* an object's lifetime |
59
-
60
- ### DbC vs. Assertions
61
-
62
- | Aspect | XDBC Decorators | Manual Assertions |
63
- |---|---|---|
64
- | Formality | Formal, declarative, co-located with signatures | Informal, scattered through method bodies |
65
- | Integration | TypeScript metadata and decorators | Built-in `console.assert` / `throw` |
66
- | Expressiveness | Composable, parameterized contract objects | Simple boolean checks |
67
- | Readability | Contracts are visible at the API surface | Validation logic obscures business logic |
68
- | Maintainability | Contracts are localized and reusable | Duplicated checks are hard to track |
69
- | Production control | Selectively enable/disable by contract type | Typically all-or-nothing |
70
-
71
- ---
72
-
73
- ## Why XDBC?
74
-
75
- - **Declarative** — contracts live as decorators alongside type signatures, not buried in method bodies
76
- - **Composable** — combine contracts with `AE`, `OR`, and `IF` for expressive validation
77
- - **Configurable** — toggle preconditions, postconditions, and invariants independently
78
- - **Diagnostic** — structured error messages pinpoint the exact violation, parameter, and context
79
- - **Extensible** — 16 built-in contracts, with support for custom contracts and Zod schema integration
80
- - **Zero runtime overhead** — disable contract checking in production with a single flag
81
-
82
- ---
83
-
84
- ## Installation
85
-
86
- ```sh
87
- npm install xdbc
88
- ```
89
-
90
- **Requirements:** TypeScript 5.x with `experimentalDecorators` and `emitDecoratorMetadata` enabled in `tsconfig.json`.
91
-
92
- ```jsonc
93
- // tsconfig.json
94
- {
95
- "compilerOptions": {
96
- "experimentalDecorators": true,
97
- "emitDecoratorMetadata": true
98
- }
99
- }
100
- ```
101
-
102
- ---
103
-
104
- ## Quick Start
105
-
106
- ```typescript
107
- import { DBC, REGEX, TYPE, EQ } from "xdbc";
108
-
109
- class UserService {
110
-
111
- // Invariant: email must always match pattern
112
- @REGEX.INVARIANT(/^[^@]+@[^@]+\.[^@]+$/)
113
- public email = "user@example.com";
114
-
115
- // Precondition: name must be a string; Postcondition: return must match pattern
116
- @REGEX.POST(/^Hello, .+$/)
117
- @DBC.ParamvalueProvider
118
- public greet(@TYPE.PRE("string") name: string): string {
119
- return `Hello, ${name}`;
120
- }
121
-
122
- // Precondition: age must be >= 0
123
- @DBC.ParamvalueProvider
124
- public setAge(@GREATER_OR_EQUAL.PRE(0) age: number) {
125
- // ...
126
- }
127
- }
128
- ```
129
-
130
- ---
131
-
132
- ## Contracts Reference
133
-
134
- XDBC ships with **16 contracts** organized into core validators and derived specializations:
135
-
136
- ### Core Contracts
137
-
138
- | Contract | Description | Constructor |
139
- |---|---|---|
140
- | **`REGEX`** | Value must match a regular expression | `new REGEX(expression: RegExp)` |
141
- | **`TYPE`** | Value must be of a specified type (supports pipe-separated: `"string\|number"`) | `new TYPE(type: string)` |
142
- | **`EQ`** | Value must equal (or not equal) a reference value | `new EQ(equivalent: any, invert?: boolean)` |
143
- | **`COMPARISON`** | Numeric comparison against a reference value | `new COMPARISON(equivalent, equalityPermitted, invert)` |
144
- | **`INSTANCE`** | Value must be an instance of a specified class | `new INSTANCE(reference: any \| any[])` |
145
- | **`AE`** | Every element in an array must satisfy a set of contracts | `new AE(conditions, index?, idxEnd?)` |
146
- | **`OR`** | At least one of a set of contracts must be satisfied | `new OR(conditions: DBC[])` |
147
- | **`IF`** | Conditional contract: if A holds, then B must also hold | `IF.PRE(condition, inCase, path?, invert?)` |
148
- | **`JSON_OP`** | Object must contain specific properties of specific types | `new JSON_OP(properties: {name, type}[], checkElements?)` |
149
- | **`JSON_Parse`** | String must be valid JSON; optionally forwards parsed result | `new JSON_Parse(receptor?: (json) => void)` |
150
- | **`DEFINED`** | Value must not be `null` or `undefined` | — |
151
- | **`UNDEFINED`** | Value must be `undefined` | |
152
- | **`ARRAY`** | Value must be an array | — |
153
- | **`HasAttribute`** | HTMLElement must possess a named attribute | `HasAttribute.PRE(attrName, invert?)` |
154
- | **`ZOD`** | Value must validate against a Zod schema | `new ZOD(schema: z.ZodType)` |
155
-
156
- ### Derived Contracts
157
-
158
- | Contract | Derives From | Semantics |
159
- |---|---|---|
160
- | **`GREATER`** | `COMPARISON` | `value > reference` |
161
- | **`GREATER_OR_EQUAL`** | `COMPARISON` | `value >= reference` |
162
- | **`LESS`** | `COMPARISON` | `value < reference` |
163
- | **`LESS_OR_EQUAL`** | `COMPARISON` | `value <= reference` |
164
- | **`DIFFERENT`** | `EQ` | `value !== reference` |
165
- | **`PLAIN_OBJECT`** | `ARRAY` | Value must be a non-null, non-array object |
166
-
167
- ### Built-in Regular Expressions
168
-
169
- `REGEX.stdExp` provides ready-to-use patterns:
170
-
171
- | Key | Validates |
172
- |---|---|
173
- | `htmlAttributeName` | HTML attribute names |
174
- | `eMail` | Email addresses |
175
- | `property` | Property identifiers |
176
- | `url` | URLs |
177
- | `keyPath` | Key paths |
178
- | `date` | Date strings |
179
- | `dateFormat` | Date format patterns |
180
- | `cssSelector` | CSS selectors |
181
- | `boolean` | Boolean string literals |
182
- | `colorCodeHEX` | Hex color codes |
183
- | `simpleHotkey` | Keyboard shortcuts |
184
- | `bcp47` | BCP 47 language tags |
185
-
186
- ---
187
-
188
- ## Core Concepts
189
-
190
- ### Decorator Types
191
-
192
- Every contract exposes three decorator factories:
193
-
194
- | Decorator | Applies To | Validates |
195
- |---|---|---|
196
- | `Contract.PRE(...)` | Method parameters | Input values before method execution |
197
- | `Contract.POST(...)` | Methods | Return value after method execution |
198
- | `Contract.INVARIANT(...)` | Fields / Properties | Value on every assignment (including initialization) |
199
-
200
- ### The `ParamvalueProvider` Decorator
201
-
202
- TypeScript parameter decorators do not natively receive parameter values. Any method using `PRE` parameter contracts **must** be decorated with `@DBC.ParamvalueProvider`:
203
-
204
- ```typescript
205
- @DBC.ParamvalueProvider
206
- public process(
207
- @TYPE.PRE("string") name: string,
208
- @REGEX.PRE(/^\d{4}$/) code: string
209
- ) { ... }
210
- ```
211
-
212
- ### Path Resolution
213
-
214
- All `PRE`, `POST`, and `INVARIANT` decorators accept an optional **`path`** parameter — a dotted path that specifies a nested property of the value to validate instead of the value itself:
215
-
216
- ```typescript
217
- // Validate that element.tagName === "SELECT"
218
- @DBC.ParamvalueProvider
219
- public handleElement(@EQ.PRE("SELECT", false, "tagName") el: HTMLElement) { }
220
-
221
- // Validate that value.length === 1
222
- @EQ.INVARIANT(1, false, "length")
223
- public singleChar = "X";
224
- ```
225
-
226
- Path resolution supports:
227
- - **Dot notation**: `"user.address.city"`
228
- - **Array indices**: `"items[0]"`
229
- - **Method calls**: `"getName()"`
230
- - **HTML attributes**: `"@data-id"`
231
-
232
- ### Custom Hints
233
-
234
- Add context to error messages with the optional **`hint`** parameter:
235
-
236
- ```typescript
237
- @DBC.ParamvalueProvider
238
- public setAge(
239
- @GREATER_OR_EQUAL.PRE(0, undefined, "Age must be non-negative") age: number
240
- ) { }
241
- ```
242
-
243
- ---
244
-
245
- ## Advanced Features
246
-
247
- ### Composing Contracts with `AE`
248
-
249
- Validate array elements against one or more contracts, optionally targeting a specific index range:
250
-
251
- ```typescript
252
- // All elements must be non-empty strings matching a date pattern
253
- @AE.PRE([new TYPE("string"), new REGEX(/^\d{4}-\d{2}-\d{2}$/)])
254
- public processDates(dates: string[]) { }
255
-
256
- // Only elements at indices 1 through 3
257
- @AE.PRE([new REGEX(/^[A-Z]+$/)], 1, 3)
258
- public processRange(items: string[]) { }
259
-
260
- // Single element at index 0
261
- @AE.PRE([new TYPE("number")], 0)
262
- public processFirst(values: unknown[]) { }
263
- ```
264
-
265
- ### Logical Composition with `OR`
266
-
267
- At least one contract must pass:
268
-
269
- ```typescript
270
- @DBC.ParamvalueProvider
271
- public setStatus(@OR.PRE([new EQ("active"), new EQ("inactive"), new EQ("pending")]) status: string) { }
272
- ```
273
-
274
- ### Conditional Contracts with `IF`
275
-
276
- Apply a contract only when a precondition holds:
277
-
278
- ```typescript
279
- // If the value is a string, it must also match digits-only
280
- @IF.PRE(new TYPE("string"), new REGEX(/^\d+$/))
281
- public processInput(value: unknown) { }
282
- ```
283
-
284
- ### Zod Schema Integration
285
-
286
- Leverage Zod schemas for complex structural validation:
287
-
288
- ```typescript
289
- import { z } from "zod";
290
-
291
- const UserSchema = z.object({
292
- name: z.string().min(1),
293
- email: z.string().email(),
294
- age: z.number().int().positive()
295
- });
296
-
297
- @DBC.ParamvalueProvider
298
- public createUser( @ZOD.PRE(UserSchema) data: unknown) { }
299
- ```
300
-
301
- ### Type-Safe Static Checks
302
-
303
- Several contracts offer static `tsCheck` methods for imperative validation outside of decorators:
304
-
305
- ```typescript
306
- // Throws if value is not a string
307
- const name = TYPE.tsCheck<string>(input, "string", "Expected a string");
308
-
309
- // Throws if value doesn't match regex
310
- const code = REGEX.tsCheck<string>(input, /^\d{4}$/, "Invalid code format");
311
-
312
- // Throws if not an instance of Date
313
- const date = INSTANCE.tsCheck<Date>(input, Date, "Expected a Date");
314
-
315
- // Throws if none of the conditions pass
316
- const result = OR.tsCheck<string>(input, [new EQ("a"), new EQ("b")]);
317
- ```
318
-
319
- ---
320
-
321
- ## Configuration
322
-
323
- ### DBC Instance Settings
324
-
325
- A default DBC instance is automatically registered at `WaXCode.DBC` when the module is imported. You can access and configure it:
326
-
327
- ```typescript
328
- import { DBC } from "xdbc";
329
-
330
- // Access the default DBC instance
331
- const dbc = (globalThis as any).WaXCode.DBC as DBC;
332
-
333
- // Toggle contract checking
334
- dbc.executionSettings.checkPreconditions = true;
335
- dbc.executionSettings.checkPostconditions = true;
336
- dbc.executionSettings.checkInvariants = true;
337
-
338
- // Configure infringement handling
339
- dbc.infringementSettings.throwException = true; // throw DBC.Infringement on violation
340
- dbc.infringementSettings.logToConsole = false; // log to console instead
341
- ```
342
-
343
- ### Multiple DBC Instances
344
-
345
- Create isolated DBC instances with separate configurations using `DBC.register()`:
346
-
347
- ```typescript
348
- // Register a vendor-specific instance at a custom path
349
- const vendorDbc = new DBC(
350
- { throwException: false, logToConsole: true },
351
- );
352
- DBC.register(vendorDbc, "MyVendor.DBC");
353
-
354
- // Route a contract to the custom instance via its path
355
- @REGEX.INVARIANT(/^[A-Z]+$/, undefined, undefined, "MyVendor.DBC")
356
- public code = "ABC";
357
- ```
358
-
359
- > **Note:** `new DBC()` does not automatically mount onto `globalThis`. Call `DBC.register(instance, path)` to make an instance available for decorator resolution.
360
-
361
- ### Test Isolation
362
-
363
- Use `DBC.isolated()` to run tests with a temporary DBC instance that doesn't affect other tests:
364
-
365
- ```typescript
366
- DBC.isolated((tempDbc) => {
367
- // tempDbc is registered at "WaXCode.DBC" for the duration of this callback
368
- tempDbc.executionSettings.checkPreconditions = false;
369
-
370
- // ... run tests with contracts disabled ...
371
- });
372
- // Original DBC instance is automatically restored here
373
- ```
374
-
375
- ### Disabling Contracts in Production
376
-
377
- ```typescript
378
- const dbc = (globalThis as any).WaXCode.DBC as DBC;
379
- dbc.executionSettings.checkPreconditions = false;
380
- dbc.executionSettings.checkPostconditions = false;
381
- dbc.executionSettings.checkInvariants = false;
382
- ```
383
-
384
- ---
385
-
386
- ## API Documentation
387
-
388
- Full generated API documentation is available at **[callaris.github.io/XDBC](https://callaris.github.io/XDBC/)**.
389
-
390
- See [`Demo.ts`](src/Demo.ts) for annotated usage examples.
391
-
392
- ---
393
-
394
- ## Contributing
395
-
396
- Participation is highly valued and warmly welcomed. The ultimate goal is to create a tool that proves genuinely useful and empowers a wide range of developers to build more robust and reliable applications.
397
-
398
- Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines, and [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md) for community standards.
399
-
400
- ---
401
-
402
- ## License
403
-
404
- [MIT](LICENSE) © Callari, Salvatore
405
-
406
- ---
407
-
408
- <sub>"Design by Contract" is a registered trademark of Eiffel Software. XDBC is an independent project and is not affiliated with or endorsed by Eiffel Software.</sub>
1
+ <p align="center">
2
+ <img src="https://img.shields.io/npm/v/xdbc?style=flat-square" alt="npm version" />
3
+ <img src="https://img.shields.io/npm/l/xdbc?style=flat-square" alt="license" />
4
+ <img src="https://img.shields.io/npm/dt/xdbc?style=flat-square" alt="downloads" />
5
+ <img src="https://img.shields.io/badge/TypeScript-5.x-blue?style=flat-square&logo=typescript" alt="TypeScript" />
6
+ <img src="https://img.shields.io/badge/decorators-experimentalDecorators-blue?style=flat-square" alt="decorators" />
7
+ <img src="https://img.shields.io/badge/optimized%20for-VS%20Code-007acc?style=flat-square&logo=visualstudiocode" alt="VS Code" />
8
+ </p>
9
+
10
+ # XDBC — e**X**plicit **D**esign **b**y **C**ontract for TypeScript
11
+
12
+ > A decorator-based Design by Contract framework that enforces preconditions, postconditions, and invariants through TypeScript metadata — delivering precise, self-documenting, and verifiable component contracts.
13
+
14
+ ---
15
+
16
+ ## At a Glance
17
+
18
+ | Approach | With XDBC | Without XDBC |
19
+ |---|---|---|
20
+ | **Parameter validation** | <pre>@DBC.ParamvalueProvider<br>method(@REGEX.PRE(/^\.*XDBC.\*$/i) input: string[]) {<br> ...<br>}</pre> | <pre>method(input: string[]) {<br> input.forEach((el, i) => {<br> console.assert(/^.\*XDBC.\*$/i.test(el), "error");<br> });<br> ...<br>}</pre> |
21
+ | **Field invariant** | <pre>@REGEX.INVARIANT(/^.\*XDBC.\*$/i)<br>public field = "XDBC";</pre> | <pre>get field(): string { return this._field; }<br>set field(v: string) {<br> console.assert(/^.\*XDBC.\*$/i.test(v), "error");<br> this._field = v;<br>}</pre> |
22
+ | **Return validation** | <pre>@REGEX.POST(/^XDBC$/i)<br>method(input: unknown): string {<br> ...<br> return result;<br>}</pre> | <pre>method(input: unknown): string {<br> ...<br> if (!/^XDBC$/i.test(result)) {<br> throw new Error("error");<br> }<br> return result;<br>}</pre> |
23
+
24
+ Contract violations produce structured, actionable diagnostics:
25
+
26
+ ```
27
+ [ XDBC Infringement [ From "method" in "MyClass": [ Parameter-value "+1d,+5d,-x10y"
28
+ of the 1st parameter did not fulfill one of it's contracts: Violating-Arrayelement at
29
+ index 2. Value has to comply to regular expression "/^(?i:(NOW)|([+-]\d+[dmy]))$/i"]]]
30
+ ```
31
+
32
+ ---
33
+
34
+ ## Table of Contents
35
+
36
+ - [What is Design by Contract?](#what-is-design-by-contract)
37
+ - [Why XDBC?](#why-xdbc)
38
+ - [Installation](#installation)
39
+ - [Decorator API](#decorator-api)
40
+ - [Quick Start](#quick-start)
41
+ - [Contracts Reference](#contracts-reference)
42
+ - [Core Concepts](#core-concepts)
43
+ - [Advanced Features](#advanced-features)
44
+ - [DOM / HTML Input Binding](#dom--html-input-binding)
45
+ - [Configuration](#configuration)
46
+ - [API Documentation](#api-documentation)
47
+ - [Built With XDBC](#built-with-xdbc)
48
+ - [Contributing](#contributing)
49
+ - [License](#license)
50
+
51
+ ---
52
+
53
+ ## What is Design by Contract?
54
+
55
+ [Design by Contract (DbC)](https://en.wikipedia.org/wiki/Design_by_contract) is a software engineering methodology that defines formal, precise, and verifiable interface specifications for software components. Each component's contract comprises:
56
+
57
+ | Element | Purpose |
58
+ |---|---|
59
+ | **Preconditions** | Conditions that must hold true *before* a method executes |
60
+ | **Postconditions** | Guarantees that must hold true *after* a method returns |
61
+ | **Invariants** | Properties that must remain true *throughout* an object's lifetime |
62
+
63
+ ### DbC vs. Assertions
64
+
65
+ | Aspect | XDBC Decorators | Manual Assertions |
66
+ |---|---|---|
67
+ | Formality | Formal, declarative, co-located with signatures | Informal, scattered through method bodies |
68
+ | Integration | TypeScript metadata and decorators | Built-in `console.assert` / `throw` |
69
+ | Expressiveness | Composable, parameterized contract objects | Simple boolean checks |
70
+ | Readability | Contracts are visible at the API surface | Validation logic obscures business logic |
71
+ | Maintainability | Contracts are localized and reusable | Duplicated checks are hard to track |
72
+ | Production control | Selectively enable/disable by contract type | Typically all-or-nothing |
73
+
74
+ ---
75
+
76
+ ## Why XDBC?
77
+
78
+ - **Declarative** — contracts live as decorators alongside type signatures, not buried in method bodies
79
+ - **Composable** — combine contracts with `AE`, `OR`, and `IF` for expressive validation
80
+ - **Configurable** — toggle preconditions, postconditions, and invariants independently
81
+ - **Diagnostic** — structured error messages pinpoint the exact violation, parameter, and context
82
+ - **Extensible** — 16 built-in contracts, with support for custom contracts and Zod schema integration
83
+ - **Zero runtime overhead** — disable contract checking in production with a single flag
84
+
85
+ ---
86
+
87
+ ## Installation
88
+
89
+ ```sh
90
+ npm install xdbc
91
+ ```
92
+
93
+ **Requirements:** TypeScript 5.x with `experimentalDecorators` and `emitDecoratorMetadata` enabled in `tsconfig.json`.
94
+
95
+ ```jsonc
96
+ // tsconfig.json
97
+ {
98
+ "compilerOptions": {
99
+ "experimentalDecorators": true,
100
+ "emitDecoratorMetadata": true
101
+ }
102
+ }
103
+ ```
104
+
105
+ ---
106
+
107
+ ## Decorator API
108
+
109
+ XDBC is built on TypeScript's **legacy (`experimentalDecorators`) decorator API** — not the TC39 Stage 3 decorator API.
110
+
111
+ **Why?** Stage 3 decorators deliberately excluded parameter decorators from their scope. Parameter decorators are the foundation of XDBC's contract syntax: `@DEFINED.PRE()`, `@GREATER.PRE(0)`, and every other `PRE` contract applied per-parameter depends on them. There is no equivalent in Stage 3, and no workaround that preserves the same ergonomics.
112
+
113
+ **Is this unusual?** No. Some of the most widely adopted TypeScript frameworks in the industry require `experimentalDecorators` for exactly the same reason and have no near-term plans to migrate: on the backend, NestJS (used at thousands of companies, tens of millions of weekly downloads), TypeORM, class-validator, and class-transformer; on the frontend, `vue-class-component` (Vue's official class-based API) and MobX (the dominant React state management library for class-based stores). `experimentalDecorators: true` is compatible with Angular, Vue, and React — it is a TypeScript compiler flag, not a framework-level constraint, and does not conflict with any framework's runtime behavior. Any project already using these libraries has `experimentalDecorators: true` in its tsconfig and can adopt XDBC with zero additional configuration. For projects that don't, enabling it requires adding two lines to `tsconfig.json` — see [Installation](#installation).
114
+
115
+ **Is it risky?** No. TypeScript explicitly supports both APIs simultaneously and has made no announcement about removing `experimentalDecorators`. Any project already using the frameworks above already has `experimentalDecorators: true` in its tsconfig, meaning XDBC requires zero additional configuration in those environments.
116
+
117
+ **What about the future?** TC39 has an active Stage 1 proposal — [Class Method Parameter Decorators](https://github.com/tc39/proposals/blob/main/stage-1-proposals.md) (Ron Buckton, 2023) — that would close this gap. When parameter decorators reach a stable stage, XDBC will migrate to Stage 3. Because all decorator wiring is contained in `DBC.ts` and the 17 contract classes are completely insulated from it, that migration will be localized and non-breaking at the API level.
118
+
119
+ ---
120
+
121
+ ## Quick Start
122
+
123
+ ```typescript
124
+ import { DBC, REGEX, TYPE, EQ } from "xdbc";
125
+
126
+ class UserService {
127
+
128
+ // Invariant: email must always match pattern
129
+ @REGEX.INVARIANT(/^[^@]+@[^@]+\.[^@]+$/)
130
+ public email = "user@example.com";
131
+
132
+ // Precondition: name must be a string; Postcondition: return must match pattern
133
+ @REGEX.POST(/^Hello, .+$/)
134
+ @DBC.ParamvalueProvider
135
+ public greet(@TYPE.PRE("string") name: string): string {
136
+ return `Hello, ${name}`;
137
+ }
138
+
139
+ // Precondition: age must be >= 0
140
+ @DBC.ParamvalueProvider
141
+ public setAge(@GREATER_OR_EQUAL.PRE(0) age: number) {
142
+ // ...
143
+ }
144
+ }
145
+ ```
146
+
147
+ ---
148
+
149
+ ## Contracts Reference
150
+
151
+ XDBC ships with **16 contracts** organized into core validators and derived specializations:
152
+
153
+ ### Core Contracts
154
+
155
+ | Contract | Description | Constructor |
156
+ |---|---|---|
157
+ | **`REGEX`** | Value must match a regular expression | `new REGEX(expression: RegExp)` |
158
+ | **`TYPE`** | Value must be of a specified type (supports pipe-separated: `"string\|number"`) | `new TYPE(type: string)` |
159
+ | **`EQ`** | Value must equal (or not equal) a reference value | `new EQ(equivalent: any, invert?: boolean)` |
160
+ | **`COMPARISON`** | Numeric comparison against a reference value | `new COMPARISON(equivalent, equalityPermitted, invert)` |
161
+ | **`INSTANCE`** | Value must be an instance of a specified class | `new INSTANCE(reference: any \| any[])` |
162
+ | **`AE`** | Every element in an array must satisfy a set of contracts | `new AE(conditions, index?, idxEnd?)` |
163
+ | **`OR`** | At least one of a set of contracts must be satisfied | `new OR(conditions: DBC[])` |
164
+ | **`IF`** | Conditional contract: if A holds, then B must also hold | `IF.PRE(condition, inCase, path?, invert?)` |
165
+ | **`JSON_OP`** | Object must contain specific properties of specific types | `new JSON_OP(properties: {name, type}[], checkElements?)` |
166
+ | **`JSON_Parse`** | String must be valid JSON; optionally forwards parsed result | `new JSON_Parse(receptor?: (json) => void)` |
167
+ | **`DEFINED`** | Value must not be `null` or `undefined` | — |
168
+ | **`UNDEFINED`** | Value must be `undefined` | — |
169
+ | **`ARRAY`** | Value must be an array | — |
170
+ | **`HasAttribute`** | HTMLElement must possess a named attribute | `HasAttribute.PRE(attrName, invert?)` |
171
+ | **`ZOD`** | Value must validate against a Zod schema | `new ZOD(schema: z.ZodType)` |
172
+
173
+ ### Derived Contracts
174
+
175
+ | Contract | Derives From | Semantics |
176
+ |---|---|---|
177
+ | **`GREATER`** | `COMPARISON` | `value > reference` |
178
+ | **`GREATER_OR_EQUAL`** | `COMPARISON` | `value >= reference` |
179
+ | **`LESS`** | `COMPARISON` | `value < reference` |
180
+ | **`LESS_OR_EQUAL`** | `COMPARISON` | `value <= reference` |
181
+ | **`DIFFERENT`** | `EQ` | `value !== reference` |
182
+ | **`PLAIN_OBJECT`** | `ARRAY` | Value must be a non-null, non-array object |
183
+
184
+ ### Built-in Regular Expressions
185
+
186
+ `REGEX.stdExp` provides ready-to-use patterns:
187
+
188
+ | Key | Validates |
189
+ |---|---|
190
+ | `htmlAttributeName` | HTML attribute names |
191
+ | `eMail` | Email addresses |
192
+ | `property` | Property identifiers |
193
+ | `url` | URLs |
194
+ | `keyPath` | Key paths |
195
+ | `date` | Date strings |
196
+ | `dateFormat` | Date format patterns |
197
+ | `cssSelector` | CSS selectors |
198
+ | `boolean` | Boolean string literals |
199
+ | `colorCodeHEX` | Hex color codes |
200
+ | `simpleHotkey` | Keyboard shortcuts |
201
+ | `bcp47` | BCP 47 language tags |
202
+
203
+ ---
204
+
205
+ ## Core Concepts
206
+
207
+ ### Decorator Types
208
+
209
+ Every contract exposes three decorator factories:
210
+
211
+ | Decorator | Applies To | Validates |
212
+ |---|---|---|
213
+ | `Contract.PRE(...)` | Method parameters | Input values before method execution |
214
+ | `Contract.POST(...)` | Methods | Return value after method execution |
215
+ | `Contract.INVARIANT(...)` | Fields / Properties | Value on every assignment (including initialization) |
216
+
217
+ ### The `ParamvalueProvider` Decorator
218
+
219
+ TypeScript parameter decorators do not natively receive parameter values. Any method using `PRE` parameter contracts **must** be decorated with `@DBC.ParamvalueProvider`:
220
+
221
+ ```typescript
222
+ @DBC.ParamvalueProvider
223
+ public process(
224
+ @TYPE.PRE("string") name: string,
225
+ @REGEX.PRE(/^\d{4}$/) code: string
226
+ ) { ... }
227
+ ```
228
+
229
+ ### Path Resolution
230
+
231
+ All `PRE`, `POST`, and `INVARIANT` decorators accept an optional **`path`** parameter — a dotted path that specifies a nested property of the value to validate instead of the value itself:
232
+
233
+ ```typescript
234
+ // Validate that element.tagName === "SELECT"
235
+ @DBC.ParamvalueProvider
236
+ public handleElement(@EQ.PRE("SELECT", false, "tagName") el: HTMLElement) { }
237
+
238
+ // Validate that value.length === 1
239
+ @EQ.INVARIANT(1, false, "length")
240
+ public singleChar = "X";
241
+ ```
242
+
243
+ Path resolution supports:
244
+ - **Dot notation**: `"user.address.city"`
245
+ - **Array indices**: `"items[0]"`
246
+ - **Method calls**: `"getName()"`
247
+ - **HTML attributes**: `"@data-id"`
248
+
249
+ ### Custom Hints
250
+
251
+ Add context to error messages with the optional **`hint`** parameter:
252
+
253
+ ```typescript
254
+ @DBC.ParamvalueProvider
255
+ public setAge(
256
+ @GREATER_OR_EQUAL.PRE(0, undefined, "Age must be non-negative") age: number
257
+ ) { }
258
+ ```
259
+
260
+ ---
261
+
262
+ ## Advanced Features
263
+
264
+ ### Composing Contracts with `AE`
265
+
266
+ Validate array elements against one or more contracts, optionally targeting a specific index range:
267
+
268
+ ```typescript
269
+ // All elements must be non-empty strings matching a date pattern
270
+ @AE.PRE([new TYPE("string"), new REGEX(/^\d{4}-\d{2}-\d{2}$/)])
271
+ public processDates(dates: string[]) { }
272
+
273
+ // Only elements at indices 1 through 3
274
+ @AE.PRE([new REGEX(/^[A-Z]+$/)], 1, 3)
275
+ public processRange(items: string[]) { }
276
+
277
+ // Single element at index 0
278
+ @AE.PRE([new TYPE("number")], 0)
279
+ public processFirst(values: unknown[]) { }
280
+ ```
281
+
282
+ ### Logical Composition with `OR`
283
+
284
+ At least one contract must pass:
285
+
286
+ ```typescript
287
+ @DBC.ParamvalueProvider
288
+ public setStatus(@OR.PRE([new EQ("active"), new EQ("inactive"), new EQ("pending")]) status: string) { }
289
+ ```
290
+
291
+ ### Conditional Contracts with `IF`
292
+
293
+ Apply a contract only when a precondition holds:
294
+
295
+ ```typescript
296
+ // If the value is a string, it must also match digits-only
297
+ @IF.PRE(new TYPE("string"), new REGEX(/^\d+$/))
298
+ public processInput(value: unknown) { }
299
+ ```
300
+
301
+ ### Zod Schema Integration
302
+
303
+ Leverage Zod schemas for complex structural validation:
304
+
305
+ ```typescript
306
+ import { z } from "zod";
307
+
308
+ const UserSchema = z.object({
309
+ name: z.string().min(1),
310
+ email: z.string().email(),
311
+ age: z.number().int().positive()
312
+ });
313
+
314
+ @DBC.ParamvalueProvider
315
+ public createUser( @ZOD.PRE(UserSchema) data: unknown) { }
316
+ ```
317
+
318
+ ### Type-Safe Static Checks
319
+
320
+ Several contracts offer static `tsCheck` methods for imperative validation outside of decorators:
321
+
322
+ ```typescript
323
+ // Throws if value is not a string
324
+ const name = TYPE.tsCheck<string>(input, "string", "Expected a string");
325
+
326
+ // Throws if value doesn't match regex
327
+ const code = REGEX.tsCheck<string>(input, /^\d{4}$/, "Invalid code format");
328
+
329
+ // Throws if not an instance of Date
330
+ const date = INSTANCE.tsCheck<Date>(input, Date, "Expected a Date");
331
+
332
+ // Throws if none of the conditions pass
333
+ const result = OR.tsCheck<string>(input, [new EQ("a"), new EQ("b")]);
334
+ ```
335
+
336
+ ---
337
+
338
+ ## DOM / HTML Input Binding
339
+
340
+ XDBC can enforce contracts directly on `<input>` and `<textarea>` elements using HTML data attributes — no JavaScript wiring required per element.
341
+
342
+ ### Setup
343
+
344
+ ```ts
345
+ import { scanDOM } from "xdbc/DBC/DOM";
346
+
347
+ // Call once after the DOM is ready. Returns a cleanup function.
348
+ const cleanup = scanDOM();
349
+
350
+ // Optionally scope to a subtree:
351
+ const cleanup = scanDOM(document.getElementById("my-form"));
352
+
353
+ // Remove all listeners (e.g. on component unmount):
354
+ cleanup();
355
+ ```
356
+
357
+ ### Marking an element
358
+
359
+ Add `data-xdbc` to opt an element in. The optional value sets the DBC instance path (default: `"WaXCode.DBC"`):
360
+
361
+ ```html
362
+ <input data-xdbc />
363
+ <input data-xdbc="MyApp.DBC" />
364
+ ```
365
+
366
+ ### Built-in contract attributes
367
+
368
+ | Attribute | Example value | Contract |
369
+ |---|---|---|
370
+ | `data-xdbc-regex` | `^\d*$` | `REGEX` |
371
+ | `data-xdbc-type` | `string\|number` | `TYPE` |
372
+ | `data-xdbc-eq` | `hello` | `EQ` |
373
+ | `data-xdbc-different` | `forbidden` | `EQ` (inverted) |
374
+ | `data-xdbc-defined` | *(no value needed)* | `DEFINED` |
375
+ | `data-xdbc-undefined` | *(no value needed)* | `UNDEFINED` |
376
+ | `data-xdbc-greater` | `5` | `COMPARISON` |
377
+ | `data-xdbc-greater-or-equal` | `5` | `COMPARISON` |
378
+ | `data-xdbc-less` | `100` | `COMPARISON` |
379
+ | `data-xdbc-less-or-equal` | `100` | `COMPARISON` |
380
+ | `data-xdbc-or` | `regex:^\d+$;;eq:N/A` | OR combinator (see below) |
381
+
382
+ Multiple attributes on one element are all enforced — the first failure blocks and reports.
383
+
384
+ ### OR fragment syntax
385
+
386
+ Use `data-xdbc-or` to express that the value must satisfy **at least one** of several contracts. Fragments are separated by `;;`; each fragment is `<contract-key>:<value>`, where the split is on the **first** `:` only (so colons inside regex patterns are safe):
387
+
388
+ ```html
389
+ <!-- digits, OR exactly the string "N/A" -->
390
+ <input data-xdbc data-xdbc-or="regex:^\d+$;;eq:N/A" />
391
+
392
+ <!-- http or https URL, OR the literal "N/A" -->
393
+ <input data-xdbc data-xdbc-or="regex:^https?://;;eq:N/A" />
394
+ ```
395
+
396
+ ### Behaviour on infringement
397
+
398
+ 1. The element's value is **reverted** to the last accepted state, blocking the invalid input.
399
+ 2. The DBC instance's `onInfringement`, `logToConsole`, and `throwException` settings are all honoured. Any throw is swallowed inside the event handler so it cannot propagate unhandled.
400
+
401
+ ### IME / composition awareness
402
+
403
+ Validation is suspended during IME composition (e.g. CJK on-screen keyboards) and runs once on `compositionend`, so partially composed characters are never incorrectly rejected.
404
+
405
+ ### Registering custom contracts
406
+
407
+ Use `registerDOMContract` to add any contract — including future ones — without modifying the library:
408
+
409
+ ```ts
410
+ import { registerDOMContract } from "xdbc/DBC/DOM";
411
+ import { MY_CONTRACT } from "./MY_CONTRACT";
412
+
413
+ // Register once, before scanDOM():
414
+ registerDOMContract("my-contract", (value, attrValue) =>
415
+ MY_CONTRACT.checkAlgorithm(value, attrValue),
416
+ );
417
+ ```
418
+
419
+ ```html
420
+ <input data-xdbc data-xdbc-my-contract="someConfig" />
421
+ ```
422
+
423
+ The `attrValue` string is whatever appears in the attribute — parse it however your contract needs.
424
+
425
+ ---
426
+
427
+ ## Configuration
428
+
429
+ ### DBC Instance Settings
430
+
431
+ A default DBC instance is automatically registered at `WaXCode.DBC` when the module is imported. You can access and configure it:
432
+
433
+ ```typescript
434
+ import { DBC } from "xdbc";
435
+
436
+ // Access the default DBC instance
437
+ const dbc = (globalThis as any).WaXCode.DBC as DBC;
438
+
439
+ // Toggle contract checking
440
+ dbc.executionSettings.checkPreconditions = true;
441
+ dbc.executionSettings.checkPostconditions = true;
442
+ dbc.executionSettings.checkInvariants = true;
443
+
444
+ // Configure infringement handling
445
+ dbc.infringementSettings.throwException = true; // throw DBC.Infringement on violation
446
+ dbc.infringementSettings.logToConsole = false; // log to console instead
447
+
448
+ # React to infringements programmatically
449
+ dbc.infringementSettings.onInfringement = (infringement, context) => {
450
+ // infringement — DBC.Infringement instance (extends Error, has .message and .stack)
451
+ // context.type — "precondition" | "postcondition" | "invariant"
452
+ // context.value — the raw value that violated the contract
453
+ Sentry.captureException(infringement, { extra: context });
454
+ };
455
+ ```
456
+
457
+ The callback fires **before** `throwException`, so it always runs even when an exception is thrown. All three settings are independent and can be combined freely.
458
+
459
+ ### Multiple DBC Instances
460
+
461
+ Create isolated DBC instances with separate configurations using `DBC.register()`:
462
+
463
+ ```typescript
464
+ // Register a vendor-specific instance at a custom path
465
+ const vendorDbc = new DBC(
466
+ { throwException: false, logToConsole: true },
467
+ );
468
+ DBC.register(vendorDbc, "MyVendor.DBC");
469
+
470
+ // Route a contract to the custom instance via its path
471
+ @REGEX.INVARIANT(/^[A-Z]+$/, undefined, undefined, "MyVendor.DBC")
472
+ public code = "ABC";
473
+ ```
474
+
475
+ > **Note:** `new DBC()` does not automatically mount onto `globalThis`. Call `DBC.register(instance, path)` to make an instance available for decorator resolution.
476
+
477
+ ### Test Isolation
478
+
479
+ Use `DBC.isolated()` to run tests with a temporary DBC instance that doesn't affect other tests:
480
+
481
+ ```typescript
482
+ DBC.isolated((tempDbc) => {
483
+ // tempDbc is registered at "WaXCode.DBC" for the duration of this callback
484
+ tempDbc.executionSettings.checkPreconditions = false;
485
+
486
+ // ... run tests with contracts disabled ...
487
+ });
488
+ // Original DBC instance is automatically restored here
489
+ ```
490
+
491
+ ### Disabling Contracts in Production
492
+
493
+ ```typescript
494
+ const dbc = (globalThis as any).WaXCode.DBC as DBC;
495
+ dbc.executionSettings.checkPreconditions = false;
496
+ dbc.executionSettings.checkPostconditions = false;
497
+ dbc.executionSettings.checkInvariants = false;
498
+ ```
499
+
500
+ ---
501
+
502
+ ## API Documentation
503
+
504
+ Full generated API documentation is available at **[callaris.github.io/XDBC](https://callaris.github.io/XDBC/)**.
505
+
506
+ See [`Demo.ts`](src/Demo.ts) for annotated usage examples.
507
+
508
+ ---
509
+
510
+ ## Built With XDBC
511
+
512
+ XDBC is actively used in production across the following projects:
513
+
514
+ | Project | Context |
515
+ |---|---|
516
+ | [CodBi](https://github.com/XIMA-formcycle-Entwicklerkreis/CodBi) | Low-code engine plugin for [XIMA Formcycle](https://www.xima.de/formcycle) |
517
+ | [tinymce-multicloud-plugin](https://github.com/CallariS/tinymce-multicloud-plugin) | multiCloud plugin for [TinyMCE](https://www.tiny.cloud) |
518
+ | *(internal)* | Comprehensive Active Directory management suite for schools, deployed at a German public administration |
519
+
520
+ *XDBC is used in the Angular frontends of the above projects.*
521
+
522
+ ---
523
+
524
+ ## Contributing
525
+
526
+ Participation is highly valued and warmly welcomed. The ultimate goal is to create a tool that proves genuinely useful and empowers a wide range of developers to build more robust and reliable applications.
527
+
528
+ Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines, and [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md) for community standards.
529
+
530
+ ---
531
+
532
+ ## License
533
+
534
+ [MIT](LICENSE) © Callari, Salvatore
535
+
536
+ ---
537
+
538
+ <sub>"Design by Contract" is a registered trademark of Eiffel Software. XDBC is an independent project and is not affiliated with or endorsed by Eiffel Software.</sub>