Loading lib/jsduck/serializer.rb 0 → 100644 +185 −0 Original line number Diff line number Diff line module JsDuck # Transforms Esprima AST into string class Serializer # Turns AST node into string def to_s(ast) case ast["type"] when "Program" ast["body"].map {|s| to_s(s) }.join # Statements when "BlockStatement" "{" + ast["body"].map {|s| to_s(s) }.join + "}" when "BreakStatement" "break" + (ast["label"] ? " " + to_s(ast["label"]) : "") + ";" when "ContinueStatement" "continue" + (ast["label"] ? " " + to_s(ast["label"]) : "") + ";" when "DoWhileStatement" "do " + to_s(ast["body"]) + " while (" + to_s(ast["test"]) + ");" when "DebuggerStatement" "debugger;" when "EmptyStatement" ";" when "ExpressionStatement" to_s(ast["expression"]) + ";" when "ForStatement" init = ast["init"] ? to_s(ast["init"]).sub(/;\Z/, "") : "" test = ast["test"] ? to_s(ast["test"]) : "" update = ast["update"] ? to_s(ast["update"]) : "" "for (" + init + "; " + test + "; " + update + ") " + to_s(ast["body"]) when "ForInStatement" left = to_s(ast["left"]).sub(/;\Z/, "") right = to_s(ast["right"]) "for (" + left + " in " + right + ") " + to_s(ast["body"]) when "IfStatement" alternate = ast["alternate"] ? " else " + to_s(ast["alternate"]) : "" "if (" + to_s(ast["test"]) + ") " + to_s(ast["consequent"]) + alternate when "LabeledStatement" to_s(ast["label"]) + ": " + to_s(ast["body"]) when "ReturnStatement" "return " + to_s(ast["argument"]) + ";" when "SwitchStatement" "switch (" + to_s(ast["discriminant"]) + ") {" + ast["cases"].map {|c| to_s(c) }.join + "}" when "SwitchCase" test = ast["test"] ? "case " + to_s(ast["test"]) : "default" test + ": " + ast["consequent"].map {|c| to_s(c) }.join when "ThrowStatement" "throw " + to_s(ast["argument"]) + ";" when "TryStatement" handlers = ast["handlers"].map {|h| to_s(h) }.join finalizer = ast["finalizer"] ? " finally " + to_s(ast["finalizer"]) : "" "try " + to_s(ast["block"]) + handlers + finalizer when "CatchClause" param = ast["param"] ? to_s(ast["param"]) : "" " catch (" + param + ") " + to_s(ast["body"]) when "WhileStatement" "while (" + to_s(ast["test"]) + ") " + to_s(ast["body"]) when "WithStatement" "with (" + to_s(ast["object"]) + ") " + to_s(ast["body"]) # Declarations when "FunctionDeclaration" function(ast) when "VariableDeclaration" ast["kind"] + " " + list(ast["declarations"]) + ";" when "VariableDeclarator" if ast["init"] to_s(ast["id"]) + " = " + to_s(ast["init"]) else to_s(ast["id"]) end # Expressions when "AssignmentExpression" to_s(ast["left"]) + " " + ast["operator"] + " " + to_s(ast["right"]) when "ArrayExpression" "[" + list(ast["elements"]) + "]" when "BinaryExpression" to_s(ast["left"]) + " " + ast["operator"] + " " + to_s(ast["right"]) when "CallExpression" call(ast) when "ConditionalExpression" to_s(ast["test"]) + " ? " + to_s(ast["consequent"]) + " : " + to_s(ast["alternate"]) when "FunctionExpression" function(ast) when "LogicalExpression" to_s(ast["left"]) + " " + ast["operator"] + " " + to_s(ast["right"]) when "MemberExpression" if ast["computed"] to_s(ast["object"]) + "[" + to_s(ast["property"]) + "]" else to_s(ast["object"]) + "." + to_s(ast["property"]) end when "NewExpression" "new " + call(ast) when "ObjectExpression" "{" + list(ast["properties"]) + "}" when "Property" to_s(ast["key"]) + ": " + to_s(ast["value"]) when "SequenceExpression" list(ast["expressions"]) when "ThisExpression" "this" when "UnaryExpression" ast["operator"] + to_s(ast["argument"]) when "UpdateExpression" if ast["prefix"] ast["operator"] + to_s(ast["argument"]) else to_s(ast["argument"]) + ast["operator"] end # Basics when "Identifier" ast["name"] when "Literal" ast["value"].to_s else throw "Unknown node type: "+ast["type"] end end # serializes function declaration or expression def function(ast) params = list(ast["params"]) id = ast["id"] ? to_s(ast["id"]) : "" "function " + id + "(" + params + ") " + to_s(ast["body"]) end # serializes list of comma-separated items def list(array) array.map {|x| to_s(x) }.join(", ") end # serializes call- and new-expression def call(ast) to_s(ast["callee"]) + "(" + list(ast["arguments"]) + ")" end end end spec/serializer_spec.rb 0 → 100644 +137 −0 Original line number Diff line number Diff line require "jsduck/esprima_core" require "jsduck/serializer" describe JsDuck::Serializer do def to_s(string) ast = JsDuck::EsprimaCore.instance.parse(string) return JsDuck::Serializer.new.to_s(ast) end def test(string) to_s(string).should == string end describe "serializes" do it "empty program" do test("") end it "function declaration" do test("function foo(a, b, c) {return 0;}") end it "variable declaration" do test("var foo, bar = 5;") end it "variable declaration with let" do test("let foo = true;") end it "assignment of function expression" do test("foo = function (a) {};") end it "member expression with this" do test("this.foo.bar;") end it "computed member expression" do test("foo[bar];") end it "+= assignment" do test("x += 15;") end it "method call on array" do test("[1, 2, 3].map(max);") end it "object expression" do test("x = {foo: 10, bar: 42};") end it "new expression" do test("new Item();") end it "logical expression" do test("true || false;") end it "binary expression" do test("1 + 2 - 3;") end it "sequence expression" do test("foo, bar;") end it "update expression" do test("++c + c--;") end it "if statement" do test("if (true) alert(5);") end it "if else statement" do test("if (true) {} else {foo();}") end it "else if statement" do test("if (true) {} else if (false) {}") end it "switch statement" do test("switch (foo) {case 1: case 2: alert(1);break;default: alert(2);}") end it "for statement" do test("for (var i = 0; i < 10; i++) {}") end it "empty for statement" do test("for (; ; ) ;") end it "for in statement" do test("for (var key in obj) {}") end it "while statement" do test("while (true) {break;continue;}") end it "do while statement" do test("do {alert();} while (true);") end it "labeled statement" do test("foo: while (1) {break foo;continue foo;}") end it "debugger statement" do test("debugger;") end it "try catch statement" do test("try {throw foo;} catch (e) {alert(e);}") end it "try catch statement with empty catch" do test("try {} catch () {}") end it "try finally statement" do test("try {} finally {}") end it "with statement" do test("with (obj) {}") end end end Loading
lib/jsduck/serializer.rb 0 → 100644 +185 −0 Original line number Diff line number Diff line module JsDuck # Transforms Esprima AST into string class Serializer # Turns AST node into string def to_s(ast) case ast["type"] when "Program" ast["body"].map {|s| to_s(s) }.join # Statements when "BlockStatement" "{" + ast["body"].map {|s| to_s(s) }.join + "}" when "BreakStatement" "break" + (ast["label"] ? " " + to_s(ast["label"]) : "") + ";" when "ContinueStatement" "continue" + (ast["label"] ? " " + to_s(ast["label"]) : "") + ";" when "DoWhileStatement" "do " + to_s(ast["body"]) + " while (" + to_s(ast["test"]) + ");" when "DebuggerStatement" "debugger;" when "EmptyStatement" ";" when "ExpressionStatement" to_s(ast["expression"]) + ";" when "ForStatement" init = ast["init"] ? to_s(ast["init"]).sub(/;\Z/, "") : "" test = ast["test"] ? to_s(ast["test"]) : "" update = ast["update"] ? to_s(ast["update"]) : "" "for (" + init + "; " + test + "; " + update + ") " + to_s(ast["body"]) when "ForInStatement" left = to_s(ast["left"]).sub(/;\Z/, "") right = to_s(ast["right"]) "for (" + left + " in " + right + ") " + to_s(ast["body"]) when "IfStatement" alternate = ast["alternate"] ? " else " + to_s(ast["alternate"]) : "" "if (" + to_s(ast["test"]) + ") " + to_s(ast["consequent"]) + alternate when "LabeledStatement" to_s(ast["label"]) + ": " + to_s(ast["body"]) when "ReturnStatement" "return " + to_s(ast["argument"]) + ";" when "SwitchStatement" "switch (" + to_s(ast["discriminant"]) + ") {" + ast["cases"].map {|c| to_s(c) }.join + "}" when "SwitchCase" test = ast["test"] ? "case " + to_s(ast["test"]) : "default" test + ": " + ast["consequent"].map {|c| to_s(c) }.join when "ThrowStatement" "throw " + to_s(ast["argument"]) + ";" when "TryStatement" handlers = ast["handlers"].map {|h| to_s(h) }.join finalizer = ast["finalizer"] ? " finally " + to_s(ast["finalizer"]) : "" "try " + to_s(ast["block"]) + handlers + finalizer when "CatchClause" param = ast["param"] ? to_s(ast["param"]) : "" " catch (" + param + ") " + to_s(ast["body"]) when "WhileStatement" "while (" + to_s(ast["test"]) + ") " + to_s(ast["body"]) when "WithStatement" "with (" + to_s(ast["object"]) + ") " + to_s(ast["body"]) # Declarations when "FunctionDeclaration" function(ast) when "VariableDeclaration" ast["kind"] + " " + list(ast["declarations"]) + ";" when "VariableDeclarator" if ast["init"] to_s(ast["id"]) + " = " + to_s(ast["init"]) else to_s(ast["id"]) end # Expressions when "AssignmentExpression" to_s(ast["left"]) + " " + ast["operator"] + " " + to_s(ast["right"]) when "ArrayExpression" "[" + list(ast["elements"]) + "]" when "BinaryExpression" to_s(ast["left"]) + " " + ast["operator"] + " " + to_s(ast["right"]) when "CallExpression" call(ast) when "ConditionalExpression" to_s(ast["test"]) + " ? " + to_s(ast["consequent"]) + " : " + to_s(ast["alternate"]) when "FunctionExpression" function(ast) when "LogicalExpression" to_s(ast["left"]) + " " + ast["operator"] + " " + to_s(ast["right"]) when "MemberExpression" if ast["computed"] to_s(ast["object"]) + "[" + to_s(ast["property"]) + "]" else to_s(ast["object"]) + "." + to_s(ast["property"]) end when "NewExpression" "new " + call(ast) when "ObjectExpression" "{" + list(ast["properties"]) + "}" when "Property" to_s(ast["key"]) + ": " + to_s(ast["value"]) when "SequenceExpression" list(ast["expressions"]) when "ThisExpression" "this" when "UnaryExpression" ast["operator"] + to_s(ast["argument"]) when "UpdateExpression" if ast["prefix"] ast["operator"] + to_s(ast["argument"]) else to_s(ast["argument"]) + ast["operator"] end # Basics when "Identifier" ast["name"] when "Literal" ast["value"].to_s else throw "Unknown node type: "+ast["type"] end end # serializes function declaration or expression def function(ast) params = list(ast["params"]) id = ast["id"] ? to_s(ast["id"]) : "" "function " + id + "(" + params + ") " + to_s(ast["body"]) end # serializes list of comma-separated items def list(array) array.map {|x| to_s(x) }.join(", ") end # serializes call- and new-expression def call(ast) to_s(ast["callee"]) + "(" + list(ast["arguments"]) + ")" end end end
spec/serializer_spec.rb 0 → 100644 +137 −0 Original line number Diff line number Diff line require "jsduck/esprima_core" require "jsduck/serializer" describe JsDuck::Serializer do def to_s(string) ast = JsDuck::EsprimaCore.instance.parse(string) return JsDuck::Serializer.new.to_s(ast) end def test(string) to_s(string).should == string end describe "serializes" do it "empty program" do test("") end it "function declaration" do test("function foo(a, b, c) {return 0;}") end it "variable declaration" do test("var foo, bar = 5;") end it "variable declaration with let" do test("let foo = true;") end it "assignment of function expression" do test("foo = function (a) {};") end it "member expression with this" do test("this.foo.bar;") end it "computed member expression" do test("foo[bar];") end it "+= assignment" do test("x += 15;") end it "method call on array" do test("[1, 2, 3].map(max);") end it "object expression" do test("x = {foo: 10, bar: 42};") end it "new expression" do test("new Item();") end it "logical expression" do test("true || false;") end it "binary expression" do test("1 + 2 - 3;") end it "sequence expression" do test("foo, bar;") end it "update expression" do test("++c + c--;") end it "if statement" do test("if (true) alert(5);") end it "if else statement" do test("if (true) {} else {foo();}") end it "else if statement" do test("if (true) {} else if (false) {}") end it "switch statement" do test("switch (foo) {case 1: case 2: alert(1);break;default: alert(2);}") end it "for statement" do test("for (var i = 0; i < 10; i++) {}") end it "empty for statement" do test("for (; ; ) ;") end it "for in statement" do test("for (var key in obj) {}") end it "while statement" do test("while (true) {break;continue;}") end it "do while statement" do test("do {alert();} while (true);") end it "labeled statement" do test("foo: while (1) {break foo;continue foo;}") end it "debugger statement" do test("debugger;") end it "try catch statement" do test("try {throw foo;} catch (e) {alert(e);}") end it "try catch statement with empty catch" do test("try {} catch () {}") end it "try finally statement" do test("try {} finally {}") end it "with statement" do test("with (obj) {}") end end end