@kuindji/typed-sql 0.2.0 → 0.4.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.
Files changed (48) hide show
  1. package/README.md +11 -3
  2. package/dist/columns.d.ts +11 -3
  3. package/dist/columns.d.ts.map +1 -1
  4. package/dist/expressions.d.ts +84 -13
  5. package/dist/expressions.d.ts.map +1 -1
  6. package/dist/parsing/extract.d.ts +13 -9
  7. package/dist/parsing/extract.d.ts.map +1 -1
  8. package/dist/parsing/normalize.d.ts +9 -3
  9. package/dist/parsing/normalize.d.ts.map +1 -1
  10. package/dist/parsing/pg-literals.d.ts +10 -2
  11. package/dist/parsing/pg-literals.d.ts.map +1 -1
  12. package/dist/parsing/split.d.ts +27 -3
  13. package/dist/parsing/split.d.ts.map +1 -1
  14. package/dist/parsing/string-utils.d.ts +2 -4
  15. package/dist/parsing/string-utils.d.ts.map +1 -1
  16. package/dist/parsing/tokenize.d.ts +27 -17
  17. package/dist/parsing/tokenize.d.ts.map +1 -1
  18. package/dist/partial.d.ts +6 -6
  19. package/dist/partial.d.ts.map +1 -1
  20. package/dist/tables.d.ts +58 -13
  21. package/dist/tables.d.ts.map +1 -1
  22. package/dist/validation/dispatch.d.ts +7 -5
  23. package/dist/validation/dispatch.d.ts.map +1 -1
  24. package/dist/validation/joins.d.ts +3 -3
  25. package/dist/validation/joins.d.ts.map +1 -1
  26. package/dist/validation/return-derived.d.ts +8 -4
  27. package/dist/validation/return-derived.d.ts.map +1 -1
  28. package/dist/validation/return-derived.js.map +1 -1
  29. package/dist/validation/return-types.d.ts +1 -1
  30. package/dist/validation/return-types.d.ts.map +1 -1
  31. package/dist/validation/validate-columns.d.ts +27 -16
  32. package/dist/validation/validate-columns.d.ts.map +1 -1
  33. package/package.json +1 -1
  34. package/src/columns.ts +168 -32
  35. package/src/expressions.ts +589 -63
  36. package/src/parsing/extract.ts +72 -32
  37. package/src/parsing/normalize.ts +114 -10
  38. package/src/parsing/pg-literals.ts +32 -10
  39. package/src/parsing/split.ts +236 -72
  40. package/src/parsing/string-utils.ts +15 -15
  41. package/src/parsing/tokenize.ts +224 -146
  42. package/src/partial.ts +9 -15
  43. package/src/tables.ts +546 -183
  44. package/src/validation/dispatch.ts +58 -52
  45. package/src/validation/joins.ts +15 -19
  46. package/src/validation/return-derived.ts +60 -4
  47. package/src/validation/return-types.ts +9 -3
  48. package/src/validation/validate-columns.ts +161 -67
@@ -13,6 +13,15 @@ import type { SqlReserved } from "./tokenize.js";
13
13
  // `{ __c: [...] }` marker. `SplitTopLevel` (the driver below) re-invokes the
14
14
  // worker on the remainder with a fresh step counter, which resets TS's internal
15
15
  // tail-recursion count per chunk — so arbitrarily long lists split losslessly.
16
+ // Segment-jump, not per-char (the old walk minted one growing-`Cur` string PER
17
+ // CHARACTER and the tail at every step). Each step advances to the LEFTMOST of
18
+ // the five state chars `,` `'` `"` `(` `)`, copying the whole run before it into
19
+ // `Cur` in a single mint; inside a quote it jumps straight to the closing quote
20
+ // (the other quote kind inside a span is data, preserving the old InQ/InDQ
21
+ // suppression; `''` escapes exit+re-enter across two jumps; an unterminated
22
+ // quote at EOF copies the rest verbatim). The `Steps` cap counts JUMPS and
23
+ // yields `{ __c: [...] }` to the driver as before. Mirrors `MtcStructJump`
24
+ // (tokenize.ts) and `SbpParenJump` (extract.ts).
16
25
  type SplitTopLevelWorker<
17
26
  S extends string,
18
27
  Depth extends any[] = [],
@@ -21,36 +30,89 @@ type SplitTopLevelWorker<
21
30
  Steps extends any[] = [],
22
31
  InQ extends boolean = false,
23
32
  InDQ extends boolean = false
