Skip to content

Commit 0e51a72

Browse files
authored
Feature: allow type-only processing of capture groups (#18)
* Feature: allow type-only processing of capture groups Having a type-safe function is amazing and all, but sometimes all you need is just the types. * Update ParseCaptures: do not include the root string token into the resulting tuple * Refactor ParseCaptures: simplify for maintainability Add ParseNamedCaptures for parity Add Tails to expoted types to address the common use-case of omitting the input string from captures
1 parent 2395170 commit 0e51a72

File tree

1 file changed

+43
-6
lines changed

1 file changed

+43
-6
lines changed

src/index.ts

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,17 @@
11
// Utils
22
// Compensation
33
type As<T, _Infer extends T> = unknown;
4-
type Head<T extends unknown[]> = T[0];
5-
type Tail<T extends unknown[]> = T extends [infer _, ...infer Rest]
4+
export type Head<T extends unknown[]> = T[0];
5+
/**
6+
* Grab the tail of a list (all elements except the first)
7+
*
8+
* @example
9+
* ```ts
10+
* // Will omit the 0-th capture, leaving only the capture groups
11+
* type Captures = Tail<ParseCaptures<MyRegex>>;
12+
* ```
13+
*/
14+
export type Tail<T extends unknown[]> = T extends [infer _, ...infer Rest]
615
? Rest
716
: never
817
;
@@ -273,7 +282,7 @@ type IndexTokenInternal<TToken extends Token, TIndex extends number> = TToken ex
273282
left: IndexTokenInternal<TToken['left'], TIndex>,
274283
right: IndexTokenInternal<TToken['right'], Add<
275284
TIndex,
276-
FlattenToken<TToken['left']>['length']
285+
FlattenToken<TToken['left']>['length']
277286
& number
278287
>>
279288
} : TToken extends { type: 'groups' } ? {
@@ -283,7 +292,7 @@ type IndexTokenInternal<TToken extends Token, TIndex extends number> = TToken ex
283292
;
284293
type IndexToken<TToken extends Token> = IndexTokenInternal<TToken, 0>;
285294
// TokenWithIndex type
286-
type TokenWithIndex = IsSatisfied<{type: string},
295+
type TokenWithIndex = IsSatisfied<{type: string},
287296
{
288297
type: 'alternation',
289298
left: TokenWithIndex,
@@ -374,7 +383,10 @@ type Distribute<T extends Record<
374383
: never
375384
;
376385

377-
type Parse<T extends string> = string extends T
386+
/**
387+
* Parse the capture groups from a regex-like string literal type
388+
*/
389+
export type Parse<T extends string> = string extends T
378390
? {
379391
captures: [string, ...(string | undefined)[]],
380392
namedCaptures: Record<string, string | undefined>;
@@ -391,6 +403,30 @@ type Parse<T extends string> = string extends T
391403
}>>>
392404
;
393405

406+
/**
407+
* Get the list of indexed captures from a regex-like string literal type
408+
*
409+
* @example
410+
* ```ts
411+
* // Will get all non-named captures, including the string itself at index 0
412+
* type AllCaptures = ParseCaptures<MyRegex>;
413+
*
414+
* // Will omit the 0-th capture, leaving only the capture groups
415+
* type OnlyGroups = Tail<ParseCaptures<MyRegex>>;
416+
* ```
417+
*/
418+
export type ParseCaptures<T extends string> = Parse<T>['captures'];
419+
420+
/**
421+
* Get the dictionary of named captures from a regex-like string literal type
422+
*
423+
* @example
424+
* ```ts
425+
* type AllNamedCaptures = ParseNamedCaptures<MyRegex>;
426+
* ```
427+
*/
428+
export type ParseNamedCaptures<T extends string> = Parse<T>['namedCaptures'];
429+
394430
type Remove<Ts extends unknown[], TMatch extends Ts[number]> = unknown extends AsLinked<Ts, infer First, infer Rest>
395431
? TMatch extends First
396432
? Rest
@@ -594,4 +630,5 @@ export const typedRegExp = <
594630
& (GlobalFalseIndicesBehavior<false> | GlobalFalseIndicesBehavior<true>)
595631
)
596632
) & (IndicesBehavior<false> | IndicesBehavior<true>)>;
597-
};
633+
634+
};

0 commit comments

Comments
 (0)