Skip to content

Commit 2f7fc40

Browse files
committed
escapeClassName to correclty replace css
1 parent 9c80c15 commit 2f7fc40

File tree

2 files changed

+55
-4
lines changed

2 files changed

+55
-4
lines changed

index.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ const {
1010
logger,
1111
getRelativePath,
1212
isFileOrInDirectory,
13+
escapeClassName
1314
} = require("./utils");
1415
const path = require("path");
1516

@@ -172,15 +173,15 @@ module.exports = (options = {}) => {
172173
newClassName = getRandomName(length);
173174
}
174175
newClassName = `.${classPrefix}${newClassName}${classSuffix}`;
175-
176+
validCssClassName = '.'+escapeClassName(oldClassName.slice(1));
176177
// If ClassName already exist replace with its value else generate new : the should have same name.
177178
if (jsonData.hasOwnProperty(oldClassName)) {
178179
selector = selector.replace(
179-
oldClassName,
180+
validCssClassName,
180181
jsonData[oldClassName]
181182
);
182183
} else {
183-
selector = selector.replace(oldClassName, newClassName);
184+
selector = selector.replace(validCssClassName, newClassName);
184185
jsonData[oldClassName] = newClassName;
185186
}
186187
singleFileData[oldClassName] = newClassName;

utils.js

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,13 +208,62 @@ function extractClassNames(obj) {
208208
return classNames;
209209
}
210210

211+
function escapeClassName(className) {
212+
// CSS escapes for some special characters
213+
const escapes = {
214+
'!': '\\!',
215+
'"': '\\"',
216+
'#': '\\#',
217+
'$': '\\$',
218+
'%': '\\%',
219+
'&': '\\&',
220+
'\'': '\\\'',
221+
'(': '\\(',
222+
')': '\\)',
223+
'*': '\\*',
224+
'+': '\\+',
225+
',': '\\,',
226+
'.': '\\.',
227+
'/': '\\/',
228+
':': '\\:',
229+
';': '\\;',
230+
'<': '\\<',
231+
'=': '\\=',
232+
'>': '\\>',
233+
'?': '\\?',
234+
'@': '\\@',
235+
'[': '\\[',
236+
'\\': '\\\\',
237+
']': '\\]',
238+
'^': '\\^',
239+
'`': '\\`',
240+
'{': '\\{',
241+
'|': '\\|',
242+
'}': '\\}',
243+
'~': '\\~',
244+
' ': '\\ ',
245+
};
246+
247+
// Special handling for class names starting with a digit
248+
if (/^\d/.test(className)) {
249+
// Convert the first digit to its hexadecimal escape code
250+
const firstCharCode = className.charCodeAt(0).toString(16);
251+
const rest = className.slice(1);
252+
253+
// Use the hexadecimal escape for the first character, followed by the rest of the class name
254+
// Note: A trailing space is added after the escape sequence to ensure separation
255+
return `\\${firstCharCode}${rest.split('').map(char => escapes[char] || char).join('')}`;
256+
}
257+
// Replace each special character with its escaped version for the rest of the class name
258+
return className.split('').map(char => escapes[char] || char).join('');
259+
}
260+
211261
function getClassNames(selectorStr) {
212262
const parse = createParser({syntax: 'progressive'});
213263
const ast = parse(selectorStr);
214264
return extractClassNames(ast);
215265
}
216266

217-
218267
function getIdNames(selectorStr) {
219268
let ids = selectorStr.replace(".#", " ").replace(".", " ").trim().split(" ");
220269
ids = ids.filter((id) => id.charAt(0) == "#");
@@ -294,4 +343,5 @@ module.exports = {
294343
logger,
295344
getRelativePath,
296345
isFileOrInDirectory,
346+
escapeClassName,
297347
};

0 commit comments

Comments
 (0)