estools / escodegen Goto Github PK
View Code? Open in Web Editor NEWECMAScript code generator
License: BSD 2-Clause "Simplified" License
ECMAScript code generator
License: BSD 2-Clause "Simplified" License
I have multiple AST trees with location info. They are either generated by CoffeeScriptRedux or esprima.parse()
(in case of raw JS files). I want to combine them into one single file with one source-map.
My naive attempt to this was to take the individual parse trees and wrap them into another Program
node:
{
type: 'Program',
body: [
{type: 'Program', loc: {source: 'file1.js', start: {line: 1, column: 1}}, body: [...]},
{type: 'Program', loc: {source: 'file2.coffee', start: {line: 1, column: 1}}, body: [...]},
]
}
Unfortunately that doesn't work, you end up with something like this:
{"version":3,"file":"test.map","sources":["test.map"],"names":[],"mappings":"AAAA,OAAA,IAAA,CAAY,UAAZ,CAAA"}
Is there a another way to concatenate multiple files that could possibly work?
Identifiers that are also keywords are not properly escaped. This causes escodegen to create invalid programs from valid ASTs. The simplest example:
{ type: 'Identifier', name: 'do' }
Expected output: either d\u006f
or \u0064o
or (hopefully not, though) \u0064\u006f
.
Observed output: do
(an invalid program).
Support directive flag for esmangle, it is implemented as option.
VisitorOption, traverse, and Syntax seem to be available in estraverse
, can we include estraverse
as a dependency and remove the duplicate code from escodegen
?
For tools that need both the output JS string and the source map, it will be more efficient.
{ type: 'UpdateExpression',
argument:
{ type: 'UnaryExpression',
argument: { type: 'Identifier', name: 'x' },
operator: '-' },
operator: '--',
prefix: true }
produces ---x
instead of -(--x)
or - --x
. I'm preparing a patch.
Currently I don't see any way to pass a chunk of code to be outputted just as is in the generated source. The use case is when generating an AST from a language that allows to define chunks of code to be placed verbatim in the generated javascript, much like CoffeeScript's backtick notation.
It could work something like this:
{
type: 'CodeExpression',
code: 'window.location.href = "http://google.com"'
}
The generator would output the contents of the code with only the following processing performed:
Since it's impossible to know the precedence order of that node, it should always be assumed that it's very low (Assignment), wrapping it with parens if used in a binary or member expression for example.
Create Options table like,
Options = {
// default options
}
and update it by provided options.
Hi all,
I am using the following code to try out escodegen:
var source = "var hello = function(){return 'hello world!';}; var hello1 = world; function world(hello){return hello;} var number = function(num){return num;}; hello(); var hello2 = 1+1*number(1)"
var res = esprima.parse(source);
escodegen.generate(res)
the output on my end is:
"var hello = function () {
undefinedreturn 'hello world!';
};
var hello1 = world;
function world(hello) {
undefinedreturn hello;
}
var number = function (num) {
undefinedreturn num;
};
hello();
var hello2 = 1 + 1 * number(1);"
The problem is with all the "undefined" appearing in the function body. Any help would be appreciated :)
Jason
When I parse var a = {a: 2}
with acorn, the resulting AST is as follows:
{
"type": "Program",
"start": 0,
"end": 14,
"body": [
{
"type": "VariableDeclaration",
"start": 0,
"end": 14,
"declarations": [
{
"type": "VariableDeclarator",
"start": 4,
"end": 14,
"id": {
"type": "Identifier",
"start": 4,
"end": 5,
"name": "a"
},
"init": {
"type": "ObjectExpression",
"start": 8,
"end": 14,
"properties": [
{
"key": {
"type": "Identifier",
"start": 9,
"end": 10,
"name": "a"
},
"value": {
"type": "Literal",
"start": 12,
"end": 13,
"value": 2,
"raw": "2"
},
"kind": "init"
}
]
}
}
],
"kind": "var"
}
]
}
As you can see the properties of the ObjectExpression
don't have a type
property. This causes escodegen to fail:
/home/arian/www/wrapup/node_modules/escodegen/escodegen.js:1385
throw new Error('Unknown expression type: ' + expr.type);
^
Error: Unknown expression type: undefined
at generateExpression (/home/arian/www/wrapup/node_modules/escodegen/escodegen.js:1385:19)
at result (/home/arian/www/wrapup/node_modules/escodegen/escodegen.js:1188:28)
at withIndent (/home/arian/www/wrapup/node_modules/escodegen/escodegen.js:592:21)
at generateExpression (/home/arian/www/wrapup/node_modules/escodegen/escodegen.js:1187:13)
at generateStatement (/home/arian/www/wrapup/node_modules/escodegen/escodegen.js:1512:21)
at generateExpression.precedence (/home/arian/www/wrapup/node_modules/escodegen/escodegen.js:1544:42)
at withIndent (/home/arian/www/wrapup/node_modules/escodegen/escodegen.js:592:21)
at generateStatement (/home/arian/www/wrapup/node_modules/escodegen/escodegen.js:1537:17)
at generateStatement (/home/arian/www/wrapup/node_modules/escodegen/escodegen.js:1757:21)
at Object.generate (/home/arian/www/wrapup/node_modules/escodegen/escodegen.js:1919:22)
Esprima addes type: "Property"
, however according to https://developer.mozilla.org/en-US/docs/SpiderMonkey/Parser_API#Expressions this is not required.
The expression "new (a().b)()" as parsed by esprima is incorrectly generated as "new a().b()".
UnaryExpression doesn't need space when space !== '' for readability.
For example,
- 10
should be
-10
I find it weird that the demo is in a separate repo. It should be in this repo, so that pull requests for changes to the demo land here.
I got to this project while discussing ways to do advanced code formatting for JS (source)
It would be great if it had the same level of control as FDT advanced code formatter - options to define how white space is handled between each kind of token (line break, space, none), indentation, keep/remove empty lines, etc.
Basically transform escodegen into a hardcore version of JSBeautifier.
With options.format.compact
enabled, the problem described at http://code.google.com/p/closure-compiler/issues/detail?id=620 can be observed.
TEMP=$(mktemp)
echo '/ / / / /' | tee "$TEMP"
node <<ENDH
console.log(require("util").inspect(
require(process.env.HOME + "/github/ariya/esprima/esprima.js").parse(
"/ / / / /", {comment: true}), null, null))
ENDH
v8 \
"$HOME/github/ariya/esprima/esprima.js" \
"$HOME/github/Constellation/escodegen/escodegen.js" \
/dev/stdin > "$TEMP" <<'ENDH'
print(escodegen.generate(esprima.parse("/ / / / /"), {format: {compact:true}}))
ENDH
cat "$TEMP"
node <<ENDH
console.log(require("util").inspect(
require(process.env.HOME + "/github/ariya/esprima/esprima.js").parse(
require("fs").readFileSync("$TEMP"), {comment: true}), null, null))
ENDH
Tested on Ubuntu 12.04 LTS with ariya/esprima@465a4ea and 5de45f6
spawn from #4
Move indent and base options to format.indent option.
Currently, the following doesn't work:
var ast = esprima.parse(sourceCode, {range: true, tokens: true, comment: true})
console.log('result:', escodegen.generate(ast, {comment: true}));
However, this works:
var ast = esprima.parse(sourceCode, {range: true, tokens: true, comment: true});
ast = escodegen.attachComments(ast, ast.comments, ast.tokens);
console.log('result:', escodegen.generate(ast, {comment: true}));
I don't understand the need for the attachComments call. Passing comment:true should be enough so that comments show up.
Esprima can provide range / loc information, so we can create SourceMap from this.
options.format.safe
would make sure that the generated code can be safely followed by another ECMAScript program. The option would take precedence over disabled options.format.semicolons
. One can think of the following behavior:
!{}
. However, it should not be added if it results in an empty statement that does not exist in the original program. For instance, a semicolon must not appear at the end of the code generated given {}
.try{}//
finally{}
yields
try {
} // finally {
}
since ddc4cd5.
A test case is available at https://gist.github.com/3142709
issue from #4
js> print(this.escodegen.generate(Reflect.parse('var a = {}; a["some thing"] = 1')))
var a = {};
a.some thing = 1;
Perhaps Syntax.MemberExpression?
result.push('.' + expr.property.name);
It seems like all of this opens a can of worms, but who knows!
Do I have to update ranges manually after any change on AST object?
npm install -g escodegen
Error: Cannot find module 'esprima'
at Function.Module._resolveFilename (module.js:338:15)
at Function.Module._load (module.js:280:25)
at Module.require (module.js:362:17)
at require (module.js:378:17)
at Object.<anonymous> (npm/lib/node_modules/escodegen/bin/esgenerate.js:29:15)
at Module._compile (module.js:449:26)
at Object.Module._extensions..js (module.js:467:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:312:12)
at Module.runMain (module.js:492:10)
I don't know if it's even possible based on the output of require('esprima').parse(str, {comment: true})
, but just in case.
I have more use cases for comment-and-whitespace-preserving JavaScript source manipulation than I can count :)
it needs at least:
ObjectPattern
escodegen.js:350: Error: Numeric literal whose value is negative
escodegen.js:1143: Error: Unknown expression type: YieldExpression
escodegen.js:1611: Error: Unknown statement type: CallExpression
Add esprima harmony code generation.
escodegen.js embeds a copy of estraverse (see https://github.com/Constellation/escodegen/blob/master/escodegen.js#L2027) - specifically one that does not benefit from bugfixes in estraverse (including the recent fix of ObjectExpressions by @michaelficarra.
It also exports the embedded traverse function which, depending on the order in which escodegen and estraverse are loaded, can clobber the fixed version.
We should handle yield statement's delegate flag
We should handle harmony operators, is & isnt.
If esprima has been used to generate a tree without any of range, tokens or comment options, I think escodegen can't output the comments. I think escodegen should just throw (or at least console.warn) in these cases to indicate that comments can't be properly outputed.
https://github.com/Constellation/escodegen/blob/master/escodegen.js#L722
It's looking at the last character which will always be the same character as the operator.
I suggest adding minify option to code generator.
currently
if (cond)stmt;else if(cond) stmt;
result
if(cond)stmt;else if(cond)stmt;
should be
if(cond)stmt;else if(cond)stmt
{
type: if,
c: {
type: if,
c: ...
},
a: {
...
}
}
is invalid AST, because this tree cannot be constructed naturally.
So we should raise error when this AST is given.
https://github.com/Constellation/escodegen/blob/master/package.json#L24
By having a floating dependency, you expose all users of your module to breaking changes when they install this in the future and new versions of your dependencies are broken. This can and will happen. Floating dependencies also make it harder to track down problems in the future as it becomes unclear what version of the code was actually tested against.
options.format.jshint
would make sure that, as far as the code generator is concerned, i.e. without transforming the abstract syntax tree, and with all enforcing options available in JSHint, generated code is JSHint-compliant. Whether the option in question is to be enabled by default is another matter.
if (cond) stmt; else stmt2;
currently
if(cond)stmt; else stmt2;
should be
if(cond)stmt;else stmt2;
Currenlty, for NoIn expression, we always add parenthesis around 'in' operator.
for example,
for (i = (20 in 30) in 40);
should not generate
for (i = 20 in 30 in 40);
Handle harmony method property.
var obj = {
method() {
}
};
Thanks to @mishoo, it is found that remove-context-sensitive-expression pass has a bug.
http://lisperator.net/blog/uglifyjs-why-not-switching-to-spidermonkey-ast/
For the time being, when options.format.semicolons
is set to false, only semicolons at the end of programs, blocks, and case blocks are omitted. However, setting this option to false should make complete reliance on automatic semicolon insertion (7.9) possible, e.g.
42;foo;
should result in (with options.format.compact
set to false)
42
foo
instead of
42;
foo
Moreover, in the future, with options.format.compact
and comments preserved, the input:
42;
/*A
*/
foo;
should result in
42/*A
*/foo
and the input
42;
//A
foo;
should result in
42//A
foo
For pitfalls with regard to reliance on automatic semicolon insertion, see http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml#Semicolons
If a JS file begins with a block comment, attachComments
does not attach the block comment to the syntax node that owns the comment.
For example, I used Esprima to parse this file, then called attachComments
:
/**
* @class MyClass
*/
function MyClass() {}
The block comment should be attached to the MyClass
declaration. Instead, it is attached to the root node. (See this gist for the complete AST.)
options.format.quirks
or more sophisticated options would allow supporting quirks. These options would take precedence over any other options.
What follows are the quirks supported by the Closure Compiler when it comes to code generation:
'-->'
as '--\\>'
,'<!--'
as '<\\!--'
,/<\/script([ \t\n\f\r]*>)/gi
as '<\\/script$1'
,']]>'
as ']]\\>'
,var \u0069\u0066;
would become var \u0069f;
),if(x)do{foo()}while(y);
),if (true) function foo(){return}
),throw
statement with a semicolon (function foo(){throw 'error';}
).A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.