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