24
- > = Steps["length"] extends 450
33
+ // CHUNK = 120 JUMPS, not chars: since the round-7 struct-jump rewrite each
34
+ // jump costs ~4 conditional evaluations through the StlStructJump* helper
35
+ // chain, so the old 450-jump chunk could burn >1000 tail counts inside ONE
36
+ // chunk (TS2589) on a 50-projection select list. 120 jumps ≈ 500 tail counts.
37
+ > = Steps["length"] extends 120
25
38
  ? { __c: [S, Depth, Acc, Cur, InQ, InDQ] }
26
39
  : string extends CleanIdent<S>
27
40
  ? [...Acc, `${Cur}string`]
28
- : S extends `${infer C}${infer Rest}`
29
- ? C extends "'"
30
- // A single quote toggles "inside string literal": commas, parens and
31
- // path braces inside a '...' literal are kept verbatim, not split.
32
- // Suppressed while inside a double-quoted identifier.
33
- ? InDQ extends true
34
- ? SplitTopLevelWorker<Rest, Depth, Acc, `${Cur}${C}`, [any, ...Steps], InQ, InDQ>
35
- : SplitTopLevelWorker<Rest, Depth, Acc, `${Cur}${C}`, [any, ...Steps], InQ extends true ? false : true, InDQ>
36
- : InQ extends true
37
- ? SplitTopLevelWorker<Rest, Depth, Acc, `${Cur}${C}`, [any, ...Steps], InQ, InDQ>
38
- : C extends `"`
39
- // A double quote toggles "inside quoted identifier": commas and
40
- // parens inside `"..."` are part of the identifier, kept verbatim.
41
- ? SplitTopLevelWorker<Rest, Depth, Acc, `${Cur}${C}`, [any, ...Steps], InQ, InDQ extends true ? false : true>
41
+ : InQ extends true
42
+ ? S extends `${infer P}'${infer R}`
43
+ ? SplitTopLevelWorker<R, Depth, Acc, `${Cur}${P}'`, [any, ...Steps], false, InDQ>
44
+ : [...Acc, `${Cur}${S}`]
42
45
  : InDQ extends true
