@pipelex/mthds-form 0.32.0 → 0.33.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/README.md +1 -1
- package/dist/{chunk-VBXFGUCG.js → chunk-4SRSGZWM.js} +333 -107
- package/dist/chunk-4SRSGZWM.js.map +1 -0
- package/dist/{chunk-PCNFELNT.js → chunk-UKTYADY3.js} +2 -2
- package/dist/{chunk-PCNFELNT.js.map → chunk-UKTYADY3.js.map} +1 -1
- package/dist/{field-renderer-Dz03dpig.d.ts → field-renderer-BYN6YrU-.d.ts} +6 -6
- package/dist/generative/headless/index.d.ts +47 -16
- package/dist/generative/headless/index.js +1 -1
- package/dist/generative/index.d.ts +56 -25
- package/dist/generative/index.js +424 -145
- package/dist/generative/index.js.map +1 -1
- package/dist/react/index.d.ts +27 -27
- package/dist/react/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-VBXFGUCG.js.map +0 -1
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ The input form for MTHDS methods, as a library: a headless kernel that maps the
|
|
|
4
4
|
|
|
5
5
|
It exists because "the form" is one problem that keeps being solved separately. A method declares its inputs; something has to decide what widget each input deserves, whether the Run button may light up, what shape the values take on the wire, and what a validation failure says to a person. That logic belongs in one place with tests around it, not copied into each surface that happens to need a form.
|
|
6
6
|
|
|
7
|
-
##
|
|
7
|
+
## Entry points
|
|
8
8
|
|
|
9
9
|
```ts
|
|
10
10
|
import { buildRunFields, computeReadiness } from '@pipelex/mthds-form'; // headless
|
|
@@ -778,59 +778,77 @@ var COMPONENT_NAMES = [
|
|
|
778
778
|
...CUSTOM_COMPONENTS,
|
|
779
779
|
...PRODUCT_COMPONENTS
|
|
780
780
|
];
|
|
781
|
-
var
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
"
|
|
785
|
-
"
|
|
786
|
-
"
|
|
787
|
-
"
|
|
788
|
-
"
|
|
789
|
-
"
|
|
790
|
-
"
|
|
791
|
-
"
|
|
792
|
-
"
|
|
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",
|
|
781
|
+
var FRAME_VOCABULARIES = {
|
|
782
|
+
composer: Object.freeze([
|
|
783
|
+
"Card",
|
|
784
|
+
"Stack",
|
|
785
|
+
"Grid",
|
|
786
|
+
"Separator",
|
|
787
|
+
"Heading",
|
|
788
|
+
"Text",
|
|
789
|
+
"Badge",
|
|
790
|
+
"Alert",
|
|
791
|
+
"Collapsible",
|
|
792
|
+
"Avatar",
|
|
809
793
|
"Input",
|
|
810
794
|
"Textarea",
|
|
811
795
|
"Select",
|
|
812
796
|
"Radio",
|
|
813
797
|
"Checkbox",
|
|
814
798
|
"Switch",
|
|
799
|
+
"Split",
|
|
800
|
+
"Tabs",
|
|
801
|
+
"Steps",
|
|
802
|
+
"Icon",
|
|
815
803
|
"Segmented",
|
|
816
804
|
"NumberInput",
|
|
817
|
-
"
|
|
818
|
-
|
|
819
|
-
|
|
805
|
+
"MthdsField",
|
|
806
|
+
"Section",
|
|
807
|
+
...COMPOSER_COMPONENTS,
|
|
808
|
+
"TextList"
|
|
809
|
+
]),
|
|
810
|
+
result: Object.freeze([
|
|
811
|
+
"Card",
|
|
812
|
+
"Stack",
|
|
813
|
+
"Grid",
|
|
814
|
+
"Separator",
|
|
815
|
+
"Heading",
|
|
816
|
+
"Text",
|
|
817
|
+
"Badge",
|
|
818
|
+
"Alert",
|
|
819
|
+
"Collapsible",
|
|
820
|
+
"Progress",
|
|
821
|
+
"Avatar",
|
|
822
|
+
"Split",
|
|
823
|
+
"Tabs",
|
|
824
|
+
"Icon",
|
|
825
|
+
"MthdsResult",
|
|
826
|
+
"DataTable",
|
|
827
|
+
"Metric",
|
|
828
|
+
"Section",
|
|
829
|
+
"SummaryRow",
|
|
830
|
+
...RESULT_COMPONENTS
|
|
831
|
+
])
|
|
820
832
|
};
|
|
833
|
+
var PAGE_VOCABULARY = Object.freeze(
|
|
834
|
+
COMPONENT_NAMES.filter((name) => !FRAME_COMPONENTS.includes(name))
|
|
835
|
+
);
|
|
821
836
|
function componentNamesFor(frame) {
|
|
822
|
-
|
|
823
|
-
const own = frame === "page" ? [] : [...FRAME_COMPONENTS];
|
|
824
|
-
return [...COMPONENT_NAMES, ...own].filter((name) => !excluded.has(name));
|
|
837
|
+
return frame === "page" ? PAGE_VOCABULARY : FRAME_VOCABULARIES[frame];
|
|
825
838
|
}
|
|
839
|
+
var frameCatalogs = /* @__PURE__ */ new Map();
|
|
826
840
|
function frameCatalog(frame) {
|
|
827
|
-
|
|
841
|
+
const built = frameCatalogs.get(frame);
|
|
842
|
+
if (built) return built;
|
|
843
|
+
const made = Object.freeze({
|
|
828
844
|
componentNames: componentNamesFor(frame),
|
|
829
845
|
actionNames: catalog.actionNames,
|
|
830
846
|
data: catalog.data,
|
|
831
847
|
schema: catalog.schema,
|
|
832
848
|
renders: COMPONENT_RENDERINGS
|
|
833
|
-
};
|
|
849
|
+
});
|
|
850
|
+
frameCatalogs.set(frame, made);
|
|
851
|
+
return made;
|
|
834
852
|
}
|
|
835
853
|
|
|
836
854
|
// src/generative/props-signature.ts
|
|
@@ -917,18 +935,106 @@ ${JSON.stringify(catalogs)}`;
|
|
|
917
935
|
}
|
|
918
936
|
|
|
919
937
|
// 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
938
|
function isExpression(value) {
|
|
931
|
-
return
|
|
939
|
+
return expressionForm(value) !== void 0;
|
|
940
|
+
}
|
|
941
|
+
function expressionForm(value) {
|
|
942
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return void 0;
|
|
943
|
+
const record = value;
|
|
944
|
+
if (typeof record.$state === "string") return "$state";
|
|
945
|
+
if (typeof record.$item === "string") return "$item";
|
|
946
|
+
if (record.$index === true) return "$index";
|
|
947
|
+
if (typeof record.$bindState === "string") return "$bindState";
|
|
948
|
+
if (typeof record.$bindItem === "string") return "$bindItem";
|
|
949
|
+
if ("$cond" in record && "$then" in record && "$else" in record) return "$cond";
|
|
950
|
+
if (typeof record.$computed === "string") return "$computed";
|
|
951
|
+
if (typeof record.$template === "string") return "$template";
|
|
952
|
+
return void 0;
|
|
953
|
+
}
|
|
954
|
+
function condBranches(value) {
|
|
955
|
+
if (expressionForm(value) !== "$cond") return void 0;
|
|
956
|
+
const record = value;
|
|
957
|
+
return [record.$then, record.$else];
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
// src/generative/share-amount.ts
|
|
961
|
+
function shareAmount(raw) {
|
|
962
|
+
if (typeof raw === "number") return raw;
|
|
963
|
+
if (typeof raw === "string" && raw.trim() !== "") return Number(raw);
|
|
964
|
+
return Number.NaN;
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
// src/generative/spec-shape.ts
|
|
968
|
+
function shown(value) {
|
|
969
|
+
if (Array.isArray(value)) return "a list";
|
|
970
|
+
if (typeof value === "bigint") return String(value);
|
|
971
|
+
if (typeof value === "symbol" || typeof value === "function") return `a ${typeof value}`;
|
|
972
|
+
try {
|
|
973
|
+
return String(JSON.stringify(value ?? null));
|
|
974
|
+
} catch {
|
|
975
|
+
return "a value that cannot be written out";
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
function isRecord(value) {
|
|
979
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
980
|
+
}
|
|
981
|
+
function specMalformation(spec) {
|
|
982
|
+
if (!isRecord(spec)) return `it is ${shown(spec)}, not a structure`;
|
|
983
|
+
if (!isRecord(spec.elements)) return 'it has no "elements" map';
|
|
984
|
+
for (const [key, element] of Object.entries(spec.elements)) {
|
|
985
|
+
const at = JSON.stringify(key);
|
|
986
|
+
if (!isRecord(element)) return `the element ${at} is not a structure`;
|
|
987
|
+
const { type, props, children, slots, repeat } = element;
|
|
988
|
+
if (typeof type !== "string") return `the element ${at} names no component "type"`;
|
|
989
|
+
if (props != null && !isRecord(props))
|
|
990
|
+
return `the element ${at} has "props" that are not a structure`;
|
|
991
|
+
if (children != null && !Array.isArray(children))
|
|
992
|
+
return `the element ${at} has "children" that are not a list`;
|
|
993
|
+
if (slots != null && (!isRecord(slots) || !Object.values(slots).every(Array.isArray))) {
|
|
994
|
+
return `the element ${at} has "slots" that are not lists`;
|
|
995
|
+
}
|
|
996
|
+
if (repeat !== void 0 && !repeatsOver(repeat)) {
|
|
997
|
+
return `the element ${at} has a "repeat" that names no "statePath"`;
|
|
998
|
+
}
|
|
999
|
+
}
|
|
1000
|
+
return void 0;
|
|
1001
|
+
}
|
|
1002
|
+
function repeatsOver(repeat) {
|
|
1003
|
+
if (!isRecord(repeat)) return false;
|
|
1004
|
+
const { statePath } = repeat;
|
|
1005
|
+
return typeof statePath === "string" || isRecord(statePath) && typeof statePath.$item === "string";
|
|
1006
|
+
}
|
|
1007
|
+
function malformedLine(what) {
|
|
1008
|
+
return `the layout is not a well-formed spec: ${what}`;
|
|
1009
|
+
}
|
|
1010
|
+
function checksFailedLine(error) {
|
|
1011
|
+
let said;
|
|
1012
|
+
try {
|
|
1013
|
+
said = String(error);
|
|
1014
|
+
} catch {
|
|
1015
|
+
said = "an error that cannot be written out";
|
|
1016
|
+
}
|
|
1017
|
+
return `the checks failed on this layout (${said}): a defect in the checks, which no repair of the layout can fix`;
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
// src/generative/zod-definition.ts
|
|
1021
|
+
function definitionOf2(schema) {
|
|
1022
|
+
if (typeof schema !== "object" || schema === null) return void 0;
|
|
1023
|
+
return schema._zod?.def;
|
|
1024
|
+
}
|
|
1025
|
+
function definitionChain(schema) {
|
|
1026
|
+
const chain = [];
|
|
1027
|
+
let def = definitionOf2(schema);
|
|
1028
|
+
for (let depth = 0; depth < 8 && def; depth += 1) {
|
|
1029
|
+
chain.push(def);
|
|
1030
|
+
if (def.innerType === void 0) return chain;
|
|
1031
|
+
def = definitionOf2(def.innerType);
|
|
1032
|
+
}
|
|
1033
|
+
return [];
|
|
1034
|
+
}
|
|
1035
|
+
function unwrapped(schema) {
|
|
1036
|
+
const chain = definitionChain(schema);
|
|
1037
|
+
return chain[chain.length - 1];
|
|
932
1038
|
}
|
|
933
1039
|
|
|
934
1040
|
// src/generative/paths.ts
|
|
@@ -1017,6 +1123,7 @@ function repeatListPathOf(spec, key, parents = parentMapOf(spec)) {
|
|
|
1017
1123
|
}
|
|
1018
1124
|
|
|
1019
1125
|
// src/generative/layout-fits.ts
|
|
1126
|
+
var MAX_COND_DEPTH = 8;
|
|
1020
1127
|
function isUnder(root, path) {
|
|
1021
1128
|
return path === root || path.startsWith(`${root}/`);
|
|
1022
1129
|
}
|
|
@@ -1095,13 +1202,15 @@ function staleRepeats(spec, parents, root, fieldAt, side) {
|
|
|
1095
1202
|
}
|
|
1096
1203
|
return problems;
|
|
1097
1204
|
}
|
|
1205
|
+
function withArticle(word) {
|
|
1206
|
+
return `${/^["']?[aeiou]/i.test(word) ? "an" : "a"} ${word}`;
|
|
1207
|
+
}
|
|
1098
1208
|
function memberWords(name) {
|
|
1099
|
-
return
|
|
1209
|
+
return withArticle(JSON.stringify(name));
|
|
1100
1210
|
}
|
|
1101
1211
|
function kindWords(kind) {
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
return `${/^[aeiou]/i.test(kind) ? "an" : "a"} ${kind} value`;
|
|
1212
|
+
const wrong = hasOwnProp(NOT_A_VALUE, kind) ? NOT_A_VALUE[kind] : void 0;
|
|
1213
|
+
return wrong ? wrong.what : withArticle(`${kind} value`);
|
|
1105
1214
|
}
|
|
1106
1215
|
var NOT_A_VALUE = {
|
|
1107
1216
|
object: { what: "a structure", instead: "a structure is shown through its members" },
|
|
@@ -1135,16 +1244,6 @@ function listProps() {
|
|
|
1135
1244
|
return found;
|
|
1136
1245
|
}
|
|
1137
1246
|
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
1247
|
function listItemsOf(schema) {
|
|
1149
1248
|
const def = unwrapped(schema);
|
|
1150
1249
|
if (def?.type !== "array") return void 0;
|
|
@@ -1214,27 +1313,84 @@ function nonScalarReads(spec, parents, root, fieldAt) {
|
|
|
1214
1313
|
);
|
|
1215
1314
|
}
|
|
1216
1315
|
};
|
|
1316
|
+
const readPath = (value) => {
|
|
1317
|
+
const form = expressionForm(value);
|
|
1318
|
+
const record = value;
|
|
1319
|
+
if (form === "$state" || form === "$bindState") return record[form];
|
|
1320
|
+
if (form === "$item" || form === "$bindItem") return itemPath(record[form]);
|
|
1321
|
+
return void 0;
|
|
1322
|
+
};
|
|
1323
|
+
const readsIndex = (value) => expressionForm(value) === "$index";
|
|
1324
|
+
const outcomes = (value, depth = 0) => {
|
|
1325
|
+
const branches = depth < MAX_COND_DEPTH ? condBranches(value) : void 0;
|
|
1326
|
+
return branches ? branches.flatMap((branch) => outcomes(branch, depth + 1)) : [value];
|
|
1327
|
+
};
|
|
1217
1328
|
const inlineShares = (entries) => {
|
|
1218
1329
|
if (element.type !== "ProportionBar") return entries;
|
|
1219
1330
|
const { labelKey, valueKey } = element.props ?? {};
|
|
1220
1331
|
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
|
-
|
|
1223
|
-
|
|
1332
|
+
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" }`;
|
|
1333
|
+
const amountRefused = (part, amount) => {
|
|
1334
|
+
if (Number.isFinite(shareAmount(amount)) || readsIndex(amount)) return false;
|
|
1335
|
+
const path = readPath(amount);
|
|
1336
|
+
if (path === void 0) {
|
|
1337
|
+
const shown2 = isExpression(amount) ? "an expression that reads no number" : String(JSON.stringify(amount ?? null));
|
|
1338
|
+
problems.push(`${part}'s ${JSON.stringify(valueKey)} is ${shown2}, not a number; ${how}`);
|
|
1339
|
+
return true;
|
|
1340
|
+
}
|
|
1341
|
+
const field = isUnder(root, path) ? fieldAt(path) : void 0;
|
|
1342
|
+
if (field && field.kind !== "number" && field.kind !== "unknown") {
|
|
1343
|
+
problems.push(
|
|
1344
|
+
`${part}'s ${JSON.stringify(valueKey)} reads ${path}, which holds ${kindWords(field.kind)}, not a number; ${how}`
|
|
1345
|
+
);
|
|
1346
|
+
return true;
|
|
1347
|
+
}
|
|
1348
|
+
return false;
|
|
1349
|
+
};
|
|
1350
|
+
const sharePart = (part, entry) => {
|
|
1224
1351
|
if (typeof entry !== "object" || entry === null || Array.isArray(entry)) {
|
|
1225
|
-
const
|
|
1226
|
-
problems.push(`${part} is ${
|
|
1227
|
-
return
|
|
1352
|
+
const shown2 = Array.isArray(entry) ? "a list" : String(JSON.stringify(entry ?? null));
|
|
1353
|
+
problems.push(`${part} is ${shown2}, not a structure; ${how}`);
|
|
1354
|
+
return [];
|
|
1228
1355
|
}
|
|
1229
1356
|
if (isExpression(entry)) {
|
|
1230
|
-
|
|
1231
|
-
|
|
1357
|
+
const path = readPath(entry);
|
|
1358
|
+
if (path === void 0) {
|
|
1359
|
+
problems.push(`${part} is an expression that reads no structure; ${how}`);
|
|
1360
|
+
return [];
|
|
1361
|
+
}
|
|
1362
|
+
const field = isUnder(root, path) ? fieldAt(path) : void 0;
|
|
1363
|
+
if (!field || field.kind === "unknown") return [];
|
|
1364
|
+
if (field.kind !== "object") {
|
|
1365
|
+
problems.push(`${part} reads ${path}, which holds ${kindWords(field.kind)}; ${how}`);
|
|
1366
|
+
return [];
|
|
1367
|
+
}
|
|
1368
|
+
for (const name of [labelKey, valueKey]) {
|
|
1369
|
+
const member = field.fields.find((m) => m.name === name);
|
|
1370
|
+
if (!member) {
|
|
1371
|
+
problems.push(
|
|
1372
|
+
`${part} reads ${path}, which has no ${JSON.stringify(name)} member; ${how}`
|
|
1373
|
+
);
|
|
1374
|
+
} else if (name === valueKey && member.kind !== "number" && member.kind !== "unknown") {
|
|
1375
|
+
problems.push(
|
|
1376
|
+
`${part} reads ${path}, whose ${JSON.stringify(name)} member holds ${kindWords(member.kind)}, not a number; ${how}`
|
|
1377
|
+
);
|
|
1378
|
+
}
|
|
1379
|
+
}
|
|
1380
|
+
return [];
|
|
1232
1381
|
}
|
|
1233
1382
|
const missing = [labelKey, valueKey].find((name) => !hasOwnProp(entry, name));
|
|
1234
1383
|
if (missing !== void 0) {
|
|
1235
1384
|
problems.push(`${part} has no ${JSON.stringify(missing)} member; ${how}`);
|
|
1385
|
+
return [entry];
|
|
1236
1386
|
}
|
|
1237
|
-
|
|
1387
|
+
const { [valueKey]: amount, ...rest } = entry;
|
|
1388
|
+
const refused = outcomes(amount).map((outcome) => amountRefused(part, outcome)).some(Boolean);
|
|
1389
|
+
return refused ? [rest] : [entry];
|
|
1390
|
+
};
|
|
1391
|
+
return entries.flatMap((entry, index) => {
|
|
1392
|
+
const part = `${key}: ProportionBar's part ${index + 1}`;
|
|
1393
|
+
return outcomes(entry).flatMap((outcome) => sharePart(part, outcome));
|
|
1238
1394
|
});
|
|
1239
1395
|
};
|
|
1240
1396
|
const walk = (prop, value) => {
|
|
@@ -1324,10 +1480,38 @@ function uncoveredUnder(field, path, offered) {
|
|
|
1324
1480
|
return [path];
|
|
1325
1481
|
}
|
|
1326
1482
|
function layoutProblems(descriptor, spec) {
|
|
1483
|
+
const misshapen = descriptorMalformation(descriptor);
|
|
1484
|
+
if (misshapen !== void 0) return [misshapen];
|
|
1485
|
+
const malformed = specMalformation(spec);
|
|
1486
|
+
if (malformed !== void 0) return [malformedLine(malformed)];
|
|
1487
|
+
return fitCheck(descriptor, spec).problems;
|
|
1488
|
+
}
|
|
1489
|
+
function descriptorMalformation(descriptor) {
|
|
1490
|
+
if (typeof descriptor !== "object" || descriptor === null) {
|
|
1491
|
+
return "the layout has no descriptor to be checked against";
|
|
1492
|
+
}
|
|
1493
|
+
const { inputs, result } = descriptor;
|
|
1494
|
+
if (inputs != null && !Array.isArray(inputs)) {
|
|
1495
|
+
return `the descriptor's "inputs" is not a list of fields`;
|
|
1496
|
+
}
|
|
1497
|
+
if (result != null && (typeof result !== "object" || Array.isArray(result) || typeof result.kind !== "string")) {
|
|
1498
|
+
return `the descriptor's "result" is not a field`;
|
|
1499
|
+
}
|
|
1500
|
+
return void 0;
|
|
1501
|
+
}
|
|
1502
|
+
function fitCheck(descriptor, spec) {
|
|
1327
1503
|
try {
|
|
1328
|
-
return collectLayoutProblems(descriptor, spec);
|
|
1504
|
+
return { problems: collectLayoutProblems(descriptor, spec), checksFailed: false };
|
|
1329
1505
|
} catch (error) {
|
|
1330
|
-
return
|
|
1506
|
+
return { problems: [checksFailedLine(error)], checksFailed: true };
|
|
1507
|
+
}
|
|
1508
|
+
}
|
|
1509
|
+
function shownAs(value) {
|
|
1510
|
+
if (typeof value === "string") return value;
|
|
1511
|
+
try {
|
|
1512
|
+
return String(JSON.stringify(value ?? null));
|
|
1513
|
+
} catch {
|
|
1514
|
+
return "a value that cannot be written out";
|
|
1331
1515
|
}
|
|
1332
1516
|
}
|
|
1333
1517
|
function collectLayoutProblems(descriptor, spec) {
|
|
@@ -1339,14 +1523,14 @@ function collectLayoutProblems(descriptor, spec) {
|
|
|
1339
1523
|
const path = typeof written === "string" ? absoluteHatchPath(spec, key, written, parents) : void 0;
|
|
1340
1524
|
if (element.type === "MthdsField") {
|
|
1341
1525
|
if (!path || !inputFieldAtPath(descriptor.inputs ?? [], path)) {
|
|
1342
|
-
problems.push(`${key}: MthdsField delegates ${
|
|
1526
|
+
problems.push(`${key}: MthdsField delegates ${shownAs(written)}, which no input has`);
|
|
1343
1527
|
} else {
|
|
1344
1528
|
delegated.push(path);
|
|
1345
1529
|
}
|
|
1346
1530
|
}
|
|
1347
1531
|
if (element.type === "MthdsResult") {
|
|
1348
1532
|
if (!path || !descriptor.result || !resultFieldAtPath(descriptor.result, path)) {
|
|
1349
|
-
problems.push(`${key}: MthdsResult delegates ${
|
|
1533
|
+
problems.push(`${key}: MthdsResult delegates ${shownAs(written)}, which no result has`);
|
|
1350
1534
|
}
|
|
1351
1535
|
}
|
|
1352
1536
|
const [onlyKey] = element.children?.length === 1 ? element.children : [];
|
|
@@ -1357,12 +1541,12 @@ function collectLayoutProblems(descriptor, spec) {
|
|
|
1357
1541
|
);
|
|
1358
1542
|
}
|
|
1359
1543
|
if (element.type === "Picture") {
|
|
1360
|
-
const
|
|
1361
|
-
const field =
|
|
1544
|
+
const shown2 = written === "" ? repeatBasePathOf(spec, key, parents) : path ?? void 0;
|
|
1545
|
+
const field = shown2 && descriptor.result ? resultFieldAtPath(descriptor.result, shown2) : void 0;
|
|
1362
1546
|
if (!field) {
|
|
1363
1547
|
problems.push(`${key}: Picture shows ${JSON.stringify(written)}, which no result has`);
|
|
1364
1548
|
} else if (field.kind !== "image") {
|
|
1365
|
-
problems.push(`${key}: Picture shows ${
|
|
1549
|
+
problems.push(`${key}: Picture shows ${shown2}, which holds a ${field.kind}, not an image`);
|
|
1366
1550
|
}
|
|
1367
1551
|
}
|
|
1368
1552
|
}
|
|
@@ -1418,26 +1602,32 @@ function valueAt(value, path) {
|
|
|
1418
1602
|
return at;
|
|
1419
1603
|
}
|
|
1420
1604
|
function isClosedVocabulary(schema) {
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1605
|
+
const type = unwrapped(schema)?.type;
|
|
1606
|
+
return type === "enum" || type === "literal";
|
|
1607
|
+
}
|
|
1608
|
+
function closedExpressionPaths(schema, value, path = []) {
|
|
1609
|
+
if (schema === void 0 || typeof value !== "object" || value === null) return [];
|
|
1610
|
+
if (path.length > 0 && isExpression(value)) return isClosedVocabulary(schema) ? [[...path]] : [];
|
|
1611
|
+
const def = unwrapped(schema);
|
|
1612
|
+
if (Array.isArray(value)) {
|
|
1613
|
+
return def?.type === "array" ? value.flatMap((entry, index) => closedExpressionPaths(def.element, entry, [...path, index])) : [];
|
|
1428
1614
|
}
|
|
1429
|
-
return
|
|
1615
|
+
if (def?.type !== "object" || !def.shape) return [];
|
|
1616
|
+
const shape = def.shape;
|
|
1617
|
+
return Object.entries(value).flatMap(
|
|
1618
|
+
([name, member]) => hasOwnProp(shape, name) ? closedExpressionPaths(shape[name], member, [...path, name]) : []
|
|
1619
|
+
);
|
|
1430
1620
|
}
|
|
1431
|
-
function
|
|
1621
|
+
function definitionOf3(catalog2, type) {
|
|
1432
1622
|
const components2 = catalog2.data.components;
|
|
1433
1623
|
return hasOwnProp(components2, type) ? components2[type] : void 0;
|
|
1434
1624
|
}
|
|
1435
1625
|
function propsSchemaOf(catalog2, type) {
|
|
1436
|
-
const props =
|
|
1626
|
+
const props = definitionOf3(catalog2, type)?.props;
|
|
1437
1627
|
return props && typeof props === "object" && "shape" in props ? props : void 0;
|
|
1438
1628
|
}
|
|
1439
1629
|
function eventsOf(catalog2, type) {
|
|
1440
|
-
const definition =
|
|
1630
|
+
const definition = definitionOf3(catalog2, type);
|
|
1441
1631
|
if (!definition) return void 0;
|
|
1442
1632
|
return Array.isArray(definition.events) ? definition.events.filter((event) => typeof event === "string") : [];
|
|
1443
1633
|
}
|
|
@@ -1484,12 +1674,19 @@ function deepestChain(spec) {
|
|
|
1484
1674
|
return deepest;
|
|
1485
1675
|
}
|
|
1486
1676
|
function validateAgainstCatalog(spec, catalog2 = frameCatalog("page")) {
|
|
1677
|
+
const malformed = specMalformation(spec);
|
|
1678
|
+
if (malformed !== void 0) {
|
|
1679
|
+
return { ok: false, problems: [{ message: malformedLine(malformed) }] };
|
|
1680
|
+
}
|
|
1681
|
+
return catalogCheck(spec, catalog2).verdict;
|
|
1682
|
+
}
|
|
1683
|
+
function catalogCheck(spec, catalog2) {
|
|
1487
1684
|
try {
|
|
1488
|
-
return checkAgainstCatalog(spec, catalog2);
|
|
1685
|
+
return { verdict: checkAgainstCatalog(spec, catalog2), checksFailed: false };
|
|
1489
1686
|
} catch (error) {
|
|
1490
1687
|
return {
|
|
1491
|
-
ok: false,
|
|
1492
|
-
|
|
1688
|
+
verdict: { ok: false, problems: [{ message: checksFailedLine(error) }] },
|
|
1689
|
+
checksFailed: true
|
|
1493
1690
|
};
|
|
1494
1691
|
}
|
|
1495
1692
|
}
|
|
@@ -1541,6 +1738,20 @@ function checkAgainstCatalog(spec, catalog2) {
|
|
|
1541
1738
|
problems.push({ elementKey: key, message: `unknown component type "${element.type}"` });
|
|
1542
1739
|
}
|
|
1543
1740
|
}
|
|
1741
|
+
for (const [key, element] of Object.entries(spec.elements)) {
|
|
1742
|
+
const slots = element.slots;
|
|
1743
|
+
if (typeof slots !== "object" || slots === null) continue;
|
|
1744
|
+
const definition = definitionOf3(catalog2, element.type);
|
|
1745
|
+
if (!definition) continue;
|
|
1746
|
+
const declared2 = Array.isArray(definition.slots) ? definition.slots : [];
|
|
1747
|
+
for (const name of Object.keys(slots)) {
|
|
1748
|
+
if (name !== "default" && declared2.includes(name)) continue;
|
|
1749
|
+
problems.push({
|
|
1750
|
+
elementKey: key,
|
|
1751
|
+
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".`
|
|
1752
|
+
});
|
|
1753
|
+
}
|
|
1754
|
+
}
|
|
1544
1755
|
for (const [key, element] of Object.entries(spec.elements)) {
|
|
1545
1756
|
const schema = propsSchemaOf(catalog2, element.type);
|
|
1546
1757
|
if (!schema) continue;
|
|
@@ -1569,6 +1780,12 @@ function checkAgainstCatalog(spec, catalog2) {
|
|
|
1569
1780
|
}
|
|
1570
1781
|
continue;
|
|
1571
1782
|
}
|
|
1783
|
+
for (const at of closedExpressionPaths(propSchema, value)) {
|
|
1784
|
+
problems.push({
|
|
1785
|
+
elementKey: key,
|
|
1786
|
+
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.`
|
|
1787
|
+
});
|
|
1788
|
+
}
|
|
1572
1789
|
const parsed = propSchema.safeParse(value);
|
|
1573
1790
|
const issues = parsed.success ? [] : parsed.error.issues.filter(
|
|
1574
1791
|
(issue) => !issue.path.some((_, n) => isExpression(valueAt(value, issue.path.slice(0, n + 1))))
|
|
@@ -1852,26 +2069,35 @@ function seedLine(seed) {
|
|
|
1852
2069
|
return `CREATIVE SEED (derive your direction from it; never reveal it): ${seed}`;
|
|
1853
2070
|
}
|
|
1854
2071
|
var REPAIR_ATTEMPTS = 2;
|
|
1855
|
-
function
|
|
2072
|
+
function layoutCheck(spec, { frame, descriptor }) {
|
|
2073
|
+
const refused = (line) => ({ problems: [line], checksFailed: false });
|
|
1856
2074
|
if (!FRAMES.includes(frame)) {
|
|
1857
|
-
return
|
|
2075
|
+
return refused(
|
|
1858
2076
|
`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"];
|
|
2077
|
+
);
|
|
1863
2078
|
}
|
|
2079
|
+
const misshapen = descriptorMalformation(descriptor);
|
|
2080
|
+
if (misshapen !== void 0) return refused(misshapen);
|
|
2081
|
+
const malformed = specMalformation(spec);
|
|
2082
|
+
if (malformed !== void 0) return refused(malformedLine(malformed));
|
|
1864
2083
|
try {
|
|
1865
|
-
const
|
|
1866
|
-
const invalid = verdict.ok ? [] : formatProblems(verdict.problems).split("\n");
|
|
2084
|
+
const catalogs = catalogCheck(spec, frameCatalog(frame));
|
|
2085
|
+
const invalid = catalogs.verdict.ok ? [] : formatProblems(catalogs.verdict.problems).split("\n");
|
|
1867
2086
|
const runless = frame !== "result" && descriptor.inputs && !pressRuns(spec) ? [
|
|
1868
2087
|
"the layout has no control that runs the method: bind `run` under a control's `on.press`"
|
|
1869
2088
|
] : [];
|
|
1870
|
-
|
|
2089
|
+
const fit = fitCheck(descriptor, spec);
|
|
2090
|
+
return {
|
|
2091
|
+
problems: [...invalid, ...runless, ...fit.problems],
|
|
2092
|
+
checksFailed: catalogs.checksFailed || fit.checksFailed
|
|
2093
|
+
};
|
|
1871
2094
|
} catch (error) {
|
|
1872
|
-
return
|
|
2095
|
+
return { problems: [checksFailedLine(error)], checksFailed: true };
|
|
1873
2096
|
}
|
|
1874
2097
|
}
|
|
2098
|
+
function layoutCheckProblems(spec, check) {
|
|
2099
|
+
return layoutCheck(spec, check).problems;
|
|
2100
|
+
}
|
|
1875
2101
|
function pressRuns(spec) {
|
|
1876
2102
|
const isRun = (binding) => typeof binding === "object" && binding !== null && binding.action === "run";
|
|
1877
2103
|
if (typeof spec !== "object" || spec === null) return false;
|
|
@@ -2136,7 +2362,7 @@ function jsonlLines(jsonl) {
|
|
|
2136
2362
|
}
|
|
2137
2363
|
|
|
2138
2364
|
// src/generative/state.ts
|
|
2139
|
-
function
|
|
2365
|
+
function isRecord2(value) {
|
|
2140
2366
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2141
2367
|
}
|
|
2142
2368
|
function payloadToState(field, payload) {
|
|
@@ -2148,12 +2374,12 @@ function payloadToState(field, payload) {
|
|
|
2148
2374
|
return content ? formatDateContent(content) : payload;
|
|
2149
2375
|
}
|
|
2150
2376
|
case "list": {
|
|
2151
|
-
const items = Array.isArray(payload) ? payload :
|
|
2377
|
+
const items = Array.isArray(payload) ? payload : isRecord2(payload) && Array.isArray(payload.items) ? payload.items : void 0;
|
|
2152
2378
|
if (!items) return payload;
|
|
2153
2379
|
return items.map((item) => payloadToState(field.item, item));
|
|
2154
2380
|
}
|
|
2155
2381
|
case "object": {
|
|
2156
|
-
if (!
|
|
2382
|
+
if (!isRecord2(payload)) return payload;
|
|
2157
2383
|
const out = { ...payload };
|
|
2158
2384
|
for (const child of field.fields) {
|
|
2159
2385
|
if (hasOwnProp(payload, child.name)) {
|
|
@@ -2216,6 +2442,6 @@ function findFixture(fixtures, pipeRef, id) {
|
|
|
2216
2442
|
return found;
|
|
2217
2443
|
}
|
|
2218
2444
|
|
|
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-
|
|
2221
|
-
//# sourceMappingURL=chunk-
|
|
2445
|
+
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 };
|
|
2446
|
+
//# sourceMappingURL=chunk-4SRSGZWM.js.map
|
|
2447
|
+
//# sourceMappingURL=chunk-4SRSGZWM.js.map
|