listimports.js 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. var Parser = require('stylus/lib/parser');
  2. var Visitor = require('stylus/lib/visitor');
  3. var nodes = require('stylus/lib/nodes');
  4. module.exports = listImports;
  5. // ImportVisitor is a simple stylus ast visitor that navigates the graph
  6. // building a list of imports in it.
  7. function ImportVisitor() {
  8. Visitor.apply(this, arguments);
  9. this.importPaths = [];
  10. }
  11. ImportVisitor.prototype = Object.create(Visitor.prototype);
  12. ImportVisitor.prototype.constructor = ImportVisitor;
  13. ImportVisitor.prototype.visitImport = function(node) {
  14. this.importPaths.push(node.path.first.string);
  15. return node;
  16. };
  17. ImportVisitor.prototype.visitRoot = function(block){
  18. for (var i = 0; i < block.nodes.length; ++i) {
  19. this.visit(block.nodes[i]);
  20. }
  21. return block;
  22. };
  23. ImportVisitor.prototype.visitExpression = function(expr) {
  24. for (var i = 0; i < expr.nodes.length; ++i) {
  25. this.visit(expr.nodes[i]);
  26. }
  27. return expr;
  28. };
  29. ImportVisitor.prototype.visitCall = function(fn) {
  30. if (fn.name === 'use' || fn.name === 'json') {
  31. this.importPaths.push(fn.args.first.string);
  32. }
  33. return fn;
  34. };
  35. ImportVisitor.prototype.visitSelector = function(sel) {
  36. for (var i = 0; i < sel.block.nodes.length; i++) {
  37. this.visit(sel.block.nodes[i]);
  38. }
  39. return sel;
  40. }
  41. ImportVisitor.prototype.visitBlock = ImportVisitor.prototype.visitRoot;
  42. ImportVisitor.prototype.visitGroup = ImportVisitor.prototype.visitRoot;
  43. // Returns a list of paths that given source imports.
  44. function listImports(source, options) {
  45. // Store source -> imports work in a cache. The Parser is the most expensive
  46. // part of stylus and we can't use their cache without creating undesired side
  47. // effects later during the actual render. In single run builds this will
  48. // benefit repeated files imported like common styling. In multiple run builds
  49. // this will help stylus import trees when a dependency changes, the higher up
  50. // files won't need to be parsed again.
  51. var cache = options.cache;
  52. if (cache && cache[source]) { return cache[source]; }
  53. // Current idea here is to silence errors and let them rise in stylus's
  54. // renderer which has more handling so that the error message is more
  55. // meaningful and easy to understand.
  56. try {
  57. var ast = new Parser(source, { cache: false }).parse();
  58. } catch (e) {
  59. return [];
  60. }
  61. var importVisitor = new ImportVisitor(ast, {});
  62. importVisitor.visit(ast);
  63. if (cache) {
  64. cache[source] = importVisitor.importPaths;
  65. }
  66. return importVisitor.importPaths;
  67. }