You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
169 lines
3.3 KiB
169 lines
3.3 KiB
|
|
/** |
|
* Module dependencies. |
|
*/ |
|
|
|
var Visitor = require('./') |
|
, Parser = require('../parser') |
|
, nodes = require('../nodes') |
|
, utils = require('../utils') |
|
, dirname = require('path').dirname |
|
, fs = require('fs'); |
|
|
|
/** |
|
* Initialize a new `DepsResolver` with the given `root` Node |
|
* and the `options`. |
|
* |
|
* @param {Node} root |
|
* @param {Object} options |
|
* @api private |
|
*/ |
|
|
|
var DepsResolver = module.exports = function DepsResolver(root, options) { |
|
this.root = root; |
|
this.filename = options.filename; |
|
this.paths = options.paths || []; |
|
this.paths.push(dirname(options.filename || '.')); |
|
this.options = options; |
|
this.functions = {}; |
|
this.deps = []; |
|
}; |
|
|
|
/** |
|
* Inherit from `Visitor.prototype`. |
|
*/ |
|
|
|
DepsResolver.prototype.__proto__ = Visitor.prototype; |
|
|
|
var visit = DepsResolver.prototype.visit; |
|
|
|
DepsResolver.prototype.visit = function(node) { |
|
switch (node.nodeName) { |
|
case 'root': |
|
case 'block': |
|
case 'expression': |
|
this.visitRoot(node); |
|
break; |
|
case 'group': |
|
case 'media': |
|
case 'atblock': |
|
case 'atrule': |
|
case 'keyframes': |
|
case 'each': |
|
case 'supports': |
|
this.visit(node.block); |
|
break; |
|
default: |
|
visit.call(this, node); |
|
} |
|
}; |
|
|
|
/** |
|
* Visit Root. |
|
*/ |
|
|
|
DepsResolver.prototype.visitRoot = function(block) { |
|
for (var i = 0, len = block.nodes.length; i < len; ++i) { |
|
this.visit(block.nodes[i]); |
|
} |
|
}; |
|
|
|
/** |
|
* Visit Ident. |
|
*/ |
|
|
|
DepsResolver.prototype.visitIdent = function(ident) { |
|
this.visit(ident.val); |
|
}; |
|
|
|
/** |
|
* Visit If. |
|
*/ |
|
|
|
DepsResolver.prototype.visitIf = function(node) { |
|
this.visit(node.block); |
|
this.visit(node.cond); |
|
for (var i = 0, len = node.elses.length; i < len; ++i) { |
|
this.visit(node.elses[i]); |
|
} |
|
}; |
|
|
|
/** |
|
* Visit Function. |
|
*/ |
|
|
|
DepsResolver.prototype.visitFunction = function(fn) { |
|
this.functions[fn.name] = fn.block; |
|
}; |
|
|
|
/** |
|
* Visit Call. |
|
*/ |
|
|
|
DepsResolver.prototype.visitCall = function(call) { |
|
if (call.name in this.functions) this.visit(this.functions[call.name]); |
|
if (call.block) this.visit(call.block); |
|
}; |
|
|
|
/** |
|
* Visit Import. |
|
*/ |
|
|
|
DepsResolver.prototype.visitImport = function(node) { |
|
var path = node.path.first.val |
|
, literal, found, oldPath; |
|
|
|
if (!path) return; |
|
|
|
literal = /\.css(?:"|$)/.test(path); |
|
|
|
// support optional .styl |
|
if (!literal && !/\.styl$/i.test(path)) { |
|
oldPath = path; |
|
path += '.styl'; |
|
} |
|
|
|
// Lookup |
|
found = utils.find(path, this.paths, this.filename); |
|
|
|
// support optional index |
|
if (!found && oldPath) found = utils.lookupIndex(oldPath, this.paths, this.filename); |
|
|
|
if (!found) return; |
|
|
|
this.deps = this.deps.concat(found); |
|
|
|
if (literal) return; |
|
|
|
// nested imports |
|
for (var i = 0, len = found.length; i < len; ++i) { |
|
var file = found[i] |
|
, dir = dirname(file) |
|
, str = fs.readFileSync(file, 'utf-8') |
|
, block = new nodes.Block |
|
, parser = new Parser(str, utils.merge({ root: block }, this.options)); |
|
|
|
if (!~this.paths.indexOf(dir)) this.paths.push(dir); |
|
|
|
try { |
|
block = parser.parse(); |
|
} catch (err) { |
|
err.filename = file; |
|
err.lineno = parser.lexer.lineno; |
|
err.column = parser.lexer.column; |
|
err.input = str; |
|
throw err; |
|
} |
|
|
|
this.visit(block); |
|
} |
|
}; |
|
|
|
/** |
|
* Get dependencies. |
|
*/ |
|
|
|
DepsResolver.prototype.resolve = function() { |
|
this.visit(this.root); |
|
return utils.uniq(this.deps); |
|
};
|
|
|