Compare commits

...

10 Commits

Author SHA1 Message Date
0776daec88 release: cut the v8.0.0-rc.1 release 2019-04-26 13:28:49 -07:00
615e1a58b2 test(ivy): pin deps on hello world size tests (#30152)
We recently had an unexpected size regression in the hello world
tests because the CLI devkit released an RC that regressed us and
the dependencies were not pinned. This change ensures that we only
update dependencies like devkit deliberately, so we do not have
mysterious breakages caused by other packages.

PR Close #30152
2019-04-26 12:34:10 -07:00
606758357e fix(bazel): update peerDep ranges (#30155)
PR Close #30155
2019-04-26 12:32:35 -07:00
ba2a3595c6 fix(ivy): output should not be subscribe twice when 2 listeners (#30144)
PR Close #30144
2019-04-26 11:11:09 -07:00
a50bfe5054 fix(ivy): property bindings use correct indices (#30129)
- Extracts and documents code that will be common to interpolation instructions
- Ensures that binding indices are updated at the proper time during compilation
- Adds additional tests

Related #30011

PR Close #30129
2019-04-26 11:09:51 -07:00
c8983bc367 docs: remove note about ivy being coupled to dynamic import (#30151)
PR Close #30151
2019-04-26 11:08:51 -07:00
8d6d2c6704 build: bazel ts-api-guardian usage fails on workspaces which don't depend on chalk (#30138)
When using the npm package in a workspace which doesn't depend on chalk, ts-api-guardian fails with an error `Error: Cannot find module 'chalk'`

PR Close #30138
2019-04-26 11:08:05 -07:00
6711f22e62 fix(bazel): Exclude common/upgrade* in metadata.tsconfig.json (#30133)
It has a dependency on @angular/upgrade which is not part of the
dependencies in package.json, so postinstall would fail.

PR Close #30133
2019-04-26 11:07:34 -07:00
8dd9192fe3 refactor(ivy): undeprecate inject (#30132)
PR Close #30132
2019-04-26 11:06:42 -07:00
870e0dab48 fix(ivy): remove debug utilities from ivy production builds (#30130)
Prior to this commit, we were pulling DebugNode and DebugElement
into production builds because BrowserModule automatically pulled
in NgProbe and thus getDebugNode. In Ivy, this is not necessary
because Ivy has its own set of debug utilities. We should use these
existing tools instead of NgProbe.

This commit adds an Ivy switch so we do not pull in NgProbe utilities
when running with Ivy. This saves us ~8KB in prod builds.

PR Close #30130
2019-04-26 11:04:48 -07:00
24 changed files with 405 additions and 107 deletions

View File

@ -1,3 +1,14 @@
<a name="8.0.0-rc.1"></a>
# [8.0.0-rc.1](https://github.com/angular/angular/compare/8.0.0-rc.0...8.0.0-rc.1) (2019-04-26)
### Bug Fixes
* **bazel:** Exclude common/upgrade* in metadata.tsconfig.json ([#30133](https://github.com/angular/angular/issues/30133)) ([6711f22](https://github.com/angular/angular/commit/6711f22))
* **bazel:** update peerDep ranges ([#30155](https://github.com/angular/angular/issues/30155)) ([6067583](https://github.com/angular/angular/commit/6067583))
<a name="8.0.0-rc.0"></a> <a name="8.0.0-rc.0"></a>
# [8.0.0-rc.0](https://github.com/angular/angular/compare/8.0.0-beta.14...8.0.0-rc.0) (2019-04-25) # [8.0.0-rc.0](https://github.com/angular/angular/compare/8.0.0-beta.14...8.0.0-rc.0) (2019-04-25)

View File

@ -223,9 +223,7 @@ const routes: Routes = [{
<div class="alert is-helpful"> <div class="alert is-helpful">
**v8 update**: When you update to version 8, the [`ng update`](cli/update) command performs the transformation automatically. Prior to version 7, the `import()` syntax works in JIT mode (with view engine). **v8 update**: When you update to version 8, the [`ng update`](cli/update) command performs the transformation automatically. Prior to version 7, the `import()` syntax only works in JIT mode (with view engine).
**Ivy:** If you are using Ivy, you must update your lazy routes to the new dynamic import syntax. See the [Ivy guide](guide/ivy) for more information.
</div> </div>

View File

@ -3,7 +3,7 @@
"master": { "master": {
"uncompressed": { "uncompressed": {
"runtime": 1497, "runtime": 1497,
"main": 167065, "main": 164945,
"polyfills": 43626 "polyfills": 43626
} }
} }
@ -12,7 +12,7 @@
"master": { "master": {
"uncompressed": { "uncompressed": {
"runtime": 1440, "runtime": 1440,
"main": 30932, "main": 14487,
"polyfills": 43567 "polyfills": 43567
} }
} }
@ -21,7 +21,7 @@
"master": { "master": {
"uncompressed": { "uncompressed": {
"runtime": 1440, "runtime": 1440,
"main": 157393, "main": 149205,
"polyfills": 43567 "polyfills": 43567
} }
} }

View File

@ -9,7 +9,7 @@ function installLocalPackages() {
readonly pwd=$(pwd) readonly pwd=$(pwd)
readonly packages=( readonly packages=(
animations common compiler core forms platform-browser animations common compiler core forms platform-browser
platform-browser-dynamic router bazel compiler-cli language-service upgrade platform-browser-dynamic router bazel compiler-cli language-service
) )
local local_packages=() local local_packages=()
for package in "${packages[@]}"; do for package in "${packages[@]}"; do

View File

@ -23,6 +23,7 @@
"node_modules/@angular/core/schematics/**", "node_modules/@angular/core/schematics/**",
"node_modules/@angular/compiler-cli/**", "node_modules/@angular/compiler-cli/**",
"node_modules/@angular/**/testing/**", "node_modules/@angular/**/testing/**",
"node_modules/@angular/common/upgrade*",
"node_modules/@angular/router/upgrade*" "node_modules/@angular/router/upgrade*"
] ]
} }

View File

@ -10,7 +10,6 @@
"@angular/platform-browser": "packages-dist:platform-browser", "@angular/platform-browser": "packages-dist:platform-browser",
"@angular/platform-browser-dynamic": "packages-dist:platform-browser-dynamic", "@angular/platform-browser-dynamic": "packages-dist:platform-browser-dynamic",
"@angular/router": "packages-dist:router", "@angular/router": "packages-dist:router",
"@angular/upgrade": "packages-dist:upgrade",
"reflect-metadata": "0.1.12", "reflect-metadata": "0.1.12",
"rxjs": "6.4.0", "rxjs": "6.4.0",
"tslib": "1.9.3", "tslib": "1.9.3",
@ -31,4 +30,4 @@
"postinstall": "ngc -p ./angular-metadata.tsconfig.json", "postinstall": "ngc -p ./angular-metadata.tsconfig.json",
"//": "TODO(gregmagolan): figure out how to keep dependencies here up to date with the root package.json" "//": "TODO(gregmagolan): figure out how to keep dependencies here up to date with the root package.json"
} }
} }

View File

@ -28,7 +28,7 @@
"zone.js": "file:../../node_modules/zone.js" "zone.js": "file:../../node_modules/zone.js"
}, },
"devDependencies": { "devDependencies": {
"@angular-devkit/build-angular": "^0.800.0-beta.11", "@angular-devkit/build-angular": "0.800.0-beta.15",
"@angular/cli": "file:../../node_modules/@angular/cli", "@angular/cli": "file:../../node_modules/@angular/cli",
"@angular/compiler-cli": "file:../../dist/packages-dist/compiler-cli", "@angular/compiler-cli": "file:../../dist/packages-dist/compiler-cli",
"@angular/language-service": "file:../../dist/packages-dist/language-service", "@angular/language-service": "file:../../dist/packages-dist/language-service",

View File

@ -28,7 +28,7 @@
"zone.js": "file:../../node_modules/zone.js" "zone.js": "file:../../node_modules/zone.js"
}, },
"devDependencies": { "devDependencies": {
"@angular-devkit/build-angular": "^0.800.0-beta.11", "@angular-devkit/build-angular": "0.800.0-beta.15",
"@angular/cli": "file:../../node_modules/@angular/cli", "@angular/cli": "file:../../node_modules/@angular/cli",
"@angular/compiler-cli": "file:../../dist/packages-dist/compiler-cli", "@angular/compiler-cli": "file:../../dist/packages-dist/compiler-cli",
"@angular/language-service": "file:../../dist/packages-dist/language-service", "@angular/language-service": "file:../../dist/packages-dist/language-service",

View File

@ -28,7 +28,7 @@
"zone.js": "file:../../node_modules/zone.js" "zone.js": "file:../../node_modules/zone.js"
}, },
"devDependencies": { "devDependencies": {
"@angular-devkit/build-angular": "^0.800.0-beta.11", "@angular-devkit/build-angular": "0.800.0-beta.15",
"@angular/cli": "file:../../node_modules/@angular/cli", "@angular/cli": "file:../../node_modules/@angular/cli",
"@angular/compiler-cli": "file:../../dist/packages-dist/compiler-cli", "@angular/compiler-cli": "file:../../dist/packages-dist/compiler-cli",
"@angular/language-service": "file:../../dist/packages-dist/language-service", "@angular/language-service": "file:../../dist/packages-dist/language-service",

View File

@ -1,6 +1,6 @@
{ {
"name": "angular-srcs", "name": "angular-srcs",
"version": "8.0.0-rc.0", "version": "8.0.0-rc.1",
"private": true, "private": true,
"branchPattern": "2.0.*", "branchPattern": "2.0.*",
"description": "Angular - a web framework for modern web apps", "description": "Angular - a web framework for modern web apps",

View File

@ -34,11 +34,11 @@
"@types/node": "6.0.84", "@types/node": "6.0.84",
"semver": "^5.6.0", "semver": "^5.6.0",
"shelljs": "0.8.2", "shelljs": "0.8.2",
"tsickle": "0.34.3" "tsickle": "^0.35.0"
}, },
"peerDependencies": { "peerDependencies": {
"@angular/compiler-cli": "0.0.0-PLACEHOLDER", "@angular/compiler-cli": "0.0.0-PLACEHOLDER",
"@bazel/typescript": "0.27.12", "@bazel/typescript": "0.*",
"typescript": ">=3.4 <3.5" "typescript": ">=3.4 <3.5"
}, },
"repository": { "repository": {

View File

@ -20,6 +20,7 @@
"node_modules/@angular/core/schematics/**", "node_modules/@angular/core/schematics/**",
"node_modules/@angular/compiler-cli/**", "node_modules/@angular/compiler-cli/**",
"node_modules/@angular/**/testing/**", "node_modules/@angular/**/testing/**",
"node_modules/@angular/common/upgrade*",
"node_modules/@angular/router/upgrade*" "node_modules/@angular/router/upgrade*"
] ]
} }

View File

@ -470,7 +470,7 @@ describe('compiler compliance: bindings', () => {
if (rf & 2) { if (rf & 2) {
i0.ɵɵselect(0); i0.ɵɵselect(0);
i0.ɵɵpropertyInterpolateV("title", "a", ctx.one, "b", ctx.two, "c", ctx.three, "d", ctx.four, "e", ctx.five, "f", ctx.six, "g", ctx.seven, "h", ctx.eight, "i", ctx.nine, "j"); i0.ɵɵpropertyInterpolateV("title", ["a", ctx.one, "b", ctx.two, "c", ctx.three, "d", ctx.four, "e", ctx.five, "f", ctx.six, "g", ctx.seven, "h", ctx.eight, "i", ctx.nine, "j"]);
i0.ɵɵselect(1); i0.ɵɵselect(1);
i0.ɵɵpropertyInterpolate8("title", "a", ctx.one, "b", ctx.two, "c", ctx.three, "d", ctx.four, "e", ctx.five, "f", ctx.six, "g", ctx.seven, "h", ctx.eight, "i"); i0.ɵɵpropertyInterpolate8("title", "a", ctx.one, "b", ctx.two, "c", ctx.three, "d", ctx.four, "e", ctx.five, "f", ctx.six, "g", ctx.seven, "h", ctx.eight, "i");
i0.ɵɵselect(2); i0.ɵɵselect(2);

View File

@ -155,16 +155,12 @@ export function convertPropertyBinding(
localResolver = new DefaultLocalResolver(); localResolver = new DefaultLocalResolver();
} }
const currValExpr = createCurrValueExpr(bindingId); const currValExpr = createCurrValueExpr(bindingId);
const stmts: o.Statement[] = [];
const visitor = const visitor =
new _AstToIrVisitor(localResolver, implicitReceiver, bindingId, interpolationFunction); new _AstToIrVisitor(localResolver, implicitReceiver, bindingId, interpolationFunction);
const outputExpr: o.Expression = expressionWithoutBuiltins.visit(visitor, _Mode.Expression); const outputExpr: o.Expression = expressionWithoutBuiltins.visit(visitor, _Mode.Expression);
const stmts: o.Statement[] = getStatementsFromVisitor(visitor, bindingId);
if (visitor.temporaryCount) { if (visitor.temporaryCount === 0 && form == BindingForm.TrySimple) {
for (let i = 0; i < visitor.temporaryCount; i++) {
stmts.push(temporaryDeclaration(bindingId, i));
}
} else if (form == BindingForm.TrySimple) {
return new ConvertPropertyBindingResult([], outputExpr); return new ConvertPropertyBindingResult([], outputExpr);
} }
@ -172,6 +168,58 @@ export function convertPropertyBinding(
return new ConvertPropertyBindingResult(stmts, currValExpr); return new ConvertPropertyBindingResult(stmts, currValExpr);
} }
/**
* Given some expression, such as a binding or interpolation expression, and a context expression to
* look values up on, visit each facet of the given expression resolving values from the context
* expression such that a list of arguments can be derived from the found values that can be used as
* arguments to an external update instruction.
*
* @param localResolver The resolver to use to look up expressions by name appropriately
* @param contextVariableExpression The expression representing the context variable used to create
* the final argument expressions
* @param expressionWithArgumentsToExtract The expression to visit to figure out what values need to
* be resolved and what arguments list to build.
* @param bindingId A name prefix used to create temporary variable names if they're needed for the
* arguments generated
* @returns An array of expressions that can be passed as arguments to instruction expressions like
* `o.importExpr(R3.propertyInterpolate).callFn(result)`
*/
export function convertUpdateArguments(
localResolver: LocalResolver, contextVariableExpression: o.Expression,
expressionWithArgumentsToExtract: cdAst.AST, bindingId: string) {
const visitor =
new _AstToIrVisitor(localResolver, contextVariableExpression, bindingId, undefined);
const outputExpr: o.InvokeFunctionExpr =
expressionWithArgumentsToExtract.visit(visitor, _Mode.Expression);
const stmts = getStatementsFromVisitor(visitor, bindingId);
// Removing the first argument, because it was a length for ViewEngine, not Ivy.
let args = outputExpr.args.slice(1);
if (expressionWithArgumentsToExtract instanceof cdAst.Interpolation) {
// If we're dealing with an interpolation of 1 value with an empty prefix and suffix, reduce the
// args returned to just the value, because we're going to pass it to a special instruction.
const strings = expressionWithArgumentsToExtract.strings;
if (args.length === 3 && strings[0] === '' && strings[1] === '') {
// Single argument interpolate instructions.
args = [args[1]];
} else if (args.length >= 19) {
// 19 or more arguments must be passed to the `interpolateV`-style instructions, which accept
// an array of arguments
args = [o.literalArr(args)];
}
}
return {stmts, args};
}
function getStatementsFromVisitor(visitor: _AstToIrVisitor, bindingId: string) {
const stmts: o.Statement[] = [];
for (let i = 0; i < visitor.temporaryCount; i++) {
stmts.push(temporaryDeclaration(bindingId, i));
}
return stmts;
}
function convertBuiltins(converterFactory: BuiltinConverterFactory, ast: cdAst.AST): cdAst.AST { function convertBuiltins(converterFactory: BuiltinConverterFactory, ast: cdAst.AST): cdAst.AST {
const visitor = new _BuiltinAstConverter(converterFactory); const visitor = new _BuiltinAstConverter(converterFactory);
return ast.visit(visitor); return ast.visit(visitor);

View File

@ -7,7 +7,7 @@
*/ */
import {flatten, sanitizeIdentifier} from '../../compile_metadata'; import {flatten, sanitizeIdentifier} from '../../compile_metadata';
import {BindingForm, BuiltinFunctionCall, LocalResolver, convertActionBinding, convertPropertyBinding} from '../../compiler_util/expression_converter'; import {BindingForm, BuiltinFunctionCall, LocalResolver, convertActionBinding, convertPropertyBinding, convertUpdateArguments} from '../../compiler_util/expression_converter';
import {ConstantPool} from '../../constant_pool'; import {ConstantPool} from '../../constant_pool';
import * as core from '../../core'; import * as core from '../../core';
import {AST, AstMemoryEfficientTransformer, BindingPipe, BindingType, FunctionCall, ImplicitReceiver, Interpolation, LiteralArray, LiteralMap, LiteralPrimitive, ParsedEventType, PropertyRead} from '../../expression_parser/ast'; import {AST, AstMemoryEfficientTransformer, BindingPipe, BindingType, FunctionCall, ImplicitReceiver, Interpolation, LiteralArray, LiteralMap, LiteralPrimitive, ParsedEventType, PropertyRead} from '../../expression_parser/ast';
@ -750,23 +750,13 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
if (inputType === BindingType.Property) { if (inputType === BindingType.Property) {
if (value instanceof Interpolation) { if (value instanceof Interpolation) {
// Interpolated properties
const {currValExpr} = convertPropertyBinding(
this, implicit, value, this.bindingContext(), BindingForm.TrySimple);
let args: o.Expression[] = (currValExpr as any).args;
args.shift(); // ViewEngine required a count, we don't need that.
// For interpolations like attr="{{foo}}", we don't need ["", foo, ""], just [foo].
if (args.length === 3 && isEmptyStringExpression(args[0]) &&
isEmptyStringExpression(args[2])) {
args = [args[1]];
}
this.updateInstruction( this.updateInstruction(
elementIndex, input.sourceSpan, propertyInterpolate(args.length), () => { elementIndex, input.sourceSpan, getPropertyInterpolationExpression(value),
return [o.literal(attrName), ...args, ...params]; () =>
}); [o.literal(attrName),
...this.getUpdateInstructionArguments(o.variable(CONTEXT_NAME), value),
...params]);
} else { } else {
// Bound, un-interpolated properties // Bound, un-interpolated properties
this.updateInstruction(elementIndex, input.sourceSpan, R3.property, () => { this.updateInstruction(elementIndex, input.sourceSpan, R3.property, () => {
@ -1076,6 +1066,21 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
o.importExpr(R3.bind).callFn([valExpr]); o.importExpr(R3.bind).callFn([valExpr]);
} }
/**
* Gets a list of argument expressions to pass to an update instruction expression. Also updates
* the temp variables state with temp variables that were identified as needing to be created
* while visiting the arguments.
* @param contextExpression The expression for the context variable used to create arguments
* @param value The original expression we will be resolving an arguments list from.
*/
private getUpdateInstructionArguments(contextExpression: o.Expression, value: AST):
o.Expression[] {
const {args, stmts} =
convertUpdateArguments(this, contextExpression, value, this.bindingContext());
this._tempVariables.push(...stmts);
return args;
}
private matchDirectives(tagName: string, elOrTpl: t.Element|t.Template) { private matchDirectives(tagName: string, elOrTpl: t.Element|t.Template) {
if (this.directiveMatcher) { if (this.directiveMatcher) {
const selector = createCssSelector(tagName, getAttrsForDirectiveMatching(elOrTpl)); const selector = createCssSelector(tagName, getAttrsForDirectiveMatching(elOrTpl));
@ -1646,16 +1651,12 @@ function interpolate(args: o.Expression[]): o.Expression {
return o.importExpr(R3.interpolationV).callFn([o.literalArr(args)]); return o.importExpr(R3.interpolationV).callFn([o.literalArr(args)]);
} }
function isEmptyStringExpression(exp: o.Expression) { /**
return exp instanceof o.LiteralExpr && exp.value === ''; * Gets the instruction to generate for an interpolated property
} * @param interpolation An Interpolation AST
*/
function propertyInterpolate(argsLength: number) { function getPropertyInterpolationExpression(interpolation: Interpolation) {
if (argsLength % 2 !== 1) { switch (getInterpolationArgsLength(interpolation)) {
error(`Invalid propertyInterpolate argument length ${argsLength}`);
}
switch (argsLength) {
case 1: case 1:
return R3.propertyInterpolate; return R3.propertyInterpolate;
case 3: case 3:
@ -1679,6 +1680,22 @@ function propertyInterpolate(argsLength: number) {
} }
} }
/**
* Gets the number of arguments expected to be passed to a generated instruction in the case of
* interpolation instructions.
* @param interpolation An interpolation ast
*/
function getInterpolationArgsLength(interpolation: Interpolation) {
const {expressions, strings} = interpolation;
if (expressions.length === 1 && strings.length === 2 && strings[0] === '' && strings[1] === '') {
// If the interpolation has one interpolated value, but the prefix and suffix are both empty
// strings, we only pass one argument, to a special instruction like `propertyInterpolate` or
// `textInterpolate`.
return 1;
} else {
return expressions.length + strings.length;
}
}
/** /**
* Options that can be used to modify how a template is parsed by `parseTemplate()`. * Options that can be used to modify how a template is parsed by `parseTemplate()`.
*/ */

View File

@ -71,10 +71,23 @@ export function injectInjectorOnly<T>(
/** /**
* Generated instruction: Injects a token from the currently active injector. * Generated instruction: Injects a token from the currently active injector.
* *
* WARNING: This function is meant to be generated by the Ivy compiler, and is not meant for * Must be used in the context of a factory function such as one defined for an
* developer consumption! * `InjectionToken`. Throws an error if not called from such a context.
* *
* https://github.com/angular/angular/blob/master/packages/core/src/render3/DELTA_INSTRUCTIONS.md * (Additional documentation moved to `inject`, as it is the public API, and an alias for this instruction)
*
* @see inject
* @codeGenApi
*/
export function ɵɵinject<T>(token: Type<T>| InjectionToken<T>): T;
export function ɵɵinject<T>(token: Type<T>| InjectionToken<T>, flags?: InjectFlags): T|null;
export function ɵɵinject<T>(token: Type<T>| InjectionToken<T>, flags = InjectFlags.Default): T|
null {
return (_injectImplementation || injectInjectorOnly)(token, flags);
}
/**
* Injects a token from the currently active injector.
* *
* Must be used in the context of a factory function such as one defined for an * Must be used in the context of a factory function such as one defined for an
* `InjectionToken`. Throws an error if not called from such a context. * `InjectionToken`. Throws an error if not called from such a context.
@ -97,17 +110,6 @@ export function injectInjectorOnly<T>(
* *
* @publicApi * @publicApi
*/ */
export function ɵɵinject<T>(token: Type<T>| InjectionToken<T>): T;
export function ɵɵinject<T>(token: Type<T>| InjectionToken<T>, flags?: InjectFlags): T|null;
export function ɵɵinject<T>(token: Type<T>| InjectionToken<T>, flags = InjectFlags.Default): T|
null {
return (_injectImplementation || injectInjectorOnly)(token, flags);
}
/**
* @deprecated in v8, delete after v10. This API should be used only be generated code, and that
* code should now use ɵɵinject instead.
* @publicApi
*/
export const inject = ɵɵinject; export const inject = ɵɵinject;
/** /**

View File

@ -110,6 +110,8 @@ function listenerInternal(
ngDevMode && assertNodeOfPossibleTypes( ngDevMode && assertNodeOfPossibleTypes(
tNode, TNodeType.Element, TNodeType.Container, TNodeType.ElementContainer); tNode, TNodeType.Element, TNodeType.Container, TNodeType.ElementContainer);
let processOutputs = true;
// add native event listener - applicable to elements only // add native event listener - applicable to elements only
if (tNode.type === TNodeType.Element) { if (tNode.type === TNodeType.Element) {
const native = getNativeByTNode(tNode, lView) as RElement; const native = getNativeByTNode(tNode, lView) as RElement;
@ -149,6 +151,7 @@ function listenerInternal(
// Attach a new listener at the head of the coalesced listeners list. // Attach a new listener at the head of the coalesced listeners list.
(<any>listenerFn).__ngNextListenerFn__ = (<any>existingListener).__ngNextListenerFn__; (<any>listenerFn).__ngNextListenerFn__ = (<any>existingListener).__ngNextListenerFn__;
(<any>existingListener).__ngNextListenerFn__ = listenerFn; (<any>existingListener).__ngNextListenerFn__ = listenerFn;
processOutputs = false;
} else { } else {
// The first argument of `listen` function in Procedural Renderer is: // The first argument of `listen` function in Procedural Renderer is:
// - either a target name (as a string) in case of global target (window, document, body) // - either a target name (as a string) in case of global target (window, document, body)
@ -180,7 +183,7 @@ function listenerInternal(
const outputs = tNode.outputs; const outputs = tNode.outputs;
let props: PropertyAliasValue|undefined; let props: PropertyAliasValue|undefined;
if (outputs && (props = outputs[eventName])) { if (processOutputs && outputs && (props = outputs[eventName])) {
const propsLength = props.length; const propsLength = props.length;
if (propsLength) { if (propsLength) {
const lCleanup = getCleanup(lView); const lCleanup = getCleanup(lView);

View File

@ -7,6 +7,7 @@
*/ */
import {assertEqual, assertLessThan} from '../../util/assert'; import {assertEqual, assertLessThan} from '../../util/assert';
import {bindingUpdated, bindingUpdated2, bindingUpdated3, bindingUpdated4} from '../bindings'; import {bindingUpdated, bindingUpdated2, bindingUpdated3, bindingUpdated4} from '../bindings';
import {SanitizerFn} from '../interfaces/sanitization';
import {BINDING_INDEX, TVIEW} from '../interfaces/view'; import {BINDING_INDEX, TVIEW} from '../interfaces/view';
import {getLView, getSelectedIndex} from '../state'; import {getLView, getSelectedIndex} from '../state';
import {NO_CHANGE} from '../tokens'; import {NO_CHANGE} from '../tokens';
@ -15,6 +16,7 @@ import {renderStringify} from '../util/misc_utils';
import {TsickleIssue1009, elementPropertyInternal, storeBindingMetadata} from './shared'; import {TsickleIssue1009, elementPropertyInternal, storeBindingMetadata} from './shared';
/** /**
* Create interpolation bindings with a variable number of expressions. * Create interpolation bindings with a variable number of expressions.
* *
@ -290,12 +292,6 @@ export function ɵɵinterpolation8(
/// NEW INSTRUCTIONS /// NEW INSTRUCTIONS
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
/**
* Shared reference to a string, used in `ɵɵpropertyInterpolate`.
*/
const EMPTY_STRING = '';
/** /**
* *
* Update an interpolated property on an element with a lone bound value * Update an interpolated property on an element with a lone bound value
@ -321,11 +317,13 @@ const EMPTY_STRING = '';
* @param prefix Static value used for concatenation only. * @param prefix Static value used for concatenation only.
* @param v0 Value checked for change. * @param v0 Value checked for change.
* @param suffix Static value used for concatenation only. * @param suffix Static value used for concatenation only.
* @param sanitizer An optional sanitizer function
* @returns itself, so that it may be chained. * @returns itself, so that it may be chained.
* @codeGenApi * @codeGenApi
*/ */
export function ɵɵpropertyInterpolate(propName: string, v0: any): TsickleIssue1009 { export function ɵɵpropertyInterpolate(
ɵɵpropertyInterpolate1(propName, EMPTY_STRING, v0, EMPTY_STRING); propName: string, v0: any, sanitizer?: SanitizerFn): TsickleIssue1009 {
ɵɵpropertyInterpolate1(propName, '', v0, '', sanitizer);
return ɵɵpropertyInterpolate; return ɵɵpropertyInterpolate;
} }
@ -354,13 +352,15 @@ export function ɵɵpropertyInterpolate(propName: string, v0: any): TsickleIssue
* @param prefix Static value used for concatenation only. * @param prefix Static value used for concatenation only.
* @param v0 Value checked for change. * @param v0 Value checked for change.
* @param suffix Static value used for concatenation only. * @param suffix Static value used for concatenation only.
* @param sanitizer An optional sanitizer function
* @returns itself, so that it may be chained. * @returns itself, so that it may be chained.
* @codeGenApi * @codeGenApi
*/ */
export function ɵɵpropertyInterpolate1( export function ɵɵpropertyInterpolate1(
propName: string, prefix: string, v0: any, suffix: string): TsickleIssue1009 { propName: string, prefix: string, v0: any, suffix: string,
sanitizer?: SanitizerFn): TsickleIssue1009 {
const index = getSelectedIndex(); const index = getSelectedIndex();
elementPropertyInternal(index, propName, ɵɵinterpolation1(prefix, v0, suffix)); elementPropertyInternal(index, propName, ɵɵinterpolation1(prefix, v0, suffix), sanitizer);
return ɵɵpropertyInterpolate1; return ɵɵpropertyInterpolate1;
} }
@ -390,14 +390,15 @@ export function ɵɵpropertyInterpolate1(
* @param i0 Static value used for concatenation only. * @param i0 Static value used for concatenation only.
* @param v1 Value checked for change. * @param v1 Value checked for change.
* @param suffix Static value used for concatenation only. * @param suffix Static value used for concatenation only.
* @param sanitizer An optional sanitizer function
* @returns itself, so that it may be chained. * @returns itself, so that it may be chained.
* @codeGenApi * @codeGenApi
*/ */
export function ɵɵpropertyInterpolate2( export function ɵɵpropertyInterpolate2(
propName: string, prefix: string, v0: any, i0: string, v1: any, propName: string, prefix: string, v0: any, i0: string, v1: any, suffix: string,
suffix: string): TsickleIssue1009 { sanitizer?: SanitizerFn): TsickleIssue1009 {
const index = getSelectedIndex(); const index = getSelectedIndex();
elementPropertyInternal(index, propName, ɵɵinterpolation2(prefix, v0, i0, v1, suffix)); elementPropertyInternal(index, propName, ɵɵinterpolation2(prefix, v0, i0, v1, suffix), sanitizer);
return ɵɵpropertyInterpolate2; return ɵɵpropertyInterpolate2;
} }
@ -430,14 +431,16 @@ export function ɵɵpropertyInterpolate2(
* @param i1 Static value used for concatenation only. * @param i1 Static value used for concatenation only.
* @param v2 Value checked for change. * @param v2 Value checked for change.
* @param suffix Static value used for concatenation only. * @param suffix Static value used for concatenation only.
* @param sanitizer An optional sanitizer function
* @returns itself, so that it may be chained. * @returns itself, so that it may be chained.
* @codeGenApi * @codeGenApi
*/ */
export function ɵɵpropertyInterpolate3( export function ɵɵpropertyInterpolate3(
propName: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, propName: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any,
suffix: string): TsickleIssue1009 { suffix: string, sanitizer?: SanitizerFn): TsickleIssue1009 {
const index = getSelectedIndex(); const index = getSelectedIndex();
elementPropertyInternal(index, propName, ɵɵinterpolation3(prefix, v0, i0, v1, i1, v2, suffix)); elementPropertyInternal(
index, propName, ɵɵinterpolation3(prefix, v0, i0, v1, i1, v2, suffix), sanitizer);
return ɵɵpropertyInterpolate3; return ɵɵpropertyInterpolate3;
} }
@ -472,15 +475,16 @@ export function ɵɵpropertyInterpolate3(
* @param i2 Static value used for concatenation only. * @param i2 Static value used for concatenation only.
* @param v3 Value checked for change. * @param v3 Value checked for change.
* @param suffix Static value used for concatenation only. * @param suffix Static value used for concatenation only.
* @param sanitizer An optional sanitizer function
* @returns itself, so that it may be chained. * @returns itself, so that it may be chained.
* @codeGenApi * @codeGenApi
*/ */
export function ɵɵpropertyInterpolate4( export function ɵɵpropertyInterpolate4(
propName: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, propName: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string,
v3: any, suffix: string): TsickleIssue1009 { v3: any, suffix: string, sanitizer?: SanitizerFn): TsickleIssue1009 {
const index = getSelectedIndex(); const index = getSelectedIndex();
elementPropertyInternal( elementPropertyInternal(
index, propName, ɵɵinterpolation4(prefix, v0, i0, v1, i1, v2, i2, v3, suffix)); index, propName, ɵɵinterpolation4(prefix, v0, i0, v1, i1, v2, i2, v3, suffix), sanitizer);
return ɵɵpropertyInterpolate4; return ɵɵpropertyInterpolate4;
} }
@ -517,15 +521,17 @@ export function ɵɵpropertyInterpolate4(
* @param i3 Static value used for concatenation only. * @param i3 Static value used for concatenation only.
* @param v4 Value checked for change. * @param v4 Value checked for change.
* @param suffix Static value used for concatenation only. * @param suffix Static value used for concatenation only.
* @param sanitizer An optional sanitizer function
* @returns itself, so that it may be chained. * @returns itself, so that it may be chained.
* @codeGenApi * @codeGenApi
*/ */
export function ɵɵpropertyInterpolate5( export function ɵɵpropertyInterpolate5(
propName: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, propName: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string,
v3: any, i3: string, v4: any, suffix: string): TsickleIssue1009 { v3: any, i3: string, v4: any, suffix: string, sanitizer?: SanitizerFn): TsickleIssue1009 {
const index = getSelectedIndex(); const index = getSelectedIndex();
elementPropertyInternal( elementPropertyInternal(
index, propName, ɵɵinterpolation5(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, suffix)); index, propName, ɵɵinterpolation5(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, suffix),
sanitizer);
return ɵɵpropertyInterpolate5; return ɵɵpropertyInterpolate5;
} }
@ -564,16 +570,18 @@ export function ɵɵpropertyInterpolate5(
* @param i4 Static value used for concatenation only. * @param i4 Static value used for concatenation only.
* @param v5 Value checked for change. * @param v5 Value checked for change.
* @param suffix Static value used for concatenation only. * @param suffix Static value used for concatenation only.
* @param sanitizer An optional sanitizer function
* @returns itself, so that it may be chained. * @returns itself, so that it may be chained.
* @codeGenApi * @codeGenApi
*/ */
export function ɵɵpropertyInterpolate6( export function ɵɵpropertyInterpolate6(
propName: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, propName: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string,
v3: any, i3: string, v4: any, i4: string, v5: any, suffix: string): TsickleIssue1009 { v3: any, i3: string, v4: any, i4: string, v5: any, suffix: string,
sanitizer?: SanitizerFn): TsickleIssue1009 {
const index = getSelectedIndex(); const index = getSelectedIndex();
elementPropertyInternal( elementPropertyInternal(
index, propName, index, propName, ɵɵinterpolation6(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, suffix),
ɵɵinterpolation6(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, suffix)); sanitizer);
return ɵɵpropertyInterpolate6; return ɵɵpropertyInterpolate6;
} }
@ -614,17 +622,19 @@ export function ɵɵpropertyInterpolate6(
* @param i5 Static value used for concatenation only. * @param i5 Static value used for concatenation only.
* @param v6 Value checked for change. * @param v6 Value checked for change.
* @param suffix Static value used for concatenation only. * @param suffix Static value used for concatenation only.
* @param sanitizer An optional sanitizer function
* @returns itself, so that it may be chained. * @returns itself, so that it may be chained.
* @codeGenApi * @codeGenApi
*/ */
export function ɵɵpropertyInterpolate7( export function ɵɵpropertyInterpolate7(
propName: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, propName: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string,
v3: any, i3: string, v4: any, i4: string, v5: any, i5: string, v6: any, v3: any, i3: string, v4: any, i4: string, v5: any, i5: string, v6: any, suffix: string,
suffix: string): TsickleIssue1009 { sanitizer?: SanitizerFn): TsickleIssue1009 {
const index = getSelectedIndex(); const index = getSelectedIndex();
elementPropertyInternal( elementPropertyInternal(
index, propName, index, propName,
ɵɵinterpolation7(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, suffix)); ɵɵinterpolation7(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, suffix),
sanitizer);
return ɵɵpropertyInterpolate7; return ɵɵpropertyInterpolate7;
} }
@ -667,17 +677,19 @@ export function ɵɵpropertyInterpolate7(
* @param i6 Static value used for concatenation only. * @param i6 Static value used for concatenation only.
* @param v7 Value checked for change. * @param v7 Value checked for change.
* @param suffix Static value used for concatenation only. * @param suffix Static value used for concatenation only.
* @param sanitizer An optional sanitizer function
* @returns itself, so that it may be chained. * @returns itself, so that it may be chained.
* @codeGenApi * @codeGenApi
*/ */
export function ɵɵpropertyInterpolate8( export function ɵɵpropertyInterpolate8(
propName: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, propName: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string,
v3: any, i3: string, v4: any, i4: string, v5: any, i5: string, v6: any, i6: string, v7: any, v3: any, i3: string, v4: any, i4: string, v5: any, i5: string, v6: any, i6: string, v7: any,
suffix: string): TsickleIssue1009 { suffix: string, sanitizer?: SanitizerFn): TsickleIssue1009 {
const index = getSelectedIndex(); const index = getSelectedIndex();
elementPropertyInternal( elementPropertyInternal(
index, propName, index, propName,
ɵɵinterpolation8(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, i6, v7, suffix)); ɵɵinterpolation8(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, i6, v7, suffix),
sanitizer);
return ɵɵpropertyInterpolate8; return ɵɵpropertyInterpolate8;
} }
@ -707,12 +719,14 @@ export function ɵɵpropertyInterpolate8(
* @param values The a collection of values and the strings inbetween those values, beginning with a * @param values The a collection of values and the strings inbetween those values, beginning with a
* string prefix and ending with a string suffix. * string prefix and ending with a string suffix.
* (e.g. `['prefix', value0, '-', value1, '-', value2, ..., value99, 'suffix']`) * (e.g. `['prefix', value0, '-', value1, '-', value2, ..., value99, 'suffix']`)
* @param sanitizer An optional sanitizer function
* @returns itself, so that it may be chained. * @returns itself, so that it may be chained.
* @codeGenApi * @codeGenApi
*/ */
export function ɵɵpropertyInterpolateV(propName: string, values: any[]): TsickleIssue1009 { export function ɵɵpropertyInterpolateV(
propName: string, values: any[], sanitizer?: SanitizerFn): TsickleIssue1009 {
const index = getSelectedIndex(); const index = getSelectedIndex();
elementPropertyInternal(index, propName, ɵɵinterpolationV(values)); elementPropertyInternal(index, propName, ɵɵinterpolationV(values), sanitizer);
return ɵɵpropertyInterpolateV; return ɵɵpropertyInterpolateV;
} }

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {Component, Directive, ErrorHandler, HostListener, QueryList, ViewChildren} from '@angular/core'; import {Component, Directive, ErrorHandler, EventEmitter, HostListener, Input, Output, QueryList, ViewChild, ViewChildren} from '@angular/core';
import {TestBed} from '@angular/core/testing'; import {TestBed} from '@angular/core/testing';
import {By} from '@angular/platform-browser'; import {By} from '@angular/platform-browser';
import {onlyInIvy} from '@angular/private/testing'; import {onlyInIvy} from '@angular/private/testing';
@ -203,5 +203,40 @@ describe('event listeners', () => {
expect(returnsFalseDir.event.preventDefault).toHaveBeenCalled(); expect(returnsFalseDir.event.preventDefault).toHaveBeenCalled();
}); });
it('should not subscribe twice to the output when there are 2 coalesced listeners', () => {
@Directive({selector: '[foo]'})
class FooDirective {
@Input('foo') model: any;
@Output('fooChange') update = new EventEmitter();
updateValue(value: any) { this.update.emit(value); }
}
@Component({
selector: 'test-component',
template: `<div [(foo)]="someValue" (fooChange)="fooChange($event)"></div>`
})
class TestComponent {
count = 0;
someValue = -1;
@ViewChild(FooDirective) fooDirective: FooDirective|null = null;
fooChange() { this.count++; }
triggerUpdate(value: any) { this.fooDirective !.updateValue(value); }
}
TestBed.configureTestingModule({declarations: [TestComponent, FooDirective]});
const fixture = TestBed.createComponent(TestComponent);
fixture.detectChanges();
const componentInstance = fixture.componentInstance;
componentInstance.triggerUpdate(42);
fixture.detectChanges();
expect(componentInstance.count).toEqual(1);
expect(componentInstance.someValue).toEqual(42);
});
}); });
}); });

View File

@ -10,8 +10,9 @@ import {Component, Input} from '@angular/core';
import {TestBed} from '@angular/core/testing'; import {TestBed} from '@angular/core/testing';
import {By} from '@angular/platform-browser'; import {By} from '@angular/platform-browser';
import {expect} from '@angular/platform-browser/testing/src/matchers'; import {expect} from '@angular/platform-browser/testing/src/matchers';
import {of } from 'rxjs';
describe('elementProperty', () => { describe('property instructions', () => {
it('should bind to properties whose names do not correspond to their attribute names', () => { it('should bind to properties whose names do not correspond to their attribute names', () => {
@Component({template: '<label [for]="forValue"></label>'}) @Component({template: '<label [for]="forValue"></label>'})
class MyComp { class MyComp {
@ -33,6 +34,25 @@ describe('elementProperty', () => {
expect(labelNode.nativeElement.getAttribute('for')).toBe('some-textarea'); expect(labelNode.nativeElement.getAttribute('for')).toBe('some-textarea');
}); });
it('should not allow unsanitary urls in bound properties', () => {
@Component({
template: `
<img [src]="naughty">
`
})
class App {
naughty = 'javascript:alert("haha, I am taking over your computer!!!");';
}
TestBed.configureTestingModule({declarations: [App]});
const fixture = TestBed.createComponent(App);
fixture.detectChanges();
const img = fixture.nativeElement.querySelector('img');
expect(img.src.indexOf('unsafe:')).toBe(0);
});
it('should not map properties whose names do not correspond to their attribute names, ' + it('should not map properties whose names do not correspond to their attribute names, ' +
'if they correspond to inputs', 'if they correspond to inputs',
() => { () => {
@ -60,4 +80,136 @@ describe('elementProperty', () => {
expect(myCompNode.nativeElement.getAttribute('for')).toBeFalsy(); expect(myCompNode.nativeElement.getAttribute('for')).toBeFalsy();
expect(myCompNode.componentInstance.for).toBe('hej'); expect(myCompNode.componentInstance.for).toBe('hej');
}); });
it('should handle all flavors of interpolated properties', () => {
@Component({
template: `
<div title="a{{one}}b{{two}}c{{three}}d{{four}}e{{five}}f{{six}}g{{seven}}h{{eight}}i{{nine}}j"></div>
<div title="a{{one}}b{{two}}c{{three}}d{{four}}e{{five}}f{{six}}g{{seven}}h{{eight}}i"></div>
<div title="a{{one}}b{{two}}c{{three}}d{{four}}e{{five}}f{{six}}g{{seven}}h"></div>
<div title="a{{one}}b{{two}}c{{three}}d{{four}}e{{five}}f{{six}}g"></div>
<div title="a{{one}}b{{two}}c{{three}}d{{four}}e{{five}}f"></div>
<div title="a{{one}}b{{two}}c{{three}}d{{four}}e"></div>
<div title="a{{one}}b{{two}}c{{three}}d"></div>
<div title="a{{one}}b{{two}}c"></div>
<div title="a{{one}}b"></div>
<div title="{{one}}"></div>
`
})
class App {
one = 1;
two = 2;
three = 3;
four = 4;
five = 5;
six = 6;
seven = 7;
eight = 8;
nine = 9;
}
TestBed.configureTestingModule({declarations: [App]});
const fixture = TestBed.createComponent(App);
fixture.detectChanges();
const titles = Array.from(fixture.nativeElement.querySelectorAll('div[title]'))
.map((div: HTMLDivElement) => div.title);
expect(titles).toEqual([
'a1b2c3d4e5f6g7h8i9j',
'a1b2c3d4e5f6g7h8i',
'a1b2c3d4e5f6g7h',
'a1b2c3d4e5f6g',
'a1b2c3d4e5f',
'a1b2c3d4e',
'a1b2c3d',
'a1b2c',
'a1b',
'1',
]);
});
it('should handle pipes in interpolated properties', () => {
@Component({
template: `
<img title="{{(details | async)?.title}}" src="{{(details | async)?.url}}" />
`
})
class App {
details = of ({
title: 'cool image',
url: 'http://somecooldomain:1234/cool_image.png',
});
}
TestBed.configureTestingModule({declarations: [App]});
const fixture = TestBed.createComponent(App);
fixture.detectChanges();
const img: HTMLImageElement = fixture.nativeElement.querySelector('img');
expect(img.src).toBe('http://somecooldomain:1234/cool_image.png');
expect(img.title).toBe('cool image');
});
// From https://angular-team.atlassian.net/browse/FW-1287
it('should handle multiple elvis operators', () => {
@Component({
template: `
<img src="{{leadSurgeon?.getCommonInfo()?.getPhotoUrl() }}">
`
})
class App {
/** Clearly this is a doctor of heavy metals. */
leadSurgeon = {
getCommonInfo() {
return {getPhotoUrl() { return 'http://somecooldomain:1234/cool_image.png'; }};
}
};
}
TestBed.configureTestingModule({declarations: [App]});
const fixture = TestBed.createComponent(App);
fixture.detectChanges();
const img = fixture.nativeElement.querySelector('img');
expect(img.src).toBe('http://somecooldomain:1234/cool_image.png');
});
it('should not allow unsanitary urls in interpolated properties', () => {
@Component({
template: `
<img src="{{naughty}}">
`
})
class App {
naughty = 'javascript:alert("haha, I am taking over your computer!!!");';
}
TestBed.configureTestingModule({declarations: [App]});
const fixture = TestBed.createComponent(App);
fixture.detectChanges();
const img: HTMLImageElement = fixture.nativeElement.querySelector('img');
expect(img.src.indexOf('unsafe:')).toBe(0);
});
it('should not allow unsanitary urls in interpolated properties, even if you are tricky', () => {
@Component({
template: `
<img src="{{ja}}{{va}}script:{{naughty}}">
`
})
class App {
ja = 'ja';
va = 'va';
naughty = 'alert("I am a h4xx0rz1!!");';
}
TestBed.configureTestingModule({declarations: [App]});
const fixture = TestBed.createComponent(App);
fixture.detectChanges();
const img = fixture.nativeElement.querySelector('img');
expect(img.src.indexOf('unsafe:')).toBe(0);
});
}); });

View File

@ -36,10 +36,19 @@ function _ngProbeTokensToMap(tokens: core.NgProbeToken[]): {[name: string]: any}
return tokens.reduce((prev: any, t: any) => (prev[t.name] = t.token, prev), {}); return tokens.reduce((prev: any, t: any) => (prev[t.name] = t.token, prev), {});
} }
/**
* In Ivy, we don't support NgProbe because we have our own set of testing utilities
* with more robust functionality.
*
* We shouldn't bring in NgProbe because it prevents DebugNode and friends from
* tree-shaking properly.
*/
export const ELEMENT_PROBE_PROVIDERS__POST_R3__ = [];
/** /**
* Providers which support debugging Angular applications (e.g. via `ng.probe`). * Providers which support debugging Angular applications (e.g. via `ng.probe`).
*/ */
export const ELEMENT_PROBE_PROVIDERS: core.Provider[] = [ export const ELEMENT_PROBE_PROVIDERS__PRE_R3__: core.Provider[] = [
{ {
provide: core.APP_INITIALIZER, provide: core.APP_INITIALIZER,
useFactory: _createNgProbe, useFactory: _createNgProbe,
@ -49,3 +58,5 @@ export const ELEMENT_PROBE_PROVIDERS: core.Provider[] = [
multi: true, multi: true,
}, },
]; ];
export const ELEMENT_PROBE_PROVIDERS = ELEMENT_PROBE_PROVIDERS__PRE_R3__;

View File

@ -18,3 +18,5 @@ export {DomSanitizer, SafeHtml, SafeResourceUrl, SafeScript, SafeStyle, SafeUrl,
export * from './private_export'; export * from './private_export';
export {VERSION} from './version'; export {VERSION} from './version';
// This must be exported so it doesn't get tree-shaken away prematurely
export {ELEMENT_PROBE_PROVIDERS__POST_R3__ as ɵELEMENT_PROBE_PROVIDERS__POST_R3__} from './dom/debug/ng_probe';

View File

@ -383,7 +383,6 @@ export interface HostListenerDecorator {
new (eventName: string, args?: string[]): any; new (eventName: string, args?: string[]): any;
} }
/** @deprecated */
export declare const inject: typeof ɵɵinject; export declare const inject: typeof ɵɵinject;
export interface Inject { export interface Inject {
@ -944,25 +943,25 @@ export declare function ɵɵprojectionDef(selectors?: CssSelectorList[]): void;
export declare function ɵɵproperty<T>(propName: string, value: T, sanitizer?: SanitizerFn | null, nativeOnly?: boolean): TsickleIssue1009; export declare function ɵɵproperty<T>(propName: string, value: T, sanitizer?: SanitizerFn | null, nativeOnly?: boolean): TsickleIssue1009;
export declare function ɵɵpropertyInterpolate(propName: string, v0: any): TsickleIssue1009; export declare function ɵɵpropertyInterpolate(propName: string, v0: any, sanitizer?: SanitizerFn): TsickleIssue1009;
export declare function ɵɵpropertyInterpolate1(propName: string, prefix: string, v0: any, suffix: string): TsickleIssue1009; export declare function ɵɵpropertyInterpolate1(propName: string, prefix: string, v0: any, suffix: string, sanitizer?: SanitizerFn): TsickleIssue1009;
export declare function ɵɵpropertyInterpolate2(propName: string, prefix: string, v0: any, i0: string, v1: any, suffix: string): TsickleIssue1009; export declare function ɵɵpropertyInterpolate2(propName: string, prefix: string, v0: any, i0: string, v1: any, suffix: string, sanitizer?: SanitizerFn): TsickleIssue1009;
export declare function ɵɵpropertyInterpolate3(propName: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, suffix: string): TsickleIssue1009; export declare function ɵɵpropertyInterpolate3(propName: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, suffix: string, sanitizer?: SanitizerFn): TsickleIssue1009;
export declare function ɵɵpropertyInterpolate4(propName: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, v3: any, suffix: string): TsickleIssue1009; export declare function ɵɵpropertyInterpolate4(propName: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, v3: any, suffix: string, sanitizer?: SanitizerFn): TsickleIssue1009;
export declare function ɵɵpropertyInterpolate5(propName: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, v3: any, i3: string, v4: any, suffix: string): TsickleIssue1009; export declare function ɵɵpropertyInterpolate5(propName: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, v3: any, i3: string, v4: any, suffix: string, sanitizer?: SanitizerFn): TsickleIssue1009;
export declare function ɵɵpropertyInterpolate6(propName: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, v3: any, i3: string, v4: any, i4: string, v5: any, suffix: string): TsickleIssue1009; export declare function ɵɵpropertyInterpolate6(propName: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, v3: any, i3: string, v4: any, i4: string, v5: any, suffix: string, sanitizer?: SanitizerFn): TsickleIssue1009;
export declare function ɵɵpropertyInterpolate7(propName: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, v3: any, i3: string, v4: any, i4: string, v5: any, i5: string, v6: any, suffix: string): TsickleIssue1009; export declare function ɵɵpropertyInterpolate7(propName: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, v3: any, i3: string, v4: any, i4: string, v5: any, i5: string, v6: any, suffix: string, sanitizer?: SanitizerFn): TsickleIssue1009;
export declare function ɵɵpropertyInterpolate8(propName: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, v3: any, i3: string, v4: any, i4: string, v5: any, i5: string, v6: any, i6: string, v7: any, suffix: string): TsickleIssue1009; export declare function ɵɵpropertyInterpolate8(propName: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, v3: any, i3: string, v4: any, i4: string, v5: any, i5: string, v6: any, i6: string, v7: any, suffix: string, sanitizer?: SanitizerFn): TsickleIssue1009;
export declare function ɵɵpropertyInterpolateV(propName: string, values: any[]): TsickleIssue1009; export declare function ɵɵpropertyInterpolateV(propName: string, values: any[], sanitizer?: SanitizerFn): TsickleIssue1009;
export declare function ɵɵProvidersFeature<T>(providers: Provider[], viewProviders?: Provider[]): (definition: DirectiveDef<T>) => void; export declare function ɵɵProvidersFeature<T>(providers: Provider[], viewProviders?: Provider[]): (definition: DirectiveDef<T>) => void;

View File

@ -37,6 +37,11 @@ def ts_api_guardian_test(
# But it will replaced to @npm//ts-api-guardian when publishing # But it will replaced to @npm//ts-api-guardian when publishing
"@angular//tools/ts-api-guardian:lib", "@angular//tools/ts-api-guardian:lib",
"@angular//tools/ts-api-guardian:bin", "@angular//tools/ts-api-guardian:bin",
# The below are required during runtime
"@npm//chalk",
"@npm//diff",
"@npm//minimist",
"@npm//typescript",
] ]
args = [ args = [