diff --git a/CHANGELOG.md b/CHANGELOG.md index b684e9cc..774f2a9f 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +# 5.0.2 - 2015-02-14 + +- Fixed: indentation and code style are now preserved ([#20](https://github.com/postcss/postcss-import/issues/20)) + # 5.0.1 - 2015-02-13 - Fixed: breaking bug with remote stylesheets ([#21](https://github.com/postcss/postcss-import/issues/21) & [#22](https://github.com/postcss/postcss-import/issues/22)) diff --git a/index.js b/index.js index f2b1f83b..f076c36d 100755 --- a/index.js +++ b/index.js @@ -77,11 +77,9 @@ function AtImport(options) { * @param {Object} options */ function parseStyles(styles, options, cb, importedFiles, ignoredAtRules, media) { - styles.eachAtRule(function checkAtRule(atRule) { - if (atRule.name !== "import") { - return - } - + var imports = [] + styles.eachAtRule("import", function checkAtRule(atRule) {imports.push(atRule)}) + imports.forEach(function(atRule) { helpers.try(function transformAtImport() { readAtImport(atRule, options, cb, importedFiles, ignoredAtRules, media) }, atRule.source) @@ -102,14 +100,16 @@ function addIgnoredAtRulesOnTop(styles, ignoredAtRules) { while (i--) { var ignoredAtRule = ignoredAtRules[i][0] ignoredAtRule.params = ignoredAtRules[i][1].fullUri + (ignoredAtRules[i][1].media ? " " + ignoredAtRules[i][1].media : "") - ignoredAtRule.before = "\n" - ignoredAtRule.after = "" + + // keep ast ref + ignoredAtRule.parent = styles // don't use prepend() to avoid weird behavior of normalize() styles.nodes.unshift(ignoredAtRule) } - if (first && first.before !== undefined) { + // separate remote import a little with others rules if no newlines already + if (first && first.before.indexOf("\n") === -1) { first.before = "\n\n" + first.before } } @@ -126,33 +126,38 @@ function readAtImport(atRule, options, cb, importedFiles, ignoredAtRules, media) // @todo extract what can be interesting from this one var parsedAtImport = parseImport(atRule.params, atRule.source) - - // adjust media according to current scope media = parsedAtImport.media ? (media ? media + " and " : "") + parsedAtImport.media : (media ? media : null) // just update protocol base uri (protocol://url) or protocol-relative (//url) if media needed if (parsedAtImport.uri.match(/^(?:[a-z]+:)?\/\//i)) { parsedAtImport.media = media - var atRuleCloned = atRule.clone() - atRuleCloned.parent = atRule.parent.clone() - ignoredAtRules.push([atRuleCloned, parsedAtImport]) - atRule.removeSelf() + + // save + ignoredAtRules.push([atRule, parsedAtImport]) + + // detach + detach(atRule) + return } addInputToPath(options) var resolvedFilename = resolveFilename(parsedAtImport.uri, options.root, options.path, atRule.source) + // skip files already imported at the same scope if (importedFiles[resolvedFilename] && importedFiles[resolvedFilename][media]) { - atRule.removeSelf() + detach(atRule) return } + + // save imported files to skip them next time if (!importedFiles[resolvedFilename]) { importedFiles[resolvedFilename] = {} } importedFiles[resolvedFilename][media] = true + readImportedContent(atRule, parsedAtImport, clone(options), resolvedFilename, cb, importedFiles, ignoredAtRules) } @@ -179,7 +184,7 @@ function readImportedContent(atRule, parsedAtImport, options, resolvedFilename, if (fileContent.trim() === "") { console.log(helpers.message(resolvedFilename + " is empty", atRule.source)) - atRule.removeSelf() + detach(atRule) return } @@ -199,29 +204,41 @@ function readImportedContent(atRule, parsedAtImport, options, resolvedFilename, * @param {Object} newStyles */ function insertRules(atRule, parsedAtImport, newStyles) { + var newNodes = newStyles.nodes + // wrap rules if the @import have a media query if (parsedAtImport.media && parsedAtImport.media.length) { + // better output + if (newStyles.nodes && newStyles.nodes.length) { + newStyles.nodes[0].before = newStyles.nodes[0].before || "\n" + // newStyles.nodes[newStyles.nodes.length - 1].after = (newStyles.nodes[newStyles.nodes.length - 1].after || "") + "\n" + } + // wrap new rules with media (media query) var wrapper = postcss.atRule({ name: "media", params: parsedAtImport.media }) - wrapper.append(newStyles) - newStyles = wrapper - // better output - newStyles.before = atRule.before - if (newStyles.nodes && newStyles.nodes.length) { - newStyles.nodes[0].before = newStyles.nodes[0].before || "\n" - } - newStyles.after = atRule.after || "\n" + // keep ast clean + newNodes.forEach(function(node) {node.parent = wrapper}) + wrapper.source = atRule.source + + // copy code style + wrapper.before = atRule.before + wrapper.after = atRule.after + + // move nodes + wrapper.nodes = newNodes + newNodes = [wrapper] } - else if (newStyles.nodes && newStyles.nodes.length) { - newStyles.nodes[0].before = atRule.before + else if (newNodes && newNodes.length) { + newNodes[0].before = atRule.before } - - atRule.parent.insertBefore(atRule, newStyles) - atRule.removeSelf() + // replace atRule by imported nodes + var nodes = atRule.parent.nodes + nodes.splice.apply(nodes, [nodes.indexOf(atRule), 0].concat(newNodes)) + detach(atRule) } /** @@ -317,3 +334,7 @@ function addInputToPath(options) { } } } + +function detach(node) { + node.parent.nodes.splice(node.parent.nodes.indexOf(node), 1) +} diff --git a/package.json b/package.json index e762e3da..86cace3d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "postcss-import", - "version": "5.0.1", + "version": "5.0.2", "description": "PostCSS plugin to import CSS files", "keywords": [ "css", diff --git a/test/fixtures/cwd.expected.css b/test/fixtures/cwd.expected.css index db5b6761..ab23ff91 100755 --- a/test/fixtures/cwd.expected.css +++ b/test/fixtures/cwd.expected.css @@ -1,3 +1,4 @@ -foo {} -bar {} -foo.recursive {} +foo{} +bar{} + +foo.recursive{} \ No newline at end of file diff --git a/test/fixtures/ignore.expected.css b/test/fixtures/ignore.expected.css index 1c7013f5..033f48b3 100644 --- a/test/fixtures/ignore.expected.css +++ b/test/fixtures/ignore.expected.css @@ -14,7 +14,7 @@ @import url('//css'); @import url(//css); -@media (min-width: 25em){ +@media (min-width: 25em) { ignore{} } diff --git a/test/fixtures/imports/qux.css b/test/fixtures/imports/qux.css index 76053408..f09fa7ce 100755 --- a/test/fixtures/imports/qux.css +++ b/test/fixtures/imports/qux.css @@ -1,3 +1,3 @@ quux{ - not: "relative/qux" + not: "relative/qux" } diff --git a/test/fixtures/imports/relative/baz.css b/test/fixtures/imports/relative/baz.css index 34c6382b..b82a6aa0 100755 --- a/test/fixtures/imports/relative/baz.css +++ b/test/fixtures/imports/relative/baz.css @@ -1,5 +1,5 @@ @import "qux.css"; baz{ - is: relative + is: relative } \ No newline at end of file diff --git a/test/fixtures/imports/relative/qux.css b/test/fixtures/imports/relative/qux.css index e7a1fc09..6697c874 100755 --- a/test/fixtures/imports/relative/qux.css +++ b/test/fixtures/imports/relative/qux.css @@ -1,3 +1,3 @@ qux{ - is: relative + is: relative } diff --git a/test/fixtures/modules.expected.css b/test/fixtures/modules.expected.css index 4fa34101..fc2287b4 100644 --- a/test/fixtures/modules.expected.css +++ b/test/fixtures/modules.expected.css @@ -3,7 +3,7 @@ .nested{} .byHand{} .dep{} -@media screen{ +@media screen { .dep{} } @@ -12,7 +12,7 @@ .web-nested{} .web-byHand{} .web-dep{} -@media screen{ +@media screen { .web-dep{} } diff --git a/test/fixtures/recursive.expected.css b/test/fixtures/recursive.expected.css index b51d129b..19ac12d1 100755 --- a/test/fixtures/recursive.expected.css +++ b/test/fixtures/recursive.expected.css @@ -1,5 +1,6 @@ -@media (min-width: 25em){ +@media (min-width: 25em) { bar{} + foo.recursive{} } diff --git a/test/fixtures/relative.expected.css b/test/fixtures/relative.expected.css index bc8edc92..f7b63ea3 100755 --- a/test/fixtures/relative.expected.css +++ b/test/fixtures/relative.expected.css @@ -1,10 +1,11 @@ qux{ is: relative } + baz{ - is: relative + is: relative } quux{ - not: "relative/qux" + not: "relative/qux" } content{} \ No newline at end of file diff --git a/test/fixtures/simple.expected.css b/test/fixtures/simple.expected.css index f67047c3..0fac7973 100755 --- a/test/fixtures/simple.expected.css +++ b/test/fixtures/simple.expected.css @@ -1,21 +1,21 @@ foo{} -@media screen{ +@media screen { foo{} } bar{} -@media screen{ +@media screen { bar{} } baz{} -@media screen{ +@media screen { baz{} } foobar{} -@media screen and (min-width: 25em){ +@media screen and (min-width: 25em) { foobar{} } foobarbaz{} -@media print, screen and (min-width: 25em){ +@media print, screen and (min-width: 25em) { foobarbaz{} } diff --git a/test/fixtures/transform.expected.css b/test/fixtures/transform.expected.css index 3eb8de04..4e5f4602 100755 --- a/test/fixtures/transform.expected.css +++ b/test/fixtures/transform.expected.css @@ -1,10 +1,10 @@ -foo{ -styl: true +foo { + styl: true; } -@media (min-width: 25em){ -foo{ -styl: true +@media (min-width: 25em) { +foo { + styl: true; } } -content{} +content{} \ No newline at end of file diff --git a/test/index.js b/test/index.js index b74c3085..25468985 100755 --- a/test/index.js +++ b/test/index.js @@ -63,13 +63,12 @@ test("@import", function(t) { "should not fail with only one absolute import" ) - base = "@import url('http://');\n@import 'test/fixtures/imports/foo.css';"; t.equal( postcss() .use(atImport()) - .process(base) + .process("@import url('http://');\n@import 'test/fixtures/imports/foo.css';") .css.trim(), - "@import url('http://');\nfoo {}", + "@import url('http://');\nfoo{}", "should not fail with absolute and local import" ) @@ -130,13 +129,12 @@ test("@import callback", function(t) { }) test("import relative files using path option only", function(t) { - var base = " content{}" t.equal( postcss() .use(atImport({path: "test/fixtures/imports/relative"})) - .process(read("fixtures/imports/relative/import") + base) + .process(read("fixtures/imports/relative/import")) .css.trim(), - read("fixtures/imports/bar") + base + read("fixtures/imports/bar") ) t.end() })