import { parse as parseCSSDocument , Rule , Declaration } from "css" ; import { calculate as calculateSpecificity , compare as compareSpecifity , SpecificityArray , } from "specificity" ; export interface IStyleAttribute { specificity : SpecificityArray ; order : number ; style : string ; selector : string ; } export function parseCss ( cssText ) { const styleSheet = parseCSSDocument ( cssText ) . stylesheet ; if ( styleSheet && ( ! styleSheet . parsingErrors || styleSheet . parsingErrors . length === 0 ) ) { /**
         * A rule block is of type
         * selector1, selector2 {
         *   declaration property:value;
         * }
         * we extract rule blocks and use
         */ const castRules = styleSheet . rules as Rule [ ] ; const selectorLookup = { } ; for ( let i = 0 ; i < castRules . length ; i ++ ) { const rule = castRules [ i ] ; const styleValueString = ( rule . declarations || [ ] ) . reduce ( ( iValue , current ) => iValue + `${ current . property }:${ current . value };` , "" ) ; ( rule . selectors || [ ] ) . forEach ( ( selector , selectorIndex ) => { if ( ! selectorLookup [ selector ] ) { selectorLookup [ selector ] = { selector , specificity : calculateSpecificity ( selector ) [ 0 ] . specificityArray , order : i * 100 + selectorIndex , style : styleValueString , } ; } else { selectorLookup [ selector ] . style += ";" + styleValueString ; selectorLookup [ selector ] . order = i * 100 + selectorIndex ; } } ) ; } const selectorValueList = Object . keys ( selectorLookup ) . map ( ( selector ) => selectorLookup [ selector ] ) ; selectorValueList . sort ( ( a , b ) => compareSpecifity ( a . specificity , b . specificity ) || a . order - b . order ) ; return selectorValueList ; } }