Skip to content

Commit a040fb7

Browse files
alan-agius4AndrewKushnir
authored andcommitted
fix(compiler): maintain multiline CSS selectors during CSS scoping (angular#55509)
Previously, multiline selectors were being converted into single lines, resulting in sourcemap disruptions due to shifts in line numbers. Closes angular#55508 PR Close angular#55509
1 parent 5c8c2eb commit a040fb7

File tree

2 files changed

+20
-8
lines changed

2 files changed

+20
-8
lines changed

packages/compiler/src/shadow_css.ts

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -658,8 +658,8 @@ export class ShadowCss {
658658

659659
private _scopeSelector(selector: string, scopeSelector: string, hostSelector: string): string {
660660
return selector
661-
.split(',')
662-
.map((part) => part.trim().split(_shadowDeepSelectors))
661+
.split(/ ?, ?/)
662+
.map((part) => part.split(_shadowDeepSelectors))
663663
.map((deepParts) => {
664664
const [shallowPart, ...otherParts] = deepParts;
665665
const applyScope = (shallowPart: string) => {
@@ -727,10 +727,10 @@ export class ShadowCss {
727727
let scopedP = p.trim();
728728

729729
if (!scopedP) {
730-
return '';
730+
return p;
731731
}
732732

733-
if (p.indexOf(_polyfillHostNoCombinator) > -1) {
733+
if (p.includes(_polyfillHostNoCombinator)) {
734734
scopedP = this._applySimpleSelectorScope(p, scopeSelector, hostSelector);
735735
} else {
736736
// remove :host since it should be unnecessary
@@ -765,13 +765,18 @@ export class ShadowCss {
765765
// - `tag:host` -> `tag[h]` (this is to avoid breaking legacy apps, should not match anything)
766766
// - `tag :host` -> `tag [h]` (`tag` is not scoped because it's considered part of a
767767
// `:host-context(tag)`)
768-
const hasHost = selector.indexOf(_polyfillHostNoCombinator) > -1;
768+
const hasHost = selector.includes(_polyfillHostNoCombinator);
769769
// Only scope parts after the first `-shadowcsshost-no-combinator` when it is present
770770
let shouldScope = !hasHost;
771771

772772
while ((res = sep.exec(selector)) !== null) {
773773
const separator = res[1];
774-
const part = selector.slice(startIndex, res.index).trim();
774+
// Do not trim the selector, as otherwise this will break sourcemaps
775+
// when they are defined on multiple lines
776+
// Example:
777+
// div,
778+
// p { color: red}
779+
const part = selector.slice(startIndex, res.index);
775780

776781
// A space following an escaped hex value and followed by another hex character
777782
// (ie: ".\fc ber" for ".über") is not a separator between 2 selectors
@@ -781,14 +786,14 @@ export class ShadowCss {
781786
continue;
782787
}
783788

784-
shouldScope = shouldScope || part.indexOf(_polyfillHostNoCombinator) > -1;
789+
shouldScope = shouldScope || part.includes(_polyfillHostNoCombinator);
785790
const scopedPart = shouldScope ? _scopeSelectorPart(part) : part;
786791
scopedSelector += `${scopedPart} ${separator} `;
787792
startIndex = sep.lastIndex;
788793
}
789794

790795
const part = selector.substring(startIndex);
791-
shouldScope = shouldScope || part.indexOf(_polyfillHostNoCombinator) > -1;
796+
shouldScope = shouldScope || part.includes(_polyfillHostNoCombinator);
792797
scopedSelector += shouldScope ? _scopeSelectorPart(part) : part;
793798

794799
// replace the placeholders with their original values

packages/compiler/test/shadow_css/shadow_css_spec.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,13 @@ describe('ShadowCss', () => {
117117
expect(css).toEqualCss('div[contenta]::after { content:"{}"}');
118118
});
119119

120+
it('should keep retain multiline selectors', () => {
121+
// This is needed as shifting in line number will cause sourcemaps to break.
122+
const styleStr = '.foo,\n.bar { color: red;}';
123+
const css = shim(styleStr, 'contenta');
124+
expect(css).toEqual('.foo[contenta], \n.bar[contenta] { color: red;}');
125+
});
126+
120127
describe('comments', () => {
121128
// Comments should be kept in the same position as otherwise inline sourcemaps break due to
122129
// shift in lines.

0 commit comments

Comments
 (0)