diff --git a/index.js b/index.js index cc1237da..1871a639 100755 --- a/index.js +++ b/index.js @@ -62,6 +62,7 @@ function AtImport(options) { state, [], [], + "", postcss ) diff --git a/lib/data-url.js b/lib/data-url.js index a59c5fb5..69c4ce94 100644 --- a/lib/data-url.js +++ b/lib/data-url.js @@ -1,14 +1,26 @@ "use strict" -const dataURLRegexp = /^data:text\/css;base64,/i +const anyDataURLRegexp = /^data:text\/css(?:;(base64|plain))?,/i +const base64DataURLRegexp = /^data:text\/css;base64,/i +const plainDataURLRegexp = /^data:text\/css;plain,/i function isValid(url) { - return dataURLRegexp.test(url) + return anyDataURLRegexp.test(url) } function contents(url) { - // "data:text/css;base64,".length === 21 - return Buffer.from(url.slice(21), "base64").toString() + if (base64DataURLRegexp.test(url)) { + // "data:text/css;base64,".length === 21 + return Buffer.from(url.slice(21), "base64").toString() + } + + if (plainDataURLRegexp.test(url)) { + // "data:text/css;plain,".length === 20 + return decodeURIComponent(url.slice(20)) + } + + // "data:text/css,".length === 14 + return decodeURIComponent(url.slice(14)) } module.exports = { diff --git a/lib/parse-statements.js b/lib/parse-statements.js index aa66e5bd..88a90ebc 100644 --- a/lib/parse-statements.js +++ b/lib/parse-statements.js @@ -20,16 +20,16 @@ function split(params, start) { return list } -module.exports = function parseStatements(result, styles) { +module.exports = function parseStatements(result, styles, from) { const statements = [] let nodes = [] styles.each(node => { let stmt if (node.type === "atrule") { - if (node.name === "import") stmt = parseImport(result, node) - else if (node.name === "media") stmt = parseMedia(result, node) - else if (node.name === "charset") stmt = parseCharset(result, node) + if (node.name === "import") stmt = parseImport(result, node, from) + else if (node.name === "media") stmt = parseMedia(result, node, from) + else if (node.name === "charset") stmt = parseCharset(result, node, from) } if (stmt) { @@ -39,6 +39,7 @@ module.exports = function parseStatements(result, styles) { nodes, media: [], layer: [], + from, }) nodes = [] } @@ -52,23 +53,25 @@ module.exports = function parseStatements(result, styles) { nodes, media: [], layer: [], + from, }) } return statements } -function parseMedia(result, atRule) { +function parseMedia(result, atRule, from) { const params = valueParser(atRule.params).nodes return { type: "media", node: atRule, media: split(params, 0), layer: [], + from, } } -function parseCharset(result, atRule) { +function parseCharset(result, atRule, from) { if (atRule.prev()) { return result.warn("@charset must precede all other statements", { node: atRule, @@ -79,10 +82,11 @@ function parseCharset(result, atRule) { node: atRule, media: [], layer: [], + from, } } -function parseImport(result, atRule) { +function parseImport(result, atRule, from) { let prev = atRule.prev() if (prev) { do { @@ -119,6 +123,7 @@ function parseImport(result, atRule) { media: [], layer: [], supports: [], + from, } for (let i = 0; i < params.length; i++) { diff --git a/lib/parse-styles.js b/lib/parse-styles.js index 50b74eba..d021dd4d 100644 --- a/lib/parse-styles.js +++ b/lib/parse-styles.js @@ -17,9 +17,10 @@ async function parseStyles( state, media, layer, + from, postcss ) { - const statements = parseStatements(result, styles) + const statements = parseStatements(result, styles, from) for (const stmt of statements) { stmt.media = joinMedia(media, stmt.media || []) @@ -90,6 +91,11 @@ async function resolveImportId(result, stmt, options, state, postcss) { postcss ) + return + } else if (dataURL.isValid(stmt.from)) { + // Data urls can't be used a base url to resolve imports. + // When the parent statement has a data url + // and the current statement doesn't have a data url we ignore the statement. return } @@ -201,7 +207,16 @@ async function loadImportContent( } // recursion: import @import from imported file - return parseStyles(result, styles, options, state, media, layer, postcss) + return parseStyles( + result, + styles, + options, + state, + media, + layer, + filename, + postcss + ) } module.exports = parseStyles diff --git a/test/fixtures/data-url.css b/test/fixtures/data-url.css index 6f1276ef..4b2b4b37 100644 --- a/test/fixtures/data-url.css +++ b/test/fixtures/data-url.css @@ -4,3 +4,7 @@ /* Mixed imports: */ @import url(data:text/css;base64,QGltcG9ydCB1cmwoZm9vLmNzcyk7CgpwIHsKICBjb2xvcjogYmx1ZTsKfQo=); @import url(data-url.css); + +/* url encoded: */ +@import url(data:text/css;plain,bar%20%7B%20color%3A%20green%20%7D); +@import url(data:text/css,bar%20%7B%20color%3A%20pink%20%7D); diff --git a/test/fixtures/data-url.expected.css b/test/fixtures/data-url.expected.css index 207253e4..af160fc5 100644 --- a/test/fixtures/data-url.expected.css +++ b/test/fixtures/data-url.expected.css @@ -1,24 +1,6 @@ -p { color: green; } +@import url(foo.css);p { color: green; }p { color: blue; }@media (min-width: 320px){@layer foo{ +p { color: green; } } }@media (min-width: 320px){@layer foo{ -p { color: blue; } - -@media (min-width: 320px) { - - @layer foo { -p { color: green; } } } - -@media (min-width: 320px) { - - @layer foo { - -p { color: blue; } } } - -/* Mixed imports: */ - -foo{} - -p { +p { color: blue; } } }/* Mixed imports: */p { color: blue; -} - -p { color: pink; } +}p { color: pink; }/* url encoded: */bar { color: green }bar { color: pink }