UNPKG

9.94 kBJavaScriptView Raw
1"use strict";
2
3var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
5var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
6
7var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
8
9// const CSSAsset = require('./CSSAsset');
10const Asset = require('../Asset');
11
12const localRequire = require('../utils/localRequire');
13
14const Resolver = require('../Resolver');
15
16const fs = require('@parcel/fs');
17
18const _require = require('path'),
19 dirname = _require.dirname,
20 resolve = _require.resolve,
21 relative = _require.relative;
22
23const _require2 = require('../utils/glob'),
24 isGlob = _require2.isGlob,
25 glob = _require2.glob;
26
27const URL_RE = /^(?:url\s*\(\s*)?['"]?(?:[#/]|(?:https?:)?\/\/)/i;
28
29class StylusAsset extends Asset {
30 constructor(name, options) {
31 super(name, options);
32 this.type = 'css';
33 }
34
35 parse(code) {
36 var _this = this;
37
38 return (0, _asyncToGenerator2.default)(function* () {
39 // stylus should be installed locally in the module that's being required
40 let stylus = yield localRequire('stylus', _this.name);
41 let opts = yield _this.getConfig(['.stylusrc', '.stylusrc.js'], {
42 packageKey: 'stylus'
43 });
44 let style = stylus(code, opts);
45 style.set('filename', _this.name);
46 style.set('include css', true); // Setup a handler for the URL function so we add dependencies for linked assets.
47
48 style.define('url', node => {
49 let filename = _this.addURLDependency(node.val, node.filename);
50
51 return new stylus.nodes.Literal(`url(${JSON.stringify(filename)})`);
52 });
53 style.set('Evaluator', (yield createEvaluator(code, _this, style.options)));
54 return style;
55 })();
56 }
57
58 generate() {
59 return [{
60 type: 'css',
61 value: this.ast.render(),
62 hasDependencies: false
63 }];
64 }
65
66 generateErrorMessage(err) {
67 let index = err.message.indexOf('\n');
68 err.codeFrame = err.message.slice(index + 1);
69 err.message = err.message.slice(0, index);
70 return err;
71 }
72
73}
74
75function getDependencies(_x, _x2, _x3, _x4) {
76 return _getDependencies.apply(this, arguments);
77}
78
79function _getDependencies() {
80 _getDependencies = (0, _asyncToGenerator2.default)(function* (code, filepath, asset, options, seen = new Set()) {
81 seen.add(filepath);
82
83 const _ref = yield Promise.all(['parser', 'visitor/deps-resolver', 'nodes', 'utils'].map(dep => localRequire('stylus/lib/' + dep, filepath))),
84 _ref2 = (0, _slicedToArray2.default)(_ref, 4),
85 Parser = _ref2[0],
86 DepsResolver = _ref2[1],
87 nodes = _ref2[2],
88 utils = _ref2[3];
89
90 nodes.filename = asset.name;
91 let parser = new Parser(code, options);
92 let ast = parser.parse();
93 let deps = new Map();
94 let resolver = new Resolver(Object.assign({}, asset.options, {
95 extensions: ['.styl', '.css']
96 }));
97
98 class ImportVisitor extends DepsResolver {
99 visitImport(imported) {
100 let path = imported.path.first.string;
101
102 if (!deps.has(path)) {
103 if (isGlob(path)) {
104 deps.set(path, glob(resolve(dirname(filepath), path), {
105 onlyFiles: true
106 }).then(entries => Promise.all(entries.map(entry => resolver.resolve('./' + relative(dirname(filepath), entry), filepath)))));
107 } else {
108 deps.set(path, resolver.resolve(path, filepath));
109 }
110 }
111 }
112
113 }
114
115 new ImportVisitor(ast, options).visit(ast); // Recursively process depdendencies, and return a map with all resolved paths.
116
117 let res = new Map();
118 yield Promise.all(Array.from(deps.entries()).map(
119 /*#__PURE__*/
120 function () {
121 var _ref3 = (0, _asyncToGenerator2.default)(function* ([path, resolved]) {
122 try {
123 resolved = yield resolved;
124 resolved = Array.isArray(resolved) ? resolved.map(r => r.path) : resolved.path;
125 } catch (err) {
126 resolved = null;
127 }
128
129 let found;
130
131 if (resolved) {
132 found = Array.isArray(resolved) ? resolved : [resolved];
133 res.set(path, resolved);
134 } else {
135 // If we couldn't resolve, try the normal stylus resolver.
136 // We just need to do this to keep track of the dependencies - stylus does the real work.
137 // support optional .styl
138 let originalPath = path;
139
140 if (!/\.styl$/i.test(path)) {
141 path += '.styl';
142 }
143
144 let paths = (options.paths || []).concat(dirname(filepath || '.'));
145 found = utils.find(path, paths, filepath);
146
147 if (!found) {
148 found = utils.lookupIndex(originalPath, paths, filepath);
149 }
150
151 if (!found) {
152 throw new Error('failed to locate file ' + originalPath);
153 }
154 } // Recursively process resolved files as well to get nested deps
155
156
157 var _iteratorNormalCompletion2 = true;
158 var _didIteratorError2 = false;
159 var _iteratorError2 = undefined;
160
161 try {
162 for (var _iterator2 = found[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
163 let resolved = _step2.value;
164
165 if (!seen.has(resolved)) {
166 asset.addDependency(resolved, {
167 includedInParent: true
168 });
169 let code = yield fs.readFile(resolved, 'utf8');
170 var _iteratorNormalCompletion3 = true;
171 var _didIteratorError3 = false;
172 var _iteratorError3 = undefined;
173
174 try {
175 for (var _iterator3 = (yield getDependencies(code, resolved, asset, options, seen))[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
176 let _step3$value = (0, _slicedToArray2.default)(_step3.value, 2),
177 path = _step3$value[0],
178 resolvedPath = _step3$value[1];
179
180 res.set(path, resolvedPath);
181 }
182 } catch (err) {
183 _didIteratorError3 = true;
184 _iteratorError3 = err;
185 } finally {
186 try {
187 if (!_iteratorNormalCompletion3 && _iterator3.return != null) {
188 _iterator3.return();
189 }
190 } finally {
191 if (_didIteratorError3) {
192 throw _iteratorError3;
193 }
194 }
195 }
196 }
197 }
198 } catch (err) {
199 _didIteratorError2 = true;
200 _iteratorError2 = err;
201 } finally {
202 try {
203 if (!_iteratorNormalCompletion2 && _iterator2.return != null) {
204 _iterator2.return();
205 }
206 } finally {
207 if (_didIteratorError2) {
208 throw _iteratorError2;
209 }
210 }
211 }
212 });
213
214 return function (_x8) {
215 return _ref3.apply(this, arguments);
216 };
217 }()));
218 return res;
219 });
220 return _getDependencies.apply(this, arguments);
221}
222
223function createEvaluator(_x5, _x6, _x7) {
224 return _createEvaluator.apply(this, arguments);
225}
226/**
227 * Puts the content of all given node blocks into the first one, essentially merging them.
228 */
229
230
231function _createEvaluator() {
232 _createEvaluator = (0, _asyncToGenerator2.default)(function* (code, asset, options) {
233 const deps = yield getDependencies(code, asset.name, asset, options);
234 const Evaluator = yield localRequire('stylus/lib/visitor/evaluator', asset.name); // This is a custom stylus evaluator that extends stylus with support for the node
235 // require resolution algorithm. It also adds all dependencies to the parcel asset
236 // tree so the file watcher works correctly, etc.
237
238 class CustomEvaluator extends Evaluator {
239 visitImport(imported) {
240 let node = this.visit(imported.path).first;
241 let path = node.string;
242
243 if (node.name !== 'url' && path && !URL_RE.test(path)) {
244 let resolved = deps.get(path); // First try resolving using the node require resolution algorithm.
245 // This allows stylus files in node_modules to be resolved properly.
246 // If we find something, update the AST so stylus gets the absolute path to load later.
247
248 if (resolved) {
249 if (!Array.isArray(resolved)) {
250 node.string = resolved;
251 } else {
252 // If the import resolves to multiple files (i.e. glob),
253 // replace it with a separate import node for each file
254 return mergeBlocks(resolved.map(resolvedPath => {
255 node.string = resolvedPath;
256 return super.visitImport(imported.clone());
257 }));
258 }
259 }
260 } // Done. Let stylus do its thing.
261
262
263 return super.visitImport(imported);
264 }
265
266 }
267
268 return CustomEvaluator;
269 });
270 return _createEvaluator.apply(this, arguments);
271}
272
273function mergeBlocks(blocks) {
274 let finalBlock;
275 var _iteratorNormalCompletion = true;
276 var _didIteratorError = false;
277 var _iteratorError = undefined;
278
279 try {
280 for (var _iterator = blocks[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
281 const block = _step.value;
282 if (!finalBlock) finalBlock = block;else {
283 block.nodes.forEach(node => finalBlock.push(node));
284 }
285 }
286 } catch (err) {
287 _didIteratorError = true;
288 _iteratorError = err;
289 } finally {
290 try {
291 if (!_iteratorNormalCompletion && _iterator.return != null) {
292 _iterator.return();
293 }
294 } finally {
295 if (_didIteratorError) {
296 throw _iteratorError;
297 }
298 }
299 }
300
301 return finalBlock;
302}
303
304module.exports = StylusAsset;
\No newline at end of file