43
- ? SplitTopLevelWorker<Rest, Depth, Acc, `${Cur}${C}`, [any, ...Steps], InQ, InDQ>
44
- : C extends "("
45
- ? SplitTopLevelWorker<Rest, [any, ...Depth], Acc, `${Cur}${C}`, [any, ...Steps], InQ, InDQ>
46
- : C extends ")"
47
- ? SplitTopLevelWorker<Rest, Depth extends [any, ...infer D] ? D : [], Acc, `${Cur}${C}`, [any, ...Steps], InQ, InDQ>
48
- : C extends ","
49
- ? Depth["length"] extends 0
50
- ? SplitTopLevelWorker<Rest, Depth, [...Acc, Cur], "", [any, ...Steps], InQ, InDQ>
51
- : SplitTopLevelWorker<Rest, Depth, Acc, `${Cur}${C}`, [any, ...Steps], InQ, InDQ>
52
- : SplitTopLevelWorker<Rest, Depth, Acc, `${Cur}${C}`, [any, ...Steps], InQ, InDQ>
53
- : [...Acc, Cur];
46
+ ? S extends `${infer P}"${infer R}`
47
+ ? SplitTopLevelWorker<R, Depth, Acc, `${Cur}${P}"`, [any, ...Steps], InQ, false>
48
+ : [...Acc, `${Cur}${S}`]
49
+ : S extends `${infer P},${infer R}`
50
+ // a structural char in the run before the first comma it is
51
+ // leftmost; defer to the struct jump
52
+ ? StlHasStruct<P> extends true
53
+ ? StlStructJump<S, Depth, Acc, Cur, Steps>
54
+ : Depth["length"] extends 0
55
+ ? SplitTopLevelWorker<R, Depth, [...Acc, `${Cur}${P}`], "", [any, ...Steps], false, false>
56
+ : SplitTopLevelWorker<R, Depth, Acc, `${Cur}${P},`, [any, ...Steps], false, false>
57
+ : StlHasStruct<S> extends true
58
+ ? StlStructJump<S, Depth, Acc, Cur, Steps>
59
+ : [...Acc, `${Cur}${S}`];
60
+
61
+ type StlHasStruct<S extends string> =
62
+ S extends `${string}'${string}` ? true
63
+ : S extends `${string}"${string}` ? true
64
+ : S extends `${string}(${string}` ? true
65
+ : S extends `${string})${string}` ? true
66
+ : false;
67
+
68
+ // Leftmost of `'` / `"` / `(` / `)` (the caller guarantees at least one occurs
69
+ // before any comma). Pairwise narrowing: split on a candidate; if an
70
+ // earlier-class char appears in its prefix, that one is leftmost instead.
71
+ type StlStructJump<
72
+ S extends string,
73
+ Depth extends any[],
74
+ Acc extends string[],
75
+ Cur extends string,
76
+ Steps extends any[]
77
+ > = S extends `${infer P}'${infer R}`
78
+ ? P extends `${string}"${string}` | `${string}(${string}` | `${string})${string}`
79
+ ? StlStructJump2<S, Depth, Acc, Cur, Steps>
80
+ : SplitTopLevelWorker<R, Depth, Acc, `${Cur}${P}'`, [any, ...Steps], true, false>
81
+ : StlStructJump2<S, Depth, Acc, Cur, Steps>;
82
+
83
+ type StlStructJump2<
84
+ S extends string,
85
+ Depth extends any[],
86
+ Acc extends string[],
87
+ Cur extends string,
88
+ Steps extends any[]
89
+ > = S extends `${infer P}"${infer R}`
90
+ ? P extends `${string}(${string}` | `${string})${string}`
91
+ ? StlStructJump3<S, Depth, Acc, Cur, Steps>
92
+ : SplitTopLevelWorker<R, Depth, Acc, `${Cur}${P}"`, [any, ...Steps], false, true>
93
+ : StlStructJump3<S, Depth, Acc, Cur, Steps>;
94
+
95
+ type StlStructJump3<
96
+ S extends string,
97
+ Depth extends any[],
98
+ Acc extends string[],
99
+ Cur extends string,
100
+ Steps extends any[]
101
+ > = S extends `${infer P}(${infer R}`
102
+ ? P extends `${string})${string}`
103
+ ? StlCloseJump<S, Depth, Acc, Cur, Steps>
104
+ : SplitTopLevelWorker<R, [any, ...Depth], Acc, `${Cur}${P}(`, [any, ...Steps], false, false>
105
+ : StlCloseJump<S, Depth, Acc, Cur, Steps>;
106
+
107
+ type StlCloseJump<
108
+ S extends string,
109
+ Depth extends any[],
110
+ Acc extends string[],
111
+ Cur extends string,
112
+ Steps extends any[]
113
+ > = S extends `${infer P})${infer R}`
114
+ ? SplitTopLevelWorker<R, Depth extends [any, ...infer D] ? D : [], Acc, `${Cur}${P})`, [any, ...Steps], false, false>
115
+ : [...Acc, `${Cur}${S}`];
54
116
 
55
117
  // Driver: run the worker chunk-by-chunk until it returns the finished `string[]`.
56
118
  // Each `{ __c: state }` yield is fed back with a fresh step counter, so no single
@@ -70,55 +132,157 @@ type SplitTopLevelDrive<R> =
70
132
  // Quote-aware on BOTH single quotes (`'...'` string literals) and double quotes
71
133
  // (`"..."` quoted identifiers): a ` from ` token sitting inside a double-quoted
72
134
  // output alias (`id as "came from import"`) is part of the identifier, not the
