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