• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

pelotom / runtypes / 7191708659

13 Dec 2023 06:46AM UTC coverage: 95.97%. First build
7191708659

Pull #339

github

web-flow
Merge 03ef182ec into f0b4cfd74
Pull Request #339: rafactor!: revise project configurations

311 of 329 branches covered (0.0%)

Branch coverage included in aggregate %.

1213 of 1259 new or added lines in 40 files covered. (96.35%)

1213 of 1259 relevant lines covered (96.35%)

1743.45 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.78
/src/Union.ts
1
import { LiteralBase } from "./Literal.ts"
2
import Runtype, { RuntypeBase, create, innerValidate } from "./Runtype.ts"
10✔
3
import Reflect from "./utils/Reflect.ts"
4
import Static from "./utils/Static.ts"
5
import FAILURE from "./utils-internal/FAILURE.ts"
10✔
6
import SUCCESS from "./utils-internal/SUCCESS.ts"
10✔
7
import hasKey from "./utils-internal/hasKey.ts"
10✔
8

9
interface Union<A extends readonly [RuntypeBase, ...RuntypeBase[]]>
10
        extends Runtype<
11
                {
12
                        [K in keyof A]: A[K] extends RuntypeBase ? Static<A[K]> : unknown
13
                }[number]
14
        > {
15
        tag: "union"
16
        alternatives: A
17
        match: Match<A>
18
}
19

20
/**
1✔
21
 * Construct a union runtype from runtypes for its alternatives.
22
 */
10✔
23
const Union = <T extends readonly [RuntypeBase, ...RuntypeBase[]]>(
10✔
24
        ...alternatives: T
10✔
25
): Union<T> => {
26
        const match =
46✔
27
                (...cases: any[]) =>
46✔
28
                (x: any) => {
46✔
29
                        for (let i = 0; i < alternatives.length; i++) {
49✔
30
                                if (alternatives[i]!.guard(x)) {
52✔
31
                                        return cases[i](x)
54✔
32
                                }
54✔
33
                        }
52!
NEW
34
                }
×
35
        const self = { tag: "union", alternatives, match } as unknown as Reflect
230✔
36
        return create<any>((value, visited) => {
46✔
37
                if (typeof value !== "object" || value === null) {
415✔
38
                        for (const alternative of alternatives)
596✔
39
                                if (innerValidate(alternative, value, visited).success) return SUCCESS(value)
596✔
40
                        return FAILURE.TYPE_INCORRECT(self, value)
755✔
41
                }
755✔
42

43
                const commonLiteralFields: { [K: string]: LiteralBase[] } = {}
603✔
44
                for (const alternative of alternatives) {
415✔
45
                        if (alternative.reflect.tag === "record") {
905✔
46
                                for (const fieldName in alternative.reflect.fields) {
1,032✔
47
                                        const field = alternative.reflect.fields[fieldName]!
1,218✔
48
                                        if (field.tag === "literal") {
1,218✔
49
                                                if (commonLiteralFields[fieldName]) {
1,235✔
50
                                                        if (commonLiteralFields[fieldName]!.every(value => value !== field.value)) {
1,246✔
51
                                                                commonLiteralFields[fieldName]!.push(field.value)
1,256✔
52
                                                        }
1,256✔
53
                                                } else {
1,235✔
54
                                                        commonLiteralFields[fieldName] = [field.value]
3,723✔
55
                                                }
1,241✔
56
                                        }
1,235✔
57
                                }
1,218✔
58
                        }
1,032✔
59
                }
905✔
60

61
                for (const fieldName in commonLiteralFields) {
783✔
62
                        if (commonLiteralFields[fieldName]!.length === alternatives.length) {
789✔
63
                                for (const alternative of alternatives) {
793✔
64
                                        if (alternative.reflect.tag === "record") {
802✔
65
                                                const field = alternative.reflect.fields[fieldName]!
802✔
66
                                                if (
802✔
67
                                                        field.tag === "literal" &&
802✔
68
                                                        hasKey(fieldName, value) &&
802✔
69
                                                        value[fieldName] === field.value
802✔
70
                                                ) {
802✔
71
                                                        return innerValidate(alternative, value, visited)
805✔
72
                                                }
805✔
73
                                        }
802✔
74
                                }
802✔
75
                        }
794✔
76
                }
789✔
77

78
                for (const targetType of alternatives)
415✔
79
                        if (innerValidate(targetType, value, visited).success) return SUCCESS(value)
415✔
80

81
                return FAILURE.TYPE_INCORRECT(self, value)
595✔
82
        }, self)
46✔
83
}
10✔
84

85
type Match<A extends readonly [RuntypeBase, ...RuntypeBase[]]> = {
86
        <Z>(...a: { [K in keyof A]: A[K] extends RuntypeBase ? Case<A[K], Z> : never }): Matcher<A, Z>
87
}
88

89
type Case<T extends RuntypeBase, Result> = (v: Static<T>) => Result
90

91
type Matcher<A extends readonly [RuntypeBase, ...RuntypeBase[]], Z> = (
92
        x: {
93
                [K in keyof A]: A[K] extends RuntypeBase<infer Type> ? Type : unknown
94
        }[number],
95
) => Z
96

97
export default Union
10✔
98
// eslint-disable-next-line import/no-named-export
99
export { type Case, type Match, type Matcher }
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc