fix(core): error if CSS custom property in host binding has number in name (#38432)

Fixes an error if a CSS custom property, used inside a host binding, has a
number in its name. The error is thrown because the styling parser only
expects characters from A to Z,dashes, underscores and a handful of other
characters.

Fixes #37292.

PR Close #38432
This commit is contained in:
crisbeto 2020-08-13 08:02:59 +02:00 committed by Andrew Scott
parent aa847cb014
commit a80f654af9
3 changed files with 35 additions and 9 deletions

View File

@ -210,7 +210,8 @@ export function consumeStyleKey(text: string, startIndex: number, endIndex: numb
let ch: number; let ch: number;
while (startIndex < endIndex && while (startIndex < endIndex &&
((ch = text.charCodeAt(startIndex)) === CharCode.DASH || ch === CharCode.UNDERSCORE || ((ch = text.charCodeAt(startIndex)) === CharCode.DASH || ch === CharCode.UNDERSCORE ||
((ch & CharCode.UPPER_CASE) >= CharCode.A && (ch & CharCode.UPPER_CASE) <= CharCode.Z))) { ((ch & CharCode.UPPER_CASE) >= CharCode.A && (ch & CharCode.UPPER_CASE) <= CharCode.Z) ||
(ch >= CharCode.ZERO && ch <= CharCode.NINE))) {
startIndex++; startIndex++;
} }
return startIndex; return startIndex;

View File

@ -22,6 +22,8 @@ export const enum CharCode {
SEMI_COLON = 59, // ";" SEMI_COLON = 59, // ";"
BACK_SLASH = 92, // "\\" BACK_SLASH = 92, // "\\"
AT_SIGN = 64, // "@" AT_SIGN = 64, // "@"
ZERO = 48, // "0"
NINE = 57, // "9"
A = 65, // "A" A = 65, // "A"
U = 85, // "U" U = 85, // "U"
R = 82, // "R" R = 82, // "R"

View File

@ -214,28 +214,51 @@ describe('styling', () => {
}); });
}); });
describe('css variables', () => { onlyInIvy('CSS variables are only supported in Ivy').describe('css variables', () => {
onlyInIvy('css variables').it('should support css variables', () => { const supportsCssVariables = typeof getComputedStyle !== 'undefined' &&
typeof CSS !== 'undefined' && typeof CSS.supports !== 'undefined' &&
CSS.supports('color', 'var(--fake-var)');
it('should support css variables', () => {
// This test only works in browsers which support CSS variables. // This test only works in browsers which support CSS variables.
if (!(typeof getComputedStyle !== 'undefined' && typeof CSS !== 'undefined' && if (!supportsCssVariables) {
typeof CSS.supports !== 'undefined' && CSS.supports('color', 'var(--fake-var)')))
return; return;
}
@Component({ @Component({
template: ` template: `
<div [style.--my-var]=" '100px' "> <div [style.--my-var]="'100px'">
<span style="width: var(--my-var)">CONTENT</span> <span style="width: var(--my-var)">CONTENT</span>
</div>` </div>
`
}) })
class Cmp { class Cmp {
} }
TestBed.configureTestingModule({declarations: [Cmp]}); TestBed.configureTestingModule({declarations: [Cmp]});
const fixture = TestBed.createComponent(Cmp); const fixture = TestBed.createComponent(Cmp);
// document.body.appendChild(fixture.nativeElement);
fixture.detectChanges(); fixture.detectChanges();
const span = fixture.nativeElement.querySelector('span') as HTMLElement; const span = fixture.nativeElement.querySelector('span') as HTMLElement;
expect(getComputedStyle(span).getPropertyValue('width')).toEqual('100px'); expect(getComputedStyle(span).getPropertyValue('width')).toEqual('100px');
}); });
it('should support css variables with numbers in their name inside a host binding', () => {
// This test only works in browsers which support CSS variables.
if (!supportsCssVariables) {
return;
}
@Component({template: `<h1 style="width: var(--my-1337-var)">Hello</h1>`})
class Cmp {
@HostBinding('style') style = '--my-1337-var: 100px;';
}
TestBed.configureTestingModule({declarations: [Cmp]});
const fixture = TestBed.createComponent(Cmp);
fixture.detectChanges();
const header = fixture.nativeElement.querySelector('h1') as HTMLElement;
expect(getComputedStyle(header).getPropertyValue('width')).toEqual('100px');
});
}); });
modifiedInIvy('shadow bindings include static portion') modifiedInIvy('shadow bindings include static portion')