Skip to content

Commit

Permalink
refactor(compiler): Not all attribute values beginning with a colon a…
Browse files Browse the repository at this point in the history
…re namespaced (#53574)

TemplateDefinitionBuilder is apparently more careful about when it attempts to split namespaces in attribute values. However, we are doing this on style attributes, which might start with a single `:`. Rather than refactor our logic to only try to split namespaces in some cases, we can just add an option to make namespace splitting fail gracefully. We only use this option for attributes, not elements.

Note also: the compiled code for this, while "correct" is absolutely insane. Maybe we should consider fixing this, as a matter of principle.

PR Close #53574
  • Loading branch information
dylhunn authored and thePunderWoman committed Dec 15, 2023
1 parent 7ef5d9d commit c987945
Show file tree
Hide file tree
Showing 6 changed files with 67 additions and 3 deletions.
Expand Up @@ -323,3 +323,34 @@ export declare class MyModule {
static ɵinj: i0.ɵɵInjectorDeclaration<MyModule>;
}

/****************************************************************************************************
* PARTIAL FILE: colon_style.js
****************************************************************************************************/
import { Component } from '@angular/core';
import * as i0 from "@angular/core";
export class MyComponent {
}
MyComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: MyComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
MyComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "0.0.0-PLACEHOLDER", type: MyComponent, isStandalone: true, selector: "my-component", ngImport: i0, template: `
<div style=":root {color: red;}"></div>
`, isInline: true });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: MyComponent, decorators: [{
type: Component,
args: [{
selector: 'my-component',
standalone: true,
template: `
<div style=":root {color: red;}"></div>
`
}]
}] });

/****************************************************************************************************
* PARTIAL FILE: colon_style.d.ts
****************************************************************************************************/
import * as i0 from "@angular/core";
export declare class MyComponent {
static ɵfac: i0.ɵɵFactoryDeclaration<MyComponent, never>;
static ɵcmp: i0.ɵɵComponentDeclaration<MyComponent, "my-component", never, {}, {}, never, never, true, never>;
}

Expand Up @@ -60,6 +60,16 @@
"files": ["empty_style_bindings.js"]
}
]
},
{
"description": "should support style bindings with a colon at the start of the applied style",
"inputFiles": ["colon_style.ts"],
"expectations": [
{
"failureMessage": "Incorrect template",
"files": ["colon_style.js"]
}
]
}
]
}
@@ -0,0 +1,8 @@
// NOTE: This is the way TemplateDefinitionBuilder behaves today, but it's crazy!!
// NOTE: TODO: Should we fix it?
consts: [[__AttributeMarker.Styles__, ":root {color", "red"]],
template: function MyComponent_Template(rf, ctx) {
if (rf & 1) {
i0.ɵɵelement(0, "div", 0);
}
}
@@ -0,0 +1,11 @@
import {Component} from '@angular/core';

@Component({
selector: 'my-component',
standalone: true,
template: `
<div style=":root {color: red;}"></div>
`
})
export class MyComponent {
}
8 changes: 6 additions & 2 deletions packages/compiler/src/ml_parser/tags.ts
Expand Up @@ -24,15 +24,19 @@ export interface TagDefinition {
getContentType(prefix?: string): TagContentType;
}

export function splitNsName(elementName: string): [string|null, string] {
export function splitNsName(elementName: string, fatal: boolean = true): [string|null, string] {
if (elementName[0] != ':') {
return [null, elementName];
}

const colonIndex = elementName.indexOf(':', 1);

if (colonIndex === -1) {
throw new Error(`Unsupported format "${elementName}" expecting ":namespace:name"`);
if (fatal) {
throw new Error(`Unsupported format "${elementName}" expecting ":namespace:name"`);
} else {
return [null, elementName];
}
}

return [elementName.slice(1, colonIndex), elementName.slice(colonIndex + 1)];
Expand Down
Expand Up @@ -161,7 +161,7 @@ class ElementAttributes {
* Gets an array of literal expressions representing the attribute's namespaced name.
*/
function getAttributeNameLiterals(name: string): o.LiteralExpr[] {
const [attributeNamespace, attributeName] = splitNsName(name);
const [attributeNamespace, attributeName] = splitNsName(name, false);
const nameLiteral = o.literal(attributeName);

if (attributeNamespace) {
Expand Down

0 comments on commit c987945

Please sign in to comment.