Skip to content

Commit 2c10fd6

Browse files
authored
Merge pull request #45 from bholloway/feature/support-sass-loader-6
sass-loader@>=6.0.0
2 parents 84f148f + 398af05 commit 2c10fd6

File tree

5 files changed

+187
-209
lines changed

5 files changed

+187
-209
lines changed

index.js

Lines changed: 23 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ var path = require('path'),
1616

1717
var findFile = require('./lib/find-file'),
1818
absoluteToRelative = require('./lib/sources-absolute-to-relative'),
19-
relativeToAbsolute = require('./lib/sources-relative-to-absolute');
19+
adjustSourceMap = require('adjust-sourcemap-loader/lib/process');
2020

2121
var PACKAGE_NAME = require('./package.json').name;
2222

@@ -31,12 +31,8 @@ function resolveUrlLoader(content, sourceMap) {
3131
/* jshint validthis:true */
3232

3333
// details of the file being processed
34-
// we would normally use compilation.getPath(options.output.path) to get the most correct outputPath,
35-
// however we need to match to the sass-loader and it does not do so
36-
var loader = this,
37-
filePath = loader.context,
38-
outputPath = path.resolve(loader.options.output.path),
39-
contextPath = path.resolve(loader.options.context);
34+
var loader = this,
35+
filePath = path.dirname(loader.resourcePath);
4036

4137
// prefer loader query, else options object, else default values
4238
var options = defaults(loaderUtils.parseQuery(loader.query), loader.options[camelcase(PACKAGE_NAME)], {
@@ -45,6 +41,7 @@ function resolveUrlLoader(content, sourceMap) {
4541
fail : false,
4642
silent : false,
4743
keepQuery: false,
44+
debug : false,
4845
root : null
4946
});
5047

@@ -62,33 +59,35 @@ function resolveUrlLoader(content, sourceMap) {
6259
var sourceMapConsumer, contentWithMap, sourceRoot;
6360
if (sourceMap) {
6461

65-
// expect sass-loader@>=4.0.0
66-
// sourcemap sources relative to context path
67-
try {
68-
relativeToAbsolute(sourceMap.sources, contextPath, resolvedRoot);
69-
}
70-
catch (unused) {
71-
72-
// fallback to sass-loader@<4.0.0
73-
// sourcemap sources relative to output path
62+
// support non-standard string encoded source-map (per less-loader)
63+
if (typeof sourceMap === 'string') {
7464
try {
75-
relativeToAbsolute(sourceMap.sources, outputPath, resolvedRoot);
65+
sourceMap = JSON.parse(sourceMap);
7666
}
7767
catch (exception) {
78-
return handleException('source-map error', exception.message);
68+
return handleException('source-map error', 'cannot parse source-map string (from less-loader?)');
7969
}
8070
}
8171

82-
// There are now absolute paths in the source map so we don't need it anymore
83-
// However, later when we go back to relative paths, we need to add it again
72+
// Note the current sourceRoot before it is removed
73+
// later when we go back to relative paths, we need to add it again
8474
sourceRoot = sourceMap.sourceRoot;
85-
sourceMap.sourceRoot = undefined;
75+
76+
// leverage adjust-sourcemap-loader's codecs to avoid having to make any assumptions about the sourcemap
77+
// historically this is a regular source of breakage
78+
var absSourceMap;
79+
try {
80+
absSourceMap = adjustSourceMap(this, {format: 'absolute'}, sourceMap);
81+
}
82+
catch (exception) {
83+
return handleException('source-map error', exception.message);
84+
}
8685

8786
// prepare the adjusted sass source-map for later look-ups
88-
sourceMapConsumer = new SourceMapConsumer(sourceMap);
87+
sourceMapConsumer = new SourceMapConsumer(absSourceMap);
8988

9089
// embed source-map in css for rework-css to use
91-
contentWithMap = content + convert.fromObject(sourceMap).toComment({multiline: true});
90+
contentWithMap = content + convert.fromObject(absSourceMap).toComment({multiline: true});
9291
}
9392
// absent source map
9493
else {
@@ -217,7 +216,7 @@ function resolveUrlLoader(content, sourceMap) {
217216
// split into uri and query/hash and then find the absolute path to the uri
218217
var split = initialised.split(/([?#])/g),
219218
uri = split[0],
220-
absolute = uri && findFile.absolute(directory, uri, resolvedRoot),
219+
absolute = uri && findFile(options).absolute(directory, uri, resolvedRoot),
221220
query = options.keepQuery ? split.slice(1).join('') : '';
222221

223222
// use the absolute path (or default to initialised)

lib/find-file.js

Lines changed: 137 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -1,120 +1,157 @@
11
'use strict';
22

3-
var fs = require('fs'),
4-
path = require('path');
3+
var fs = require('fs'),
4+
path = require('path'),
5+
defaults = require('lodash.defaults');
56

6-
module.exports = {
7-
absolute: absolute,
8-
base : base
9-
};
7+
var PACKAGE_NAME = require('../package.json').name;
108

119
/**
12-
* Search for the relative file reference from the <code>startPath</code> up to the process
13-
* working directory, avoiding any other directories with a <code>package.json</code> or <code>bower.json</code>.
14-
* @param {string} startPath The location of the uri declaration and the place to start the search from
15-
* @param {string} uri The content of the url() statement, expected to be a relative file path
16-
* @param {string} [limit] Optional directory to limit the search to
17-
* @returns {string|null} <code>null</code> where not found else the absolute path to the file
10+
* Factory for find-file with the given <code>options</code> hash.
11+
* @param {{debug: boolean}} [opt] Optional options hash
1812
*/
19-
function absolute(startPath, uri, limit) {
20-
var basePath = base(startPath, uri, limit);
21-
return !!basePath && path.resolve(basePath, uri) || null;
22-
}
13+
function findFile(opt) {
14+
var options = defaults(opt, {
15+
debug: false
16+
});
17+
return {
18+
absolute: absolute,
19+
base : base
20+
};
2321

24-
/**
25-
* Search for the relative file reference from the <code>startPath</code> up to the process
26-
* working directory, avoiding any other directories with a <code>package.json</code> or <code>bower.json</code>.
27-
* @param {string} startPath The location of the uri declaration and the place to start the search from
28-
* @param {string} uri The content of the url() statement, expected to be a relative file path
29-
* @param {string} [limit] Optional directory to limit the search to
30-
* @returns {string|null} <code>null</code> where not found else the base path upon which the uri may be resolved
31-
*/
32-
function base(startPath, uri, limit) {
33-
34-
// ensure we have some limit to the search
35-
limit = limit && path.resolve(limit) || process.cwd();
36-
37-
// ignore data uris and ensure we are at a valid start path
38-
var absoluteStart = !(/^data\:/.test(uri)) && path.resolve(startPath);
39-
if (absoluteStart) {
40-
41-
// find path to the root, stopping at cwd, package.json or bower.json
42-
var pathToRoot = [];
43-
var isWorking;
44-
do {
45-
pathToRoot.push(absoluteStart);
46-
isWorking = testWithinLimit(absoluteStart) && testNotPackage(absoluteStart);
47-
absoluteStart = path.resolve(absoluteStart, '..');
48-
} while (isWorking);
49-
50-
// start a queue with the path to the root
51-
var queue = pathToRoot.concat();
52-
53-
// process the queue until empty
54-
// the queue pattern ensures that we favour paths closest the the start path
55-
while (queue.length) {
56-
57-
// shift the first item off the queue, consider it the base for our relative uri
58-
var basePath = queue.shift();
59-
var fullPath = path.resolve(basePath, uri);
60-
61-
// file exists so convert to a dataURI and end
62-
if (fs.existsSync(fullPath)) {
63-
return basePath;
64-
}
65-
// enqueue subdirectories that are not packages and are not in the root path
66-
else {
67-
enqueue(queue, basePath);
68-
}
69-
}
22+
/**
23+
* Search for the relative file reference from the <code>startPath</code> up to the process
24+
* working directory, avoiding any other directories with a <code>package.json</code> or <code>bower.json</code>.
25+
* @param {string} startPath The location of the uri declaration and the place to start the search from
26+
* @param {string} uri The content of the url() statement, expected to be a relative file path
27+
* @param {string} [limit] Optional directory to limit the search to
28+
* @returns {string|null} <code>null</code> where not found else the absolute path to the file
29+
*/
30+
function absolute(startPath, uri, limit) {
31+
var basePath = base(startPath, uri, limit);
32+
return !!basePath && path.resolve(basePath, uri) || null;
7033
}
7134

72-
// ignored or not found
73-
return null;
74-
7535
/**
76-
* Enqueue subdirectories that are not packages and are not in the root path
77-
* @param {Array} queue The queue to add to
78-
* @param {string} basePath The path to consider
36+
* Search for the relative file reference from the <code>startPath</code> up to the process
37+
* working directory, avoiding any other directories with a <code>package.json</code> or <code>bower.json</code>.
38+
* @param {string} startPath The location of the uri declaration and the place to start the search from
39+
* @param {string} uri The content of the url() statement, expected to be a relative file path
40+
* @param {string} [limit] Optional directory to limit the search to
41+
* @returns {string|null} <code>null</code> where not found else the base path upon which the uri may be resolved
7942
*/
80-
function enqueue(queue, basePath) {
81-
fs.readdirSync(basePath)
82-
.filter(function notHidden(filename) {
83-
return (filename.charAt(0) !== '.');
84-
})
85-
.map(function toAbsolute(filename) {
86-
return path.join(basePath, filename);
87-
})
88-
.filter(function directoriesOnly(absolutePath) {
89-
return fs.existsSync(absolutePath) && fs.statSync(absolutePath).isDirectory();
90-
})
91-
.filter(function notInRootPath(absolutePath) {
92-
return (pathToRoot.indexOf(absolutePath) < 0);
93-
})
94-
.filter(testNotPackage)
95-
.forEach(function enqueue(absolutePath) {
96-
queue.push(absolutePath);
97-
});
43+
function base(startPath, uri, limit) {
44+
var messages = [];
45+
46+
// ensure we have some limit to the search
47+
limit = limit && path.resolve(limit) || process.cwd();
48+
49+
// ignore data uris and ensure we are at a valid start path
50+
var absoluteStart = !(/^data\:/.test(uri)) && path.resolve(startPath);
51+
if (absoluteStart) {
52+
53+
// find path to the root, stopping at cwd, package.json or bower.json
54+
var pathToRoot = [];
55+
var isWorking;
56+
do {
57+
pathToRoot.push(absoluteStart);
58+
isWorking = testWithinLimit(absoluteStart) && testNotPackage(absoluteStart);
59+
absoluteStart = path.resolve(absoluteStart, '..');
60+
} while (isWorking);
61+
62+
// start a queue with the path to the root
63+
var queue = pathToRoot.concat();
64+
65+
// process the queue until empty
66+
// the queue pattern ensures that we favour paths closest the the start path
67+
while (queue.length) {
68+
69+
// shift the first item off the queue, consider it the base for our relative uri
70+
var basePath = queue.shift();
71+
var fullPath = path.resolve(basePath, uri);
72+
messages.push(basePath);
73+
74+
// file exists so convert to a dataURI and end
75+
if (fs.existsSync(fullPath)) {
76+
flushMessages('FOUND');
77+
return basePath;
78+
}
79+
// enqueue subdirectories that are not packages and are not in the root path
80+
else {
81+
enqueue(queue, basePath);
82+
}
83+
}
84+
85+
// not found
86+
flushMessages('NOT FOUND');
87+
return null;
88+
}
89+
// ignored
90+
else {
91+
flushMessages('IGNORED');
92+
return null;
93+
}
94+
95+
/**
96+
* Enqueue subdirectories that are not packages and are not in the root path
97+
* @param {Array} queue The queue to add to
98+
* @param {string} basePath The path to consider
99+
*/
100+
function enqueue(queue, basePath) {
101+
fs.readdirSync(basePath)
102+
.filter(function notHidden(filename) {
103+
return (filename.charAt(0) !== '.');
104+
})
105+
.map(function toAbsolute(filename) {
106+
return path.join(basePath, filename);
107+
})
108+
.filter(function directoriesOnly(absolutePath) {
109+
return fs.existsSync(absolutePath) && fs.statSync(absolutePath).isDirectory();
110+
})
111+
.filter(function notInRootPath(absolutePath) {
112+
return (pathToRoot.indexOf(absolutePath) < 0);
113+
})
114+
.filter(testNotPackage)
115+
.forEach(function enqueue(absolutePath) {
116+
queue.push(absolutePath);
117+
});
118+
}
119+
120+
/**
121+
* Test whether the given directory is above but not equal to any of the project root directories.
122+
* @param {string} absolutePath An absolute path
123+
* @returns {boolean} True where a package.json or bower.json exists, else False
124+
*/
125+
function testWithinLimit(absolutePath) {
126+
var relative = path.relative(limit, absolutePath);
127+
return !!relative && (relative.slice(0, 2) !== '..');
128+
}
129+
130+
/**
131+
* Print verbose debug info where <code>options.debug</code> is in effect.
132+
* @param {string} result Final text to append to the message
133+
*/
134+
function flushMessages(result) {
135+
if (options.debug) {
136+
var text = ['\n' + PACKAGE_NAME + ': ' + uri]
137+
.concat(messages)
138+
.concat(result)
139+
.join('\n ');
140+
console.log(text);
141+
}
142+
}
98143
}
99144

100145
/**
101-
* Test whether the given directory is above but not equal to any of the project root directories.
146+
* Test whether the given directory is the root of its own package.
102147
* @param {string} absolutePath An absolute path
103148
* @returns {boolean} True where a package.json or bower.json exists, else False
104149
*/
105-
function testWithinLimit(absolutePath) {
106-
var relative = path.relative(limit, absolutePath);
107-
return !!relative && (relative.slice(0, 2) !== '..');
150+
function testNotPackage(absolutePath) {
151+
return ['package.json', 'bower.json'].every(function fileFound(file) {
152+
return !fs.existsSync(path.resolve(absolutePath, file));
153+
});
108154
}
109155
}
110156

111-
/**
112-
* Test whether the given directory is the root of its own package.
113-
* @param {string} absolutePath An absolute path
114-
* @returns {boolean} True where a package.json or bower.json exists, else False
115-
*/
116-
function testNotPackage(absolutePath) {
117-
return ['package.json', 'bower.json'].every(function fileFound(file) {
118-
return !fs.existsSync(path.resolve(absolutePath, file));
119-
});
120-
}
157+
module.exports = findFile;

0 commit comments

Comments
 (0)