@manifesto-ai/codegen 0.1.3 → 0.1.5

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.js CHANGED
@@ -179,7 +179,9 @@ async function generate(opts) {
179
179
  if (hasErrors) {
180
180
  return { files, artifacts: allArtifacts, diagnostics };
181
181
  }
182
- await fs.rm(opts.outDir, { recursive: true, force: true });
182
+ if (opts.cleanOutDir) {
183
+ await fs.rm(opts.outDir, { recursive: true, force: true });
184
+ }
183
185
  const header = generateHeader({
184
186
  sourceId: opts.sourceId,
185
187
  schemaHash: opts.schema.hash,
@@ -215,13 +217,770 @@ function validatePluginNames(plugins) {
215
217
  return void 0;
216
218
  }
217
219
 
220
+ // src/plugins/domain-type-model.ts
221
+ var UNKNOWN_TYPE = { kind: "unknown" };
222
+ var NULL_TYPE = { kind: "primitive", type: "null" };
223
+ function unknownType() {
224
+ return UNKNOWN_TYPE;
225
+ }
226
+ function primitiveType(type) {
227
+ return type === "null" ? NULL_TYPE : { kind: "primitive", type };
228
+ }
229
+ function literalType(value) {
230
+ return value === null ? NULL_TYPE : { kind: "literal", value };
231
+ }
232
+ function arrayType(element) {
233
+ return { kind: "array", element };
234
+ }
235
+ function tupleType(elements) {
236
+ return { kind: "tuple", elements };
237
+ }
238
+ function objectType(fields) {
239
+ return { kind: "object", fields };
240
+ }
241
+ function recordType(key, value) {
242
+ return { kind: "record", key, value };
243
+ }
244
+ function fieldSpecToDomainField(spec) {
245
+ return {
246
+ type: fieldSpecToDomainType(spec),
247
+ optional: !spec.required
248
+ };
249
+ }
250
+ function fieldSpecToDomainType(spec) {
251
+ let base;
252
+ if (typeof spec.type === "object" && "enum" in spec.type) {
253
+ base = unionOf(
254
+ spec.type.enum.map((value) => literalValueToType(value))
255
+ );
256
+ } else {
257
+ switch (spec.type) {
258
+ case "string":
259
+ base = primitiveType("string");
260
+ break;
261
+ case "number":
262
+ base = primitiveType("number");
263
+ break;
264
+ case "boolean":
265
+ base = primitiveType("boolean");
266
+ break;
267
+ case "null":
268
+ base = NULL_TYPE;
269
+ break;
270
+ case "object":
271
+ if (spec.fields) {
272
+ const fields = {};
273
+ for (const name of Object.keys(spec.fields)) {
274
+ fields[name] = fieldSpecToDomainField(spec.fields[name]);
275
+ }
276
+ base = objectType(fields);
277
+ break;
278
+ }
279
+ base = recordType(primitiveType("string"), unknownType());
280
+ break;
281
+ case "array":
282
+ base = arrayType(
283
+ spec.items ? fieldSpecToDomainType(spec.items) : unknownType()
284
+ );
285
+ break;
286
+ default:
287
+ base = unknownType();
288
+ break;
289
+ }
290
+ }
291
+ return spec.required ? base : unionOf([base, NULL_TYPE]);
292
+ }
293
+ function literalValueToType(value) {
294
+ if (value === null) {
295
+ return NULL_TYPE;
296
+ }
297
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
298
+ return literalType(value);
299
+ }
300
+ if (Array.isArray(value)) {
301
+ return arrayType(
302
+ value.length === 0 ? unknownType() : unionOf(value.map((item) => literalValueToType(item)))
303
+ );
304
+ }
305
+ if (isPlainObject(value)) {
306
+ const fields = {};
307
+ for (const name of Object.keys(value)) {
308
+ fields[name] = {
309
+ type: literalValueToType(value[name]),
310
+ optional: false
311
+ };
312
+ }
313
+ return objectType(fields);
314
+ }
315
+ return unknownType();
316
+ }
317
+ function unionOf(types) {
318
+ const flattened = [];
319
+ for (const type of types) {
320
+ if (type.kind === "unknown") {
321
+ return type;
322
+ }
323
+ if (type.kind === "union") {
324
+ flattened.push(...type.types);
325
+ continue;
326
+ }
327
+ flattened.push(type);
328
+ }
329
+ const unique = /* @__PURE__ */ new Map();
330
+ for (const type of flattened) {
331
+ unique.set(stableTypeKey(type), type);
332
+ }
333
+ const deduped = Array.from(unique.values());
334
+ if (deduped.length === 0) {
335
+ return unknownType();
336
+ }
337
+ if (deduped.length === 1) {
338
+ return deduped[0];
339
+ }
340
+ return { kind: "union", types: deduped };
341
+ }
342
+ function removeNullType(type) {
343
+ switch (type.kind) {
344
+ case "primitive":
345
+ return type.type === "null" ? [] : [type];
346
+ case "literal":
347
+ return type.value === null ? [] : [type];
348
+ case "union":
349
+ return type.types.flatMap((member) => removeNullType(member));
350
+ default:
351
+ return [type];
352
+ }
353
+ }
354
+ function renderDomainType(type) {
355
+ switch (type.kind) {
356
+ case "unknown":
357
+ return "unknown";
358
+ case "primitive":
359
+ return type.type;
360
+ case "literal":
361
+ return renderLiteral(type.value);
362
+ case "array":
363
+ return `${wrapArrayElement(renderDomainType(type.element), type.element)}[]`;
364
+ case "tuple":
365
+ return `[${type.elements.map((element) => renderDomainType(element)).join(", ")}]`;
366
+ case "object": {
367
+ const fieldNames = Object.keys(type.fields).sort();
368
+ if (fieldNames.length === 0) {
369
+ return "{}";
370
+ }
371
+ const parts = fieldNames.map((name) => {
372
+ const field = type.fields[name];
373
+ const optional = field.optional ? "?" : "";
374
+ return `${name}${optional}: ${renderDomainType(field.type)}`;
375
+ });
376
+ return `{ ${parts.join("; ")} }`;
377
+ }
378
+ case "record":
379
+ return `Record<${renderDomainType(type.key)}, ${renderDomainType(type.value)}>`;
380
+ case "union":
381
+ return type.types.map((member) => renderDomainType(member)).join(" | ");
382
+ }
383
+ }
384
+ function wrapArrayElement(rendered, type) {
385
+ if (type.kind === "union") {
386
+ return `(${rendered})`;
387
+ }
388
+ return rendered;
389
+ }
390
+ function renderLiteral(value) {
391
+ if (typeof value === "string") {
392
+ return JSON.stringify(value);
393
+ }
394
+ return String(value);
395
+ }
396
+ function stableTypeKey(type) {
397
+ switch (type.kind) {
398
+ case "unknown":
399
+ return "unknown";
400
+ case "primitive":
401
+ return `primitive:${type.type}`;
402
+ case "literal":
403
+ return `literal:${JSON.stringify(type.value)}`;
404
+ case "array":
405
+ return `array:${stableTypeKey(type.element)}`;
406
+ case "tuple":
407
+ return `tuple:${type.elements.map((element) => stableTypeKey(element)).join(",")}`;
408
+ case "object": {
409
+ const keys = Object.keys(type.fields).sort();
410
+ const fields = keys.map((name) => {
411
+ const field = type.fields[name];
412
+ return `${name}:${field.optional ? "?" : ""}${stableTypeKey(field.type)}`;
413
+ });
414
+ return `object:${fields.join(",")}`;
415
+ }
416
+ case "record":
417
+ return `record:${stableTypeKey(type.key)}:${stableTypeKey(type.value)}`;
418
+ case "union":
419
+ return `union:${type.types.map((member) => stableTypeKey(member)).sort().join("|")}`;
420
+ }
421
+ }
422
+ function isPlainObject(value) {
423
+ return value !== null && typeof value === "object" && !Array.isArray(value);
424
+ }
425
+
426
+ // src/plugins/domain-type-inference.ts
427
+ var META_TYPE = objectType({
428
+ actionName: { type: primitiveType("string"), optional: false },
429
+ intentId: { type: primitiveType("string"), optional: false },
430
+ timestamp: { type: primitiveType("number"), optional: false }
431
+ });
432
+ function createInferenceContext(schema, diagnostics, pluginName) {
433
+ return {
434
+ schema,
435
+ pluginName,
436
+ diagnostics,
437
+ warnedMessages: /* @__PURE__ */ new Set(),
438
+ computedCache: /* @__PURE__ */ new Map(),
439
+ computedInFlight: /* @__PURE__ */ new Set()
440
+ };
441
+ }
442
+ function inferComputedType(name, ctx) {
443
+ if (ctx.computedCache.has(name)) {
444
+ return ctx.computedCache.get(name) ?? unknownType();
445
+ }
446
+ const spec = ctx.schema.computed.fields[name];
447
+ if (!spec) {
448
+ warn(ctx, `Unknown computed field "${name}". Emitting "unknown".`);
449
+ return unknownType();
450
+ }
451
+ if (ctx.computedInFlight.has(name)) {
452
+ warn(ctx, `Recursive computed field "${name}" could not be inferred. Emitting "unknown".`);
453
+ return unknownType();
454
+ }
455
+ ctx.computedInFlight.add(name);
456
+ const inferred = inferExprType(spec.expr, ctx, /* @__PURE__ */ new Map());
457
+ ctx.computedInFlight.delete(name);
458
+ ctx.computedCache.set(name, inferred);
459
+ return inferred;
460
+ }
461
+ function inferExprType(expr, ctx, env = /* @__PURE__ */ new Map()) {
462
+ switch (expr.kind) {
463
+ case "lit":
464
+ return literalValueToType(expr.value);
465
+ case "get":
466
+ return inferPathType(expr.path, ctx, env);
467
+ case "eq":
468
+ case "neq":
469
+ case "gt":
470
+ case "gte":
471
+ case "lt":
472
+ case "lte":
473
+ case "and":
474
+ case "or":
475
+ case "not":
476
+ case "startsWith":
477
+ case "endsWith":
478
+ case "strIncludes":
479
+ case "includes":
480
+ case "every":
481
+ case "some":
482
+ case "hasKey":
483
+ case "isNull":
484
+ case "toBoolean":
485
+ return primitiveType("boolean");
486
+ case "add":
487
+ case "sub":
488
+ case "mul":
489
+ case "div":
490
+ case "mod":
491
+ case "min":
492
+ case "max":
493
+ case "abs":
494
+ case "neg":
495
+ case "floor":
496
+ case "ceil":
497
+ case "round":
498
+ case "sqrt":
499
+ case "pow":
500
+ case "sumArray":
501
+ case "strLen":
502
+ case "len":
503
+ case "indexOf":
504
+ case "toNumber":
505
+ return primitiveType("number");
506
+ case "concat":
507
+ case "substring":
508
+ case "trim":
509
+ case "toLowerCase":
510
+ case "toUpperCase":
511
+ case "replace":
512
+ case "typeof":
513
+ case "toString":
514
+ return primitiveType("string");
515
+ case "if":
516
+ return unionOf([
517
+ inferExprType(expr.then, ctx, env),
518
+ inferExprType(expr.else, ctx, env)
519
+ ]);
520
+ case "split":
521
+ return arrayType(primitiveType("string"));
522
+ case "at":
523
+ return unionOf([inferIndexedAccessType(expr.array, ctx, env), primitiveType("null")]);
524
+ case "first":
525
+ case "last":
526
+ case "minArray":
527
+ case "maxArray":
528
+ return unionOf([inferCollectionElementType(expr.array, ctx, env), primitiveType("null")]);
529
+ case "slice":
530
+ case "reverse":
531
+ case "unique":
532
+ return inferArrayLikeType(expr.array, ctx, env);
533
+ case "filter": {
534
+ const elementType = inferCollectionElementType(expr.array, ctx, env);
535
+ const nextEnv = withCollectionEnv(env, elementType);
536
+ inferExprType(expr.predicate, ctx, nextEnv);
537
+ return arrayType(elementType);
538
+ }
539
+ case "map": {
540
+ const elementType = inferCollectionElementType(expr.array, ctx, env);
541
+ const nextEnv = withCollectionEnv(env, elementType);
542
+ return arrayType(inferExprType(expr.mapper, ctx, nextEnv));
543
+ }
544
+ case "find": {
545
+ const elementType = inferCollectionElementType(expr.array, ctx, env);
546
+ const nextEnv = withCollectionEnv(env, elementType);
547
+ inferExprType(expr.predicate, ctx, nextEnv);
548
+ return unionOf([elementType, primitiveType("null")]);
549
+ }
550
+ case "append": {
551
+ const baseArray = inferArrayLikeType(expr.array, ctx, env);
552
+ const baseElement = getArrayElementType(baseArray);
553
+ const itemTypes = expr.items.map((item) => inferExprType(item, ctx, env));
554
+ return arrayType(unionOf([baseElement, ...itemTypes]));
555
+ }
556
+ case "flat":
557
+ return inferFlatType(expr.array, ctx, env);
558
+ case "object": {
559
+ const fields = {};
560
+ for (const name of Object.keys(expr.fields)) {
561
+ fields[name] = {
562
+ type: inferExprType(expr.fields[name], ctx, env),
563
+ optional: false
564
+ };
565
+ }
566
+ return objectType(fields);
567
+ }
568
+ case "field":
569
+ return inferFieldType(inferExprType(expr.object, ctx, env), expr.property);
570
+ case "keys":
571
+ return arrayType(primitiveType("string"));
572
+ case "values":
573
+ return arrayType(inferObjectValueType(inferExprType(expr.obj, ctx, env)));
574
+ case "entries":
575
+ return arrayType(
576
+ tupleType([
577
+ primitiveType("string"),
578
+ inferObjectValueType(inferExprType(expr.obj, ctx, env))
579
+ ])
580
+ );
581
+ case "merge":
582
+ return inferMergeType(
583
+ expr.objects.map((objectExpr) => inferExprType(objectExpr, ctx, env))
584
+ );
585
+ case "pick":
586
+ return inferPickLikeType(expr.obj, expr.keys, false, ctx, env);
587
+ case "omit":
588
+ return inferPickLikeType(expr.obj, expr.keys, true, ctx, env);
589
+ case "fromEntries":
590
+ return inferFromEntriesType(expr.entries, ctx, env);
591
+ case "coalesce": {
592
+ const members = expr.args.flatMap(
593
+ (arg) => removeNullType(inferExprType(arg, ctx, env))
594
+ );
595
+ return members.length === 0 ? primitiveType("null") : unionOf(members);
596
+ }
597
+ default:
598
+ warn(ctx, `Unsupported expression kind "${expr.kind}". Emitting "unknown".`);
599
+ return unknownType();
600
+ }
601
+ }
602
+ function inferPathType(path, ctx, env) {
603
+ const [head, ...tail] = path.split(".");
604
+ if (!head) {
605
+ warn(ctx, `Empty get() path encountered. Emitting "unknown".`);
606
+ return unknownType();
607
+ }
608
+ let base = env.get(head);
609
+ if (!base) {
610
+ if (head === "meta") {
611
+ base = META_TYPE;
612
+ } else if (Object.hasOwn(ctx.schema.state.fields, head)) {
613
+ base = fieldSpecToDomainType(ctx.schema.state.fields[head]);
614
+ } else if (Object.hasOwn(ctx.schema.computed.fields, head)) {
615
+ base = inferComputedType(head, ctx);
616
+ }
617
+ }
618
+ if (!base) {
619
+ warn(ctx, `Unknown get() path "${path}". Emitting "unknown".`);
620
+ return unknownType();
621
+ }
622
+ return walkPathType(base, tail);
623
+ }
624
+ function walkPathType(base, segments) {
625
+ let current = base;
626
+ for (const segment of segments) {
627
+ current = accessSegmentType(current, segment);
628
+ }
629
+ return current;
630
+ }
631
+ function accessSegmentType(base, segment) {
632
+ switch (base.kind) {
633
+ case "object":
634
+ return Object.hasOwn(base.fields, segment) ? base.fields[segment].type : unknownType();
635
+ case "record":
636
+ return unionOf([base.value, primitiveType("null")]);
637
+ case "array":
638
+ return isNumericSegment(segment) ? unionOf([base.element, primitiveType("null")]) : unknownType();
639
+ case "tuple":
640
+ return isNumericSegment(segment) ? base.elements[Number(segment)] ?? unknownType() : unknownType();
641
+ case "union":
642
+ return unionIgnoringUnknown(
643
+ base.types.map((member) => accessSegmentType(member, segment))
644
+ );
645
+ default:
646
+ return unknownType();
647
+ }
648
+ }
649
+ function inferIndexedAccessType(expr, ctx, env) {
650
+ const base = inferExprType(expr, ctx, env);
651
+ switch (base.kind) {
652
+ case "array":
653
+ return base.element;
654
+ case "tuple":
655
+ return unionOf(base.elements);
656
+ case "record":
657
+ return base.value;
658
+ case "union":
659
+ return unionOf(base.types.map((member) => inferIndexedAccessFromType(member)));
660
+ default:
661
+ return unknownType();
662
+ }
663
+ }
664
+ function inferIndexedAccessFromType(type) {
665
+ switch (type.kind) {
666
+ case "array":
667
+ return type.element;
668
+ case "tuple":
669
+ return unionOf(type.elements);
670
+ case "record":
671
+ return type.value;
672
+ default:
673
+ return unknownType();
674
+ }
675
+ }
676
+ function inferCollectionElementType(expr, ctx, env) {
677
+ return getArrayElementType(inferExprType(expr, ctx, env));
678
+ }
679
+ function getArrayElementType(type) {
680
+ switch (type.kind) {
681
+ case "array":
682
+ return type.element;
683
+ case "tuple":
684
+ return unionOf(type.elements);
685
+ case "union":
686
+ return unionOf(type.types.map((member) => getArrayElementType(member)));
687
+ default:
688
+ return unknownType();
689
+ }
690
+ }
691
+ function inferArrayLikeType(expr, ctx, env) {
692
+ const inferred = inferExprType(expr, ctx, env);
693
+ switch (inferred.kind) {
694
+ case "array":
695
+ return inferred;
696
+ case "tuple":
697
+ return arrayType(unionOf(inferred.elements));
698
+ case "union": {
699
+ const arrays = inferred.types.map((member) => inferArrayLikeFromType(member)).filter((member) => member.kind !== "unknown");
700
+ return arrays.length === 0 ? arrayType(unknownType()) : unionOf(arrays);
701
+ }
702
+ default:
703
+ return arrayType(unknownType());
704
+ }
705
+ }
706
+ function inferArrayLikeFromType(type) {
707
+ switch (type.kind) {
708
+ case "array":
709
+ return type;
710
+ case "tuple":
711
+ return arrayType(unionOf(type.elements));
712
+ default:
713
+ return unknownType();
714
+ }
715
+ }
716
+ function inferFlatType(expr, ctx, env) {
717
+ const outer = inferArrayLikeType(expr, ctx, env);
718
+ const outerElement = getArrayElementType(outer);
719
+ switch (outerElement.kind) {
720
+ case "array":
721
+ return arrayType(outerElement.element);
722
+ case "tuple":
723
+ return arrayType(unionOf(outerElement.elements));
724
+ case "union": {
725
+ const flatMembers = [];
726
+ for (const member of outerElement.types) {
727
+ if (member.kind === "array") {
728
+ flatMembers.push(member.element);
729
+ continue;
730
+ }
731
+ if (member.kind === "tuple") {
732
+ flatMembers.push(unionOf(member.elements));
733
+ continue;
734
+ }
735
+ flatMembers.push(member);
736
+ }
737
+ return arrayType(unionOf(flatMembers));
738
+ }
739
+ default:
740
+ return arrayType(outerElement);
741
+ }
742
+ }
743
+ function inferFieldType(base, property) {
744
+ switch (base.kind) {
745
+ case "object":
746
+ return Object.hasOwn(base.fields, property) ? base.fields[property].type : primitiveType("null");
747
+ case "record":
748
+ return unionOf([base.value, primitiveType("null")]);
749
+ case "union":
750
+ return unionOf(base.types.map((member) => inferFieldType(member, property)));
751
+ default:
752
+ return primitiveType("null");
753
+ }
754
+ }
755
+ function inferObjectValueType(type) {
756
+ switch (type.kind) {
757
+ case "object": {
758
+ const values = Object.keys(type.fields).map((name) => type.fields[name].type);
759
+ return values.length === 0 ? unknownType() : unionOf(values);
760
+ }
761
+ case "record":
762
+ return type.value;
763
+ case "union":
764
+ return unionOf(type.types.map((member) => inferObjectValueType(member)));
765
+ default:
766
+ return unknownType();
767
+ }
768
+ }
769
+ function inferMergeType(types) {
770
+ const fields = {};
771
+ let sawObject = false;
772
+ for (const type of types) {
773
+ if (type.kind !== "object") {
774
+ continue;
775
+ }
776
+ sawObject = true;
777
+ for (const name of Object.keys(type.fields)) {
778
+ fields[name] = type.fields[name];
779
+ }
780
+ }
781
+ return sawObject ? objectType(fields) : objectType({});
782
+ }
783
+ function inferPickLikeType(objectExpr, keysExpr, omit, ctx, env) {
784
+ const base = inferExprType(objectExpr, ctx, env);
785
+ if (base.kind !== "object") {
786
+ return objectType({});
787
+ }
788
+ const keys = readStringArrayLiteral(keysExpr);
789
+ if (!keys) {
790
+ return base;
791
+ }
792
+ const selected = new Set(keys);
793
+ const fields = {};
794
+ for (const name of Object.keys(base.fields)) {
795
+ const shouldInclude = omit ? !selected.has(name) : selected.has(name);
796
+ if (shouldInclude) {
797
+ fields[name] = base.fields[name];
798
+ }
799
+ }
800
+ return objectType(fields);
801
+ }
802
+ function inferFromEntriesType(entriesExpr, ctx, env) {
803
+ const literalEntries = readLiteralEntries(entriesExpr);
804
+ if (literalEntries) {
805
+ const valueTypes = literalEntries.map(([, value]) => literalValueToType(value));
806
+ return recordType(primitiveType("string"), unionOf(valueTypes));
807
+ }
808
+ const entriesType = inferExprType(entriesExpr, ctx, env);
809
+ const elementType = getArrayElementType(entriesType);
810
+ if (elementType.kind === "tuple" && elementType.elements.length >= 2) {
811
+ return recordType(primitiveType("string"), elementType.elements[1]);
812
+ }
813
+ return recordType(primitiveType("string"), unknownType());
814
+ }
815
+ function withCollectionEnv(env, itemType) {
816
+ const next = new Map(env);
817
+ next.set("$index", primitiveType("number"));
818
+ next.set("$item", itemType);
819
+ return next;
820
+ }
821
+ function readStringArrayLiteral(expr) {
822
+ if (expr.kind !== "lit" || !Array.isArray(expr.value)) {
823
+ return null;
824
+ }
825
+ const values = [];
826
+ for (const item of expr.value) {
827
+ if (typeof item !== "string") {
828
+ return null;
829
+ }
830
+ values.push(item);
831
+ }
832
+ return values;
833
+ }
834
+ function readLiteralEntries(expr) {
835
+ if (expr.kind !== "lit" || !Array.isArray(expr.value)) {
836
+ return null;
837
+ }
838
+ const entries = [];
839
+ for (const item of expr.value) {
840
+ if (!Array.isArray(item) || item.length !== 2 || typeof item[0] !== "string") {
841
+ return null;
842
+ }
843
+ entries.push([item[0], item[1]]);
844
+ }
845
+ return entries;
846
+ }
847
+ function unionIgnoringUnknown(types) {
848
+ const filtered = types.filter((type) => type.kind !== "unknown");
849
+ return filtered.length === 0 ? unknownType() : unionOf(filtered);
850
+ }
851
+ function isNumericSegment(segment) {
852
+ return /^\d+$/.test(segment);
853
+ }
854
+ function warn(ctx, message) {
855
+ if (ctx.warnedMessages.has(message)) {
856
+ return;
857
+ }
858
+ ctx.warnedMessages.add(message);
859
+ ctx.diagnostics.push({
860
+ level: "warn",
861
+ plugin: ctx.pluginName,
862
+ message
863
+ });
864
+ }
865
+
866
+ // src/plugins/domain-plugin.ts
867
+ var PLUGIN_NAME = "codegen-plugin-domain";
868
+ function createDomainPlugin(options) {
869
+ return {
870
+ name: PLUGIN_NAME,
871
+ generate(ctx) {
872
+ const diagnostics = [];
873
+ const inference = createInferenceContext(ctx.schema, diagnostics, PLUGIN_NAME);
874
+ const interfaceName = options?.interfaceName ?? deriveInterfaceName(ctx) ?? "Domain";
875
+ const fileName = options?.fileName ?? deriveFileName(ctx.sourceId);
876
+ const stateFields = renderFieldBlock(
877
+ ctx.schema.state.fields,
878
+ { includeReservedState: options?.includeReservedState ?? false },
879
+ (_name, spec) => fieldSpecToDomainField(spec)
880
+ );
881
+ const computedFields = renderFieldBlock(
882
+ ctx.schema.computed.fields,
883
+ { includeReservedState: true },
884
+ (name) => ({
885
+ type: inferComputedType(name, inference),
886
+ optional: false
887
+ })
888
+ );
889
+ const actionNames = Object.keys(ctx.schema.actions).sort();
890
+ const actionLines = actionNames.map((name) => {
891
+ const action = ctx.schema.actions[name];
892
+ return ` ${name}: ${renderActionSignature(action.input)}`;
893
+ });
894
+ const sections = [
895
+ "export interface " + interfaceName + " {",
896
+ " readonly state: {",
897
+ stateFields,
898
+ " }",
899
+ " readonly computed: {",
900
+ computedFields,
901
+ " }",
902
+ " readonly actions: {",
903
+ actionLines.join("\n"),
904
+ " }",
905
+ "}"
906
+ ];
907
+ return {
908
+ patches: [{ op: "set", path: fileName, content: sections.join("\n") + "\n" }],
909
+ diagnostics
910
+ };
911
+ }
912
+ };
913
+ }
914
+ function renderFieldBlock(source, options, mapField) {
915
+ const names = Object.keys(source).filter((name) => options.includeReservedState || !name.startsWith("$")).sort();
916
+ if (names.length === 0) {
917
+ return "";
918
+ }
919
+ return names.map((name) => {
920
+ const field = mapField(name, source[name]);
921
+ const optional = field.optional ? "?" : "";
922
+ return ` ${name}${optional}: ${renderDomainType(field.type)}`;
923
+ }).join("\n");
924
+ }
925
+ function renderActionSignature(input) {
926
+ if (!input || typeof input !== "object" || !("type" in input)) {
927
+ return "() => void";
928
+ }
929
+ if (input.type !== "object" || !input.fields) {
930
+ return `(input: ${renderDomainType(fieldSpecToDomainType(input))}) => void`;
931
+ }
932
+ const names = Object.keys(input.fields);
933
+ if (names.length === 0) {
934
+ return "() => void";
935
+ }
936
+ const params = names.map((name) => {
937
+ const field = fieldSpecToDomainField(input.fields[name]);
938
+ const optional = field.optional ? "?" : "";
939
+ return `${name}${optional}: ${renderDomainType(field.type)}`;
940
+ });
941
+ return `(${params.join(", ")}) => void`;
942
+ }
943
+ function deriveInterfaceName(ctx) {
944
+ const metaName = ctx.schema.meta?.name?.trim();
945
+ if (metaName) {
946
+ return metaName;
947
+ }
948
+ const basename = basenameWithoutExtension(ctx.sourceId);
949
+ if (!basename) {
950
+ return null;
951
+ }
952
+ const candidate = pascalCase(basename);
953
+ return candidate.endsWith("Domain") ? candidate : `${candidate}Domain`;
954
+ }
955
+ function deriveFileName(sourceId) {
956
+ if (!sourceId) {
957
+ return "domain.ts";
958
+ }
959
+ const normalized = sourceId.replace(/\\/g, "/");
960
+ return `${normalized}.ts`;
961
+ }
962
+ function basenameWithoutExtension(sourceId) {
963
+ if (!sourceId) {
964
+ return null;
965
+ }
966
+ const normalized = sourceId.replace(/\\/g, "/");
967
+ const basename = normalized.split("/").pop() ?? "";
968
+ if (!basename) {
969
+ return null;
970
+ }
971
+ return basename.replace(/\.[^.]+$/, "");
972
+ }
973
+ function pascalCase(value) {
974
+ return value.split(/[^a-zA-Z0-9]+/).filter(Boolean).map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1)).join("");
975
+ }
976
+
218
977
  // src/plugins/ts-plugin.ts
