@compilr-dev/factory 0.1.2 → 0.1.3
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/model/tools.js +119 -66
- package/package.json +1 -1
package/dist/model/tools.js
CHANGED
|
@@ -162,18 +162,22 @@ EXAMPLES:
|
|
|
162
162
|
description: 'Field name (string) for updateField/removeField/renameField, or full field object (for addField). Field object requires: name (camelCase), label, type (string|number|boolean|date|enum), required.',
|
|
163
163
|
},
|
|
164
164
|
relationship: {
|
|
165
|
-
|
|
166
|
-
|
|
165
|
+
oneOf: [
|
|
166
|
+
{
|
|
167
|
+
type: 'object',
|
|
168
|
+
additionalProperties: true,
|
|
169
|
+
properties: {
|
|
170
|
+
type: { type: 'string', enum: ['belongsTo', 'hasMany'] },
|
|
171
|
+
target: { type: 'string' },
|
|
172
|
+
fieldName: { type: 'string' },
|
|
173
|
+
},
|
|
174
|
+
},
|
|
175
|
+
{ type: 'string' },
|
|
176
|
+
],
|
|
167
177
|
description: 'Relationship object for addRelationship. Requires: type ("belongsTo" or "hasMany"), target (entity name). Optional: fieldName.',
|
|
168
|
-
properties: {
|
|
169
|
-
type: { type: 'string', enum: ['belongsTo', 'hasMany'] },
|
|
170
|
-
target: { type: 'string' },
|
|
171
|
-
fieldName: { type: 'string' },
|
|
172
|
-
},
|
|
173
178
|
},
|
|
174
179
|
updates: {
|
|
175
|
-
type: 'object',
|
|
176
|
-
additionalProperties: true,
|
|
180
|
+
oneOf: [{ type: 'object', additionalProperties: true }, { type: 'string' }],
|
|
177
181
|
description: 'Partial updates object for updateIdentity, updateLayout, updateFeatures, updateTheme, updateTechStack, updateEntity.',
|
|
178
182
|
},
|
|
179
183
|
newName: {
|
|
@@ -237,28 +241,53 @@ EXAMPLES:
|
|
|
237
241
|
},
|
|
238
242
|
});
|
|
239
243
|
}
|
|
244
|
+
/**
|
|
245
|
+
* Coerce a value to an object. LLMs sometimes send stringified JSON for nested objects.
|
|
246
|
+
* Returns the parsed object, or null if coercion fails.
|
|
247
|
+
*/
|
|
248
|
+
function coerceToObject(value) {
|
|
249
|
+
if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
|
|
250
|
+
return value;
|
|
251
|
+
}
|
|
252
|
+
if (typeof value === 'string') {
|
|
253
|
+
try {
|
|
254
|
+
const parsed = JSON.parse(value);
|
|
255
|
+
if (typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed)) {
|
|
256
|
+
return parsed;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
catch {
|
|
260
|
+
// Not valid JSON
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
return null;
|
|
264
|
+
}
|
|
240
265
|
function buildOperation(input) {
|
|
241
266
|
switch (input.op) {
|
|
242
267
|
case 'addEntity': {
|
|
243
|
-
|
|
244
|
-
|
|
268
|
+
const entity = coerceToObject(input.entity);
|
|
269
|
+
if (!entity) {
|
|
270
|
+
throw new Error(`addEntity requires "entity" as an object with name, pluralName, icon, fields, views, relationships. ` +
|
|
271
|
+
`Got: ${input.entity === undefined ? 'missing' : typeof input.entity}. ` +
|
|
272
|
+
`Example: { "op": "addEntity", "entity": { "name": "Employee", "pluralName": "Employees", "icon": "👤", "fields": [{ "name": "name", "label": "Name", "type": "string", "required": true }], "views": ["list", "detail", "card"], "relationships": [] } }`);
|
|
245
273
|
}
|
|
246
|
-
|
|
247
|
-
return { op: 'addEntity', entity };
|
|
274
|
+
return { op: 'addEntity', entity: entity };
|
|
248
275
|
}
|
|
249
|
-
case 'updateEntity':
|
|
276
|
+
case 'updateEntity': {
|
|
250
277
|
if (typeof input.entity !== 'string')
|
|
251
|
-
throw new Error(
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
278
|
+
throw new Error(`updateEntity requires "entity" as a string (entity name). Got: ${input.entity === undefined ? 'missing' : typeof input.entity}`);
|
|
279
|
+
const updates = coerceToObject(input.updates);
|
|
280
|
+
if (!updates)
|
|
281
|
+
throw new Error(`updateEntity requires "updates" object. Got: ${input.updates === undefined ? 'missing' : typeof input.updates}`);
|
|
282
|
+
return { op: 'updateEntity', entity: input.entity, updates };
|
|
283
|
+
}
|
|
255
284
|
case 'removeEntity':
|
|
256
285
|
if (typeof input.entity !== 'string')
|
|
257
|
-
throw new Error(
|
|
286
|
+
throw new Error(`removeEntity requires "entity" as a string (entity name). Got: ${input.entity === undefined ? 'missing' : typeof input.entity}`);
|
|
258
287
|
return { op: 'removeEntity', entity: input.entity, force: input.force };
|
|
259
288
|
case 'renameEntity':
|
|
260
289
|
if (typeof input.entity !== 'string')
|
|
261
|
-
throw new Error(
|
|
290
|
+
throw new Error(`renameEntity requires "entity" as a string (entity name). Got: ${input.entity === undefined ? 'missing' : typeof input.entity}`);
|
|
262
291
|
if (!input.newName)
|
|
263
292
|
throw new Error('renameEntity requires newName');
|
|
264
293
|
return { op: 'renameEntity', entity: input.entity, newName: input.newName };
|
|
@@ -268,36 +297,39 @@ function buildOperation(input) {
|
|
|
268
297
|
return { op: 'reorderEntities', order: input.order };
|
|
269
298
|
case 'addField': {
|
|
270
299
|
if (typeof input.entity !== 'string')
|
|
271
|
-
throw new Error(
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
case 'updateField':
|
|
278
|
-
if (typeof input.entity !== 'string')
|
|
279
|
-
throw new Error('updateField requires entity name (string)');
|
|
280
|
-
if (typeof input.field !== 'string')
|
|
281
|
-
throw new Error('updateField requires field name (string)');
|
|
282
|
-
if (!input.updates)
|
|
283
|
-
throw new Error('updateField requires updates object');
|
|
300
|
+
throw new Error(`addField requires "entity" as a string (entity name). Got: ${input.entity === undefined ? 'missing' : typeof input.entity}`);
|
|
301
|
+
const field = coerceToObject(input.field);
|
|
302
|
+
if (!field)
|
|
303
|
+
throw new Error(`addField requires "field" as an object with name, label, type, required. ` +
|
|
304
|
+
`Got: ${input.field === undefined ? 'missing' : typeof input.field}. ` +
|
|
305
|
+
`Example: { "op": "addField", "entity": "Employee", "field": { "name": "email", "label": "Email", "type": "string", "required": true } }`);
|
|
284
306
|
return {
|
|
285
|
-
op: '
|
|
307
|
+
op: 'addField',
|
|
286
308
|
entity: input.entity,
|
|
287
|
-
field:
|
|
288
|
-
updates: input.updates,
|
|
309
|
+
field: field,
|
|
289
310
|
};
|
|
311
|
+
}
|
|
312
|
+
case 'updateField': {
|
|
313
|
+
if (typeof input.entity !== 'string')
|
|
314
|
+
throw new Error(`updateField requires "entity" as a string (entity name). Got: ${input.entity === undefined ? 'missing' : typeof input.entity}`);
|
|
315
|
+
if (typeof input.field !== 'string')
|
|
316
|
+
throw new Error(`updateField requires "field" as a string (field name). Got: ${input.field === undefined ? 'missing' : typeof input.field}`);
|
|
317
|
+
const updates = coerceToObject(input.updates);
|
|
318
|
+
if (!updates)
|
|
319
|
+
throw new Error(`updateField requires "updates" object. Got: ${input.updates === undefined ? 'missing' : typeof input.updates}`);
|
|
320
|
+
return { op: 'updateField', entity: input.entity, field: input.field, updates };
|
|
321
|
+
}
|
|
290
322
|
case 'removeField':
|
|
291
323
|
if (typeof input.entity !== 'string')
|
|
292
|
-
throw new Error(
|
|
324
|
+
throw new Error(`removeField requires "entity" as a string (entity name). Got: ${input.entity === undefined ? 'missing' : typeof input.entity}`);
|
|
293
325
|
if (typeof input.field !== 'string')
|
|
294
|
-
throw new Error(
|
|
326
|
+
throw new Error(`removeField requires "field" as a string (field name). Got: ${input.field === undefined ? 'missing' : typeof input.field}`);
|
|
295
327
|
return { op: 'removeField', entity: input.entity, field: input.field };
|
|
296
328
|
case 'renameField':
|
|
297
329
|
if (typeof input.entity !== 'string')
|
|
298
|
-
throw new Error(
|
|
330
|
+
throw new Error(`renameField requires "entity" as a string (entity name). Got: ${input.entity === undefined ? 'missing' : typeof input.entity}`);
|
|
299
331
|
if (typeof input.field !== 'string')
|
|
300
|
-
throw new Error(
|
|
332
|
+
throw new Error(`renameField requires "field" as a string (field name). Got: ${input.field === undefined ? 'missing' : typeof input.field}`);
|
|
301
333
|
if (!input.newName)
|
|
302
334
|
throw new Error('renameField requires newName');
|
|
303
335
|
return {
|
|
@@ -308,38 +340,59 @@ function buildOperation(input) {
|
|
|
308
340
|
};
|
|
309
341
|
case 'addRelationship': {
|
|
310
342
|
if (typeof input.entity !== 'string')
|
|
311
|
-
throw new Error(
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
343
|
+
throw new Error(`addRelationship requires "entity" as a string (entity name). Got: ${input.entity === undefined ? 'missing' : typeof input.entity}`);
|
|
344
|
+
const relationship = coerceToObject(input.relationship);
|
|
345
|
+
if (!relationship)
|
|
346
|
+
throw new Error(`addRelationship requires "relationship" object with type and target. ` +
|
|
347
|
+
`Got: ${input.relationship === undefined ? 'missing' : typeof input.relationship}. ` +
|
|
348
|
+
`Example: { "op": "addRelationship", "entity": "Task", "relationship": { "type": "belongsTo", "target": "Project" } }`);
|
|
349
|
+
return {
|
|
350
|
+
op: 'addRelationship',
|
|
351
|
+
entity: input.entity,
|
|
352
|
+
relationship: relationship,
|
|
353
|
+
};
|
|
316
354
|
}
|
|
317
355
|
case 'removeRelationship':
|
|
318
356
|
if (typeof input.entity !== 'string')
|
|
319
|
-
throw new Error(
|
|
357
|
+
throw new Error(`removeRelationship requires "entity" as a string (entity name). Got: ${input.entity === undefined ? 'missing' : typeof input.entity}`);
|
|
320
358
|
if (!input.target)
|
|
321
359
|
throw new Error('removeRelationship requires target');
|
|
322
360
|
return { op: 'removeRelationship', entity: input.entity, target: input.target };
|
|
323
|
-
case 'updateIdentity':
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
if (!
|
|
333
|
-
throw new Error(
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
return { op: '
|
|
361
|
+
case 'updateIdentity': {
|
|
362
|
+
const updates = coerceToObject(input.updates);
|
|
363
|
+
if (!updates)
|
|
364
|
+
throw new Error(`updateIdentity requires "updates" object. Got: ${input.updates === undefined ? 'missing' : typeof input.updates}. ` +
|
|
365
|
+
`Example: { "op": "updateIdentity", "updates": { "name": "My App", "description": "An app" } }`);
|
|
366
|
+
return { op: 'updateIdentity', updates };
|
|
367
|
+
}
|
|
368
|
+
case 'updateLayout': {
|
|
369
|
+
const updates = coerceToObject(input.updates);
|
|
370
|
+
if (!updates)
|
|
371
|
+
throw new Error(`updateLayout requires "updates" object. Got: ${input.updates === undefined ? 'missing' : typeof input.updates}. ` +
|
|
372
|
+
`Example: { "op": "updateLayout", "updates": { "shell": "sidebar-header" } }`);
|
|
373
|
+
return { op: 'updateLayout', updates };
|
|
374
|
+
}
|
|
375
|
+
case 'updateFeatures': {
|
|
376
|
+
const updates = coerceToObject(input.updates);
|
|
377
|
+
if (!updates)
|
|
378
|
+
throw new Error(`updateFeatures requires "updates" object. Got: ${input.updates === undefined ? 'missing' : typeof input.updates}. ` +
|
|
379
|
+
`Example: { "op": "updateFeatures", "updates": { "dashboard": true } }`);
|
|
380
|
+
return { op: 'updateFeatures', updates };
|
|
381
|
+
}
|
|
382
|
+
case 'updateTheme': {
|
|
383
|
+
const updates = coerceToObject(input.updates);
|
|
384
|
+
if (!updates)
|
|
385
|
+
throw new Error(`updateTheme requires "updates" object. Got: ${input.updates === undefined ? 'missing' : typeof input.updates}. ` +
|
|
386
|
+
`Example: { "op": "updateTheme", "updates": { "primaryColor": "#1976D2" } }`);
|
|
387
|
+
return { op: 'updateTheme', updates };
|
|
388
|
+
}
|
|
389
|
+
case 'updateTechStack': {
|
|
390
|
+
const updates = coerceToObject(input.updates);
|
|
391
|
+
if (!updates)
|
|
392
|
+
throw new Error(`updateTechStack requires "updates" object. Got: ${input.updates === undefined ? 'missing' : typeof input.updates}. ` +
|
|
393
|
+
`Example: { "op": "updateTechStack", "updates": { "toolkit": "react-node" } }`);
|
|
394
|
+
return { op: 'updateTechStack', updates };
|
|
395
|
+
}
|
|
343
396
|
default:
|
|
344
397
|
throw new Error(`Unknown operation: ${input.op}`);
|
|
345
398
|
}
|