123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331 |
- var JSON5 = require("json5");
- var path = require("path");
- var util = require("util");
- var os = require("os");
- var assign = require("object-assign");
- var emojiRegex = /[\uD800-\uDFFF]./;
- var emojiList = require("emojis-list").filter(function(emoji) {
- return emojiRegex.test(emoji)
- });
- var matchAbsolutePath = /^\/|^[A-Z]:[/\\]|^\\\\/i; // node 0.10 does not support path.isAbsolute()
- var matchAbsoluteWin32Path = /^[A-Z]:[/\\]|^\\\\/i;
- var matchRelativePath = /^\.\.?[/\\]/;
- var baseEncodeTables = {
- 26: "abcdefghijklmnopqrstuvwxyz",
- 32: "123456789abcdefghjkmnpqrstuvwxyz", // no 0lio
- 36: "0123456789abcdefghijklmnopqrstuvwxyz",
- 49: "abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ", // no lIO
- 52: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
- 58: "123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ", // no 0lIO
- 62: "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
- 64: "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_"
- };
- var emojiCache = {};
- var parseQueryDeprecationWarning = util.deprecate(function() {},
- "loaderUtils.parseQuery() received a non-string value which can be problematic, " +
- "see https://github.com/webpack/loader-utils/issues/56" + os.EOL +
- "parseQuery() will be replaced with getOptions() in the next major version of loader-utils."
- );
- function encodeStringToEmoji(content, length) {
- if (emojiCache[content]) return emojiCache[content];
- length = length || 1;
- var emojis = [];
- do {
- var index = Math.floor(Math.random() * emojiList.length);
- emojis.push(emojiList[index]);
- emojiList.splice(index, 1);
- } while (--length > 0);
- var emojiEncoding = emojis.join('');
- emojiCache[content] = emojiEncoding;
- return emojiEncoding;
- }
- function encodeBufferToBase(buffer, base) {
- var encodeTable = baseEncodeTables[base];
- if (!encodeTable) throw new Error("Unknown encoding base" + base);
- var readLength = buffer.length;
- var Big = require('big.js');
- Big.RM = Big.DP = 0;
- var b = new Big(0);
- for (var i = readLength - 1; i >= 0; i--) {
- b = b.times(256).plus(buffer[i]);
- }
- var output = "";
- while (b.gt(0)) {
- output = encodeTable[b.mod(base)] + output;
- b = b.div(base);
- }
- Big.DP = 20;
- Big.RM = 1;
- return output;
- }
- exports.parseQuery = function parseQuery(query) {
- var specialValues = {
- 'null': null,
- 'true': true,
- 'false': false
- };
- if(!query) return {};
- if(typeof query !== "string") {
- parseQueryDeprecationWarning();
- return query;
- }
- if(query.substr(0, 1) !== "?")
- throw new Error("a valid query string passed to parseQuery should begin with '?'");
- query = query.substr(1);
- var queryLength = query.length;
- if(query.substr(0, 1) === "{" && query.substr(-1) === "}") {
- return JSON5.parse(query);
- }
- var queryArgs = query.split(/[,\&]/g);
- var result = {};
- queryArgs.forEach(function(arg) {
- var idx = arg.indexOf("=");
- if(idx >= 0) {
- var name = arg.substr(0, idx);
- var value = decodeURIComponent(arg.substr(idx+1));
- if (specialValues.hasOwnProperty(value)) {
- value = specialValues[value];
- }
- if(name.substr(-2) === "[]") {
- name = decodeURIComponent(name.substr(0, name.length-2));
- if(!Array.isArray(result[name]))
- result[name] = [];
- result[name].push(value);
- } else {
- name = decodeURIComponent(name);
- result[name] = value;
- }
- } else {
- if(arg.substr(0, 1) === "-") {
- result[decodeURIComponent(arg.substr(1))] = false;
- } else if(arg.substr(0, 1) === "+") {
- result[decodeURIComponent(arg.substr(1))] = true;
- } else {
- result[decodeURIComponent(arg)] = true;
- }
- }
- });
- return result;
- };
- exports.getLoaderConfig = function(loaderContext, defaultConfigKey) {
- var query = exports.parseQuery(loaderContext.query);
- var configKey = query.config || defaultConfigKey;
- if (configKey) {
- var config = loaderContext.options[configKey] || {};
- delete query.config;
- return assign({}, config, query);
- }
- return query;
- };
- exports.stringifyRequest = function(loaderContext, request) {
- var splitted = request.split("!");
- var context = loaderContext.context || (loaderContext.options && loaderContext.options.context);
- return JSON.stringify(splitted.map(function(part) {
- // First, separate singlePath from query, because the query might contain paths again
- var splittedPart = part.match(/^(.*?)(\?.*)/);
- var singlePath = splittedPart ? splittedPart[1] : part;
- var query = splittedPart ? splittedPart[2] : "";
- if(matchAbsolutePath.test(singlePath) && context) {
- singlePath = path.relative(context, singlePath);
- if(matchAbsolutePath.test(singlePath)) {
- // If singlePath still matches an absolute path, singlePath was on a different drive than context.
- // In this case, we leave the path platform-specific without replacing any separators.
- // @see https://github.com/webpack/loader-utils/pull/14
- return singlePath + query;
- }
- if(matchRelativePath.test(singlePath) === false) {
- // Ensure that the relative path starts at least with ./ otherwise it would be a request into the modules directory (like node_modules).
- singlePath = "./" + singlePath;
- }
- }
- return singlePath.replace(/\\/g, "/") + query;
- }).join("!"));
- };
- function dotRequest(obj) {
- return obj.request;
- }
- exports.getRemainingRequest = function(loaderContext) {
- if(loaderContext.remainingRequest)
- return loaderContext.remainingRequest;
- var request = loaderContext.loaders.slice(loaderContext.loaderIndex+1).map(dotRequest).concat([loaderContext.resource]);
- return request.join("!");
- };
- exports.getCurrentRequest = function(loaderContext) {
- if(loaderContext.currentRequest)
- return loaderContext.currentRequest;
- var request = loaderContext.loaders.slice(loaderContext.loaderIndex).map(dotRequest).concat([loaderContext.resource]);
- return request.join("!");
- };
- exports.isUrlRequest = function(url, root) {
- // An URL is not an request if
- // 1. it's a Data Url
- // 2. it's an absolute url or and protocol-relative
- // 3. it's some kind of url for a template
- if(/^data:|^chrome-extension:|^(https?:)?\/\/|^[\{\}\[\]#*;,'§\$%&\(=?`´\^°<>]/.test(url)) return false;
- // 4. It's also not an request if root isn't set and it's a root-relative url
- if((root === undefined || root === false) && /^\//.test(url)) return false;
- return true;
- };
- exports.urlToRequest = function(url, root) {
- var moduleRequestRegex = /^[^?]*~/;
- var request;
- if(matchAbsoluteWin32Path.test(url)) {
- // absolute windows path, keep it
- request = url;
- } else if(root !== undefined && root !== false && /^\//.test(url)) {
- // if root is set and the url is root-relative
- switch(typeof root) {
- // 1. root is a string: root is prefixed to the url
- case "string":
- // special case: `~` roots convert to module request
- if (moduleRequestRegex.test(root)) {
- request = root.replace(/([^~\/])$/, "$1/") + url.slice(1);
- } else {
- request = root + url;
- }
- break;
- // 2. root is `true`: absolute paths are allowed
- // *nix only, windows-style absolute paths are always allowed as they doesn't start with a `/`
- case "boolean":
- request = url;
- break;
- default:
- throw new Error("Unexpected parameters to loader-utils 'urlToRequest': url = " + url + ", root = " + root + ".");
- }
- } else if(/^\.\.?\//.test(url)) {
- // A relative url stays
- request = url;
- } else {
- // every other url is threaded like a relative url
- request = "./" + url;
- }
- // A `~` makes the url an module
- if (moduleRequestRegex.test(request)) {
- request = request.replace(moduleRequestRegex, "");
- }
- return request;
- };
- exports.parseString = function parseString(str) {
- try {
- if(str[0] === '"') return JSON.parse(str);
- if(str[0] === "'" && str.substr(str.length - 1) === "'") {
- return parseString(str.replace(/\\.|"/g, function(x) {
- if(x === '"') return '\\"';
- return x;
- }).replace(/^'|'$/g, '"'));
- }
- return JSON.parse('"' + str + '"');
- } catch(e) {
- return str;
- }
- };
- exports.getHashDigest = function getHashDigest(buffer, hashType, digestType, maxLength) {
- hashType = hashType || "md5";
- maxLength = maxLength || 9999;
- var hash = require("crypto").createHash(hashType);
- hash.update(buffer);
- if (digestType === "base26" || digestType === "base32" || digestType === "base36" ||
- digestType === "base49" || digestType === "base52" || digestType === "base58" ||
- digestType === "base62" || digestType === "base64") {
- return encodeBufferToBase(hash.digest(), digestType.substr(4)).substr(0, maxLength);
- } else {
- return hash.digest(digestType || "hex").substr(0, maxLength);
- }
- };
- exports.interpolateName = function interpolateName(loaderContext, name, options) {
- var filename;
- if (typeof name === "function") {
- filename = name(loaderContext.resourcePath);
- } else {
- filename = name || "[hash].[ext]";
- }
- var context = options.context;
- var content = options.content;
- var regExp = options.regExp;
- var ext = "bin";
- var basename = "file";
- var directory = "";
- var folder = "";
- if(loaderContext.resourcePath) {
- var resourcePath = loaderContext.resourcePath;
- var idx = resourcePath.lastIndexOf(".");
- var i = resourcePath.lastIndexOf("\\");
- var j = resourcePath.lastIndexOf("/");
- var p = i < 0 ? j : j < 0 ? i : i < j ? i : j;
- if(idx >= 0) {
- ext = resourcePath.substr(idx+1);
- resourcePath = resourcePath.substr(0, idx);
- }
- if(p >= 0) {
- basename = resourcePath.substr(p+1);
- resourcePath = resourcePath.substr(0, p+1);
- }
- if (typeof context !== 'undefined') {
- directory = path.relative(context, resourcePath + "_").replace(/\\/g, "/").replace(/\.\.(\/)?/g, "_$1");
- directory = directory.substr(0, directory.length-1);
- }
- else {
- directory = resourcePath.replace(/\\/g, "/").replace(/\.\.(\/)?/g, "_$1");
- }
- if (directory.length === 1) {
- directory = "";
- } else if (directory.length > 1) {
- folder = path.basename(directory);
- }
- }
- var url = filename;
- if(content) {
- // Match hash template
- url = url.replace(/\[(?:(\w+):)?hash(?::([a-z]+\d*))?(?::(\d+))?\]/ig, function() {
- return exports.getHashDigest(content, arguments[1], arguments[2], parseInt(arguments[3], 10));
- }).replace(/\[emoji(?::(\d+))?\]/ig, function() {
- return encodeStringToEmoji(content, arguments[1]);
- });
- }
- url = url.replace(/\[ext\]/ig, function() {
- return ext;
- }).replace(/\[name\]/ig, function() {
- return basename;
- }).replace(/\[path\]/ig, function() {
- return directory;
- }).replace(/\[folder\]/ig, function() {
- return folder;
- });
- if(regExp && loaderContext.resourcePath) {
- var re = new RegExp(regExp);
- var match = loaderContext.resourcePath.match(re);
- if(match) {
- for (var i = 0; i < match.length; i++) {
- var re = new RegExp("\\[" + i + "\\]", "ig");
- url = url.replace(re, match[i]);
- }
- }
- }
- if(typeof loaderContext.options === "object" && typeof loaderContext.options.customInterpolateName === "function") {
- url = loaderContext.options.customInterpolateName.call(loaderContext, url, name, options);
- }
- return url;
- };
|