@@ -12,13 +12,7 @@ import extractImports from "postcss-modules-extract-imports";
12
12
import modulesScope from "postcss-modules-scope" ;
13
13
import camelCase from "camelcase" ;
14
14
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 ) / ;
22
16
23
17
// eslint-disable-next-line no-useless-escape
24
18
const regexSingleEscape = / [ - , . \/ : - @ [ \] \^ ` { - ~ ] / ;
@@ -72,24 +66,95 @@ function escape(string) {
72
66
return output ;
73
67
}
74
68
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
+
75
112
function 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 ;
93
158
}
94
159
95
160
function normalizePath ( file ) {
@@ -139,6 +204,8 @@ function defaultGetLocalIdent(
139
204
return interpolateName ( loaderContext , localIdentName , options ) ;
140
205
}
141
206
207
+ const NATIVE_WIN32_PATH = / ^ [ A - Z ] : [ / \\ ] | ^ \\ \\ / i;
208
+
142
209
function normalizeUrl ( url , isStringValue ) {
143
210
let normalizedUrl = url
144
211
. replace ( / ^ ( | \t \n | \r \n | \r | \f ) * / g, "" )
@@ -148,7 +215,7 @@ function normalizeUrl(url, isStringValue) {
148
215
normalizedUrl = normalizedUrl . replace ( / \\ ( \n | \r \n | \r | \f ) / g, "" ) ;
149
216
}
150
217
151
- if ( matchNativeWin32Path . test ( url ) ) {
218
+ if ( NATIVE_WIN32_PATH . test ( url ) ) {
152
219
try {
153
220
normalizedUrl = decodeURI ( normalizedUrl ) ;
154
221
} catch ( error ) {
@@ -768,7 +835,7 @@ function isUrlRequestable(url) {
768
835
}
769
836
770
837
// 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 ) ) {
772
839
return false ;
773
840
}
774
841
@@ -811,6 +878,6 @@ export {
811
878
resolveRequests ,
812
879
isUrlRequestable ,
813
880
sort ,
814
- webpackIgnoreCommentRegexp ,
881
+ WEBPACK_IGNORE_COMMENT_REGEXP ,
815
882
combineRequests ,
816
883
} ;
0 commit comments