appflare 0.2.44 → 0.2.46
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/cli/schema-compiler.ts +7 -7
- package/cli/templates/dashboard/builders/functions/render-page/request-panel.ts +117 -17
- package/cli/templates/dashboard/builders/functions/render-page/scripts.ts +149 -0
- package/cli/utils/handler-discovery.ts +37 -2
- package/dist/cli/index.js +578 -369
- package/dist/cli/index.mjs +578 -369
- package/package.json +1 -1
package/cli/schema-compiler.ts
CHANGED
|
@@ -936,17 +936,17 @@ function emitDrizzleSchema(
|
|
|
936
936
|
}
|
|
937
937
|
}
|
|
938
938
|
|
|
939
|
-
const enumColumns = new Map<string, ColumnDefinition>();
|
|
940
|
-
for (const table of Object.
|
|
939
|
+
const enumColumns = new Map<string, { column: ColumnDefinition; tableName: string; fieldName: string }>();
|
|
940
|
+
for (const [tableName, table] of Object.entries(definition.tables)) {
|
|
941
941
|
for (const [fieldName, column] of Object.entries(table.columns)) {
|
|
942
942
|
if (
|
|
943
943
|
column.type === "enum" &&
|
|
944
944
|
column.enumValues &&
|
|
945
945
|
column.enumValues.length > 0
|
|
946
946
|
) {
|
|
947
|
-
const key = column.enumRef ?? `${fieldName}`;
|
|
947
|
+
const key = column.enumRef ?? `${tableName}_${fieldName}`;
|
|
948
948
|
if (!enumColumns.has(key)) {
|
|
949
|
-
enumColumns.set(key, column);
|
|
949
|
+
enumColumns.set(key, { column, tableName, fieldName });
|
|
950
950
|
}
|
|
951
951
|
}
|
|
952
952
|
}
|
|
@@ -954,9 +954,9 @@ function emitDrizzleSchema(
|
|
|
954
954
|
|
|
955
955
|
const enumTypeLines: string[] = [];
|
|
956
956
|
const enumCustomTypeLines: string[] = [];
|
|
957
|
-
for (const [key,
|
|
957
|
+
for (const [key, info] of enumColumns.entries()) {
|
|
958
958
|
const typeName = toPascalCase(key);
|
|
959
|
-
const valuesStr = column.enumValues!.map((v) => `"${v}"`).join(" | ");
|
|
959
|
+
const valuesStr = info.column.enumValues!.map((v) => `"${v}"`).join(" | ");
|
|
960
960
|
enumTypeLines.push(`export type ${typeName} = ${valuesStr};`);
|
|
961
961
|
enumCustomTypeLines.push(
|
|
962
962
|
`export const ${typeName}Column = t.customType<{ data: ${typeName}; dataNotNull: ${typeName} }>({ dataType: () => "text" });`,
|
|
@@ -978,7 +978,7 @@ function emitDrizzleSchema(
|
|
|
978
978
|
column.enumValues &&
|
|
979
979
|
column.enumValues.length > 0
|
|
980
980
|
) {
|
|
981
|
-
const enumKey = column.enumRef ?? fieldName
|
|
981
|
+
const enumKey = column.enumRef ?? `${tableName}_${fieldName}`;
|
|
982
982
|
const typeName = toPascalCase(enumKey);
|
|
983
983
|
const resolvedSqlName = column.sqlName ?? toSnakeCase(fieldName);
|
|
984
984
|
const needsExplicitName = resolvedSqlName !== fieldName;
|
|
@@ -1,9 +1,47 @@
|
|
|
1
|
-
import { DiscoveredHandlerOperation } from "../../../../../utils/handler-discovery";
|
|
1
|
+
import { DiscoveredArgField, DiscoveredHandlerOperation } from "../../../../../utils/handler-discovery";
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
const fieldInputClass =
|
|
4
|
+
"input input-xs input-bordered font-mono flex-1 bg-base-200/30 focus:bg-base-100 focus:border-primary transition-all rounded-lg border-base-200";
|
|
5
|
+
|
|
6
|
+
function renderObjectFieldInputs(fields: DiscoveredArgField[]): string {
|
|
7
|
+
return fields
|
|
8
|
+
.map((f) => {
|
|
9
|
+
const badge =
|
|
10
|
+
f.type !== "unknown"
|
|
11
|
+
? `<span class="badge badge-xs badge-ghost font-mono opacity-25 ml-1">${f.type}</span>`
|
|
12
|
+
: "";
|
|
13
|
+
|
|
14
|
+
if (f.type === "boolean") {
|
|
15
|
+
return `
|
|
16
|
+
<div class="flex items-center gap-2">
|
|
17
|
+
<input
|
|
18
|
+
type="checkbox"
|
|
19
|
+
data-obj-key="${f.name}"
|
|
20
|
+
data-obj-field-type="boolean"
|
|
21
|
+
class="checkbox checkbox-xs checkbox-primary shrink-0"
|
|
22
|
+
${f.defaultValue === "true" ? "checked" : ""}
|
|
23
|
+
/>
|
|
24
|
+
<span class="text-[10px] font-mono opacity-50">${f.name}${badge}</span>
|
|
25
|
+
</div>`;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const inputType =
|
|
29
|
+
f.type === "number" ? "number" : f.type === "date" ? "datetime-local" : "text";
|
|
30
|
+
|
|
31
|
+
return `
|
|
32
|
+
<div class="flex items-center gap-2">
|
|
33
|
+
<span class="text-[10px] font-mono opacity-50 w-20 shrink-0 truncate" title="${f.name}">${f.name}${badge}</span>
|
|
34
|
+
<input
|
|
35
|
+
type="${inputType}"
|
|
36
|
+
data-obj-key="${f.name}"
|
|
37
|
+
data-obj-field-type="${f.type}"
|
|
38
|
+
placeholder="${f.defaultValue ?? ""}"
|
|
39
|
+
value="${f.defaultValue ?? ""}"
|
|
40
|
+
class="${fieldInputClass}"
|
|
41
|
+
/>
|
|
42
|
+
</div>`;
|
|
43
|
+
})
|
|
44
|
+
.join("\n");
|
|
7
45
|
}
|
|
8
46
|
|
|
9
47
|
function renderArgRows(h: DiscoveredHandlerOperation): string {
|
|
@@ -14,17 +52,26 @@ function renderArgRows(h: DiscoveredHandlerOperation): string {
|
|
|
14
52
|
`;
|
|
15
53
|
}
|
|
16
54
|
|
|
55
|
+
const inputClass =
|
|
56
|
+
"input input-sm input-bordered font-mono w-full bg-base-200/30 focus:bg-base-100 focus:border-primary transition-all rounded-xl border-base-200";
|
|
57
|
+
|
|
17
58
|
return fields
|
|
18
59
|
.map((field) => {
|
|
19
|
-
const inputType = renderArgInputType(field.type);
|
|
20
|
-
const isCheckbox = inputType === "checkbox";
|
|
21
60
|
const label = `${field.name}${field.optional ? "" : " *"}`;
|
|
22
61
|
const badge =
|
|
23
62
|
field.type !== "unknown"
|
|
24
63
|
? `<span class="badge badge-xs badge-ghost font-mono opacity-40 ml-1">${field.type}</span>`
|
|
25
64
|
: "";
|
|
65
|
+
const optionalAlt = field.optional
|
|
66
|
+
? '<span class="label-text-alt text-[10px] opacity-30 italic">optional</span>'
|
|
67
|
+
: "";
|
|
68
|
+
const labelRow = `
|
|
69
|
+
<label class="label py-0.5">
|
|
70
|
+
<span class="label-text text-[11px] font-mono font-semibold">${label}${badge}</span>
|
|
71
|
+
${optionalAlt}
|
|
72
|
+
</label>`;
|
|
26
73
|
|
|
27
|
-
if (
|
|
74
|
+
if (field.type === "boolean") {
|
|
28
75
|
return `
|
|
29
76
|
<div class="flex items-center gap-3 py-1">
|
|
30
77
|
<input
|
|
@@ -36,27 +83,80 @@ function renderArgRows(h: DiscoveredHandlerOperation): string {
|
|
|
36
83
|
/>
|
|
37
84
|
<span class="text-sm font-mono opacity-70">${field.name}${badge}</span>
|
|
38
85
|
${field.optional ? '<span class="text-[10px] opacity-30 italic ml-auto">optional</span>' : ""}
|
|
39
|
-
</div
|
|
40
|
-
|
|
86
|
+
</div>`;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (field.type === "object") {
|
|
90
|
+
if (field.fields && field.fields.length > 0) {
|
|
91
|
+
return `
|
|
92
|
+
<div class="form-control">
|
|
93
|
+
${labelRow}
|
|
94
|
+
<div
|
|
95
|
+
data-arg-key="${field.name}"
|
|
96
|
+
data-arg-type="object"
|
|
97
|
+
class="border border-base-200 rounded-xl p-3 bg-base-200/20 flex flex-col gap-2"
|
|
98
|
+
>
|
|
99
|
+
${renderObjectFieldInputs(field.fields)}
|
|
100
|
+
</div>
|
|
101
|
+
</div>`;
|
|
102
|
+
}
|
|
103
|
+
// Fallback when schema isn't statically known
|
|
104
|
+
return `
|
|
105
|
+
<div class="form-control">
|
|
106
|
+
${labelRow}
|
|
107
|
+
<textarea
|
|
108
|
+
data-arg-key="${field.name}"
|
|
109
|
+
data-arg-type="object"
|
|
110
|
+
placeholder="{}"
|
|
111
|
+
rows="4"
|
|
112
|
+
class="textarea textarea-sm textarea-bordered font-mono w-full bg-base-200/30 focus:bg-base-100 focus:border-primary transition-all rounded-xl border-base-200 resize-y text-xs"
|
|
113
|
+
${!field.optional ? "required" : ""}
|
|
114
|
+
>${field.defaultValue ?? ""}</textarea>
|
|
115
|
+
</div>`;
|
|
41
116
|
}
|
|
42
117
|
|
|
118
|
+
if (field.type === "array") {
|
|
119
|
+
const itemType = field.itemType ?? "string";
|
|
120
|
+
const itemFieldsJson = JSON.stringify(
|
|
121
|
+
(field.itemFields ?? []).map((f) => ({ name: f.name, type: f.type })),
|
|
122
|
+
);
|
|
123
|
+
return `
|
|
124
|
+
<div class="form-control">
|
|
125
|
+
${labelRow}
|
|
126
|
+
<div
|
|
127
|
+
data-arg-key="${field.name}"
|
|
128
|
+
data-arg-type="array"
|
|
129
|
+
data-item-type="${itemType}"
|
|
130
|
+
data-item-fields='${itemFieldsJson}'
|
|
131
|
+
class="flex flex-col gap-2"
|
|
132
|
+
></div>
|
|
133
|
+
<button
|
|
134
|
+
type="button"
|
|
135
|
+
onclick="addArrayItem('${field.name}')"
|
|
136
|
+
class="btn btn-xs btn-ghost gap-1 mt-1 self-start opacity-50 hover:opacity-100"
|
|
137
|
+
>
|
|
138
|
+
<iconify-icon icon="solar:add-circle-linear" width="12" height="12"></iconify-icon>
|
|
139
|
+
Add item
|
|
140
|
+
</button>
|
|
141
|
+
</div>`;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const inputType =
|
|
145
|
+
field.type === "number" ? "number" : field.type === "date" ? "datetime-local" : "text";
|
|
146
|
+
|
|
43
147
|
return `
|
|
44
148
|
<div class="form-control">
|
|
45
|
-
|
|
46
|
-
<span class="label-text text-[11px] font-mono font-semibold">${label}${badge}</span>
|
|
47
|
-
${field.optional ? '<span class="label-text-alt text-[10px] opacity-30 italic">optional</span>' : ""}
|
|
48
|
-
</label>
|
|
149
|
+
${labelRow}
|
|
49
150
|
<input
|
|
50
151
|
type="${inputType}"
|
|
51
152
|
placeholder="${field.defaultValue ?? ""}"
|
|
52
153
|
data-arg-key="${field.name}"
|
|
53
154
|
data-arg-type="${field.type}"
|
|
54
155
|
value="${field.defaultValue ?? ""}"
|
|
55
|
-
class="
|
|
156
|
+
class="${inputClass}"
|
|
56
157
|
${!field.optional ? "required" : ""}
|
|
57
158
|
/>
|
|
58
|
-
</div
|
|
59
|
-
`;
|
|
159
|
+
</div>`;
|
|
60
160
|
})
|
|
61
161
|
.join("\n");
|
|
62
162
|
}
|
|
@@ -74,6 +74,29 @@ export function renderScripts(h: DiscoveredHandlerOperation): string {
|
|
|
74
74
|
container.appendChild(row);
|
|
75
75
|
};
|
|
76
76
|
|
|
77
|
+
// ── Field-level value helpers ──────────────────────────────────────────────
|
|
78
|
+
function getFieldValue(el) {
|
|
79
|
+
var type = el.getAttribute('data-obj-field-type') || 'string';
|
|
80
|
+
if (type === 'boolean') return el.checked;
|
|
81
|
+
if (type === 'number') {
|
|
82
|
+
var raw = el.value.trim();
|
|
83
|
+
return raw === '' ? undefined : Number(raw);
|
|
84
|
+
}
|
|
85
|
+
var v = el.value.trim();
|
|
86
|
+
return v === '' ? undefined : v;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function collectObjectRow(container) {
|
|
90
|
+
var obj = {};
|
|
91
|
+
container.querySelectorAll('[data-obj-key]').forEach(function(f) {
|
|
92
|
+
var k = f.getAttribute('data-obj-key');
|
|
93
|
+
if (!k) return;
|
|
94
|
+
var v = getFieldValue(f);
|
|
95
|
+
if (v !== undefined) obj[k] = v;
|
|
96
|
+
});
|
|
97
|
+
return Object.keys(obj).length ? obj : undefined;
|
|
98
|
+
}
|
|
99
|
+
|
|
77
100
|
// ── Collect args from server-rendered inputs ───────────────────────────────
|
|
78
101
|
function collectArgs() {
|
|
79
102
|
var result = {};
|
|
@@ -87,6 +110,36 @@ export function renderScripts(h: DiscoveredHandlerOperation): string {
|
|
|
87
110
|
} else if (type === 'number') {
|
|
88
111
|
var raw = el.value.trim();
|
|
89
112
|
value = raw === '' ? undefined : Number(raw);
|
|
113
|
+
} else if (type === 'object') {
|
|
114
|
+
if (el.tagName === 'TEXTAREA') {
|
|
115
|
+
// Fallback JSON textarea
|
|
116
|
+
var raw = el.value.trim();
|
|
117
|
+
if (!raw) return;
|
|
118
|
+
try { value = JSON.parse(raw); } catch(e) { value = raw; }
|
|
119
|
+
} else {
|
|
120
|
+
// Structured field inputs
|
|
121
|
+
value = collectObjectRow(el);
|
|
122
|
+
}
|
|
123
|
+
} else if (type === 'array') {
|
|
124
|
+
var itemType = el.getAttribute('data-item-type') || 'string';
|
|
125
|
+
if (itemType === 'object') {
|
|
126
|
+
var rows = el.querySelectorAll('.array-item-row');
|
|
127
|
+
var arr = Array.from(rows).map(function(row) {
|
|
128
|
+
return collectObjectRow(row);
|
|
129
|
+
}).filter(Boolean);
|
|
130
|
+
value = arr.length ? arr : undefined;
|
|
131
|
+
} else {
|
|
132
|
+
var items = el.querySelectorAll('.array-item-input');
|
|
133
|
+
var arr = Array.from(items).map(function(inp) {
|
|
134
|
+
var ft = inp.getAttribute('data-obj-field-type') || 'string';
|
|
135
|
+
if (ft === 'number') {
|
|
136
|
+
var raw = inp.value.trim();
|
|
137
|
+
return raw === '' ? undefined : Number(raw);
|
|
138
|
+
}
|
|
139
|
+
return inp.value.trim() || undefined;
|
|
140
|
+
}).filter(function(v) { return v !== undefined; });
|
|
141
|
+
value = arr.length ? arr : undefined;
|
|
142
|
+
}
|
|
90
143
|
} else {
|
|
91
144
|
value = el.value;
|
|
92
145
|
}
|
|
@@ -97,6 +150,102 @@ export function renderScripts(h: DiscoveredHandlerOperation): string {
|
|
|
97
150
|
return result;
|
|
98
151
|
}
|
|
99
152
|
|
|
153
|
+
// ── Array / object item helpers ────────────────────────────────────────────
|
|
154
|
+
function makeFieldInput(field) {
|
|
155
|
+
if (field.type === 'boolean') {
|
|
156
|
+
var cb = document.createElement('input');
|
|
157
|
+
cb.type = 'checkbox';
|
|
158
|
+
cb.className = 'checkbox checkbox-xs checkbox-primary shrink-0';
|
|
159
|
+
cb.setAttribute('data-obj-key', field.name);
|
|
160
|
+
cb.setAttribute('data-obj-field-type', 'boolean');
|
|
161
|
+
return cb;
|
|
162
|
+
}
|
|
163
|
+
var inputType = field.type === 'number' ? 'number'
|
|
164
|
+
: field.type === 'date' ? 'datetime-local'
|
|
165
|
+
: 'text';
|
|
166
|
+
var inp = document.createElement('input');
|
|
167
|
+
inp.type = inputType;
|
|
168
|
+
inp.placeholder = field.name;
|
|
169
|
+
inp.className = 'input input-xs input-bordered font-mono flex-1 bg-base-200/30 focus:bg-base-100 focus:border-primary transition-all rounded-lg border-base-200';
|
|
170
|
+
inp.setAttribute('data-obj-key', field.name);
|
|
171
|
+
inp.setAttribute('data-obj-field-type', field.type);
|
|
172
|
+
return inp;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
window.addArrayItem = function(key) {
|
|
176
|
+
var container = document.querySelector('[data-arg-key="' + key + '"][data-arg-type="array"]');
|
|
177
|
+
if (!container) return;
|
|
178
|
+
var itemType = container.getAttribute('data-item-type') || 'string';
|
|
179
|
+
|
|
180
|
+
if (itemType === 'object') {
|
|
181
|
+
var fieldsJson = container.getAttribute('data-item-fields') || '[]';
|
|
182
|
+
var itemFields;
|
|
183
|
+
try { itemFields = JSON.parse(fieldsJson); } catch(e) { itemFields = []; }
|
|
184
|
+
|
|
185
|
+
var rowCount = container.querySelectorAll('.array-item-row').length + 1;
|
|
186
|
+
|
|
187
|
+
var row = document.createElement('div');
|
|
188
|
+
row.className = 'array-item-row border border-base-200 rounded-xl p-3 bg-base-200/20 flex flex-col gap-2';
|
|
189
|
+
|
|
190
|
+
var header = document.createElement('div');
|
|
191
|
+
header.className = 'flex items-center justify-between';
|
|
192
|
+
|
|
193
|
+
var lbl = document.createElement('span');
|
|
194
|
+
lbl.className = 'text-[10px] font-mono opacity-30';
|
|
195
|
+
lbl.textContent = 'Item ' + rowCount;
|
|
196
|
+
|
|
197
|
+
var removeBtn = document.createElement('button');
|
|
198
|
+
removeBtn.type = 'button';
|
|
199
|
+
removeBtn.className = 'btn btn-xs btn-ghost text-error opacity-40 hover:opacity-100 px-1.5';
|
|
200
|
+
removeBtn.innerHTML = '<iconify-icon icon="solar:close-circle-linear" width="14" height="14"></iconify-icon>';
|
|
201
|
+
removeBtn.onclick = function() { row.remove(); };
|
|
202
|
+
|
|
203
|
+
header.appendChild(lbl);
|
|
204
|
+
header.appendChild(removeBtn);
|
|
205
|
+
row.appendChild(header);
|
|
206
|
+
|
|
207
|
+
itemFields.forEach(function(field) {
|
|
208
|
+
var fieldRow = document.createElement('div');
|
|
209
|
+
fieldRow.className = 'flex items-center gap-2';
|
|
210
|
+
|
|
211
|
+
var fieldLbl = document.createElement('span');
|
|
212
|
+
fieldLbl.className = 'text-[10px] font-mono opacity-50 w-20 shrink-0 truncate';
|
|
213
|
+
fieldLbl.title = field.name;
|
|
214
|
+
fieldLbl.textContent = field.name;
|
|
215
|
+
|
|
216
|
+
fieldRow.appendChild(fieldLbl);
|
|
217
|
+
fieldRow.appendChild(makeFieldInput(field));
|
|
218
|
+
row.appendChild(fieldRow);
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
container.appendChild(row);
|
|
222
|
+
} else {
|
|
223
|
+
var inputType = itemType === 'number' ? 'number'
|
|
224
|
+
: itemType === 'date' ? 'datetime-local'
|
|
225
|
+
: 'text';
|
|
226
|
+
|
|
227
|
+
var row = document.createElement('div');
|
|
228
|
+
row.className = 'flex items-center gap-2';
|
|
229
|
+
|
|
230
|
+
var inp = document.createElement('input');
|
|
231
|
+
inp.type = inputType;
|
|
232
|
+
inp.className = 'array-item-input input input-xs input-bordered font-mono flex-1 bg-base-200/30 focus:bg-base-100 focus:border-primary transition-all rounded-lg border-base-200';
|
|
233
|
+
inp.placeholder = 'value';
|
|
234
|
+
inp.setAttribute('data-obj-field-type', itemType);
|
|
235
|
+
|
|
236
|
+
var removeBtn = document.createElement('button');
|
|
237
|
+
removeBtn.type = 'button';
|
|
238
|
+
removeBtn.className = 'btn btn-xs btn-ghost text-error opacity-40 hover:opacity-100 px-1.5';
|
|
239
|
+
removeBtn.innerHTML = '<iconify-icon icon="solar:close-circle-linear" width="14" height="14"></iconify-icon>';
|
|
240
|
+
removeBtn.onclick = function() { row.remove(); };
|
|
241
|
+
|
|
242
|
+
row.appendChild(inp);
|
|
243
|
+
row.appendChild(removeBtn);
|
|
244
|
+
container.appendChild(row);
|
|
245
|
+
inp.focus();
|
|
246
|
+
}
|
|
247
|
+
};
|
|
248
|
+
|
|
100
249
|
function collectHeaders() {
|
|
101
250
|
var result = {};
|
|
102
251
|
document.querySelectorAll('#headers-rows [data-hdr-key]').forEach(function(keyEl) {
|
|
@@ -13,9 +13,15 @@ export type HandlerKind =
|
|
|
13
13
|
|
|
14
14
|
export type DiscoveredArgField = {
|
|
15
15
|
name: string;
|
|
16
|
-
type: "string" | "number" | "boolean" | "unknown";
|
|
16
|
+
type: "string" | "number" | "boolean" | "date" | "object" | "array" | "unknown";
|
|
17
17
|
optional: boolean;
|
|
18
18
|
defaultValue?: string;
|
|
19
|
+
/** Populated when type === "object": schema of the object's properties */
|
|
20
|
+
fields?: DiscoveredArgField[];
|
|
21
|
+
/** Populated when type === "array": element type */
|
|
22
|
+
itemType?: "string" | "number" | "boolean" | "date" | "object" | "unknown";
|
|
23
|
+
/** Populated when type === "array" and itemType === "object": element object schema */
|
|
24
|
+
itemFields?: DiscoveredArgField[];
|
|
19
25
|
};
|
|
20
26
|
|
|
21
27
|
export type DiscoveredHandlerOperation = {
|
|
@@ -83,6 +89,9 @@ function readZodArgField(
|
|
|
83
89
|
let optional = false;
|
|
84
90
|
let defaultValue: string | undefined;
|
|
85
91
|
let baseType: DiscoveredArgField["type"] = "unknown";
|
|
92
|
+
let fields: DiscoveredArgField[] | undefined;
|
|
93
|
+
let itemType: DiscoveredArgField["itemType"] | undefined;
|
|
94
|
+
let itemFields: DiscoveredArgField[] | undefined;
|
|
86
95
|
|
|
87
96
|
// Walk the call chain: z.string().optional().default("x")
|
|
88
97
|
// Each iteration processes one layer (e.g. .default, .optional, .string)
|
|
@@ -120,13 +129,39 @@ function readZodArgField(
|
|
|
120
129
|
} else if (prop === "boolean") {
|
|
121
130
|
baseType = "boolean";
|
|
122
131
|
break;
|
|
132
|
+
} else if (prop === "date") {
|
|
133
|
+
baseType = "date";
|
|
134
|
+
break;
|
|
135
|
+
} else if (prop === "object") {
|
|
136
|
+
baseType = "object";
|
|
137
|
+
const objArg = node.arguments[0];
|
|
138
|
+
if (objArg && ts.isObjectLiteralExpression(objArg)) {
|
|
139
|
+
fields = [];
|
|
140
|
+
for (const property of objArg.properties) {
|
|
141
|
+
if (ts.isPropertyAssignment(property) && ts.isIdentifier(property.name)) {
|
|
142
|
+
fields.push(readZodArgField(property.initializer, property.name.text));
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
break;
|
|
147
|
+
} else if (prop === "array") {
|
|
148
|
+
baseType = "array";
|
|
149
|
+
const itemArg = node.arguments[0];
|
|
150
|
+
if (itemArg) {
|
|
151
|
+
const itemField = readZodArgField(itemArg, "");
|
|
152
|
+
itemType = itemField.type === "array" ? "unknown" : itemField.type;
|
|
153
|
+
if (itemField.type === "object") {
|
|
154
|
+
itemFields = itemField.fields;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
break;
|
|
123
158
|
} else {
|
|
124
159
|
// unknown modifier (.min, .max, .trim, etc.) — keep walking inward
|
|
125
160
|
node = expr.expression;
|
|
126
161
|
}
|
|
127
162
|
}
|
|
128
163
|
|
|
129
|
-
return { name, type: baseType, optional, defaultValue };
|
|
164
|
+
return { name, type: baseType, optional, defaultValue, fields, itemType, itemFields };
|
|
130
165
|
}
|
|
131
166
|
|
|
132
167
|
function readArgsFields(
|