1import type {
2 ArrayIndex,
3 Expr,
4 Identifier,
5 NameRef,
6 NumberLiteral,
7 PropRef,
8 ValueRef,
9 Word,
10} from "./Expr.ts";
11
12export type ParseProjectionExpression<Text extends string> = Parse<
13 Text,
14 [],
15 undefined
16>;
17
18type AsExpr<T> = Extract<T, Expr>;
19
20type Parse<
21 Text extends string,
22 Expressions extends Expr[],
23 Exp extends Expr | undefined,
24> = Text extends `.${infer Rest}`
25 ? Exp extends Expr
26 ? Parse<Rest, Expressions, PropRef<Exp, Identifier<"">>>
27 : never
28 : Text extends `[:${infer Rest}`
29 ? Parse<Rest, Expressions, ArrayIndex<AsExpr<Exp>, ValueRef<"">>>
30 : Text extends `[${infer Rest}`
31 ? Parse<Rest, Expressions, ArrayIndex<AsExpr<Exp>, NumberLiteral<"">>>
32 : Text extends `]${infer Rest}`
33 ? Parse<Rest, Expressions, Exp>
34 : Text extends `]`
35 ? Concat<Expressions, Exp>
36 : Text extends `${"," | " "}${infer Rest}`
37 ? Parse<Rest, Concat<Expressions, Exp>, undefined>
38 : Text extends `#${infer Rest}`
39 ? Parse<Rest, Concat<Expressions, Exp>, NameRef<Rest>>
40 : Text extends `:${infer Rest}`
41 ? Parse<Rest, Concat<Expressions, Exp>, ValueRef<Rest>>
42 : Text extends `${Word}${string}`
43 ? Text extends `${infer char}${infer Rest}`
44 ? Parse<Rest, Expressions, Append<Exp, char>>
45 : never
46 : Text extends `${Word}${string}`
47 ? Text extends `${infer char}${infer Rest}`
48 ? Parse<Rest, Expressions, Append<Exp, char>>
49 : never
50 : Concat<Expressions, Exp>;
51
52type Concat<
53 Expressions extends Expr[],
54 CurrentExpr extends Expr | undefined,
55> = undefined extends CurrentExpr
56 ? Expressions
57 : [...Expressions, Extract<CurrentExpr, Expr>];
58
59type Append<
60 Exp extends Expr | undefined,
61 char extends string,
62> = Exp extends undefined
63 ? Identifier<char>
64 : Exp extends Identifier<infer Name>
65 ? Identifier<`${Name}${char}`>
66 : Exp extends NumberLiteral<infer Name>
67 ? NumberLiteral<`${Name}${char}`>
68 : Exp extends NameRef<infer Name>
69 ? NameRef<`${Name}${char}`>
70 : Exp extends ValueRef<infer Name>
71 ? ValueRef<`${Name}${char}`>
72 : Exp extends PropRef<infer expr, infer name>
73 ? PropRef<expr, Extract<Append<name, char>, Identifier>>
74 : Exp extends ArrayIndex<infer expr, infer idx>
75 ? ArrayIndex<expr, Extract<Append<idx, char>, NumberLiteral>>
76 : never;
77
78export type ApplyProjection<T, Expr extends string> = Flatten<
79 UnionToIntersection<
80 ApplyProjectionExpr<T, ParseProjectionExpression<Expr>[number]>
81 >
82>;
83
84type ApplyProjectionExpr<T, Exp extends Expr> = T extends undefined
85 ? never
86 : Exp extends PropRef<infer expr, infer i>
87 ? {
88 [p in keyof ApplyProjectionExpr<T, expr>]: ApplyProjectionExpr<
89 ApplyProjectionExpr<T, expr>[p],
90 i
91 >;
92 }
93 : Exp extends ArrayIndex<infer expr, infer i>
94 ? {
95 [p in keyof ApplyProjectionExpr<T, expr>]: ApplyProjectionExpr<
96 ApplyProjectionExpr<T, expr>[keyof ApplyProjectionExpr<T, expr>],
97 i
98 >;
99 }
100 : Exp extends Identifier<infer I>
101 ? I extends keyof T
102 ? Pick<T, I>
103 : never
104 : Exp extends NumberLiteral<infer I>
105 ? ParseInt<I> extends keyof T
106 ? Pick<T, ParseInt<I>>
107 : never
108 : never;
109
110type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (
111 k: infer I,
112) => void
113 ? I
114 : never;
115
116type Flatten<T> = T extends object
117 ? keyof T extends number
118 ? FlattenArray<Extract<T, Record<number, any>>>
119 : {
120 [k in keyof T]: Flatten<T[k]>;
121 }
122 : T;
123
124type FlattenArray<
125 T extends { [i in number]: any },
126 i extends number = 0,
127> = i extends keyof T
128 ? [T[i], ...FlattenArray<T, Inc<i>>]
129 : number extends i
130 ? []
131 : FlattenArray<T, Inc<i>>;
132
133type BuildTuple<N extends number, T extends any[] = []> = T["length"] extends N
134 ? T
135 : BuildTuple<N, [...T, any]>;
136
137type Inc<N extends number> = Extract<[...BuildTuple<N>, any]["length"], number>;
138
139type ParseInt<N extends string> = N extends "0"
140 ? 0
141 : N extends "1"
142 ? 1
143 : N extends "2"
144 ? 2
145 : N extends "3"
146 ? 3
147 : N extends "4"
148 ? 4
149 : N extends "5"
150 ? 5
151 : N extends "6"
152 ? 6
153 : N extends "7"
154 ? 7
155 : N extends "8"
156 ? 8
157 : N extends "9"
158 ? 9
159 : number;