postcss-import
Advanced tools
Comparing version 7.1.3 to 8.0.0
@@ -0,1 +1,57 @@ | ||
# 8.0.0 - 2015-01-27 | ||
- Removed: async mode/option (now async by default) | ||
([#107](https://github.com/postcss/postcss-import/pull/107)) | ||
- Removed: "bower_components" not supported by default anymore, | ||
use "path" option to add it back | ||
- Removed: `encoding` option. Encoding can be specified in custom `load` option | ||
```js | ||
postcssImport({ | ||
load: function(filename) { | ||
return fs.readFileSync(filename, "utf-8") | ||
} | ||
}) | ||
``` | ||
([#144](https://github.com/postcss/postcss-import/pull/144)) | ||
- Removed: glob support | ||
([#146](https://github.com/postcss/postcss-import/pull/146)) | ||
Globs can be implemented with custom `resolve` option | ||
```js | ||
postcssImport({ | ||
resolve: function(id, base) { | ||
return glob.sync(path.join(base, id)) | ||
} | ||
}) | ||
``` | ||
([#116](https://github.com/postcss/postcss-import/pull/116)) | ||
- 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)) | ||
- Changed: support promise in `transform` option and `undefined` result will be | ||
skipped | ||
([#147](https://github.com/postcss/postcss-import/pull/147)) | ||
- Changed: `options.plugins` are applied to unprocessed ast before imports | ||
detecting | ||
([157](https://github.com/postcss/postcss-import/pull/157)) | ||
- Added: custom resolve function can return array of paths | ||
([#120](https://github.com/postcss/postcss-import/pull/120)) | ||
- Added: custom syntax in imported files support | ||
([#130](https://github.com/postcss/postcss-import/pull/130)) | ||
- Added: support custom `load` option | ||
([#144](https://github.com/postcss/postcss-import/pull/144)) | ||
- Added: detect css extension in package.json `main` field | ||
([153](https://github.com/postcss/postcss-import/pull/153)) | ||
**Note:** | ||
_If you miss options/default behavior (glob etc), a new plugin will handle all | ||
those things. | ||
Please follow issue [#145](https://github.com/postcss/postcss-import/issues/145) | ||
_ | ||
# 7.1.3 - 2015-11-05 | ||
@@ -2,0 +58,0 @@ |
722
index.js
@@ -1,43 +0,21 @@ | ||
/** | ||
* Module dependencies. | ||
*/ | ||
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 joinMedia = require("./lib/join-media") | ||
var resolveId = require("./lib/resolve-id") | ||
var loadContent = require("./lib/load-content") | ||
var parseStatements = require("./lib/parse-statements") | ||
var resolvedPromise = new Promise(function(resolvePromise) { | ||
resolvePromise() | ||
}) | ||
/** | ||
* Constants | ||
*/ | ||
var moduleDirectories = [ | ||
"web_modules", | ||
"node_modules", | ||
"bower_components", | ||
] | ||
var warnNodesMessage = | ||
"It looks like you didn't end correctly your @import statement. " + | ||
"Some children nodes are attached to it." | ||
/** | ||
* Inline `@import`ed files | ||
* | ||
* @param {Object} options | ||
*/ | ||
function AtImport(options) { | ||
options = assign({ | ||
root: process.cwd(), | ||
async: false, | ||
path: [], | ||
skipDuplicates: true, | ||
}, options || {}) | ||
resolve: resolveId, | ||
load: loadContent, | ||
plugins: [], | ||
}, options) | ||
options.root = path.resolve(options.root) | ||
// convert string to an array of a single element | ||
@@ -48,523 +26,312 @@ if (typeof options.path === "string") { | ||
return function(styles, result) { | ||
var opts = assign({}, options || {}) | ||
if (!Array.isArray(options.path)) { | ||
options.path = [] | ||
} | ||
// auto add from option if possible | ||
if ( | ||
!opts.from && | ||
styles && | ||
styles.nodes && | ||
styles.nodes[0] && | ||
styles.nodes[0].source && | ||
styles.nodes[0].source.input && | ||
styles.nodes[0].source.input.file | ||
) { | ||
opts.from = styles.nodes[0].source.input.file | ||
} | ||
options.path = options.path.map(function(p) { | ||
return path.resolve(options.root, p) | ||
}) | ||
// if from available, prepend from directory in the path array | ||
addInputToPath(opts) | ||
// if we got nothing for the path, just use cwd | ||
if (opts.path.length === 0) { | ||
opts.path.push(process.cwd()) | ||
} | ||
return function(styles, result) { | ||
var state = { | ||
importedFiles: {}, | ||
ignoredAtRules: [], | ||
hashFiles: {}, | ||
} | ||
if (opts.from) { | ||
state.importedFiles[opts.from] = { | ||
"": true, | ||
} | ||
if (styles.source && styles.source.input && styles.source.input.file) { | ||
state.importedFiles[styles.source.input.file] = {} | ||
} | ||
var parsedStylesResult = parseStyles( | ||
if (options.plugins && !Array.isArray(options.plugins)) { | ||
throw new Error("plugins option must be an array") | ||
} | ||
return parseStyles( | ||
result, | ||
styles, | ||
opts, | ||
options, | ||
state, | ||
null, | ||
createProcessor(result, options.plugins) | ||
) | ||
[] | ||
).then(function(bundle) { | ||
function onParseEnd() { | ||
addIgnoredAtRulesOnTop(styles, state.ignoredAtRules) | ||
applyRaws(bundle) | ||
applyMedia(bundle) | ||
applyStyles(bundle, styles) | ||
if ( | ||
typeof opts.addDependencyTo === "object" && | ||
typeof opts.addDependencyTo.addDependency === "function" | ||
typeof options.addDependencyTo === "object" && | ||
typeof options.addDependencyTo.addDependency === "function" | ||
) { | ||
Object.keys(state.importedFiles) | ||
.forEach(opts.addDependencyTo.addDependency) | ||
.forEach(options.addDependencyTo.addDependency) | ||
} | ||
if (typeof opts.onImport === "function") { | ||
opts.onImport(Object.keys(state.importedFiles)) | ||
if (typeof options.onImport === "function") { | ||
options.onImport(Object.keys(state.importedFiles)) | ||
} | ||
} | ||
if (options.async) { | ||
return parsedStylesResult.then(onParseEnd) | ||
} | ||
// else (!options.async) | ||
onParseEnd() | ||
}) | ||
} | ||
} | ||
function createProcessor(result, plugins) { | ||
if (plugins) { | ||
if (!Array.isArray(plugins)) { | ||
throw new Error("plugins option must be an array") | ||
function applyRaws(bundle) { | ||
bundle.forEach(function(stmt, index) { | ||
if (index === 0) { | ||
return | ||
} | ||
return postcss(plugins) | ||
} | ||
return postcss() | ||
if (stmt.parent) { | ||
var before = stmt.parent.node.raws.before | ||
if (stmt.type === "nodes") { | ||
stmt.nodes[0].raws.before = before | ||
} | ||
else { | ||
stmt.node.raws.before = before | ||
} | ||
} | ||
else if (stmt.type === "nodes") { | ||
stmt.nodes[0].raws.before = stmt.nodes[0].raws.before || "\n" | ||
} | ||
}) | ||
} | ||
/** | ||
* lookup for @import rules | ||
* | ||
* @param {Object} styles | ||
* @param {Object} options | ||
*/ | ||
function parseStyles( | ||
result, | ||
styles, | ||
options, | ||
state, | ||
media, | ||
processor | ||
) { | ||
var imports = [] | ||
styles.walkAtRules("import", function checkAtRule(atRule) { | ||
if (atRule.nodes) { | ||
result.warn(warnNodesMessage, { node: atRule }) | ||
function applyMedia(bundle) { | ||
bundle.forEach(function(stmt) { | ||
if (!stmt.media.length) { | ||
return | ||
} | ||
if (options.glob && glob.hasMagic(atRule.params)) { | ||
imports = parseGlob(atRule, options, imports) | ||
if (stmt.type === "import") { | ||
stmt.node.params = stmt.fullUri + " " + stmt.media.join(", ") | ||
} | ||
else if (stmt.type ==="media") { | ||
stmt.node.params = stmt.media.join(", ") | ||
} | ||
else { | ||
imports.push(atRule) | ||
} | ||
}) | ||
var nodes = stmt.nodes | ||
var parent = nodes[0].parent | ||
var mediaNode = postcss.atRule({ | ||
name: "media", | ||
params: stmt.media.join(", "), | ||
source: parent.source, | ||
}) | ||
var importResults = imports.map(function(atRule) { | ||
return helpers.try(function transformAtImport() { | ||
return readAtImport( | ||
result, | ||
atRule, | ||
options, | ||
state, | ||
media, | ||
processor | ||
) | ||
}, atRule.source) | ||
}) | ||
parent.insertBefore(nodes[0], mediaNode) | ||
if (options.async) { | ||
return Promise.all(importResults) | ||
} | ||
// else (!options.async) | ||
// nothing | ||
} | ||
// remove nodes | ||
nodes.forEach(function(node) { | ||
node.parent = undefined | ||
}) | ||
/** | ||
* 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, "") | ||
.replace(/(?:url\(|\))/g, "") | ||
var paths = options.path.concat(moduleDirectories) | ||
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 | ||
// better output | ||
nodes[0].raws.before = nodes[0].raws.before || "\n" | ||
paths.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) | ||
}) | ||
}) | ||
// wrap new rules with media query | ||
mediaNode.append(nodes) | ||
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) | ||
stmt.type = "media" | ||
stmt.node = mediaNode | ||
delete stmt.nodes | ||
} | ||
atRule.parent.insertBefore(atRule, deglobbedAtRule) | ||
imports.push(deglobbedAtRule) | ||
}) | ||
atRule.remove() | ||
return imports | ||
} | ||
/** | ||
* put back at the top ignored url (absolute url) | ||
* | ||
* @param {Object} styles | ||
* @param {Array} state | ||
*/ | ||
function addIgnoredAtRulesOnTop(styles, ignoredAtRules) { | ||
var i = ignoredAtRules.length | ||
if (i) { | ||
var first = styles.first | ||
function applyStyles(bundle, styles) { | ||
styles.nodes = [] | ||
while (i--) { | ||
var ignoredAtRule = ignoredAtRules[i][0] | ||
ignoredAtRule.params = ignoredAtRules[i][1].fullUri + | ||
(ignoredAtRules[i][1].media ? " " + ignoredAtRules[i][1].media : "") | ||
// keep ast ref | ||
ignoredAtRule.parent = styles | ||
// don't use prepend() to avoid weird behavior of normalize() | ||
styles.nodes.unshift(ignoredAtRule) | ||
bundle.forEach(function(stmt) { | ||
if (stmt.type === "import") { | ||
stmt.node.parent = undefined | ||
styles.append(stmt.node) | ||
} | ||
// separate remote import a little with others rules if no newlines already | ||
if (first && | ||
first.raws.before.indexOf("\n") === -1) { | ||
first.raws.before = "\n\n" + first.raws.before | ||
else if (stmt.type === "media") { | ||
stmt.node.parent = undefined | ||
styles.append(stmt.node) | ||
} | ||
} | ||
else if (stmt.type === "nodes") { | ||
stmt.nodes.forEach(function(node) { | ||
node.parent = undefined | ||
styles.append(node) | ||
}) | ||
} | ||
}) | ||
} | ||
/** | ||
* parse @import rules & inline appropriate rules | ||
* | ||
* @param {Object} atRule postcss atRule | ||
* @param {Object} options | ||
*/ | ||
function readAtImport( | ||
function parseStyles( | ||
result, | ||
atRule, | ||
styles, | ||
options, | ||
state, | ||
media, | ||
processor | ||
media | ||
) { | ||
// parse-import module parse entire line | ||
// @todo extract what can be interesting from this one | ||
var parsedAtImport = parseImport(atRule.params, atRule.source) | ||
var statements = parseStatements(result, styles) | ||
// adjust media according to current scope | ||
media = parsedAtImport.media | ||
? (media ? media + " and " : "") + parsedAtImport.media | ||
: (media ? media : null) | ||
return Promise.all(statements.map(function(stmt) { | ||
stmt.media = joinMedia(media, stmt.media) | ||
// just update protocol base uri (protocol://url) or protocol-relative | ||
// (//url) if media needed | ||
if (parsedAtImport.uri.match(/^(?:[a-z]+:)?\/\//i)) { | ||
parsedAtImport.media = media | ||
// skip protocol base uri (protocol://url) or protocol-relative | ||
if (stmt.type !== "import" || /^(?:[a-z]+:)?\/\//i.test(stmt.uri)) { | ||
return | ||
} | ||
return resolveImportId( | ||
result, | ||
stmt, | ||
options, | ||
state | ||
) | ||
})).then(function() { | ||
var imports = [] | ||
var bundle = [] | ||
// save | ||
state.ignoredAtRules.push([ atRule, parsedAtImport ]) | ||
// squash statements and their children | ||
statements.forEach(function(stmt) { | ||
if (stmt.type === "import") { | ||
if (stmt.children) { | ||
stmt.children.forEach(function(child, index) { | ||
if (child.type === "import") { | ||
imports.push(child) | ||
} | ||
else { | ||
bundle.push(child) | ||
} | ||
// For better output | ||
if (index === 0) { | ||
child.parent = stmt | ||
} | ||
}) | ||
} | ||
else { | ||
imports.push(stmt) | ||
} | ||
} | ||
else if (stmt.type === "media" || stmt.type === "nodes") { | ||
bundle.push(stmt) | ||
} | ||
}) | ||
// detach | ||
detach(atRule) | ||
return imports.concat(bundle) | ||
}) | ||
} | ||
return resolvedPromise | ||
} | ||
function resolveImportId( | ||
result, | ||
stmt, | ||
options, | ||
state | ||
) { | ||
var atRule = stmt.node | ||
var base = atRule.source && atRule.source.input && atRule.source.input.file | ||
? path.dirname(atRule.source.input.file) | ||
: options.root | ||
addInputToPath(options) | ||
var resolvedFilename = resolveFilename( | ||
parsedAtImport.uri, | ||
options.root, | ||
options.path, | ||
atRule.source, | ||
options.resolve | ||
) | ||
return Promise.resolve(options.resolve(stmt.uri, base, options)) | ||
.then(function(resolved) { | ||
if (!Array.isArray(resolved)) { | ||
resolved = [ resolved ] | ||
} | ||
return Promise.all(resolved.map(function(file) { | ||
return loadImportContent( | ||
result, | ||
stmt, | ||
file, | ||
options, | ||
state | ||
) | ||
})) | ||
}) | ||
.then(function(result) { | ||
// Merge loaded statements | ||
stmt.children = result.reduce(function(result, statements) { | ||
if (statements) { | ||
result = result.concat(statements) | ||
} | ||
return result | ||
}, []) | ||
}) | ||
.catch(function(err) { | ||
result.warn(err.message, { node: atRule }) | ||
}) | ||
} | ||
function loadImportContent( | ||
result, | ||
stmt, | ||
filename, | ||
options, | ||
state | ||
) { | ||
var atRule = stmt.node | ||
var media = stmt.media | ||
if (options.skipDuplicates) { | ||
// skip files already imported at the same scope | ||
if ( | ||
state.importedFiles[resolvedFilename] && | ||
state.importedFiles[resolvedFilename][media] | ||
state.importedFiles[filename] && | ||
state.importedFiles[filename][media] | ||
) { | ||
detach(atRule) | ||
return resolvedPromise | ||
return | ||
} | ||
// save imported files to skip them next time | ||
if (!state.importedFiles[resolvedFilename]) { | ||
state.importedFiles[resolvedFilename] = {} | ||
if (!state.importedFiles[filename]) { | ||
state.importedFiles[filename] = {} | ||
} | ||
state.importedFiles[resolvedFilename][media] = true | ||
state.importedFiles[filename][media] = true | ||
} | ||
return readImportedContent( | ||
result, | ||
atRule, | ||
parsedAtImport, | ||
assign({}, options), | ||
resolvedFilename, | ||
state, | ||
media, | ||
processor | ||
) | ||
} | ||
/** | ||
* insert imported content at the right place | ||
* | ||
* @param {Object} atRule | ||
* @param {Object} parsedAtImport | ||
* @param {Object} options | ||
* @param {String} resolvedFilename | ||
*/ | ||
function readImportedContent( | ||
result, | ||
atRule, | ||
parsedAtImport, | ||
options, | ||
resolvedFilename, | ||
state, | ||
media, | ||
processor | ||
) { | ||
// add directory containing the @imported file in the paths | ||
// to allow local import from this file | ||
var dirname = path.dirname(resolvedFilename) | ||
if (options.path.indexOf(dirname) === -1) { | ||
options.path = options.path.slice() | ||
options.path.unshift(dirname) | ||
} | ||
options.from = resolvedFilename | ||
var fileContent = readFile( | ||
resolvedFilename, | ||
options.encoding, | ||
options.transform || function(value) { | ||
return value | ||
return Promise.resolve(options.load(filename, options)) | ||
.then(function(content) { | ||
if (typeof options.transform !== "function") { | ||
return content | ||
} | ||
) | ||
if (fileContent.trim() === "") { | ||
result.warn(resolvedFilename + " is empty", { node: atRule }) | ||
detach(atRule) | ||
return resolvedPromise | ||
} | ||
// skip previous imported files not containing @import rules | ||
if ( | ||
state.hashFiles[fileContent] && | ||
state.hashFiles[fileContent][media] | ||
) { | ||
detach(atRule) | ||
return resolvedPromise | ||
} | ||
var newStyles = postcss.parse(fileContent, options) | ||
if (options.skipDuplicates) { | ||
var hasImport = newStyles.some(function(child) { | ||
return child.type === "atrule" && child.name === "import" | ||
return Promise.resolve(options.transform(content, filename, options)) | ||
.then(function(transformed) { | ||
return typeof transformed === "string" ? transformed : content | ||
}) | ||
if (!hasImport) { | ||
// save hash files to skip them next time | ||
if (!state.hashFiles[fileContent]) { | ||
state.hashFiles[fileContent] = {} | ||
} | ||
state.hashFiles[fileContent][media] = true | ||
}) | ||
.then(function(content) { | ||
if (content.trim() === "") { | ||
result.warn(filename + " is empty", { node: atRule }) | ||
return | ||
} | ||
} | ||
// recursion: import @import from imported file | ||
var parsedResult = parseStyles( | ||
result, | ||
newStyles, | ||
options, | ||
state, | ||
parsedAtImport.media, | ||
processor | ||
) | ||
if (options.async) { | ||
return parsedResult.then(function() { | ||
return processor.process(newStyles) | ||
.then(function(newResult) { | ||
result.messages = result.messages.concat(newResult.messages) | ||
}) | ||
}) | ||
.then(function() { | ||
insertRules(atRule, parsedAtImport, newStyles) | ||
}) | ||
} | ||
// else (!options.async) | ||
var newResult = processor.process(newStyles) | ||
result.messages = result.messages.concat(newResult.messages) | ||
insertRules(atRule, parsedAtImport, newStyles) | ||
} | ||
/** | ||
* insert new imported rules at the right place | ||
* | ||
* @param {Object} atRule | ||
* @param {Object} parsedAtImport | ||
* @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].raws.before = newStyles.nodes[0].raws.before || "\n" | ||
// skip previous imported files not containing @import rules | ||
if ( | ||
state.hashFiles[content] && | ||
state.hashFiles[content][media] | ||
) { | ||
return | ||
} | ||
// wrap new rules with media (media query) | ||
var wrapper = postcss.atRule({ | ||
name: "media", | ||
params: parsedAtImport.media, | ||
return postcss(options.plugins).process(content, { | ||
from: filename, | ||
syntax: result.opts.syntax, | ||
parser: result.opts.parser, | ||
}) | ||
.then(function(importedResult) { | ||
var styles = importedResult.root | ||
result.messages = result.messages.concat(importedResult.messages) | ||
// keep AST clean | ||
newNodes.forEach(function(node) { | ||
node.parent = wrapper | ||
}) | ||
wrapper.source = atRule.source | ||
// copy code style | ||
wrapper.raws.before = atRule.raws.before | ||
wrapper.raws.after = atRule.raws.after | ||
// move nodes | ||
wrapper.nodes = newNodes | ||
newNodes = [ wrapper ] | ||
} | ||
else if (newNodes && newNodes.length) { | ||
newNodes[0].raws.before = atRule.raws.before | ||
} | ||
// keep AST clean | ||
newNodes.forEach(function(node) { | ||
node.parent = atRule.parent | ||
}) | ||
// replace atRule by imported nodes | ||
var nodes = atRule.parent.nodes | ||
nodes.splice.apply(nodes, [ nodes.indexOf(atRule), 0 ].concat(newNodes)) | ||
detach(atRule) | ||
} | ||
/** | ||
* parse @import parameter | ||
*/ | ||
function parseImport(str, source) { | ||
var regex = /((?:url\s?\()?(?:'|")?([^)'"]+)(?:'|")?\)?)(?:(?:\s)(.*))?/gi | ||
var matches = regex.exec(str) | ||
if (matches === null) { | ||
throw new Error("Unable to find uri in '" + str + "'", source) | ||
} | ||
return { | ||
fullUri: matches[1], | ||
uri: matches[2], | ||
media: matches[3] ? matches[3] : null, | ||
} | ||
} | ||
/** | ||
* 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 | ||
if (options.skipDuplicates) { | ||
var hasImport = styles.some(function(child) { | ||
return child.type === "atrule" && child.name === "import" | ||
}) | ||
if (!hasImport) { | ||
// save hash files to skip them next time | ||
if (!state.hashFiles[content]) { | ||
state.hashFiles[content] = {} | ||
} | ||
state.hashFiles[content][media] = true | ||
} | ||
} | ||
} | ||
return path.normalize(file) | ||
} | ||
catch (e) { | ||
throw new Error( | ||
"Failed to find '" + name + "' from " + root + | ||
"\n in [ " + | ||
"\n " + paths.join(",\n ") + | ||
"\n ]", | ||
source | ||
) | ||
} | ||
// recursion: import @import from imported file | ||
return parseStyles( | ||
result, | ||
styles, | ||
options, | ||
state, | ||
media | ||
) | ||
}) | ||
}) | ||
} | ||
/** | ||
* Read the contents of a file | ||
* | ||
* @param {String} file | ||
*/ | ||
function readFile(file, encoding, transform) { | ||
return transform(fs.readFileSync(file, encoding || "utf8"), file) | ||
} | ||
/** | ||
* add `from` dirname to `path` if not already present | ||
* | ||
* @param {Object} options | ||
*/ | ||
function addInputToPath(options) { | ||
if (options.from) { | ||
var fromDir = path.dirname(options.from) | ||
if (options.path.indexOf(fromDir) === -1) { | ||
options.path.unshift(fromDir) | ||
} | ||
} | ||
} | ||
function detach(node) { | ||
node.parent.nodes.splice(node.parent.nodes.indexOf(node), 1) | ||
} | ||
module.exports = postcss.plugin( | ||
@@ -574,2 +341,1 @@ "postcss-import", | ||
) | ||
module.exports.warnNodesMessage = warnNodesMessage |
{ | ||
"name": "postcss-import", | ||
"version": "7.1.3", | ||
"version": "8.0.0", | ||
"description": "PostCSS plugin to import CSS files", | ||
@@ -20,55 +20,24 @@ "keywords": [ | ||
"dependencies": { | ||
"glob": "^5.0.14", | ||
"object-assign": "^4.0.1", | ||
"postcss": "^5.0.2", | ||
"postcss-message-helpers": "^2.0.0", | ||
"resolve": "^1.1.6" | ||
"postcss": "^5.0.14", | ||
"postcss-value-parser": "^3.2.3", | ||
"read-cache": "^1.0.0", | ||
"resolve": "^1.1.7" | ||
}, | ||
"devDependencies": { | ||
"css-whitespace": "^1.1.1", | ||
"eslint": "^1.1.0", | ||
"tape": "^4.0.3" | ||
"ava": "^0.11.0", | ||
"eslint": "^1.10.3", | ||
"eslint-config-i-am-meticulous": "^2.0.0", | ||
"npmpub": "^3.0.1", | ||
"postcss-scss": "^0.1.3" | ||
}, | ||
"scripts": { | ||
"eslint": "eslint .", | ||
"tape": "tape test", | ||
"test": "npm run eslint && npm run tape" | ||
"lint": "eslint .", | ||
"pretest": "npm run lint", | ||
"test": "ava", | ||
"release": "npmpub" | ||
}, | ||
"eslintConfig": { | ||
"extends": "eslint:recommended", | ||
"ecmaFeatures": { | ||
"modules": true, | ||
"experimentalObjectRestSpread": true | ||
}, | ||
"env": { | ||
"es6": true, | ||
"node": true | ||
}, | ||
"rules": { | ||
"indent": [ 2, 2 ], | ||
"max-len": [ 2, 80, 4 ], | ||
"no-multiple-empty-lines": [ 2, { "max": 1 } ], | ||
"quotes": [ 2, "double" ], | ||
"semi": [ 2, "never" ], | ||
"comma-dangle": [ 2, "always-multiline" ], | ||
"comma-style": [ 2, "last" ], | ||
"brace-style": [ 2, "stroustrup" ], | ||
"dot-location": [ 2, "property" ], | ||
"computed-property-spacing": [ 2, "never" ], | ||
"object-curly-spacing": [ 2, "always" ], | ||
"array-bracket-spacing": [ 2, "always" ], | ||
"space-after-keywords": [ 2, "always" ], | ||
"space-before-blocks": [ 2, "always" ], | ||
"space-before-function-paren": [ 2, "never" ], | ||
"space-in-parens": [ 2, "never" ], | ||
"space-unary-ops": [ 2, { "words": true, "nonwords": false } ], | ||
"spaced-comment": [ 2, "always" ], | ||
"one-var": [ 2, "never" ], | ||
"no-bitwise": [ 2 ], | ||
"prefer-const": [ 2 ] | ||
} | ||
"extends": "eslint-config-i-am-meticulous/es5" | ||
} | ||
} |
115
README.md
@@ -1,11 +0,17 @@ | ||
# postcss-import [![Travis Build Status](https://travis-ci.org/postcss/postcss-import.svg)](https://travis-ci.org/postcss/postcss-import) [![AppVeyor Build status](https://ci.appveyor.com/api/projects/status/u8l6u3lr6s5u5tpi?svg=true)](https://ci.appveyor.com/project/MoOx/postcss-import) | ||
# postcss-import | ||
> [PostCSS](https://github.com/postcss/postcss) plugin to transform `@import` rules by inlining content. | ||
[![Unix Build status](https://img.shields.io/travis/postcss/postcss-import/master.svg?branch=master&label=unix%20build)](https://travis-ci.org/postcss/postcss-import) | ||
[![Windows Build status](https://img.shields.io/appveyor/ci/MoOx/postcss-import/master.svg?label=window%20build)](https://ci.appveyor.com/project/MoOx/postcss-import/branch/master) | ||
[![Version](https://img.shields.io/npm/v/postcss-import.svg)](https://github.com/postcss/postcss-import/blob/master/CHANGELOG.md) | ||
> [PostCSS](https://github.com/postcss/postcss) plugin to transform `@import` | ||
rules by inlining content. | ||
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()`), `node_modules`, `web_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._ | ||
`package.json` in the `style` or `main` fields._ | ||
You can also provide manually multiples paths where to look at. | ||
@@ -15,7 +21,13 @@ | ||
- **This plugin should probably be used as the first plugin of your list. This way, other plugins will work on the AST as if there were only a single file to process, and will probably work as you can expect**. | ||
- This plugin works great with [postcss-url](https://github.com/postcss/postcss-url) plugin, | ||
which will allow you to adjust assets `url()` (or even inline them) after inlining imported files. | ||
- In order to optimize output, **this plugin will only import a file once** on a given scope (root, media query...). | ||
Tests are made from the path & the content of imported files (using a hash table). | ||
- **This plugin should probably be used as the first plugin of your list. | ||
This way, other plugins will work on the AST as if there were only a single file | ||
to process, and will probably work as you can expect**. | ||
- This plugin works great with | ||
[postcss-url](https://github.com/postcss/postcss-url) plugin, | ||
which will allow you to adjust assets `url()` (or even inline them) after | ||
inlining imported files. | ||
- In order to optimize output, **this plugin will only import a file once** on | ||
a given scope (root, media query...). | ||
Tests are made from the path & the content of imported files (using a hash | ||
table). | ||
If this behavior is not what you want, look at `skipDuplicates` option | ||
@@ -31,3 +43,5 @@ | ||
If your stylesheets are not in the same place where you run postcss (`process.cwd()`), you will need to use `from` option to make relative imports work from input dirname. | ||
If your stylesheets are not in the same place where you run postcss | ||
(`process.cwd()`), you will need to use `from` option to make relative imports | ||
work from input dirname. | ||
@@ -44,3 +58,3 @@ ```js | ||
// process css | ||
var output = postcss() | ||
postcss() | ||
.use(atImport()) | ||
@@ -51,5 +65,7 @@ .process(css, { | ||
}) | ||
.css | ||
.then(function (result) { | ||
var output = result.css | ||
console.log(output) | ||
console.log(output) | ||
}) | ||
``` | ||
@@ -60,7 +76,6 @@ | ||
```css | ||
/* can consume `node_modules`, `web_modules`, `bower_components` or local modules */ | ||
/* can consume `node_modules`, `web_modules` or local modules */ | ||
@import "cssrecipes-defaults"; /* == @import "./node_modules/cssrecipes-defaults/index.css"; */ | ||
@import "normalize.css"; /* == @import "./node_modules/normalize.css/normalize.css"; */ | ||
@import "normalize.css/normalize"; /* == @import "./bower_components/normalize.css/normalize.css"; */ | ||
@import "css/foo.css"; /* relative to stylesheets/ according to `from` option above */ | ||
@@ -78,6 +93,5 @@ | ||
```css | ||
/* ... content of ./node_modules/my-css-on-npm/index.css */ | ||
/* ... content of ./node_modules/cssrecipes-defaults/index.css */ | ||
/* ... content of ./node_modules/normalize.css/normalize.css */ | ||
/* ... content of ./bower_components/my-css-on-bower/index.css */ | ||
/* ... content of foo.css */ | ||
@@ -101,5 +115,9 @@ | ||
Type: `String` | ||
Default: `process.cwd()` | ||
Default: `process.cwd()` or _dirname of | ||
[the postcss `from`](https://github.com/postcss/postcss#node-source)_ | ||
Define the root where to resolve path (eg: place where `node_modules` and `bower_components` are). Should not be used that much. | ||
Define the root where to resolve path (eg: place where `node_modules` are). | ||
Should not be used that much. | ||
_Note: nested `@import` will additionally benefit of the relative dirname of | ||
imported files._ | ||
@@ -109,16 +127,6 @@ #### `path` | ||
Type: `String|Array` | ||
Default: `process.cwd()` or _dirname of [the postcss `from`](https://github.com/postcss/postcss#node-source)_ | ||
Default: `[]` | ||
A string or an array of paths in where to look for files. | ||
_Note: nested `@import` will additionally benefit of the relative dirname of imported files._ | ||
A string or an array of paths in where to look for files. | ||
#### `async` | ||
Type: `Boolean` | ||
Default: `false` | ||
Allow to enable PostCSS async API usage. Before enabling this, check that your | ||
runner allow async usage. | ||
_Note: this is not enabling async fs read yet._ | ||
#### `transform` | ||
@@ -129,3 +137,5 @@ | ||
A function to transform the content of imported files. Take one argument (file content) & should return the modified content. | ||
A function to transform the content of imported files. Take one argument (file | ||
content) and should return the modified content or promise with it. | ||
`undefined` result will be skipped. | ||
@@ -137,11 +147,4 @@ #### `plugins` | ||
An array of plugins to be applied on each imported file. | ||
An array of plugins to be applied on each imported files. | ||
#### `encoding` | ||
Type: `String` | ||
Default: `utf8` | ||
Use if your CSS is encoded in anything other than UTF-8. | ||
#### `onImport` | ||
@@ -152,17 +155,23 @@ | ||
Function called after the import process. Take one argument (array of imported files). | ||
Function called after the import process. Take one argument (array of imported | ||
files). | ||
#### `glob` | ||
#### `resolve` | ||
Type: `Boolean` | ||
Default: `false` | ||
Type: `Function` | ||
Default: `null` | ||
Set to `true` if you want @import rules to parse glob patterns. | ||
You can overwrite the default path resolving way by setting this option. | ||
This function gets `(id, basedir, importOptions)` arguments and returns full | ||
path, array of paths or promise resolving paths. | ||
You can use [resolve](https://github.com/substack/node-resolve) for that. | ||
#### `resolve` | ||
#### `load` | ||
Type: `Function` | ||
Default: `null` | ||
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 loading way by setting this option. | ||
This function gets `(filename, importOptions)` arguments and returns content or | ||
promised content. | ||
@@ -203,3 +212,3 @@ #### `skipDuplicates` | ||
var css = postcss() | ||
postcss() | ||
.use(atImport({ | ||
@@ -210,3 +219,5 @@ path: ["src/css"] | ||
.process(cssString) | ||
.css | ||
.then(function (result) { | ||
var css = result.css | ||
}) | ||
``` | ||
@@ -213,0 +224,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
223
1
23967
5
302
1
+ Addedpostcss-value-parser@^3.2.3
+ Addedread-cache@^1.0.0
+ Addedpify@2.3.0(transitive)
+ Addedpostcss-value-parser@3.3.1(transitive)
+ Addedread-cache@1.0.0(transitive)
- Removedglob@^5.0.14
- Removedpostcss-message-helpers@^2.0.0
- Removedbalanced-match@1.0.2(transitive)
- Removedbrace-expansion@1.1.11(transitive)
- Removedconcat-map@0.0.1(transitive)
- Removedglob@5.0.15(transitive)
- Removedinflight@1.0.6(transitive)
- Removedinherits@2.0.4(transitive)
- Removedminimatch@3.1.2(transitive)
- Removedonce@1.4.0(transitive)
- Removedpath-is-absolute@1.0.1(transitive)
- Removedpostcss-message-helpers@2.0.0(transitive)
- Removedwrappy@1.0.2(transitive)
Updatedpostcss@^5.0.14
Updatedresolve@^1.1.7