73
- // SELECT/FROM boundary, so it must not split the list. `InString` tracks single
74
- // quotes; `InDString` tracks double quotes. Parens and the ` from ` boundary are
75
- // only honoured when outside BOTH kinds of quote.
76
- export type ExtractBeforeFromTopLevel<
135
+ // SELECT/FROM boundary, so it must not split the list. Parens and the ` from `
136
+ // boundary are only honoured when outside BOTH kinds of quote.
137
+ // Struct-jump, not per-char (the old walk minted a growing `Acc` PER CHARACTER
138
+ // over every subquery select-list). At depth 0 each step advances to the
139
+ // LEFTMOST of `'` `"` `(` `)` ` from ` (pairwise narrowing, multi-char keyword
140
+ // checked last); at depth > 0 the ` from ` candidate is dropped (a nested FROM
141
+ // is not the boundary). Quote spans are jumped quote-to-quote (the other quote
142
+ // kind inside a span is data, preserving the old InString/InDString
143
+ // suppression; an unterminated quote swallows the rest, as the old
144
+ // walk-to-EOF did).
145
+ //
146
+ // CHUNKED worker/driver (mirrors `SplitTopLevel`): each jump costs ~4-5
147
+ // conditional evaluations through the EbftJump* helper chain, so a single
148
+ // recursion chain crosses TS's 1000 tail-count budget at ~200+ jumps — a
149
+ // 50-projection SELECT list of quoted/parenthesised expressions gets there
150
+ // (TS2589). The worker yields its state every 120 jumps and the driver
151
+ // re-invokes it with a fresh step counter, so arbitrarily long select lists
152
+ // complete losslessly. (The pre-chunking version bailed to a lenient
153
+ // `ExtractBefore<S, " from ">` at a 350-jump cap — and blew TS2589 before
154
+ // ever reaching it on exactly the queries the cap was meant to protect.)
155
+ export type ExtractBeforeFromTopLevel<S extends string> =
156
+ EbftDrive<EbftWorker<S>>;
157
+
158
+ type EbftDrive<R> =
159
+ [R] extends [never]
160
+ ? never
161
+ : R extends { __c: [infer S extends string, infer Depth extends any[], infer Acc extends string] }
162
+ ? EbftDrive<EbftWorker<S, Depth, Acc, []>>
163
+ : R;
164
+
165
+ type EbftWorker<
77
166
  S extends string,
78
167
  Depth extends any[] = [],
79
- InString extends boolean = false,
80
168
  Acc extends string = "",
