Skip to content

Commit 82009a5

Browse files
mmalerbadylhunn
authored andcommitted
refactor(compiler): Make ElementAttributes an implementation detail (angular#51258)
Refactors ElementAttributes to be an implementation detail of the const collection phase, rather than an object that is added to all ElementOps. PR Close angular#51258
1 parent aa9223e commit 82009a5

6 files changed

Lines changed: 127 additions & 144 deletions

File tree

packages/compiler/src/template/pipeline/ir/index.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,8 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
export * from './src/element';
10-
export * from './src/expression';
119
export * from './src/enums';
10+
export * from './src/expression';
1211
export * from './src/operations';
1312
export * from './src/ops/create';
1413
export * from './src/ops/host';

packages/compiler/src/template/pipeline/ir/src/element.ts

Lines changed: 0 additions & 129 deletions
This file was deleted.

packages/compiler/src/template/pipeline/ir/src/enums.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,3 +299,43 @@ export enum SanitizerFn {
299299
ResourceUrl,
300300
IframeAttribute,
301301
}
302+
303+
/**
304+
* Enumeration of the types of attributes which can be applied to an element.
305+
*/
306+
export enum BindingKind {
307+
/**
308+
* Static attributes.
309+
*/
310+
Attribute,
311+
312+
/**
313+
* Class bindings.
314+
*/
315+
ClassName,
316+
317+
/**
318+
* Style bindings.
319+
*/
320+
StyleProperty,
321+
322+
/**
323+
* Dynamic property bindings.
324+
*/
325+
Property,
326+
327+
/**
328+
* Property or attribute bindings on a template.
329+
*/
330+
Template,
331+
332+
/**
333+
* Internationalized attributes.
334+
*/
335+
I18n,
336+
337+
/**
338+
* Animation property bindings.
339+
*/
340+
Animation,
341+
}

packages/compiler/src/template/pipeline/ir/src/ops/create.ts

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@
88

99
import * as o from '../../../../../output/output_ast';
1010
import {ParseSourceSpan} from '../../../../../parse_util';
11-
import {BindingKind, ElementAttributes} from '../element';
12-
import {OpKind} from '../enums';
11+
import {BindingKind, OpKind} from '../enums';
1312
import {Op, OpList, XrefId} from '../operations';
1413
import {ConsumesSlotOpTrait, TRAIT_CONSUMES_SLOT, TRAIT_USES_SLOT_INDEX, UsesSlotIndexTrait} from '../traits';
1514

@@ -75,15 +74,10 @@ export interface ElementOrContainerOpBase extends Op<CreateOp>, ConsumesSlotOpTr
7574
xref: XrefId;
7675

7776
/**
78-
* Attributes of various kinds on this element.
79-
*
80-
* Before attribute processing, this is an `ElementAttributes` structure representing the
81-
* attributes on this element.
82-
*
83-
* After processing, it's a `ConstIndex` pointer into the shared `consts` array of the component
84-
* compilation.
77+
* Attributes of various kinds on this element. Represented as a `ConstIndex` pointer into the
78+
* shared `consts` array of the component compilation.
8579
*/
86-
attributes: ElementAttributes|ConstIndex|null;
80+
attributes: ConstIndex|null;
8781

8882
/**
8983
* Local references to this element.

packages/compiler/src/template/pipeline/ir/src/ops/update.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,7 @@
99
import {SecurityContext} from '../../../../../core';
1010
import * as o from '../../../../../output/output_ast';
1111
import {ParseSourceSpan} from '../../../../../parse_util';
12-
import {BindingKind} from '../element';
13-
import {OpKind} from '../enums';
12+
import {BindingKind, OpKind} from '../enums';
1413
import {Op, XrefId} from '../operations';
1514
import {ConsumesVarsTrait, DependsOnSlotContextOpTrait, TRAIT_CONSUMES_VARS, TRAIT_DEPENDS_ON_SLOT_CONTEXT} from '../traits';
1615

packages/compiler/src/template/pipeline/src/phases/const_collection.ts

Lines changed: 81 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77
*/
88

99
import * as core from '../../../../core';
10+
import {splitNsName} from '../../../../ml_parser/tags';
1011
import * as o from '../../../../output/output_ast';
1112
import * as ir from '../../ir';
12-
import {ElementAttributes} from '../../ir/src/element';
1313
import {ComponentCompilationJob} from '../compilation';
1414

1515
/**
@@ -47,6 +47,86 @@ export function phaseConstCollection(cpl: ComponentCompilationJob): void {
4747
}
4848
}
4949

50+
/**
51+
* Shared instance of an empty array to avoid unnecessary array allocations.
52+
*/
53+
const FLYWEIGHT_ARRAY: ReadonlyArray<o.Expression> = Object.freeze<o.Expression[]>([]);
54+
55+
/**
56+
* Container for all of the various kinds of attributes which are applied on an element.
57+
*/
58+
class ElementAttributes {
59+
private known = new Set<string>();
60+
private byKind = new Map<ir.BindingKind, o.Expression[]>;
61+
62+
projectAs: string|null = null;
63+
64+
get attributes(): ReadonlyArray<o.Expression> {
65+
return this.byKind.get(ir.BindingKind.Attribute) ?? FLYWEIGHT_ARRAY;
66+
}
67+
68+
get classes(): ReadonlyArray<o.Expression> {
69+
return this.byKind.get(ir.BindingKind.ClassName) ?? FLYWEIGHT_ARRAY;
70+
}
71+
72+
get styles(): ReadonlyArray<o.Expression> {
73+
return this.byKind.get(ir.BindingKind.StyleProperty) ?? FLYWEIGHT_ARRAY;
74+
}
75+
76+
get bindings(): ReadonlyArray<o.Expression> {
77+
return this.byKind.get(ir.BindingKind.Property) ?? FLYWEIGHT_ARRAY;
78+
}
79+
80+
get template(): ReadonlyArray<o.Expression> {
81+
return this.byKind.get(ir.BindingKind.Template) ?? FLYWEIGHT_ARRAY;
82+
}
83+
84+
get i18n(): ReadonlyArray<o.Expression> {
85+
return this.byKind.get(ir.BindingKind.I18n) ?? FLYWEIGHT_ARRAY;
86+
}
87+
88+
add(kind: ir.BindingKind, name: string, value: o.Expression|null): void {
89+
if (this.known.has(name)) {
90+
return;
91+
}
92+
this.known.add(name);
93+
const array = this.arrayFor(kind);
94+
array.push(...getAttributeNameLiterals(name));
95+
if (kind === ir.BindingKind.Attribute || kind === ir.BindingKind.StyleProperty) {
96+
if (value === null) {
97+
throw Error('Attribute & style element attributes must have a value');
98+
}
99+
array.push(value);
100+
}
101+
}
102+
103+
private arrayFor(kind: ir.BindingKind): o.Expression[] {
104+
if (!this.byKind.has(kind)) {
105+
this.byKind.set(kind, []);
106+
}
107+
return this.byKind.get(kind)!;
108+
}
109+
}
110+
111+
/**
112+
* Gets an array of literal expressions representing the attribute's namespaced name.
113+
*/
114+
function getAttributeNameLiterals(name: string): o.LiteralExpr[] {
115+
const [attributeNamespace, attributeName] = splitNsName(name);
116+
const nameLiteral = o.literal(attributeName);
117+
118+
if (attributeNamespace) {
119+
return [
120+
o.literal(core.AttributeMarker.NamespaceURI), o.literal(attributeNamespace), nameLiteral
121+
];
122+
}
123+
124+
return [nameLiteral];
125+
}
126+
127+
/**
128+
* Serializes an ElementAttributes object into an array expression.
129+
*/
50130
function serializeAttributes({attributes, bindings, classes, i18n, projectAs, styles, template}:
51131
ElementAttributes): o.LiteralArrayExpr {
52132
const attrArray = [...attributes];

0 commit comments

Comments
 (0)