From 1d785321947e35f3f274250b20c739983a8a695b Mon Sep 17 00:00:00 2001 From: evilebottnawi Date: Mon, 4 Mar 2019 21:03:15 +0300 Subject: [PATCH] fix: handle escaping selectors --- src/index.js | 31 +++++++++++++++++++++-- test/test-cases/export-class/expected.css | 17 ++++++++++++- test/test-cases/export-class/source.css | 12 +++++++++ 3 files changed, 57 insertions(+), 3 deletions(-) diff --git a/src/index.js b/src/index.js index a46d67e..2f02270 100644 --- a/src/index.js +++ b/src/index.js @@ -51,6 +51,28 @@ function getSingleLocalNamesForComposes(root) { }); } +const whitespace = '[\\x20\\t\\r\\n\\f]'; +const unescapeRegExp = new RegExp( + '\\\\([\\da-f]{1,6}' + whitespace + '?|(' + whitespace + ')|.)', + 'ig' +); + +function unescape(str) { + return str.replace(unescapeRegExp, (_, escaped, escapedWhitespace) => { + const high = '0x' + escaped - 0x10000; + + // NaN means non-codepoint + // Workaround erroneous numeric interpretation of +"0x" + return high !== high || escapedWhitespace + ? escaped + : high < 0 + ? // BMP codepoint + String.fromCharCode(high + 0x10000) + : // Supplemental Plane codepoint (surrogate pair) + String.fromCharCode((high >> 10) | 0xd800, (high & 0x3ff) | 0xdc00); + }); +} + const processor = postcss.plugin('postcss-modules-scope', function(options) { return css => { const generateScopedName = @@ -64,10 +86,15 @@ const processor = postcss.plugin('postcss-modules-scope', function(options) { css.source.input.from, css.source.input.css ); + exports[name] = exports[name] || []; - if (exports[name].indexOf(scopedName) < 0) { - exports[name].push(scopedName); + + const unescapedScopedName = unescape(scopedName); + + if (exports[name].indexOf(unescapedScopedName) < 0) { + exports[name].push(unescapedScopedName); } + return scopedName; } diff --git a/test/test-cases/export-class/expected.css b/test/test-cases/export-class/expected.css index a21c8da..adbce42 100644 --- a/test/test-cases/export-class/expected.css +++ b/test/test-cases/export-class/expected.css @@ -10,6 +10,18 @@ color: rebeccapurple; } +._input__\31 a2b3c { + color: gainsboro; +} + +._input__\32 { + color: aqua; +} + +._input__𝌆 { + color: fuchsia; +} + @media (max-width: 520px) { /* selector doubled to increase specificity */ ._input__exportName._input__exportName { @@ -22,7 +34,10 @@ } :export { + 2: _input__2; exportName: _input__exportName; - ::::: _input__\:\:\:\:; + ::::: _input__::::; + 1a2b3c: _input__1a2b3c; + 𝌆: _input__𝌆; newExport: _input__newExport; } diff --git a/test/test-cases/export-class/source.css b/test/test-cases/export-class/source.css index ae9a680..4cb0a71 100644 --- a/test/test-cases/export-class/source.css +++ b/test/test-cases/export-class/source.css @@ -10,6 +10,18 @@ color: rebeccapurple; } +:local(.\31 a2b3c) { + color: gainsboro; +} + +:local(.\32) { + color: aqua; +} + +:local(.𝌆) { + color: fuchsia; +} + @media (max-width: 520px) { /* selector doubled to increase specificity */ :local(.exportName):local(.exportName) {