Skip to content

Commit

Permalink
fix: scoped class attribute
Browse files Browse the repository at this point in the history
  • Loading branch information
alexander-akait authored and TheSTL committed May 1, 2021
2 parents c32c7f9 + 6f8ff19 commit 3a05d8d
Show file tree
Hide file tree
Showing 9 changed files with 78 additions and 26 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -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": {
Expand Down
59 changes: 34 additions & 25 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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;
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
attribute \("\[target\="_blank"]\"\) is not allowed in a :local block
3 changes: 3 additions & 0 deletions test/test-cases/error-other-than-class-attribute/source.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
:local(.exportName1[target="_blank"]) {
color: blue;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
attribute \("\[class\*\="exportName2"\]\"\) is not allowed in a :local block
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
:local(.exportName1[class*="exportName2"]) {
color: blue;
}
16 changes: 16 additions & 0 deletions test/test-cases/export-class-attribute/expected.css
Original file line number Diff line number Diff line change
@@ -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;
}
11 changes: 11 additions & 0 deletions test/test-cases/export-class-attribute/source.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
:local(.exportName1) {
color: red;
}

:local(.exportName2) {
color: green;
}

:local(.exportName2[class=exportName1]) {
color: blue;
}

0 comments on commit 3a05d8d

Please sign in to comment.