Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

allow saving and loading in ast format #106

Merged
merged 6 commits into from Aug 7, 2014
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 3 additions & 1 deletion README.md
Expand Up @@ -19,7 +19,7 @@ Usage
```
$ jsfmt --help
Usage:
jsfmt [--no-format] [--diff|--list|--write] [--validate] [--rewrite PATTERN|--search PATTERN] [--json] [<file>...]
jsfmt [--no-format] [--save-ast] [--diff|--list|--write] [--validate] [--rewrite PATTERN|--search PATTERN] [--json|--ast] [<file>...]
jsfmt (--version | --help)

Options:
Expand All @@ -31,6 +31,8 @@ Options:
--no-format Do not format the input file(s)
-w --write Overwrite the original file with jsfmt output
-j --json Tell jsfmt that the file being parsed is json
-a --ast Tell jsfmt that the file being parsed is in JSON AST
--save-ast Output the resulting js in JSON AST format
-r=PATTERN --rewrite PATTERN Rewrite rule (e.g., 'a.slice(b, len(a) -> a.slice(b)')
-s=PATTERN --search PATTERN Search rule (e.g., 'a.slice')
```
Expand Down
24 changes: 24 additions & 0 deletions lib/ast.js
@@ -0,0 +1,24 @@
var escodegen = require('escodegen');
var esprima = require('esprima');


module.exports.parseAST = function(ast){
var js = escodegen.generate(ast, {
comment: true,
format: {
quotes: 'double'
}
});
return js;
};

module.exports.generateAST = function(js){
var ast = esprima.parse(js, {
raw: true,
tokens: true,
range: true,
comment: true
});
ast = escodegen.attachComments(ast, ast.comments, ast.tokens);
return ast;
};
3 changes: 3 additions & 0 deletions lib/index.js
@@ -1,6 +1,7 @@
var rewritePath = './rewrite.js';
var format = require('./format.js');
var validate = require('./validate.js');
var ast = require('./ast.js');

exports.rewrite = require(rewritePath).rewrite;
exports.search = require(rewritePath).search;
Expand All @@ -9,3 +10,5 @@ exports.formatJSON = format.formatJSON;
exports.validate = validate.validate;
exports.validateJSON = validate.validateJSON;
exports.getConfig = require('./config.js').getConfig;
exports.parseAST = ast.parseAST;
exports.generateAST = ast.generateAST;
15 changes: 14 additions & 1 deletion lib/run.js
Expand Up @@ -15,7 +15,7 @@ tmp.setGracefulCleanup();

