Permalink
Browse files

api: touch only parts of AST

  • Loading branch information...
1 parent a81d7ac commit 79124f8c6b4c2f18045c3700b96e9241b2ee458a @indutny committed Sep 27, 2012
Showing with 60 additions and 9 deletions.
  1. +55 −5 lib/spoon/api.js
  2. +2 −2 lib/spoon/cfg.js
  3. +2 −1 package.json
  4. +1 −1 test/asyncify-test.js
View
@@ -1,5 +1,6 @@
var api = exports,
esprima = require('esprima'),
+ escodegen = require('escodegen'),
uglify = require('uglify-js');
api.construct = function construct(ast) {
@@ -16,16 +17,65 @@ api.render = function render(cfg) {
return r.render();
};
+function patch(ast, decl, callback) {
+ var lastFn = null;
+ function traverse(ast) {
+ if (Array.isArray(ast)) return ast.forEach(traverse);
+
+ if (typeof ast !== 'object' || ast === null || !ast.type) return;
+ var restore;
+
+ if (ast.type === 'Literal') {
+ if (ast.value === decl && lastFn) {
+ lastFn.body = callback(lastFn).body[0].body;
+ }
+ return;
+ } else if (ast.type === 'FunctionDeclaration' ||
+ ast.type ===' FunctionExpression') {
+ restore = lastFn;
+ lastFn = ast;
+ }
+
+ // Very naive traverse
+ Object.keys(ast).forEach(function(key) {
+ // Ignore obvious keys
+ if (key === 'type' || key === 'prefix' || key === 'operator') return;
+ traverse(ast[key]);
+ });
+
+ if (restore !== undefined) lastFn = restore;
+ }
+
+ traverse(ast);
+};
+
api.preprocess = function preprocess(code, options, callback) {
if (!options) options = {};
- var ast = esprima.parse(code, options.esprima),
- cfg = api.spoon.construct(ast);
+ var ast = esprima.parse(code, options.esprima);
+
+ if (options.declaration) {
+ patch(ast, options.declaration, function replace(ast) {
+ var cfg = api.spoon.construct(ast);
+
+ if (callback) callback(cfg);
+
+ ast = api.spoon.render(cfg);
+
+ // A big fat hack here, but I need to get Esprima AST to replace it.
+ return esprima.parse(uglify.uglify.gen_code(ast, options.uglify),
+ options.esprima);
+ });
- if (callback) callback(cfg);
+ // And this is a hack too
+ ast = uglify.parser.parse(escodegen.generate(ast));
+ } else {
+ var cfg = api.spoon.construct(ast);
- ast = api.spoon.render(cfg);
+ if (callback) callback(cfg);
+ ast = api.spoon.render(cfg);
+ }
return uglify.uglify.gen_code(ast, options.uglify);
};
@@ -35,6 +85,6 @@ api.spoon = function spoon(code, fns, options) {
return api.preprocess(code, options, function(cfg) {
cfg.asyncify(fns.map(function(fn) {
return esprima.parse(fn, options.esprima);
- }), options.level);
+ }), options);
});
};
View
@@ -133,7 +133,7 @@ Cfg.prototype.split = function split(at, root, asyncify) {
return info.fn;
};
-Cfg.prototype.asyncify = function asyncify(asts, level) {
+Cfg.prototype.asyncify = function asyncify(asts, options) {
this.asyncifyState = {};
this.derive();
@@ -189,7 +189,7 @@ Cfg.prototype.asyncify = function asyncify(asts, level) {
// Find declaration first
var found = block.instructions.some(function(instr) {
if (instr.type !== 'literal' ||
- instr.args[0] !== 'enable spoon' ||
+ instr.args[0] !== (options.declaration || 'enable spoon') ||
instr.uses.length > 0) {
return false;
}
View
@@ -4,7 +4,8 @@
"main": "lib/spoon",
"dependencies": {
"esprima": "~0.9.9",
- "uglify-js": "~1.3.3"
+ "uglify-js": "~1.3.3",
+ "escodegen": "0.0.9"
},
"devDependencies": {
"mocha": "~1.4.2"
View
@@ -9,7 +9,7 @@ describe('Spoon', function() {
var ast = esprima.parse(code.toString()),
cfg = spoon.construct(ast);
- cfg.asyncify([esprima.parse(what || 'async')], 1);
+ cfg.asyncify([esprima.parse(what || 'async')], {});
var out = spoon.render(cfg);
var code = uglify.uglify.gen_code(out, { beautify: true });

0 comments on commit 79124f8

Please sign in to comment.