-
Notifications
You must be signed in to change notification settings - Fork 2.3k
/
Copy pathtypes.ts
135 lines (123 loc) · 3.78 KB
/
types.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
export type NullTypeT = {
kind: 'null';
};
export type NumberTypeT = {
kind: 'number';
};
export type StringTypeT = {
kind: 'string';
};
export type BooleanTypeT = {
kind: 'boolean';
};
export type ColorTypeT = {
kind: 'color';
};
export type ObjectTypeT = {
kind: 'object';
};
export type ValueTypeT = {
kind: 'value';
};
export type ErrorTypeT = {
kind: 'error';
};
export type CollatorTypeT = {
kind: 'collator';
};
export type FormattedTypeT = {
kind: 'formatted';
};
export type ResolvedImageTypeT = {
kind: 'resolvedImage';
};
export type EvaluationKind = 'constant' | 'source' | 'camera' | 'composite';
export type Type = NullTypeT | NumberTypeT | StringTypeT | BooleanTypeT | ColorTypeT | ObjectTypeT | ValueTypeT |
ArrayType | ErrorTypeT | CollatorTypeT | FormattedTypeT | ResolvedImageTypeT;
export type ArrayType = {
kind: 'array';
itemType: Type;
N: number | null | undefined;
};
export type NativeType = 'number' | 'string' | 'boolean' | 'null' | 'array' | 'object';
export const NullType = {kind: 'null'} as const;
export const NumberType = {kind: 'number'} as const;
export const StringType = {kind: 'string'} as const;
export const BooleanType = {kind: 'boolean'} as const;
export const ColorType = {kind: 'color'} as const;
export const ObjectType = {kind: 'object'} as const;
export const ValueType = {kind: 'value'} as const;
export const ErrorType = {kind: 'error'} as const;
export const CollatorType = {kind: 'collator'} as const;
export const FormattedType = {kind: 'formatted'} as const;
export const ResolvedImageType = {kind: 'resolvedImage'} as const;
export function array(itemType: Type, N?: number | null): ArrayType {
return {
kind: 'array',
itemType,
N
};
}
export function toString(type: Type): string {
if (type.kind === 'array') {
const itemType = toString(type.itemType);
return typeof type.N === 'number' ?
`array<${itemType}, ${type.N}>` :
type.itemType.kind === 'value' ? 'array' : `array<${itemType}>`;
} else {
return type.kind;
}
}
const valueMemberTypes = [
NullType,
NumberType,
StringType,
BooleanType,
ColorType,
FormattedType,
ObjectType,
array(ValueType),
ResolvedImageType
];
/**
* Returns null if `t` is a subtype of `expected`; otherwise returns an
* error message.
* @private
*/
export function checkSubtype(expected: Type, t: Type): string | null | undefined {
if (t.kind === 'error') {
// Error is a subtype of every type
return null;
} else if (expected.kind === 'array') {
if (t.kind === 'array' &&
((t.N === 0 && t.itemType.kind === 'value') || !checkSubtype(expected.itemType, t.itemType)) &&
(typeof expected.N !== 'number' || expected.N === t.N)) {
return null;
}
} else if (expected.kind === t.kind) {
return null;
} else if (expected.kind === 'value') {
for (const memberType of valueMemberTypes) {
if (!checkSubtype(memberType, t)) {
return null;
}
}
}
return `Expected ${toString(expected)} but found ${toString(t)} instead.`;
}
export function isValidType(provided: Type, allowedTypes: Array<Type>): boolean {
return allowedTypes.some(t => t.kind === provided.kind);
}
export function isValidNativeType(provided: any, allowedTypes: Array<NativeType>): boolean {
return allowedTypes.some(t => {
if (t === 'null') {
return provided === null;
} else if (t === 'array') {
return Array.isArray(provided);
} else if (t === 'object') {
return provided && !Array.isArray(provided) && typeof provided === 'object';
} else {
return t === typeof provided;
}
});
}