/
intersect.ts
166 lines (149 loc) 路 4.28 KB
/
intersect.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
import type {
BaseIssue,
BaseSchema,
Dataset,
ErrorMessage,
InferIssue,
} from '../../types/index.ts';
import { _addIssue } from '../../utils/index.ts';
import type {
InferIntersectInput,
InferIntersectOutput,
IntersectIssue,
IntersectOptions,
} from './types.ts';
import { _merge } from './utils/index.ts';
/**
* Intersect schema type.
*/
export interface IntersectSchema<
TOptions extends IntersectOptions,
TMessage extends ErrorMessage<IntersectIssue> | undefined,
> extends BaseSchema<
InferIntersectInput<TOptions>,
InferIntersectOutput<TOptions>,
IntersectIssue | InferIssue<TOptions[number]>
> {
/**
* The schema type.
*/
readonly type: 'intersect';
/**
* The schema reference.
*/
readonly reference: typeof intersect;
/**
* The intersect options.
*/
readonly options: TOptions;
/**
* The error message.
*/
readonly message: TMessage;
}
/**
* Creates an intersect schema.
*
* @param options The intersect options.
*
* @returns An intersect schema.
*/
export function intersect<const TOptions extends IntersectOptions>(
options: TOptions
): IntersectSchema<TOptions, undefined>;
/**
* Creates an intersect schema.
*
* @param options The intersect options.
* @param message The error message.
*
* @returns An intersect schema.
*/
export function intersect<
const TOptions extends IntersectOptions,
const TMessage extends ErrorMessage<IntersectIssue> | undefined,
>(options: TOptions, message: TMessage): IntersectSchema<TOptions, TMessage>;
export function intersect(
options: IntersectOptions,
message?: ErrorMessage<IntersectIssue>
): IntersectSchema<IntersectOptions, ErrorMessage<IntersectIssue> | undefined> {
return {
kind: 'schema',
type: 'intersect',
reference: intersect,
expects:
[...new Set(options.map((option) => option.expects))].join(' & ') ||
'never',
async: false,
options,
message,
_run(dataset, config) {
// Parse input with schema of options, if not empty
if (this.options.length) {
// Get input value from dataset
const input = dataset.value;
// Create variable to store outputs
let outputs: unknown[] | undefined;
// Set typed initially to `true`
dataset.typed = true;
// Parse schema of each option and collect outputs
for (const schema of this.options) {
const optionDataset = schema._run(
{ typed: false, value: input },
config
);
// If there are issues, capture them
if (optionDataset.issues) {
if (dataset.issues) {
// @ts-expect-error
dataset.issues.push(...optionDataset.issues);
} else {
// @ts-expect-error
dataset.issues = optionDataset.issues;
}
// If necessary, abort early
if (config.abortEarly) {
dataset.typed = false;
break;
}
}
// If not typed, set typed to `false`
if (!optionDataset.typed) {
dataset.typed = false;
}
// Add output of option if necessary
if (dataset.typed) {
if (outputs) {
outputs.push(optionDataset.value);
} else {
outputs = [optionDataset.value];
}
}
}
// If outputs are typed, merge them
if (dataset.typed) {
// Set first output as initial output
dataset.value = outputs![0];
// Merge outputs into one final output
for (let index = 1; index < outputs!.length; index++) {
const mergeDataset = _merge(dataset.value, outputs![index]);
// If outputs can't be merged, add issue and break loop
if (mergeDataset.issue) {
_addIssue(this, 'type', dataset, config, {
received: 'unknown',
});
break;
}
// Otherwise, set merged output
dataset.value = mergeDataset.value;
}
}
// Otherwise, add intersect issue
} else {
_addIssue(this, 'type', dataset, config);
}
// Return output dataset
return dataset as Dataset<unknown, IntersectIssue | BaseIssue<unknown>>;
},
};
}