@parcel/transformer-stylus 2.0.0-beta.1 → 2.0.0-nightly.1002
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/StylusTransformer.js +245 -63
- package/package.json +11 -9
- package/src/StylusTransformer.js +167 -72
package/lib/StylusTransformer.js
CHANGED
|
@@ -5,17 +5,111 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.default = void 0;
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
function _plugin() {
|
|
9
|
+
const data = require("@parcel/plugin");
|
|
9
10
|
|
|
10
|
-
|
|
11
|
+
_plugin = function () {
|
|
12
|
+
return data;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
return data;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function _utils() {
|
|
19
|
+
const data = require("@parcel/utils");
|
|
20
|
+
|
|
21
|
+
_utils = function () {
|
|
22
|
+
return data;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
return data;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function _path() {
|
|
29
|
+
const data = _interopRequireDefault(require("path"));
|
|
30
|
+
|
|
31
|
+
_path = function () {
|
|
32
|
+
return data;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
return data;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function _fs() {
|
|
39
|
+
const data = _interopRequireDefault(require("fs"));
|
|
40
|
+
|
|
41
|
+
_fs = function () {
|
|
42
|
+
return data;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
return data;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function _stylus() {
|
|
49
|
+
const data = _interopRequireDefault(require("stylus"));
|
|
50
|
+
|
|
51
|
+
_stylus = function () {
|
|
52
|
+
return data;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
return data;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function _parser() {
|
|
59
|
+
const data = _interopRequireDefault(require("stylus/lib/parser"));
|
|
60
|
+
|
|
61
|
+
_parser = function () {
|
|
62
|
+
return data;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
return data;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function _depsResolver() {
|
|
69
|
+
const data = _interopRequireDefault(require("stylus/lib/visitor/deps-resolver"));
|
|
70
|
+
|
|
71
|
+
_depsResolver = function () {
|
|
72
|
+
return data;
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
return data;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function _nodes() {
|
|
79
|
+
const data = _interopRequireDefault(require("stylus/lib/nodes"));
|
|
11
80
|
|
|
12
|
-
|
|
81
|
+
_nodes = function () {
|
|
82
|
+
return data;
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
return data;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function _utils2() {
|
|
89
|
+
const data = _interopRequireDefault(require("stylus/lib/utils"));
|
|
90
|
+
|
|
91
|
+
_utils2 = function () {
|
|
92
|
+
return data;
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
return data;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function _evaluator() {
|
|
99
|
+
const data = _interopRequireDefault(require("stylus/lib/visitor/evaluator"));
|
|
100
|
+
|
|
101
|
+
_evaluator = function () {
|
|
102
|
+
return data;
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
return data;
|
|
106
|
+
}
|
|
13
107
|
|
|
14
108
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
15
109
|
|
|
16
110
|
const URL_RE = /^(?:url\s*\(\s*)?['"]?(?:[#/]|(?:https?:)?\/\/)/i;
|
|
17
111
|
|
|
18
|
-
var _default = new _plugin.Transformer({
|
|
112
|
+
var _default = new (_plugin().Transformer)({
|
|
19
113
|
async loadConfig({
|
|
20
114
|
config
|
|
21
115
|
}) {
|
|
@@ -24,27 +118,18 @@ var _default = new _plugin.Transformer({
|
|
|
24
118
|
});
|
|
25
119
|
|
|
26
120
|
if (configFile) {
|
|
27
|
-
let isJavascript = _path.default.extname(configFile.filePath) === '.js';
|
|
121
|
+
let isJavascript = _path().default.extname(configFile.filePath) === '.js';
|
|
28
122
|
|
|
29
123
|
if (isJavascript) {
|
|
30
|
-
config.
|
|
31
|
-
|
|
32
|
-
}
|
|
124
|
+
config.invalidateOnStartup();
|
|
125
|
+
} // Resolve relative paths from config file
|
|
33
126
|
|
|
34
|
-
config.setResult({
|
|
35
|
-
contents: configFile.contents,
|
|
36
|
-
isSerialisable: !isJavascript
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
},
|
|
40
127
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
if (!config.result) return; // Ensure we dont try to serialise functions
|
|
128
|
+
if (configFile.contents.paths) {
|
|
129
|
+
configFile.contents.paths = configFile.contents.paths.map(p => _path().default.resolve(_path().default.dirname(configFile.filePath), p));
|
|
130
|
+
}
|
|
45
131
|
|
|
46
|
-
|
|
47
|
-
config.result.contents = {};
|
|
132
|
+
return configFile.contents;
|
|
48
133
|
}
|
|
49
134
|
},
|
|
50
135
|
|
|
@@ -54,21 +139,27 @@ var _default = new _plugin.Transformer({
|
|
|
54
139
|
config,
|
|
55
140
|
options
|
|
56
141
|
}) {
|
|
57
|
-
let stylusConfig = config
|
|
58
|
-
|
|
59
|
-
let stylus = await options.packageManager.require('stylus', asset.filePath, {
|
|
60
|
-
autoinstall: options.autoinstall
|
|
61
|
-
});
|
|
142
|
+
let stylusConfig = config !== null && config !== void 0 ? config : {};
|
|
62
143
|
let code = await asset.getCode();
|
|
63
|
-
let style =
|
|
144
|
+
let style = (0, _stylus().default)(code, { ...stylusConfig
|
|
145
|
+
});
|
|
64
146
|
style.set('filename', asset.filePath);
|
|
65
147
|
style.set('include css', true); // Setup a handler for the URL function so we add dependencies for linked assets.
|
|
66
148
|
|
|
67
149
|
style.define('url', node => {
|
|
68
|
-
let filename = asset.addURLDependency(node.val,
|
|
69
|
-
|
|
150
|
+
let filename = asset.addURLDependency(node.val, {
|
|
151
|
+
loc: (0, _utils().createDependencyLocation)({
|
|
152
|
+
line: node.lineno,
|
|
153
|
+
column: node.column
|
|
154
|
+
}, node.val)
|
|
155
|
+
});
|
|
156
|
+
return new (_stylus().default.nodes.Literal)(`url(${JSON.stringify(filename)})`);
|
|
70
157
|
});
|
|
71
|
-
|
|
158
|
+
let {
|
|
159
|
+
resolved: stylusPath
|
|
160
|
+
} = await options.packageManager.resolve('stylus', __filename);
|
|
161
|
+
let nativeGlob = await options.packageManager.require('glob', stylusPath);
|
|
162
|
+
style.set('Evaluator', await createEvaluator(code, asset, resolve, style.options, options, nativeGlob));
|
|
72
163
|
asset.type = 'css';
|
|
73
164
|
asset.setCode(style.render());
|
|
74
165
|
asset.meta.hasDependencies = false;
|
|
@@ -79,31 +170,48 @@ var _default = new _plugin.Transformer({
|
|
|
79
170
|
|
|
80
171
|
exports.default = _default;
|
|
81
172
|
|
|
82
|
-
|
|
173
|
+
function attemptResolve(importedPath, filepath, asset, resolve, deps) {
|
|
174
|
+
if (deps.has(importedPath)) {
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if ((0, _utils().isGlob)(importedPath)) {
|
|
179
|
+
// Invalidate when new files are created that match the glob pattern.
|
|
180
|
+
let absoluteGlob = _path().default.resolve(_path().default.dirname(filepath), importedPath);
|
|
181
|
+
|
|
182
|
+
asset.invalidateOnFileCreate({
|
|
183
|
+
glob: absoluteGlob
|
|
184
|
+
});
|
|
185
|
+
deps.set(importedPath, (0, _utils().glob)(absoluteGlob, asset.fs, {
|
|
186
|
+
onlyFiles: true
|
|
187
|
+
}).then(entries => Promise.all(entries.map(entry => resolve(filepath, './' + _path().default.relative(_path().default.dirname(filepath), entry))))));
|
|
188
|
+
} else {
|
|
189
|
+
deps.set(importedPath, resolve(filepath, importedPath));
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
async function getDependencies(code, filepath, asset, resolve, options, parcelOptions, nativeGlob, seen = new Set(), includeImports = true) {
|
|
83
194
|
seen.add(filepath);
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
})));
|
|
87
|
-
nodes.filename = asset.filePath;
|
|
88
|
-
let parser = new Parser(code, options);
|
|
195
|
+
_nodes().default.filename = asset.filePath;
|
|
196
|
+
let parser = new (_parser().default)(code, options);
|
|
89
197
|
let ast = parser.parse();
|
|
90
198
|
let deps = new Map();
|
|
91
|
-
|
|
199
|
+
|
|
200
|
+
if (includeImports && options.imports) {
|
|
201
|
+
for (let importedPath of options.imports) {
|
|
202
|
+
attemptResolve(importedPath, filepath, asset, resolve, deps);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
class ImportVisitor extends _depsResolver().default {
|
|
92
207
|
visitImport(imported) {
|
|
93
208
|
let importedPath = imported.path.first.string;
|
|
94
|
-
|
|
95
|
-
if (!deps.has(importedPath)) {
|
|
96
|
-
if ((0, _utils.isGlob)(importedPath)) {
|
|
97
|
-
deps.set(importedPath, (0, _utils.glob)(_path.default.resolve(_path.default.dirname(filepath), importedPath), parcelOptions.inputFS, {
|
|
98
|
-
onlyFiles: true
|
|
99
|
-
}).then(entries => Promise.all(entries.map(entry => resolve(filepath, './' + _path.default.relative(_path.default.dirname(filepath), entry))))));
|
|
100
|
-
} else {
|
|
101
|
-
deps.set(importedPath, resolve(filepath, importedPath));
|
|
102
|
-
}
|
|
103
|
-
}
|
|
209
|
+
attemptResolve(importedPath, filepath, asset, resolve, deps);
|
|
104
210
|
}
|
|
105
211
|
|
|
106
|
-
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
new ImportVisitor(ast, options).visit(ast); // Recursively process depdendencies, and return a map with all resolved paths.
|
|
107
215
|
|
|
108
216
|
let res = new Map();
|
|
109
217
|
await Promise.all(Array.from(deps.entries()).map(async ([importedPath, resolved]) => {
|
|
@@ -115,7 +223,7 @@ async function getDependencies(code, filepath, asset, resolve, options, parcelOp
|
|
|
115
223
|
|
|
116
224
|
let found;
|
|
117
225
|
|
|
118
|
-
if (resolved) {
|
|
226
|
+
if (resolved && (!Array.isArray(resolved) || resolved.length > 0)) {
|
|
119
227
|
found = Array.isArray(resolved) ? resolved : [resolved];
|
|
120
228
|
res.set(importedPath, resolved);
|
|
121
229
|
} else {
|
|
@@ -126,13 +234,20 @@ async function getDependencies(code, filepath, asset, resolve, options, parcelOp
|
|
|
126
234
|
|
|
127
235
|
if (!/\.styl$/i.test(importedPath)) {
|
|
128
236
|
importedPath += '.styl';
|
|
129
|
-
}
|
|
237
|
+
} // Patch the native FS so we use Parcel's FS, and track files that are
|
|
238
|
+
// checked so we invalidate the cache when they are created.
|
|
130
239
|
|
|
131
|
-
|
|
132
|
-
|
|
240
|
+
|
|
241
|
+
let restore = patchNativeFS(asset.fs, nativeGlob);
|
|
242
|
+
let paths = [...new Set((options.paths || []).concat(_path().default.dirname(filepath || '.')))];
|
|
243
|
+
found = _utils2().default.find(importedPath, paths, filepath);
|
|
133
244
|
|
|
134
245
|
if (!found) {
|
|
135
|
-
found =
|
|
246
|
+
found = _utils2().default.lookupIndex(originalPath, paths, filepath);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
for (let invalidation of restore()) {
|
|
250
|
+
asset.invalidateOnFileCreate(invalidation);
|
|
136
251
|
}
|
|
137
252
|
|
|
138
253
|
if (!found) {
|
|
@@ -143,12 +258,10 @@ async function getDependencies(code, filepath, asset, resolve, options, parcelOp
|
|
|
143
258
|
|
|
144
259
|
for (let resolved of found) {
|
|
145
260
|
if (!seen.has(resolved)) {
|
|
146
|
-
await asset.
|
|
147
|
-
filePath: resolved
|
|
148
|
-
});
|
|
261
|
+
await asset.invalidateOnFileChange(resolved);
|
|
149
262
|
let code = await asset.fs.readFile(resolved, 'utf8');
|
|
150
263
|
|
|
151
|
-
for (let [path, resolvedPath] of await getDependencies(code, resolved, asset, resolve, options, parcelOptions, seen)) {
|
|
264
|
+
for (let [path, resolvedPath] of await getDependencies(code, resolved, asset, resolve, options, parcelOptions, nativeGlob, seen, false)) {
|
|
152
265
|
res.set(path, resolvedPath);
|
|
153
266
|
}
|
|
154
267
|
}
|
|
@@ -157,13 +270,12 @@ async function getDependencies(code, filepath, asset, resolve, options, parcelOp
|
|
|
157
270
|
return res;
|
|
158
271
|
}
|
|
159
272
|
|
|
160
|
-
async function createEvaluator(code, asset, resolve, options, parcelOptions) {
|
|
161
|
-
const deps = await getDependencies(code, asset.filePath, asset, resolve, options, parcelOptions);
|
|
162
|
-
const Evaluator = await parcelOptions.packageManager.require('stylus/lib/visitor/evaluator', asset.filePath); // This is a custom stylus evaluator that extends stylus with support for the node
|
|
273
|
+
async function createEvaluator(code, asset, resolve, options, parcelOptions, nativeGlob) {
|
|
274
|
+
const deps = await getDependencies(code, asset.filePath, asset, resolve, options, parcelOptions, nativeGlob); // This is a custom stylus evaluator that extends stylus with support for the node
|
|
163
275
|
// require resolution algorithm. It also adds all dependencies to the parcel asset
|
|
164
276
|
// tree so the file watcher works correctly, etc.
|
|
165
277
|
|
|
166
|
-
|
|
278
|
+
class CustomEvaluator extends _evaluator().default {
|
|
167
279
|
visitImport(imported) {
|
|
168
280
|
let node = this.visit(imported.path).first;
|
|
169
281
|
let path = node.string;
|
|
@@ -181,16 +293,86 @@ async function createEvaluator(code, asset, resolve, options, parcelOptions) {
|
|
|
181
293
|
// replace it with a separate import node for each file
|
|
182
294
|
return mergeBlocks(resolved.map(resolvedPath => {
|
|
183
295
|
node.string = resolvedPath;
|
|
184
|
-
|
|
296
|
+
let restore = patchNativeFS(asset.fs, nativeGlob);
|
|
297
|
+
let res = super.visitImport(imported.clone());
|
|
298
|
+
restore();
|
|
299
|
+
return res;
|
|
185
300
|
}));
|
|
186
301
|
}
|
|
187
302
|
}
|
|
188
|
-
} //
|
|
303
|
+
} // Patch the native FS so stylus uses Parcel's FS to read the file.
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
let restore = patchNativeFS(asset.fs, nativeGlob); // Done. Let stylus do its thing.
|
|
189
307
|
|
|
308
|
+
let res = super.visitImport(imported);
|
|
309
|
+
restore();
|
|
310
|
+
return res;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
return CustomEvaluator;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
function patchNativeFS(fs, nativeGlob) {
|
|
319
|
+
let invalidations = [];
|
|
320
|
+
|
|
321
|
+
let readFileSync = _fs().default.readFileSync;
|
|
190
322
|
|
|
191
|
-
|
|
323
|
+
let statSync = _fs().default.statSync; // $FlowFixMe
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
_fs().default.readFileSync = (filename, encoding) => {
|
|
327
|
+
return fs.readFileSync(filename, encoding);
|
|
328
|
+
}; // $FlowFixMe
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
_fs().default.statSync = p => {
|
|
332
|
+
try {
|
|
333
|
+
return fs.statSync(p);
|
|
334
|
+
} catch (err) {
|
|
335
|
+
// Track files that were checked but don't exist so that we watch for their creation.
|
|
336
|
+
if (!p.includes(`node_modules${_path().default.sep}stylus`)) {
|
|
337
|
+
invalidations.push({
|
|
338
|
+
filePath: p
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
throw err;
|
|
192
343
|
}
|
|
344
|
+
}; // Patch the `glob` module as well so we use the Parcel FS and track invalidations.
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
let glob = nativeGlob.sync;
|
|
348
|
+
|
|
349
|
+
nativeGlob.sync = p => {
|
|
350
|
+
let res = (0, _utils().globSync)(p, fs);
|
|
351
|
+
|
|
352
|
+
if (!p.includes(`node_modules${_path().default.sep}stylus`)) {
|
|
353
|
+
// Sometimes stylus passes file paths with no glob parts to the `glob` module.
|
|
354
|
+
// We want to avoid treating these as globs for performance.
|
|
355
|
+
if ((0, _utils().isGlob)(p)) {
|
|
356
|
+
invalidations.push({
|
|
357
|
+
glob: p
|
|
358
|
+
});
|
|
359
|
+
} else if (res.length === 0) {
|
|
360
|
+
invalidations.push({
|
|
361
|
+
filePath: p
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
return res;
|
|
367
|
+
};
|
|
368
|
+
|
|
369
|
+
return () => {
|
|
370
|
+
// $FlowFixMe
|
|
371
|
+
_fs().default.readFileSync = readFileSync; // $FlowFixMe
|
|
193
372
|
|
|
373
|
+
_fs().default.statSync = statSync;
|
|
374
|
+
nativeGlob.sync = glob;
|
|
375
|
+
return invalidations;
|
|
194
376
|
};
|
|
195
377
|
}
|
|
196
378
|
/**
|
package/package.json
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@parcel/transformer-stylus",
|
|
3
|
-
"version": "2.0.0-
|
|
3
|
+
"version": "2.0.0-nightly.1002+5530a6ef",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
8
|
+
"funding": {
|
|
9
|
+
"type": "opencollective",
|
|
10
|
+
"url": "https://opencollective.com/parcel"
|
|
11
|
+
},
|
|
8
12
|
"repository": {
|
|
9
13
|
"type": "git",
|
|
10
14
|
"url": "https://github.com/parcel-bundler/parcel.git"
|
|
@@ -12,15 +16,13 @@
|
|
|
12
16
|
"main": "lib/StylusTransformer.js",
|
|
13
17
|
"source": "src/StylusTransformer.js",
|
|
14
18
|
"engines": {
|
|
15
|
-
"node": ">=
|
|
16
|
-
"parcel": "
|
|
19
|
+
"node": ">= 12.0.0",
|
|
20
|
+
"parcel": "2.0.0-nightly.1000+5530a6ef"
|
|
17
21
|
},
|
|
18
22
|
"dependencies": {
|
|
19
|
-
"@parcel/plugin": "2.0.0-
|
|
20
|
-
"@parcel/utils": "2.0.0-
|
|
21
|
-
|
|
22
|
-
"devDependencies": {
|
|
23
|
-
"stylus": "^0.54.5"
|
|
23
|
+
"@parcel/plugin": "2.0.0-nightly.1002+5530a6ef",
|
|
24
|
+
"@parcel/utils": "2.0.0-nightly.1002+5530a6ef",
|
|
25
|
+
"stylus": "^0.55.0"
|
|
24
26
|
},
|
|
25
|
-
"gitHead": "
|
|
27
|
+
"gitHead": "5530a6eff8b619873353baeb0457ae4ec591e9fa"
|
|
26
28
|
}
|
package/src/StylusTransformer.js
CHANGED
|
@@ -1,12 +1,19 @@
|
|
|
1
1
|
// @flow
|
|
2
2
|
|
|
3
3
|
import {Transformer} from '@parcel/plugin';
|
|
4
|
-
import {isGlob, glob} from '@parcel/utils';
|
|
4
|
+
import {createDependencyLocation, isGlob, glob, globSync} from '@parcel/utils';
|
|
5
5
|
import path from 'path';
|
|
6
|
+
import nativeFS from 'fs';
|
|
7
|
+
import stylus from 'stylus';
|
|
8
|
+
import Parser from 'stylus/lib/parser';
|
|
9
|
+
import DepsResolver from 'stylus/lib/visitor/deps-resolver';
|
|
10
|
+
import nodes from 'stylus/lib/nodes';
|
|
11
|
+
import utils from 'stylus/lib/utils';
|
|
12
|
+
import Evaluator from 'stylus/lib/visitor/evaluator';
|
|
6
13
|
|
|
7
14
|
const URL_RE = /^(?:url\s*\(\s*)?['"]?(?:[#/]|(?:https?:)?\/\/)/i;
|
|
8
15
|
|
|
9
|
-
export default new Transformer({
|
|
16
|
+
export default (new Transformer({
|
|
10
17
|
async loadConfig({config}) {
|
|
11
18
|
let configFile = await config.getConfig(['.stylusrc', '.stylusrc.js'], {
|
|
12
19
|
packageKey: 'stylus',
|
|
@@ -15,47 +22,53 @@ export default new Transformer({
|
|
|
15
22
|
if (configFile) {
|
|
16
23
|
let isJavascript = path.extname(configFile.filePath) === '.js';
|
|
17
24
|
if (isJavascript) {
|
|
18
|
-
config.
|
|
19
|
-
config.shouldReload();
|
|
25
|
+
config.invalidateOnStartup();
|
|
20
26
|
}
|
|
21
27
|
|
|
22
|
-
config
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
preSerializeConfig({config}) {
|
|
30
|
-
if (!config.result) return;
|
|
28
|
+
// Resolve relative paths from config file
|
|
29
|
+
if (configFile.contents.paths) {
|
|
30
|
+
configFile.contents.paths = configFile.contents.paths.map(p =>
|
|
31
|
+
path.resolve(path.dirname(configFile.filePath), p),
|
|
32
|
+
);
|
|
33
|
+
}
|
|
31
34
|
|
|
32
|
-
|
|
33
|
-
if (!config.result.isSerialisable) {
|
|
34
|
-
config.result.contents = {};
|
|
35
|
+
return configFile.contents;
|
|
35
36
|
}
|
|
36
37
|
},
|
|
37
38
|
|
|
38
39
|
async transform({asset, resolve, config, options}) {
|
|
39
|
-
let stylusConfig = config
|
|
40
|
-
// stylus should be installed locally in the module that's being required
|
|
41
|
-
let stylus = await options.packageManager.require(
|
|
42
|
-
'stylus',
|
|
43
|
-
asset.filePath,
|
|
44
|
-
{autoinstall: options.autoinstall},
|
|
45
|
-
);
|
|
46
|
-
|
|
40
|
+
let stylusConfig = config ?? {};
|
|
47
41
|
let code = await asset.getCode();
|
|
48
|
-
let style = stylus(code, stylusConfig);
|
|
42
|
+
let style = stylus(code, {...stylusConfig});
|
|
49
43
|
style.set('filename', asset.filePath);
|
|
50
44
|
style.set('include css', true);
|
|
51
45
|
// Setup a handler for the URL function so we add dependencies for linked assets.
|
|
52
|
-
style.define('url', node => {
|
|
53
|
-
let filename = asset.addURLDependency(node.val,
|
|
46
|
+
style.define('url', (node: stylus.nodes.String | stylus.nodes.Literal) => {
|
|
47
|
+
let filename = asset.addURLDependency(node.val, {
|
|
48
|
+
loc: createDependencyLocation(
|
|
49
|
+
{line: node.lineno, column: node.column},
|
|
50
|
+
node.val,
|
|
51
|
+
),
|
|
52
|
+
});
|
|
54
53
|
return new stylus.nodes.Literal(`url(${JSON.stringify(filename)})`);
|
|
55
54
|
});
|
|
55
|
+
|
|
56
|
+
let {resolved: stylusPath} = await options.packageManager.resolve(
|
|
57
|
+
'stylus',
|
|
58
|
+
__filename,
|
|
59
|
+
);
|
|
60
|
+
let nativeGlob = await options.packageManager.require('glob', stylusPath);
|
|
61
|
+
|
|
56
62
|
style.set(
|
|
57
63
|
'Evaluator',
|
|
58
|
-
await createEvaluator(
|
|
64
|
+
await createEvaluator(
|
|
65
|
+
code,
|
|
66
|
+
asset,
|
|
67
|
+
resolve,
|
|
68
|
+
style.options,
|
|
69
|
+
options,
|
|
70
|
+
nativeGlob,
|
|
71
|
+
),
|
|
59
72
|
);
|
|
60
73
|
|
|
61
74
|
asset.type = 'css';
|
|
@@ -63,7 +76,37 @@ export default new Transformer({
|
|
|
63
76
|
asset.meta.hasDependencies = false;
|
|
64
77
|
return [asset];
|
|
65
78
|
},
|
|
66
|
-
});
|
|
79
|
+
}): Transformer);
|
|
80
|
+
|
|
81
|
+
function attemptResolve(importedPath, filepath, asset, resolve, deps) {
|
|
82
|
+
if (deps.has(importedPath)) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (isGlob(importedPath)) {
|
|
87
|
+
// Invalidate when new files are created that match the glob pattern.
|
|
88
|
+
let absoluteGlob = path.resolve(path.dirname(filepath), importedPath);
|
|
89
|
+
asset.invalidateOnFileCreate({glob: absoluteGlob});
|
|
90
|
+
|
|
91
|
+
deps.set(
|
|
92
|
+
importedPath,
|
|
93
|
+
glob(absoluteGlob, asset.fs, {
|
|
94
|
+
onlyFiles: true,
|
|
95
|
+
}).then(entries =>
|
|
96
|
+
Promise.all(
|
|
97
|
+
entries.map(entry =>
|
|
98
|
+
resolve(
|
|
99
|
+
filepath,
|
|
100
|
+
'./' + path.relative(path.dirname(filepath), entry),
|
|
101
|
+
),
|
|
102
|
+
),
|
|
103
|
+
),
|
|
104
|
+
),
|
|
105
|
+
);
|
|
106
|
+
} else {
|
|
107
|
+
deps.set(importedPath, resolve(filepath, importedPath));
|
|
108
|
+
}
|
|
109
|
+
}
|
|
67
110
|
|
|
68
111
|
async function getDependencies(
|
|
69
112
|
code,
|
|
@@ -72,16 +115,11 @@ async function getDependencies(
|
|
|
72
115
|
resolve,
|
|
73
116
|
options,
|
|
74
117
|
parcelOptions,
|
|
118
|
+
nativeGlob,
|
|
75
119
|
seen = new Set(),
|
|
120
|
+
includeImports = true,
|
|
76
121
|
) {
|
|
77
122
|
seen.add(filepath);
|
|
78
|
-
const [Parser, DepsResolver, nodes, utils] = await Promise.all(
|
|
79
|
-
['parser', 'visitor/deps-resolver', 'nodes', 'utils'].map(dep =>
|
|
80
|
-
parcelOptions.packageManager.require('stylus/lib/' + dep, filepath, {
|
|
81
|
-
autoinstall: options.autoinstall,
|
|
82
|
-
}),
|
|
83
|
-
),
|
|
84
|
-
);
|
|
85
123
|
|
|
86
124
|
nodes.filename = asset.filePath;
|
|
87
125
|
|
|
@@ -89,35 +127,16 @@ async function getDependencies(
|
|
|
89
127
|
let ast = parser.parse();
|
|
90
128
|
let deps = new Map();
|
|
91
129
|
|
|
130
|
+
if (includeImports && options.imports) {
|
|
131
|
+
for (let importedPath of options.imports) {
|
|
132
|
+
attemptResolve(importedPath, filepath, asset, resolve, deps);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
92
136
|
class ImportVisitor extends DepsResolver {
|
|
93
137
|
visitImport(imported) {
|
|
94
138
|
let importedPath = imported.path.first.string;
|
|
95
|
-
|
|
96
|
-
if (!deps.has(importedPath)) {
|
|
97
|
-
if (isGlob(importedPath)) {
|
|
98
|
-
deps.set(
|
|
99
|
-
importedPath,
|
|
100
|
-
glob(
|
|
101
|
-
path.resolve(path.dirname(filepath), importedPath),
|
|
102
|
-
parcelOptions.inputFS,
|
|
103
|
-
{
|
|
104
|
-
onlyFiles: true,
|
|
105
|
-
},
|
|
106
|
-
).then(entries =>
|
|
107
|
-
Promise.all(
|
|
108
|
-
entries.map(entry =>
|
|
109
|
-
resolve(
|
|
110
|
-
filepath,
|
|
111
|
-
'./' + path.relative(path.dirname(filepath), entry),
|
|
112
|
-
),
|
|
113
|
-
),
|
|
114
|
-
),
|
|
115
|
-
),
|
|
116
|
-
);
|
|
117
|
-
} else {
|
|
118
|
-
deps.set(importedPath, resolve(filepath, importedPath));
|
|
119
|
-
}
|
|
120
|
-
}
|
|
139
|
+
attemptResolve(importedPath, filepath, asset, resolve, deps);
|
|
121
140
|
}
|
|
122
141
|
}
|
|
123
142
|
|
|
@@ -134,7 +153,7 @@ async function getDependencies(
|
|
|
134
153
|
}
|
|
135
154
|
|
|
136
155
|
let found;
|
|
137
|
-
if (resolved) {
|
|
156
|
+
if (resolved && (!Array.isArray(resolved) || resolved.length > 0)) {
|
|
138
157
|
found = Array.isArray(resolved) ? resolved : [resolved];
|
|
139
158
|
res.set(importedPath, resolved);
|
|
140
159
|
} else {
|
|
@@ -147,12 +166,24 @@ async function getDependencies(
|
|
|
147
166
|
importedPath += '.styl';
|
|
148
167
|
}
|
|
149
168
|
|
|
150
|
-
|
|
169
|
+
// Patch the native FS so we use Parcel's FS, and track files that are
|
|
170
|
+
// checked so we invalidate the cache when they are created.
|
|
171
|
+
let restore = patchNativeFS(asset.fs, nativeGlob);
|
|
172
|
+
|
|
173
|
+
let paths = [
|
|
174
|
+
...new Set(
|
|
175
|
+
(options.paths || []).concat(path.dirname(filepath || '.')),
|
|
176
|
+
),
|
|
177
|
+
];
|
|
151
178
|
found = utils.find(importedPath, paths, filepath);
|
|
152
179
|
if (!found) {
|
|
153
180
|
found = utils.lookupIndex(originalPath, paths, filepath);
|
|
154
181
|
}
|
|
155
182
|
|
|
183
|
+
for (let invalidation of restore()) {
|
|
184
|
+
asset.invalidateOnFileCreate(invalidation);
|
|
185
|
+
}
|
|
186
|
+
|
|
156
187
|
if (!found) {
|
|
157
188
|
throw new Error('failed to locate file ' + originalPath);
|
|
158
189
|
}
|
|
@@ -161,7 +192,7 @@ async function getDependencies(
|
|
|
161
192
|
// Recursively process resolved files as well to get nested deps
|
|
162
193
|
for (let resolved of found) {
|
|
163
194
|
if (!seen.has(resolved)) {
|
|
164
|
-
await asset.
|
|
195
|
+
await asset.invalidateOnFileChange(resolved);
|
|
165
196
|
|
|
166
197
|
let code = await asset.fs.readFile(resolved, 'utf8');
|
|
167
198
|
for (let [path, resolvedPath] of await getDependencies(
|
|
@@ -171,7 +202,9 @@ async function getDependencies(
|
|
|
171
202
|
resolve,
|
|
172
203
|
options,
|
|
173
204
|
parcelOptions,
|
|
205
|
+
nativeGlob,
|
|
174
206
|
seen,
|
|
207
|
+
false,
|
|
175
208
|
)) {
|
|
176
209
|
res.set(path, resolvedPath);
|
|
177
210
|
}
|
|
@@ -183,7 +216,14 @@ async function getDependencies(
|
|
|
183
216
|
return res;
|
|
184
217
|
}
|
|
185
218
|
|
|
186
|
-
async function createEvaluator(
|
|
219
|
+
async function createEvaluator(
|
|
220
|
+
code,
|
|
221
|
+
asset,
|
|
222
|
+
resolve,
|
|
223
|
+
options,
|
|
224
|
+
parcelOptions,
|
|
225
|
+
nativeGlob,
|
|
226
|
+
) {
|
|
187
227
|
const deps = await getDependencies(
|
|
188
228
|
code,
|
|
189
229
|
asset.filePath,
|
|
@@ -191,10 +231,7 @@ async function createEvaluator(code, asset, resolve, options, parcelOptions) {
|
|
|
191
231
|
resolve,
|
|
192
232
|
options,
|
|
193
233
|
parcelOptions,
|
|
194
|
-
|
|
195
|
-
const Evaluator = await parcelOptions.packageManager.require(
|
|
196
|
-
'stylus/lib/visitor/evaluator',
|
|
197
|
-
asset.filePath,
|
|
234
|
+
nativeGlob,
|
|
198
235
|
);
|
|
199
236
|
|
|
200
237
|
// This is a custom stylus evaluator that extends stylus with support for the node
|
|
@@ -219,21 +256,79 @@ async function createEvaluator(code, asset, resolve, options, parcelOptions) {
|
|
|
219
256
|
return mergeBlocks(
|
|
220
257
|
resolved.map(resolvedPath => {
|
|
221
258
|
node.string = resolvedPath;
|
|
222
|
-
|
|
259
|
+
let restore = patchNativeFS(asset.fs, nativeGlob);
|
|
260
|
+
let res = super.visitImport(imported.clone());
|
|
261
|
+
restore();
|
|
262
|
+
return res;
|
|
223
263
|
}),
|
|
224
264
|
);
|
|
225
265
|
}
|
|
226
266
|
}
|
|
227
267
|
}
|
|
228
268
|
|
|
269
|
+
// Patch the native FS so stylus uses Parcel's FS to read the file.
|
|
270
|
+
let restore = patchNativeFS(asset.fs, nativeGlob);
|
|
271
|
+
|
|
229
272
|
// Done. Let stylus do its thing.
|
|
230
|
-
|
|
273
|
+
let res = super.visitImport(imported);
|
|
274
|
+
|
|
275
|
+
restore();
|
|
276
|
+
return res;
|
|
231
277
|
}
|
|
232
278
|
}
|
|
233
279
|
|
|
234
280
|
return CustomEvaluator;
|
|
235
281
|
}
|
|
236
282
|
|
|
283
|
+
function patchNativeFS(fs, nativeGlob) {
|
|
284
|
+
let invalidations = [];
|
|
285
|
+
let readFileSync = nativeFS.readFileSync;
|
|
286
|
+
let statSync = nativeFS.statSync;
|
|
287
|
+
|
|
288
|
+
// $FlowFixMe
|
|
289
|
+
nativeFS.readFileSync = (filename, encoding) => {
|
|
290
|
+
return fs.readFileSync(filename, encoding);
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
// $FlowFixMe
|
|
294
|
+
nativeFS.statSync = p => {
|
|
295
|
+
try {
|
|
296
|
+
return fs.statSync(p);
|
|
297
|
+
} catch (err) {
|
|
298
|
+
// Track files that were checked but don't exist so that we watch for their creation.
|
|
299
|
+
if (!p.includes(`node_modules${path.sep}stylus`)) {
|
|
300
|
+
invalidations.push({filePath: p});
|
|
301
|
+
}
|
|
302
|
+
throw err;
|
|
303
|
+
}
|
|
304
|
+
};
|
|
305
|
+
|
|
306
|
+
// Patch the `glob` module as well so we use the Parcel FS and track invalidations.
|
|
307
|
+
let glob = nativeGlob.sync;
|
|
308
|
+
nativeGlob.sync = p => {
|
|
309
|
+
let res = globSync(p, fs);
|
|
310
|
+
if (!p.includes(`node_modules${path.sep}stylus`)) {
|
|
311
|
+
// Sometimes stylus passes file paths with no glob parts to the `glob` module.
|
|
312
|
+
// We want to avoid treating these as globs for performance.
|
|
313
|
+
if (isGlob(p)) {
|
|
314
|
+
invalidations.push({glob: p});
|
|
315
|
+
} else if (res.length === 0) {
|
|
316
|
+
invalidations.push({filePath: p});
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
return res;
|
|
320
|
+
};
|
|
321
|
+
|
|
322
|
+
return () => {
|
|
323
|
+
// $FlowFixMe
|
|
324
|
+
nativeFS.readFileSync = readFileSync;
|
|
325
|
+
// $FlowFixMe
|
|
326
|
+
nativeFS.statSync = statSync;
|
|
327
|
+
nativeGlob.sync = glob;
|
|
328
|
+
return invalidations;
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
|
|
237
332
|
/**
|
|
238
333
|
* Puts the content of all given node blocks into the first one, essentially merging them.
|
|
239
334
|
*/
|