softlayer / sl-ember-components

An Ember CLI Addon that provides a variety of UI components.
http://softlayer.github.io/sl-ember-components
MIT License
114 stars 27 forks source link

Research ability to include only specific components #32

Open notmessenger opened 9 years ago

notmessenger commented 9 years ago

Similar to the idea in https://github.com/dockyard/ember-cli-bootstrap#importing-specific-bootstrap_for_ember-components

While all components would benefit from this, sl-chart would be an ideal candidate as Highcharts requires a commercial license for use and not everyone will want to make this available in their consuming application.

notmessenger commented 9 years ago

Maybe somehow the index.js file in https://github.com/ember-cli/ember-cli-qunit/compare/v0.1.2...v0.3.1 can serve as inspiration

notmessenger commented 9 years ago

https://github.com/6to5/ember-cli-6to5/blob/master/index.js accepts options (tangentially related)

notmessenger commented 8 years ago

Another idea is to look at the AST data to determine components being used. These comments made by @rwjblue in the Ember Slack community may be useful:

http://rwjblue.jsbin.com/nuyujo/edit?js - AST transform using visitor API (Ember 2.0.0+)
http://rwjblue.jsbin.com/rujeji/edit?html,js - AST Transform changing SubExpression (v-get) into PathExpression.
http://jsbin.com/yomugu/edit?html,js - AST Transform for removing an element attribute (data-test).(edited)

the middle one should be pretty demonstrative

​basically it replaces `{{v-get asdfasdf asdfasdf}}` with a more complicated path expression

​this is done at compile time, just like you want

https://github.com/emberjs/ember.js/blob/master/packages/ember-template-compiler/lib/plugins/transform-unescaped-inline-link-to.js(edited)

Another example, this one is used by Ember to transform `{{link-to 'thing' 'routeName'}}` into `{{#link-to 'routeName'}}thing{{/link-to}}
notmessenger commented 8 years ago

More ideas:

notmessenger commented 8 years ago

Robert Jackson has begun some preliminary work for the ember internationalization addon that will parse templates looking for text that does not use the translation helper. This work may serve as a decent starting point for our own template parsing for this issue.

http://jsbin.com/vayamom/edit?html,js,output

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Ember Starter Kit</title>
  <link rel="stylesheet" href="http://cdnjs.cloudflare.com/ajax/libs/normalize/2.1.0/normalize.css">
  <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
  <script src="http://builds.emberjs.com/tags/v2.3.0/ember.debug.js"></script>
  <script src="http://builds.emberjs.com/tags/v2.3.0/ember-template-compiler.js"></script>
</head>
<body>
  <div id='app'></div>
  <pre id="logs"></pre>

  <script type="text/x-handlebars" id="application">
    <h2>{{t "rwjblue's Ember JSBins"}}</h2>

    <div>{{t 'Some Text Here'}}</div>
    <div>Plain Text Here</div>

    {{#ignore-static-strings}}
      <div>This is not logged, because this string is wrapped in an ignore.</div>
    {{/ignore-static-strings}}
  </script>
</body>
</html>
var App = Ember.Application.create({
  rootElement: '#app',
  LOG_RESOLVER: true
});

App.Router.map(function() {
});

App.ApplicationRoute = Ember.Route.extend({
  actions: {
    error: function(error) {
      log(error.message);
    }
  }  
});

App.THelper = Ember.Helper.helper(function([text]) {
  return text;
});

function LogStaticStrings(options) {
  this.options = options;
  this.syntax = null; // set by HTMLBars
}

LogStaticStrings.prototype.transform = function(ast) {
  var pluginContext = this;
  let b = this.syntax.builders;
  let walker = new this.syntax.Walker();

  walker.visit(ast, function(node) {
    if (pluginContext.detectStaticString(node)) {
      return pluginContext.processStaticString(node);
    }

    pluginContext.processProgram(node);
  });

  return ast;
};

LogStaticStrings.prototype.processStaticString = function(node) { 
  let locationDisplay = calculateLocationDisplay(this.options.moduleName, node.loc);

  log(`Non translated string used${locationDisplay} \`${node.chars}\``);
}

LogStaticStrings.prototype.detectStaticString = function(node) {  
  return node.type === 'TextNode' && !node.raw && node.chars.trim() !== '';
};

LogStaticStrings.prototype.processIgnoreBlock = function(node, index, childNode) { 
  let walker = new this.syntax.Walker();

  // walk all nodes under an ignore block, and 
  // mark their `TextNode`'s as "raw"
  // this prevents them from being flagged as static strings
  walker.visit(childNode, function(node) {
    if (node.type === 'TextNode') {
      node.raw = true;
    }
  });

  // remove the {{#raw}}{{/raw}} block, and replace it with
  // its direct children
  node.body.splice(index, 1, ...childNode.program.body);
}

LogStaticStrings.prototype.detectIgnoreBlock = function(node) {  
  return node.type === 'BlockStatement' && node.path.original === 'ignore-static-strings';
};

LogStaticStrings.prototype.processProgram = function(node) {  
  if (node.type !== 'Program') {
    return false;
  }

  for (let i = node.body.length - 1; i > 0; i--) {
    let childNode = node.body[i];

    if (this.detectIgnoreBlock(childNode)) {
      this.processIgnoreBlock(node, i, childNode);
    }
  }
};

Ember.HTMLBars.registerPlugin('ast', LogStaticStrings);

// copied from emberjs/ember.js packages/ember-template-compiler/lib/system/calculate-location-display.js
function calculateLocationDisplay(moduleName, _loc) {
  let loc = _loc || {};
  let { column, line } = loc.start || {};
  let moduleInfo = '';
  if (moduleName) {
    moduleInfo +=  `'${moduleName}'`;
  }

  if (line !== undefined && column !== undefined) {
    if (moduleName) {
      // only prepend @ if the moduleName was present
      moduleInfo += '@ ';
    }
    moduleInfo += `L${line}:C${column}`;
  }

  if (moduleInfo) {
    moduleInfo = `(${moduleInfo}) `;
  }

  return moduleInfo;
}

Ember.onerror = function(error) {
  log(error.stack);
};
function log() {
  var msg = [].slice.call(arguments).join(' ');
  logs.insertBefore(document.createTextNode("\n" + msg), logs.firstChild);
}