var walker = ASTWalker();
var rawAST = esprima.parse(codeStr, { loc : true, range : true, comment : true});
walker.startWalk( rawAST, {} );
var code = walker.getCode();
During initialization options can be given Namespace as option
var walker = ASTWalker({
defaultNamespace: "DOM", // "react", "DOM", "SVG"
toES5: true,
noOutput:false
});
Each node can belong to a namespace, for example DOM nodes are int DOM namespace, SVG nodes in SVG namespace and React nodes are in React -namespace. When DOM tree is walked and SVG node is encountered, the parser will push "SVG" into namespace stack.
https://github.com/terotests/ASTWalker/blob/master/release/ASTWalker-0.95.js#L2754
When "SVG" is the current namespace, the ASTWalker first looks for SVGJSXElement
instead of JSXElement
and calls it, if the function is found. If it is not found, then the function without prefix gets called.
noOutput
will disable code generation (output string), it will just walk the AST tree and generate context variables. This is useful when evaluating some statistics of the code and not actually using the end result output.
defaultNamespace
is the initial namespace, the default prefix for the function used to walk the AST nodes from the beginning.
forceNamespace
is the same as defaultNamepace
, but it will not allow automatic SVG namespace detection to change the initial namespace to something else based on node type.
toES5
(NOTE: current must be set to true
, arrow functions have a bug) transpiles arrow functions to ES5, but does not try to do anything more at the moment.
- ArrayExpression
- ArrayPattern
- ArrowExpression
- ArrowFunctionExpression
- AssignmentExpression
- BinaryExpression
- BlockStatement
- BreakStatement
- breakWalk
- CallExpression
- CatchClause
- ClassBody
- ClassDeclaration
- ConditionalExpression
- ContinueStatement
- createContext
- createId
- createObject
- DebuggerStatement
- DoWhileStatement
- EmptyStatement
- endBlock
- endCollecting
- ExpressionStatement
- find
- ForInStatement
- ForOfStatement
- ForStatement
- FunctionDeclaration
- FunctionExpression
- getCode
- getLineNumber
- getParent
- getStructures
- Identifier
- IfStatement
- indent
- initDOMC
- initDOMCNamespace
- initDOMNamespace
- initFRZRNamespace
- initReactNamespace
- initSVGNamespace
- JSXAttribute
- JSXClosingElement
- JSXElement
- JSXEmptyExpression
- JSXExpressionContainer
- JSXIdentifier
- JSXMemberExpression
- JSXNamespacedName
- JSXOpeningElement
- JSXSpreadAttribute
- LabeledStatement
- Literal
- LogicalExpression
- MemberExpression
- MethodDefinition
- NewExpression
- nlIfNot
- ObjectExpression
- ObjectPattern
- out
- prevChar
- Program
- Property
- pushStructure
- RestElement
- ReturnStatement
- saveNode
- SequenceExpression
- skip
- startBlock
- startCollecting
- startWalk
- Super
- SwitchCase
- SwitchStatement
- TemplateElement
- TemplateLiteral
- ThisExpression
- ThrowStatement
- TryStatement
- UnaryExpression
- UpdateExpression
- VariableDeclaration
- VariableDeclarator
- walk
- walkAsString
- WhileStatement
- WithStatement
- YieldExpression
The class has following internal singleton variables:
- _cnt
var me = this;
// Check values...
if( node.elements && node.elements.length>=0) {
// Walk the array elements
this.out("[");
var cnt=0;
node.elements.forEach( function(e) {
if(cnt++>0) me.out(",");
me.trigger("ArrayElement", e);
me.walk(e, ctx);
})
this.out("]");
}
var me = this;
// Check values...
if( node.elements && node.elements.length>0) {
// Walk the array elements
this.out("[");
var cnt=0;
node.elements.forEach( function(e) {
if(cnt++>0) me.out(",");
me.trigger("ArrayElement", e);
me.walk(e, ctx);
})
this.out("]");
}
if(this._options.toES5) {
this.out("function");
if(node.generator) {
this.out("* ");
}
var me = this;
this.out("(");
var cnt=0;
node.params.forEach(function(p) {
if(cnt++>0) me.out(",");
me.walk(p,ctx);
if(node.defaults && node.defaults[cnt-1]) {
var defP = node.defaults[cnt-1];
me.out("=");
me.walk( defP, ctx);
}
})
this.out(")");
me.trigger("FunctionBody", node.body);
if(node.body.type!="BlockStatement") this.out("{ return ");
this.walk(node.body, ctx);
if(node.body.type!="BlockStatement") this.out("}");
this.out(".bind(this)");
return;
}
this.out("function");
if(node.generator) {
this.trigger("FunctionGenerator", node);
this.out("* ");
}
if(node.id && node.id.name) {
this.trigger("FunctionName", node);
this.out(" "+node.id.name+" ");
} else {
this.trigger("FunctionAnonymous", node);
}
var me = this;
this.out("(");
var cnt=0;
node.params.forEach(function(p) {
if(cnt++>0) me.out(",");
me.trigger("FunctionParam", p);
me.walk(p,ctx);
if(node.defaults && node.defaults[cnt-1]) {
var defP = node.defaults[cnt-1];
me.out("=");
me.trigger("FunctionDefaultParam", defP);
me.walk( defP, ctx);
}
})
this.out(")");
me.trigger("FunctionBody", node.body);
this.walk(node.body, ctx);
this.trigger("AssigmentLeft", node.left);
this.walk(node.left, ctx);
this.out(" "+node.operator+" ");
this.trigger("AssigmentRight", node.right);
this.walk(node.right, ctx);
// var logicals = ["==", "<=", ">=", "==", "===", "!=", ]
var bLeftNeedsPar = true, bRightNeedsPar=true;
if(node.left.type == "Identifier" || node.left.type == "Literal") {
bLeftNeedsPar = false;
}
if(node.right.type == "Identifier" || node.right.type == "Literal") {
bRightNeedsPar = false;
}
if(bLeftNeedsPar) this.out("(");
this.walk(node.left, ctx);
if(bLeftNeedsPar) this.out(")");
this.out(" "+node.operator+" ");
if(bRightNeedsPar) this.out("(");
this.walk(node.right, ctx);
if(bRightNeedsPar) this.out(")");
// keeps at the same context right now I guess....
this.out(" {",true);
this.indent(1);
this.walk(node.body,ctx, true);
this.indent(-1);
this.out("}");
this.nlIfNot();
this.out("break ");
if(node.label) this.walk(node.label, ctx);
this.out("", true);
this._breakWalk = true;
if(node.callee) {
if(node.callee.type=="FunctionExpression") this.out("(");
this.walk(node.callee, ctx);
if(node.callee.type=="FunctionExpression") this.out(")");
this.out("(");
if(node.arguments) {
var me = this,
cnt=0;
node.arguments.forEach(function(n) {
if(cnt++>0) me.out(", ");
me.walk(n,ctx);
});
}
this.out(")");
}
this.out(" catch ");
if(node.param) {
this.out("(");
this.walk(node.param, ctx);
this.out(")");
}
if(node.body) {
this.walk(node.body, ctx);
}
this.out("{", true);
// walk the class body
this.indent(1);
this.walk(node.body, ctx);
this.indent(-1);
this.out("}", true);
this.out("class ");
if(node.id) {
this.walk( node.id, ctx );
this.out(" ");
}
if(node.superClass) {
this.trigger("Extends", node.superClass);
this.out(" extends ");
this.walk( node.superClass, ctx);
}
if(node.body) {
this.walk( node.body,ctx);
}
this.walk(node.test, ctx);
this.out(" ? ");
this.walk(node.consequent, ctx);
this.out(" : ");
this.walk(node.alternate, ctx);
/*
interface ConditionalExpression <: Expression {
type: "ConditionalExpression";
test: Expression;
alternate: Expression;
consequent: Expression;
}
*/
this.nlIfNot();
this.out("continue ");
if(node.label) this.walk(node.label, ctx);
this.out("", true);
parent
Parent context
if(!this._objects) {
this._objects = {};
}
var id = this.createId();
var ctx = {
id : id,
vars : {},
functions : {},
parentCtx : parent
};
this._objects[id] = ctx;
return ctx;
prefix
Opitional prefix
if(!this._localId) {
this._localId = 0;
}
this._localId++;
return (prefix ? prefix : "") + this._localId;
if(!this._objects) this._objects = {};
this._objects[id] = objData;
this.nlIfNot();
this.out("debugger;");
this.nlIfNot();
this.out("do ",true);
if(node.body) {
var bNeedsPar = false;
if(node.body.type != "BlockStatement" && ( node.body.type.indexOf("Statement")>=0) ) {
bNeedsPar = true;
}
if(bNeedsPar) {
this.out("{");
this.indent(1);
}
this.walk(node.body,ctx);
if(bNeedsPar) {
this.indent(-1);
this.out("}");
}
}
this.out(" ");
if(node.test) {
this.out("while(");
this.trigger("DoWhileTest", node.test);
this.walk(node.test,ctx);
this.out(")");
}
this.out("", true);
this.out("}", true);
this.indent(-1);
this._collecting = false;
this.nlIfNot();
this.walk(node.expression, ctx);
this.out(";", true);
id
Object to look for
this.nlIfNot();
this.out("for");
this.out("(");
var oldf = ctx._forVar;
ctx._forVar = 1;
if(node.left) {
this.trigger("ForInLeft", node.left);
this.walk(node.left,ctx);
}
ctx._forVar = oldf;
this.out(" in ");
if(node.right) {
this.trigger("ForInRight", node.right);
this.walk(node.right,ctx);
}
this.out(")");
if(node.body) {
this.trigger("ForInBody", node.body);
var bNeedsPar = false;
if(node.body.type != "BlockStatement" && ( node.body.type.indexOf("Statement")>=0) ) {
bNeedsPar = true;
}
if(bNeedsPar) {
this.out("{");
this.indent(1);
}
this.walk(node.body,ctx);
if(bNeedsPar) {
this.indent(-1);
this.out("}");
}
}
this.out("", true);
this.nlIfNot();
this.out("for");
this.out("(");
var oldf = ctx._forVar;
ctx._forVar = 1;
if(node.left) {
this.trigger("ForOfLeft", node.left);
this.walk(node.left,ctx);
}
ctx._forVar = oldf;
this.out(" of ");
if(node.right) {
this.trigger("ForOfRight", node.right);
this.walk(node.right,ctx);
}
this.out(")");
if(node.body) {
this.trigger("ForOfBody", node.body);
var bNeedsPar = false;
if(node.body.type != "BlockStatement" && ( node.body.type.indexOf("Statement")>=0) ) {
bNeedsPar = true;
}
if(bNeedsPar) {
this.out("{");
this.indent(1);
}
this.walk(node.body,ctx);
if(bNeedsPar) {
this.indent(-1);
this.out("}");
}
}
this.out("", true);
this.out("for");
this.out("(");
var oldf = ctx._forVar;
ctx._forVar = 1;
if(node.init) {
this.walk(node.init,ctx);
}
ctx._forVar = oldf;
this.out("; ");
if(node.test) {
this.walk(node.test,ctx);
}
this.out("; ");
if(node.update) {
this.walk(node.update,ctx);
}
this.out(")");
if(node.body) {
var bNeedsPar = false;
if(node.body.type != "BlockStatement" && ( node.body.type.indexOf("Statement")>=0) ) {
bNeedsPar = true;
}
if(bNeedsPar) {
this.out("{");
this.indent(1);
}
this.walk(node.body,ctx);
if(bNeedsPar) {
this.indent(-1);
this.out("}");
}
}
this.out("", true);
var subCtx = this.createContext( ctx );
node.contextId = subCtx.id;
this.out("function");
if(node.generator) this.out("*");
if(node.id && node.id.name) {
this.trigger("FunctionName", node);
this.out(" "+node.id.name+" ");
if(node.id.name) {
ctx.functions[node.id.name] = node;
}
} else {
this.trigger("FunctionAnonymous", node);
}
var me = this;
this.out("(");
var cnt=0;
node.params.forEach(function(p) {
if(cnt++>0) me.out(",");
me.trigger("FunctionParam", p);
me.walk(p,subCtx);
if(node.defaults && node.defaults[cnt-1]) {
var defP = node.defaults[cnt-1];
me.out("=");
me.trigger("FunctionDefaultParam", defP);
me.walk( defP, subCtx);
}
})
this.out(")");
me.trigger("FunctionBody", node.body);
this.walk(node.body, subCtx);
var subCtx = this.createContext( ctx ); // { parentCtx : ctx };
node.contextId = subCtx.id;
if(!this.__insideMethod) this.out("function");
if(node.generator) {
this.trigger("FunctionGenerator", node);
this.out("* ");
}
if(node.id && node.id.name) {
this.trigger("FunctionName", node);
this.out(" "+node.id.name+" ");
if(node.id.name) {
ctx.functions[node.id.name] == node;
}
} else {
this.trigger("FunctionAnonymous", node);
}
var me = this;
this.out("(");
var cnt=0;
node.params.forEach(function(p) {
if(cnt++>0) me.out(",");
me.trigger("FunctionParam", p);
me.walk(p,subCtx);
if(node.defaults && node.defaults[cnt-1]) {
var defP = node.defaults[cnt-1];
me.out("=");
me.trigger("FunctionDefaultParam", defP);
me.walk( defP, subCtx);
}
})
this.out(")");
me.trigger("FunctionBody", node.body);
this.walk(node.body, subCtx);
return this._codeStr;
return this._lineNumber;
if(node) {
if(node.nodeid) {
var p = this._nodeParents[node.nodeid];
return p;
}
return;
}
if(this._path) {
var len = this._path.length;
return this._path[len-1];
}
return this._structures;
node
Node to walk
ctx
Context to use
// just output the identifier name...
this.out(node.name);
this.nlIfNot();
this.out("if(");
this.trigger("IfTest", node.test);
this.walk(node.test, ctx);
this.out(")");
if(node.consequent) {
var bNeedsPar = false;
if(node.consequent.type != "BlockStatement" ) bNeedsPar=true;
this.trigger("IfConsequent", node.consequent);
if(bNeedsPar) {
this.out("{");
this.indent(1);
}
this.walk(node.consequent,ctx);
if(bNeedsPar) {
this.indent(-1);
this.out("}");
}
}
if(node.alternate) {
this.out(" else ");
var bNeedsPar = false;
if(node.alternate.type != "BlockStatement" ) bNeedsPar=true;
this.trigger("IfAlternate", node.alternate);
if(bNeedsPar) {
this.out("{");
this.indent(1);
}
this.walk(node.alternate,ctx);
if(bNeedsPar) {
this.indent(-1);
if(this.prevChar() != "{") this.out("",true);
this.out("}");
}
}
this.out("", true);
change
Delta to modify the indent
this._indent += change;
if(this._indent<0) this._indent = 0;
Walks the AST tree, creates events on walk steps. Options : defaultNamespace, forceNamespace.
this._structures = [];
this._path = [];
this._tabChar = " ";
this._codeStr = "";
this._currentLine = "";
this._indent = 0;
this._options = options || {};
if(options && !options.toES5) {
this._options.toES5 = false;
} else {
this._options.toES5 = true;
}
this._nsList = ["react", "DOM", "SVG", "FRZR"];
this.initReactNamespace();
this.initDOMNamespace();
this.initDOMCNamespace();
this.initSVGNamespace();
this.initFRZRNamespace();
if(this._options.defaultNamespace == "DOMC") {
// this.out("$$x(e,expr)",true);
this.out("function $$x(e,expr){",true);
this.out("if(typeof(expr)=='string' || typeof(expr)=='number') {",true);
this.indent(1);
this.out("e.appendChild(document.createTextNode(expr));",true);
this.indent(-1);
this.out("} else {");
this.indent(1);
this.out("if(expr instanceof Array) {",true);
this.indent(1);
this.out('expr.forEach(function(ee){e.appendChild(ee)});',true)
this.indent(-1);
this.out("} else { ",true);
this.out("if(typeof(expr)=='object')",true);
this.indent(1);
this.out("e.appendChild(expr);",true);
this.indent(-1);
this.out("}",true);
this.indent(-1);
this.out("}");
this.out("}",true);
// this.out("$et(e,\""+str+"\")",true);
// this.out("e.appendChild(document.createTextNode(\""+str+"\"));",true);
this.out("function $$t(e,s){",true);
this.out("e.appendChild(document.createTextNode(s));",true);
this.out("}",true);
// this.out("e=$$e('"+elemName+"');",true);
// this.out("e=document.createElement('"+elemName+"');",true);
this.out("function $$e(e){",true);
this.out("return document.createElement(e);",true);
this.out("}",true);
// this.out("var el=$$o(this)");
this.out("function $$o(me){",true);
this.out("var fn = function(){this.parent=me;};");
this.out("fn.prototype = me;",true);
this.out("return fn;",true);
this.out("}",true);
}
Compressed namespace for DOM elements
// tags that will be converted to DOM element access
var _elemNamesList = ["a", "abbr", "acronym","address","applet","area","article","aside","audio",
"b","base","basefont","bdi","bdo","big","blockquote","body","br","button","canvas",
"caption","center","cite","code","col","colgroup","datalist","dd","del","details",
"dfn","dialog","dir","div","dl","dt","em","embed","fieldset","figcaption","figure","font",
"footer","form","frame","frameset","h1","h2","h3","h4","h5","h6","head","header","hgroup",
"hr","html","i","iframe","img","input","ins","kbd","keygen","label","legend","li","link",
"main","map","mark","menu","menuitem","meta","meter","nav","noframes","noscript","object",
"ol","optgroup","option","output","p","param","pre","progress","q","rp","rt","ruby",
"s","sampe","script","section","select","small","source","span","strike","strong","style",
"sub","summary","sup","table","tbody","td","textarea","tfoot","th","thead","time","title",
"tr","track","tt","u","ul","var","video","wbr"];
// _fnCall indicates the result is a key-value of an object expression
_myTrait_.DOMCJSXAttribute = function(node, ctx) {
this.out("\"");
if(node.name.type=="JSXNamespacedName") {
this.out(node.name.namespace.name);
this.out(":");
this.out(node.name.name.name);
} else {
this.out(node.name.name);
}
this.out("\"");
if(ctx._fnCall) {
this.out(":");
} else {
this.out(",");
}
this.walk(node.value,ctx);
}
_myTrait_.DOMCJSXOpeningElement = function(node,ctx) {
this.out("(function() { ",true);
this.indent(1);
this.out("var e,me=this;",true);
var elemName, objName;
if(node.name.type=="JSXMemberExpression") {
var obj = node.name;
if(obj.object.name == ctx.ns) {
elemName = obj.property.name;
} else {
elemName = obj.property.name;
objName = obj.object.name;
// console.error("JSXMemberExpression not currently supported at react Namepace");
}
} else {
elemName = node.name.name;
}
// Allowed elem names etc...
if(!objName && _elemNamesList.indexOf(elemName)>=0) {
this.out("e=$$e('"+elemName+"');",true);
// this.out("e=document.createElement('"+elemName+"');",true);
if(node.attributes && node.attributes.length) {
for(var i=0; i<node.attributes.length;i++) {
var attrName = node.attributes[i].name.name;
if(attrName && attrName.substring(0,2)=="on") {
var eventName = attrName.slice(2).toLowerCase();
this.out("e.addEventListener('"+eventName+"', function(){me['"+attrName+"'](");
this.walk(node.attributes[i].value,ctx);
this.out(")}.bind(this));",true);
continue;
}
this.out("e.setAttribute(");
this.walk(node.attributes[i],ctx);
this.out(");",true);
}
} else {
// this.out("null");
}
} else {
this.out("var el=$$o(this);",true);
//this.out("var self = function(){this.parent=me;};");
//this.out("self.prototype = this;",true);
if(objName) {
this.out("e = " + objName+"."+elemName + ".apply(new el(),[");
} else {
this.out("e = " + elemName + ".apply(new el(),[");
}
var prevFnState = ctx._fnCall;
ctx._fnCall = true;
if (node.attributes && node.attributes.length) {
this.out("{", true);
this.indent(1);
for (var i = 0; i < node.attributes.length; i++) {
if (i > 0) this.out(",", true);
this.walk(node.attributes[i], ctx);
}
this.indent(-1);
this.out("}");
}
ctx._fnCall = prevFnState;
this.out("]);", true);
}
if(node.selfClosing) {
this.out("return e;");
this.indent(-1);
this.out("}).apply(this,[])",true);
} else {
}
}
_myTrait_.DOMCLiteral = function(node,ctx) {
if(typeof(node.value)=="string") {
this.out("\"");
this.out(node.value.split("\n").join("\\n"));
// this.out(node.value);
this.out("\"");
} else {
this.out(node.value);
}
}
_myTrait_.DOMCJSXExpressionContainer = function(node,ctx) {
this.walk(node.expression, ctx);
}
_myTrait_.DOMCJSXElement = function(node,ctx) {
var inJsx = ctx._inJSX;
ctx._inJSX = true;
var bExpr = false;
this.walk(node.openingElement, ctx);
var cnt=0;
if(node.children) {
for(var i=0; i<node.children.length;i++) {
var child = node.children[i];
if(child.type=="JSXElement") {
this.out("e.appendChild(");
this.indent(1);
this.walk(child,ctx);
this.indent(-1);
this.out(")",true);
}
if(child.type=="Literal") {
var value = child.value;
if(typeof(value)=="string") {
var lines = value.split("\n");
var str = lines.join("\\n");
this.out("$$t(e,\""+str+"\")",true);
// this.out("e.appendChild(document.createTextNode(\""+str+"\"));",true);
} else {
this.out("e.appendChild(document.createTextNode(");
this.walk(child,ctx);
this.out("))",true);
}
}
if(child.type=="JSXExpressionContainer") {
if(!bExpr) {
this.out("var expr=")
this.walk(child, ctx);
this.out(";",true);
}
this.out("$$x(e,expr)",true);
/*
this.out("if(typeof(expr)=='string' || typeof(expr)=='number') {",true);
this.indent(1);
this.out("e.appendChild(document.createTextNode(expr));",true);
this.indent(-1);
this.out("} else {");
this.indent(1);
this.out("if(expr instanceof Array) {",true);
this.indent(1);
this.out('expr.forEach(function(ee){e.appendChild(ee)});',true)
this.indent(-1);
this.out("} else { ",true);
this.out("if(typeof(expr)=='object')",true);
this.indent(1);
this.out("e.appendChild(expr);",true);
this.indent(-1);
this.out("}",true);
this.indent(-1);
this.out("}");
*/
}
}
}
this.walk(node.closingElement, ctx);
// if(!inJsx) this.out(";", true);
ctx._inJSX = inJsx;
}
_myTrait_.DOMCJSXClosingElement = function(node,ctx) {
this.out("return e;",true);
this.indent(-1);
this.out("}).apply(this,[])",true);
}
// tags that will be converted to DOM element access
var _elemNamesList = ["a", "abbr", "acronym","address","applet","area","article","aside","audio",
"b","base","basefont","bdi","bdo","big","blockquote","body","br","button","canvas",
"caption","center","cite","code","col","colgroup","datalist","dd","del","details",
"dfn","dialog","dir","div","dl","dt","em","embed","fieldset","figcaption","figure","font",
"footer","form","frame","frameset","h1","h2","h3","h4","h5","h6","head","header","hgroup",
"hr","html","i","iframe","img","input","ins","kbd","keygen","label","legend","li","link",
"main","map","mark","menu","menuitem","meta","meter","nav","noframes","noscript","object",
"ol","optgroup","option","output","p","param","pre","progress","q","rp","rt","ruby",
"s","sampe","script","section","select","small","source","span","strike","strong","style",
"sub","summary","sup","table","tbody","td","textarea","tfoot","th","thead","time","title",
"tr","track","tt","u","ul","var","video","wbr"];
// _fnCall indicates the result is a key-value of an object expression
_myTrait_.DOMJSXAttribute = function(node, ctx) {
this.out("\"");
if(node.name.type=="JSXNamespacedName") {
this.out(node.name.namespace.name);
this.out(":");
this.out(node.name.name.name);
} else {
this.out(node.name.name);
}
this.out("\"");
if(ctx._fnCall) {
this.out(":");
} else {
this.out(",");
}
if(node.value===null) {
this.out("null");
} else {
this.walk(node.value,ctx);
}
}
_myTrait_.DOMJSXOpeningElement = function(node,ctx) {
this.out("(function() { ",true);
this.indent(1);
this.out("var e,me=this;",true);
var elemName, objName;
if(node.name.type=="JSXMemberExpression") {
var obj = node.name;
if(obj.object.name == ctx.ns) {
elemName = obj.property.name;
} else {
elemName = obj.property.name;
objName = obj.object.name;
// console.error("JSXMemberExpression not currently supported at react Namepace");
}
} else {
elemName = node.name.name;
}
// Allowed elem names etc...
if(!objName && _elemNamesList.indexOf(elemName)>=0) {
this.out("e=document.createElement('"+elemName+"');",true);
if(node.attributes && node.attributes.length) {
for(var i=0; i<node.attributes.length;i++) {
var attrName = node.attributes[i].name.name;
if(attrName && attrName.substring(0,2)=="on") {
var eventName = attrName.slice(2).toLowerCase();
// e.addEventListener('click', function(){me['click']("ok")});return e;}).apply(this,[])
var valueNode = node.attributes[i].value;
// && valueNode.expression.type=="CallExpression"
if(valueNode.type=="JSXExpressionContainer" ) {
this.trigger("JSXEventListener", { event : eventName, fn : attrName, elemNode : node, node: node.attributes[i], ctx : ctx });
this.out("e.addEventListener('"+eventName+"', function(event){");
this.walk(valueNode.expression,ctx);
this.out("}.bind(this));",true);
} else {
this.trigger("JSXEventListener", { event : eventName, fn : attrName, elemNode : node, node: node.attributes[i], ctx : ctx });
this.out("e.addEventListener('"+eventName+"', function(event){me['"+attrName+"'](");
this.walk(node.attributes[i].value,ctx);
this.out(")});",true);
}
continue;
}
this.out("e.setAttribute(");
this.walk(node.attributes[i],ctx);
this.out(");",true);
}
} else {
// this.out("null");
}
} else {
// remove the "parent"
this.out("var self = function(){ this._parent = me;};");
this.out("self.prototype = this;",true);
if(objName) {
this.out("e = " + objName+"."+elemName + ".apply(new self(),[");
} else {
this.out("e = " + elemName + ".apply(new self(),[");
}
this.trigger("JSXCustomElement", { obj : objName, elem : elemName, node: node, ctx : ctx });
var prevFnState = ctx._fnCall;
ctx._fnCall = true;
if (node.attributes && node.attributes.length) {
this.out("{", true);
this.indent(1);
for (var i = 0; i < node.attributes.length; i++) {
if (i > 0) this.out(",", true);
this.walk(node.attributes[i], ctx);
}
this.indent(-1);
this.out("}");
}
ctx._fnCall = prevFnState;
this.out("]);", true);
}
if(node.selfClosing) {
this.out("return e;");
this.indent(-1);
this.out("}).apply(this,[])",true);
} else {
}
}
_myTrait_.DOMLiteral = function(node,ctx) {
if(typeof(node.value)=="string") {
this.out("\"");
this.out(node.value.split("\n").join("\\n"));
// this.out(node.value);
this.out("\"");
} else {
if(typeof(node.raw)!="undefined") {
this.out(node.raw);
} else {
this.out(node.value);
}
}
}
_myTrait_.DOMJSXExpressionContainer = function(node,ctx) {
this.walk(node.expression, ctx);
}
_myTrait_.DOMJSXElement = function(node,ctx) {
var inJsx = ctx._inJSX;
ctx._inJSX = true;
var bExpr = false;
this.walk(node.openingElement, ctx);
var cnt=0;
if(node.children) {
for(var i=0; i<node.children.length;i++) {
var child = node.children[i];
if(child.type=="JSXElement") {
this.out("e.appendChild(");
this.indent(1);
this.walk(child,ctx);
this.indent(-1);
this.out(")",true);
}
if(child.type=="Literal") {
var value = child.value;
if(typeof(value)=="string") {
var lines = value.split("\n");
var str = lines.join("\\n");
this.out("e.appendChild(document.createTextNode(\""+str+"\"));",true);
} else {
this.out("e.appendChild(document.createTextNode(");
this.walk(child,ctx);
this.out("))",true);
}
}
if(child.type=="JSXExpressionContainer") {
if(!bExpr) {
this.out("var expr=")
this.walk(child, ctx);
this.out(";",true);
}
this.out("if(typeof(expr)=='string' || typeof(expr)=='number') {",true);
this.indent(1);
this.out("e.appendChild(document.createTextNode(expr));",true);
this.indent(-1);
this.out("} else {");
this.indent(1);
this.out("if(expr instanceof Array) {",true);
this.indent(1);
this.out('expr.forEach(function(ee){e.appendChild(ee)});',true)
this.indent(-1);
this.out("} else { ",true);
this.out("if(typeof(expr)=='object')",true);
this.indent(1);
this.out("e.appendChild(expr);",true);
this.indent(-1);
this.out("}",true);
this.indent(-1);
this.out("}");
}
}
}
this.walk(node.closingElement, ctx);
// if(!inJsx) this.out(";", true);
ctx._inJSX = inJsx;
}
_myTrait_.DOMJSXClosingElement = function(node,ctx) {
this.out("return e;",true);
this.indent(-1);
this.out("}).apply(this,[])",true);
}
// tags that will be converted to DOM element access
var _elemNamesList = ["a", "abbr", "acronym","address","applet","area","article","aside","audio",
"b","base","basefont","bdi","bdo","big","blockquote","body","br","button","canvas",
"caption","center","cite","code","col","colgroup","datalist","dd","del","details",
"dfn","dialog","dir","div","dl","dt","em","embed","fieldset","figcaption","figure","font",
"footer","form","frame","frameset","h1","h2","h3","h4","h5","h6","head","header","hgroup",
"hr","html","i","iframe","img","input","ins","kbd","keygen","label","legend","li","link",
"main","map","mark","menu","menuitem","meta","meter","nav","noframes","noscript","object",
"ol","optgroup","option","output","p","param","pre","progress","q","rp","rt","ruby",
"s","sampe","script","section","select","small","source","span","strike","strong","style",
"sub","summary","sup","table","tbody","td","textarea","tfoot","th","thead","time","title",
"tr","track","tt","u","ul","var","video","wbr"];
// _fnCall indicates the result is a key-value of an object expression
_myTrait_.FRZRJSXAttribute = function(node, ctx) {
this.out("\"");
if(node.name.type=="JSXNamespacedName") {
this.out(node.name.namespace.name);
this.out(":");
this.out(node.name.name.name);
} else {
this.out(node.name.name);
}
this.out("\"");
if(ctx._fnCall) {
this.out(":");
} else {
this.out(",");
}
if(node.value===null) {
this.out("null");
} else {
this.walk(node.value,ctx);
}
}
_myTrait_.FRZRJSXOpeningElement = function(node,ctx) {
this.out("(function() { ",true);
this.indent(1);
this.out("var e,me=this;",true);
var elemName, objName;
if(node.name.type=="JSXMemberExpression") {
var obj = node.name;
if(obj.object.name == ctx.ns) {
elemName = obj.property.name;
} else {
elemName = obj.property.name;
objName = obj.object.name;
// console.error("JSXMemberExpression not currently supported at react Namepace");
}
} else {
elemName = node.name.name;
}
// Allowed elem names etc...
if(!objName && _elemNamesList.indexOf(elemName)>=0) {
this.out("e = new frzr.View({el:'"+elemName+"'",false);
// -- set attributes
// if (i > 0) this.out(",", true);
// -- update
ctx._fnCall = true;
var bHasAttrs = false;
if(node.attributes && node.attributes.length) {
bHasAttrs = true;
this.indent(2);
var _updFn;
for(var i=0; i<node.attributes.length;i++) {
var attrName = node.attributes[i].name.name;
if(attrName && attrName.substring(0,2)=="on") {
continue;
}
if(attrName =="update") {
_updFn = node.attributes[i];
continue;
}
this.out(",", true);
this.walk(node.attributes[i],ctx);
}
if(_updFn) {
this.out(",", true);
this.walk(_updFn,ctx);
}
this.indent(-2);
} else {
// this.out("null");
}
ctx._fnCall = false;
this.out("});",true);
if(bHasAttrs) {
for(var i=0; i<node.attributes.length;i++) {
var attrName = node.attributes[i].name.name;
if(attrName && attrName.substring(0,2)=="on") {
var eventName = attrName.slice(2).toLowerCase();
var valueNode = node.attributes[i].value;
// && valueNode.expression.type=="CallExpression"
if(valueNode.type=="JSXExpressionContainer" ) {
this.out("e.addListener('"+eventName+"', function(event){");
this.walk(valueNode.expression,ctx);
this.out("}.bind(this));",true);
} else {
this.out("e.addListener('"+eventName+"', function(event){me['"+attrName+"'](");
this.walk(node.attributes[i].value,ctx);
this.out(")});",true);
}
continue;
}
}
}
} else {
// remove the "parent"
this.out("var self = function(){ this._parent = me;};");
this.out("self.prototype = this;",true);
if(objName) {
this.out("e = " + objName+"."+elemName + ".apply(new self(),[");
} else {
this.out("e = " + elemName + ".apply(new self(),[");
}
this.trigger("JSXCustomElement", { obj : objName, elem : elemName, node: node, ctx : ctx });
var prevFnState = ctx._fnCall;
ctx._fnCall = true;
if (node.attributes && node.attributes.length) {
this.out("{", true);
this.indent(1);
for (var i = 0; i < node.attributes.length; i++) {
if (i > 0) this.out(",", true);
this.walk(node.attributes[i], ctx);
}
this.indent(-1);
this.out("}");
}
ctx._fnCall = prevFnState;
this.out("]);", true);
}
if(node.selfClosing) {
this.out("return e;");
this.indent(-1);
this.out("}).apply(this,[])",true);
} else {
}
}
_myTrait_.FRZRLiteral = function(node,ctx) {
if(typeof(node.value)=="string") {
this.out("\"");
this.out(node.value.split("\n").join("\\n"));
this.out("\"");
} else {
if(typeof(node.raw)!="undefined") {
this.out(node.raw);
} else {
this.out(node.value);
}
}
}
_myTrait_.FRZRJSXExpressionContainer = function(node,ctx) {
this.walk(node.expression, ctx);
}
_myTrait_.FRZRJSXElement = function(node,ctx) {
var inJsx = ctx._inJSX;
ctx._inJSX = true;
var bExpr = false;
this.walk(node.openingElement, ctx);
var cnt=0;
if(node.children) {
for(var i=0; i<node.children.length;i++) {
var child = node.children[i];
if(child.type=="JSXElement") {
this.out("e.addChild(");
this.indent(1);
this.walk(child,ctx);
this.indent(-1);
this.out(")",true);
}
/*
this.out("e.appendChild(document.createTextNode(\""+str+"\"));",true);
} else {
this.out("e.appendChild(document.createTextNode(");
this.walk(child,ctx);
this.out("))",true);
}
}
if(child.type=="JSXExpressionContainer") {
if(!bExpr) {
this.out("var expr=")
this.walk(child, ctx);
this.out(";",true);
}
this.out("if(typeof(expr)=='string' || typeof(expr)=='number') {",true);
this.indent(1);
this.out("e.appendChild(document.createTextNode(expr));",true);
*/
if(child.type=="Literal") {
var value = child.value;
if(typeof(value)=="string") {
var lines = value.split("\n");
var str = lines.join("\\n");
this.out("e.addChild( new frzr.View({el:document.createTextNode(\""+str+"\")}))",true);
} else {
this.out("e.addChild( new frzr.View({el:document.createTextNode(");
this.walk(child,ctx);
this.out(")}))",true);
}
}
if(child.type=="JSXExpressionContainer") {
if(!bExpr) {
this.out("var expr=")
this.walk(child, ctx);
this.out(";",true);
}
this.out("if(typeof(expr)=='string' || typeof(expr)=='number') {",true);
this.indent(1);
this.out("e.addChild( new frzr.View({el:document.createTextNode(expr)}))",true);
this.indent(-1);
this.out("} else {");
this.indent(1);
this.out("if(expr instanceof Array) {",true);
this.indent(1);
this.out('expr.forEach(function(ee){e.addChild(ee)});',true)
this.indent(-1);
this.out("} else { ",true);
this.out("if(typeof(expr)=='object')",true);
this.indent(1);
this.out("e.addChild(expr);",true);
this.indent(-1);
this.out("}",true);
this.indent(-1);
this.out("}");
}
}
}
this.walk(node.closingElement, ctx);
// if(!inJsx) this.out(";", true);
ctx._inJSX = inJsx;
}
_myTrait_.FRZRJSXClosingElement = function(node,ctx) {
this.out("return e;",true);
this.indent(-1);
this.out("}).apply(this,[])",true);
}
_myTrait_.reactJSXAttribute = function(node,ctx) {
this.walk(node.name, ctx);
this.out(":");
this.walk(node.value, ctx);
}
_myTrait_.reactJSXOpeningElement = function(node,ctx) {
console.log("reactJSXOpeningElement at namepace "+ctx.ns);
this.out("React.createElement(", true);
this.indent(1);
if(node.name.type=="JSXMemberExpression") {
var obj = node.name;
if(obj.object.name == "react") {
this.out("\""+obj.property.name+"\",",true);
} else {
// console.error("JSXMemberExpression not currently supported at react Namepace");
}
} else {
if(node.name) {
if(/[A-Z]/.test(node.name.name)) {
this.out(node.name.name + ",", true);
}else {
this.out("\"" + node.name.name + "\",", true);
}
}
}
if(node.attributes && node.attributes.length) {
this.out("{",true);
this.indent(1);
for(var i=0; i<node.attributes.length;i++) {
if(i>0) this.out(",",true);
this.walk(node.attributes[i],ctx);
}
this.indent(-1);
this.out("}");
} else {
this.out("null");
}
if(node.selfClosing) {
this.indent(-1);
this.out("");
this.out(")",true);
}
}
_myTrait_.reactLiteral = function(node,ctx) {
if(ctx._inJSX) {
var v = node.value.trim();
if(v.length==0) return;
this.out("\"");
this.out(node.value.trim());
this.out("\"");
} else {
this.out(node.raw);
}
}
_myTrait_.reactJSXExpressionContainer = function(node,ctx) {
this.walk(node.expression, ctx);
}
_myTrait_.reactJSXElement = function(node,ctx) {
var inJsx = ctx._inJSX;
ctx._inJSX = true;
this.walk(node.openingElement, ctx);
var cnt=0;
if(node.children) {
for(var i=0; i<node.children.length;i++) {
var child = node.children[i];
if(child.type=="Literal" && typeof(child.value)=="string" && child.value.trim().length==0) continue;
this.out(",",true);
this.walk(node.children[i],ctx);
}
}
this.walk(node.closingElement, ctx);
ctx._inJSX = inJsx;
}
_myTrait_.reactJSXClosingElement = function(node,ctx) {
this.indent(-1);
this.out("");
this.out(")",true);
}
// tags that will be converted to DOM element access
var _elemNamesList = [ "circle",
"rect",
"path",
"svg",
"image",
"line",
"text",
"tspan",
"g",
"pattern",
"polygon",
"polyline",
"clippath",
"defs",
"feoffset",
"femerge",
"femergenode",
"linearGradient",
"mask",
"polyline",
"feColorMatrix",
"radialGradient",
"stop",
"feGaussianBlur",
"filter"];
if(!this._autoNs) this._autoNs = {};
var me = this;
_elemNamesList.forEach(function(n) {
me._autoNs[n] = "SVG";
})
/*
circle clipPath defs ellipse g line linearGradient mask path pattern polygon polyline
radialGradient rect stop svg text tspan
*/
var svgNS = "http://www.w3.org/2000/svg";
// _fnCall indicates the result is a key-value of an object expression
_myTrait_.SVGJSXAttribute = function(node, ctx) {
this.out("\"");
this.out(node.name.name);
this.out("\"");
if(ctx._fnCall) {
this.out(":");
} else {
this.out(",");
}
this.walk(node.value,ctx);
}
_myTrait_.SVGJSXOpeningElement = function(node,ctx) {
this.out("(function() { ",true);
this.indent(1);
this.out("var e,me=this;",true);
var elemName, objName, bRootSvg=false;
if(node.name.type=="JSXMemberExpression") {
var obj = node.name;
if(obj.object.name == ctx.ns) {
elemName = obj.property.name;
} else {
elemName = obj.property.name;
objName = obj.object.name;
}
} else {
elemName = node.name.name;
}
// Allowed elem names etc...
if(!objName && _elemNamesList.indexOf(elemName)>=0) {
if(elemName=="svg") {
this.out("e=document.createElementNS('http://www.w3.org/2000/svg', 'svg');",true);
this.out('e.setAttribute("xmlns", "http://www.w3.org/2000/svg");',true);
this.out('e.setAttribute("xmlns:xlink", "http://www.w3.org/1999/xlink");',true);
bRootSvg=true;
} else {
this.out("e=document.createElementNS('http://www.w3.org/2000/svg', '"+elemName+"');",true);
}
if(node.attributes && node.attributes.length) {
for(var i=0; i<node.attributes.length;i++) {
var attr = node.attributes[i].name;
if(attr.type=="JSXIdentifier") {
var attrName = attr.name;
if(attrName && attrName.substring(0,2)=="on") {
var eventName = attrName.slice(2).toLowerCase();
// e.addEventListener('click', function(){me['click']("ok")});return e;}).apply(this,[])
this.out("e.addEventListener('"+eventName+"', function(){me['"+attrName+"'](");
this.walk(node.attributes[i].value,ctx);
this.out(")});",true);
continue;
}
}
/*
e.setAttribute("xmlns", "http://www.w3.org/2000/svg");
e.setAttribute("xmlns:xlink", "http://www.w3.org/1999/xlink");
e.setAttributeNS(null,"xmlns","http://www.w3.org/2000/svg");
e.setAttributeNS('http://www.w3.org/1999/xmlns',"xlink","
*/
if(attr.type=="JSXIdentifier") {
if(bRootSvg && attr.name == "xmlns") continue;
this.out("e.setAttributeNS(null,");
this.walk(node.attributes[i],ctx);
this.out(");",true);
} else {
if(attr.type=="JSXNamespacedName") {
/*
this.out("\"");
this.out(node.name.name);
this.out("\"");
if(ctx._fnCall) {
this.out(":");
} else {
this.out(",");
}
this.walk(node.value,ctx);
*/
if(bRootSvg && attr.name.name == "xlink") continue;
if(bRootSvg) {
this.out('e.setAttribute("'+attr.namespace.name+':'+attr.name.name+'",');
// "http://www.w3.org/1999/xlink");',true);
this.walk(node.attributes[i].value,ctx);
this.out(");",true);
} else {
this.out("e.setAttributeNS('http://www.w3.org/1999/"+attr.namespace.name+"',");
this.out("\"");
this.out(attr.name.name);
this.out("\"");
this.out(",");
this.walk(node.attributes[i].value,ctx);
this.out(");",true);
}
}
}
/*
if(n=="xlink:href") {
me._dom.setAttributeNS('http://www.w3.org/1999/xlink', 'href', val);
} else {
host._attributes[n] = val;
me._dom.setAttributeNS(null, n,val);
}
*/
}
} else {
// this.out("null");
}
} else {
this.out("var self = function(){this.parent=me;};");
this.out("self.prototype = this;",true);
if(objName) {
this.out("e = " + objName+"."+elemName + ".apply(new self(),[");
} else {
this.out("e = " + elemName + ".apply(new self(),[");
}
var prevFnState = ctx._fnCall;
ctx._fnCall = true;
if (node.attributes && node.attributes.length) {
this.out("{", true);
this.indent(1);
for (var i = 0; i < node.attributes.length; i++) {
if (i > 0) this.out(",", true);
this.walk(node.attributes[i], ctx);
}
this.indent(-1);
this.out("}");
}
ctx._fnCall = prevFnState;
this.out("]);", true);
}
if(node.selfClosing) {
this.out("return e;");
this.indent(-1);
this.out("}).apply(this,[])",true);
} else {
}
}
_myTrait_.SVGLiteral = function(node,ctx) {
if(typeof(node.value)=="string") {
this.out("\"");
this.out(node.value.split("\n").join("\\n"));
// this.out(node.value);
this.out("\"");
} else {
this.out(node.value);
}
}
_myTrait_.SVGJSXExpressionContainer = function(node,ctx) {
this.walk(node.expression, ctx);
}
_myTrait_.SVGJSXElement = function(node,ctx) {
var inJsx = ctx._inJSX;
ctx._inJSX = true;
var bExpr = false;
this.walk(node.openingElement, ctx);
var cnt=0;
if(node.children) {
for(var i=0; i<node.children.length;i++) {
var child = node.children[i];
if(child.type=="JSXElement") {
this.out("e.appendChild(");
this.indent(1);
this.walk(child,ctx);
this.indent(-1);
this.out(")",true);
}
if(child.type=="Literal") {
var value = child.value;
if(typeof(value)=="string") {
var lines = value.split("\n");
var str = lines.join("\\n");
this.out("e.appendChild(document.createTextNode(\""+str+"\"));",true);
} else {
this.out("e.appendChild(document.createTextNode(");
this.walk(child,ctx);
this.out("))",true);
}
}
if(child.type=="JSXExpressionContainer") {
if(!bExpr) {
this.out("var expr=")
this.walk(child, ctx);
this.out(";",true);
}
this.out("if(typeof(expr)=='string' || typeof(expr)=='number') {",true);
this.indent(1);
this.out("e.appendChild(document.createTextNode(expr));",true);
this.indent(-1);
this.out("} else {");
this.indent(1);
this.out("if(expr instanceof Array) {",true);
this.indent(1);
this.out('expr.forEach(function(ee){e.appendChild(ee)});',true)
this.indent(-1);
this.out("} else { ",true);
this.out("if(typeof(expr)=='object')",true);
this.indent(1);
this.out("e.appendChild(expr);",true);
this.indent(-1);
this.out("}",true);
this.indent(-1);
this.out("}");
}
}
}
this.walk(node.closingElement, ctx);
// if(!inJsx) this.out(";", true);
ctx._inJSX = inJsx;
}
_myTrait_.SVGJSXClosingElement = function(node,ctx) {
this.out("return e;",true);
this.indent(-1);
this.out("}).apply(this,[])",true);
}
this.walk(node.name, ctx);
this.out("=");
this.walk(node.value, ctx);
this.out("</");
this.walk(node.name, ctx);
// this.out(node.name.name);
this.out(">");
// openingElement
// closingElement
// selfClosing
this.walk(node.openingElement, ctx);
// --> children
this.out("", true);
this.indent(1);
this.walk(node.children, ctx);
this.indent(-1);
if(node.selfClosing) {
this.out("/>", true);
} else {
if(node.closingElement) this.walk(node.closingElement, ctx);
}
this.out("{");
this.walk(node.expression, ctx);
this.out("}");
this.out(node.name);
this.walk(node.object,ctx);
if(node.computed) {
this.out("[");
this.walk(node.property, ctx);
this.out("]");
} else {
this.out(".");
this.walk(node.property, ctx);
}
this.out(node.namespace);
this.out(":");
this.out(node.name);
// -> would create a component, JSXIdentifier
this.out("<");
this.walk(node.name, ctx);
this.out(" ");
this.walk(node.attributes, ctx);
if(node.selfClosing) {
this.out("/>");
} else {
this.out(">");
}
console.error("JSXSpreadAttribute is not implemented");
/*
this.out("{...");
// argument
this.walk(node.argument, ctx);
this.out("}");
*/
this.nlIfNot();
this.walk(node.label, ctx);
this.out(":", true);
this.indent(1);
if(node.body) this.walk(node.body, ctx);
this.indent(-1);
this.out(node.raw);
var bLeftNeedsPar = true, bRightNeedsPar=true;
if(node.left.type == "Identifier" || node.left.type == "Literal") {
bLeftNeedsPar = false;
}
if(node.right.type == "Identifier" || node.right.type == "Literal") {
bRightNeedsPar = false;
}
if(bLeftNeedsPar) this.out("(");
this.walk(node.left, ctx);
if(bLeftNeedsPar) this.out(")");
if(node.operator) {
this.out(" "+node.operator+" ");
}
if(bRightNeedsPar) this.out("(");
this.walk(node.right, ctx);
if(bRightNeedsPar) this.out(")");
/*
interface LogicalExpression <: Expression {
type: "LogicalExpression";
operator: LogicalOperator;
left: Expression;
right: Expression;
}
*/
this.trigger("MemberExpressionObject", node.object);
// MemberExpression
var bNeedPar = true;
if(node.object.type == "Identifier" || node.object.type == "Literal" || node.object.type == "ThisExpression") {
bNeedPar = false;
if(typeof node.object.value === "number") {
bNeedPar = true;
}
}
if(bNeedPar) this.out("(");
this.walk(node.object,ctx);
if(bNeedPar) this.out(")");
if(node.computed) {
this.out("[");
this.trigger("MemberExpressionProperty", node.property);
this.walk(node.property, ctx);
this.out("]");
} else {
this.out(".");
this.trigger("MemberExpressionProperty", node.property);
this.walk(node.property, ctx);
}
if(node.key) {
this.__insideMethod = true;
if(node.kind=="constructor") {
this.trigger("ClassConstructor", node);
}
if(node.static) this.out("static ");
this.walk(node.key,ctx);
this.walk(node.value, ctx);
this.out("", true);
this.__insideMethod = false;
}
if(node.callee) {
this.out(" new ");
this.trigger("NewExpressionClass", node.callee);
this.walk(node.callee, ctx);
this.out("(");
if(node.arguments) {
var me = this,
cnt=0;
node.arguments.forEach(function(n) {
me.trigger("NewExpressionArgument", n);
if(cnt++>0) me.out(", ");
me.walk(n,ctx);
});
}
this.out(")");
}
var len = this._currentLine.length;
if(len > 0) {
// {
if((this._currentLine[len-1] =="{") || (this._currentLine[len-1] ==";")) {
this.out("", true);
} else {
this.out(";", true);
}
}
var me = this;
try {
me.out("{");
var cnt=0;
if(node && node.properties) {
if(node.properties.length>1) me.out("", true);
me.indent(1);
node.properties.forEach( function(p) {
if(cnt++>0) me.out(",", true);
me.trigger("ObjectExpressionProperty", p);
me.walk(p, ctx);
});
me.indent(-1);
}
me.out("}");
} catch(e) {
console.error(e.message);
}
var me = this;
try {
me.out("{");
var cnt=0;
if(node && node.properties) {
//if(node.properties.length>1) me.out("", true);
node.properties.forEach( function(p) {
if(cnt++>0) me.out(",");
me.trigger("ObjectExpressionProperty", p);
me.walk(p, ctx);
});
}
me.out("}");
} catch(e) {
console.error(e.message);
}
str
Code to output
newline
if ends with newline
if(this._options.noOutput) return;
if(this._collecting) {
if(str) {
if(this._collectLine.length==0) {
for(var i=0; i<this._indent; i++) {
this._collectLine+= this._tabChar;
}
}
this._collectLine += str;
}
if(newline) {
this._collectStr+=this._collectLine+"\n";
this._collectLine = "";
this._collectStr+="\n";
}
return;
}
if(str) {
if(this._currentLine.length==0) {
this.trigger("startline");
this.trigger("tabs", this._indent);
for(var i=0; i<this._indent; i++) {
this._currentLine+= this._tabChar;
}
}
this.trigger("out", str);
this._currentLine += str;
}
if(newline) {
this.trigger("newline");
this._codeStr+=this._currentLine+"\n";
this._currentLine = "";
this._lineNumber++;
}
var len = this._currentLine.length;
if(len > 0) {
return this._currentLine[len-1];
} else {
return "\n";
}
this.walk(node.body,ctx, true);
// kind: "init" | "get" | "set";
this.trigger("ObjectPropertyKey", node.key);
this.walk(node.key, ctx);
if(!node.shorthand) {
this.out(":");
this.trigger("ObjectPropertyValue", node.value);
this.walk(node.value, ctx);
}
def
Structure definition
if(!this._structures) this._structures = [];
this._structures.push( def );
if(node.argument) this.trigger("RestArgument", node.argument);
this.out(" ...");
this.walk(node.argument, ctx);
this.nlIfNot();
this.out("return ");
this.trigger("ReturnValue", node.argument);
this.walk(node.argument, ctx);
this.out(";");
if(!node.nodeid) node.nodeid = this.createId();
this.createObject( node.nodeid, node );
if(node.expressions) {
var me = this;
var cnt = 0;
this.out("(");
node.expressions.forEach( function(n) {
if(cnt++>0) me.out(",");
me.walk( n, ctx );
})
this.out(")");
}
this._skipWalk = true;
this.out("{", true);
this.indent(1);
this._collecting = true;
node
AST Node
Starts the walking of AST tree
this._breakWalk = false;
this._path = [];
this._codeStr = "";
this._currentLine = "";
this._lineNumber = 0;
this.initDOMC();
this.walk(node, ctx);
this.out("",true);
this.out("super");
this.nlIfNot();
if(node.test) {
this.out("case ");
this.walk(node.test, ctx);
this.out(" : ", true);
} else {
this.out("default: ", true);
}
if(node.consequent) {
var me = this;
node.consequent.forEach( function(c) {
me.walk(c, ctx);
})
}
this.nlIfNot();
this.out("switch");
this.out("(");
this.walk( node.discriminant, ctx );
this.out(")");
this.out("{",true);
this.indent(1);
var me = this;
node.cases.forEach(function(c) {
me.walk(c,ctx);
})
this.indent(-1);
this.out("}",true);
/*
interface SwitchStatement <: Statement {
type: "SwitchStatement";
discriminant: Expression;
cases: [ SwitchCase ];
lexical: boolean;
}
*/
this.out(node.value.raw);
this.out("`");
for(var i=0; i<node.quasis.length;i++) {
if(i>0) {
this.out("${");
if(node.expressions[i-1]) this.walk(node.expressions[i-1],ctx);
this.out("}");
}
var q = node.quasis[i];
this.walk(q, ctx);
}
this.out("`");
this.out("this");
this.nlIfNot();
this.out("throw ");
this.trigger("ThrowArgument", node.argument);
this.walk( node.argument, ctx );
this.out("try ");
this.walk(node.block, ctx);
if(node.handler) {
this.walk(node.handler, ctx);
}
if(node.finalizer) {
this.out(" finally ");
this.walk(node.finalizer, ctx);
}
/*
interface TryStatement <: Statement {
type: "TryStatement";
block: BlockStatement;
handler: CatchClause | null;
guardedHandlers: [ CatchClause ];
finalizer: BlockStatement | null;
}
*/
var bNeedsPar = true;
if(node.argument.type == "Identifier" || node.argument.type == "Literal") {
bNeedsPar = false;
}
this.out(node.operator);
if(node.operator!="!") this.out(" ");
if(bNeedsPar) this.out("(");
this.trigger("UnaryExpressionArgument", node.argument);
this.walk(node.argument,ctx);
if(bNeedsPar) this.out(")");
this.trigger("UpdateExpressionArgument", node.argument);
if(node.prefix) {
this.out(node.operator);
this.walk(node.argument, ctx);
} else {
this.walk(node.argument, ctx);
this.out(node.operator);
}
node
Object to use to create a variable declaration
ctx
Context of the node
var me = this;
var cnt=0;
if(node.kind=="var") me.out("var ");
if(node.kind=="let") me.out("let ");
if(node.kind=="const") me.out("const ");
var indent=0;
node.declarations.forEach( function(vd) {
if(vd.deleted) return;
if(cnt++>0) {
if(cnt==2) {
indent+=2;
me.indent(indent);
}
me.out(",", true); // always a new declaration
}
me.walk(vd,ctx);
});
this.indent(-1*indent);
if(cnt==0) this._undoOutput=true;
if(!ctx._forVar) this.out(";",true);
var me = this;
if(node.id) {
me.walk(node.id, ctx);
if(node.id.name) {
ctx.vars[node.id.name] = node;
}
}
if(node.init) {
this.out(" = ");
me.walk( node.init, ctx );
}
node
The object to walk the AST with
ctx
The current context
if(!node) return;
if(!ctx) {
console.log("ERROR: no context defined for ", node);
console.trace();
return;
}
// What is going on here then...
if(node instanceof Array) {
var me = this;
this.trigger("nodeArray", {
node : node,
ctx : ctx
});
node.forEach( function(n) {
me.walk( n, ctx );
if(newLine) me.nlIfNot(); // insert newline just in case to the end...
})
} else {
if(node.deleted) return;
if(node.type) {
this.saveNode(node);
node.contextId = ctx.id;
var parentNode = this.getParent();
if(!this._nodeParents) this._nodeParents = {};
if(parentNode) {
this._nodeParents[node.nodeid] = parentNode;
}
var runTime = {
node : node,
ctx : ctx
};
this.trigger("node", runTime);
this.trigger(node.type, runTime);
if(this._skipWalk) {
this._skipWalk = false;
return;
}
if(this._wCb) this._wCb(node);
if(this[node.type]) {
this._path.push(node);
var oldLine = this._currentLine;
var oldPos = this._codeStr.length;
var bDidEnterNs = false, old_ns;
if(node.type=="JSXElement" && node.openingElement && node.openingElement.name) {
if(node.openingElement.name.type=="JSXMemberExpression") {
// could be entering a namespace
var member = node.openingElement.name;
var nameSpace = member.object.name;
if(this._nsList.indexOf(nameSpace)>=0) {
if(!ctx.nsStack) ctx.nsStack = [];
ctx.nsStack.push(nameSpace);
old_ns = ctx.ns;
ctx.ns = nameSpace;
bDidEnterNs = true;
} else {
if(!ctx.ns) {
nameSpace = this._options.defaultNamespace || "DOM";
if(this._options.forceNamespace) nameSpace = this._options.forceNamespace;
if(!ctx.nsStack) ctx.nsStack = [];
ctx.nsStack.push(nameSpace);
old_ns = ctx.ns;
ctx.ns = nameSpace;
bDidEnterNs = true;
}
}
} else {
if(!ctx.ns) {
var nameSpace = this._options.defaultNamespace || "DOM"; // <- default namespace, could be a setting though
var nName = node.openingElement.name.name;
if(nName == "svg") nameSpace = "SVG";
if(this._autoNs && this._autoNs[nName]) nameSpace = this._autoNs[nName];
if(this._options.forceNamespace) nameSpace = this._options.forceNamespace;
if(!ctx.nsStack) ctx.nsStack = [];
ctx.nsStack.push(nameSpace);
old_ns = ctx.ns;
ctx.ns = nameSpace;
bDidEnterNs = true;
} else {
if(ctx.ns=="DOM") {
if(node.openingElement.name.name == "svg") {
//
var nameSpace = "SVG";
if(!ctx.nsStack) ctx.nsStack = [];
ctx.nsStack.push(nameSpace);
old_ns = ctx.ns;
ctx.ns = nameSpace;
bDidEnterNs = true;
}
}
}
}
}
if(ctx.ns) {
var tryThis = ctx.ns+node.type;
if(typeof(this[tryThis]) != "undefined") {
this[tryThis](node, ctx);
} else {
this[node.type](node, ctx);
}
} else {
this[node.type](node, ctx);
}
if(bDidEnterNs) {
ctx.nsStack.pop();
ctx.ns = old_ns;
}
if(this._undoOutput) {
this._codeStr = this._codeStr.substring(0, oldPos);
this._currentLine = oldLine;
this._undoOutput = false;
}
this._path.pop();
} else {
console.log("Did not find "+node.type);
console.log(node);
}
this.trigger("nodeWalked", runTime);
this.trigger("After"+node.type, runTime);
}
}
var str="";
try {
this.startCollecting();
this._collectStr = "";
this._collectLine = "";
this.walk(node, ctx);
str = this._collectStr;
this.endCollecting();
} catch(e) {
}
return str;
this.nlIfNot();
this.out("while ");
if(node.test) {
this.trigger("WhileTest", node.test);
this.out("(");
this.walk(node.test,ctx);
this.out(")");
}
if(node.body) {
var bNeedsPar = false;
if(node.body.type != "BlockStatement" && ( node.body.type.indexOf("Statement")>=0) ) {
bNeedsPar = true;
}
if(bNeedsPar) {
this.out("{");
this.indent(1);
}
this.walk(node.body,ctx);
if(bNeedsPar) {
this.indent(-1);
this.out("}");
}
}
this.out("", true);
console.error("With statement is not supported");
this.out("yield ");
this.walk(node.argument, ctx);
/*
interface YieldExpression <: Expression {
type: "YieldExpression";
argument: Expression | null;
}
*/
The class has following internal singleton variables:
en
Event name
Binds event name to event function
if(!this._ev) this._ev = {};
if(!this._ev[en]) this._ev[en] = [];
this._ev[en].push(ef);
return this;
if(!this._ev) return;
if(!this._ev[name]) return;
var list = this._ev[name];
for(var i=0; i<list.length; i++) {
if(list[i]==fn) {
list.splice(i,1);
return;
}
}
triggers event with data and optional function
if(!this._ev) return;
if(!this._ev[en]) return;
var me = this;
this._ev[en].forEach( function(cb) { cb( data, fn) } );
return this;