@manifesto-ai/codegen 0.1.4 → 0.2.1

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,792 @@ 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
+
977
+ // src/compiler-codegen.ts
978
+ function createCompilerCodegen(options = {}) {
979
+ const outDir = options.outDir ?? ".";
980
+ const plugins = options.plugins ?? [createDomainPlugin()];
981
+ return async (input) => {
982
+ const result = await generate({
983
+ schema: input.schema,
984
+ sourceId: input.sourceId,
985
+ outDir,
986
+ plugins,
987
+ stamp: options.stamp
988
+ });
989
+ const errors = result.diagnostics.filter((diagnostic) => diagnostic.level === "error");
990
+ if (errors.length > 0) {
991
+ const details = errors.map((diagnostic) => `[${diagnostic.plugin}] ${diagnostic.message}`).join("\n");
992
+ throw new Error(`Codegen failed for ${input.sourceId}
993
+ ${details}`);
994
+ }
995
+ return result;
996
+ };
997
+ }
998
+
218
999
  // src/plugins/ts-plugin.ts
219
- var PLUGIN_NAME = "codegen-plugin-ts";
1000
+ var PLUGIN_NAME2 = "codegen-plugin-ts";
220
1001
  function createTsPlugin(options) {
221
1002
  const typesFile = options?.typesFile ?? "types.ts";
222
1003
  const actionsFile = options?.actionsFile ?? "actions.ts";
223
1004
  return {
224
- name: PLUGIN_NAME,
1005
+ name: PLUGIN_NAME2,
225
1006
  generate(ctx) {
226
1007
  const diagnostics = [];
227
1008
  const typeNames = [];
@@ -238,7 +1019,7 @@ function createTsPlugin(options) {
238
1019
  for (const actionName of sortedActionNames) {
239
1020
  const spec = ctx.schema.actions[actionName];
240
1021
  if (spec.input) {
241
- const typeName = pascalCase(actionName) + "Input";
1022
+ const typeName = pascalCase2(actionName) + "Input";
242
1023
  actionDecls.push(renderActionInputType(typeName, spec, diagnostics));
243
1024
  }
244
1025
  }
@@ -283,7 +1064,7 @@ function mapTypeDefinition(def, diagnostics) {
283
1064
  case "primitive":
284
1065
  return mapPrimitive(def.type);
285
1066
  case "literal":
286
- return renderLiteral(def.value);
1067
+ return renderLiteral2(def.value);
287
1068
  case "array":
288
1069
  return `${wrapComplex(mapTypeDefinition(def.element, diagnostics), def.element)}[]`;
289
1070
  case "record":
@@ -306,7 +1087,7 @@ function mapTypeDefinition(def, diagnostics) {
306
1087
  default: {
307
1088
  diagnostics.push({
308
1089
  level: "warn",
309
- plugin: PLUGIN_NAME,
1090
+ plugin: PLUGIN_NAME2,
310
1091
  message: `Unknown TypeDefinition kind: "${def.kind}". Emitting "unknown".`
311
1092
  });
312
1093
  return "unknown";
@@ -327,7 +1108,7 @@ function mapPrimitive(type) {
327
1108
  return "unknown";
328
1109
  }
329
1110
  }
330
- function renderLiteral(value) {
1111
+ function renderLiteral2(value) {
331
1112
  if (typeof value === "string") {
332
1113
  return JSON.stringify(value);
333
1114
  }
@@ -355,7 +1136,7 @@ function mapFieldSpec(spec, diagnostics) {
355
1136
  }
356
1137
  function mapFieldType(type, spec, diagnostics) {
357
1138
  if (typeof type === "object" && "enum" in type) {
358
- return type.enum.map((v) => renderLiteral(v)).join(" | ");
1139
+ return type.enum.map((v) => renderLiteral2(v)).join(" | ");
359
1140
  }
360
1141
  switch (type) {
361
1142
  case "string":
@@ -380,7 +1161,7 @@ function mapFieldType(type, spec, diagnostics) {
380
1161
  }
381
1162
  diagnostics.push({
382
1163
  level: "warn",
383
- plugin: PLUGIN_NAME,
1164
+ plugin: PLUGIN_NAME2,
384
1165
  message: "Object field without fields spec, degrading to Record<string, unknown>"
385
1166
  });
386
1167
  return "Record<string, unknown>";
@@ -391,7 +1172,7 @@ function mapFieldType(type, spec, diagnostics) {
391
1172
  }
392
1173
  diagnostics.push({
393
1174
  level: "warn",
394
- plugin: PLUGIN_NAME,
1175
+ plugin: PLUGIN_NAME2,
395
1176
  message: "Array field without items spec, degrading to unknown[]"
396
1177
  });
397
1178
  return "unknown[]";
@@ -400,17 +1181,17 @@ function mapFieldType(type, spec, diagnostics) {
400
1181
  return "unknown";
401
1182
  }
402
1183
  }
403
- function pascalCase(str) {
1184
+ function pascalCase2(str) {
404
1185
  return str.split(/[-_\s]+/).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("");
405
1186
  }
406
1187
 
407
1188
  // src/plugins/zod-plugin.ts
408
- var PLUGIN_NAME2 = "codegen-plugin-zod";
1189
+ var PLUGIN_NAME3 = "codegen-plugin-zod";
409
1190
  var TS_PLUGIN_NAME = "codegen-plugin-ts";
410
1191
  function createZodPlugin(options) {
411
1192
  const schemasFile = options?.schemasFile ?? "base.ts";
412
1193
  return {
413
- name: PLUGIN_NAME2,
1194
+ name: PLUGIN_NAME3,
414
1195
  generate(ctx) {
415
1196
  const diagnostics = [];
416
1197
  const tsArtifacts = ctx.artifacts[TS_PLUGIN_NAME];
@@ -462,7 +1243,7 @@ function mapTypeDefinition2(def, allTypeNames, diagnostics) {
462
1243
  default: {
463
1244
  diagnostics.push({
464
1245
  level: "warn",
465
- plugin: PLUGIN_NAME2,
1246
+ plugin: PLUGIN_NAME3,
466
1247
  message: `Unknown TypeDefinition kind: "${def.kind}". Emitting "z.unknown()".`
467
1248
  });
468
1249
  return "z.unknown()";
@@ -497,7 +1278,7 @@ function handleRecord(def, allTypeNames, diagnostics) {
497
1278
  if (def.key.kind !== "primitive" || def.key.type !== "string") {
498
1279
  diagnostics.push({
499
1280
  level: "warn",
500
- plugin: PLUGIN_NAME2,
1281
+ plugin: PLUGIN_NAME3,
501
1282
  message: `Record key type is not string (got ${JSON.stringify(def.key)}). Degrading to z.record(z.string(), ...).`
502
1283
  });
503
1284
  return `z.record(z.string(), ${valueSchema})`;
@@ -534,6 +1315,8 @@ function handleUnion(types, allTypeNames, diagnostics) {
534
1315
  return `z.union([${schemas.join(", ")}])`;
535
1316
  }
536
1317
  export {
1318
+ createCompilerCodegen,
1319
+ createDomainPlugin,
537
1320
  createTsPlugin,
538
1321
  createZodPlugin,
539
1322
  generate,