Skip to content

Instantly share code, notes, and snippets.

@frkd-dev
Last active January 13, 2018 13:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save frkd-dev/0e0f0e7b6b89d0731e3f7a260e8e1cb1 to your computer and use it in GitHub Desktop.
Save frkd-dev/0e0f0e7b6b89d0731e3f7a260e8e1cb1 to your computer and use it in GitHub Desktop.
Tiny emmet parser implementation
/*
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)? ' />' : '>&nbsp;</'+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 = '&nbsp;';
_(arr, (v) => s = s.replace(/\&nbsp;/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(/(\&nbsp;)|(\{\s+\})/g, '');
};
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment