utils.js 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.normalizeOptions = normalizeOptions;
  6. exports.shouldUseModulesPlugins = shouldUseModulesPlugins;
  7. exports.shouldUseImportPlugin = shouldUseImportPlugin;
  8. exports.shouldUseURLPlugin = shouldUseURLPlugin;
  9. exports.shouldUseIcssPlugin = shouldUseIcssPlugin;
  10. exports.normalizeUrl = normalizeUrl;
  11. exports.requestify = requestify;
  12. exports.getFilter = getFilter;
  13. exports.getModulesOptions = getModulesOptions;
  14. exports.getModulesPlugins = getModulesPlugins;
  15. exports.normalizeSourceMap = normalizeSourceMap;
  16. exports.getPreRequester = getPreRequester;
  17. exports.getImportCode = getImportCode;
  18. exports.getModuleCode = getModuleCode;
  19. exports.getExportCode = getExportCode;
  20. exports.resolveRequests = resolveRequests;
  21. exports.isUrlRequestable = isUrlRequestable;
  22. exports.sort = sort;
  23. exports.combineRequests = combineRequests;
  24. exports.camelCase = camelCase;
  25. exports.WEBPACK_IGNORE_COMMENT_REGEXP = void 0;
  26. var _url = require("url");
  27. var _path = _interopRequireDefault(require("path"));
  28. var _loaderUtils = require("loader-utils");
  29. var _postcssModulesValues = _interopRequireDefault(require("postcss-modules-values"));
  30. var _postcssModulesLocalByDefault = _interopRequireDefault(require("postcss-modules-local-by-default"));
  31. var _postcssModulesExtractImports = _interopRequireDefault(require("postcss-modules-extract-imports"));
  32. var _postcssModulesScope = _interopRequireDefault(require("postcss-modules-scope"));
  33. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  34. /*
  35. MIT License http://www.opensource.org/licenses/mit-license.php
  36. Author Tobias Koppers @sokra
  37. */
  38. const WEBPACK_IGNORE_COMMENT_REGEXP = /webpackIgnore:(\s+)?(true|false)/; // eslint-disable-next-line no-useless-escape
  39. exports.WEBPACK_IGNORE_COMMENT_REGEXP = WEBPACK_IGNORE_COMMENT_REGEXP;
  40. const regexSingleEscape = /[ -,.\/:-@[\]\^`{-~]/;
  41. const regexExcessiveSpaces = /(^|\\+)?(\\[A-F0-9]{1,6})\x20(?![a-fA-F0-9\x20])/g;
  42. const preserveCamelCase = string => {
  43. let result = string;
  44. let isLastCharLower = false;
  45. let isLastCharUpper = false;
  46. let isLastLastCharUpper = false;
  47. for (let i = 0; i < result.length; i++) {
  48. const character = result[i];
  49. if (isLastCharLower && /[\p{Lu}]/u.test(character)) {
  50. result = `${result.slice(0, i)}-${result.slice(i)}`;
  51. isLastCharLower = false;
  52. isLastLastCharUpper = isLastCharUpper;
  53. isLastCharUpper = true;
  54. i += 1;
  55. } else if (isLastCharUpper && isLastLastCharUpper && /[\p{Ll}]/u.test(character)) {
  56. result = `${result.slice(0, i - 1)}-${result.slice(i - 1)}`;
  57. isLastLastCharUpper = isLastCharUpper;
  58. isLastCharUpper = false;
  59. isLastCharLower = true;
  60. } else {
  61. isLastCharLower = character.toLowerCase() === character && character.toUpperCase() !== character;
  62. isLastLastCharUpper = isLastCharUpper;
  63. isLastCharUpper = character.toUpperCase() === character && character.toLowerCase() !== character;
  64. }
  65. }
  66. return result;
  67. };
  68. function camelCase(input) {
  69. let result = input.trim();
  70. if (result.length === 0) {
  71. return "";
  72. }
  73. if (result.length === 1) {
  74. return result.toLowerCase();
  75. }
  76. const hasUpperCase = result !== result.toLowerCase();
  77. if (hasUpperCase) {
  78. result = preserveCamelCase(result);
  79. }
  80. return result.replace(/^[_.\- ]+/, "").toLowerCase().replace(/[_.\- ]+([\p{Alpha}\p{N}_]|$)/gu, (_, p1) => p1.toUpperCase()).replace(/\d+([\p{Alpha}\p{N}_]|$)/gu, m => m.toUpperCase());
  81. }
  82. function escape(string) {
  83. let output = "";
  84. let counter = 0;
  85. while (counter < string.length) {
  86. // eslint-disable-next-line no-plusplus
  87. const character = string.charAt(counter++);
  88. let value; // eslint-disable-next-line no-control-regex
  89. if (/[\t\n\f\r\x0B]/.test(character)) {
  90. const codePoint = character.charCodeAt();
  91. value = `\\${codePoint.toString(16).toUpperCase()} `;
  92. } else if (character === "\\" || regexSingleEscape.test(character)) {
  93. value = `\\${character}`;
  94. } else {
  95. value = character;
  96. }
  97. output += value;
  98. }
  99. const firstChar = string.charAt(0);
  100. if (/^-[-\d]/.test(output)) {
  101. output = `\\-${output.slice(1)}`;
  102. } else if (/\d/.test(firstChar)) {
  103. output = `\\3${firstChar} ${output.slice(1)}`;
  104. } // Remove spaces after `\HEX` escapes that are not followed by a hex digit,
  105. // since they’re redundant. Note that this is only possible if the escape
  106. // sequence isn’t preceded by an odd number of backslashes.
  107. output = output.replace(regexExcessiveSpaces, ($0, $1, $2) => {
  108. if ($1 && $1.length % 2) {
  109. // It’s not safe to remove the space, so don’t.
  110. return $0;
  111. } // Strip the space.
  112. return ($1 || "") + $2;
  113. });
  114. return output;
  115. }
  116. function gobbleHex(str) {
  117. const lower = str.toLowerCase();
  118. let hex = "";
  119. let spaceTerminated = false; // eslint-disable-next-line no-undefined
  120. for (let i = 0; i < 6 && lower[i] !== undefined; i++) {
  121. const code = lower.charCodeAt(i); // check to see if we are dealing with a valid hex char [a-f|0-9]
  122. const valid = code >= 97 && code <= 102 || code >= 48 && code <= 57; // https://drafts.csswg.org/css-syntax/#consume-escaped-code-point
  123. spaceTerminated = code === 32;
  124. if (!valid) {
  125. break;
  126. }
  127. hex += lower[i];
  128. }
  129. if (hex.length === 0) {
  130. // eslint-disable-next-line no-undefined
  131. return undefined;
  132. }
  133. const codePoint = parseInt(hex, 16);
  134. const isSurrogate = codePoint >= 0xd800 && codePoint <= 0xdfff; // Add special case for
  135. // "If this number is zero, or is for a surrogate, or is greater than the maximum allowed code point"
  136. // https://drafts.csswg.org/css-syntax/#maximum-allowed-code-point
  137. if (isSurrogate || codePoint === 0x0000 || codePoint > 0x10ffff) {
  138. return ["\uFFFD", hex.length + (spaceTerminated ? 1 : 0)];
  139. }
  140. return [String.fromCodePoint(codePoint), hex.length + (spaceTerminated ? 1 : 0)];
  141. }
  142. const CONTAINS_ESCAPE = /\\/;
  143. function unescape(str) {
  144. const needToProcess = CONTAINS_ESCAPE.test(str);
  145. if (!needToProcess) {
  146. return str;
  147. }
  148. let ret = "";
  149. for (let i = 0; i < str.length; i++) {
  150. if (str[i] === "\\") {
  151. const gobbled = gobbleHex(str.slice(i + 1, i + 7)); // eslint-disable-next-line no-undefined
  152. if (gobbled !== undefined) {
  153. ret += gobbled[0];
  154. i += gobbled[1]; // eslint-disable-next-line no-continue
  155. continue;
  156. } // Retain a pair of \\ if double escaped `\\\\`
  157. // https://github.com/postcss/postcss-selector-parser/commit/268c9a7656fb53f543dc620aa5b73a30ec3ff20e
  158. if (str[i + 1] === "\\") {
  159. ret += "\\";
  160. i += 1; // eslint-disable-next-line no-continue
  161. continue;
  162. } // if \\ is at the end of the string retain it
  163. // https://github.com/postcss/postcss-selector-parser/commit/01a6b346e3612ce1ab20219acc26abdc259ccefb
  164. if (str.length === i + 1) {
  165. ret += str[i];
  166. } // eslint-disable-next-line no-continue
  167. continue;
  168. }
  169. ret += str[i];
  170. }
  171. return ret;
  172. }
  173. function normalizePath(file) {
  174. return _path.default.sep === "\\" ? file.replace(/\\/g, "/") : file;
  175. } // eslint-disable-next-line no-control-regex
  176. const filenameReservedRegex = /[<>:"/\\|?*]/g; // eslint-disable-next-line no-control-regex
  177. const reControlChars = /[\u0000-\u001f\u0080-\u009f]/g;
  178. function escapeLocalIdent(localident) {
  179. // TODO simplify in the next major release
  180. return escape(localident // For `[hash]` placeholder
  181. .replace(/^((-?[0-9])|--)/, "_$1").replace(filenameReservedRegex, "-").replace(reControlChars, "-").replace(/\./g, "-"));
  182. }
  183. function defaultGetLocalIdent(loaderContext, localIdentName, localName, options) {
  184. let relativeMatchResource = ""; // eslint-disable-next-line no-underscore-dangle
  185. if (loaderContext._module && loaderContext._module.matchResource) {
  186. relativeMatchResource = `${normalizePath( // eslint-disable-next-line no-underscore-dangle
  187. _path.default.relative(options.context, loaderContext._module.matchResource))}\x00`;
  188. }
  189. const relativeResourcePath = normalizePath(_path.default.relative(options.context, loaderContext.resourcePath)); // eslint-disable-next-line no-param-reassign
  190. options.content = `${options.hashPrefix}${relativeMatchResource}${relativeResourcePath}\x00${localName}`;
  191. return (0, _loaderUtils.interpolateName)(loaderContext, localIdentName, options);
  192. }
  193. const NATIVE_WIN32_PATH = /^[A-Z]:[/\\]|^\\\\/i;
  194. function normalizeUrl(url, isStringValue) {
  195. let normalizedUrl = url.replace(/^( |\t\n|\r\n|\r|\f)*/g, "").replace(/( |\t\n|\r\n|\r|\f)*$/g, "");
  196. if (isStringValue && /\\(\n|\r\n|\r|\f)/.test(normalizedUrl)) {
  197. normalizedUrl = normalizedUrl.replace(/\\(\n|\r\n|\r|\f)/g, "");
  198. }
  199. if (NATIVE_WIN32_PATH.test(url)) {
  200. try {
  201. normalizedUrl = decodeURI(normalizedUrl);
  202. } catch (error) {// Ignore
  203. }
  204. return normalizedUrl;
  205. }
  206. normalizedUrl = unescape(normalizedUrl);
  207. try {
  208. normalizedUrl = decodeURI(normalizedUrl);
  209. } catch (error) {// Ignore
  210. }
  211. return normalizedUrl;
  212. }
  213. function requestify(url, rootContext) {
  214. if (/^file:/i.test(url)) {
  215. return (0, _url.fileURLToPath)(url);
  216. }
  217. return url.charAt(0) === "/" ? (0, _loaderUtils.urlToRequest)(url, rootContext) : (0, _loaderUtils.urlToRequest)(url);
  218. }
  219. function getFilter(filter, resourcePath) {
  220. return (...args) => {
  221. if (typeof filter === "function") {
  222. return filter(...args, resourcePath);
  223. }
  224. return true;
  225. };
  226. }
  227. function getValidLocalName(localName, exportLocalsConvention) {
  228. if (exportLocalsConvention === "dashesOnly") {
  229. return dashesCamelCase(localName);
  230. }
  231. return camelCase(localName);
  232. }
  233. const moduleRegExp = /\.module(s)?\.\w+$/i;
  234. const icssRegExp = /\.icss\.\w+$/i;
  235. function getModulesOptions(rawOptions, loaderContext) {
  236. const resourcePath = // eslint-disable-next-line no-underscore-dangle
  237. loaderContext._module && loaderContext._module.matchResource || loaderContext.resourcePath;
  238. let isIcss;
  239. if (typeof rawOptions.modules === "undefined") {
  240. const isModules = moduleRegExp.test(resourcePath);
  241. if (!isModules) {
  242. isIcss = icssRegExp.test(resourcePath);
  243. }
  244. if (!isModules && !isIcss) {
  245. return false;
  246. }
  247. } else if (typeof rawOptions.modules === "boolean" && rawOptions.modules === false) {
  248. return false;
  249. }
  250. let modulesOptions = {
  251. compileType: isIcss ? "icss" : "module",
  252. auto: true,
  253. mode: "local",
  254. exportGlobals: false,
  255. localIdentName: "[hash:base64]",
  256. localIdentContext: loaderContext.rootContext,
  257. localIdentHashPrefix: "",
  258. // eslint-disable-next-line no-undefined
  259. localIdentRegExp: undefined,
  260. // eslint-disable-next-line no-undefined
  261. getLocalIdent: undefined,
  262. namedExport: false,
  263. exportLocalsConvention: "asIs",
  264. exportOnlyLocals: false
  265. };
  266. if (typeof rawOptions.modules === "boolean" || typeof rawOptions.modules === "string") {
  267. modulesOptions.mode = typeof rawOptions.modules === "string" ? rawOptions.modules : "local";
  268. } else {
  269. if (rawOptions.modules) {
  270. if (typeof rawOptions.modules.auto === "boolean") {
  271. const isModules = rawOptions.modules.auto && moduleRegExp.test(resourcePath);
  272. if (!isModules) {
  273. return false;
  274. }
  275. } else if (rawOptions.modules.auto instanceof RegExp) {
  276. const isModules = rawOptions.modules.auto.test(resourcePath);
  277. if (!isModules) {
  278. return false;
  279. }
  280. } else if (typeof rawOptions.modules.auto === "function") {
  281. const isModule = rawOptions.modules.auto(resourcePath);
  282. if (!isModule) {
  283. return false;
  284. }
  285. }
  286. if (rawOptions.modules.namedExport === true && typeof rawOptions.modules.exportLocalsConvention === "undefined") {
  287. modulesOptions.exportLocalsConvention = "camelCaseOnly";
  288. }
  289. }
  290. modulesOptions = { ...modulesOptions,
  291. ...(rawOptions.modules || {})
  292. };
  293. }
  294. if (typeof modulesOptions.mode === "function") {
  295. modulesOptions.mode = modulesOptions.mode(loaderContext.resourcePath);
  296. }
  297. if (modulesOptions.namedExport === true) {
  298. if (rawOptions.esModule === false) {
  299. throw new Error('The "modules.namedExport" option requires the "esModules" option to be enabled');
  300. }
  301. if (modulesOptions.exportLocalsConvention !== "camelCaseOnly" && modulesOptions.exportLocalsConvention !== "dashesOnly") {
  302. throw new Error('The "modules.namedExport" option requires the "modules.exportLocalsConvention" option to be "camelCaseOnly" or "dashesOnly"');
  303. }
  304. }
  305. if (/\[emoji(?::(\d+))?\]/i.test(modulesOptions.localIdentName)) {
  306. loaderContext.emitWarning("Emoji is deprecated and will be removed in next major release.");
  307. }
  308. return modulesOptions;
  309. }
  310. function normalizeOptions(rawOptions, loaderContext) {
  311. const modulesOptions = getModulesOptions(rawOptions, loaderContext);
  312. return {
  313. url: typeof rawOptions.url === "undefined" ? true : rawOptions.url,
  314. import: typeof rawOptions.import === "undefined" ? true : rawOptions.import,
  315. modules: modulesOptions,
  316. sourceMap: typeof rawOptions.sourceMap === "boolean" ? rawOptions.sourceMap : loaderContext.sourceMap,
  317. importLoaders: typeof rawOptions.importLoaders === "string" ? parseInt(rawOptions.importLoaders, 10) : rawOptions.importLoaders,
  318. esModule: typeof rawOptions.esModule === "undefined" ? true : rawOptions.esModule
  319. };
  320. }
  321. function shouldUseImportPlugin(options) {
  322. if (options.modules.exportOnlyLocals) {
  323. return false;
  324. }
  325. if (typeof options.import === "boolean") {
  326. return options.import;
  327. }
  328. return true;
  329. }
  330. function shouldUseURLPlugin(options) {
  331. if (options.modules.exportOnlyLocals) {
  332. return false;
  333. }
  334. if (typeof options.url === "boolean") {
  335. return options.url;
  336. }
  337. return true;
  338. }
  339. function shouldUseModulesPlugins(options) {
  340. return options.modules.compileType === "module";
  341. }
  342. function shouldUseIcssPlugin(options) {
  343. return options.icss === true || Boolean(options.modules);
  344. }
  345. function getModulesPlugins(options, loaderContext) {
  346. const {
  347. mode,
  348. getLocalIdent,
  349. localIdentName,
  350. localIdentContext,
  351. localIdentHashPrefix,
  352. localIdentRegExp
  353. } = options.modules;
  354. let plugins = [];
  355. try {
  356. plugins = [_postcssModulesValues.default, (0, _postcssModulesLocalByDefault.default)({
  357. mode
  358. }), (0, _postcssModulesExtractImports.default)(), (0, _postcssModulesScope.default)({
  359. generateScopedName(exportName) {
  360. let localIdent;
  361. if (typeof getLocalIdent !== "undefined") {
  362. localIdent = getLocalIdent(loaderContext, localIdentName, unescape(exportName), {
  363. context: localIdentContext,
  364. hashPrefix: localIdentHashPrefix,
  365. regExp: localIdentRegExp
  366. });
  367. } // A null/undefined value signals that we should invoke the default
  368. // getLocalIdent method.
  369. if (typeof localIdent === "undefined" || localIdent === null) {
  370. localIdent = defaultGetLocalIdent(loaderContext, localIdentName, unescape(exportName), {
  371. context: localIdentContext,
  372. hashPrefix: localIdentHashPrefix,
  373. regExp: localIdentRegExp
  374. });
  375. return escapeLocalIdent(localIdent).replace(/\\\[local\\]/gi, exportName);
  376. }
  377. return escapeLocalIdent(localIdent);
  378. },
  379. exportGlobals: options.modules.exportGlobals
  380. })];
  381. } catch (error) {
  382. loaderContext.emitError(error);
  383. }
  384. return plugins;
  385. }
  386. const IS_NATIVE_WIN32_PATH = /^[a-z]:[/\\]|^\\\\/i;
  387. const ABSOLUTE_SCHEME = /^[a-z0-9+\-.]+:/i;
  388. function getURLType(source) {
  389. if (source[0] === "/") {
  390. if (source[1] === "/") {
  391. return "scheme-relative";
  392. }
  393. return "path-absolute";
  394. }
  395. if (IS_NATIVE_WIN32_PATH.test(source)) {
  396. return "path-absolute";
  397. }
  398. return ABSOLUTE_SCHEME.test(source) ? "absolute" : "path-relative";
  399. }
  400. function normalizeSourceMap(map, resourcePath) {
  401. let newMap = map; // Some loader emit source map as string
  402. // Strip any JSON XSSI avoidance prefix from the string (as documented in the source maps specification), and then parse the string as JSON.
  403. if (typeof newMap === "string") {
  404. newMap = JSON.parse(newMap);
  405. }
  406. delete newMap.file;
  407. const {
  408. sourceRoot
  409. } = newMap;
  410. delete newMap.sourceRoot;
  411. if (newMap.sources) {
  412. // Source maps should use forward slash because it is URLs (https://github.com/mozilla/source-map/issues/91)
  413. // We should normalize path because previous loaders like `sass-loader` using backslash when generate source map
  414. newMap.sources = newMap.sources.map(source => {
  415. // Non-standard syntax from `postcss`
  416. if (source.indexOf("<") === 0) {
  417. return source;
  418. }
  419. const sourceType = getURLType(source); // Do no touch `scheme-relative` and `absolute` URLs
  420. if (sourceType === "path-relative" || sourceType === "path-absolute") {
  421. const absoluteSource = sourceType === "path-relative" && sourceRoot ? _path.default.resolve(sourceRoot, normalizePath(source)) : normalizePath(source);
  422. return _path.default.relative(_path.default.dirname(resourcePath), absoluteSource);
  423. }
  424. return source;
  425. });
  426. }
  427. return newMap;
  428. }
  429. function getPreRequester({
  430. loaders,
  431. loaderIndex
  432. }) {
  433. const cache = Object.create(null);
  434. return number => {
  435. if (cache[number]) {
  436. return cache[number];
  437. }
  438. if (number === false) {
  439. cache[number] = "";
  440. } else {
  441. const loadersRequest = loaders.slice(loaderIndex, loaderIndex + 1 + (typeof number !== "number" ? 0 : number)).map(x => x.request).join("!");
  442. cache[number] = `-!${loadersRequest}!`;
  443. }
  444. return cache[number];
  445. };
  446. }
  447. function getImportCode(imports, options) {
  448. let code = "";
  449. for (const item of imports) {
  450. const {
  451. importName,
  452. url,
  453. icss
  454. } = item;
  455. if (options.esModule) {
  456. if (icss && options.modules.namedExport) {
  457. code += `import ${options.modules.exportOnlyLocals ? "" : `${importName}, `}* as ${importName}_NAMED___ from ${url};\n`;
  458. } else {
  459. code += `import ${importName} from ${url};\n`;
  460. }
  461. } else {
  462. code += `var ${importName} = require(${url});\n`;
  463. }
  464. }
  465. return code ? `// Imports\n${code}` : "";
  466. }
  467. function normalizeSourceMapForRuntime(map, loaderContext) {
  468. const resultMap = map ? map.toJSON() : null;
  469. if (resultMap) {
  470. delete resultMap.file;
  471. resultMap.sourceRoot = "";
  472. resultMap.sources = resultMap.sources.map(source => {
  473. // Non-standard syntax from `postcss`
  474. if (source.indexOf("<") === 0) {
  475. return source;
  476. }
  477. const sourceType = getURLType(source);
  478. if (sourceType !== "path-relative") {
  479. return source;
  480. }
  481. const resourceDirname = _path.default.dirname(loaderContext.resourcePath);
  482. const absoluteSource = _path.default.resolve(resourceDirname, source);
  483. const contextifyPath = normalizePath(_path.default.relative(loaderContext.rootContext, absoluteSource));
  484. return `webpack://./${contextifyPath}`;
  485. });
  486. }
  487. return JSON.stringify(resultMap);
  488. }
  489. function getModuleCode(result, api, replacements, options, loaderContext) {
  490. if (options.modules.exportOnlyLocals === true) {
  491. return "";
  492. }
  493. const sourceMapValue = options.sourceMap ? `,${normalizeSourceMapForRuntime(result.map, loaderContext)}` : "";
  494. let code = JSON.stringify(result.css);
  495. let beforeCode = `var ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(${options.sourceMap ? "___CSS_LOADER_API_SOURCEMAP_IMPORT___" : "function(i){return i[1]}"});\n`;
  496. for (const item of api) {
  497. const {
  498. url,
  499. media,
  500. dedupe
  501. } = item;
  502. beforeCode += url ? `___CSS_LOADER_EXPORT___.push([module.id, ${JSON.stringify(`@import url(${url});`)}${media ? `, ${JSON.stringify(media)}` : ""}]);\n` : `___CSS_LOADER_EXPORT___.i(${item.importName}${media ? `, ${JSON.stringify(media)}` : dedupe ? ', ""' : ""}${dedupe ? ", true" : ""});\n`;
  503. }
  504. for (const item of replacements) {
  505. const {
  506. replacementName,
  507. importName,
  508. localName
  509. } = item;
  510. if (localName) {
  511. code = code.replace(new RegExp(replacementName, "g"), () => options.modules.namedExport ? `" + ${importName}_NAMED___[${JSON.stringify(getValidLocalName(localName, options.modules.exportLocalsConvention))}] + "` : `" + ${importName}.locals[${JSON.stringify(localName)}] + "`);
  512. } else {
  513. const {
  514. hash,
  515. needQuotes
  516. } = item;
  517. const getUrlOptions = [].concat(hash ? [`hash: ${JSON.stringify(hash)}`] : []).concat(needQuotes ? "needQuotes: true" : []);
  518. const preparedOptions = getUrlOptions.length > 0 ? `, { ${getUrlOptions.join(", ")} }` : "";
  519. beforeCode += `var ${replacementName} = ___CSS_LOADER_GET_URL_IMPORT___(${importName}${preparedOptions});\n`;
  520. code = code.replace(new RegExp(replacementName, "g"), () => `" + ${replacementName} + "`);
  521. }
  522. }
  523. return `${beforeCode}// Module\n___CSS_LOADER_EXPORT___.push([module.id, ${code}, ""${sourceMapValue}]);\n`;
  524. }
  525. function dashesCamelCase(str) {
  526. return str.replace(/-+(\w)/g, (match, firstLetter) => firstLetter.toUpperCase());
  527. }
  528. function getExportCode(exports, replacements, needToUseIcssPlugin, options) {
  529. let code = "// Exports\n";
  530. if (!needToUseIcssPlugin) {
  531. code += `${options.esModule ? "export default" : "module.exports ="} ___CSS_LOADER_EXPORT___;\n`;
  532. return code;
  533. }
  534. let localsCode = "";
  535. const addExportToLocalsCode = (name, value) => {
  536. if (options.modules.namedExport) {
  537. localsCode += `export var ${name} = ${JSON.stringify(value)};\n`;
  538. } else {
  539. if (localsCode) {
  540. localsCode += `,\n`;
  541. }
  542. localsCode += `\t${JSON.stringify(name)}: ${JSON.stringify(value)}`;
  543. }
  544. };
  545. for (const {
  546. name,
  547. value
  548. } of exports) {
  549. switch (options.modules.exportLocalsConvention) {
  550. case "camelCase":
  551. {
  552. addExportToLocalsCode(name, value);
  553. const modifiedName = camelCase(name);
  554. if (modifiedName !== name) {
  555. addExportToLocalsCode(modifiedName, value);
  556. }
  557. break;
  558. }
  559. case "camelCaseOnly":
  560. {
  561. addExportToLocalsCode(camelCase(name), value);
  562. break;
  563. }
  564. case "dashes":
  565. {
  566. addExportToLocalsCode(name, value);
  567. const modifiedName = dashesCamelCase(name);
  568. if (modifiedName !== name) {
  569. addExportToLocalsCode(modifiedName, value);
  570. }
  571. break;
  572. }
  573. case "dashesOnly":
  574. {
  575. addExportToLocalsCode(dashesCamelCase(name), value);
  576. break;
  577. }
  578. case "asIs":
  579. default:
  580. addExportToLocalsCode(name, value);
  581. break;
  582. }
  583. }
  584. for (const item of replacements) {
  585. const {
  586. replacementName,
  587. localName
  588. } = item;
  589. if (localName) {
  590. const {
  591. importName
  592. } = item;
  593. localsCode = localsCode.replace(new RegExp(replacementName, "g"), () => {
  594. if (options.modules.namedExport) {
  595. return `" + ${importName}_NAMED___[${JSON.stringify(getValidLocalName(localName, options.modules.exportLocalsConvention))}] + "`;
  596. } else if (options.modules.exportOnlyLocals) {
  597. return `" + ${importName}[${JSON.stringify(localName)}] + "`;
  598. }
  599. return `" + ${importName}.locals[${JSON.stringify(localName)}] + "`;
  600. });
  601. } else {
  602. localsCode = localsCode.replace(new RegExp(replacementName, "g"), () => `" + ${replacementName} + "`);
  603. }
  604. }
  605. if (options.modules.exportOnlyLocals) {
  606. code += options.modules.namedExport ? localsCode : `${options.esModule ? "export default" : "module.exports ="} {\n${localsCode}\n};\n`;
  607. return code;
  608. }
  609. code += options.modules.namedExport ? localsCode : `___CSS_LOADER_EXPORT___.locals = {${localsCode ? `\n${localsCode}\n` : ""}};\n`;
  610. code += `${options.esModule ? "export default" : "module.exports ="} ___CSS_LOADER_EXPORT___;\n`;
  611. return code;
  612. }
  613. async function resolveRequests(resolve, context, possibleRequests) {
  614. return resolve(context, possibleRequests[0]).then(result => result).catch(error => {
  615. const [, ...tailPossibleRequests] = possibleRequests;
  616. if (tailPossibleRequests.length === 0) {
  617. throw error;
  618. }
  619. return resolveRequests(resolve, context, tailPossibleRequests);
  620. });
  621. }
  622. function isUrlRequestable(url) {
  623. // Protocol-relative URLs
  624. if (/^\/\//.test(url)) {
  625. return false;
  626. } // `file:` protocol
  627. if (/^file:/i.test(url)) {
  628. return true;
  629. } // Absolute URLs
  630. if (/^[a-z][a-z0-9+.-]*:/i.test(url) && !NATIVE_WIN32_PATH.test(url)) {
  631. return false;
  632. } // `#` URLs
  633. if (/^#/.test(url)) {
  634. return false;
  635. }
  636. return true;
  637. }
  638. function sort(a, b) {
  639. return a.index - b.index;
  640. }
  641. function combineRequests(preRequest, url) {
  642. const idx = url.indexOf("!=!");
  643. return idx !== -1 ? url.slice(0, idx + 3) + preRequest + url.slice(idx + 3) : preRequest + url;
  644. }