resolve-url-loader
Advanced tools
Comparing version 4.0.0-alpha.3 to 4.0.0-alpha.4
33
index.js
@@ -15,5 +15,5 @@ /* | ||
var valueProcessor = require('./lib/value-processor'); | ||
var joinFn = require('./lib/join-function'); | ||
var logToTestHarness = require('./lib/log-to-test-harness'); | ||
var valueProcessor = require('./lib/value-processor'), | ||
joinFn = require('./lib/join-function'), | ||
logToTestHarness = require('./lib/log-to-test-harness'); | ||
@@ -78,3 +78,2 @@ const DEPRECATED_OPTIONS = { | ||
{ | ||
fs : loader.fs, | ||
sourceMap: loader.sourceMap, | ||
@@ -111,9 +110,23 @@ engine : 'postcss', | ||
); | ||
} else if (options.join.length !== 1) { | ||
} else if (options.join.length !== 2) { | ||
return handleAsError( | ||
'loader misconfiguration', | ||
'"join" Function must take exactly 1 arguments (options hash)' | ||
'"join" Function must take exactly 2 arguments (options, loader)' | ||
); | ||
} | ||
// validate the result of calling the join option | ||
var joinProper = options.join(options, loader); | ||
if (typeof joinProper !== 'function') { | ||
return handleAsError( | ||
'loader misconfiguration', | ||
'"join" option must itself return a Function when it is called' | ||
); | ||
} else if (joinProper.length !== 1) { | ||
return handleAsError( | ||
'loader misconfiguration', | ||
'"join" Function must create a function that takes exactly 1 arguments (item)' | ||
); | ||
} | ||
// validate root option | ||
@@ -204,6 +217,10 @@ if (typeof options.root === 'string') { | ||
outputSourceMap : !!options.sourceMap, | ||
transformDeclaration: valueProcessor(loader.resourcePath, options), | ||
absSourceMap : absSourceMap, | ||
sourceMapConsumer : sourceMapConsumer, | ||
removeCR : options.removeCR | ||
removeCR : options.removeCR, | ||
transformDeclaration: valueProcessor({ | ||
join : joinProper, | ||
root : options.root, | ||
directory: path.dirname(loader.resourcePath) | ||
}) | ||
})) | ||
@@ -210,0 +227,0 @@ .catch(onFailure) |
@@ -149,3 +149,3 @@ /* | ||
if (error.message === 'Cannot find module \'' + moduleName + '\'') { | ||
throw new Error('To use the "rework" engine you must install the optionalPeerDependencies'); | ||
throw new Error('to use the "rework" engine you must install the optionalPeerDependencies'); | ||
} | ||
@@ -152,0 +152,0 @@ else { |
@@ -7,39 +7,52 @@ /* | ||
var path = require('path'); | ||
const path = require('path'); | ||
var PACKAGE_NAME = require('../../package.json').name; | ||
const PACKAGE_NAME = require('../../package.json').name; | ||
/** | ||
* Paths are formatted to have posix style path separators and those within the CWD are made relative to CWD. | ||
* | ||
* @param {string} absolutePath An absolute path to format | ||
* @returns {string} the formatted path | ||
*/ | ||
const pathToString = (absolutePath) => { | ||
if (absolutePath === '') { | ||
return '-empty-'; | ||
} else { | ||
const relative = path.relative(process.cwd(), absolutePath).split(path.sep); | ||
const segments = | ||
(relative[0] !== '..') ? ['.'].concat(relative).filter(Boolean) : | ||
(relative.lastIndexOf('..') < 2) ? relative : | ||
absolutePath.split(path.sep); | ||
return segments.join('/'); | ||
} | ||
}; | ||
exports.pathToString = pathToString; | ||
/** | ||
* Format a debug message. | ||
* | ||
* @param {string} file The file being processed by webpack | ||
* @param {string} filename The file being processed by webpack | ||
* @param {string} uri A uri path, relative or absolute | ||
* @param {Array<string>} bases Absolute base paths up to and including the found one | ||
* @param {boolean} isFound Indicates the last base was a positive match | ||
* @param {Array<{base:string,joined:string,isSuccess:boolean}>} attempts An array of attempts, possibly empty | ||
* @return {string} Formatted message | ||
*/ | ||
function formatJoinMessage(file, uri, bases, isFound) { | ||
return [PACKAGE_NAME + ': ' + pathToString(file) + ': ' + uri] | ||
.concat(bases.map(pathToString)) | ||
.concat(isFound ? 'FOUND' : 'NOT FOUND') | ||
.join('\n '); | ||
const formatJoinMessage = (filename, uri, attempts) => { | ||
const attemptToCells = (_, i, array) => { | ||
const { base: prev } = (i === 0) ? {} : array[i-1]; | ||
const { base: curr, joined } = array[i]; | ||
return [(curr === prev) ? '' : pathToString(curr), pathToString(joined)]; | ||
}; | ||
/** | ||
* If given path is within `process.cwd()` then show relative posix path, otherwise show absolute posix path. | ||
* | ||
* @param {string} absolute An absolute path | ||
* @return {string} A relative or absolute path | ||
*/ | ||
function pathToString(absolute) { | ||
if (!absolute) { | ||
return '-empty-'; | ||
} else { | ||
var relative = path.relative(process.cwd(), absolute) | ||
.split(path.sep); | ||
const formatCells = (lines) => { | ||
const maxWidth = lines.reduce((max, [cellA]) => Math.max(max, cellA.length), 0); | ||
return lines.map(([cellA, cellB]) => [cellA.padEnd(maxWidth), cellB]).map((cells) => cells.join(' --> ')); | ||
}; | ||
return ((relative[0] === '..') ? absolute.split(path.sep) : ['.'].concat(relative).filter(Boolean)) | ||
.join('/'); | ||
} | ||
} | ||
} | ||
return [PACKAGE_NAME + ': ' + pathToString(filename) + ': ' + uri] | ||
.concat(attempts.length === 0 ? '-empty-' : formatCells(attempts.map(attemptToCells))) | ||
.concat(attempts.some(({ isSuccess }) => isSuccess) ? 'FOUND' : 'NOT FOUND') | ||
.join('\n '); | ||
}; | ||
@@ -60,18 +73,16 @@ exports.formatJoinMessage = formatJoinMessage; | ||
*/ | ||
function createDebugLogger(debug) { | ||
var log = !!debug && ((typeof debug === 'function') ? debug : console.log), | ||
cache = {}; | ||
return log ? actuallyLog : noop; | ||
const createDebugLogger = (debug) => { | ||
const log = !!debug && ((typeof debug === 'function') ? debug : console.log); | ||
const cache = {}; | ||
return log ? | ||
((msgFn, params) => { | ||
const key = Function.prototype.toString.call(msgFn) + JSON.stringify(params); | ||
if (!cache[key]) { | ||
cache[key] = true; | ||
log(msgFn.apply(null, params)); | ||
} | ||
}) : | ||
(() => undefined); | ||
}; | ||
function noop() {} | ||
function actuallyLog(msgFn, params) { | ||
var key = Function.prototype.toString.call(msgFn) + JSON.stringify(params); | ||
if (!cache[key]) { | ||
cache[key] = true; | ||
log(msgFn.apply(null, params)); | ||
} | ||
} | ||
} | ||
exports.createDebugLogger = createDebugLogger; |
@@ -7,206 +7,230 @@ /* | ||
var path = require('path'); | ||
const path = require('path'); | ||
var sanitiseIterable = require('./sanitise-iterable'), | ||
debug = require('./debug'); | ||
const { createDebugLogger, formatJoinMessage } = require('./debug'); | ||
const fsUtils = require('./fs-utils'); | ||
/** | ||
* Generated name from "flower" series | ||
* @see https://gf.dev/sprintname | ||
*/ | ||
var CURRENT_SCHEME = require('../../package.json').scheme; | ||
const ITERATION_SAFETY_LIMIT = 100e3; | ||
/** | ||
* Webpack `fs` from `enhanced-resolve` doesn't support `existsSync()` so we shim using `statsSync()`. | ||
* Wrap a function such that it always returns a generator of tuple elements. | ||
* | ||
* @param {{statSync:function(string):{isFile:function():boolean}}} webpackFs The webpack `fs` from `loader.fs`. | ||
* @param {string} absolutePath Absolute path to the file in question | ||
* @returns {boolean} True where file exists, else False | ||
* @param {function({uri:string},...):(Array|Iterator)<[string,string]|string>} fn The function to wrap | ||
* @returns {function({uri:string},...):(Array|Iterator)<[string,string]>} A function that always returns tuple elements | ||
*/ | ||
function webpackExistsSync(webpackFs, absolutePath) { | ||
try { | ||
return webpackFs.statSync(absolutePath).isFile(); | ||
} catch (e) { | ||
return false; | ||
} | ||
} | ||
const asGenerator = (fn) => { | ||
const toTuple = (defaults) => (value) => { | ||
const partial = [].concat(value); | ||
return [...partial, ...defaults.slice(partial.length)]; | ||
}; | ||
exports.webpackExistsSync = webpackExistsSync; | ||
const isTupleUnique = (v, i, a) => { | ||
const required = v.join(','); | ||
return a.findIndex((vv) => vv.join(',') === required) === i; | ||
}; | ||
/** | ||
* The default iterable factory will order `subString` then `value` then `property` then `selector`. | ||
* | ||
* @param {string} filename The absolute path of the file being processed | ||
* @param {string} uri The uri given in the file webpack is processing | ||
* @param {boolean} isAbsolute True for absolute URIs, false for relative URIs | ||
* @param {{subString:string, value:string, property:string, selector:string}} bases A hash of possible base paths | ||
* @param {{fs:Object, root:string, debug:boolean|function}} options The loader options including webpack file system | ||
* @returns {Array<string>} An iterable of possible base paths in preference order | ||
*/ | ||
function defaultJoinGenerator(filename, uri, isAbsolute, bases, options) { | ||
return isAbsolute ? [options.root] : [bases.subString, bases.value, bases.property, bases.selector]; | ||
} | ||
return (item, ...rest) => { | ||
const {uri} = item; | ||
const mapTuple = toTuple([null, uri]); | ||
const pending = fn(item, ...rest); | ||
if (Array.isArray(pending)) { | ||
return pending.map(mapTuple).filter(isTupleUnique)[Symbol.iterator](); | ||
} else if ( | ||
pending && | ||
(typeof pending === 'object') && | ||
(typeof pending.next === 'function') && | ||
(pending.next.length === 0) | ||
) { | ||
return pending; | ||
} else { | ||
throw new TypeError(`in "join" function expected "generator" to return Array|Iterator`); | ||
} | ||
}; | ||
}; | ||
exports.defaultJoinGenerator = defaultJoinGenerator; | ||
exports.asGenerator = asGenerator; | ||
/** | ||
* The default operation simply joins the given base to the uri and returns it where it exists. | ||
* A high-level utility to create a join function. | ||
* | ||
* The result of `next()` represents the eventual result and needs to be returned otherwise. | ||
* The `generator` is responsible for ordering possible base paths. The `operation` is responsible for joining a single | ||
* `base` path with the given `uri`. The `predicate` is responsible for reporting whether the single joined value is | ||
* successful as the overall result. | ||
* | ||
* If none of the expected files exist then any given `fallback` argument to `next()` is used even if it does not exist. | ||
* Both the `generator` and `operation` may be `function*()` or simply `function(...):Array<string>`. | ||
* | ||
* @param {string} filename The absolute path of the file being processed | ||
* @param {string} uri The uri given in the file webpack is processing | ||
* @param {string} base A value from the iterator currently being processed | ||
* @param {function(?string):<string|Array<string>>} next Optionally set fallback then recurse next iteration | ||
* @param {{fs:Object, root:string, debug:boolean|function}} options The loader options including webpack file system | ||
* @returns {string|Array<string>} Result from the last iteration that occurred | ||
* @param {function({uri:string, isAbsolute:boolean, bases:{subString:string, value:string, property:string, | ||
* selector:string}}, {filename:string, fs:Object, debug:function|boolean, root:string}): | ||
* (Array<string>|Iterator<string>)} generator A function that takes the hash of base paths from the `engine` and | ||
* returns ordered iterable of paths to consider | ||
* @returns {function({filename:string, fs:Object, debug:function|boolean, root:string}): | ||
* (function({uri:string, isAbsolute:boolean, bases:{subString:string, value:string, property:string, | ||
* selector:string}}):string)} join implementation | ||
*/ | ||
function defaultJoinOperation(filename, uri, base, next, options) { | ||
var absolute = path.normalize(path.join(base, uri)), | ||
isSuccess = webpackExistsSync(options.fs, absolute) && options.fs.statSync(absolute).isFile(); | ||
return isSuccess ? absolute : next(absolute); | ||
} | ||
const createJoinImplementation = (generator) => (item, options, loader) => { | ||
const { isAbsolute } = item; | ||
const { root } = options; | ||
const { fs } = loader; | ||
exports.defaultJoinOperation = defaultJoinOperation; | ||
// generate the iterator | ||
const iterator = generator(item, options, loader); | ||
const isValidIterator = iterator && typeof iterator === 'object' && typeof iterator.next === 'function'; | ||
if (!isValidIterator) { | ||
throw new Error('expected generator to return Iterator'); | ||
} | ||
// run the iterator lazily and record attempts | ||
const { isFileSync, isDirectorySync } = fsUtils(fs); | ||
const attempts = []; | ||
for (let i = 0; i < ITERATION_SAFETY_LIMIT; i++) { | ||
const { value, done } = iterator.next(); | ||
if (done) { | ||
break; | ||
} else if (value) { | ||
const tuple = Array.isArray(value) && value.length === 2 ? value : null; | ||
if (!tuple) { | ||
throw new Error('expected Iterator values to be tuple of [string,string], do you need asGenerator utility?'); | ||
} | ||
// skip elements where base or uri is non-string | ||
// noting that we need to support base="" when root="" | ||
const [base, uri] = value; | ||
if ((typeof base === 'string') && (typeof uri === 'string')) { | ||
// validate | ||
const isValidBase = (isAbsolute && base === root) || (path.isAbsolute(base) && isDirectorySync(base)); | ||
if (!isValidBase) { | ||
throw new Error(`expected "base" to be absolute path to a valid directory, got "${base}"`); | ||
} | ||
// make the attempt | ||
const joined = path.normalize(path.join(base, uri)); | ||
const isFallback = true; | ||
const isSuccess = isFileSync(joined); | ||
attempts.push({base, uri, joined, isFallback, isSuccess}); | ||
if (isSuccess) { | ||
break; | ||
} | ||
// validate any non-strings are falsey | ||
} else { | ||
const isValidTuple = value.every((v) => (typeof v === 'string') || !v); | ||
if (!isValidTuple) { | ||
throw new Error('expected Iterator values to be tuple of [string,string]'); | ||
} | ||
} | ||
} | ||
} | ||
return attempts; | ||
}; | ||
exports.createJoinImplementation = createJoinImplementation; | ||
/** | ||
* The default join function iterates over possible base paths until a suitable join is found. | ||
* A low-level utility to create a join function. | ||
* | ||
* The first base path is used as fallback for the case where none of the base paths can locate the actual file. | ||
* The `implementation` function processes an individual `item` and returns an Array of attempts. Each attempt consists | ||
* of a `base` and a `joined` value with `isSuccessful` and `isFallback` flags. | ||
* | ||
* @type {function} | ||
*/ | ||
exports.defaultJoin = createJoinFunction({ | ||
name : 'defaultJoin', | ||
scheme : CURRENT_SCHEME, | ||
generator: defaultJoinGenerator, | ||
operation: defaultJoinOperation | ||
}); | ||
/** | ||
* A utility to create a join function. | ||
* In the case that any attempt `isSuccessful` then its `joined` value is the outcome. Otherwise the first `isFallback` | ||
* attempt is used. If there is no successful or fallback attempts then `null` is returned indicating no change to the | ||
* original URI in the CSS. | ||
* | ||
* Refer to implementation of `defaultJoinGenerator` and `defaultJoinOperation`. | ||
* The `attempts` Array is logged to console when in `debug` mode. | ||
* | ||
* @param {string} name Name for the resulting join function | ||
* @param {string} scheme A keyword that confirms your implementation matches the current scheme. | ||
* @param {function(string, {subString:string, value:string, property:string, selector:string}, Object): | ||
* (Array<string>|Iterator<string>)} generator A function that takes the hash of base paths from the `engine` and | ||
* returns ordered iterable of paths to consider | ||
* @param {function({filename:string, uri:string, base:string}, function(?string):<string|Array<string>>, | ||
* {fs:Object, root:string}):(string|Array<string>)} operation A function that tests values and returns joined paths | ||
* @returns {function(string, {fs:Object, debug:function|boolean, root:string}): | ||
* (function(string, {subString:string, value:string, property:string, selector:string}):string)} join function factory | ||
* @param {function({uri:string, query:string, isAbsolute:boolean, bases:{subString:string, value:string, | ||
* property:string, selector:string}}, {filename:string, fs:Object, debug:function|boolean, root:string}): | ||
* Array<{base:string,joined:string,fallback?:string,result?:string}>} implementation A function accepts an item and | ||
* returns a list of attempts | ||
* @returns {function({filename:string, fs:Object, debug:function|boolean, root:string}): | ||
* (function({uri:string, isAbsolute:boolean, bases:{subString:string, value:string, property:string, | ||
* selector:string}}):string)} join function | ||
*/ | ||
function createJoinFunction({ name, scheme, generator, operation }) { | ||
if (typeof scheme !== 'string' || scheme.toLowerCase() !== CURRENT_SCHEME) { | ||
throw new Error(`Custom join function has changed, please update to the latest scheme. Refer to the docs.`); | ||
} | ||
const createJoinFunction = (name, implementation) => { | ||
const assertAttempts = (value) => { | ||
const isValid = | ||
Array.isArray(value) && value.every((v) => | ||
v && | ||
(typeof v === 'object') && | ||
(typeof v.base === 'string') && | ||
(typeof v.uri === 'string') && | ||
(typeof v.joined === 'string') && | ||
(typeof v.isSuccess === 'boolean') && | ||
(typeof v.isFallback === 'boolean') | ||
); | ||
if (!isValid) { | ||
throw new Error(`expected implementation to return Array of {base, uri, joined, isSuccess, isFallback}`); | ||
} else { | ||
return value; | ||
} | ||
}; | ||
/** | ||
* A factory for a join function with logging. | ||
* | ||
* Options are curried and a join function proper is returned. | ||
* | ||
* @param {{fs:Object, root:string, debug:boolean|function}} options The loader options including webpack file system | ||
*/ | ||
function join(options) { | ||
var log = debug.createDebugLogger(options.debug); | ||
const assertJoined = (value) => { | ||
const isValid = value && (typeof value === 'string') && path.isAbsolute(value) || (value === null); | ||
if (!isValid) { | ||
throw new Error(`expected "joined" to be absolute path, got "${value}"`); | ||
} else { | ||
return value; | ||
} | ||
}; | ||
/** | ||
* Join function proper. | ||
* | ||
* For absolute uri only `uri` will be provided and no `bases`. | ||
* | ||
* @param {string} filename The current file being processed | ||
* @param {string} uri A uri path, relative or absolute | ||
* @param {boolean} isAbsolute True for absolute URIs, false for relative URIs | ||
* @param {{subString:string, value:string, property:string, selector:string}} bases Hash of possible base paths | ||
* @return {string} Just the uri where base is empty or the uri appended to the base | ||
*/ | ||
return function joinProper(filename, uri, isAbsolute, bases) { | ||
var iterator = sanitiseIterable(generator(filename, uri, isAbsolute, bases, options)), | ||
result = reduceIterator({inputs:[], outputs:[], isFound:false}, iterator), | ||
lastOutput = result.outputs[result.outputs.length-1], | ||
fallback = result.outputs.find(Boolean) || uri; | ||
const join = (options, loader) => { | ||
const { debug } = options; | ||
const { resourcePath } = loader; | ||
const log = createDebugLogger(debug); | ||
log(debug.formatJoinMessage, [filename, uri, result.inputs, result.isFound]); | ||
return (item) => { | ||
const { uri } = item; | ||
const attempts = implementation(item, options, loader); | ||
assertAttempts(attempts, !!debug); | ||
return result.isFound ? lastOutput : fallback; | ||
const { joined: fallback } = attempts.find(({ isFallback }) => isFallback) || {}; | ||
const { joined: result } = attempts.find(({ isSuccess }) => isSuccess) || {}; | ||
/** | ||
* Run the next iterator value. | ||
* | ||
* @param {Array<string>} accumulator Current result | ||
* @returns {Array<string>} Updated result | ||
*/ | ||
function reduceIterator(accumulator) { | ||
var inputs = accumulator.inputs || [], | ||
outputs = accumulator.outputs || [], | ||
nextItem = iterator.next(); | ||
log(formatJoinMessage, [resourcePath, uri, attempts]); | ||
if (nextItem.done) { | ||
return accumulator; | ||
} else { | ||
var base = assertAbsolute(nextItem.value, 'expected Iterator<string> of absolute base path', ''), | ||
pending = operation(filename, uri, base, next, options); | ||
if (!!pending && typeof pending === 'object') { | ||
return pending; | ||
} else { | ||
assertAbsolute(pending, 'operation must return an absolute path or the result of calling next()'); | ||
return { | ||
inputs : inputs.concat(base), | ||
outputs: outputs.concat(pending), | ||
isFound: true | ||
}; | ||
} | ||
} | ||
/** | ||
* Provide a possible fallback but run the next iteration either way. | ||
* | ||
* @param {string} fallback? Optional absolute path as fallback value | ||
* @returns {Array<string>} Nested result | ||
*/ | ||
function next(fallback) { | ||
assertAbsolute(fallback, 'next() expects absolute path string or no argument', null, undefined); | ||
return reduceIterator({ | ||
inputs : inputs.concat(base), | ||
outputs: outputs.concat(fallback || []), | ||
isFound: false | ||
}); | ||
} | ||
/** | ||
* Assert that the given value is an absolute path or some other accepted literal. | ||
* | ||
* @param {*} candidate Possible result | ||
* @param {string} message Error message | ||
* @param {...*} alsoAcceptable? Any number of simple values that are also acceptable | ||
* @throws An error with the given message where the candidate fails the assertion | ||
*/ | ||
function assertAbsolute(candidate, message, ...alsoAcceptable) { | ||
var isValid = (alsoAcceptable.indexOf(candidate) >= 0) || | ||
(typeof candidate === 'string') && path.isAbsolute(candidate); | ||
if (!isValid) { | ||
throw new Error(message); | ||
} | ||
return candidate; | ||
} | ||
} | ||
return assertJoined(result || fallback || null); | ||
}; | ||
} | ||
}; | ||
function toString() { | ||
return '[Function ' + name + ']'; | ||
} | ||
const toString = () => '[Function ' + name + ']'; | ||
return Object.assign(join, !!name && { | ||
toString: toString, | ||
toJSON : toString | ||
toString, | ||
toJSON: toString | ||
}); | ||
} | ||
}; | ||
exports.createJoinFunction = createJoinFunction; | ||
/** | ||
* The default iterable factory will order `subString` then `value` then `property` then `selector`. | ||
* | ||
* @param {string} uri The uri given in the file webpack is processing | ||
* @param {boolean} isAbsolute True for absolute URIs, false for relative URIs | ||
* @param {string} subString A possible base path | ||
* @param {string} value A possible base path | ||
* @param {string} property A possible base path | ||
* @param {string} selector A possible base path | ||
* @param {string} root The loader options.root value where given | ||
* @returns {Array<string>} An iterable of possible base paths in preference order | ||
*/ | ||
const defaultJoinGenerator = asGenerator( | ||
({ uri, isAbsolute, bases: { subString, value, property, selector } }, { root }) => | ||
isAbsolute ? [root] : [subString, value, property, selector] | ||
); | ||
exports.defaultJoinGenerator = defaultJoinGenerator; | ||
/** | ||
* @type {function({filename:string, fs:Object, debug:function|boolean, root:string}): | ||
* (function({uri:string, isAbsolute:boolean, bases:{subString:string, value:string, property:string, | ||
* selector:string}}):string)} join function | ||
*/ | ||
exports.defaultJoin = createJoinFunction( | ||
'defaultJoin', | ||
createJoinImplementation(defaultJoinGenerator) | ||
); |
@@ -13,13 +13,11 @@ /* | ||
* | ||
* @param {string} filename The current file being processed | ||
* @param {{fs:Object, debug:function|boolean, join:function, root:string}} options Options hash | ||
* @param {function(Object):string} join The inner join function | ||
* @param {string} root The loader options.root value where given | ||
* @param {string} directory The directory of the file webpack is currently processing | ||
* @return {function} value processing function | ||
*/ | ||
function valueProcessor(filename, options) { | ||
function valueProcessor({ join, root, directory }) { | ||
var URL_STATEMENT_REGEX = /(url\s*\(\s*)(?:(['"])((?:(?!\2).)*)(\2)|([^'"](?:(?!\)).)*[^'"]))(\s*\))/g, | ||
QUERY_REGEX = /([?#])/g; | ||
var directory = path.dirname(filename), | ||
joinProper = options.join(options); | ||
/** | ||
@@ -87,23 +85,25 @@ * Process the given CSS declaration value. | ||
// split into uri and query/hash and then find the absolute path to the uri | ||
// construct iterator as late as possible in case sourcemap is invalid at this location | ||
var split = unescaped.split(QUERY_REGEX), | ||
uri = split[0], | ||
query = split.slice(1).join(''), | ||
absolute = testIsRelative(uri) && joinProper(filename, uri, false, getPathsAtChar(position)) || | ||
testIsAbsolute(uri) && joinProper(filename, uri, true, getPathsAtChar(position)); | ||
// split into uri and query/hash and then determine if the uri is some type of file | ||
var split = unescaped.split(QUERY_REGEX), | ||
uri = split[0], | ||
query = split.slice(1).join(''), | ||
isRelative = testIsRelative(uri), | ||
isAbsolute = testIsAbsolute(uri); | ||
// not all URIs are files | ||
if (!absolute) { | ||
return element; | ||
} else { | ||
return loaderUtils.urlToRequest( | ||
path.relative(directory, absolute).replace(/\\/g, '/') + query // #6 - backslashes are not legal in URI | ||
); | ||
// file like URIs are processed but not all URIs are files | ||
if (isRelative || isAbsolute) { | ||
var bases = getPathsAtChar(position), // construct iterator as late as possible in case sourcemap invalid | ||
absolute = join({ uri, query, isAbsolute, bases }); | ||
if (typeof absolute === 'string') { | ||
var relative = path.relative(directory, absolute) | ||
.replace(/\\/g, '/'); // #6 - backslashes are not legal in URI | ||
return loaderUtils.urlToRequest(relative + query); | ||
} | ||
} | ||
} | ||
// everything else, including parentheses and quotation (where present) and media statements | ||
else { | ||
return element; | ||
} | ||
return element; | ||
} | ||
@@ -133,3 +133,3 @@ }; | ||
function testIsAbsolute(uri) { | ||
return !!uri && (typeof options.root === 'string') && loaderUtils.isUrlRequest(uri, options.root) && | ||
return !!uri && (typeof root === 'string') && loaderUtils.isUrlRequest(uri, root) && | ||
(/^\//.test(uri) || path.isAbsolute(uri)); | ||
@@ -136,0 +136,0 @@ } |
{ | ||
"name": "resolve-url-loader", | ||
"version": "4.0.0-alpha.3", | ||
"version": "4.0.0-alpha.4", | ||
"description": "Webpack loader that resolves relative paths in url() statements based on the original source file", | ||
@@ -55,4 +55,3 @@ "main": "index.js", | ||
} | ||
}, | ||
"scheme": "alstroemeria" | ||
} | ||
} |
@@ -62,2 +62,4 @@ # Resolve URL Loader | ||
> **Upgrading?** the [changelog](CHANGELOG.md) shows how to migrate your webpack config. | ||
### Install | ||
@@ -64,0 +66,0 @@ |
71979
1087
141