注入环境配置的Ember蓝图?

时间:2015-05-16 04:56:12

标签: node.js ember.js ember-cli

我对Ember相对较新,并且想知道是否有办法创建一个蓝图/生成器,它会在维护所有现有配置的同时将新值注入环境配置。是否有一些Ember魔法允许现有文件充当蓝图模板?我理想的实现看起来像这样:

ember g platform foo

// config/environment.js
module.exports = function(environment) {
var ENV = {
  // Existing config values here...
  APP: {
    platforms: {
      foo: 'abc123'  // Generator injects the 'foo' platform and a GUID
    }
  };
  // Existing environment-specific settings here...
  return ENV;
};

这是使用节点fs.readFile()fs.writeFile()更容易实现的吗?如果是这样,我该如何解析environment.js

感谢任何想法 - 谢谢!

1 个答案:

答案 0 :(得分:1)

在我不知道的情况下,Ember中没有现存的魔法。当您生成路由时,会发生与您正在谈论的内容非常相似的内容,但代码相当复杂。 ember generate route new_route函数调用此函数

function addRouteToRouter(name, options) {
  var routerPath = path.join(options.root, 'app', 'router.js');
  var source = fs.readFileSync(routerPath, 'utf-8');

  var routes = new EmberRouterGenerator(source);
  var newRoutes = routes.add(name, options);

  fs.writeFileSync(routerPath, newRoutes.code());
}

然后执行解释器级别,如代码添加路由器并将其还原为代码:

module.exports = EmberRouterGenerator;

var recast    = require('recast');
var traverse  = require('es-simpler-traverser');

var Scope     = require('./scope');
var DefineCallExpression = require('./visitors/define-call-expression.js');

var findFunctionExpression = require('./helpers/find-function-expression');
var hasRoute               = require('./helpers/has-route');
var newFunctionExpression  = require('./helpers/new-function-expression');
var resourceNode           = require('./helpers/resource-node');
var routeNode              = require('./helpers/route-node');

function EmberRouterGenerator(source, ast) {
  this.source = source;
  this.ast = ast;
  this.mapNode = null;
  this.scope = new Scope();

  this.visitors = {
    CallExpression: new DefineCallExpression(this.scope, this)
  };

  this._ast();
  this._walk();
}

EmberRouterGenerator.prototype.clone = function() {
  var route = new EmberRouterGenerator(this.source);

  return route;
};

EmberRouterGenerator.prototype._ast  = function() {
  this.ast = this.ast || recast.parse(this.source);
};

EmberRouterGenerator.prototype._walk  = function() {
  var scope = this.scope;
  var visitors = this.visitors;

  traverse(this.ast, {
    exit: function(node) {
      var visitor = visitors[node.type];

      if (visitor && typeof visitor.exit === 'function') {
        visitor.exit(node);
      }
    },

    enter: function(node) {
      var visitor = visitors[node.type];

      if (visitor && typeof visitor.enter === 'function') {
        visitor.enter(node);
      }
    }
  });
};

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 route    = hasRoute(parent, routes);

  if (!route) {
    if (options.type === 'resource') {
      route = resourceNode(name, options);
      routes.push(route);
    } else {
      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);
    }

    this._add(children, routesFunction.body.body, options);
  }
};

EmberRouterGenerator.prototype.remove = function(routeName) {
  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;

  var newRoutes = route._remove.call(
    route,
    routeName.split('/'),
    routes
  );

  if (newRoutes) {
    route.mapNode.arguments[0].body.body = newRoutes;
  }

  return route;
};



EmberRouterGenerator.prototype._remove = function(nameParts, routes) {
  var parent   =  nameParts[0];
  var name     = parent;
  var children = nameParts.slice(1);
  var route    = hasRoute(parent, routes);
  var newRoutes;

  if (children.length > 0) {
    var routesFunction = route.expression && findFunctionExpression(route.expression.arguments);

    if (routesFunction) {
      newRoutes = this._remove(children, routesFunction.body.body);

      if (newRoutes) {
        routesFunction.body.body = newRoutes;
      }

      return routes;
    }
  } else {
    if (route) {
      routes = routes.filter(function(node) {
        return node !== route;
      });

      return routes;
    } else {
      return false;
    }
  }
};

EmberRouterGenerator.prototype.code = function(options) {
  options = options || { tabWidth: 2, quote: 'single' };

  return recast.print(this.ast, options).code;
};

然后就是替代方案,它涉及读取文件,在正确解析文件后在正确的位置添加新环境,然后再写回流。您想要做的事情的复杂性可能超过了手动IMO所需的时间。如果这是你经常做的事情,也许可以考虑用另一种语言编写一个脚本,这种语言在文本文件操作方面更好(阅读更多人用它)