@rbxts/types 1.0.948 → 1.0.949
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/include/selector.d.ts +195 -106
- package/package.json +1 -1
package/include/selector.d.ts
CHANGED
|
@@ -10,143 +10,232 @@
|
|
|
10
10
|
* `Instance`; attribute filters and pseudo-classes never change the class. Note that
|
|
11
11
|
* whitespace is not a combinator in this grammar (descendant matching is `>>`), so spaces
|
|
12
12
|
* are ignored rather than treated as separators.
|
|
13
|
+
*
|
|
14
|
+
* Dynamic templates and selectors exceeding the bounded analysis budget fall back to
|
|
15
|
+
* `Instance`. Validation checks unsupported pseudo-classes and empty list entries; it
|
|
16
|
+
* is not a complete runtime grammar check.
|
|
13
17
|
*/
|
|
14
18
|
declare namespace Selector {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
type
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
type ReadHead<
|
|
30
|
-
Head extends string | undefined = undefined,
|
|
31
|
-
Done extends boolean = false,
|
|
32
|
-
C extends string = "",
|
|
33
|
-
> = Done extends true
|
|
34
|
-
? [Head, Done]
|
|
35
|
-
: Head extends undefined
|
|
36
|
-
? Trim<C> extends ""
|
|
37
|
-
? [undefined, false]
|
|
38
|
-
: C extends HeadBreak
|
|
39
|
-
? ["", true]
|
|
40
|
-
: [C, false]
|
|
41
|
-
: C extends HeadBreak
|
|
42
|
-
? [Head, true]
|
|
43
|
-
: [`${Head}${C}`, false];
|
|
44
|
-
|
|
45
|
-
type SolveChars<
|
|
46
|
-
S extends string,
|
|
47
|
-
Head extends string | undefined = undefined,
|
|
48
|
-
Done extends boolean = false,
|
|
49
|
-
Result = never,
|
|
50
|
-
Depth extends Array<any> = [],
|
|
51
|
-
> = S extends `${infer C}${infer Rest}`
|
|
52
|
-
? Depth extends []
|
|
53
|
-
? C extends "("
|
|
54
|
-
? SolveChars<Rest, Head, Done, Result, [any]>
|
|
55
|
-
: C extends ","
|
|
56
|
-
? SolveChars<Rest, undefined, false, AddSolvedHead<Result, Head>, Depth>
|
|
57
|
-
: C extends ">"
|
|
58
|
-
? SolveChars<Rest, undefined, false, Result, Depth>
|
|
59
|
-
: ReadHead<Head, Done, C> extends [
|
|
60
|
-
infer NextHead extends string | undefined,
|
|
61
|
-
infer NextDone extends boolean,
|
|
62
|
-
]
|
|
63
|
-
? SolveChars<Rest, NextHead, NextDone, Result, Depth>
|
|
64
|
-
: never
|
|
65
|
-
: C extends "("
|
|
66
|
-
? SolveChars<Rest, Head, Done, Result, [...Depth, any]>
|
|
67
|
-
: C extends ")"
|
|
68
|
-
? SolveChars<Rest, Head, Done, Result, Depth extends [any, ...infer D] ? D : []>
|
|
69
|
-
: SolveChars<Rest, Head, Done, Result, Depth>
|
|
70
|
-
: AddSolvedHead<Result, Head>;
|
|
71
|
-
|
|
72
|
-
// Nested pseudo-classes can contain selector lists, so this path tracks only top-level
|
|
73
|
-
// separators while keeping the subject class from the current segment.
|
|
74
|
-
type SlowSolve<T extends string> = SolveChars<T>;
|
|
19
|
+
// Bounds are deliberately below TypeScript's recursion limit. A broad string means
|
|
20
|
+
// analysis stopped; callers must preserve it as an Instance fallback, never a partial type.
|
|
21
|
+
type OtherWhitespace = "\t" | "\n" | "\r" | "\f" | "\v";
|
|
22
|
+
type Trim<T extends string, Steps extends Array<unknown> = []> = Steps["length"] extends 128
|
|
23
|
+
? string
|
|
24
|
+
: T extends `${infer S} `
|
|
25
|
+
? Trim<S, [...Steps, unknown]>
|
|
26
|
+
: T extends ` ${infer S}`
|
|
27
|
+
? Trim<S, [...Steps, unknown]>
|
|
28
|
+
: T;
|
|
29
|
+
|
|
30
|
+
// Infinite template-literal key sets (including `${number}`) have no required keys.
|
|
31
|
+
// Unlike `string extends S`, this also detects selectors such as `Part.${string}`.
|
|
32
|
+
type IsDynamic<S extends string> = Record<never, never> extends Record<S, unknown> ? true : false;
|
|
75
33
|
|
|
76
34
|
// Only the final combinator segment can determine the subject type.
|
|
77
|
-
type LastSegment<S extends string
|
|
35
|
+
type LastSegment<S extends string, Steps extends Array<unknown> = []> = Steps["length"] extends 128
|
|
36
|
+
? string
|
|
37
|
+
: S extends `${string}>${infer R}`
|
|
38
|
+
? LastSegment<R, [...Steps, unknown]>
|
|
39
|
+
: S;
|
|
78
40
|
|
|
79
41
|
type CutAt<S extends string, D extends string> = S extends `${infer Prefix}${D}${string}` ? Prefix : S;
|
|
80
42
|
|
|
81
43
|
type LeadingClass<S extends string> = CutAt<CutAt<CutAt<CutAt<Trim<S>, ":">, ".">, "#">, " ">;
|
|
82
44
|
|
|
83
|
-
//
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
?
|
|
88
|
-
:
|
|
89
|
-
|
|
90
|
-
type FastClause<S extends string> =
|
|
91
|
-
LeadingClass<LastSegment<S>> extends infer C extends keyof Instances ? Instances[C] : Instance;
|
|
45
|
+
// Consume a quoted value without interpreting the other quote character as syntax.
|
|
46
|
+
// Values without backslashes use a single template match, regardless of their length.
|
|
47
|
+
type QuotedRest<S extends string, Quote extends "'" | '"'> = S extends `${infer A}${Quote}${infer B}`
|
|
48
|
+
? A extends `${string}\\${string}`
|
|
49
|
+
? EscapedQuotedRest<S, Quote>
|
|
50
|
+
: B
|
|
51
|
+
: string;
|
|
92
52
|
|
|
93
|
-
type
|
|
53
|
+
type EscapedQuotedRest<
|
|
54
|
+
S extends string,
|
|
55
|
+
Quote extends string,
|
|
56
|
+
Steps extends Array<unknown> = [],
|
|
57
|
+
> = Steps["length"] extends 256
|
|
58
|
+
? string
|
|
59
|
+
: S extends `\\${string}${infer Rest}`
|
|
60
|
+
? EscapedQuotedRest<Rest, Quote, [...Steps, unknown]>
|
|
61
|
+
: S extends `${Quote}${infer Rest}`
|
|
62
|
+
? Rest
|
|
63
|
+
: S extends `${string}${infer Rest}`
|
|
64
|
+
? EscapedQuotedRest<Rest, Quote, [...Steps, unknown]>
|
|
65
|
+
: string;
|
|
66
|
+
|
|
67
|
+
type StripQuote<
|
|
68
|
+
S extends string,
|
|
69
|
+
Quote extends "'" | '"',
|
|
70
|
+
Out extends string,
|
|
71
|
+
Steps extends Array<unknown>,
|
|
72
|
+
> = S extends `${infer A}${Quote}${infer B}`
|
|
73
|
+
? QuotedRest<B, Quote> extends infer Rest extends string
|
|
74
|
+
? string extends Rest
|
|
75
|
+
? string
|
|
76
|
+
: StripQuotes<Rest, `${Out}${A}`, [...Steps, unknown]>
|
|
77
|
+
: never
|
|
78
|
+
: `${Out}${S}`;
|
|
94
79
|
|
|
95
|
-
type
|
|
96
|
-
|
|
97
|
-
|
|
80
|
+
type StripQuotes<
|
|
81
|
+
S extends string,
|
|
82
|
+
Out extends string = "",
|
|
83
|
+
Steps extends Array<unknown> = [],
|
|
84
|
+
> = Steps["length"] extends 128
|
|
85
|
+
? string
|
|
86
|
+
: S extends `${infer A}'${string}`
|
|
87
|
+
? A extends `${string}"${string}`
|
|
88
|
+
? StripQuote<S, '"', Out, Steps>
|
|
89
|
+
: StripQuote<S, "'", Out, Steps>
|
|
90
|
+
: S extends `${string}"${string}`
|
|
91
|
+
? StripQuote<S, '"', Out, Steps>
|
|
92
|
+
: `${Out}${S}`;
|
|
93
|
+
|
|
94
|
+
// Quoted delimiters must be removed before filters or pseudo-class groups are read.
|
|
95
|
+
// Sharing this normalization between validation and inference also lets the checker cache it.
|
|
96
|
+
// A dot is an opaque filter marker: it preserves a nonempty selector inside :not([$x]).
|
|
97
|
+
type StripFilters<S extends string, Steps extends Array<unknown> = []> = Steps["length"] extends 128
|
|
98
|
+
? string
|
|
99
|
+
: S extends `${infer A}[${string}]${infer B}`
|
|
100
|
+
? StripFilters<`${A}.${B}`, [...Steps, unknown]>
|
|
101
|
+
: S;
|
|
102
|
+
type ReplaceWhitespace<
|
|
103
|
+
S extends string,
|
|
104
|
+
W extends string,
|
|
105
|
+
Steps extends Array<unknown> = [],
|
|
106
|
+
> = Steps["length"] extends 128
|
|
107
|
+
? string
|
|
108
|
+
: S extends `${infer A}${W}${infer B}`
|
|
109
|
+
? ReplaceWhitespace<`${A} ${B}`, W, [...Steps, unknown]>
|
|
110
|
+
: S;
|
|
111
|
+
type NormalizeWhitespace<S extends string> = S extends `${string}${OtherWhitespace}${string}`
|
|
112
|
+
? ReplaceWhitespace<
|
|
113
|
+
ReplaceWhitespace<ReplaceWhitespace<ReplaceWhitespace<ReplaceWhitespace<S, "\t">, "\n">, "\r">, "\f">,
|
|
114
|
+
"\v"
|
|
115
|
+
>
|
|
116
|
+
: S;
|
|
117
|
+
type Normalize<S extends string> = NormalizeWhitespace<StripFilters<StripQuotes<S>>>;
|
|
118
|
+
|
|
119
|
+
// Jump between parentheses rather than visiting every character. Quoted values and
|
|
120
|
+
// filters are already opaque, so only these delimiters affect nesting.
|
|
121
|
+
type StripClose<
|
|
122
|
+
S extends string,
|
|
123
|
+
Out extends string,
|
|
124
|
+
Depth extends Array<unknown>,
|
|
125
|
+
Steps extends Array<unknown>,
|
|
126
|
+
> = S extends `${string})${infer Rest}`
|
|
127
|
+
? Depth extends [unknown, ...infer D]
|
|
128
|
+
? StripParens<Rest, Out, D, [...Steps, unknown]>
|
|
129
|
+
: string
|
|
130
|
+
: string;
|
|
131
|
+
|
|
132
|
+
type StripParens<
|
|
133
|
+
S extends string,
|
|
134
|
+
Out extends string = "",
|
|
135
|
+
Depth extends Array<unknown> = [],
|
|
136
|
+
Steps extends Array<unknown> = [],
|
|
137
|
+
> = Steps["length"] extends 128
|
|
138
|
+
? string
|
|
139
|
+
: S extends `${infer A}(${infer B}`
|
|
140
|
+
? A extends `${string})${string}`
|
|
141
|
+
? StripClose<S, Out, Depth, Steps>
|
|
142
|
+
: StripParens<B, Depth extends [] ? `${Out}${A}` : Out, [...Depth, unknown], [...Steps, unknown]>
|
|
143
|
+
: S extends `${string})${string}`
|
|
144
|
+
? StripClose<S, Out, Depth, Steps>
|
|
145
|
+
: Depth extends []
|
|
146
|
+
? `${Out}${S}`
|
|
147
|
+
: string;
|
|
148
|
+
|
|
149
|
+
type FastClause<S extends string> = S extends keyof Instances
|
|
150
|
+
? Instances[S]
|
|
151
|
+
: LeadingClass<LastSegment<S>> extends infer C extends keyof Instances
|
|
152
|
+
? Instances[C]
|
|
153
|
+
: Instance;
|
|
98
154
|
|
|
99
|
-
|
|
155
|
+
// Accumulate the union so long lists remain tail-recursive.
|
|
156
|
+
type FastSolve<S extends string, Result = never, Steps extends Array<unknown> = []> = Steps["length"] extends 128
|
|
157
|
+
? Instance
|
|
158
|
+
: S extends `${infer A},${infer B}`
|
|
159
|
+
? FastSolve<B, Result | FastClause<A>, [...Steps, unknown]>
|
|
160
|
+
: Result | FastClause<S>;
|
|
100
161
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
? StripValidationGroups<`${A}${B}`>
|
|
162
|
+
type StripFlatParens<S extends string, Steps extends Array<unknown> = []> = Steps["length"] extends 128
|
|
163
|
+
? string
|
|
164
|
+
: S extends `${infer A}(${string})${infer B}`
|
|
165
|
+
? StripFlatParens<`${A}${B}`, [...Steps, unknown]>
|
|
106
166
|
: S;
|
|
107
167
|
|
|
168
|
+
type SolveNormalized<S extends string> = string extends S
|
|
169
|
+
? Instance
|
|
170
|
+
: S extends `${string}(${string}`
|
|
171
|
+
? S extends `${string}(${string}(${string})${string})${string}`
|
|
172
|
+
? FastSolve<StripParens<S>>
|
|
173
|
+
: FastSolve<StripFlatParens<S>>
|
|
174
|
+
: S extends `${string},${string}`
|
|
175
|
+
? FastSolve<S>
|
|
176
|
+
: FastClause<S>;
|
|
177
|
+
|
|
108
178
|
type SupportedPseudo = "not" | "has";
|
|
109
179
|
|
|
110
|
-
type CheckPseudos<S extends string> =
|
|
111
|
-
?
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
180
|
+
type CheckPseudos<S extends string, Steps extends Array<unknown> = []> = Steps["length"] extends 128
|
|
181
|
+
? never
|
|
182
|
+
: S extends `${string}:${infer R}`
|
|
183
|
+
? R extends `${infer Name}(${infer Rest}`
|
|
184
|
+
? Name extends SupportedPseudo
|
|
185
|
+
? CheckPseudos<Rest, [...Steps, unknown]>
|
|
186
|
+
: Name
|
|
187
|
+
: R // ':' not followed by 'name(' -> pseudo-classes require arguments
|
|
188
|
+
: never;
|
|
189
|
+
|
|
190
|
+
// Parentheses delimit nested lists just as commas delimit their entries.
|
|
191
|
+
type HasEmptyGroup<S extends string, Steps extends Array<unknown> = []> = Steps["length"] extends 128
|
|
192
|
+
? false
|
|
193
|
+
: S extends `${string}(${infer Rest}`
|
|
194
|
+
? Trim<Rest> extends `)${string}` | `,${string}`
|
|
195
|
+
? true
|
|
196
|
+
: HasEmptyGroup<Rest, [...Steps, unknown]>
|
|
197
|
+
: false;
|
|
117
198
|
|
|
118
199
|
// The whole-empty selector "" is intentionally allowed.
|
|
119
200
|
type HasEmptyListItem<S extends string> = S extends `${string},${string}` ? CheckListItems<S> : false;
|
|
120
|
-
type CheckListItems<S extends string> =
|
|
121
|
-
?
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
:
|
|
201
|
+
type CheckListItems<S extends string, Steps extends Array<unknown> = []> = Steps["length"] extends 128
|
|
202
|
+
? false
|
|
203
|
+
: S extends `${infer A},${infer B}`
|
|
204
|
+
? Trim<A> extends "" | `${string}(` | `)${string}`
|
|
205
|
+
? true
|
|
206
|
+
: CheckListItems<B, [...Steps, unknown]>
|
|
207
|
+
: Trim<S> extends "" | `)${string}`
|
|
208
|
+
? true
|
|
209
|
+
: false;
|
|
127
210
|
|
|
128
211
|
type ValidateUnquoted<S extends string, Q extends string> = Q extends `${string}:${string}`
|
|
129
212
|
? CheckPseudos<Q> extends infer Bad
|
|
130
213
|
? [Bad] extends [never]
|
|
131
|
-
? HasEmptyListItem<Q>
|
|
214
|
+
? true extends HasEmptyListItem<Q> | HasEmptyGroup<Q>
|
|
132
215
|
? `Invalid selector: empty selector in list (check for a stray or trailing comma)`
|
|
133
216
|
: S
|
|
134
217
|
: `Invalid selector: ':${Bad & string}' is not a supported pseudo-class (only ':not()' and ':has()' are allowed)`
|
|
135
218
|
: never
|
|
136
219
|
: Q extends `${string},${string}`
|
|
137
|
-
? HasEmptyListItem<Q>
|
|
220
|
+
? true extends HasEmptyListItem<Q> | HasEmptyGroup<Q>
|
|
138
221
|
? `Invalid selector: empty selector in list (check for a stray or trailing comma)`
|
|
139
222
|
: S
|
|
140
223
|
: S;
|
|
141
224
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
?
|
|
146
|
-
:
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
:
|
|
225
|
+
// Distribute over the original selector so each normalized branch retains its own input.
|
|
226
|
+
export type ValidateSelector<S extends string> = S extends `${string}${":" | ","}${string}`
|
|
227
|
+
? IsDynamic<S> extends true
|
|
228
|
+
? S
|
|
229
|
+
: Normalize<S> extends infer Q extends string
|
|
230
|
+
? string extends Q
|
|
231
|
+
? S
|
|
232
|
+
: ValidateUnquoted<S, Q>
|
|
233
|
+
: never
|
|
234
|
+
: S;
|
|
235
|
+
|
|
236
|
+
export type Solve<S extends string> = S extends keyof Instances
|
|
237
|
+
? Instances[S]
|
|
238
|
+
: IsDynamic<S> extends true
|
|
239
|
+
? Instance
|
|
240
|
+
: SolveNormalized<Normalize<S>>;
|
|
152
241
|
}
|