Skip to content

Commit f9438a6

Browse files
Multiple ignored CSS blocks
If there are multiple ignored CSS blocks within a single clean-css warning message, only the first is replaced with the ignore code. This means that some ingored blocks are simply deleted from the output. The problem is simply that the RegExp is only applied once, despite having the global flag set on it. This is fixed by calling `exec` on the RegExp until it yields no further matches. Added a test for this error case. Fixes terser#180
1 parent c4a7ae0 commit f9438a6

File tree

2 files changed

+35
-7
lines changed

2 files changed

+35
-7
lines changed

src/htmlminifier.js

+24-7
Original file line numberDiff line numberDiff line change
@@ -904,14 +904,31 @@ async function minifyHTML(value, options, partialMarkup) {
904904
});
905905

906906
const ids = [];
907-
new CleanCSS().minify(wrapCSS(text, type)).warnings.forEach(function (warning) {
908-
const match = uidPattern.exec(warning);
909-
if (match) {
910-
const id = uidAttr + match[2] + uidAttr;
911-
text = text.replace(id, ignoreCSS(id));
912-
ids.push(id);
907+
// Loop removing a single ID at a time from the warnings, a
908+
// warning might contain multiple IDs in the context, but we only
909+
// handle the first match on each attempt.
910+
while (true) {
911+
const minifyTest = new CleanCSS().minify(wrapCSS(text, type));
912+
if (minifyTest.warnings.length === 0) {
913+
// There are no warnings.
914+
break;
913915
}
914-
});
916+
minifyTest.warnings.forEach(function (warning) {
917+
// It is very important to reset the RegExp before searching
918+
// as it's re-used each time.
919+
uidPattern.lastIndex = 0;
920+
const match = uidPattern.exec(warning);
921+
if (match) {
922+
const id = uidAttr + match[2] + uidAttr;
923+
text = text.replace(id, ignoreCSS(id));
924+
ids.push(id);
925+
}
926+
});
927+
if (uidPattern.lastIndex === 0) {
928+
// There was a warning that didn't match the pattern.
929+
break;
930+
}
931+
}
915932

916933
return fn(text, type).then(chunk => {
917934
ids.forEach(function (id) {

tests/minifier.spec.js

+11
Original file line numberDiff line numberDiff line change
@@ -3594,3 +3594,14 @@ test('minify Content-Security-Policy', async () => {
35943594
input = '<meta http-equiv="content-security-policy" content="default-src \'self\'; img-src https://*;">';
35953595
expect(await minify(input)).toBe(input);
35963596
});
3597+
3598+
test('minify CSS multiple ignore in single warning', async () => {
3599+
const input = '<style type="text/css">\n{% ignore1 %}\na {\n{% ignore2 %}\n}\n{% ignore3 %}\n</style>';
3600+
const output = '<style type="text/css">\n{% ignore1 %}\na{\n{% ignore2 %}\n}\n{% ignore3 %}\n</style>';
3601+
expect(await minify(input, {
3602+
ignoreCustomFragments: [/\{%[\s\S]*?%\}/],
3603+
minifyCSS: {
3604+
level: 0
3605+
}
3606+
})).toBe(output);
3607+
});

0 commit comments

Comments
 (0)