|
|
- /*
- MIT License http://www.opensource.org/licenses/mit-license.php
- Author Tobias Koppers @sokra
- */
- var formatCodeFrame = require("babel-code-frame");
- var Tokenizer = require("css-selector-tokenizer");
- var postcss = require("postcss");
- var loaderUtils = require("loader-utils");
- var getLocalIdent = require("./getLocalIdent");
-
- var icssUtils = require('icss-utils');
- var localByDefault = require("postcss-modules-local-by-default");
- var extractImports = require("postcss-modules-extract-imports");
- var modulesScope = require("postcss-modules-scope");
- var modulesValues = require("postcss-modules-values");
- var valueParser = require('postcss-value-parser');
-
- var parserPlugin = postcss.plugin("css-loader-parser", function(options) {
- return function(css) {
- var imports = {};
- var exports = {};
- var importItems = [];
- var urlItems = [];
-
- function replaceImportsInString(str) {
- if(options.import) {
- var tokens = valueParser(str);
- tokens.walk(function (node) {
- if (node.type !== 'word') {
- return;
- }
- var token = node.value;
- var importIndex = imports["$" + token];
- if(typeof importIndex === "number") {
- node.value = "___CSS_LOADER_IMPORT___" + importIndex + "___";
- }
- })
- return tokens.toString();
- }
- return str;
- }
-
- if(options.import) {
- css.walkAtRules(/^import$/i, function(rule) {
- var values = Tokenizer.parseValues(rule.params);
- var url = values.nodes[0].nodes[0];
- if(url && url.type === "url") {
- url = url.url;
- } else if(url && url.type === "string") {
- url = url.value;
- } else throw rule.error("Unexpected format " + rule.params);
- if (!url.replace(/\s/g, '').length) {
- return;
- }
- values.nodes[0].nodes.shift();
- var mediaQuery = Tokenizer.stringifyValues(values);
-
- if(loaderUtils.isUrlRequest(url)) {
- url = loaderUtils.urlToRequest(url);
- }
-
- importItems.push({
- url: url,
- mediaQuery: mediaQuery
- });
- rule.remove();
- });
- }
-
- var icss = icssUtils.extractICSS(css);
- exports = icss.icssExports;
- Object.keys(icss.icssImports).forEach(function(key) {
- var url = loaderUtils.parseString(key);
- Object.keys(icss.icssImports[key]).forEach(function(prop) {
- imports["$" + prop] = importItems.length;
- importItems.push({
- url: url,
- export: icss.icssImports[key][prop]
- });
- })
- });
-
- Object.keys(exports).forEach(function(exportName) {
- exports[exportName] = replaceImportsInString(exports[exportName]);
- });
-
- function processNode(item) {
- switch (item.type) {
- case "value":
- item.nodes.forEach(processNode);
- break;
- case "nested-item":
- item.nodes.forEach(processNode);
- break;
- case "item":
- var importIndex = imports["$" + item.name];
- if (typeof importIndex === "number") {
- item.name = "___CSS_LOADER_IMPORT___" + importIndex + "___";
- }
- break;
- case "url":
- if (options.url && item.url.replace(/\s/g, '').length && !/^#/.test(item.url) && loaderUtils.isUrlRequest(item.url)) {
- // Strip quotes, they will be re-added if the module needs them
- item.stringType = "";
- delete item.innerSpacingBefore;
- delete item.innerSpacingAfter;
- var url = item.url;
- item.url = "___CSS_LOADER_URL___" + urlItems.length + "___";
- urlItems.push({
- url: url
- });
- }
- break;
- }
- }
-
- css.walkDecls(function(decl) {
- var values = Tokenizer.parseValues(decl.value);
- values.nodes.forEach(function(value) {
- value.nodes.forEach(processNode);
- });
- decl.value = Tokenizer.stringifyValues(values);
- });
- css.walkAtRules(function(atrule) {
- if(typeof atrule.params === "string") {
- atrule.params = replaceImportsInString(atrule.params);
- }
- });
-
- options.importItems = importItems;
- options.urlItems = urlItems;
- options.exports = exports;
- };
- });
-
- module.exports = function processCss(inputSource, inputMap, options, callback) {
- var query = options.query;
- var context = query.context;
- var localIdentName = query.localIdentName || "[hash:base64]";
- var localIdentRegExp = query.localIdentRegExp;
-
- var customGetLocalIdent = query.getLocalIdent || getLocalIdent;
-
- var parserOptions = {
- mode: options.mode,
- url: query.url !== false,
- import: query.import !== false,
- resolve: options.resolve
- };
-
- var pipeline = postcss([
- modulesValues,
- localByDefault({
- mode: options.mode,
- rewriteUrl: function(global, url) {
- if(parserOptions.url){
- url = url.trim();
-
- if(!url.replace(/\s/g, '').length || !loaderUtils.isUrlRequest(url)) {
- return url;
- }
- if(global) {
- return loaderUtils.urlToRequest(url);
- }
- }
- return url;
- }
- }),
- extractImports(),
- modulesScope({
- generateScopedName: function generateScopedName (exportName) {
- return customGetLocalIdent(options.loaderContext, localIdentName, exportName, {
- regExp: localIdentRegExp,
- hashPrefix: query.hashPrefix || "",
- context: context
- });
- }
- }),
- parserPlugin(parserOptions)
- ]);
-
- pipeline.process(inputSource, {
- // we need a prefix to avoid path rewriting of PostCSS
- from: "/css-loader!" + options.from,
- to: options.to,
- map: options.sourceMap ? {
- prev: inputMap,
- sourcesContent: true,
- inline: false,
- annotation: false
- } : null
- }).then(function(result) {
- callback(null, {
- source: result.css,
- map: result.map && result.map.toJSON(),
- exports: parserOptions.exports,
- importItems: parserOptions.importItems,
- importItemRegExpG: /___CSS_LOADER_IMPORT___([0-9]+)___/g,
- importItemRegExp: /___CSS_LOADER_IMPORT___([0-9]+)___/,
- urlItems: parserOptions.urlItems,
- urlItemRegExpG: /___CSS_LOADER_URL___([0-9]+)___/g,
- urlItemRegExp: /___CSS_LOADER_URL___([0-9]+)___/
- });
- }).catch(function(err) {
- if (err.name === 'CssSyntaxError') {
- var wrappedError = new CSSLoaderError(
- 'Syntax Error',
- err.reason,
- err.line != null && err.column != null
- ? {line: err.line, column: err.column}
- : null,
- err.input.source
- );
- callback(wrappedError);
- } else {
- callback(err);
- }
- });
- };
-
- function formatMessage(message, loc, source) {
- var formatted = message;
- if (loc) {
- formatted = formatted
- + ' (' + loc.line + ':' + loc.column + ')';
- }
- if (loc && source) {
- formatted = formatted
- + '\n\n' + formatCodeFrame(source, loc.line, loc.column) + '\n';
- }
- return formatted;
- }
-
- function CSSLoaderError(name, message, loc, source, error) {
- Error.call(this);
- Error.captureStackTrace(this, CSSLoaderError);
- this.name = name;
- this.error = error;
- this.message = formatMessage(message, loc, source);
- this.hideStack = true;
- }
-
- CSSLoaderError.prototype = Object.create(Error.prototype);
- CSSLoaderError.prototype.constructor = CSSLoaderError;
|