I think the rules for infinite-lookahead would be:
- If the first token is an ident or function, then:
- If it's a dashed-ident (or function with a dashed-ident name), followed by any amount of whitespace, followed by a colon: it's a custom property.
- If it's followed by any amount of whitespace and a colon, then look forward until you see either a semicolon or EOF (it's a property) or a {}-block (it's a rule).
- Otherwise, it's a rule.
- Otherwise, it's a rule.
This gives us infinite lookahead, with arbitrary mixing of properties and selectors, with only three compromises:
- Non-custom properties can never contain top-level {}-blocks. (They can put them in strings, or in functions, or in parens, whatever. Just not at the top.)
- Selectors can never contain top-level semicolons. (Ditto.)
- Nested selectors can't start with a type selector that's a dashed-ident (that is, start with a --) followed by a pseudo-class. If you have a markup language that allows this (HTML doesn't), you still have to wrap it in an
:is()
or whatever. (But any other combo works ---foo.bar
is just fine.)
Note on look-ahead, you also stop on seeing a
}
or EOF, it's a property, only{
causes it to be a rule (and you don't have to look ahead for the closing}
.