@pipelex/mthds-form 0.32.0 → 0.34.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.
Files changed (36) hide show
  1. package/README.md +1 -1
  2. package/dist/brand/index.js +2 -2
  3. package/dist/{chunk-PCNFELNT.js → chunk-5RV3ASMO.js} +141 -69
  4. package/dist/chunk-5RV3ASMO.js.map +1 -0
  5. package/dist/{chunk-VH5CDQDR.js → chunk-AURDKAIC.js} +3 -3
  6. package/dist/{chunk-VH5CDQDR.js.map → chunk-AURDKAIC.js.map} +1 -1
  7. package/dist/{chunk-ZX52CQJ4.js → chunk-CFBK7NO7.js} +3 -3
  8. package/dist/{chunk-ZX52CQJ4.js.map → chunk-CFBK7NO7.js.map} +1 -1
  9. package/dist/{chunk-3GO65HWP.js → chunk-PNNWNRPG.js} +11 -7
  10. package/dist/chunk-PNNWNRPG.js.map +1 -0
  11. package/dist/{chunk-XO5OENNF.js → chunk-TF4RTKLH.js} +32 -5
  12. package/dist/chunk-TF4RTKLH.js.map +1 -0
  13. package/dist/{chunk-IBBAJXIO.js → chunk-XIWBKV7T.js} +3 -3
  14. package/dist/{chunk-IBBAJXIO.js.map → chunk-XIWBKV7T.js.map} +1 -1
  15. package/dist/{chunk-VBXFGUCG.js → chunk-XYS5KCXB.js} +465 -112
  16. package/dist/chunk-XYS5KCXB.js.map +1 -0
  17. package/dist/core/gate.js +2 -2
  18. package/dist/core/index.js +4 -4
  19. package/dist/core/readiness.d.ts +34 -1
  20. package/dist/core/readiness.js +1 -1
  21. package/dist/core/seed.js +2 -2
  22. package/dist/core/values.js +2 -2
  23. package/dist/{field-renderer-Dz03dpig.d.ts → field-renderer-BYN6YrU-.d.ts} +6 -6
  24. package/dist/generative/headless/index.d.ts +53 -16
  25. package/dist/generative/headless/index.js +3 -2
  26. package/dist/generative/index.d.ts +79 -25
  27. package/dist/generative/index.js +942 -275
  28. package/dist/generative/index.js.map +1 -1
  29. package/dist/react/index.d.ts +56 -29
  30. package/dist/react/index.js +4 -4
  31. package/dist/styles.css +1 -1
  32. package/package.json +1 -1
  33. package/dist/chunk-3GO65HWP.js.map +0 -1
  34. package/dist/chunk-PCNFELNT.js.map +0 -1
  35. package/dist/chunk-VBXFGUCG.js.map +0 -1
  36. package/dist/chunk-XO5OENNF.js.map +0 -1
@@ -1,5 +1,6 @@
1
1
  import { isNativeValueNode, readDateContent, formatDateContent, isNativeHtmlNode, isNativeDateNode, isNativeCompositeNode } from './chunk-QQK6Y55E.js';
2
- import { APP_STYLES } from './chunk-3GO65HWP.js';
2
+ import { APP_STYLES } from './chunk-PNNWNRPG.js';
3
+ import { isFilled } from './chunk-TF4RTKLH.js';
3
4
  import { hasOwnProp } from './chunk-V3OV2XQT.js';
4
5
  import { defineSchema, defineCatalog, validateSpec, compileSpecStream } from '@json-render/core';
5
6
  import { z } from 'zod';
@@ -778,59 +779,77 @@ var COMPONENT_NAMES = [
778
779
  ...CUSTOM_COMPONENTS,
779
780
  ...PRODUCT_COMPONENTS
780
781
  ];
