@primmel/primmel 1.21.12 → 1.21.14

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 (117) hide show
  1. package/dist/src/check-allowlist.d.ts +12 -0
  2. package/dist/src/check-allowlist.d.ts.map +1 -1
  3. package/dist/src/check-allowlist.js +35 -4
  4. package/dist/src/check-allowlist.js.map +1 -1
  5. package/dist/src/check-rules.d.ts.map +1 -1
  6. package/dist/src/check-rules.js +30 -0
  7. package/dist/src/check-rules.js.map +1 -1
  8. package/dist/src/check.d.ts +38 -0
  9. package/dist/src/check.d.ts.map +1 -1
  10. package/dist/src/check.js +1155 -4
  11. package/dist/src/check.js.map +1 -1
  12. package/dist/src/export/retrieval.d.ts +9 -1
  13. package/dist/src/export/retrieval.d.ts.map +1 -1
  14. package/dist/src/export/retrieval.js +29 -0
  15. package/dist/src/export/retrieval.js.map +1 -1
  16. package/dist/src/expressions/index.d.ts +83 -0
  17. package/dist/src/expressions/index.d.ts.map +1 -0
  18. package/dist/src/expressions/index.js +382 -0
  19. package/dist/src/expressions/index.js.map +1 -0
  20. package/dist/src/fmt.d.ts +11 -0
  21. package/dist/src/fmt.d.ts.map +1 -0
  22. package/dist/src/fmt.js +71 -0
  23. package/dist/src/fmt.js.map +1 -0
  24. package/dist/src/ser-des/config/calculation.d.ts.map +1 -1
  25. package/dist/src/ser-des/config/calculation.js +46 -0
  26. package/dist/src/ser-des/config/calculation.js.map +1 -1
  27. package/dist/src/ser-des/config/competenceKind.d.ts.map +1 -1
  28. package/dist/src/ser-des/config/competenceKind.js +9 -20
  29. package/dist/src/ser-des/config/competenceKind.js.map +1 -1
  30. package/dist/src/ser-des/config/conformanceTest.d.ts.map +1 -1
  31. package/dist/src/ser-des/config/conformanceTest.js +33 -6
  32. package/dist/src/ser-des/config/conformanceTest.js.map +1 -1
  33. package/dist/src/ser-des/config/constraint.d.ts.map +1 -1
  34. package/dist/src/ser-des/config/constraint.js +24 -2
  35. package/dist/src/ser-des/config/constraint.js.map +1 -1
  36. package/dist/src/ser-des/config/index.d.ts +7 -0
  37. package/dist/src/ser-des/config/index.d.ts.map +1 -1
  38. package/dist/src/ser-des/config/index.js +50 -0
  39. package/dist/src/ser-des/config/index.js.map +1 -1
  40. package/dist/src/ser-des/config/lmlAligned.d.ts +16 -0
  41. package/dist/src/ser-des/config/lmlAligned.d.ts.map +1 -0
  42. package/dist/src/ser-des/config/lmlAligned.js +337 -0
  43. package/dist/src/ser-des/config/lmlAligned.js.map +1 -0
  44. package/dist/src/ser-des/config/packageManifest.d.ts.map +1 -1
  45. package/dist/src/ser-des/config/packageManifest.js +3 -0
  46. package/dist/src/ser-des/config/packageManifest.js.map +1 -1
  47. package/dist/src/ser-des/config/process.d.ts.map +1 -1
  48. package/dist/src/ser-des/config/process.js +192 -0
  49. package/dist/src/ser-des/config/process.js.map +1 -1
  50. package/dist/src/ser-des/config/requirement.d.ts.map +1 -1
  51. package/dist/src/ser-des/config/requirement.js +123 -7
  52. package/dist/src/ser-des/config/requirement.js.map +1 -1
  53. package/dist/src/ser-des/config/symbol.d.ts.map +1 -1
  54. package/dist/src/ser-des/config/symbol.js +21 -0
  55. package/dist/src/ser-des/config/symbol.js.map +1 -1
  56. package/dist/src/ser-des/config/table.d.ts.map +1 -1
  57. package/dist/src/ser-des/config/table.js +7 -0
  58. package/dist/src/ser-des/config/table.js.map +1 -1
  59. package/dist/src/ser-des/config/uncertaintyBudget.d.ts +5 -0
  60. package/dist/src/ser-des/config/uncertaintyBudget.d.ts.map +1 -0
  61. package/dist/src/ser-des/config/uncertaintyBudget.js +211 -0
  62. package/dist/src/ser-des/config/uncertaintyBudget.js.map +1 -0
  63. package/dist/src/ser-des/config/verdict.d.ts.map +1 -1
  64. package/dist/src/ser-des/config/verdict.js +12 -2
  65. package/dist/src/ser-des/config/verdict.js.map +1 -1
  66. package/dist/src/ser-des/dump.d.ts.map +1 -1
  67. package/dist/src/ser-des/dump.js +46 -0
  68. package/dist/src/ser-des/dump.js.map +1 -1
  69. package/dist/src/ser-des/expression-carrier.d.ts +17 -0
  70. package/dist/src/ser-des/expression-carrier.d.ts.map +1 -0
  71. package/dist/src/ser-des/expression-carrier.js +72 -0
  72. package/dist/src/ser-des/expression-carrier.js.map +1 -0
  73. package/dist/src/ser-des/package.d.ts.map +1 -1
  74. package/dist/src/ser-des/package.js +54 -4
  75. package/dist/src/ser-des/package.js.map +1 -1
  76. package/dist/src/ser-des/parse.d.ts.map +1 -1
  77. package/dist/src/ser-des/parse.js +36 -2
  78. package/dist/src/ser-des/parse.js.map +1 -1
  79. package/dist/src/ser-des/shape-front-end.d.ts.map +1 -1
  80. package/dist/src/ser-des/shape-front-end.js +24 -5
  81. package/dist/src/ser-des/shape-front-end.js.map +1 -1
  82. package/dist/src/ser-des/types.d.ts +10 -0
  83. package/dist/src/ser-des/types.d.ts.map +1 -1
  84. package/dist/src/text-coverage.d.ts.map +1 -1
  85. package/dist/src/text-coverage.js +52 -0
  86. package/dist/src/text-coverage.js.map +1 -1
  87. package/dist/src/types/Calculation.d.ts +14 -0
  88. package/dist/src/types/Calculation.d.ts.map +1 -1
  89. package/dist/src/types/CompetenceKind.d.ts +6 -14
  90. package/dist/src/types/CompetenceKind.d.ts.map +1 -1
  91. package/dist/src/types/ConformanceTest.d.ts +5 -1
  92. package/dist/src/types/ConformanceTest.d.ts.map +1 -1
  93. package/dist/src/types/Constraint.d.ts +10 -1
  94. package/dist/src/types/Constraint.d.ts.map +1 -1
  95. package/dist/src/types/LmlAligned.d.ts +76 -0
  96. package/dist/src/types/LmlAligned.d.ts.map +1 -0
  97. package/dist/src/types/LmlAligned.js +8 -0
  98. package/dist/src/types/LmlAligned.js.map +1 -0
  99. package/dist/src/types/Package.d.ts +7 -0
  100. package/dist/src/types/Package.d.ts.map +1 -1
  101. package/dist/src/types/Requirement.d.ts +33 -0
  102. package/dist/src/types/Requirement.d.ts.map +1 -1
  103. package/dist/src/types/Standard.d.ts +12 -0
  104. package/dist/src/types/Standard.d.ts.map +1 -1
  105. package/dist/src/types/Symbol.d.ts +8 -0
  106. package/dist/src/types/Symbol.d.ts.map +1 -1
  107. package/dist/src/types/UncertaintyBudget.d.ts +68 -0
  108. package/dist/src/types/UncertaintyBudget.d.ts.map +1 -0
  109. package/dist/src/types/UncertaintyBudget.js +3 -0
  110. package/dist/src/types/UncertaintyBudget.js.map +1 -0
  111. package/dist/src/types/Verdict.d.ts +3 -1
  112. package/dist/src/types/Verdict.d.ts.map +1 -1
  113. package/dist/src/types/process.d.ts +52 -1
  114. package/dist/src/types/process.d.ts.map +1 -1
  115. package/dist-browser/index.mjs +2791 -1925
  116. package/dist-cli/primmel.mjs +2931 -76
  117. package/package.json +1 -1
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // scripts/check.mts
4
- import { existsSync as existsSync8, readdirSync as readdirSync7, statSync as statSync4, writeFileSync } from "node:fs";
5
- import { join as join9 } from "node:path";
4
+ import { existsSync as existsSync8, readdirSync as readdirSync8, statSync as statSync5, writeFileSync as writeFileSync2 } from "node:fs";
5
+ import { join as join10 } from "node:path";
6
6
 
7
7
  // src/check.ts
8
8
  import { existsSync as existsSync5, readdirSync as readdirSync3, readFileSync as readFileSync5, statSync as statSync2 } from "fs";
@@ -200,16 +200,44 @@ function parse(mmelString, parsers, options = {}) {
200
200
  continue;
201
201
  }
