Last active
January 22, 2017 10:20
-
-
Save nexpr/6e8a5bb09a58b81d3ee16f1dc6afda24 to your computer and use it in GitHub Desktop.
HJML: Hyper Javascript Markup Language
Convert xml to js
This file contains 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
!function(){ | |
var tags = { | |
// [stmt/exp] | |
// make function | |
function(elem){ | |
var body = prv.block(elem) | |
var name = elem.getAttribute("j:name") || "" | |
var arguments_name = elem.getAttribute("j:arguments") | |
var args | |
if(arguments_name){ | |
args = `...${arguments_name}` | |
}else{ | |
args = Array.from(elem.attributes, attr => { | |
if(attr.prefix === null && !attr.name.includes("-")){ | |
var value | |
if(attr.value === ""){ | |
value = "" | |
}else{ | |
try{ | |
JSON.parse(attr.value) | |
value = `= ${attr.value}` | |
}catch(e){ | |
value = `= "${attr.value}"` | |
} | |
} | |
return `${attr.localName}${value}` | |
} | |
}).filter(e => e).join(", ") | |
} | |
var fn = `function ${name}(${args}){\n${body.replace(/^/gm, "\t")}\n}` | |
return elem.hasAttribute("call-immediate") | |
? `(${fn})()` | |
: fn | |
}, | |
// [exp] | |
lambda(elem){ | |
if(elem.firstElementChild){ | |
var arg = elem.getAttribute("argument") | |
var body = prv.call(elem.firstElementChild) | |
return `${arg} => ${body}` | |
}else{ | |
return `() => {}` | |
} | |
}, | |
// [exp] | |
call(elem){ | |
var name = elem.getAttribute("name") | |
var args = Array.from(elem.children, prv.call).filter(e => e) | |
return `${name}(${args.join(", ")})` | |
}, | |
// [stmt] | |
let(elem){ | |
return prv.define(elem, "let") | |
}, | |
// [stmt] | |
const(elem){ | |
return prv.define(elem, "const") | |
}, | |
// [exp] | |
value(elem){ | |
var str = "" | |
Array.from(elem.childNodes).some(e => { | |
if(e.data) str += e.data | |
return e.nodeType !== Node.TEXT_NODE | |
}) | |
try{ | |
JSON.parse(str) | |
return str | |
}catch(err){ | |
return `"${str}"` | |
} | |
}, | |
// [exp] | |
number(elem){ | |
if(elem.firstElementChild){ | |
return `+${prv.call(elem.firstElementChild).trim()}` | |
}else{ | |
return elem.innerHTML.trim() | |
} | |
}, | |
// [exp] | |
string(elem){ | |
if(elem.firstElementChild){ | |
return `(${prv.call(elem.firstElementChild).trim()}).toString()` | |
}else{ | |
// trim whitespace except nbsp | |
var str = elem.innerHTML.replace(/(^[ \t\n\t]+)|([ \t\n\r]+$)/g, "") | |
return `"${str}"` | |
} | |
}, | |
// [exp] | |
boolean(elem){ | |
if(elem.innerHTML.trim().toLowerCase() === "true"){ | |
return "true" | |
}else if(elem.innerHTML.trim().toLowerCase() === "false"){ | |
return "false" | |
} | |
return `!!(${prv.call(elem.firstElementChild).trim()})` | |
}, | |
// [exp] | |
array(elem){ | |
var items = Array.from(elem.children, prv.call).filter(e => e).join(",\n") | |
return "[\n" + items.replace(/^/gm, "\t") + "\n]" | |
}, | |
// [exp] | |
object(elem){ | |
var items = Array.from(elem.children, slem => { | |
var key = slem.localName | |
var vlem = slem.firstElementChild | |
var value = vlem && prv.call(vlem).trim() | |
return `${key}${vlem ? ": " + value : ""}` | |
}).join(",\n") | |
return "{\n" + items.replace(/^/gm, "\t") + "\n}" | |
}, | |
// [exp] | |
true(elem){ | |
return "true" | |
}, | |
// [exp] | |
false(elem){ | |
return "false" | |
}, | |
// [exp] | |
null(elem){ | |
return "null" | |
}, | |
// [exp] | |
undefined(elem){ | |
return "undefined" | |
}, | |
// [exp] | |
var(elem){ | |
return elem.getAttribute("name") || "" | |
}, | |
// [exp] | |
if(elem){ | |
var cond_elem = prv.childSearch(elem, "cond") | |
var cond_exp = cond_elem | |
? prv.call(cond_elem.firstElementChild) | |
: "" | |
var then_elem = prv.childSearch(elem, "then") | |
var then_exp = then_elem && then_elem.firstElementChild | |
? prv.call(then_elem.firstElementChild) | |
: "" | |
var else_elem = prv.childSearch(elem, "else") | |
var else_exp = else_elem && else_elem.firstElementChild | |
? prv.call(else_elem.firstElementChild) | |
: "" | |
return `${cond_exp}\n\t? ${then_exp}\n\t: ${else_exp}` | |
}, | |
// [exp] | |
equals(elem){ | |
return prv.equals(elem, "===") | |
}, | |
// [exp] | |
"lazy-equals"(elem){ | |
return prv.equals(elem, "==") | |
}, | |
// [exp] | |
assign(elem){ | |
var from = elem.getAttribute("from") | |
var to = elem.getAttribute("to") | |
if(to && !from){ | |
var from_elem = elem.firstElementChild | |
? elem.firstElementChild.localName.toLowerCase() === "from" | |
? elem.firstElementChild | |
: elem | |
: null | |
from = from_elem.firstElementChild ? prv.call(from_elem.firstElementChild) : "" | |
}else{ | |
var from_elem = prv.childSearch(elem, "from") | |
var to_elem = prv.childSearch(elem, "to") | |
from = from_elem.firstElementChild ? prv.call(from_elem.firstElementChild) : "" | |
to = to.firstElementChild ? prv.call(to_elem.firstElementChild) : "" | |
} | |
return `${to} = ${from}` | |
}, | |
// [exp] | |
and(elem){ | |
return `(${Array.from(elem.children, prv.call).filter(e => e).join(" && ")})` | |
}, | |
// [exp] | |
or(elem){ | |
return `(${Array.from(elem.children, prv.call).filter(e => e).join(" || ")})` | |
}, | |
// [exp] | |
add(elem){ | |
return `(${Array.from(elem.children, prv.call).filter(e => e).join(" + ")})` | |
}, | |
// [stmt] | |
stif(elem){ | |
var cond_elem = prv.childSearch(elem, "cond") | |
var cond_exp = cond_elem | |
? prv.call(cond_elem.firstElementChild) | |
: "" | |
var then_elem = prv.childSearch(elem, "then") | |
var then_block = then_elem && then_elem.firstElementChild | |
? prv.block(then_elem) | |
: "" | |
var else_elem = prv.childSearch(elem, "else") | |
var else_block = else_elem && else_elem.firstElementChild | |
? prv.block(else_elem) | |
: "" | |
if(else_block){ | |
return `if(${cond_exp}){\n${then_block.replace(/^/gm, "\t")}\n} else {${else_block.replace(/^/gm, "\t")}\n}` | |
}else{ | |
return `if(${cond_exp}){\n${then_block.replace(/^/gm, "\t")}\n}` | |
} | |
}, | |
// [stmt] | |
return(elem){ | |
var v = elem.getAttribute("var") | |
if(v){ | |
return `return ${v}` | |
} | |
if(elem.firstElementChild){ | |
return `return ${prv.call(elem.firstElementChild).trim()}` | |
} | |
return "return" | |
}, | |
// [stmt] | |
for(elem){ | |
var from = elem.getAttribute("from") || "" | |
var as = elem.getAttribute("as") || "" | |
var block = prv.block(elem) | |
return `for(const ${as} of ${from}){\n${block.replace(/^/gm, "\t")}\n}` | |
}, | |
// [stmt] | |
while(elem){ | |
var cond_elem = prv.childSearch(elem, "cond") | |
var cond_exp = cond_elem | |
? prv.call(cond_elem.firstElementChild) | |
: "" | |
var do_elem = prv.childSearch(elem, "do") | |
var do_block = do_elem && do_elem.firstElementChild | |
? prv.block(do_elem) | |
: "" | |
return `while(${cond_exp}){\n${do_block.replace(/^/gm, "\t")}\n}` | |
}, | |
// [extend] | |
register(elem){ | |
Array.from(elem.children).forEach(child => { | |
var name = child.localName | |
var arg_name = child.getAttribute("argument") || "elem" | |
var cdata = Array.from(child.childNodes).find(e => e.nodeType === Node.CDATA_SECTION_NODE) | |
if(!cdata) return | |
tags[name] = Function(arg_name, "hjml", cdata.data) | |
}) | |
}, | |
} | |
var prv = { | |
// let, const | |
define(elem, def_type){ | |
var type = (elem.getAttribute("j:type") || "").toLowerCase() | |
var attr_lets = Array.from(elem.attributes, attr => { | |
if(attr.prefix || attr.localName.includes("-")) return null | |
if(type !== "string" && attr.value === ""){ | |
return `${def_type} ${attr.localName}` | |
}else{ | |
return `${def_type} ${attr.localName} = ${type==="string"?'"':""}${attr.value}${type==="string"?'"':""}` | |
} | |
}).filter(e => e) | |
var children_lets = Array.from(elem.children, slem => { | |
var name = slem.localName | |
if(slem.firstElementChild){ | |
var exp = prv.call(slem.firstElementChild) | |
return `${def_type} ${name} = ${exp.trim()}` | |
}else{ | |
return `${def_type} ${name}` | |
} | |
}) | |
return attr_lets.concat(children_lets).join("\n") | |
}, | |
// equals | |
equals(elem, eq_type){ | |
var items = Array.from(elem.children, prv.call) | |
return items.reduce((a, b) => { | |
a.prev && a.result.push(`${a.prev} ${eq_type} ${b}`) | |
a.prev = b | |
return a | |
}, {prev: null, result: []}).result.join(" && ") | |
}, | |
// reference variable of elem name | |
refVar(elem){ | |
return elem.localName | |
}, | |
// call tagname's action | |
call(elem){ | |
switch(elem.prefix){ | |
case "var": | |
return prv.refVar(elem) | |
case "fn": | |
var args = Array.from(elem.children, prv.call) | |
return `${elem.localName}(${args.join(", ")})` | |
} | |
var fn = tags[elem.localName.toLowerCase()] || prv.refVar | |
return fn(elem, {tags, prv}) | |
}, | |
block(elem){ | |
return Array.from(elem.children, child => { | |
var stmt = prv.call(child) | |
if(stmt && ["[", "(", "/", "`"].includes(stmt.charAt(0))){ | |
stmt = ";" + stmt | |
} | |
return stmt | |
}).filter(e => e).join("\n") | |
}, | |
childSearch(elem, tagname){ | |
return Array.prototype.find.call(elem.children, e => e.localName.toLowerCase() === tagname) | |
}, | |
} | |
window.hjml = { | |
parse(xml){ | |
var root = new DOMParser().parseFromString(xml, "text/xml").firstElementChild | |
return prv.call(root) | |
}, | |
} | |
}() |
This file contains 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
console.log(hjml.parse(xml)) |
This file contains 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
(function (){ | |
function sample(){ | |
let x = 1 | |
const y = "a" | |
let a = 100 | |
let b = 200 | |
let val | |
val = add_all(a, b, x) | |
const obj = { | |
key1: "1 ", | |
key2: false, | |
arr: [ | |
false, | |
true, | |
undefined, | |
10, | |
null, | |
"abc" | |
] | |
} | |
if((x === 1 && val == 301)){ | |
return | |
} | |
return false | |
? true | |
: plus(val, plus1(x)) | |
} | |
function plus(a, b= 1){ | |
return (a + b) | |
} | |
function plus1(a){ | |
return (a + 1) | |
} | |
function add_all(...args){ | |
let total = 0 | |
for(const e of args){ | |
total = plus(total, e) | |
} | |
return total | |
} | |
console.log(sample()) | |
console.log(((23 + 34 + 45) / (1 - 2 - 3) / 2)) | |
})() |
This file contains 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
<function xmlns:j="hjml" xmlns:var="hjml" xmlns:fn="hjml" call-immediate="true"> | |
<function j:name="sample"> | |
<let x="1"/> | |
<const y="a" j:type="string"/> | |
<let a="100" b="200"/> | |
<let val=""/> | |
<assign to="val"> | |
<call name="add_all"> | |
<a/> | |
<b/> | |
<var:x/> | |
</call> | |
</assign> | |
<const> | |
<obj> | |
<object> | |
<key1> | |
<string> 1 </string> | |
</key1> | |
<key2> | |
<boolean>false</boolean> | |
</key2> | |
<arr> | |
<array> | |
<false/> | |
<true/> | |
<undefined/> | |
<number>10</number> | |
<null/> | |
<string>abc</string> | |
</array> | |
</arr> | |
</object> | |
</obj> | |
</const> | |
<stif> | |
<cond> | |
<and> | |
<equals> | |
<var name="x"/> | |
<value>1</value> | |
</equals> | |
<lazy-equals> | |
<val/> | |
<value>301</value> | |
</lazy-equals> | |
</and> | |
</cond> | |
<then> | |
<return/> | |
</then> | |
</stif> | |
<return> | |
<if> | |
<cond> | |
<false/> | |
</cond> | |
<then> | |
<true/> | |
</then> | |
<else> | |
<call name="plus"> | |
<val/> | |
<call name="plus1"> | |
<var name="x"/> | |
</call> | |
</call> | |
</else> | |
</if> | |
</return> | |
</function> | |
<function j:name="plus" a="" b="1"> | |
<return> | |
<add> | |
<var:a/> | |
<b/> | |
</add> | |
</return> | |
</function> | |
<function j:name="plus1" a=""> | |
<return> | |
<add> | |
<var name="a"/> | |
<number>1</number> | |
</add> | |
</return> | |
</function> | |
<function j:name="add_all" j:arguments="args"> | |
<let total="0" j:type="number"/> | |
<for from="args" as="e"> | |
<assign to="total"> | |
<fn:plus> | |
<var name="total"/> | |
<var name="e"/> | |
</fn:plus> | |
</assign> | |
</for> | |
<return var="total"/> | |
</function> | |
<fn:console.log> | |
<call name="sample"/> | |
</fn:console.log> | |
<!-- extension --> | |
<register> | |
<sub argument="element"> | |
<![CDATA[ | |
return "(" + Array.from(element.children, hjml.prv.call).join(" - ") + ")" | |
]]> | |
</sub> | |
<div> | |
<![CDATA[ | |
return "(" + Array.from(elem.children, hjml.prv.call).join(" / ") + ")" | |
]]> | |
</div> | |
</register> | |
<fn:console.log> | |
<div> | |
<add> | |
<number>23</number> | |
<number>34</number> | |
<number>45</number> | |
</add> | |
<sub> | |
<number>1</number> | |
<number>2</number> | |
<number>3</number> | |
</sub> | |
<number>2</number> | |
</div> | |
</fn:console.log> | |
</function> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment