'use strict';
|
|
const matchOptions = require('./match-options');
|
const paths = require('./paths');
|
|
const getPathDeclFile = paths.getPathDeclFile;
|
const getDirDeclFile = paths.getDirDeclFile;
|
const prepareAsset = paths.prepareAsset;
|
|
/**
|
* @typedef UrlRegExp
|
* @name UrlRegExp
|
* @desc A regex for match url with parentheses:
|
* (before url)(the url)(after url).
|
* (the url) will be replace with new url, and before and after will remain
|
* @type RegExp
|
*/
|
/**
|
* @type {UrlRegExp[]}
|
*/
|
const URL_PATTERNS = [
|
/(url\(\s*['"]?)([^"')]+)(["']?\s*\))/g,
|
/(AlphaImageLoader\(\s*src=['"]?)([^"')]+)(["'])/g
|
];
|
|
const WITH_QUOTES = /^['"]/;
|
|
/**
|
* Restricted modes
|
*
|
* @type {String[]}
|
*/
|
const PROCESS_TYPES = ['rebase', 'inline', 'copy', 'custom'];
|
|
const getUrlProcessorType = (optionUrl) =>
|
typeof optionUrl === 'function' ? 'custom' : (optionUrl || 'rebase');
|
|
/**
|
* @param {String} optionUrl
|
* @returns {PostcssUrl~UrlProcessor}
|
*/
|
function getUrlProcessor(optionUrl) {
|
const mode = getUrlProcessorType(optionUrl);
|
|
if (PROCESS_TYPES.indexOf(mode) === -1) {
|
throw new Error(`Unknown mode for postcss-url: ${mode}`);
|
}
|
|
return require(`../type/${mode}`);
|
}
|
|
/**
|
* @param {PostcssUrl~UrlProcessor} urlProcessor
|
* @param {Result} result
|
* @param {Decl} decl
|
* @returns {Function}
|
*/
|
const wrapUrlProcessor = (urlProcessor, result, decl) => {
|
const warn = (message) => decl.warn(result, message);
|
const addDependency = (file) => result.messages.push({
|
type: 'dependency',
|
file,
|
parent: getPathDeclFile(decl)
|
});
|
|
return (asset, dir, option) =>
|
urlProcessor(asset, dir, option, decl, warn, result, addDependency);
|
};
|
|
/**
|
* @param {Decl} decl
|
* @returns {RegExp}
|
*/
|
const getPattern = (decl) =>
|
URL_PATTERNS.find((pattern) => pattern.test(decl.value));
|
|
/**
|
* @param {String} url
|
* @param {Dir} dir
|
* @param {Options} options
|
* @param {Result} result
|
* @param {Decl} decl
|
* @returns {String|undefined}
|
*/
|
const replaceUrl = (url, dir, options, result, decl) => {
|
const asset = prepareAsset(url, dir, decl);
|
|
const matchedOptions = matchOptions(asset, options);
|
|
if (!matchedOptions) return;
|
|
const process = (option) => {
|
const wrappedUrlProcessor = wrapUrlProcessor(getUrlProcessor(option.url), result, decl);
|
|
return wrappedUrlProcessor(asset, dir, option);
|
};
|
|
if (Array.isArray(matchedOptions)) {
|
matchedOptions.forEach((option) => asset.url = process(option));
|
} else {
|
asset.url = process(matchedOptions);
|
}
|
|
return asset.url;
|
};
|
|
/**
|
* @param {String} from
|
* @param {String} to
|
* @param {PostcssUrl~Options} options
|
* @param {Result} result
|
* @param {Decl} decl
|
* @returns {PostcssUrl~DeclProcessor}
|
*/
|
const declProcessor = (from, to, options, result, decl) => {
|
const dir = { from, to, file: getDirDeclFile(decl) };
|
const pattern = getPattern(decl);
|
|
if (!pattern) return;
|
|
decl.value = decl.value
|
.replace(pattern, (matched, before, url, after) => {
|
const newUrl = replaceUrl(url, dir, options, result, decl);
|
|
if (!newUrl) return matched;
|
|
if (WITH_QUOTES.test(newUrl) && WITH_QUOTES.test(after)) {
|
before = before.slice(0, -1);
|
after = after.slice(1);
|
}
|
|
return `${before}${newUrl}${after}`;
|
});
|
};
|
|
module.exports = {
|
replaceUrl,
|
declProcessor
|
};
|
|
/**
|
* @typedef {Object} PostcssUrl~Options - postcss-url Options
|
* @property {String} [url=^rebase|inline|copy|custom] - processing mode
|
* @property {Minimatch|RegExp|Function} [filter] - filter assets by relative pathname
|
* @property {String} [assetsPath] - absolute or relative path to copy assets
|
* @property {String|String[]} [basePath] - absolute or relative paths to search, when copy or inline
|
* @property {Number} [maxSize] - max file size in kbytes for inline mode
|
* @property {String} [fallback] - fallback mode if file exceeds maxSize
|
* @property {Boolean} [useHash] - use file hash instead filename
|
* @property {HashOptions} [hashOptions] - params for generating hash name
|
*/
|