type As = unknown; type Head = T[0]; /** * Grab the tail of a list (all elements except the first) * * @example * ```ts * // Will omit the 0-th capture, leaving only the capture groups * type Captures = Tail>; * ``` */ type Tail = T extends [infer _, ...infer Rest] ? Rest : never; type AsLinked, InferRest extends Tail> = InferRest extends unknown[] ? unknown : never; type RangeInternal = TArr['length'] extends T ? TArr : RangeInternal; type Range = RangeInternal; type Increment = [...Range, unknown]['length'] & number; type Decrement = Range extends [unknown, ...infer Rest] ? Rest['length'] : never; type Add = T2 extends 0 ? T : Increment>>; type Prettify = { [K in keyof T]: T[K]; } & {}; type ToTupleInternal, Index extends number> = keyof TRecord extends never ? [] : [ ...(Index extends keyof TRecord ? [TRecord[Index]] : []), ...ToTupleInternal, Increment> ]; type ToTuple> = ToTupleInternal; type IsSatisfied = TCandidate; type Is = T extends true ? TIf : TElse; type CharOfInternal = T extends `${infer First}${infer Rest}` ? First | CharOfInternal : never; type CharOf = string extends T ? string : CharOfInternal; type FirstMatch = TSource extends `${infer First}${infer Rest}` ? First extends T ? First : FirstMatch : never; type ToNattyNumber = T extends `0${infer Rest extends `${number}`}` ? ToNattyNumber : T extends `-${string}` | `${string}.${string}` ? never : T extends `${infer N extends number}` ? number extends N ? never : N : never; type Fallback = [T] extends [never] ? TFall : T; type Exists = T extends never ? never : unknown; type AsSkippedEscape = Exists; type AsSkippedCharacterClass ? Remainder : T extends `[${infer Rest}` ? ResolveCharacterClass : never> = Exists; type AsSkippedGroup ? Remainder : T extends `(${infer Rest}` ? ResolveGroup : never> = Exists; type ResolveCharacterClass = T extends `${infer First}${infer Rest}` ? unknown extends AsSkippedEscape ? ResolveCharacterClass : First extends ']' ? Rest : ResolveCharacterClass : never; type ResolveGroup = T extends `${infer First}${infer Rest}` ? unknown extends AsSkippedGroup ? ResolveGroup : First extends ')' ? Rest : ResolveGroup : never; type ResolveAlternation = T extends `${infer First}${infer Rest}` ? unknown extends AsSkippedGroup ? ResolveAlternation : First extends '|' ? Rest : ResolveAlternation : never; type InferMin = T extends `${infer Min},${infer Max}` ? Max extends '' ? ToNattyNumber : ToNattyNumber extends never ? never : ToNattyNumber : ToNattyNumber; type GroupPatterns = T extends `?<${infer Name}>${infer TheRest}` ? { value: { isCaptured: true; isNamed: true; name: Name; }; rest: TheRest; } : T extends `?${':' | `${'<' | ''}${'=' | '!'}`}${infer TheRest}` ? { value: { isCaptured: false; }; rest: TheRest; } : { value: { isCaptured: true; isNamed: false; }; rest: T; }; type GroupsTree = T extends `${string}${infer Rest}` ? unknown extends AsSkippedCharacterClass ? GroupsTree : unknown extends As, infer Tail> ? T extends `(${infer Content})${Tail}` ? [ GroupPatterns['value'] & { isOptional: Tail extends `${'?' | '*'}${string}` ? true : Tail extends `{${infer ModRange}}${string}` ? 0 extends InferMin ? true : false : false; inner: TokenTree['rest']>; }, ...GroupsTree ] : GroupsTree : never : []; type TokenTree = unknown extends As, infer Right> ? T extends `${infer Left}|${Right}` ? { type: 'alternation'; left: TokenTree; right: TokenTree; } : { type: 'groups'; groups: GroupsTree; } : never; type Token = IsSatisfied<{ type: string; }, { type: 'alternation'; left: Token; right: Token; } | { type: 'groups'; groups: ({ isOptional: boolean; inner: Token; } & IsSatisfied<{ isCaptured: boolean; }, { isCaptured: false; } | ({ isCaptured: true; } & IsSatisfied<{ isNamed: boolean; }, { isNamed: false; } | { isNamed: true; name: string; }>)>)[]; }>; type Groups = (Token & { type: 'groups'; })['groups']; type FlattenGroups = unknown extends AsLinked ? [ First, ...FlattenToken, ...FlattenGroups ] : []; type FlattenTokenInternal = Limit extends [unknown, ...infer L] ? TToken extends { type: 'alternation'; } ? [ ...FlattenTokenInternal, ...FlattenTokenInternal ] : TToken extends { type: 'groups'; } ? FlattenGroups : never : never; type FlattenToken = FlattenTokenInternal>; type IndexGroups = unknown extends AsLinked ? [ { index: TIndex; value: Omit & { inner: IndexTokenInternal>; }; }, ...IndexGroups['length'] & number>> ] : []; type IndexTokenInternal = TToken extends { type: 'alternation'; } ? { type: 'alternation'; left: IndexTokenInternal; right: IndexTokenInternal['length'] & number>>; } : TToken extends { type: 'groups'; } ? { type: 'groups'; groups: IndexGroups; } : never; type IndexToken = IndexTokenInternal; type TokenWithIndex = IsSatisfied<{ type: string; }, { type: 'alternation'; left: TokenWithIndex; right: TokenWithIndex; } | { type: 'groups'; groups: { index: number; value: { isOptional: boolean; inner: TokenWithIndex; } & IsSatisfied<{ isCaptured: boolean; }, { isCaptured: false; } | ({ isCaptured: true; } & IsSatisfied<{ isNamed: boolean; }, { isNamed: false; } | { isNamed: true; name: string; }>)>; }[]; }>; type GroupWithIndexes = (TokenWithIndex & { type: 'groups'; })['groups']; type GroupWithIndex = GroupWithIndexes[number]; type ContextualValue = Record; type UnsetGroups = unknown extends AsLinked ? ContextualValue & UnsetToken & UnsetGroups : {}; type UnsetToken = TToken extends { type: 'alternation'; } ? UnsetToken & UnsetToken : TToken extends { type: 'groups'; } ? UnsetGroups : never; type ContextualizeGroups = unknown extends AsLinked ? ((First['value']['isOptional'] extends true ? UnsetGroups<[First]> : never) | (ContextualValue & ContextualizeToken)) & ContextualizeGroups : {}; type ContextualizeToken = TToken extends { type: 'alternation'; } ? ((ContextualizeToken & UnsetToken) | (ContextualizeToken & UnsetToken)) : TToken extends { type: 'groups'; } ? ContextualizeGroups : never; type CaptureValue, K extends keyof T> = Fallback; type Transform> = T extends unknown ? unknown extends As<{ [K in keyof T as T[K]['reference']['isCaptured'] extends false ? never : K]: T[K]; }, infer CaptureRecord> ? { captures: ToTuple<{ [K in keyof CaptureRecord]: CaptureValue; }>; namedCaptures: { [K in keyof CaptureRecord as unknown extends As ? Capture extends { isCaptured: true; isNamed: true; } ? Capture['name'] : never : never]: CaptureValue; }; } : never : never; /** * Parse the capture groups from a regex-like string literal type */ type Parse = string extends T ? { captures: [string, ...(string | undefined)[]]; namedCaptures: Record; } : Transform; } ]; }>>>; /** * Get the list of indexed captures from a regex-like string literal type * * @example * ```ts * // Will get all non-named captures, including the string itself at index 0 * type AllCaptures = ParseCaptures; * * // Will omit the 0-th capture, leaving only the capture groups * type OnlyGroups = Tail>; * ``` */ type ParseCaptures = Parse['captures']; /** * Get the dictionary of named captures from a regex-like string literal type * * @example * ```ts * type AllNamedCaptures = ParseNamedCaptures; * ``` */ type ParseNamedCaptures = Parse['namedCaptures']; type Remove = unknown extends AsLinked ? TMatch extends First ? Rest : [First, ...Remove] : []; type Flags = ['d', 'g', 'i', 'm', 's', 'u' | 'v', 'y']; type Flag = Flags[number]; type GetFlagsInternal = unknown extends AsLinked ? `${Fallback, ''>}${GetFlagsInternal}` : ''; type GetFlags = string extends T ? string : GetFlagsInternal; type AreFlagsValid = TSource extends `${infer First}${infer Rest}` ? First extends TFlags[number] ? AreFlagsValid> : false : true; type ValidatedFlags = AreFlagsValid extends true ? T : never; declare const typedRegExp: (pattern: TPattern, flags?: ValidatedFlags) => Prettify(source: T) => (Is ? true : false : never : never, [Head["captures"]>, ...Head["captures"]>[]], Omit, "groups" | "input"> & Pick<{ groups: keyof Parse["namedCaptures"] extends never ? undefined : Parse["namedCaptures"]; input: T; }, "groups" | "input"> & (Parse["captures"] extends infer T_2 extends Parse["captures"] ? { [K in keyof T_2 as K extends number ? number extends Parse["captures"]["length"] ? K : never : K]: Parse["captures"][K]; } : never)>) | null; replaceIn: { (string: T, replacer: (...p: [match: Head["captures"]>, ...p: Tail["captures"]>, offset: number, string: T, ...keyof Parse["namedCaptures"] extends never ? [] : [groups: Parse["namedCaptures"]]]) => string): string; (string: T, replaceValue: string): string; }; searchIn: (source: string) => number; splitIn: (source: string, limit?: number | undefined) => string[]; exec: (string: T) => (Omit, "groups" | "input"> & Pick<{ groups: keyof Parse["namedCaptures"] extends never ? undefined : Parse["namedCaptures"]; input: T; }, "groups" | "input"> & (Parse["captures"] extends infer T_1 extends Parse["captures"] ? { [K in keyof T_1 as K extends number ? number extends Parse["captures"]["length"] ? K : never : K]: Parse["captures"][K]; } : never)) | null; test: (string: string) => boolean; source: TPattern extends "" ? "(?:)" : TPattern; global: string extends ([TFlags] extends [never] ? "" : TFlags) ? boolean : "g" extends infer T ? T extends "g" ? T extends CharOf<[TFlags] extends [never] ? "" : TFlags> ? true : false : never : never; ignoreCase: string extends ([TFlags] extends [never] ? "" : TFlags) ? boolean : "i" extends infer T_1 ? T_1 extends "i" ? T_1 extends CharOf<[TFlags] extends [never] ? "" : TFlags> ? true : false : never : never; multiline: boolean; lastIndex: number; compile: (pattern: string, flags?: string) => RegExp; flags: GetFlags<[TFlags] extends [never] ? "" : TFlags>; sticky: string extends ([TFlags] extends [never] ? "" : TFlags) ? boolean : "y" extends infer T_2 ? T_2 extends "y" ? T_2 extends CharOf<[TFlags] extends [never] ? "" : TFlags> ? true : false : never : never; unicode: string extends ([TFlags] extends [never] ? "" : TFlags) ? boolean : "u" extends infer T_3 ? T_3 extends "u" ? T_3 extends CharOf<[TFlags] extends [never] ? "" : TFlags> ? true : false : never : never; dotAll: string extends ([TFlags] extends [never] ? "" : TFlags) ? boolean : "s" extends infer T_4 ? T_4 extends "s" ? T_4 extends CharOf<[TFlags] extends [never] ? "" : TFlags> ? true : false : never : never; hasIndices: string extends ([TFlags] extends [never] ? "" : TFlags) ? boolean : "d" extends infer T_5 ? T_5 extends "d" ? T_5 extends CharOf<[TFlags] extends [never] ? "" : TFlags> ? true : false : never : never; unicodeSets: string extends ([TFlags] extends [never] ? "" : TFlags) ? boolean : "v" extends infer T_6 ? T_6 extends "v" ? T_6 extends CharOf<[TFlags] extends [never] ? "" : TFlags> ? true : false : never : never; regExp: RegExp; } & ((string extends "g" | ([TFlags] extends [never] ? "" : TFlags) ? boolean : "g" extends infer T_7 ? T_7 extends "g" ? T_7 extends CharOf<[TFlags] extends [never] ? "" : TFlags> ? true : false : never : never) extends infer T_8 ? T_8 extends (string extends "g" | ([TFlags] extends [never] ? "" : TFlags) ? boolean : "g" extends infer T_9 ? T_9 extends "g" ? T_9 extends CharOf<[TFlags] extends [never] ? "" : TFlags> ? true : false : never : never) ? T_8 extends true ? { matchAllIn: (source: T_9) => RegExpStringIterator, "groups" | "input"> & Pick<{ groups: keyof Parse["namedCaptures"] extends never ? undefined : Parse["namedCaptures"]; input: T_9; }, "groups" | "input"> & (Parse["captures"] extends infer T_10 extends Parse["captures"] ? { [K in keyof T_10 as K extends number ? number extends Parse["captures"]["length"] ? K : never : K]: Parse["captures"][K]; } : never)>; replaceAllIn: { (string: T_9, replacer: (...p: [match: Head["captures"]>, ...p: Tail["captures"]>, offset: number, string: T_9, ...keyof Parse["namedCaptures"] extends never ? [] : [groups: Parse["namedCaptures"]]]) => string): string; (string: T_9, replaceValue: string): string; }; } : {} : never : never), "exec" | "matchIn" | "matchAllIn"> & ((Omit<{ global: true; } & { matchAllIn: (source: T_10) => RegExpStringIterator, "groups" | "input"> & Pick<{ groups: keyof Parse["namedCaptures"] extends never ? undefined : Parse["namedCaptures"]; input: T_10; }, "groups" | "input"> & (Parse["captures"] extends infer T_11 extends Parse["captures"] ? { [K in keyof T_11 as K extends number ? number extends Parse["captures"]["length"] ? K : never : K]: Parse["captures"][K]; } : never)>; replaceAllIn: { (string: T_10, replacer: (...p: [match: Head["captures"]>, ...p: Tail["captures"]>, offset: number, string: T_10, ...keyof Parse["namedCaptures"] extends never ? [] : [groups: Parse["namedCaptures"]]]) => string): string; (string: T_10, replaceValue: string): string; }; }, "matchAllIn"> & { matchIn: (string: string) => [Head["captures"]>, ...Head["captures"]>[]] | null; } & (({ hasIndices: false; } & { matchAllIn: (string: TString) => RegExpStringIterator, "groups" | "input"> & Pick<{ groups: keyof Parse["namedCaptures"] extends never ? undefined : Parse["namedCaptures"]; input: TString; }, "groups" | "input"> & (Parse["captures"] extends infer T_10 extends Parse["captures"] ? { [K in keyof T_10 as K extends number ? number extends Parse["captures"]["length"] ? K : never : K]: Parse["captures"][K]; } : never)>; }) | ({ hasIndices: true; } & { matchAllIn: (string: TString) => RegExpStringIterator, "groups" | "input"> & Pick<{ groups: keyof Parse["namedCaptures"] extends never ? undefined : Parse["namedCaptures"]; input: TString; }, "groups" | "input"> & (Parse["captures"] extends infer T_10 extends Parse["captures"] ? { [K in keyof T_10 as K extends number ? number extends Parse["captures"]["length"] ? K : never : K]: Parse["captures"][K]; } : never) & { indices: NonNullable; }>; }))) | (({ global: false; } & {}) & (({ hasIndices: false; } & { matchIn: (string: TString) => (Omit, "groups" | "input"> & Pick<{ groups: keyof Parse["namedCaptures"] extends never ? undefined : Parse["namedCaptures"]; input: TString; }, "groups" | "input"> & (Parse["captures"] extends infer T_10 extends Parse["captures"] ? { [K in keyof T_10 as K extends number ? number extends Parse["captures"]["length"] ? K : never : K]: Parse["captures"][K]; } : never)) | null; }) | ({ hasIndices: true; } & { matchIn: (string: TString) => (Omit, "groups" | "input"> & Pick<{ groups: keyof Parse["namedCaptures"] extends never ? undefined : Parse["namedCaptures"]; input: TString; }, "groups" | "input"> & (Parse["captures"] extends infer T_10 extends Parse["captures"] ? { [K in keyof T_10 as K extends number ? number extends Parse["captures"]["length"] ? K : never : K]: Parse["captures"][K]; } : never) & { indices: NonNullable; }) | null; })))) & (({ hasIndices: false; } & { exec: (string: TString) => (Omit, "groups" | "input"> & Pick<{ groups: keyof Parse["namedCaptures"] extends never ? undefined : Parse["namedCaptures"]; input: TString; }, "groups" | "input"> & (Parse["captures"] extends infer T_10 extends Parse["captures"] ? { [K in keyof T_10 as K extends number ? number extends Parse["captures"]["length"] ? K : never : K]: Parse["captures"][K]; } : never)) | null; }) | ({ hasIndices: true; } & { exec: (string: TString) => (Omit, "groups" | "input"> & Pick<{ groups: keyof Parse["namedCaptures"] extends never ? undefined : Parse["namedCaptures"]; input: TString; }, "groups" | "input"> & (Parse["captures"] extends infer T_10 extends Parse["captures"] ? { [K in keyof T_10 as K extends number ? number extends Parse["captures"]["length"] ? K : never : K]: Parse["captures"][K]; } : never) & { indices: NonNullable; }) | null; }))>; export { type Head, type Parse, type ParseCaptures, type ParseNamedCaptures, type Tail, typedRegExp };