UNPKG

3.37 kBJavaScriptView Raw
1
2/**
3 * Module dependencies.
4 */
5
6var Visitor = require('./')
7 , Parser = require('../parser')
8 , nodes = require('../nodes')
9 , utils = require('../utils')
10 , dirname = require('path').dirname
11 , fs = require('fs');
12
13/**
14 * Initialize a new `DepsResolver` with the given `root` Node
15 * and the `options`.
16 *
17 * @param {Node} root
18 * @param {Object} options
19 * @api private
20 */
21
22var DepsResolver = module.exports = function DepsResolver(root, options) {
23 this.root = root;
24 this.filename = options.filename;
25 this.paths = options.paths || [];
26 this.paths.push(dirname(options.filename || '.'));
27 this.options = options;
28 this.functions = {};
29 this.deps = [];
30};
31
32/**
33 * Inherit from `Visitor.prototype`.
34 */
35
36DepsResolver.prototype.__proto__ = Visitor.prototype;
37
38var visit = DepsResolver.prototype.visit;
39
40DepsResolver.prototype.visit = function(node) {
41 switch (node.nodeName) {
42 case 'root':
43 case 'block':
44 case 'expression':
45 this.visitRoot(node);
46 break;
47 case 'group':
48 case 'media':
49 case 'atblock':
50 case 'atrule':
51 case 'keyframes':
52 case 'each':
53 case 'supports':
54 this.visit(node.block);
55 break;
56 default:
57 visit.call(this, node);
58 }
59};
60
61/**
62 * Visit Root.
63 */
64
65DepsResolver.prototype.visitRoot = function(block) {
66 for (var i = 0, len = block.nodes.length; i < len; ++i) {
67 this.visit(block.nodes[i]);
68 }
69};
70
71/**
72 * Visit Ident.
73 */
74
75DepsResolver.prototype.visitIdent = function(ident) {
76 this.visit(ident.val);
77};
78
79/**
80 * Visit If.
81 */
82
83DepsResolver.prototype.visitIf = function(node) {
84 this.visit(node.block);
85 this.visit(node.cond);
86 for (var i = 0, len = node.elses.length; i < len; ++i) {
87 this.visit(node.elses[i]);
88 }
89};
90
91/**
92 * Visit Function.
93 */
94
95DepsResolver.prototype.visitFunction = function(fn) {
96 this.functions[fn.name] = fn.block;
97};
98
99/**
100 * Visit Call.
101 */
102
103DepsResolver.prototype.visitCall = function(call) {
104 if (call.name in this.functions) this.visit(this.functions[call.name]);
105 if (call.block) this.visit(call.block);
106};
107
108/**
109 * Visit Import.
110 */
111
112DepsResolver.prototype.visitImport = function(node) {
113 var path = node.path.first.val
114 , literal, found, oldPath;
115
116 if (!path) return;
117
118 literal = /\.css(?:"|$)/.test(path);
119
120 // support optional .styl
121 if (!literal && !/\.styl$/i.test(path)) {
122 oldPath = path;
123 path += '.styl';
124 }
125
126 // Lookup
127 found = utils.find(path, this.paths, this.filename);
128
129 // support optional index
130 if (!found && oldPath) found = utils.lookupIndex(oldPath, this.paths, this.filename);
131
132 if (!found) return;
133
134 this.deps = this.deps.concat(found);
135
136 if (literal) return;
137
138 // nested imports
139 for (var i = 0, len = found.length; i < len; ++i) {
140 var file = found[i]
141 , dir = dirname(file)
142 , str = fs.readFileSync(file, 'utf-8')
143 , block = new nodes.Block
144 , parser = new Parser(str, utils.merge({ root: block }, this.options));
145
146 if (!~this.paths.indexOf(dir)) this.paths.push(dir);
147
148 try {
149 block = parser.parse();
150 } catch (err) {
151 err.filename = file;
152 err.lineno = parser.lexer.lineno;
153 err.column = parser.lexer.column;
154 err.input = str;
155 throw err;
156 }
157
158 this.visit(block);
159 }
160};
161
162/**
163 * Get dependencies.
164 */
165
166DepsResolver.prototype.resolve = function() {
167 this.visit(this.root);
168 return utils.uniq(this.deps);
169};