(cssText: string)
| 23 | export type ParsedCSS = Array<ParsedAtRule | ParsedStyleRule>; |
| 24 | |
| 25 | export function parseCSS(cssText: string): ParsedCSS { |
| 26 | cssText = removeCSSComments(cssText); |
| 27 | cssText = cssText.trim(); |
| 28 | if (!cssText) { |
| 29 | return []; |
| 30 | } |
| 31 | |
| 32 | const rules: ParsedCSS = []; |
| 33 | |
| 34 | // Find {...} ranges excluding inside of "...", [...] etc. |
| 35 | const excludeRanges = getTokenExclusionRanges(cssText); |
| 36 | const bracketRanges = getAllOpenCloseRanges(cssText, '{', '}', excludeRanges); |
| 37 | |
| 38 | let ruleStart = 0; |
| 39 | bracketRanges.forEach((brackets) => { |
| 40 | const key = cssText.substring(ruleStart, brackets.start).trim(); |
| 41 | const content = cssText.substring(brackets.start + 1, brackets.end - 1); |
| 42 | |
| 43 | if (key.startsWith('@')) { |
| 44 | const typeEndIndex = key.search(/[\s\(]/); |
| 45 | const rule: ParsedAtRule = { |
| 46 | type: typeEndIndex < 0 ? key : key.substring(0, typeEndIndex), |
| 47 | query: typeEndIndex < 0 ? '' : key.substring(typeEndIndex).trim(), |
| 48 | rules: parseCSS(content), |
| 49 | }; |
| 50 | rules.push(rule); |
| 51 | } else { |
| 52 | const rule: ParsedStyleRule = { |
| 53 | selectors: parseSelectors(key), |
| 54 | declarations: parseDeclarations(content), |
| 55 | }; |
| 56 | rules.push(rule); |
| 57 | } |
| 58 | |
| 59 | ruleStart = brackets.end; |
| 60 | }); |
| 61 | |
| 62 | return rules; |
| 63 | } |
| 64 | |
| 65 | function getAllOpenCloseRanges( |
| 66 | input: string, |
no test coverage detected