import { InputToken, Stylesheet, Rule, AtRule, QualifiedRule } from './CSS3Parser'; /** * Consume a CSS3 parsed stylesheet and convert the rules and selectors to the * NativeScript internal JSON representation. */ export class CSSNativeScript { public parseStylesheet(stylesheet: Stylesheet): any { return { type: 'stylesheet', stylesheet: { rules: this.parseRules(stylesheet.rules), }, }; } private parseRules(rules: Rule[]): any { return rules.map((rule) => this.parseRule(rule)); } private parseRule(rule: Rule): any { if (rule.type === 'at-rule') { return this.parseAtRule(rule); } else if (rule.type === 'qualified-rule') { return this.parseQualifiedRule(rule); } } private parseAtRule(rule: AtRule): any { if (rule.name === 'import') { // TODO: We have used an "@import { url('path somewhere'); }" at few places. return { import: rule.prelude .map((m) => (typeof m === 'string' ? m : m.text)) .join('') .trim(), type: 'import', }; } return; } private parseQualifiedRule(rule: QualifiedRule): any { return { type: 'rule', selectors: this.preludeToSelectorsStringArray(rule.prelude), declarations: this.ruleBlockToDeclarations(rule.block.values), }; } private ruleBlockToDeclarations(declarationsInputTokens: InputToken[]): { type: 'declaration'; property: string; value: string }[] { // return declarationsInputTokens; const declarations: { type: 'declaration'; property: string; value: string; }[] = []; let property = ''; let value = ''; let reading: 'property' | 'value' = 'property'; for (let i = 0; i < declarationsInputTokens.length; i++) { const inputToken = declarationsInputTokens[i]; if (reading === 'property') { if (inputToken === ':') { reading = 'value'; } else if (typeof inputToken === 'string') { property += inputToken; } else { property += inputToken.text; } } else { if (inputToken === ';') { property = property.trim(); value = value.trim(); declarations.push({ type: 'declaration', property, value }); property = ''; value = ''; reading = 'property'; } else if (typeof inputToken === 'string') { value += inputToken; } else { value += inputToken.text; } } } property = property.trim(); value = value.trim(); if (property || value) { declarations.push({ type: 'declaration', property, value }); } return declarations; } private preludeToSelectorsStringArray(prelude: InputToken[]): string[] { const selectors = []; let selector = ''; prelude.forEach((inputToken) => { if (typeof inputToken === 'string') { if (inputToken === ',') { if (selector) { selectors.push(selector.trim()); } selector = ''; } else { selector += inputToken; } } else if (typeof inputToken === 'object') { selector += inputToken.text; } }); if (selector) { selectors.push(selector.trim()); } return selectors; } }