| 1 | import type { |
| 2 | ArrayIndex, |
| 3 | Expr, |
| 4 | Identifier, |
| 5 | NameRef, |
| 6 | NumberLiteral, |
| 7 | PropRef, |
| 8 | ValueRef, |
| 9 | Word, |
| 10 | } from "./Expr.ts"; |
| 11 | |
| 12 | export type ParseProjectionExpression<Text extends string> = Parse< |
| 13 | Text, |
| 14 | [], |
| 15 | undefined |
| 16 | >; |
| 17 | |
| 18 | type AsExpr<T> = Extract<T, Expr>; |
| 19 | |
| 20 | type 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 | |
| 52 | type Concat< |
| 53 | Expressions extends Expr[], |
| 54 | CurrentExpr extends Expr | undefined, |
| 55 | > = undefined extends CurrentExpr |
| 56 | ? Expressions |
| 57 | : [...Expressions, Extract<CurrentExpr, Expr>]; |
| 58 | |
| 59 | type 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 | |
| 78 | export type ApplyProjection<T, Expr extends string> = Flatten< |
| 79 | UnionToIntersection< |
| 80 | ApplyProjectionExpr<T, ParseProjectionExpression<Expr>[number]> |
| 81 | > |
| 82 | >; |
| 83 | |
| 84 | type 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 | |
| 110 | type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends ( |
| 111 | k: infer I, |
| 112 | ) => void |
| 113 | ? I |
| 114 | : never; |
| 115 | |
| 116 | type 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 | |
| 124 | type 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 | |
| 133 | type BuildTuple<N extends number, T extends any[] = []> = T["length"] extends N |
| 134 | ? T |
| 135 | : BuildTuple<N, [...T, any]>; |
| 136 | |
| 137 | type Inc<N extends number> = Extract<[...BuildTuple<N>, any]["length"], number>; |
| 138 | |
| 139 | type 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; |