@hyperscale0/udl 1.0.0 → 1.0.123

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 (234) hide show
  1. package/CHANGELOG.md +5 -216
  2. package/LICENSE.md +356 -0
  3. package/NOTICE.md +8 -0
  4. package/README.md +14 -106
  5. package/dist/canonical.d.ts.map +1 -1
  6. package/dist/canonical.js +1 -29
  7. package/dist/canonical.js.map +1 -1
  8. package/dist/diagnostics.d.ts +13 -165
  9. package/dist/diagnostics.d.ts.map +1 -1
  10. package/dist/diagnostics.js +33 -157
  11. package/dist/diagnostics.js.map +1 -1
  12. package/dist/field-value.d.ts +5 -0
  13. package/dist/field-value.d.ts.map +1 -0
  14. package/dist/field-value.js +85 -0
  15. package/dist/field-value.js.map +1 -0
  16. package/dist/finance.d.ts +10 -53
  17. package/dist/finance.d.ts.map +1 -1
  18. package/dist/finance.js +252 -536
  19. package/dist/finance.js.map +1 -1
  20. package/dist/index.d.ts +9 -13
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +9 -9
  23. package/dist/index.js.map +1 -1
  24. package/dist/json.d.ts +2 -0
  25. package/dist/json.d.ts.map +1 -0
  26. package/dist/json.js +30 -0
  27. package/dist/json.js.map +1 -0
  28. package/dist/limits.d.ts +3 -28
  29. package/dist/limits.d.ts.map +1 -1
  30. package/dist/limits.js +5 -31
  31. package/dist/limits.js.map +1 -1
  32. package/dist/object-contract.d.ts +140 -0
  33. package/dist/object-contract.d.ts.map +1 -0
  34. package/dist/object-contract.js +314 -0
  35. package/dist/object-contract.js.map +1 -0
  36. package/dist/object-semantics-schema.d.ts +5710 -0
  37. package/dist/object-semantics-schema.d.ts.map +1 -0
  38. package/dist/object-semantics-schema.js +119 -0
  39. package/dist/object-semantics-schema.js.map +1 -0
  40. package/dist/object-semantics.d.ts +6 -0
  41. package/dist/object-semantics.d.ts.map +1 -0
  42. package/dist/object-semantics.js +279 -0
  43. package/dist/object-semantics.js.map +1 -0
  44. package/dist/object-structures.d.ts +4 -0
  45. package/dist/object-structures.d.ts.map +1 -0
  46. package/dist/object-structures.js +134 -0
  47. package/dist/object-structures.js.map +1 -0
  48. package/dist/reporting-validation.d.ts +8 -0
  49. package/dist/reporting-validation.d.ts.map +1 -0
  50. package/dist/reporting-validation.js +252 -0
  51. package/dist/reporting-validation.js.map +1 -0
  52. package/dist/reporting.d.ts +477 -0
  53. package/dist/reporting.d.ts.map +1 -0
  54. package/dist/reporting.js +169 -0
  55. package/dist/reporting.js.map +1 -0
  56. package/dist/schema.d.ts +5572 -2710
  57. package/dist/schema.d.ts.map +1 -1
  58. package/dist/schema.js +444 -1121
  59. package/dist/schema.js.map +1 -1
  60. package/dist/validation.d.ts +10 -73
  61. package/dist/validation.d.ts.map +1 -1
  62. package/dist/validation.js +1109 -2569
  63. package/dist/validation.js.map +1 -1
  64. package/docs/assets/brand/manifest.json +30 -0
  65. package/docs/assets/brand/udl-horizontal-white.svg +1 -0
  66. package/docs/assets/brand/udl-horizontal.svg +1 -0
  67. package/docs/assets/brand/udl-stacked-white.svg +1 -0
  68. package/docs/assets/brand/udl-stacked.svg +1 -0
  69. package/docs/assets/udl.svg +11 -0
  70. package/package.json +13 -22
  71. package/spec/README.md +300 -172
  72. package/spec/cars.udl.json +249 -0
  73. package/spec/udl.schema.json +3066 -2242
  74. package/src/canonical.ts +1 -35
  75. package/src/diagnostics.ts +76 -209
  76. package/src/field-value.ts +87 -0
  77. package/src/finance.ts +327 -832
  78. package/src/index.ts +18 -95
  79. package/src/json.ts +34 -0
  80. package/src/limits.ts +5 -31
  81. package/src/object-contract.ts +559 -0
  82. package/src/object-semantics-schema.ts +148 -0
  83. package/src/object-semantics.ts +378 -0
  84. package/src/object-structures.ts +255 -0
  85. package/src/reporting-validation.ts +383 -0
  86. package/src/reporting.ts +178 -0
  87. package/src/schema.ts +510 -1277
  88. package/src/validation.ts +1630 -4545
  89. package/LICENSE +0 -661
  90. package/LICENSING.md +0 -51
  91. package/TRADEMARKS.md +0 -35
  92. package/conformance/README.md +0 -82
  93. package/conformance/evolution/action-contract.expected.json +0 -10
  94. package/conformance/evolution/action-contract.live.udl +0 -44
  95. package/conformance/evolution/action-contract.next.udl +0 -45
  96. package/conformance/evolution/product-identity.expected.json +0 -10
  97. package/conformance/evolution/product-identity.live.udl +0 -55
  98. package/conformance/evolution/product-identity.next.udl +0 -55
  99. package/conformance/evolution/version-required.expected.json +0 -10
  100. package/conformance/evolution/version-required.live.udl +0 -55
  101. package/conformance/evolution/version-required.next.udl +0 -58
  102. package/conformance/invalid/action-without-transition.expected.json +0 -10
  103. package/conformance/invalid/action-without-transition.udl +0 -60
  104. package/conformance/invalid/agent-description-too-long.expected.json +0 -10
  105. package/conformance/invalid/agent-description-too-long.udl +0 -57
  106. package/conformance/invalid/blank-title.expected.json +0 -10
  107. package/conformance/invalid/blank-title.udl +0 -54
  108. package/conformance/invalid/composition-dial-duplicate-key.expected.json +0 -10
  109. package/conformance/invalid/composition-dial-duplicate-key.udl +0 -73
  110. package/conformance/invalid/depth-budget.expected.json +0 -10
  111. package/conformance/invalid/depth-budget.udl +0 -49
  112. package/conformance/invalid/duplicate-subject.expected.json +0 -10
  113. package/conformance/invalid/duplicate-subject.udl +0 -230
  114. package/conformance/invalid/forged-effects.expected.json +0 -10
  115. package/conformance/invalid/forged-effects.udl +0 -76
  116. package/conformance/invalid/format-version.expected.json +0 -10
  117. package/conformance/invalid/format-version.udl +0 -54
  118. package/conformance/invalid/instrument-id-not-snake-case.expected.json +0 -10
  119. package/conformance/invalid/instrument-id-not-snake-case.udl +0 -54
  120. package/conformance/invalid/invalid-aggregate-gate-shape.expected.json +0 -10
  121. package/conformance/invalid/invalid-aggregate-gate-shape.udl +0 -1819
  122. package/conformance/invalid/invalid-check-duration.expected.json +0 -10
  123. package/conformance/invalid/invalid-check-duration.udl +0 -219
  124. package/conformance/invalid/invalid-dial-anchor.expected.json +0 -10
  125. package/conformance/invalid/invalid-dial-anchor.udl +0 -219
  126. package/conformance/invalid/invalid-exception-parent-ref.expected.json +0 -10
  127. package/conformance/invalid/invalid-exception-parent-ref.udl +0 -2487
  128. package/conformance/invalid/invalid-exposure-shape.expected.json +0 -10
  129. package/conformance/invalid/invalid-exposure-shape.udl +0 -1819
  130. package/conformance/invalid/invalid-remainder.expected.json +0 -10
  131. package/conformance/invalid/invalid-remainder.udl +0 -220
  132. package/conformance/invalid/invalid-schema-keyword.expected.json +0 -10
  133. package/conformance/invalid/invalid-schema-keyword.udl +0 -220
  134. package/conformance/invalid/invalid-utf8.expected.json +0 -10
  135. package/conformance/invalid/invalid-utf8.udl +0 -1
  136. package/conformance/invalid/malformed-json.expected.json +0 -10
  137. package/conformance/invalid/malformed-json.udl +0 -1
  138. package/conformance/invalid/missing-create-action.expected.json +0 -10
  139. package/conformance/invalid/missing-create-action.udl +0 -48
  140. package/conformance/invalid/missing-exception-amount-field.expected.json +0 -10
  141. package/conformance/invalid/missing-exception-amount-field.udl +0 -2487
  142. package/conformance/invalid/missing-exception-contract.expected.json +0 -14
  143. package/conformance/invalid/missing-exception-contract.udl +0 -2523
  144. package/conformance/invalid/missing-exception-reason-field.expected.json +0 -10
  145. package/conformance/invalid/missing-exception-reason-field.udl +0 -2487
  146. package/conformance/invalid/not-an-object.expected.json +0 -10
  147. package/conformance/invalid/not-an-object.udl +0 -1
  148. package/conformance/invalid/payout-reconcile-not-a-bank-debit.expected.json +0 -10
  149. package/conformance/invalid/payout-reconcile-not-a-bank-debit.udl +0 -259
  150. package/conformance/invalid/quote-freeze-set-incomplete.expected.json +0 -10
  151. package/conformance/invalid/quote-freeze-set-incomplete.udl +0 -261
  152. package/conformance/invalid/quote-named-reference-gate.expected.json +0 -10
  153. package/conformance/invalid/quote-named-reference-gate.udl +0 -50
  154. package/conformance/invalid/reconcile-named-reference-gate.expected.json +0 -10
  155. package/conformance/invalid/reconcile-named-reference-gate.udl +0 -50
  156. package/conformance/invalid/unknown-key.expected.json +0 -10
  157. package/conformance/invalid/unknown-key.udl +0 -55
  158. package/conformance/invalid/unknown-reference-gate-field.expected.json +0 -10
  159. package/conformance/invalid/unknown-reference-gate-field.udl +0 -1819
  160. package/conformance/invalid/unknown-required-field.expected.json +0 -10
  161. package/conformance/invalid/unknown-required-field.udl +0 -220
  162. package/conformance/invalid/unreachable-state.expected.json +0 -10
  163. package/conformance/invalid/unreachable-state.udl +0 -55
  164. package/conformance/invalid/wrong-exception-amount-field.expected.json +0 -10
  165. package/conformance/invalid/wrong-exception-amount-field.udl +0 -2487
  166. package/conformance/invalid/wrong-exception-reason-field.expected.json +0 -10
  167. package/conformance/invalid/wrong-exception-reason-field.udl +0 -2487
  168. package/conformance/valid/agent-description.expected.json +0 -6
  169. package/conformance/valid/agent-description.udl +0 -66
  170. package/conformance/valid/cards.expected.json +0 -6
  171. package/conformance/valid/cards.udl +0 -1579
  172. package/conformance/valid/commerce-escrow.expected.json +0 -6
  173. package/conformance/valid/commerce-escrow.udl +0 -1512
  174. package/conformance/valid/compiled-crowdfunding.expected.json +0 -6
  175. package/conformance/valid/compiled-crowdfunding.udl +0 -1843
  176. package/conformance/valid/compiled-watch-club.expected.json +0 -6
  177. package/conformance/valid/compiled-watch-club.udl +0 -2486
  178. package/conformance/valid/complete-contract.expected.json +0 -6
  179. package/conformance/valid/complete-contract.udl +0 -218
  180. package/conformance/valid/effect-signatures.expected.json +0 -6
  181. package/conformance/valid/effect-signatures.udl +0 -75
  182. package/conformance/valid/hand-edited.expected.json +0 -6
  183. package/conformance/valid/hand-edited.udl +0 -1
  184. package/conformance/valid/insured-car-marketplace.expected.json +0 -6
  185. package/conformance/valid/insured-car-marketplace.udl +0 -1050
  186. package/conformance/valid/insured-travel.expected.json +0 -6
  187. package/conformance/valid/insured-travel.udl +0 -3469
  188. package/conformance/valid/minimal.expected.json +0 -6
  189. package/conformance/valid/minimal.udl +0 -54
  190. package/conformance/valid/protection.expected.json +0 -6
  191. package/conformance/valid/protection.udl +0 -1551
  192. package/conformance/valid/string-escaping.expected.json +0 -6
  193. package/conformance/valid/string-escaping.udl +0 -54
  194. package/dist/check-profiles.d.ts +0 -57
  195. package/dist/check-profiles.d.ts.map +0 -1
  196. package/dist/check-profiles.js +0 -62
  197. package/dist/check-profiles.js.map +0 -1
  198. package/dist/cli.d.ts +0 -3
  199. package/dist/cli.d.ts.map +0 -1
  200. package/dist/cli.js +0 -184
  201. package/dist/cli.js.map +0 -1
  202. package/dist/effects.d.ts +0 -41
  203. package/dist/effects.d.ts.map +0 -1
  204. package/dist/effects.js +0 -110
  205. package/dist/effects.js.map +0 -1
  206. package/dist/evolution.d.ts +0 -120
  207. package/dist/evolution.d.ts.map +0 -1
  208. package/dist/evolution.js +0 -567
  209. package/dist/evolution.js.map +0 -1
  210. package/dist/parser.d.ts +0 -4
  211. package/dist/parser.d.ts.map +0 -1
  212. package/dist/parser.js +0 -44
  213. package/dist/parser.js.map +0 -1
  214. package/docs/README.md +0 -14
  215. package/docs/guide/01-a-document.md +0 -37
  216. package/docs/guide/02-money-steps.md +0 -23
  217. package/docs/guide/03-laws.md +0 -18
  218. package/docs/guide/04-fees-and-remainder.md +0 -15
  219. package/docs/guide/05-checks-updates-dials.md +0 -7
  220. package/docs/guide/06-effects.md +0 -11
  221. package/docs/guide/07-evolution.md +0 -11
  222. package/docs/guide/08-implementing.md +0 -13
  223. package/docs/llms-full.txt +0 -1241
  224. package/docs/llms.txt +0 -14
  225. package/docs/reference/canonical.md +0 -16
  226. package/docs/reference/clauses.md +0 -986
  227. package/docs/reference/cli.md +0 -22
  228. package/docs/reference/diagnostics.md +0 -32
  229. package/skills/udl/SKILL.md +0 -28
  230. package/src/check-profiles.ts +0 -80
  231. package/src/cli.ts +0 -196
  232. package/src/effects.ts +0 -163
  233. package/src/evolution.ts +0 -965
  234. package/src/parser.ts +0 -58
