Thought I would write a CSS Parser in TypeScript Types. Like all these exercises there is no practical application, but I thought they are fun.
Maybe there is something to learn, cause I did.
type WS = ' ' | '\n' | '\t'; type Trim<T> = T extends (`${WS}${infer V}` | `${infer V}${WS}`) ? Trim<V> : T; type AddKey<O extends {}, Key , Value, Z = Trim<Key>> = Trim<Z> extends '' ? Value : Z extends PropertyKey ? {[k in Z]:Value} & (Z extends keyof O ? Exclude<O, Z> : O) : Value; type _ParseComment<T> = Trim<T> extends `/*${infer Comment}*/${infer Rest}` ? [Comment, Rest] : ['', T] type _ParseSelector<T> = T extends `${infer Selector}{${infer Rest}` ? Trim<Selector> extends '' ? ['' , T] : [Trim<Selector>, Trim<Rest>] : ['', T]; type _ParseMediaQuery<T, Ret extends {} = {}> = T extends `${infer Query}{${infer Content}` ? _ParseCSS<Content> extends [infer CSSI, infer Rest] ? Trim<Rest> extends `}${infer CRest}` ? [ AddKey<Ret, Query, CSSI>, CRest ] : [Ret, ''] : [Ret, ''] : [Ret, '']; type _ParseProperties<T, Ret extends {} = {}> = _ParseComment<T> extends [string, infer PR] ? Trim<PR> extends '' ? [Ret, ''] : Trim<PR> extends `}${infer Rest}` ? [Ret, Rest] : Trim<PR> extends `${infer Key}:${infer Val};${infer Rest}` ? _ParseProperties<Rest, AddKey<Ret, Key, Trim<Val>>> : Trim<PR> extends `${infer Key}:${infer Val}}${infer Rest}` ? [ AddKey<Ret, Key, Trim<Val>>, Rest] : [Ret, PR]: [Ret, T]; type _ParseCSS<S, Ret extends {} = {}> = Trim<S> extends '' ? [Ret, ''] : Trim<S> extends `}${string}` ? [ Ret, S ] : _ParseComment<S> extends [string, infer CRest] ? _ParseSelector<CRest> extends [infer Selector, infer Rest] ? _ParseProperties<Rest> extends [infer Props, infer PRest] ? _ParseCSS<PRest, AddKey<Ret, Selector, Props>> : never : never : never ; type ParseCSS<S, Ret extends {} = {}> = Trim<S> extends '' ? Ret : S extends `${infer Before}@media${infer Media}` ? _ParseCSS<Before, Ret> extends [infer O, string] ? _ParseMediaQuery<Media, O> extends [infer R, infer Con] ? ParseCSS<Con, R> : never : ParseCSS<S, Ret> : _ParseCSS<S> extends [infer R, string] ? R : never; type MQ = _ParseMediaQuery<`only screen and (max-width: 600px) { body { background-color: lightblue; } } `>; type PC1 = ParseCSS<'.stuff { color:white }'>; type PC1S = PC1['.stuff']['color']; type PC2 = ParseCSS<'/* what */ .stuff { color:white; }'>; type PC3 = ParseCSS<'/* what */ .stuff { color:white; background:red }'>; type PC4 = ParseCSS<' .stuff { color:white; /* what */background:red }'>; type PC5 = ParseCSS<`.stuff { color:white;background:red } .selector2 { font:sans-serif }`>; type PC51 = PC5['.selector2']['font']; type _PC = _ParseCSS<`.stuff { color:white;background:red }`>; type TQ1 = ParseCSS<`.stuff { background-color: lightblue; }`>; type MQ1 = ParseCSS<`@media only screen and (max-width: 600px) { body { background-color: lightblue; } }`>; type MQ2 = ParseCSS<`@media only screen and (max-width: 600px) { body { background-color: lightblue; } }`>; type MQ3 = ParseCSS<`body { color: pink } @media only screen and (max-width: 600px) { body { background-color: lightblue; } } @media only screen { body { background-color: lightblue; } }`>;