Skip to content

Commit

Permalink
fix: handling urls in @import (#1016)
Browse files Browse the repository at this point in the history
  • Loading branch information
evilebottnawi committed Dec 11, 2019
1 parent 30a9269 commit c80c39f
Show file tree
Hide file tree
Showing 7 changed files with 216 additions and 61 deletions.
36 changes: 23 additions & 13 deletions src/plugins/postcss-import-parser.js
@@ -1,22 +1,24 @@
import postcss from 'postcss';
import valueParser from 'postcss-value-parser';
import { isUrlRequest, urlToRequest } from 'loader-utils';
import { isUrlRequest } from 'loader-utils';

const pluginName = 'postcss-import-parser';
import { normalizeUrl } from '../utils';

function getArg(nodes) {
return nodes.length !== 0 && nodes[0].type === 'string'
? nodes[0].value
: valueParser.stringify(nodes);
}
const pluginName = 'postcss-import-parser';

function getUrl(node) {
function getParsedValue(node) {
if (node.type === 'function' && node.value.toLowerCase() === 'url') {
return getArg(node.nodes);
const { nodes } = node;
const isStringValue = nodes.length !== 0 && nodes[0].type === 'string';
const url = isStringValue ? nodes[0].value : valueParser.stringify(nodes);

return { url, isStringValue };
}

if (node.type === 'string') {
return node.value;
const url = node.value;

return { url, isStringValue: true };
}

return null;
Expand All @@ -29,14 +31,22 @@ function parseImport(params) {
return null;
}

let url = getUrl(nodes[0]);
const value = getParsedValue(nodes[0]);

if (!url || url.trim().length === 0) {
if (!value) {
return null;
}

let { url } = value;

if (url.trim().length === 0) {
return null;
}

if (isUrlRequest(url)) {
url = urlToRequest(url);
const { isStringValue } = value;

url = normalizeUrl(url, isStringValue);
}

return {
Expand Down
49 changes: 22 additions & 27 deletions src/plugins/postcss-url-parser.js
@@ -1,8 +1,7 @@
import postcss from 'postcss';
import valueParser from 'postcss-value-parser';
import { urlToRequest } from 'loader-utils';

import { unescape } from '../utils';
import { normalizeUrl } from '../utils';

const pluginName = 'postcss-url-parser';

Expand All @@ -21,13 +20,11 @@ function walkUrls(parsed, callback) {
}

if (isUrlFunc.test(node.value)) {
const isStringNode =
node.nodes.length !== 0 && node.nodes[0].type === 'string';
const url = isStringNode
? node.nodes[0].value
: valueParser.stringify(node.nodes);
const { nodes } = node;
const isStringValue = nodes.length !== 0 && nodes[0].type === 'string';
const url = isStringValue ? nodes[0].value : valueParser.stringify(nodes);

callback(getNodeFromUrlFunc(node), url, false, isStringNode);
callback(getNodeFromUrlFunc(node), url, false, isStringValue);

// Do not traverse inside `url`
// eslint-disable-next-line consistent-return
Expand All @@ -36,18 +33,22 @@ function walkUrls(parsed, callback) {

if (isImageSetFunc.test(node.value)) {
node.nodes.forEach((nNode) => {
if (nNode.type === 'function' && isUrlFunc.test(nNode.value)) {
const isStringNode =
nNode.nodes.length !== 0 && nNode.nodes[0].type === 'string';
const url = isStringNode
? nNode.nodes[0].value
: valueParser.stringify(nNode.nodes);

callback(getNodeFromUrlFunc(nNode), url, false, isStringNode);
const { type, value } = nNode;

if (type === 'function' && isUrlFunc.test(value)) {
const { nodes } = nNode;

const isStringValue =
nodes.length !== 0 && nodes[0].type === 'string';
const url = isStringValue
? nodes[0].value
: valueParser.stringify(nodes);

callback(getNodeFromUrlFunc(nNode), url, false, isStringValue);
}

if (nNode.type === 'string') {
callback(nNode, nNode.value, true, true);
if (type === 'string') {
callback(nNode, value, true, true);
}
});

Expand All @@ -66,7 +67,7 @@ function getUrlsFromValue(value, result, filter, decl) {
const parsed = valueParser(value);
const urls = [];

walkUrls(parsed, (node, url, needQuotes, isStringNode) => {
walkUrls(parsed, (node, url, needQuotes, isStringValue) => {
if (url.trim().replace(/\\[\r\n]/g, '').length === 0) {
result.warn(`Unable to find uri in '${decl ? decl.toString() : value}'`, {
node: decl,
Expand All @@ -80,19 +81,13 @@ function getUrlsFromValue(value, result, filter, decl) {
}

const splittedUrl = url.split(/(\?)?#/);
let [normalizedUrl] = splittedUrl;
const [, singleQuery, hashValue] = splittedUrl;
const [urlWithoutHash, singleQuery, hashValue] = splittedUrl;
const hash =
singleQuery || hashValue
? `${singleQuery ? '?' : ''}${hashValue ? `#${hashValue}` : ''}`
: '';

// See https://drafts.csswg.org/css-values-4/#strings
if (isStringNode && /\\[\n]/.test(normalizedUrl)) {
normalizedUrl = normalizedUrl.replace(/\\[\n]/g, '');
}

normalizedUrl = urlToRequest(decodeURIComponent(unescape(normalizedUrl)));
const normalizedUrl = normalizeUrl(urlWithoutHash, isStringValue);

urls.push({ node, url: normalizedUrl, hash, needQuotes });
});
Expand Down
52 changes: 33 additions & 19 deletions src/utils.js
Expand Up @@ -4,7 +4,11 @@
*/
import path from 'path';

import loaderUtils, { isUrlRequest, stringifyRequest } from 'loader-utils';
import loaderUtils, {
isUrlRequest,
stringifyRequest,
urlToRequest,
} from 'loader-utils';
import normalizePath from 'normalize-path';
import cssesc from 'cssesc';
import modulesValues from 'postcss-modules-values';
Expand All @@ -13,23 +17,6 @@ import extractImports from 'postcss-modules-extract-imports';
import modulesScope from 'postcss-modules-scope';
import camelCase from 'camelcase';

function getImportPrefix(loaderContext, importLoaders) {
if (importLoaders === false) {
return '';
}

const numberImportedLoaders = parseInt(importLoaders, 10) || 0;
const loadersRequest = loaderContext.loaders
.slice(
loaderContext.loaderIndex,
loaderContext.loaderIndex + 1 + numberImportedLoaders
)
.map((x) => x.request)
.join('!');

return `-!${loadersRequest}!`;
}

const whitespace = '[\\x20\\t\\r\\n\\f]';
const unescapeRegExp = new RegExp(
`\\\\([\\da-f]{1,6}${whitespace}?|(${whitespace})|.)`,
Expand Down Expand Up @@ -90,6 +77,16 @@ function getLocalIdent(loaderContext, localIdentName, localName, options) {
).replace(/\\\[local\\\]/gi, localName);
}

function normalizeUrl(url, isStringValue) {
let normalizedUrl = url;

if (isStringValue && /\\[\n]/.test(normalizedUrl)) {
normalizedUrl = normalizedUrl.replace(/\\[\n]/g, '');
}

return urlToRequest(decodeURIComponent(unescape(normalizedUrl)));
}

function getFilter(filter, resourcePath, defaultFilter = null) {
return (item) => {
if (defaultFilter && !defaultFilter(item)) {
Expand Down Expand Up @@ -186,6 +183,23 @@ function normalizeSourceMap(map) {
return newMap;
}

function getImportPrefix(loaderContext, importLoaders) {
if (importLoaders === false) {
return '';
}

const numberImportedLoaders = parseInt(importLoaders, 10) || 0;
const loadersRequest = loaderContext.loaders
.slice(
loaderContext.loaderIndex,
loaderContext.loaderIndex + 1 + numberImportedLoaders
)
.map((x) => x.request)
.join('!');

return `-!${loadersRequest}!`;
}

function getImportCode(
loaderContext,
imports,
Expand Down Expand Up @@ -395,7 +409,7 @@ function getExportCode(
}

export {
unescape,
normalizeUrl,
getFilter,
getModulesPlugins,
normalizeSourceMap,
Expand Down

0 comments on commit c80c39f

Please sign in to comment.