inferred-types 0.26.0 → 0.28.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.
Files changed (37) hide show
  1. package/.vscode/settings.json +5 -0
  2. package/dist/index.d.ts +441 -126
  3. package/dist/index.js +80 -6
  4. package/dist/index.mjs +74 -6
  5. package/package.json +1 -1
  6. package/src/types/Mutable.ts +3 -1
  7. package/src/types/TypeInfo/Extends.ts +14 -0
  8. package/src/types/TypeInfo/IsBooleanLiteral.ts +9 -0
  9. package/src/types/TypeInfo/IsLiteral.ts +36 -2
  10. package/src/types/TypeInfo/IsNumericLiteral.ts +9 -0
  11. package/src/types/TypeInfo/IsObject.ts +27 -0
  12. package/src/types/TypeInfo/IsScalar.ts +14 -0
  13. package/src/types/TypeInfo/IsStringLiteral.ts +9 -0
  14. package/src/types/TypeInfo/IsUndefined.ts +14 -0
  15. package/src/types/TypeInfo/TypeDefault.ts +58 -0
  16. package/src/types/TypeInfo/index.ts +4 -0
  17. package/src/types/alphabetic/Cardinality.ts +80 -0
  18. package/src/types/alphabetic/index.ts +1 -0
  19. package/src/types/dictionary/MapTo.ts +332 -13
  20. package/src/types/dictionary/props.ts +11 -0
  21. package/src/types/index.ts +1 -0
  22. package/src/types/kv/DictFromKv.ts +1 -1
  23. package/src/types/literal-unions/OptRequired.ts +4 -0
  24. package/src/types/literal-unions/index.ts +1 -0
  25. package/src/types/string-literals/Replace.ts +8 -4
  26. package/src/types/type-testing.ts +2 -5
  27. package/src/utility/dictionary/kv/kvToDict.ts +1 -2
  28. package/src/utility/dictionary/mapTo.ts +160 -28
  29. package/src/utility/dictionary/merge.ts +36 -0
  30. package/src/utility/runtime/conditions/isObject.ts +2 -16
  31. package/tests/TypeInfo/IsLiteral.spec.ts +17 -1
  32. package/tests/createFnWithProps.spec.ts +1 -0
  33. package/tests/dictionary/IntersectingKeys.test.ts +42 -0
  34. package/tests/dictionary/TypeDefault.test.ts +76 -0
  35. package/tests/dictionary/mapTo.test.ts +327 -94
  36. package/tests/dictionary/merge.test.ts +41 -0
  37. package/tests/withValue.spec.ts +0 -1