781
- var FRAME_EXCLUDED = {
782
- page: [...FRAME_COMPONENTS],
783
- composer: [
784
- "AppBar",
785
- "Footer",
786
- "Workspace",
787
- "Rail",
788
- "Cta",
789
- "Button",
790
- "Hero",
791
- "SummaryRow",
792
- "MthdsResult",
793
- "DataTable",
794
- "Metric",
795
- "Progress",
796
- // `TextList` stays: a composer may list short texts too, such as what a
797
- // run gives back.
798
- ...RESULT_COMPONENTS.filter((name) => name !== "TextList")
799
- ],
800
- result: [
801
- "AppBar",
802
- "Footer",
803
- "Workspace",
804
- "Rail",
805
- "Cta",
806
- "Button",
807
- "Hero",
808
- "MthdsField",
782
+ var FRAME_VOCABULARIES = {
783
+ composer: Object.freeze([
784
+ "Card",
785
+ "Stack",
786
+ "Grid",
787
+ "Separator",
788
+ "Heading",
789
+ "Text",
790
+ "Badge",
791
+ "Alert",
792
+ "Collapsible",
793
+ "Avatar",
809
794
  "Input",
810
795
  "Textarea",
811
796
  "Select",
812
797
  "Radio",
813
798
  "Checkbox",
814
799
  "Switch",
800
+ "Split",
801
+ "Tabs",
802
+ "Steps",
803
+ "Icon",
815
804
  "Segmented",
816
805
  "NumberInput",
817
- "Steps",
818
- ...COMPOSER_COMPONENTS
819
- ]
806
+ "MthdsField",
807
+ "Section",
808
+ ...COMPOSER_COMPONENTS,
809
+ "TextList"
810
+ ]),
811
+ result: Object.freeze([
812
+ "Card",
813
+ "Stack",
814
+ "Grid",
815
+ "Separator",
816
+ "Heading",
817
+ "Text",
818
+ "Badge",
819
+ "Alert",
820
+ "Collapsible",
821
+ "Progress",
822
+ "Avatar",
823
+ "Split",
824
+ "Tabs",
825
+ "Icon",
826
+ "MthdsResult",
827
+ "DataTable",
828
+ "Metric",
829
+ "Section",
830
+ "SummaryRow",
831
+ ...RESULT_COMPONENTS
832
+ ])
820
833
  };
834
+ var PAGE_VOCABULARY = Object.freeze(
835
+ COMPONENT_NAMES.filter((name) => !FRAME_COMPONENTS.includes(name))
836
+ );
821
837
  function componentNamesFor(frame) {
822
- const excluded = new Set(FRAME_EXCLUDED[frame]);
823
- const own = frame === "page" ? [] : [...FRAME_COMPONENTS];
824
- return [...COMPONENT_NAMES, ...own].filter((name) => !excluded.has(name));
838
+ return frame === "page" ? PAGE_VOCABULARY : FRAME_VOCABULARIES[frame];
825
839
  }
840
+ var frameCatalogs = /* @__PURE__ */ new Map();
826
841
  function frameCatalog(frame) {
827
- return {
842
+ const built = frameCatalogs.get(frame);
843
+ if (built) return built;
844
+ const made = Object.freeze({
828
845
  componentNames: componentNamesFor(frame),
829
846
  actionNames: catalog.actionNames,
830
847
  data: catalog.data,
831
848
  schema: catalog.schema,
832
849
  renders: COMPONENT_RENDERINGS
833
- };
850
+ });
851
+ frameCatalogs.set(frame, made);
852
+ return made;
834
853
  }
835
854
 
836
855
  // src/generative/props-signature.ts
@@ -917,18 +936,121 @@ ${JSON.stringify(catalogs)}`;
917
936
  }
918
937
 
919
938
  // src/generative/expressions.ts
920
- var EXPRESSION_KEYS = [
921
- "$state",
922
- "$item",
923
- "$index",
924
- "$bindState",
925
- "$bindItem",
926
- "$cond",
927
- "$computed",
928
- "$template"
929
- ];
930
939
  function isExpression(value) {
931
- return typeof value === "object" && value !== null && !Array.isArray(value) && Object.keys(value).some((key) => EXPRESSION_KEYS.includes(key));
940
+ return expressionForm(value) !== void 0;
941
+ }
942
+ function expressionForm(value) {
943
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return void 0;
944
+ const record = value;
945
+ if (typeof record.$state === "string") return "$state";
946
+ if (typeof record.$item === "string") return "$item";
947
+ if (record.$index === true) return "$index";
948
+ if (typeof record.$bindState === "string") return "$bindState";
949
+ if (typeof record.$bindItem === "string") return "$bindItem";
950
+ if ("$cond" in record && "$then" in record && "$else" in record) return "$cond";
951
+ if (typeof record.$computed === "string") return "$computed";
952
+ if (typeof record.$template === "string") return "$template";
953
+ return void 0;
954
+ }
955
+ function condBranches(value) {
956
+ if (expressionForm(value) !== "$cond") return void 0;
957
+ const record = value;
958
+ return [record.$then, record.$else];
959
+ }
960
+
961
+ // src/generative/share-amount.ts
962
+ var DECIMAL = /^[-+]?(\d+(\.\d*)?|\.\d+)(e[-+]?\d+)?$/i;
963
+ function shareAmount(raw) {
964
+ if (typeof raw === "number") return raw;
965
+ if (typeof raw === "string" && DECIMAL.test(raw.trim())) return Number(raw);
966
+ return Number.NaN;
967
+ }
968
+
969
+ // src/generative/spec-shape.ts
970
+ function shown(value) {
971
+ if (Array.isArray(value)) return "a list";
972
+ if (typeof value === "bigint") return String(value);
973
+ if (typeof value === "symbol" || typeof value === "function") return `a ${typeof value}`;
974
+ try {
975
+ return String(JSON.stringify(value ?? null));
976
+ } catch {
977
+ return "a value that cannot be written out";
978
+ }
979
+ }
980
+ function isRecord(value) {
981
+ return typeof value === "object" && value !== null && !Array.isArray(value);
982
+ }
983
+ function specMalformation(spec) {
984
+ if (!isRecord(spec)) return `it is ${shown(spec)}, not a structure`;
985
+ if (spec.root !== void 0 && typeof spec.root !== "string") {
986
+ return `its "root" is ${shown(spec.root)}, not an element's key`;
987
+ }
988
+ if (!isRecord(spec.elements)) return 'it has no "elements" map';
989
+ for (const [key, element] of Object.entries(spec.elements)) {
990
+ const at = JSON.stringify(key);
991
+ if (!isRecord(element)) return `the element ${at} is not a structure`;
992
+ const { type, props, children, slots, repeat } = element;
993
+ if (typeof type !== "string") return `the element ${at} names no component "type"`;
994
+ if (props != null && !isRecord(props))
995
+ return `the element ${at} has "props" that are not a structure`;
996
+ if (children != null && !Array.isArray(children))
997
+ return `the element ${at} has "children" that are not a list`;
998
+ const child = Array.isArray(children) ? firstNotAKey(children) : void 0;
999
+ if (child)
1000
+ return `the element ${at} has a child that is ${shown(child.entry)}, not an element's key`;
1001
+ if (slots != null && (!isRecord(slots) || !Object.values(slots).every(Array.isArray))) {
1002
+ return `the element ${at} has "slots" that are not lists`;
1003
+ }
1004
+ const slotted = isRecord(slots) ? firstNotAKey(Object.values(slots).flatMap((entries) => entries)) : void 0;
1005
+ if (slotted) {
1006
+ return `the element ${at} has a slot entry that is ${shown(slotted.entry)}, not an element's key`;
1007
+ }
1008
+ if (repeat !== void 0 && !repeatsOver(repeat)) {
1009
+ return `the element ${at} has a "repeat" that names no "statePath"`;
1010
+ }
1011
+ }
1012
+ return void 0;
1013
+ }
1014
+ function firstNotAKey(entries) {
1015
+ for (const entry of entries) if (typeof entry !== "string") return { entry };
1016
+ return void 0;
1017
+ }
1018
+ function repeatsOver(repeat) {
1019
+ if (!isRecord(repeat)) return false;
1020
+ const { statePath } = repeat;
1021
+ return typeof statePath === "string" || isRecord(statePath) && typeof statePath.$item === "string";
1022
+ }
1023
+ function malformedLine(what) {
1024
+ return `the layout is not a well-formed spec: ${what}`;
1025
+ }
1026
+ function checksFailedLine(error) {
1027
+ let said;
1028
+ try {
1029
+ said = String(error);
1030
+ } catch {
1031
+ said = "an error that cannot be written out";
1032
+ }
1033
+ return `the checks failed on this layout (${said}): a defect in the checks, which no repair of the layout can fix`;
1034
+ }
1035
+
1036
+ // src/generative/zod-definition.ts
1037
+ function definitionOf2(schema) {
1038
+ if (typeof schema !== "object" || schema === null) return void 0;
1039
+ return schema._zod?.def;
1040
+ }
1041
+ function definitionChain(schema) {
1042
+ const chain = [];
1043
+ let def = definitionOf2(schema);
1044
+ for (let depth = 0; depth < 8 && def; depth += 1) {
1045
+ chain.push(def);
1046
+ if (def.innerType === void 0) return chain;
1047
+ def = definitionOf2(def.innerType);
1048
+ }
1049
+ return [];
1050
+ }
1051
+ function unwrapped(schema) {
1052
+ const chain = definitionChain(schema);
1053
+ return chain[chain.length - 1];
932
1054
  }
933
1055
 
934
1056
  // src/generative/paths.ts
@@ -1017,6 +1139,7 @@ function repeatListPathOf(spec, key, parents = parentMapOf(spec)) {
1017
1139
  }
1018
1140
 
1019
1141
  // src/generative/layout-fits.ts
1142
+ var MAX_COND_DEPTH = 8;
1020
1143
  function isUnder(root, path) {
1021
1144
  return path === root || path.startsWith(`${root}/`);
1022
1145
  }
@@ -1095,13 +1218,15 @@ function staleRepeats(spec, parents, root, fieldAt, side) {
1095
1218
  }
1096
1219
  return problems;
1097
1220
  }
1221
+ function withArticle(word) {
1222
+ return `${/^["']?[aeiou]/i.test(word) ? "an" : "a"} ${word}`;
1223
+ }
1098
1224
  function memberWords(name) {
1099
- return `${/^[aeiou]/i.test(name) ? "an" : "a"} ${JSON.stringify(name)}`;
1225
+ return withArticle(JSON.stringify(name));
1100
1226
  }
1101
1227
  function kindWords(kind) {
1102
- if (kind === "object") return "a structure";
1103
- if (kind === "document" || kind === "image") return "a file";
1104
- return `${/^[aeiou]/i.test(kind) ? "an" : "a"} ${kind} value`;
1228
+ const wrong = hasOwnProp(NOT_A_VALUE, kind) ? NOT_A_VALUE[kind] : void 0;
1229
+ return wrong ? wrong.what : withArticle(`${kind} value`);
1105
1230
  }
1106
1231
  var NOT_A_VALUE = {
1107
1232
  object: { what: "a structure", instead: "a structure is shown through its members" },
@@ -1135,16 +1260,6 @@ function listProps() {
1135
1260
  return found;
1136
1261
  }
1137
1262
  var VALUE_SCHEMAS = /* @__PURE__ */ new Set(["string", "number", "boolean", "enum", "literal"]);
1138
- function unwrapped(schema) {
1139
- let current = schema;
1140
- for (let depth = 0; depth < 8; depth += 1) {
1141
- const def = current.def;
1142
- if (!def) return void 0;
1143
- if (def.innerType === void 0) return def;
1144
- current = def.innerType;
1145
- }
1146
- return void 0;
1147
- }
1148
1263
  function listItemsOf(schema) {
1149
1264
  const def = unwrapped(schema);
1150
1265
  if (def?.type !== "array") return void 0;
@@ -1214,27 +1329,124 @@ function nonScalarReads(spec, parents, root, fieldAt) {
1214
1329
  );
1215
1330
  }
1216
1331
  };
1332
+ const readPath = (value) => {
1333
+ const form = expressionForm(value);
1334
+ const record = value;
1335
+ if (form === "$state" || form === "$bindState") return record[form];
1336
+ if (form === "$item" || form === "$bindItem") return itemPath(record[form]);
1337
+ return void 0;
1338
+ };
1339
+ const readsIndex = (value) => expressionForm(value) === "$index";
1340
+ const outcomes = (value, depth = 0) => {
1341
+ const branches = depth < MAX_COND_DEPTH ? condBranches(value) : void 0;
1342
+ return branches ? branches.flatMap((branch) => outcomes(branch, depth + 1)) : [value];
1343
+ };
1344
+ const amountPathRefusal = (path) => {
1345
+ const field = isUnder(root, path) ? fieldAt(path) : void 0;
1346
+ if (field && field.kind !== "number" && field.kind !== "unknown") {
1347
+ return `reads ${path}, which holds ${kindWords(field.kind)}, not a number`;
1348
+ }
1349
+ return void 0;
1350
+ };
1351
+ const amountRefusal = (amount) => {
1352
+ if (Number.isFinite(shareAmount(amount)) || readsIndex(amount)) return void 0;
1353
+ const path = readPath(amount);
1354
+ if (path === void 0) {
1355
+ const shown2 = isExpression(amount) ? "an expression that reads no number" : String(JSON.stringify(amount ?? null));
1356
+ return `is ${shown2}, not a number`;
1357
+ }
1358
+ return amountPathRefusal(path);
1359
+ };
1360
+ if (element.type === "ProportionBar") {
1361
+ const props = element.props ?? {};
1362
+ for (const prop of ["total", "of"]) {
1363
+ const refusals = outcomes(props[prop]).filter((outcome) => outcome !== null && outcome !== void 0).map(
1364
+ (outcome) => readsIndex(outcome) ? "is the repeat's index, not an amount" : amountRefusal(outcome)
1365
+ ).filter((refusal) => refusal !== void 0);
1366
+ for (const refusal of new Set(refusals)) {
1367
+ problems.push(
1368
+ `${key}: ProportionBar's ${prop} ${refusal}; a total or a ceiling is a number, or reads a path that holds one with { "$state" }`
1369
+ );
1370
+ }
1371
+ }
1372
+ }
1217
1373
  const inlineShares = (entries) => {
1218
1374
  if (element.type !== "ProportionBar") return entries;
1219
1375
  const { labelKey, valueKey } = element.props ?? {};
1220
1376
  if (typeof labelKey !== "string" || typeof valueKey !== "string") return entries;
1221
- const how = `each part is written as a structure with ${memberWords(labelKey)} member and ${memberWords(valueKey)} member, or the whole list is read with { "$state" }`;
1222
- return entries.filter((entry, index) => {
1223
- const part = `${key}: ProportionBar's part ${index + 1}`;
1377
+ const how = `each part is written as a structure with ${memberWords(labelKey)} member and ${memberWords(valueKey)} member holding a number, or the whole list is read with { "$state" }`;
1378
+ const templateAmount = (amount) => {
1379
+ if (expressionForm(amount) !== "$template") return void 0;
1380
+ const text = amount.$template;
1381
+ const sole = /^\s*(\$\{[^}]+\})\s*$/.exec(text)?.[1];
1382
+ if (sole !== void 0) {
1383
+ const [path] = interpolatedPaths(sole, itemPath);
1384
+ return path === void 0 ? "more" : { path };
1385
+ }
1386
+ return interpolatedPaths(text, itemPath).length > 0 ? "more" : { text };
1387
+ };
1388
+ const inlineAmountRefusal = (amount) => {
1389
+ if (expressionForm(amount) === "$computed") {
1390
+ return "is a $computed, which a page has no function to resolve, not a number";
1391
+ }
1392
+ const written = templateAmount(amount);
1393
+ if (written === void 0) return amountRefusal(amount);
1394
+ if (written === "more") {
1395
+ return "is a template that writes text beside its value, not a number";
1396
+ }
1397
+ if ("path" in written) return amountPathRefusal(written.path);
1398
+ return Number.isFinite(shareAmount(written.text)) ? void 0 : `is a template that writes ${JSON.stringify(written.text)} out, not a number`;
1399
+ };
1400
+ const amountRefused = (part, amount) => {
1401
+ const refusal = inlineAmountRefusal(amount);
1402
+ if (refusal === void 0) return false;
1403
+ problems.push(`${part}'s ${JSON.stringify(valueKey)} ${refusal}; ${how}`);
1404
+ return true;
1405
+ };
1406
+ const sharePart = (part, entry) => {
1224
1407
  if (typeof entry !== "object" || entry === null || Array.isArray(entry)) {
1225
- const shown = Array.isArray(entry) ? "a list" : String(JSON.stringify(entry ?? null));
1226
- problems.push(`${part} is ${shown}, not a structure; ${how}`);
1227
- return false;
1408
+ const shown2 = Array.isArray(entry) ? "a list" : String(JSON.stringify(entry ?? null));
1409
+ problems.push(`${part} is ${shown2}, not a structure; ${how}`);
1410
+ return [];
1228
1411
  }
1229
1412
  if (isExpression(entry)) {
1230
- problems.push(`${part} is an expression, not a structure; ${how}`);
1231
- return false;
1413
+ const path = readPath(entry);
1414
+ if (path === void 0) {
1415
+ problems.push(`${part} is an expression that reads no structure; ${how}`);
1416
+ return [];
1417
+ }
1418
+ const field = isUnder(root, path) ? fieldAt(path) : void 0;
1419
+ if (!field || field.kind === "unknown") return [];
1420
+ if (field.kind !== "object") {
1421
+ problems.push(`${part} reads ${path}, which holds ${kindWords(field.kind)}; ${how}`);
1422
+ return [];
1423
+ }
1424
+ for (const name of [labelKey, valueKey]) {
1425
+ const member = field.fields.find((m) => m.name === name);
1426
+ if (!member) {
1427
+ problems.push(
1428
+ `${part} reads ${path}, which has no ${JSON.stringify(name)} member; ${how}`
1429
+ );
1430
+ } else if (name === valueKey && member.kind !== "number" && member.kind !== "unknown") {
1431
+ problems.push(
1432
+ `${part} reads ${path}, whose ${JSON.stringify(name)} member holds ${kindWords(member.kind)}, not a number; ${how}`
1433
+ );
1434
+ }
1435
+ }
1436
+ return [];
1232
1437
  }
1233
1438
  const missing = [labelKey, valueKey].find((name) => !hasOwnProp(entry, name));
1234
1439
  if (missing !== void 0) {
1235
1440
  problems.push(`${part} has no ${JSON.stringify(missing)} member; ${how}`);
1441
+ return [entry];
1236
1442
  }
1237
- return true;
1443
+ const { [valueKey]: amount, ...rest } = entry;
1444
+ const refused = outcomes(amount).map((outcome) => amountRefused(part, outcome)).some(Boolean);
1445
+ return refused ? [rest] : [entry];
1446
+ };
1447
+ return entries.flatMap((entry, index) => {
1448
+ const part = `${key}: ProportionBar's part ${index + 1}`;
1449
+ return outcomes(entry).flatMap((outcome) => sharePart(part, outcome));
1238
1450
  });
1239
1451
  };
1240
1452
  const walk = (prop, value) => {
@@ -1257,6 +1469,7 @@ function nonScalarReads(spec, parents, root, fieldAt) {
1257
1469
  }
1258
1470
  };
1259
1471
  for (const [prop, value] of Object.entries(element.props ?? {})) {
1472
+ if (element.type === "ProportionBar" && (prop === "total" || prop === "of")) continue;
1260
1473
  const items = listy?.get(prop);
1261
1474
  if (items === void 0 || Array.isArray(value)) {
1262
1475
  walk(prop, prop === "items" && Array.isArray(value) ? inlineShares(value) : value);
@@ -1316,18 +1529,113 @@ function isOffered(path, offered) {
1316
1529
  if (offered.bound.has(path) || offered.repeated.has(path)) return true;
1317
1530
  return offered.delegated.some((at) => path === at || path.startsWith(`${at}/`));
1318
1531
  }
1319
- function uncoveredUnder(field, path, offered) {
1532
+ function uncoveredUnder(field, path, offered, seeded) {
1320
1533
  if (isOffered(path, offered)) return [];
1321
1534
  if (field.kind === "object") {
1322
- return field.fields.filter((child) => child.required).flatMap((child) => uncoveredUnder(child, joinPath(path, child.name), offered));
1535
+ const seededBelow = seeded && field.required && field.defaultValue === void 0;
1536
+ const under = (child) => uncoveredUnder(child, joinPath(path, child.name), offered, seededBelow);
1537
+ const required = field.fields.filter((child) => child.required);
1538
+ if (required.length > 0) return required.flatMap(under);
1539
+ return field.fields.some(
1540
+ (child) => seededBelow && isFilled(child.defaultValue) || under(child).length === 0
1541
+ ) ? [] : [path];
1323
1542
  }
1324
1543
  return [path];
1325
1544
  }
1326
1545
  function layoutProblems(descriptor, spec) {
1546
+ const misshapen = descriptorMalformation(descriptor);
1547
+ if (misshapen !== void 0) return [misshapen];
1548
+ const malformed = specMalformation(spec);
1549
+ if (malformed !== void 0) return [malformedLine(malformed)];
1550
+ return fitCheck(descriptor, spec).problems;
1551
+ }
1552
+ function descriptorMalformation(descriptor) {
1553
+ if (typeof descriptor !== "object" || descriptor === null) {
1554
+ return "the layout has no descriptor to be checked against";
1555
+ }
1556
+ try {
1557
+ const budget = { fields: 0 };
1558
+ const { inputs, result } = descriptor;
1559
+ if (inputs != null && !Array.isArray(inputs)) {
1560
+ return `the descriptor's "inputs" is not a list of fields`;
1561
+ }
1562
+ for (const [index, input] of (inputs ?? []).entries()) {
1563
+ const problem = fieldMalformation(input, `input ${index + 1}`, /* @__PURE__ */ new Set(), budget);
1564
+ if (problem !== void 0) return `the descriptor's ${problem}`;
1565
+ }
1566
+ if (result != null) {
1567
+ if (!isField(result)) return `the descriptor's "result" is not a field`;
1568
+ const problem = fieldMalformation(result, '"result"', /* @__PURE__ */ new Set(), budget);
1569
+ if (problem !== void 0) return `the descriptor's ${problem}`;
1570
+ }
1571
+ return void 0;
1572
+ } catch (error) {
1573
+ let said;
1574
+ try {
1575
+ said = String(error);
1576
+ } catch {
1577
+ said = "an error that cannot be written out";
1578
+ }
1579
+ return `the descriptor cannot be read (${said})`;
1580
+ }
1581
+ }
1582
+ var MAX_FIELD_DEPTH = 64;
1583
+ var MAX_DESCRIPTOR_FIELDS = 1e4;
1584
+ function isField(value) {
1585
+ return typeof value === "object" && value !== null && !Array.isArray(value) && typeof value.kind === "string" && typeof value.name === "string";
1586
+ }
1587
+ function fieldMalformation(value, subject, ancestors, budget) {
1588
+ if (++budget.fields > MAX_DESCRIPTOR_FIELDS) {
1589
+ return `fields number more than ${MAX_DESCRIPTOR_FIELDS}, counted at each place one is held`;
1590
+ }
1591
+ if (!isField(value)) return `${subject} is not a field`;
1592
+ const named = `${subject} (${JSON.stringify(value.name)})`;
1593
+ if (ancestors.has(value)) return `${named} contains itself`;
1594
+ if (ancestors.size >= MAX_FIELD_DEPTH) {
1595
+ return `${named} is nested more than ${MAX_FIELD_DEPTH} fields deep`;
1596
+ }
1597
+ ancestors.add(value);
1598
+ try {
1599
+ if (value.kind === "object") {
1600
+ const { fields } = value;
1601
+ if (!Array.isArray(fields)) return `${named} has no list of member "fields"`;
1602
+ for (const [index, member] of fields.entries()) {
1603
+ const problem = fieldMalformation(
1604
+ member,
1605
+ `${named} member ${index + 1}`,
1606
+ ancestors,
1607
+ budget
1608
+ );
1609
+ if (problem !== void 0) return problem;
1610
+ }
1611
+ }
1612
+ if (value.kind === "list") {
1613
+ const problem = fieldMalformation(
1614
+ value.item,
1615
+ `${named} item`,
1616
+ ancestors,
1617
+ budget
1618
+ );
1619
+ if (problem !== void 0) return problem;
1620
+ }
1621
+ return void 0;
1622
+ } finally {
1623
+ ancestors.delete(value);
1624
+ }
1625
+ }
1626
+ function fitCheck(descriptor, spec) {
1327
1627
  try {
1328
- return collectLayoutProblems(descriptor, spec);
1628
+ return { problems: collectLayoutProblems(descriptor, spec), checksFailed: false };
1329
1629
  } catch (error) {
1330
- return [`the layout is not a well-formed spec: ${String(error)}`];
1630
+ return { problems: [checksFailedLine(error)], checksFailed: true };
1631
+ }
1632
+ }
1633
+ function shownAs(value) {
1634
+ if (typeof value === "string") return value;
1635
+ try {
1636
+ return String(JSON.stringify(value ?? null));
1637
+ } catch {
1638
+ return "a value that cannot be written out";
1331
1639
  }
1332
1640
  }
1333
1641
  function collectLayoutProblems(descriptor, spec) {
@@ -1339,14 +1647,14 @@ function collectLayoutProblems(descriptor, spec) {
1339
1647
  const path = typeof written === "string" ? absoluteHatchPath(spec, key, written, parents) : void 0;
1340
1648
  if (element.type === "MthdsField") {
1341
1649
  if (!path || !inputFieldAtPath(descriptor.inputs ?? [], path)) {
1342
- problems.push(`${key}: MthdsField delegates ${String(written)}, which no input has`);
1650
+ problems.push(`${key}: MthdsField delegates ${shownAs(written)}, which no input has`);
1343
1651
  } else {
1344
1652
  delegated.push(path);
1345
1653
  }
1346
1654
  }
1347
1655
  if (element.type === "MthdsResult") {
1348
1656
  if (!path || !descriptor.result || !resultFieldAtPath(descriptor.result, path)) {
1349
- problems.push(`${key}: MthdsResult delegates ${String(written)}, which no result has`);
1657
+ problems.push(`${key}: MthdsResult delegates ${shownAs(written)}, which no result has`);
1350
1658
  }
1351
1659
  }
1352
1660
  const [onlyKey] = element.children?.length === 1 ? element.children : [];
@@ -1357,12 +1665,12 @@ function collectLayoutProblems(descriptor, spec) {
1357
1665
  );
1358
1666
  }
1359
1667
  if (element.type === "Picture") {
1360
- const shown = written === "" ? repeatBasePathOf(spec, key, parents) : path ?? void 0;
1361
- const field = shown && descriptor.result ? resultFieldAtPath(descriptor.result, shown) : void 0;
1668
+ const shown2 = written === "" ? repeatBasePathOf(spec, key, parents) : path ?? void 0;
1669
+ const field = shown2 && descriptor.result ? resultFieldAtPath(descriptor.result, shown2) : void 0;
1362
1670
  if (!field) {
1363
1671
  problems.push(`${key}: Picture shows ${JSON.stringify(written)}, which no result has`);
1364
1672
  } else if (field.kind !== "image") {
1365
- problems.push(`${key}: Picture shows ${shown}, which holds a ${field.kind}, not an image`);
1673
+ problems.push(`${key}: Picture shows ${shown2}, which holds a ${field.kind}, not an image`);
1366
1674
  }
1367
1675
  }
1368
1676
  }
@@ -1397,7 +1705,7 @@ function collectLayoutProblems(descriptor, spec) {
1397
1705
  };
1398
1706
  for (const field of inputs) {
1399
1707
  if (!field.required) continue;
1400
- for (const path of uncoveredUnder(field, joinPath(INPUTS_ROOT, field.name), offered)) {
1708
+ for (const path of uncoveredUnder(field, joinPath(INPUTS_ROOT, field.name), offered, true)) {
1401
1709
  problems.push(`${path} is required, and the layout offers nowhere to enter it`);
1402
1710
  }
1403
1711
  }
@@ -1418,26 +1726,32 @@ function valueAt(value, path) {
1418
1726
  return at;
1419
1727
  }
1420
1728
  function isClosedVocabulary(schema) {
1421
- let current = schema;
1422
- for (let depth = 0; depth < 8; depth += 1) {
1423
- const def = current.def;
1424
- if (!def) return false;
1425
- if (def.type === "enum" || def.type === "literal") return true;
1426
- if (def.innerType === void 0) return false;
1427
- current = def.innerType;
1729
+ const type = unwrapped(schema)?.type;
1730
+ return type === "enum" || type === "literal";
1731
+ }
1732
+ function closedExpressionPaths(schema, value, path = []) {
1733
+ if (schema === void 0 || typeof value !== "object" || value === null) return [];
1734
+ if (path.length > 0 && isExpression(value)) return isClosedVocabulary(schema) ? [[...path]] : [];
1735
+ const def = unwrapped(schema);
1736
+ if (Array.isArray(value)) {
1737
+ return def?.type === "array" ? value.flatMap((entry, index) => closedExpressionPaths(def.element, entry, [...path, index])) : [];
1428
1738
  }
1429
- return false;
1739
+ if (def?.type !== "object" || !def.shape) return [];
1740
+ const shape = def.shape;
1741
+ return Object.entries(value).flatMap(
1742
+ ([name, member]) => hasOwnProp(shape, name) ? closedExpressionPaths(shape[name], member, [...path, name]) : []
1743
+ );
1430
1744
  }
1431
- function definitionOf2(catalog2, type) {
1745
+ function definitionOf3(catalog2, type) {
1432
1746
  const components2 = catalog2.data.components;
1433
1747
  return hasOwnProp(components2, type) ? components2[type] : void 0;
1434
1748
  }
1435
1749
  function propsSchemaOf(catalog2, type) {
1436
- const props = definitionOf2(catalog2, type)?.props;
1750
+ const props = definitionOf3(catalog2, type)?.props;
1437
1751
  return props && typeof props === "object" && "shape" in props ? props : void 0;
1438
1752
  }
1439
1753
  function eventsOf(catalog2, type) {
1440
- const definition = definitionOf2(catalog2, type);
1754
+ const definition = definitionOf3(catalog2, type);
1441
1755
  if (!definition) return void 0;
1442
1756
  return Array.isArray(definition.events) ? definition.events.filter((event) => typeof event === "string") : [];
1443
1757
  }
@@ -1484,12 +1798,19 @@ function deepestChain(spec) {
1484
1798
  return deepest;
1485
1799
  }
1486
1800
  function validateAgainstCatalog(spec, catalog2 = frameCatalog("page")) {
1801
+ const malformed = specMalformation(spec);
1802
+ if (malformed !== void 0) {
1803
+ return { ok: false, problems: [{ message: malformedLine(malformed) }] };
1804
+ }
1805
+ return catalogCheck(spec, catalog2).verdict;
1806
+ }
1807
+ function catalogCheck(spec, catalog2) {
1487
1808
  try {
1488
- return checkAgainstCatalog(spec, catalog2);
1809
+ return { verdict: checkAgainstCatalog(spec, catalog2), checksFailed: false };
1489
1810
  } catch (error) {
1490
1811
  return {
1491
- ok: false,
1492
- problems: [{ message: `the layout is not a well-formed spec: ${String(error)}` }]
1812
+ verdict: { ok: false, problems: [{ message: checksFailedLine(error) }] },
1813
+ checksFailed: true
1493
1814
  };
1494
1815
  }
1495
1816
  }
@@ -1541,6 +1862,20 @@ function checkAgainstCatalog(spec, catalog2) {
1541
1862
  problems.push({ elementKey: key, message: `unknown component type "${element.type}"` });
1542
1863
  }
1543
1864
  }
1865
+ for (const [key, element] of Object.entries(spec.elements)) {
1866
+ const slots = element.slots;
1867
+ if (typeof slots !== "object" || slots === null) continue;
1868
+ const definition = definitionOf3(catalog2, element.type);
1869
+ if (!definition) continue;
1870
+ const declared2 = Array.isArray(definition.slots) ? definition.slots : [];
1871
+ for (const name of Object.keys(slots)) {
1872
+ if (name !== "default" && declared2.includes(name)) continue;
1873
+ problems.push({
1874
+ elementKey: key,
1875
+ message: name === "default" ? `"${key}" puts children in a slot named "default"; a component's own content goes in "children".` : `"${key}" puts children in slot "${name}", which ${element.type} does not have; its content goes in "children".`
1876
+ });
1877
+ }
1878
+ }
1544
1879
  for (const [key, element] of Object.entries(spec.elements)) {
1545
1880
  const schema = propsSchemaOf(catalog2, element.type);
1546
1881
  if (!schema) continue;
@@ -1569,6 +1904,12 @@ function checkAgainstCatalog(spec, catalog2) {
1569
1904
  }
1570
1905
  continue;
1571
1906
  }
1907
+ for (const at of closedExpressionPaths(propSchema, value)) {
1908
+ problems.push({
1909
+ elementKey: key,
1910
+ message: `${element.type}.${name}.${at.map(String).join(".")} is one of a fixed set of names, so it must be written as a literal, never as an expression.`
1911
+ });
1912
+ }
1572
1913
  const parsed = propSchema.safeParse(value);
1573
1914
  const issues = parsed.success ? [] : parsed.error.issues.filter(
1574
1915
  (issue) => !issue.path.some((_, n) => isExpression(valueAt(value, issue.path.slice(0, n + 1))))
@@ -1852,26 +2193,38 @@ function seedLine(seed) {
1852
2193
  return `CREATIVE SEED (derive your direction from it; never reveal it): ${seed}`;
1853
2194
  }
1854
2195
  var REPAIR_ATTEMPTS = 2;
1855
- function layoutCheckProblems(spec, { frame, descriptor }) {
2196
+ function layoutCheck(spec, { frame, descriptor }) {
2197
+ const refused = (line) => ({ problems: [line], checksFailed: false });
1856
2198
  if (!FRAMES.includes(frame)) {
1857
- return [
1858
- `the layout names the frame ${JSON.stringify(frame)}, which is none of ${FRAMES.join(", ")}`
1859
- ];
1860
- }
1861
- if (typeof descriptor !== "object" || descriptor === null) {
1862
- return ["the layout has no descriptor to be checked against"];
2199
+ return {
2200
+ problems: [
2201
+ `the layout is checked against the frame ${JSON.stringify(frame)}, which is none of ${FRAMES.join(", ")}`
2202
+ ],
2203
+ checksFailed: true
2204
+ };
1863
2205
  }
2206
+ const misshapen = descriptorMalformation(descriptor);
2207
+ if (misshapen !== void 0) return { problems: [misshapen], checksFailed: true };
2208
+ const malformed = specMalformation(spec);
2209
+ if (malformed !== void 0) return refused(malformedLine(malformed));
1864
2210
  try {
1865
- const verdict = validateAgainstCatalog(spec, frameCatalog(frame));
1866
- const invalid = verdict.ok ? [] : formatProblems(verdict.problems).split("\n");
2211
+ const catalogs = catalogCheck(spec, frameCatalog(frame));
2212
+ const invalid = catalogs.verdict.ok ? [] : formatProblems(catalogs.verdict.problems).split("\n");
1867
2213
  const runless = frame !== "result" && descriptor.inputs && !pressRuns(spec) ? [
1868
2214
  "the layout has no control that runs the method: bind `run` under a control's `on.press`"
1869
2215
  ] : [];
1870
- return [...invalid, ...runless, ...layoutProblems(descriptor, spec)];
2216
+ const fit = fitCheck(descriptor, spec);
2217
+ return {
2218
+ problems: [...invalid, ...runless, ...fit.problems],
2219
+ checksFailed: catalogs.checksFailed || fit.checksFailed
2220
+ };
1871
2221
  } catch (error) {
1872
- return [`the layout is not a well-formed spec: ${String(error)}`];
2222
+ return { problems: [checksFailedLine(error)], checksFailed: true };
1873
2223
  }
1874
2224
  }
2225
+ function layoutCheckProblems(spec, check) {
2226
+ return layoutCheck(spec, check).problems;
2227
+ }
1875
2228
  function pressRuns(spec) {
1876
2229
  const isRun = (binding) => typeof binding === "object" && binding !== null && binding.action === "run";
1877
2230
  if (typeof spec !== "object" || spec === null) return false;
@@ -2136,7 +2489,7 @@ function jsonlLines(jsonl) {
2136
2489
  }
2137
2490
 
2138
2491
  // src/generative/state.ts
2139
- function isRecord(value) {
2492
+ function isRecord2(value) {
2140
2493
  return typeof value === "object" && value !== null && !Array.isArray(value);
2141
2494
  }
2142
2495
  function payloadToState(field, payload) {
@@ -2148,12 +2501,12 @@ function payloadToState(field, payload) {
2148
2501
  return content ? formatDateContent(content) : payload;
2149
2502
  }
2150
2503
  case "list": {
2151
- const items = Array.isArray(payload) ? payload : isRecord(payload) && Array.isArray(payload.items) ? payload.items : void 0;
2504
+ const items = Array.isArray(payload) ? payload : isRecord2(payload) && Array.isArray(payload.items) ? payload.items : void 0;
2152
2505
  if (!items) return payload;
2153
2506
  return items.map((item) => payloadToState(field.item, item));
2154
2507
  }
2155
2508
  case "object": {
2156
- if (!isRecord(payload)) return payload;
2509
+ if (!isRecord2(payload)) return payload;
2157
2510
  const out = { ...payload };
2158
2511
  for (const child of field.fields) {
2159
2512
  if (hasOwnProp(payload, child.name)) {
@@ -2216,6 +2569,6 @@ function findFixture(fixtures, pipeRef, id) {
2216
2569
  return found;
2217
2570
  }
2218
2571
 
2219
- export { COMPONENT_NAMES, COMPONENT_RENDERINGS, COMPOSER_COMPONENTS, CUSTOM_COMPONENTS, DESIGNER_BRIEF_CONCEPT, DESIGNER_CATALOG_CONCEPT, FRAMES, FRAME_COMPONENTS, ICON_NAMES, INPUTS_ROOT, METRIC_FORMATS, PICKED_SHADCN, PRODUCT_COMPONENTS, PROMPT_HASH, REPAIR_ATTEMPTS, RESULT_COMPONENTS, RESULT_ROOT, absoluteHatchPath, baseCatalog, catalog, componentNamesFor, designerCatalog, fieldAtSegments, findFixture, fixtureId, fixtureLabel, formatProblems, frameCatalog, frameComponents, inputBrief, inputFieldAtPath, isDelegatedInput, isDelegatedResult, joinPath, jsonlLines, layoutCheckProblems, layoutFits, layoutProblems, payloadToState, promptHashSubject, repeatBasePathOf, resultBrief, resultFieldAtPath, seedLine, segmentsUnder, specFromJsonl, specToJsonl, validateAgainstCatalog };
2220
- //# sourceMappingURL=chunk-VBXFGUCG.js.map
2221
- //# sourceMappingURL=chunk-VBXFGUCG.js.map
2572
+ export { COMPONENT_NAMES, COMPONENT_RENDERINGS, COMPOSER_COMPONENTS, CUSTOM_COMPONENTS, DESIGNER_BRIEF_CONCEPT, DESIGNER_CATALOG_CONCEPT, FRAMES, FRAME_COMPONENTS, ICON_NAMES, INPUTS_ROOT, METRIC_FORMATS, PICKED_SHADCN, PRODUCT_COMPONENTS, PROMPT_HASH, REPAIR_ATTEMPTS, RESULT_COMPONENTS, RESULT_ROOT, absoluteHatchPath, baseCatalog, catalog, componentNamesFor, definitionChain, designerCatalog, fieldAtSegments, findFixture, fixtureId, fixtureLabel, formatProblems, frameCatalog, frameComponents, inputBrief, inputFieldAtPath, isDelegatedInput, isDelegatedResult, joinPath, jsonlLines, layoutCheck, layoutCheckProblems, layoutFits, layoutProblems, payloadToState, promptHashSubject, repeatBasePathOf, resultBrief, resultFieldAtPath, seedLine, segmentsUnder, shareAmount, specFromJsonl, specToJsonl, unwrapped, validateAgainstCatalog };
2573
+ //# sourceMappingURL=chunk-XYS5KCXB.js.map
2574
+ //# sourceMappingURL=chunk-XYS5KCXB.js.map