Skip to content

Commit 628ab40

Browse files
crisbetokirjs
authored andcommitted
refactor(core): do not store input/output public names (angular#60036)
Reworks the `TNode.inputs` and `TNode.outputs` to not store the public names of bindings. The only reason they were stored was for host directive re-aliasing which is handled through a different data structure now. PR Close angular#60036
1 parent 9f44b41 commit 628ab40

File tree

4 files changed

+50
-51
lines changed

4 files changed

+50
-51
lines changed

packages/core/src/render3/instructions/listener.ts

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {setActiveConsumer} from '@angular/core/primitives/signals';
1010

1111
import {NotificationSource} from '../../change_detection/scheduling/zoneless_scheduling';
1212
import {assertIndexInRange} from '../../util/assert';
13-
import {NodeOutputBindings, TNode, TNodeType} from '../interfaces/node';
13+
import {TNode, TNodeType} from '../interfaces/node';
1414
import {GlobalTargetResolver, Renderer} from '../interfaces/renderer';
1515
import {RElement} from '../interfaces/renderer_dom';
1616
import {isComponentHost, isDirectiveHost} from '../interfaces/type_checks';
@@ -238,36 +238,54 @@ export function listenerInternal(
238238
if (hostDirectiveOutputConfig && hostDirectiveOutputConfig.length) {
239239
for (let i = 0; i < hostDirectiveOutputConfig.length; i += 2) {
240240
const index = hostDirectiveOutputConfig[i] as number;
241-
ngDevMode && assertIndexInRange(lView, index);
242-
const instance = lView[index];
243241
const lookupName = hostDirectiveOutputConfig[i + 1] as string;
244-
const def = tView.data[index] as DirectiveDef<unknown>;
245-
const minifiedName = def.outputs[lookupName];
246-
listenToOutput(tNode, instance, eventName, minifiedName, listenerFn, lCleanup, tCleanup);
242+
listenToOutput(
243+
tNode,
244+
tView,
245+
lView,
246+
index,
247+
lookupName,
248+
eventName,
249+
listenerFn,
250+
lCleanup,
251+
tCleanup,
252+
);
247253
}
248254
}
249255

250256
if (outputConfig && outputConfig.length) {
251-
for (let i = 0; i < outputConfig.length; i += 2) {
252-
const index = outputConfig[i] as number;
253-
ngDevMode && assertIndexInRange(lView, index);
254-
const instance = lView[index];
255-
const minifiedName = outputConfig[i + 1] as string;
256-
listenToOutput(tNode, instance, eventName, minifiedName, listenerFn, lCleanup, tCleanup);
257+
for (const index of outputConfig) {
258+
listenToOutput(
259+
tNode,
260+
tView,
261+
lView,
262+
index,
263+
eventName,
264+
eventName,
265+
listenerFn,
266+
lCleanup,
267+
tCleanup,
268+
);
257269
}
258270
}
259271
}
260272
}
261273

262274
function listenToOutput(
263275
tNode: TNode,
264-
instance: any,
276+
tView: TView,
277+
lView: LView,
278+
index: number,
279+
lookupName: string,
265280
eventName: string,
266-
propertyName: string,
267281
listenerFn: (e?: any) => any,
268282
lCleanup: any[],
269283
tCleanup: any[] | null,
270284
) {
285+
ngDevMode && assertIndexInRange(lView, index);
286+
const instance = lView[index];
287+
const def = tView.data[index] as DirectiveDef<unknown>;
288+
const propertyName = def.outputs[lookupName];
271289
const output = instance[propertyName];
272290

273291
if (ngDevMode && !isOutputSubscribable(output)) {

packages/core/src/render3/instructions/shared.ts

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -324,8 +324,6 @@ function setNgReflectProperties(
324324
return;
325325
}
326326

327-
// TODO: this is identical to the block below, but will diverge in a future refactor.
328-
// Figure out if we still can't consolidate them somehow.
329327
const inputConfig = tNode.inputs?.[publicName];
330328
const hostInputConfig = tNode.hostDirectiveInputs?.[publicName];
331329

@@ -340,11 +338,9 @@ function setNgReflectProperties(
340338

341339
// Note: we set the private name of the input as the reflected property, not the public one.
342340
if (inputConfig) {
343-
for (let i = 0; i < inputConfig.length; i += 2) {
344-
const index = inputConfig[i] as number;
345-
const lookupName = inputConfig[i + 1] as string;
341+
for (const index of inputConfig) {
346342
const def = tView.data[index] as DirectiveDef<unknown>;
347-
setNgReflectProperty(lView, tNode, def.inputs[lookupName][0], value);
343+
setNgReflectProperty(lView, tNode, def.inputs[publicName][0], value);
348344
}
349345
}
350346
}
@@ -636,8 +632,6 @@ export function setInputsForProperty(
636632
const hostDirectiveInputs = tNode.hostDirectiveInputs?.[publicName];
637633
let hasMatch = false;
638634

639-
// TODO: this is identical to the block below, but will diverge in a future refactor.
640-
// Figure out if we still can't consolidate them somehow.
641635
if (hostDirectiveInputs) {
642636
for (let i = 0; i < hostDirectiveInputs.length; i += 2) {
643637
const index = hostDirectiveInputs[i] as number;
@@ -650,13 +644,11 @@ export function setInputsForProperty(
650644
}
651645

652646
if (inputs) {
653-
for (let i = 0; i < inputs.length; i += 2) {
654-
const index = inputs[i] as number;
647+
for (const index of inputs) {
655648
ngDevMode && assertIndexInRange(lView, index);
656-
const privateName = inputs[i + 1] as string;
657649
const instance = lView[index];
658650
const def = tView.data[index] as DirectiveDef<any>;
659-
writeToDirectiveInput(def, instance, privateName, value);
651+
writeToDirectiveInput(def, instance, publicName, value);
660652
hasMatch = true;
661653
}
662654
}

packages/core/src/render3/interfaces/node.ts

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -782,36 +782,28 @@ export interface TLetDeclarationNode extends TNode {
782782
export type TDirectiveHostNode = TElementNode | TContainerNode | TElementContainerNode;
783783

784784
/**
785-
* Store the runtime output names for all the directives.
785+
* Maps the public names of outputs available on a specific node to the index
786+
* of the directive instance that defines the output, for example:
786787
*
787-
* i+0: directive instance index
788-
* i+1: privateName
789-
*
790-
* e.g.
791788
* ```
792789
* {
793-
* "publicName": [0, 'change-minified']
790+
* "publicName": [0, 5]
794791
* }
792+
* ```
795793
*/
796-
export type NodeOutputBindings = Record<string, (number | string)[]>;
794+
export type NodeOutputBindings = Record<string, number[]>;
797795

798796
/**
799-
* Store the runtime input for all directives applied to a node.
800-
*
801-
* This allows efficiently setting the same input on a directive that
802-
* might apply to multiple directives.
803-
*
804-
* i+0: directive instance index
805-
* i+1: privateName
797+
* Maps the public names of inputs applied to a specific node to the index of the
798+
* directive instance to which the input value should be written, for example:
806799
*
807-
* e.g.
808800
* ```
809801
* {
810-
* "publicName": [0, 'change-minified']
802+
* "publicName": [0, 5]
811803
* }
812804
* ```
813805
*/
814-
export type NodeInputBindings = Record<string, (number | string)[]>;
806+
export type NodeInputBindings = Record<string, number[]>;
815807

816808
/**
817809
* This array contains information about input properties that

packages/core/src/render3/view/directives.ts

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -289,18 +289,14 @@ function setupSelectorMatchedInputsOrOutputs<T>(
289289

290290
for (const publicName in aliasMap) {
291291
if (aliasMap.hasOwnProperty(publicName)) {
292-
const value = aliasMap[publicName];
293292
let bindings: NodeInputBindings | NodeOutputBindings;
294-
let privateName: string;
295293
if (mode === BindingType.Inputs) {
296294
bindings = tNode.inputs ??= {};
297-
privateName = publicName;
298295
} else {
299296
bindings = tNode.outputs ??= {};
300-
privateName = value as string;
301297
}
302298
bindings[publicName] ??= [];
303-
bindings[publicName].push(directiveIndex, privateName);
299+
bindings[publicName].push(directiveIndex);
304300
setShadowStylingInputFlags(tNode, publicName);
305301
}
306302
}
@@ -397,10 +393,11 @@ function setupInitialInputs(tNode: TNode, directiveIndex: number, isHostDirectiv
397393
// through the directive def, but we want to do it using the inputs store so that it can
398394
// account for host directive aliases.
399395
const inputConfig = inputs![attrName as string];
400-
for (let j = 0; j < inputConfig.length; j += 2) {
401-
if (inputConfig[j] === directiveIndex) {
396+
397+
for (const index of inputConfig) {
398+
if (index === directiveIndex) {
402399
inputsToStore ??= [];
403-
inputsToStore.push(inputConfig[j + 1] as string, attrs[i + 1] as string);
400+
inputsToStore.push(attrName as string, attrs[i + 1] as string);
404401
// A directive can't have multiple inputs with the same name so we can break here.
405402
break;
406403
}

0 commit comments

Comments
 (0)