Skip to content

Commit dfa0247

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 dfa0247

File tree

2 files changed

+41
-7
lines changed

2 files changed

+41
-7
lines changed

src/htmlminifier.js

+30-7
Original file line numberDiff line numberDiff line change
@@ -904,14 +904,37 @@ 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+
// Only substitute each ID once, if this has come up
924+
// multiple times, then we need to abort.
925+
if (ids.indexOf(id) !== -1) {
926+
uidPattern.lastIndex = 0;
927+
} else {
928+
text = text.replace(id, ignoreCSS(id));
929+
ids.push(id);
930+
}
931+
}
932+
});
933+
if (uidPattern.lastIndex === 0) {
934+
// There was a warning that didn't match the pattern.
935+
break;
936+
}
937+
}
915938

916939
return fn(text, type).then(chunk => {
917940
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)