fix(ivy): verify Host Bindings and Host Listeners before compiling them (#28356)

Prior to this change we may encounter some errors (like pipes being used where they should not be used) while compiling Host Bindings and Listeners. With this update we move validation logic to the analyze phase and throw an error if something is wrong. This also aligns error messages between Ivy and VE.

PR Close #28356
This commit is contained in:
Andrew Kushnir
2019-01-24 17:25:46 -08:00
committed by Jason Aden
parent ad499628cb
commit 76cedb8bf3
11 changed files with 175 additions and 49 deletions

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {ConstantPool, Expression, R3DirectiveMetadata, R3QueryMetadata, Statement, WrappedNodeExpr, compileDirectiveFromMetadata, makeBindingParser, parseHostBindings} from '@angular/compiler';
import {ConstantPool, Expression, ParseError, R3DirectiveMetadata, R3QueryMetadata, Statement, WrappedNodeExpr, compileDirectiveFromMetadata, makeBindingParser, parseHostBindings, verifyHostBindings} from '@angular/compiler';
import * as ts from 'typescript';
import {ErrorCode, FatalDiagnosticError} from '../../diagnostics';
@ -437,7 +437,17 @@ function extractHostBindings(
});
}
const {attributes, listeners, properties} = parseHostBindings(hostMetadata);
const bindings = parseHostBindings(hostMetadata);
// TODO: create and provide proper sourceSpan to make error message more descriptive (FW-995)
const errors = verifyHostBindings(bindings, /* sourceSpan */ null !);
if (errors.length > 0) {
throw new FatalDiagnosticError(
// TODO: provide more granular diagnostic and output specific host expression that triggered
// an error instead of the whole host object
ErrorCode.HOST_BINDING_PARSE_ERROR, metadata.get('host') !,
errors.map((error: ParseError) => error.msg).join('\n'));
}
filterToMembersWithDecorator(members, 'HostBinding', coreModule)
.forEach(({member, decorators}) => {
@ -456,7 +466,7 @@ function extractHostBindings(
hostPropertyName = resolved;
}
properties[hostPropertyName] = member.name;
bindings.properties[hostPropertyName] = member.name;
});
});
@ -492,10 +502,10 @@ function extractHostBindings(
}
}
listeners[eventName] = `${member.name}(${args.join(',')})`;
bindings.listeners[eventName] = `${member.name}(${args.join(',')})`;
});
});
return {attributes, properties, listeners};
return bindings;
}
const QUERY_TYPES = new Set([

View File

@ -24,6 +24,12 @@ export enum ErrorCode {
SYMBOL_EXPORTED_UNDER_DIFFERENT_NAME = 3002,
CONFIG_FLAT_MODULE_NO_INDEX = 4001,
/**
* Raised when a host expression has a parse error, such as a host listener or host binding
* expression containing a pipe.
*/
HOST_BINDING_PARSE_ERROR = 5001,
}
export function ngErrorCode(code: ErrorCode): number {