Last active
January 13, 2018 13:36
-
-
Save frkd-dev/0e0f0e7b6b89d0731e3f7a260e8e1cb1 to your computer and use it in GitHub Desktop.
Tiny emmet parser implementation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Tiny emmet implementation. | |
Cleaned and improved fork of: github.com/valleykid/zen-coding | |
Supports: | |
">" - childs, "*" - multiplications, "+" - siblings, "()" - grouping, custom attributes, tag names, "#" - id, "." - class attributes | |
Usage: let html = emm('div#page>header.hd+(section.sc>div.main-wrap>span*3)+footer.ft>div.a'); | |
*/ | |
(function(){ | |
window['emm'] = (s) => { | |
let zen = {}; | |
zen.frags = {}; | |
zen.fragIndex = 0; | |
// each closure | |
const _ = (obj, iteratee) => { | |
let r = [], k; | |
for (k in obj) | |
r.push(iteratee(obj[k], k)); | |
return r; | |
}; | |
const _frag = (s) => { | |
let arr = s.split('+'), ret = []; | |
_(arr, (v, i) => { | |
if(/\{\d+\}/.test(v)){ | |
if(~v.indexOf('*')){ | |
v = v.split('*'); | |
let ss = _getPH(v[0]), sss = ''; | |
for(let m=0; m<v[1]; m++){ sss+=ss; } | |
ret[i] = sss; | |
} else { | |
ret[i] = _getPH(v); | |
} | |
} else { | |
ret[i] = _getFrag(v); | |
} | |
}); | |
return ret; | |
} | |
const _attrs = (str) => { | |
if(!str) return ''; | |
let arr, sid, clas = [], o = {}, s = []; | |
arr = str.match(/(\#[\w\-\d]+)|(\.[\w\-\d]+)|(\[[^\]]+\])/g); | |
if(arr){ | |
_(arr, (me)=>{ | |
if(me.charAt(0)==='['){ | |
s.push(me.replace(/\[|\]/g, '')); | |
} else if(me.charAt(0)==='.' && o[me]===undefined){ | |
clas.push(me.slice(1)); | |
o[me] = true; | |
} else { | |
sid = sid || me.slice(1); // The first effective | |
} | |
}); | |
} | |
if(sid) s.push('id="'+sid+'"'); | |
if(clas.length) s.push('class="'+clas.join(' ')+'"'); | |
return s.join(' '); | |
} | |
const _tag = (str) => { | |
if(!str) return ''; | |
if(/\<[^\>]+\>/.test(str)) return str; | |
if(/[\+\*\>\{]/.test(str)) return _getFrag(str); | |
let tag = str.match(/^[^\W]+/), s, | |
attrs = _attrs(str); | |
attrs = attrs? ' '+attrs : ''; | |
if(!tag) tag = 'div'; | |
s = '<'+tag+attrs+(/img|input|br|hr/i.test(tag)? ' />' : '> </'+tag+'>'); | |
return s; | |
} | |
const _sibling = (str) => { | |
if(!str) return ''; | |
let arr = str.split('+'), s = ''; | |
_(arr, (v) => s += _tag(v)); | |
return s; | |
} | |
const _repeat = (str) => { | |
if(!str) return ''; | |
let arr = str.split('*'), s = ''; | |
for(let i=0; i<(arr[1] || 0); i++){ | |
s += _tag(arr[0]); | |
} | |
return s; | |
} | |
const _stack = (str) => { | |
if(!str) return ''; | |
let arr = str.split('>'); | |
let s = ' '; | |
_(arr, (v) => s = s.replace(/\ /g, _tag(v))); | |
return s; | |
} | |
const _bracket = (str, zen) => { | |
if(!str) return ''; | |
if(!/\([^\(\)]+\)/.test(str)) return str; | |
let arr = str.match(/\([^\(\)]+\)/g); | |
_(arr, (f) => { | |
let key = '{'+zen.fragIndex+'}'; | |
if(zen.frags[f]===undefined){ | |
zen.frags[key] = f.replace(/\(|\)/g, ''); | |
} | |
str = str.split(f).join(key); | |
zen.fragIndex++; | |
}); | |
if(/\([^\(\)]+\)/.test(str)) return _bracket(str, zen); | |
return str; | |
} | |
const _getStack = (str, zen) => { | |
if(!str) return ''; | |
if(str.indexOf('>')<0) return str; | |
let reg = /[^\>\+]+\>[^\>]+$/, | |
last = str.match(reg); | |
if(last){ | |
let key = '{'+zen.fragIndex+'}', f = last[0]; | |
if(zen.frags[f]===undefined){ | |
zen.frags[key] = f; | |
} | |
str = str.replace(reg, key); | |
zen.fragIndex++; | |
} | |
if(~str.indexOf('>')) return _getStack(str, zen); | |
return str; | |
} | |
const _getFrag = (str) => { | |
if(~str.indexOf('>')) return _stack(str); | |
if(~str.indexOf('+')) return _sibling(str); | |
if(~str.indexOf('*')) return _repeat(str); | |
if(str.indexOf('{')<0) return _tag(str); | |
return str; | |
} | |
const _getPH = (str) => { | |
let arr = str.split(/\{|\}/g), ret = []; | |
_(arr, (v, i) => { | |
if(!v){ | |
ret[i] = ''; | |
} else if(!isNaN(v)){ | |
let ph = zen.frags[v]; | |
ret[i] = ph? _getPH(ph) : '{'+v+'}'; | |
} else { | |
ret[i] = v; | |
} | |
}); | |
return ret.join(''); | |
} | |
let _s = _bracket(s, zen); | |
_s = _getStack(_s, zen); | |
_(zen.frags, (r, k) => { | |
if(!/\{\d+\}/.test(k)) return; | |
zen.frags[k.replace(/\{|\}/g, '')] = _getFrag(r); | |
}); | |
return _frag(_s).join('').replace(/(\ )|(\{\s+\})/g, ''); | |
}; | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment