@hyperscale0/udl 1.0.265 → 1.0.284

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 (62) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/README.md +1 -1
  3. package/SECURITY.md +15 -14
  4. package/dist/diagnostics.d.ts +7 -6
  5. package/dist/diagnostics.d.ts.map +1 -1
  6. package/dist/diagnostics.js.map +1 -1
  7. package/dist/field-value.d.ts.map +1 -1
  8. package/dist/field-value.js +5 -6
  9. package/dist/field-value.js.map +1 -1
  10. package/dist/finance.d.ts +2 -6
  11. package/dist/finance.d.ts.map +1 -1
  12. package/dist/finance.js +20 -14
  13. package/dist/finance.js.map +1 -1
  14. package/dist/limits.d.ts +0 -1
  15. package/dist/limits.d.ts.map +1 -1
  16. package/dist/limits.js +0 -1
  17. package/dist/limits.js.map +1 -1
  18. package/dist/object-contract.d.ts +2 -2
  19. package/dist/object-contract.d.ts.map +1 -1
  20. package/dist/object-contract.js +4 -4
  21. package/dist/object-contract.js.map +1 -1
  22. package/dist/object-semantics-schema.d.ts +0 -10
  23. package/dist/object-semantics-schema.d.ts.map +1 -1
  24. package/dist/object-semantics.d.ts.map +1 -1
  25. package/dist/object-semantics.js +9 -9
  26. package/dist/object-semantics.js.map +1 -1
  27. package/dist/object-structures.d.ts.map +1 -1
  28. package/dist/object-structures.js +2 -3
  29. package/dist/object-structures.js.map +1 -1
  30. package/dist/primitives.d.ts +12 -0
  31. package/dist/primitives.d.ts.map +1 -0
  32. package/dist/primitives.js +21 -0
  33. package/dist/primitives.js.map +1 -0
  34. package/dist/reporting-validation.d.ts.map +1 -1
  35. package/dist/reporting-validation.js +2 -1
  36. package/dist/reporting-validation.js.map +1 -1
  37. package/dist/reporting.d.ts +0 -5
  38. package/dist/reporting.d.ts.map +1 -1
  39. package/dist/reporting.js +0 -5
  40. package/dist/reporting.js.map +1 -1
  41. package/dist/schema.d.ts +1 -11
  42. package/dist/schema.d.ts.map +1 -1
  43. package/dist/schema.js +2 -1
  44. package/dist/schema.js.map +1 -1
  45. package/dist/validation.d.ts.map +1 -1
  46. package/dist/validation.js +20 -43
  47. package/dist/validation.js.map +1 -1
  48. package/package.json +2 -2
  49. package/spec/README.md +24 -23
  50. package/spec/udl.schema.json +1 -36
  51. package/src/diagnostics.ts +7 -6
  52. package/src/field-value.ts +5 -6
  53. package/src/finance.ts +20 -22
  54. package/src/limits.ts +0 -1
  55. package/src/object-contract.ts +4 -10
  56. package/src/object-semantics.ts +14 -13
  57. package/src/object-structures.ts +2 -4
  58. package/src/primitives.ts +29 -0
  59. package/src/reporting-validation.ts +2 -1
  60. package/src/reporting.ts +0 -5
  61. package/src/schema.ts +2 -1
  62. package/src/validation.ts +22 -65
