@bomb.sh/router 0.7.0 → 0.8.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.
- package/README.md +50 -24
- package/esm/lib/checkpoint.js +26 -1
- package/esm/lib/command.d.ts +3 -2
- package/esm/lib/command.js +2 -1
- package/esm/lib/dynamic.d.ts +3 -3
- package/esm/lib/dynamic.js +20 -3
- package/esm/lib/extend.d.ts +3 -2
- package/esm/lib/extend.js +3 -1
- package/esm/lib/parse.js +6 -5
- package/esm/lib/pipeline.d.ts +1 -1
- package/esm/lib/route.d.ts +16 -3
- package/esm/lib/route.js +5 -2
- package/esm/lib/types.d.ts +4 -4
- package/esm/mod.d.ts +2 -1
- package/esm/mod.js +2 -1
- package/package.json +1 -1
- package/src/_dnt.polyfills.ts +0 -27
- package/src/lib/argument.ts +0 -100
- package/src/lib/bind.ts +0 -421
- package/src/lib/checkpoint.ts +0 -10
- package/src/lib/command.ts +0 -36
- package/src/lib/dasherize.ts +0 -7
- package/src/lib/decode.ts +0 -55
- package/src/lib/definition.ts +0 -17
- package/src/lib/dynamic.ts +0 -39
- package/src/lib/env.ts +0 -142
- package/src/lib/extend.ts +0 -12
- package/src/lib/maybe.ts +0 -22
- package/src/lib/multiple.ts +0 -23
- package/src/lib/option.ts +0 -57
- package/src/lib/param.ts +0 -96
- package/src/lib/parse.ts +0 -478
- package/src/lib/pipeline.ts +0 -549
- package/src/lib/print.ts +0 -216
- package/src/lib/read.ts +0 -133
- package/src/lib/rest.ts +0 -10
- package/src/lib/result.ts +0 -10
- package/src/lib/route.ts +0 -77
- package/src/lib/toggle.ts +0 -132
- package/src/lib/tokenize.ts +0 -74
- package/src/lib/tokenizer.ts +0 -191
- package/src/lib/transform.ts +0 -49
- package/src/lib/types.ts +0 -460
- package/src/lib/values.ts +0 -131
- package/src/mod.ts +0 -74
package/src/lib/bind.ts
DELETED
|
@@ -1,421 +0,0 @@
|
|
|
1
|
-
import { Just, type Maybe } from "./maybe.js";
|
|
2
|
-
import type { AnyParam, Param } from "./param.js";
|
|
3
|
-
import type { CLIRead, Symbol } from "./read.js";
|
|
4
|
-
import type { Rest } from "./rest.js";
|
|
5
|
-
import type { Result } from "./result.js";
|
|
6
|
-
import type { Word } from "./tokenize.js";
|
|
7
|
-
import type { TokenInput, Tokenizer, TokenRange } from "./tokenizer.js";
|
|
8
|
-
import type { AnyPhase, Issue, OutputOf, Path } from "./types.js";
|
|
9
|
-
|
|
10
|
-
export interface Binding<T> {
|
|
11
|
-
readonly rest: Rest;
|
|
12
|
-
readonly result: Result<T>;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export interface PhaseBinding {
|
|
16
|
-
readonly rest: Rest;
|
|
17
|
-
readonly model: Record<string, unknown>;
|
|
18
|
-
readonly issues: Issue[];
|
|
19
|
-
readonly valid: boolean;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export interface PhaseSegment {
|
|
23
|
-
readonly range: TokenRange;
|
|
24
|
-
readonly path: Path;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export function fromCLI<P extends Param<string, unknown, "one">>(options: {
|
|
28
|
-
readonly param: P;
|
|
29
|
-
readonly view: TokenInput<Symbol>;
|
|
30
|
-
readonly rest: Rest;
|
|
31
|
-
}): Maybe<Binding<OutputOf<P["schema"]>>> {
|
|
32
|
-
let { param, view, rest } = options;
|
|
33
|
-
return fromRead(param, param.cli.read(view), rest);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export function fromValues<P extends AnyParam>(options: {
|
|
37
|
-
readonly param: P;
|
|
38
|
-
readonly route: Path;
|
|
39
|
-
readonly rest: Rest;
|
|
40
|
-
}): Maybe<Binding<OutputOf<P["schema"]>>> {
|
|
41
|
-
let { param, route, rest } = options;
|
|
42
|
-
let claim = rest.values.claim({
|
|
43
|
-
route,
|
|
44
|
-
address: [param.name],
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
if (!claim.result.exists) {
|
|
48
|
-
return { exists: false };
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
return {
|
|
52
|
-
exists: true,
|
|
53
|
-
value: {
|
|
54
|
-
rest: {
|
|
55
|
-
...rest,
|
|
56
|
-
values: claim.rest,
|
|
57
|
-
},
|
|
58
|
-
result: validate(param, claim.result.value.value, [param.name]),
|
|
59
|
-
},
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
export function fromEnv<P extends AnyParam>(options: {
|
|
64
|
-
readonly param: P;
|
|
65
|
-
readonly route: Path;
|
|
66
|
-
readonly rest: Rest;
|
|
67
|
-
}): Maybe<Binding<OutputOf<P["schema"]>>> {
|
|
68
|
-
let { param, route, rest } = options;
|
|
69
|
-
let claim = rest.envs.claim({
|
|
70
|
-
route,
|
|
71
|
-
address: [param.name],
|
|
72
|
-
key: param.env,
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
if (!claim.result.exists) {
|
|
76
|
-
return { exists: false };
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
let value = claim.result.value.value;
|
|
80
|
-
|
|
81
|
-
let candidates = param.cardinality === "one"
|
|
82
|
-
? param.decode(value)
|
|
83
|
-
: param.decode([value]);
|
|
84
|
-
|
|
85
|
-
return {
|
|
86
|
-
exists: true,
|
|
87
|
-
value: {
|
|
88
|
-
rest: {
|
|
89
|
-
...rest,
|
|
90
|
-
envs: claim.rest,
|
|
91
|
-
},
|
|
92
|
-
result: decode(param, value, candidates, [param.name]),
|
|
93
|
-
},
|
|
94
|
-
};
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
export function bindPhase(options: {
|
|
98
|
-
readonly phase: AnyPhase;
|
|
99
|
-
readonly segment: PhaseSegment;
|
|
100
|
-
readonly rest: Rest;
|
|
101
|
-
}): PhaseBinding {
|
|
102
|
-
let { phase, segment } = options;
|
|
103
|
-
let rest = options.rest;
|
|
104
|
-
let params = Object.values(phase.model.params) as AnyParam[];
|
|
105
|
-
let pending = new Map(params.map((param) => [param.name, param]));
|
|
106
|
-
let results = new Map<string, Result<unknown>>();
|
|
107
|
-
|
|
108
|
-
function settle(
|
|
109
|
-
param: AnyParam,
|
|
110
|
-
binding: Binding<unknown>,
|
|
111
|
-
): void {
|
|
112
|
-
rest = binding.rest;
|
|
113
|
-
results.set(param.name, binding.result);
|
|
114
|
-
pending.delete(param.name);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
function accept(
|
|
118
|
-
param: AnyParam,
|
|
119
|
-
attempt: Maybe<Binding<unknown>>,
|
|
120
|
-
): void {
|
|
121
|
-
if (!attempt.exists) {
|
|
122
|
-
return;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
settle(param, attempt.value);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
let captures = new Map<string, Capture>();
|
|
129
|
-
|
|
130
|
-
// Every pending reader proposes a claim against the same immutable view.
|
|
131
|
-
// Commit the proposal beginning earliest in argv, then recompute the view.
|
|
132
|
-
// This lets `--port 9000` outrank a positional claim on `9000` without
|
|
133
|
-
// attaching binding-policy metadata to either reader.
|
|
134
|
-
while (true) {
|
|
135
|
-
let horizon = first(rest.tokens, segment.range);
|
|
136
|
-
let offer: {
|
|
137
|
-
param: AnyParam;
|
|
138
|
-
read: CLIRead;
|
|
139
|
-
index: number;
|
|
140
|
-
} | undefined;
|
|
141
|
-
|
|
142
|
-
for (let param of pending.values()) {
|
|
143
|
-
let view = rest.tokens.view({
|
|
144
|
-
range: segment.range,
|
|
145
|
-
through: horizon?.index,
|
|
146
|
-
});
|
|
147
|
-
let read = param.cli.read(view);
|
|
148
|
-
|
|
149
|
-
if (read.result.ok && !read.result.value.exists) {
|
|
150
|
-
continue;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
let index = earliest(read.claim.tokens);
|
|
154
|
-
if (!offer || index < offer.index) {
|
|
155
|
-
offer = { param, read, index };
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
if (!offer) {
|
|
160
|
-
break;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
if (offer.param.cardinality === "many") {
|
|
164
|
-
rest = {
|
|
165
|
-
...rest,
|
|
166
|
-
tokens: offer.read.claim.rest,
|
|
167
|
-
};
|
|
168
|
-
|
|
169
|
-
let current = captures.get(offer.param.name) ?? {
|
|
170
|
-
param: offer.param,
|
|
171
|
-
values: [],
|
|
172
|
-
issues: [],
|
|
173
|
-
failed: false,
|
|
174
|
-
};
|
|
175
|
-
|
|
176
|
-
current.issues.push(...offer.read.result.issues ?? []);
|
|
177
|
-
|
|
178
|
-
if (offer.read.result.ok && offer.read.result.value.exists) {
|
|
179
|
-
current.values.push(offer.read.result.value.value);
|
|
180
|
-
} else {
|
|
181
|
-
current.failed = true;
|
|
182
|
-
}
|
|
183
|
-
captures.set(offer.param.name, current);
|
|
184
|
-
|
|
185
|
-
continue;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
accept(offer.param, fromRead(offer.param, offer.read, rest));
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
// deal wil all multiple
|
|
192
|
-
for (let capture of captures.values()) {
|
|
193
|
-
if (capture.failed) {
|
|
194
|
-
settle(capture.param, {
|
|
195
|
-
rest,
|
|
196
|
-
result: { ok: false, issues: capture.issues },
|
|
197
|
-
});
|
|
198
|
-
} else {
|
|
199
|
-
let values = capture.values;
|
|
200
|
-
|
|
201
|
-
let candidates: Maybe<unknown[]>[] = values.every(
|
|
202
|
-
(value): value is string => typeof value === "string",
|
|
203
|
-
)
|
|
204
|
-
? capture.param.decode(values)
|
|
205
|
-
: [Just(values)];
|
|
206
|
-
|
|
207
|
-
let result = merge(
|
|
208
|
-
decode(capture.param, values, candidates, [capture.param.name]),
|
|
209
|
-
capture.issues,
|
|
210
|
-
);
|
|
211
|
-
settle(capture.param, { result, rest });
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
// Address sources have stable visibility once the route is known. They are
|
|
216
|
-
// tried only after CLI has reached its fixed point so a provisional CLI miss
|
|
217
|
-
// cannot let a lower-priority source settle the parameter too early.
|
|
218
|
-
for (let source of [fromEnv, fromValues]) {
|
|
219
|
-
for (let param of pending.values()) {
|
|
220
|
-
accept(
|
|
221
|
-
param,
|
|
222
|
-
source({
|
|
223
|
-
param,
|
|
224
|
-
route: segment.path,
|
|
225
|
-
rest,
|
|
226
|
-
}),
|
|
227
|
-
);
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
// Only total absence reaches the schema as undefined. This is where required,
|
|
232
|
-
// optional, and defaulting parameters diverge.
|
|
233
|
-
for (let param of pending.values()) {
|
|
234
|
-
results.set(param.name, validate(param, undefined, [param.name]));
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
let bindings: Record<string, unknown> = {};
|
|
238
|
-
let issues: Issue[] = [];
|
|
239
|
-
let valid = true;
|
|
240
|
-
|
|
241
|
-
// Collect in declaration order, independent of the source or sweep that
|
|
242
|
-
// settled each parameter.
|
|
243
|
-
for (let param of params) {
|
|
244
|
-
let result = results.get(param.name)!;
|
|
245
|
-
issues.push(...result.issues ?? []);
|
|
246
|
-
if (result.ok) {
|
|
247
|
-
bindings[param.name] = result.value;
|
|
248
|
-
} else {
|
|
249
|
-
valid = false;
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
let model = {};
|
|
254
|
-
for (let step of phase.model.steps) {
|
|
255
|
-
let result = step(model, bindings);
|
|
256
|
-
if (!result.ok) {
|
|
257
|
-
valid = false;
|
|
258
|
-
issues.push(...result.issues);
|
|
259
|
-
break;
|
|
260
|
-
} else {
|
|
261
|
-
model = result.value;
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
return { rest, model, issues, valid };
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
function fromRead<P extends Param<string, unknown, "one">>(
|
|
269
|
-
param: P,
|
|
270
|
-
read: CLIRead,
|
|
271
|
-
rest: Rest,
|
|
272
|
-
): Maybe<Binding<OutputOf<P["schema"]>>> {
|
|
273
|
-
let path = [param.name];
|
|
274
|
-
|
|
275
|
-
if (!read.result.ok) {
|
|
276
|
-
return {
|
|
277
|
-
exists: true,
|
|
278
|
-
value: {
|
|
279
|
-
rest: {
|
|
280
|
-
...rest,
|
|
281
|
-
tokens: read.claim.rest,
|
|
282
|
-
},
|
|
283
|
-
result: read.result,
|
|
284
|
-
},
|
|
285
|
-
};
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
if (!read.result.value.exists) {
|
|
289
|
-
return { exists: false };
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
let value = read.result.value.value;
|
|
293
|
-
|
|
294
|
-
let candidates = typeof value === "string"
|
|
295
|
-
? param.decode(value)
|
|
296
|
-
: [Just(value)];
|
|
297
|
-
let result = merge(
|
|
298
|
-
decode(param, value, candidates, path),
|
|
299
|
-
read.result.issues,
|
|
300
|
-
);
|
|
301
|
-
|
|
302
|
-
return {
|
|
303
|
-
exists: true,
|
|
304
|
-
value: {
|
|
305
|
-
rest: {
|
|
306
|
-
...rest,
|
|
307
|
-
tokens: read.claim.rest,
|
|
308
|
-
},
|
|
309
|
-
result,
|
|
310
|
-
},
|
|
311
|
-
};
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
function decode<P extends AnyParam>(
|
|
315
|
-
param: P,
|
|
316
|
-
value: unknown,
|
|
317
|
-
candidates: Maybe<unknown>[],
|
|
318
|
-
path: string[],
|
|
319
|
-
): Result<OutputOf<P["schema"]>> {
|
|
320
|
-
if (candidates.length === 0) {
|
|
321
|
-
return {
|
|
322
|
-
ok: false,
|
|
323
|
-
issues: [{
|
|
324
|
-
message: `unable to decode ${JSON.stringify(value)}`,
|
|
325
|
-
path,
|
|
326
|
-
}],
|
|
327
|
-
};
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
let issues: readonly Issue[] | undefined;
|
|
331
|
-
|
|
332
|
-
let values = candidates.flatMap((candidate) =>
|
|
333
|
-
candidate.exists ? [candidate.value] : []
|
|
334
|
-
);
|
|
335
|
-
|
|
336
|
-
for (let candidate of values) {
|
|
337
|
-
let result = validate(param, candidate, path);
|
|
338
|
-
if (result.ok) {
|
|
339
|
-
return result;
|
|
340
|
-
}
|
|
341
|
-
issues = issues ?? result.issues;
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
return {
|
|
345
|
-
ok: false,
|
|
346
|
-
issues: issues ?? [],
|
|
347
|
-
};
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
function validate<P extends AnyParam>(
|
|
351
|
-
param: P,
|
|
352
|
-
value: unknown,
|
|
353
|
-
path: string[],
|
|
354
|
-
): Result<OutputOf<P["schema"]>> {
|
|
355
|
-
let validated = param.schema["~standard"].validate(value);
|
|
356
|
-
if (validated instanceof Promise) {
|
|
357
|
-
return {
|
|
358
|
-
ok: false,
|
|
359
|
-
issues: [{
|
|
360
|
-
message: `async schemas are not allowed`,
|
|
361
|
-
path,
|
|
362
|
-
}],
|
|
363
|
-
};
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
if (validated.issues) {
|
|
367
|
-
return {
|
|
368
|
-
ok: false,
|
|
369
|
-
issues: validated.issues.map((issue) => ({
|
|
370
|
-
...issue,
|
|
371
|
-
message: issue.message,
|
|
372
|
-
path,
|
|
373
|
-
})),
|
|
374
|
-
};
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
return {
|
|
378
|
-
ok: true,
|
|
379
|
-
issues: [],
|
|
380
|
-
value: validated.value,
|
|
381
|
-
};
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
function merge<T>(
|
|
385
|
-
result: Result<T>,
|
|
386
|
-
issues: readonly Issue[] | undefined,
|
|
387
|
-
): Result<T> {
|
|
388
|
-
if (!issues || issues.length === 0) {
|
|
389
|
-
return result;
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
return {
|
|
393
|
-
...result,
|
|
394
|
-
issues: [...issues, ...(result.issues ?? [])],
|
|
395
|
-
};
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
function first(tokens: Tokenizer<Symbol>, range: TokenRange): Word | undefined {
|
|
399
|
-
for (let token of tokens.view({ range })) {
|
|
400
|
-
if (token.type === "word") {
|
|
401
|
-
return token;
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
function earliest(tokens: readonly Symbol[]): number {
|
|
407
|
-
let first = Infinity;
|
|
408
|
-
|
|
409
|
-
for (let token of tokens) {
|
|
410
|
-
first = Math.min(first, token.index);
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
return first;
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
interface Capture {
|
|
417
|
-
param: Param<string, unknown, "many">;
|
|
418
|
-
values: (string | boolean)[];
|
|
419
|
-
issues: Issue[];
|
|
420
|
-
failed: boolean;
|
|
421
|
-
}
|
package/src/lib/checkpoint.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { dynamic } from "./dynamic.js";
|
|
2
|
-
import type { DynamicElement } from "./pipeline.js";
|
|
3
|
-
import { type ValueSource, withValues } from "./values.js";
|
|
4
|
-
|
|
5
|
-
export function checkpoint(): DynamicElement<
|
|
6
|
-
ValueSource[],
|
|
7
|
-
ReturnType<typeof withValues>
|
|
8
|
-
> {
|
|
9
|
-
return dynamic((values: ValueSource[]) => withValues(values));
|
|
10
|
-
}
|
package/src/lib/command.ts
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
// deno-lint-ignore-file ban-types
|
|
2
|
-
import type { Check, Fold, Materialize, Unary } from "./pipeline.js";
|
|
3
|
-
import type { Definition, Done, Route } from "./types.js";
|
|
4
|
-
|
|
5
|
-
export type CommandZero<N extends string = string> = Route<
|
|
6
|
-
N,
|
|
7
|
-
"help" | "execute",
|
|
8
|
-
[Done<{}, []>]
|
|
9
|
-
>;
|
|
10
|
-
|
|
11
|
-
export function command<
|
|
12
|
-
const N extends string,
|
|
13
|
-
const E extends readonly Unary[],
|
|
14
|
-
>(
|
|
15
|
-
start: Definition<N>,
|
|
16
|
-
...elements: E & Check<CommandZero<N>, E>
|
|
17
|
-
): Materialize<Fold<CommandZero<N>, E>> {
|
|
18
|
-
let zero: CommandZero<N> = {
|
|
19
|
-
...start,
|
|
20
|
-
methods: ["help", "execute"],
|
|
21
|
-
phases: [{
|
|
22
|
-
model: {
|
|
23
|
-
params: {},
|
|
24
|
-
steps: [],
|
|
25
|
-
},
|
|
26
|
-
routes: [],
|
|
27
|
-
values: [],
|
|
28
|
-
envs: [],
|
|
29
|
-
}],
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
return elements.reduce<unknown>(
|
|
33
|
-
(value, element) => element(value as never),
|
|
34
|
-
zero,
|
|
35
|
-
) as Materialize<Fold<CommandZero<N>, E>>;
|
|
36
|
-
}
|
package/src/lib/dasherize.ts
DELETED
package/src/lib/decode.ts
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import { Just, type Maybe, Nothing } from "./maybe.js";
|
|
2
|
-
|
|
3
|
-
export type Decoder<A, B> = (value: A) => Maybe<B>[];
|
|
4
|
-
|
|
5
|
-
export const number: Decoder<string, number> = (value) => {
|
|
6
|
-
if (!numeric.test(value)) {
|
|
7
|
-
return [Nothing()];
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
let decoded = Number(value);
|
|
11
|
-
return Number.isFinite(decoded) ? [Just(decoded)] : [Nothing()];
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
export const scalar: Decoder<string, string | number> = (value) => {
|
|
15
|
-
return [...number(value), Just(value)];
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
export const boolean: Decoder<string, boolean> = (value) => {
|
|
19
|
-
if (value === "true") {
|
|
20
|
-
return [Just(true)];
|
|
21
|
-
}
|
|
22
|
-
if (value === "false") {
|
|
23
|
-
return [Just(false)];
|
|
24
|
-
}
|
|
25
|
-
return [Nothing()];
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
export function multiple<A, B>(decoder: Decoder<A, B>): Decoder<A[], B[]> {
|
|
29
|
-
return (input: A[]): Maybe<B[]>[] => {
|
|
30
|
-
let decodings = input.map(decoder);
|
|
31
|
-
|
|
32
|
-
let result: Maybe<B[]>[] = [];
|
|
33
|
-
|
|
34
|
-
for (let i = 0; i < decodings.length; i++) {
|
|
35
|
-
let decoding = decodings[i];
|
|
36
|
-
for (let j = 0; j < decoding.length; j++) {
|
|
37
|
-
let row: Maybe<B[]> | undefined = result[j];
|
|
38
|
-
if (!row) {
|
|
39
|
-
row = result[j] = Just([]);
|
|
40
|
-
}
|
|
41
|
-
if (row.exists) {
|
|
42
|
-
let candidate = decoding[j];
|
|
43
|
-
if (candidate.exists) {
|
|
44
|
-
row.value[i] = candidate.value;
|
|
45
|
-
} else {
|
|
46
|
-
result[j] = Nothing();
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
return result;
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
const numeric = /^-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?$/;
|
package/src/lib/definition.ts
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { brand, type IdentityElement } from "./pipeline.js";
|
|
2
|
-
import type { Definition } from "./types.js";
|
|
3
|
-
|
|
4
|
-
export function name<N extends string>(name: N): Definition<N> {
|
|
5
|
-
return { name };
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export function description(
|
|
9
|
-
description: string,
|
|
10
|
-
): IdentityElement<Definition<string>> {
|
|
11
|
-
return brand<IdentityElement<Definition<string>>>((
|
|
12
|
-
definition: Definition<string>,
|
|
13
|
-
) => ({
|
|
14
|
-
...definition,
|
|
15
|
-
description,
|
|
16
|
-
}));
|
|
17
|
-
}
|
package/src/lib/dynamic.ts
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import type { AnyRoute } from "./types.js";
|
|
2
|
-
import { type AnyElement, brand, type DynamicElement } from "./pipeline.js";
|
|
3
|
-
|
|
4
|
-
export type { ConjoinPhases, Seed } from "./pipeline.js";
|
|
5
|
-
export type PhaseOf<R extends AnyRoute> = R["phases"][0];
|
|
6
|
-
export type PhasesOf<R extends AnyRoute> = R["phases"];
|
|
7
|
-
|
|
8
|
-
export function dynamic<
|
|
9
|
-
Requirement,
|
|
10
|
-
E,
|
|
11
|
-
>(
|
|
12
|
-
extension: (requires: Requirement) => E,
|
|
13
|
-
..._valid: E extends AnyElement ? [] : [never]
|
|
14
|
-
): DynamicElement<Requirement, Extract<E, AnyElement>> {
|
|
15
|
-
return brand<DynamicElement<Requirement, Extract<E, AnyElement>>>(
|
|
16
|
-
(route: AnyRoute) => {
|
|
17
|
-
let phases = [...route.phases];
|
|
18
|
-
let phase = phases.pop()!;
|
|
19
|
-
|
|
20
|
-
phases.push({
|
|
21
|
-
...phase,
|
|
22
|
-
resolver: extension as unknown as (
|
|
23
|
-
requirement: never,
|
|
24
|
-
) => (input: never) => AnyRoute,
|
|
25
|
-
});
|
|
26
|
-
phases.push({
|
|
27
|
-
model: {
|
|
28
|
-
params: {},
|
|
29
|
-
steps: [],
|
|
30
|
-
},
|
|
31
|
-
routes: [],
|
|
32
|
-
values: [],
|
|
33
|
-
envs: [],
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
return { ...route, phases };
|
|
37
|
-
},
|
|
38
|
-
);
|
|
39
|
-
}
|