202
202
  if (cfg.takesID) {
203
- if (i + 1 > tokens.length) {
203
+ let formatTok;
204
+ if (cfg.takesFormat) {
205
+ const f = tokens[i++];
206
+ if (!["xml", "yaml", "json", "toml", "csv"].includes(f.value)) {
207
+ throw new Error(
208
+ `Parsing error: mapping. Unknown format "${f.value}" at line ${f.start.line} col ${f.start.col} (xml, yaml, json, toml, csv)`
209
+ );
210
+ }
211
+ formatTok = f;
212
+ }
213
+ if (i + 1 >= tokens.length) {
204
214
  throw new Error(
205
215
  `Keyword "${tok.value}" at line ${tok.start.line} col ${tok.start.col} expects an ID and payload, but only ${tokens.length - i + 1} token(s) remain.`
206
216
  );
207
217
  }
208
218
  const idTok = tokens[i++];
219
+ if (cfg.optionalTypedId && tokens[i]?.value === ":") {
220
+ const typeTok = tokens[i + 1];
221
+ const blockTok = tokens[i + 2];
222
+ if (!typeTok || !blockTok) {
223
+ throw new Error(
224
+ `Keyword "${tok.value}" at line ${tok.start.line} col ${tok.start.col} expects a type and payload, but too few token(s) remain.`
225
+ );
226
+ }
227
+ i += 3;
228
+ declarations.push({
229
+ keyword: tok.value,
230
+ id: idTok.value,
231
+ payload: `: ${typeTok.value} ${blockTok.value}`,
232
+ start: tok.start,
233
+ end: blockTok.end
234
+ });
235
+ continue;
236
+ }
209
237
  const payloadTok = tokens[i++];
210
238
  declarations.push({
211
239
  keyword: tok.value,
212
- id: idTok.value,
240
+ id: formatTok ? `${formatTok.value}:${idTok.value}` : idTok.value,
213
241
  payload: payloadTok.value,
214
242
  start: tok.start,
215
243
  end: payloadTok.end
@@ -269,6 +297,11 @@ function parseDeclarations(declarations, parsers, options = {}) {
269
297
  calculations: {},
270
298
  verdicts: {},
271
299
  referenceMaterials: {},
300
+ wireMappings: {},
301
+ stringFormats: {},
302
+ namespaces: {},
303
+ datums: {},
304
+ checks: {},
272
305
  testPointSets: {},
273
306
  commonTestConditions: {},
274
307
  competenceKinds: {},
@@ -277,6 +310,7 @@ function parseDeclarations(declarations, parsers, options = {}) {
277
310
  schemeTypes: {},
278
311
  predicates: {},
279
312
  constraints: {},
313
+ uncertaintyBudgets: {},
280
314
  discrepancyRecords: {},
281
315
  stateMachines: {},
282
316
  conformanceTests: {},
@@ -2495,6 +2529,403 @@ var parseMetadata = function(token) {
2495
2529
  return ctx;
2496
2530
  };
2497
2531
  };
2532
+ var dumpMetadata = function(meta) {
2533
+ let out = "metadata {\n";
2534
+ out += ' title "' + escapeString(meta.title) + '"\n';
2535
+ out += ' schema "' + escapeString(meta.schema) + '"\n';
2536
+ out += ' edition "' + escapeString(meta.edition) + '"\n';
2537
+ out += ' author "' + escapeString(meta.author) + '"\n';
2538
+ out += ' namespace "' + escapeString(meta.namespace) + '"\n';
2539
+ out += ' shortname "' + escapeString(meta.shortname ?? "") + '"\n';
2540
+ out += "}\n";
2541
+ return out;
2542
+ };
2543
+
2544
+ // src/expressions/index.ts
2545
+ var OPERATORS = [
2546
+ "->",
2547
+ "<=",
2548
+ ">=",
2549
+ "!=",
2550
+ "\u2260",
2551
+ "<",
2552
+ ">",
2553
+ "=",
2554
+ "+",
2555
+ "-",
2556
+ "*",
2557
+ "/",
2558
+ "(",
2559
+ ")",
2560
+ ",",
2561
+ ".",
2562
+ "|"
2563
+ ];
2564
+ var NAV_OPS = /* @__PURE__ */ new Set(["forAll", "exists", "select", "collect"]);
2565
+ function lex(src) {
2566
+ const tokens = [];
2567
+ let i = 0;
2568
+ while (i < src.length) {
2569
+ const c = src[i];
2570
+ if (/\s/.test(c)) {
2571
+ i += 1;
2572
+ continue;
2573
+ }
2574
+ if (c === "'") {
2575
+ let j = i + 1;
2576
+ while (j < src.length && src[j] !== "'") {
2577
+ j += 1;
2578
+ }
2579
+ if (j >= src.length) {
2580
+ throw new Error(`expression: unterminated string at offset ${i}`);
2581
+ }
2582
+ tokens.push({ kind: "str", value: src.slice(i + 1, j) });
2583
+ i = j + 1;
2584
+ continue;
2585
+ }
2586
+ if (/[0-9]/.test(c)) {
2587
+ let j = i;
2588
+ while (j < src.length && /[0-9.]/.test(src[j])) {
2589
+ j += 1;
2590
+ }
2591
+ tokens.push({ kind: "num", value: Number(src.slice(i, j)) });
2592
+ i = j;
2593
+ continue;
2594
+ }
2595
+ if (/[A-Za-z_]/.test(c)) {
2596
+ let j = i;
2597
+ while (j < src.length && /[A-Za-z0-9_.]/.test(src[j])) {
2598
+ j += 1;
2599
+ }
2600
+ tokens.push({ kind: "name", value: src.slice(i, j) });
2601
+ i = j;
2602
+ continue;
2603
+ }
2604
+ const two = src.slice(i, i + 2);
2605
+ if (OPERATORS.includes(two)) {
2606
+ tokens.push({ kind: "op", value: two });
2607
+ i += 2;
2608
+ continue;
2609
+ }
2610
+ if (OPERATORS.includes(c)) {
2611
+ tokens.push({ kind: "op", value: c });
2612
+ i += 1;
2613
+ continue;
2614
+ }
2615
+ throw new Error(`expression: unexpected character "${c}" at offset ${i}`);
2616
+ }
2617
+ return tokens;
2618
+ }
2619
+ var BINARY_LEVELS = [
2620
+ ["implies"],
2621
+ ["or"],
2622
+ ["xor"],
2623
+ ["and"],
2624
+ ["<=", ">=", "<", ">", "=", "!=", "\u2260"],
2625
+ ["+", "-"],
2626
+ ["*", "/"]
2627
+ ];
2628
+ var WORD_BINOPS = /* @__PURE__ */ new Set(["implies", "or", "xor", "and"]);
2629
+ var ExprParser = class {
2630
+ tokens;
2631
+ pos = 0;
2632
+ constructor(tokens) {
2633
+ this.tokens = tokens;
2634
+ }
2635
+ peek() {
2636
+ return this.tokens[this.pos];
2637
+ }
2638
+ take() {
2639
+ const tok = this.tokens[this.pos];
2640
+ if (tok === void 0) {
2641
+ throw new Error("expression: unexpected end");
2642
+ }
2643
+ this.pos += 1;
2644
+ return tok;
2645
+ }
2646
+ parse() {
2647
+ const ast = this.parseLevel(0);
2648
+ if (this.pos !== this.tokens.length) {
2649
+ throw new Error(`expression: trailing tokens at position ${this.pos}`);
2650
+ }
2651
+ return ast;
2652
+ }
2653
+ parseLevel(level) {
2654
+ if (level >= BINARY_LEVELS.length) {
2655
+ return this.parseUnary();
2656
+ }
2657
+ let left = this.parseLevel(level + 1);
2658
+ for (; ; ) {
2659
+ const tok = this.peek();
2660
+ const op = tok?.kind === "op" ? tok.value : tok?.kind === "name" && WORD_BINOPS.has(tok.value) ? tok.value : void 0;
2661
+ if (op === void 0 || !BINARY_LEVELS[level].includes(op)) {
2662
+ return left;
2663
+ }
2664
+ this.take();
2665
+ const right = this.parseLevel(level + 1);
2666
+ left = { type: "binop", op, left, right };
2667
+ }
2668
+ }
2669
+ parseUnary() {
2670
+ const tok = this.peek();
2671
+ if (tok?.kind === "name" && (tok.value === "not" || tok.value === "-")) {
2672
+ this.take();
2673
+ return { type: "unop", op: tok.value, operand: this.parseUnary() };
2674
+ }
2675
+ if (tok?.kind === "op" && tok.value === "-") {
2676
+ this.take();
2677
+ return { type: "unop", op: "-", operand: this.parseUnary() };
2678
+ }
2679
+ return this.parsePrimary();
2680
+ }
2681
+ parsePrimary() {
2682
+ const tok = this.take();
2683
+ if (tok.kind === "num") {
2684
+ return { type: "num", value: tok.value };
2685
+ }
2686
+ if (tok.kind === "str") {
2687
+ return { type: "str", value: tok.value };
2688
+ }
2689
+ if (tok.kind === "op" && tok.value === "(") {
2690
+ const inner = this.parseLevel(0);
2691
+ const close = this.take();
2692
+ if (close.kind !== "op" || close.value !== ")") {
2693
+ throw new Error("expression: expected closing parenthesis");
2694
+ }
2695
+ return inner;
2696
+ }
2697
+ if (tok.kind === "name") {
2698
+ if (tok.value === "true" || tok.value === "false") {
2699
+ return { type: "bool", value: tok.value === "true" };
2700
+ }
2701
+ if (tok.value === "if") {
2702
+ const cond = this.parseLevel(0);
2703
+ const thenTok = this.take();
2704
+ if (thenTok.kind !== "name" || thenTok.value !== "then") {
2705
+ throw new Error('expression: expected "then" in the conditional');
2706
+ }
2707
+ const whenTrue = this.parseLevel(0);
2708
+ const elseTok = this.take();
2709
+ if (elseTok.kind !== "name" || elseTok.value !== "else") {
2710
+ throw new Error('expression: expected "else" in the conditional');
2711
+ }
2712
+ const whenFalse = this.parseLevel(0);
2713
+ const endTok = this.take();
2714
+ if (endTok.kind !== "name" || endTok.value !== "endif") {
2715
+ throw new Error(
2716
+ 'expression: expected "endif" to close the conditional'
2717
+ );
2718
+ }
2719
+ return { type: "ifelse", cond, then: whenTrue, else: whenFalse };
2720
+ }
2721
+ const segs = [tok.value];
2722
+ while (this.peek()?.kind === "op" && this.peek().value === ".") {
2723
+ this.take();
2724
+ const seg = this.take();
2725
+ if (seg.kind !== "name") {
2726
+ throw new Error('expression: expected a path segment after "."');
2727
+ }
2728
+ segs.push(seg.value);
2729
+ }
2730
+ const next = this.peek();
2731
+ if (next?.kind === "op" && next.value === "(" && !WORD_BINOPS.has(segs[0])) {
2732
+ this.take();
2733
+ const args2 = [];
2734
+ const closing = this.peek();
2735
+ if (closing?.kind === "op" && closing.value === ")") {
2736
+ this.take();
2737
+ return { type: "call", callee: segs.join("."), args: args2 };
2738
+ }
2739
+ for (; ; ) {
2740
+ args2.push(this.parseLevel(0));
2741
+ const sep = this.peek();
2742
+ if (sep?.kind === "op" && sep.value === ",") {
2743
+ this.take();
2744
+ continue;
2745
+ }
2746
+ break;
2747
+ }
2748
+ const close = this.take();
2749
+ if (close.kind !== "op" || close.value !== ")") {
2750
+ throw new Error("expression: expected closing parenthesis");
2751
+ }
2752
+ return { type: "call", callee: segs.join("."), args: args2 };
2753
+ }
2754
+ const arrow = this.peek();
2755
+ if (arrow?.kind === "op" && arrow.value === "->") {
2756
+ this.take();
2757
+ const opTok = this.take();
2758
+ if (opTok.kind !== "name" || !NAV_OPS.has(opTok.value)) {
2759
+ throw new Error(
2760
+ "expression: expected a collection iterator (forAll | exists | select | collect)"
2761
+ );
2762
+ }
2763
+ if (this.peek()?.kind !== "op" || this.peek().value !== "(") {
2764
+ throw new Error("expression: expected ( after the iterator");
2765
+ }
2766
+ this.take();
2767
+ const varTok = this.take();
2768
+ if (varTok.kind !== "name") {
2769
+ throw new Error("expression: expected the lambda parameter");
2770
+ }
2771
+ if (this.peek()?.kind !== "op" || this.peek().value !== "|") {
2772
+ throw new Error("expression: expected | after the parameter");
2773
+ }
2774
+ this.take();
2775
+ const body = this.parseLevel(0);
2776
+ const close = this.take();
2777
+ if (close.kind !== "op" || close.value !== ")") {
2778
+ throw new Error("expression: expected closing parenthesis");
2779
+ }
2780
+ return {
2781
+ type: "nav",
2782
+ source: segs.join("."),
2783
+ op: opTok.value,
2784
+ var: varTok.value,
2785
+ body
2786
+ };
2787
+ }
2788
+ return { type: "name", path: segs };
2789
+ }
2790
+ throw new Error(`expression: unexpected token "${String(tok.value)}"`);
2791
+ }
2792
+ };
2793
+ function parseExpression(src) {
2794
+ return new ExprParser(lex(src)).parse();
2795
+ }
2796
+ function canonicalizeExpression(raw) {
2797
+ const body = raw.trim();
2798
+ if (body.length === 0) {
2799
+ throw new Error("expression: the block is empty");
2800
+ }
2801
+ return renderExpression(parseExpression(body));
2802
+ }
2803
+ function freeIdentifiers(ast) {
2804
+ const out = { names: [], calls: [] };
2805
+ const walk = (node, bound) => {
2806
+ switch (node.type) {
2807
+ case "num":
2808
+ return;
2809
+ case "str":
2810
+ return;
2811
+ case "bool":
2812
+ return;
2813
+ case "ifelse":
2814
+ walk(node.cond, bound);
2815
+ walk(node.then, bound);
2816
+ walk(node.else, bound);
2817
+ return;
2818
+ case "name": {
2819
+ if (bound.has(node.path[0].split(".")[0])) {
2820
+ return;
2821
+ }
2822
+ out.names.push(node.path.join("."));
2823
+ return;
2824
+ }
2825
+ case "call":
2826
+ out.calls.push(node.callee);
2827
+ for (const a of node.args) {
2828
+ walk(a, bound);
2829
+ }
2830
+ return;
2831
+ case "unop":
2832
+ walk(node.operand, bound);
2833
+ return;
2834
+ case "binop":
2835
+ walk(node.left, bound);
2836
+ walk(node.right, bound);
2837
+ return;
2838
+ case "nav": {
2839
+ const inner = new Set(bound);
2840
+ inner.add(node["var"]);
2841
+ walk({ type: "name", path: [node.source] }, bound);
2842
+ walk(node.body, inner);
2843
+ return;
2844
+ }
2845
+ }
2846
+ };
2847
+ walk(ast, /* @__PURE__ */ new Set());
2848
+ return out;
2849
+ }
2850
+ function renderExpression(ast) {
2851
+ switch (ast.type) {
2852
+ case "num":
2853
+ return String(ast.value);
2854
+ case "str":
2855
+ return "'" + ast.value + "'";
2856
+ case "bool":
2857
+ return ast.value ? "true" : "false";
2858
+ case "ifelse":
2859
+ return "if " + renderExpression(ast.cond) + " then " + renderExpression(ast.then) + " else " + renderExpression(ast.else) + " endif";
2860
+ case "name":
2861
+ return ast.path.join(".");
2862
+ case "call":
2863
+ return ast.callee + "(" + ast.args.map(renderExpression).join(", ") + ")";
2864
+ case "unop": {
2865
+ const inner = renderExpression(ast.operand);
2866
+ return ast.op + (ast.operand.type === "binop" ? " (" + inner + ")" : " " + inner);
2867
+ }
2868
+ case "nav":
2869
+ return ast.source + " -> " + ast.op + "(" + ast["var"] + " | " + renderExpression(ast.body) + ")";
2870
+ case "binop":
2871
+ return renderExpression(ast.left) + " " + ast.op + " " + renderExpression(ast.right);
2872
+ }
2873
+ }
2874
+
2875
+ // src/ser-des/expression-carrier.ts
2876
+ function readExpressionCarrier(token, what) {
2877
+ if (token.startsWith("{")) {
2878
+ try {
2879
+ return {
2880
+ source: canonicalizeExpression(unwrapBlock(token)),
2881
+ inline: true
2882
+ };
2883
+ } catch (e) {
2884
+ throw new Error(
2885
+ `Parsing error: ${what}: ${e.message ?? String(e)}`
2886
+ );
2887
+ }
2888
+ }
2889
+ if (token.length >= 2 && token.charAt(0) === '"') {
2890
+ return {
2891
+ source: unescapeString(token.substr(1, token.length - 2)),
2892
+ inline: false
2893
+ };
2894
+ }
2895
+ return { source: token, inline: false };
2896
+ }
2897
+ function dumpExpressionBlock(keyword, source, indent) {
2898
+ const body = source.split("\n").map((l) => indent + " " + l).join("\n");
2899
+ return indent + keyword + " {\n" + body + "\n" + indent + "}\n";
2900
+ }
2901
+ function readArgsBlock(token) {
2902
+ const at = tokenize(token);
2903
+ const args2 = [];
2904
+ let k = 0;
2905
+ while (k < at.length) {
2906
+ const name = unescapeStringOrBare(at[k++]);
2907
+ if (k >= at.length) {
2908
+ throw new Error(`limit args: "${name}" binds to nothing`);
2909
+ }
2910
+ if (at[k] !== "<-") {
2911
+ throw new Error(
2912
+ `limit args: expected "<-" after "${name}" (name <- source)`
2913
+ );
2914
+ }
2915
+ k += 1;
2916
+ if (k >= at.length) {
2917
+ throw new Error(`limit args: "${name}" binds to nothing`);
2918
+ }
2919
+ args2.push({ name, source: unescapeStringOrBare(at[k++]) });
2920
+ }
2921
+ return args2;
2922
+ }
2923
+ function unescapeStringOrBare(t) {
2924
+ if (t.length >= 2 && t.charAt(0) === '"' && t.charAt(t.length - 1) === '"') {
2925
+ return unescapeString(t.substr(1, t.length - 2));
2926
+ }
2927
+ return t;
2928
+ }
2498
2929
 
2499
2930
  // src/ser-des/config/quantity.ts
2500
2931
  var NUMERIC = /^-?\d+(\.\d+)?([eE][+-]?\d+)?$/;
@@ -2987,10 +3418,20 @@ var STEP_KINDS = /* @__PURE__ */ new Set([
2987
3418
  "timer_event",
2988
3419
  "signal_event"
2989
3420
  ]);
3421
+ function parseCallBindings(block) {
3422
+ return parseParamList(unwrapBlock(block)).map((pr) => ({
3423
+ param: pr.name,
3424
+ bind: pr.type
3425
+ }));
3426
+ }
2990
3427
  function parseStepBody(id, kind, block) {
2991
3428
  const step = {
2992
3429
  id,
2993
3430
  kind,
3431
+ signatureBlock: "",
3432
+ sigInputs: [],
3433
+ sigOutputs: [],
3434
+ completion: "",
2994
3435
  executor: "",
2995
3436
  role: "",
2996
3437
  capture: "",
@@ -3260,6 +3701,112 @@ var parseProcess = function(id, data) {
3260
3701
  result._relations.page = value();
3261
3702
  } else if (keyword === "validate_provision") {
3262
3703
  result._relations.provision = tokenizePackage(value());
3704
+ } else if (keyword === "step" || keyword === "binding") {
3705
+ const sid = stripWrapping(value());
3706
+ const blockTok = value();
3707
+ if (keyword === "step") {
3708
+ const raw = blockTok !== void 0 && blockTok.startsWith("{") ? unwrapBlock(blockTok) : blockTok ?? "";
3709
+ const st = {
3710
+ id: sid,
3711
+ kind: "action",
3712
+ executor: "",
3713
+ role: "",
3714
+ capture: "",
3715
+ reads: [],
3716
+ writes: [],
3717
+ fires: "",
3718
+ calls: "",
3719
+ callIn: [],
3720
+ callOut: [],
3721
+ wait: "",
3722
+ period: "",
3723
+ signal: "",
3724
+ signatureBlock: raw,
3725
+ sigInputs: [],
3726
+ sigOutputs: [],
3727
+ completion: "",
3728
+ description: ""
3729
+ };
3730
+ const tt = tokenizePackage(raw);
3731
+ let ti = 0;
3732
+ while (ti < tt.length) {
3733
+ const tc = tt[ti++];
3734
+ if (ti >= tt.length) {
3735
+ break;
3736
+ }
3737
+ if (tc === "inputs" || tc === "outputs") {
3738
+ const pairs = parseParamList(unwrapBlock(tt[ti++]));
3739
+ const names = pairs.map((pr) => pr.name);
3740
+ if (tc === "inputs") {
3741
+ st.sigInputs = names;
3742
+ } else {
3743
+ st.sigOutputs = names;
3744
+ }
3745
+ } else if (tc === "requires") {
3746
+ const ids = tokenizePackage(unwrapBlock(tt[ti++])).map(stripWrapping).filter((x) => x.length > 0);
3747
+ (result.stepRequires ??= []).push(...ids);
3748
+ } else if (tc === "completion") {
3749
+ if (tt[ti] === "check") {
3750
+ ti += 1;
3751
+ st.completionGate = stripWrapping(tt[ti++]);
3752
+ const bt = tokenizePackage(unwrapBlock(tt[ti++]));
3753
+ let bi = 0;
3754
+ while (bi < bt.length) {
3755
+ const bc = bt[bi++];
3756
+ if (bi >= bt.length) {
3757
+ break;
3758
+ }
3759
+ if (bc === "expression") {
3760
+ const c = readExpressionCarrier(
3761
+ bt[bi++],
3762
+ "step completion"
3763
+ );
3764
+ st.completion = c.source;
3765
+ st.completionBound = c.inline || void 0;
3766
+ } else {
3767
+ bi = skipUnknownEntry(bt, bi);
3768
+ }
3769
+ }
3770
+ } else {
3771
+ const c = readExpressionCarrier(tt[ti++], "step completion");
3772
+ st.completion = c.source;
3773
+ st.completionBound = c.inline || void 0;
3774
+ }
3775
+ } else if (tc === "calls") {
3776
+ st.calls = stripWrapping(tt[ti++]);
3777
+ if (ti < tt.length && tt[ti] === "with") {
3778
+ const wt = tokenize(unwrapBlock(tt[ti++]));
3779
+ let wk = 0;
3780
+ while (wk < wt.length) {
3781
+ const wc = wt[wk++];
3782
+ if (wk >= wt.length) {
3783
+ break;
3784
+ }
3785
+ if (wc === "in") {
3786
+ st.callIn.push(...parseCallBindings(wt[wk++]));
3787
+ } else if (wc === "out") {
3788
+ st.callOut.push(...parseCallBindings(wt[wk++]));
3789
+ } else {
3790
+ unwrapBlock(wt[wk++]);
3791
+ }
3792
+ }
3793
+ }
3794
+ } else if (tc === "description") {
3795
+ st.description = stripWrapping(tt[ti++]);
3796
+ } else {
3797
+ ti = skipUnknownEntry(tt, ti);
3798
+ }
3799
+ }
3800
+ (result.steps ??= []).push(st);
3801
+ } else {
3802
+ (result.bindings ??= []).push({
3803
+ id: sid,
3804
+ block: blockTok !== void 0 && blockTok.startsWith("{") ? unwrapBlock(blockTok) : blockTok ?? ""
3805
+ });
3806
+ }
3807
+ } else if (keyword === "requires") {
3808
+ const inner = tokenizePackage(unwrapBlock(value()));
3809
+ (result.stepRequires ??= []).push(...inner.map(stripWrapping));
3263
3810
  } else if (keyword === "validate_measurement") {
3264
3811
  result.measure = tokenizePackage(value()).map((x) => unwrapBlock(x));
3265
3812
  } else if (keyword === "output") {
@@ -3417,6 +3964,25 @@ var resolveProcess = function(ctx, unresolved) {
3417
3964
  }
3418
3965
  return p;
3419
3966
  };
3967
+ function indentBlock(block) {
3968
+ return block.split("\n").map((line) => line ? " " + line : line).join("\n");
3969
+ }
3970
+ function dumpProcessTree(process2, lookup, nested = false) {
3971
+ let out = dumpProcess(process2, { nested });
3972
+ if (process2.children.length > 0) {
3973
+ const childBlocks = [];
3974
+ for (const childId of process2.children) {
3975
+ const child = lookup.get(childId);
3976
+ if (child) {
3977
+ childBlocks.push(indentBlock(dumpProcessTree(child, lookup, true)));
3978
+ }
3979
+ }
3980
+ if (childBlocks.length > 0) {
3981
+ out = out.replace(/\n}\n$/, "\n" + childBlocks.join("\n") + "}\n");
3982
+ }
3983
+ }
3984
+ return out;
3985
+ }
3420
3986
  function dumpParamList(params) {
3421
3987
  return params.map(
3422
3988
  (p) => p.name + (p.type ? " : " + p.type : "") + (p.initial !== void 0 ? " = " + dumpQuantityValue(p.initial) : "")
@@ -3531,6 +4097,26 @@ var dumpProcess = function(process2, ctx) {
3531
4097
  if (process2.machineSteps && process2.machineSteps.length > 0) {
3532
4098
  out += " machine_steps { " + process2.machineSteps.map(dumpBareSafe).join(" ") + " }\n";
3533
4099
  }
4100
+ for (const st of process2.steps ?? []) {
4101
+ if (st.signatureBlock) {
4102
+ const lines = st.signatureBlock.split("\n").map((l) => l.trim()).filter((l) => l !== "");
4103
+ out += " step " + st.id + " {\n";
4104
+ for (const line of lines) {
4105
+ out += " " + line + "\n";
4106
+ }
4107
+ out += " }\n";
4108
+ }
4109
+ }
4110
+ for (const b of process2.bindings ?? []) {
4111
+ out += " binding " + b.id + " {\n";
4112
+ for (const line of b.block.split("\n")) {
4113
+ out += line === "" ? "\n" : " " + line + "\n";
4114
+ }
4115
+ out += " }\n";
4116
+ }
4117
+ for (const req of process2.stepRequires ?? []) {
4118
+ out += " requires { " + req + " }\n";
4119
+ }
3534
4120
  const inputIds = process2.inputRefs && process2.inputRefs.length > 0 ? process2.inputRefs : process2.input.map((r) => r.id);
3535
4121
  if (inputIds.length > 0) {
3536
4122
  out += " reference_data_registry {\n";
@@ -5270,6 +5856,11 @@ function parseColumnDefs(block) {
5270
5856
  if (!name) {
5271
5857
  break;
5272
5858
  }
5859
+ if (i < t.length && t[i] === "{") {
5860
+ throw new Error(
5861
+ `Parsing error: table. Column "${name}": the old columns dialect (colN { name ... type ... }) is retired \u2014 write the canonical form: ${name === "" ? "name" : name}: type "unit"`
5862
+ );
5863
+ }
5273
5864
  if (i < t.length && t[i] === ":") {
5274
5865
  i++;
5275
5866
  }
@@ -6695,6 +7286,7 @@ var parseSymbol = function(id, data) {
6695
7286
  type: "number",
6696
7287
  unit: "1",
6697
7288
  latex: "",
7289
+ renders: [],
6698
7290
  values: [],
6699
7291
  series: null,
6700
7292
  kind: "",
@@ -6746,6 +7338,20 @@ var parseSymbol = function(id, data) {
6746
7338
  result.unit = unwrapped(value);
6747
7339
  } else if (command === "latex") {
6748
7340
  result.latex = unwrapped(value);
7341
+ } else if (command === "render") {
7342
+ const notation = stripWrapping(value());
7343
+ const text = peek() !== void 0 ? stripWrapping(value()) : "";
7344
+ if (!result.renders) {
7345
+ result.renders = [];
7346
+ }
7347
+ if (["asciimath", "latex", "unicodemath", "mathml", "omml"].includes(
7348
+ notation
7349
+ )) {
7350
+ result.renders.push({ notation, text });
7351
+ if (notation === "latex" && !result.latex) {
7352
+ result.latex = text;
7353
+ }
7354
+ }
6749
7355
  } else if (command === "values") {
6750
7356
  const v = value();
6751
7357
  result.values = v.startsWith("{") ? tokenizePackage(v).map(stripWrapping) : [stripWrapping(v)];
@@ -6826,6 +7432,9 @@ var dumpSymbol = function(s) {
6826
7432
  if (s.latex) {
6827
7433
  out += ' latex "' + escapeString(s.latex) + '"\n';
6828
7434
  }
7435
+ for (const r of s.renders ?? []) {
7436
+ out += " render " + r.notation + ' "' + escapeString(r.text) + '"\n';
7437
+ }
6829
7438
  if (s.values.length > 0) {
6830
7439
  out += " values { " + s.values.map(dumpBareSafe).join(" ") + " }\n";
6831
7440
  }
@@ -6971,6 +7580,23 @@ var parseCalculation = function(id, data) {
6971
7580
  result.description = unwrapBlock(t[i++]);
6972
7581
  } else if (command === "expression") {
6973
7582
  result.expression = unwrapBlock(t[i++]);
7583
+ } else if (command === "math") {
7584
+ const inner = tokenizePackage(unwrapBlock(t[i++]));
7585
+ let notation = "";
7586
+ let formula = "";
7587
+ let j = 0;
7588
+ while (j < inner.length) {
7589
+ const k = inner[j++];
7590
+ if (j >= inner.length) {
7591
+ break;
7592
+ }
7593
+ if (k === "notation") {
7594
+ notation = stripWrapping(inner[j++]);
7595
+ } else if (k === "formula") {
7596
+ formula = stripWrapping(inner[j++]);
7597
+ }
7598
+ }
7599
+ result.math = { notation, formula };
6974
7600
  } else if (command === "reference") {
6975
7601
  result._relations.ref = tokenizePackage(t[i++]);
6976
7602
  } else if (command === "ref") {
@@ -7287,6 +7913,23 @@ function parseVariant(vid, block, calcId) {
7287
7913
  variant.params = tokenize(stripWrapping(t[i++])).map(stripWrapping).filter((s) => s.length > 0);
7288
7914
  } else if (cmd === "expression") {
7289
7915
  variant.expression = stripWrapping(t[i++]);
7916
+ } else if (cmd === "math") {
7917
+ const inner = tokenizePackage(unwrapBlock(t[i++]));
7918
+ let notation = "";
7919
+ let formula = "";
7920
+ let j = 0;
7921
+ while (j < inner.length) {
7922
+ const k = inner[j++];
7923
+ if (j >= inner.length) {
7924
+ break;
7925
+ }
7926
+ if (k === "notation") {
7927
+ notation = stripWrapping(inner[j++]);
7928
+ } else if (k === "formula") {
7929
+ formula = stripWrapping(inner[j++]);
7930
+ }
7931
+ }
7932
+ variant.math = { notation, formula };
7290
7933
  } else if (cmd === "lookup") {
7291
7934
  variant.lookup = parseLookup(unwrapBlock(t[i++]));
7292
7935
  } else if (cmd === "profile") {
@@ -7427,6 +8070,12 @@ var dumpCalculation = function(c) {
7427
8070
  if (c.expression) {
7428
8071
  out += ' expression "' + escapeString(c.expression) + '"\n';
7429
8072
  }
8073
+ if (c.math) {
8074
+ out += " math {\n";
8075
+ out += " notation " + c.math.notation + "\n";
8076
+ out += ' formula "' + escapeString(c.math.formula) + '"\n';
8077
+ out += " }\n";
8078
+ }
7430
8079
  if (c.params && c.params.length > 0) {
7431
8080
  out += " params { " + c.params.join(" ") + " }\n";
7432
8081
  }
@@ -8605,7 +9254,7 @@ function parseRequiredCompetence(block) {
8605
9254
  const entry = {
8606
9255
  kind: stripWrapping(t[i++]),
8607
9256
  range: null,
8608
- methodStandard: "",
9257
+ methodRef: "",
8609
9258
  resolution: null,
8610
9259
  stability: null,
8611
9260
  description: ""
@@ -8638,8 +9287,8 @@ function parseRequiredCompetence(block) {
8638
9287
  }
8639
9288
  }
8640
9289
  entry.range = range;
8641
- } else if (cc === "method_standard") {
8642
- entry.methodStandard = stripWrapping(ct[j++]);
9290
+ } else if (cc === "method_ref") {
9291
+ entry.methodRef = stripWrapping(ct[j++]);
8643
9292
  } else if (cc === "resolution") {
8644
9293
  entry.resolution = readQuantity(unwrapBlock(ct[j++]));
8645
9294
  } else if (cc === "stability") {
@@ -8682,8 +9331,8 @@ function dumpRequiredCompetence(entries) {
8682
9331
  line += ' unit "' + escapeString(e.range.unit) + '" }\n';
8683
9332
  out += line;
8684
9333
  }
8685
- if (e.methodStandard) {
8686
- out += ' method_standard "' + escapeString(e.methodStandard) + '"\n';
9334
+ if (e.methodRef) {
9335
+ out += " method_ref " + e.methodRef + "\n";
8687
9336
  }
8688
9337
  out += dumpQuantity("resolution", e.resolution);
8689
9338
  out += dumpQuantity("stability", e.stability);
@@ -8706,8 +9355,7 @@ var parseCompetenceKind = function(id, data) {
8706
9355
  id,
8707
9356
  label: "",
8708
9357
  definition: "",
8709
- source: null,
8710
- methodStandards: []
9358
+ source: null
8711
9359
  };
8712
9360
  const t = tokenizePackage(data);
8713
9361
  let i = 0;
@@ -8724,14 +9372,6 @@ var parseCompetenceKind = function(id, data) {
8724
9372
  result.definition = readValue(t[i++]);
8725
9373
  } else if (keyword === "source") {
8726
9374
  result.source = readSource(unwrapBlock(t[i++]));
8727
- } else if (keyword === "method_standard") {
8728
- const stdId = stripWrapping(t[i++]);
8729
- if (i >= t.length) {
8730
- throw new Error(
8731
- `Parsing error: competence_kind. ID ${id}: Expecting title for method_standard ${stdId}`
8732
- );
8733
- }
8734
- result.methodStandards.push({ id: stdId, title: readValue(t[i++]) });
8735
9375
  } else if (keyword === "ref") {
8736
9376
  const rr = parseRef(t, i, stripWrapping, unwrapBlock);
8737
9377
  if (!foldRefIntoLegacy(result, rr.ref)) {
@@ -8762,9 +9402,6 @@ var dumpCompetenceKind = function(k) {
8762
9402
  if (k.source && (k.source.doc || k.source.clause)) {
8763
9403
  out += ' source { doc "' + escapeString(k.source.doc) + '" clause "' + escapeString(k.source.clause) + '"' + (k.source.fragment ? ' fragment "' + escapeString(k.source.fragment) + '"' : "") + " }\n";
8764
9404
  }
8765
- for (const ms of k.methodStandards) {
8766
- out += " method_standard " + ms.id + ' "' + escapeString(ms.title) + '"\n';
8767
- }
8768
9405
  out += dumpCorrespondences(
8769
9406
  k.correspondences,
8770
9407
  " ",
@@ -8825,7 +9462,9 @@ function parseTestVariables(block) {
8825
9462
  } else if (vc === "source") {
8826
9463
  v.source = stripWrapping(vt[j++]);
8827
9464
  } else if (vc === "derivation") {
8828
- v.derivation = stripWrapping(vt[j++]);
9465
+ const c = readExpressionCarrier(vt[j++], "test variable derivation");
9466
+ v.derivation = c.source;
9467
+ v.derivationBound = c.inline || void 0;
8829
9468
  } else if (vc === "description") {
8830
9469
  v.description = stripWrapping(vt[j++]);
8831
9470
  } else if (vc === "item_type") {
@@ -8885,7 +9524,9 @@ function parsePreconditions(block) {
8885
9524
  break;
8886
9525
  }
8887
9526
  if (pc === "check") {
8888
- p.check = stripWrapping(pt[j++]);
9527
+ const c = readExpressionCarrier(pt[j++], "precondition check");
9528
+ p.check = c.source;
9529
+ p.checkBound = c.inline || void 0;
8889
9530
  } else if (pc === "description") {
8890
9531
  p.description = stripWrapping(pt[j++]);
8891
9532
  } else if (pc === "on_violation") {
@@ -9651,8 +10292,17 @@ var dumpConformanceTest = function(ct) {
9651
10292
  if (v.source) {
9652
10293
  line += "source " + v.source + " ";
9653
10294
  }
10295
+ let derivationBlock = "";
9654
10296
  if (v.derivation) {
9655
- line += 'derivation "' + escapeString(v.derivation) + '" ';
10297
+ if (v.derivationBound) {
10298
+ derivationBlock = dumpExpressionBlock(
10299
+ "derivation",
10300
+ v.derivation,
10301
+ " "
10302
+ );
10303
+ } else {
10304
+ line += 'derivation "' + escapeString(v.derivation) + '" ';
10305
+ }
9656
10306
  }
9657
10307
  if (v.description) {
9658
10308
  line += 'description "' + escapeString(v.description) + '" ';
@@ -9679,7 +10329,11 @@ var dumpConformanceTest = function(ct) {
9679
10329
  }
9680
10330
  line += pv + "} ";
9681
10331
  }
9682
- out += line + "}\n";
10332
+ if (derivationBlock) {
10333
+ out += line + "\n" + derivationBlock + " }\n";
10334
+ } else {
10335
+ out += line + "}\n";
10336
+ }
9683
10337
  }
9684
10338
  out += " }\n";
9685
10339
  }
@@ -9707,8 +10361,13 @@ var dumpConformanceTest = function(ct) {
9707
10361
  out += " preconditions {\n";
9708
10362
  for (const p of ct.preconditions) {
9709
10363
  let line = " precondition " + p.id + " { ";
10364
+ let checkBlock = "";
9710
10365
  if (p.check) {
9711
- line += 'check "' + escapeString(p.check) + '" ';
10366
+ if (p.checkBound) {
10367
+ checkBlock = dumpExpressionBlock("check", p.check, " ");
10368
+ } else {
10369
+ line += 'check "' + escapeString(p.check) + '" ';
10370
+ }
9712
10371
  }
9713
10372
  if (p.description) {
9714
10373
  line += 'description "' + escapeString(p.description) + '" ';
@@ -9717,7 +10376,11 @@ var dumpConformanceTest = function(ct) {
9717
10376
  if (p.onUnresolvable) {
9718
10377
  line += "on_unresolvable " + p.onUnresolvable + " ";
9719
10378
  }
9720
- out += line + "}\n";
10379
+ if (checkBlock) {
10380
+ out += line + "\n" + checkBlock + " }\n";
10381
+ } else {
10382
+ out += line + "}\n";
10383
+ }
9721
10384
  }
9722
10385
  out += " }\n";
9723
10386
  }
@@ -10082,7 +10745,9 @@ var parseVerdict = function(id, data) {
10082
10745
  } else if (keyword === "behavior") {
10083
10746
  result.behavior = value();
10084
10747
  } else if (keyword === "derive" || keyword === "expression") {
10085
- result.derive = unwrapped(value);
10748
+ const c = readExpressionCarrier(value(), "verdict derive");
10749
+ result.derive = c.source;
10750
+ result.deriveBound = c.inline || void 0;
10086
10751
  } else if (keyword === "inputs" || keyword === "uses") {
10087
10752
  result.inputs = readIdList3(value());
10088
10753
  } else if (keyword === "series_reduction") {
@@ -10140,7 +10805,11 @@ var dumpVerdict = function(v) {
10140
10805
  out += " }\n";
10141
10806
  }
10142
10807
  if (v.derive) {
10143
- out += ' derive "' + escapeString(v.derive) + '"\n';
10808
+ if (v.deriveBound) {
10809
+ out += dumpExpressionBlock("derive", v.derive, " ");
10810
+ } else {
10811
+ out += ' derive "' + escapeString(v.derive) + '"\n';
10812
+ }
10144
10813
  }
10145
10814
  if (v.inputs.length > 0) {
10146
10815
  out += " inputs { " + v.inputs.join(" ") + " }\n";
@@ -10743,8 +11412,15 @@ var parseConstraint = function(id, data) {
10743
11412
  result.stereotype = stripWrapping(t[i++]);
10744
11413
  } else if (keyword === "name") {
10745
11414
  result.name = readValue2(t[i++]);
11415
+ } else if (keyword === "args") {
11416
+ if (!result.args) {
11417
+ result.args = [];
11418
+ }
11419
+ result.args.push(...readArgsBlock(unwrapBlock(t[i++])));
10746
11420
  } else if (keyword === "check") {
10747
- result.check = readValue2(t[i++]);
11421
+ const c = readExpressionCarrier(t[i++], "constraint check");
11422
+ result.check = c.source;
11423
+ result.checkBound = c.inline || void 0;
10748
11424
  } else if (keyword === "violation_meaning") {
10749
11425
  result.violationMeaning = readValue2(t[i++]);
10750
11426
  } else if (keyword === "on_violation") {
@@ -10778,8 +11454,19 @@ var dumpConstraint = function(c) {
10778
11454
  if (c.name) {
10779
11455
  out += ' name "' + escapeString(c.name) + '"\n';
10780
11456
  }
11457
+ if ((c.args ?? []).length > 0) {
11458
+ out += " args {\n";
11459
+ for (const a of c.args ?? []) {
11460
+ out += " " + a.name + " <- " + a.source + "\n";
11461
+ }
11462
+ out += " }\n";
11463
+ }
10781
11464
  if (c.check) {
10782
- out += ' check "' + escapeString(c.check) + '"\n';
11465
+ if (c.checkBound) {
11466
+ out += dumpExpressionBlock("check", c.check, " ");
11467
+ } else {
11468
+ out += ' check "' + escapeString(c.check) + '"\n';
11469
+ }
10783
11470
  }
10784
11471
  if (c.violationMeaning) {
10785
11472
  out += ' violation_meaning "' + escapeString(c.violationMeaning) + '"\n';
@@ -10798,6 +11485,169 @@ var dumpConstraint = function(c) {
10798
11485
  return out;
10799
11486
  };
10800
11487
 
11488
+ // src/ser-des/config/uncertaintyBudget.ts
11489
+ var DISTRIBUTIONS = /* @__PURE__ */ new Set([
11490
+ "rectangular",
11491
+ "triangular",
11492
+ "normal",
11493
+ "ushape"
11494
+ ]);
11495
+ function readComponent(block) {
11496
+ const c = {
11497
+ id: "",
11498
+ type: "B",
11499
+ series: "",
11500
+ distribution: "",
11501
+ halfWidth: "",
11502
+ unit: "",
11503
+ source: null,
11504
+ description: ""
11505
+ };
11506
+ const t = tokenizePackage(block);
11507
+ let i = 0;
11508
+ while (i < t.length) {
11509
+ const kw = t[i++];
11510
+ if (i >= t.length) {
11511
+ throw new Error(
11512
+ `Parsing error: uncertainty_budget component. ID ${c.id}: Expecting value for ${kw}`
11513
+ );
11514
+ }
11515
+ if (kw === "type") {
11516
+ const v = stripWrapping(t[i++]);
11517
+ if (v !== "A" && v !== "B") {
11518
+ throw new Error(
11519
+ `Parsing error: uncertainty_budget component. ID ${c.id}: unknown type "${v}" (A evaluates the statistics of a series; B states a distribution)`
11520
+ );
11521
+ }
11522
+ c.type = v;
11523
+ } else if (kw === "series") {
11524
+ c.series = stripWrapping(t[i++]);
11525
+ } else if (kw === "distribution") {
11526
+ const v = stripWrapping(t[i++]);
11527
+ if (!DISTRIBUTIONS.has(v)) {
11528
+ throw new Error(
11529
+ `Parsing error: uncertainty_budget component. ID ${c.id}: unknown distribution "${v}" (rectangular | triangular | normal | ushape)`
11530
+ );
11531
+ }
11532
+ c.distribution = v;
11533
+ } else if (kw === "half_width") {
11534
+ c.halfWidth = stripWrapping(t[i++]);
11535
+ } else if (kw === "unit") {
11536
+ c.unit = stripWrapping(t[i++]);
11537
+ } else if (kw === "description") {
11538
+ c.description = stripWrapping(t[i++]);
11539
+ } else if (kw === "source") {
11540
+ c.source = readSource(unwrapBlock(t[i++]));
11541
+ } else {
11542
+ i = skipUnknownValue(t, i, kw);
11543
+ }
11544
+ }
11545
+ return c;
11546
+ }
11547
+ var parseUncertaintyBudget = function(id, data) {
11548
+ const result = {
11549
+ id,
11550
+ target: "",
11551
+ coverageK: "",
11552
+ components: [],
11553
+ source: null
11554
+ };
11555
+ const t = tokenizePackage(data);
11556
+ let i = 0;
11557
+ while (i < t.length) {
11558
+ const kw = t[i++];
11559
+ if (i >= t.length) {
11560
+ throw new Error(
11561
+ `Parsing error: uncertainty_budget. ID ${id}: Expecting value for ${kw}`
11562
+ );
11563
+ }
11564
+ if (kw === "target") {
11565
+ result.target = stripWrapping(t[i++]);
11566
+ } else if (kw === "coverage") {
11567
+ const head = stripWrapping(t[i++]);
11568
+ if (head !== "k") {
11569
+ throw new Error(
11570
+ `Parsing error: uncertainty_budget. ID ${id}: coverage states its factor \u2014 coverage k <number>`
11571
+ );
11572
+ }
11573
+ result.coverageK = stripWrapping(t[i++]);
11574
+ } else if (kw === "component") {
11575
+ if (t[i].startsWith("{")) {
11576
+ throw new Error(
11577
+ `Parsing error: uncertainty_budget. ID ${id}: a component carries an id \u2014 component <id> { \u2026 }`
11578
+ );
11579
+ }
11580
+ const cid = stripWrapping(t[i++]);
11581
+ const c = readComponent(unwrapBlock(t[i++]));
11582
+ c.id = cid;
11583
+ result.components.push(c);
11584
+ } else if (kw === "source") {
11585
+ result.source = readSource(unwrapBlock(t[i++]));
11586
+ } else if (kw === "ref") {
11587
+ const rr = parseRef(t, i, stripWrapping, unwrapBlock);
11588
+ if (!foldRefIntoLegacy(result, rr.ref)) {
11589
+ (result.refs ??= []).push(rr.ref);
11590
+ }
11591
+ i = rr.next;
11592
+ } else if (kw === "corresponds") {
11593
+ const cc = parseCorresponds(t, i, stripWrapping);
11594
+ (result.correspondences ??= []).push(cc.corr);
11595
+ i = cc.next;
11596
+ } else {
11597
+ i = skipUnknownValue(t, i, kw);
11598
+ }
11599
+ }
11600
+ return (ctx) => {
11601
+ ctx.uncertaintyBudgets[id] = result;
11602
+ return ctx;
11603
+ };
11604
+ };
11605
+ var dumpUncertaintyBudget = function(b) {
11606
+ let out = "uncertainty_budget " + b.id + " {\n";
11607
+ if (b.target) {
11608
+ out += " target " + b.target + "\n";
11609
+ }
11610
+ if (b.coverageK) {
11611
+ out += " coverage k " + b.coverageK + "\n";
11612
+ }
11613
+ for (const c of b.components) {
11614
+ out += " component " + c.id + " {\n";
11615
+ out += " type " + c.type + "\n";
11616
+ if (c.type === "A" && c.series) {
11617
+ out += " series " + c.series + "\n";
11618
+ }
11619
+ if (c.type === "B") {
11620
+ if (c.distribution) {
11621
+ out += " distribution " + c.distribution + "\n";
11622
+ }
11623
+ if (c.halfWidth) {
11624
+ out += " half_width " + c.halfWidth + "\n";
11625
+ }
11626
+ if (c.unit) {
11627
+ out += ' unit "' + escapeString(c.unit) + '"\n';
11628
+ }
11629
+ }
11630
+ if (c.description) {
11631
+ out += ' description "' + escapeString(c.description) + '"\n';
11632
+ }
11633
+ if (c.source && (c.source.doc || c.source.clause)) {
11634
+ out += ' source { doc "' + escapeString(c.source.doc) + '" clause "' + escapeString(c.source.clause) + '"' + (c.source.fragment ? ' fragment "' + escapeString(c.source.fragment) + '"' : "") + " }\n";
11635
+ }
11636
+ out += " }\n";
11637
+ }
11638
+ if (b.source && (b.source.doc || b.source.clause)) {
11639
+ out += ' source { doc "' + escapeString(b.source.doc) + '" clause "' + escapeString(b.source.clause) + '"' + (b.source.fragment ? ' fragment "' + escapeString(b.source.fragment) + '"' : "") + " }\n";
11640
+ }
11641
+ out += dumpCorrespondences(
11642
+ b.correspondences,
11643
+ " ",
11644
+ escapeString,
11645
+ dumpBareSafe
11646
+ );
11647
+ out += "}\n";
11648
+ return out;
11649
+ };
11650
+
10801
11651
  // src/ser-des/config/discrepancyRecord.ts
10802
11652
  var VALID_STATUSES = ["open", "resolved"];
10803
11653
  var parseDiscrepancyRecord = function(id, data) {
@@ -11146,8 +11996,8 @@ function readAccepts(block) {
11146
11996
  }
11147
11997
  return accepts;
11148
11998
  }
11149
- function readLimit(block) {
11150
- const limit = {
11999
+ function blankLimit() {
12000
+ return {
11151
12001
  expression: "",
11152
12002
  uses: [],
11153
12003
  modality: "",
@@ -11158,15 +12008,51 @@ function readLimit(block) {
11158
12008
  acceptance: null,
11159
12009
  sourceDiscrepancy: null
11160
12010
  };
11161
- const t = tokenize(block);
11162
- let i = 0;
12011
+ }
12012
+ function readLimit(block) {
12013
+ const limit = blankLimit();
12014
+ readLegacyLimitFields(tokenize(block), limit, 0);
12015
+ return limit;
12016
+ }
12017
+ function readExpressionBlock(raw) {
12018
+ return canonicalizeExpression(raw);
12019
+ }
12020
+ function readLegacyLimitFields(t, limit, start) {
12021
+ let i = start;
11163
12022
  while (i < t.length) {
11164
12023
  const cmd = t[i++];
11165
12024
  if (i >= t.length) {
11166
12025
  break;
11167
12026
  }
11168
- if (cmd === "expression") {
11169
- limit.expression = stripWrapping(t[i++]);
12027
+ if (cmd === "args") {
12028
+ if (!limit.args) {
12029
+ limit.args = [];
12030
+ }
12031
+ const at = tokenize(unwrapBlock(t[i++]));
12032
+ let k = 0;
12033
+ while (k < at.length) {
12034
+ const name = stripWrapping(at[k++]);
12035
+ const arrow = at[k];
12036
+ if (arrow !== "<-") {
12037
+ throw new Error(
12038
+ `limit args: expected "<-" after "${name}" (name <- source)`
12039
+ );
12040
+ }
12041
+ k += 1;
12042
+ if (k >= at.length) {
12043
+ throw new Error(`limit args: "${name}" binds to nothing`);
12044
+ }
12045
+ const source = stripWrapping(at[k++]);
12046
+ limit.args.push({ name, source });
12047
+ }
12048
+ } else if (cmd === "expression") {
12049
+ const value = t[i++];
12050
+ if (value.startsWith("{")) {
12051
+ limit.argsBound = true;
12052
+ limit.expression = readExpressionBlock(unwrapBlock(value));
12053
+ } else {
12054
+ limit.expression = stripWrapping(value);
12055
+ }
11170
12056
  } else if (cmd === "uses") {
11171
12057
  limit.uses = readIdList4(t[i++]);
11172
12058
  } else if (cmd === "modality") {
@@ -11203,7 +12089,6 @@ function readLimit(block) {
11203
12089
  i = skipUnknownValue(t, i, cmd);
11204
12090
  }
11205
12091
  }
11206
- return limit;
11207
12092
  }
11208
12093
  function readSubjects(block) {
11209
12094
  const out = [];
@@ -11415,6 +12300,52 @@ var parseRequirement = function(id, data) {
11415
12300
  };
11416
12301
  };
11417
12302
  function dumpLimit(limit) {
12303
+ if (limit.argsBound) {
12304
+ let out2 = " limit {\n";
12305
+ if ((limit.args ?? []).length > 0) {
12306
+ out2 += " args {\n";
12307
+ for (const a of limit.args ?? []) {
12308
+ out2 += " " + a.name + " <- " + a.source + "\n";
12309
+ }
12310
+ out2 += " }\n";
12311
+ }
12312
+ out2 += " expression {\n";
12313
+ for (const line of limit.expression.split("\n")) {
12314
+ out2 += " " + line + "\n";
12315
+ }
12316
+ out2 += " }\n";
12317
+ if (limit.modality) {
12318
+ out2 += " modality " + limit.modality + "\n";
12319
+ }
12320
+ if (limit.relativeTo) {
12321
+ out2 += " relative_to " + limit.relativeTo + "\n";
12322
+ }
12323
+ if (limit.notes) {
12324
+ out2 += ' notes "' + escapeString(limit.notes) + '"\n';
12325
+ }
12326
+ if (limit.accepts) {
12327
+ const a = limit.accepts;
12328
+ let line = " accepts { verdict " + a.verdict;
12329
+ if (a.op) {
12330
+ line += " op " + a.op;
12331
+ }
12332
+ if (a.limit) {
12333
+ line += ' limit "' + escapeString(a.limit) + '"';
12334
+ }
12335
+ if (a.sourceDiscrepancy) {
12336
+ line += " " + dumpSourceDiscrepancy(a.sourceDiscrepancy, "");
12337
+ }
12338
+ out2 += line + " }\n";
12339
+ }
12340
+ if (limit.acceptance) {
12341
+ out2 += dumpAcceptance(limit.acceptance, " ") + "\n";
12342
+ }
12343
+ if (limit.sourceDiscrepancy) {
12344
+ out2 += dumpSourceDiscrepancy(limit.sourceDiscrepancy, " ") + "\n";
12345
+ }
12346
+ out2 += " }\n";
12347
+ return out2;
12348
+ }
11418
12349
  let out = " limit {\n";
11419
12350
  if (limit.expression) {
11420
12351
  out += ' expression "' + escapeString(limit.expression) + '"\n';
@@ -11578,8 +12509,12 @@ var parseRequirementClass = function(id, data) {
11578
12509
  subject: "",
11579
12510
  guidance: "",
11580
12511
  dependencies: [],
11581
- referenceIds: []
12512
+ referenceIds: [],
12513
+ limit: null,
12514
+ members: []
11582
12515
  };
12516
+ const nestedParsers = [];
12517
+ const members = [];
11583
12518
  const t = tokenizePackage(data);
11584
12519
  let i = 0;
11585
12520
  while (i < t.length) {
@@ -11603,11 +12538,24 @@ var parseRequirementClass = function(id, data) {
11603
12538
  result.dependencies = readIdList4(t[i++]);
11604
12539
  } else if (cmd === "reference") {
11605
12540
  result.referenceIds = readIdList4(t[i++]);
12541
+ } else if (cmd === "limit") {
12542
+ result.limit = readLimit(unwrapBlock(t[i++]));
12543
+ } else if (cmd === "requirement") {
12544
+ const childId = stripWrapping(t[i++]);
12545
+ const childBlock = t[i++];
12546
+ const childParse = parseRequirement(childId, unwrapBlock(childBlock));
12547
+ nestedParsers.push(childParse);
12548
+ members.push(childId);
11606
12549
  } else {
11607
12550
  i = skipUnknownValue(t, i, cmd);
11608
12551
  }
11609
12552
  }
11610
12553
  return (ctx) => {
12554
+ const c = ctx;
12555
+ for (const parse2 of nestedParsers) {
12556
+ parse2(c);
12557
+ }
12558
+ result.members = members;
11611
12559
  ctx.requirementClasses[id] = result;
11612
12560
  return ctx;
11613
12561
  };
@@ -11632,6 +12580,9 @@ var dumpRequirementClass = function(rc) {
11632
12580
  if (rc.referenceIds.length > 0) {
11633
12581
  out += " reference { " + rc.referenceIds.join(" ") + " }\n";
11634
12582
  }
12583
+ if (rc.limit) {
12584
+ out += dumpLimit(rc.limit);
12585
+ }
11635
12586
  out += "}\n";
11636
12587
  return out;
11637
12588
  };
@@ -11700,6 +12651,8 @@ var parsePackage = function(data) {
11700
12651
  manifest.title = stripWrapping(t[i++]);
11701
12652
  } else if (cmd === "version") {
11702
12653
  manifest.version = stripWrapping(t[i++]);
12654
+ } else if (cmd === "language") {
12655
+ manifest.language = stripWrapping(t[i++]);
11703
12656
  } else if (cmd === "editions") {
11704
12657
  manifest.editions = readList(t[i++]);
11705
12658
  } else if (cmd === "baseUrn" || cmd === "base_urn") {
@@ -18912,6 +19865,298 @@ var dumpPartAnnex = function(a) {
18912
19865
  return out;
18913
19866
  };
18914
19867
 
19868
+ // src/ser-des/config/lmlAligned.ts
19869
+ var MATH_NOTATIONS = ["asciimath", "latex", "unicodemath", "mathml", "omml"];
19870
+ var MAPPING_FORMATS = ["xml", "yaml", "json", "toml", "csv"];
19871
+ function splitMappingId(id) {
19872
+ const at = id.indexOf(":");
19873
+ const format = at === -1 ? "xml" : id.slice(0, at);
19874
+ return { format, target: at === -1 ? id : id.slice(at + 1) };
19875
+ }
19876
+ var parseWireMapping = function(id, data) {
19877
+ const { format, target } = splitMappingId(id);
19878
+ const out = {
19879
+ id,
19880
+ format,
19881
+ target,
19882
+ element: "",
19883
+ namespaceRef: "",
19884
+ content: "",
19885
+ mixed: false,
19886
+ renderNil: null,
19887
+ entries: [],
19888
+ source: null
19889
+ };
19890
+ forEachEntry(
19891
+ data,
19892
+ (command, value, peek) => {
19893
+ if (command === "element") {
19894
+ out.element = stripWrapping(value());
19895
+ } else if (command === "namespace") {
19896
+ out.namespaceRef = stripWrapping(value());
19897
+ } else if (command === "mixed_content") {
19898
+ value();
19899
+ out.mixed = true;
19900
+ } else if (command === "render_nil") {
19901
+ out.renderNil = stripWrapping(value()) === "true";
19902
+ } else if (command === "map_content") {
19903
+ out.content = stripWrapping(value());
19904
+ } else if (command === "map_element" || command === "map_attribute" || command === "map") {
19905
+ const wire = stripWrapping(value());
19906
+ const name = peek() !== void 0 ? stripWrapping(value()) : "";
19907
+ const kind = command === "map_element" ? "element" : command === "map_attribute" ? "attribute" : "map";
19908
+ out.entries.push({ kind, wire, name, modifier: "" });
19909
+ } else if (command === "map_key" || command === "map_value") {
19910
+ const modifier = stripWrapping(value());
19911
+ const name = peek() !== void 0 ? stripWrapping(value()) : "";
19912
+ out.entries.push({ kind: "map", wire: command, name, modifier });
19913
+ } else {
19914
+ return false;
19915
+ }
19916
+ return true;
19917
+ },
19918
+ { construct: "mapping", id }
19919
+ );
19920
+ return (ctx) => {
19921
+ ctx.wireMappings[id] = out;
19922
+ return ctx;
19923
+ };
19924
+ };
19925
+ var dumpWireMapping = function(w) {
19926
+ const lines = [`mapping ${w.format} ${w.target} {`];
19927
+ if (w.element) {
19928
+ lines.push(` element "${escapeString(w.element)}"`);
19929
+ }
19930
+ if (w.namespaceRef) {
19931
+ lines.push(` namespace ${w.namespaceRef}`);
19932
+ }
19933
+ for (const e of w.entries) {
19934
+ if (e.kind === "map" && e.modifier) {
19935
+ lines.push(` ${e.wire} ${e.modifier} ${e.name}`);
19936
+ } else {
19937
+ const kw = e.kind === "element" ? "map_element" : e.kind === "attribute" ? "map_attribute" : "map";
19938
+ lines.push(` ${kw} "${escapeString(e.wire)}" ${e.name}`);
19939
+ }
19940
+ }
19941
+ if (w.content) {
19942
+ lines.push(` map_content ${w.content}`);
19943
+ }
19944
+ if (w.mixed) {
19945
+ lines.push(` mixed_content`);
19946
+ }
19947
+ if (w.renderNil !== null) {
19948
+ lines.push(` render_nil ${w.renderNil}`);
19949
+ }
19950
+ lines.push("}");
19951
+ return lines.join("\n");
19952
+ };
19953
+ var parseStringFormat = function(rawId, data) {
19954
+ if (!rawId.startsWith(":")) {
19955
+ throw new Error(
19956
+ `Parsing error: string_format. ID ${rawId}: the registered format name carries the colon sigil (string_format :${rawId})`
19957
+ );
19958
+ }
19959
+ const id = rawId.slice(1);
19960
+ const out = { id, artifact: "", root: "", source: null };
19961
+ forEachEntry(
19962
+ data,
19963
+ (command, value) => {
19964
+ if (command === "artifact") {
19965
+ out.artifact = stripWrapping(value());
19966
+ } else if (command === "root") {
19967
+ out.root = stripWrapping(value());
19968
+ } else {
19969
+ return false;
19970
+ }
19971
+ return true;
19972
+ },
19973
+ { construct: "string_format", id }
19974
+ );
19975
+ return (ctx) => {
19976
+ ctx.stringFormats[id] = out;
19977
+ return ctx;
19978
+ };
19979
+ };
19980
+ var dumpStringFormat = function(f) {
19981
+ return [
19982
+ `string_format :${f.id} {`,
19983
+ ` artifact "${escapeString(f.artifact)}"`,
19984
+ ` root "${escapeString(f.root)}"`,
19985
+ "}"
19986
+ ].join("\n");
19987
+ };
19988
+ var parseNamespace = function(id, data) {
19989
+ const out = {
19990
+ id,
19991
+ uri: "",
19992
+ prefix: "",
19993
+ isDefault: false,
19994
+ source: null
19995
+ };
19996
+ forEachEntry(
19997
+ data,
19998
+ (command, value) => {
19999
+ if (command === "uri") {
20000
+ out.uri = stripWrapping(value());
20001
+ } else if (command === "prefix") {
20002
+ out.prefix = stripWrapping(value());
20003
+ } else if (command === "default") {
20004
+ value();
20005
+ out.isDefault = true;
20006
+ } else {
20007
+ return false;
20008
+ }
20009
+ return true;
20010
+ },
20011
+ { construct: "namespace", id }
20012
+ );
20013
+ return (ctx) => {
20014
+ ctx.namespaces[id] = out;
20015
+ return ctx;
20016
+ };
20017
+ };
20018
+ var dumpNamespace = function(d) {
20019
+ const lines = [`namespace ${d.id} {`, ` uri "${escapeString(d.uri)}"`];
20020
+ if (d.prefix) {
20021
+ lines.push(` prefix "${escapeString(d.prefix)}"`);
20022
+ }
20023
+ if (d.isDefault) {
20024
+ lines.push(` default`);
20025
+ }
20026
+ lines.push("}");
20027
+ return lines.join("\n");
20028
+ };
20029
+ var parseDatum = function(id, raw) {
20030
+ const data = raw.replace(/^\s*:\s*\S+\s*/, "");
20031
+ const out = {
20032
+ id,
20033
+ type: "",
20034
+ unit: "",
20035
+ quantityKind: "",
20036
+ origin: "declared",
20037
+ scope: "",
20038
+ renders: [],
20039
+ label: "",
20040
+ description: "",
20041
+ source: null
20042
+ };
20043
+ forEachEntry(
20044
+ data,
20045
+ (command, value, peek) => {
20046
+ if (command === "render") {
20047
+ const notation = stripWrapping(value());
20048
+ const text = peek() !== void 0 ? stripWrapping(value()) : "";
20049
+ if (MATH_NOTATIONS.includes(notation)) {
20050
+ out.renders.push({ notation, text });
20051
+ }
20052
+ } else if (command === "label") {
20053
+ out.label = stripWrapping(value());
20054
+ } else if (command === "description") {
20055
+ const v = value();
20056
+ out.description = v.startsWith("{") ? unwrapBlock(v) : stripWrapping(v);
20057
+ } else if (command === "unit") {
20058
+ out.unit = stripWrapping(value());
20059
+ } else if (command === "quantity_kind") {
20060
+ out.quantityKind = stripWrapping(value());
20061
+ } else if (command === "origin") {
20062
+ const o = stripWrapping(value());
20063
+ if (["declared", "design-fixed", "observed", "computed"].includes(o)) {
20064
+ out.origin = o;
20065
+ }
20066
+ } else if (command === "scope") {
20067
+ out.scope = stripWrapping(value());
20068
+ } else {
20069
+ return false;
20070
+ }
20071
+ return true;
20072
+ },
20073
+ { construct: "datum", id }
20074
+ );
20075
+ return (ctx) => {
20076
+ ctx.datums[id] = out;
20077
+ return ctx;
20078
+ };
20079
+ };
20080
+ var dumpDatum = function(x) {
20081
+ const lines = [`datum ${x.id}${x.type ? ` : ${x.type}` : ""} {`];
20082
+ if (x.quantityKind) {
20083
+ lines.push(` quantity_kind ${x.quantityKind}`);
20084
+ }
20085
+ if (x.unit) {
20086
+ lines.push(` unit ${x.unit}`);
20087
+ }
20088
+ if (x.origin !== "declared") {
20089
+ lines.push(` origin ${x.origin}`);
20090
+ }
20091
+ if (x.scope) {
20092
+ lines.push(` scope ${x.scope}`);
20093
+ }
20094
+ for (const r of x.renders) {
20095
+ lines.push(` render ${r.notation} "${escapeString(r.text)}"`);
20096
+ }
20097
+ if (x.label) {
20098
+ lines.push(` label "${escapeString(x.label)}"`);
20099
+ }
20100
+ if (x.description) {
20101
+ lines.push(` description { ${x.description} }`);
20102
+ }
20103
+ lines.push("}");
20104
+ return lines.join("\n");
20105
+ };
20106
+ var parseCheck = function(id, data) {
20107
+ const out = {
20108
+ id,
20109
+ inputs: [],
20110
+ expression: "",
20111
+ operator: "",
20112
+ threshold: "",
20113
+ source: null
20114
+ };
20115
+ forEachEntry(
20116
+ data,
20117
+ (command, value, peek) => {
20118
+ if (command === "inputs") {
20119
+ const block = value();
20120
+ const inner = block.startsWith("{") ? tokenizePackage(unwrapBlock(block)) : [];
20121
+ out.inputs = inner.map((x) => stripWrapping(x));
20122
+ } else if (command === "expression") {
20123
+ out.expression = stripWrapping(value());
20124
+ } else if (command === "operator") {
20125
+ out.operator = stripWrapping(value());
20126
+ } else if (command === "threshold") {
20127
+ const v = value();
20128
+ out.threshold = v.startsWith("{") ? unwrapBlock(v) : stripWrapping(v);
20129
+ } else {
20130
+ return false;
20131
+ }
20132
+ void peek;
20133
+ return true;
20134
+ },
20135
+ { construct: "check", id }
20136
+ );
20137
+ return (ctx) => {
20138
+ ctx.checks[id] = out;
20139
+ return ctx;
20140
+ };
20141
+ };
20142
+ var dumpCheck = function(x) {
20143
+ const lines = [`check ${x.id} {`];
20144
+ if (x.inputs.length) {
20145
+ lines.push(` inputs { ${x.inputs.join(" ")} }`);
20146
+ }
20147
+ if (x.expression) {
20148
+ lines.push(` expression "${escapeString(x.expression)}"`);
20149
+ }
20150
+ if (x.operator) {
20151
+ lines.push(` operator ${x.operator}`);
20152
+ }
20153
+ if (x.threshold) {
20154
+ lines.push(` threshold ${x.threshold}`);
20155
+ }
20156
+ lines.push("}");
20157
+ return lines.join("\n");
20158
+ };
20159
+
18915
20160
  // src/ser-des/config/index.ts
18916
20161
  function defineConstruct(def) {
18917
20162
  return def;
@@ -19287,6 +20532,14 @@ var CONSTRUCTS = [
19287
20532
  parse: parseConstraint,
19288
20533
  dump: dumpConstraint
19289
20534
  }),
20535
+ // The uncertainty budgets (register W5 — the GUM plane's language side)
20536
+ defineConstruct({
20537
+ keyword: "uncertainty_budget",
20538
+ field: "uncertaintyBudgets",
20539
+ takesID: true,
20540
+ parse: parseUncertaintyBudget,
20541
+ dump: dumpUncertaintyBudget
20542
+ }),
19290
20543
  // Corpus-level source-discrepancy records (TODO.roadmap/54 — gap 13's
19291
20544
  // corpus-level extension of the source_discrepancy facet)
19292
20545
  defineConstruct({
@@ -19575,7 +20828,45 @@ var CONSTRUCTS = [
19575
20828
  // Primmel v3.2 consumption constructs (TODO.primmel/11; MN 114 clause
19576
20829
  // 10.6): the top-level applicability dimension (one grammar with the
19577
20830
  // instrument's inline dimension blocks, two placements).
19578
- dimensionConstruct
20831
+ dimensionConstruct,
20832
+ // ── the LML-aligned substrate (TODO.lang-gaps; Annex F) ─────────
20833
+ defineConstruct({
20834
+ keyword: "mapping",
20835
+ field: "wireMappings",
20836
+ takesID: true,
20837
+ takesFormat: true,
20838
+ parse: parseWireMapping,
20839
+ dump: dumpWireMapping
20840
+ }),
20841
+ defineConstruct({
20842
+ keyword: "string_format",
20843
+ field: "stringFormats",
20844
+ takesID: true,
20845
+ parse: parseStringFormat,
20846
+ dump: dumpStringFormat
20847
+ }),
20848
+ defineConstruct({
20849
+ keyword: "namespace",
20850
+ field: "namespaces",
20851
+ takesID: true,
20852
+ parse: parseNamespace,
20853
+ dump: dumpNamespace
20854
+ }),
20855
+ defineConstruct({
20856
+ keyword: "datum",
20857
+ field: "datums",
20858
+ takesID: true,
20859
+ optionalTypedId: true,
20860
+ parse: parseDatum,
20861
+ dump: dumpDatum
20862
+ }),
20863
+ defineConstruct({
20864
+ keyword: "check",
20865
+ field: "checks",
20866
+ takesID: true,
20867
+ parse: parseCheck,
20868
+ dump: dumpCheck
20869
+ })
19579
20870
  ];
19580
20871
  function buildParserConfig(constructs) {
19581
20872
  const out = {};
@@ -19585,6 +20876,8 @@ function buildParserConfig(constructs) {
19585
20876
  }
19586
20877
  const entry = {
19587
20878
  takesID: c.takesID,
20879
+ takesFormat: c.takesFormat,
20880
+ optionalTypedId: c.optionalTypedId,
19588
20881
  parse: c.parse,
19589
20882
  field: c.field,
19590
20883
  ...c.deprecated ? { deprecated: c.deprecated } : {}
@@ -19811,6 +21104,9 @@ function loadPackageInternal(dir, options = {}, withProvenance = false) {
19811
21104
  return composePackage(dir, options, manifest, withProvenance);
19812
21105
  }
19813
21106
  const parseOptions = withProvenance ? { ...options, withProvenance: true } : options;
21107
+ if (manifest?.language) {
21108
+ parseOptions.strict = true;
21109
+ }
19814
21110
  const ctx = parse(joinChunks(chunks), PARSER_CONFIG, parseOptions);
19815
21111
  if (manifest) {
19816
21112
  ctx.packageManifest = manifest;
@@ -19894,6 +21190,11 @@ var MERGE_FIELDS = [
19894
21190
  "calculations",
19895
21191
  "verdicts",
19896
21192
  "referenceMaterials",
21193
+ "wireMappings",
21194
+ "stringFormats",
21195
+ "namespaces",
21196
+ "datums",
21197
+ "checks",
19897
21198
  "testPointSets",
19898
21199
  "commonTestConditions",
19899
21200
  "competenceKinds",
@@ -19903,6 +21204,7 @@ var MERGE_FIELDS = [
19903
21204
  "schemeActivityKinds",
19904
21205
  "schemeTypes",
19905
21206
  "constraints",
21207
+ "uncertaintyBudgets",
19906
21208
  "discrepancyRecords",
19907
21209
  "stateMachines",
19908
21210
  "conformanceTests",
@@ -20134,7 +21436,12 @@ function composePackage(rootDir, options, rootManifest, withProvenance = false)
20134
21436
  const ctxs = /* @__PURE__ */ new Map();
20135
21437
  const pkgChunks = /* @__PURE__ */ new Map();
20136
21438
  for (const id of order) {
20137
- const parsed = parsePackageContent(dirs.get(id), parseOptions);
21439
+ const pkgOptions = { ...parseOptions };
21440
+ const pkgManifest = manifests.get(id);
21441
+ if (pkgManifest?.language) {
21442
+ pkgOptions.strict = true;
21443
+ }
21444
+ const parsed = parsePackageContent(dirs.get(id), pkgOptions);
20138
21445
  ctxs.set(id, parsed.ctx);
20139
21446
  pkgChunks.set(id, parsed.chunks);
20140
21447
  }
@@ -20233,7 +21540,21 @@ function composePackage(rootDir, options, rootManifest, withProvenance = false)
20233
21540
  for (const id of order) {
20234
21541
  const m = manifests.get(id);
20235
21542
  for (const req of m.requires ?? []) {
20236
- const satisfied = order.some(
21543
+ const at = req.indexOf(":");
21544
+ const scoped = at > 0 ? { pkg: req.slice(0, at), token: req.slice(at + 1) } : null;
21545
+ let scopedProvides = null;
21546
+ if (scoped && !order.includes(scoped.pkg)) {
21547
+ try {
21548
+ const dir = locate(scoped.pkg);
21549
+ if (dir) {
21550
+ const rm = readPackageManifest(dir);
21551
+ scopedProvides = rm.provides ?? [];
21552
+ manifests.set(scoped.pkg, rm);
21553
+ }
21554
+ } catch {
21555
+ }
21556
+ }
21557
+ const satisfied = scoped ? order.includes(scoped.pkg) ? (manifests.get(scoped.pkg).provides ?? []).includes(scoped.token) : (scopedProvides ?? []).includes(scoped.token) : order.some(
20237
21558
  (other) => other !== id && (other === req || (manifests.get(other).provides ?? []).includes(req))
20238
21559
  );
20239
21560
  if (!satisfied) {
@@ -22042,6 +23363,176 @@ var CHECK_RULES = [
22042
23363
  "normal",
22043
23364
  "the MMEL v2 validation parity (the rename contract \u2014 TODO.editor/41)"
22044
23365
  ),
23366
+ // ── the LML-aligned substrate (TODO.lang-gaps; the spec's validation
23367
+ // contract, language-v3 §16) ── The five constructs (mapping /
23368
+ // string_format / namespace / datum / check) carry their declared
23369
+ // data; the checker does the discipline. C163 is the release
23370
+ // classification contract — it runs over `primmel diff --exit-code`
23371
+ // (the existing diff classifier, src/model-diff.ts), so its catalog
23372
+ // entry documents the contract the CLI already enforces; no second
23373
+ // implementation lives here. C165/C166 are RESERVED for the
23374
+ // calculation math plane (the formula identifier bindings and the
23375
+ // Plurimath-conformant parse) — catalogued, not faked.
23376
+ R(
23377
+ "C158",
23378
+ "prose-quarantine",
23379
+ "base",
23380
+ "error",
23381
+ "normal",
23382
+ "the LML-aligned validation contract (language-v3 \xA716; TODO.lang-gaps)"
23383
+ ),
23384
+ R(
23385
+ "C159",
23386
+ "urn-only-refs",
23387
+ "base",
23388
+ "error",
23389
+ "normal",
23390
+ "the LML-aligned validation contract (language-v3 \xA716; TODO.lang-gaps)"
23391
+ ),
23392
+ R(
23393
+ "C160",
23394
+ "signature-closure",
23395
+ "base",
23396
+ "error",
23397
+ "normal",
23398
+ "the LML-aligned validation contract (language-v3 \xA716; TODO.lang-gaps)"
23399
+ ),
23400
+ R(
23401
+ "C161",
23402
+ "check-surface",
23403
+ "base",
23404
+ "error",
23405
+ "normal",
23406
+ "the LML-aligned validation contract (language-v3 \xA716; TODO.lang-gaps)"
23407
+ ),
23408
+ R(
23409
+ "C162",
23410
+ "namespace-coherence",
23411
+ "base",
23412
+ "error",
23413
+ "normal",
23414
+ "the LML-aligned validation contract (language-v3 \xA716; TODO.lang-gaps)"
23415
+ ),
23416
+ R(
23417
+ "C163",
23418
+ "change-levels",
23419
+ "base",
23420
+ "error",
23421
+ "normal",
23422
+ "the LML-aligned validation contract (language-v3 \xA716) \u2014 runs over `primmel diff --exit-code` (src/model-diff.ts, the diff classifier)"
23423
+ ),
23424
+ R(
23425
+ "C164",
23426
+ "wire-mapping-coverage",
23427
+ "base",
23428
+ "error",
23429
+ "normal",
23430
+ "the LML-aligned validation contract (language-v3 \xA716; TODO.lang-gaps)"
23431
+ ),
23432
+ R(
23433
+ "C165",
23434
+ "math-symbols-declared",
23435
+ "quantities",
23436
+ "warning",
23437
+ "normal",
23438
+ "RESERVED for the calculation math plane (language-v3 \xA716) \u2014 the formula identifier bindings"
23439
+ ),
23440
+ R(
23441
+ "C166",
23442
+ "math-parses",
23443
+ "quantities",
23444
+ "warning",
23445
+ "normal",
23446
+ "RESERVED for the calculation math plane (language-v3 \xA716) \u2014 the Plurimath-conformant parse (plurimath-ts)"
23447
+ ),
23448
+ R(
23449
+ "C167",
23450
+ "qualified-unit-reference",
23451
+ "quantities",
23452
+ "error",
23453
+ "normal",
23454
+ "the LML-aligned validation contract (language-v3 \xA716; TODO.lang-gaps)"
23455
+ ),
23456
+ R(
23457
+ "C168",
23458
+ "method-ref-resolves",
23459
+ "process",
23460
+ "error",
23461
+ "normal",
23462
+ "a conformance test method_ref names a process to be realized \u2014 bare in-package, or scoped <package>:<id> resolved read-only through the locator; never a bibliographic standard id"
23463
+ ),
23464
+ R(
23465
+ "C169",
23466
+ "provenance-clause-resolves",
23467
+ "base",
23468
+ "error",
23469
+ "normal",
23470
+ "a provenance binding citing a shipped document lands on a real fragment or sentence of that document \u2014 nothing linked to air"
23471
+ ),
23472
+ R(
23473
+ "C170",
23474
+ "edition-lineage-declared",
23475
+ "base",
23476
+ "error",
23477
+ "normal",
23478
+ "a package declaring more than one edition carries edition-mapping.json (primmel-edition-mapping/1) naming both edition states \u2014 the cross-edition linkage is an artifact, never implicit"
23479
+ ),
23480
+ R(
23481
+ "C171",
23482
+ "expression-identifiers-resolve",
23483
+ "base",
23484
+ "error",
23485
+ "normal",
23486
+ "every identifier inside a limit expression, derivation, or derive resolves to a declared name in scope \u2014 the formula is the executable core, nothing in it is air"
23487
+ ),
23488
+ R(
23489
+ "C172",
23490
+ "requirement-algebra-resolves",
23491
+ "base",
23492
+ "error",
23493
+ "normal",
23494
+ "containment is conjunction; a requirement class limit (the law) names its contained members with the OCL booleans \u2014 and/or/xor/implies \u2014 and every member appears in the law"
23495
+ ),
23496
+ R(
23497
+ "C176",
23498
+ "language-declared-wellformed",
23499
+ "base",
23500
+ "error",
23501
+ "normal",
23502
+ "a declared language generation is well-formed (v<major>[.<minor>]); the declaration makes the package parse strictly \u2014 unknown keywords are errors"
23503
+ ),
23504
+ R(
23505
+ "C179",
23506
+ "uncertainty-budget-resolves",
23507
+ "base",
23508
+ "error",
23509
+ "normal",
23510
+ "an uncertainty budget targets a declared verdict; a Type A component names a declared captured series, a Type B component states its distribution and half-width; the coverage factor is a positive number"
23511
+ ),
23512
+ R(
23513
+ "C173",
23514
+ "step-plane-refs-resolve",
23515
+ "process",
23516
+ "error",
23517
+ "normal",
23518
+ "a signature step's completion is one expression over the step's own declared ios; the calls bindings resolve the callee's declared signature; the dot-descent process:step.io resolves to a declared io"
23519
+ ),
23520
+ R(
23521
+ "C177",
23522
+ "kind-coherence",
23523
+ "base",
23524
+ "error",
23525
+ "normal",
23526
+ "a comparison in an inline expression sets operands of the same declared quantity kind \u2014 the kinds from the args' declared sources; unknown-kind and bare-number operands never conflict"
23527
+ ),
23528
+ R(
23529
+ "C178",
23530
+ "legacy-carrier-deprecated",
23531
+ "base",
23532
+ "warning",
23533
+ "normal",
23534
+ "a package declaring the deprecation generation carries quoted ocl{\u2026} expression carriers \u2014 the inline blocks (expression { \u2026 }, derive { \u2026 }, derivation { \u2026 }, check { \u2026 }) are the only forward form"
23535
+ ),
22045
23536
  // ── mapping (TODO.roadmap/04) ─────────────────────────────────────
22046
23537
  R(
22047
23538
  "C21",
@@ -23525,6 +25016,22 @@ var EMPTY = {
23525
25016
  textCoverageBudgetReason: null,
23526
25017
  entries: []
23527
25018
  };
25019
+ function issueElementId(message) {
25020
+ const m = message.match(/^[a-z_]+ ([^:\s][^:]*):/);
25021
+ return m ? m[1] : "";
25022
+ }
25023
+ function entryMatches(entry, issue) {
25024
+ if (issue.check !== entry.rule) {
25025
+ return false;
25026
+ }
25027
+ if (!globMatch(entry.match, issue.message)) {
25028
+ return false;
25029
+ }
25030
+ if (entry.id !== void 0) {
25031
+ return globMatch(entry.id, issueElementId(issue.message));
25032
+ }
25033
+ return true;
25034
+ }
23528
25035
  function globMatch(glob, text) {
23529
25036
  const re = new RegExp(
23530
25037
  "^" + glob.split("*").map(escapeRegExp).join("[\\s\\S]*") + "$"
@@ -23624,6 +25131,8 @@ function parseEntry2(block) {
23624
25131
  entry.rule = value;
23625
25132
  } else if (key === "match") {
23626
25133
  entry.match = value;
25134
+ } else if (key === "id") {
25135
+ entry.id = value;
23627
25136
  } else if (key === "reason") {
23628
25137
  entry.reason = value;
23629
25138
  } else if (key === "audit_ref") {
@@ -23642,6 +25151,13 @@ function validateEntry(entry) {
23642
25151
  message: `${ALLOWLIST_FILENAME}: entry${label} names ${entry.rule ? `unknown rule "${entry.rule}"` : "no rule"} \u2014 every allowlist entry names a real rule id (allowlist-malformed)`
23643
25152
  });
23644
25153
  }
25154
+ if (entry.id !== void 0 && entry.id === "") {
25155
+ issues.push({
25156
+ check: "C56",
25157
+ severity: "error",
25158
+ message: `${ALLOWLIST_FILENAME}: entry for rule "${entry.rule}" has an empty id glob \u2014 the structured key pins the element identity or is absent (allowlist-malformed)`
25159
+ });
25160
+ }
23645
25161
  if (!entry.match) {
23646
25162
  issues.push({
23647
25163
  check: "C56",
@@ -23677,7 +25193,7 @@ function applyAllowlist(issues, allowlist, activeRules) {
23677
25193
  }
23678
25194
  let matched = false;
23679
25195
  for (const issue of out) {
23680
- if (issue.check === entry.rule && globMatch(entry.match, issue.message)) {
25196
+ if (entryMatches(entry, issue)) {
23681
25197
  issue.known = true;
23682
25198
  matched = true;
23683
25199
  }
@@ -23742,7 +25258,7 @@ function applyProviderAllowlists(issues, providers, activeRules) {
23742
25258
  }
23743
25259
  let matched = false;
23744
25260
  for (const issue of out) {
23745
- if (!issue.known && issue.check === entry.rule && globMatch(entry.match, issue.message)) {
25261
+ if (!issue.known && entryMatches(entry, issue)) {
23746
25262
  issue.known = true;
23747
25263
  matched = true;
23748
25264
  }
@@ -24081,6 +25597,40 @@ function computeTextCoverage(standard, manifests, config) {
24081
25597
  }
24082
25598
  const documents = [];
24083
25599
  const matchedAllowanceSentences = /* @__PURE__ */ new Map();
25600
+ for (const manifest of manifests) {
25601
+ const urn = manifest.document.urn;
25602
+ const fragments = /* @__PURE__ */ new Set();
25603
+ const addresses = /* @__PURE__ */ new Set();
25604
+ for (const s of manifest.sentences) {
25605
+ fragments.add(s.fragment);
25606
+ addresses.add(s.address);
25607
+ }
25608
+ for (const b of bindings) {
25609
+ if (b.doc !== urn) {
25610
+ continue;
25611
+ }
25612
+ if (fragments.has(b.fragmentPath) || addresses.has(b.fragmentPath)) {
25613
+ continue;
25614
+ }
25615
+ const prefix = b.fragmentPath + ".";
25616
+ let resolved = false;
25617
+ for (const f of fragments) {
25618
+ if (f.startsWith(prefix) || b.fragmentPath.startsWith(f + "/")) {
25619
+ resolved = true;
25620
+ break;
25621
+ }
25622
+ }
25623
+ if (resolved) {
25624
+ continue;
25625
+ }
25626
+ const subpart = /^(table|figure|annex)-/.test(b.fragmentPath);
25627
+ configIssues.push({
25628
+ check: "C169",
25629
+ severity: subpart ? "warning" : "error",
25630
+ message: `provenance binding ${b.doc}#${b.fragmentPath} (${b.element}, ${b.kind}) names no fragment or sentence of the shipped document \u2014 ${subpart ? "a bare subpart citation the clause-only harvest cannot verify" : "linked to air"} (provenance-clause-resolves)`
25631
+ });
25632
+ }
25633
+ }
24084
25634
  for (const manifest of manifests) {
24085
25635
  const urn = manifest.document.urn;
24086
25636
  const sentences = manifest.sentences;
@@ -24479,6 +26029,7 @@ function checkPackage(dir, options = {}) {
24479
26029
  issues.push(...checkDimensions(standard));
24480
26030
  issues.push(...checkReferences(standard));
24481
26031
  issues.push(...checkVerdictChains(standard));
26032
+ issues.push(...checkLmlAligned(standard));
24482
26033
  issues.push(...checkClosedDerivations(standard));
24483
26034
  issues.push(...checkAttestations(standard));
24484
26035
  issues.push(...checkTypedPayloads(standard));
@@ -24563,9 +26114,12 @@ function checkPackage(dir, options = {}) {
24563
26114
  };
24564
26115
  (form.fields ?? []).forEach(checkField);
24565
26116
  }
26117
+ const classIds = new Set(
26118
+ (standard.requirementClasses ?? []).map((rc) => rc.id)
26119
+ );
24566
26120
  for (const t of standard.conformanceTests ?? []) {
24567
26121
  for (const target of t.targets ?? []) {
24568
- if (!reqIds.has(target)) {
26122
+ if (!reqIds.has(target) && !classIds.has(target)) {
24569
26123
  err(
24570
26124
  "C2",
24571
26125
  `conformance test ${t.id}: target "${target}" is not a declared requirement`
@@ -24722,9 +26276,19 @@ function checkPackage(dir, options = {}) {
24722
26276
  }
24723
26277
  }
24724
26278
  const covered = /* @__PURE__ */ new Set();
26279
+ const classMembers = /* @__PURE__ */ new Map();
26280
+ for (const rc of standard.requirementClasses ?? []) {
26281
+ classMembers.set(rc.id, rc.members ?? []);
26282
+ }
26283
+ const coverWithMembers = (id) => {
26284
+ covered.add(id);
26285
+ for (const m of classMembers.get(id) ?? []) {
26286
+ covered.add(m);
26287
+ }
26288
+ };
24725
26289
  for (const t of standard.conformanceTests ?? []) {
24726
26290
  for (const target of t.targets ?? []) {
24727
- covered.add(target);
26291
+ coverWithMembers(target);
24728
26292
  }
24729
26293
  }
24730
26294
  const provisioned = /* @__PURE__ */ new Set();
@@ -24763,6 +26327,1003 @@ function checkPackage(dir, options = {}) {
24763
26327
  warn("C5", `conformance test ${t.id}: targets no requirement`);
24764
26328
  }
24765
26329
  }
26330
+ const OCL_WORDS = /* @__PURE__ */ new Set([
26331
+ "and",
26332
+ "or",
26333
+ "not",
26334
+ "xor",
26335
+ "implies",
26336
+ "if",
26337
+ "then",
26338
+ "else",
26339
+ "endif",
26340
+ "true",
26341
+ "false",
26342
+ "null",
26343
+ "invalid",
26344
+ "abs",
26345
+ "max",
26346
+ "min",
26347
+ "floor",
26348
+ "ceil",
26349
+ "mod",
26350
+ "div",
26351
+ "round",
26352
+ "sqrt",
26353
+ "exp",
26354
+ "ln",
26355
+ "log",
26356
+ "sum",
26357
+ "count",
26358
+ "exists",
26359
+ "forall",
26360
+ "oclIsUndefined",
26361
+ "oclIsKindOf",
26362
+ "oclIsTypeOf",
26363
+ "String",
26364
+ "Integer",
26365
+ "Real",
26366
+ "Boolean",
26367
+ "Set",
26368
+ "Bag",
26369
+ "Sequence",
26370
+ "Collection",
26371
+ // the subject-chain roots: every expression reads the dispatch
26372
+ // context through them — context, never air
26373
+ "sample",
26374
+ "family",
26375
+ "group",
26376
+ "model",
26377
+ "instrument",
26378
+ "specimen",
26379
+ "max_of",
26380
+ "min_of",
26381
+ "mean_of",
26382
+ "stddev_of",
26383
+ "count_of"
26384
+ ]);
26385
+ const globalExprNames = new Set(
26386
+ [
26387
+ ...(standard.symbols ?? []).map((s) => s.id),
26388
+ ...(standard.symbols ?? []).map((s) => s.id.split("/").pop() ?? ""),
26389
+ ...(standard.datums ?? []).map((d) => d.id),
26390
+ ...(standard.verdicts ?? []).map((v) => v.id),
26391
+ // the lookup tables: a dotted helper call's OBJECT is declared here —
26392
+ // the method name rides the declared object
26393
+ ...(standard.tables ?? []).map((v) => v.id),
26394
+ // the subject anatomy: a declared attribute is a declaration
26395
+ ...(standard.attributeDefinitions ?? []).map((a) => a.id),
26396
+ ...(standard.attributeDefinitions ?? []).map(
26397
+ (a) => a.id.split("/").pop() ?? ""
26398
+ ),
26399
+ // the calculations: a derivation may call a declared calculation
26400
+ // (twin-cert's lookupMPE) — the callable registry
26401
+ ...(standard.calculations ?? []).map((c) => c.id),
26402
+ ...(standard.calculations ?? []).map((c) => c.id.split("/").pop() ?? "")
26403
+ ].filter((x) => x !== "")
26404
+ );
26405
+ const symbolKinds = /* @__PURE__ */ new Map();
26406
+ for (const s of standard.symbols ?? []) {
26407
+ if (s.quantityKind) {
26408
+ symbolKinds.set(s.id, s.quantityKind);
26409
+ symbolKinds.set(s.id.split("/").pop() ?? "", s.quantityKind);
26410
+ }
26411
+ }
26412
+ const attributeKinds = /* @__PURE__ */ new Map();
26413
+ for (const a of standard.attributeDefinitions ?? []) {
26414
+ if (a.quantityKind) {
26415
+ attributeKinds.set(a.id, a.quantityKind);
26416
+ attributeKinds.set(
26417
+ a.id.split("/").pop() ?? "",
26418
+ a.quantityKind
26419
+ );
26420
+ }
26421
+ }
26422
+ const verdictKinds = /* @__PURE__ */ new Map();
26423
+ for (const v of standard.verdicts ?? []) {
26424
+ if (v.quantityKind) {
26425
+ verdictKinds.set(v.id, v.quantityKind);
26426
+ }
26427
+ }
26428
+ const tableColumnTypes = /* @__PURE__ */ new Map();
26429
+ for (const t of standard.tables ?? []) {
26430
+ const cols = /* @__PURE__ */ new Map();
26431
+ for (const c of t.columnDefs ?? []) {
26432
+ cols.set(c.name, (c.type || "").toLowerCase());
26433
+ }
26434
+ if (cols.size > 0) {
26435
+ tableColumnTypes.set(t.id, cols);
26436
+ }
26437
+ }
26438
+ const bare = (q) => q.split(":").pop() ?? q;
26439
+ const usesCovers = (uses, id) => uses.some((u) => {
26440
+ const tail = bare(u.replace(/\./g, ":"));
26441
+ return u === id || tail === id || u.endsWith("." + id);
26442
+ });
26443
+ const exprIds = (expr) => {
26444
+ const paths = expr.match(/[A-Za-z_][A-Za-z0-9_]*(?:\.[A-Za-z_][A-Za-z0-9_]*)*/g) ?? [];
26445
+ const out = [];
26446
+ const seen = /* @__PURE__ */ new Set();
26447
+ for (const p of paths) {
26448
+ if (p.includes(".")) {
26449
+ const segs = p.split(".");
26450
+ if (globalExprNames.has(segs[0])) {
26451
+ continue;
26452
+ }
26453
+ const finalSeg = segs[segs.length - 1];
26454
+ if (!seen.has(p)) {
26455
+ seen.add(p);
26456
+ if (!OCL_WORDS.has(finalSeg)) {
26457
+ out.push(finalSeg);
26458
+ }
26459
+ }
26460
+ continue;
26461
+ }
26462
+ if (!OCL_WORDS.has(p) && !seen.has(p)) {
26463
+ seen.add(p);
26464
+ out.push(p);
26465
+ }
26466
+ }
26467
+ return out;
26468
+ };
26469
+ const unresolvedIn = (expr, scope, uses) => {
26470
+ const scopeSet = /* @__PURE__ */ new Set([...scope, ...globalExprNames]);
26471
+ const seen = /* @__PURE__ */ new Set();
26472
+ const out = [];
26473
+ for (const id of exprIds(expr)) {
26474
+ if (seen.has(id)) {
26475
+ continue;
26476
+ }
26477
+ seen.add(id);
26478
+ if (OCL_WORDS.has(id) || scopeSet.has(id) || usesCovers(uses, id)) {
26479
+ continue;
26480
+ }
26481
+ out.push(id);
26482
+ }
26483
+ return out;
26484
+ };
26485
+ const mappedCalcIds = /* @__PURE__ */ new Set();
26486
+ {
26487
+ const mapsTo = standard.packageManifest?.mapsTo ?? [];
26488
+ for (const target of mapsTo) {
26489
+ if (!options.resolvePackage) {
26490
+ continue;
26491
+ }
26492
+ try {
26493
+ const depDir = options.resolvePackage(target);
26494
+ if (!depDir) {
26495
+ continue;
26496
+ }
26497
+ const dep = loadPackageWithIssues(depDir);
26498
+ for (const c of dep.standard?.calculations ?? []) {
26499
+ mappedCalcIds.add(c.id);
26500
+ mappedCalcIds.add(c.id.split("/").pop() ?? "");
26501
+ }
26502
+ } catch {
26503
+ }
26504
+ }
26505
+ for (const x of mappedCalcIds) {
26506
+ if (x !== "") {
26507
+ globalExprNames.add(x);
26508
+ }
26509
+ }
26510
+ }
26511
+ const INLINE_FUNCTION_WORDS = /* @__PURE__ */ new Set([
26512
+ "abs",
26513
+ "max",
26514
+ "min",
26515
+ "floor",
26516
+ "ceil",
26517
+ "round",
26518
+ "sqrt",
26519
+ "exp",
26520
+ "ln",
26521
+ "log",
26522
+ "mod",
26523
+ "sum",
26524
+ "count",
26525
+ "exists",
26526
+ "forall",
26527
+ // the series aggregations (register W4): the GUM type A vocabulary —
26528
+ // the statistics of a captured series; the evaluation is plurimath's
26529
+ "max_of",
26530
+ "min_of",
26531
+ "mean_of",
26532
+ "stddev_of",
26533
+ "count_of"
26534
+ ]);
26535
+ const DECLARATION_KINDS = /* @__PURE__ */ new Set([
26536
+ "symbol",
26537
+ "table",
26538
+ "datum",
26539
+ "verdict",
26540
+ "attribute",
26541
+ "process"
26542
+ ]);
26543
+ const CONTEXT_ROOTS = /* @__PURE__ */ new Set([
26544
+ "sample",
26545
+ "family",
26546
+ "group",
26547
+ "model",
26548
+ "instrument",
26549
+ "specimen"
26550
+ ]);
26551
+ const checkInlineLimit = (ownerKind, ownerId, limit, memberScope) => {
26552
+ let ast;
26553
+ try {
26554
+ ast = parseExpression(limit.expression);
26555
+ } catch (e) {
26556
+ err(
26557
+ "C171",
26558
+ `${ownerKind} ${ownerId}: the inline limit expression does not parse \u2014 ${String(e.message ?? e)} (expression-identifiers-resolve)`
26559
+ );
26560
+ return;
26561
+ }
26562
+ const ids = freeIdentifiers(ast);
26563
+ const args2 = limit.args ?? [];
26564
+ const argNames = new Set(args2.map((a) => a.name));
26565
+ if (memberScope === null && args2.length === 0 && ids.names.some((n) => !n.includes("."))) {
26566
+ err(
26567
+ "C171",
26568
+ `${ownerKind} ${ownerId}: the inline limit declares no arguments \u2014 every identifier must bind explicitly, args { name <- <declaration> } (expression-identifiers-resolve)`
26569
+ );
26570
+ }
26571
+ for (const call of new Set(ids.calls)) {
26572
+ if (INLINE_FUNCTION_WORDS.has(call)) {
26573
+ continue;
26574
+ }
26575
+ if (globalExprNames.has(call)) {
26576
+ continue;
26577
+ }
26578
+ if (call.includes(".")) {
26579
+ const root = call.split(".")[0];
26580
+ if (argNames.has(root) || globalExprNames.has(root) || root === "self" || CONTEXT_ROOTS.has(root)) {
26581
+ continue;
26582
+ }
26583
+ }
26584
+ if (argNames.has(call)) {
26585
+ continue;
26586
+ }
26587
+ err(
26588
+ "C171",
26589
+ `${ownerKind} ${ownerId}: the limit calls "${call}(\u2026)", which no argument binds and which is not in the expression function vocabulary (abs max min floor ceil round sqrt exp ln log mod sum count exists forall) \u2014 air inside the formula (expression-identifiers-resolve)`
26590
+ );
26591
+ }
26592
+ for (const id of new Set(ids.names)) {
26593
+ const root = id.split(".")[0];
26594
+ if (id.includes(".") && (root === "self" || argNames.has(root) || CONTEXT_ROOTS.has(root))) {
26595
+ continue;
26596
+ }
26597
+ if (argNames.has(id)) {
26598
+ continue;
26599
+ }
26600
+ if (memberScope !== null && memberScope.has(id)) {
26601
+ continue;
26602
+ }
26603
+ const lawScoped = memberScope !== null;
26604
+ const fix = lawScoped ? "the law composes the containment only \u2014 its identifiers are the members" : "add args { " + id + " <- <declaration> } or remove it";
26605
+ err(
26606
+ lawScoped ? "C172" : "C171",
26607
+ `${ownerKind} ${ownerId}: the limit expression names "${id}", which no argument binds \u2014 ${fix} (${lawScoped ? "requirement-algebra-resolves" : "expression-identifiers-resolve"})`
26608
+ );
26609
+ }
26610
+ for (const a of args2) {
26611
+ if (a.source.includes(":")) {
26612
+ const segs = a.source.split(":");
26613
+ if (segs.some((s) => s.length === 0)) {
26614
+ err(
26615
+ "C171",
26616
+ `${ownerKind} ${ownerId}: argument "${a.name}" binds to "${a.source}" \u2014 a binding is <kind>:<id> in this package or <package>:<kind>:<id> across a uses edge (expression-identifiers-resolve)`
26617
+ );
26618
+ continue;
26619
+ }
26620
+ if (segs.length === 2) {
26621
+ const [kind, id] = segs;
26622
+ if (kind === "process") {
26623
+ const segs2 = id.split(".");
26624
+ const proc = (standard.processes ?? []).find(
26625
+ (pp) => pp.id === segs2[0]
26626
+ );
26627
+ if (!proc) {
26628
+ err(
26629
+ "C171",
26630
+ `${ownerKind} ${ownerId}: argument "${a.name}" binds to "${a.source}", which no declared process names \u2014 air inside the formula (expression-identifiers-resolve)`
26631
+ );
26632
+ } else if (segs2.length >= 2) {
26633
+ const stp = (proc.steps ?? []).find((ss) => ss.id === segs2[1]);
26634
+ if (!stp) {
26635
+ err(
26636
+ "C171",
26637
+ `${ownerKind} ${ownerId}: argument "${a.name}" binds to "${a.source}" \u2014 the process declares no step "${segs2[1]}" (expression-identifiers-resolve)`
26638
+ );
26639
+ } else if (segs2.length >= 3) {
26640
+ const io = segs2.slice(2).join(".");
26641
+ if (!(stp.sigInputs ?? []).includes(io) && !(stp.sigOutputs ?? []).includes(io)) {
26642
+ err(
26643
+ "C171",
26644
+ `${ownerKind} ${ownerId}: argument "${a.name}" binds to "${a.source}" \u2014 the step declares no io "${io}" (expression-identifiers-resolve)`
26645
+ );
26646
+ }
26647
+ }
26648
+ }
26649
+ continue;
26650
+ }
26651
+ if (kind !== "observable") {
26652
+ if (!DECLARATION_KINDS.has(kind)) {
26653
+ err(
26654
+ "C171",
26655
+ `${ownerKind} ${ownerId}: argument "${a.name}" binds to "${a.source}" \u2014 "${kind}" is not a declaration kind (symbol table datum verdict attribute observable) (expression-identifiers-resolve)`
26656
+ );
26657
+ continue;
26658
+ }
26659
+ const idRoot = id.split(".")[0];
26660
+ const idTail = id.split(".").pop() ?? id;
26661
+ if (!globalExprNames.has(id) && !globalExprNames.has(idRoot) && !globalExprNames.has(idTail)) {
26662
+ err(
26663
+ "C171",
26664
+ `${ownerKind} ${ownerId}: argument "${a.name}" binds to "${a.source}", which no declared ${kind} names \u2014 air inside the formula (expression-identifiers-resolve)`
26665
+ );
26666
+ }
26667
+ }
26668
+ continue;
26669
+ }
26670
+ continue;
26671
+ }
26672
+ if (a.source === "self" || a.source.startsWith("self.")) {
26673
+ continue;
26674
+ }
26675
+ const bare2 = (q) => q.split(":").pop() ?? q;
26676
+ const sourceBare = bare2(a.source.replace(/\./g, ":"));
26677
+ if (memberScope !== null) {
26678
+ if (!memberScope.has(a.source) && !memberScope.has(sourceBare)) {
26679
+ err(
26680
+ "C172",
26681
+ `requirement class ${ownerId}: the law binds "${a.name}" to "${a.source}", which is not a contained member (requirement-algebra-resolves)`
26682
+ );
26683
+ }
26684
+ continue;
26685
+ }
26686
+ if (!globalExprNames.has(a.source) && !globalExprNames.has(sourceBare) && !usesCovers(limit.uses, sourceBare)) {
26687
+ err(
26688
+ "C171",
26689
+ `${ownerKind} ${ownerId}: argument "${a.name}" binds to "${a.source}", which no symbol, datum, verdict, attribute, or uses entry declares \u2014 air inside the formula (expression-identifiers-resolve)`
26690
+ );
26691
+ }
26692
+ }
26693
+ const kindLabel = (k) => k === void 0 ? "an operand of unknown kind" : k === "TEXT" ? "text" : k === null ? "a bare number" : `the "${k}" quantity`;
26694
+ const argKindOf = (source) => {
26695
+ if (source.includes(":")) {
26696
+ const segs = source.split(":");
26697
+ if (segs.length !== 2) {
26698
+ return void 0;
26699
+ }
26700
+ const [kind, id] = segs;
26701
+ if (kind === "symbol") {
26702
+ return symbolKinds.get(id.split(".").pop() ?? id);
26703
+ }
26704
+ if (kind === "attribute") {
26705
+ return attributeKinds.get(id.split(".").pop() ?? id);
26706
+ }
26707
+ if (kind === "verdict") {
26708
+ return verdictKinds.get(id.split(".")[0]);
26709
+ }
26710
+ if (kind === "table") {
26711
+ const segs2 = id.split(".");
26712
+ const colType = segs2.length === 2 ? tableColumnTypes.get(segs2[0])?.get(segs2[1]) : void 0;
26713
+ return colType === "string" ? "TEXT" : void 0;
26714
+ }
26715
+ return void 0;
26716
+ }
26717
+ if (source === "self" || source.startsWith("self.")) {
26718
+ return void 0;
26719
+ }
26720
+ return symbolKinds.get(source) ?? attributeKinds.get(source) ?? void 0;
26721
+ };
26722
+ const kindConflicts = /* @__PURE__ */ new Set();
26723
+ const kindMixErr = (node, l, r) => {
26724
+ const key = renderExpression(node);
26725
+ if (kindConflicts.has(key)) {
26726
+ return;
26727
+ }
26728
+ kindConflicts.add(key);
26729
+ err(
26730
+ "C177",
26731
+ `${ownerKind} ${ownerId}: ${kindLabel(l)} is set against ${kindLabel(r)} in "${renderExpression(node)}" \u2014 the operands must share the quantity kind (kind-coherence)`
26732
+ );
26733
+ };
26734
+ const kindOf = (node) => {
26735
+ switch (node.type) {
26736
+ case "num":
26737
+ return null;
26738
+ case "str":
26739
+ return null;
26740
+ case "bool":
26741
+ return null;
26742
+ case "ifelse": {
26743
+ kindOf(node.cond);
26744
+ const l = kindOf(node.then);
26745
+ const r = kindOf(node.else);
26746
+ if (l !== void 0 && r !== void 0 && l !== null && r !== null && l !== r) {
26747
+ kindMixErr(node, l, r);
26748
+ }
26749
+ return l !== void 0 && l !== null ? l : r;
26750
+ }
26751
+ case "name": {
26752
+ const root = node.path[0];
26753
+ if (node.path.length > 1 && (root === "self" || CONTEXT_ROOTS.has(root))) {
26754
+ return void 0;
26755
+ }
26756
+ const arg = args2.find((a) => a.name === root);
26757
+ return arg ? argKindOf(arg.source) : void 0;
26758
+ }
26759
+ case "call": {
26760
+ if (node.callee.includes(".")) {
26761
+ return void 0;
26762
+ }
26763
+ const kinded = [
26764
+ "abs",
26765
+ "max",
26766
+ "min",
26767
+ "floor",
26768
+ "ceil",
26769
+ "round",
26770
+ "sqrt",
26771
+ "exp",
26772
+ "ln",
26773
+ "log",
26774
+ "mod"
26775
+ ];
26776
+ if (!kinded.includes(node.callee)) {
26777
+ return null;
26778
+ }
26779
+ let acc = void 0;
26780
+ for (const a of node.args) {
26781
+ const k = kindOf(a);
26782
+ if (k === void 0) {
26783
+ continue;
26784
+ }
26785
+ if (acc === void 0 || acc === null) {
26786
+ acc = k;
26787
+ continue;
26788
+ }
26789
+ if (k !== void 0 && k !== null && k !== acc) {
26790
+ kindMixErr(node, acc, k);
26791
+ }
26792
+ }
26793
+ return acc;
26794
+ }
26795
+ case "unop":
26796
+ return node.op === "not" ? null : kindOf(node.operand);
26797
+ case "nav":
26798
+ return node.op === "select" ? void 0 : node.op === "collect" ? kindOf(node.body) : null;
26799
+ case "binop": {
26800
+ if (["<=", ">=", "<", ">", "=", "!=", "\u2260"].includes(node.op)) {
26801
+ const l2 = kindOf(node.left);
26802
+ const r2 = kindOf(node.right);
26803
+ if (l2 !== void 0 && r2 !== void 0 && l2 !== null && r2 !== null && l2 !== r2) {
26804
+ kindMixErr(node, l2, r2);
26805
+ }
26806
+ return null;
26807
+ }
26808
+ if (["and", "or", "xor", "implies"].includes(node.op)) {
26809
+ kindOf(node.left);
26810
+ kindOf(node.right);
26811
+ return null;
26812
+ }
26813
+ const l = kindOf(node.left);
26814
+ const r = kindOf(node.right);
26815
+ if (l !== void 0 && r !== void 0 && l !== null && r !== null && l !== r) {
26816
+ kindMixErr(node, l, r);
26817
+ }
26818
+ return l !== void 0 && l !== null ? l : r;
26819
+ }
26820
+ }
26821
+ };
26822
+ kindOf(ast);
26823
+ };
26824
+ for (const r of standard.requirements ?? []) {
26825
+ if (r.limit?.argsBound) {
26826
+ checkInlineLimit("requirement", r.id, r.limit, null);
26827
+ continue;
26828
+ }
26829
+ const expr = r.limit?.expression;
26830
+ if (!expr) {
26831
+ continue;
26832
+ }
26833
+ const ocl = expr.replace(/^ocl\{/, "").replace(/\}$/, "");
26834
+ const uses = r.limit?.uses ?? [];
26835
+ for (const id of unresolvedIn(ocl, [], uses)) {
26836
+ err(
26837
+ "C171",
26838
+ `requirement ${r.id}: the limit expression names "${id}", which no uses entry, symbol, datum, or verdict declares \u2014 air inside the formula (expression-identifiers-resolve)`
26839
+ );
26840
+ }
26841
+ }
26842
+ const resolveInlineCarrier = (ownerKind, ownerId, what, src, scope) => {
26843
+ let ast;
26844
+ try {
26845
+ ast = parseExpression(src);
26846
+ } catch (e) {
26847
+ err(
26848
+ "C171",
26849
+ `${ownerKind} ${ownerId}: the ${what} does not parse \u2014 ${String(e.message ?? e)} (expression-identifiers-resolve)`
26850
+ );
26851
+ return;
26852
+ }
26853
+ const ids = freeIdentifiers(ast);
26854
+ for (const call of new Set(ids.calls)) {
26855
+ if (INLINE_FUNCTION_WORDS.has(call)) {
26856
+ continue;
26857
+ }
26858
+ if (call.includes(".")) {
26859
+ const root = call.split(".")[0];
26860
+ if (scope.has(root) || globalExprNames.has(root) || root === "self" || CONTEXT_ROOTS.has(root)) {
26861
+ continue;
26862
+ }
26863
+ }
26864
+ if (scope.has(call) || globalExprNames.has(call)) {
26865
+ continue;
26866
+ }
26867
+ err(
26868
+ "C171",
26869
+ `${ownerKind} ${ownerId}: the ${what} calls "${call}(\u2026)", which nothing declares and which is not in the expression function vocabulary \u2014 air inside the formula (expression-identifiers-resolve)`
26870
+ );
26871
+ }
26872
+ for (const id of new Set(ids.names)) {
26873
+ const root = id.split(".")[0];
26874
+ if (id.includes(".") && (scope.has(root) || root === "self" || CONTEXT_ROOTS.has(root))) {
26875
+ continue;
26876
+ }
26877
+ if (scope.has(id)) {
26878
+ continue;
26879
+ }
26880
+ if (globalExprNames.has(id) || globalExprNames.has(id.split(".").pop() ?? id)) {
26881
+ continue;
26882
+ }
26883
+ err(
26884
+ "C171",
26885
+ `${ownerKind} ${ownerId}: the ${what} names "${id}", which nothing in scope declares \u2014 air inside the formula (expression-identifiers-resolve)`
26886
+ );
26887
+ }
26888
+ };
26889
+ for (const v of standard.verdicts ?? []) {
26890
+ const expr = v.derive;
26891
+ if (!expr) {
26892
+ continue;
26893
+ }
26894
+ const inputs = v.inputs ?? [];
26895
+ if (v.deriveBound) {
26896
+ resolveInlineCarrier("verdict", v.id, "derive", expr, new Set(inputs));
26897
+ continue;
26898
+ }
26899
+ const ocl = expr.replace(/^ocl\{/, "").replace(/\}$/, "");
26900
+ for (const id of unresolvedIn(ocl, inputs, [])) {
26901
+ err(
26902
+ "C171",
26903
+ `verdict ${v.id}: the derive expression names "${id}", which no input declares \u2014 air inside the formula (expression-identifiers-resolve)`
26904
+ );
26905
+ }
26906
+ }
26907
+ for (const t of standard.conformanceTests ?? []) {
26908
+ const scope = (t.variables ?? []).map((v) => v.name);
26909
+ for (const v of t.variables ?? []) {
26910
+ if (!v.derivation) {
26911
+ continue;
26912
+ }
26913
+ if (v.derivationBound) {
26914
+ resolveInlineCarrier(
26915
+ "conformance test",
26916
+ t.id,
26917
+ `variable ${v.name}'s derivation`,
26918
+ v.derivation,
26919
+ new Set(scope)
26920
+ );
26921
+ continue;
26922
+ }
26923
+ const ocl = v.derivation.replace(/^ocl\{/, "").replace(/\}$/, "");
26924
+ for (const id of unresolvedIn(ocl, scope, [])) {
26925
+ err(
26926
+ "C171",
26927
+ `conformance test ${t.id}: variable ${v.name}'s derivation names "${id}", which no sibling variable, symbol, datum, or verdict declares \u2014 air inside the formula (expression-identifiers-resolve)`
26928
+ );
26929
+ }
26930
+ }
26931
+ }
26932
+ for (const c of standard.constraints ?? []) {
26933
+ if (!c.checkBound || !c.check) {
26934
+ continue;
26935
+ }
26936
+ const cArgs = c.args ?? [];
26937
+ const cScope = new Set(cArgs.map((a) => a.name));
26938
+ for (const a of cArgs) {
26939
+ if (a.source.includes(":")) {
26940
+ const segs = a.source.split(":");
26941
+ if (segs.length === 2 && segs[0] !== "observable") {
26942
+ const [kind, id] = segs;
26943
+ if (!DECLARATION_KINDS.has(kind)) {
26944
+ err(
26945
+ "C171",
26946
+ `constraint ${c.id}: argument "${a.name}" binds to "${a.source}" \u2014 "${kind}" is not a declaration kind (expression-identifiers-resolve)`
26947
+ );
26948
+ } else {
26949
+ const idRoot = id.split(".")[0];
26950
+ const idTail = id.split(".").pop() ?? id;
26951
+ if (!globalExprNames.has(id) && !globalExprNames.has(idRoot) && !globalExprNames.has(idTail)) {
26952
+ err(
26953
+ "C171",
26954
+ `constraint ${c.id}: argument "${a.name}" binds to "${a.source}", which no declared ${kind} names \u2014 air inside the formula (expression-identifiers-resolve)`
26955
+ );
26956
+ }
26957
+ }
26958
+ }
26959
+ continue;
26960
+ }
26961
+ if (a.source === "self" || a.source.startsWith("self.")) {
26962
+ continue;
26963
+ }
26964
+ const bare2 = a.source.split(":").pop() ?? a.source;
26965
+ if (!globalExprNames.has(a.source) && !globalExprNames.has(bare2)) {
26966
+ err(
26967
+ "C171",
26968
+ `constraint ${c.id}: argument "${a.name}" binds to "${a.source}", which nothing declares \u2014 air inside the formula (expression-identifiers-resolve)`
26969
+ );
26970
+ }
26971
+ }
26972
+ resolveInlineCarrier("constraint", c.id, "check", c.check, cScope);
26973
+ try {
26974
+ const ast = parseExpression(c.check);
26975
+ const booleanTop = ast.type === "binop" && [
26976
+ "<=",
26977
+ ">=",
26978
+ "<",
26979
+ ">",
26980
+ "=",
26981
+ "!=",
26982
+ "\u2260",
26983
+ "and",
26984
+ "or",
26985
+ "xor",
26986
+ "implies"
26987
+ ].includes(ast.op) || ast.type === "nav" && ["forAll", "exists"].includes(ast.op);
26988
+ if (!booleanTop) {
26989
+ err(
26990
+ "C84",
26991
+ `constraint ${c.id}: the check does not evaluate to a boolean \u2014 an invariant is one comparison or logical composition (constraint-shape)`
26992
+ );
26993
+ }
26994
+ } catch {
26995
+ }
26996
+ }
26997
+ const memberSet = /* @__PURE__ */ new Map();
26998
+ for (const rc of standard.requirementClasses ?? []) {
26999
+ memberSet.set(rc.id, new Set((rc.members ?? []).map(String)));
27000
+ }
27001
+ for (const rc of standard.requirementClasses ?? []) {
27002
+ const law = rc.limit?.expression;
27003
+ const members = memberSet.get(rc.id) ?? /* @__PURE__ */ new Set();
27004
+ if (!law) {
27005
+ continue;
27006
+ }
27007
+ if (rc.limit?.argsBound) {
27008
+ checkInlineLimit("requirement class", rc.id, rc.limit, members);
27009
+ const covered2 = /* @__PURE__ */ new Set();
27010
+ try {
27011
+ for (const n of freeIdentifiers(parseExpression(law)).names) {
27012
+ covered2.add(n);
27013
+ }
27014
+ } catch {
27015
+ }
27016
+ for (const a of rc.limit.args ?? []) {
27017
+ covered2.add(a.name);
27018
+ covered2.add(a.source);
27019
+ }
27020
+ for (const m of members) {
27021
+ if (!covered2.has(m)) {
27022
+ warn(
27023
+ "C172",
27024
+ `requirement class ${rc.id}: member ${m} does not appear in the law \u2014 either it is always-required (add it with \`and\`) or it is orphaned (requirement-algebra-resolves)`
27025
+ );
27026
+ }
27027
+ }
27028
+ continue;
27029
+ }
27030
+ const ocl = law.replace(/^ocl\{/, "").replace(/\}$/, "");
27031
+ const ids = (ocl.match(/[A-Za-z_][A-Za-z0-9_]*/g) ?? []).filter(
27032
+ (x) => !OCL_WORDS.has(x)
27033
+ );
27034
+ const lawIds = /* @__PURE__ */ new Set();
27035
+ for (const id of ids) {
27036
+ lawIds.add(id);
27037
+ if (!members.has(id)) {
27038
+ err(
27039
+ "C172",
27040
+ `requirement class ${rc.id}: the law names "${id}", which is not a contained member \u2014 the algebra composes the containment only (requirement-algebra-resolves)`
27041
+ );
27042
+ }
27043
+ }
27044
+ for (const m of members) {
27045
+ if (!lawIds.has(m)) {
27046
+ warn(
27047
+ "C172",
27048
+ `requirement class ${rc.id}: member ${m} does not appear in the law \u2014 either it is always-required (add it with \`and\`) or it is orphaned (requirement-algebra-resolves)`
27049
+ );
27050
+ }
27051
+ }
27052
+ }
27053
+ const DEPRECATION_GENERATION = "v3.4";
27054
+ const generationRank = (g) => {
27055
+ const m = g.match(/^v(\d+)(?:\.(\d+))?$/);
27056
+ if (!m) {
27057
+ return -1;
27058
+ }
27059
+ return Number(m[1]) * 1e3 + Number(m[2] ?? "0");
27060
+ };
27061
+ try {
27062
+ const mf = readPackageManifest(dir);
27063
+ if (mf.language !== void 0) {
27064
+ if (!/^v\d+(\.\d+)?$/.test(mf.language)) {
27065
+ err(
27066
+ "C176",
27067
+ `the declared language "${mf.language}" is not a generation (v<major>[.<minor>]) (language-declared-wellformed)`
27068
+ );
27069
+ } else if (generationRank(mf.language) >= generationRank(DEPRECATION_GENERATION)) {
27070
+ let legacy = 0;
27071
+ for (const r of standard.requirements ?? []) {
27072
+ if (r.limit && !r.limit.argsBound && r.limit.expression) {
27073
+ legacy += 1;
27074
+ }
27075
+ }
27076
+ for (const v of standard.verdicts ?? []) {
27077
+ if (v.derive && !v.deriveBound) {
27078
+ legacy += 1;
27079
+ }
27080
+ }
27081
+ for (const t of standard.conformanceTests ?? []) {
27082
+ for (const v of t.variables ?? []) {
27083
+ if (v.derivation && !v.derivationBound) {
27084
+ legacy += 1;
27085
+ }
27086
+ }
27087
+ for (const p of t.preconditions ?? []) {
27088
+ if (p.check && !p.checkBound) {
27089
+ legacy += 1;
27090
+ }
27091
+ }
27092
+ }
27093
+ for (const c of standard.constraints ?? []) {
27094
+ if (c.check && !c.checkBound) {
27095
+ legacy += 1;
27096
+ }
27097
+ }
27098
+ if (legacy > 0) {
27099
+ warn(
27100
+ "C178",
27101
+ `${legacy} quoted expression carrier${legacy === 1 ? "" : "s"} \u2014 the ocl{\u2026} string form is deprecated as of ${DEPRECATION_GENERATION}; migrate to the inline blocks (expression { \u2026 }, derive { \u2026 }, derivation { \u2026 }, check { \u2026 }) (legacy-carrier-deprecated)`
27102
+ );
27103
+ }
27104
+ }
27105
+ }
27106
+ } catch {
27107
+ }
27108
+ {
27109
+ const seriesVariables = /* @__PURE__ */ new Map();
27110
+ for (const t of standard.conformanceTests ?? []) {
27111
+ for (const v of t.variables ?? []) {
27112
+ seriesVariables.set(v.name, v.series !== null);
27113
+ }
27114
+ }
27115
+ for (const b of standard.uncertaintyBudgets ?? []) {
27116
+ if (!b.target) {
27117
+ err(
27118
+ "C179",
27119
+ `uncertainty_budget ${b.id}: declares no target \u2014 the budget backs a declared verdict's measured quantity (uncertainty-budget-resolves)`
27120
+ );
27121
+ } else if (!(standard.verdicts ?? []).some((v) => v.id === b.target)) {
27122
+ err(
27123
+ "C179",
27124
+ `uncertainty_budget ${b.id}: target "${b.target}" is not a declared verdict \u2014 the budget backs a measured quantity the verdicts own (uncertainty-budget-resolves)`
27125
+ );
27126
+ }
27127
+ if (b.components.length === 0) {
27128
+ warn(
27129
+ "C179",
27130
+ `uncertainty_budget ${b.id}: declares no components \u2014 an empty budget states no uncertainty (uncertainty-budget-resolves)`
27131
+ );
27132
+ }
27133
+ if (b.coverageK && !(Number(b.coverageK) > 0)) {
27134
+ err(
27135
+ "C179",
27136
+ `uncertainty_budget ${b.id}: coverage k "${b.coverageK}" is not a positive number (uncertainty-budget-resolves)`
27137
+ );
27138
+ }
27139
+ for (const c of b.components) {
27140
+ if (c.type === "A") {
27141
+ if (!c.series) {
27142
+ err(
27143
+ "C179",
27144
+ `uncertainty_budget ${b.id}: component ${c.id} is Type A but names no series \u2014 the statistics compute from a declared captured series (uncertainty-budget-resolves)`
27145
+ );
27146
+ } else if (!seriesVariables.has(c.series)) {
27147
+ err(
27148
+ "C179",
27149
+ `uncertainty_budget ${b.id}: component ${c.id}'s series "${c.series}" is not a declared test variable (uncertainty-budget-resolves)`
27150
+ );
27151
+ } else if (!seriesVariables.get(c.series)) {
27152
+ err(
27153
+ "C179",
27154
+ `uncertainty_budget ${b.id}: component ${c.id}'s series "${c.series}" declares no series shape \u2014 a Type A evaluation needs the captured series' axes and cell (uncertainty-budget-resolves)`
27155
+ );
27156
+ }
27157
+ } else {
27158
+ if (!c.distribution) {
27159
+ err(
27160
+ "C179",
27161
+ `uncertainty_budget ${b.id}: component ${c.id} is Type B but states no distribution (uncertainty-budget-resolves)`
27162
+ );
27163
+ }
27164
+ if (!c.halfWidth) {
27165
+ err(
27166
+ "C179",
27167
+ `uncertainty_budget ${b.id}: component ${c.id} is Type B but states no half_width \u2014 the distribution spans a half-width (uncertainty-budget-resolves)`
27168
+ );
27169
+ }
27170
+ }
27171
+ }
27172
+ }
27173
+ }
27174
+ for (const p of standard.processes ?? []) {
27175
+ for (const st of p.steps ?? []) {
27176
+ if (!st.completion) {
27177
+ continue;
27178
+ }
27179
+ const ios = /* @__PURE__ */ new Set([...st.sigInputs, ...st.sigOutputs]);
27180
+ let ids;
27181
+ try {
27182
+ ids = freeIdentifiers(
27183
+ parseExpression(
27184
+ st.completion.replace(/^ocl\{/, "").replace(/\}$/, "")
27185
+ )
27186
+ );
27187
+ } catch (e) {
27188
+ err(
27189
+ "C173",
27190
+ `process ${p.id}: step "${st.id}" completion does not parse \u2014 ${String(e.message ?? e)} \u2014 the completion is one expression over the step's ios (step-plane-refs-resolve)`
27191
+ );
27192
+ continue;
27193
+ }
27194
+ for (const call of new Set(ids.calls)) {
27195
+ if (!INLINE_FUNCTION_WORDS.has(call)) {
27196
+ err(
27197
+ "C173",
27198
+ `process ${p.id}: step "${st.id}" completion calls "${call}(\u2026)", which is not in the expression function vocabulary (step-plane-refs-resolve)`
27199
+ );
27200
+ }
27201
+ }
27202
+ for (const id of new Set(ids.names)) {
27203
+ const root = id.split(".")[0];
27204
+ if (id.includes(".") && (root === "self" || CONTEXT_ROOTS.has(root))) {
27205
+ continue;
27206
+ }
27207
+ if (ios.has(id) || ios.has(root)) {
27208
+ continue;
27209
+ }
27210
+ err(
27211
+ "C173",
27212
+ `process ${p.id}: step "${st.id}" completion names "${id}", which is not a declared io of the step \u2014 the completion reads the step's own inputs and outputs (step-plane-refs-resolve)`
27213
+ );
27214
+ }
27215
+ }
27216
+ }
27217
+ try {
27218
+ const mf = readPackageManifest(dir);
27219
+ const eds = (mf.editions ?? []).map(String);
27220
+ if (eds.length > 1) {
27221
+ const map = JSON.parse(
27222
+ readFileSync5(join4(dir, "edition-mapping.json"), "utf8")
27223
+ );
27224
+ if (map.kind !== "primmel-edition-mapping/1") {
27225
+ err(
27226
+ "C170",
27227
+ `edition-mapping.json: kind "${String(map.kind)}" is not primmel-edition-mapping/1 (edition-lineage-declared)`
27228
+ );
27229
+ } else {
27230
+ const fromEd = map.from?.edition === void 0 ? void 0 : String(map.from.edition);
27231
+ const toEd = map.to?.edition === void 0 ? void 0 : String(map.to.edition);
27232
+ for (const [side, ed] of [
27233
+ ["from", fromEd],
27234
+ ["to", toEd]
27235
+ ]) {
27236
+ if (!ed || !eds.includes(ed)) {
27237
+ err(
27238
+ "C170",
27239
+ `edition-mapping.json: the ${side} edition ${String(ed)} is not among the manifest's declared editions [${eds.join(", ")}] (edition-lineage-declared)`
27240
+ );
27241
+ }
27242
+ }
27243
+ }
27244
+ }
27245
+ } catch (e) {
27246
+ const code = e.code;
27247
+ if (code === "ENOENT") {
27248
+ const eds = (() => {
27249
+ try {
27250
+ return (readPackageManifest(dir).editions ?? []).map(
27251
+ String
27252
+ );
27253
+ } catch {
27254
+ return [];
27255
+ }
27256
+ })();
27257
+ if (eds.length > 1) {
27258
+ err(
27259
+ "C170",
27260
+ `the package declares ${eds.length} editions [${eds.join(", ")}] but ships no edition-mapping.json \u2014 the cross-edition linkage is an artifact, never implicit (edition-lineage-declared)`
27261
+ );
27262
+ }
27263
+ } else if (e instanceof SyntaxError) {
27264
+ err(
27265
+ "C170",
27266
+ `edition-mapping.json is not valid JSON: ${e.message} (edition-lineage-declared)`
27267
+ );
27268
+ }
27269
+ }
27270
+ const methodTargetIds = (s) => /* @__PURE__ */ new Set([
27271
+ ...(s.processes ?? []).map((p) => p.id),
27272
+ ...(s.conformanceTests ?? []).map((x) => x.id)
27273
+ ]);
27274
+ const localMethodIds = methodTargetIds(standard);
27275
+ const scopedMethodIds = /* @__PURE__ */ new Map();
27276
+ const resolveCitation = (elemId, ref) => {
27277
+ const colon = ref.indexOf(":");
27278
+ if (colon <= 0) {
27279
+ if (!localMethodIds.has(ref)) {
27280
+ err(
27281
+ "C168",
27282
+ `${elemId}: the reference "${ref}" names no process or conformance test declared in this package (method-ref-resolves)`
27283
+ );
27284
+ }
27285
+ return;
27286
+ }
27287
+ if (!options.resolvePackage) {
27288
+ return;
27289
+ }
27290
+ const pkgId = ref.slice(0, colon);
27291
+ const localId = ref.slice(colon + 1);
27292
+ let ids = scopedMethodIds.get(pkgId);
27293
+ if (!ids) {
27294
+ ids = /* @__PURE__ */ new Set();
27295
+ try {
27296
+ const depDir = options.resolvePackage(pkgId);
27297
+ if (depDir) {
27298
+ const dep = loadPackageWithIssues(depDir);
27299
+ ids = methodTargetIds(dep.standard);
27300
+ }
27301
+ } catch {
27302
+ }
27303
+ scopedMethodIds.set(pkgId, ids);
27304
+ }
27305
+ if (!ids.has(localId)) {
27306
+ err(
27307
+ "C168",
27308
+ `${elemId}: the reference "${ref}" names no process or conformance test declared in package "${pkgId}" (method-ref-resolves)`
27309
+ );
27310
+ }
27311
+ };
27312
+ for (const t of standard.conformanceTests ?? []) {
27313
+ const ref = t.methodRef;
27314
+ if (ref) {
27315
+ resolveCitation(t.id, ref);
27316
+ }
27317
+ }
27318
+ for (const pr of standard.processes ?? []) {
27319
+ const raw = pr;
27320
+ for (const st of raw.steps ?? []) {
27321
+ const call = st.calls || st.signatureBlock?.match(/\bcalls +([\w:/.-]+)/)?.[1];
27322
+ if (call) {
27323
+ resolveCitation(`${pr.id}/step/${st.id ?? ""}`, call);
27324
+ }
27325
+ }
27326
+ }
24766
27327
  const ASPECT_FAMILY = {
24767
27328
  metadata: "is",
24768
27329
  provenance: "is",
@@ -25650,7 +28211,7 @@ function checkPackage(dir, options = {}) {
25650
28211
  `constraint ${c.id}: stereotype "${c.stereotype || "(none)"}" \u2014 a constraint is always \xABinv\xBB, the subject's declaration-level invariant (constraint-shape)`
25651
28212
  );
25652
28213
  }
25653
- if (!OCL_CHECK.test(c.check)) {
28214
+ if (!c.checkBound && !OCL_CHECK.test(c.check)) {
25654
28215
  err(
25655
28216
  "C84",
25656
28217
  `constraint ${c.id}: check is not one OCL boolean expression ocl{\u2026} over the subject's declared anatomy (constraint-shape)`
@@ -28745,9 +31306,9 @@ function checkPackage(dir, options = {}) {
28745
31306
  if (!dataclassByEntity.has(c.id)) {
28746
31307
  dataclassByEntity.set(c.id, c);
28747
31308
  }
28748
- const bare = c.id.includes("#") ? c.id.slice(0, c.id.indexOf("#")) : c.id;
28749
- if (!dataclassByEntity.has(bare)) {
28750
- dataclassByEntity.set(bare, c);
31309
+ const bare2 = c.id.includes("#") ? c.id.slice(0, c.id.indexOf("#")) : c.id;
31310
+ if (!dataclassByEntity.has(bare2)) {
31311
+ dataclassByEntity.set(bare2, c);
28751
31312
  }
28752
31313
  }
28753
31314
  const whereFields = (where) => {
@@ -30345,6 +32906,101 @@ function checkVerdictChains(standard) {
30345
32906
  }
30346
32907
  return issues;
30347
32908
  }
32909
+ function checkLmlAligned(standard) {
32910
+ const issues = [];
32911
+ const err = (check, message) => issues.push({ check, severity: "error", message });
32912
+ const warn = (check, message) => issues.push({ check, severity: "warning", message });
32913
+ const namespaceIds = new Set((standard.namespaces ?? []).map((n) => n.id));
32914
+ const dataclassIds = /* @__PURE__ */ new Set();
32915
+ for (const c of standard.dataclasses ?? []) {
32916
+ dataclassIds.add(c.id);
32917
+ dataclassIds.add(c.id.replace(/#data$/, ""));
32918
+ }
32919
+ const symbolIds = new Set((standard.symbols ?? []).map((s) => s.id));
32920
+ const datumIds = new Set((standard.datums ?? []).map((d) => d.id));
32921
+ const CLAUSE_CITATION = /clause-\d|§\d/i;
32922
+ for (const d of standard.datums ?? []) {
32923
+ if (!d.description) {
32924
+ continue;
32925
+ }
32926
+ if (CLAUSE_CITATION.test(d.description)) {
32927
+ err(
32928
+ "C158",
32929
+ `datum ${d.id}: the description cites a clause \u2014 a reference in prose belongs in a urn reference, not the quarantined free text (prose-quarantine)`
32930
+ );
32931
+ } else if (d.description.includes("TODO.roadmap")) {
32932
+ warn(
32933
+ "C158",
32934
+ `datum ${d.id}: the description carries the unfinished-prose marker TODO.roadmap (prose-quarantine)`
32935
+ );
32936
+ }
32937
+ }
32938
+ for (const w of standard.wireMappings ?? []) {
32939
+ if (w.namespaceRef && !namespaceIds.has(w.namespaceRef)) {
32940
+ err(
32941
+ "C159",
32942
+ `mapping ${w.id}: namespace "${w.namespaceRef}" names no declared namespace block (urn-only-refs)`
32943
+ );
32944
+ }
32945
+ }
32946
+ for (const c of standard.checks ?? []) {
32947
+ for (const inp of c.inputs ?? []) {
32948
+ if (!(datumIds.has(inp) || symbolIds.has(inp))) {
32949
+ err(
32950
+ "C160",
32951
+ `check ${c.id}: input "${inp}" resolves to no declared datum or symbol \u2014 the check consumes an undeclared name (signature-closure)`
32952
+ );
32953
+ }
32954
+ }
32955
+ }
32956
+ for (const d of standard.datums ?? []) {
32957
+ for (const r of d.renders ?? []) {
32958
+ if (!MATH_NOTATIONS.includes(r.notation)) {
32959
+ err(
32960
+ "C161",
32961
+ `datum ${d.id}: render notation "${r.notation}" is outside the closed vocabulary (${MATH_NOTATIONS.join("|")}) (check-surface)`
32962
+ );
32963
+ }
32964
+ }
32965
+ }
32966
+ const metaNamespace = standard.meta?.namespace ?? "";
32967
+ if (metaNamespace && namespaceIds.size > 0 && !namespaceIds.has(metaNamespace)) {
32968
+ err(
32969
+ "C162",
32970
+ `metadata namespace "${metaNamespace}" names no declared namespace block (namespace-coherence)`
32971
+ );
32972
+ }
32973
+ for (const w of standard.wireMappings ?? []) {
32974
+ if (!MAPPING_FORMATS.includes(w.format)) {
32975
+ err(
32976
+ "C164",
32977
+ `mapping ${w.id}: format "${w.format}" is outside the wire vocabulary (${MAPPING_FORMATS.join("|")}) (wire-mapping-coverage)`
32978
+ );
32979
+ }
32980
+ if (dataclassIds.size > 0 && !dataclassIds.has(w.target)) {
32981
+ err(
32982
+ "C164",
32983
+ `mapping ${w.id}: the class "${w.target}" is no declared dataclass \u2014 a class serialized to a format carries the declared mapping (wire-mapping-coverage)`
32984
+ );
32985
+ }
32986
+ }
32987
+ const QUALIFIED_REF = /^[a-z]+:[A-Za-z0-9_-]+$/;
32988
+ for (const d of standard.datums ?? []) {
32989
+ if (d.unit && !QUALIFIED_REF.test(d.unit)) {
32990
+ err(
32991
+ "C167",
32992
+ `datum ${d.id}: unit "${d.unit}" is bare \u2014 a unit reference uses the qualified <namespace>:<id> form (si:\u2026, unitsdb:\u2026) (qualified-unit-reference)`
32993
+ );
32994
+ }
32995
+ if (d.quantityKind && !QUALIFIED_REF.test(d.quantityKind)) {
32996
+ err(
32997
+ "C167",
32998
+ `datum ${d.id}: quantity_kind "${d.quantityKind}" is bare \u2014 a quantity-kind reference uses the qualified <namespace>:<id> form (si:\u2026, unitsdb:\u2026) (qualified-unit-reference)`
32999
+ );
33000
+ }
33001
+ }
33002
+ return issues;
33003
+ }
30348
33004
  function checkEditionLifecycle(dir, standard) {
30349
33005
  const issues = [];
30350
33006
  const err = (check, message) => issues.push({ check, severity: "error", message });
@@ -30546,6 +33202,143 @@ function findCycle(adj) {
30546
33202
  return cycle;
30547
33203
  }
30548
33204
 
33205
+ // src/fmt.ts
33206
+ import { readFileSync as readFileSync6, readdirSync as readdirSync4, statSync as statSync3, writeFileSync } from "node:fs";
33207
+ import { join as join5 } from "node:path";
33208
+
33209
+ // src/ser-des/dump.ts
33210
+ function dump(model, dumpers) {
33211
+ let out = "";
33212
+ if (model.root !== null) {
33213
+ out += "root " + model.root.id + "\n\n";
33214
+ }
33215
+ out += dumpMetadata(model.meta) + "\n";
33216
+ const childIds = /* @__PURE__ */ new Set();
33217
+ for (const p of model.processes) {
33218
+ for (const c of p.children) {
33219
+ childIds.add(c);
33220
+ }
33221
+ }
33222
+ const processMap = new Map(model.processes.map((p) => [p.id, p]));
33223
+ const memberIds = /* @__PURE__ */ new Set();
33224
+ for (const rc of model.requirementClasses ?? []) {
33225
+ for (const m of rc.members ?? []) {
33226
+ memberIds.add(m);
33227
+ }
33228
+ }
33229
+ const requirementMap = new Map(
33230
+ (model.requirements ?? []).map((r) => [r.id, r])
33231
+ );
33232
+ const classMap = new Map(
33233
+ (model.requirementClasses ?? []).map((rc) => [rc.id, rc])
33234
+ );
33235
+ const dumpersRef = dumpers;
33236
+ const dumpClassTree = (rcId) => {
33237
+ const rc = classMap.get(rcId);
33238
+ if (!rc) {
33239
+ return "";
33240
+ }
33241
+ const base = dumpersRef.requirementClasses(rc);
33242
+ if (!rc.members || rc.members.length === 0) {
33243
+ return base;
33244
+ }
33245
+ const inner = rc.members.map((m) => {
33246
+ const body = dumpersRef.requirements(requirementMap.get(m));
33247
+ return body.split("\n").filter((l) => l !== "").map((l) => " " + l).join("\n");
33248
+ }).join("\n");
33249
+ return base.slice(0, base.lastIndexOf("}")) + inner + "\n}\n";
33250
+ };
33251
+ Object.keys(dumpers).forEach((field) => {
33252
+ if (field === "processes") {
33253
+ for (const p of model.processes) {
33254
+ if (!childIds.has(p.id)) {
33255
+ out += dumpProcessTree(p, processMap);
33256
+ }
33257
+ }
33258
+ return;
33259
+ }
33260
+ if (field === "requirements") {
33261
+ for (const r of model.requirements ?? []) {
33262
+ if (!memberIds.has(r.id)) {
33263
+ out += dumpersRef.requirements(r);
33264
+ }
33265
+ }
33266
+ return;
33267
+ }
33268
+ if (field === "requirementClasses") {
33269
+ for (const rc of model.requirementClasses ?? []) {
33270
+ out += dumpClassTree(rc.id);
33271
+ }
33272
+ return;
33273
+ }
33274
+ const items = model[field];
33275
+ const dumper = dumpers[field];
33276
+ for (const item of items) {
33277
+ out += dumper(item);
33278
+ }
33279
+ });
33280
+ return out;
33281
+ }
33282
+
33283
+ // src/ser-des/index.ts
33284
+ function load(mmelString, options = {}) {
33285
+ const context = parse(mmelString, PARSER_CONFIG, options);
33286
+ return resolve(context, RESOLVER_CONFIG);
33287
+ }
33288
+ function loadFile(filePath, options = {}) {
33289
+ const content = preprocessIncludes(filePath);
33290
+ return load(content, options);
33291
+ }
33292
+ function dump2(standard) {
33293
+ return dump(standard, DUMPER_CONFIG);
33294
+ }
33295
+
33296
+ // src/fmt.ts
33297
+ var ALLOWLIST = ".primmel-allowlist.prl";
33298
+ function walkPrl(dir, out = []) {
33299
+ for (const e of readdirSync4(dir).sort()) {
33300
+ const p = join5(dir, e);
33301
+ if (statSync3(p).isDirectory()) {
33302
+ walkPrl(p, out);
33303
+ } else if (e.endsWith(".prl") && e !== ALLOWLIST) {
33304
+ out.push(p);
33305
+ }
33306
+ }
33307
+ return out;
33308
+ }
33309
+ function fmtPackage(dir, check = false) {
33310
+ const result = { dir, files: [], written: 0 };
33311
+ for (const file of walkPrl(dir)) {
33312
+ const src = readFileSync6(file, "utf8");
33313
+ if (/^\s*include\s+"/m.test(src)) {
33314
+ result.files.push({ file, status: "skipped-includes" });
33315
+ continue;
33316
+ }
33317
+ let canonical2;
33318
+ try {
33319
+ const raw = dump2(loadFile(file));
33320
+ if (dump2(load(raw)) !== raw) {
33321
+ result.files.push({ file, status: "unstable" });
33322
+ continue;
33323
+ }
33324
+ canonical2 = /^\s*metadata\s*\{/.test(src) ? raw : raw.replace(/^metadata \{\n(?: {2}\w+ ""\n)*\}\n+/, "");
33325
+ } catch {
33326
+ result.files.push({ file, status: "unstable" });
33327
+ continue;
33328
+ }
33329
+ if (canonical2 === src) {
33330
+ result.files.push({ file, status: "unchanged" });
33331
+ continue;
33332
+ }
33333
+ if (!check) {
33334
+ writeFileSync(file, canonical2);
33335
+ result.written += 1;
33336
+ }
33337
+ result.files.push({ file, status: "formatted" });
33338
+ }
33339
+ return result;
33340
+ }
33341
+
30549
33342
  // src/export/reqif.ts
30550
33343
  var REQIF_NAMESPACE = "http://www.omg.org/spec/ReqIF/20110401/reqif.xsd";
30551
33344
  var REQIF_VERSION = "1.0";
@@ -31819,23 +34612,23 @@ function renderJsonLd(prefixes, triples) {
31819
34612
 
31820
34613
  // src/export/retrieval.ts
31821
34614
  import { createHash } from "node:crypto";
31822
- import { readdirSync as readdirSync4, readFileSync as readFileSync7, statSync as statSync3 } from "node:fs";
31823
- import { join as join6, relative } from "node:path";
34615
+ import { readdirSync as readdirSync5, readFileSync as readFileSync8, statSync as statSync4 } from "node:fs";
34616
+ import { join as join7, relative } from "node:path";
31824
34617
 
31825
34618
  // src/export/unitsdb.ts
31826
- import { existsSync as existsSync6, readFileSync as readFileSync6 } from "node:fs";
31827
- import { join as join5 } from "node:path";
34619
+ import { existsSync as existsSync6, readFileSync as readFileSync7 } from "node:fs";
34620
+ import { join as join6 } from "node:path";
31828
34621
  function loadUnitsDb(dir) {
31829
34622
  if (!dir) {
31830
34623
  return null;
31831
34624
  }
31832
34625
  try {
31833
34626
  const entries = [];
31834
- const jsonPath = join5(dir, "units.json");
34627
+ const jsonPath = join6(dir, "units.json");
31835
34628
  if (!existsSync6(jsonPath)) {
31836
34629
  return null;
31837
34630
  }
31838
- const parsed = JSON.parse(readFileSync6(jsonPath, "utf8")).units;
34631
+ const parsed = JSON.parse(readFileSync7(jsonPath, "utf8")).units;
31839
34632
  if (!Array.isArray(parsed)) {
31840
34633
  return null;
31841
34634
  }
@@ -32066,12 +34859,12 @@ function retrievalDigest(value) {
32066
34859
  return createHash("sha256").update(canonicalJson(value), "utf8").digest("hex");
32067
34860
  }
32068
34861
  function* walkPackage(dir) {
32069
- for (const entry of readdirSync4(dir).sort()) {
34862
+ for (const entry of readdirSync5(dir).sort()) {
32070
34863
  if (entry === ".DS_Store") {
32071
34864
  continue;
32072
34865
  }
32073
- const p = join6(dir, entry);
32074
- if (statSync3(p).isDirectory()) {
34866
+ const p = join7(dir, entry);
34867
+ if (statSync4(p).isDirectory()) {
32075
34868
  yield* walkPackage(p);
32076
34869
  } else {
32077
34870
  yield p;
@@ -32083,7 +34876,7 @@ function packageSourceHash(dir) {
32083
34876
  for (const file of walkPackage(dir)) {
32084
34877
  h.update(relative(dir, file));
32085
34878
  h.update("\0");
32086
- h.update(createHash("sha256").update(readFileSync7(file)).digest());
34879
+ h.update(createHash("sha256").update(readFileSync8(file)).digest());
32087
34880
  h.update("\n");
32088
34881
  }
32089
34882
  return h.digest("hex");
@@ -32339,6 +35132,9 @@ function retrievalFacet(unit, pkg) {
32339
35132
  facet[`app_${dim}_match`] = match;
32340
35133
  }
32341
35134
  }
35135
+ if ((unit.method_refs ?? []).length > 0) {
35136
+ facet.method_refs = unit.method_refs.join("|");
35137
+ }
32342
35138
  return facet;
32343
35139
  }
32344
35140
  function resolveTextAddress(address, elementIds) {
@@ -32483,11 +35279,34 @@ function requirementUnit(r) {
32483
35279
  collectClauses(r)
32484
35280
  );
32485
35281
  }
35282
+ function processUnit(pr) {
35283
+ const steps = pr.steps ?? [];
35284
+ const calls = steps.map((s) => {
35285
+ const st = s;
35286
+ const call = st.calls || st.signatureBlock?.match(/\bcalls +([\w:/.-]+)/)?.[1] || "";
35287
+ return call ? { id: st.id ?? "", calls: call } : null;
35288
+ }).filter((s) => s !== null);
35289
+ return assemble(
35290
+ {
35291
+ id: pr.id,
35292
+ kind: "process",
35293
+ ...present(pr.name) ? { name: pr.name } : {},
35294
+ ...present(pr.summary) ? { statement: pr.summary } : {},
35295
+ ...calls.length > 0 ? { calls } : {}
35296
+ },
35297
+ collectClauses(pr)
35298
+ );
35299
+ }
32486
35300
  function conformanceTestUnit(t) {
32487
35301
  const payload = {
32488
35302
  ...present(t.kind) ? { test_kind: t.kind } : {},
32489
35303
  ...present(t.methodRef) ? { method_ref: t.methodRef } : {}
32490
35304
  };
35305
+ const methodRefs = [
35306
+ ...new Set(
35307
+ [t.methodRef, ...(t.requiredCompetence ?? []).map((rc) => rc.methodRef)].filter((m) => present(m)).map((m) => m)
35308
+ )
35309
+ ].sort();
32491
35310
  const decision = acceptanceDecisionOf(t.acceptance);
32492
35311
  const criteria = testAcceptanceCriteriaOf(t);
32493
35312
  return assemble(
@@ -32515,6 +35334,7 @@ function conformanceTestUnit(t) {
32515
35334
  }))
32516
35335
  } : {},
32517
35336
  ...presentList(t.dependencies) ? { dependencies: t.dependencies } : {},
35337
+ ...methodRefs.length > 0 ? { method_refs: methodRefs } : {},
32518
35338
  ...Object.keys(payload).length > 0 ? { payload } : {}
32519
35339
  },
32520
35340
  collectClauses(t)
@@ -32946,6 +35766,9 @@ function exportStandardRetrieval(standard, options = {}) {
32946
35766
  for (const t of standard.conformanceTests ?? []) {
32947
35767
  push(conformanceTestUnit(t), t.id);
32948
35768
  }
35769
+ for (const pr of standard.processes ?? []) {
35770
+ push(processUnit(pr), pr.id);
35771
+ }
32949
35772
  for (const t of standard.terms ?? []) {
32950
35773
  push(termUnit(t, pkg.base_urn), t.id);
32951
35774
  }
@@ -33256,8 +36079,8 @@ function exportPackageImpact(dir) {
33256
36079
  }
33257
36080
 
33258
36081
  // src/export/cddal.ts
33259
- import { readFileSync as readFileSync8, readdirSync as readdirSync5 } from "node:fs";
33260
- import { basename, join as join7, resolve as resolve5 } from "node:path";
36082
+ import { readFileSync as readFileSync9, readdirSync as readdirSync6 } from "node:fs";
36083
+ import { basename, join as join8, resolve as resolve5 } from "node:path";
33261
36084
  var CDDAL_PROJECTION_VERSION = "primmel-cddal/1";
33262
36085
  function escapeCddalString(s) {
33263
36086
  return s.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
@@ -33403,23 +36226,23 @@ function projectCddal(model, packageId, l10n = /* @__PURE__ */ new Map()) {
33403
36226
  }
33404
36227
  function exportPackageCddal(dir) {
33405
36228
  const model = loadPackage(dir);
33406
- const l10nFiles = readdirSync5(dir).filter((e) => /^l10n\.[^/]+\.prl$/.test(e)).map((e) => join7(dir, e));
33407
- const l10n = readL10n(l10nFiles, (p) => readFileSync8(p, "utf8"));
36229
+ const l10nFiles = readdirSync6(dir).filter((e) => /^l10n\.[^/]+\.prl$/.test(e)).map((e) => join8(dir, e));
36230
+ const l10n = readL10n(l10nFiles, (p) => readFileSync9(p, "utf8"));
33408
36231
  return projectCddal(model, basename(resolve5(dir)), l10n);
33409
36232
  }
33410
36233
 
33411
36234
  // src/package-diff.ts
33412
- import { existsSync as existsSync7, readdirSync as readdirSync6, readFileSync as readFileSync9 } from "fs";
33413
- import { join as join8 } from "path";
36235
+ import { existsSync as existsSync7, readdirSync as readdirSync7, readFileSync as readFileSync10 } from "fs";
36236
+ import { join as join9 } from "path";
33414
36237
  function packageMappings(dir, standard) {
33415
36238
  const profiles = [...standard.mapProfiles ?? []];
33416
36239
  if (existsSync7(dir)) {
33417
- for (const entry of readdirSync6(dir).sort()) {
36240
+ for (const entry of readdirSync7(dir).sort()) {
33418
36241
  if (!entry.endsWith(".prm")) {
33419
36242
  continue;
33420
36243
  }
33421
36244
  profiles.push(
33422
- ...prmToMapProfiles(loadPrm(readFileSync9(join8(dir, entry), "utf8")))
36245
+ ...prmToMapProfiles(loadPrm(readFileSync10(join9(dir, entry), "utf8")))
33423
36246
  );
33424
36247
  }
33425
36248
  }
@@ -33428,17 +36251,17 @@ function packageMappings(dir, standard) {
33428
36251
  }
33429
36252
  function packageClauseTexts(dir) {
33430
36253
  const out = /* @__PURE__ */ new Map();
33431
- const prdDir = join8(dir, "sources-prd");
36254
+ const prdDir = join9(dir, "sources-prd");
33432
36255
  if (!existsSync7(prdDir)) {
33433
36256
  return out;
33434
36257
  }
33435
- for (const entry of readdirSync6(prdDir).sort()) {
36258
+ for (const entry of readdirSync7(prdDir).sort()) {
33436
36259
  if (!entry.endsWith(".sentences.json")) {
33437
36260
  continue;
33438
36261
  }
33439
36262
  let payload;
33440
36263
  try {
33441
- payload = JSON.parse(readFileSync9(join8(prdDir, entry), "utf8"));
36264
+ payload = JSON.parse(readFileSync10(join9(prdDir, entry), "utf8"));
33442
36265
  } catch {
33443
36266
  continue;
33444
36267
  }
@@ -33491,15 +36314,15 @@ var DIFF_USAGE = "Usage: primmel diff [--json] [--exit-code] [--compare-texts] [
33491
36314
  var EXPORT_USAGE = "Usage: primmel export reqif|rdf|retrieval|impact|cddal <package-dir> [--out <file>] [--format turtle|jsonld]";
33492
36315
  function readablePackageDirProblem(target, needsManifest) {
33493
36316
  try {
33494
- if (!statSync4(target).isDirectory()) {
36317
+ if (!statSync5(target).isDirectory()) {
33495
36318
  return "not a directory";
33496
36319
  }
33497
- readdirSync7(target);
36320
+ readdirSync8(target);
33498
36321
  } catch (e) {
33499
36322
  const err = e;
33500
36323
  return err.code === "ENOENT" ? "no such directory" : err.message;
33501
36324
  }
33502
- if (needsManifest && !existsSync8(join9(target, "package.primmel"))) {
36325
+ if (needsManifest && !existsSync8(join10(target, "package.primmel"))) {
33503
36326
  return "no package.primmel found";
33504
36327
  }
33505
36328
  return null;
@@ -33725,7 +36548,7 @@ function exportCli(args2) {
33725
36548
  const out = values.get("--out");
33726
36549
  if (out !== void 0) {
33727
36550
  try {
33728
- writeFileSync(out, document);
36551
+ writeFileSync2(out, document);
33729
36552
  } catch (e) {
33730
36553
  console.error(`cannot write ${out}: ${e.message}`);
33731
36554
  process.exit(1);
@@ -33736,6 +36559,32 @@ function exportCli(args2) {
33736
36559
  }
33737
36560
  process.exit(0);
33738
36561
  }
36562
+ function fmtCli(argv) {
36563
+ const check = argv.includes("--check");
36564
+ const rest = argv.filter((a) => a !== "--check");
36565
+ const dir = rest[rest.length - 1];
36566
+ if (!dir || !existsSync8(dir)) {
36567
+ console.error(`cannot read package at ${dir || "(none)"}: no such directory`);
36568
+ process.exit(2);
36569
+ }
36570
+ let result;
36571
+ try {
36572
+ result = fmtPackage(dir, check);
36573
+ } catch (e) {
36574
+ console.error(`cannot format package at ${dir}: ${e.message}`);
36575
+ process.exit(2);
36576
+ }
36577
+ for (const f of result.files) {
36578
+ const label = f.file.startsWith(dir + "/") ? f.file.slice(dir.length + 1) : f.file;
36579
+ const note = f.status === "formatted" ? check ? "would reformat" : "formatted" : f.status === "unchanged" ? "ok" : f.status === "unstable" ? "UNSTABLE \u2014 does not round-trip; left as-is" : "skipped (includes)";
36580
+ console.log(` ${label}: ${note}`);
36581
+ }
36582
+ const unstable = result.files.filter((f) => f.status === "unstable").length;
36583
+ console.log(
36584
+ `fmt: ${result.files.length} files, ${check ? result.files.filter((f) => f.status === "formatted").length + " would reformat" : result.written + " written"}, ${unstable} unstable`
36585
+ );
36586
+ process.exit(unstable > 0 ? 2 : check && result.files.some((f) => f.status === "formatted") ? 1 : 0);
36587
+ }
33739
36588
  var args = process.argv.slice(2);
33740
36589
  if (args[0] === "diff") {
33741
36590
  diffCli(args.slice(1));
@@ -33743,6 +36592,12 @@ if (args[0] === "diff") {
33743
36592
  checkCli(args.slice(1));
33744
36593
  } else if (args[0] === "export") {
33745
36594
  exportCli(args.slice(1));
36595
+ } else if (args[0] === "fmt") {
36596
+ fmtCli(args.slice(1));
33746
36597
  } else {
33747
36598
  checkCli(args);
33748
36599
  }
36600
+ //! The Primmel expression language: the lexer, the precedence parser, and
36601
+ //! the AST. The machine-executable core — first-class syntax, never a
36602
+ //! quoted string. The identifiers resolve against the caller's scope (the
36603
+ //! argument bindings); the unbound names surface at parse time.