package/dist/index.js CHANGED
@@ -21,8 +21,12 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var src_exports = {};
22
22
  __export(src_exports, {
23
23
  Configurator: () => Configurator,
24
+ DEFAULT_MANY_TO_ONE_MAPPING: () => DEFAULT_MANY_TO_ONE_MAPPING,
25
+ DEFAULT_ONE_TO_MANY_MAPPING: () => DEFAULT_ONE_TO_MANY_MAPPING,
26
+ DEFAULT_ONE_TO_ONE_MAPPING: () => DEFAULT_ONE_TO_ONE_MAPPING,
24
27
  ExplicitFunction: () => ExplicitFunction,
25
28
  FluentConfigurator: () => FluentConfigurator,
29
+ MapCardinality: () => MapCardinality,
26
30
  Model: () => Model,
27
31
  MutationIdentity: () => MutationIdentity,
28
32
  and: () => and,
@@ -67,6 +71,8 @@ __export(src_exports, {
67
71
  kvToDict: () => kvToDict,
68
72
  literal: () => literal,
69
73
  mapTo: () => mapTo,
74
+ mapToDict: () => mapToDict,
75
+ mapToFn: () => mapToFn,
70
76
  mapValues: () => mapValues,
71
77
  nameLiteral: () => nameLiteral,
72
78
  not: () => not,
@@ -126,6 +132,14 @@ var valueTypes = {
126
132
  literalArray: (arr) => [arr, true]
127
133
  };
128
134
 
135
+ // src/types/dictionary/MapTo.ts
136
+ var MapCardinality = /* @__PURE__ */ ((MapCardinality2) => {
137
+ MapCardinality2["OneToMany"] = "I -> O[]";
138
+ MapCardinality2["OneToOne"] = "I -> O";
139
+ MapCardinality2["ManyToOne"] = "I[] -> O";
140
+ return MapCardinality2;
141
+ })(MapCardinality || {});
142
+
129
143
  // src/utility/keys.ts
130
144
  function keys(obj, ...without) {
131
145
  const v = without.length > 0 ? Object.keys(obj).filter((k) => !without.includes(k)) : Object.keys(obj);
@@ -579,14 +593,68 @@ function mapValues(obj, valueMapper) {
579
593
  }
580
594
 
581
595
  // src/utility/dictionary/mapTo.ts
582
- var mapTo = (cb) => (source) => {
583
- if (Array.isArray(source)) {
584
- return source.flatMap((i) => cb(i)).filter((i) => i !== null);
585
- } else {
586
- const result = cb(source);
587
- return result ? result : [];
596
+ var toFinalizedConfig = (config) => {
597
+ return { ...config, finalized: true };
598
+ };
599
+ var DEFAULT_ONE_TO_MANY_MAPPING = toFinalizedConfig({
600
+ input: "req",
601
+ output: "opt",
602
+ cardinality: "I -> O[]"
603
+ });
604
+ var DEFAULT_ONE_TO_ONE_MAPPING = toFinalizedConfig({
605
+ input: "req",
606
+ output: "req",
607
+ cardinality: "I -> O"
608
+ });
609
+ var DEFAULT_MANY_TO_ONE_MAPPING = toFinalizedConfig({
610
+ input: "req",
611
+ output: "req",
612
+ cardinality: "I[] -> O"
613
+ });
614
+ var mapper = (config) => (map) => {
615
+ return (source) => {
616
+ const isArray2 = config.cardinality === "I -> O[]" && Array.isArray(source) ? true : config.cardinality === "I[] -> O" && Array.isArray(source) && Array.isArray(source[0]) ? true : false;
617
+ if (isArray2) {
618
+ return source.flatMap(map);
619
+ } else {
620
+ return map(source);
621
+ }
622
+ };
623
+ };
624
+ var setMapper = (config = { input: void 0, output: void 0, cardinality: void 0 }, defaultValue) => ({
625
+ map: (source) => {
626
+ const c = {
627
+ ...defaultValue,
628
+ ...config
629
+ };
630
+ return mapper(c)(source);
631
+ },
632
+ input: (config == null ? void 0 : config.input) || defaultValue.input,
633
+ output: (config == null ? void 0 : config.output) || defaultValue.output,
634
+ cardinality: (config == null ? void 0 : config.cardinality) || defaultValue.cardinality
635
+ });
636
+ var mapToFn = (map) => {
637
+ return mapper(DEFAULT_ONE_TO_MANY_MAPPING)(map);
638
+ };
639
+ var mapToDict = {
640
+ config(config) {
641
+ const c = { ...DEFAULT_ONE_TO_MANY_MAPPING, ...config };
642
+ return setMapper(c, DEFAULT_ONE_TO_MANY_MAPPING);
643
+ },
644
+ oneToOne(config) {
645
+ const c = { ...DEFAULT_ONE_TO_ONE_MAPPING, ...config };
646
+ return setMapper(c, DEFAULT_ONE_TO_ONE_MAPPING);
647
+ },
648
+ manyToOne(config) {
649
+ const c = { ...DEFAULT_MANY_TO_ONE_MAPPING, ...config };
650
+ return setMapper(c, DEFAULT_MANY_TO_ONE_MAPPING);
651
+ },
652
+ oneToMany(config) {
653
+ const c = { ...DEFAULT_ONE_TO_MANY_MAPPING, ...config };
654
+ return setMapper(c, DEFAULT_ONE_TO_MANY_MAPPING);
588
655
  }
589
656
  };
657
+ var mapTo = createFnWithProps(mapToFn, mapToDict);
590
658
 
591
659
  // src/utility/dictionary/strArrayToDict.ts
592
660
  function strArrayToDict(...strings) {
@@ -752,8 +820,12 @@ function Model(name) {
752
820
  // Annotate the CommonJS export names for ESM import in node:
753
821
  0 && (module.exports = {
754
822
  Configurator,
823
+ DEFAULT_MANY_TO_ONE_MAPPING,
824
+ DEFAULT_ONE_TO_MANY_MAPPING,
825
+ DEFAULT_ONE_TO_ONE_MAPPING,
755
826
  ExplicitFunction,
756
827
  FluentConfigurator,
828
+ MapCardinality,
757
829
  Model,
758
830
  MutationIdentity,
759
831
  and,
@@ -798,6 +870,8 @@ function Model(name) {
798
870
  kvToDict,
799
871
  literal,
800
872
  mapTo,
873
+ mapToDict,
874
+ mapToFn,
801
875
  mapValues,
802
876
  nameLiteral,
803
877
  not,
package/dist/index.mjs CHANGED
@@ -41,6 +41,14 @@ var valueTypes = {
41
41
  literalArray: (arr) => [arr, true]
42
42
  };
43
43
 
44
+ // src/types/dictionary/MapTo.ts
45
+ var MapCardinality = /* @__PURE__ */ ((MapCardinality2) => {
46
+ MapCardinality2["OneToMany"] = "I -> O[]";
47
+ MapCardinality2["OneToOne"] = "I -> O";
48
+ MapCardinality2["ManyToOne"] = "I[] -> O";
49
+ return MapCardinality2;
50
+ })(MapCardinality || {});
51
+
44
52
  // src/utility/keys.ts
45
53
  function keys(obj, ...without) {
46
54
  const v = without.length > 0 ? Object.keys(obj).filter((k) => !without.includes(k)) : Object.keys(obj);
@@ -494,14 +502,68 @@ function mapValues(obj, valueMapper) {
494
502
  }
495
503
 
496
504
  // src/utility/dictionary/mapTo.ts
497
- var mapTo = (cb) => (source) => {
498
- if (Array.isArray(source)) {
499
- return source.flatMap((i) => cb(i)).filter((i) => i !== null);
500
- } else {
501
- const result = cb(source);
502
- return result ? result : [];
505
+ var toFinalizedConfig = (config) => {
506
+ return { ...config, finalized: true };
507
+ };
508
+ var DEFAULT_ONE_TO_MANY_MAPPING = toFinalizedConfig({
509
+ input: "req",
510
+ output: "opt",
511
+ cardinality: "I -> O[]"
512
+ });
513
+ var DEFAULT_ONE_TO_ONE_MAPPING = toFinalizedConfig({
514
+ input: "req",
515
+ output: "req",
516
+ cardinality: "I -> O"
517
+ });
518
+ var DEFAULT_MANY_TO_ONE_MAPPING = toFinalizedConfig({
519
+ input: "req",
520
+ output: "req",
521
+ cardinality: "I[] -> O"
522
+ });
523
+ var mapper = (config) => (map) => {
524
+ return (source) => {
525
+ const isArray2 = config.cardinality === "I -> O[]" && Array.isArray(source) ? true : config.cardinality === "I[] -> O" && Array.isArray(source) && Array.isArray(source[0]) ? true : false;
526
+ if (isArray2) {
527
+ return source.flatMap(map);
528
+ } else {
529
+ return map(source);
530
+ }
531
+ };
532
+ };
533
+ var setMapper = (config = { input: void 0, output: void 0, cardinality: void 0 }, defaultValue) => ({
534
+ map: (source) => {
535
+ const c = {
536
+ ...defaultValue,
537
+ ...config
538
+ };
539
+ return mapper(c)(source);
540
+ },
541
+ input: (config == null ? void 0 : config.input) || defaultValue.input,
542
+ output: (config == null ? void 0 : config.output) || defaultValue.output,
543
+ cardinality: (config == null ? void 0 : config.cardinality) || defaultValue.cardinality
544
+ });
545
+ var mapToFn = (map) => {
546
+ return mapper(DEFAULT_ONE_TO_MANY_MAPPING)(map);
547
+ };
548
+ var mapToDict = {
549
+ config(config) {
550
+ const c = { ...DEFAULT_ONE_TO_MANY_MAPPING, ...config };
551
+ return setMapper(c, DEFAULT_ONE_TO_MANY_MAPPING);
552
+ },
553
+ oneToOne(config) {
554
+ const c = { ...DEFAULT_ONE_TO_ONE_MAPPING, ...config };
555
+ return setMapper(c, DEFAULT_ONE_TO_ONE_MAPPING);
556
+ },
557
+ manyToOne(config) {
558
+ const c = { ...DEFAULT_MANY_TO_ONE_MAPPING, ...config };
559
+ return setMapper(c, DEFAULT_MANY_TO_ONE_MAPPING);
560
+ },
561
+ oneToMany(config) {
562
+ const c = { ...DEFAULT_ONE_TO_MANY_MAPPING, ...config };
563
+ return setMapper(c, DEFAULT_ONE_TO_MANY_MAPPING);
503
564
  }
504
565
  };
566
+ var mapTo = createFnWithProps(mapToFn, mapToDict);
505
567
 
506
568
  // src/utility/dictionary/strArrayToDict.ts
507
569
  function strArrayToDict(...strings) {
@@ -666,8 +728,12 @@ function Model(name) {
666
728
  }
667
729
  export {
668
730
  Configurator,
731
+ DEFAULT_MANY_TO_ONE_MAPPING,
732
+ DEFAULT_ONE_TO_MANY_MAPPING,
733
+ DEFAULT_ONE_TO_ONE_MAPPING,
669
734
  ExplicitFunction,
670
735
  FluentConfigurator,
736
+ MapCardinality,
671
737
  Model,
672
738
  MutationIdentity,
673
739
  and,
@@ -712,6 +778,8 @@ export {
712
778
  kvToDict,
713
779
  literal,
714
780
  mapTo,
781
+ mapToDict,
782
+ mapToFn,
715
783
  mapValues,
716
784
  nameLiteral,
717
785
  not,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "inferred-types",
3
- "version": "0.26.0",
3
+ "version": "0.28.0",
4
4
  "description": "Functions which provide useful type inference on TS projects",
5
5
  "license": "MIT",
6
6
  "author": "Ken Snyder<ken@ken.net>",
@@ -1,6 +1,8 @@
1
+ import { IsObject } from "./TypeInfo";
2
+
1
3
  /**
2
4
  * Makes a readonly structure mutable
3
5
  */
4
6
  export type Mutable<T> = {
5
- -readonly [K in keyof T]: T[K];
7
+ -readonly [K in keyof T]: IsObject<T[K]> extends true ? Mutable<T[K]> : T[K];
6
8
  };
@@ -0,0 +1,14 @@
1
+ /**
2
+ * **Extends**
3
+ *
4
+ * Boolean type utility which returns `true` if `E` _extends_ `T`.
5
+ */
6
+ export type Extends<E, T> = E extends T ? true : false;
7
+
8
+ /**
9
+ * **IfExtends**
10
+ *
11
+ * Branching type utility which returns type `IF` when `E` _extends_ `T`; otherwise
12
+ * it will return the type `ELSE`.
13
+ */
14
+ export type IfExtends<E, T, IF, ELSE> = Extends<E, T> extends true ? IF : ELSE;
@@ -5,3 +5,12 @@
5
5
  * just the wider _boolean_ type.
6
6
  */
7
7
  export type IsBooleanLiteral<T extends boolean> = boolean extends T ? false : true;
8
+
9
+ /**
10
+ * **IfBooleanLiteral**
11
+ *
12
+ * Branch utility which returns `IF` type when `T` is a boolean literal and `ELSE` otherwise
13
+ */
14
+ export type IfBooleanLiteral<T extends boolean, IF, ELSE> = IsBooleanLiteral<T> extends true
15
+ ? IF
16
+ : ELSE;
@@ -11,10 +11,44 @@ import { IsNumericLiteral } from "./IsNumericLiteral";
11
11
  * string, number, or boolean -- is a _literal_ value of that type (true) or
12
12
  * the more generic wide type (false).
13
13
  */
14
- export type IsLiteral<T extends string | number | boolean> = [T] extends [string]
14
+ export type IsLiteral<T> = [T] extends [string]
15
15
  ? IsStringLiteral<T>
16
16
  : [T] extends [boolean]
17
17
  ? IsBooleanLiteral<T>
18
18
  : [T] extends [number]
19
19
  ? IsNumericLiteral<T>
20
- : never;
20
+ : false;
21
+
22
+ /**
23
+ * **IsOptionalLiteral**
24
+ *
25
+ * Type utility which returns true/false if the value passed -- a form of a
26
+ * string, number, or boolean -- is a _literal_ value of that type (true) or
27
+ * the more generic wide type (false).
28
+ *
29
+ * This type also strips off _undefined_ from any possible union type to evaluate
30
+ * to `true` even when a literal value is in union with _undefined_. If you don't
31
+ * want to test for the union with _undefined_ use the `IsOptional` utility instead.
32
+ */
33
+ export type IsOptionalLiteral<T> = [Exclude<T, undefined>] extends [string]
34
+ ? IsStringLiteral<Exclude<T, undefined>>
35
+ : [Exclude<T, undefined>] extends [boolean]
36
+ ? IsBooleanLiteral<Exclude<T, undefined>>
37
+ : [Exclude<T, undefined>] extends [number]
38
+ ? IsNumericLiteral<Exclude<T, undefined>>
39
+ : false;
40
+
41
+ /**
42
+ * **IfLiteral**
43
+ *
44
+ * Branch type utility with return `IF` when `T` is a _literal_ value and `ELSE` otherwise
45
+ */
46
+ export type IfLiteral<T, IF, ELSE> = IsLiteral<T> extends true ? IF : ELSE;
47
+
48
+ /**
49
+ * **IfOptionalLiteral**
50
+ *
51
+ * Branch type utility with return `IF` when `T` is a _literal_ value (with possibly
52
+ * the inclusion of _undefined_); otherwise returns the type `ELSE`
53
+ */
54
+ export type IfOptionalLiteral<T, IF, ELSE> = IsOptionalLiteral<T> extends true ? IF : ELSE;
@@ -5,3 +5,12 @@
5
5
  * just the _number_ type.
6
6
  */
7
7
  export type IsNumericLiteral<T extends number> = number extends T ? false : true;
8
+
9
+ /**
10
+ * **IfNumericLiteral**
11
+ *
12
+ * Branch utility which returns `IF` type when `T` is a numeric literal and `ELSE` otherwise
13
+ */
14
+ export type IfNumericLiteral<T extends number, IF, ELSE> = IsNumericLiteral<T> extends true
15
+ ? IF
16
+ : ELSE;
@@ -0,0 +1,27 @@
1
+ import { FunctionType } from "../FunctionType";
2
+ import { Mutable } from "../Mutable";
3
+
4
+ /**
5
+ * **IsObject**
6
+ *
7
+ * Boolean type utility used to check whether a type `T` is an object
8
+ */
9
+ export type IsObject<T> = Mutable<T> extends Record<string, any>
10
+ ? // an object of some type
11
+ T extends FunctionType
12
+ ? // when a function with props is found, categorize as a function not object
13
+ false
14
+ : Mutable<T> extends any[]
15
+ ? // Array's are objects too but in our narrower definition we're looking only
16
+ // dictionary based arrays.
17
+ false
18
+ : true
19
+ : false;
20
+
21
+ /**
22
+ * **IfObject**
23
+ *
24
+ * Branch type utility with return `IF` when `T` extends an object type
25
+ * and `ELSE` otherwise
26
+ */
27
+ export type IfObject<T, IF, ELSE> = IsObject<T> extends true ? IF : ELSE;
@@ -0,0 +1,14 @@
1
+ export type IsScalar<T> = [T] extends [string]
2
+ ? true
3
+ : [T] extends [number]
4
+ ? true
5
+ : [T] extends [boolean]
6
+ ? true
7
+ : false;
8
+
9
+ /**
10
+ * **IfScalar**
11
+ *
12
+ * Branch type utility which returns `IF` when `T` is a scalar value and `ELSE` otherwise
13
+ */
14
+ export type IfScalar<T, IF, ELSE> = IsScalar<T> extends true ? IF : ELSE;
@@ -5,3 +5,12 @@
5
5
  * just the _string_ type.
6
6
  */
7
7
  export type IsStringLiteral<T extends string> = string extends T ? false : true;
8
+
9
+ /**
10
+ * **IfStringLiteral**
11
+ *
12
+ * Branch utility which returns `IF` type when `T` is a string literal and `ELSE` otherwise
13
+ */
14
+ export type IfStringLiteral<T extends string, IF, ELSE> = IsStringLiteral<T> extends true
15
+ ? IF
16
+ : ELSE;
@@ -0,0 +1,14 @@
1
+ /**
2
+ * **IsUndefined**
3
+ *
4
+ * Boolean type utility returns `true` if `T` is undefined; `false` otherwise
5
+ */
6
+ export type IsUndefined<T> = T extends undefined ? true : false;
7
+
8
+ /**
9
+ * **IfUndefined**
10
+ *
11
+ * Branch utility which returns `IF` type when `T` is an _undefined_ value
12
+ * otherwise returns `ELSE` type
13
+ */
14
+ export type IfUndefined<T, IF, ELSE> = IsUndefined<T> extends true ? IF : ELSE;
@@ -0,0 +1,58 @@
1
+ import { IsObject } from "src/types/TypeInfo";
2
+ import { SimplifyObject } from "../SimplifyObject";
3
+ import { IfExtends } from "./Extends";
4
+ import { IfOptionalLiteral } from "./IsLiteral";
5
+ import { IfUndefined } from "./IsUndefined";
6
+
7
+ /**
8
+ * **TypeDefault**
9
+ *
10
+ * A type utility designed to help maintain strong and narrow types where
11
+ * you have a value `T` which _might_ be **undefined** and a type `D` which
12
+ * defines all the _default_ type for `T`.
13
+ *
14
+ * - In all cases we compare first whether `T` is undefined and replace it's
15
+ * type with `D` 1-for-1 if it is
16
+ * - To address a larger set of use cases, when `D` _extends_ an object we will
17
+ * compare each property of `D` against `T`
18
+ * ```ts
19
+ * type I = { foo?: "foo" | undefined; bar?: 42 | 53 | undefined };
20
+ * type D = { foo: "foo"; bar: 53 };
21
+ * type DF = TypeDefault<I,D>; // `D`
22
+ * const i = { foo: undefined, bar: 99 } as const;
23
+ * type DF2 = TypeDefault<typeof i, D>; // `{ foo: "foo"; bar: 99 }`
24
+ * ```
25
+ */
26
+ export type TypeDefault<T, D> = //
27
+ IsObject<D> extends true //
28
+ ? IsObject<T> extends true
29
+ ? // both T and D are objects; start by iterating over D
30
+ SimplifyObject<{
31
+ [K in keyof D]: K extends keyof T
32
+ ? // both D[T] and K[T] are present
33
+ TypeDefault<T[K], D[K]>
34
+ : // only D[K] present
35
+ D[K];
36
+ }>
37
+ : // T is not an object, but D is
38
+ IfUndefined<
39
+ T, // check if T is undefined
40
+ D, // use D as the type
41
+ Exclude<T, undefined> // use T as the type but remove "undefined"
42
+ >
43
+ : // neither D or T is an object
44
+ IfUndefined<
45
+ T, // check whether is T is undefined
46
+ D, // assign to D if it is
47
+ IfOptionalLiteral<
48
+ T, // if T is a literal
49
+ IfExtends<
50
+ D,
51
+ T,
52
+ D, // use D since it extends the value of T
53
+ Exclude<T, undefined> // use T's literal value minus "undefined"
54
+ >,
55
+ // T is a wide type
56
+ Exclude<T, undefined>
57
+ >
58
+ >;
@@ -1,5 +1,9 @@
1
1
  export * from "./Includes";
2
2
  export * from "./IsBooleanLiteral";
3
3
  export * from "./IsNumericLiteral";
4
+ export * from "./IsScalar";
4
5
  export * from "./IsStringLiteral";
5
6
  export * from "./IsLiteral";
7
+ export * from "./Extends";
8
+ export * from "./TypeDefault";
9
+ export * from "./IsObject";
@@ -0,0 +1,80 @@
1
+ import { UnionToTuple } from "../type-conversion";
2
+
3
+ export type OneToOne = `1:1`;
4
+ export type OneToMany = `1:M`;
5
+ export type OneToZero = `1:0`;
6
+ export type ZeroToOne = `0:1`;
7
+ export type ZeroToMany = `0:M`;
8
+ export type ZeroToZero = `0:0`;
9
+ export type ManyToMany = "M:M";
10
+ export type ManyToOne = "M:1";
11
+ export type ManyToZero = "M:0";
12
+
13
+ export type CardinalityNode = "0" | "1" | "M";
14
+
15
+ /**
16
+ * Cardinality which expects a singular input and requires
17
+ * 1 or many outputs.
18
+ *
19
+ * Note: choose `CardinalityFilter1` if you want to allow output
20
+ * to have no outputs.
21
+ */
22
+ export type Cardinality1 = OneToOne | OneToMany;
23
+
24
+ /**
25
+ * Cardinality which expects a singular input and maps to 0,
26
+ * 1, or many outputs.
27
+ */
28
+ export type CardinalityFilter1 = OneToOne | OneToMany | OneToZero;
29
+
30
+ /**
31
+ * Cardinality which expects a singular input which is allowed to be
32
+ * _undefined_ or the expected type.
33
+ */
34
+ export type Cardinality0 = ZeroToOne | ZeroToMany | OneToOne | OneToMany;
35
+
36
+ /**
37
+ * Cardinality which expects a singular input -- which is allowed to be
38
+ * _undefined_ -- and maps to 0,
39
+ * 1, or many outputs.
40
+ */
41
+ export type CardinalityFilter0 =
42
+ | ZeroToOne
43
+ | ZeroToMany
44
+ | OneToOne
45
+ | OneToMany
46
+ | OneToZero
47
+ | ZeroToZero;
48
+
49
+ export type CardinalityExplicit = `${number}:${number}`;
50
+
51
+ /**
52
+ * Cardinality of any sort between two types
53
+ */
54
+ export type Cardinality =
55
+ | CardinalityFilter0
56
+ | CardinalityFilter1
57
+ | ManyToMany
58
+ | ManyToOne
59
+ | ManyToZero
60
+ | CardinalityExplicit;
61
+
62
+ export type CardinalityTuple<T extends Cardinality> = UnionToTuple<T>;
63
+
64
+ /**
65
+ * The first or _input_ part of the Cardinality relationship
66
+ */
67
+ export type CardinalityIn<T extends Cardinality> = T extends `${infer IN}:${string}` ? IN : never;
68
+
69
+ /**
70
+ * The second or _output_ part of the Cardinality relationship
71
+ */
72
+ export type CardinalityOut<T extends Cardinality> = T extends `${string}:${infer OUT}`
73
+ ? OUT
74
+ : never;
75
+
76
+ export type CardinalityInput<T, C extends Cardinality> = CardinalityTuple<C>[0] extends 0
77
+ ? T | undefined
78
+ : CardinalityTuple<C>[0] extends 1
79
+ ? T
80
+ : T[];
@@ -9,6 +9,7 @@ export * from "./CamelCase";
9
9
  export * from "./CapitalizeWords";
10
10
  export * from "./DashToSnake";
11
11
  export * from "./DashUppercase";
12
+ export * from "./Cardinality";
12
13
  export * from "./Dasherize";
13
14
  export * from "./HasUppercase";
14
15
  export * from "./IsCapitalized";