@kurotako/ir 0.1.0 → 0.2.0

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/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  # @kurotako/ir
2
2
 
3
+ ## 0.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 7a50439: IR union type support: `FieldType` gains `ref` and `union` kinds (recursive,
8
+ `v.lazy`-wrapped schema, hand-written type), a `TypeAlias` registry
9
+ (`SourceIR.typeAliases?`), the builder API (`f.ref`, `f.union` with
10
+ `UnionBuilder`, `addTypeAlias`), resolution helpers (`resolveRef`,
11
+ `resolveTypeAlias`, `iterTypeAliases`, `flattenUnion`) and an exhaustive
12
+ `scalarTsType`. Validation walks field types recursively (`unresolved_ref`,
13
+ `unresolved_type_alias`, `type_alias_key_mismatch`), tolerates degenerate
14
+ unions and reference cycles through a new non-fatal `info` channel on
15
+ `IrValidation` (`degenerate_union`, `union_cycle`).
16
+
17
+ Bumps `IR_VERSION` from `1` to `2`; `isCompatible` stays strict equality, so a
18
+ persisted `irVersion: '1'` dump is rejected with `version_incompatible`.
19
+
3
20
  ## 0.1.0
4
21
 
5
22
  ### Minor Changes
package/dist/index.cjs CHANGED
@@ -51,10 +51,13 @@ __export(index_exports, {
51
51
  ScalarTypeSchema: () => ScalarTypeSchema,
52
52
  SourceIrSchema: () => SourceIrSchema,
53
53
  StringFormatSchema: () => StringFormatSchema,
54
+ TypeAliasSchema: () => TypeAliasSchema,
54
55
  assertIR: () => assertIR,
55
56
  assertSourceIR: () => assertSourceIR,
57
+ collectRefNames: () => collectRefNames,
56
58
  createFields: () => createFields,
57
59
  createSourceIR: () => createSourceIR,
60
+ flattenUnion: () => flattenUnion,
58
61
  getSource: () => getSource,
59
62
  isCompatible: () => isCompatible,
60
63
  isCreateOptional: () => isCreateOptional,
@@ -62,11 +65,15 @@ __export(index_exports, {
62
65
  isDbAssigned: () => isDbAssigned,
63
66
  iterEntities: () => iterEntities,
64
67
  iterFields: () => iterFields,
68
+ iterTypeAliases: () => iterTypeAliases,
65
69
  parseIR: () => parseIR,
66
70
  primaryKeyFields: () => primaryKeyFields,
71
+ refCycleMembers: () => refCycleMembers,
67
72
  resolveEntity: () => resolveEntity,
68
73
  resolveEnum: () => resolveEnum,
74
+ resolveRef: () => resolveRef,
69
75
  resolveRelationTarget: () => resolveRelationTarget,
76
+ resolveTypeAlias: () => resolveTypeAlias,
70
77
  scalarTsType: () => scalarTsType,
71
78
  updateFields: () => updateFields,
72
79
  validateIR: () => validateIR,
@@ -131,11 +138,29 @@ var IndexTypeSchema = v.picklist([
131
138
  "brin",
132
139
  "spgist"
133
140
  ]);
134
- var FieldTypeSchema = v.variant("kind", [
135
- v.object({ kind: v.literal("scalar"), scalar: ScalarTypeSchema }),
136
- v.object({ kind: v.literal("enum"), ref: v.string() }),
137
- v.object({ kind: v.literal("unknown"), hint: v.optional(v.string()) })
138
- ]);
141
+ var FieldTypeSchema = v.lazy(
142
+ () => v.variant("kind", [
143
+ v.object({ kind: v.literal("scalar"), scalar: ScalarTypeSchema }),
144
+ v.object({ kind: v.literal("enum"), ref: v.string() }),
145
+ v.object({ kind: v.literal("unknown"), hint: v.optional(v.string()) }),
146
+ v.object({ kind: v.literal("ref"), ref: v.string() }),
147
+ v.object({
148
+ kind: v.literal("union"),
149
+ variants: v.array(FieldTypeSchema),
150
+ discriminator: v.optional(
151
+ v.object({
152
+ propertyName: v.string(),
153
+ mapping: v.optional(v.record(v.string(), v.string()))
154
+ })
155
+ )
156
+ })
157
+ ])
158
+ );
159
+ var TypeAliasSchema = v.object({
160
+ name: v.string(),
161
+ type: FieldTypeSchema,
162
+ doc: v.optional(v.string())
163
+ });
139
164
  var ConstraintsSchema = v.object({
140
165
  min: v.optional(v.number()),
141
166
  max: v.optional(v.number()),
@@ -216,7 +241,8 @@ var SourceIrSchema = v.object({
216
241
  parser: v.string(),
217
242
  parserVersion: v.optional(v.string()),
218
243
  entities: v.record(v.string(), EntitySchema),
219
- enums: v.record(v.string(), EnumDefSchema)
244
+ enums: v.record(v.string(), EnumDefSchema),
245
+ typeAliases: v.optional(v.record(v.string(), TypeAliasSchema))
220
246
  });
221
247
  var IrSchema = v.object({
222
248
  irVersion: v.string(),
@@ -227,7 +253,7 @@ var IrSchema = v.object({
227
253
  var v2 = __toESM(require("valibot"), 1);
228
254
 
229
255
  // src/version.ts
230
- var IR_VERSION = "1";
256
+ var IR_VERSION = "2";
231
257
  function isCompatible(irVersion) {
232
258
  return irVersion === IR_VERSION;
233
259
  }
@@ -296,7 +322,134 @@ function checkEnumValues(issues, path, values) {
296
322
  seen.add(value.name);
297
323
  }
298
324
  }
299
- function checkSource(namespace, source, lookupEntity, isNamespacePresent, issues) {
325
+ function walkFieldType(type, path, entity, source, issues, info) {
326
+ switch (type.kind) {
327
+ case "scalar":
328
+ case "unknown":
329
+ return;
330
+ case "enum": {
331
+ const resolved = entity?.enums?.[type.ref] ?? source.enums[type.ref];
332
+ if (resolved === void 0) {
333
+ pushIssue(
334
+ issues,
335
+ path,
336
+ "unresolved_enum_ref",
337
+ `field type references unknown enum '${type.ref}'`
338
+ );
339
+ }
340
+ return;
341
+ }
342
+ case "ref": {
343
+ const known = source.entities[type.ref] !== void 0 || source.typeAliases?.[type.ref] !== void 0;
344
+ if (!known) {
345
+ pushIssue(
346
+ issues,
347
+ path,
348
+ "unresolved_ref",
349
+ `ref '${type.ref}' resolves to no entity and no type alias`
350
+ );
351
+ }
352
+ return;
353
+ }
354
+ case "union": {
355
+ if (type.variants.length < 2) {
356
+ pushIssue(
357
+ info,
358
+ path,
359
+ "degenerate_union",
360
+ `union has ${type.variants.length} variant(s); expected at least 2`
361
+ );
362
+ }
363
+ type.variants.forEach((variant2, i) => {
364
+ walkFieldType(
365
+ variant2,
366
+ `${path}.variants.${i}`,
367
+ entity,
368
+ source,
369
+ issues,
370
+ info
371
+ );
372
+ });
373
+ const mapping = type.discriminator?.mapping;
374
+ if (mapping !== void 0) {
375
+ const refVariants = new Set(
376
+ type.variants.flatMap((vv) => vv.kind === "ref" ? [vv.ref] : [])
377
+ );
378
+ for (const [key, target] of Object.entries(mapping)) {
379
+ if (!refVariants.has(target)) {
380
+ pushIssue(
381
+ issues,
382
+ `${path}.discriminator.mapping.${key}`,
383
+ "unresolved_type_alias",
384
+ `discriminator mapping '${key}' -> '${target}' names no ref variant of the union`
385
+ );
386
+ }
387
+ }
388
+ }
389
+ return;
390
+ }
391
+ }
392
+ }
393
+ function collectRefs(type, out) {
394
+ if (type.kind === "ref") {
395
+ out.add(type.ref);
396
+ } else if (type.kind === "union") {
397
+ for (const variant2 of type.variants) {
398
+ collectRefs(variant2, out);
399
+ }
400
+ }
401
+ }
402
+ function checkRefCycles(namespace, source, info) {
403
+ const adjacency = /* @__PURE__ */ new Map();
404
+ for (const [key, alias] of Object.entries(source.typeAliases ?? {})) {
405
+ const refs = /* @__PURE__ */ new Set();
406
+ collectRefs(alias.type, refs);
407
+ adjacency.set(key, refs);
408
+ }
409
+ for (const [key, entity] of Object.entries(source.entities)) {
410
+ const refs = adjacency.get(key) ?? /* @__PURE__ */ new Set();
411
+ for (const field of entity.fields) {
412
+ collectRefs(field.type, refs);
413
+ }
414
+ adjacency.set(key, refs);
415
+ }
416
+ const state = /* @__PURE__ */ new Map();
417
+ const stack = [];
418
+ const reported = /* @__PURE__ */ new Set();
419
+ const visit = (node) => {
420
+ state.set(node, "gray");
421
+ stack.push(node);
422
+ for (const next of adjacency.get(node) ?? []) {
423
+ if (!adjacency.has(next)) {
424
+ continue;
425
+ }
426
+ const seen = state.get(next);
427
+ if (seen === "gray") {
428
+ const cycle = stack.slice(stack.indexOf(next));
429
+ const signature = [...cycle].sort().join("|");
430
+ if (!reported.has(signature)) {
431
+ reported.add(signature);
432
+ pushIssue(
433
+ info,
434
+ namespace,
435
+ "union_cycle",
436
+ `reference cycle: ${[...cycle, next].join(" -> ")}`
437
+ );
438
+ }
439
+ } else if (seen === void 0) {
440
+ visit(next);
441
+ }
442
+ }
443
+ stack.pop();
444
+ state.set(node, "black");
445
+ };
446
+ for (const node of adjacency.keys()) {
447
+ if (state.get(node) === void 0) {
448
+ visit(node);
449
+ }
450
+ }
451
+ }
452
+ function checkSource(namespace, source, lookupEntity, isNamespacePresent, issues, info) {
300
453
  for (const [key, def] of Object.entries(source.enums)) {
301
454
  if (def.name !== key) {
302
455
  pushIssue(
@@ -331,17 +484,7 @@ function checkSource(namespace, source, lookupEntity, isNamespacePresent, issues
331
484
  }
332
485
  fieldNames.add(field.name);
333
486
  checkConstraints(issues, `${fPath}.constraints`, field.constraints);
334
- if (field.type.kind === "enum") {
335
- const resolved = entity.enums?.[field.type.ref] ?? source.enums[field.type.ref];
336
- if (resolved === void 0) {
337
- pushIssue(
338
- issues,
339
- fPath,
340
- "unresolved_enum_ref",
341
- `field '${field.name}' references unknown enum '${field.type.ref}'`
342
- );
343
- }
344
- }
487
+ walkFieldType(field.type, fPath, entity, source, issues, info);
345
488
  }
346
489
  for (const [localKey, def] of Object.entries(entity.enums ?? {})) {
347
490
  if (def.name !== localKey) {
@@ -439,6 +582,19 @@ function checkSource(namespace, source, lookupEntity, isNamespacePresent, issues
439
582
  }
440
583
  });
441
584
  }
585
+ for (const [key, alias] of Object.entries(source.typeAliases ?? {})) {
586
+ const aPath = `${namespace}.typeAliases.${key}`;
587
+ if (alias.name !== key) {
588
+ pushIssue(
589
+ issues,
590
+ aPath,
591
+ "type_alias_key_mismatch",
592
+ `type alias key '${key}' does not match name '${alias.name}'`
593
+ );
594
+ }
595
+ walkFieldType(alias.type, `${aPath}.type`, void 0, source, issues, info);
596
+ }
597
+ checkRefCycles(namespace, source, info);
442
598
  }
443
599
  function validateSourceIR(value) {
444
600
  const parsed = v2.safeParse(SourceIrSchema, value);
@@ -447,10 +603,14 @@ function validateSourceIR(value) {
447
603
  }
448
604
  const source = parsed.output;
449
605
  const issues = [];
606
+ const info = [];
450
607
  const lookup = (ns, name) => ns === source.namespace ? source.entities[name] : void 0;
451
608
  const isPresent = (ns) => ns === source.namespace;
452
- checkSource(source.namespace, source, lookup, isPresent, issues);
453
- return issues.length > 0 ? { ok: false, issues } : { ok: true, value: source };
609
+ checkSource(source.namespace, source, lookup, isPresent, issues, info);
610
+ if (issues.length > 0) {
611
+ return { ok: false, issues };
612
+ }
613
+ return info.length > 0 ? { ok: true, value: source, info } : { ok: true, value: source };
454
614
  }
455
615
  function validateIR(value) {
456
616
  const parsed = v2.safeParse(IrSchema, value);
@@ -459,6 +619,7 @@ function validateIR(value) {
459
619
  }
460
620
  const ir = parsed.output;
461
621
  const issues = [];
622
+ const info = [];
462
623
  if (!isCompatible(ir.irVersion)) {
463
624
  pushIssue(
464
625
  issues,
@@ -478,9 +639,12 @@ function validateIR(value) {
478
639
  `source key '${key}' does not match namespace '${source.namespace}'`
479
640
  );
480
641
  }
481
- checkSource(source.namespace, source, lookup, isPresent, issues);
642
+ checkSource(source.namespace, source, lookup, isPresent, issues, info);
643
+ }
644
+ if (issues.length > 0) {
645
+ return { ok: false, issues };
482
646
  }
483
- return issues.length > 0 ? { ok: false, issues } : { ok: true, value: ir };
647
+ return info.length > 0 ? { ok: true, value: ir, info } : { ok: true, value: ir };
484
648
  }
485
649
  function assertIR(value) {
486
650
  const result = validateIR(value);
@@ -539,6 +703,123 @@ var EnumBuilderImpl = class {
539
703
  return this.#def;
540
704
  }
541
705
  };
706
+ function checkedScalar(path, t) {
707
+ if (!v3.is(ScalarTypeSchema, t)) {
708
+ throw new IrBuildError(path, `unknown scalar type '${t}'`);
709
+ }
710
+ return { kind: "scalar", scalar: t };
711
+ }
712
+ var UnionBuilderImpl = class _UnionBuilderImpl {
713
+ #path;
714
+ #variants = [];
715
+ #discriminator;
716
+ constructor(path) {
717
+ this.#path = path;
718
+ }
719
+ scalar(t) {
720
+ this.#variants.push(checkedScalar(this.#path, t));
721
+ return this;
722
+ }
723
+ enum(ref) {
724
+ this.#variants.push({ kind: "enum", ref });
725
+ return this;
726
+ }
727
+ ref(name) {
728
+ this.#variants.push({ kind: "ref", ref: name });
729
+ return this;
730
+ }
731
+ union(build) {
732
+ const nested = new _UnionBuilderImpl(this.#path);
733
+ build(nested);
734
+ for (const variant2 of nested.#variants) {
735
+ this.#variants.push(variant2);
736
+ }
737
+ return this;
738
+ }
739
+ unknown(hint) {
740
+ this.#variants.push(
741
+ hint === void 0 ? { kind: "unknown" } : { kind: "unknown", hint }
742
+ );
743
+ return this;
744
+ }
745
+ discriminator(propertyName, mapping) {
746
+ this.#discriminator = mapping === void 0 ? { propertyName } : { propertyName, mapping };
747
+ return this;
748
+ }
749
+ build() {
750
+ if (this.#variants.length < 2) {
751
+ throw new IrBuildError(
752
+ this.#path,
753
+ `union() needs at least 2 variants, got ${this.#variants.length}`
754
+ );
755
+ }
756
+ const mapping = this.#discriminator?.mapping;
757
+ if (mapping !== void 0) {
758
+ const refVariants = new Set(
759
+ this.#variants.flatMap((vv) => vv.kind === "ref" ? [vv.ref] : [])
760
+ );
761
+ for (const [key, target] of Object.entries(mapping)) {
762
+ if (!refVariants.has(target)) {
763
+ throw new IrBuildError(
764
+ this.#path,
765
+ `discriminator mapping '${key}' -> '${target}' names no ref variant`
766
+ );
767
+ }
768
+ }
769
+ }
770
+ const type = {
771
+ kind: "union",
772
+ variants: this.#variants
773
+ };
774
+ if (this.#discriminator !== void 0) {
775
+ type.discriminator = this.#discriminator;
776
+ }
777
+ return type;
778
+ }
779
+ };
780
+ var TypeAliasBuilderImpl = class {
781
+ #path;
782
+ #name;
783
+ #type = { kind: "unknown" };
784
+ #doc;
785
+ constructor(path, name) {
786
+ this.#path = path;
787
+ this.#name = name;
788
+ }
789
+ scalar(t) {
790
+ this.#type = checkedScalar(this.#path, t);
791
+ return this;
792
+ }
793
+ enum(ref) {
794
+ this.#type = { kind: "enum", ref };
795
+ return this;
796
+ }
797
+ ref(name) {
798
+ this.#type = { kind: "ref", ref: name };
799
+ return this;
800
+ }
801
+ union(build) {
802
+ const nested = new UnionBuilderImpl(this.#path);
803
+ build(nested);
804
+ this.#type = nested.build();
805
+ return this;
806
+ }
807
+ unknown(hint) {
808
+ this.#type = hint === void 0 ? { kind: "unknown" } : { kind: "unknown", hint };
809
+ return this;
810
+ }
811
+ doc(text) {
812
+ this.#doc = text;
813
+ return this;
814
+ }
815
+ build() {
816
+ const alias = { name: this.#name, type: this.#type };
817
+ if (this.#doc !== void 0) {
818
+ alias.doc = this.#doc;
819
+ }
820
+ return alias;
821
+ }
822
+ };
542
823
  var FieldBuilderImpl = class {
543
824
  #path;
544
825
  #field;
@@ -566,6 +847,16 @@ var FieldBuilderImpl = class {
566
847
  this.#field.type = { kind: "enum", ref };
567
848
  return this;
568
849
  }
850
+ ref(name) {
851
+ this.#field.type = { kind: "ref", ref: name };
852
+ return this;
853
+ }
854
+ union(build) {
855
+ const builder = new UnionBuilderImpl(this.#path);
856
+ build(builder);
857
+ this.#field.type = builder.build();
858
+ return this;
859
+ }
569
860
  unknown(hint) {
570
861
  this.#field.type = hint === void 0 ? { kind: "unknown" } : { kind: "unknown", hint };
571
862
  return this;
@@ -810,6 +1101,7 @@ var SourceIrBuilderImpl = class {
810
1101
  #entities = [];
811
1102
  #entityNames = /* @__PURE__ */ new Set();
812
1103
  #enums = {};
1104
+ #typeAliases = {};
813
1105
  constructor(init) {
814
1106
  this.#namespace = init.namespace;
815
1107
  this.#parser = init.parser;
@@ -834,6 +1126,21 @@ var SourceIrBuilderImpl = class {
834
1126
  this.#entities.push(builder);
835
1127
  return this;
836
1128
  }
1129
+ addTypeAlias(name, def) {
1130
+ if (name in this.#typeAliases) {
1131
+ throw new IrBuildError(
1132
+ `${this.#namespace}.typeAliases.${name}`,
1133
+ `duplicate type alias '${name}'`
1134
+ );
1135
+ }
1136
+ const builder = new TypeAliasBuilderImpl(
1137
+ `${this.#namespace}.typeAliases.${name}`,
1138
+ name
1139
+ );
1140
+ def(builder);
1141
+ this.#typeAliases[name] = builder.build();
1142
+ return this;
1143
+ }
837
1144
  build() {
838
1145
  const source = {
839
1146
  namespace: this.#namespace,
@@ -849,6 +1156,9 @@ var SourceIrBuilderImpl = class {
849
1156
  if (this.#parserVersion !== void 0) {
850
1157
  source.parserVersion = this.#parserVersion;
851
1158
  }
1159
+ if (Object.keys(this.#typeAliases).length > 0) {
1160
+ source.typeAliases = this.#typeAliases;
1161
+ }
852
1162
  try {
853
1163
  assertSourceIR(source);
854
1164
  } catch (err) {
@@ -879,6 +1189,112 @@ function resolveEntity(ir, namespace, name) {
879
1189
  function resolveEnum(source, entity, ref) {
880
1190
  return entity?.enums?.[ref] ?? source.enums[ref];
881
1191
  }
1192
+ function resolveRef(source, ref) {
1193
+ return source.entities[ref] ?? source.typeAliases?.[ref];
1194
+ }
1195
+ function resolveTypeAlias(source, name) {
1196
+ return source.typeAliases?.[name];
1197
+ }
1198
+ function* iterTypeAliases(ir) {
1199
+ for (const [namespace, source] of Object.entries(ir.sources)) {
1200
+ for (const alias of Object.values(source.typeAliases ?? {})) {
1201
+ yield { namespace, alias };
1202
+ }
1203
+ }
1204
+ }
1205
+ function collectRefNames(type, into = /* @__PURE__ */ new Set()) {
1206
+ if (type.kind === "ref") {
1207
+ into.add(type.ref);
1208
+ } else if (type.kind === "union") {
1209
+ for (const variant2 of type.variants) {
1210
+ collectRefNames(variant2, into);
1211
+ }
1212
+ }
1213
+ return into;
1214
+ }
1215
+ function refCycleMembers(source) {
1216
+ const adjacency = /* @__PURE__ */ new Map();
1217
+ const edgesFor = (key) => {
1218
+ let set = adjacency.get(key);
1219
+ if (set === void 0) {
1220
+ set = /* @__PURE__ */ new Set();
1221
+ adjacency.set(key, set);
1222
+ }
1223
+ return set;
1224
+ };
1225
+ for (const [key, alias] of Object.entries(source.typeAliases ?? {})) {
1226
+ collectRefNames(alias.type, edgesFor(key));
1227
+ }
1228
+ for (const [key, entity] of Object.entries(source.entities)) {
1229
+ const set = edgesFor(key);
1230
+ for (const field of entity.fields) {
1231
+ collectRefNames(field.type, set);
1232
+ }
1233
+ }
1234
+ const canReachSelf = (start) => {
1235
+ const seen = /* @__PURE__ */ new Set();
1236
+ const stack = [...adjacency.get(start) ?? []];
1237
+ while (stack.length > 0) {
1238
+ const node = stack.pop();
1239
+ if (node === void 0) {
1240
+ break;
1241
+ }
1242
+ if (node === start) {
1243
+ return true;
1244
+ }
1245
+ if (seen.has(node) || !adjacency.has(node)) {
1246
+ continue;
1247
+ }
1248
+ seen.add(node);
1249
+ for (const next of adjacency.get(node) ?? []) {
1250
+ stack.push(next);
1251
+ }
1252
+ }
1253
+ return false;
1254
+ };
1255
+ const members = /* @__PURE__ */ new Set();
1256
+ for (const node of adjacency.keys()) {
1257
+ if (canReachSelf(node)) {
1258
+ members.add(node);
1259
+ }
1260
+ }
1261
+ return members;
1262
+ }
1263
+ function fieldTypeKey(type) {
1264
+ switch (type.kind) {
1265
+ case "scalar":
1266
+ return `scalar:${type.scalar}`;
1267
+ case "enum":
1268
+ return `enum:${type.ref}`;
1269
+ case "ref":
1270
+ return `ref:${type.ref}`;
1271
+ case "unknown":
1272
+ return `unknown:${type.hint ?? ""}`;
1273
+ case "union":
1274
+ return `union:${flattenUnion(type).map(fieldTypeKey).join(",")}`;
1275
+ }
1276
+ }
1277
+ function flattenUnion(type) {
1278
+ const out = [];
1279
+ const seen = /* @__PURE__ */ new Set();
1280
+ const push = (t) => {
1281
+ if (t.kind === "union") {
1282
+ for (const variant2 of t.variants) {
1283
+ push(variant2);
1284
+ }
1285
+ return;
1286
+ }
1287
+ const key = fieldTypeKey(t);
1288
+ if (!seen.has(key)) {
1289
+ seen.add(key);
1290
+ out.push(t);
1291
+ }
1292
+ };
1293
+ for (const variant2 of type.variants) {
1294
+ push(variant2);
1295
+ }
1296
+ return out;
1297
+ }
882
1298
  function isCrossSource(fromNamespace, rel) {
883
1299
  return rel.target.namespace !== fromNamespace;
884
1300
  }
@@ -931,10 +1347,16 @@ function scalarTsType(type) {
931
1347
  switch (type.kind) {
932
1348
  case "enum":
933
1349
  return type.ref;
1350
+ case "ref":
1351
+ return type.ref;
934
1352
  case "unknown":
935
1353
  return "unknown";
936
1354
  case "scalar":
937
1355
  return mapScalar(type.scalar);
1356
+ case "union":
1357
+ return flattenUnion(type).map(
1358
+ (variant2) => variant2.kind === "union" ? `(${scalarTsType(variant2)})` : scalarTsType(variant2)
1359
+ ).join(" | ");
938
1360
  }
939
1361
  }
940
1362
  function mapScalar(scalar) {
@@ -982,10 +1404,13 @@ function mapScalar(scalar) {
982
1404
  ScalarTypeSchema,
983
1405
  SourceIrSchema,
984
1406
  StringFormatSchema,
1407
+ TypeAliasSchema,
985
1408
  assertIR,
986
1409
  assertSourceIR,
1410
+ collectRefNames,
987
1411
  createFields,
988
1412
  createSourceIR,
1413
+ flattenUnion,
989
1414
  getSource,
990
1415
  isCompatible,
991
1416
  isCreateOptional,
@@ -993,11 +1418,15 @@ function mapScalar(scalar) {
993
1418
  isDbAssigned,
994
1419
  iterEntities,
995
1420
  iterFields,
1421
+ iterTypeAliases,
996
1422
  parseIR,
997
1423
  primaryKeyFields,
1424
+ refCycleMembers,
998
1425
  resolveEntity,
999
1426
  resolveEnum,
1427
+ resolveRef,
1000
1428
  resolveRelationTarget,
1429
+ resolveTypeAlias,
1001
1430
  scalarTsType,
1002
1431
  updateFields,
1003
1432
  validateIR,