Skip to content

Commit

Permalink
Merge pull request #106 from brettlangdon/ast
Browse files Browse the repository at this point in the history
allow saving and loading in ast format
  • Loading branch information
jimfleming committed Aug 7, 2014
2 parents a18921c + 5607fdc commit 0fa7953
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 2 deletions.
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;
20 changes: 19 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,15 @@ function handleJavascript(fullPath, original) {
var js = original;
var relativePath = path.relative(process.cwd(), fullPath);

if (argv['--ast']) {
try {
js = jsfmt.parseAST(JSON.parse(js));
} catch(err) {
console.error(relativePath, err.message);
return;
}
}

if (argv['--search']) {
try {
jsfmt.search(js, argv['--search']).forEach(function(match) {
Expand Down Expand Up @@ -157,6 +168,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);
});
});

0 comments on commit 0fa7953

Please sign in to comment.