@json-render/core 0.2.0 → 0.4.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.mjs CHANGED
@@ -46,19 +46,154 @@ function getByPath(obj, path) {
46
46
  }
47
47
  return current;
48
48
  }
49
+ function isNumericIndex(str) {
50
+ return /^\d+$/.test(str);
51
+ }
49
52
  function setByPath(obj, path, value) {
50
53
  const segments = path.startsWith("/") ? path.slice(1).split("/") : path.split("/");
51
54
  if (segments.length === 0) return;
52
55
  let current = obj;
53
56
  for (let i = 0; i < segments.length - 1; i++) {
54
57
  const segment = segments[i];
55
- if (!(segment in current) || typeof current[segment] !== "object") {
56
- current[segment] = {};
58
+ const nextSegment = segments[i + 1];
59
+ const nextIsNumeric = nextSegment !== void 0 && isNumericIndex(nextSegment);
60
+ if (Array.isArray(current)) {
61
+ const index = parseInt(segment, 10);
62
+ if (current[index] === void 0 || typeof current[index] !== "object") {
63
+ current[index] = nextIsNumeric ? [] : {};
64
+ }
65
+ current = current[index];
66
+ } else {
67
+ if (!(segment in current) || typeof current[segment] !== "object") {
68
+ current[segment] = nextIsNumeric ? [] : {};
69
+ }
70
+ current = current[segment];
57
71
  }
58
- current = current[segment];
59
72
  }
60
73
  const lastSegment = segments[segments.length - 1];
61
- current[lastSegment] = value;
74
+ if (Array.isArray(current)) {
75
+ const index = parseInt(lastSegment, 10);
76
+ current[index] = value;
77
+ } else {
78
+ current[lastSegment] = value;
79
+ }
80
+ }
81
+ function findFormValue(fieldName, params, data) {
82
+ if (params?.[fieldName] !== void 0) {
83
+ const val = params[fieldName];
84
+ if (typeof val !== "string" || !val.includes(".")) {
85
+ return val;
86
+ }
87
+ }
88
+ if (params) {
89
+ for (const key of Object.keys(params)) {
90
+ if (key.endsWith(`.${fieldName}`)) {
91
+ const val = params[key];
92
+ if (typeof val !== "string" || !val.includes(".")) {
93
+ return val;
94
+ }
95
+ }
96
+ }
97
+ }
98
+ if (data) {
99
+ for (const key of Object.keys(data)) {
100
+ if (key === fieldName || key.endsWith(`.${fieldName}`)) {
101
+ return data[key];
102
+ }
103
+ }
104
+ const prefixes = ["form", "newCustomer", "customer", ""];
105
+ for (const prefix of prefixes) {
106
+ const path = prefix ? `${prefix}/${fieldName}` : fieldName;
107
+ const val = getByPath(data, path);
108
+ if (val !== void 0) {
109
+ return val;
110
+ }
111
+ }
112
+ }
113
+ return void 0;
114
+ }
115
+ function parseSpecStreamLine(line) {
116
+ const trimmed = line.trim();
117
+ if (!trimmed || !trimmed.startsWith("{")) return null;
118
+ try {
119
+ const patch = JSON.parse(trimmed);
120
+ if (patch.op && patch.path !== void 0) {
121
+ return patch;
122
+ }
123
+ return null;
124
+ } catch {
125
+ return null;
126
+ }
127
+ }
128
+ function applySpecStreamPatch(obj, patch) {
129
+ if (patch.op === "set" || patch.op === "add" || patch.op === "replace") {
130
+ setByPath(obj, patch.path, patch.value);
131
+ } else if (patch.op === "remove") {
132
+ setByPath(obj, patch.path, void 0);
133
+ }
134
+ return obj;
135
+ }
136
+ function compileSpecStream(stream, initial = {}) {
137
+ const lines = stream.split("\n");
138
+ const result = { ...initial };
139
+ for (const line of lines) {
140
+ const patch = parseSpecStreamLine(line);
141
+ if (patch) {
142
+ applySpecStreamPatch(result, patch);
143
+ }
144
+ }
145
+ return result;
146
+ }
147
+ function createSpecStreamCompiler(initial = {}) {
148
+ let result = { ...initial };
149
+ let buffer = "";
150
+ const appliedPatches = [];
151
+ const processedLines = /* @__PURE__ */ new Set();
152
+ return {
153
+ push(chunk) {
154
+ buffer += chunk;
155
+ const newPatches = [];
156
+ const lines = buffer.split("\n");
157
+ buffer = lines.pop() || "";
158
+ for (const line of lines) {
159
+ const trimmed = line.trim();
160
+ if (!trimmed || processedLines.has(trimmed)) continue;
161
+ processedLines.add(trimmed);
162
+ const patch = parseSpecStreamLine(trimmed);
163
+ if (patch) {
164
+ applySpecStreamPatch(result, patch);
165
+ appliedPatches.push(patch);
166
+ newPatches.push(patch);
167
+ }
168
+ }
169
+ if (newPatches.length > 0) {
170
+ result = { ...result };
171
+ }
172
+ return { result, newPatches };
173
+ },
174
+ getResult() {
175
+ if (buffer.trim()) {
176
+ const patch = parseSpecStreamLine(buffer);
177
+ if (patch && !processedLines.has(buffer.trim())) {
178
+ processedLines.add(buffer.trim());
179
+ applySpecStreamPatch(result, patch);
180
+ appliedPatches.push(patch);
181
+ result = { ...result };
182
+ }
183
+ buffer = "";
184
+ }
185
+ return result;
186
+ },
187
+ getPatches() {
188
+ return [...appliedPatches];
189
+ },
190
+ reset(newInitial = {}) {
191
+ result = { ...newInitial };
192
+ buffer = "";
193
+ appliedPatches.length = 0;
194
+ processedLines.clear();
195
+ }
196
+ };
62
197
  }
63
198
 
64
199
  // src/visibility.ts
@@ -553,8 +688,367 @@ var check = {
553
688
  })
