bxo 0.0.5-dev.80 → 0.0.5-dev.81

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 CHANGED
@@ -320,9 +320,35 @@ app.post("/items", async (ctx) => {
320
320
  });
321
321
  ```
322
322
 
323
+ ### Deep Nested Array Objects
324
+ Form fields like `workspace_items[0][id]`, `workspace_items[0][type]` are automatically converted to arrays of objects:
325
+
326
+ ```typescript
327
+ const WorkspaceSchema = z.object({
328
+ id: z.string(),
329
+ workspace_items: z.array(z.object({
330
+ id: z.string(),
331
+ type: z.string(),
332
+ value: z.string(),
333
+ options: z.string(),
334
+ label: z.string()
335
+ }))
336
+ });
337
+
338
+ app.post("/workspace", async (ctx) => {
339
+ // Form data: workspace_items[0][id]="item1", workspace_items[0][type]="Link"
340
+ // becomes { workspace_items: [{ id: "item1", type: "Link", ... }] }
341
+ console.log(ctx.body); // { id: "...", workspace_items: [{ id: "item1", type: "Link", ... }] }
342
+ return ctx.json({ success: true, data: ctx.body });
343
+ }, {
344
+ body: WorkspaceSchema
345
+ });
346
+ ```
347
+
323
348
  ### Supported Patterns
324
349
  - **Nested objects**: `profile[name]`, `settings[theme]` → `{ profile: { name: "..." }, settings: { theme: "..." } }`
325
350
  - **Arrays**: `items[0]`, `items[1]` → `{ items: ["...", "..."] }`
351
+ - **Deep nested array objects**: `workspace_items[0][id]`, `workspace_items[0][type]` → `{ workspace_items: [{ id: "...", type: "..." }] }`
326
352
  - **Duplicate keys**: Multiple values with same key → `{ tags: ["tag1", "tag2"] }`
327
353
 
328
354
  ## Running
@@ -63,6 +63,46 @@ app.post("/items", async (ctx) => {
63
63
  }
64
64
  });
65
65
 
66
+ // Example with deep nested array objects (like workspace_items[0][id])
67
+ const WorkspaceFormSchema = z.object({
68
+ id: z.string(),
69
+ created_at: z.string(),
70
+ updated_at: z.string(),
71
+ updated_by: z.string(),
72
+ doc_status: z.string().transform(val => parseInt(val, 10)),
73
+ idx: z.string().transform(val => parseInt(val, 10)),
74
+ workspace_items: z.array(z.object({
75
+ id: z.string(),
76
+ type: z.string(),
77
+ value: z.string(),
78
+ options: z.string(),
79
+ workspaceId: z.string(),
80
+ owner: z.string(),
81
+ created_at: z.string(),
82
+ updated_at: z.string(),
83
+ created_by: z.string(),
84
+ updated_by: z.string(),
85
+ doc_status: z.string().transform(val => parseInt(val, 10)),
86
+ label: z.string()
87
+ }))
88
+ });
89
+
90
+ app.post("/workspace", async (ctx) => {
91
+ console.log("Parsed workspace form data:", ctx.body);
92
+
93
+ return ctx.json({
94
+ message: "Workspace processed successfully",
95
+ data: ctx.body
96
+ });
97
+ }, {
98
+ body: WorkspaceFormSchema,
99
+ detail: {
100
+ summary: "Process workspace with deep nested array objects",
101
+ description: "Handles form data like workspace_items[0][id], workspace_items[0][type]",
102
+ tags: ["Workspace"]
103
+ }
104
+ });
105
+
66
106
  // Test route to show how the parsing works
67
107
  app.get("/test-parsing", async (ctx) => {
68
108
  const html = `
