@nerd-bible/valio 0.1.13 → 0.1.15
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/dist/codecs.d.ts +1 -1
- package/dist/codecs.d.ts.map +1 -1
- package/dist/codecs.js +21 -4
- package/dist/codecs.js.map +1 -1
- package/dist/containers.d.ts +22 -5
- package/dist/containers.d.ts.map +1 -1
- package/dist/containers.js +129 -93
- package/dist/containers.js.map +1 -1
- package/dist/pipe.d.ts +15 -18
- package/dist/pipe.d.ts.map +1 -1
- package/dist/pipe.js +34 -45
- package/dist/pipe.js.map +1 -1
- package/dist/primitives.d.ts +111 -13
- package/dist/primitives.d.ts.map +1 -1
- package/dist/primitives.js +99 -29
- package/dist/primitives.js.map +1 -1
- package/package.json +1 -1
- package/src/codecs.test.ts +2 -4
- package/src/codecs.ts +23 -6
- package/src/containers.test.ts +9 -1
- package/src/containers.ts +143 -124
- package/src/pipe.ts +68 -68
- package/src/primitives.ts +124 -44
package/src/containers.ts
CHANGED
|
@@ -1,44 +1,52 @@
|
|
|
1
1
|
import type { Input, Output, Result } from "./pipe.ts";
|
|
2
|
-
import { Context,
|
|
2
|
+
import { Context, Pipe } from "./pipe.ts";
|
|
3
3
|
import * as p from "./primitives.ts";
|
|
4
4
|
|
|
5
5
|
export class ValioArray<T> extends p.Arrayish<any[], T[]> {
|
|
6
6
|
element: Pipe<any, T>;
|
|
7
7
|
|
|
8
|
+
constructor(element: Pipe<any, T>) {
|
|
9
|
+
super();
|
|
10
|
+
this.element = element;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
get inputName() {
|
|
14
|
+
return "array";
|
|
15
|
+
}
|
|
16
|
+
|
|
8
17
|
static typeCheck(v: any): v is any[] {
|
|
9
18
|
return Array.isArray(v);
|
|
10
19
|
}
|
|
11
20
|
|
|
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
|
-
this.element = element;
|
|
21
|
+
inputTypeCheck(v: any): v is any[] {
|
|
22
|
+
return ValioArray.typeCheck(v);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
inputTransform(input: any[], ctx: Context): Result<T[]> {
|
|
26
|
+
const output = new Array<T>(input.length);
|
|
27
|
+
let success = true;
|
|
28
|
+
|
|
29
|
+
const length = ctx.jsonPath.length;
|
|
30
|
+
for (let i = 0; i < input.length; i++) {
|
|
31
|
+
ctx.jsonPath[length] = i.toString();
|
|
32
|
+
const decoded = this.element.decode(input[i], ctx);
|
|
33
|
+
if (decoded.success) output[i] = decoded.output;
|
|
34
|
+
else success = false;
|
|
35
|
+
}
|
|
36
|
+
ctx.jsonPath.length = length;
|
|
37
|
+
|
|
38
|
+
if (!success) return { success, errors: ctx.errors };
|
|
39
|
+
return { success, output };
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
get outputName() {
|
|
43
|
+
return `array<${this.element.outputName}>`;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
outputTypeCheck(v: any): v is T[] {
|
|
47
|
+
if (!ValioArray.typeCheck(v)) return false;
|
|
48
|
+
for (const e of v) if (!this.element.outputTypeCheck(e)) return false;
|
|
49
|
+
return true;
|
|
42
50
|
}
|
|
43
51
|
}
|
|
44
52
|
export function array<T>(element: Pipe<any, T>): ValioArray<T> {
|
|
@@ -52,54 +60,61 @@ export class ValioRecord<K extends PropertyKey, V> extends Pipe<
|
|
|
52
60
|
keyPipe: Pipe<any, K>;
|
|
53
61
|
valPipe: Pipe<any, V>;
|
|
54
62
|
|
|
63
|
+
constructor(keyPipe: Pipe<any, K>, valPipe: Pipe<any, V>) {
|
|
64
|
+
super();
|
|
65
|
+
this.keyPipe = keyPipe;
|
|
66
|
+
this.valPipe = valPipe;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
get inputName() {
|
|
70
|
+
return "object";
|
|
71
|
+
}
|
|
72
|
+
|
|
55
73
|
static typeCheck(v: any): v is Record<any, any> {
|
|
56
|
-
return
|
|
74
|
+
return v && typeof v === "object";
|
|
57
75
|
}
|
|
58
76
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
success = false;
|
|
78
|
-
}
|
|
79
|
-
} else {
|
|
80
|
-
success = false;
|
|
81
|
-
}
|
|
77
|
+
inputTypeCheck(v: any): v is Record<any, any> {
|
|
78
|
+
return ValioRecord.typeCheck(v);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
inputTransform(input: Record<any, any>, ctx: Context): Result<Record<K, V>> {
|
|
82
|
+
const output = {} as Record<K, V>;
|
|
83
|
+
|
|
84
|
+
let success = true;
|
|
85
|
+
const length = ctx.jsonPath.length;
|
|
86
|
+
for (const key in input) {
|
|
87
|
+
ctx.jsonPath[length] = key;
|
|
88
|
+
const decodedKey = this.keyPipe.decode(key, ctx);
|
|
89
|
+
if (decodedKey.success) {
|
|
90
|
+
const decodedVal = this.valPipe.decode((input as any)[key], ctx);
|
|
91
|
+
if (decodedVal.success) {
|
|
92
|
+
output[decodedKey.output] = decodedVal.output;
|
|
93
|
+
} else {
|
|
94
|
+
success = false;
|
|
82
95
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
96
|
+
} else {
|
|
97
|
+
success = false;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
ctx.jsonPath.length = length;
|
|
101
|
+
|
|
102
|
+
if (!success) return { success, errors: ctx.errors };
|
|
103
|
+
return { success, output };
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
get outputName() {
|
|
107
|
+
return `record<${this.keyPipe.inputName},${this.valPipe.outputName}>`;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
outputTypeCheck(v: any): v is Record<K, V> {
|
|
111
|
+
if (!ValioRecord.typeCheck(v)) return false;
|
|
112
|
+
for (const k in v) {
|
|
113
|
+
// Keys will always be strings.
|
|
114
|
+
// if (!keyPipe.o.typeCheck(k)) return false;
|
|
115
|
+
if (!this.valPipe.outputTypeCheck(v[k])) return false;
|
|
116
|
+
}
|
|
117
|
+
return true;
|
|
103
118
|
}
|
|
104
119
|
}
|
|
105
120
|
export function record<K extends PropertyKey, V>(
|
|
@@ -116,37 +131,45 @@ export class Union<T extends Readonly<Pipe[]>> extends Pipe<
|
|
|
116
131
|
options: T;
|
|
117
132
|
|
|
118
133
|
constructor(options: T) {
|
|
119
|
-
|
|
120
|
-
type O = Output<T[number]>;
|
|
121
|
-
super(
|
|
122
|
-
new HalfPipe(
|
|
123
|
-
name,
|
|
124
|
-
function isUnionType(v: any): v is O {
|
|
125
|
-
for (const f of options) if (f.i.typeCheck(v)) return true;
|
|
126
|
-
return false;
|
|
127
|
-
},
|
|
128
|
-
(data: O, ctx: Context): Result<O> => {
|
|
129
|
-
// Throw away errors since we expect them.
|
|
130
|
-
const newCtx = new Context();
|
|
131
|
-
newCtx.pushErrorFmt = () => {};
|
|
132
|
-
newCtx.pushError = () => {};
|
|
133
|
-
for (const f of options) {
|
|
134
|
-
const decoded = f.decode(data, newCtx);
|
|
135
|
-
if (decoded.success) return decoded;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
// Sad path -- do again with real ctx to gather errors.
|
|
139
|
-
for (const f of options) f.decode(data, ctx);
|
|
140
|
-
return { success: false, errors: ctx.errors };
|
|
141
|
-
},
|
|
142
|
-
),
|
|
143
|
-
new HalfPipe(name, function isUnionType2(v: any): v is O {
|
|
144
|
-
for (const f of options) if (f.o.typeCheck(v)) return true;
|
|
145
|
-
return false;
|
|
146
|
-
}),
|
|
147
|
-
);
|
|
134
|
+
super();
|
|
148
135
|
this.options = options;
|
|
149
136
|
}
|
|
137
|
+
|
|
138
|
+
get inputName() {
|
|
139
|
+
return this.options.map((o) => o.outputName).join("|");
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
inputTypeCheck(v: any): v is Output<T[number]> {
|
|
143
|
+
for (const f of this.options) if (f.inputTypeCheck(v)) return true;
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
inputTransform(
|
|
148
|
+
data: Output<T[number]>,
|
|
149
|
+
ctx: Context,
|
|
150
|
+
): Result<Output<T[number]>> {
|
|
151
|
+
// Throw away errors since we expect them.
|
|
152
|
+
const newCtx = new Context();
|
|
153
|
+
newCtx.pushErrorFmt = () => {};
|
|
154
|
+
newCtx.pushError = () => {};
|
|
155
|
+
for (const f of this.options) {
|
|
156
|
+
const decoded = f.decode(data, newCtx);
|
|
157
|
+
if (decoded.success) return decoded;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Sad path -- do again with real ctx to gather errors.
|
|
161
|
+
for (const f of this.options) f.decode(data, ctx);
|
|
162
|
+
return { success: false, errors: ctx.errors };
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
get outputName() {
|
|
166
|
+
return this.inputName;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
outputTypeCheck(v: any): v is Output<T[number]> {
|
|
170
|
+
for (const f of this.options) if (f.outputTypeCheck(v)) return true;
|
|
171
|
+
return false;
|
|
172
|
+
}
|
|
150
173
|
}
|
|
151
174
|
export function union<T extends Readonly<Pipe[]>>(options: T): Union<T> {
|
|
152
175
|
return new Union(options);
|
|
@@ -188,30 +211,26 @@ export class ValioObject<
|
|
|
188
211
|
}
|
|
189
212
|
|
|
190
213
|
constructor(shape: Shape, isLoose: boolean) {
|
|
191
|
-
super(
|
|
192
|
-
new HalfPipe("object", ValioObject.typeCheck, (data, ctx) =>
|
|
193
|
-
this.transformInput(data, ctx),
|
|
194
|
-
),
|
|
195
|
-
new HalfPipe(
|
|
196
|
-
`{${Object.entries(shape)
|
|
197
|
-
.map(([k, v]) => `${k}: ${v.o.name}`)
|
|
198
|
-
.join(",")}}`,
|
|
199
|
-
(v) => this.typeCheckOutput(v),
|
|
200
|
-
),
|
|
201
|
-
);
|
|
202
|
-
|
|
214
|
+
super();
|
|
203
215
|
this.shape = shape;
|
|
204
216
|
this.isLoose = isLoose;
|
|
205
217
|
}
|
|
206
218
|
|
|
207
|
-
|
|
208
|
-
return
|
|
219
|
+
get inputName() {
|
|
220
|
+
return "object";
|
|
209
221
|
}
|
|
210
222
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
223
|
+
get outputName() {
|
|
224
|
+
return `{${Object.entries(this.shape)
|
|
225
|
+
.map(([k, v]) => `${k}: ${v.outputName}`)
|
|
226
|
+
.join(",")}}`;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
inputTypeCheck(v: any): v is Record<any, any> {
|
|
230
|
+
return ValioObject.typeCheck(v);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
inputTransform(data: object, ctx: Context): Result<ObjectOutput<Shape>> {
|
|
215
234
|
const output: Record<PropertyKey, any> = this.isLoose ? data : {};
|
|
216
235
|
let success = true;
|
|
217
236
|
|
|
@@ -232,10 +251,10 @@ export class ValioObject<
|
|
|
232
251
|
return { success, output: output as ObjectOutput<Shape> };
|
|
233
252
|
}
|
|
234
253
|
|
|
235
|
-
|
|
254
|
+
outputTypeCheck(v: any): v is ObjectOutput<Shape> {
|
|
236
255
|
if (!ValioObject.typeCheck(v)) return false;
|
|
237
256
|
for (const s in this.shape)
|
|
238
|
-
if (!this.shape[s]!.
|
|
257
|
+
if (!this.shape[s]!.outputTypeCheck(v[s])) return false;
|
|
239
258
|
return true;
|
|
240
259
|
}
|
|
241
260
|
|
package/src/pipe.ts
CHANGED
|
@@ -5,49 +5,12 @@ export type Errors = { [inputPath: string]: Error[] };
|
|
|
5
5
|
export type Result<T> =
|
|
6
6
|
| { success: true; output: T }
|
|
7
7
|
| { success: false; errors: any };
|
|
8
|
-
|
|
9
|
-
function clone<T>(obj: T): T {
|
|
10
|
-
return Object.create(
|
|
11
|
-
Object.getPrototypeOf(obj),
|
|
12
|
-
Object.getOwnPropertyDescriptors(obj),
|
|
13
|
-
);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
interface Check<T> {
|
|
8
|
+
export interface Check<T> {
|
|
17
9
|
valid(data: T, ctx: Context): boolean;
|
|
18
10
|
name: string;
|
|
19
11
|
props: Record<any, any>;
|
|
20
12
|
}
|
|
21
13
|
|
|
22
|
-
export class HalfPipe<I, O = never> {
|
|
23
|
-
name: string;
|
|
24
|
-
typeCheck: (v: any) => v is I;
|
|
25
|
-
transform?: (v: I, ctx: Context) => Result<O>;
|
|
26
|
-
/** Checks to run after type check */
|
|
27
|
-
checks: Check<I>[] = [];
|
|
28
|
-
|
|
29
|
-
constructor(
|
|
30
|
-
name: string,
|
|
31
|
-
typeCheck: (v: any) => v is I,
|
|
32
|
-
transform?: (v: I, ctx: Context) => Result<O>,
|
|
33
|
-
checks: Check<I>[] = [],
|
|
34
|
-
) {
|
|
35
|
-
this.name = name;
|
|
36
|
-
this.typeCheck = typeCheck;
|
|
37
|
-
this.transform = transform;
|
|
38
|
-
this.checks = checks;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
clone(): HalfPipe<I, O> {
|
|
42
|
-
return new HalfPipe(
|
|
43
|
-
this.name,
|
|
44
|
-
this.typeCheck,
|
|
45
|
-
this.transform,
|
|
46
|
-
this.checks.slice(),
|
|
47
|
-
);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
14
|
/** During encoding, decoding, or validation. */
|
|
52
15
|
export class Context {
|
|
53
16
|
jsonPath: (string | number)[] = [];
|
|
@@ -75,13 +38,18 @@ export class Context {
|
|
|
75
38
|
this.pushError({ input, message });
|
|
76
39
|
}
|
|
77
40
|
|
|
78
|
-
run<I
|
|
79
|
-
|
|
80
|
-
|
|
41
|
+
run<I>(
|
|
42
|
+
input: any,
|
|
43
|
+
name: () => string,
|
|
44
|
+
typeCheck: (v: any) => v is I,
|
|
45
|
+
checks?: Check<I>[],
|
|
46
|
+
): Result<I> {
|
|
47
|
+
if (!typeCheck(input)) {
|
|
48
|
+
this.pushErrorFmt("type", input, { expected: name() });
|
|
81
49
|
return { success: false, errors: this.errors };
|
|
82
50
|
}
|
|
83
51
|
let success = true;
|
|
84
|
-
for (const c of
|
|
52
|
+
for (const c of checks ?? []) {
|
|
85
53
|
if (!c.valid(input, this)) {
|
|
86
54
|
this.pushErrorFmt(c.name, input, c.props);
|
|
87
55
|
success = false;
|
|
@@ -92,35 +60,47 @@ export class Context {
|
|
|
92
60
|
}
|
|
93
61
|
}
|
|
94
62
|
|
|
95
|
-
export
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
63
|
+
export function cloneObject(obj: any) {
|
|
64
|
+
const res =
|
|
65
|
+
Object.getPrototypeOf(obj) == Object.prototype ? {} : Object.create(obj);
|
|
66
|
+
for (const p in obj) {
|
|
67
|
+
const v = obj[p];
|
|
68
|
+
if (Array.isArray(v)) res[p] = v.slice();
|
|
69
|
+
else if (v && v.clone) res[p] = v.clone();
|
|
70
|
+
else if (v && typeof v === "object") res[p] = cloneObject(v);
|
|
71
|
+
else res[p] = v;
|
|
72
|
+
}
|
|
73
|
+
return res;
|
|
74
|
+
}
|
|
103
75
|
|
|
76
|
+
export abstract class Pipe<I = any, O = any> {
|
|
104
77
|
pipes: Pipe<any, any>[] = [];
|
|
105
78
|
registry: Record<PropertyKey, any> = {};
|
|
106
|
-
|
|
79
|
+
|
|
80
|
+
abstract inputName: string;
|
|
81
|
+
abstract inputTypeCheck(v: any): v is I;
|
|
82
|
+
/** Checks to run after type check */
|
|
83
|
+
inputChecks?: Check<I>[];
|
|
84
|
+
inputTransform?(v: I, ctx: Context): Result<O>;
|
|
85
|
+
|
|
86
|
+
abstract outputName: string;
|
|
87
|
+
abstract outputTypeCheck(v: any): v is O;
|
|
88
|
+
/** Checks to run after type check */
|
|
89
|
+
outputChecks?: Check<O>[];
|
|
90
|
+
outputTransform?(v: O, ctx: Context): Result<I>;
|
|
107
91
|
|
|
108
92
|
clone(): this {
|
|
109
|
-
|
|
110
|
-
res.i = res.i.clone();
|
|
111
|
-
res.o = res.o.clone();
|
|
112
|
-
res.pipes = res.pipes.slice();
|
|
113
|
-
res.registry = { ...res.registry };
|
|
114
|
-
return res;
|
|
93
|
+
return cloneObject(this);
|
|
115
94
|
}
|
|
116
95
|
|
|
117
96
|
refine(
|
|
118
97
|
valid: (data: O, ctx: Context) => boolean,
|
|
119
98
|
name: string,
|
|
120
99
|
props: Record<any, any> = {},
|
|
121
|
-
)
|
|
100
|
+
) {
|
|
122
101
|
const res = this.clone();
|
|
123
|
-
res.
|
|
102
|
+
res.outputChecks ??= [];
|
|
103
|
+
res.outputChecks.push({ valid, name, props });
|
|
124
104
|
return res;
|
|
125
105
|
}
|
|
126
106
|
|
|
@@ -132,15 +112,25 @@ export class Pipe<I = any, O = any> {
|
|
|
132
112
|
|
|
133
113
|
decodeAny(input: any, ctx = new Context()): Result<O> {
|
|
134
114
|
// 1. Verify input
|
|
135
|
-
let res: Result<any> = ctx.run(
|
|
115
|
+
let res: Result<any> = ctx.run(
|
|
116
|
+
input,
|
|
117
|
+
() => this.inputName,
|
|
118
|
+
this.inputTypeCheck.bind(this),
|
|
119
|
+
this.inputChecks,
|
|
120
|
+
);
|
|
136
121
|
if (!res.success) return res;
|
|
137
122
|
// 2. Transform input to output
|
|
138
|
-
if (this.
|
|
139
|
-
res = this.
|
|
123
|
+
if (this.inputTransform) {
|
|
124
|
+
res = this.inputTransform(res.output, ctx);
|
|
140
125
|
if (!res.success) return res;
|
|
141
126
|
}
|
|
142
127
|
// 3. Verify output
|
|
143
|
-
res = ctx.run(
|
|
128
|
+
res = ctx.run(
|
|
129
|
+
res.output,
|
|
130
|
+
() => this.outputName,
|
|
131
|
+
this.outputTypeCheck.bind(this),
|
|
132
|
+
this.outputChecks,
|
|
133
|
+
);
|
|
144
134
|
if (!res.success) return res;
|
|
145
135
|
// 4. Next
|
|
146
136
|
for (const p of this.pipes) {
|
|
@@ -161,21 +151,31 @@ export class Pipe<I = any, O = any> {
|
|
|
161
151
|
if (!res.success) return res;
|
|
162
152
|
}
|
|
163
153
|
// 2. Verify output
|
|
164
|
-
res = ctx.run(
|
|
154
|
+
res = ctx.run(
|
|
155
|
+
res.output,
|
|
156
|
+
() => this.outputName,
|
|
157
|
+
this.outputTypeCheck.bind(this),
|
|
158
|
+
this.outputChecks,
|
|
159
|
+
);
|
|
165
160
|
if (!res.success) return res;
|
|
166
161
|
// 3. Transform output to input
|
|
167
|
-
if (this.
|
|
168
|
-
res = this.
|
|
162
|
+
if (this.outputTransform) {
|
|
163
|
+
res = this.outputTransform(res.output, ctx);
|
|
169
164
|
if (!res.success) return res;
|
|
170
165
|
}
|
|
171
166
|
// 4. Verify input
|
|
172
|
-
return ctx.run(
|
|
167
|
+
return ctx.run(
|
|
168
|
+
res.output,
|
|
169
|
+
() => this.inputName,
|
|
170
|
+
this.inputTypeCheck.bind(this),
|
|
171
|
+
this.inputChecks,
|
|
172
|
+
);
|
|
173
173
|
}
|
|
174
174
|
encode(output: O, ctx = new Context()): Result<I> {
|
|
175
175
|
return this.encodeAny(output, ctx);
|
|
176
176
|
}
|
|
177
177
|
|
|
178
|
-
register(key: PropertyKey, value: any):
|
|
178
|
+
register(key: PropertyKey, value: any): Pipe<I, O> {
|
|
179
179
|
const res = this.clone();
|
|
180
180
|
res.registry[key] = value;
|
|
181
181
|
return res;
|