Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
- Removed: async mode/option
([#107](https://github.com/postcss/postcss-import/pull/107))
- Removed: "bower_components" not supported by default anymore, use "path" option to add it back
([#116](https://github.com/postcss/postcss-import/pull/116))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fyi, you can just add bower support by it to the path option.
So I would use "bower_components" not supported by default anymore, use "path" option to add it back.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bower support is also bower.json support, which is not simple with main field as array.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know that, but bower is more a downloader, so I guess lots of people just point to the right css file when they import it (eg: @import "jquery-slider-fx-2016/slider.css") so we don't really care about it. The idea is just to inform people that are currently using the feature we are breaking how to upgrade easily.

- Changed: custom resolve has more responsibility for paths resolving.
See [resolve option](https://github.com/postcss/postcss-import#resolve) for more information about this change
([#116](https://github.com/postcss/postcss-import/pull/116))

# 7.1.3 - 2015-11-05

Expand Down
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

This plugin can consume local files, node modules or bower packages.
To resolve path of an `@import` rule, it can look into root directory
(by default `process.cwd()`), `web_modules`, `node_modules`, `bower_components`
(by default `process.cwd()`), `web_modules`, `node_modules`
or local modules.
_When importing a module, it will looks for `index.css` or file referenced in
`package.json` in the `style` field._
Expand Down Expand Up @@ -144,7 +144,9 @@ Set to `true` if you want @import rules to parse glob patterns.
Type: `Function`
Default: `null`

You can overwrite the default path resolving way by setting this option, using the `resolve.sync(id, opts)` signature that [resolve.sync](https://github.com/substack/node-resolve#resolvesyncid-opts) has.
You can overwrite the default path resolving way by setting this option.
This function gets `(id, basedir, importOptions)` arguments and returns full path or promise resolving full path.
You can use [resolve](https://github.com/substack/node-resolve) for that.

#### `skipDuplicates`

Expand Down
196 changes: 77 additions & 119 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,18 @@ var fs = require("fs")
var path = require("path")

var assign = require("object-assign")
var resolve = require("resolve")
var postcss = require("postcss")
var helpers = require("postcss-message-helpers")
var glob = require("glob")
var parseImports = require("./lib/parse-imports")
var resolveMedia = require("./lib/resolve-media")
var resolveId = require("./lib/resolve-id")

/**
* Constants
*/
var moduleDirectories = [
"web_modules",
"node_modules",
"bower_components",
]

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be added in the CHANGELOG since it's a breaking changes (and we should add how to add bower support like it was).

/**
Expand Down Expand Up @@ -67,7 +65,6 @@ function AtImport(options) {

var state = {
importedFiles: {},
ignoredAtRules: [],
hashFiles: {},
}
if (opts.from) {
Expand All @@ -85,8 +82,8 @@ function AtImport(options) {
createProcessor(result, options.plugins)
)

function onParseEnd() {
addIgnoredAtRulesOnTop(styles, state.ignoredAtRules)
function onParseEnd(ignored) {
addIgnoredAtRulesOnTop(styles, ignored)

if (
typeof opts.addDependencyTo === "object" &&
Expand Down Expand Up @@ -141,20 +138,32 @@ function parseStyles(
})

var importResults = imports.map(function(instance) {
return helpers.try(function transformAtImport() {
return readAtImport(
result,
instance.node,
instance,
options,
state,
media,
processor
)
}, instance.node.source)
return readAtImport(
result,
instance.node,
instance,
options,
state,
media,
processor
)
})

return Promise.all(importResults)
return Promise.all(importResults).then(function(result) {
// Flatten ignored instances
return result.reduce(function(ignored, item) {
if (Array.isArray(item)) {
item = item.filter(function(instance) {
return instance
})
ignored = ignored.concat(item)
}
else if (item) {
ignored.push(item)
}
return ignored
}, [])
})
}

/**
Expand Down Expand Up @@ -212,15 +221,14 @@ function parseGlob(imports, instance, options) {
* @param {Array} state
*/
function addIgnoredAtRulesOnTop(styles, ignoredAtRules) {
var i = ignoredAtRules.length
if (i) {
while (i--) {
var ignored = ignoredAtRules[i][1]
ignored.node.params = ignored.fullUri +
(ignored.media.length ? " " + ignored.media.join(", ") : "")

styles.prepend(ignored.node)
}
var i = ignoredAtRules.length - 1
while (i !== -1) {
var ignored = ignoredAtRules[i]
ignored.node.params = ignored.fullUri +
(ignored.media.length ? " " + ignored.media.join(", ") : "")

styles.prepend(ignored.node)
i -= 1
}
}

Expand All @@ -247,51 +255,54 @@ function readAtImport(
if (parsedAtImport.uri.match(/^(?:[a-z]+:)?\/\//i)) {
parsedAtImport.media = media

// save
state.ignoredAtRules.push([ atRule, parsedAtImport ])

// detach
atRule.remove()

return Promise.resolve()
return Promise.resolve(parsedAtImport)
}

var dir = atRule.source && atRule.source.input && atRule.source.input.file
? path.dirname(path.resolve(options.root, atRule.source.input.file))
: options.root

addInputToPath(options)
var resolvedFilename = resolveFilename(
parsedAtImport.uri,
options.root,
options.path,
atRule.source,
options.resolve
)

if (options.skipDuplicates) {
// skip files already imported at the same scope
if (
state.importedFiles[resolvedFilename] &&
state.importedFiles[resolvedFilename][media]
) {
atRule.remove()
return Promise.resolve()
return Promise.resolve().then(function() {
if (options.resolve) {
return options.resolve(parsedAtImport.uri, dir, options)
}
return resolveId(parsedAtImport.uri, dir, options.path)
}).then(function(resolvedFilename) {
if (options.skipDuplicates) {
// skip files already imported at the same scope
if (
state.importedFiles[resolvedFilename] &&
state.importedFiles[resolvedFilename][media]
) {
atRule.remove()
return Promise.resolve()
}

// save imported files to skip them next time
if (!state.importedFiles[resolvedFilename]) {
state.importedFiles[resolvedFilename] = {}
// save imported files to skip them next time
if (!state.importedFiles[resolvedFilename]) {
state.importedFiles[resolvedFilename] = {}
}
state.importedFiles[resolvedFilename][media] = true
}
state.importedFiles[resolvedFilename][media] = true
}

return readImportedContent(
result,
atRule,
parsedAtImport,
assign({}, options),
resolvedFilename,
state,
media,
processor
)
return readImportedContent(
result,
atRule,
parsedAtImport,
assign({}, options),
resolvedFilename,
state,
media,
processor
)
}).catch(function(err) {
result.warn(err.message, { node: atRule })
})
}

/**
Expand Down Expand Up @@ -368,14 +379,18 @@ function readImportedContent(
processor
)

return parsedResult.then(function() {
var instances

return parsedResult.then(function(result) {
instances = result
return processor.process(newStyles)
})
.then(function(newResult) {
result.messages = result.messages.concat(newResult.messages)
})
.then(function() {
insertRules(atRule, parsedAtImport, newStyles)
return instances
})
}

Expand Down Expand Up @@ -414,63 +429,6 @@ function insertRules(atRule, parsedAtImport, newStyles) {
atRule.replaceWith(newNodes)
}

/**
* Check if a file exists
*
* @param {String} name
*/
function resolveFilename(name, root, paths, source, resolver) {
var dir = source && source.input && source.input.file
? path.dirname(path.resolve(root, source.input.file))
: root

try {
var resolveOpts = {
basedir: dir,
moduleDirectory: moduleDirectories.concat(paths),
paths: paths,
extensions: [ ".css" ],
packageFilter: function processPackage(pkg) {
pkg.main = pkg.style || "index.css"
return pkg
},
}
var file
resolver = resolver || resolve.sync
try {
file = resolver(name, resolveOpts)
}
catch (e) {
// fix to try relative files on windows with "./"
// if it's look like it doesn't start with a relative path already
// if (name.match(/^\.\.?/)) {throw e}
try {
file = resolver("./" + name, resolveOpts)
}
catch (err) {
// LAST HOPE
if (!paths.some(function(dir2) {
file = path.join(dir2, name)
return fs.existsSync(file)
})) {
throw err
}
}
}

return path.normalize(file)
}
catch (e) {
throw new Error(
"Failed to find '" + name + "' from " + root +
"\n in [ " +
"\n " + paths.join(",\n ") +
"\n ]",
source
)
}
}

/**
* Read the contents of a file
*
Expand Down
70 changes: 70 additions & 0 deletions lib/resolve-id.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
var fs = require("fs")
var path = require("path")
var resolve = require("resolve")

var moduleDirectories = [
"web_modules",
"node_modules",
]

function isFilePromise(path) {
return new Promise(function(resolve, reject) {
fs.stat(path, function(err, stat) {
if (err) {
if (err.code === "ENOENT") {
return resolve(false)
}
return reject(err)
}
resolve(stat.isFile() || stat.isFIFO())
})
})
}

function resolvePromise(id, opts) {
return new Promise(function(res, rej) {
resolve(id, opts, function(err, path) {
if (err) {
return rej(err)
}
res(path)
})
})
}

module.exports = function(id, base, paths) {
var resolveOpts = {
basedir: base,
moduleDirectory: moduleDirectories,
paths: paths,
extensions: [ ".css" ],
packageFilter: function processPackage(pkg) {
pkg.main = pkg.style || "index.css"
return pkg
},
}
return resolvePromise(id, resolveOpts).catch(function() {
// fix to try relative files on windows with "./"
// if it's look like it doesn't start with a relative path already
// if (id.match(/^\.\.?/)) {throw e}
return resolvePromise("./" + id, resolveOpts)
}).catch(function() {
// LAST HOPE
return Promise.all(paths.map(function(p) {
return isFilePromise(path.resolve(p, id))
})).then(function(results) {
for (var i = 0; i < results.length; i += 1) {
if (results[i]) {
return path.resolve(paths[i], id)
}
}

throw new Error([
"Failed to find '" + id + "'",
"in [ ",
" " + paths.join(",\n "),
"]",
].join("\n "))
})
})
}
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
"glob": "^5.0.14",
"object-assign": "^4.0.1",
"postcss": "^5.0.2",
"postcss-message-helpers": "^2.0.0",
"postcss-value-parser": "^3.2.3",
"resolve": "^1.1.6"
},
Expand Down
Loading