219
- var PLUGIN_NAME = "codegen-plugin-ts";
978
+ var PLUGIN_NAME2 = "codegen-plugin-ts";
220
979
  function createTsPlugin(options) {
221
980
  const typesFile = options?.typesFile ?? "types.ts";
222
981
  const actionsFile = options?.actionsFile ?? "actions.ts";
223
982
  return {
224
- name: PLUGIN_NAME,
983
+ name: PLUGIN_NAME2,
225
984
  generate(ctx) {
226
985
  const diagnostics = [];
227
986
  const typeNames = [];
@@ -238,7 +997,7 @@ function createTsPlugin(options) {
238
997
  for (const actionName of sortedActionNames) {
239
998
  const spec = ctx.schema.actions[actionName];
240
999
  if (spec.input) {
241
- const typeName = pascalCase(actionName) + "Input";
1000
+ const typeName = pascalCase2(actionName) + "Input";
242
1001
  actionDecls.push(renderActionInputType(typeName, spec, diagnostics));
243
1002
  }
244
1003
  }
@@ -283,7 +1042,7 @@ function mapTypeDefinition(def, diagnostics) {
283
1042
  case "primitive":
284
1043
  return mapPrimitive(def.type);
285
1044
  case "literal":
286
- return renderLiteral(def.value);
1045
+ return renderLiteral2(def.value);
287
1046
  case "array":
288
1047
  return `${wrapComplex(mapTypeDefinition(def.element, diagnostics), def.element)}[]`;
289
1048
  case "record":
@@ -306,7 +1065,7 @@ function mapTypeDefinition(def, diagnostics) {
306
1065
  default: {
307
1066
  diagnostics.push({
308
1067
  level: "warn",
309
- plugin: PLUGIN_NAME,
1068
+ plugin: PLUGIN_NAME2,
310
1069
  message: `Unknown TypeDefinition kind: "${def.kind}". Emitting "unknown".`
311
1070
  });
312
1071
  return "unknown";
@@ -327,7 +1086,7 @@ function mapPrimitive(type) {
327
1086
  return "unknown";
328
1087
  }
329
1088
  }
330
- function renderLiteral(value) {
1089
+ function renderLiteral2(value) {
331
1090
  if (typeof value === "string") {
332
1091
  return JSON.stringify(value);
333
1092
  }
@@ -355,7 +1114,7 @@ function mapFieldSpec(spec, diagnostics) {
355
1114
  }
356
1115
  function mapFieldType(type, spec, diagnostics) {
357
1116
  if (typeof type === "object" && "enum" in type) {
358
- return type.enum.map((v) => renderLiteral(v)).join(" | ");
1117
+ return type.enum.map((v) => renderLiteral2(v)).join(" | ");
359
1118
  }
360
1119
  switch (type) {
361
1120
  case "string":
@@ -380,7 +1139,7 @@ function mapFieldType(type, spec, diagnostics) {
380
1139
  }
381
1140
  diagnostics.push({
382
1141
  level: "warn",
383
- plugin: PLUGIN_NAME,
1142
+ plugin: PLUGIN_NAME2,
384
1143
  message: "Object field without fields spec, degrading to Record<string, unknown>"
385
1144
  });
386
1145
  return "Record<string, unknown>";
@@ -391,7 +1150,7 @@ function mapFieldType(type, spec, diagnostics) {
391
1150
  }
392
1151
  diagnostics.push({
393
1152
  level: "warn",
394
- plugin: PLUGIN_NAME,
1153
+ plugin: PLUGIN_NAME2,
395
1154
  message: "Array field without items spec, degrading to unknown[]"
396
1155
  });
397
1156
  return "unknown[]";
@@ -400,17 +1159,17 @@ function mapFieldType(type, spec, diagnostics) {
400
1159
  return "unknown";
401
1160
  }
402
1161
  }
403
- function pascalCase(str) {
1162
+ function pascalCase2(str) {
404
1163
  return str.split(/[-_\s]+/).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("");
405
1164
  }
406
1165
 
407
1166
  // src/plugins/zod-plugin.ts
408
- var PLUGIN_NAME2 = "codegen-plugin-zod";
1167
+ var PLUGIN_NAME3 = "codegen-plugin-zod";
409
1168
  var TS_PLUGIN_NAME = "codegen-plugin-ts";
410
1169
  function createZodPlugin(options) {
411
1170
  const schemasFile = options?.schemasFile ?? "base.ts";
412
1171
  return {
413
- name: PLUGIN_NAME2,
1172
+ name: PLUGIN_NAME3,
414
1173
  generate(ctx) {
415
1174
  const diagnostics = [];
416
1175
  const tsArtifacts = ctx.artifacts[TS_PLUGIN_NAME];
@@ -462,7 +1221,7 @@ function mapTypeDefinition2(def, allTypeNames, diagnostics) {
462
1221
  default: {
463
1222
  diagnostics.push({
464
1223
  level: "warn",
465
- plugin: PLUGIN_NAME2,
1224
+ plugin: PLUGIN_NAME3,
466
1225
  message: `Unknown TypeDefinition kind: "${def.kind}". Emitting "z.unknown()".`
467
1226
  });
468
1227
  return "z.unknown()";
@@ -497,7 +1256,7 @@ function handleRecord(def, allTypeNames, diagnostics) {
497
1256
  if (def.key.kind !== "primitive" || def.key.type !== "string") {
498
1257
  diagnostics.push({
499
1258
  level: "warn",
500
- plugin: PLUGIN_NAME2,
1259
+ plugin: PLUGIN_NAME3,
501
1260
  message: `Record key type is not string (got ${JSON.stringify(def.key)}). Degrading to z.record(z.string(), ...).`
502
1261
  });
503
1262
  return `z.record(z.string(), ${valueSchema})`;
@@ -534,6 +1293,7 @@ function handleUnion(types, allTypeNames, diagnostics) {
534
1293
  return `z.union([${schemas.join(", ")}])`;
535
1294
  }
536
1295
  export {
1296
+ createDomainPlugin,
537
1297
  createTsPlugin,
538
1298
  createZodPlugin,
539
1299
  generate,