@hyperscale0/udl 1.0.0-rc.1 → 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.
- package/CHANGELOG.md +5 -211
- package/LICENSE.md +356 -0
- package/NOTICE.md +8 -0
- package/README.md +14 -106
- package/dist/canonical.d.ts.map +1 -1
- package/dist/canonical.js +1 -29
- package/dist/canonical.js.map +1 -1
- package/dist/diagnostics.d.ts +13 -165
- package/dist/diagnostics.d.ts.map +1 -1
- package/dist/diagnostics.js +33 -157
- package/dist/diagnostics.js.map +1 -1
- package/dist/field-value.d.ts +5 -0
- package/dist/field-value.d.ts.map +1 -0
- package/dist/field-value.js +85 -0
- package/dist/field-value.js.map +1 -0
- package/dist/finance.d.ts +10 -53
- package/dist/finance.d.ts.map +1 -1
- package/dist/finance.js +252 -536
- package/dist/finance.js.map +1 -1
- package/dist/index.d.ts +9 -13
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -9
- package/dist/index.js.map +1 -1
- package/dist/json.d.ts +2 -0
- package/dist/json.d.ts.map +1 -0
- package/dist/json.js +30 -0
- package/dist/json.js.map +1 -0
- package/dist/limits.d.ts +3 -28
- package/dist/limits.d.ts.map +1 -1
- package/dist/limits.js +5 -31
- package/dist/limits.js.map +1 -1
- package/dist/object-contract.d.ts +140 -0
- package/dist/object-contract.d.ts.map +1 -0
- package/dist/object-contract.js +314 -0
- package/dist/object-contract.js.map +1 -0
- package/dist/object-semantics-schema.d.ts +5710 -0
- package/dist/object-semantics-schema.d.ts.map +1 -0
- package/dist/object-semantics-schema.js +119 -0
- package/dist/object-semantics-schema.js.map +1 -0
- package/dist/object-semantics.d.ts +6 -0
- package/dist/object-semantics.d.ts.map +1 -0
- package/dist/object-semantics.js +279 -0
- package/dist/object-semantics.js.map +1 -0
- package/dist/object-structures.d.ts +4 -0
- package/dist/object-structures.d.ts.map +1 -0
- package/dist/object-structures.js +134 -0
- package/dist/object-structures.js.map +1 -0
- package/dist/reporting-validation.d.ts +8 -0
- package/dist/reporting-validation.d.ts.map +1 -0
- package/dist/reporting-validation.js +252 -0
- package/dist/reporting-validation.js.map +1 -0
- package/dist/reporting.d.ts +477 -0
- package/dist/reporting.d.ts.map +1 -0
- package/dist/reporting.js +169 -0
- package/dist/reporting.js.map +1 -0
- package/dist/schema.d.ts +5572 -2710
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +444 -1121
- package/dist/schema.js.map +1 -1
- package/dist/validation.d.ts +10 -73
- package/dist/validation.d.ts.map +1 -1
- package/dist/validation.js +1109 -2569
- package/dist/validation.js.map +1 -1
- package/docs/assets/brand/manifest.json +30 -0
- package/docs/assets/brand/udl-horizontal-white.svg +1 -0
- package/docs/assets/brand/udl-horizontal.svg +1 -0
- package/docs/assets/brand/udl-stacked-white.svg +1 -0
- package/docs/assets/brand/udl-stacked.svg +1 -0
- package/docs/assets/udl.svg +11 -0
- package/package.json +13 -22
- package/spec/README.md +300 -172
- package/spec/cars.udl.json +249 -0
- package/spec/udl.schema.json +3066 -2242
- package/src/canonical.ts +1 -35
- package/src/diagnostics.ts +76 -209
- package/src/field-value.ts +87 -0
- package/src/finance.ts +327 -832
- package/src/index.ts +18 -95
- package/src/json.ts +34 -0
- package/src/limits.ts +5 -31
- package/src/object-contract.ts +559 -0
- package/src/object-semantics-schema.ts +148 -0
- package/src/object-semantics.ts +378 -0
- package/src/object-structures.ts +255 -0
- package/src/reporting-validation.ts +383 -0
- package/src/reporting.ts +178 -0
- package/src/schema.ts +510 -1277
- package/src/validation.ts +1630 -4545
- package/LICENSE +0 -661
- package/LICENSING.md +0 -51
- package/TRADEMARKS.md +0 -35
- package/conformance/README.md +0 -82
- package/conformance/evolution/action-contract.expected.json +0 -10
- package/conformance/evolution/action-contract.live.udl +0 -44
- package/conformance/evolution/action-contract.next.udl +0 -45
- package/conformance/evolution/product-identity.expected.json +0 -10
- package/conformance/evolution/product-identity.live.udl +0 -55
- package/conformance/evolution/product-identity.next.udl +0 -55
- package/conformance/evolution/version-required.expected.json +0 -10
- package/conformance/evolution/version-required.live.udl +0 -55
- package/conformance/evolution/version-required.next.udl +0 -58
- package/conformance/invalid/action-without-transition.expected.json +0 -10
- package/conformance/invalid/action-without-transition.udl +0 -60
- package/conformance/invalid/agent-description-too-long.expected.json +0 -10
- package/conformance/invalid/agent-description-too-long.udl +0 -57
- package/conformance/invalid/blank-title.expected.json +0 -10
- package/conformance/invalid/blank-title.udl +0 -54
- package/conformance/invalid/composition-dial-duplicate-key.expected.json +0 -10
- package/conformance/invalid/composition-dial-duplicate-key.udl +0 -73
- package/conformance/invalid/depth-budget.expected.json +0 -10
- package/conformance/invalid/depth-budget.udl +0 -49
- package/conformance/invalid/duplicate-subject.expected.json +0 -10
- package/conformance/invalid/duplicate-subject.udl +0 -230
- package/conformance/invalid/forged-effects.expected.json +0 -10
- package/conformance/invalid/forged-effects.udl +0 -76
- package/conformance/invalid/format-version.expected.json +0 -10
- package/conformance/invalid/format-version.udl +0 -54
- package/conformance/invalid/instrument-id-not-snake-case.expected.json +0 -10
- package/conformance/invalid/instrument-id-not-snake-case.udl +0 -54
- package/conformance/invalid/invalid-aggregate-gate-shape.expected.json +0 -10
- package/conformance/invalid/invalid-aggregate-gate-shape.udl +0 -1819
- package/conformance/invalid/invalid-check-duration.expected.json +0 -10
- package/conformance/invalid/invalid-check-duration.udl +0 -219
- package/conformance/invalid/invalid-dial-anchor.expected.json +0 -10
- package/conformance/invalid/invalid-dial-anchor.udl +0 -219
- package/conformance/invalid/invalid-exception-parent-ref.expected.json +0 -10
- package/conformance/invalid/invalid-exception-parent-ref.udl +0 -2487
- package/conformance/invalid/invalid-exposure-shape.expected.json +0 -10
- package/conformance/invalid/invalid-exposure-shape.udl +0 -1819
- package/conformance/invalid/invalid-remainder.expected.json +0 -10
- package/conformance/invalid/invalid-remainder.udl +0 -220
- package/conformance/invalid/invalid-schema-keyword.expected.json +0 -10
- package/conformance/invalid/invalid-schema-keyword.udl +0 -220
- package/conformance/invalid/invalid-utf8.expected.json +0 -10
- package/conformance/invalid/invalid-utf8.udl +0 -1
- package/conformance/invalid/malformed-json.expected.json +0 -10
- package/conformance/invalid/malformed-json.udl +0 -1
- package/conformance/invalid/missing-create-action.expected.json +0 -10
- package/conformance/invalid/missing-create-action.udl +0 -48
- package/conformance/invalid/missing-exception-amount-field.expected.json +0 -10
- package/conformance/invalid/missing-exception-amount-field.udl +0 -2487
- package/conformance/invalid/missing-exception-contract.expected.json +0 -14
- package/conformance/invalid/missing-exception-contract.udl +0 -2523
- package/conformance/invalid/missing-exception-reason-field.expected.json +0 -10
- package/conformance/invalid/missing-exception-reason-field.udl +0 -2487
- package/conformance/invalid/not-an-object.expected.json +0 -10
- package/conformance/invalid/not-an-object.udl +0 -1
- package/conformance/invalid/payout-reconcile-not-a-bank-debit.expected.json +0 -10
- package/conformance/invalid/payout-reconcile-not-a-bank-debit.udl +0 -259
- package/conformance/invalid/quote-freeze-set-incomplete.expected.json +0 -10
- package/conformance/invalid/quote-freeze-set-incomplete.udl +0 -261
- package/conformance/invalid/quote-named-reference-gate.expected.json +0 -10
- package/conformance/invalid/quote-named-reference-gate.udl +0 -50
- package/conformance/invalid/reconcile-named-reference-gate.expected.json +0 -10
- package/conformance/invalid/reconcile-named-reference-gate.udl +0 -50
- package/conformance/invalid/unknown-key.expected.json +0 -10
- package/conformance/invalid/unknown-key.udl +0 -55
- package/conformance/invalid/unknown-reference-gate-field.expected.json +0 -10
- package/conformance/invalid/unknown-reference-gate-field.udl +0 -1819
- package/conformance/invalid/unknown-required-field.expected.json +0 -10
- package/conformance/invalid/unknown-required-field.udl +0 -220
- package/conformance/invalid/unreachable-state.expected.json +0 -10
- package/conformance/invalid/unreachable-state.udl +0 -55
- package/conformance/invalid/wrong-exception-amount-field.expected.json +0 -10
- package/conformance/invalid/wrong-exception-amount-field.udl +0 -2487
- package/conformance/invalid/wrong-exception-reason-field.expected.json +0 -10
- package/conformance/invalid/wrong-exception-reason-field.udl +0 -2487
- package/conformance/valid/agent-description.expected.json +0 -6
- package/conformance/valid/agent-description.udl +0 -66
- package/conformance/valid/cards.expected.json +0 -6
- package/conformance/valid/cards.udl +0 -1579
- package/conformance/valid/commerce-escrow.expected.json +0 -6
- package/conformance/valid/commerce-escrow.udl +0 -1512
- package/conformance/valid/compiled-crowdfunding.expected.json +0 -6
- package/conformance/valid/compiled-crowdfunding.udl +0 -1843
- package/conformance/valid/compiled-watch-club.expected.json +0 -6
- package/conformance/valid/compiled-watch-club.udl +0 -2486
- package/conformance/valid/complete-contract.expected.json +0 -6
- package/conformance/valid/complete-contract.udl +0 -218
- package/conformance/valid/effect-signatures.expected.json +0 -6
- package/conformance/valid/effect-signatures.udl +0 -75
- package/conformance/valid/hand-edited.expected.json +0 -6
- package/conformance/valid/hand-edited.udl +0 -1
- package/conformance/valid/insured-car-marketplace.expected.json +0 -6
- package/conformance/valid/insured-car-marketplace.udl +0 -1050
- package/conformance/valid/insured-travel.expected.json +0 -6
- package/conformance/valid/insured-travel.udl +0 -3469
- package/conformance/valid/minimal.expected.json +0 -6
- package/conformance/valid/minimal.udl +0 -54
- package/conformance/valid/protection.expected.json +0 -6
- package/conformance/valid/protection.udl +0 -1551
- package/conformance/valid/string-escaping.expected.json +0 -6
- package/conformance/valid/string-escaping.udl +0 -54
- package/dist/check-profiles.d.ts +0 -57
- package/dist/check-profiles.d.ts.map +0 -1
- package/dist/check-profiles.js +0 -62
- package/dist/check-profiles.js.map +0 -1
- package/dist/cli.d.ts +0 -3
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js +0 -184
- package/dist/cli.js.map +0 -1
- package/dist/effects.d.ts +0 -41
- package/dist/effects.d.ts.map +0 -1
- package/dist/effects.js +0 -110
- package/dist/effects.js.map +0 -1
- package/dist/evolution.d.ts +0 -120
- package/dist/evolution.d.ts.map +0 -1
- package/dist/evolution.js +0 -567
- package/dist/evolution.js.map +0 -1
- package/dist/parser.d.ts +0 -4
- package/dist/parser.d.ts.map +0 -1
- package/dist/parser.js +0 -44
- package/dist/parser.js.map +0 -1
- package/docs/README.md +0 -14
- package/docs/guide/01-a-document.md +0 -37
- package/docs/guide/02-money-steps.md +0 -23
- package/docs/guide/03-laws.md +0 -18
- package/docs/guide/04-fees-and-remainder.md +0 -15
- package/docs/guide/05-checks-updates-dials.md +0 -7
- package/docs/guide/06-effects.md +0 -11
- package/docs/guide/07-evolution.md +0 -11
- package/docs/guide/08-implementing.md +0 -13
- package/docs/llms-full.txt +0 -1241
- package/docs/llms.txt +0 -14
- package/docs/reference/canonical.md +0 -16
- package/docs/reference/clauses.md +0 -986
- package/docs/reference/cli.md +0 -22
- package/docs/reference/diagnostics.md +0 -32
- package/skills/udl/SKILL.md +0 -28
- package/src/check-profiles.ts +0 -80
- package/src/cli.ts +0 -196
- package/src/effects.ts +0 -163
- package/src/evolution.ts +0 -965
- package/src/parser.ts +0 -58
package/docs/reference/cli.md
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
<!-- Generated by scripts/docs/build.ts from @hyperscale0/udl 1.0.0-rc.1. Edit the source, not cli.md. -->
|
|
2
|
-
|
|
3
|
-
# Command reference
|
|
4
|
-
|
|
5
|
-
The installed `udl` binary exposes the following commands and exit codes.
|
|
6
|
-
|
|
7
|
-
```text
|
|
8
|
-
udl - the Universal Domain Language toolchain
|
|
9
|
-
|
|
10
|
-
usage:
|
|
11
|
-
udl validate <file> parse <file> and report every issue found
|
|
12
|
-
udl fmt <file> [--write] print the canonical form, or rewrite the file
|
|
13
|
-
udl canon <file> [--digest] print canonical bytes, or their SHA-256 digest
|
|
14
|
-
udl diff <live> <next> check <next> against the append-only law
|
|
15
|
-
udl explain UDL#### explain one stable diagnostic code
|
|
16
|
-
udl help print this
|
|
17
|
-
|
|
18
|
-
exit codes:
|
|
19
|
-
0 the document is admissible, or the change is additive
|
|
20
|
-
1 the document was refused, or the change breaks the append-only law
|
|
21
|
-
2 the command line was wrong, or a file could not be read
|
|
22
|
-
```
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
<!-- Generated by scripts/docs/build.ts from @hyperscale0/udl 1.0.0-rc.1. Edit the source, not diagnostics.md. -->
|
|
2
|
-
|
|
3
|
-
# Diagnostic reference
|
|
4
|
-
|
|
5
|
-
Codes are stable. Titles and messages may become clearer without changing the code. Apply the listed fix, then validate the whole document again.
|
|
6
|
-
|
|
7
|
-
| Code | Family | Category | Title | Fix |
|
|
8
|
-
| --------- | --------- | ----------------- | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
|
|
9
|
-
| `UDL1001` | admission | invalid_utf8 | Invalid UTF-8 | Encode the document as valid UTF-8. |
|
|
10
|
-
| `UDL1002` | admission | invalid_json | Invalid JSON | Repair the JSON syntax before validation. |
|
|
11
|
-
| `UDL1003` | admission | invalid_shape | Invalid document shape | Match the published UDL JSON Schema. |
|
|
12
|
-
| `UDL1004` | admission | resource_limit | Resource limit exceeded | Reduce the source size, nesting, values, strings, references, or financial paths named by the message. |
|
|
13
|
-
| `UDL2001` | document | invalid_semantics | Duplicate declaration | Give each declaration a unique name. |
|
|
14
|
-
| `UDL2002` | document | invalid_semantics | Document law violation | Repair the declaration, subject contract, or derived effects named by the message. |
|
|
15
|
-
| `UDL2005` | document | invalid_semantics | Derived effects mismatch | Regenerate the action effects from its clauses. |
|
|
16
|
-
| `UDL3001` | lifecycle | invalid_semantics | Lifecycle is not closed | Declare every state and action transition, and make every state reachable. |
|
|
17
|
-
| `UDL4001` | finance | invalid_semantics | Money graph violation | Balance every funded amount and close every hold on each lifecycle path. |
|
|
18
|
-
| `UDL5001` | gates | invalid_semantics | Reference gate violation | Point the gate at a declared instrument, action, state, field, and reference. |
|
|
19
|
-
| `UDL5002` | gates | invalid_semantics | Check requirement violation | Use a declared check with compatible evidence and recurrence. |
|
|
20
|
-
| `UDL5003` | gates | invalid_semantics | Exposure gate violation | Use declared account and money fields for the exposure gate. |
|
|
21
|
-
| `UDL5004` | gates | invalid_semantics | Aggregate law violation | Point the aggregate at compatible parent and child fields. |
|
|
22
|
-
| `UDL5005` | gates | invalid_semantics | Settlement or payout violation | Use a declared settlement account and a compatible payout statement line. |
|
|
23
|
-
| `UDL5006` | gates | invalid_semantics | Quote and commit violation | Declare one complete quote freeze set and one matching commit action. |
|
|
24
|
-
| `UDL5007` | gates | invalid_semantics | Reconcile exception child violation | Name a declared child whose reference points back to this instrument. |
|
|
25
|
-
| `UDL5008` | gates | invalid_semantics | Action clause violation | Repair the clause fields and keep incompatible clauses separate. |
|
|
26
|
-
| `UDL5009` | gates | invalid_semantics | Reconcile exception amount field is missing or optional | Name the exception child's required money field in amountField. |
|
|
27
|
-
| `UDL5010` | gates | invalid_semantics | Reconcile exception amount field has the wrong type | Point amountField at a money field declared by the exception child. |
|
|
28
|
-
| `UDL5011` | gates | invalid_semantics | Reconcile exception reason field is missing or optional | Name the exception child's required text field in reasonField. |
|
|
29
|
-
| `UDL5012` | gates | invalid_semantics | Reconcile exception reason field has the wrong type | Point reasonField at a required plain text field declared by the exception child. |
|
|
30
|
-
| `UDL6001` | schema | invalid_semantics | Unsupported JSON Schema | Use only the sealed UDL JSON Schema subset. |
|
|
31
|
-
| `UDL7001` | evolution | invalid_evolution | Stored contract changed | Keep stored identities and contracts unchanged, and add only allowed optional declarations. |
|
|
32
|
-
| `UDL7002` | evolution | invalid_evolution | Version was not increased | Increase the product version for every semantic change. |
|
package/skills/udl/SKILL.md
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: udl
|
|
3
|
-
description: Read, validate, explain, or write Universal Domain Language documents directly. Use for canonical UDL JSON and format-level diagnostics. SDK and MCP consumers should use their generated contracts instead.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# UDL
|
|
7
|
-
|
|
8
|
-
Use UDL when the task concerns the canonical product document, format conformance, or a validator implementation. Use HSX when authoring a product from reusable modules.
|
|
9
|
-
|
|
10
|
-
## Read first
|
|
11
|
-
|
|
12
|
-
1. Read `docs/guide/01-a-document.md` for the document frame.
|
|
13
|
-
2. Read `docs/guide/03-laws.md` before changing lifecycle, money, gates, or references.
|
|
14
|
-
3. Look up exact fields in `spec/udl.schema.json` and clauses in `docs/reference/clauses.md`.
|
|
15
|
-
|
|
16
|
-
## Edit loop
|
|
17
|
-
|
|
18
|
-
1. Change the smallest complete clause.
|
|
19
|
-
2. Run `udl validate <file>`.
|
|
20
|
-
3. Look up each `UDL####` code with `udl explain UDL####` or `docs/reference/diagnostics.md`.
|
|
21
|
-
4. Apply the listed fix. Validate the whole document again.
|
|
22
|
-
5. Run `udl canon <file> --digest` before pinning bytes or an identity.
|
|
23
|
-
|
|
24
|
-
Never hand-author `effects`. Derive them from action clauses. Never represent money as a JSON number. Use an integer minor-unit string and its declared currency. Never add a money move without checking every terminal lifecycle path for a matching drain or unwind.
|
|
25
|
-
|
|
26
|
-
For a stored definition, validate both documents before `udl diff <live> <next>`. Treat any `UDL7xxx` result as a refused change. A data migration does not make an incompatible document edit additive.
|
|
27
|
-
|
|
28
|
-
Validator work must run the complete `conformance/` contract and follow `docs/reference/canonical.md` byte for byte.
|
package/src/check-profiles.ts
DELETED
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Evidence profiles that an instrument action may require before it runs.
|
|
3
|
-
* The public grammar and the runtime both read this table. A pair absent here
|
|
4
|
-
* cannot gate an action.
|
|
5
|
-
*/
|
|
6
|
-
export interface UdlCheckEvidenceProfile {
|
|
7
|
-
readonly family: string;
|
|
8
|
-
readonly checkKind: string;
|
|
9
|
-
readonly kindField?: string;
|
|
10
|
-
readonly statusField: string;
|
|
11
|
-
readonly statuses: readonly string[];
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export const udlCheckEvidenceProfiles = [
|
|
15
|
-
{
|
|
16
|
-
family: "national_identity",
|
|
17
|
-
checkKind: "identity_verification",
|
|
18
|
-
kindField: "checkKind",
|
|
19
|
-
statusField: "verificationStatus",
|
|
20
|
-
statuses: [
|
|
21
|
-
"requested",
|
|
22
|
-
"waiting",
|
|
23
|
-
"completed",
|
|
24
|
-
"rejected",
|
|
25
|
-
"expired",
|
|
26
|
-
"error",
|
|
27
|
-
],
|
|
28
|
-
},
|
|
29
|
-
{
|
|
30
|
-
family: "national_identity",
|
|
31
|
-
checkKind: "contact_ownership_verification",
|
|
32
|
-
kindField: "checkKind",
|
|
33
|
-
statusField: "matchResult",
|
|
34
|
-
statuses: ["match", "no_match"],
|
|
35
|
-
},
|
|
36
|
-
{
|
|
37
|
-
family: "credit_bureau",
|
|
38
|
-
checkKind: "consumer_inquiry",
|
|
39
|
-
kindField: "inquiryType",
|
|
40
|
-
statusField: "bureauStatus",
|
|
41
|
-
statuses: ["returned", "acknowledged", "correction_required"],
|
|
42
|
-
},
|
|
43
|
-
{
|
|
44
|
-
family: "credit_bureau",
|
|
45
|
-
checkKind: "commercial_inquiry",
|
|
46
|
-
kindField: "inquiryType",
|
|
47
|
-
statusField: "bureauStatus",
|
|
48
|
-
statuses: ["returned", "acknowledged", "correction_required"],
|
|
49
|
-
},
|
|
50
|
-
{
|
|
51
|
-
family: "credit_bureau",
|
|
52
|
-
checkKind: "facility_report",
|
|
53
|
-
kindField: "inquiryType",
|
|
54
|
-
statusField: "bureauStatus",
|
|
55
|
-
statuses: ["returned", "acknowledged", "correction_required"],
|
|
56
|
-
},
|
|
57
|
-
{
|
|
58
|
-
family: "sanctions_screening",
|
|
59
|
-
checkKind: "screen",
|
|
60
|
-
kindField: "checkKind",
|
|
61
|
-
statusField: "screeningStatus",
|
|
62
|
-
statuses: ["clear", "hit", "manual_review"],
|
|
63
|
-
},
|
|
64
|
-
{
|
|
65
|
-
family: "enforcement_instrument",
|
|
66
|
-
checkKind: "note_request",
|
|
67
|
-
statusField: "requestStatus",
|
|
68
|
-
statuses: ["debtor_approved", "debtor_rejected", "auto_cancelled"],
|
|
69
|
-
},
|
|
70
|
-
] as const satisfies readonly UdlCheckEvidenceProfile[];
|
|
71
|
-
|
|
72
|
-
/** Returns the tenant-gateable evidence profile for one family and check. */
|
|
73
|
-
export function udlCheckEvidenceProfile(
|
|
74
|
-
family: string,
|
|
75
|
-
checkKind: string,
|
|
76
|
-
): UdlCheckEvidenceProfile | undefined {
|
|
77
|
-
return udlCheckEvidenceProfiles.find(
|
|
78
|
-
(profile) => profile.family === family && profile.checkKind === checkKind,
|
|
79
|
-
);
|
|
80
|
-
}
|
package/src/cli.ts
DELETED
|
@@ -1,196 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* The `udl` command. Actions over the same library the compiler uses:
|
|
4
|
-
* `validate` answers whether a document is admissible, `fmt` writes the
|
|
5
|
-
* canonical bytes, and `diff` answers whether a change is legal against a
|
|
6
|
-
* document that already has live instances.
|
|
7
|
-
*/
|
|
8
|
-
import { readFile, writeFile } from "node:fs/promises";
|
|
9
|
-
|
|
10
|
-
import {
|
|
11
|
-
canonicalizeUdl,
|
|
12
|
-
canonicalDigest,
|
|
13
|
-
diffValidatedUdlEvolution,
|
|
14
|
-
parseUdl,
|
|
15
|
-
UdlError,
|
|
16
|
-
type UdlDocument,
|
|
17
|
-
udlDiagnostic,
|
|
18
|
-
} from "./index.js";
|
|
19
|
-
|
|
20
|
-
const USAGE = `udl - the Universal Domain Language toolchain
|
|
21
|
-
|
|
22
|
-
usage:
|
|
23
|
-
udl validate <file> parse <file> and report every issue found
|
|
24
|
-
udl fmt <file> [--write] print the canonical form, or rewrite the file
|
|
25
|
-
udl canon <file> [--digest] print canonical bytes, or their SHA-256 digest
|
|
26
|
-
udl diff <live> <next> check <next> against the append-only law
|
|
27
|
-
udl explain UDL#### explain one stable diagnostic code
|
|
28
|
-
udl help print this
|
|
29
|
-
|
|
30
|
-
exit codes:
|
|
31
|
-
0 the document is admissible, or the change is additive
|
|
32
|
-
1 the document was refused, or the change breaks the append-only law
|
|
33
|
-
2 the command line was wrong, or a file could not be read`;
|
|
34
|
-
|
|
35
|
-
async function main(argv: readonly string[]): Promise<number> {
|
|
36
|
-
const [command, ...rest] = argv;
|
|
37
|
-
switch (command) {
|
|
38
|
-
case "help":
|
|
39
|
-
case "-h":
|
|
40
|
-
case "--help":
|
|
41
|
-
console.log(USAGE);
|
|
42
|
-
return 0;
|
|
43
|
-
case "validate":
|
|
44
|
-
return validateCommand(rest);
|
|
45
|
-
case "fmt":
|
|
46
|
-
return formatCommand(rest);
|
|
47
|
-
case "canon":
|
|
48
|
-
return canonCommand(rest);
|
|
49
|
-
case "diff":
|
|
50
|
-
return diffCommand(rest);
|
|
51
|
-
case "explain":
|
|
52
|
-
return explainCommand(rest);
|
|
53
|
-
case undefined:
|
|
54
|
-
return usageError("udl: no command given");
|
|
55
|
-
default:
|
|
56
|
-
return usageError(`udl: unknown command ${command}`);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
async function canonCommand(args: readonly string[]): Promise<number> {
|
|
61
|
-
const digest = args.includes("--digest");
|
|
62
|
-
const [file, ...extra] = args.filter((argument) => argument !== "--digest");
|
|
63
|
-
if (file === undefined || extra.length > 0) {
|
|
64
|
-
return usageError("usage: udl canon <file> [--digest]");
|
|
65
|
-
}
|
|
66
|
-
const bytes = await readDocument(file);
|
|
67
|
-
if (bytes === null) return 2;
|
|
68
|
-
let document: UdlDocument;
|
|
69
|
-
try {
|
|
70
|
-
document = parseUdl(bytes);
|
|
71
|
-
} catch (error) {
|
|
72
|
-
return reportIssues(file, error);
|
|
73
|
-
}
|
|
74
|
-
if (digest) console.log(await canonicalDigest(document));
|
|
75
|
-
else process.stdout.write(canonicalizeUdl(bytes));
|
|
76
|
-
return 0;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
function explainCommand(args: readonly string[]): number {
|
|
80
|
-
const [code, ...extra] = args;
|
|
81
|
-
if (code === undefined || extra.length > 0) {
|
|
82
|
-
return usageError("usage: udl explain UDL####");
|
|
83
|
-
}
|
|
84
|
-
const diagnostic = udlDiagnostic(code);
|
|
85
|
-
if (!diagnostic) {
|
|
86
|
-
return usageError(`udl: unknown diagnostic code ${code}`);
|
|
87
|
-
}
|
|
88
|
-
console.log(`${code} ${diagnostic.title}`);
|
|
89
|
-
console.log(`category: ${diagnostic.category}`);
|
|
90
|
-
console.log(`family: ${diagnostic.family}`);
|
|
91
|
-
console.log(`fix: ${diagnostic.fix}`);
|
|
92
|
-
return 0;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
async function validateCommand(args: readonly string[]): Promise<number> {
|
|
96
|
-
const [file, ...extra] = args;
|
|
97
|
-
if (file === undefined || extra.length > 0) {
|
|
98
|
-
return usageError("usage: udl validate <file>");
|
|
99
|
-
}
|
|
100
|
-
const bytes = await readDocument(file);
|
|
101
|
-
if (bytes === null) return 2;
|
|
102
|
-
if (parseDocument(file, bytes) === null) return 1;
|
|
103
|
-
console.log(`${file}: ok`);
|
|
104
|
-
return 0;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
async function formatCommand(args: readonly string[]): Promise<number> {
|
|
108
|
-
const write = args.includes("--write");
|
|
109
|
-
const [file, ...extra] = args.filter((argument) => argument !== "--write");
|
|
110
|
-
if (file === undefined || extra.length > 0) {
|
|
111
|
-
return usageError("usage: udl fmt <file> [--write]");
|
|
112
|
-
}
|
|
113
|
-
const bytes = await readDocument(file);
|
|
114
|
-
if (bytes === null) return 2;
|
|
115
|
-
|
|
116
|
-
let canonical: string;
|
|
117
|
-
try {
|
|
118
|
-
canonical = canonicalizeUdl(bytes);
|
|
119
|
-
} catch (error) {
|
|
120
|
-
return reportIssues(file, error);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
if (!write) {
|
|
124
|
-
process.stdout.write(canonical);
|
|
125
|
-
return 0;
|
|
126
|
-
}
|
|
127
|
-
// The bytes decoded cleanly already: canonicalizeUdl refuses anything else.
|
|
128
|
-
if (new TextDecoder().decode(bytes) === canonical) return 0;
|
|
129
|
-
await writeFile(file, canonical);
|
|
130
|
-
console.log(`${file}: formatted`);
|
|
131
|
-
return 0;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
async function diffCommand(args: readonly string[]): Promise<number> {
|
|
135
|
-
const [livePath, nextPath, ...extra] = args;
|
|
136
|
-
if (livePath === undefined || nextPath === undefined || extra.length > 0) {
|
|
137
|
-
return usageError("usage: udl diff <live> <next>");
|
|
138
|
-
}
|
|
139
|
-
const liveBytes = await readDocument(livePath);
|
|
140
|
-
const nextBytes = await readDocument(nextPath);
|
|
141
|
-
if (liveBytes === null || nextBytes === null) return 2;
|
|
142
|
-
|
|
143
|
-
const live = parseDocument(livePath, liveBytes);
|
|
144
|
-
const next = parseDocument(nextPath, nextBytes);
|
|
145
|
-
if (live === null || next === null) return 1;
|
|
146
|
-
|
|
147
|
-
// `parseDocument` already validated both, so take the door that does not
|
|
148
|
-
// validate a second time.
|
|
149
|
-
const violations = diffValidatedUdlEvolution(live, next);
|
|
150
|
-
if (violations.length === 0) {
|
|
151
|
-
console.log(`${nextPath}: additive`);
|
|
152
|
-
return 0;
|
|
153
|
-
}
|
|
154
|
-
for (const violation of violations) {
|
|
155
|
-
console.error(
|
|
156
|
-
`${nextPath}: ${violation.code} ${violation.path}: ${violation.message}`,
|
|
157
|
-
);
|
|
158
|
-
}
|
|
159
|
-
return 1;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
async function readDocument(file: string): Promise<Uint8Array | null> {
|
|
163
|
-
try {
|
|
164
|
-
return await readFile(file);
|
|
165
|
-
} catch (error) {
|
|
166
|
-
const reason = error instanceof Error ? error.message : String(error);
|
|
167
|
-
console.error(`udl: cannot read ${file}: ${reason}`);
|
|
168
|
-
return null;
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
/** Parses one document, printing its issues. Null means the document was refused. */
|
|
173
|
-
function parseDocument(file: string, bytes: Uint8Array): UdlDocument | null {
|
|
174
|
-
try {
|
|
175
|
-
return parseUdl(bytes);
|
|
176
|
-
} catch (error) {
|
|
177
|
-
reportIssues(file, error);
|
|
178
|
-
return null;
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
function reportIssues(file: string, error: unknown): number {
|
|
183
|
-
if (!(error instanceof UdlError)) throw error;
|
|
184
|
-
for (const issue of error.issues) {
|
|
185
|
-
console.error(`${file}: ${issue.code} ${issue.path}: ${issue.message}`);
|
|
186
|
-
}
|
|
187
|
-
return 1;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
function usageError(message: string): number {
|
|
191
|
-
console.error(message);
|
|
192
|
-
console.error(USAGE);
|
|
193
|
-
return 2;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
process.exitCode = await main(process.argv.slice(2));
|
package/src/effects.ts
DELETED
|
@@ -1,163 +0,0 @@
|
|
|
1
|
-
export const udlEffectKinds = [
|
|
2
|
-
"decides",
|
|
3
|
-
"holds",
|
|
4
|
-
"moves",
|
|
5
|
-
"notifies",
|
|
6
|
-
"reads",
|
|
7
|
-
"schedules",
|
|
8
|
-
] as const;
|
|
9
|
-
|
|
10
|
-
export type UdlEffectKind = (typeof udlEffectKinds)[number];
|
|
11
|
-
|
|
12
|
-
type EffectDescriptor = {
|
|
13
|
-
readonly kind: UdlEffectKind;
|
|
14
|
-
readonly per: "clause" | "element";
|
|
15
|
-
readonly signature:
|
|
16
|
-
| { readonly fixed: string }
|
|
17
|
-
| { readonly fromField: string }
|
|
18
|
-
| { readonly movementClass: true };
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
type ActionClauseDescriptor = {
|
|
22
|
-
readonly effects?: readonly EffectDescriptor[];
|
|
23
|
-
readonly scope: "action" | "instrument";
|
|
24
|
-
readonly target: string;
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
type EffectRow = {
|
|
28
|
-
readonly channel?: string;
|
|
29
|
-
readonly role?: string;
|
|
30
|
-
readonly signature: string;
|
|
31
|
-
readonly source: string;
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
export type DerivedUdlEffects = Partial<
|
|
35
|
-
Readonly<Record<UdlEffectKind, readonly EffectRow[]>>
|
|
36
|
-
>;
|
|
37
|
-
|
|
38
|
-
export type UdlMovementClass =
|
|
39
|
-
| "collection.pay_in"
|
|
40
|
-
| "deposit.attributed"
|
|
41
|
-
| "payout.external"
|
|
42
|
-
| "transfer.internal";
|
|
43
|
-
|
|
44
|
-
interface Movement {
|
|
45
|
-
readonly bind?: Readonly<Record<string, unknown>>;
|
|
46
|
-
readonly operation: string;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function boundPath(move: Movement, endpoint: string): string | undefined {
|
|
50
|
-
const binding = move.bind?.[endpoint];
|
|
51
|
-
if (binding === null || typeof binding !== "object") return undefined;
|
|
52
|
-
const path = (binding as { readonly path?: unknown }).path;
|
|
53
|
-
return typeof path === "string" ? path : undefined;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Maps a UDL money operation to the meter and pricing class that owns it.
|
|
58
|
-
* Internal-transfer endpoint bindings are product accounts by construction.
|
|
59
|
-
* External collection, deposit, and payout operations carry their role in the
|
|
60
|
-
* operation family because their remote endpoint is not a UDL account binding.
|
|
61
|
-
*/
|
|
62
|
-
export function movementClass(move: Movement): UdlMovementClass {
|
|
63
|
-
if (move.operation.startsWith("internal_transfer.")) {
|
|
64
|
-
const source = boundPath(move, "sourceAccountId");
|
|
65
|
-
const destination = boundPath(move, "destinationAccountId");
|
|
66
|
-
if (
|
|
67
|
-
source?.startsWith("fields.") &&
|
|
68
|
-
destination === "refs.escrowAccountId"
|
|
69
|
-
) {
|
|
70
|
-
return "collection.pay_in";
|
|
71
|
-
}
|
|
72
|
-
return "transfer.internal";
|
|
73
|
-
}
|
|
74
|
-
if (move.operation.startsWith("collection.pay_in.")) {
|
|
75
|
-
return "collection.pay_in";
|
|
76
|
-
}
|
|
77
|
-
if (move.operation.startsWith("deposit.")) {
|
|
78
|
-
return "deposit.attributed";
|
|
79
|
-
}
|
|
80
|
-
if (move.operation.startsWith("payout.")) {
|
|
81
|
-
return "payout.external";
|
|
82
|
-
}
|
|
83
|
-
throw new Error(`cannot classify UDL movement operation ${move.operation}`);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/** Derive the ABI effect rows declared by the action-clause vocabulary. */
|
|
87
|
-
export function deriveUdlActionEffects(
|
|
88
|
-
action: Readonly<Record<string, unknown>>,
|
|
89
|
-
vocabulary: readonly ActionClauseDescriptor[],
|
|
90
|
-
): DerivedUdlEffects {
|
|
91
|
-
const effects: Partial<Record<UdlEffectKind, EffectRow[]>> = {};
|
|
92
|
-
for (const clause of vocabulary) {
|
|
93
|
-
if (clause.scope !== "action" || !clause.effects) continue;
|
|
94
|
-
const value = actionClauseValue(action, clause.target);
|
|
95
|
-
if (value === undefined) continue;
|
|
96
|
-
for (const descriptor of clause.effects) {
|
|
97
|
-
const values =
|
|
98
|
-
descriptor.per === "element" && Array.isArray(value) ? value : [value];
|
|
99
|
-
for (const [index, candidate] of values.entries()) {
|
|
100
|
-
const object = recordValue(candidate);
|
|
101
|
-
if (
|
|
102
|
-
descriptor.kind === "holds" &&
|
|
103
|
-
"fixed" in descriptor.signature &&
|
|
104
|
-
descriptor.signature.fixed === "reserve" &&
|
|
105
|
-
object?.operation !== "internal_transfer.reserve"
|
|
106
|
-
) {
|
|
107
|
-
continue;
|
|
108
|
-
}
|
|
109
|
-
const suffix = effectSignatureSuffix(descriptor, object);
|
|
110
|
-
if (!suffix) continue;
|
|
111
|
-
(effects[descriptor.kind] ??= []).push({
|
|
112
|
-
signature: `${descriptor.kind}.${suffix}`,
|
|
113
|
-
source:
|
|
114
|
-
descriptor.per === "element"
|
|
115
|
-
? `${clause.target}[${index}]`
|
|
116
|
-
: clause.target,
|
|
117
|
-
...(descriptor.kind === "notifies" &&
|
|
118
|
-
typeof object?.channel === "string" &&
|
|
119
|
-
typeof object.role === "string"
|
|
120
|
-
? { channel: object.channel, role: object.role }
|
|
121
|
-
: {}),
|
|
122
|
-
});
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
return effects;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
function actionClauseValue(
|
|
130
|
-
action: Readonly<Record<string, unknown>>,
|
|
131
|
-
target: string,
|
|
132
|
-
): unknown {
|
|
133
|
-
const [head, tail] = target.split(".");
|
|
134
|
-
if (!head) return undefined;
|
|
135
|
-
const value = action[head];
|
|
136
|
-
if (!tail) return value;
|
|
137
|
-
return recordValue(value)?.[tail];
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
function effectSignatureSuffix(
|
|
141
|
-
descriptor: EffectDescriptor,
|
|
142
|
-
value: Readonly<Record<string, unknown>> | undefined,
|
|
143
|
-
): string | undefined {
|
|
144
|
-
if ("fixed" in descriptor.signature) return descriptor.signature.fixed;
|
|
145
|
-
if ("fromField" in descriptor.signature) {
|
|
146
|
-
const field = value?.[descriptor.signature.fromField];
|
|
147
|
-
return typeof field === "string" ? field : undefined;
|
|
148
|
-
}
|
|
149
|
-
if (!value || !("movementClass" in descriptor.signature)) return undefined;
|
|
150
|
-
const operation = value.operation;
|
|
151
|
-
const bind = recordValue(value.bind);
|
|
152
|
-
return typeof operation === "string"
|
|
153
|
-
? movementClass({ ...(bind ? { bind } : {}), operation })
|
|
154
|
-
: undefined;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
function recordValue(
|
|
158
|
-
value: unknown,
|
|
159
|
-
): Readonly<Record<string, unknown>> | undefined {
|
|
160
|
-
return value !== null && typeof value === "object" && !Array.isArray(value)
|
|
161
|
-
? (value as Readonly<Record<string, unknown>>)
|
|
162
|
-
: undefined;
|
|
163
|
-
}
|