Created
October 2, 2020 11:43
-
-
Save phenomnomnominal/b3b912d4c824b7f25c4ea19b4e75c9a9 to your computer and use it in GitHub Desktop.
Oh no.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Check it out here: | |
// https://www.typescriptlang.org/play?ts=4.1.0-dev.20201001#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-VppsFWzAjwQ1-OzfG5l5a82xuLTmjtWsvkAPkd0OtlUm6Dori221GLdVuojX2hp+LujKupCOs1Nhl2TrDSW3FXaZ26QlZMxI4kAWyt5kXY+yzNn5W3ZGg5RyYkBotVa4aNqvnmJtSTcNDr50VvWsazcZLSoUsyfS-dLyuq+HUVSG5WbkIiPfrnT+UAhXQAIpjUi5F8CUTJvZf9KIHkPrOeyZNgUAavtGu+0Ns7v1lv7Z64jR5AMwWA3C9pZGNHBm9gfCOdzkACsXTw2hIyxUHqlcehj+o8CnsWRe10FAtk3p-QRCgRzlonPU2c8pH7OYxsI+mnUJH3lZQ0W+n5VG41ztowutlGbJNMcBQJvubGqo2s4-vQ+vH+NspoXGVdYHA0QbURomD2m4PuZ42q7hKH7LwfXHnRRqH0Nk01exqkbm35xc3F54GKHTX+YBYkSDwWbWbvQVAWLH9xGCbjGh3d10A0TLE7Zn10nz3rLkwp3tVnkDKZU48kiTdG3NpfSZijZm-nUdLSyr5jaa32ZY-FZzpyPzjpQIVoL0GSuwfK6rIeBtI0JcIkll1embCrb-CNhOY3m4fp0gChbHEOnEqhgJ2F8V4VhURZ0lFP0-oYs-Yp7rD3BBUshoTCFNFyVArgqDqmNN4xLbbZZ6bo0CF5doppt5RXNsaNK2FvWe2pvlqwtFnbmB2FzIUch5Awqjt1aLR81zg9MjDx-dl9aPmRUiY-I1qZ52sLSKpK6YM6BziOBwOcAAWktQQlJKCdfbd15Tqn6uTY9QJ87w7ucBbeVm5Le6Mc88lXz2R9cgGC+WSLsXEvJe9HOBsK45wZdy-k9errLLlf9alE3Ddl2wICcoxNizNGUcCeXf4nSUPHNhUR1+ondGw9uwzCurVTP168vdtWWI7OWK5dTf65bn5jdHuXa1pZHW3eK49313V-rMfoz1y6g3elAeh7ZR7dHjOOM8p7B7HP3Q8-qbr0bw94lS8+DPeX+Xlfkfls97X+tBXseaK26Fsny6qG5dqzp-Nzekch-LV85dMZfPa6XxtlfuPts9+HB2Le1XEv079+l5dd-+-U9p-ntdvOS9uzL7J6fOPXFefVXfzc7dbKDS-BBa-XbFnfbH9BLGLdPHsO-EnGnR-HfL3XYBZNrIXQ1JGeJSnIUQsR5KUZrOBXjXGQg3jIUY0Ug3YPDCAcg65SggghJSLP8GgQ0SgegrwTqGCF0ZgynKg9grhTg7gug5kAAESMQYEDiEN415xEKIIoENEkJIhbhymhGiEICkIRBREgkXEpyULYJUIFF4OgE0OAG0OAEIH-BMDwFeGMON2UJoIoD5AsOMy0J0NsR2WcMmVcI4KFCFE8KsJsMID2B9DiDgn8JDlMLcNFFCJqnCJwA4EkE3BeFiMrhmRUIlCSLsXCI9iyMCLEKFHrHyO8NsKsOKPiKCIoDzAqOsJ0NNEghqPCGoLqJIOZDCJ0IACFp5BA2ici3CyxGjwidExBIAhiOjSiKAKxPD7gpDhDajZjZQ+Bl4NVmRFjmpFAwBA5m5WD2jRCkkKA1jl5zh+jkArh+jnAFipDcVzQVA8AQBpjji0khR5Q7iWgWofhXiVDZQcAxgrg1RqBPDG0HiniXjFCXCViTiNQwTlRcJlijiVC1R1iNAESVQdi9inFDjhi6i0Tl4rhrjeJzgLj0Bbj3Q3ZkT8TZiRdExPDj9Agii8SZiTiRdSB0SGSqSGERxsAWQxA8AngaS2T3iKARdhROTl5uSSImTsBqjWS3ipVxT0AcwpS4AZSpQ5T3ZWjFSVCRd8x1TNTdhtT+iYi9S3CJSjTNjZSk9AgJipiLS6iRdaBrTGS3Y5UFUXQ-jLTQSeSM8ZCTA5DcBqToSAjYSxTgwRcbStS7T5Swy4iUTfTSBaB0BjSvBtTC4vR0AWSOCTCkznT0BSBSB0z8g4yIBAzgzk8fTCzSAizuSgA | |
type LowercaseAlpha = '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 UppercaseAlpha = Capitalize<LowercaseAlpha>; | |
type Alphabet = LowercaseAlpha | UppercaseAlpha; | |
type Numbers = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'; | |
type Symbols = '-' | '_' | |
type Identifiers = Alphabet | Number | Symbols; | |
type Whitespace = ' ' | '\n' | '\t' | '\f' | '\n'; | |
type Quotes = "'" | '"'; | |
type Traversal = ',' | '>' | '<' | '~' | '+'; | |
type Id = '#'; | |
type Class = '.'; | |
type Universal = '*' | |
type EOF = ''; | |
type Finished = ''; | |
type AttributeOpen = '['; | |
type AttributeClose = ']'; | |
type AttributeCases = '~' | '^' | '$' | '*' | '!' | '|'; | |
type Equal = '='; | |
type Attributes = AttributeOpen | AttributeClose | AttributeCases | Equal; | |
type Chars = Identifiers | Whitespace | Quotes | Traversal | Id | Class | Universal | EOF | Attributes; | |
type LexError<Message extends string> = { message: Message }; | |
type TakeAll< | |
V extends string, | |
Chars | |
> = | |
V extends `${infer C}${infer R}` ? | |
C extends Chars ? | |
TakeAll<R, Chars> : | |
V : | |
V; | |
type TakeUntil< | |
V extends string, | |
Chars extends string | |
> = | |
V extends `${infer Start}${Chars}${infer Rest}` ? | |
Start : | |
V; | |
type ConsumeNext<S extends string> = | |
S extends EOF ? | |
[EOF, Finished] : | |
S extends `${infer Char}${infer Rest}` ? | |
[Char, Rest] : | |
[S, Finished]; | |
type ConsumeNextValid< | |
S extends string, | |
Consumed extends [string, string] = ConsumeNext<S>, | |
Char = Consumed[0], | |
Rest = Consumed[1], | |
> = | |
Char extends Chars ? | |
[Char, Rest] : | |
never; | |
type Input = 'Input'; | |
type Current = 'Current'; | |
type HasAlphabetCharacter = 'HasAlphabetCharacter'; | |
type HasAttributeOpen = 'HasAttributeOpen'; | |
type HasAttributeEqual = 'HasAttributeEqual'; | |
type HasFirstSelector = 'HasFirstSelector'; | |
type HasQuote = 'HasQuote'; | |
type HasWhitespace = 'HasWhitespace'; | |
type ExpectIdentifier = 'ExpectIdentifier'; | |
type LexState = { | |
Input: string, | |
HasAlphabetCharacter: boolean, | |
HasAttributeEqual: boolean, | |
HasAttributeOpen: boolean, | |
HasFirstSelector: boolean, | |
HasQuote: Array<Quotes>, | |
HasWhitespace: boolean, | |
ExpectIdentifier: boolean | |
} | |
type InitialState<Input extends string> = { | |
Input: Input, | |
HasAlphabetCharacter: false, | |
HasAttributeEqual: false, | |
HasAttributeOpen: false, | |
HasFirstSelector: false, | |
HasQuote: [], | |
HasWhitespace: false, | |
ExpectIdentifier: false | |
} | |
type UpdateState< | |
Previous extends LexState, | |
Next extends Partial<LexState> | |
> = | |
Omit<Previous, keyof Next> & Next; | |
type CSSSelector< | |
Selector extends string, | |
Consumed extends [string, string] = ConsumeNext<Selector>, | |
CurrentCharacter extends string = Consumed[0] | |
> = | |
ConsumeNextValid<Selector> extends never ? | |
LexError<`CSS Selector: Unexpected character "${CurrentCharacter}"`> : | |
LexText<InitialState<Selector>>; | |
type LexText< | |
State extends LexState, | |
Text extends string = State[Input], | |
Consumed extends [string, string] = ConsumeNextValid<Text>, | |
CurrentCharacter extends string = Consumed[0], | |
Rest extends string = Consumed[1], | |
> = | |
CurrentCharacter extends EOF ? | |
State[HasAttributeOpen] extends true ? | |
LexError<'EOF: Unclosed Attribute selector'> : | |
State[Input] : | |
CurrentCharacter extends Whitespace ? | |
LexWhiteSpace<State, CurrentCharacter, Rest> : | |
CurrentCharacter extends Traversal ? | |
LexTraversal<State, CurrentCharacter, Rest> : | |
CurrentCharacter extends Universal ? | |
LexUniversal<State, CurrentCharacter, Rest> : | |
CurrentCharacter extends Class | Id ? | |
LexClassId<State, CurrentCharacter, Rest> : | |
CurrentCharacter extends Identifiers ? | |
LexIdentifier<State, Text> : | |
CurrentCharacter extends Attributes ? | |
LexAttribute<State, CurrentCharacter, Rest> : | |
LexError<`Text: Unexpected "${CurrentCharacter}"`>; | |
type LexWhiteSpace< | |
State extends LexState, | |
CurrentCharacter extends Whitespace, | |
Rest extends string, | |
> = | |
LexText<UpdateState<State, { HasWhitespace: true }>, TakeAll<Rest, Whitespace>>; | |
type LexTraversal< | |
State extends LexState, | |
CurrentCharacter extends Traversal, | |
Rest extends string, | |
> = | |
State[HasFirstSelector] extends false ? | |
LexError<`Traversal: Unexpected '${CurrentCharacter}'`> : | |
LexText<State, Rest>; | |
type LexUniversal< | |
State extends LexState, | |
CurrentCharacter extends Universal, | |
Rest extends string | |
> = | |
State[HasFirstSelector] extends false ? | |
LexText<UpdateState<State, { HasFirstSelector: true, HasWhitespace: false }>, Rest> : | |
State[HasWhitespace] extends true ? | |
LexText<UpdateState<State, { HasWhitespace: false }>, Rest> : | |
LexError<`Universal: Unexpected '${CurrentCharacter}''`>; | |
type LexClassId< | |
State extends LexState, | |
CurrentCharacter extends Class | Id, | |
Rest extends string | |
> = | |
LexIdentifier<UpdateState<State, { HasAlphabetCharacter: false }>, Rest>; | |
type LexIdentifier< | |
State extends LexState, | |
Text extends string, | |
Consumed extends [string, string] = ConsumeNextValid<Text>, | |
CurrentCharacter extends string = Consumed[0], | |
Rest extends string = Consumed[1] | |
> = | |
CurrentCharacter extends Alphabet ? | |
LexText<UpdateState<State, { HasAlphabetCharacter: true, HasFirstSelector: true }>, Rest> : | |
State[HasAlphabetCharacter] extends false ? | |
LexError<`Identifier: Expected [a-zA-Z] got '${CurrentCharacter}'`> : | |
CurrentCharacter extends Identifiers ? | |
LexText<State, Rest> : | |
LexError<`Identifier: Expected [a-zA-Z0-9_-] got '${CurrentCharacter}'`>; | |
type LexAttribute< | |
State extends LexState, | |
CurrentCharacter extends Attributes, | |
Rest extends string | |
> = | |
CurrentCharacter extends AttributeCases ? | |
State[HasAttributeEqual] extends true ? | |
LexError<`Attribute: Unexpected '${CurrentCharacter}'`> : | |
LexText<State, Rest> : | |
CurrentCharacter extends Equal ? | |
State[HasAttributeEqual] extends true ? | |
LexError<`Attribute: Unexpected '${CurrentCharacter}'`> : | |
LexText<UpdateState<State, { HasAttributeEqual: true }>, Rest> : | |
CurrentCharacter extends AttributeClose ? | |
LexText<UpdateState<State, { HasAttributeOpen: false }>, Rest> : | |
State[HasAttributeOpen] extends true ? | |
LexError<`Attribute: Unexpected '${CurrentCharacter}'`> : | |
LexIdentifier<UpdateState<State, { HasAlphabetCharacter: false, HasAttributeOpen: true }>, Rest>; | |
type UnexpectedCharacter = CSSSelector<'$'>; | |
type UniversalSelector = CSSSelector<'*'>; | |
type WhitespaceUniversalSelector = CSSSelector<' * '>; | |
type NestedUniversalSelector = CSSSelector<'* *'>; | |
type DoubleUniversalSelectorError = CSSSelector<'**'>; | |
type StartWithDescendentSelectorError = CSSSelector<'>'>; | |
type StartWithMultiSelectorError = CSSSelector<','>; | |
type StartWithParentSelectorError = CSSSelector<'<'>; | |
type StartWithSiblingSelectorError = CSSSelector<'~'>; | |
type StartWithAdjacentSelectorError = CSSSelector<'+'>; | |
type StartWithEqualSelectorError = CSSSelector<'='>; | |
type StartWithStartSelectorError = CSSSelector<'^'>; | |
type StartWithEndSelectorError = CSSSelector<'$'>; | |
type StartWithBangSelectorError = CSSSelector<'!'>; | |
type StartWithPipeSelectorError = CSSSelector<'|'>; | |
type IDSelector = CSSSelector<'#foo'>; | |
type IDComplexSelector = CSSSelector<'#foo-Bar_Baz'>; | |
type IDCharacterOnlySelectorError = CSSSelector<'#'>; | |
type IDNonAlphaSelectorError = CSSSelector<'#A3_.a'>; | |
type ClassCharacterOnlySelectorError = CSSSelector<'.'>; | |
type ClassSelector = CSSSelector<'.foo'>; | |
type ClassComplexSelector = CSSSelector<'.foo__Bar--Baz'>; | |
type AttributeSelector = CSSSelector<'[a]'>; | |
type AttributeCaseEqualSelector = CSSSelector<'[a=foo]'>; | |
type AttributeCaseTildeSelector = CSSSelector<'[a~=foo]'>; | |
type AttributeCaseStartSelector = CSSSelector<'[a^=foo]'>; | |
type AttributeCaseEndSelector = CSSSelector<'[a$=foo]'>; | |
type AttributeCaseBangSelector = CSSSelector<'[a~=foo]'>; | |
type AttributeCasePipeSelector = CSSSelector<'[a|=foo]'>; | |
type AttributeUnclosedSelectorError = CSSSelector<'[a'>; | |
type AttributeDoubleAttributeSelectorError = CSSSelector<'[[a'>; | |
type AttributeCaseSelectorError = CSSSelector<'[a=|a]'>; | |
type AttributeCaseExtraEqualSelectorError = CSSSelector<'[a==]'>; | |
type AttributeCaseDoubleCaseSelectorError = CSSSelector<'[a=a=]'>; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment