diff --git a/src/index.js b/src/index.js index c7e3ff4..52bcaa8 100644 --- a/src/index.js +++ b/src/index.js @@ -137,21 +137,28 @@ const plugin = (options = {}) => { case "selector": node.nodes = node.map((item) => localizeNode(item)); return node; - case "class": + case "class": { + const scopedName = exportScopedName( + node.value, + node.raws && node.raws.value ? node.raws.value : null, + node + ); + return selectorParser.className({ - value: exportScopedName( - node.value, - node.raws && node.raws.value ? node.raws.value : null, - node - ), + value: unescape(scopedName), + raws: { value: scopedName }, }); + } case "id": { + const scopedName = exportScopedName( + node.value, + node.raws && node.raws.value ? node.raws.value : null, + node + ); + return selectorParser.id({ - value: exportScopedName( - node.value, - node.raws && node.raws.value ? node.raws.value : null, - node - ), + value: unescape(scopedName), + raws: { value: scopedName }, }); } case "attribute": { @@ -190,7 +197,9 @@ const plugin = (options = {}) => { nextNode && nextNode.type === "combinator" && nextNode.value === " " && - /\\[A-F0-9]{1,6}$/.test(selector.last.value) + /\\[A-F0-9]{1,6}$/.test( + selector.last.stringifyProperty("value") + ) ) { selector.last.spaces.after = " "; } diff --git a/test/test-cases/escaped-scoped-names/expected.css b/test/test-cases/escaped-scoped-names/expected.css new file mode 100644 index 0000000..79f29ba --- /dev/null +++ b/test/test-cases/escaped-scoped-names/expected.css @@ -0,0 +1,29 @@ +.a\+x\/y\=\= { + color: red; +} + +#b\+x\/y\=\= { + color: red; +} + +.a\+x\/y\=\= .c\+x\/y\=\= { + color: red; +} + +.a\+x\/y\=\=.c\+x\/y\=\= { + color: red; +} + +.a\+x\/y\=\= > #b\+x\/y\=\= { + color: red; +} + +.global .a\+x\/y\=\= .global { + color: red; +} + +:export { + a: a+x/y==; + b: b+x/y==; + c: c+x/y==; +} diff --git a/test/test-cases/escaped-scoped-names/options.js b/test/test-cases/escaped-scoped-names/options.js new file mode 100644 index 0000000..29ca669 --- /dev/null +++ b/test/test-cases/escaped-scoped-names/options.js @@ -0,0 +1,6 @@ +module.exports = { + // Return names that are already escaped for CSS, as css-loader does. + generateScopedName: function (name) { + return String.raw`${name}\+x\/y\=\=`; + }, +}; diff --git a/test/test-cases/escaped-scoped-names/source.css b/test/test-cases/escaped-scoped-names/source.css new file mode 100644 index 0000000..5d0882d --- /dev/null +++ b/test/test-cases/escaped-scoped-names/source.css @@ -0,0 +1,23 @@ +:local(.a) { + color: red; +} + +:local(#b) { + color: red; +} + +:local(.a) :local(.c) { + color: red; +} + +:local(.a):local(.c) { + color: red; +} + +:local(.a) > :local(#b) { + color: red; +} + +.global :local(.a) .global { + color: red; +}