From 281dda9895f74034e776fbfd82f713923fb47b0f Mon Sep 17 00:00:00 2001 From: Karl Swedberg Date: Tue, 14 Apr 2015 15:33:12 -0400 Subject: [PATCH] Add glob option (Boolean, with default false). Closes gh-8 --- README.md | 7 ++++ index.js | 46 +++++++++++++++++++++++++- package.json | 1 + test/fixtures/glob.css | 1 + test/fixtures/glob.expected.css | 2 ++ test/fixtures/imports/glob-missing.css | 2 ++ test/index.js | 20 ++++++++++- 7 files changed, 77 insertions(+), 2 deletions(-) create mode 100644 test/fixtures/glob.css create mode 100644 test/fixtures/glob.expected.css create mode 100644 test/fixtures/imports/glob-missing.css diff --git a/README.md b/README.md index 882f18e4..82b006ae 100755 --- a/README.md +++ b/README.md @@ -114,6 +114,13 @@ Default: `null` Function called after the import process. Take one argument (array of imported files). +#### `glob` + +Type: `Boolean` +Default: `false` + +Set to `true` if you want @import rules to parse glob patterns. + #### Example with some options ```js diff --git a/index.js b/index.js index c551e3a3..5d7f17a5 100755 --- a/index.js +++ b/index.js @@ -11,6 +11,7 @@ var resolve = require("resolve") var postcss = require("postcss") var helpers = require("postcss-message-helpers") var hash = require("string-hash") +var glob = require("glob") /** * Constants @@ -81,7 +82,14 @@ function AtImport(options) { */ function parseStyles(styles, options, cb, importedFiles, ignoredAtRules, media, hashFiles) { var imports = [] - styles.eachAtRule("import", function checkAtRule(atRule) {imports.push(atRule)}) + styles.eachAtRule("import", function checkAtRule(atRule) { + if (options.glob && glob.hasMagic(atRule.params)) { + imports = parseGlob(atRule, options, imports) + } + else { + imports.push(atRule) + } + }) imports.forEach(function(atRule) { helpers.try(function transformAtImport() { readAtImport(atRule, options, cb, importedFiles, ignoredAtRules, media, hashFiles) @@ -89,6 +97,42 @@ function parseStyles(styles, options, cb, importedFiles, ignoredAtRules, media, }) } +/** + * parse glob patterns (for relative paths only) + * + * @param {Object} atRule + * @param {Object} options + * @param {Array} imports + */ +function parseGlob(atRule, options, imports) { + var globPattern = atRule.params.replace(/"/g, "") + var files = [] + var dir = options.source && options.source.input && options.source.input.file ? + path.dirname(path.resolve(options.root, options.source.input.file)) : + options.root + options.path.forEach(function(p) { + p = path.resolve(dir, p) + var globbed = glob.sync(path.join(p, globPattern)) + globbed.forEach(function(file) { + file = path.relative(p, file) + files.push(file) + }); + }); + + files.forEach(function(file) { + var deglobbedAtRule = atRule.clone({ + params: "\"" + file + "\"" + }) + if (deglobbedAtRule.source && deglobbedAtRule.source.input && deglobbedAtRule.source.input.css) { + deglobbedAtRule.source.input.css = atRule.source.input.css.replace(globPattern, file) + } + atRule.parent.insertBefore(atRule, deglobbedAtRule) + imports.push(deglobbedAtRule) + }); + atRule.removeSelf() + return imports; +} + /** * put back at the top ignored url (absolute url) * diff --git a/package.json b/package.json index 7a9370d3..6da0d739 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ ], "dependencies": { "clone": "^0.1.17", + "glob": "^5.0.1", "postcss": "^4.0.2", "postcss-message-helpers": "^2.0.0", "resolve": "^1.0.0", diff --git a/test/fixtures/glob.css b/test/fixtures/glob.css new file mode 100644 index 00000000..019ab757 --- /dev/null +++ b/test/fixtures/glob.css @@ -0,0 +1 @@ +@import "./foobar*.css"; diff --git a/test/fixtures/glob.expected.css b/test/fixtures/glob.expected.css new file mode 100644 index 00000000..3c6dd4b1 --- /dev/null +++ b/test/fixtures/glob.expected.css @@ -0,0 +1,2 @@ +foobar{} +foobarbaz{} diff --git a/test/fixtures/imports/glob-missing.css b/test/fixtures/imports/glob-missing.css new file mode 100644 index 00000000..a9a40a79 --- /dev/null +++ b/test/fixtures/imports/glob-missing.css @@ -0,0 +1,2 @@ +@import "./missing*.css"; +@import "foobar.css"; diff --git a/test/index.js b/test/index.js index b03b4036..e95fc3db 100755 --- a/test/index.js +++ b/test/index.js @@ -36,6 +36,11 @@ test("@import", function(t) { compareFixtures(t, "ignore", "should ignore & adjust external import") + compareFixtures(t, "glob", "should handle a glob pattern", { + path: importsDir, + glob: true + }) + compareFixtures(t, "recursive", "should import stylsheets recursively") compareFixtures(t, "relative", "should import stylsheets relatively") @@ -75,7 +80,6 @@ test("@import", function(t) { t.end() }) - test("@import error output", function(t) { var file = importsDir + "/import-missing.css" t.throws( @@ -92,6 +96,20 @@ test("@import error output", function(t) { t.end() }) +test("@import glob pattern matches no files", function(t) { + var file = importsDir + "/glob-missing.css" + t.equal( + postcss() + .use(atImport({glob: true})) + .process(fs.readFileSync(file), {from: file}) + .css.trim(), + "foobar{}", + "should fail silently, skipping the globbed import, if no files found" + ) + + t.end() +}) + test("@import sourcemap", function(t) { t.equal( postcss()