postcss-modules-extract-imports
Advanced tools
Comparing version 2.0.0 to 3.0.0-rc.0
{ | ||
"name": "postcss-modules-extract-imports", | ||
"version": "2.0.0", | ||
"version": "3.0.0-rc.0", | ||
"description": "A CSS Modules transform to extract local aliases for inline imports", | ||
"main": "src/index.js", | ||
"engines": { | ||
"node": ">= 6" | ||
"node": ">= 10.13.0 || >= 12.13.0 || >= 14" | ||
}, | ||
@@ -13,12 +13,12 @@ "files": [ | ||
"scripts": { | ||
"prettier": "prettier -l --ignore-path .gitignore . \"!test/test-cases\"", | ||
"eslint": "eslint --ignore-path .gitignore .", | ||
"lint": "yarn eslint && yarn prettier", | ||
"pretest": "yarn lint", | ||
"test": "jest --coverage", | ||
"precommit": "lint-staged", | ||
"prepublish": "yarn run test" | ||
"autotest": "jest --coverage --watch", | ||
"cover": "jest --coverage", | ||
"ci": "yarn pretest && yarn cover", | ||
"prepublishOnly": "yarn test" | ||
}, | ||
"lint-staged": { | ||
"*.js": [ | ||
"prettier --single-quote --no-semi --write", | ||
"git add" | ||
] | ||
}, | ||
"repository": { | ||
@@ -39,13 +39,15 @@ "type": "git", | ||
"homepage": "https://github.com/css-modules/postcss-modules-extract-imports", | ||
"dependencies": { | ||
"postcss": "^7.0.5" | ||
"devDependencies": { | ||
"codecov.io": "^0.1.6", | ||
"coveralls": "^3.1.0", | ||
"eslint": "^7.9.0", | ||
"husky": "^4.3.0", | ||
"jest": "^26.4.2", | ||
"lint-staged": "^10.4.0", | ||
"postcss": "^8.0.6", | ||
"prettier": "^2.1.2" | ||
}, | ||
"devDependencies": { | ||
"codecov.io": "^0.1.2", | ||
"coveralls": "^2.11.2", | ||
"husky": "^0.13.3", | ||
"jest": "^20.0.3", | ||
"lint-staged": "^3.4.2", | ||
"prettier": "^1.3.1" | ||
"peerDependencies": { | ||
"postcss": "^8.0.6" | ||
} | ||
} |
@@ -30,2 +30,3 @@ # CSS Modules: Extract Imports | ||
- An extend-import has the following format: | ||
``` | ||
@@ -41,4 +42,4 @@ composes: className [... className] from "path/to/file.css"; | ||
.aa { | ||
composes: b from './b.css'; | ||
composes: c from './c.css'; | ||
composes: b from "./b.css"; | ||
composes: c from "./c.css"; | ||
} | ||
@@ -48,4 +49,4 @@ | ||
/* "b.css" should be before "c.css" in this case */ | ||
composes: c from './c.css'; | ||
composes: b from './b.css'; | ||
composes: c from "./c.css"; | ||
composes: b from "./b.css"; | ||
} | ||
@@ -63,10 +64,5 @@ ``` | ||
* Lines: [![Coverage Status](https://coveralls.io/repos/css-modules/postcss-modules-extract-imports/badge.svg?branch=master)](https://coveralls.io/r/css-modules/postcss-modules-extract-imports?branch=master) | ||
* Statements: [![codecov.io](http://codecov.io/github/css-modules/postcss-modules-extract-imports/coverage.svg?branch=master)](http://codecov.io/github/css-modules/postcss-modules-extract-imports?branch=master) | ||
- Lines: [![Coverage Status](https://coveralls.io/repos/css-modules/postcss-modules-extract-imports/badge.svg?branch=master)](https://coveralls.io/r/css-modules/postcss-modules-extract-imports?branch=master) | ||
- Statements: [![codecov.io](http://codecov.io/github/css-modules/postcss-modules-extract-imports/coverage.svg?branch=master)](http://codecov.io/github/css-modules/postcss-modules-extract-imports?branch=master) | ||
## Development | ||
- `npm watch` will watch `src` for changes and rebuild | ||
- `npm autotest` will watch `src` and `test` for changes and retest | ||
## License | ||
@@ -83,2 +79,3 @@ | ||
--- | ||
Glen Maddern, 2015. |
243
src/index.js
@@ -1,17 +0,17 @@ | ||
const postcss = require('postcss') | ||
const topologicalSort = require('./topologicalSort') | ||
const postcss = require("postcss"); | ||
const topologicalSort = require("./topologicalSort"); | ||
const declWhitelist = ['composes'] | ||
const declFilter = new RegExp(`^(${declWhitelist.join('|')})$`) | ||
const matchImports = /^(.+?)\s+from\s+(?:"([^"]+)"|'([^']+)'|(global))$/ | ||
const icssImport = /^:import\((?:"([^"]+)"|'([^']+)')\)/ | ||
const declWhitelist = ["composes"]; | ||
const declFilter = new RegExp(`^(${declWhitelist.join("|")})$`); | ||
const matchImports = /^(.+?)\s+from\s+(?:"([^"]+)"|'([^']+)'|(global))$/; | ||
const icssImport = /^:import\((?:"([^"]+)"|'([^']+)')\)/; | ||
const VISITED_MARKER = 1 | ||
const VISITED_MARKER = 1; | ||
function createParentName(rule, root) { | ||
return `__${root.index(rule.parent)}_${rule.selector}` | ||
return `__${root.index(rule.parent)}_${rule.selector}`; | ||
} | ||
function serializeImports(imports) { | ||
return imports.map(importPath => '`' + importPath + '`').join(', ') | ||
return imports.map((importPath) => "`" + importPath + "`").join(", "); | ||
} | ||
@@ -41,141 +41,156 @@ | ||
function addImportToGraph(importId, parentId, graph, visited) { | ||
const siblingsId = parentId + '_' + 'siblings' | ||
const visitedId = parentId + '_' + importId | ||
const siblingsId = parentId + "_" + "siblings"; | ||
const visitedId = parentId + "_" + importId; | ||
if (visited[visitedId] !== VISITED_MARKER) { | ||
if (!Array.isArray(visited[siblingsId])) visited[siblingsId] = [] | ||
if (!Array.isArray(visited[siblingsId])) { | ||
visited[siblingsId] = []; | ||
} | ||
const siblings = visited[siblingsId] | ||
const siblings = visited[siblingsId]; | ||
if (Array.isArray(graph[importId])) | ||
graph[importId] = graph[importId].concat(siblings) | ||
else graph[importId] = siblings.slice() | ||
if (Array.isArray(graph[importId])) { | ||
graph[importId] = graph[importId].concat(siblings); | ||
} else { | ||
graph[importId] = siblings.slice(); | ||
} | ||
visited[visitedId] = VISITED_MARKER | ||
siblings.push(importId) | ||
visited[visitedId] = VISITED_MARKER; | ||
siblings.push(importId); | ||
} | ||
} | ||
module.exports = postcss.plugin('modules-extract-imports', function( | ||
options = {} | ||
) { | ||
const failOnWrongOrder = options.failOnWrongOrder | ||
module.exports = (options = {}) => { | ||
const failOnWrongOrder = options.failOnWrongOrder; | ||
return css => { | ||
const graph = {} | ||
const visited = {} | ||
return { | ||
postcssPlugin: "postcss-modules-extract-imports", | ||
RootExit(root) { | ||
const graph = {}; | ||
const visited = {}; | ||
const existingImports = {} | ||
const importDecls = {} | ||
const imports = {} | ||
const existingImports = {}; | ||
const importDecls = {}; | ||
const imports = {}; | ||
let importIndex = 0 | ||
let importIndex = 0; | ||
const createImportedName = typeof options.createImportedName !== 'function' | ||
? (importName /*, path*/) => | ||
`i__imported_${importName.replace(/\W/g, '_')}_${importIndex++}` | ||
: options.createImportedName | ||
const createImportedName = | ||
typeof options.createImportedName !== "function" | ||
? (importName /*, path*/) => | ||
`i__imported_${importName.replace(/\W/g, "_")}_${importIndex++}` | ||
: options.createImportedName; | ||
// Check the existing imports order and save refs | ||
css.walkRules(rule => { | ||
const matches = icssImport.exec(rule.selector) | ||
// Check the existing imports order and save refs | ||
root.walkRules((rule) => { | ||
const matches = icssImport.exec(rule.selector); | ||
if (matches) { | ||
const [, /*match*/ doubleQuotePath, singleQuotePath] = matches | ||
const importPath = doubleQuotePath || singleQuotePath | ||
if (matches) { | ||
const [, /*match*/ doubleQuotePath, singleQuotePath] = matches; | ||
const importPath = doubleQuotePath || singleQuotePath; | ||
addImportToGraph(importPath, 'root', graph, visited) | ||
addImportToGraph(importPath, "root", graph, visited); | ||
existingImports[importPath] = rule | ||
} | ||
}) | ||
existingImports[importPath] = rule; | ||
} | ||
}); | ||
// Find any declaration that supports imports | ||
css.walkDecls(declFilter, decl => { | ||
let matches = decl.value.match(matchImports) | ||
let tmpSymbols | ||
// Find any declaration that supports imports | ||
root.walkDecls(declFilter, (decl) => { | ||
let matches = decl.value.match(matchImports); | ||
let tmpSymbols; | ||
if (matches) { | ||
let [ | ||
, | ||
/*match*/ symbols, | ||
doubleQuotePath, | ||
singleQuotePath, | ||
global | ||
] = matches | ||
if (matches) { | ||
let [ | ||
, | ||
/*match*/ symbols, | ||
doubleQuotePath, | ||
singleQuotePath, | ||
global, | ||
] = matches; | ||
if (global) { | ||
// Composing globals simply means changing these classes to wrap them in global(name) | ||
tmpSymbols = symbols.split(/\s+/).map(s => `global(${s})`) | ||
} else { | ||
const importPath = doubleQuotePath || singleQuotePath | ||
const parentRule = createParentName(decl.parent, css) | ||
if (global) { | ||
// Composing globals simply means changing these classes to wrap them in global(name) | ||
tmpSymbols = symbols.split(/\s+/).map((s) => `global(${s})`); | ||
} else { | ||
const importPath = doubleQuotePath || singleQuotePath; | ||
const parentRule = createParentName(decl.parent, root); | ||
addImportToGraph(importPath, parentRule, graph, visited) | ||
addImportToGraph(importPath, parentRule, graph, visited); | ||
importDecls[importPath] = decl | ||
imports[importPath] = imports[importPath] || {} | ||
importDecls[importPath] = decl; | ||
imports[importPath] = imports[importPath] || {}; | ||
tmpSymbols = symbols.split(/\s+/).map(s => { | ||
if (!imports[importPath][s]) { | ||
imports[importPath][s] = createImportedName(s, importPath) | ||
} | ||
tmpSymbols = symbols.split(/\s+/).map((s) => { | ||
if (!imports[importPath][s]) { | ||
imports[importPath][s] = createImportedName(s, importPath); | ||
} | ||
return imports[importPath][s] | ||
}) | ||
return imports[importPath][s]; | ||
}); | ||
} | ||
decl.value = tmpSymbols.join(" "); | ||
} | ||
}); | ||
decl.value = tmpSymbols.join(' ') | ||
} | ||
}) | ||
const importsOrder = topologicalSort(graph, failOnWrongOrder); | ||
const importsOrder = topologicalSort(graph, failOnWrongOrder) | ||
if (importsOrder instanceof Error) { | ||
const importPath = importsOrder.nodes.find((importPath) => | ||
// eslint-disable-next-line no-prototype-builtins | ||
importDecls.hasOwnProperty(importPath) | ||
); | ||
const decl = importDecls[importPath]; | ||
if (importsOrder instanceof Error) { | ||
const importPath = importsOrder.nodes.find(importPath => | ||
importDecls.hasOwnProperty(importPath) | ||
) | ||
const decl = importDecls[importPath] | ||
const errMsg = | ||
"Failed to resolve order of composed modules " + | ||
serializeImports(importsOrder.nodes) + | ||
"."; | ||
const errMsg = | ||
'Failed to resolve order of composed modules ' + | ||
serializeImports(importsOrder.nodes) + | ||
'.' | ||
throw decl.error(errMsg, { | ||
plugin: "postcss-modules-extract-imports", | ||
word: "composes", | ||
}); | ||
} | ||
throw decl.error(errMsg, { | ||
plugin: 'modules-extract-imports', | ||
word: 'composes' | ||
}) | ||
} | ||
let lastImportRule; | ||
let lastImportRule | ||
importsOrder.forEach(path => { | ||
const importedSymbols = imports[path] | ||
let rule = existingImports[path] | ||
importsOrder.forEach((path) => { | ||
const importedSymbols = imports[path]; | ||
let rule = existingImports[path]; | ||
if (!rule && importedSymbols) { | ||
rule = postcss.rule({ | ||
selector: `:import("${path}")`, | ||
raws: { after: '\n' } | ||
}) | ||
if (!rule && importedSymbols) { | ||
rule = postcss.rule({ | ||
selector: `:import("${path}")`, | ||
raws: { after: "\n" }, | ||
}); | ||
if (lastImportRule) css.insertAfter(lastImportRule, rule) | ||
else css.prepend(rule) | ||
} | ||
if (lastImportRule) { | ||
root.insertAfter(lastImportRule, rule); | ||
} else { | ||
root.prepend(rule); | ||
} | ||
} | ||
lastImportRule = rule | ||
lastImportRule = rule; | ||
if (!importedSymbols) return | ||
if (!importedSymbols) { | ||
return; | ||
} | ||
Object.keys(importedSymbols).forEach(importedSymbol => { | ||
rule.append( | ||
postcss.decl({ | ||
value: importedSymbol, | ||
prop: importedSymbols[importedSymbol], | ||
raws: { before: '\n ' } | ||
}) | ||
) | ||
}) | ||
}) | ||
} | ||
}) | ||
Object.keys(importedSymbols).forEach((importedSymbol) => { | ||
rule.append( | ||
postcss.decl({ | ||
value: importedSymbol, | ||
prop: importedSymbols[importedSymbol], | ||
raws: { before: "\n " }, | ||
}) | ||
); | ||
}); | ||
}); | ||
}, | ||
}; | ||
}; | ||
module.exports.postcss = true; |
@@ -1,54 +0,66 @@ | ||
const PERMANENT_MARKER = 2 | ||
const TEMPORARY_MARKER = 1 | ||
const PERMANENT_MARKER = 2; | ||
const TEMPORARY_MARKER = 1; | ||
function createError(node, graph) { | ||
const er = new Error("Nondeterministic import's order") | ||
const er = new Error("Nondeterministic import's order"); | ||
const related = graph[node] | ||
const related = graph[node]; | ||
const relatedNode = related.find( | ||
relatedNode => graph[relatedNode].indexOf(node) > -1 | ||
) | ||
(relatedNode) => graph[relatedNode].indexOf(node) > -1 | ||
); | ||
er.nodes = [node, relatedNode] | ||
er.nodes = [node, relatedNode]; | ||
return er | ||
return er; | ||
} | ||
function walkGraph(node, graph, state, result, strict) { | ||
if (state[node] === PERMANENT_MARKER) return | ||
if (state[node] === PERMANENT_MARKER) { | ||
return; | ||
} | ||
if (state[node] === TEMPORARY_MARKER) { | ||
if (strict) return createError(node, graph) | ||
return | ||
if (strict) { | ||
return createError(node, graph); | ||
} | ||
return; | ||
} | ||
state[node] = TEMPORARY_MARKER | ||
state[node] = TEMPORARY_MARKER; | ||
const children = graph[node] | ||
const length = children.length | ||
const children = graph[node]; | ||
const length = children.length; | ||
for (let i = 0; i < length; ++i) { | ||
const er = walkGraph(children[i], graph, state, result, strict) | ||
if (er instanceof Error) return er | ||
const er = walkGraph(children[i], graph, state, result, strict); | ||
if (er instanceof Error) { | ||
return er; | ||
} | ||
} | ||
state[node] = PERMANENT_MARKER | ||
state[node] = PERMANENT_MARKER; | ||
result.push(node) | ||
result.push(node); | ||
} | ||
function topologicalSort(graph, strict) { | ||
const result = [] | ||
const state = {} | ||
const result = []; | ||
const state = {}; | ||
const nodes = Object.keys(graph) | ||
const length = nodes.length | ||
const nodes = Object.keys(graph); | ||
const length = nodes.length; | ||
for (let i = 0; i < length; ++i) { | ||
const er = walkGraph(nodes[i], graph, state, result, strict) | ||
if (er instanceof Error) return er | ||
const er = walkGraph(nodes[i], graph, state, result, strict); | ||
if (er instanceof Error) { | ||
return er; | ||
} | ||
} | ||
return result | ||
return result; | ||
} | ||
module.exports = topologicalSort | ||
module.exports = topologicalSort; |
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
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
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
10394
203
8
1
77
2
+ Addednanoid@3.3.7(transitive)
+ Addedpicocolors@1.0.0(transitive)
+ Addedpostcss@8.4.38(transitive)
+ Addedsource-map-js@1.2.0(transitive)
- Removedpostcss@^7.0.5
- Removedpicocolors@0.2.1(transitive)
- Removedpostcss@7.0.39(transitive)
- Removedsource-map@0.6.1(transitive)