package/src/canonical.ts CHANGED
@@ -1,6 +1,5 @@
1
1
  import { assertValidUdl } from "./validation.js";
2
-
3
- const INDENT = " ";
2
+ import { writeJson } from "./json.js";
4
3
 
5
4
  export function serializeUdl(value: unknown): string {
6
5
  const document = assertValidUdl(value);
@@ -17,36 +16,3 @@ export async function canonicalDigest(value: unknown): Promise<string> {
17
16
  .map((byte) => byte.toString(16).padStart(2, "0"))
18
17
  .join("");
19
18
  }
20
-
21
- function writeJson(value: unknown, depth: number): string {
22
- if (value === null || typeof value !== "object") {
23
- const encoded = JSON.stringify(value);
24
- if (encoded === undefined) {
25
- throw new TypeError("UDL canonical JSON received a non-JSON value");
26
- }
27
- return encoded;
28
- }
29
-
30
- const indent = INDENT.repeat(depth);
31
- const childIndent = INDENT.repeat(depth + 1);
32
- if (Array.isArray(value)) {
33
- if (value.length === 0) return "[]";
34
- return `[\n${value
35
- .map((item) => `${childIndent}${writeJson(item, depth + 1)}`)
36
- .join(",\n")}\n${indent}]`;
37
- }
38
-
39
- const record = value as Record<string, unknown>;
40
- const keys = Object.keys(record).sort(compareCodeUnits);
41
- if (keys.length === 0) return "{}";
42
- return `{\n${keys
43
- .map(
44
- (key) =>
45
- `${childIndent}${JSON.stringify(key)}: ${writeJson(record[key], depth + 1)}`,
46
- )
47
- .join(",\n")}\n${indent}}`;
48
- }
49
-
50
- function compareCodeUnits(left: string, right: string): number {
51
- return left < right ? -1 : left > right ? 1 : 0;
52
- }
@@ -1,221 +1,88 @@
1
- export type UdlIssueCategory =
2
- | "invalid_evolution"
3
- | "invalid_json"
4
- | "invalid_semantics"
5
- | "invalid_shape"
6
- | "invalid_utf8"
7
- | "resource_limit";
8
-
9
- export type UdlDiagnosticFamily =
10
- | "admission"
11
- | "document"
12
- | "evolution"
13
- | "finance"
14
- | "gates"
15
- | "lifecycle"
16
- | "schema";
17
-
18
- const diagnosticDefinitions = {
19
- UDL1001: {
20
- category: "invalid_utf8",
21
- family: "admission",
22
- title: "Invalid UTF-8",
23
- fix: "Encode the document as valid UTF-8.",
24
- },
25
- UDL1002: {
26
- category: "invalid_json",
27
- family: "admission",
28
- title: "Invalid JSON",
29
- fix: "Repair the JSON syntax before validation.",
30
- },
31
- UDL1003: {
32
- category: "invalid_shape",
33
- family: "admission",
34
- title: "Invalid document shape",
35
- fix: "Match the published UDL JSON Schema.",
36
- },
37
- UDL1004: {
38
- category: "resource_limit",
39
- family: "admission",
40
- title: "Resource limit exceeded",
41
- fix: "Reduce the source size, nesting, values, strings, references, or financial paths named by the message.",
42
- },
43
-
44
- UDL2001: {
45
- category: "invalid_semantics",
46
- family: "document",
47
- title: "Duplicate declaration",
48
- fix: "Give each declaration a unique name.",
49
- },
50
- UDL2002: {
51
- category: "invalid_semantics",
52
- family: "document",
53
- title: "Document law violation",
54
- fix: "Repair the declaration, subject contract, or derived effects named by the message.",
55
- },
56
- UDL2005: {
57
- category: "invalid_semantics",
58
- family: "document",
59
- title: "Derived effects mismatch",
60
- fix: "Regenerate the action effects from its clauses.",
61
- },
62
-
63
- UDL3001: {
64
- category: "invalid_semantics",
65
- family: "lifecycle",
66
- title: "Lifecycle is not closed",
67
- fix: "Declare every state and action transition, and make every state reachable.",
68
- },
69
-
70
- UDL4001: {
71
- category: "invalid_semantics",
72
- family: "finance",
73
- title: "Money graph violation",
74
- fix: "Balance every funded amount and close every hold on each lifecycle path.",
75
- },
76
-
77
- UDL5001: {
78
- category: "invalid_semantics",
79
- family: "gates",
80
- title: "Reference gate violation",
81
- fix: "Point the gate at a declared instrument, action, state, field, and reference.",
82
- },
83
- UDL5002: {
84
- category: "invalid_semantics",
85
- family: "gates",
86
- title: "Check requirement violation",
87
- fix: "Use a declared check with compatible evidence and recurrence.",
88
- },
89
- UDL5003: {
90
- category: "invalid_semantics",
91
- family: "gates",
92
- title: "Exposure gate violation",
93
- fix: "Use declared account and money fields for the exposure gate.",
94
- },
95
- UDL5004: {
96
- category: "invalid_semantics",
97
- family: "gates",
98
- title: "Aggregate law violation",
99
- fix: "Point the aggregate at compatible parent and child fields.",
100
- },
101
- UDL5005: {
102
- category: "invalid_semantics",
103
- family: "gates",
104
- title: "Settlement or payout violation",
105
- fix: "Use a declared settlement account and a compatible payout statement line.",
106
- },
107
- UDL5006: {
108
- category: "invalid_semantics",
109
- family: "gates",
110
- title: "Quote and commit violation",
111
- fix: "Declare one complete quote freeze set and one matching commit action.",
112
- },
113
- UDL5007: {
114
- category: "invalid_semantics",
115
- family: "gates",
116
- title: "Reconcile exception child violation",
117
- fix: "Name a declared child whose reference points back to this instrument.",
118
- },
119
- UDL5008: {
120
- category: "invalid_semantics",
121
- family: "gates",
122
- title: "Action clause violation",
123
- fix: "Repair the clause fields and keep incompatible clauses separate.",
124
- },
125
- UDL5009: {
126
- category: "invalid_semantics",
127
- family: "gates",
128
- title: "Reconcile exception amount field is missing or optional",
129
- fix: "Name the exception child's required money field in amountField.",
130
- },
131
- UDL5010: {
132
- category: "invalid_semantics",
133
- family: "gates",
134
- title: "Reconcile exception amount field has the wrong type",
135
- fix: "Point amountField at a money field declared by the exception child.",
136
- },
137
- UDL5011: {
138
- category: "invalid_semantics",
139
- family: "gates",
140
- title: "Reconcile exception reason field is missing or optional",
141
- fix: "Name the exception child's required text field in reasonField.",
142
- },
143
- UDL5012: {
144
- category: "invalid_semantics",
145
- family: "gates",
146
- title: "Reconcile exception reason field has the wrong type",
147
- fix: "Point reasonField at a required plain text field declared by the exception child.",
148
- },
149
-
150
- UDL6001: {
151
- category: "invalid_semantics",
152
- family: "schema",
153
- title: "Unsupported JSON Schema",
154
- fix: "Use only the sealed UDL JSON Schema subset.",
155
- },
156
-
157
- UDL7001: {
158
- category: "invalid_evolution",
159
- family: "evolution",
160
- title: "Stored contract changed",
161
- fix: "Keep stored identities and contracts unchanged, and add only allowed optional declarations.",
162
- },
163
- UDL7002: {
164
- category: "invalid_evolution",
165
- family: "evolution",
166
- title: "Version was not increased",
167
- fix: "Increase the product version for every semantic change.",
168
- },
169
- } as const satisfies Record<
170
- string,
171
- {
172
- readonly category: UdlIssueCategory;
173
- readonly family: UdlDiagnosticFamily;
174
- readonly fix: string;
175
- readonly title: string;
176
- }
177
- >;
178
-
179
- export type UdlIssueCode = keyof typeof diagnosticDefinitions;
180
-
181
- export interface UdlDiagnostic {
182
- readonly category: UdlIssueCategory;
183
- readonly code: UdlIssueCode;
184
- readonly family: UdlDiagnosticFamily;
185
- readonly fix: string;
186
- readonly title: string;
187
- }
188
-
189
- export const udlDiagnostics: readonly UdlDiagnostic[] = Object.entries(
190
- diagnosticDefinitions,
191
- ).map(([code, diagnostic]) => ({
192
- code: code as UdlIssueCode,
193
- ...diagnostic,
194
- }));
195
-
196
- export function udlDiagnostic(code: string): UdlDiagnostic | undefined {
197
- return udlDiagnostics.find((diagnostic) => diagnostic.code === code);
198
- }
199
-
1
+ export type UdlIssueCode =
2
+ | "economic_party_unbound"
3
+ | "economic_move_invalid"
4
+ | "economic_reservation_conflict"
5
+ | "subject_field_conflict"
6
+ | "subject_field_unknown"
7
+ | "subject_requirement_missing"
8
+ | "subject_adapter_unbound"
9
+ | "subject_party_unbound"
10
+ | "party_name_reserved"
11
+ | "party_kind_mismatch"
12
+ | "staff_role_unknown"
13
+ | "product_party_unbound"
14
+ | "product_party_invalid"
15
+ | "UDL1003"
16
+ | "UDL1004"
17
+ | "UDL2001"
18
+ | "UDL2002"
19
+ | "UDL2010"
20
+ | "UDL3001"
21
+ | "UDL4001"
22
+ | "UDL5001";
200
23
  export interface UdlIssue {
201
- readonly category: UdlIssueCategory;
202
- readonly code: UdlIssueCode;
203
- readonly fix: string;
204
- readonly message: string;
205
- readonly path: string;
24
+ code: UdlIssueCode;
25
+ path: string;
26
+ message: string;
27
+ fix: string;
28
+ category: string;
29
+ stranded?: {
30
+ state: string;
31
+ accounts: string[];
32
+ actions: string[];
33
+ paths: Record<string, string[]>;
34
+ };
206
35
  }
36
+ const fixes: Record<UdlIssueCode, string> = {
37
+ economic_party_unbound:
38
+ "Bind sourceParty to a money party retained by this attachment.",
39
+ economic_move_invalid:
40
+ "Declare a cash purpose on a cash transfer or its posting; use internal for non-cash accounting.",
41
+ economic_reservation_conflict:
42
+ "Keep the reservation's economics on its posting.",
43
+ subject_field_conflict:
44
+ "Rename the field or use matching types and constraints.",
45
+ subject_field_unknown: "Name a declared subject requirement or object field.",
46
+ subject_requirement_missing: "Supply the required action field.",
47
+ subject_adapter_unbound: "Bind the required adapter declaration.",
48
+ subject_party_unbound:
49
+ "Bind the parameter to a subject role or declared party.",
50
+ party_name_reserved:
51
+ "Choose a party name other than owner, actor or operator.",
52
+ party_kind_mismatch: "Use a business or subject role for money.",
53
+ staff_role_unknown: "Use a registered staff permission role.",
54
+ product_party_unbound:
55
+ "Supply the consumed business in the Build party bindings.",
56
+ product_party_invalid:
57
+ "Bind a business participant in the same tenant and environment.",
207
58
 
59
+ UDL1003: "Use the UDL 1 typed grammar.",
60
+ UDL1004: "Reduce the declared structure or expansion.",
61
+ UDL2001: "Give each declaration a distinct name.",
62
+ UDL2002: "Repair the named type or declaration.",
63
+ UDL2010: "Remove the invocation cycle or reduce its expansion.",
64
+ UDL3001: "Declare reachable states and one transition per action.",
65
+ UDL4001:
66
+ "Fund owned accounts before spending and close them with zero balances.",
67
+ UDL5001: "Use a declared reference of the required type.",
68
+ };
208
69
  export function issue(
209
70
  code: UdlIssueCode,
210
71
  path: string,
211
- messageDetail?: string,
72
+ message: string,
212
73
  ): UdlIssue {
213
- const diagnostic = diagnosticDefinitions[code];
214
74
  return {
215
- category: diagnostic.category,
216
75
  code,
217
- fix: diagnostic.fix,
218
- message: messageDetail ?? diagnostic.title,
219
76
  path,
77
+ message,
78
+ fix: fixes[code],
79
+ category: category(code),
220
80
  };
221
81
  }
82
+ function category(code: string): string {
83
+ return code === "UDL1003"
84
+ ? "invalid_shape"
85
+ : code === "UDL1004"
86
+ ? "resource_limit"
87
+ : "invalid_semantics";
88
+ }
@@ -0,0 +1,87 @@
1
+ import * as z from "zod";
2
+ import { udlObjectIdSchema, type UdlField } from "./schema.js";
3
+
4
+ const amount = z.string().regex(/^(0|[1-9][0-9]{0,17})$/);
5
+ const text = z.string().min(1).max(2048);
6
+
7
+ /** Values, rather than declarations. The same validator feeds forms and admission. */
8
+ export function udlFieldValueSchema(field: UdlField): z.ZodType {
9
+ let schema: z.ZodType;
10
+ switch (field.type) {
11
+ case "money":
12
+ schema = amount
13
+ .refine(
14
+ (value) =>
15
+ /^(0|[1-9][0-9]{0,17})$/.test(value) &&
16
+ (field.minimum === undefined ||
17
+ BigInt(value) >= BigInt(field.minimum)) &&
18
+ (field.maximum === undefined ||
19
+ BigInt(value) <= BigInt(field.maximum)),
20
+ "Money is outside its declared bounds",
21
+ )
22
+ .meta({
23
+ ...(field.minimum !== undefined
24
+ ? { "x-udl-minimum": field.minimum }
25
+ : {}),
26
+ ...(field.maximum !== undefined
27
+ ? { "x-udl-maximum": field.maximum }
28
+ : {}),
29
+ });
30
+ break;
31
+ case "account":
32
+ schema = text;
33
+ break;
34
+ case "ref":
35
+ schema = field.targetKind === "object" ? udlObjectIdSchema : text;
36
+ break;
37
+ case "date":
38
+ schema = z.iso.datetime({ offset: true });
39
+ break;
40
+ case "duration":
41
+ schema = z.number().int().safe().positive();
42
+ break;
43
+ case "text": {
44
+ let value = z
45
+ .string()
46
+ .min(field.minLength ?? 1)
47
+ .max(field.maxLength ?? 2048);
48
+ if (field.pattern) value = value.regex(new RegExp(field.pattern));
49
+ schema = value;
50
+ break;
51
+ }
52
+ case "integer": {
53
+ let value = z.number().int().safe();
54
+ if (field.minimum !== undefined) value = value.min(field.minimum);
55
+ if (field.maximum !== undefined) value = value.max(field.maximum);
56
+ schema = value;
57
+ break;
58
+ }
59
+ case "percent":
60
+ schema = z.number().int().min(0).max(10000);
61
+ break;
62
+ case "boolean":
63
+ schema = z.boolean();
64
+ break;
65
+ case "enum":
66
+ schema = z.enum(field.values);
67
+ break;
68
+ case "list": {
69
+ const item =
70
+ field.item === "money"
71
+ ? amount
72
+ : field.item === "date"
73
+ ? z.iso.datetime({ offset: true })
74
+ : field.item === "integer"
75
+ ? z.number().int().safe()
76
+ : field.item === "ref" && field.targetKind === "object"
77
+ ? udlObjectIdSchema
78
+ : text;
79
+ schema = z.array(item).max(field.maxItems);
80
+ break;
81
+ }
82
+ }
83
+ if ("value" in field && field.value !== undefined)
84
+ schema = z.literal(field.value);
85
+ if (field.description) schema = schema.describe(field.description);
86
+ return schema;
87
+ }