diff --git a/CHANGELOG.md b/CHANGELOG.md index c1ba2ac..a08eeac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). +## [3.0.0](https://github.com/postcss-modules-local-by-default/compare/v3.0.0-rc.2...v3.0.0) - 2020-10-13 + +### Fixes + +- compatibility with plugins other plugins +- handle animation short name +- perf + ## [3.0.0-rc.2](https://github.com/postcss-modules-local-by-default/compare/v3.0.0-rc.1...v3.0.0-rc.2) - 2020-10-11 ### BREAKING CHANGE diff --git a/package.json b/package.json index b428388..9605f10 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "postcss-modules-scope", - "version": "3.0.0-rc.2", + "version": "3.0.0", "description": "A CSS Modules transform to extract export statements from local-scope classes", "main": "src/index.js", "engines": { diff --git a/src/index.js b/src/index.js index f5107a5..29df9bc 100644 --- a/src/index.js +++ b/src/index.js @@ -88,7 +88,7 @@ const plugin = (options = {}) => { return { postcssPlugin: "postcss-modules-scope", - OnceExit(root, { rule }) { + Once(root, { rule }) { const exports = Object.create(null); function exportScopedName(name, rawName) { @@ -134,6 +134,16 @@ const plugin = (options = {}) => { ), }); } + case "attribute": { + if (node.attribute === "class" && node.operator === "=") { + return selectorParser.attribute({ + attribute: node.attribute, + operator: node.operator, + quoteMark: "'", + value: exportScopedName(node.value), + }); + } + } } throw new Error( @@ -188,15 +198,13 @@ const plugin = (options = {}) => { // Find any :import and remember imported names const importedNames = {}; - root.walkRules((rule) => { - if (/^:import\(.+\)$/.test(rule.selector)) { - rule.walkDecls((decl) => { - importedNames[decl.prop] = true; - }); - } + root.walkRules(/^:import\(.+\)$/, (rule) => { + rule.walkDecls((decl) => { + importedNames[decl.prop] = true; + }); }); - // Find any :local classes + // Find any :local selectors root.walkRules((rule) => { let parsedSelector = selectorParser().astSync(rule); @@ -233,30 +241,31 @@ const plugin = (options = {}) => { decl.remove(); }); + // Find any :local values rule.walkDecls((decl) => { + if (!/:local\s*\((.+?)\)/.test(decl.value)) { + return; + } + let tokens = decl.value.split(/(,|'[^']*'|"[^"]*")/); tokens = tokens.map((token, idx) => { if (idx === 0 || tokens[idx - 1] === ",") { let result = token; - const localMatch = /^(\s*):local\s*\((.+?)\)/.exec(token); - const nextLocalMatch = /:local\s*\((.+?)\)/.exec(token); + const localMatch = /:local\s*\((.+?)\)/.exec(token); if (localMatch) { - result = - localMatch[1] + - exportScopedName(localMatch[2]) + - token.substr(localMatch[0].length); - } else if (nextLocalMatch) { - const input = nextLocalMatch.input; - const matchPattern = nextLocalMatch[0]; - const matchVal = nextLocalMatch[1]; + const input = localMatch.input; + const matchPattern = localMatch[0]; + const matchVal = localMatch[1]; const newVal = exportScopedName(matchVal); + result = input.replace(matchPattern, newVal); } else { - // do nothing + return token; } + return result; } else { return token; @@ -268,14 +277,14 @@ const plugin = (options = {}) => { }); // Find any :local keyframes - root.walkAtRules((atRule) => { - if (/keyframes$/i.test(atRule.name)) { - const localMatch = /^\s*:local\s*\((.+?)\)\s*$/.exec(atRule.params); + root.walkAtRules(/keyframes$/i, (atRule) => { + const localMatch = /^\s*:local\s*\((.+?)\)\s*$/.exec(atRule.params); - if (localMatch) { - atRule.params = exportScopedName(localMatch[1]); - } + if (!localMatch) { + return; } + + atRule.params = exportScopedName(localMatch[1]); }); // If we found any :locals, insert an :export rule diff --git a/test/test-cases/error-other-than-class-attribute/expected.error.txt b/test/test-cases/error-other-than-class-attribute/expected.error.txt new file mode 100644 index 0000000..ab88d38 --- /dev/null +++ b/test/test-cases/error-other-than-class-attribute/expected.error.txt @@ -0,0 +1 @@ +attribute \("\[target\="_blank"]\"\) is not allowed in a :local block \ No newline at end of file diff --git a/test/test-cases/error-other-than-class-attribute/source.css b/test/test-cases/error-other-than-class-attribute/source.css new file mode 100644 index 0000000..48d4bdd --- /dev/null +++ b/test/test-cases/error-other-than-class-attribute/source.css @@ -0,0 +1,3 @@ +:local(.exportName1[target="_blank"]) { + color: blue; +} diff --git a/test/test-cases/error-other-than-equal- in-class-attribute/expected.error.txt b/test/test-cases/error-other-than-equal- in-class-attribute/expected.error.txt new file mode 100644 index 0000000..8dbce66 --- /dev/null +++ b/test/test-cases/error-other-than-equal- in-class-attribute/expected.error.txt @@ -0,0 +1 @@ +attribute \("\[class\*\="exportName2"\]\"\) is not allowed in a :local block \ No newline at end of file diff --git a/test/test-cases/error-other-than-equal- in-class-attribute/source.css b/test/test-cases/error-other-than-equal- in-class-attribute/source.css new file mode 100644 index 0000000..c4742cd --- /dev/null +++ b/test/test-cases/error-other-than-equal- in-class-attribute/source.css @@ -0,0 +1,3 @@ +:local(.exportName1[class*="exportName2"]) { + color: blue; +} diff --git a/test/test-cases/export-class-attribute/expected.css b/test/test-cases/export-class-attribute/expected.css new file mode 100644 index 0000000..802a6d4 --- /dev/null +++ b/test/test-cases/export-class-attribute/expected.css @@ -0,0 +1,16 @@ +._input__exportName1 { + color: red; +} + +._input__exportName2 { + color: green; +} + +._input__exportName2[class=_input__exportName1] { + color: blue; +} + +:export { + exportName1: _input__exportName1; + exportName2: _input__exportName2; +} diff --git a/test/test-cases/export-class-attribute/source.css b/test/test-cases/export-class-attribute/source.css new file mode 100644 index 0000000..9c248d3 --- /dev/null +++ b/test/test-cases/export-class-attribute/source.css @@ -0,0 +1,11 @@ +:local(.exportName1) { + color: red; +} + +:local(.exportName2) { + color: green; +} + +:local(.exportName2[class=exportName1]) { + color: blue; +}