81
- Steps extends any[] = [],
82
- InDString extends boolean = false
83
- > = Steps["length"] extends 350
84
- ? `${Acc}${ExtractBefore<S, " from ">}`
85
- : InString extends true
86
- ? S extends `${infer C}${infer Rest}`
87
- ? C extends "'"
88
- ? ExtractBeforeFromTopLevel<Rest, Depth, false, `${Acc}${C}`, [any, ...Steps], InDString>
89
- : ExtractBeforeFromTopLevel<Rest, Depth, InString, `${Acc}${C}`, [any, ...Steps], InDString>
90
- : Acc
91
- : InDString extends true
92
- ? S extends `${infer C}${infer Rest}`
93
- ? C extends `"`
94
- ? ExtractBeforeFromTopLevel<Rest, Depth, InString, `${Acc}${C}`, [any, ...Steps], false>
95
- : ExtractBeforeFromTopLevel<Rest, Depth, InString, `${Acc}${C}`, [any, ...Steps], true>
96
- : Acc
97
- : Depth["length"] extends 0
98
- ? S extends ` from ${string}`
99
- ? Acc
100
- : S extends `${infer C}${infer Rest}`
101
- ? C extends "'"
102
- ? ExtractBeforeFromTopLevel<Rest, Depth, true, `${Acc}${C}`, [any, ...Steps], InDString>
103
- : C extends `"`
104
- ? ExtractBeforeFromTopLevel<Rest, Depth, InString, `${Acc}${C}`, [any, ...Steps], true>
105
- : C extends "("
106
- ? ExtractBeforeFromTopLevel<Rest, [any, ...Depth], InString, `${Acc}${C}`, [any, ...Steps], InDString>
107
- : C extends ")"
108
- ? ExtractBeforeFromTopLevel<Rest, Depth extends [any, ...infer D] ? D : [], InString, `${Acc}${C}`, [any, ...Steps], InDString>
109
- : ExtractBeforeFromTopLevel<Rest, Depth, InString, `${Acc}${C}`, [any, ...Steps], InDString>
110
- : Acc
111
- : S extends `${infer C}${infer Rest}`
112
- ? C extends "'"
113
- ? ExtractBeforeFromTopLevel<Rest, Depth, true, `${Acc}${C}`, [any, ...Steps], InDString>
114
- : C extends `"`
115
- ? ExtractBeforeFromTopLevel<Rest, Depth, InString, `${Acc}${C}`, [any, ...Steps], true>
116
- : C extends "("
117
- ? ExtractBeforeFromTopLevel<Rest, [any, ...Depth], InString, `${Acc}${C}`, [any, ...Steps], InDString>
118
- : C extends ")"
119
- ? ExtractBeforeFromTopLevel<Rest, Depth extends [any, ...infer D] ? D : [], InString, `${Acc}${C}`, [any, ...Steps], InDString>
120
- : ExtractBeforeFromTopLevel<Rest, Depth, InString, `${Acc}${C}`, [any, ...Steps], InDString>
121
- : Acc;
169
+ Steps extends any[] = []
170
+ > = Steps["length"] extends 120
171
+ ? { __c: [S, Depth, Acc] }
172
+ : Depth["length"] extends 0
173
+ ? EbftJumpTop<S, Depth, Acc, Steps>
174
+ : EbftJumpNested<S, Depth, Acc, Steps>;
175
+
176
+ // inside `'…'`: resume after the closing quote (any depth; quotes ignore depth)
177
+ type EbftQuoteClose<
178
+ R extends string,
179
+ Depth extends any[],
180
+ Acc extends string,
181
+ Steps extends any[]
182
+ > = R extends `${infer Span}'${infer R2}`
183
+ ? EbftWorker<R2, Depth, `${Acc}${Span}'`, [any, ...Steps]>
184
+ : `${Acc}${R}`;
185
+
186
+ type EbftDQuoteClose<
187
+ R extends string,
188
+ Depth extends any[],
189
+ Acc extends string,
190
+ Steps extends any[]
191
+ > = R extends `${infer Span}"${infer R2}`
192
+ ? EbftWorker<R2, Depth, `${Acc}${Span}"`, [any, ...Steps]>
193
+ : `${Acc}${R}`;
194
+
195
+ type EbftJumpTop<
196
+ S extends string,
197
+ Depth extends any[],
198
+ Acc extends string,
199
+ Steps extends any[]
200
+ > = S extends `${infer P}'${infer R}`
201
+ ? P extends `${string}"${string}` | `${string}(${string}` | `${string})${string}` | `${string} from ${string}`
202
+ ? EbftJumpTop2<S, Depth, Acc, Steps>
203
+ : EbftQuoteClose<R, Depth, `${Acc}${P}'`, Steps>
204
+ : EbftJumpTop2<S, Depth, Acc, Steps>;
205
+
206
+ type EbftJumpTop2<
207
+ S extends string,
208
+ Depth extends any[],
209
+ Acc extends string,
210
+ Steps extends any[]
211
+ > = S extends `${infer P}"${infer R}`
212
+ ? P extends `${string}(${string}` | `${string})${string}` | `${string} from ${string}`
213
+ ? EbftJumpTop3<S, Depth, Acc, Steps>
214
+ : EbftDQuoteClose<R, Depth, `${Acc}${P}"`, Steps>
215
+ : EbftJumpTop3<S, Depth, Acc, Steps>;
216
+
217
+ type EbftJumpTop3<
218
+ S extends string,
219
+ Depth extends any[],
220
+ Acc extends string,
221
+ Steps extends any[]
222
+ > = S extends `${infer P}(${infer R}`
223
+ ? P extends `${string})${string}` | `${string} from ${string}`
224
+ ? EbftJumpTop4<S, Depth, Acc, Steps>
225
+ : EbftWorker<R, [any, ...Depth], `${Acc}${P}(`, [any, ...Steps]>
226
+ : EbftJumpTop4<S, Depth, Acc, Steps>;
227
+
228
+ type EbftJumpTop4<
229
+ S extends string,
230
+ Depth extends any[],
231
+ Acc extends string,
232
+ Steps extends any[]
233
+ > = S extends `${infer P})${infer R}`
234
+ ? P extends `${string} from ${string}`
235
+ ? EbftJumpTop5<S, Acc>
236
+ // an unmatched `)` at depth 0 stays at depth 0 (pop of empty = empty)
237
+ : EbftWorker<R, [], `${Acc}${P})`, [any, ...Steps]>
238
+ : EbftJumpTop5<S, Acc>;
239
+
240
+ type EbftJumpTop5<S extends string, Acc extends string> =
241
+ S extends `${infer P} from ${string}`
242
+ ? `${Acc}${P}`
243
+ : `${Acc}${S}`;
244
+
245
+ type EbftJumpNested<
246
+ S extends string,
247
+ Depth extends any[],
248
+ Acc extends string,
249
+ Steps extends any[]
250
+ > = S extends `${infer P}'${infer R}`
251
+ ? P extends `${string}"${string}` | `${string}(${string}` | `${string})${string}`
252
+ ? EbftJumpNested2<S, Depth, Acc, Steps>
253
+ : EbftQuoteClose<R, Depth, `${Acc}${P}'`, Steps>
254
+ : EbftJumpNested2<S, Depth, Acc, Steps>;
255
+
256
+ type EbftJumpNested2<
257
+ S extends string,
258
+ Depth extends any[],
259
+ Acc extends string,
260
+ Steps extends any[]
261
+ > = S extends `${infer P}"${infer R}`
262
+ ? P extends `${string}(${string}` | `${string})${string}`
263
+ ? EbftJumpNested3<S, Depth, Acc, Steps>
264
+ : EbftDQuoteClose<R, Depth, `${Acc}${P}"`, Steps>
265
+ : EbftJumpNested3<S, Depth, Acc, Steps>;
266
+
267
+ type EbftJumpNested3<
268
+ S extends string,
269
+ Depth extends any[],
270
+ Acc extends string,
271
+ Steps extends any[]
272
+ > = S extends `${infer P}(${infer R}`
273
+ ? P extends `${string})${string}`
274
+ ? EbftJumpNested4<S, Depth, Acc, Steps>
275
+ : EbftWorker<R, [any, ...Depth], `${Acc}${P}(`, [any, ...Steps]>
276
+ : EbftJumpNested4<S, Depth, Acc, Steps>;
277
+
278
+ type EbftJumpNested4<
279
+ S extends string,
280
+ Depth extends any[],
281
+ Acc extends string,
282
+ Steps extends any[]
283
+ > = S extends `${infer P})${infer R}`
284
+ ? EbftWorker<R, Depth extends [any, ...infer D] ? D : [], `${Acc}${P})`, [any, ...Steps]>
285
+ : `${Acc}${S}`;
122
286
 
