mirror of
https://github.com/angular/angular
synced 2026-05-24 09:28:37 +00:00
fix(compiler): don't choke on unbalanced parens in declaration block
Following https://github.com/angular/angular/pull/64509 we started choking on unbalanced closing parentheses in declaration blocks, specifically in quoted background-image urls. This was reported in https://github.com/angular/angular/issues/65137. This occured because we previously (and now again) traverse the entire declaration block when selecting for :host-context() selectors to shim. This is an oddity of how we parse styles today, and is likely something we'd want to remove if we parsed selectors properly. This change adds a new flag to _splitOnTopLevelCommas which allows it to continue past unbalanced closing parentheses in the declaration block, returning _convertColonHostContext to its previous behavior while keeping support for the extra nesting in :host-context().
This commit is contained in:
parent
c15836c8c7
commit
9e7ddcaa10
2 changed files with 14 additions and 6 deletions
|
|
@ -512,7 +512,7 @@ export class ShadowCss {
|
|||
return cssText.replace(_cssColonHostRe, (_, hostSelectors: string, otherSelectors: string) => {
|
||||
if (hostSelectors) {
|
||||
const convertedSelectors: string[] = [];
|
||||
for (const hostSelector of this._splitOnTopLevelCommas(hostSelectors)) {
|
||||
for (const hostSelector of this._splitOnTopLevelCommas(hostSelectors, true)) {
|
||||
const trimmedHostSelector = hostSelector.trim();
|
||||
if (!trimmedHostSelector) break;
|
||||
const convertedSelector =
|
||||
|
|
@ -533,8 +533,9 @@ export class ShadowCss {
|
|||
* Yields each part of the string between top-level commas. Terminates if an extra closing paren is found.
|
||||
*
|
||||
* @param text The string to split
|
||||
* @param returnOnClosingParen Whether to return when exiting the current level of parentheses nesting
|
||||
*/
|
||||
private *_splitOnTopLevelCommas(text: string): Generator<string> {
|
||||
private *_splitOnTopLevelCommas(text: string, returnOnClosingParen: boolean): Generator<string> {
|
||||
const length = text.length;
|
||||
let parens = 0;
|
||||
let prev = 0;
|
||||
|
|
@ -546,8 +547,8 @@ export class ShadowCss {
|
|||
parens++;
|
||||
} else if (charCode === chars.$RPAREN) {
|
||||
parens--;
|
||||
if (parens < 0) {
|
||||
// Found an extra closing paren. Assume we want the list terminated here
|
||||
if (parens < 0 && returnOnClosingParen) {
|
||||
// Found an extra closing paren.
|
||||
yield text.slice(prev, i);
|
||||
return;
|
||||
}
|
||||
|
|
@ -582,7 +583,7 @@ export class ShadowCss {
|
|||
// individually and stitches them back together. This ensures that individual selectors don't
|
||||
// affect each other.
|
||||
const results: string[] = [];
|
||||
for (const part of this._splitOnTopLevelCommas(cssText)) {
|
||||
for (const part of this._splitOnTopLevelCommas(cssText, false)) {
|
||||
results.push(this._convertColonHostContextInSelectorPart(part));
|
||||
}
|
||||
return results.join(',');
|
||||
|
|
@ -615,7 +616,7 @@ export class ShadowCss {
|
|||
// Extract comma-separated selectors between the parentheses
|
||||
const newContextSelectors: string[] = [];
|
||||
let endIndex = 0; // Index of the closing paren of the :host-context()
|
||||
for (const selector of this._splitOnTopLevelCommas(afterPrefix.substring(1))) {
|
||||
for (const selector of this._splitOnTopLevelCommas(afterPrefix.substring(1), true)) {
|
||||
endIndex = endIndex + selector.length + 1;
|
||||
const trimmed = selector.trim();
|
||||
if (trimmed) {
|
||||
|
|
|
|||
|
|
@ -339,6 +339,13 @@ describe('ShadowCss', () => {
|
|||
expect(css).toEqualCss('div[contenta] {background-image:url("a.jpg"); color:red;}');
|
||||
});
|
||||
|
||||
it('should handle when quoted content contains a closing parenthesis', () => {
|
||||
// Regression test for https://github.com/angular/angular/issues/65137
|
||||
expect(shim('p { background-image: url(")") } p { color: red }', 'contenta')).toEqualCss(
|
||||
'p[contenta] { background-image: url(")") } p[contenta] { color: red }',
|
||||
);
|
||||
});
|
||||
|
||||
it('should shim rules with an escaped quote inside quoted content', () => {
|
||||
const styleStr = 'div::after { content: "\\"" }';
|
||||
const css = shim(styleStr, 'contenta');
|
||||
|
|
|
|||
Loading…
Reference in a new issue