@bomb.sh/router 0.7.0 → 0.7.1

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.
@@ -1,191 +0,0 @@
1
- import type { AnyToken } from "./tokenize.js";
2
-
3
- export interface TokenInput<T extends AnyToken> extends Iterable<T> {
4
- claimNext(): Claim<T>;
5
-
6
- claimOne<S extends T>(match: (token: T) => token is S): Claim<S, T>;
7
- claimOne(match: (token: T) => boolean): Claim<T, T>;
8
-
9
- claimPair(match: (a: T, b: T) => boolean): Claim<T, T>;
10
-
11
- claimAll<S extends T>(match: (token: T) => token is S): Claim<S, T>;
12
- claimAll(match: (token: T) => boolean): Claim<T, T>;
13
- }
14
-
15
- export interface TokenRange {
16
- readonly start: number;
17
- readonly end?: number;
18
- }
19
-
20
- export interface ViewOptions {
21
- readonly range: TokenRange;
22
- readonly through?: number;
23
- }
24
-
25
- export class Tokenizer<T extends AnyToken> implements TokenInput<T> {
26
- readonly tokens: readonly T[];
27
- readonly claimed: ReadonlySet<number>;
28
-
29
- constructor(
30
- tokens: readonly T[],
31
- claimed: ReadonlySet<number> = new Set(),
32
- ) {
33
- this.tokens = tokens;
34
- this.claimed = new Set(claimed);
35
- }
36
-
37
- claimNext(): Claim<T> {
38
- return this.claimOne(() => true);
39
- }
40
-
41
- claimOne<S extends T>(match: (token: T) => token is S): Claim<S, T>;
42
- claimOne(match: (token: T) => boolean): Claim<T, T>;
43
- claimOne(match: (token: T) => boolean): Claim<T> {
44
- for (let token of this) {
45
- if (match(token)) {
46
- return {
47
- tokens: [token],
48
- rest: remainder(this, [token.index]),
49
- };
50
- }
51
- }
52
- return { tokens: [], rest: this };
53
- }
54
-
55
- claimPair(match: (a: T, b: T) => boolean): Claim<T, T> {
56
- let previous: T | undefined;
57
- for (let token of this) {
58
- if (!previous) {
59
- previous = token;
60
- continue;
61
- }
62
- if (token.index === previous.index + 1 && match(previous, token)) {
63
- return {
64
- tokens: [previous, token],
65
- rest: remainder(this, [previous.index, token.index]),
66
- };
67
- }
68
- previous = token;
69
- }
70
- return { tokens: [], rest: this };
71
- }
72
-
73
- claimAll<S extends T>(match: (token: T) => token is S): Claim<S, T>;
74
- claimAll(match: (token: T) => boolean): Claim<T, T>;
75
- claimAll(match: (token: T) => boolean): Claim<T> {
76
- let tokens: T[] = [];
77
- let claimed = new Set<number>();
78
- for (let token of this) {
79
- if (match(token)) {
80
- claimed.add(token.index);
81
- tokens.push(token);
82
- }
83
- }
84
- return {
85
- tokens,
86
- rest: tokens.length > 0 ? remainder(this, claimed) : this,
87
- };
88
- }
89
-
90
- view(options: ViewOptions): TokenInput<T> {
91
- return new View(this, options);
92
- }
93
-
94
- *[Symbol.iterator](): Generator<T, void, unknown> {
95
- for (let token of this.tokens) {
96
- if (!this.claimed.has(token.index)) {
97
- yield token;
98
- }
99
- }
100
- }
101
- }
102
-
103
- export interface Claim<T extends AnyToken, R extends AnyToken = T> {
104
- tokens: T[];
105
- rest: Tokenizer<R>;
106
- }
107
-
108
- class View<T extends AnyToken> implements TokenInput<T> {
109
- constructor(
110
- readonly source: Tokenizer<T>,
111
- readonly options: ViewOptions,
112
- ) {}
113
-
114
- claimNext(): Claim<T> {
115
- return this.claimOne(() => true);
116
- }
117
-
118
- claimOne<S extends T>(match: (token: T) => token is S): Claim<S, T>;
119
- claimOne(match: (token: T) => boolean): Claim<T, T>;
120
- claimOne(match: (token: T) => boolean): Claim<T> {
121
- for (let token of this) {
122
- if (match(token)) {
123
- return {
124
- tokens: [token],
125
- rest: remainder(this.source, [token.index]),
126
- };
127
- }
128
- }
129
- return { tokens: [], rest: this.source };
130
- }
131
-
132
- claimPair(match: (a: T, b: T) => boolean): Claim<T, T> {
133
- let previous: T | undefined;
134
- for (let token of this) {
135
- if (!previous) {
136
- previous = token;
137
- continue;
138
- }
139
- if (token.index === previous.index + 1 && match(previous, token)) {
140
- return {
141
- tokens: [previous, token],
142
- rest: remainder(this.source, [previous.index, token.index]),
143
- };
144
- }
145
- previous = token;
146
- }
147
- return { tokens: [], rest: this.source };
148
- }
149
-
150
- claimAll<S extends T>(match: (token: T) => token is S): Claim<S, T>;
151
- claimAll(match: (token: T) => boolean): Claim<T, T>;
152
- claimAll(match: (token: T) => boolean): Claim<T> {
153
- let tokens: T[] = [];
154
- let claimed = new Set<number>();
155
- for (let token of this) {
156
- if (match(token)) {
157
- claimed.add(token.index);
158
- tokens.push(token);
159
- }
160
- }
161
- return {
162
- tokens,
163
- rest: tokens.length > 0 ? remainder(this.source, claimed) : this.source,
164
- };
165
- }
166
-
167
- *[Symbol.iterator](): Generator<T, void, unknown> {
168
- let { start, end } = this.options.range;
169
- let { through } = this.options;
170
-
171
- for (let token of this.source) {
172
- if (
173
- token.index > start &&
174
- (end === undefined || token.index < end) &&
175
- (through === undefined || token.index <= through)
176
- ) {
177
- yield token;
178
- }
179
- }
180
- }
181
- }
182
-
183
- function remainder<T extends AnyToken>(
184
- source: Tokenizer<T>,
185
- claimed: Iterable<number>,
186
- ): Tokenizer<T> {
187
- return new Tokenizer(
188
- source.tokens,
189
- new Set([...source.claimed, ...claimed]),
190
- );
191
- }
@@ -1,49 +0,0 @@
1
- import { brand, type ModelElement, type ModelTransform } from "./pipeline.js";
2
- import type { AnyRoute, Schema } from "./types.js";
3
-
4
- export function transform<
5
- Input extends object,
6
- Output extends object,
7
- >(
8
- schema: Schema<Input, Output>,
9
- ): ModelElement<SchemaTransform<Input, Output>> {
10
- return brand(
11
- (route: AnyRoute) => {
12
- let phases = [...route.phases];
13
- let phase = phases.pop()!;
14
- phases.push({
15
- ...phase,
16
- model: {
17
- params: phase.model.params,
18
- steps: phase.model.steps.concat((current) => {
19
- let result = schema["~standard"].validate(current);
20
- if (result instanceof Promise) {
21
- return {
22
- ok: false,
23
- issues: [{
24
- message: `async validation not currently supported`,
25
- }],
26
- };
27
- } else if (result.issues) {
28
- return { ok: false, issues: result.issues };
29
- } else {
30
- return { ok: true, value: result.value };
31
- }
32
- }),
33
- },
34
- });
35
- return {
36
- ...route,
37
- phases,
38
- };
39
- },
40
- );
41
- }
42
-
43
- interface SchemaTransform<
44
- Input extends object,
45
- Output extends object,
46
- > extends ModelTransform {
47
- readonly input: Input;
48
- readonly output: Output;
49
- }
package/src/lib/types.ts DELETED
@@ -1,460 +0,0 @@
1
- import type { StandardSchemaV1 } from "@standard-schema/spec";
2
- import type { EnvSource } from "./env.js";
3
- import type { Literal } from "./tokenize.js";
4
- import type { AnyParam } from "./param.js";
5
- import type { Result } from "./result.js";
6
- import type { ValueSource } from "./values.js";
7
-
8
- export type Issue = StandardSchemaV1.Issue;
9
- export type Schema<Input = unknown, Output = Input> = StandardSchemaV1<
10
- Input,
11
- Output
12
- >;
13
- export type OutputOf<S extends Schema> = StandardSchemaV1.InferOutput<S>;
14
-
15
- export interface Definition<N extends string> {
16
- readonly name: N;
17
- readonly description?: string;
18
- }
19
-
20
- export interface Route<
21
- N extends string,
22
- M extends Method,
23
- P extends AnyPhases,
24
- > extends Definition<N> {
25
- readonly methods: readonly M[];
26
- readonly version?: string;
27
- readonly phases: P;
28
- }
29
-
30
- export type Parse<R extends AnyRoute> = Outcome<ParseAt<R, "/", {}>>;
31
-
32
- export type Phase<
33
- Model extends object,
34
- Routes extends readonly AnyRoute[],
35
- Requirement = never,
36
- > = [Requirement] extends [never] ? Done<Model, Routes>
37
- : Next<Model, Routes, Requirement>;
38
-
39
- export type Next<
40
- Model extends object,
41
- Routes extends readonly AnyRoute[],
42
- T,
43
- > = {
44
- readonly [phaseModel]?: Model;
45
- readonly model: {
46
- params: Params;
47
- steps: ((
48
- previous: object,
49
- bindings: Record<string, unknown>,
50
- ) => Result<object>)[];
51
- };
52
- readonly routes: Routes;
53
- readonly values: readonly ValueSource[];
54
- readonly envs: readonly EnvSource[];
55
- readonly resolver: (
56
- requirement: T,
57
- ) => (input: AnyRoute) => AnyRoute;
58
- };
59
-
60
- export type Done<
61
- Model extends object,
62
- Routes extends readonly AnyRoute[],
63
- > = {
64
- readonly [phaseModel]?: Model;
65
- readonly model: {
66
- params: Params;
67
- steps: ((
68
- previous: object,
69
- bindings: Record<string, unknown>,
70
- ) => Result<object>)[];
71
- };
72
- readonly routes: Routes;
73
- readonly values: readonly ValueSource[];
74
- readonly envs: readonly EnvSource[];
75
- };
76
-
77
- export type Params = Readonly<Record<string, AnyParam>>;
78
-
79
- export interface ParseIncrement<
80
- R extends AnyRoute,
81
- P extends RoutePath = "/",
82
- Models extends ModelsByRoute = {},
83
- > {
84
- readonly ok: true;
85
- readonly route: P;
86
- readonly model: IncrementModelOf<R>;
87
-
88
- resume(
89
- result: Result<RequirementOf<R>>,
90
- ): Outcome<ParseAt<ContinuationOf<R>, P, Models>>;
91
- }
92
-
93
- export type ContinuationOf<R extends AnyRoute> = Route<
94
- R["name"],
95
- MethodsOf<R>,
96
- SettleNext<R["phases"]>
97
- >;
98
-
99
- export type ModelOf<
100
- R extends AnyRoute,
101
- P extends RoutePath = "/",
102
- > = ModelOfRoute<RouteAt<R, P>>;
103
-
104
- export type ChildrenOf<R extends AnyRoute> = RoutesIn<R["phases"]>;
105
-
106
- export type RequirementsOf<R extends AnyRoute> = RequirementsIn<R["phases"]>;
107
-
108
- export type RequirementOf<R extends AnyRoute> = RequirementInPhases<
109
- R["phases"]
110
- >;
111
-
112
- export interface AnyRoute extends Definition<string> {
113
- readonly methods: readonly Method[];
114
- readonly version?: string;
115
- readonly phases: AnyPhases;
116
- }
117
-
118
- export interface AnyPhase {
119
- readonly [phaseModel]?: object;
120
- readonly model: {
121
- params: Params;
122
- steps: ((
123
- previous: object,
124
- bindings: Record<string, unknown>,
125
- ) => Result<object>)[];
126
- };
127
- readonly routes: readonly AnyRoute[];
128
- readonly values: readonly ValueSource[];
129
- readonly envs: readonly EnvSource[];
130
- readonly resolver?: (requirement: never) => (route: never) => AnyRoute;
131
- }
132
-
133
- export type AnyPhases = readonly [AnyPhase, ...AnyPhase[]];
134
-
135
- export type Method = "help" | "version" | "execute";
136
- export type MethodsOf<R extends AnyRoute> = R["methods"][number];
137
-
138
- export type Path = readonly string[];
139
-
140
- export type Input = {
141
- argv: string[];
142
- values?: readonly ValueSource[];
143
- envs?: readonly EnvSource[];
144
- };
145
-
146
- export interface Failure<C extends Status> {
147
- readonly ok: false;
148
- readonly code: C;
149
- }
150
-
151
- export type Outcome<T> = T | MethodNotAllowed | UnprocessableContent;
152
-
153
- export type IntentsOf<R extends AnyRoute> = IntentsAt<R, `/`, {}>;
154
-
155
- export type RoutePath = `/${string}`;
156
-
157
- export type ModelsByRoute = {
158
- readonly [path: RoutePath]: object;
159
- };
160
-
161
- export type PathOf<R extends RoutePath> = R extends "/" ? []
162
- : R extends `/${infer Rest}` ? Split<Rest>
163
- : never;
164
-
165
- export type AnyIntent =
166
- | Help<RoutePath>
167
- | Version<RoutePath>
168
- | Execute<RoutePath, ModelsByRoute>;
169
-
170
- export type ChildIntents<
171
- C extends readonly AnyRoute[],
172
- P extends RoutePath,
173
- Models extends ModelsByRoute,
174
- > = C extends readonly [
175
- infer Head extends AnyRoute,
176
- ...infer Tail extends readonly AnyRoute[],
177
- ] ? (
178
- | IntentsAt<Head, Append<P, Head["name"]>, Models>
179
- | ChildIntents<Tail, P, Models>
180
- )
181
- : never;
182
-
183
- export interface Intent<
184
- M extends Method,
185
- P extends RoutePath,
186
- > {
187
- readonly ok: true;
188
- readonly method: M;
189
- readonly route: P;
190
- readonly definition: AnyRoute;
191
- readonly path: PathOf<P>;
192
- readonly literals: Iterable<Literal>;
193
- }
194
-
195
- export type Help<P extends RoutePath> = Intent<
196
- "help",
197
- P
198
- >;
199
-
200
- export type Version<P extends RoutePath> = Intent<
201
- "version",
202
- P
203
- >;
204
-
205
- export interface Execute<
206
- P extends RoutePath,
207
- Models extends ModelsByRoute,
208
- > extends Intent<"execute", P> {
209
- readonly issues: readonly Issue[];
210
- readonly model: Models[P];
211
- readonly models: Models;
212
- }
213
-
214
- export type Status =
215
- | "method-not-allowed"
216
- | "unprocessable-content";
217
-
218
- export interface MethodNotAllowed extends Failure<"method-not-allowed"> {
219
- readonly route: string;
220
- readonly definition: AnyRoute;
221
- readonly path: Path;
222
- readonly method: Method;
223
- readonly allowed: readonly Method[];
224
- }
225
-
226
- export interface UnprocessableContent extends Failure<"unprocessable-content"> {
227
- readonly route: string;
228
- readonly definition: AnyRoute;
229
- readonly path: Path;
230
- readonly issues: Issue[];
231
- }
232
-
233
- declare const phaseModel: unique symbol;
234
-
235
- type ModelOfRoute<R extends AnyRoute> = ModelsIn<R["phases"]> extends
236
- infer Model extends object ? { [K in keyof Model]: Model[K] }
237
- : never;
238
-
239
- type ModelsIn<P extends readonly AnyPhase[]> = P extends readonly [
240
- infer Head extends AnyPhase,
241
- ...infer Tail extends readonly AnyPhase[],
242
- ] ? Omit<PhaseModelOf<Head>, ModelKeys<Tail>> & ModelsIn<Tail>
243
- : {};
244
-
245
- type ModelKeys<P extends readonly AnyPhase[]> = P extends readonly [
246
- infer Head extends AnyPhase,
247
- ...infer Tail extends readonly AnyPhase[],
248
- ] ? keyof PhaseModelOf<Head> | ModelKeys<Tail>
249
- : never;
250
-
251
- type PhaseModelOf<P extends AnyPhase> = P extends {
252
- readonly [phaseModel]?: infer Model extends object;
253
- } ? Model
254
- : never;
255
-
256
- type RoutesIn<P extends readonly AnyPhase[]> = P extends readonly [
257
- infer Head extends AnyPhase,
258
- ...infer Tail extends readonly AnyPhase[],
259
- ] ? readonly [...Head["routes"], ...RoutesIn<Tail>]
260
- : readonly [];
261
-
262
- type RouteAt<
263
- R extends AnyRoute,
264
- P extends RoutePath,
265
- > = P extends "/" ? R
266
- : P extends `/${infer Head}/${infer Tail}`
267
- ? FindRoute<ChildrenOf<R>, Head> extends infer Child extends AnyRoute
268
- ? RouteAt<Child, `/${Tail}`>
269
- : never
270
- : P extends `/${infer Name}` ? FindRoute<ChildrenOf<R>, Name>
271
- : never;
272
-
273
- type FindRoute<
274
- C extends readonly AnyRoute[],
275
- N extends string,
276
- > = C extends readonly [
277
- infer Head extends AnyRoute,
278
- ...infer Tail extends readonly AnyRoute[],
279
- ] ? Head["name"] extends N ? Head
280
- : FindRoute<Tail, N>
281
- : never;
282
-
283
- type SettleNext<P extends AnyPhases> = P extends readonly [
284
- infer Head extends AnyPhase,
285
- ...infer Tail extends readonly AnyPhase[],
286
- ]
287
- ? Head extends Next<infer Model, infer Routes, infer _Requirement>
288
- ? readonly [Done<Model, Routes>, ...Tail]
289
- : Tail extends AnyPhases ? readonly [Head, ...SettleNext<Tail>]
290
- : P
291
- : never;
292
-
293
- type NextModelIn<P extends readonly AnyPhase[]> = P extends readonly [
294
- infer Head extends AnyPhase,
295
- ...infer Tail extends readonly AnyPhase[],
296
- ] ? Head extends Next<
297
- infer Model,
298
- readonly AnyRoute[],
299
- infer _Requirement
300
- > ? Model
301
- : NextModelIn<Tail>
302
- : never;
303
-
304
- type RequirementIn<P extends AnyPhase> = P extends {
305
- readonly resolver: (
306
- requirement: infer Requirement,
307
- ) => (route: AnyRoute) => AnyRoute;
308
- } ? Requirement
309
- : never;
310
-
311
- type RequirementInPhases<P extends readonly AnyPhase[]> = P extends readonly [
312
- infer Head extends AnyPhase,
313
- ...infer Tail extends readonly AnyPhase[],
314
- ] ? [RequirementIn<Head>] extends [never] ? RequirementInPhases<Tail>
315
- : RequirementIn<Head>
316
- : never;
317
-
318
- type IncrementModelOf<R extends AnyRoute> = NextModelIn<R["phases"]>;
319
-
320
- type ParseAt<
321
- R extends AnyRoute,
322
- P extends RoutePath,
323
- Models extends ModelsByRoute,
324
- > = [RequirementOf<R>] extends [never] ? (
325
- | Help<P>
326
- | (
327
- "version" extends MethodsOf<R> ? Version<P>
328
- : never
329
- )
330
- | (
331
- "execute" extends MethodsOf<R> ? AddModel<
332
- Models,
333
- P,
334
- ModelOf<R>
335
- > extends infer Bound extends ModelsByRoute ? Execute<
336
- P,
337
- { [K in keyof Bound]: Bound[K] }
338
- >
339
- : never
340
- : never
341
- )
342
- | ParseChildren<
343
- ChildrenOf<R>,
344
- P,
345
- AddModel<Models, P, ModelOf<R>>
346
- >
347
- )
348
- : ParseIncrement<R, P, { [K in keyof Models]: Models[K] }>;
349
-
350
- type ParseChildren<
351
- C extends readonly AnyRoute[],
352
- P extends RoutePath,
353
- Models extends ModelsByRoute,
354
- > = C extends readonly [
355
- infer Head extends AnyRoute,
356
- ...infer Tail extends readonly AnyRoute[],
357
- ] ? (
358
- | ParseAt<Head, Append<P, Head["name"]>, Models>
359
- | ParseChildren<Tail, P, Models>
360
- )
361
- : never;
362
-
363
- type RequirementsIn<P extends readonly AnyPhase[]> = P extends readonly [
364
- infer Head extends AnyPhase,
365
- ...infer Tail extends AnyPhase[],
366
- ] ? [RequirementIn<Head>] extends [never] ? RequirementsIn<Tail>
367
- : readonly [RequirementIn<Head>, ...RequirementsIn<Tail>]
368
- : readonly [];
369
-
370
- type AddModel<
371
- Models extends ModelsByRoute,
372
- P extends RoutePath,
373
- T extends object,
374
- > = {
375
- [K in keyof Models | P]: K extends P ? T
376
- : K extends keyof Models ? Models[K]
377
- : never;
378
- };
379
-
380
- type Split<S extends string> = string extends S ? Path
381
- : S extends `${infer Head}/${infer Tail}` ? [Head, ...Split<Tail>]
382
- : S extends "" ? []
383
- : [S];
384
-
385
- type Append<
386
- A extends RoutePath,
387
- N extends string,
388
- > = A extends "/" ? `/${N}`
389
- : `${A}/${N}`;
390
-
391
- export type AddRoutesToLast<
392
- P extends AnyPhases,
393
- C extends readonly AnyRoute[],
394
- > = ReplaceLast<
395
- P,
396
- AddRoutes<LastOf<P>, C>
397
- >;
398
-
399
- type LastOf<P extends AnyPhases> = P extends readonly [
400
- ...AnyPhase[],
401
- infer Last extends AnyPhase,
402
- ] ? Last
403
- : never;
404
-
405
- type ReplaceLast<
406
- P extends AnyPhases,
407
- Last extends AnyPhase,
408
- > = P extends readonly [AnyPhase] ? readonly [Last]
409
- : P extends readonly [
410
- infer First extends AnyPhase,
411
- ...infer Middle extends AnyPhase[],
412
- AnyPhase,
413
- ] ? readonly [First, ...Middle, Last]
414
- : never;
415
-
416
- type AddRoutes<
417
- Phase extends AnyPhase,
418
- Added extends readonly AnyRoute[],
419
- > = Phase extends Next<
420
- infer Model,
421
- infer Routes,
422
- infer Requirement
423
- > ? Next<
424
- Model,
425
- readonly [...Routes, ...Added],
426
- Requirement
427
- >
428
- : Phase extends Done<infer Model, infer Routes> ? Done<
429
- Model,
430
- readonly [...Routes, ...Added]
431
- >
432
- : never;
433
-
434
- type IntentsAt<
435
- R extends AnyRoute,
436
- P extends RoutePath,
437
- Models extends ModelsByRoute,
438
- > =
439
- | Help<P>
440
- | (
441
- "version" extends MethodsOf<R> ? Version<P>
442
- : never
443
- )
444
- | (
445
- "execute" extends MethodsOf<R> ? AddModel<
446
- Models,
447
- P,
448
- ModelOf<R>
449
- > extends infer Bound extends ModelsByRoute ? Execute<
450
- P,
451
- { [K in keyof Bound]: Bound[K] }
452
- >
453
- : never
454
- : never
455
- )
456
- | ChildIntents<
457
- ChildrenOf<R>,
458
- P,
459
- AddModel<Models, P, ModelOf<R>>
460
- >;