import type { Split, SplitPattern } from './split.ts' import type { ForceDistributive } from './utils.ts' export interface ParsedPattern { protocol: Token[] | undefined hostname: Token[] | undefined port: string | undefined pathname: Token[] | undefined search: string | undefined } // prettier-ignore export type Parse = T extends ForceDistributive ? Split extends infer S extends SplitPattern ? { protocol: S['protocol'] extends string ? ParsePart : undefined hostname: S['hostname'] extends string ? ParsePart : undefined port: S['port'] extends string ? S['port'] : undefined pathname: S['pathname'] extends string ? ParsePart : undefined search: S['search'] extends string ? S['search'] : undefined } : never : never export type Variable = { type: 'variable'; name: string } export type Wildcard = { type: 'wildcard'; name?: string } export type Text = { type: 'text'; value: string } export type Separator = { type: 'separator' } export type Optional = { type: 'optional'; tokens: Token[] } export type Token = Variable | Wildcard | Text | Separator | Optional type ParsePartState = { tokens: Token[] optionals: Array rest: string } type ParsePart = _ParsePart< { tokens: [] optionals: [] rest: T }, Sep > // prettier-ignore type _ParsePart = S extends { rest: `${infer Head}${infer Tail}` } ? Head extends Sep ? _ParsePart, Sep> : Head extends ':' ? IdentifierParse extends { identifier: infer name extends string, rest: infer rest extends string } ? (name extends '' ? never : _ParsePart, Sep>) : never : Head extends '*' ? IdentifierParse extends { identifier: infer name extends string, rest: infer rest extends string } ? _ParsePart, Sep> : never : Head extends '(' ? _ParsePart, Sep> : Head extends ')' ? PopOptional extends infer next extends ParsePartState ? _ParsePart : never : Head extends '\\' ? Tail extends `${infer L}${infer R}` ? _ParsePart, Sep> : never : _ParsePart, Sep> : S['optionals'] extends [] ? S['tokens'] : never // prettier-ignore type AppendToken = S['optionals'] extends [...infer O extends Array, infer Top extends Token[]] ? { tokens: S['tokens'] optionals: [...O, [...Top, token]] rest: rest } : { tokens: [...S['tokens'], token] optionals: S['optionals'] rest: rest; } // prettier-ignore type AppendText = S['optionals'] extends [...infer O extends Array, infer Top extends Token[]] ? ( Top extends [...infer Tokens extends Array, { type: 'text', value: infer value extends string }] ? { tokens: S['tokens']; optionals: [...O, [...Tokens, { type: 'text', value: `${value}${text}` }]]; rest: rest } : { tokens: S['tokens']; optionals: [...O, [...Top, { type: 'text', value: text }]]; rest: rest } ) : ( S['tokens'] extends [...infer Tokens extends Array, { type: 'text', value: infer value extends string }] ? { tokens: [...Tokens, { type: 'text', value: `${value}${text}` }]; optionals: S['optionals']; rest: rest } : { tokens: [...S['tokens'], { type: 'text', value: text }]; optionals: S['optionals']; rest: rest } ) type PushOptional = { tokens: S['tokens'] optionals: [...S['optionals'], []] rest: rest } type PopOptional = S['optionals'] extends [ ...infer O extends Array, infer Top extends Array, ] ? O extends [...infer OO extends Array, infer Parent extends Token[]] ? { tokens: S['tokens'] optionals: [...OO, [...Parent, { type: 'optional'; tokens: Top }]] rest: R } : { tokens: [...S['tokens'], { type: 'optional'; tokens: Top }]; optionals: []; rest: R } : never // prettier-ignore type _a_z = 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'h' | 'i' | 'j' | 'k' | 'l' | 'm' | 'n' | 'o' | 'p' | 'q' | 'r' | 's' | 't' | 'u' | 'v' | 'w' | 'x' | 'y' | 'z' type _A_Z = Uppercase<_a_z> type _0_9 = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' type IdentifierHead = _a_z | _A_Z | '_' | '$' type IdentifierTail = IdentifierHead | _0_9 type IdentifierParse = _IdentifierParse<{ identifier: ''; rest: T }> // prettier-ignore type _IdentifierParse = S extends { identifier: '', rest: `${infer Head extends IdentifierHead}${infer Tail}` } ? _IdentifierParse<{ identifier: Head, rest: Tail }> : S extends { identifier: string, rest: `${infer Head extends IdentifierTail}${infer Tail}`} ? _IdentifierParse<{ identifier: `${S['identifier']}${Head}`, rest: Tail }> : S