1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 | var 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 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 | var 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 |
|
34 |
|
35 |
|
36 | DepsResolver.prototype.__proto__ = Visitor.prototype;
|
37 |
|
38 | var visit = DepsResolver.prototype.visit;
|
39 |
|
40 | DepsResolver.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 |
|
63 |
|
64 |
|
65 | DepsResolver.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 |
|
73 |
|
74 |
|
75 | DepsResolver.prototype.visitIdent = function(ident) {
|
76 | this.visit(ident.val);
|
77 | };
|
78 |
|
79 |
|
80 |
|
81 |
|
82 |
|
83 | DepsResolver.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 |
|
93 |
|
94 |
|
95 | DepsResolver.prototype.visitFunction = function(fn) {
|
96 | this.functions[fn.name] = fn.block;
|
97 | };
|
98 |
|
99 |
|
100 |
|
101 |
|
102 |
|
103 | DepsResolver.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 |
|
110 |
|
111 |
|
112 | DepsResolver.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 |
|
121 | if (!literal && !/\.styl$/i.test(path)) {
|
122 | oldPath = path;
|
123 | path += '.styl';
|
124 | }
|
125 |
|
126 |
|
127 | found = utils.find(path, this.paths, this.filename);
|
128 |
|
129 |
|
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 |
|
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 |
|
164 |
|
165 |
|
166 | DepsResolver.prototype.resolve = function() {
|
167 | this.visit(this.root);
|
168 | return utils.uniq(this.deps);
|
169 | };
|