@fuaran-ui/ops 0.9.0 → 0.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { FORM_FIELD_KIND_NAMES, NODE_KIND_GROUPS, defaults, projectSelectionField, controlValueDefaults } from '@fuaran-ui/schema';
1
+ import { FORM_FIELD_KIND_NAMES, NODE_KIND_GROUPS, defaults, controlValueDefaults, MAX_NODE_DEPTH, MAX_NODES, MAX_STRING_LENGTH, MAX_JSON_DEPTH, MAX_ARRAY_LENGTH, narrows, admitAll, NODE_KIND_NAMES, admits, policyHint, projectSelectionField } from '@fuaran-ui/schema';
2
2
 
3
3
  // src/encode.ts
4
4
  var assertNever = (x) => {
@@ -78,10 +78,11 @@ var formatFiniteDouble = (n) => {
78
78
  return neg ? "-" + out : out;
79
79
  };
80
80
  var num = (n) => {
81
- if (Number.isNaN(n)) return '"NaN"';
82
- if (n === Infinity) return '"Infinity"';
83
- if (n === -Infinity) return '"-Infinity"';
84
- return formatFiniteDouble(n);
81
+ const v = Number(n);
82
+ if (Number.isNaN(v)) return '"NaN"';
83
+ if (v === Infinity) return '"Infinity"';
84
+ if (v === -Infinity) return '"-Infinity"';
85
+ return formatFiniteDouble(v);
85
86
  };
86
87
  var bool = (b) => b ? "true" : "false";
87
88
  var jObject = (fields) => {
@@ -591,6 +592,9 @@ var pushWeightOptional = (fields, w) => {
591
592
  var pushEmphasisOptional = (fields, e) => {
592
593
  if (e !== "Normal") fields.push(["emphasis", str(e)]);
593
594
  };
595
+ var pushTrendPolarityOptional = (fields, p) => {
596
+ if (p !== "HigherIsBetter") fields.push(["trendPolarity", str(p)]);
597
+ };
594
598
  var pushCellFormatOptional = (fields, key, f) => {
595
599
  if (f.kind !== "None") fields.push([key, cellFormat(f)]);
596
600
  };
@@ -608,6 +612,7 @@ var metricSpec = (s) => {
608
612
  pushEmphasisOptional(fields, s.emphasis);
609
613
  if (s.trend !== void 0) fields.push(["trend", binding(s.trend)]);
610
614
  if (s.trendFormat !== void 0) fields.push(["trendFormat", cellFormat(s.trendFormat)]);
615
+ pushTrendPolarityOptional(fields, s.trendPolarity);
611
616
  if (s.icon !== void 0) fields.push(["icon", str(s.icon)]);
612
617
  if (s.subtext !== void 0) fields.push(["subtext", textSource(s.subtext)]);
613
618
  return jObject(fields);
@@ -654,11 +659,40 @@ var linkSpec = (s) => {
654
659
  if (s.protection !== void 0) fields.push(["protection", str(s.protection)]);
655
660
  return jObject(fields);
656
661
  };
657
- var imageSpec = (s) => jObject([
658
- ["alt", textSource(s.alt)],
659
- ["src", binding(s.src)],
660
- ["variant", str(s.variant)]
662
+ var srcSetEntry = (e) => jObject([
663
+ ["src", binding(e.src)],
664
+ ["width", num(e.width)]
661
665
  ]);
666
+ var imageSpec = (s) => {
667
+ const fields = [
668
+ ["alt", textSource(s.alt)],
669
+ ["src", binding(s.src)],
670
+ ["variant", str(s.variant)]
671
+ ];
672
+ if (s.fit !== "Natural") fields.push(["fit", str(s.fit)]);
673
+ if (s.aspectRatio !== "Natural") fields.push(["aspectRatio", str(s.aspectRatio)]);
674
+ if (s.loading !== "Eager") fields.push(["loading", str(s.loading)]);
675
+ if (s.caption !== void 0) fields.push(["caption", textSource(s.caption)]);
676
+ if (s.srcSet.length > 0) fields.push(["srcSet", jArray(s.srcSet.map(srcSetEntry))]);
677
+ if (s.expandable) fields.push(["expandable", bool(true)]);
678
+ return jObject(fields);
679
+ };
680
+ var mediaKind = (k) => {
681
+ if (k.$type === "Audio") return caseObj("Audio", []);
682
+ const fields = [];
683
+ if (k.autoplay) fields.push(["autoplay", bool(true)]);
684
+ if (k.poster !== void 0) fields.push(["poster", binding(k.poster)]);
685
+ return caseObj("Video", fields);
686
+ };
687
+ var mediaSpec = (s) => {
688
+ const fields = [];
689
+ if (!s.controls) fields.push(["controls", bool(false)]);
690
+ fields.push(["kind", mediaKind(s.kind)]);
691
+ fields.push(["label", textSource(s.label)]);
692
+ if (s.loop) fields.push(["loop", bool(true)]);
693
+ fields.push(["src", binding(s.src)]);
694
+ return jObject(fields);
695
+ };
662
696
  var listSpec = (s) => jObject([
663
697
  ["items", jArray(s.items.map(textSource))],
664
698
  ["ordered", bool(s.ordered)]
@@ -867,6 +901,8 @@ var displayKind = (d) => {
867
901
  return hoistSpec("Link", linkSpec(d.spec));
868
902
  case "Image":
869
903
  return hoistSpec("Image", imageSpec(d.spec));
904
+ case "Media":
905
+ return hoistSpec("Media", mediaSpec(d.spec));
870
906
  case "List":
871
907
  return hoistSpec("List", listSpec(d.spec));
872
908
  case "Toast":
@@ -994,6 +1030,20 @@ var formFieldKind = (autoBind, k) => {
994
1030
  return assertNever(k);
995
1031
  }
996
1032
  };
1033
+ var compareRule = (c) => jObject([
1034
+ ["against", binding(c.against)],
1035
+ ["op", str(c.op)]
1036
+ ]);
1037
+ var fieldRule = (r) => {
1038
+ const fields = [];
1039
+ if (r.compare !== void 0) fields.push(["compare", compareRule(r.compare)]);
1040
+ if (r.format !== void 0) fields.push(["format", str(r.format)]);
1041
+ if (r.maxLength !== void 0) fields.push(["maxLength", intLit(r.maxLength)]);
1042
+ if (r.message !== void 0) fields.push(["message", textSource(r.message)]);
1043
+ if (r.minLength !== void 0) fields.push(["minLength", intLit(r.minLength)]);
1044
+ if (r.pattern !== void 0) fields.push(["pattern", str(r.pattern)]);
1045
+ return jObject(fields);
1046
+ };
997
1047
  var formField = (f) => {
998
1048
  const fields = [
999
1049
  ["id", str(f.id)],
@@ -1002,6 +1052,7 @@ var formField = (f) => {
1002
1052
  ["required", bool(f.required)]
1003
1053
  ];
1004
1054
  if (f.help !== void 0) fields.push(["help", textSource(f.help)]);
1055
+ if (f.rule !== void 0) fields.push(["rule", fieldRule(f.rule)]);
1005
1056
  return jObject(fields);
1006
1057
  };
1007
1058
  var formSpec = (s) => {
@@ -1269,6 +1320,11 @@ var boxLayout = (l) => {
1269
1320
  if (l.templateColumns !== void 0) fields.push(["templateColumns", str(l.templateColumns)]);
1270
1321
  return caseObj("Grid", fields);
1271
1322
  }
1323
+ case "Masonry": {
1324
+ const fields = [["cols", intLit(l.cols)]];
1325
+ if (l.gap !== void 0) fields.push(["gap", intLit(l.gap)]);
1326
+ return caseObj("Masonry", fields);
1327
+ }
1272
1328
  case "Auto":
1273
1329
  return caseObj("Auto", []);
1274
1330
  default:
@@ -2681,8 +2737,6 @@ var stepParams = (t) => {
2681
2737
  var pipelineParams = (pipeline) => [
2682
2738
  ...new Set(pipeline.flatMap((t) => stepParams(t)))
2683
2739
  ];
2684
-
2685
- // src/parse.ts
2686
2740
  var peek = (s) => s.pos < s.text.length ? s.text[s.pos] : " ";
2687
2741
  var advance = (s) => {
2688
2742
  s.pos += 1;
@@ -2697,6 +2751,10 @@ var skipWs = (s) => {
2697
2751
  }
2698
2752
  }
2699
2753
  };
2754
+ var failLimit = (s, message) => ({
2755
+ ok: false,
2756
+ error: { message, offset: s.pos, limit: true }
2757
+ });
2700
2758
  var fail = (s, message) => ({
2701
2759
  ok: false,
2702
2760
  error: { message, offset: s.pos }
@@ -2719,7 +2777,14 @@ var parseStringRaw = (s) => {
2719
2777
  advance(s);
2720
2778
  if (c === '"') {
2721
2779
  return { ok: true, value: out };
2722
- } else if (c === "\\") {
2780
+ }
2781
+ if (out.length > MAX_STRING_LENGTH) {
2782
+ return failLimit(
2783
+ s,
2784
+ `string is longer than the wire limit MAX_STRING_LENGTH = ${MAX_STRING_LENGTH}`
2785
+ );
2786
+ }
2787
+ if (c === "\\") {
2723
2788
  if (s.pos >= s.text.length) return fail(s, "unterminated escape");
2724
2789
  const esc = s.text[s.pos];
2725
2790
  advance(s);
@@ -2819,6 +2884,12 @@ var parseValue = (s) => {
2819
2884
  }
2820
2885
  };
2821
2886
  var parseObjectValue = (s) => {
2887
+ if (s.depth >= MAX_JSON_DEPTH) {
2888
+ return failLimit(
2889
+ s,
2890
+ `JSON nesting deeper than the wire limit MAX_JSON_DEPTH = ${MAX_JSON_DEPTH}`
2891
+ );
2892
+ }
2822
2893
  const open = expectChar(s, "{");
2823
2894
  if (!open.ok) return open;
2824
2895
  skipWs(s);
@@ -2827,15 +2898,34 @@ var parseObjectValue = (s) => {
2827
2898
  advance(s);
2828
2899
  return { ok: true, value: { kind: "JObject", fields } };
2829
2900
  }
2901
+ s.depth += 1;
2902
+ let count = 0;
2830
2903
  for (; ; ) {
2831
2904
  skipWs(s);
2832
2905
  const keyR = parseStringRaw(s);
2833
- if (!keyR.ok) return keyR;
2906
+ if (!keyR.ok) {
2907
+ s.depth -= 1;
2908
+ return keyR;
2909
+ }
2834
2910
  skipWs(s);
2835
2911
  const colon = expectChar(s, ":");
2836
- if (!colon.ok) return colon;
2912
+ if (!colon.ok) {
2913
+ s.depth -= 1;
2914
+ return colon;
2915
+ }
2837
2916
  const valR = parseValue(s);
2838
- if (!valR.ok) return valR;
2917
+ if (!valR.ok) {
2918
+ s.depth -= 1;
2919
+ return valR;
2920
+ }
2921
+ count += 1;
2922
+ if (count > MAX_ARRAY_LENGTH) {
2923
+ s.depth -= 1;
2924
+ return failLimit(
2925
+ s,
2926
+ `object has more members than the wire limit MAX_ARRAY_LENGTH = ${MAX_ARRAY_LENGTH}`
2927
+ );
2928
+ }
2839
2929
  fields.set(keyR.value, valR.value);
2840
2930
  skipWs(s);
2841
2931
  const c = peek(s);
@@ -2843,13 +2933,21 @@ var parseObjectValue = (s) => {
2843
2933
  advance(s);
2844
2934
  } else if (c === "}") {
2845
2935
  advance(s);
2936
+ s.depth -= 1;
2846
2937
  return { ok: true, value: { kind: "JObject", fields } };
2847
2938
  } else {
2939
+ s.depth -= 1;
2848
2940
  return fail(s, `expected ',' or '}' but found '${c}'`);
2849
2941
  }
2850
2942
  }
2851
2943
  };
2852
2944
  var parseArrayValue = (s) => {
2945
+ if (s.depth >= MAX_JSON_DEPTH) {
2946
+ return failLimit(
2947
+ s,
2948
+ `JSON nesting deeper than the wire limit MAX_JSON_DEPTH = ${MAX_JSON_DEPTH}`
2949
+ );
2950
+ }
2853
2951
  const open = expectChar(s, "[");
2854
2952
  if (!open.ok) return open;
2855
2953
  skipWs(s);
@@ -2858,24 +2956,37 @@ var parseArrayValue = (s) => {
2858
2956
  advance(s);
2859
2957
  return { ok: true, value: { kind: "JArray", items } };
2860
2958
  }
2959
+ s.depth += 1;
2861
2960
  for (; ; ) {
2862
2961
  const valR = parseValue(s);
2863
- if (!valR.ok) return valR;
2962
+ if (!valR.ok) {
2963
+ s.depth -= 1;
2964
+ return valR;
2965
+ }
2864
2966
  items.push(valR.value);
2967
+ if (items.length > MAX_ARRAY_LENGTH) {
2968
+ s.depth -= 1;
2969
+ return failLimit(
2970
+ s,
2971
+ `array is longer than the wire limit MAX_ARRAY_LENGTH = ${MAX_ARRAY_LENGTH}`
2972
+ );
2973
+ }
2865
2974
  skipWs(s);
2866
2975
  const c = peek(s);
2867
2976
  if (c === ",") {
2868
2977
  advance(s);
2869
2978
  } else if (c === "]") {
2870
2979
  advance(s);
2980
+ s.depth -= 1;
2871
2981
  return { ok: true, value: { kind: "JArray", items } };
2872
2982
  } else {
2983
+ s.depth -= 1;
2873
2984
  return fail(s, `expected ',' or ']' but found '${c}'`);
2874
2985
  }
2875
2986
  }
2876
2987
  };
2877
2988
  var parse = (input) => {
2878
- const s = { text: input, pos: 0 };
2989
+ const s = { text: input, pos: 0, depth: 0 };
2879
2990
  skipWs(s);
2880
2991
  if (s.pos >= s.text.length) {
2881
2992
  return { ok: false, error: { message: "input is empty", offset: 0 } };
@@ -2893,6 +3004,7 @@ var makeError = (code, path, message, expectedShape) => ({
2893
3004
  var missingField = (path, key, expected) => makeError("MISSING_FIELD", `${path}.${key}`, `missing required field '${key}'`, expected);
2894
3005
  var wrongType = (path, expected) => makeError("WRONG_TYPE", path, `expected ${expected}`, expected);
2895
3006
  var unknownDuCase = (path, got, expected) => makeError("UNKNOWN_DU_CASE", `${path}.$type`, `unknown discriminator '${got}'`, expected);
3007
+ var unknownEnumCase = (path, got, expected) => makeError("UNKNOWN_DU_CASE", path, `unknown discriminator '${got}'`, expected);
2896
3008
  var CLOSURE2 = "<closure>";
2897
3009
  var OPAQUE2 = "<opaque>";
2898
3010
  var requireObject = (path, j) => j.kind === "JObject" ? ok(j.fields) : wrongType(path, "JSON object");
@@ -3045,7 +3157,7 @@ var decodeJValMap = (path, j) => {
3045
3157
  var bareEnum = (path, j, valid, label) => {
3046
3158
  if (j.kind !== "JString") return wrongType(path, `JSON string (${label})`);
3047
3159
  if (valid.includes(j.value)) return ok(j.value);
3048
- return unknownDuCase(path, j.value, valid.join(" | "));
3160
+ return unknownEnumCase(path, j.value, valid.join(" | "));
3049
3161
  };
3050
3162
  var ORIENTATION_ALIASES = {
3051
3163
  // CSS flex-direction prior: a row lays out horizontally, a column vertically.
@@ -3083,6 +3195,14 @@ var decodeHeadingVariant = (p, j) => {
3083
3195
  return bareEnum(p, j, ["Standard", "Eyebrow", "Caption", "Lead"], "HeadingVariant");
3084
3196
  };
3085
3197
  var decodeImageVariant = (p, j) => bareEnum(p, j, ["Default", "Avatar", "Rounded"], "ImageVariant");
3198
+ var decodeImageFit = (p, j) => bareEnum(p, j, ["Natural", "Cover", "Contain"], "ImageFit");
3199
+ var decodeImageAspect = (p, j) => bareEnum(
3200
+ p,
3201
+ j,
3202
+ ["Natural", "Square", "FourThree", "ThreeTwo", "SixteenNine"],
3203
+ "ImageAspect"
3204
+ );
3205
+ var decodeImageLoading = (p, j) => bareEnum(p, j, ["Eager", "Lazy"], "ImageLoading");
3086
3206
  var decodeScrollOrientation = (p, j) => bareEnum(p, j, ["Vertical", "Horizontal", "Both"], "ScrollOrientation");
3087
3207
  var decodeDateVariant = (p, j) => bareEnum(p, j, ["Date", "Time", "DateTime"], "DateVariant");
3088
3208
  var decodeMathDisplay = (p, j) => bareEnum(p, j, ["Inline", "Block"], "MathDisplay");
@@ -3116,6 +3236,7 @@ var decodeWeight = (p, j) => (
3116
3236
  // Compact|Standard|Spacious means density (WIRE_FORMAT.md §3.6).
3117
3237
  bareEnum(p, j, ["Compact", "Standard", "Spacious"], "StyleWeight")
3118
3238
  );
3239
+ var decodeTrendPolarity = (p, j) => bareEnum(p, j, ["HigherIsBetter", "LowerIsBetter"], "TrendPolarity");
3119
3240
  var decodeEmphasis = (p, j) => {
3120
3241
  if (j.kind === "JString" && j.value in EMPHASIS_ALIASES) return ok(EMPHASIS_ALIASES[j.value]);
3121
3242
  if (j.kind === "JBool") return ok(j.value ? "Loud" : "Normal");
@@ -4317,29 +4438,43 @@ var decodeBinding = (path, j, parseStatic = (_p, v) => ok(decodeAstValue(v)), pl
4317
4438
  if (!pipeJ.ok) return pipeJ;
4318
4439
  const liveTagAst = srcJ.value.kind === "JObject" ? srcJ.value.fields.get("$type") : void 0;
4319
4440
  const liveTag = liveTagAst !== void 0 && liveTagAst.kind === "JString" && (liveTagAst.value === "State" || liveTagAst.value === "Selection" || liveTagAst.value === "Query") ? liveTagAst.value : void 0;
4320
- const hasCarried = srcJ.value.kind === "JObject" && srcJ.value.fields.has("defaultValue");
4321
4441
  let source;
4322
- if (liveTag === void 0 || liveTag === "State" && !hasCarried) {
4442
+ if (liveTag === void 0) {
4323
4443
  const src = decodeDataSource(normaliseTransformSource(srcJ.value));
4324
4444
  if (!src.ok) return makeError("WRONG_TYPE", `${path}.source`, src.error);
4325
4445
  source = { kind: "Data", source: src.value };
4326
4446
  } else {
4327
4447
  const b2 = decodeBinding(`${path}.source`, srcJ.value, decodeJVal, void 0);
4328
4448
  if (!b2.ok) return b2;
4449
+ const liveBinding = (() => {
4450
+ const raw = b2.value;
4451
+ const declared = srcJ.value.kind === "JObject" && srcJ.value.fields.has("defaultValue");
4452
+ return raw.kind === "State" && !declared ? { ...raw, defaultValue: void 0 } : raw;
4453
+ })();
4329
4454
  if (liveTag === "State") {
4330
- const snap = decodeDataSource(normaliseTransformSource(srcJ.value));
4331
- if (!snap.ok) return makeError("WRONG_TYPE", `${path}.source`, snap.error);
4332
- source = {
4333
- kind: "Live",
4334
- binding: b2.value,
4335
- initial: snap.value
4336
- };
4455
+ const carriedJ = srcJ.value.kind === "JObject" ? srcJ.value.fields.get("defaultValue") : void 0;
4456
+ const carriesNoData = carriedJ === void 0 || carriedJ.kind === "JArray" && carriedJ.items.length === 0;
4457
+ if (carriesNoData) {
4458
+ source = {
4459
+ kind: "Live",
4460
+ binding: liveBinding,
4461
+ initial: { kind: "Embedded", table: { schema: [], columns: [] } }
4462
+ };
4463
+ } else {
4464
+ const snap = decodeDataSource(normaliseTransformSource(srcJ.value));
4465
+ if (!snap.ok) return makeError("WRONG_TYPE", `${path}.source`, snap.error);
4466
+ source = {
4467
+ kind: "Live",
4468
+ binding: liveBinding,
4469
+ initial: snap.value
4470
+ };
4471
+ }
4337
4472
  } else {
4338
4473
  const dv = srcJ.value.kind === "JObject" ? srcJ.value.fields.get("defaultValue") : void 0;
4339
4474
  const snap = dv !== void 0 ? decodeDataSource(normaliseTransformSource(dv)) : void 0;
4340
4475
  source = {
4341
4476
  kind: "Live",
4342
- binding: b2.value,
4477
+ binding: liveBinding,
4343
4478
  initial: snap !== void 0 && snap.ok ? snap.value : { kind: "Embedded", table: { schema: [], columns: [] } }
4344
4479
  };
4345
4480
  }
@@ -4496,8 +4631,10 @@ var decodeBindingArgs = (path, j) => {
4496
4631
  }
4497
4632
  return ok(out);
4498
4633
  };
4499
- var decodeBindingString = (p, j) => decodeBinding(p, j);
4500
- var decodeBindingBool = (p, j) => decodeBinding(p, j);
4634
+ var decodeBindingString = (p, j) => decodeBinding(p, j, requireString, "");
4635
+ var decodeBindingBool = (p, j) => decodeBinding(p, j, requireBool, false);
4636
+ var decodeBindingFloat = (p, j) => decodeBinding(p, j, requireFloat, 0);
4637
+ var decodeBindingInt = (p, j) => decodeBinding(p, j, requireInt, 0);
4501
4638
  var OPTIONS_PLACEHOLDER = [
4502
4639
  { value: OPAQUE2, label: { kind: "Literal", value: OPAQUE2 } }
4503
4640
  ];
@@ -4840,7 +4977,14 @@ var decodeMetricSpec = (path, j) => {
4840
4977
  const f = fo.value;
4841
4978
  const label = reqField(path, f, "label", "Metric label TextSource", decodeTextSource);
4842
4979
  if (!label.ok) return label;
4843
- const source = reqFieldAliased(path, f, "value", ["data"], "Metric value binding", decodeBinding);
4980
+ const source = reqFieldAliased(
4981
+ path,
4982
+ f,
4983
+ "value",
4984
+ ["data"],
4985
+ "Metric value binding",
4986
+ decodeBindingFloat
4987
+ );
4844
4988
  if (!source.ok) {
4845
4989
  if (source.error.message.includes("expected JSON number")) {
4846
4990
  return {
@@ -4861,10 +5005,12 @@ var decodeMetricSpec = (path, j) => {
4861
5005
  if (!weight.ok) return weight;
4862
5006
  const emphasis = optField(path, f, "emphasis", decodeEmphasis);
4863
5007
  if (!emphasis.ok) return emphasis;
4864
- const trend = optField(path, f, "trend", decodeBinding);
5008
+ const trend = optField(path, f, "trend", decodeBindingFloat);
4865
5009
  if (!trend.ok) return trend;
4866
5010
  const trendFormat = optField(path, f, "trendFormat", decodeCellFormat);
4867
5011
  if (!trendFormat.ok) return trendFormat;
5012
+ const trendPolarity = optField(path, f, "trendPolarity", decodeTrendPolarity);
5013
+ if (!trendPolarity.ok) return trendPolarity;
4868
5014
  const icon = optField(path, f, "icon", decodeIconSource);
4869
5015
  if (!icon.ok) return icon;
4870
5016
  const subtext = optField(path, f, "subtext", decodeTextSource);
@@ -4878,6 +5024,7 @@ var decodeMetricSpec = (path, j) => {
4878
5024
  emphasis: emphasis.value ?? "Normal",
4879
5025
  ...trend.value !== void 0 ? { trend: trend.value } : {},
4880
5026
  ...trendFormat.value !== void 0 ? { trendFormat: trendFormat.value } : {},
5027
+ trendPolarity: trendPolarity.value ?? "HigherIsBetter",
4881
5028
  ...icon.value !== void 0 ? { icon: icon.value } : {},
4882
5029
  ...subtext.value !== void 0 ? { subtext: subtext.value } : {}
4883
5030
  });
@@ -4906,7 +5053,7 @@ var decodeLabelValueRowSpec = (path, j) => {
4906
5053
  "value",
4907
5054
  ["data"],
4908
5055
  "row Binding<float> value",
4909
- decodeBinding
5056
+ decodeBindingFloat
4910
5057
  );
4911
5058
  if (!source.ok) return source;
4912
5059
  const format = optField(path, f, "format", decodeCellFormat);
@@ -4995,6 +5142,23 @@ var decodeLinkSpec = (path, j) => {
4995
5142
  });
4996
5143
  };
4997
5144
  var decodeLinkProtection = (p, j) => bareEnum(p, j, ["email"], "LinkProtection");
5145
+ var decodeSrcSetEntry = (path, j) => {
5146
+ const fo = requireObject(path, j);
5147
+ if (!fo.ok) return fo;
5148
+ const src = reqField(
5149
+ path,
5150
+ fo.value,
5151
+ "src",
5152
+ "srcSet entry Binding<string> src",
5153
+ decodeBindingString
5154
+ );
5155
+ if (!src.ok) return src;
5156
+ const widthJ = tryField(fo.value, "width");
5157
+ if (widthJ === void 0) return missingField(path, "width", "positive intrinsic pixel width");
5158
+ if (widthJ.kind !== "JNumber" || widthJ.value <= 0 || !Number.isInteger(widthJ.value))
5159
+ return wrongType(`${path}.width`, "JSON number (positive integer pixel width)");
5160
+ return ok({ src: src.value, width: widthJ.value });
5161
+ };
4998
5162
  var decodeImageSpec = (path, j) => {
4999
5163
  const fo = requireObject(path, j);
5000
5164
  if (!fo.ok) return fo;
@@ -5005,7 +5169,90 @@ var decodeImageSpec = (path, j) => {
5005
5169
  if (!src.ok) return src;
5006
5170
  const variant = reqField(path, f, "variant", "ImageVariant", decodeImageVariant);
5007
5171
  if (!variant.ok) return variant;
5008
- return ok({ alt: alt.value, src: src.value, variant: variant.value });
5172
+ const fitJ = tryField(f, "fit");
5173
+ const fit = fitJ === void 0 ? ok("Natural") : decodeImageFit(`${path}.fit`, fitJ);
5174
+ if (!fit.ok) return fit;
5175
+ const aspectJ = tryField(f, "aspectRatio");
5176
+ const aspectRatio = aspectJ === void 0 ? ok("Natural") : decodeImageAspect(`${path}.aspectRatio`, aspectJ);
5177
+ if (!aspectRatio.ok) return aspectRatio;
5178
+ const loadingJ = tryField(f, "loading");
5179
+ const loading = loadingJ === void 0 ? ok("Eager") : decodeImageLoading(`${path}.loading`, loadingJ);
5180
+ if (!loading.ok) return loading;
5181
+ const caption = optField(path, f, "caption", decodeTextSource);
5182
+ if (!caption.ok) return caption;
5183
+ const srcSetJ = tryField(f, "srcSet");
5184
+ const srcSet = srcSetJ === void 0 ? ok([]) : (() => {
5185
+ const arr = requireArray(`${path}.srcSet`, srcSetJ);
5186
+ if (!arr.ok) return arr;
5187
+ return traverseIndexed(
5188
+ arr.value,
5189
+ (i, el) => decodeSrcSetEntry(`${path}.srcSet[${i}]`, el)
5190
+ );
5191
+ })();
5192
+ if (!srcSet.ok) return srcSet;
5193
+ const expandableJ = tryField(f, "expandable");
5194
+ const expandable = expandableJ === void 0 ? ok(false) : requireBool(`${path}.expandable`, expandableJ);
5195
+ if (!expandable.ok) return expandable;
5196
+ return ok({
5197
+ alt: alt.value,
5198
+ src: src.value,
5199
+ variant: variant.value,
5200
+ fit: fit.value,
5201
+ aspectRatio: aspectRatio.value,
5202
+ loading: loading.value,
5203
+ srcSet: srcSet.value,
5204
+ expandable: expandable.value,
5205
+ ...caption.value !== void 0 ? { caption: caption.value } : {}
5206
+ });
5207
+ };
5208
+ var decodeMediaKind = (path, j) => {
5209
+ const fo = requireObject(path, j);
5210
+ if (!fo.ok) return fo;
5211
+ const f = fo.value;
5212
+ const d = requireDiscriminator(path, f);
5213
+ if (!d.ok) return d;
5214
+ switch (d.value) {
5215
+ case "Video": {
5216
+ const autoplayJ = tryField(f, "autoplay");
5217
+ const autoplay = autoplayJ === void 0 ? ok(false) : requireBool(`${path}.autoplay`, autoplayJ);
5218
+ if (!autoplay.ok) return autoplay;
5219
+ const poster = optField(path, f, "poster", decodeBindingString);
5220
+ if (!poster.ok) return poster;
5221
+ return ok({
5222
+ $type: "Video",
5223
+ autoplay: autoplay.value,
5224
+ ...poster.value !== void 0 ? { poster: poster.value } : {}
5225
+ });
5226
+ }
5227
+ case "Audio":
5228
+ return ok({ $type: "Audio" });
5229
+ default:
5230
+ return unknownDuCase(path, d.value, "Video | Audio");
5231
+ }
5232
+ };
5233
+ var decodeMediaSpec = (path, j) => {
5234
+ const fo = requireObject(path, j);
5235
+ if (!fo.ok) return fo;
5236
+ const f = fo.value;
5237
+ const src = reqField(path, f, "src", "Media Binding<string> Src", decodeBindingString);
5238
+ if (!src.ok) return src;
5239
+ const label = reqField(path, f, "label", "Media accessible label TextSource", decodeTextSource);
5240
+ if (!label.ok) return label;
5241
+ const kind = reqField(path, f, "kind", "MediaKind (Video | Audio)", decodeMediaKind);
5242
+ if (!kind.ok) return kind;
5243
+ const controlsJ = tryField(f, "controls");
5244
+ const controls = controlsJ === void 0 ? ok(true) : requireBool(`${path}.controls`, controlsJ);
5245
+ if (!controls.ok) return controls;
5246
+ const loopJ = tryField(f, "loop");
5247
+ const loop = loopJ === void 0 ? ok(false) : requireBool(`${path}.loop`, loopJ);
5248
+ if (!loop.ok) return loop;
5249
+ return ok({
5250
+ src: src.value,
5251
+ label: label.value,
5252
+ controls: controls.value,
5253
+ loop: loop.value,
5254
+ kind: kind.value
5255
+ });
5009
5256
  };
5010
5257
  var decodeListSpec = (path, j) => {
5011
5258
  const fo = requireObject(path, j);
@@ -5149,7 +5396,7 @@ var decodeProgressSpec = (path, j) => {
5149
5396
  const fo = requireObject(path, j);
5150
5397
  if (!fo.ok) return fo;
5151
5398
  const f = fo.value;
5152
- const fraction = reqField(path, f, "fraction", "Progress fraction binding", decodeBinding);
5399
+ const fraction = reqField(path, f, "fraction", "Progress fraction binding", decodeBindingFloat);
5153
5400
  if (!fraction.ok) return fraction;
5154
5401
  const indeterminate = optField(path, f, "indeterminate", requireBool);
5155
5402
  if (!indeterminate.ok) return indeterminate;
@@ -5199,9 +5446,9 @@ var decodeDrawStyle = (path, j) => {
5199
5446
  if (!fill.ok) return fill;
5200
5447
  const stroke = optField(path, f, "stroke", decodeBindingString);
5201
5448
  if (!stroke.ok) return stroke;
5202
- const strokeWidth = optField(path, f, "strokeWidth", decodeBinding);
5449
+ const strokeWidth = optField(path, f, "strokeWidth", decodeBindingFloat);
5203
5450
  if (!strokeWidth.ok) return strokeWidth;
5204
- const opacity = optField(path, f, "opacity", decodeBinding);
5451
+ const opacity = optField(path, f, "opacity", decodeBindingFloat);
5205
5452
  if (!opacity.ok) return opacity;
5206
5453
  const textAnchor = optField(path, f, "textAnchor", decodeTextAnchor);
5207
5454
  if (!textAnchor.ok) return textAnchor;
@@ -5480,6 +5727,10 @@ var decodeDisplayKind = (path, j) => {
5480
5727
  const r = decodeImageSpec(path, j);
5481
5728
  return r.ok ? ok({ kind: "Image", spec: r.value }) : r;
5482
5729
  }
5730
+ case "Media": {
5731
+ const r = decodeMediaSpec(path, j);
5732
+ return r.ok ? ok({ kind: "Media", spec: r.value }) : r;
5733
+ }
5483
5734
  case "List": {
5484
5735
  const r = decodeListSpec(path, j);
5485
5736
  return r.ok ? ok({ kind: "List", spec: r.value }) : r;
@@ -5531,7 +5782,11 @@ var decodeFormFieldKind = (autoBind, path, j) => {
5531
5782
  return v.ok ? ok({ kind: "Text", value: v.value, ...onChangeField }) : v;
5532
5783
  }
5533
5784
  case "Number": {
5534
- const v = valueOr(decodeBinding, controlValueDefaults.number, "Number value binding");
5785
+ const v = valueOr(
5786
+ decodeBindingFloat,
5787
+ controlValueDefaults.number,
5788
+ "Number value binding"
5789
+ );
5535
5790
  return v.ok ? ok({ kind: "Number", value: v.value, ...onChangeField }) : v;
5536
5791
  }
5537
5792
  case "Checkbox": {
@@ -5583,7 +5838,7 @@ var decodeFormFieldKind = (autoBind, path, j) => {
5583
5838
  }
5584
5839
  case "RangedNumber": {
5585
5840
  const value = valueOr(
5586
- decodeBinding,
5841
+ decodeBindingFloat,
5587
5842
  controlValueDefaults.number,
5588
5843
  "RangedNumber value binding"
5589
5844
  );
@@ -5697,6 +5952,77 @@ var decodeFormFieldKind = (autoBind, path, j) => {
5697
5952
  return unknownDuCase(path, d.value, WRONG_FORM_FIELD_KIND_HINT);
5698
5953
  }
5699
5954
  };
5955
+ var TEXT_FORMATS = ["email", "url", "tel"];
5956
+ var COMPARE_OPS = ["eq", "neq", "lt", "lte", "gt", "gte"];
5957
+ var decodeTextFormat = (path, j) => bareEnum(path, j, TEXT_FORMATS, "TextFormat");
5958
+ var decodeCompareOp = (path, j) => bareEnum(path, j, COMPARE_OPS, "CompareOp");
5959
+ var decodeCompareRule = (path, j) => {
5960
+ const fo = requireObject(path, j);
5961
+ if (!fo.ok) return fo;
5962
+ const f = fo.value;
5963
+ const op = reqField(path, f, "op", "CompareOp", decodeCompareOp);
5964
+ if (!op.ok) return op;
5965
+ const against = reqField(path, f, "against", "Binding", (p, v) => decodeBinding(p, v));
5966
+ if (!against.ok) return against;
5967
+ return ok({ op: op.value, against: against.value });
5968
+ };
5969
+ var decodeFieldRule = (path, j) => {
5970
+ const fo = requireObject(path, j);
5971
+ if (!fo.ok) return fo;
5972
+ const f = fo.value;
5973
+ const format = optField(path, f, "format", decodeTextFormat);
5974
+ if (!format.ok) return format;
5975
+ const pattern = optField(path, f, "pattern", requireString);
5976
+ if (!pattern.ok) return pattern;
5977
+ const minLength = optField(path, f, "minLength", requireInt);
5978
+ if (!minLength.ok) return minLength;
5979
+ const maxLength = optField(path, f, "maxLength", requireInt);
5980
+ if (!maxLength.ok) return maxLength;
5981
+ const compare = optField(path, f, "compare", decodeCompareRule);
5982
+ if (!compare.ok) return compare;
5983
+ const message = optField(path, f, "message", decodeTextSource);
5984
+ if (!message.ok) return message;
5985
+ const constrains = format.value !== void 0 || pattern.value !== void 0 || minLength.value !== void 0 || maxLength.value !== void 0 || compare.value !== void 0;
5986
+ if (!constrains)
5987
+ return makeError(
5988
+ "WRONG_TYPE",
5989
+ path,
5990
+ "a rule that constrains nothing is a defect, not a no-op \u2014 declare at least one of format / pattern / minLength / maxLength / compare, or omit 'rule' entirely",
5991
+ "FieldRule with at least one constraint slot"
5992
+ );
5993
+ if (minLength.value !== void 0 && maxLength.value !== void 0 && minLength.value > maxLength.value)
5994
+ return makeError(
5995
+ "WRONG_TYPE",
5996
+ path,
5997
+ `minLength ${minLength.value} is above maxLength ${maxLength.value} \u2014 an inverted length bound admits no value at all, so the field could never be submitted`,
5998
+ "minLength <= maxLength"
5999
+ );
6000
+ return ok({
6001
+ ...format.value !== void 0 ? { format: format.value } : {},
6002
+ ...pattern.value !== void 0 ? { pattern: pattern.value } : {},
6003
+ ...minLength.value !== void 0 ? { minLength: minLength.value } : {},
6004
+ ...maxLength.value !== void 0 ? { maxLength: maxLength.value } : {},
6005
+ ...compare.value !== void 0 ? { compare: compare.value } : {},
6006
+ ...message.value !== void 0 ? { message: message.value } : {}
6007
+ });
6008
+ };
6009
+ var FORM_FIELD_NEAR_MISSES = [
6010
+ ["validation", "rule"],
6011
+ ["constraints", "rule"],
6012
+ ["validate", "rule"]
6013
+ ];
6014
+ var checkFormFieldNearMisses = (path, f) => {
6015
+ for (const [name, canonical] of FORM_FIELD_NEAR_MISSES) {
6016
+ if (tryField(f, name) !== void 0)
6017
+ return makeError(
6018
+ "WRONG_TYPE",
6019
+ `${path}.${name}`,
6020
+ `'${name}' is not part of the form vocabulary \u2014 it would be ignored, not honoured, and the field would accept anything`,
6021
+ canonical
6022
+ );
6023
+ }
6024
+ return ok(void 0);
6025
+ };
5700
6026
  var decodeFormField = (path, j) => {
5701
6027
  const fo = requireObject(path, j);
5702
6028
  if (!fo.ok) return fo;
@@ -5718,12 +6044,17 @@ var decodeFormField = (path, j) => {
5718
6044
  if (!required.ok) return required;
5719
6045
  const help = optField(path, f, "help", decodeTextSource);
5720
6046
  if (!help.ok) return help;
6047
+ const nm = checkFormFieldNearMisses(path, f);
6048
+ if (!nm.ok) return nm;
6049
+ const rule = optField(path, f, "rule", decodeFieldRule);
6050
+ if (!rule.ok) return rule;
5721
6051
  return ok({
5722
6052
  id: id.value,
5723
6053
  kind: kind.value,
5724
6054
  label: label.value,
5725
6055
  required: required.value,
5726
- ...help.value !== void 0 ? { help: help.value } : {}
6056
+ ...help.value !== void 0 ? { help: help.value } : {},
6057
+ ...rule.value !== void 0 ? { rule: rule.value } : {}
5727
6058
  });
5728
6059
  };
5729
6060
  var decodeFormSpec = (path, j) => {
@@ -6462,10 +6793,23 @@ var decodeBoxLayout = (path, j) => {
6462
6793
  ...templateColumns.value !== void 0 ? { templateColumns: templateColumns.value } : {}
6463
6794
  });
6464
6795
  }
6796
+ case "Masonry": {
6797
+ const colsJ = tryField(f, "cols") ?? tryField(f, "columns");
6798
+ if (colsJ === void 0) return missingField(path, "cols", "positive integer column count");
6799
+ if (colsJ.kind !== "JNumber" || colsJ.value <= 0 || !Number.isInteger(colsJ.value))
6800
+ return wrongType(`${path}.cols`, "JSON number (positive integer column count)");
6801
+ const masonryGap = optField(path, f, "gap", requireInt);
6802
+ if (!masonryGap.ok) return masonryGap;
6803
+ return ok({
6804
+ kind: "Masonry",
6805
+ cols: colsJ.value,
6806
+ ...masonryGap.value !== void 0 ? { gap: masonryGap.value } : {}
6807
+ });
6808
+ }
6465
6809
  case "Auto":
6466
6810
  return ok({ kind: "Auto" });
6467
6811
  default:
6468
- return unknownDuCase(path, d.value, "Flex | Grid | Auto");
6812
+ return unknownDuCase(path, d.value, "Flex | Grid | Masonry | Auto");
6469
6813
  }
6470
6814
  };
6471
6815
  var decodeBoxRole = (path, j) => {
@@ -6478,7 +6822,7 @@ var decodeBoxRole = (path, j) => {
6478
6822
  case "Separator":
6479
6823
  return ok(s.value);
6480
6824
  default:
6481
- return unknownDuCase(path, s.value, "Group | Card | Dashboard | Separator");
6825
+ return unknownEnumCase(path, s.value, "Group | Card | Dashboard | Separator");
6482
6826
  }
6483
6827
  };
6484
6828
  var decodeBox = (path, j) => {
@@ -6561,7 +6905,7 @@ var decodeTabsSpec = (path, j) => {
6561
6905
  }
6562
6906
  const activeTag = optField(path, f, "activeTag", decodeBindingString);
6563
6907
  if (!activeTag.ok) return activeTag;
6564
- const activeIndex = optField(path, f, "activeIndex", decodeBinding);
6908
+ const activeIndex = optField(path, f, "activeIndex", decodeBindingInt);
6565
6909
  if (!activeIndex.ok) return activeIndex;
6566
6910
  return ok({
6567
6911
  children: children.value,
@@ -6578,7 +6922,7 @@ var decodeStepperSpec = (path, j) => {
6578
6922
  const fo = requireObject(path, j);
6579
6923
  if (!fo.ok) return fo;
6580
6924
  const f = fo.value;
6581
- const activeStep = reqField(path, f, "activeStep", "activeStep binding", decodeBinding);
6925
+ const activeStep = reqField(path, f, "activeStep", "activeStep binding", decodeBindingInt);
6582
6926
  if (!activeStep.ok) return activeStep;
6583
6927
  const children = decodeChildren(path, f);
6584
6928
  if (!children.ok) return children;
@@ -6743,7 +7087,7 @@ var decodeContentHash = (path, j) => {
6743
7087
  if (!strictnessR.ok) return strictnessR;
6744
7088
  const s = strictnessR.value;
6745
7089
  if (s !== "StrictReplay" && s !== "AdvisoryWarning" && s !== "Enforced") {
6746
- return unknownDuCase(`${path}.strictness`, s, "StrictReplay | AdvisoryWarning | Enforced");
7090
+ return unknownEnumCase(`${path}.strictness`, s, "StrictReplay | AdvisoryWarning | Enforced");
6747
7091
  }
6748
7092
  return ok({ algorithm: algorithm.value, hash: hash.value, strictness: s });
6749
7093
  };
@@ -6874,11 +7218,11 @@ var decodeEffectClass = (path, j) => {
6874
7218
  const host = reqField(path, fo.value, "hostEffect", "EffectClass hostEffect", requireString);
6875
7219
  if (!host.ok) return host;
6876
7220
  if (host.value !== "Pure" && host.value !== "ReadsHost" && host.value !== "WritesHost")
6877
- return unknownDuCase(`${path}.hostEffect`, host.value, "Pure | ReadsHost | WritesHost");
7221
+ return unknownEnumCase(`${path}.hostEffect`, host.value, "Pure | ReadsHost | WritesHost");
6878
7222
  const det = reqField(path, fo.value, "determinism", "EffectClass determinism", requireString);
6879
7223
  if (!det.ok) return det;
6880
7224
  if (det.value !== "Deterministic" && det.value !== "Clock" && det.value !== "Random" && det.value !== "Network")
6881
- return unknownDuCase(
7225
+ return unknownEnumCase(
6882
7226
  `${path}.determinism`,
6883
7227
  det.value,
6884
7228
  "Deterministic | Clock | Random | Network"
@@ -6898,6 +7242,14 @@ var decodeNodeKind = (path, j) => {
6898
7242
  const f = fo.value;
6899
7243
  const d = requireDiscriminator(path, f);
6900
7244
  if (!d.ok) return d;
7245
+ if (narrows(walkPolicy) && NODE_KIND_NAMES.includes(d.value) && !admits(walkPolicy, d.value)) {
7246
+ return makeError(
7247
+ "KIND_NOT_ADMITTED",
7248
+ `${path}.$type`,
7249
+ `node kind '${d.value}' is not admitted by decode policy '${walkPolicy.identity}'`,
7250
+ policyHint(walkPolicy)
7251
+ );
7252
+ }
6901
7253
  switch (d.value) {
6902
7254
  // The four behavioural categories are flat on the wire (WIRE_FORMAT §3.2):
6903
7255
  // the `kind` object carries the primitive discriminator directly, so route
@@ -6927,6 +7279,7 @@ var decodeNodeKind = (path, j) => {
6927
7279
  case "Fact":
6928
7280
  case "Link":
6929
7281
  case "Image":
7282
+ case "Media":
6930
7283
  case "List":
6931
7284
  case "Toast":
6932
7285
  case "CodeBlock":
@@ -7202,10 +7555,54 @@ var decodeSemanticStyle = (path, j) => {
7202
7555
  voice: voice.value ?? "Default"
7203
7556
  });
7204
7557
  };
7558
+ var A11Y_NEAR_MISSES = [
7559
+ [
7560
+ "aria-label",
7561
+ "label \u2014 the accessible name, a Binding<string> (a bare string is the \xA73.6 shorthand)"
7562
+ ],
7563
+ [
7564
+ "ariaLabel",
7565
+ "label \u2014 the accessible name, a Binding<string> (a bare string is the \xA73.6 shorthand)"
7566
+ ],
7567
+ ["aria-labelledby", "labelledBy \u2014 the id of a sibling node whose text carries the name"],
7568
+ ["ariaLabelledBy", "labelledBy \u2014 the id of a sibling node whose text carries the name"],
7569
+ [
7570
+ "labelledby",
7571
+ "labelledBy \u2014 the slot name is camelCase on the wire, not the ARIA attribute spelling"
7572
+ ],
7573
+ ["aria-describedby", "describedBy \u2014 the id of a sibling node whose text carries the description"],
7574
+ ["ariaDescribedBy", "describedBy \u2014 the id of a sibling node whose text carries the description"],
7575
+ [
7576
+ "describedby",
7577
+ "describedBy \u2014 the slot name is camelCase on the wire, not the ARIA attribute spelling"
7578
+ ],
7579
+ ["aria-role", "role \u2014 the ARIA role NAME as a bare string"],
7580
+ ["ariaRole", "role \u2014 the ARIA role NAME as a bare string"],
7581
+ ["aria-live", 'liveRegion \u2014 the closed token set "polite" / "assertive" / "off"'],
7582
+ ["ariaLive", 'liveRegion \u2014 the closed token set "polite" / "assertive" / "off"'],
7583
+ ["live", 'liveRegion \u2014 the closed token set "polite" / "assertive" / "off"'],
7584
+ ["liveregion", 'liveRegion \u2014 the closed token set "polite" / "assertive" / "off"'],
7585
+ ["aria-hidden", "hidden \u2014 a Binding<bool> (a bare bool is the \xA73.6 shorthand)"],
7586
+ ["ariaHidden", "hidden \u2014 a Binding<bool> (a bare bool is the \xA73.6 shorthand)"]
7587
+ ];
7588
+ var checkA11yNearMisses = (path, f) => {
7589
+ for (const [name, canonical] of A11Y_NEAR_MISSES) {
7590
+ if (tryField(f, name) !== void 0)
7591
+ return makeError(
7592
+ "WRONG_TYPE",
7593
+ `${path}.${name}`,
7594
+ `'${name}' is not part of the accessibility vocabulary \u2014 it would be ignored, not honoured, and the intent would reach assistive technology as nothing at all`,
7595
+ canonical
7596
+ );
7597
+ }
7598
+ return ok(void 0);
7599
+ };
7205
7600
  var decodeAccessibility = (path, j) => {
7206
7601
  const fo = requireObject(path, j);
7207
7602
  if (!fo.ok) return fo;
7208
7603
  const f = fo.value;
7604
+ const nearMiss2 = checkA11yNearMisses(path, f);
7605
+ if (!nearMiss2.ok) return nearMiss2;
7209
7606
  const label = optField(path, f, "label", decodeBindingString);
7210
7607
  if (!label.ok) return label;
7211
7608
  const labelledBy = optField(path, f, "labelledBy", requireString);
@@ -7250,7 +7647,39 @@ var placeholderClosureNode = {
7250
7647
  voice: "Default"
7251
7648
  }
7252
7649
  };
7650
+ var walkDepth = 0;
7651
+ var walkNodes = 0;
7652
+ var opDepth = 0;
7653
+ var walkPolicy = admitAll;
7654
+ var resetWalk = (policy = admitAll) => {
7655
+ walkDepth = 0;
7656
+ walkNodes = 0;
7657
+ opDepth = 0;
7658
+ walkPolicy = policy;
7659
+ };
7660
+ var limitError = (path, message, expected) => makeError("LIMIT_EXCEEDED", path, message, expected);
7253
7661
  var decodeNodeAst = (path, j) => {
7662
+ if (walkDepth >= MAX_NODE_DEPTH) {
7663
+ return limitError(
7664
+ path,
7665
+ `node nesting deeper than the wire limit MAX_NODE_DEPTH = ${MAX_NODE_DEPTH}`,
7666
+ `a tree nesting nodes no more than ${MAX_NODE_DEPTH} levels deep`
7667
+ );
7668
+ }
7669
+ walkNodes += 1;
7670
+ if (walkNodes > MAX_NODES) {
7671
+ return limitError(
7672
+ path,
7673
+ `the document holds more than the wire limit MAX_NODES = ${MAX_NODES} nodes`,
7674
+ `a tree of no more than ${MAX_NODES} nodes in total`
7675
+ );
7676
+ }
7677
+ walkDepth += 1;
7678
+ const r = decodeNodeAstInner(path, j);
7679
+ walkDepth -= 1;
7680
+ return r;
7681
+ };
7682
+ var decodeNodeAstInner = (path, j) => {
7254
7683
  const fo = requireObject(path, j);
7255
7684
  if (!fo.ok) return fo;
7256
7685
  const f = fo.value;
@@ -7278,6 +7707,25 @@ var decodeNodeAst = (path, j) => {
7278
7707
  });
7279
7708
  };
7280
7709
  var decodeTreeOpAst = (path, j) => {
7710
+ if (opDepth >= MAX_NODE_DEPTH) {
7711
+ return limitError(
7712
+ path,
7713
+ `op nesting deeper than the wire limit MAX_NODE_DEPTH = ${MAX_NODE_DEPTH}`,
7714
+ `a Batch nesting ops no more than ${MAX_NODE_DEPTH} levels deep`
7715
+ );
7716
+ }
7717
+ opDepth += 1;
7718
+ const r = decodeTreeOpAstInner(path, j);
7719
+ opDepth -= 1;
7720
+ return r;
7721
+ };
7722
+ var retiredPositionalField = (path, f, name, opKind) => tryField(f, name) !== void 0 ? makeError(
7723
+ "WRONG_TYPE",
7724
+ `${path}.${name}`,
7725
+ `'${name}' was removed from the wire format \u2014 ${opKind} appends, and order is stated by naming ids with ReorderChildren`,
7726
+ "a Batch of the structural op followed by ReorderChildren"
7727
+ ) : ok(void 0);
7728
+ var decodeTreeOpAstInner = (path, j) => {
7281
7729
  const fo = requireObject(path, j);
7282
7730
  if (!fo.ok) return fo;
7283
7731
  const f = fo.value;
@@ -7330,6 +7778,8 @@ var decodeTreeOpAst = (path, j) => {
7330
7778
  return state.ok ? ok({ kind: "UpdateState", target: t.value, state: state.value }) : state;
7331
7779
  }
7332
7780
  case "InsertChild": {
7781
+ const retired = retiredPositionalField(path, f, "position", "InsertChild");
7782
+ if (!retired.ok) return retired;
7333
7783
  const parentJ = reqField(path, f, "parentId", "parent NodeId", requireString);
7334
7784
  if (!parentJ.ok) return parentJ;
7335
7785
  const child = reqField(path, f, "child", "child Node object", decodeNodeAst);
@@ -7344,6 +7794,8 @@ var decodeTreeOpAst = (path, j) => {
7344
7794
  return t.ok ? ok({ kind: "RemoveNode", target: t.value }) : t;
7345
7795
  }
7346
7796
  case "MoveNode": {
7797
+ const retired = retiredPositionalField(path, f, "newPosition", "MoveNode");
7798
+ if (!retired.ok) return retired;
7347
7799
  const t = target();
7348
7800
  if (!t.ok) return t;
7349
7801
  const newParent = reqField(path, f, "newParentId", "new parent NodeId", requireString);
@@ -7425,6 +7877,8 @@ var coerce = {
7425
7877
  tone: (v) => viaAst(v, decodeTone),
7426
7878
  weight: (v) => viaAst(v, decodeWeight),
7427
7879
  emphasis: (v) => viaAst(v, decodeEmphasis),
7880
+ /** `Metric.TrendPolarity` (Phase 867) - the UpdateProp twin of `decodeTrendPolarity`. */
7881
+ trendPolarity: (v) => viaAst(v, decodeTrendPolarity),
7428
7882
  /**
7429
7883
  * The behavioural `emphasis` BOOL on Fact / LabelValueRow — the UpdateProp
7430
7884
  * twin of `decodeEmphasisFlag`, so a TreeOp edit gets the same
@@ -7445,13 +7899,18 @@ var invalidJson = (parseMessage) => makeError(
7445
7899
  `input is not valid JSON: ${parseMessage}`,
7446
7900
  "well-formed JSON object per the canonical-JSON shape"
7447
7901
  );
7448
- var decodeNode = (json) => {
7902
+ var parseFailure = (e) => e.limit === true ? makeError("LIMIT_EXCEEDED", "$", e.message, "a document within the WIRE_FORMAT \xA721 limits") : invalidJson(e.message);
7903
+ var decodeNode = (json, policy) => {
7449
7904
  const parsed = parse(json);
7450
- return parsed.ok ? decodeNodeAst("$", parsed.value) : invalidJson(parsed.error.message);
7905
+ if (!parsed.ok) return parseFailure(parsed.error);
7906
+ resetWalk(policy);
7907
+ return decodeNodeAst("$", parsed.value);
7451
7908
  };
7452
- var decodeOp = (json) => {
7909
+ var decodeOp = (json, policy) => {
7453
7910
  const parsed = parse(json);
7454
- return parsed.ok ? decodeTreeOpAst("$", parsed.value) : invalidJson(parsed.error.message);
7911
+ if (!parsed.ok) return parseFailure(parsed.error);
7912
+ resetWalk(policy);
7913
+ return decodeTreeOpAst("$", parsed.value);
7455
7914
  };
7456
7915
 
7457
7916
  // src/apply.ts
@@ -7618,6 +8077,11 @@ var updateField = (field2, value, kind) => {
7618
8077
  coerce.cellFormat(value),
7619
8078
  (x) => disp({ kind: "Metric", spec: { ...s, trendFormat: x } })
7620
8079
  );
8080
+ case "TrendPolarity":
8081
+ return patch(
8082
+ coerce.trendPolarity(value),
8083
+ (x) => disp({ kind: "Metric", spec: { ...s, trendPolarity: x } })
8084
+ );
7621
8085
  case "Icon":
7622
8086
  return patch(
7623
8087
  coerce.iconSource(value),
@@ -7901,6 +8365,12 @@ var updateField = (field2, value, kind) => {
7901
8365
  (x) => lay({ kind: "Box", spec: { ...s, layout: { ...mode, cols: x } } })
7902
8366
  );
7903
8367
  }
8368
+ if (field2 === "Cols" && mode.kind === "Masonry") {
8369
+ return patch(
8370
+ coerce.int(value),
8371
+ (x) => lay({ kind: "Box", spec: { ...s, layout: { ...mode, cols: x } } })
8372
+ );
8373
+ }
7904
8374
  if (field2 === "TemplateColumns" && mode.kind === "Grid") {
7905
8375
  return patch(
7906
8376
  coerce.string(value),
@@ -9765,7 +10235,61 @@ var validateAnswerDocument = (json) => {
9765
10235
  if (!answer.ok) return answer;
9766
10236
  return validateAnswerAt("$.answer", contract.value, answer.value);
9767
10237
  };
10238
+ var HOST_RESERVED_PREFIX = "host.";
10239
+ var isHostReserved = (key) => typeof key === "string" && key.startsWith(HOST_RESERVED_PREFIX);
10240
+ var isPlainObject = (v) => v !== null && typeof v === "object" && !Array.isArray(v);
10241
+ var isStateDeclaration = (v) => isPlainObject(v) && v["kind"] === "State" && typeof v["key"] === "string" && "defaultValue" in v && v["defaultValue"] !== void 0;
10242
+ var controlDefaults = Object.values(controlValueDefaults);
10243
+ var deepEqual = (a, b) => {
10244
+ try {
10245
+ return JSON.stringify(a) === JSON.stringify(b);
10246
+ } catch {
10247
+ return false;
10248
+ }
10249
+ };
10250
+ var isAutoBoundFieldValue = (binding2, fieldId) => binding2.key === fieldId && controlDefaults.some((d) => deepEqual(d, binding2.defaultValue));
10251
+ var isEmptyDeclaration = (value) => {
10252
+ if (Array.isArray(value)) return value.length === 0;
10253
+ if (isPlainObject(value)) {
10254
+ const columns = value["columns"];
10255
+ if (isPlainObject(columns)) return Object.keys(columns).length === 0;
10256
+ }
10257
+ return false;
10258
+ };
10259
+ var collectStateSeeds = (tree) => {
10260
+ const seeds = {};
10261
+ const seen = /* @__PURE__ */ new Set();
10262
+ const visit = (value, autoBindFieldId) => {
10263
+ if (value === null || typeof value !== "object") return;
10264
+ if (seen.has(value)) return;
10265
+ seen.add(value);
10266
+ if (Array.isArray(value)) {
10267
+ for (const item of value) visit(item, autoBindFieldId);
10268
+ return;
10269
+ }
10270
+ const obj = value;
10271
+ if (isStateDeclaration(obj)) {
10272
+ const key = obj.key;
10273
+ const shouldSkip = isHostReserved(key) || Object.prototype.hasOwnProperty.call(seeds, key) || isEmptyDeclaration(obj.defaultValue) || autoBindFieldId !== void 0 && isAutoBoundFieldValue(obj, autoBindFieldId);
10274
+ if (!shouldSkip) seeds[key] = obj.defaultValue;
10275
+ }
10276
+ const record = obj;
10277
+ const ownId = record["id"];
10278
+ const fieldId = typeof ownId === "string" && typeof record["required"] === "boolean" ? ownId : void 0;
10279
+ for (const [k, v] of Object.entries(obj)) {
10280
+ const established = k === "kind" && fieldId !== void 0 ? fieldId : void 0;
10281
+ visit(v, established ?? autoBindFieldId);
10282
+ }
10283
+ };
10284
+ visit(tree, void 0);
10285
+ return seeds;
10286
+ };
10287
+ var withStateSeeds = (tree, sources) => {
10288
+ const seeds = collectStateSeeds(tree);
10289
+ if (Object.keys(seeds).length === 0) return sources;
10290
+ return { ...sources, state: { ...seeds, ...sources.state ?? {} } };
10291
+ };
9768
10292
 
9769
- export { ELICITATION_KEY, ELICITATION_VERSION, PAYLOAD_KEY, PROFILE_KEY, REQUIRED_PROFILE_KEY, apply, canPlace, cellString, coerce, coreV1, decodeDagRecord, decodeElicitation, decodeElicitationOutcome, decodeEnvelope, decodeEnvelopeAst, decodeNode, decodeNodeTolerant, decodeOp, decodeTolerant, derivedFreshIds, duplicateOp, duplicateOpWith, encodeCell, encodeColExpr, encodeDagRecord, encodeDataSource, encodeElicitation, encodeElicitationOutcome, encodeEnvelope2 as encodeEnvelope, encodeNode, encodeOp, encodePipeline, evalErrorString, evalPipeline, evalPipelineInEnv, evalPipelineWith, evalPipelineWithInEnv, evalSource, field as jsonField, liveValueToTable, merge3Way, moveOp, negotiate, negotiateEnvelope, noResolve, nudgeOp, parse, pasteOp, pasteOpWith, pipelineParams, placeOp, reencodeNode, renderAstCanonical, renderProfile, sequentialFreshIds, stepParams, tryParseProfile, validateAnswer, validateAnswerAt, validateAnswerDocument };
10293
+ export { ELICITATION_KEY, ELICITATION_VERSION, HOST_RESERVED_PREFIX, PAYLOAD_KEY, PROFILE_KEY, REQUIRED_PROFILE_KEY, apply, canPlace, cellString, coerce, collectStateSeeds, coreV1, decodeDagRecord, decodeElicitation, decodeElicitationOutcome, decodeEnvelope, decodeEnvelopeAst, decodeNode, decodeNodeTolerant, decodeOp, decodeTolerant, derivedFreshIds, duplicateOp, duplicateOpWith, encodeCell, encodeColExpr, encodeDagRecord, encodeDataSource, encodeElicitation, encodeElicitationOutcome, encodeEnvelope2 as encodeEnvelope, encodeNode, encodeOp, encodePipeline, evalErrorString, evalPipeline, evalPipelineInEnv, evalPipelineWith, evalPipelineWithInEnv, evalSource, field as jsonField, liveValueToTable, merge3Way, moveOp, negotiate, negotiateEnvelope, noResolve, nudgeOp, parse, pasteOp, pasteOpWith, pipelineParams, placeOp, reencodeNode, renderAstCanonical, renderProfile, sequentialFreshIds, stepParams, tryParseProfile, validateAnswer, validateAnswerAt, validateAnswerDocument, withStateSeeds };
9770
10294
  //# sourceMappingURL=index.js.map
9771
10295
  //# sourceMappingURL=index.js.map