| OLD | NEW |
| (Empty) | |
| 1 |
| 2 |
| 3 /* |
| 4 Extremely simple css parser. Intended to be not more than what we need |
| 5 and definitely not necessarly correct =). |
| 6 */ |
| 7 (function() { |
| 8 |
| 9 // given a string of css, return a simple rule tree |
| 10 function parse(text) { |
| 11 text = clean(text); |
| 12 return parseCss(lex(text), text); |
| 13 } |
| 14 |
| 15 // remove stuff we don't care about that may hinder parsing |
| 16 function clean(cssText) { |
| 17 return cssText.replace(rx.comments, '').replace(rx.port, ''); |
| 18 } |
| 19 |
| 20 // super simple {...} lexer that returns a node tree |
| 21 function lex(text) { |
| 22 var root = {start: 0, end: text.length}; |
| 23 var n = root; |
| 24 for (var i=0, s=0, l=text.length; i < l; i++) { |
| 25 switch (text[i]) { |
| 26 case OPEN_BRACE: |
| 27 //console.group(i); |
| 28 if (!n.rules) { |
| 29 n.rules = []; |
| 30 } |
| 31 var p = n; |
| 32 var previous = p.rules[p.rules.length-1]; |
| 33 n = {start: i+1, parent: p, previous: previous}; |
| 34 p.rules.push(n); |
| 35 break; |
| 36 case CLOSE_BRACE: |
| 37 //console.groupEnd(n.start); |
| 38 n.end = i+1; |
| 39 n = n.parent || root; |
| 40 break; |
| 41 } |
| 42 } |
| 43 return root; |
| 44 } |
| 45 |
| 46 // add selectors/cssText to node tree |
| 47 function parseCss(node, text) { |
| 48 var t = text.substring(node.start, node.end-1); |
| 49 node.cssText = t.trim(); |
| 50 if (node.parent) { |
| 51 var ss = node.previous ? node.previous.end : node.parent.start; |
| 52 t = text.substring(ss, node.start-1); |
| 53 // TODO(sorvell): ad hoc; make selector include only after last ; |
| 54 // helps with mixin syntax |
| 55 t = t.substring(t.lastIndexOf(';')+1); |
| 56 node.selector = t.trim(); |
| 57 } |
| 58 var r$ = node.rules; |
| 59 if (r$) { |
| 60 for (var i=0, l=r$.length, r; (i<l) && (r=r$[i]); i++) { |
| 61 parseCss(r, text); |
| 62 } |
| 63 } |
| 64 return node; |
| 65 } |
| 66 |
| 67 // stringify parsed css. |
| 68 function stringify(node, text) { |
| 69 text = text || ''; |
| 70 // calc rule cssText |
| 71 var cssText = ''; |
| 72 if (node.cssText || node.rules) { |
| 73 var r$ = node.rules; |
| 74 if (r$ && !hasMixinRules(r$)) { |
| 75 for (var i=0, l=r$.length, r; (i<l) && (r=r$[i]); i++) { |
| 76 cssText = stringify(r, cssText); |
| 77 } |
| 78 } else { |
| 79 cssText = removeCustomProps(node.cssText).trim(); |
| 80 if (cssText) { |
| 81 cssText = ' ' + cssText + '\n'; |
| 82 } |
| 83 } |
| 84 } |
| 85 // emit rule iff there is cssText |
| 86 if (cssText) { |
| 87 if (node.selector) { |
| 88 text += node.selector + ' ' + OPEN_BRACE + '\n'; |
| 89 } |
| 90 text += cssText; |
| 91 if (node.selector) { |
| 92 text += CLOSE_BRACE + '\n\n'; |
| 93 } |
| 94 } |
| 95 return text; |
| 96 } |
| 97 |
| 98 var OPEN_BRACE = '{'; |
| 99 var CLOSE_BRACE = '}'; |
| 100 |
| 101 function hasMixinRules(rules) { |
| 102 return (rules[0].selector.indexOf(VAR_START) >= 0); |
| 103 } |
| 104 |
| 105 function removeCustomProps(cssText) { |
| 106 return cssText |
| 107 .replace(rx.customProp, '') |
| 108 .replace(rx.mixinProp, '') |
| 109 .replace(rx.mixinApply, ''); |
| 110 } |
| 111 |
| 112 var VAR_START = '--'; |
| 113 |
| 114 // helper regexp's |
| 115 var rx = { |
| 116 comments: /\/\*[^*]*\*+([^/*][^*]*\*+)*\//gim, |
| 117 port: /@import[^;]*;/gim, |
| 118 customProp: /--[^;{]*?:[^{};]*?;/gim, |
| 119 mixinProp: /--[^;{]*?:[^{;]*?{[^}]*?}/gim, |
| 120 mixinApply: /@mixin[\s]*\([^)]*?\)[\s]*;/gim |
| 121 }; |
| 122 |
| 123 // exports |
| 124 Polymer.CssParse = { |
| 125 parse: parse, |
| 126 stringify: stringify |
| 127 }; |
| 128 |
| 129 })(); |
| 130 |
| OLD | NEW |