Sitelet https://github.com/angular/angular/commit/b6f9cc5d7013f8f136b38cccfe486264200f04f5
Skip to content

Commit b6f9cc5

Browse files
jhjh1214amishne
authored andcommitted
fix(compiler): do not scope comments placed inside of a selector
Comments are replaced with a placeholder before the styles are scoped. A comment that is placed inside of a selector, e.g. `.a /* comment */ {}` or `.a, /* comment */ .b {}`, ended up as its own selector part and got the content attribute appended, which changed what the rule matches (e.g. `.a[c] [c] {}` and `.a[c], [c] .b[c] {}`). Parts that only consist of comment placeholders are now left untouched. (cherry picked from commit 8acf703)
1 parent e59a230 commit b6f9cc5

2 files changed

Lines changed: 37 additions & 1 deletion

File tree

‎packages/compiler/src/shadow_css.ts‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -753,7 +753,9 @@ export class ShadowCss {
753753
const _scopeSelectorPart = (p: string) => {
754754
let scopedP = p.trim();
755755

756-
if (!scopedP || scopedP === '&') {
756+
// Comments are replaced with placeholders before scoping. A part that only consists of
757+
// comments is not a selector and must be left untouched.
758+
if (!scopedP || scopedP === '&' || _onlyCommentPlaceholdersRe.test(scopedP)) {
757759
return p;
758760
}
759761

@@ -1031,6 +1033,7 @@ const _commentRe = /\/\*[\s\S]*?\*\//g;
10311033
const _commentWithHashRe = /\/\*\s*#\s*source(Mapping)?URL=/g;
10321034
const COMMENT_PLACEHOLDER = '%COMMENT%';
10331035
const _commentWithHashPlaceHolderRe = new RegExp(COMMENT_PLACEHOLDER, 'g');
1036+
const _onlyCommentPlaceholdersRe = new RegExp(`^(?:${COMMENT_PLACEHOLDER})+$`);
10341037

10351038
const BLOCK_PLACEHOLDER = '%BLOCK%';
10361039
const _ruleRe = new RegExp(

‎packages/compiler/test/shadow_css/shadow_css_spec.ts‎

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,39 @@ describe('ShadowCss', () => {
390390
it('should handle adjacent comments', () => {
391391
expect(shim('/* comment 1 */ /* comment 2 */ b {}', 'contenta')).toBe(' b[contenta] {}');
392392
});
393+
394+
it('should not scope comments that are placed between a selector and its block', () => {
395+
expect(shim('.a /* comment */ {}', 'contenta')).toBe('.a[contenta] {}');
396+
});
397+
398+
it('should not scope comments that are placed between selectors of a list', () => {
399+
expect(shim('.a, /* comment */ .b {}', 'contenta')).toBe('.a[contenta], .b[contenta] {}');
400+
expect(shim('.a /* comment */, .b {}', 'contenta')).toBe('.a[contenta] , .b[contenta] {}');
401+
});
402+
403+
it('should not scope comments that are placed between compound selectors', () => {
404+
expect(shim('.a /* comment */ .b {}', 'contenta')).toBe('.a[contenta] .b[contenta] {}');
405+
expect(shim('.a > /* comment */ .b {}', 'contenta')).toBe(
406+
'.a[contenta] > .b[contenta] {}',
407+
);
408+
expect(shim('.a /* c1 */ /* c2 */ .b {}', 'contenta')).toBe(
409+
'.a[contenta] .b[contenta] {}',
410+
);
411+
});
412+
413+
it('should not scope comments inside of :host and pseudo selector functions', () => {
414+
expect(shim(':host /* comment */ .b {}', 'contenta', 'a-host')).toBe(
415+
'[a-host] .b[contenta] {}',
416+
);
417+
expect(shim(':is(.a, /* comment */ .b) {}', 'contenta')).toBe(
418+
':is(.a[contenta], .b[contenta]) {}',
419+
);
420+
});
421+
422+
it('should scope compound selectors that contain a comment', () => {
423+
expect(shim('.a/* comment */.b {}', 'contenta')).toBe('.a.b[contenta] {}');
424+
expect(shim('.a/* comment */:hover {}', 'contenta')).toBe('.a[contenta]:hover {}');
425+
});
393426
});
394427

395428
describe('CSS variable namespacing', () => {

0 commit comments

Comments
 (0)