package/src/validation.ts CHANGED
@@ -2,8 +2,8 @@ import {
2
2
  udlDocumentSchema,
3
3
  subjectPartyRoles,
4
4
  sameObjectField,
5
- MAX_ACTION_EXPANSION,
6
5
  type UdlDocument,
6
+ type UdlFamily,
7
7
  type UdlField,
8
8
  type UdlInstrument,
9
9
  type UdlValue,
@@ -20,6 +20,7 @@ import { validateReportDefinition } from "./reporting-validation.js";
20
20
  import { analyzeInstrumentFinance } from "./finance.js";
21
21
  import { UDL_LIMITS } from "./limits.js";
22
22
  import { udlFieldValueSchema } from "./field-value.js";
23
+ import { isMinorUnits, own, targetIds } from "./primitives.js";
23
24
 
24
25
  export const RESERVED_OBJECT_NAMES = [
25
26
  "objectId",
@@ -136,17 +137,13 @@ function bounded(value: unknown): boolean {
136
137
  }
137
138
  }
138
139
 
139
- function own<T>(
140
- record: Record<string, T> | undefined,
141
- key: string,
142
- ): T | undefined {
143
- return record && Object.hasOwn(record, key) ? record[key] : undefined;
144
- }
145
-
146
- const targetIds = (target: string | string[]): string[] =>
147
- typeof target === "string" ? [target] : target;
148
140
  const overlap = (a: string | string[], b: string | string[]) =>
149
141
  targetIds(a).some((id) => targetIds(b).includes(id));
142
+ const sameFamily = (actual: UdlFamily | undefined, expected: UdlFamily) =>
143
+ actual !== undefined &&
144
+ actual.module === expected.module &&
145
+ actual.exportPath === expected.exportPath &&
146
+ actual.revision === expected.revision;
150
147
 
151
148
  /** Union paths retain only fields with compatible types on every member. */
152
149
  function commonField(
@@ -615,10 +612,7 @@ export function validateUdl(value: unknown): UdlValidationResult {
615
612
  const targetInst = byId.get(id);
616
613
  if (
617
614
  targetInst &&
618
- (!targetInst.family ||
619
- targetInst.family.module !== f.targetFamily.module ||
620
- targetInst.family.exportPath !== f.targetFamily.exportPath ||
621
- targetInst.family.revision !== f.targetFamily.revision)
615
+ !sameFamily(targetInst.family, f.targetFamily)
622
616
  ) {
623
617
  add(
624
618
  where,
@@ -659,13 +653,7 @@ export function validateUdl(value: unknown): UdlValidationResult {
659
653
  );
660
654
  } else if (f.target) {
661
655
  const targetInst = byId.get(f.target);
662
- if (
663
- targetInst &&
664
- (!targetInst.family ||
665
- targetInst.family.module !== f.targetFamily.module ||
666
- targetInst.family.exportPath !== f.targetFamily.exportPath ||
667
- targetInst.family.revision !== f.targetFamily.revision)
668
- ) {
656
+ if (targetInst && !sameFamily(targetInst.family, f.targetFamily)) {
669
657
  add(
670
658
  where,
671
659
  `targetFamily does not match target instrument ${f.target} family`,
@@ -775,7 +763,7 @@ export function validateUdl(value: unknown): UdlValidationResult {
775
763
  }
776
764
  }
777
765
 
778
- const calls = new Map<string, { targets: string[]; count: number }[]>();
766
+ const calls = new Map<string, string[]>();
779
767
  for (const [index, inst] of document.instruments.entries()) {
780
768
  const base = `$.instruments[${index}]`;
781
769
  if (inst.subject && !byObjectId.has(inst.subject))
@@ -831,8 +819,7 @@ export function validateUdl(value: unknown): UdlValidationResult {
831
819
  }
832
820
  const valid =
833
821
  type === "money"
834
- ? typeof v.literal === "string" &&
835
- /^(0|[1-9][0-9]{0,17})$/.test(v.literal)
822
+ ? typeof v.literal === "string" && isMinorUnits(v.literal)
836
823
  : type === "integer" || type === "percent" || type === "duration"
837
824
  ? typeof v.literal === "number" &&
838
825
  Number.isSafeInteger(v.literal) &&
@@ -885,10 +872,7 @@ export function validateUdl(value: unknown): UdlValidationResult {
885
872
  where: string,
886
873
  input: readonly UdlField[] = [],
887
874
  ) => {
888
- const ids =
889
- typeof selection.instrument === "string"
890
- ? [selection.instrument]
891
- : selection.instrument;
875
+ const ids = targetIds(selection.instrument);
892
876
  duplicate(ids, where);
893
877
  const targets = ids.flatMap((id) => {
894
878
  const target = byId.get(id);
@@ -905,13 +889,7 @@ export function validateUdl(value: unknown): UdlValidationResult {
905
889
  overlap(a.target, b.target)));
906
890
  const anchor = field(selection.anchor, input);
907
891
  for (const target of targets) {
908
- if (
909
- selection.family &&
910
- (!target.family ||
911
- target.family.module !== selection.family.module ||
912
- target.family.exportPath !== selection.family.exportPath ||
913
- target.family.revision !== selection.family.revision)
914
- )
892
+ if (selection.family && !sameFamily(target.family, selection.family))
915
893
  add(
916
894
  where,
917
895
  `selection family does not match target instrument ${target.id} family`,
@@ -1077,7 +1055,7 @@ export function validateUdl(value: unknown): UdlValidationResult {
1077
1055
  "literal" in operand &&
1078
1056
  (typeof operand.literal === "number" ||
1079
1057
  (typeof operand.literal === "string" &&
1080
- /^(0|[1-9][0-9]{0,17})$/.test(operand.literal))) &&
1058
+ isMinorUnits(operand.literal))) &&
1081
1059
  (positive
1082
1060
  ? BigInt(operand.literal) <= 0n
1083
1061
  : BigInt(operand.literal) < 0n)
@@ -1651,7 +1629,7 @@ export function validateUdl(value: unknown): UdlValidationResult {
1651
1629
  }
1652
1630
  }
1653
1631
  };
1654
- const targets: { targets: string[]; count: number }[] = [];
1632
+ const targets: string[] = [];
1655
1633
  for (const call of action.invoke ?? []) {
1656
1634
  if (call.guard)
1657
1635
  checkRequirements([call.guard], where, action.input, action);
@@ -1725,11 +1703,7 @@ export function validateUdl(value: unknown): UdlValidationResult {
1725
1703
  }
1726
1704
  }
1727
1705
  }
1728
- targets.push({
1729
- targets: ids.map((id) => `${id}.${call.action}`),
1730
- count:
1731
- "selection" in call ? call.selection.limit : (range?.maximum ?? 1),
1732
- });
1706
+ targets.push(...ids.map((id) => `${id}.${call.action}`));
1733
1707
  }
1734
1708
  calls.set(`${inst.id}.${actionName}`, targets);
1735
1709
  }
@@ -1742,34 +1716,17 @@ export function validateUdl(value: unknown): UdlValidationResult {
1742
1716
  );
1743
1717
  }
1744
1718
  const active = new Set<string>();
1745
- const depths = new Map<string, number>();
1746
- const visit = (key: string): number => {
1719
+ const visited = new Set<string>();
1720
+ const visit = (key: string): void => {
1747
1721
  if (active.has(key)) {
1748
1722
  add("$.instruments", `invocation cycle at ${key}`, "UDL2010");
1749
- return MAX_ACTION_EXPANSION + 1;
1723
+ return;
1750
1724
  }
1751
- const known = depths.get(key);
1752
- if (known !== undefined) return known;
1725
+ if (visited.has(key)) return;
1753
1726
  active.add(key);
1754
- const size =
1755
- 1 +
1756
- (calls.get(key) ?? []).reduce(
1757
- (n, edge) => n + edge.count * Math.max(0, ...edge.targets.map(visit)),
1758
- 0,
1759
- );
1727
+ for (const target of calls.get(key) ?? []) visit(target);
1760
1728
  active.delete(key);
1761
- depths.set(key, size);
1762
- const [id, action] = key.split(".");
1763
- const limit =
1764
- document.instruments.find((item) => item.id === id)?.actions[action!]
1765
- ?.expansionLimit ?? MAX_ACTION_EXPANSION;
1766
- if (size > limit)
1767
- add(
1768
- "$.instruments",
1769
- `invocation ${key} exceeds ${limit} actions`,
1770
- "UDL2010",
1771
- );
1772
- return size;
1729
+ visited.add(key);
1773
1730
  };
1774
1731
  for (const key of calls.keys()) visit(key);
1775
1732
  return issues.length ? { ok: false, issues } : { ok: true, value: document };