@@ -12,13 +12,7 @@ import extractImports from "postcss-modules-extract-imports";
1212import modulesScope from "postcss-modules-scope" ;
1313import camelCase from "camelcase" ;
1414
15- const whitespace = "[\\x20\\t\\r\\n\\f]" ;
16- const unescapeRegExp = new RegExp (
17- `\\\\([\\da-f]{1,6}${ whitespace } ?|(${ whitespace } )|.)` ,
18- "ig"
19- ) ;
20- const matchNativeWin32Path = / ^ [ A - Z ] : [ / \\ ] | ^ \\ \\ / i;
21- const webpackIgnoreCommentRegexp = / w e b p a c k I g n o r e : ( \s + ) ? ( t r u e | f a l s e ) / ;
15+ const WEBPACK_IGNORE_COMMENT_REGEXP = / w e b p a c k I g n o r e : ( \s + ) ? ( t r u e | f a l s e ) / ;
2216
2317// eslint-disable-next-line no-useless-escape
2418const regexSingleEscape = / [ - , . \/ : - @ [ \] \^ ` { - ~ ] / ;
@@ -72,24 +66,95 @@ function escape(string) {
7266 return output ;
7367}
7468
69+ function gobbleHex ( str ) {
70+ const lower = str . toLowerCase ( ) ;
71+ let hex = "" ;
72+ let spaceTerminated = false ;
73+
74+ // eslint-disable-next-line no-undefined
75+ for ( let i = 0 ; i < 6 && lower [ i ] !== undefined ; i ++ ) {
76+ const code = lower . charCodeAt ( i ) ;
77+ // check to see if we are dealing with a valid hex char [a-f|0-9]
78+ const valid = ( code >= 97 && code <= 102 ) || ( code >= 48 && code <= 57 ) ;
79+ // https://drafts.csswg.org/css-syntax/#consume-escaped-code-point
80+ spaceTerminated = code === 32 ;
81+
82+ if ( ! valid ) {
83+ break ;
84+ }
85+
86+ hex += lower [ i ] ;
87+ }
88+
89+ if ( hex . length === 0 ) {
90+ // eslint-disable-next-line no-undefined
91+ return undefined ;
92+ }
93+
94+ const codePoint = parseInt ( hex , 16 ) ;
95+
96+ const isSurrogate = codePoint >= 0xd800 && codePoint <= 0xdfff ;
97+ // Add special case for
98+ // "If this number is zero, or is for a surrogate, or is greater than the maximum allowed code point"
99+ // https://drafts.csswg.org/css-syntax/#maximum-allowed-code-point
100+ if ( isSurrogate || codePoint === 0x0000 || codePoint > 0x10ffff ) {
101+ return [ "\uFFFD" , hex . length + ( spaceTerminated ? 1 : 0 ) ] ;
102+ }
103+
104+ return [
105+ String . fromCodePoint ( codePoint ) ,
106+ hex . length + ( spaceTerminated ? 1 : 0 ) ,
107+ ] ;
108+ }
109+
110+ const CONTAINS_ESCAPE = / \\ / ;
111+
75112function unescape ( str ) {
76- return str . replace ( unescapeRegExp , ( _ , escaped , escapedWhitespace ) => {
77- const high = `0x${ escaped } ` - 0x10000 ;
78-
79- /* eslint-disable line-comment-position */
80- // NaN means non-codepoint
81- // Workaround erroneous numeric interpretation of +"0x"
82- // eslint-disable-next-line no-self-compare
83- return high !== high || escapedWhitespace
84- ? escaped
85- : high < 0
86- ? // BMP codepoint
87- String . fromCharCode ( high + 0x10000 )
88- : // Supplemental Plane codepoint (surrogate pair)
89- // eslint-disable-next-line no-bitwise
90- String . fromCharCode ( ( high >> 10 ) | 0xd800 , ( high & 0x3ff ) | 0xdc00 ) ;
91- /* eslint-enable line-comment-position */
92- } ) ;
113+ const needToProcess = CONTAINS_ESCAPE . test ( str ) ;
114+
115+ if ( ! needToProcess ) {
116+ return str ;
117+ }
118+
119+ let ret = "" ;
120+
121+ for ( let i = 0 ; i < str . length ; i ++ ) {
122+ if ( str [ i ] === "\\" ) {
123+ const gobbled = gobbleHex ( str . slice ( i + 1 , i + 7 ) ) ;
124+
125+ // eslint-disable-next-line no-undefined
126+ if ( gobbled !== undefined ) {
127+ ret += gobbled [ 0 ] ;
128+ i += gobbled [ 1 ] ;
129+
130+ // eslint-disable-next-line no-continue
131+ continue ;
132+ }
133+
134+ // Retain a pair of \\ if double escaped `\\\\`
135+ // https://github.com/postcss/postcss-selector-parser/commit/268c9a7656fb53f543dc620aa5b73a30ec3ff20e
136+ if ( str [ i + 1 ] === "\\" ) {
137+ ret += "\\" ;
138+ i += 1 ;
139+
140+ // eslint-disable-next-line no-continue
141+ continue ;
142+ }
143+
144+ // if \\ is at the end of the string retain it
145+ // https://github.com/postcss/postcss-selector-parser/commit/01a6b346e3612ce1ab20219acc26abdc259ccefb
146+ if ( str . length === i + 1 ) {
147+ ret += str [ i ] ;
148+ }
149+
150+ // eslint-disable-next-line no-continue
151+ continue ;
152+ }
153+
154+ ret += str [ i ] ;
155+ }
156+
157+ return ret ;
93158}
94159
95160function normalizePath ( file ) {
@@ -139,6 +204,8 @@ function defaultGetLocalIdent(
139204 return interpolateName ( loaderContext , localIdentName , options ) ;
140205}
141206
207+ const NATIVE_WIN32_PATH = / ^ [ A - Z ] : [ / \\ ] | ^ \\ \\ / i;
208+
142209function normalizeUrl ( url , isStringValue ) {
143210 let normalizedUrl = url
144211 . replace ( / ^ ( | \t \n | \r \n | \r | \f ) * / g, "" )
@@ -148,7 +215,7 @@ function normalizeUrl(url, isStringValue) {
148215 normalizedUrl = normalizedUrl . replace ( / \\ ( \n | \r \n | \r | \f ) / g, "" ) ;
149216 }
150217
151- if ( matchNativeWin32Path . test ( url ) ) {
218+ if ( NATIVE_WIN32_PATH . test ( url ) ) {
152219 try {
153220 normalizedUrl = decodeURI ( normalizedUrl ) ;
154221 } catch ( error ) {
@@ -768,7 +835,7 @@ function isUrlRequestable(url) {
768835 }
769836
770837 // Absolute URLs
771- if ( / ^ [ a - z ] [ a - z 0 - 9 + . - ] * : / i. test ( url ) && ! matchNativeWin32Path . test ( url ) ) {
838+ if ( / ^ [ a - z ] [ a - z 0 - 9 + . - ] * : / i. test ( url ) && ! NATIVE_WIN32_PATH . test ( url ) ) {
772839 return false ;
773840 }
774841
@@ -811,6 +878,6 @@ export {
811878 resolveRequests ,
812879 isUrlRequestable ,
813880 sort ,
814- webpackIgnoreCommentRegexp ,
881+ WEBPACK_IGNORE_COMMENT_REGEXP ,
815882 combineRequests ,
816883} ;
0 commit comments