Skip to content

Instantly share code, notes, and snippets.

@nexpr
Last active January 22, 2017 10:20
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 nexpr/6e8a5bb09a58b81d3ee16f1dc6afda24 to your computer and use it in GitHub Desktop.
Save nexpr/6e8a5bb09a58b81d3ee16f1dc6afda24 to your computer and use it in GitHub Desktop.
HJML: Hyper Javascript Markup Language Convert xml to js
!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)
},
}
}()
console.log(hjml.parse(xml))
(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))
})()
<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>&#x0020;1&#x00A0;</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