554
689
  };
555
690
 
556
- // src/catalog.ts
691
+ // src/schema.ts
557
692
  import { z as z5 } from "zod";
693
+ function createBuilder() {
694
+ return {
695
+ string: () => ({ kind: "string" }),
696
+ number: () => ({ kind: "number" }),
697
+ boolean: () => ({ kind: "boolean" }),
698
+ array: (item) => ({ kind: "array", inner: item }),
699
+ object: (shape) => ({ kind: "object", inner: shape }),
700
+ record: (value) => ({ kind: "record", inner: value }),
701
+ any: () => ({ kind: "any" }),
702
+ zod: () => ({ kind: "zod" }),
703
+ ref: (path) => ({ kind: "ref", inner: path }),
704
+ propsOf: (path) => ({ kind: "propsOf", inner: path }),
705
+ map: (entryShape) => ({ kind: "map", inner: entryShape }),
706
+ optional: () => ({ optional: true })
707
+ };
708
+ }
709
+ function defineSchema(builder, options) {
710
+ const s = createBuilder();
711
+ const definition = builder(s);
712
+ return {
713
+ definition,
714
+ promptTemplate: options?.promptTemplate,
715
+ createCatalog(catalog) {
716
+ return createCatalogFromSchema(this, catalog);
717
+ }
718
+ };
719
+ }
720
+ function createCatalogFromSchema(schema, catalogData) {
721
+ const components = catalogData.components;
722
+ const actions = catalogData.actions;
723
+ const componentNames = components ? Object.keys(components) : [];
724
+ const actionNames = actions ? Object.keys(actions) : [];
725
+ const zodSchema = buildZodSchemaFromDefinition(
726
+ schema.definition,
727
+ catalogData
728
+ );
729
+ return {
730
+ schema,
731
+ data: catalogData,
732
+ componentNames,
733
+ actionNames,
734
+ prompt(options = {}) {
735
+ return generatePrompt(this, options);
736
+ },
737
+ jsonSchema() {
738
+ return zodToJsonSchema(zodSchema);
739
+ },
740
+ validate(spec) {
741
+ const result = zodSchema.safeParse(spec);
742
+ if (result.success) {
743
+ return {
744
+ success: true,
745
+ data: result.data
746
+ };
747
+ }
748
+ return { success: false, error: result.error };
749
+ },
750
+ zodSchema() {
751
+ return zodSchema;
752
+ },
753
+ get _specType() {
754
+ throw new Error("_specType is only for type inference");
755
+ }
756
+ };
757
+ }
758
+ function buildZodSchemaFromDefinition(definition, catalogData) {
759
+ return buildZodType(definition.spec, catalogData);
760
+ }
761
+ function buildZodType(schemaType, catalogData) {
762
+ switch (schemaType.kind) {
763
+ case "string":
764
+ return z5.string();
765
+ case "number":
766
+ return z5.number();
767
+ case "boolean":
768
+ return z5.boolean();
769
+ case "any":
770
+ return z5.any();
771
+ case "array": {
772
+ const inner = buildZodType(schemaType.inner, catalogData);
773
+ return z5.array(inner);
774
+ }
775
+ case "object": {
776
+ const shape = schemaType.inner;
777
+ const zodShape = {};
778
+ for (const [key, value] of Object.entries(shape)) {
779
+ let zodType = buildZodType(value, catalogData);
780
+ if (value.optional) {
781
+ zodType = zodType.optional();
782
+ }
783
+ zodShape[key] = zodType;
784
+ }
785
+ return z5.object(zodShape);
786
+ }
787
+ case "record": {
788
+ const inner = buildZodType(schemaType.inner, catalogData);
789
+ return z5.record(z5.string(), inner);
790
+ }
791
+ case "ref": {
792
+ const path = schemaType.inner;
793
+ const keys = getKeysFromPath(path, catalogData);
794
+ if (keys.length === 0) {
795
+ return z5.string();
796
+ }
797
+ if (keys.length === 1) {
798
+ return z5.literal(keys[0]);
799
+ }
800
+ return z5.enum(keys);
801
+ }
802
+ case "propsOf": {
803
+ const path = schemaType.inner;
804
+ const propsSchemas = getPropsFromPath(path, catalogData);
805
+ if (propsSchemas.length === 0) {
806
+ return z5.record(z5.string(), z5.unknown());
807
+ }
808
+ if (propsSchemas.length === 1) {
809
+ return propsSchemas[0];
810
+ }
811
+ return z5.record(z5.string(), z5.unknown());
812
+ }
813
+ default:
814
+ return z5.unknown();
815
+ }
816
+ }
817
+ function getKeysFromPath(path, catalogData) {
818
+ const parts = path.split(".");
819
+ let current = { catalog: catalogData };
820
+ for (const part of parts) {
821
+ if (current && typeof current === "object") {
822
+ current = current[part];
823
+ } else {
824
+ return [];
825
+ }
826
+ }
827
+ if (current && typeof current === "object") {
828
+ return Object.keys(current);
829
+ }
830
+ return [];
831
+ }
832
+ function getPropsFromPath(path, catalogData) {
833
+ const parts = path.split(".");
834
+ let current = { catalog: catalogData };
835
+ for (const part of parts) {
836
+ if (current && typeof current === "object") {
837
+ current = current[part];
838
+ } else {
839
+ return [];
840
+ }
841
+ }
842
+ if (current && typeof current === "object") {
843
+ return Object.values(current).map((entry) => entry.props).filter((props) => props !== void 0);
844
+ }
845
+ return [];
846
+ }
847
+ function generatePrompt(catalog, options) {
848
+ if (catalog.schema.promptTemplate) {
849
+ const context = {
850
+ catalog: catalog.data,
851
+ componentNames: catalog.componentNames,
852
+ actionNames: catalog.actionNames,
853
+ options,
854
+ formatZodType
855
+ };
856
+ return catalog.schema.promptTemplate(context);
857
+ }
858
+ const {
859
+ system = "You are a UI generator that outputs JSON.",
860
+ customRules = []
861
+ } = options;
862
+ const lines = [];
863
+ lines.push(system);
864
+ lines.push("");
865
+ lines.push("OUTPUT FORMAT:");
866
+ lines.push(
867
+ "Output JSONL (one JSON object per line) with patches to build a UI tree."
868
+ );
869
+ lines.push(
870
+ "Each line is a JSON patch operation. Start with the root, then add each element."
871
+ );
872
+ lines.push("");
873
+ lines.push("Example output (each line is a separate JSON object):");
874
+ lines.push("");
875
+ lines.push(`{"op":"set","path":"/root","value":"card-1"}
876
+ {"op":"set","path":"/elements/card-1","value":{"key":"card-1","type":"Card","props":{"title":"Dashboard"},"children":["metric-1","chart-1"],"parentKey":""}}
877
+ {"op":"set","path":"/elements/metric-1","value":{"key":"metric-1","type":"Metric","props":{"label":"Revenue","valuePath":"analytics.revenue","format":"currency"},"children":[],"parentKey":"card-1"}}
878
+ {"op":"set","path":"/elements/chart-1","value":{"key":"chart-1","type":"Chart","props":{"type":"bar","dataPath":"analytics.salesByRegion"},"children":[],"parentKey":"card-1"}}`);
879
+ lines.push("");
880
+ const components = catalog.data.components;
881
+ if (components) {
882
+ lines.push(`AVAILABLE COMPONENTS (${catalog.componentNames.length}):`);
883
+ lines.push("");
884
+ for (const [name, def] of Object.entries(components)) {
885
+ const propsStr = def.props ? formatZodType(def.props) : "{}";
886
+ const hasChildren = def.slots && def.slots.length > 0;
887
+ const childrenStr = hasChildren ? " [accepts children]" : "";
888
+ const descStr = def.description ? ` - ${def.description}` : "";
889
+ lines.push(`- ${name}: ${propsStr}${descStr}${childrenStr}`);
890
+ }
891
+ lines.push("");
892
+ }
893
+ const actions = catalog.data.actions;
894
+ if (actions && catalog.actionNames.length > 0) {
895
+ lines.push("AVAILABLE ACTIONS:");
896
+ lines.push("");
897
+ for (const [name, def] of Object.entries(actions)) {
898
+ lines.push(`- ${name}${def.description ? `: ${def.description}` : ""}`);
899
+ }
900
+ lines.push("");
901
+ }
902
+ lines.push("RULES:");
903
+ const baseRules = [
904
+ "Output ONLY JSONL patches - one JSON object per line, no markdown, no code fences",
905
+ 'First line sets root: {"op":"set","path":"/root","value":"<root-key>"}',
906
+ 'Then add each element: {"op":"set","path":"/elements/<key>","value":{...}}',
907
+ "ONLY use components listed above",
908
+ "Each element value needs: key, type, props, children (array of child keys), parentKey",
909
+ "Use unique keys (e.g., 'header', 'metric-1', 'chart-revenue')",
910
+ "Root element's parentKey is empty string, children reference their parent's key"
911
+ ];
912
+ const allRules = [...baseRules, ...customRules];
913
+ allRules.forEach((rule, i) => {
914
+ lines.push(`${i + 1}. ${rule}`);
915
+ });
916
+ return lines.join("\n");
917
+ }
918
+ function getZodTypeName(schema) {
919
+ if (!schema || !schema._def) return "";
920
+ const def = schema._def;
921
+ return def.typeName ?? def.type ?? "";
922
+ }
923
+ function formatZodType(schema) {
924
+ if (!schema || !schema._def) return "unknown";
925
+ const def = schema._def;
926
+ const typeName = getZodTypeName(schema);
927
+ switch (typeName) {
928
+ case "ZodString":
929
+ case "string":
930
+ return "string";
931
+ case "ZodNumber":
932
+ case "number":
933
+ return "number";
934
+ case "ZodBoolean":
935
+ case "boolean":
936
+ return "boolean";
937
+ case "ZodLiteral":
938
+ case "literal":
939
+ return JSON.stringify(def.value);
940
+ case "ZodEnum":
941
+ case "enum": {
942
+ let values;
943
+ if (Array.isArray(def.values)) {
944
+ values = def.values;
945
+ } else if (def.entries && typeof def.entries === "object") {
946
+ values = Object.values(def.entries);
947
+ } else {
948
+ return "enum";
949
+ }
950
+ return values.map((v) => `"${v}"`).join(" | ");
951
+ }
952
+ case "ZodArray":
953
+ case "array": {
954
+ const inner = def.type ?? def.element;
955
+ return inner ? `Array<${formatZodType(inner)}>` : "Array<unknown>";
956
+ }
957
+ case "ZodObject":
958
+ case "object": {
959
+ const shape = typeof def.shape === "function" ? def.shape() : def.shape;
960
+ if (!shape) return "object";
961
+ const props = Object.entries(shape).map(([key, value]) => {
962
+ const innerTypeName = getZodTypeName(value);
963
+ const isOptional = innerTypeName === "ZodOptional" || innerTypeName === "ZodNullable" || innerTypeName === "optional" || innerTypeName === "nullable";
964
+ return `${key}${isOptional ? "?" : ""}: ${formatZodType(value)}`;
965
+ }).join(", ");
966
+ return `{ ${props} }`;
967
+ }
968
+ case "ZodOptional":
969
+ case "optional":
970
+ case "ZodNullable":
971
+ case "nullable": {
972
+ const inner = def.innerType ?? def.wrapped;
973
+ return inner ? formatZodType(inner) : "unknown";
974
+ }
975
+ case "ZodUnion":
976
+ case "union": {
977
+ const options = def.options;
978
+ return options ? options.map((opt) => formatZodType(opt)).join(" | ") : "unknown";
979
+ }
980
+ default:
981
+ return "unknown";
982
+ }
983
+ }
984
+ function zodToJsonSchema(schema) {
985
+ const def = schema._def;
986
+ const typeName = def.typeName ?? "";
987
+ switch (typeName) {
988
+ case "ZodString":
989
+ return { type: "string" };
990
+ case "ZodNumber":
991
+ return { type: "number" };
992
+ case "ZodBoolean":
993
+ return { type: "boolean" };
994
+ case "ZodLiteral":
995
+ return { const: def.value };
996
+ case "ZodEnum":
997
+ return { enum: def.values };
998
+ case "ZodArray": {
999
+ const inner = def.type;
1000
+ return {
1001
+ type: "array",
1002
+ items: inner ? zodToJsonSchema(inner) : {}
1003
+ };
1004
+ }
1005
+ case "ZodObject": {
1006
+ const shape = def.shape?.();
1007
+ if (!shape) return { type: "object" };
1008
+ const properties = {};
1009
+ const required = [];
1010
+ for (const [key, value] of Object.entries(shape)) {
1011
+ properties[key] = zodToJsonSchema(value);
1012
+ const innerDef = value._def;
1013
+ if (innerDef.typeName !== "ZodOptional" && innerDef.typeName !== "ZodNullable") {
1014
+ required.push(key);
1015
+ }
1016
+ }
1017
+ return {
1018
+ type: "object",
1019
+ properties,
1020
+ required: required.length > 0 ? required : void 0,
1021
+ additionalProperties: false
1022
+ };
1023
+ }
1024
+ case "ZodRecord": {
1025
+ const valueType = def.valueType;
1026
+ return {
1027
+ type: "object",
1028
+ additionalProperties: valueType ? zodToJsonSchema(valueType) : true
1029
+ };
1030
+ }
1031
+ case "ZodOptional":
1032
+ case "ZodNullable": {
1033
+ const inner = def.innerType;
1034
+ return inner ? zodToJsonSchema(inner) : {};
1035
+ }
1036
+ case "ZodUnion": {
1037
+ const options = def.options;
1038
+ return options ? { anyOf: options.map(zodToJsonSchema) } : {};
1039
+ }
1040
+ case "ZodAny":
1041
+ return {};
1042
+ default:
1043
+ return {};
1044
+ }
1045
+ }
1046
+ function defineCatalog(schema, catalog) {
1047
+ return schema.createCatalog(catalog);
1048
+ }
1049
+
1050
+ // src/catalog.ts
1051
+ import { z as z6 } from "zod";
558
1052
  function createCatalog(config) {
559
1053
  const {
560
1054
  name = "unnamed",
@@ -568,37 +1062,37 @@ function createCatalog(config) {
568
1062
  const functionNames = Object.keys(functions);
569
1063
  const componentSchemas = componentNames.map((componentName) => {
570
1064
  const def = components[componentName];
571
- return z5.object({
572
- key: z5.string(),
573
- type: z5.literal(componentName),
1065
+ return z6.object({
1066
+ key: z6.string(),
1067
+ type: z6.literal(componentName),
574
1068
  props: def.props,
575
- children: z5.array(z5.string()).optional(),
576
- parentKey: z5.string().nullable().optional(),
1069
+ children: z6.array(z6.string()).optional(),
1070
+ parentKey: z6.string().nullable().optional(),
577
1071
  visible: VisibilityConditionSchema.optional()
578
1072
  });
579
1073
  });
580
1074
  let elementSchema;
581
1075
  if (componentSchemas.length === 0) {
582
- elementSchema = z5.object({
583
- key: z5.string(),
584
- type: z5.string(),
585
- props: z5.record(z5.string(), z5.unknown()),
586
- children: z5.array(z5.string()).optional(),
587
- parentKey: z5.string().nullable().optional(),
1076
+ elementSchema = z6.object({
1077
+ key: z6.string(),
1078
+ type: z6.string(),
1079
+ props: z6.record(z6.string(), z6.unknown()),
1080
+ children: z6.array(z6.string()).optional(),
1081
+ parentKey: z6.string().nullable().optional(),
588
1082
  visible: VisibilityConditionSchema.optional()
589
1083
  });
590
1084
  } else if (componentSchemas.length === 1) {
591
1085
  elementSchema = componentSchemas[0];
592
1086
  } else {
593
- elementSchema = z5.discriminatedUnion("type", [
1087
+ elementSchema = z6.discriminatedUnion("type", [
594
1088
  componentSchemas[0],
595
1089
  componentSchemas[1],
596
1090
  ...componentSchemas.slice(2)
597
1091
  ]);
598
1092
  }
599
- const treeSchema = z5.object({
600
- root: z5.string(),
601
- elements: z5.record(z5.string(), elementSchema)
1093
+ const specSchema = z6.object({
1094
+ root: z6.string(),
1095
+ elements: z6.record(z6.string(), elementSchema)
602
1096
  });
603
1097
  return {
604
1098
  name,
@@ -610,7 +1104,7 @@ function createCatalog(config) {
610
1104
  actions,
611
1105
  functions,
612
1106
  elementSchema,
613
- treeSchema,
1107
+ specSchema,
614
1108
  hasComponent(type) {
615
1109
  return type in components;
616
1110
  },
@@ -627,8 +1121,8 @@ function createCatalog(config) {
627
1121
  }
628
1122
  return { success: false, error: result.error };
629
1123
  },
630
- validateTree(tree) {
631
- const result = treeSchema.safeParse(tree);
1124
+ validateSpec(spec) {
1125
+ const result = specSchema.safeParse(spec);
632
1126
  if (result.success) {
633
1127
  return { success: true, data: result.data };
634
1128
  }
@@ -684,6 +1178,155 @@ function generateCatalogPrompt(catalog) {
684
1178
  lines.push("");
685
1179
  return lines.join("\n");
686
1180
  }
1181
+ function formatZodType2(schema, isOptional = false) {
1182
+ const def = schema._def;
1183
+ const typeName = def.typeName ?? "";
1184
+ let result;
1185
+ switch (typeName) {
1186
+ case "ZodString":
1187
+ result = "string";
1188
+ break;
1189
+ case "ZodNumber":
1190
+ result = "number";
1191
+ break;
1192
+ case "ZodBoolean":
1193
+ result = "boolean";
1194
+ break;
1195
+ case "ZodLiteral":
1196
+ result = JSON.stringify(def.value);
1197
+ break;
1198
+ case "ZodEnum":
1199
+ result = def.values.map((v) => `"${v}"`).join("|");
1200
+ break;
1201
+ case "ZodNativeEnum":
1202
+ result = Object.values(def.values).map((v) => `"${v}"`).join("|");
1203
+ break;
1204
+ case "ZodArray":
1205
+ result = def.type ? `Array<${formatZodType2(def.type)}>` : "Array<unknown>";
1206
+ break;
1207
+ case "ZodObject": {
1208
+ if (!def.shape) {
1209
+ result = "object";
1210
+ break;
1211
+ }
1212
+ const shape = def.shape();
1213
+ const props = Object.entries(shape).map(([key, value]) => {
1214
+ const innerDef = value._def;
1215
+ const innerOptional = innerDef.typeName === "ZodOptional" || innerDef.typeName === "ZodNullable";
1216
+ return `${key}${innerOptional ? "?" : ""}: ${formatZodType2(value)}`;
1217
+ }).join(", ");
1218
+ result = `{ ${props} }`;
1219
+ break;
1220
+ }
1221
+ case "ZodOptional":
1222
+ return def.innerType ? formatZodType2(def.innerType, true) : "unknown?";
1223
+ case "ZodNullable":
1224
+ return def.innerType ? formatZodType2(def.innerType, true) : "unknown?";
1225
+ case "ZodDefault":
1226
+ return def.innerType ? formatZodType2(def.innerType, isOptional) : "unknown";
1227
+ case "ZodUnion":
1228
+ result = def.options ? def.options.map((opt) => formatZodType2(opt)).join("|") : "unknown";
1229
+ break;
1230
+ case "ZodNull":
1231
+ result = "null";
1232
+ break;
1233
+ case "ZodUndefined":
1234
+ result = "undefined";
1235
+ break;
1236
+ case "ZodAny":
1237
+ result = "any";
1238
+ break;
1239
+ case "ZodUnknown":
1240
+ result = "unknown";
1241
+ break;
1242
+ default:
1243
+ result = "unknown";
1244
+ }
1245
+ return isOptional ? `${result}?` : result;
1246
+ }
1247
+ function extractPropsFromSchema(schema) {
1248
+ const def = schema._def;
1249
+ const typeName = def.typeName ?? "";
1250
+ if (typeName !== "ZodObject" || !def.shape) {
1251
+ return [];
1252
+ }
1253
+ const shape = def.shape();
1254
+ return Object.entries(shape).map(([name, value]) => {
1255
+ const innerDef = value._def;
1256
+ const optional = innerDef.typeName === "ZodOptional" || innerDef.typeName === "ZodNullable";
1257
+ return {
1258
+ name,
1259
+ type: formatZodType2(value),
1260
+ optional
1261
+ };
1262
+ });
1263
+ }
1264
+ function formatPropsCompact(props) {
1265
+ if (props.length === 0) return "{}";
1266
+ const entries = props.map(
1267
+ (p) => `${p.name}${p.optional ? "?" : ""}: ${p.type}`
1268
+ );
1269
+ return `{ ${entries.join(", ")} }`;
1270
+ }
1271
+ function generateSystemPrompt(catalog, options = {}) {
1272
+ const {
1273
+ system = "You are a UI generator that outputs JSONL (JSON Lines) patches.",
1274
+ customRules = []
1275
+ } = options;
1276
+ const lines = [];
1277
+ lines.push(system);
1278
+ lines.push("");
1279
+ const componentCount = catalog.componentNames.length;
1280
+ lines.push(`AVAILABLE COMPONENTS (${componentCount}):`);
1281
+ lines.push("");
1282
+ for (const name of catalog.componentNames) {
1283
+ const def = catalog.components[name];
1284
+ const props = extractPropsFromSchema(def.props);
1285
+ const propsStr = formatPropsCompact(props);
1286
+ const hasChildrenStr = def.hasChildren ? " Has children." : "";
1287
+ const descStr = def.description ? ` ${def.description}` : "";
1288
+ lines.push(`- ${String(name)}: ${propsStr}${descStr}${hasChildrenStr}`);
1289
+ }
1290
+ lines.push("");
1291
+ if (catalog.actionNames.length > 0) {
1292
+ lines.push("AVAILABLE ACTIONS:");
1293
+ lines.push("");
1294
+ for (const name of catalog.actionNames) {
1295
+ const def = catalog.actions[name];
1296
+ lines.push(
1297
+ `- ${String(name)}${def.description ? `: ${def.description}` : ""}`
1298
+ );
1299
+ }
1300
+ lines.push("");
1301
+ }
1302
+ lines.push("OUTPUT FORMAT (JSONL):");
1303
+ lines.push('{"op":"set","path":"/root","value":"element-key"}');
1304
+ lines.push(
1305
+ '{"op":"add","path":"/elements/key","value":{"key":"...","type":"...","props":{...},"children":[...]}}'
1306
+ );
1307
+ lines.push("");
1308
+ lines.push("RULES:");
1309
+ const baseRules = [
1310
+ "First line sets /root to root element key",
1311
+ "Add elements with /elements/{key}",
1312
+ "Children array contains string keys, not objects",
1313
+ "Parent first, then children",
1314
+ "Each element needs: key, type, props",
1315
+ "ONLY use props listed above - never invent new props"
1316
+ ];
1317
+ const allRules = [...baseRules, ...customRules];
1318
+ allRules.forEach((rule, i) => {
1319
+ lines.push(`${i + 1}. ${rule}`);
1320
+ });
1321
+ lines.push("");
1322
+ if (catalog.functionNames.length > 0) {
1323
+ lines.push("CUSTOM VALIDATION FUNCTIONS:");
1324
+ lines.push(catalog.functionNames.map(String).join(", "));
1325
+ lines.push("");
1326
+ }
1327
+ lines.push("Generate JSONL:");
1328
+ return lines.join("\n");
1329
+ }
687
1330
  export {
688
1331
  ActionConfirmSchema,
689
1332
  ActionOnErrorSchema,
@@ -698,15 +1341,23 @@ export {
698
1341
  ValidationConfigSchema,
699
1342
  VisibilityConditionSchema,
700
1343
  action,
1344
+ applySpecStreamPatch,
701
1345
  builtInValidationFunctions,
702
1346
  check,
1347
+ compileSpecStream,
703
1348
  createCatalog,
1349
+ createSpecStreamCompiler,
1350
+ defineCatalog,
1351
+ defineSchema,
704
1352
  evaluateLogicExpression,
705
1353
  evaluateVisibility,
706
1354
  executeAction,
1355
+ findFormValue,
707
1356
  generateCatalogPrompt,
1357
+ generateSystemPrompt,
708
1358
  getByPath,
709
1359
  interpolateString,
1360
+ parseSpecStreamLine,
710
1361
  resolveAction,
711
1362
  resolveDynamicValue,
712
1363
  runValidation,