diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ce29f94..b3840035 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ +# 3.1.0 - 2014-11-24 + +- Add ability to consume local modules (fix [#12](https://github.com/postcss/postcss-import/issues/12)) + # 3.0.0 - 2014-11-21 -- Add ability to consume npm packages ([ref](https://github.com/postcss/postcss-import/issues/7)). +- Add ability to consume node modules ([ref](https://github.com/postcss/postcss-import/issues/7)). This means you don't have to add `node_modules` in the path anymore (or using `@import "../node_modules/..."`). Also, `index.css` can be ommited. diff --git a/index.js b/index.js index 5584bf0b..c8a0c3bc 100755 --- a/index.js +++ b/index.js @@ -7,9 +7,9 @@ var fs = require("fs") var path = require("path") var clone = require("clone") -var findFile = require("find-file") var resolve = require("resolve") var postcss = require("postcss") +var helpers = require("postcss-message-helpers") /** * Expose the plugin. @@ -44,7 +44,7 @@ function AtImport(options) { options.path.push(process.cwd()) } - parseStyles(styles, options) + parseStyles(styles, options, insertRules) } } @@ -54,7 +54,7 @@ function AtImport(options) { * @param {Object} styles * @param {Object} options */ -function parseStyles(styles, options, importedFiles, ignoredAtRules, media) { +function parseStyles(styles, options, cb, importedFiles, ignoredAtRules, media) { var isRoot = ignoredAtRules === undefined importedFiles = importedFiles || {} ignoredAtRules = ignoredAtRules || [] @@ -63,7 +63,9 @@ function parseStyles(styles, options, importedFiles, ignoredAtRules, media) { return } - readAtImport(atRule, options, importedFiles, ignoredAtRules, media) + helpers.try(function transformAtImport() { + readAtImport(atRule, options, cb, importedFiles, ignoredAtRules, media) + }, atRule.source) }) if (isRoot) { @@ -102,7 +104,7 @@ function addIgnoredAtRulesOnTop(styles, ignoredAtRules) { * @param {Object} atRule postcss atRule * @param {Object} options */ -function readAtImport(atRule, options, importedFiles, ignoredAtRules, media) { +function readAtImport(atRule, options, cb, importedFiles, ignoredAtRules, media) { // parse-import module parse entire line // @todo extract what can be interesting from this one var parsedAtImport = parseImport(atRule.params, atRule.source) @@ -130,7 +132,7 @@ function readAtImport(atRule, options, importedFiles, ignoredAtRules, media) { } importedFiles[resolvedFilename][media] = true - insertAtImportContent(atRule, parsedAtImport, clone(options), resolvedFilename, importedFiles, ignoredAtRules) + readImportedContent(atRule, parsedAtImport, clone(options), resolvedFilename, cb, importedFiles, ignoredAtRules) } /** @@ -140,10 +142,9 @@ function readAtImport(atRule, options, importedFiles, ignoredAtRules, media) { * @param {Object} parsedAtImport * @param {Object} options * @param {String} resolvedFilename - * @param {Array} importedFiles - * @param {Array} ignoredAtRules + * @param {Function} cb */ -function insertAtImportContent(atRule, parsedAtImport, options, resolvedFilename, importedFiles, ignoredAtRules) { +function readImportedContent(atRule, parsedAtImport, options, resolvedFilename, cb, importedFiles, ignoredAtRules) { // add directory containing the @imported file in the paths // to allow local import from this file var dirname = path.dirname(resolvedFilename) @@ -156,7 +157,7 @@ function insertAtImportContent(atRule, parsedAtImport, options, resolvedFilename var fileContent = readFile(resolvedFilename, options.encoding, options.transform || function(value) { return value }) if (fileContent.trim() === "") { - console.warn(gnuMessage(resolvedFilename + " is empty", atRule.source)) + console.warn(helpers.message(resolvedFilename + " is empty", atRule.source)) atRule.removeSelf() return } @@ -164,9 +165,9 @@ function insertAtImportContent(atRule, parsedAtImport, options, resolvedFilename var newStyles = postcss.parse(fileContent, options) // recursion: import @import from imported file - parseStyles(newStyles, options, importedFiles, ignoredAtRules, parsedAtImport.media) + parseStyles(newStyles, options, cb, importedFiles, ignoredAtRules, parsedAtImport.media) - insertRules(atRule, parsedAtImport, newStyles) + cb(atRule, parsedAtImport, newStyles, resolvedFilename) } /** @@ -209,7 +210,7 @@ function parseImport(str, source) { var regex = /((?:url\s?\()?(?:'|")?([^)'"]+)(?:'|")?\)?)(?:(?:\s)(.*))?/gi var matches = regex.exec(str) if (matches === null) { - throw new Error(gnuMessage("Unable to find uri in '" + str + "'", source)) + throw new Error("Unable to find uri in '" + str + "'", source) } return { @@ -225,20 +226,13 @@ function parseImport(str, source) { * @param {String} name */ function resolveFilename(name, paths, source) { - var file = findFile(name, {path: paths, global: false}) - if (file) { - // if (file.length > 1) { - // console.warn(gnuMessage("Warning: multiples files found for `" + name + "`: " + file, source)) - // } - return file[0] - } - var root = paths[paths.length - 1] var dir = source && source.file ? path.dirname(path.resolve(root, source.file)) : root try { - file = resolve.sync(name, { + var file = resolve.sync(name, { basedir: dir, + moduleDirectory: ["node_modules"].concat(paths), extensions: [".css"], packageFilter: function processPackage(pkg) { pkg.main = pkg.style || "index.css" @@ -250,14 +244,11 @@ function resolveFilename(name, paths, source) { } catch (e) { throw new Error( - // GNU style message - gnuMessage( - "Failed to find '" + name + "'" + - "\n in [ " + - "\n " + paths.join(",\n ") + - "\n ]", - source - ) + "Failed to find '" + name + "'" + + "\n in [ " + + "\n " + paths.join(",\n ") + + "\n ]", + source ) } } @@ -284,13 +275,3 @@ function addInputToPath(options) { } } } - -/** - * return GNU style message - * - * @param {String} message - * @param {Object} source - */ -function gnuMessage(message, source) { - return (source ? (source.file ? source.file : "") + ":" + source.start.line + ":" + source.start.column + " " : "") + message -} diff --git a/package.json b/package.json index 96a97131..d561de05 100644 --- a/package.json +++ b/package.json @@ -23,8 +23,8 @@ ], "dependencies": { "clone": "^0.1.17", - "find-file": "^0.1.4", "postcss": "^3.0.0", + "postcss-message-helpers": "^1.1.0", "resolve": "^1.0.0" }, "devDependencies": { diff --git a/test/fixtures/imports/local-module/main.css b/test/fixtures/imports/local-module/main.css new file mode 100644 index 00000000..68c41250 --- /dev/null +++ b/test/fixtures/imports/local-module/main.css @@ -0,0 +1 @@ +.local-module{} diff --git a/test/fixtures/imports/local-module/package.json b/test/fixtures/imports/local-module/package.json new file mode 100644 index 00000000..ae14fa6b --- /dev/null +++ b/test/fixtures/imports/local-module/package.json @@ -0,0 +1 @@ +{"style": "main.css"} diff --git a/test/fixtures/npm.css b/test/fixtures/modules.css similarity index 85% rename from test/fixtures/npm.css rename to test/fixtures/modules.css index fed6692f..626badbb 100644 --- a/test/fixtures/npm.css +++ b/test/fixtures/modules.css @@ -5,3 +5,4 @@ @import "use-dep"; @import "use-dep-too"; @import "use-dep" screen; +@import "local-module"; diff --git a/test/fixtures/npm.expected.css b/test/fixtures/modules.expected.css similarity index 80% rename from test/fixtures/npm.expected.css rename to test/fixtures/modules.expected.css index 8fe06479..dba57a85 100644 --- a/test/fixtures/npm.expected.css +++ b/test/fixtures/modules.expected.css @@ -6,3 +6,4 @@ @media screen{ .dep{} } +.local-module{} diff --git a/test/index.js b/test/index.js index bbbd7cf9..52f2344a 100755 --- a/test/index.js +++ b/test/index.js @@ -1,7 +1,6 @@ "use strict"; var test = require("tape") -var assert = require("assert") var path = require("path") var fs = require("fs") @@ -18,7 +17,10 @@ function read(name) { function compareFixtures(t, name, msg, opts, postcssOpts) { opts = opts || {path: importsDir} - var actual = postcss().use(atImport(opts)).process(read("fixtures/" + name), postcssOpts).css.trim() + var actual = postcss() + .use(atImport(opts)) + .process(read("fixtures/" + name), postcssOpts) + .css.trim() var expected = read("fixtures/" + name + ".expected") // handy thing: checkout actual in the *.actual.css file @@ -49,20 +51,16 @@ test("@import", function(t) { compareFixtures(t, "relative-to-source", "should not need `path` option if `source` option has been passed to postcss", null, {from: "test/fixtures/relative-to-source.css"}) - compareFixtures(t, "npm", "should be able to consume npm package") + compareFixtures(t, "modules", "should be able to consume npm package or local modules") t.end() }) test("@import error output", function(t) { var file = importsDir + "/import-missing.css" - t.doesNotThrow( - function() { - assert.throws( - function() {postcss().use(atImport()).process(fs.readFileSync(file), {from: file})}, - /import-missing.css:2:5 Failed to find 'missing-file.css'\n\s+in \[/gm - ) - }, + t.throws( + function() {postcss().use(atImport()).process(fs.readFileSync(file), {from: file})}, + /import-missing.css:2:5: Failed to find 'missing-file.css'\n\s+in \[/gm, "should output readable trace" )