ember-legacy-class-transform
Version:
The default blueprint for ember-cli addons.
186 lines (143 loc) • 4.62 kB
JavaScript
module.exports = EmberRouterGenerator;
var recast = require('recast');
var findFunctionExpression = require('./helpers/find-function-expression');
var findRoutes = require('./helpers/find-routes');
var newFunctionExpression = require('./helpers/new-function-expression');
var routeNode = require('./helpers/route-node');
function EmberRouterGenerator(source, ast) {
this.source = source;
this.ast = ast;
this.mapNode = null;
this._ast();
this._walk();
}
EmberRouterGenerator.prototype.clone = function() {
return new EmberRouterGenerator(this.code());
};
EmberRouterGenerator.prototype._ast = function() {
return (this.ast = this.ast || recast.parse(this.source));
};
EmberRouterGenerator.prototype._walk = function() {
var petal = this;
recast.visit(this._ast(), {
visitCallExpression: function(path) {
var node = path.node;
if (node.callee.type === 'MemberExpression' && node.callee.property.name === 'map') {
petal.mapNode = node;
return false;
} else {
this.traverse(path);
}
}
});
};
EmberRouterGenerator.prototype.add = function(routeName, options) {
if (typeof this.mapNode === 'undefined') {
throw new Error('Source doesn\'t include Ember.map');
}
var route = this.clone();
var routes = route.mapNode.arguments[0].body.body;
route._add.call(
route,
routeName.split('/'),
routes,
options
);
return route;
};
EmberRouterGenerator.prototype._add = function(nameParts, routes, options) {
options = options || {};
var parent = nameParts[0];
var name = parent;
var children = nameParts.slice(1);
var paths = findRoutes(parent, routes, options.identifier);
var route = paths.length ? paths[paths.length - 1].node : false;
if (!route) {
route = routeNode(name, options);
routes.push(route);
}
if (children.length > 0) {
var routesFunction = findFunctionExpression(route.expression.arguments);
if (!routesFunction) {
routesFunction = newFunctionExpression();
route.expression.arguments.push(routesFunction);
}
var isAutogeneratedIndexRoute = isIndexRoute(children) && !options.path;
if (!isAutogeneratedIndexRoute) {
this._add(children, routesFunction.body.body, options);
}
}
};
EmberRouterGenerator.prototype.remove = function(routeName, options) {
if (typeof this.mapNode === 'undefined') {
throw new Error('Source doesn\'t include Ember.map');
}
options = options || {};
var route = this.clone();
var routes = route.mapNode.arguments[0].body.body;
var newRoutes = route._remove.call(
route,
routeName.split('/'),
routes,
options
);
if (newRoutes) {
route.mapNode.arguments[0].body.body = newRoutes;
}
return route;
};
EmberRouterGenerator.prototype._remove = function(nameParts, routes, options) {
var parent = nameParts[0];
var children = nameParts.slice(1);
var paths = findRoutes(parent, routes, options.identifier);
var context = this;
return paths.reduce(function(routes, path) {
var newRoutes = context._removePath(routes, parent, children, path, options);
return newRoutes || routes;
}, false);
};
EmberRouterGenerator.prototype._removePath = function(routes, parent, children, path, options) {
var route = path ? path.node : path;
var newRoutes;
if (children.length > 0) {
var routesFunction = route.expression && findFunctionExpression(route.expression.arguments);
if(isIndexRoute(children)) {
removeSubRoute(path.node);
var isAutogeneratedIndexRoute = parent === 'index' && lastExprArg(path.node).type !== 'ObjectExpression';
if (isAutogeneratedIndexRoute) {
path.replace();
}
return routes;
}
if (routesFunction) {
newRoutes = this._remove(children, routesFunction.body.body, options);
if (newRoutes) {
routesFunction.body.body = newRoutes;
}
return routes;
}
} else {
if (route) {
path.replace();
return routes;
} else {
return false;
}
}
};
EmberRouterGenerator.prototype.code = function(options) {
options = options || { tabWidth: 2, quote: 'single' };
return recast.print(this.ast, options).code;
};
function lastExprArg(node) {
return node.expression.arguments[node.expression.arguments.length-1];
}
function removeSubRoute(node) {
var lastArgument = lastExprArg(node);
if(lastArgument.type === 'FunctionExpression') {
node.expression.arguments.pop();
}
}
function isIndexRoute(children) {
return children.length === 1 && children[children.length-1] === 'index';
}