refactor(ivy): generatePropertyAliases (#22082)

PR Close #22082
This commit is contained in:
Victor Berchet 2018-02-07 22:19:24 -08:00 committed by Miško Hevery
parent 92a5876f51
commit 61341b2791
2 changed files with 53 additions and 42 deletions

View File

@ -113,6 +113,11 @@ let bindingIndex: number;
*/ */
let cleanup: any[]|null; let cleanup: any[]|null;
const enum BindingDirection {
Input,
Output,
}
/** /**
* Swap the current state with a new state. * Swap the current state with a new state.
* *
@ -581,12 +586,11 @@ export function listener(eventName: string, listener: EventListener, useCapture
if (tNode.outputs === undefined) { if (tNode.outputs === undefined) {
// if we create TNode here, inputs must be undefined so we know they still need to be // if we create TNode here, inputs must be undefined so we know they still need to be
// checked // checked
tNode.outputs = null; tNode.outputs = generatePropertyAliases(node.flags, BindingDirection.Output);
tNode = generatePropertyAliases(node.flags, tNode);
} }
const outputs = tNode.outputs; const outputs = tNode.outputs;
let outputData: (number | string)[]|undefined; let outputData: PropertyAliasValue|undefined;
if (outputs && (outputData = outputs[eventName])) { if (outputs && (outputData = outputs[eventName])) {
createOutput(outputData, listener); createOutput(outputData, listener);
} }
@ -596,7 +600,7 @@ export function listener(eventName: string, listener: EventListener, useCapture
* Iterates through the outputs associated with a particular event name and subscribes to * Iterates through the outputs associated with a particular event name and subscribes to
* each output. * each output.
*/ */
function createOutput(outputs: (number | string)[], listener: Function): void { function createOutput(outputs: PropertyAliasValue, listener: Function): void {
for (let i = 0; i < outputs.length; i += 2) { for (let i = 0; i < outputs.length; i += 2) {
ngDevMode && assertDataInRange(outputs[i] as number); ngDevMode && assertDataInRange(outputs[i] as number);
const subscription = data[outputs[i] as number][outputs[i | 1]].subscribe(listener); const subscription = data[outputs[i] as number][outputs[i | 1]].subscribe(listener);
@ -658,18 +662,16 @@ export function elementAttribute(index: number, attrName: string, value: any): v
export function elementProperty<T>(index: number, propName: string, value: T | NO_CHANGE): void { export function elementProperty<T>(index: number, propName: string, value: T | NO_CHANGE): void {
if (value === NO_CHANGE) return; if (value === NO_CHANGE) return;
const node = data[index] as LElementNode; const node = data[index] as LElementNode;
const tNode = node.tNode !;
let tNode: TNode|null = node.tNode !;
// if tNode.inputs is undefined, a listener has created outputs, but inputs haven't // if tNode.inputs is undefined, a listener has created outputs, but inputs haven't
// yet been checked // yet been checked
if (tNode.inputs === undefined) { if (tNode.inputs === undefined) {
// mark inputs as checked // mark inputs as checked
tNode.inputs = null; tNode.inputs = generatePropertyAliases(node.flags, BindingDirection.Input);
tNode = generatePropertyAliases(node.flags, tNode, true);
} }
const inputData = tNode.inputs; const inputData = tNode.inputs;
let dataValue: PropertyAliasValue|null; let dataValue: PropertyAliasValue|undefined;
if (inputData && (dataValue = inputData[propName])) { if (inputData && (dataValue = inputData[propName])) {
setInputsForProperty(dataValue, value); setInputsForProperty(dataValue, value);
} else { } else {
@ -707,7 +709,7 @@ function createTNode(
* Given a list of directive indices and minified input names, sets the * Given a list of directive indices and minified input names, sets the
* input properties on the corresponding directives. * input properties on the corresponding directives.
*/ */
function setInputsForProperty(inputs: (number | string)[], value: any): void { function setInputsForProperty(inputs: PropertyAliasValue, value: any): void {
for (let i = 0; i < inputs.length; i += 2) { for (let i = 0; i < inputs.length; i += 2) {
ngDevMode && assertDataInRange(inputs[i] as number); ngDevMode && assertDataInRange(inputs[i] as number);
data[inputs[i] as number][inputs[i | 1]] = value; data[inputs[i] as number][inputs[i | 1]] = value;
@ -715,33 +717,37 @@ function setInputsForProperty(inputs: (number | string)[], value: any): void {
} }
/** /**
* This function consolidates all the inputs or outputs defined by directives * Consolidates all inputs or outputs of all directives on this logical node.
* on this node into one object and stores it in tData so it can
* be shared between all templates of this type.
* *
* @param index Index where data should be stored in tData * @param number lNodeFlags logical node flags
* @param Direction direction whether to consider inputs or outputs
* @returns PropertyAliases|null aggregate of all properties if any, `null` otherwise
*/ */
function generatePropertyAliases(flags: number, tNode: TNode, isInputData = false): TNode { function generatePropertyAliases(lNodeFlags: number, direction: BindingDirection): PropertyAliases|
const start = flags >> LNodeFlags.INDX_SHIFT; null {
const size = (flags & LNodeFlags.SIZE_MASK) >> LNodeFlags.SIZE_SHIFT; const size = (lNodeFlags & LNodeFlags.SIZE_MASK) >> LNodeFlags.SIZE_SHIFT;
let propStore: PropertyAliases|null = null;
if (size > 0) {
const start = lNodeFlags >> LNodeFlags.INDX_SHIFT;
const isInput = direction === BindingDirection.Input;
for (let i = start, ii = start + size; i < ii; i++) { for (let i = start, ii = start + size; i < ii; i++) {
const directiveDef: DirectiveDef<any> = tData ![i] as DirectiveDef<any>; const directiveDef = tData ![i] as DirectiveDef<any>;
const propertyAliasMap: {[publicName: string]: string} = const propertyAliasMap: {[publicName: string]: string} =
isInputData ? directiveDef.inputs : directiveDef.outputs; isInput ? directiveDef.inputs : directiveDef.outputs;
for (let publicName in propertyAliasMap) { for (let publicName in propertyAliasMap) {
if (propertyAliasMap.hasOwnProperty(publicName)) { if (propertyAliasMap.hasOwnProperty(publicName)) {
propStore = propStore || {};
const internalName = propertyAliasMap[publicName]; const internalName = propertyAliasMap[publicName];
const staticDirData: PropertyAliases = isInputData ? const hasProperty = propStore.hasOwnProperty(publicName);
(tNode.inputs || (tNode.inputs = {})) : hasProperty ? propStore[publicName].push(i, internalName) :
(tNode.outputs || (tNode.outputs = {})); (propStore[publicName] = [i, internalName]);
const hasProperty: boolean = staticDirData.hasOwnProperty(publicName);
hasProperty ? staticDirData[publicName].push(i, internalName) :
(staticDirData[publicName] = [i, internalName]);
} }
} }
} }
return tNode; }
return propStore;
} }
/** /**
@ -801,7 +807,6 @@ export function elementStyle<T>(
} }
////////////////////////// //////////////////////////
//// Text //// Text
////////////////////////// //////////////////////////

View File

@ -253,16 +253,23 @@ export interface TNode {
*/ */
localNames: (string|number)[]|null; localNames: (string|number)[]|null;
/** /** Information about input properties that need to be set once from attribute data. */
* This property contains information about input properties that
* need to be set once from attribute data.
*/
initialInputs: InitialInputData|null|undefined; initialInputs: InitialInputData|null|undefined;
/** Input data for all directives on this node. */ /**
* Input data for all directives on this node.
*
* - `undefined` means that the prop has not been initialized yet,
* - `null` means that the prop has been initialized but no inputs have been found.
*/
inputs: PropertyAliases|null|undefined; inputs: PropertyAliases|null|undefined;
/** Output data for all directives on this node. */ /**
* Output data for all directives on this node.
*
* - `undefined` means that the prop has not been initialized yet,
* - `null` means that the prop has been initialized but no outputs have been found.
*/
outputs: PropertyAliases|null|undefined; outputs: PropertyAliases|null|undefined;
/** /**
@ -298,11 +305,10 @@ export type PropertyAliases = {
}; };
/** /**
* The value in PropertyAliases. * Store the runtime input or output names for all the directives.
* *
* In each array: * - Even indices: directive index
* Even indices: directive index * - Odd indices: minified / internal name
* Odd indices: minified / internal name
* *
* e.g. [0, 'change-minified'] * e.g. [0, 'change-minified']
*/ */