123
287
  // Simple comma split (no paren awareness)
124
288
 
@@ -69,6 +69,7 @@ export type HasSpecial<S extends string> =
69
69
  S extends `${string}-${string}` ? true :
70
70
  S extends `${string}*${string}` ? true :
71
71
  S extends `${string}/${string}` ? true :
72
+ S extends `${string}%${string}` ? true :
72
73
  S extends `${string}=${string}` ? true :
73
74
  S extends `${string}<${string}` ? true :
74
75
  S extends `${string}>${string}` ? true :
@@ -136,17 +137,21 @@ export type SplitLast<S extends string, Delim extends string> =
136
137
  : [Head, Tail]
137
138
  : [S, ""];
138
139
 
139
- export type SplitOnDot<S extends string> =
140
- S extends `${infer A}.${infer B}` ? [A, ...SplitOnDot<B>] : [S];
141
-
140
+ // Direct template-match split of a (≤3-part) dotted ref into cleaned segments.
141
+ // Replaces the old recursive `SplitOnDot` array build (its `[S]` base case and
142
+ // `[A, ...rest]` prepend minted tuples per qualified ref, and the 1/2/3-arm
143
+ // dispatch re-matched the built array three times). `${infer A}.${infer R}`
144
+ // binds the LEFTMOST dot, so A is the first segment exactly as before; a 4th
145
+ // segment (a dot remaining after the third split) yields `[]`, matching the old
146
+ // "no arm matches a 4+-tuple" fall-through.
142
147
  export type SplitOnDotClean<S extends string> =
143
- SplitOnDot<S> extends [infer A extends string, infer B extends string, infer C extends string]
144
- ? [CleanIdent<A>, CleanIdent<B>, CleanIdent<C>]
145
- : SplitOnDot<S> extends [infer A extends string, infer B extends string]
146
- ? [CleanIdent<A>, CleanIdent<B>]
147
- : SplitOnDot<S> extends [infer A extends string]
148
- ? [CleanIdent<A>]
149
- : [];
148
+ S extends `${infer A}.${infer R}`
149
+ ? R extends `${infer B}.${infer R2}`
150
+ ? R2 extends `${string}.${string}`
151
+ ? []
152
+ : [CleanIdent<A>, CleanIdent<B>, CleanIdent<R2>]
153
+ : [CleanIdent<A>, CleanIdent<R>]
154
+ : [CleanIdent<S>];
150
155
 
151
156
  export type MapClean<Tokens extends string[], Acc extends string[] = []> =
152
157
  Tokens extends [infer H extends string, ...infer R extends string[]]
@@ -154,11 +159,6 @@ export type MapClean<Tokens extends string[], Acc extends string[] = []> =
154
159
  : Acc;
155
160
 
156
161
 
157
- export type MapCleanLoose<Tokens extends string[], Acc extends string[] = []> =
158
- Tokens extends [infer H extends string, ...infer R extends string[]]
159
- ? MapCleanLoose<R, [...Acc, CleanLooseToken<H>]>
160
- : Acc;
161
-
162
162
  export type CleanLooseToken<S extends string> =
163
163
  S extends OperatorToken
164
164
  ? S