var doc = [
'Usage:',
' jsfmt [--no-format] [--diff|--list|--write] [--validate] [--rewrite PATTERN|--search PATTERN] [--json] [<file>...]',
' jsfmt [--no-format] [--save-ast] [--diff|--list|--write] [--validate] [--rewrite PATTERN|--search PATTERN] [--json|--ast] [<file>...]',
' jsfmt (--version | --help)',
'',
'Options:',
Expand All @@ -27,6 +27,8 @@ var doc = [
' --no-format Do not format the input file(s)',
' -w --write Overwrite the original file with jsfmt output',
' -j --json Tell jsfmt that the file being parsed is json',
' -a --ast Tell jsfmt that the file being parsed is in JSON AST',
' --save-ast Output the resulting js in JSON AST format',
' -r=PATTERN --rewrite PATTERN Rewrite rule (e.g., \'a.slice(b, len(a) -> a.slice(b)\')',
' -s=PATTERN --search PATTERN Search rule (e.g., \'a.slice\')',
].join("\r\n");
Expand Down Expand Up @@ -90,6 +92,10 @@ function handleJavascript(fullPath, original) {
var js = original;
var relativePath = path.relative(process.cwd(), fullPath);

if (argv['--ast']) {
js = jsfmt.parseAST(JSON.parse(js));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want a try/catch here or just let it error?

}

if (argv['--search']) {
try {
jsfmt.search(js, argv['--search']).forEach(function(match) {
Expand Down Expand Up @@ -157,6 +163,13 @@ function handleJavascript(fullPath, original) {
// Overwrite original file
fs.writeFileSync(fullPath, js);
} else {
if (argv['--save-ast']) {
var ast = jsfmt.generateAST(js);
js = JSON.stringify(ast);
if (!argv['--no-format']) {
js = jsfmt.formatJSON(js);
}
}
// Print to stdout
console.log(js);
}
Expand Down
28 changes: 28 additions & 0 deletions tests/ast.js
@@ -0,0 +1,28 @@
/* jshint node:true */
/* global describe,it */
'use strict';
var should = require('should');

var libPath = process.env.JSFMT_COV ? 'lib-cov' : 'lib';
var jsfmt = require('../' + libPath + '/index');

describe('jsfmt.parseAST', function() {
it('should test basic ast json parsing', function() {
var ast = '{"type":"Program","body":[{"type":"VariableDeclaration","declarations":[{"type":"VariableDeclarator","id":{"type":"Identifier","name":"a","range":[4,5]},"init":{"type":"Literal","value":50,"raw":"50","range":[8,10]},"range":[4,10]}],"kind":"var","range":[0,11]},{"type":"VariableDeclaration","declarations":[{"type":"VariableDeclarator","id":{"type":"Identifier","name":"b","range":[16,17]},"init":{"type":"Literal","value":100,"raw":"100","range":[20,23]},"range":[16,23]}],"kind":"var","range":[12,24]}],"range":[0,24],"comments":[],"tokens":[{"type":"Keyword","value":"var","range":[0,3]},{"type":"Identifier","value":"a","range":[4,5]},{"type":"Punctuator","value":"=","range":[6,7]},{"type":"Numeric","value":"50","range":[8,10]},{"type":"Punctuator","value":";","range":[10,11]},{"type":"Keyword","value":"var","range":[12,15]},{"type":"Identifier","value":"b","range":[16,17]},{"type":"Punctuator","value":"=","range":[18,19]},{"type":"Numeric","value":"100","range":[20,23]},{"type":"Punctuator","value":";","range":[23,24]}]}';
ast = JSON.parse(ast);

var js = jsfmt.parseAST(ast);
js.should.eql('var a = 50;\nvar b = 100;');
});
});

describe('jsfmt.generateAST', function() {
it('should test basic ast generation', function() {
var js = 'var a = 50;\nvar b = 100;';
var ast = jsfmt.generateAST(js);

var astExpected = '{"type":"Program","body":[{"type":"VariableDeclaration","declarations":[{"type":"VariableDeclarator","id":{"type":"Identifier","name":"a","range":[4,5]},"init":{"type":"Literal","value":50,"raw":"50","range":[8,10]},"range":[4,10]}],"kind":"var","range":[0,11]},{"type":"VariableDeclaration","declarations":[{"type":"VariableDeclarator","id":{"type":"Identifier","name":"b","range":[16,17]},"init":{"type":"Literal","value":100,"raw":"100","range":[20,23]},"range":[16,23]}],"kind":"var","range":[12,24]}],"range":[0,24],"comments":[],"tokens":[{"type":"Keyword","value":"var","range":[0,3]},{"type":"Identifier","value":"a","range":[4,5]},{"type":"Punctuator","value":"=","range":[6,7]},{"type":"Numeric","value":"50","range":[8,10]},{"type":"Punctuator","value":";","range":[10,11]},{"type":"Keyword","value":"var","range":[12,15]},{"type":"Identifier","value":"b","range":[16,17]},{"type":"Punctuator","value":"=","range":[18,19]},{"type":"Numeric","value":"100","range":[20,23]},{"type":"Punctuator","value":";","range":[23,24]}]}';

JSON.stringify(ast).should.eql(astExpected);
});
});