@@ -156,6 +196,80 @@ app.get("/test-parsing", async (ctx) => {
156
196
  <button type="submit">Submit Items Form</button>
157
197
  </form>
158
198
 
199
+ <h2>Test 3: Deep Nested Array Objects (workspace_items[0][id])</h2>
200
+ <form id="workspaceForm" enctype="multipart/form-data">
201
+ <div class="form-group">
202
+ <label>ID:</label>
203
+ <input type="text" name="id" value="01993f54-758e-7000-9f98-4533a7cf8ce9">
204
+ </div>
205
+ <div class="form-group">
206
+ <label>Created At:</label>
207
+ <input type="text" name="created_at" value="2025-09-13 02:08:43">
208
+ </div>
209
+ <div class="form-group">
210
+ <label>Updated At:</label>
211
+ <input type="text" name="updated_at" value="2025-09-13 02:08:43">
212
+ </div>
213
+ <div class="form-group">
214
+ <label>Updated By:</label>
215
+ <input type="text" name="updated_by" value="01995120-fae9-7000-8d46-8f3502e901b6">
216
+ </div>
217
+ <div class="form-group">
218
+ <label>Doc Status:</label>
219
+ <input type="text" name="doc_status" value="0">
220
+ </div>
221
+ <div class="form-group">
222
+ <label>Index:</label>
223
+ <input type="text" name="idx" value="0">
224
+ </div>
225
+
226
+ <h3>Workspace Item 1:</h3>
227
+ <div class="form-group">
228
+ <label>Item ID:</label>
229
+ <input type="text" name="workspace_items[0][id]" value="temp_1758097169599">
230
+ </div>
231
+ <div class="form-group">
232
+ <label>Item Type:</label>
233
+ <input type="text" name="workspace_items[0][type]" value="Link - URL">
234
+ </div>
235
+ <div class="form-group">
236
+ <label>Item Value:</label>
237
+ <input type="text" name="workspace_items[0][value]" value="asd">
238
+ </div>
239
+ <div class="form-group">
240
+ <label>Item Options:</label>
241
+ <input type="text" name="workspace_items[0][options]" value="asdasd">
242
+ </div>
243
+ <div class="form-group">
244
+ <label>Item Label:</label>
245
+ <input type="text" name="workspace_items[0][label]" value="asdasd">
246
+ </div>
247
+
248
+ <h3>Workspace Item 2:</h3>
249
+ <div class="form-group">
250
+ <label>Item ID:</label>
251
+ <input type="text" name="workspace_items[1][id]" value="temp_1758097169600">
252
+ </div>
253
+ <div class="form-group">
254
+ <label>Item Type:</label>
255
+ <input type="text" name="workspace_items[1][type]" value="Text">
256
+ </div>
257
+ <div class="form-group">
258
+ <label>Item Value:</label>
259
+ <input type="text" name="workspace_items[1][value]" value="Another item">
260
+ </div>
261
+ <div class="form-group">
262
+ <label>Item Options:</label>
263
+ <input type="text" name="workspace_items[1][options]" value="More options">
264
+ </div>
265
+ <div class="form-group">
266
+ <label>Item Label:</label>
267
+ <input type="text" name="workspace_items[1][label]" value="Second item">
268
+ </div>
269
+
270
+ <button type="submit">Submit Workspace Form</button>
271
+ </form>
272
+
159
273
  <div id="result" class="result" style="display: none;">
160
274
  <h3>Result:</h3>
161
275
  <pre id="resultContent"></pre>
@@ -187,6 +301,11 @@ app.get("/test-parsing", async (ctx) => {
187
301
  e.preventDefault();
188
302
  submitForm(e.target, '/items');
189
303
  });
304
+
305
+ document.getElementById('workspaceForm').addEventListener('submit', (e) => {
306
+ e.preventDefault();
307
+ submitForm(e.target, '/workspace');
308
+ });
190
309
  </script>
191
310
  </body>
192
311
  </html>
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  ".": "./src/index.ts",
6
6
  "./plugins": "./plugins/index.ts"
7
7
  },
8
- "version": "0.0.5-dev.80",
8
+ "version": "0.0.5-dev.81",
9
9
  "type": "module",
10
10
  "devDependencies": {
11
11
  "@types/bun": "latest"
package/src/index.ts CHANGED
@@ -196,6 +196,35 @@ function formDataToObject(fd: FormData): Record<string, any> {
196
196
  }
197
197
 
198
198
  function setNestedValue(obj: Record<string, any>, key: string, value: any): void {
199
+ // Handle deeply nested array objects like workspace_items[0][id], workspace_items[0][type]
200
+ const deepArrayMatch = key.match(/^(.+)\[(\d+)\]\[([^\]]+)\]$/);
201
+ if (deepArrayMatch) {
202
+ const [, arrayKey, index, propertyKey] = deepArrayMatch;
203
+ const arrayIndex = parseInt(index, 10);
204
+
205
+ if (!obj[arrayKey]) {
206
+ obj[arrayKey] = [];
207
+ }
208
+
209
+ // Ensure it's an array
210
+ if (!Array.isArray(obj[arrayKey])) {
211
+ obj[arrayKey] = [];
212
+ }
213
+
214
+ // Ensure the object at the index exists
215
+ if (!obj[arrayKey][arrayIndex]) {
216
+ obj[arrayKey][arrayIndex] = {};
217
+ }
218
+
219
+ // Ensure it's an object
220
+ if (typeof obj[arrayKey][arrayIndex] !== 'object' || Array.isArray(obj[arrayKey][arrayIndex])) {
221
+ obj[arrayKey][arrayIndex] = {};
222
+ }
223
+
224
+ obj[arrayKey][arrayIndex][propertyKey] = value;
225
+ return;
226
+ }
227
+
199
228
  // Handle array notation like items[0], items[1]
200
229
  const arrayMatch = key.match(/^(.+)\[(\d+)\]$/);
201
230
  if (arrayMatch) {