@angular/core 15.0.0-next.2 → 15.0.0-next.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm2020/src/core_private_export.mjs +2 -2
- package/esm2020/src/debug/debug_node.mjs +1 -1
- package/esm2020/src/di/index.mjs +1 -1
- package/esm2020/src/di/injector.mjs +1 -1
- package/esm2020/src/di/injector_compatibility.mjs +15 -11
- package/esm2020/src/di/interface/injector.mjs +1 -1
- package/esm2020/src/di/r3_injector.mjs +3 -2
- package/esm2020/src/render3/component_ref.mjs +103 -84
- package/esm2020/src/render3/context_discovery.mjs +17 -14
- package/esm2020/src/render3/definition.mjs +3 -2
- package/esm2020/src/render3/di.mjs +3 -2
- package/esm2020/src/render3/features/host_directives_feature.mjs +35 -13
- package/esm2020/src/render3/instructions/element.mjs +4 -16
- package/esm2020/src/render3/instructions/listener.mjs +2 -4
- package/esm2020/src/render3/instructions/lview_debug.mjs +9 -9
- package/esm2020/src/render3/instructions/projection.mjs +1 -1
- package/esm2020/src/render3/instructions/shared.mjs +123 -101
- package/esm2020/src/render3/instructions/styling.mjs +2 -2
- package/esm2020/src/render3/interfaces/definition.mjs +1 -1
- package/esm2020/src/render3/interfaces/node.mjs +3 -3
- package/esm2020/src/render3/interfaces/type_checks.mjs +3 -3
- package/esm2020/src/render3/jit/directive.mjs +7 -2
- package/esm2020/src/render3/ng_module_ref.mjs +1 -1
- package/esm2020/src/render3/node_manipulation.mjs +20 -5
- package/esm2020/src/render3/node_manipulation_i18n.mjs +2 -2
- package/esm2020/src/render3/util/discovery_utils.mjs +2 -2
- package/esm2020/src/util/is_dev_mode.mjs +11 -19
- package/esm2020/src/version.mjs +1 -1
- package/esm2020/src/zone/async-stack-tagging.mjs +28 -0
- package/esm2020/src/zone/ng_zone.mjs +8 -3
- package/esm2020/testing/src/logger.mjs +3 -3
- package/esm2020/testing/src/ng_zone_mock.mjs +3 -3
- package/esm2020/testing/src/test_bed.mjs +4 -4
- package/fesm2015/core.mjs +1463 -1363
- package/fesm2015/core.mjs.map +1 -1
- package/fesm2015/testing.mjs +970 -901
- package/fesm2015/testing.mjs.map +1 -1
- package/fesm2020/core.mjs +1464 -1366
- package/fesm2020/core.mjs.map +1 -1
- package/fesm2020/testing.mjs +969 -900
- package/fesm2020/testing.mjs.map +1 -1
- package/index.d.ts +100 -33
- package/package.json +1 -1
- package/testing/index.d.ts +9 -1
package/fesm2015/testing.mjs
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @license Angular v15.0.0-next.
|
|
2
|
+
* @license Angular v15.0.0-next.4
|
|
3
3
|
* (c) 2010-2022 Google LLC. https://angular.io/
|
|
4
4
|
* License: MIT
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { getDebugNode as getDebugNode$1, RendererFactory2 as RendererFactory2$1, InjectionToken as InjectionToken$1, ɵstringify, ɵReflectionCapabilities, Directive, Component, Pipe, NgModule, ɵgetInjectableDef, resolveForwardRef as resolveForwardRef$1, ɵNG_COMP_DEF, ɵRender3NgModuleRef, ApplicationInitStatus, LOCALE_ID as LOCALE_ID$1, ɵDEFAULT_LOCALE_ID, ɵsetLocaleId, ɵRender3ComponentFactory, ɵcompileComponent, ɵNG_DIR_DEF, ɵcompileDirective, ɵNG_PIPE_DEF, ɵcompilePipe, ɵNG_MOD_DEF, ɵtransitiveScopesFor, ɵpatchComponentDefWithScope, ɵNG_INJ_DEF, ɵcompileNgModuleDefs, NgZone, Compiler, COMPILER_OPTIONS, ɵNgModuleFactory, ModuleWithComponentFactories, Injector as Injector$1, InjectFlags as InjectFlags$1, ɵsetAllowDuplicateNgModuleIdsForTest, ɵresetCompiledComponents, ɵsetUnknownElementStrictMode as ɵsetUnknownElementStrictMode$1, ɵsetUnknownPropertyStrictMode as ɵsetUnknownPropertyStrictMode$1, ɵgetUnknownElementStrictMode as ɵgetUnknownElementStrictMode$1, ɵgetUnknownPropertyStrictMode as ɵgetUnknownPropertyStrictMode$1, ɵflushModuleScopingQueueAsMuchAsPossible } from '@angular/core';
|
|
7
|
+
import { getDebugNode as getDebugNode$1, RendererFactory2 as RendererFactory2$1, InjectionToken as InjectionToken$1, ɵstringify, ɵReflectionCapabilities, Directive, Component, Pipe, NgModule, ɵgetInjectableDef, resolveForwardRef as resolveForwardRef$1, ɵNG_COMP_DEF, ɵRender3NgModuleRef, ApplicationInitStatus, LOCALE_ID as LOCALE_ID$1, ɵDEFAULT_LOCALE_ID, ɵsetLocaleId, ɵRender3ComponentFactory, ɵcompileComponent, ɵNG_DIR_DEF, ɵcompileDirective, ɵNG_PIPE_DEF, ɵcompilePipe, ɵNG_MOD_DEF, ɵtransitiveScopesFor, ɵpatchComponentDefWithScope, ɵNG_INJ_DEF, ɵcompileNgModuleDefs, NgZone, Compiler, COMPILER_OPTIONS, ɵNgModuleFactory, ModuleWithComponentFactories, ɵconvertToBitFlags, Injector as Injector$1, InjectFlags as InjectFlags$1, ɵsetAllowDuplicateNgModuleIdsForTest, ɵresetCompiledComponents, ɵsetUnknownElementStrictMode as ɵsetUnknownElementStrictMode$1, ɵsetUnknownPropertyStrictMode as ɵsetUnknownPropertyStrictMode$1, ɵgetUnknownElementStrictMode as ɵgetUnknownElementStrictMode$1, ɵgetUnknownPropertyStrictMode as ɵgetUnknownPropertyStrictMode$1, ɵflushModuleScopingQueueAsMuchAsPossible } from '@angular/core';
|
|
8
8
|
import { __awaiter } from 'tslib';
|
|
9
9
|
import { ResourceLoader } from '@angular/compiler';
|
|
10
10
|
import { Subject, Subscription } from 'rxjs';
|
|
@@ -2175,17 +2175,21 @@ Please check that 1) the type for the parameter at index ${index} is correct and
|
|
|
2175
2175
|
* @publicApi
|
|
2176
2176
|
*/
|
|
2177
2177
|
function inject$1(token, flags = InjectFlags.Default) {
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
return
|
|
2178
|
+
return ɵɵinject(token, convertToBitFlags(flags));
|
|
2179
|
+
}
|
|
2180
|
+
// Converts object-based DI flags (`InjectOptions`) to bit flags (`InjectFlags`).
|
|
2181
|
+
function convertToBitFlags(flags) {
|
|
2182
|
+
if (typeof flags === 'undefined' || typeof flags === 'number') {
|
|
2183
|
+
return flags;
|
|
2184
|
+
}
|
|
2185
|
+
// While TypeScript doesn't accept it without a cast, bitwise OR with false-y values in
|
|
2186
|
+
// JavaScript is a no-op. We can use that for a very codesize-efficient conversion from
|
|
2187
|
+
// `InjectOptions` to `InjectFlags`.
|
|
2188
|
+
return (0 /* InternalInjectFlags.Default */ | // comment to force a line break in the formatter
|
|
2189
|
+
(flags.optional && 8 /* InternalInjectFlags.Optional */) |
|
|
2190
|
+
(flags.host && 1 /* InternalInjectFlags.Host */) |
|
|
2191
|
+
(flags.self && 2 /* InternalInjectFlags.Self */) |
|
|
2192
|
+
(flags.skipSelf && 4 /* InternalInjectFlags.SkipSelf */));
|
|
2189
2193
|
}
|
|
2190
2194
|
function injectArgs(types) {
|
|
2191
2195
|
const args = [];
|
|
@@ -2569,7 +2573,8 @@ function ɵɵdefineComponent(componentDefinition) {
|
|
|
2569
2573
|
setInput: null,
|
|
2570
2574
|
schemas: componentDefinition.schemas || null,
|
|
2571
2575
|
tView: null,
|
|
2572
|
-
|
|
2576
|
+
findHostDirectiveDefs: null,
|
|
2577
|
+
hostDirectives: null,
|
|
2573
2578
|
};
|
|
2574
2579
|
const dependencies = componentDefinition.dependencies;
|
|
2575
2580
|
const feature = componentDefinition.features;
|
|
@@ -2903,10 +2908,10 @@ function isLContainer(value) {
|
|
|
2903
2908
|
return Array.isArray(value) && value[TYPE] === true;
|
|
2904
2909
|
}
|
|
2905
2910
|
function isContentQueryHost(tNode) {
|
|
2906
|
-
return (tNode.flags &
|
|
2911
|
+
return (tNode.flags & 4 /* TNodeFlags.hasContentQuery */) !== 0;
|
|
2907
2912
|
}
|
|
2908
2913
|
function isComponentHost(tNode) {
|
|
2909
|
-
return
|
|
2914
|
+
return tNode.componentOffset > -1;
|
|
2910
2915
|
}
|
|
2911
2916
|
function isDirectiveHost(tNode) {
|
|
2912
2917
|
return (tNode.flags & 1 /* TNodeFlags.isDirectiveHost */) === 1 /* TNodeFlags.isDirectiveHost */;
|
|
@@ -4316,7 +4321,7 @@ const unusedValueExportToPlacateAjd$5 = 1;
|
|
|
4316
4321
|
* @param tNode
|
|
4317
4322
|
*/
|
|
4318
4323
|
function hasClassInput(tNode) {
|
|
4319
|
-
return (tNode.flags &
|
|
4324
|
+
return (tNode.flags & 8 /* TNodeFlags.hasClassInput */) !== 0;
|
|
4320
4325
|
}
|
|
4321
4326
|
/**
|
|
4322
4327
|
* Returns `true` if the `TNode` has a directive which has `@Input()` for `style` binding.
|
|
@@ -4340,7 +4345,7 @@ function hasClassInput(tNode) {
|
|
|
4340
4345
|
* @param tNode
|
|
4341
4346
|
*/
|
|
4342
4347
|
function hasStyleInput(tNode) {
|
|
4343
|
-
return (tNode.flags &
|
|
4348
|
+
return (tNode.flags & 16 /* TNodeFlags.hasStyleInput */) !== 0;
|
|
4344
4349
|
}
|
|
4345
4350
|
|
|
4346
4351
|
/**
|
|
@@ -5232,7 +5237,7 @@ class NodeInjector {
|
|
|
5232
5237
|
this._lView = _lView;
|
|
5233
5238
|
}
|
|
5234
5239
|
get(token, notFoundValue, flags) {
|
|
5235
|
-
return getOrCreateInjectable(this._tNode, this._lView, token, flags, notFoundValue);
|
|
5240
|
+
return getOrCreateInjectable(this._tNode, this._lView, token, convertToBitFlags(flags), notFoundValue);
|
|
5236
5241
|
}
|
|
5237
5242
|
}
|
|
5238
5243
|
/** Creates a `NodeInjector` for the current node. */
|
|
@@ -7135,6 +7140,7 @@ class R3Injector extends EnvironmentInjector {
|
|
|
7135
7140
|
}
|
|
7136
7141
|
get(token, notFoundValue = THROW_IF_NOT_FOUND, flags = InjectFlags.Default) {
|
|
7137
7142
|
this.assertNotDestroyed();
|
|
7143
|
+
flags = convertToBitFlags(flags);
|
|
7138
7144
|
// Set the injection context.
|
|
7139
7145
|
const previousInjector = setCurrentInjector(this);
|
|
7140
7146
|
const previousInjectImplementation = setInjectImplementation(undefined);
|
|
@@ -7636,7 +7642,7 @@ class Version {
|
|
|
7636
7642
|
/**
|
|
7637
7643
|
* @publicApi
|
|
7638
7644
|
*/
|
|
7639
|
-
const VERSION = new Version('15.0.0-next.
|
|
7645
|
+
const VERSION = new Version('15.0.0-next.4');
|
|
7640
7646
|
|
|
7641
7647
|
/**
|
|
7642
7648
|
* @license
|
|
@@ -7671,29 +7677,70 @@ const NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR = {};
|
|
|
7671
7677
|
* Use of this source code is governed by an MIT-style license that can be
|
|
7672
7678
|
* found in the LICENSE file at https://angular.io/license
|
|
7673
7679
|
*/
|
|
7680
|
+
// Keeps track of the currently-active LViews.
|
|
7681
|
+
const TRACKED_LVIEWS = new Map();
|
|
7682
|
+
// Used for generating unique IDs for LViews.
|
|
7683
|
+
let uniqueIdCounter = 0;
|
|
7684
|
+
/** Gets a unique ID that can be assigned to an LView. */
|
|
7685
|
+
function getUniqueLViewId() {
|
|
7686
|
+
return uniqueIdCounter++;
|
|
7687
|
+
}
|
|
7688
|
+
/** Starts tracking an LView. */
|
|
7689
|
+
function registerLView(lView) {
|
|
7690
|
+
ngDevMode && assertNumber(lView[ID], 'LView must have an ID in order to be registered');
|
|
7691
|
+
TRACKED_LVIEWS.set(lView[ID], lView);
|
|
7692
|
+
}
|
|
7693
|
+
/** Gets an LView by its unique ID. */
|
|
7694
|
+
function getLViewById(id) {
|
|
7695
|
+
ngDevMode && assertNumber(id, 'ID used for LView lookup must be a number');
|
|
7696
|
+
return TRACKED_LVIEWS.get(id) || null;
|
|
7697
|
+
}
|
|
7698
|
+
/** Stops tracking an LView. */
|
|
7699
|
+
function unregisterLView(lView) {
|
|
7700
|
+
ngDevMode && assertNumber(lView[ID], 'Cannot stop tracking an LView that does not have an ID');
|
|
7701
|
+
TRACKED_LVIEWS.delete(lView[ID]);
|
|
7702
|
+
}
|
|
7703
|
+
|
|
7674
7704
|
/**
|
|
7675
|
-
*
|
|
7676
|
-
*
|
|
7677
|
-
* - Element properties named with dash case (`-`).
|
|
7678
|
-
* Dash case is the naming convention for custom elements.
|
|
7705
|
+
* @license
|
|
7706
|
+
* Copyright Google LLC All Rights Reserved.
|
|
7679
7707
|
*
|
|
7680
|
-
*
|
|
7708
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
7709
|
+
* found in the LICENSE file at https://angular.io/license
|
|
7681
7710
|
*/
|
|
7682
|
-
const CUSTOM_ELEMENTS_SCHEMA = {
|
|
7683
|
-
name: 'custom-elements'
|
|
7684
|
-
};
|
|
7685
7711
|
/**
|
|
7686
|
-
*
|
|
7687
|
-
*
|
|
7688
|
-
*
|
|
7689
|
-
*
|
|
7690
|
-
* and may hide real errors in your template. Consider using the `CUSTOM_ELEMENTS_SCHEMA` instead.
|
|
7712
|
+
* The internal view context which is specific to a given DOM element, directive or
|
|
7713
|
+
* component instance. Each value in here (besides the LView and element node details)
|
|
7714
|
+
* can be present, null or undefined. If undefined then it implies the value has not been
|
|
7715
|
+
* looked up yet, otherwise, if null, then a lookup was executed and nothing was found.
|
|
7691
7716
|
*
|
|
7692
|
-
*
|
|
7717
|
+
* Each value will get filled when the respective value is examined within the getContext
|
|
7718
|
+
* function. The component, element and each directive instance will share the same instance
|
|
7719
|
+
* of the context.
|
|
7693
7720
|
*/
|
|
7694
|
-
|
|
7695
|
-
|
|
7696
|
-
|
|
7721
|
+
class LContext {
|
|
7722
|
+
constructor(
|
|
7723
|
+
/**
|
|
7724
|
+
* ID of the component's parent view data.
|
|
7725
|
+
*/
|
|
7726
|
+
lViewId,
|
|
7727
|
+
/**
|
|
7728
|
+
* The index instance of the node.
|
|
7729
|
+
*/
|
|
7730
|
+
nodeIndex,
|
|
7731
|
+
/**
|
|
7732
|
+
* The instance of the DOM node that is attached to the lNode.
|
|
7733
|
+
*/
|
|
7734
|
+
native) {
|
|
7735
|
+
this.lViewId = lViewId;
|
|
7736
|
+
this.nodeIndex = nodeIndex;
|
|
7737
|
+
this.native = native;
|
|
7738
|
+
}
|
|
7739
|
+
/** Component's parent view data. */
|
|
7740
|
+
get lView() {
|
|
7741
|
+
return getLViewById(this.lViewId);
|
|
7742
|
+
}
|
|
7743
|
+
}
|
|
7697
7744
|
|
|
7698
7745
|
/**
|
|
7699
7746
|
* @license
|
|
@@ -7702,337 +7749,305 @@ const NO_ERRORS_SCHEMA = {
|
|
|
7702
7749
|
* Use of this source code is governed by an MIT-style license that can be
|
|
7703
7750
|
* found in the LICENSE file at https://angular.io/license
|
|
7704
7751
|
*/
|
|
7705
|
-
let shouldThrowErrorOnUnknownElement = false;
|
|
7706
|
-
/**
|
|
7707
|
-
* Sets a strict mode for JIT-compiled components to throw an error on unknown elements,
|
|
7708
|
-
* instead of just logging the error.
|
|
7709
|
-
* (for AOT-compiled ones this check happens at build time).
|
|
7710
|
-
*/
|
|
7711
|
-
function ɵsetUnknownElementStrictMode(shouldThrow) {
|
|
7712
|
-
shouldThrowErrorOnUnknownElement = shouldThrow;
|
|
7713
|
-
}
|
|
7714
|
-
/**
|
|
7715
|
-
* Gets the current value of the strict mode.
|
|
7716
|
-
*/
|
|
7717
|
-
function ɵgetUnknownElementStrictMode() {
|
|
7718
|
-
return shouldThrowErrorOnUnknownElement;
|
|
7719
|
-
}
|
|
7720
|
-
let shouldThrowErrorOnUnknownProperty = false;
|
|
7721
|
-
/**
|
|
7722
|
-
* Sets a strict mode for JIT-compiled components to throw an error on unknown properties,
|
|
7723
|
-
* instead of just logging the error.
|
|
7724
|
-
* (for AOT-compiled ones this check happens at build time).
|
|
7725
|
-
*/
|
|
7726
|
-
function ɵsetUnknownPropertyStrictMode(shouldThrow) {
|
|
7727
|
-
shouldThrowErrorOnUnknownProperty = shouldThrow;
|
|
7728
|
-
}
|
|
7729
|
-
/**
|
|
7730
|
-
* Gets the current value of the strict mode.
|
|
7731
|
-
*/
|
|
7732
|
-
function ɵgetUnknownPropertyStrictMode() {
|
|
7733
|
-
return shouldThrowErrorOnUnknownProperty;
|
|
7734
|
-
}
|
|
7735
7752
|
/**
|
|
7736
|
-
*
|
|
7737
|
-
* an error if it's not the case.
|
|
7738
|
-
* This check is relevant for JIT-compiled components (for AOT-compiled
|
|
7739
|
-
* ones this check happens at build time).
|
|
7753
|
+
* Returns the matching `LContext` data for a given DOM node, directive or component instance.
|
|
7740
7754
|
*
|
|
7741
|
-
*
|
|
7742
|
-
* -
|
|
7743
|
-
*
|
|
7744
|
-
* - the element matches any directive
|
|
7745
|
-
* - the element is allowed by one of the schemas
|
|
7755
|
+
* This function will examine the provided DOM element, component, or directive instance\'s
|
|
7756
|
+
* monkey-patched property to derive the `LContext` data. Once called then the monkey-patched
|
|
7757
|
+
* value will be that of the newly created `LContext`.
|
|
7746
7758
|
*
|
|
7747
|
-
*
|
|
7748
|
-
*
|
|
7749
|
-
*
|
|
7750
|
-
*
|
|
7751
|
-
*
|
|
7759
|
+
* If the monkey-patched value is the `LView` instance then the context value for that
|
|
7760
|
+
* target will be created and the monkey-patch reference will be updated. Therefore when this
|
|
7761
|
+
* function is called it may mutate the provided element\'s, component\'s or any of the associated
|
|
7762
|
+
* directive\'s monkey-patch values.
|
|
7763
|
+
*
|
|
7764
|
+
* If the monkey-patch value is not detected then the code will walk up the DOM until an element
|
|
7765
|
+
* is found which contains a monkey-patch reference. When that occurs then the provided element
|
|
7766
|
+
* will be updated with a new context (which is then returned). If the monkey-patch value is not
|
|
7767
|
+
* detected for a component/directive instance then it will throw an error (all components and
|
|
7768
|
+
* directives should be automatically monkey-patched by ivy).
|
|
7769
|
+
*
|
|
7770
|
+
* @param target Component, Directive or DOM Node.
|
|
7752
7771
|
*/
|
|
7753
|
-
function
|
|
7754
|
-
|
|
7755
|
-
|
|
7756
|
-
|
|
7757
|
-
|
|
7758
|
-
|
|
7759
|
-
|
|
7760
|
-
|
|
7761
|
-
|
|
7762
|
-
|
|
7763
|
-
|
|
7764
|
-
|
|
7765
|
-
|
|
7766
|
-
|
|
7767
|
-
|
|
7768
|
-
|
|
7769
|
-
|
|
7770
|
-
|
|
7771
|
-
|
|
7772
|
-
|
|
7773
|
-
|
|
7774
|
-
|
|
7775
|
-
|
|
7776
|
-
let message = `'${tagName}' is not a known element${templateLocation}:\n`;
|
|
7777
|
-
message += `1. If '${tagName}' is an Angular component, then verify that it is ${isHostStandalone ? 'included in the \'@Component.imports\' of this component' :
|
|
7778
|
-
'a part of an @NgModule where this component is declared'}.\n`;
|
|
7779
|
-
if (tagName && tagName.indexOf('-') > -1) {
|
|
7780
|
-
message +=
|
|
7781
|
-
`2. If '${tagName}' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the ${schemas} of this component to suppress this message.`;
|
|
7772
|
+
function getLContext(target) {
|
|
7773
|
+
let mpValue = readPatchedData(target);
|
|
7774
|
+
if (mpValue) {
|
|
7775
|
+
// only when it's an array is it considered an LView instance
|
|
7776
|
+
// ... otherwise it's an already constructed LContext instance
|
|
7777
|
+
if (isLView(mpValue)) {
|
|
7778
|
+
const lView = mpValue;
|
|
7779
|
+
let nodeIndex;
|
|
7780
|
+
let component = undefined;
|
|
7781
|
+
let directives = undefined;
|
|
7782
|
+
if (isComponentInstance(target)) {
|
|
7783
|
+
nodeIndex = findViaComponent(lView, target);
|
|
7784
|
+
if (nodeIndex == -1) {
|
|
7785
|
+
throw new Error('The provided component was not found in the application');
|
|
7786
|
+
}
|
|
7787
|
+
component = target;
|
|
7788
|
+
}
|
|
7789
|
+
else if (isDirectiveInstance(target)) {
|
|
7790
|
+
nodeIndex = findViaDirective(lView, target);
|
|
7791
|
+
if (nodeIndex == -1) {
|
|
7792
|
+
throw new Error('The provided directive was not found in the application');
|
|
7793
|
+
}
|
|
7794
|
+
directives = getDirectivesAtNodeIndex(nodeIndex, lView);
|
|
7782
7795
|
}
|
|
7783
7796
|
else {
|
|
7784
|
-
|
|
7785
|
-
|
|
7797
|
+
nodeIndex = findViaNativeElement(lView, target);
|
|
7798
|
+
if (nodeIndex == -1) {
|
|
7799
|
+
return null;
|
|
7800
|
+
}
|
|
7786
7801
|
}
|
|
7787
|
-
|
|
7788
|
-
|
|
7802
|
+
// the goal is not to fill the entire context full of data because the lookups
|
|
7803
|
+
// are expensive. Instead, only the target data (the element, component, container, ICU
|
|
7804
|
+
// expression or directive details) are filled into the context. If called multiple times
|
|
7805
|
+
// with different target values then the missing target data will be filled in.
|
|
7806
|
+
const native = unwrapRNode(lView[nodeIndex]);
|
|
7807
|
+
const existingCtx = readPatchedData(native);
|
|
7808
|
+
const context = (existingCtx && !Array.isArray(existingCtx)) ?
|
|
7809
|
+
existingCtx :
|
|
7810
|
+
createLContext(lView, nodeIndex, native);
|
|
7811
|
+
// only when the component has been discovered then update the monkey-patch
|
|
7812
|
+
if (component && context.component === undefined) {
|
|
7813
|
+
context.component = component;
|
|
7814
|
+
attachPatchData(context.component, context);
|
|
7789
7815
|
}
|
|
7790
|
-
|
|
7791
|
-
|
|
7816
|
+
// only when the directives have been discovered then update the monkey-patch
|
|
7817
|
+
if (directives && context.directives === undefined) {
|
|
7818
|
+
context.directives = directives;
|
|
7819
|
+
for (let i = 0; i < directives.length; i++) {
|
|
7820
|
+
attachPatchData(directives[i], context);
|
|
7821
|
+
}
|
|
7822
|
+
}
|
|
7823
|
+
attachPatchData(context.native, context);
|
|
7824
|
+
mpValue = context;
|
|
7825
|
+
}
|
|
7826
|
+
}
|
|
7827
|
+
else {
|
|
7828
|
+
const rElement = target;
|
|
7829
|
+
ngDevMode && assertDomNode(rElement);
|
|
7830
|
+
// if the context is not found then we need to traverse upwards up the DOM
|
|
7831
|
+
// to find the nearest element that has already been monkey patched with data
|
|
7832
|
+
let parent = rElement;
|
|
7833
|
+
while (parent = parent.parentNode) {
|
|
7834
|
+
const parentContext = readPatchedData(parent);
|
|
7835
|
+
if (parentContext) {
|
|
7836
|
+
const lView = Array.isArray(parentContext) ? parentContext : parentContext.lView;
|
|
7837
|
+
// the edge of the app was also reached here through another means
|
|
7838
|
+
// (maybe because the DOM was changed manually).
|
|
7839
|
+
if (!lView) {
|
|
7840
|
+
return null;
|
|
7841
|
+
}
|
|
7842
|
+
const index = findViaNativeElement(lView, rElement);
|
|
7843
|
+
if (index >= 0) {
|
|
7844
|
+
const native = unwrapRNode(lView[index]);
|
|
7845
|
+
const context = createLContext(lView, index, native);
|
|
7846
|
+
attachPatchData(native, context);
|
|
7847
|
+
mpValue = context;
|
|
7848
|
+
break;
|
|
7849
|
+
}
|
|
7792
7850
|
}
|
|
7793
7851
|
}
|
|
7794
7852
|
}
|
|
7853
|
+
return mpValue || null;
|
|
7795
7854
|
}
|
|
7796
7855
|
/**
|
|
7797
|
-
*
|
|
7798
|
-
|
|
7799
|
-
|
|
7800
|
-
|
|
7856
|
+
* Creates an empty instance of a `LContext` context
|
|
7857
|
+
*/
|
|
7858
|
+
function createLContext(lView, nodeIndex, native) {
|
|
7859
|
+
return new LContext(lView[ID], nodeIndex, native);
|
|
7860
|
+
}
|
|
7861
|
+
/**
|
|
7862
|
+
* Takes a component instance and returns the view for that component.
|
|
7801
7863
|
*
|
|
7802
|
-
*
|
|
7803
|
-
*
|
|
7804
|
-
* - the element is allowed by one of the schemas
|
|
7805
|
-
* - the property is used for animations
|
|
7806
|
-
*
|
|
7807
|
-
* @param element Element to validate
|
|
7808
|
-
* @param propName Name of the property to check
|
|
7809
|
-
* @param tagName Name of the tag hosting the property
|
|
7810
|
-
* @param schemas Array of schemas
|
|
7811
|
-
*/
|
|
7812
|
-
function isPropertyValid(element, propName, tagName, schemas) {
|
|
7813
|
-
// If `schemas` is set to `null`, that's an indication that this Component was compiled in AOT
|
|
7814
|
-
// mode where this check happens at compile time. In JIT mode, `schemas` is always present and
|
|
7815
|
-
// defined as an array (as an empty array in case `schemas` field is not defined) and we should
|
|
7816
|
-
// execute the check below.
|
|
7817
|
-
if (schemas === null)
|
|
7818
|
-
return true;
|
|
7819
|
-
// The property is considered valid if the element matches the schema, it exists on the element,
|
|
7820
|
-
// or it is synthetic, and we are in a browser context (web worker nodes should be skipped).
|
|
7821
|
-
if (matchingSchemas(schemas, tagName) || propName in element || isAnimationProp(propName)) {
|
|
7822
|
-
return true;
|
|
7823
|
-
}
|
|
7824
|
-
// Note: `typeof Node` returns 'function' in most browsers, but on IE it is 'object' so we
|
|
7825
|
-
// need to account for both here, while being careful with `typeof null` also returning 'object'.
|
|
7826
|
-
return typeof Node === 'undefined' || Node === null || !(element instanceof Node);
|
|
7827
|
-
}
|
|
7828
|
-
/**
|
|
7829
|
-
* Logs or throws an error that a property is not supported on an element.
|
|
7830
|
-
*
|
|
7831
|
-
* @param propName Name of the invalid property
|
|
7832
|
-
* @param tagName Name of the tag hosting the property
|
|
7833
|
-
* @param nodeType Type of the node hosting the property
|
|
7834
|
-
* @param lView An `LView` that represents a current component
|
|
7864
|
+
* @param componentInstance
|
|
7865
|
+
* @returns The component's view
|
|
7835
7866
|
*/
|
|
7836
|
-
function
|
|
7837
|
-
|
|
7838
|
-
|
|
7839
|
-
|
|
7840
|
-
|
|
7841
|
-
|
|
7842
|
-
|
|
7843
|
-
|
|
7844
|
-
|
|
7845
|
-
|
|
7846
|
-
|
|
7847
|
-
const templateLocation = getTemplateLocationDetails(lView);
|
|
7848
|
-
let message = `Can't bind to '${propName}' since it isn't a known property of '${tagName}'${templateLocation}.`;
|
|
7849
|
-
const schemas = `'${isHostStandalone ? '@Component' : '@NgModule'}.schemas'`;
|
|
7850
|
-
const importLocation = isHostStandalone ?
|
|
7851
|
-
'included in the \'@Component.imports\' of this component' :
|
|
7852
|
-
'a part of an @NgModule where this component is declared';
|
|
7853
|
-
if (KNOWN_CONTROL_FLOW_DIRECTIVES.has(propName)) {
|
|
7854
|
-
// Most likely this is a control flow directive (such as `*ngIf`) used in
|
|
7855
|
-
// a template, but the directive or the `CommonModule` is not imported.
|
|
7856
|
-
const correspondingImport = KNOWN_CONTROL_FLOW_DIRECTIVES.get(propName);
|
|
7857
|
-
message += `\nIf the '${propName}' is an Angular control flow directive, ` +
|
|
7858
|
-
`please make sure that either the '${correspondingImport}' directive or the 'CommonModule' is ${importLocation}.`;
|
|
7867
|
+
function getComponentViewByInstance(componentInstance) {
|
|
7868
|
+
let patchedData = readPatchedData(componentInstance);
|
|
7869
|
+
let lView;
|
|
7870
|
+
if (isLView(patchedData)) {
|
|
7871
|
+
const contextLView = patchedData;
|
|
7872
|
+
const nodeIndex = findViaComponent(contextLView, componentInstance);
|
|
7873
|
+
lView = getComponentLViewByIndex(nodeIndex, contextLView);
|
|
7874
|
+
const context = createLContext(contextLView, nodeIndex, lView[HOST]);
|
|
7875
|
+
context.component = componentInstance;
|
|
7876
|
+
attachPatchData(componentInstance, context);
|
|
7877
|
+
attachPatchData(context.native, context);
|
|
7859
7878
|
}
|
|
7860
7879
|
else {
|
|
7861
|
-
|
|
7862
|
-
|
|
7863
|
-
|
|
7864
|
-
|
|
7865
|
-
if (tagName && tagName.indexOf('-') > -1) {
|
|
7866
|
-
message += `\n2. If '${tagName}' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' ` +
|
|
7867
|
-
`to the ${schemas} of this component to suppress this message.`;
|
|
7868
|
-
message += `\n3. To allow any property add 'NO_ERRORS_SCHEMA' to ` +
|
|
7869
|
-
`the ${schemas} of this component.`;
|
|
7870
|
-
}
|
|
7871
|
-
else {
|
|
7872
|
-
// If it's expected, the error can be suppressed by the `NO_ERRORS_SCHEMA` schema.
|
|
7873
|
-
message += `\n2. To allow any property add 'NO_ERRORS_SCHEMA' to ` +
|
|
7874
|
-
`the ${schemas} of this component.`;
|
|
7875
|
-
}
|
|
7880
|
+
const context = patchedData;
|
|
7881
|
+
const contextLView = context.lView;
|
|
7882
|
+
ngDevMode && assertLView(contextLView);
|
|
7883
|
+
lView = getComponentLViewByIndex(context.nodeIndex, contextLView);
|
|
7876
7884
|
}
|
|
7877
|
-
|
|
7885
|
+
return lView;
|
|
7878
7886
|
}
|
|
7879
|
-
|
|
7880
|
-
|
|
7881
|
-
|
|
7887
|
+
/**
|
|
7888
|
+
* This property will be monkey-patched on elements, components and directives.
|
|
7889
|
+
*/
|
|
7890
|
+
const MONKEY_PATCH_KEY_NAME = '__ngContext__';
|
|
7891
|
+
/**
|
|
7892
|
+
* Assigns the given data to the given target (which could be a component,
|
|
7893
|
+
* directive or DOM node instance) using monkey-patching.
|
|
7894
|
+
*/
|
|
7895
|
+
function attachPatchData(target, data) {
|
|
7896
|
+
ngDevMode && assertDefined(target, 'Target expected');
|
|
7897
|
+
// Only attach the ID of the view in order to avoid memory leaks (see #41047). We only do this
|
|
7898
|
+
// for `LView`, because we have control over when an `LView` is created and destroyed, whereas
|
|
7899
|
+
// we can't know when to remove an `LContext`.
|
|
7900
|
+
if (isLView(data)) {
|
|
7901
|
+
target[MONKEY_PATCH_KEY_NAME] = data[ID];
|
|
7902
|
+
registerLView(data);
|
|
7882
7903
|
}
|
|
7883
7904
|
else {
|
|
7884
|
-
|
|
7905
|
+
target[MONKEY_PATCH_KEY_NAME] = data;
|
|
7885
7906
|
}
|
|
7886
7907
|
}
|
|
7887
7908
|
/**
|
|
7888
|
-
*
|
|
7889
|
-
*
|
|
7890
|
-
* be too slow for production mode and also it relies on the constructor function being available.
|
|
7891
|
-
*
|
|
7892
|
-
* Gets a reference to the host component def (where a current component is declared).
|
|
7893
|
-
*
|
|
7894
|
-
* @param lView An `LView` that represents a current component that is being rendered.
|
|
7909
|
+
* Returns the monkey-patch value data present on the target (which could be
|
|
7910
|
+
* a component, directive or a DOM node).
|
|
7895
7911
|
*/
|
|
7896
|
-
function
|
|
7897
|
-
|
|
7898
|
-
const
|
|
7899
|
-
|
|
7900
|
-
|
|
7901
|
-
|
|
7902
|
-
|
|
7903
|
-
|
|
7912
|
+
function readPatchedData(target) {
|
|
7913
|
+
ngDevMode && assertDefined(target, 'Target expected');
|
|
7914
|
+
const data = target[MONKEY_PATCH_KEY_NAME];
|
|
7915
|
+
return (typeof data === 'number') ? getLViewById(data) : data || null;
|
|
7916
|
+
}
|
|
7917
|
+
function readPatchedLView(target) {
|
|
7918
|
+
const value = readPatchedData(target);
|
|
7919
|
+
if (value) {
|
|
7920
|
+
return (isLView(value) ? value : value.lView);
|
|
7921
|
+
}
|
|
7922
|
+
return null;
|
|
7923
|
+
}
|
|
7924
|
+
function isComponentInstance(instance) {
|
|
7925
|
+
return instance && instance.constructor && instance.constructor.ɵcmp;
|
|
7926
|
+
}
|
|
7927
|
+
function isDirectiveInstance(instance) {
|
|
7928
|
+
return instance && instance.constructor && instance.constructor.ɵdir;
|
|
7904
7929
|
}
|
|
7905
7930
|
/**
|
|
7906
|
-
*
|
|
7907
|
-
* and must **not** be used in production bundles. The function makes megamorphic reads, which might
|
|
7908
|
-
* be too slow for production mode.
|
|
7909
|
-
*
|
|
7910
|
-
* Checks if the current component is declared inside of a standalone component template.
|
|
7911
|
-
*
|
|
7912
|
-
* @param lView An `LView` that represents a current component that is being rendered.
|
|
7931
|
+
* Locates the element within the given LView and returns the matching index
|
|
7913
7932
|
*/
|
|
7914
|
-
function
|
|
7915
|
-
|
|
7916
|
-
|
|
7917
|
-
|
|
7918
|
-
|
|
7933
|
+
function findViaNativeElement(lView, target) {
|
|
7934
|
+
const tView = lView[TVIEW];
|
|
7935
|
+
for (let i = HEADER_OFFSET; i < tView.bindingStartIndex; i++) {
|
|
7936
|
+
if (unwrapRNode(lView[i]) === target) {
|
|
7937
|
+
return i;
|
|
7938
|
+
}
|
|
7939
|
+
}
|
|
7940
|
+
return -1;
|
|
7919
7941
|
}
|
|
7920
7942
|
/**
|
|
7921
|
-
*
|
|
7922
|
-
* and must **not** be used in production bundles. The function makes megamorphic reads, which might
|
|
7923
|
-
* be too slow for production mode.
|
|
7924
|
-
*
|
|
7925
|
-
* Constructs a string describing the location of the host component template. The function is used
|
|
7926
|
-
* in dev mode to produce error messages.
|
|
7927
|
-
*
|
|
7928
|
-
* @param lView An `LView` that represents a current component that is being rendered.
|
|
7943
|
+
* Locates the next tNode (child, sibling or parent).
|
|
7929
7944
|
*/
|
|
7930
|
-
function
|
|
7931
|
-
|
|
7932
|
-
|
|
7933
|
-
|
|
7934
|
-
|
|
7935
|
-
|
|
7945
|
+
function traverseNextElement(tNode) {
|
|
7946
|
+
if (tNode.child) {
|
|
7947
|
+
return tNode.child;
|
|
7948
|
+
}
|
|
7949
|
+
else if (tNode.next) {
|
|
7950
|
+
return tNode.next;
|
|
7951
|
+
}
|
|
7952
|
+
else {
|
|
7953
|
+
// Let's take the following template: <div><span>text</span></div><component/>
|
|
7954
|
+
// After checking the text node, we need to find the next parent that has a "next" TNode,
|
|
7955
|
+
// in this case the parent `div`, so that we can find the component.
|
|
7956
|
+
while (tNode.parent && !tNode.parent.next) {
|
|
7957
|
+
tNode = tNode.parent;
|
|
7958
|
+
}
|
|
7959
|
+
return tNode.parent && tNode.parent.next;
|
|
7960
|
+
}
|
|
7936
7961
|
}
|
|
7937
7962
|
/**
|
|
7938
|
-
*
|
|
7939
|
-
* We use this set to produce a more precises error message with a note
|
|
7940
|
-
* that the `CommonModule` should also be included.
|
|
7963
|
+
* Locates the component within the given LView and returns the matching index
|
|
7941
7964
|
*/
|
|
7942
|
-
|
|
7943
|
-
|
|
7944
|
-
|
|
7945
|
-
|
|
7965
|
+
function findViaComponent(lView, componentInstance) {
|
|
7966
|
+
const componentIndices = lView[TVIEW].components;
|
|
7967
|
+
if (componentIndices) {
|
|
7968
|
+
for (let i = 0; i < componentIndices.length; i++) {
|
|
7969
|
+
const elementComponentIndex = componentIndices[i];
|
|
7970
|
+
const componentView = getComponentLViewByIndex(elementComponentIndex, lView);
|
|
7971
|
+
if (componentView[CONTEXT] === componentInstance) {
|
|
7972
|
+
return elementComponentIndex;
|
|
7973
|
+
}
|
|
7974
|
+
}
|
|
7975
|
+
}
|
|
7976
|
+
else {
|
|
7977
|
+
const rootComponentView = getComponentLViewByIndex(HEADER_OFFSET, lView);
|
|
7978
|
+
const rootComponent = rootComponentView[CONTEXT];
|
|
7979
|
+
if (rootComponent === componentInstance) {
|
|
7980
|
+
// we are dealing with the root element here therefore we know that the
|
|
7981
|
+
// element is the very first element after the HEADER data in the lView
|
|
7982
|
+
return HEADER_OFFSET;
|
|
7983
|
+
}
|
|
7984
|
+
}
|
|
7985
|
+
return -1;
|
|
7986
|
+
}
|
|
7946
7987
|
/**
|
|
7947
|
-
*
|
|
7948
|
-
* @param schemas Array of schemas
|
|
7949
|
-
* @param tagName Name of the tag
|
|
7988
|
+
* Locates the directive within the given LView and returns the matching index
|
|
7950
7989
|
*/
|
|
7951
|
-
function
|
|
7952
|
-
if (
|
|
7953
|
-
|
|
7954
|
-
|
|
7955
|
-
|
|
7956
|
-
|
|
7957
|
-
|
|
7990
|
+
function findViaDirective(lView, directiveInstance) {
|
|
7991
|
+
// if a directive is monkey patched then it will (by default)
|
|
7992
|
+
// have a reference to the LView of the current view. The
|
|
7993
|
+
// element bound to the directive being search lives somewhere
|
|
7994
|
+
// in the view data. We loop through the nodes and check their
|
|
7995
|
+
// list of directives for the instance.
|
|
7996
|
+
let tNode = lView[TVIEW].firstChild;
|
|
7997
|
+
while (tNode) {
|
|
7998
|
+
const directiveIndexStart = tNode.directiveStart;
|
|
7999
|
+
const directiveIndexEnd = tNode.directiveEnd;
|
|
8000
|
+
for (let i = directiveIndexStart; i < directiveIndexEnd; i++) {
|
|
8001
|
+
if (lView[i] === directiveInstance) {
|
|
8002
|
+
return tNode.index;
|
|
7958
8003
|
}
|
|
7959
8004
|
}
|
|
8005
|
+
tNode = traverseNextElement(tNode);
|
|
7960
8006
|
}
|
|
7961
|
-
return
|
|
8007
|
+
return -1;
|
|
7962
8008
|
}
|
|
7963
|
-
|
|
7964
8009
|
/**
|
|
7965
|
-
*
|
|
7966
|
-
*
|
|
8010
|
+
* Returns a list of directives applied to a node at a specific index. The list includes
|
|
8011
|
+
* directives matched by selector and any host directives, but it excludes components.
|
|
8012
|
+
* Use `getComponentAtNodeIndex` to find the component applied to a node.
|
|
7967
8013
|
*
|
|
7968
|
-
*
|
|
7969
|
-
*
|
|
8014
|
+
* @param nodeIndex The node index
|
|
8015
|
+
* @param lView The target view data
|
|
7970
8016
|
*/
|
|
7971
|
-
|
|
7972
|
-
|
|
7973
|
-
|
|
7974
|
-
|
|
7975
|
-
|
|
7976
|
-
|
|
8017
|
+
function getDirectivesAtNodeIndex(nodeIndex, lView) {
|
|
8018
|
+
const tNode = lView[TVIEW].data[nodeIndex];
|
|
8019
|
+
if (tNode.directiveStart === 0)
|
|
8020
|
+
return EMPTY_ARRAY;
|
|
8021
|
+
const results = [];
|
|
8022
|
+
for (let i = tNode.directiveStart; i < tNode.directiveEnd; i++) {
|
|
8023
|
+
const directiveInstance = lView[i];
|
|
8024
|
+
if (!isComponentInstance(directiveInstance)) {
|
|
8025
|
+
results.push(directiveInstance);
|
|
8026
|
+
}
|
|
8027
|
+
}
|
|
8028
|
+
return results;
|
|
7977
8029
|
}
|
|
7978
|
-
function
|
|
7979
|
-
|
|
8030
|
+
function getComponentAtNodeIndex(nodeIndex, lView) {
|
|
8031
|
+
const tNode = lView[TVIEW].data[nodeIndex];
|
|
8032
|
+
const { directiveStart, componentOffset } = tNode;
|
|
8033
|
+
return componentOffset > -1 ? lView[directiveStart + componentOffset] : null;
|
|
7980
8034
|
}
|
|
7981
|
-
|
|
7982
|
-
/**
|
|
7983
|
-
* @license
|
|
7984
|
-
* Copyright Google LLC All Rights Reserved.
|
|
7985
|
-
*
|
|
7986
|
-
* Use of this source code is governed by an MIT-style license that can be
|
|
7987
|
-
* found in the LICENSE file at https://angular.io/license
|
|
7988
|
-
*/
|
|
7989
8035
|
/**
|
|
7990
|
-
*
|
|
7991
|
-
*
|
|
7992
|
-
* The default implementation of `ErrorHandler` prints error messages to the `console`. To
|
|
7993
|
-
* intercept error handling, write a custom exception handler that replaces this default as
|
|
7994
|
-
* appropriate for your app.
|
|
7995
|
-
*
|
|
7996
|
-
* @usageNotes
|
|
7997
|
-
* ### Example
|
|
7998
|
-
*
|
|
7999
|
-
* ```
|
|
8000
|
-
* class MyErrorHandler implements ErrorHandler {
|
|
8001
|
-
* handleError(error) {
|
|
8002
|
-
* // do something with the exception
|
|
8003
|
-
* }
|
|
8004
|
-
* }
|
|
8005
|
-
*
|
|
8006
|
-
* @NgModule({
|
|
8007
|
-
* providers: [{provide: ErrorHandler, useClass: MyErrorHandler}]
|
|
8008
|
-
* })
|
|
8009
|
-
* class MyModule {}
|
|
8010
|
-
* ```
|
|
8011
|
-
*
|
|
8012
|
-
* @publicApi
|
|
8036
|
+
* Returns a map of local references (local reference name => element or directive instance) that
|
|
8037
|
+
* exist on a given element.
|
|
8013
8038
|
*/
|
|
8014
|
-
|
|
8015
|
-
|
|
8016
|
-
|
|
8017
|
-
|
|
8018
|
-
|
|
8019
|
-
|
|
8020
|
-
|
|
8021
|
-
|
|
8022
|
-
const originalError = this._findOriginalError(error);
|
|
8023
|
-
this._console.error('ERROR', error);
|
|
8024
|
-
if (originalError) {
|
|
8025
|
-
this._console.error('ORIGINAL ERROR', originalError);
|
|
8026
|
-
}
|
|
8027
|
-
}
|
|
8028
|
-
/** @internal */
|
|
8029
|
-
_findOriginalError(error) {
|
|
8030
|
-
let e = error && getOriginalError(error);
|
|
8031
|
-
while (e && getOriginalError(e)) {
|
|
8032
|
-
e = getOriginalError(e);
|
|
8039
|
+
function discoverLocalRefs(lView, nodeIndex) {
|
|
8040
|
+
const tNode = lView[TVIEW].data[nodeIndex];
|
|
8041
|
+
if (tNode && tNode.localNames) {
|
|
8042
|
+
const result = {};
|
|
8043
|
+
let localIndex = tNode.index + 1;
|
|
8044
|
+
for (let i = 0; i < tNode.localNames.length; i += 2) {
|
|
8045
|
+
result[tNode.localNames[i]] = lView[localIndex];
|
|
8046
|
+
localIndex++;
|
|
8033
8047
|
}
|
|
8034
|
-
return
|
|
8048
|
+
return result;
|
|
8035
8049
|
}
|
|
8050
|
+
return null;
|
|
8036
8051
|
}
|
|
8037
8052
|
|
|
8038
8053
|
/**
|
|
@@ -8043,46 +8058,28 @@ class ErrorHandler {
|
|
|
8043
8058
|
* found in the LICENSE file at https://angular.io/license
|
|
8044
8059
|
*/
|
|
8045
8060
|
/**
|
|
8046
|
-
*
|
|
8061
|
+
* Defines a schema that allows an NgModule to contain the following:
|
|
8062
|
+
* - Non-Angular elements named with dash case (`-`).
|
|
8063
|
+
* - Element properties named with dash case (`-`).
|
|
8064
|
+
* Dash case is the naming convention for custom elements.
|
|
8047
8065
|
*
|
|
8048
|
-
*
|
|
8049
|
-
*/
|
|
8050
|
-
const COMMENT_DISALLOWED = /^>|^->|<!--|-->|--!>|<!-$/g;
|
|
8051
|
-
/**
|
|
8052
|
-
* Delimiter in the disallowed strings which needs to be wrapped with zero with character.
|
|
8066
|
+
* @publicApi
|
|
8053
8067
|
*/
|
|
8054
|
-
const
|
|
8055
|
-
|
|
8068
|
+
const CUSTOM_ELEMENTS_SCHEMA = {
|
|
8069
|
+
name: 'custom-elements'
|
|
8070
|
+
};
|
|
8056
8071
|
/**
|
|
8057
|
-
*
|
|
8058
|
-
*
|
|
8059
|
-
* The issue is that HTML does not specify any way to escape comment end text inside the comment.
|
|
8060
|
-
* Consider: `<!-- The way you close a comment is with ">", and "->" at the beginning or by "-->" or
|
|
8061
|
-
* "--!>" at the end. -->`. Above the `"-->"` is meant to be text not an end to the comment. This
|
|
8062
|
-
* can be created programmatically through DOM APIs. (`<!--` are also disallowed.)
|
|
8063
|
-
*
|
|
8064
|
-
* see: https://html.spec.whatwg.org/multipage/syntax.html#comments
|
|
8065
|
-
*
|
|
8066
|
-
* ```
|
|
8067
|
-
* div.innerHTML = div.innerHTML
|
|
8068
|
-
* ```
|
|
8069
|
-
*
|
|
8070
|
-
* One would expect that the above code would be safe to do, but it turns out that because comment
|
|
8071
|
-
* text is not escaped, the comment may contain text which will prematurely close the comment
|
|
8072
|
-
* opening up the application for XSS attack. (In SSR we programmatically create comment nodes which
|
|
8073
|
-
* may contain such text and expect them to be safe.)
|
|
8072
|
+
* Defines a schema that allows any property on any element.
|
|
8074
8073
|
*
|
|
8075
|
-
* This
|
|
8076
|
-
*
|
|
8077
|
-
*
|
|
8078
|
-
* text it will render normally but it will not cause the HTML parser to close/open the comment.
|
|
8074
|
+
* This schema allows you to ignore the errors related to any unknown elements or properties in a
|
|
8075
|
+
* template. The usage of this schema is generally discouraged because it prevents useful validation
|
|
8076
|
+
* and may hide real errors in your template. Consider using the `CUSTOM_ELEMENTS_SCHEMA` instead.
|
|
8079
8077
|
*
|
|
8080
|
-
* @
|
|
8081
|
-
* sequence.
|
|
8078
|
+
* @publicApi
|
|
8082
8079
|
*/
|
|
8083
|
-
|
|
8084
|
-
|
|
8085
|
-
}
|
|
8080
|
+
const NO_ERRORS_SCHEMA = {
|
|
8081
|
+
name: 'no-errors-schema'
|
|
8082
|
+
};
|
|
8086
8083
|
|
|
8087
8084
|
/**
|
|
8088
8085
|
* @license
|
|
@@ -8091,400 +8088,412 @@ function escapeCommentText(value) {
|
|
|
8091
8088
|
* Use of this source code is governed by an MIT-style license that can be
|
|
8092
8089
|
* found in the LICENSE file at https://angular.io/license
|
|
8093
8090
|
*/
|
|
8094
|
-
|
|
8095
|
-
// Attribute names with `$` (eg `x-y$`) are valid per spec, but unsupported by some browsers
|
|
8096
|
-
name = camelCaseToDashCase(name.replace(/[$@]/g, '_'));
|
|
8097
|
-
return `ng-reflect-${name}`;
|
|
8098
|
-
}
|
|
8099
|
-
const CAMEL_CASE_REGEXP = /([A-Z])/g;
|
|
8100
|
-
function camelCaseToDashCase(input) {
|
|
8101
|
-
return input.replace(CAMEL_CASE_REGEXP, (...m) => '-' + m[1].toLowerCase());
|
|
8102
|
-
}
|
|
8103
|
-
function normalizeDebugBindingValue(value) {
|
|
8104
|
-
try {
|
|
8105
|
-
// Limit the size of the value as otherwise the DOM just gets polluted.
|
|
8106
|
-
return value != null ? value.toString().slice(0, 30) : value;
|
|
8107
|
-
}
|
|
8108
|
-
catch (e) {
|
|
8109
|
-
return '[ERROR] Exception while trying to serialize the value';
|
|
8110
|
-
}
|
|
8111
|
-
}
|
|
8112
|
-
|
|
8091
|
+
let shouldThrowErrorOnUnknownElement = false;
|
|
8113
8092
|
/**
|
|
8114
|
-
*
|
|
8115
|
-
*
|
|
8116
|
-
*
|
|
8117
|
-
* Use of this source code is governed by an MIT-style license that can be
|
|
8118
|
-
* found in the LICENSE file at https://angular.io/license
|
|
8093
|
+
* Sets a strict mode for JIT-compiled components to throw an error on unknown elements,
|
|
8094
|
+
* instead of just logging the error.
|
|
8095
|
+
* (for AOT-compiled ones this check happens at build time).
|
|
8119
8096
|
*/
|
|
8120
|
-
|
|
8121
|
-
|
|
8122
|
-
// Used for generating unique IDs for LViews.
|
|
8123
|
-
let uniqueIdCounter = 0;
|
|
8124
|
-
/** Gets a unique ID that can be assigned to an LView. */
|
|
8125
|
-
function getUniqueLViewId() {
|
|
8126
|
-
return uniqueIdCounter++;
|
|
8127
|
-
}
|
|
8128
|
-
/** Starts tracking an LView. */
|
|
8129
|
-
function registerLView(lView) {
|
|
8130
|
-
ngDevMode && assertNumber(lView[ID], 'LView must have an ID in order to be registered');
|
|
8131
|
-
TRACKED_LVIEWS.set(lView[ID], lView);
|
|
8132
|
-
}
|
|
8133
|
-
/** Gets an LView by its unique ID. */
|
|
8134
|
-
function getLViewById(id) {
|
|
8135
|
-
ngDevMode && assertNumber(id, 'ID used for LView lookup must be a number');
|
|
8136
|
-
return TRACKED_LVIEWS.get(id) || null;
|
|
8137
|
-
}
|
|
8138
|
-
/** Stops tracking an LView. */
|
|
8139
|
-
function unregisterLView(lView) {
|
|
8140
|
-
ngDevMode && assertNumber(lView[ID], 'Cannot stop tracking an LView that does not have an ID');
|
|
8141
|
-
TRACKED_LVIEWS.delete(lView[ID]);
|
|
8097
|
+
function ɵsetUnknownElementStrictMode(shouldThrow) {
|
|
8098
|
+
shouldThrowErrorOnUnknownElement = shouldThrow;
|
|
8142
8099
|
}
|
|
8143
|
-
|
|
8144
8100
|
/**
|
|
8145
|
-
*
|
|
8146
|
-
* Copyright Google LLC All Rights Reserved.
|
|
8147
|
-
*
|
|
8148
|
-
* Use of this source code is governed by an MIT-style license that can be
|
|
8149
|
-
* found in the LICENSE file at https://angular.io/license
|
|
8101
|
+
* Gets the current value of the strict mode.
|
|
8150
8102
|
*/
|
|
8103
|
+
function ɵgetUnknownElementStrictMode() {
|
|
8104
|
+
return shouldThrowErrorOnUnknownElement;
|
|
8105
|
+
}
|
|
8106
|
+
let shouldThrowErrorOnUnknownProperty = false;
|
|
8151
8107
|
/**
|
|
8152
|
-
*
|
|
8153
|
-
*
|
|
8154
|
-
*
|
|
8155
|
-
* looked up yet, otherwise, if null, then a lookup was executed and nothing was found.
|
|
8156
|
-
*
|
|
8157
|
-
* Each value will get filled when the respective value is examined within the getContext
|
|
8158
|
-
* function. The component, element and each directive instance will share the same instance
|
|
8159
|
-
* of the context.
|
|
8108
|
+
* Sets a strict mode for JIT-compiled components to throw an error on unknown properties,
|
|
8109
|
+
* instead of just logging the error.
|
|
8110
|
+
* (for AOT-compiled ones this check happens at build time).
|
|
8160
8111
|
*/
|
|
8161
|
-
|
|
8162
|
-
|
|
8163
|
-
/**
|
|
8164
|
-
* ID of the component's parent view data.
|
|
8165
|
-
*/
|
|
8166
|
-
lViewId,
|
|
8167
|
-
/**
|
|
8168
|
-
* The index instance of the node.
|
|
8169
|
-
*/
|
|
8170
|
-
nodeIndex,
|
|
8171
|
-
/**
|
|
8172
|
-
* The instance of the DOM node that is attached to the lNode.
|
|
8173
|
-
*/
|
|
8174
|
-
native) {
|
|
8175
|
-
this.lViewId = lViewId;
|
|
8176
|
-
this.nodeIndex = nodeIndex;
|
|
8177
|
-
this.native = native;
|
|
8178
|
-
}
|
|
8179
|
-
/** Component's parent view data. */
|
|
8180
|
-
get lView() {
|
|
8181
|
-
return getLViewById(this.lViewId);
|
|
8182
|
-
}
|
|
8112
|
+
function ɵsetUnknownPropertyStrictMode(shouldThrow) {
|
|
8113
|
+
shouldThrowErrorOnUnknownProperty = shouldThrow;
|
|
8183
8114
|
}
|
|
8184
|
-
|
|
8185
8115
|
/**
|
|
8186
|
-
*
|
|
8187
|
-
* Copyright Google LLC All Rights Reserved.
|
|
8188
|
-
*
|
|
8189
|
-
* Use of this source code is governed by an MIT-style license that can be
|
|
8190
|
-
* found in the LICENSE file at https://angular.io/license
|
|
8116
|
+
* Gets the current value of the strict mode.
|
|
8191
8117
|
*/
|
|
8118
|
+
function ɵgetUnknownPropertyStrictMode() {
|
|
8119
|
+
return shouldThrowErrorOnUnknownProperty;
|
|
8120
|
+
}
|
|
8192
8121
|
/**
|
|
8193
|
-
*
|
|
8122
|
+
* Validates that the element is known at runtime and produces
|
|
8123
|
+
* an error if it's not the case.
|
|
8124
|
+
* This check is relevant for JIT-compiled components (for AOT-compiled
|
|
8125
|
+
* ones this check happens at build time).
|
|
8194
8126
|
*
|
|
8195
|
-
*
|
|
8196
|
-
*
|
|
8197
|
-
*
|
|
8127
|
+
* The element is considered known if either:
|
|
8128
|
+
* - it's a known HTML element
|
|
8129
|
+
* - it's a known custom element
|
|
8130
|
+
* - the element matches any directive
|
|
8131
|
+
* - the element is allowed by one of the schemas
|
|
8198
8132
|
*
|
|
8199
|
-
*
|
|
8200
|
-
*
|
|
8201
|
-
*
|
|
8202
|
-
*
|
|
8203
|
-
*
|
|
8204
|
-
* If the monkey-patch value is not detected then the code will walk up the DOM until an element
|
|
8205
|
-
* is found which contains a monkey-patch reference. When that occurs then the provided element
|
|
8206
|
-
* will be updated with a new context (which is then returned). If the monkey-patch value is not
|
|
8207
|
-
* detected for a component/directive instance then it will throw an error (all components and
|
|
8208
|
-
* directives should be automatically monkey-patched by ivy).
|
|
8209
|
-
*
|
|
8210
|
-
* @param target Component, Directive or DOM Node.
|
|
8133
|
+
* @param element Element to validate
|
|
8134
|
+
* @param lView An `LView` that represents a current component that is being rendered
|
|
8135
|
+
* @param tagName Name of the tag to check
|
|
8136
|
+
* @param schemas Array of schemas
|
|
8137
|
+
* @param hasDirectives Boolean indicating that the element matches any directive
|
|
8211
8138
|
*/
|
|
8212
|
-
function
|
|
8213
|
-
|
|
8214
|
-
|
|
8215
|
-
|
|
8216
|
-
|
|
8217
|
-
|
|
8218
|
-
|
|
8219
|
-
|
|
8220
|
-
|
|
8221
|
-
|
|
8222
|
-
|
|
8223
|
-
|
|
8224
|
-
|
|
8225
|
-
|
|
8226
|
-
|
|
8227
|
-
|
|
8228
|
-
|
|
8229
|
-
|
|
8230
|
-
|
|
8231
|
-
|
|
8232
|
-
|
|
8233
|
-
|
|
8234
|
-
|
|
8139
|
+
function validateElementIsKnown(element, lView, tagName, schemas, hasDirectives) {
|
|
8140
|
+
// If `schemas` is set to `null`, that's an indication that this Component was compiled in AOT
|
|
8141
|
+
// mode where this check happens at compile time. In JIT mode, `schemas` is always present and
|
|
8142
|
+
// defined as an array (as an empty array in case `schemas` field is not defined) and we should
|
|
8143
|
+
// execute the check below.
|
|
8144
|
+
if (schemas === null)
|
|
8145
|
+
return;
|
|
8146
|
+
// If the element matches any directive, it's considered as valid.
|
|
8147
|
+
if (!hasDirectives && tagName !== null) {
|
|
8148
|
+
// The element is unknown if it's an instance of HTMLUnknownElement, or it isn't registered
|
|
8149
|
+
// as a custom element. Note that unknown elements with a dash in their name won't be instances
|
|
8150
|
+
// of HTMLUnknownElement in browsers that support web components.
|
|
8151
|
+
const isUnknown =
|
|
8152
|
+
// Note that we can't check for `typeof HTMLUnknownElement === 'function'`,
|
|
8153
|
+
// because while most browsers return 'function', IE returns 'object'.
|
|
8154
|
+
(typeof HTMLUnknownElement !== 'undefined' && HTMLUnknownElement &&
|
|
8155
|
+
element instanceof HTMLUnknownElement) ||
|
|
8156
|
+
(typeof customElements !== 'undefined' && tagName.indexOf('-') > -1 &&
|
|
8157
|
+
!customElements.get(tagName));
|
|
8158
|
+
if (isUnknown && !matchingSchemas(schemas, tagName)) {
|
|
8159
|
+
const isHostStandalone = isHostComponentStandalone(lView);
|
|
8160
|
+
const templateLocation = getTemplateLocationDetails(lView);
|
|
8161
|
+
const schemas = `'${isHostStandalone ? '@Component' : '@NgModule'}.schemas'`;
|
|
8162
|
+
let message = `'${tagName}' is not a known element${templateLocation}:\n`;
|
|
8163
|
+
message += `1. If '${tagName}' is an Angular component, then verify that it is ${isHostStandalone ? 'included in the \'@Component.imports\' of this component' :
|
|
8164
|
+
'a part of an @NgModule where this component is declared'}.\n`;
|
|
8165
|
+
if (tagName && tagName.indexOf('-') > -1) {
|
|
8166
|
+
message +=
|
|
8167
|
+
`2. If '${tagName}' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the ${schemas} of this component to suppress this message.`;
|
|
8235
8168
|
}
|
|
8236
8169
|
else {
|
|
8237
|
-
|
|
8238
|
-
|
|
8239
|
-
return null;
|
|
8240
|
-
}
|
|
8241
|
-
}
|
|
8242
|
-
// the goal is not to fill the entire context full of data because the lookups
|
|
8243
|
-
// are expensive. Instead, only the target data (the element, component, container, ICU
|
|
8244
|
-
// expression or directive details) are filled into the context. If called multiple times
|
|
8245
|
-
// with different target values then the missing target data will be filled in.
|
|
8246
|
-
const native = unwrapRNode(lView[nodeIndex]);
|
|
8247
|
-
const existingCtx = readPatchedData(native);
|
|
8248
|
-
const context = (existingCtx && !Array.isArray(existingCtx)) ?
|
|
8249
|
-
existingCtx :
|
|
8250
|
-
createLContext(lView, nodeIndex, native);
|
|
8251
|
-
// only when the component has been discovered then update the monkey-patch
|
|
8252
|
-
if (component && context.component === undefined) {
|
|
8253
|
-
context.component = component;
|
|
8254
|
-
attachPatchData(context.component, context);
|
|
8170
|
+
message +=
|
|
8171
|
+
`2. To allow any element add 'NO_ERRORS_SCHEMA' to the ${schemas} of this component.`;
|
|
8255
8172
|
}
|
|
8256
|
-
|
|
8257
|
-
|
|
8258
|
-
context.directives = directives;
|
|
8259
|
-
for (let i = 0; i < directives.length; i++) {
|
|
8260
|
-
attachPatchData(directives[i], context);
|
|
8261
|
-
}
|
|
8173
|
+
if (shouldThrowErrorOnUnknownElement) {
|
|
8174
|
+
throw new RuntimeError(304 /* RuntimeErrorCode.UNKNOWN_ELEMENT */, message);
|
|
8262
8175
|
}
|
|
8263
|
-
|
|
8264
|
-
|
|
8265
|
-
}
|
|
8266
|
-
}
|
|
8267
|
-
else {
|
|
8268
|
-
const rElement = target;
|
|
8269
|
-
ngDevMode && assertDomNode(rElement);
|
|
8270
|
-
// if the context is not found then we need to traverse upwards up the DOM
|
|
8271
|
-
// to find the nearest element that has already been monkey patched with data
|
|
8272
|
-
let parent = rElement;
|
|
8273
|
-
while (parent = parent.parentNode) {
|
|
8274
|
-
const parentContext = readPatchedData(parent);
|
|
8275
|
-
if (parentContext) {
|
|
8276
|
-
const lView = Array.isArray(parentContext) ? parentContext : parentContext.lView;
|
|
8277
|
-
// the edge of the app was also reached here through another means
|
|
8278
|
-
// (maybe because the DOM was changed manually).
|
|
8279
|
-
if (!lView) {
|
|
8280
|
-
return null;
|
|
8281
|
-
}
|
|
8282
|
-
const index = findViaNativeElement(lView, rElement);
|
|
8283
|
-
if (index >= 0) {
|
|
8284
|
-
const native = unwrapRNode(lView[index]);
|
|
8285
|
-
const context = createLContext(lView, index, native);
|
|
8286
|
-
attachPatchData(native, context);
|
|
8287
|
-
mpValue = context;
|
|
8288
|
-
break;
|
|
8289
|
-
}
|
|
8176
|
+
else {
|
|
8177
|
+
console.error(formatRuntimeError(304 /* RuntimeErrorCode.UNKNOWN_ELEMENT */, message));
|
|
8290
8178
|
}
|
|
8291
8179
|
}
|
|
8292
8180
|
}
|
|
8293
|
-
return mpValue || null;
|
|
8294
8181
|
}
|
|
8295
8182
|
/**
|
|
8296
|
-
*
|
|
8183
|
+
* Validates that the property of the element is known at runtime and returns
|
|
8184
|
+
* false if it's not the case.
|
|
8185
|
+
* This check is relevant for JIT-compiled components (for AOT-compiled
|
|
8186
|
+
* ones this check happens at build time).
|
|
8187
|
+
*
|
|
8188
|
+
* The property is considered known if either:
|
|
8189
|
+
* - it's a known property of the element
|
|
8190
|
+
* - the element is allowed by one of the schemas
|
|
8191
|
+
* - the property is used for animations
|
|
8192
|
+
*
|
|
8193
|
+
* @param element Element to validate
|
|
8194
|
+
* @param propName Name of the property to check
|
|
8195
|
+
* @param tagName Name of the tag hosting the property
|
|
8196
|
+
* @param schemas Array of schemas
|
|
8297
8197
|
*/
|
|
8298
|
-
function
|
|
8299
|
-
|
|
8198
|
+
function isPropertyValid(element, propName, tagName, schemas) {
|
|
8199
|
+
// If `schemas` is set to `null`, that's an indication that this Component was compiled in AOT
|
|
8200
|
+
// mode where this check happens at compile time. In JIT mode, `schemas` is always present and
|
|
8201
|
+
// defined as an array (as an empty array in case `schemas` field is not defined) and we should
|
|
8202
|
+
// execute the check below.
|
|
8203
|
+
if (schemas === null)
|
|
8204
|
+
return true;
|
|
8205
|
+
// The property is considered valid if the element matches the schema, it exists on the element,
|
|
8206
|
+
// or it is synthetic, and we are in a browser context (web worker nodes should be skipped).
|
|
8207
|
+
if (matchingSchemas(schemas, tagName) || propName in element || isAnimationProp(propName)) {
|
|
8208
|
+
return true;
|
|
8209
|
+
}
|
|
8210
|
+
// Note: `typeof Node` returns 'function' in most browsers, but on IE it is 'object' so we
|
|
8211
|
+
// need to account for both here, while being careful with `typeof null` also returning 'object'.
|
|
8212
|
+
return typeof Node === 'undefined' || Node === null || !(element instanceof Node);
|
|
8300
8213
|
}
|
|
8301
8214
|
/**
|
|
8302
|
-
*
|
|
8215
|
+
* Logs or throws an error that a property is not supported on an element.
|
|
8303
8216
|
*
|
|
8304
|
-
* @param
|
|
8305
|
-
* @
|
|
8217
|
+
* @param propName Name of the invalid property
|
|
8218
|
+
* @param tagName Name of the tag hosting the property
|
|
8219
|
+
* @param nodeType Type of the node hosting the property
|
|
8220
|
+
* @param lView An `LView` that represents a current component
|
|
8306
8221
|
*/
|
|
8307
|
-
function
|
|
8308
|
-
|
|
8309
|
-
|
|
8310
|
-
|
|
8311
|
-
|
|
8312
|
-
|
|
8313
|
-
|
|
8314
|
-
|
|
8315
|
-
|
|
8316
|
-
|
|
8317
|
-
|
|
8222
|
+
function handleUnknownPropertyError(propName, tagName, nodeType, lView) {
|
|
8223
|
+
// Special-case a situation when a structural directive is applied to
|
|
8224
|
+
// an `<ng-template>` element, for example: `<ng-template *ngIf="true">`.
|
|
8225
|
+
// In this case the compiler generates the `ɵɵtemplate` instruction with
|
|
8226
|
+
// the `null` as the tagName. The directive matching logic at runtime relies
|
|
8227
|
+
// on this effect (see `isInlineTemplate`), thus using the 'ng-template' as
|
|
8228
|
+
// a default value of the `tNode.value` is not feasible at this moment.
|
|
8229
|
+
if (!tagName && nodeType === 4 /* TNodeType.Container */) {
|
|
8230
|
+
tagName = 'ng-template';
|
|
8231
|
+
}
|
|
8232
|
+
const isHostStandalone = isHostComponentStandalone(lView);
|
|
8233
|
+
const templateLocation = getTemplateLocationDetails(lView);
|
|
8234
|
+
let message = `Can't bind to '${propName}' since it isn't a known property of '${tagName}'${templateLocation}.`;
|
|
8235
|
+
const schemas = `'${isHostStandalone ? '@Component' : '@NgModule'}.schemas'`;
|
|
8236
|
+
const importLocation = isHostStandalone ?
|
|
8237
|
+
'included in the \'@Component.imports\' of this component' :
|
|
8238
|
+
'a part of an @NgModule where this component is declared';
|
|
8239
|
+
if (KNOWN_CONTROL_FLOW_DIRECTIVES.has(propName)) {
|
|
8240
|
+
// Most likely this is a control flow directive (such as `*ngIf`) used in
|
|
8241
|
+
// a template, but the directive or the `CommonModule` is not imported.
|
|
8242
|
+
const correspondingImport = KNOWN_CONTROL_FLOW_DIRECTIVES.get(propName);
|
|
8243
|
+
message += `\nIf the '${propName}' is an Angular control flow directive, ` +
|
|
8244
|
+
`please make sure that either the '${correspondingImport}' directive or the 'CommonModule' is ${importLocation}.`;
|
|
8318
8245
|
}
|
|
8319
8246
|
else {
|
|
8320
|
-
|
|
8321
|
-
|
|
8322
|
-
|
|
8323
|
-
|
|
8247
|
+
// May be an Angular component, which is not imported/declared?
|
|
8248
|
+
message += `\n1. If '${tagName}' is an Angular component and it has the ` +
|
|
8249
|
+
`'${propName}' input, then verify that it is ${importLocation}.`;
|
|
8250
|
+
// May be a Web Component?
|
|
8251
|
+
if (tagName && tagName.indexOf('-') > -1) {
|
|
8252
|
+
message += `\n2. If '${tagName}' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' ` +
|
|
8253
|
+
`to the ${schemas} of this component to suppress this message.`;
|
|
8254
|
+
message += `\n3. To allow any property add 'NO_ERRORS_SCHEMA' to ` +
|
|
8255
|
+
`the ${schemas} of this component.`;
|
|
8256
|
+
}
|
|
8257
|
+
else {
|
|
8258
|
+
// If it's expected, the error can be suppressed by the `NO_ERRORS_SCHEMA` schema.
|
|
8259
|
+
message += `\n2. To allow any property add 'NO_ERRORS_SCHEMA' to ` +
|
|
8260
|
+
`the ${schemas} of this component.`;
|
|
8261
|
+
}
|
|
8324
8262
|
}
|
|
8325
|
-
|
|
8263
|
+
reportUnknownPropertyError(message);
|
|
8326
8264
|
}
|
|
8327
|
-
|
|
8328
|
-
|
|
8329
|
-
|
|
8330
|
-
const MONKEY_PATCH_KEY_NAME = '__ngContext__';
|
|
8331
|
-
/**
|
|
8332
|
-
* Assigns the given data to the given target (which could be a component,
|
|
8333
|
-
* directive or DOM node instance) using monkey-patching.
|
|
8334
|
-
*/
|
|
8335
|
-
function attachPatchData(target, data) {
|
|
8336
|
-
ngDevMode && assertDefined(target, 'Target expected');
|
|
8337
|
-
// Only attach the ID of the view in order to avoid memory leaks (see #41047). We only do this
|
|
8338
|
-
// for `LView`, because we have control over when an `LView` is created and destroyed, whereas
|
|
8339
|
-
// we can't know when to remove an `LContext`.
|
|
8340
|
-
if (isLView(data)) {
|
|
8341
|
-
target[MONKEY_PATCH_KEY_NAME] = data[ID];
|
|
8342
|
-
registerLView(data);
|
|
8265
|
+
function reportUnknownPropertyError(message) {
|
|
8266
|
+
if (shouldThrowErrorOnUnknownProperty) {
|
|
8267
|
+
throw new RuntimeError(303 /* RuntimeErrorCode.UNKNOWN_BINDING */, message);
|
|
8343
8268
|
}
|
|
8344
8269
|
else {
|
|
8345
|
-
|
|
8270
|
+
console.error(formatRuntimeError(303 /* RuntimeErrorCode.UNKNOWN_BINDING */, message));
|
|
8346
8271
|
}
|
|
8347
8272
|
}
|
|
8348
8273
|
/**
|
|
8349
|
-
*
|
|
8350
|
-
*
|
|
8274
|
+
* WARNING: this is a **dev-mode only** function (thus should always be guarded by the `ngDevMode`)
|
|
8275
|
+
* and must **not** be used in production bundles. The function makes megamorphic reads, which might
|
|
8276
|
+
* be too slow for production mode and also it relies on the constructor function being available.
|
|
8277
|
+
*
|
|
8278
|
+
* Gets a reference to the host component def (where a current component is declared).
|
|
8279
|
+
*
|
|
8280
|
+
* @param lView An `LView` that represents a current component that is being rendered.
|
|
8351
8281
|
*/
|
|
8352
|
-
function
|
|
8353
|
-
ngDevMode &&
|
|
8354
|
-
const
|
|
8355
|
-
|
|
8356
|
-
|
|
8357
|
-
|
|
8358
|
-
|
|
8359
|
-
|
|
8360
|
-
return (isLView(value) ? value : value.lView);
|
|
8361
|
-
}
|
|
8362
|
-
return null;
|
|
8282
|
+
function getDeclarationComponentDef(lView) {
|
|
8283
|
+
!ngDevMode && throwError('Must never be called in production mode');
|
|
8284
|
+
const declarationLView = lView[DECLARATION_COMPONENT_VIEW];
|
|
8285
|
+
const context = declarationLView[CONTEXT];
|
|
8286
|
+
// Unable to obtain a context.
|
|
8287
|
+
if (!context)
|
|
8288
|
+
return null;
|
|
8289
|
+
return context.constructor ? getComponentDef$1(context.constructor) : null;
|
|
8363
8290
|
}
|
|
8364
|
-
|
|
8365
|
-
|
|
8291
|
+
/**
|
|
8292
|
+
* WARNING: this is a **dev-mode only** function (thus should always be guarded by the `ngDevMode`)
|
|
8293
|
+
* and must **not** be used in production bundles. The function makes megamorphic reads, which might
|
|
8294
|
+
* be too slow for production mode.
|
|
8295
|
+
*
|
|
8296
|
+
* Checks if the current component is declared inside of a standalone component template.
|
|
8297
|
+
*
|
|
8298
|
+
* @param lView An `LView` that represents a current component that is being rendered.
|
|
8299
|
+
*/
|
|
8300
|
+
function isHostComponentStandalone(lView) {
|
|
8301
|
+
!ngDevMode && throwError('Must never be called in production mode');
|
|
8302
|
+
const componentDef = getDeclarationComponentDef(lView);
|
|
8303
|
+
// Treat host component as non-standalone if we can't obtain the def.
|
|
8304
|
+
return !!(componentDef === null || componentDef === void 0 ? void 0 : componentDef.standalone);
|
|
8366
8305
|
}
|
|
8367
|
-
|
|
8368
|
-
|
|
8306
|
+
/**
|
|
8307
|
+
* WARNING: this is a **dev-mode only** function (thus should always be guarded by the `ngDevMode`)
|
|
8308
|
+
* and must **not** be used in production bundles. The function makes megamorphic reads, which might
|
|
8309
|
+
* be too slow for production mode.
|
|
8310
|
+
*
|
|
8311
|
+
* Constructs a string describing the location of the host component template. The function is used
|
|
8312
|
+
* in dev mode to produce error messages.
|
|
8313
|
+
*
|
|
8314
|
+
* @param lView An `LView` that represents a current component that is being rendered.
|
|
8315
|
+
*/
|
|
8316
|
+
function getTemplateLocationDetails(lView) {
|
|
8317
|
+
var _a;
|
|
8318
|
+
!ngDevMode && throwError('Must never be called in production mode');
|
|
8319
|
+
const hostComponentDef = getDeclarationComponentDef(lView);
|
|
8320
|
+
const componentClassName = (_a = hostComponentDef === null || hostComponentDef === void 0 ? void 0 : hostComponentDef.type) === null || _a === void 0 ? void 0 : _a.name;
|
|
8321
|
+
return componentClassName ? ` (used in the '${componentClassName}' component template)` : '';
|
|
8369
8322
|
}
|
|
8370
8323
|
/**
|
|
8371
|
-
*
|
|
8324
|
+
* The set of known control flow directives and their corresponding imports.
|
|
8325
|
+
* We use this set to produce a more precises error message with a note
|
|
8326
|
+
* that the `CommonModule` should also be included.
|
|
8372
8327
|
*/
|
|
8373
|
-
|
|
8374
|
-
|
|
8375
|
-
|
|
8376
|
-
|
|
8377
|
-
|
|
8328
|
+
const KNOWN_CONTROL_FLOW_DIRECTIVES = new Map([
|
|
8329
|
+
['ngIf', 'NgIf'], ['ngFor', 'NgFor'], ['ngSwitchCase', 'NgSwitchCase'],
|
|
8330
|
+
['ngSwitchDefault', 'NgSwitchDefault']
|
|
8331
|
+
]);
|
|
8332
|
+
/**
|
|
8333
|
+
* Returns true if the tag name is allowed by specified schemas.
|
|
8334
|
+
* @param schemas Array of schemas
|
|
8335
|
+
* @param tagName Name of the tag
|
|
8336
|
+
*/
|
|
8337
|
+
function matchingSchemas(schemas, tagName) {
|
|
8338
|
+
if (schemas !== null) {
|
|
8339
|
+
for (let i = 0; i < schemas.length; i++) {
|
|
8340
|
+
const schema = schemas[i];
|
|
8341
|
+
if (schema === NO_ERRORS_SCHEMA ||
|
|
8342
|
+
schema === CUSTOM_ELEMENTS_SCHEMA && tagName && tagName.indexOf('-') > -1) {
|
|
8343
|
+
return true;
|
|
8344
|
+
}
|
|
8378
8345
|
}
|
|
8379
8346
|
}
|
|
8380
|
-
return
|
|
8347
|
+
return false;
|
|
8381
8348
|
}
|
|
8349
|
+
|
|
8382
8350
|
/**
|
|
8383
|
-
*
|
|
8351
|
+
* @license
|
|
8352
|
+
* Copyright Google LLC All Rights Reserved.
|
|
8353
|
+
*
|
|
8354
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
8355
|
+
* found in the LICENSE file at https://angular.io/license
|
|
8384
8356
|
*/
|
|
8385
|
-
|
|
8386
|
-
|
|
8387
|
-
|
|
8357
|
+
const ERROR_ORIGINAL_ERROR = 'ngOriginalError';
|
|
8358
|
+
function wrappedError(message, originalError) {
|
|
8359
|
+
const msg = `${message} caused by: ${originalError instanceof Error ? originalError.message : originalError}`;
|
|
8360
|
+
const error = Error(msg);
|
|
8361
|
+
error[ERROR_ORIGINAL_ERROR] = originalError;
|
|
8362
|
+
return error;
|
|
8363
|
+
}
|
|
8364
|
+
function getOriginalError(error) {
|
|
8365
|
+
return error[ERROR_ORIGINAL_ERROR];
|
|
8366
|
+
}
|
|
8367
|
+
|
|
8368
|
+
/**
|
|
8369
|
+
* @license
|
|
8370
|
+
* Copyright Google LLC All Rights Reserved.
|
|
8371
|
+
*
|
|
8372
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
8373
|
+
* found in the LICENSE file at https://angular.io/license
|
|
8374
|
+
*/
|
|
8375
|
+
/**
|
|
8376
|
+
* Provides a hook for centralized exception handling.
|
|
8377
|
+
*
|
|
8378
|
+
* The default implementation of `ErrorHandler` prints error messages to the `console`. To
|
|
8379
|
+
* intercept error handling, write a custom exception handler that replaces this default as
|
|
8380
|
+
* appropriate for your app.
|
|
8381
|
+
*
|
|
8382
|
+
* @usageNotes
|
|
8383
|
+
* ### Example
|
|
8384
|
+
*
|
|
8385
|
+
* ```
|
|
8386
|
+
* class MyErrorHandler implements ErrorHandler {
|
|
8387
|
+
* handleError(error) {
|
|
8388
|
+
* // do something with the exception
|
|
8389
|
+
* }
|
|
8390
|
+
* }
|
|
8391
|
+
*
|
|
8392
|
+
* @NgModule({
|
|
8393
|
+
* providers: [{provide: ErrorHandler, useClass: MyErrorHandler}]
|
|
8394
|
+
* })
|
|
8395
|
+
* class MyModule {}
|
|
8396
|
+
* ```
|
|
8397
|
+
*
|
|
8398
|
+
* @publicApi
|
|
8399
|
+
*/
|
|
8400
|
+
class ErrorHandler {
|
|
8401
|
+
constructor() {
|
|
8402
|
+
/**
|
|
8403
|
+
* @internal
|
|
8404
|
+
*/
|
|
8405
|
+
this._console = console;
|
|
8388
8406
|
}
|
|
8389
|
-
|
|
8390
|
-
|
|
8407
|
+
handleError(error) {
|
|
8408
|
+
const originalError = this._findOriginalError(error);
|
|
8409
|
+
this._console.error('ERROR', error);
|
|
8410
|
+
if (originalError) {
|
|
8411
|
+
this._console.error('ORIGINAL ERROR', originalError);
|
|
8412
|
+
}
|
|
8391
8413
|
}
|
|
8392
|
-
|
|
8393
|
-
|
|
8394
|
-
|
|
8395
|
-
|
|
8396
|
-
|
|
8397
|
-
tNode = tNode.parent;
|
|
8414
|
+
/** @internal */
|
|
8415
|
+
_findOriginalError(error) {
|
|
8416
|
+
let e = error && getOriginalError(error);
|
|
8417
|
+
while (e && getOriginalError(e)) {
|
|
8418
|
+
e = getOriginalError(e);
|
|
8398
8419
|
}
|
|
8399
|
-
return
|
|
8420
|
+
return e || null;
|
|
8400
8421
|
}
|
|
8401
8422
|
}
|
|
8423
|
+
|
|
8402
8424
|
/**
|
|
8403
|
-
*
|
|
8425
|
+
* @license
|
|
8426
|
+
* Copyright Google LLC All Rights Reserved.
|
|
8427
|
+
*
|
|
8428
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
8429
|
+
* found in the LICENSE file at https://angular.io/license
|
|
8404
8430
|
*/
|
|
8405
|
-
function findViaComponent(lView, componentInstance) {
|
|
8406
|
-
const componentIndices = lView[TVIEW].components;
|
|
8407
|
-
if (componentIndices) {
|
|
8408
|
-
for (let i = 0; i < componentIndices.length; i++) {
|
|
8409
|
-
const elementComponentIndex = componentIndices[i];
|
|
8410
|
-
const componentView = getComponentLViewByIndex(elementComponentIndex, lView);
|
|
8411
|
-
if (componentView[CONTEXT] === componentInstance) {
|
|
8412
|
-
return elementComponentIndex;
|
|
8413
|
-
}
|
|
8414
|
-
}
|
|
8415
|
-
}
|
|
8416
|
-
else {
|
|
8417
|
-
const rootComponentView = getComponentLViewByIndex(HEADER_OFFSET, lView);
|
|
8418
|
-
const rootComponent = rootComponentView[CONTEXT];
|
|
8419
|
-
if (rootComponent === componentInstance) {
|
|
8420
|
-
// we are dealing with the root element here therefore we know that the
|
|
8421
|
-
// element is the very first element after the HEADER data in the lView
|
|
8422
|
-
return HEADER_OFFSET;
|
|
8423
|
-
}
|
|
8424
|
-
}
|
|
8425
|
-
return -1;
|
|
8426
|
-
}
|
|
8427
8431
|
/**
|
|
8428
|
-
*
|
|
8432
|
+
* Disallowed strings in the comment.
|
|
8433
|
+
*
|
|
8434
|
+
* see: https://html.spec.whatwg.org/multipage/syntax.html#comments
|
|
8429
8435
|
*/
|
|
8430
|
-
|
|
8431
|
-
|
|
8432
|
-
|
|
8433
|
-
|
|
8434
|
-
|
|
8435
|
-
|
|
8436
|
-
let tNode = lView[TVIEW].firstChild;
|
|
8437
|
-
while (tNode) {
|
|
8438
|
-
const directiveIndexStart = tNode.directiveStart;
|
|
8439
|
-
const directiveIndexEnd = tNode.directiveEnd;
|
|
8440
|
-
for (let i = directiveIndexStart; i < directiveIndexEnd; i++) {
|
|
8441
|
-
if (lView[i] === directiveInstance) {
|
|
8442
|
-
return tNode.index;
|
|
8443
|
-
}
|
|
8444
|
-
}
|
|
8445
|
-
tNode = traverseNextElement(tNode);
|
|
8446
|
-
}
|
|
8447
|
-
return -1;
|
|
8448
|
-
}
|
|
8436
|
+
const COMMENT_DISALLOWED = /^>|^->|<!--|-->|--!>|<!-$/g;
|
|
8437
|
+
/**
|
|
8438
|
+
* Delimiter in the disallowed strings which needs to be wrapped with zero with character.
|
|
8439
|
+
*/
|
|
8440
|
+
const COMMENT_DELIMITER = /(<|>)/;
|
|
8441
|
+
const COMMENT_DELIMITER_ESCAPED = '\u200B$1\u200B';
|
|
8449
8442
|
/**
|
|
8450
|
-
*
|
|
8451
|
-
* provided list of directive index values.
|
|
8443
|
+
* Escape the content of comment strings so that it can be safely inserted into a comment node.
|
|
8452
8444
|
*
|
|
8453
|
-
*
|
|
8454
|
-
*
|
|
8455
|
-
*
|
|
8445
|
+
* The issue is that HTML does not specify any way to escape comment end text inside the comment.
|
|
8446
|
+
* Consider: `<!-- The way you close a comment is with ">", and "->" at the beginning or by "-->" or
|
|
8447
|
+
* "--!>" at the end. -->`. Above the `"-->"` is meant to be text not an end to the comment. This
|
|
8448
|
+
* can be created programmatically through DOM APIs. (`<!--` are also disallowed.)
|
|
8449
|
+
*
|
|
8450
|
+
* see: https://html.spec.whatwg.org/multipage/syntax.html#comments
|
|
8451
|
+
*
|
|
8452
|
+
* ```
|
|
8453
|
+
* div.innerHTML = div.innerHTML
|
|
8454
|
+
* ```
|
|
8455
|
+
*
|
|
8456
|
+
* One would expect that the above code would be safe to do, but it turns out that because comment
|
|
8457
|
+
* text is not escaped, the comment may contain text which will prematurely close the comment
|
|
8458
|
+
* opening up the application for XSS attack. (In SSR we programmatically create comment nodes which
|
|
8459
|
+
* may contain such text and expect them to be safe.)
|
|
8460
|
+
*
|
|
8461
|
+
* This function escapes the comment text by looking for comment delimiters (`<` and `>`) and
|
|
8462
|
+
* surrounding them with `_>_` where the `_` is a zero width space `\u200B`. The result is that if a
|
|
8463
|
+
* comment contains any of the comment start/end delimiters (such as `<!--`, `-->` or `--!>`) the
|
|
8464
|
+
* text it will render normally but it will not cause the HTML parser to close/open the comment.
|
|
8465
|
+
*
|
|
8466
|
+
* @param value text to make safe for comment node by escaping the comment open/close character
|
|
8467
|
+
* sequence.
|
|
8456
8468
|
*/
|
|
8457
|
-
function
|
|
8458
|
-
|
|
8459
|
-
let directiveStartIndex = tNode.directiveStart;
|
|
8460
|
-
if (directiveStartIndex == 0)
|
|
8461
|
-
return EMPTY_ARRAY;
|
|
8462
|
-
const directiveEndIndex = tNode.directiveEnd;
|
|
8463
|
-
if (!includeComponents && tNode.flags & 2 /* TNodeFlags.isComponentHost */)
|
|
8464
|
-
directiveStartIndex++;
|
|
8465
|
-
return lView.slice(directiveStartIndex, directiveEndIndex);
|
|
8466
|
-
}
|
|
8467
|
-
function getComponentAtNodeIndex(nodeIndex, lView) {
|
|
8468
|
-
const tNode = lView[TVIEW].data[nodeIndex];
|
|
8469
|
-
let directiveStartIndex = tNode.directiveStart;
|
|
8470
|
-
return tNode.flags & 2 /* TNodeFlags.isComponentHost */ ? lView[directiveStartIndex] : null;
|
|
8469
|
+
function escapeCommentText(value) {
|
|
8470
|
+
return value.replace(COMMENT_DISALLOWED, (text) => text.replace(COMMENT_DELIMITER, COMMENT_DELIMITER_ESCAPED));
|
|
8471
8471
|
}
|
|
8472
|
+
|
|
8472
8473
|
/**
|
|
8473
|
-
*
|
|
8474
|
-
*
|
|
8474
|
+
* @license
|
|
8475
|
+
* Copyright Google LLC All Rights Reserved.
|
|
8476
|
+
*
|
|
8477
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
8478
|
+
* found in the LICENSE file at https://angular.io/license
|
|
8475
8479
|
*/
|
|
8476
|
-
function
|
|
8477
|
-
|
|
8478
|
-
|
|
8479
|
-
|
|
8480
|
-
|
|
8481
|
-
|
|
8482
|
-
|
|
8483
|
-
|
|
8484
|
-
|
|
8485
|
-
|
|
8480
|
+
function normalizeDebugBindingName(name) {
|
|
8481
|
+
// Attribute names with `$` (eg `x-y$`) are valid per spec, but unsupported by some browsers
|
|
8482
|
+
name = camelCaseToDashCase(name.replace(/[$@]/g, '_'));
|
|
8483
|
+
return `ng-reflect-${name}`;
|
|
8484
|
+
}
|
|
8485
|
+
const CAMEL_CASE_REGEXP = /([A-Z])/g;
|
|
8486
|
+
function camelCaseToDashCase(input) {
|
|
8487
|
+
return input.replace(CAMEL_CASE_REGEXP, (...m) => '-' + m[1].toLowerCase());
|
|
8488
|
+
}
|
|
8489
|
+
function normalizeDebugBindingValue(value) {
|
|
8490
|
+
try {
|
|
8491
|
+
// Limit the size of the value as otherwise the DOM just gets polluted.
|
|
8492
|
+
return value != null ? value.toString().slice(0, 30) : value;
|
|
8493
|
+
}
|
|
8494
|
+
catch (e) {
|
|
8495
|
+
return '[ERROR] Exception while trying to serialize the value';
|
|
8486
8496
|
}
|
|
8487
|
-
return null;
|
|
8488
8497
|
}
|
|
8489
8498
|
|
|
8490
8499
|
/**
|
|
@@ -9215,9 +9224,10 @@ function getClosestRElement(tView, tNode, lView) {
|
|
|
9215
9224
|
}
|
|
9216
9225
|
else {
|
|
9217
9226
|
ngDevMode && assertTNodeType(parentTNode, 3 /* TNodeType.AnyRNode */ | 4 /* TNodeType.Container */);
|
|
9218
|
-
|
|
9227
|
+
const { componentOffset } = parentTNode;
|
|
9228
|
+
if (componentOffset > -1) {
|
|
9219
9229
|
ngDevMode && assertTNodeForLView(parentTNode, lView);
|
|
9220
|
-
const encapsulation = tView.data[parentTNode.directiveStart]
|
|
9230
|
+
const { encapsulation } = tView.data[parentTNode.directiveStart + componentOffset];
|
|
9221
9231
|
// We've got a parent which is an element in the current view. We just need to verify if the
|
|
9222
9232
|
// parent element is not a component. Component's content nodes are not inserted immediately
|
|
9223
9233
|
// because they will be projected, and so doing insert at this point would be wasteful.
|
|
@@ -9450,10 +9460,10 @@ function applyNodes(renderer, action, tNode, lView, parentRElement, beforeNode,
|
|
|
9450
9460
|
if (isProjection) {
|
|
9451
9461
|
if (action === 0 /* WalkTNodeTreeAction.Create */) {
|
|
9452
9462
|
rawSlotValue && attachPatchData(unwrapRNode(rawSlotValue), lView);
|
|
9453
|
-
tNode.flags |=
|
|
9463
|
+
tNode.flags |= 2 /* TNodeFlags.isProjected */;
|
|
9454
9464
|
}
|
|
9455
9465
|
}
|
|
9456
|
-
if ((tNode.flags &
|
|
9466
|
+
if ((tNode.flags & 32 /* TNodeFlags.isDetached */) !== 32 /* TNodeFlags.isDetached */) {
|
|
9457
9467
|
if (tNodeType & 8 /* TNodeType.ElementContainer */) {
|
|
9458
9468
|
applyNodes(renderer, action, tNode.child, lView, parentRElement, beforeNode, false);
|
|
9459
9469
|
applyToElementOrContainer(action, renderer, parentRElement, rawSlotValue, beforeNode);
|
|
@@ -9647,6 +9657,19 @@ function writeDirectClass(renderer, element, newValue) {
|
|
|
9647
9657
|
}
|
|
9648
9658
|
ngDevMode && ngDevMode.rendererSetClassName++;
|
|
9649
9659
|
}
|
|
9660
|
+
/** Sets up the static DOM attributes on an `RNode`. */
|
|
9661
|
+
function setupStaticAttributes(renderer, element, tNode) {
|
|
9662
|
+
const { mergedAttrs, classes, styles } = tNode;
|
|
9663
|
+
if (mergedAttrs !== null) {
|
|
9664
|
+
setUpAttributes(renderer, element, mergedAttrs);
|
|
9665
|
+
}
|
|
9666
|
+
if (classes !== null) {
|
|
9667
|
+
writeDirectClass(renderer, element, classes);
|
|
9668
|
+
}
|
|
9669
|
+
if (styles !== null) {
|
|
9670
|
+
writeDirectStyle(renderer, element, styles);
|
|
9671
|
+
}
|
|
9672
|
+
}
|
|
9650
9673
|
|
|
9651
9674
|
/**
|
|
9652
9675
|
* @license
|
|
@@ -11508,6 +11531,7 @@ class TNode {
|
|
|
11508
11531
|
index, //
|
|
11509
11532
|
insertBeforeIndex, //
|
|
11510
11533
|
injectorIndex, //
|
|
11534
|
+
componentOffset, //
|
|
11511
11535
|
directiveStart, //
|
|
11512
11536
|
directiveEnd, //
|
|
11513
11537
|
directiveStylingLast, //
|
|
@@ -11540,6 +11564,7 @@ class TNode {
|
|
|
11540
11564
|
this.index = index;
|
|
11541
11565
|
this.insertBeforeIndex = insertBeforeIndex;
|
|
11542
11566
|
this.injectorIndex = injectorIndex;
|
|
11567
|
+
this.componentOffset = componentOffset;
|
|
11543
11568
|
this.directiveStart = directiveStart;
|
|
11544
11569
|
this.directiveEnd = directiveEnd;
|
|
11545
11570
|
this.directiveStylingLast = directiveStylingLast;
|
|
@@ -11617,21 +11642,19 @@ class TNode {
|
|
|
11617
11642
|
}
|
|
11618
11643
|
get flags_() {
|
|
11619
11644
|
const flags = [];
|
|
11620
|
-
if (this.flags &
|
|
11645
|
+
if (this.flags & 8 /* TNodeFlags.hasClassInput */)
|
|
11621
11646
|
flags.push('TNodeFlags.hasClassInput');
|
|
11622
|
-
if (this.flags &
|
|
11647
|
+
if (this.flags & 4 /* TNodeFlags.hasContentQuery */)
|
|
11623
11648
|
flags.push('TNodeFlags.hasContentQuery');
|
|
11624
|
-
if (this.flags &
|
|
11649
|
+
if (this.flags & 16 /* TNodeFlags.hasStyleInput */)
|
|
11625
11650
|
flags.push('TNodeFlags.hasStyleInput');
|
|
11626
|
-
if (this.flags &
|
|
11651
|
+
if (this.flags & 64 /* TNodeFlags.hasHostBindings */)
|
|
11627
11652
|
flags.push('TNodeFlags.hasHostBindings');
|
|
11628
|
-
if (this.flags & 2 /* TNodeFlags.isComponentHost */)
|
|
11629
|
-
flags.push('TNodeFlags.isComponentHost');
|
|
11630
11653
|
if (this.flags & 1 /* TNodeFlags.isDirectiveHost */)
|
|
11631
11654
|
flags.push('TNodeFlags.isDirectiveHost');
|
|
11632
|
-
if (this.flags &
|
|
11655
|
+
if (this.flags & 32 /* TNodeFlags.isDetached */)
|
|
11633
11656
|
flags.push('TNodeFlags.isDetached');
|
|
11634
|
-
if (this.flags &
|
|
11657
|
+
if (this.flags & 2 /* TNodeFlags.isProjected */)
|
|
11635
11658
|
flags.push('TNodeFlags.isProjected');
|
|
11636
11659
|
return flags.join('|');
|
|
11637
11660
|
}
|
|
@@ -12141,7 +12164,7 @@ function getOrCreateTNode(tView, index, type, name, attrs) {
|
|
|
12141
12164
|
// See `TNodeType.Placeholder` and `LFrame.inI18n` for more context.
|
|
12142
12165
|
// If the `TNode` was not pre-declared than it means it was not mentioned which means it was
|
|
12143
12166
|
// removed, so we mark it as detached.
|
|
12144
|
-
tNode.flags |=
|
|
12167
|
+
tNode.flags |= 32 /* TNodeFlags.isDetached */;
|
|
12145
12168
|
}
|
|
12146
12169
|
}
|
|
12147
12170
|
else if (tNode.type & 64 /* TNodeType.Placeholder */) {
|
|
@@ -12445,7 +12468,7 @@ function createDirectivesInstances(tView, lView, tNode) {
|
|
|
12445
12468
|
if (!getBindingsEnabled())
|
|
12446
12469
|
return;
|
|
12447
12470
|
instantiateAllDirectives(tView, lView, tNode, getNativeByTNode(tNode, lView));
|
|
12448
|
-
if ((tNode.flags &
|
|
12471
|
+
if ((tNode.flags & 64 /* TNodeFlags.hasHostBindings */) === 64 /* TNodeFlags.hasHostBindings */) {
|
|
12449
12472
|
invokeDirectivesHostBindings(tView, lView, tNode);
|
|
12450
12473
|
}
|
|
12451
12474
|
}
|
|
@@ -12645,6 +12668,7 @@ function createTNode(tView, tParent, type, index, value, attrs) {
|
|
|
12645
12668
|
index, // index: number
|
|
12646
12669
|
null, // insertBeforeIndex: null|-1|number|number[]
|
|
12647
12670
|
injectorIndex, // injectorIndex: number
|
|
12671
|
+
-1, // componentOffset: number
|
|
12648
12672
|
-1, // directiveStart: number
|
|
12649
12673
|
-1, // directiveEnd: number
|
|
12650
12674
|
-1, // directiveStylingLast: number
|
|
@@ -12680,6 +12704,7 @@ function createTNode(tView, tParent, type, index, value, attrs) {
|
|
|
12680
12704
|
directiveStart: -1,
|
|
12681
12705
|
directiveEnd: -1,
|
|
12682
12706
|
directiveStylingLast: -1,
|
|
12707
|
+
componentOffset: -1,
|
|
12683
12708
|
propertyBindings: null,
|
|
12684
12709
|
flags: 0,
|
|
12685
12710
|
providerIndexes: 0,
|
|
@@ -12743,24 +12768,23 @@ function initializeInputAndOutputAliases(tView, tNode) {
|
|
|
12743
12768
|
let outputsStore = null;
|
|
12744
12769
|
for (let i = start; i < end; i++) {
|
|
12745
12770
|
const directiveDef = tViewData[i];
|
|
12746
|
-
|
|
12771
|
+
inputsStore = generatePropertyAliases(directiveDef.inputs, i, inputsStore);
|
|
12772
|
+
outputsStore = generatePropertyAliases(directiveDef.outputs, i, outputsStore);
|
|
12747
12773
|
// Do not use unbound attributes as inputs to structural directives, since structural
|
|
12748
12774
|
// directive inputs can only be set using microsyntax (e.g. `<div *dir="exp">`).
|
|
12749
12775
|
// TODO(FW-1930): microsyntax expressions may also contain unbound/static attributes, which
|
|
12750
12776
|
// should be set for inline templates.
|
|
12751
|
-
const initialInputs = (tNodeAttrs !== null && !isInlineTemplate(tNode)) ?
|
|
12752
|
-
generateInitialInputs(
|
|
12777
|
+
const initialInputs = (inputsStore !== null && tNodeAttrs !== null && !isInlineTemplate(tNode)) ?
|
|
12778
|
+
generateInitialInputs(inputsStore, i, tNodeAttrs) :
|
|
12753
12779
|
null;
|
|
12754
12780
|
inputsFromAttrs.push(initialInputs);
|
|
12755
|
-
inputsStore = generatePropertyAliases(directiveInputs, i, inputsStore);
|
|
12756
|
-
outputsStore = generatePropertyAliases(directiveDef.outputs, i, outputsStore);
|
|
12757
12781
|
}
|
|
12758
12782
|
if (inputsStore !== null) {
|
|
12759
12783
|
if (inputsStore.hasOwnProperty('class')) {
|
|
12760
|
-
tNode.flags |=
|
|
12784
|
+
tNode.flags |= 8 /* TNodeFlags.hasClassInput */;
|
|
12761
12785
|
}
|
|
12762
12786
|
if (inputsStore.hasOwnProperty('style')) {
|
|
12763
|
-
tNode.flags |=
|
|
12787
|
+
tNode.flags |= 16 /* TNodeFlags.hasStyleInput */;
|
|
12764
12788
|
}
|
|
12765
12789
|
}
|
|
12766
12790
|
tNode.initialInputs = inputsFromAttrs;
|
|
@@ -12867,28 +12891,6 @@ function setNgReflectProperties(lView, element, type, dataValue, value) {
|
|
|
12867
12891
|
}
|
|
12868
12892
|
}
|
|
12869
12893
|
}
|
|
12870
|
-
/**
|
|
12871
|
-
* Instantiate a root component.
|
|
12872
|
-
*/
|
|
12873
|
-
function instantiateRootComponent(tView, lView, def) {
|
|
12874
|
-
const rootTNode = getCurrentTNode();
|
|
12875
|
-
if (tView.firstCreatePass) {
|
|
12876
|
-
if (def.providersResolver)
|
|
12877
|
-
def.providersResolver(def);
|
|
12878
|
-
const directiveIndex = allocExpando(tView, lView, 1, null);
|
|
12879
|
-
ngDevMode &&
|
|
12880
|
-
assertEqual(directiveIndex, rootTNode.directiveStart, 'Because this is a root component the allocated expando should match the TNode component.');
|
|
12881
|
-
configureViewWithDirective(tView, rootTNode, lView, directiveIndex, def);
|
|
12882
|
-
initializeInputAndOutputAliases(tView, rootTNode);
|
|
12883
|
-
}
|
|
12884
|
-
const directive = getNodeInjectable(lView, tView, rootTNode.directiveStart, rootTNode);
|
|
12885
|
-
attachPatchData(directive, lView);
|
|
12886
|
-
const native = getNativeByTNode(rootTNode, lView);
|
|
12887
|
-
if (native) {
|
|
12888
|
-
attachPatchData(native, lView);
|
|
12889
|
-
}
|
|
12890
|
-
return directive;
|
|
12891
|
-
}
|
|
12892
12894
|
/**
|
|
12893
12895
|
* Resolve the matched directives on a node.
|
|
12894
12896
|
*/
|
|
@@ -12901,53 +12903,13 @@ function resolveDirectives(tView, lView, tNode, localRefs) {
|
|
|
12901
12903
|
const directiveDefs = findDirectiveDefMatches(tView, lView, tNode);
|
|
12902
12904
|
const exportsMap = localRefs === null ? null : { '': -1 };
|
|
12903
12905
|
if (directiveDefs !== null) {
|
|
12904
|
-
|
|
12905
|
-
|
|
12906
|
-
// When the same token is provided by several directives on the same node, some rules apply in
|
|
12907
|
-
// the viewEngine:
|
|
12908
|
-
// - viewProviders have priority over providers
|
|
12909
|
-
// - the last directive in NgModule.declarations has priority over the previous one
|
|
12910
|
-
// So to match these rules, the order in which providers are added in the arrays is very
|
|
12911
|
-
// important.
|
|
12912
|
-
for (let i = 0; i < directiveDefs.length; i++) {
|
|
12913
|
-
const def = directiveDefs[i];
|
|
12914
|
-
if (def.providersResolver)
|
|
12915
|
-
def.providersResolver(def);
|
|
12916
|
-
}
|
|
12917
|
-
let preOrderHooksFound = false;
|
|
12918
|
-
let preOrderCheckHooksFound = false;
|
|
12919
|
-
let directiveIdx = allocExpando(tView, lView, directiveDefs.length, null);
|
|
12920
|
-
ngDevMode &&
|
|
12921
|
-
assertSame(directiveIdx, tNode.directiveStart, 'TNode.directiveStart should point to just allocated space');
|
|
12906
|
+
// Publishes the directive types to DI so they can be injected. Needs to
|
|
12907
|
+
// happen in a separate pass before the TNode flags have been initialized.
|
|
12922
12908
|
for (let i = 0; i < directiveDefs.length; i++) {
|
|
12923
|
-
|
|
12924
|
-
// Merge the attrs in the order of matches. This assumes that the first directive is the
|
|
12925
|
-
// component itself, so that the component has the least priority.
|
|
12926
|
-
tNode.mergedAttrs = mergeHostAttrs(tNode.mergedAttrs, def.hostAttrs);
|
|
12927
|
-
configureViewWithDirective(tView, tNode, lView, directiveIdx, def);
|
|
12928
|
-
saveNameToExportMap(directiveIdx, def, exportsMap);
|
|
12929
|
-
if (def.contentQueries !== null)
|
|
12930
|
-
tNode.flags |= 8 /* TNodeFlags.hasContentQuery */;
|
|
12931
|
-
if (def.hostBindings !== null || def.hostAttrs !== null || def.hostVars !== 0)
|
|
12932
|
-
tNode.flags |= 128 /* TNodeFlags.hasHostBindings */;
|
|
12933
|
-
const lifeCycleHooks = def.type.prototype;
|
|
12934
|
-
// Only push a node index into the preOrderHooks array if this is the first
|
|
12935
|
-
// pre-order hook found on this node.
|
|
12936
|
-
if (!preOrderHooksFound &&
|
|
12937
|
-
(lifeCycleHooks.ngOnChanges || lifeCycleHooks.ngOnInit || lifeCycleHooks.ngDoCheck)) {
|
|
12938
|
-
// We will push the actual hook function into this array later during dir instantiation.
|
|
12939
|
-
// We cannot do it now because we must ensure hooks are registered in the same
|
|
12940
|
-
// order that directives are created (i.e. injection order).
|
|
12941
|
-
(tView.preOrderHooks || (tView.preOrderHooks = [])).push(tNode.index);
|
|
12942
|
-
preOrderHooksFound = true;
|
|
12943
|
-
}
|
|
12944
|
-
if (!preOrderCheckHooksFound && (lifeCycleHooks.ngOnChanges || lifeCycleHooks.ngDoCheck)) {
|
|
12945
|
-
(tView.preOrderCheckHooks || (tView.preOrderCheckHooks = [])).push(tNode.index);
|
|
12946
|
-
preOrderCheckHooksFound = true;
|
|
12947
|
-
}
|
|
12948
|
-
directiveIdx++;
|
|
12909
|
+
diPublicInInjector(getOrCreateNodeInjectorForNode(tNode, lView), tView, directiveDefs[i].type);
|
|
12949
12910
|
}
|
|
12950
|
-
|
|
12911
|
+
hasDirectives = true;
|
|
12912
|
+
initializeDirectives(tView, lView, tNode, directiveDefs, exportsMap);
|
|
12951
12913
|
}
|
|
12952
12914
|
if (exportsMap)
|
|
12953
12915
|
cacheMatchingLocalNames(tNode, localRefs, exportsMap);
|
|
@@ -12956,17 +12918,66 @@ function resolveDirectives(tView, lView, tNode, localRefs) {
|
|
|
12956
12918
|
tNode.mergedAttrs = mergeHostAttrs(tNode.mergedAttrs, tNode.attrs);
|
|
12957
12919
|
return hasDirectives;
|
|
12958
12920
|
}
|
|
12921
|
+
/** Initializes the data structures necessary for a list of directives to be instantiated. */
|
|
12922
|
+
function initializeDirectives(tView, lView, tNode, directives, exportsMap) {
|
|
12923
|
+
ngDevMode && assertFirstCreatePass(tView);
|
|
12924
|
+
initTNodeFlags(tNode, tView.data.length, directives.length);
|
|
12925
|
+
// When the same token is provided by several directives on the same node, some rules apply in
|
|
12926
|
+
// the viewEngine:
|
|
12927
|
+
// - viewProviders have priority over providers
|
|
12928
|
+
// - the last directive in NgModule.declarations has priority over the previous one
|
|
12929
|
+
// So to match these rules, the order in which providers are added in the arrays is very
|
|
12930
|
+
// important.
|
|
12931
|
+
for (let i = 0; i < directives.length; i++) {
|
|
12932
|
+
const def = directives[i];
|
|
12933
|
+
if (def.providersResolver)
|
|
12934
|
+
def.providersResolver(def);
|
|
12935
|
+
}
|
|
12936
|
+
let preOrderHooksFound = false;
|
|
12937
|
+
let preOrderCheckHooksFound = false;
|
|
12938
|
+
let directiveIdx = allocExpando(tView, lView, directives.length, null);
|
|
12939
|
+
ngDevMode &&
|
|
12940
|
+
assertSame(directiveIdx, tNode.directiveStart, 'TNode.directiveStart should point to just allocated space');
|
|
12941
|
+
for (let i = 0; i < directives.length; i++) {
|
|
12942
|
+
const def = directives[i];
|
|
12943
|
+
// Merge the attrs in the order of matches. This assumes that the first directive is the
|
|
12944
|
+
// component itself, so that the component has the least priority.
|
|
12945
|
+
tNode.mergedAttrs = mergeHostAttrs(tNode.mergedAttrs, def.hostAttrs);
|
|
12946
|
+
configureViewWithDirective(tView, tNode, lView, directiveIdx, def);
|
|
12947
|
+
saveNameToExportMap(directiveIdx, def, exportsMap);
|
|
12948
|
+
if (def.contentQueries !== null)
|
|
12949
|
+
tNode.flags |= 4 /* TNodeFlags.hasContentQuery */;
|
|
12950
|
+
if (def.hostBindings !== null || def.hostAttrs !== null || def.hostVars !== 0)
|
|
12951
|
+
tNode.flags |= 64 /* TNodeFlags.hasHostBindings */;
|
|
12952
|
+
const lifeCycleHooks = def.type.prototype;
|
|
12953
|
+
// Only push a node index into the preOrderHooks array if this is the first
|
|
12954
|
+
// pre-order hook found on this node.
|
|
12955
|
+
if (!preOrderHooksFound &&
|
|
12956
|
+
(lifeCycleHooks.ngOnChanges || lifeCycleHooks.ngOnInit || lifeCycleHooks.ngDoCheck)) {
|
|
12957
|
+
// We will push the actual hook function into this array later during dir instantiation.
|
|
12958
|
+
// We cannot do it now because we must ensure hooks are registered in the same
|
|
12959
|
+
// order that directives are created (i.e. injection order).
|
|
12960
|
+
(tView.preOrderHooks || (tView.preOrderHooks = [])).push(tNode.index);
|
|
12961
|
+
preOrderHooksFound = true;
|
|
12962
|
+
}
|
|
12963
|
+
if (!preOrderCheckHooksFound && (lifeCycleHooks.ngOnChanges || lifeCycleHooks.ngDoCheck)) {
|
|
12964
|
+
(tView.preOrderCheckHooks || (tView.preOrderCheckHooks = [])).push(tNode.index);
|
|
12965
|
+
preOrderCheckHooksFound = true;
|
|
12966
|
+
}
|
|
12967
|
+
directiveIdx++;
|
|
12968
|
+
}
|
|
12969
|
+
initializeInputAndOutputAliases(tView, tNode);
|
|
12970
|
+
}
|
|
12959
12971
|
/**
|
|
12960
12972
|
* Add `hostBindings` to the `TView.hostBindingOpCodes`.
|
|
12961
12973
|
*
|
|
12962
12974
|
* @param tView `TView` to which the `hostBindings` should be added.
|
|
12963
12975
|
* @param tNode `TNode` the element which contains the directive
|
|
12964
|
-
* @param lView `LView` current `LView`
|
|
12965
12976
|
* @param directiveIdx Directive index in view.
|
|
12966
12977
|
* @param directiveVarsIdx Where will the directive's vars be stored
|
|
12967
12978
|
* @param def `ComponentDef`/`DirectiveDef`, which contains the `hostVars`/`hostBindings` to add.
|
|
12968
12979
|
*/
|
|
12969
|
-
function registerHostBindingOpCodes(tView, tNode,
|
|
12980
|
+
function registerHostBindingOpCodes(tView, tNode, directiveIdx, directiveVarsIdx, def) {
|
|
12970
12981
|
ngDevMode && assertFirstCreatePass(tView);
|
|
12971
12982
|
const hostBindings = def.hostBindings;
|
|
12972
12983
|
if (hostBindings) {
|
|
@@ -13067,7 +13078,7 @@ function invokeHostBindingsInCreationMode(def, directive) {
|
|
|
13067
13078
|
* Matches the current node against all available selectors.
|
|
13068
13079
|
* If a component is matched (at most one), it is returned in first position in the array.
|
|
13069
13080
|
*/
|
|
13070
|
-
function findDirectiveDefMatches(tView,
|
|
13081
|
+
function findDirectiveDefMatches(tView, lView, tNode) {
|
|
13071
13082
|
var _a;
|
|
13072
13083
|
ngDevMode && assertFirstCreatePass(tView);
|
|
13073
13084
|
ngDevMode && assertTNodeType(tNode, 3 /* TNodeType.AnyRNode */ | 12 /* TNodeType.AnyContainer */);
|
|
@@ -13078,25 +13089,47 @@ function findDirectiveDefMatches(tView, viewData, tNode) {
|
|
|
13078
13089
|
const def = registry[i];
|
|
13079
13090
|
if (isNodeMatchingSelectorList(tNode, def.selectors, /* isProjectionMode */ false)) {
|
|
13080
13091
|
matches || (matches = ngDevMode ? new MatchesArray() : []);
|
|
13081
|
-
diPublicInInjector(getOrCreateNodeInjectorForNode(tNode, viewData), tView, def.type);
|
|
13082
13092
|
if (isComponentDef(def)) {
|
|
13083
13093
|
if (ngDevMode) {
|
|
13084
13094
|
assertTNodeType(tNode, 2 /* TNodeType.Element */, `"${tNode.value}" tags cannot be used as component hosts. ` +
|
|
13085
13095
|
`Please use a different tag to activate the ${stringify(def.type)} component.`);
|
|
13086
|
-
if (tNode
|
|
13087
|
-
|
|
13088
|
-
// `matches` array, see how we store components/directives in `matches` below.
|
|
13089
|
-
throwMultipleComponentError(tNode, matches[0].type, def.type);
|
|
13096
|
+
if (isComponentHost(tNode)) {
|
|
13097
|
+
throwMultipleComponentError(tNode, matches.find(isComponentDef).type, def.type);
|
|
13090
13098
|
}
|
|
13091
13099
|
}
|
|
13092
|
-
|
|
13093
|
-
//
|
|
13094
|
-
|
|
13100
|
+
// Components are inserted at the front of the matches array so that their lifecycle
|
|
13101
|
+
// hooks run before any directive lifecycle hooks. This appears to be for ViewEngine
|
|
13102
|
+
// compatibility. This logic doesn't make sense with host directives, because it
|
|
13103
|
+
// would allow the host directives to undo any overrides the host may have made.
|
|
13104
|
+
// To handle this case, the host directives of components are inserted at the beginning
|
|
13105
|
+
// of the array, followed by the component. As such, the insertion order is as follows:
|
|
13106
|
+
// 1. Host directives belonging to the selector-matched component.
|
|
13107
|
+
// 2. Selector-matched component.
|
|
13108
|
+
// 3. Host directives belonging to selector-matched directives.
|
|
13109
|
+
// 4. Selector-matched directives.
|
|
13110
|
+
if (def.findHostDirectiveDefs !== null) {
|
|
13111
|
+
const hostDirectiveMatches = [];
|
|
13112
|
+
def.findHostDirectiveDefs(hostDirectiveMatches, def, tView, lView, tNode);
|
|
13113
|
+
// Add all host directives declared on this component, followed by the component itself.
|
|
13114
|
+
// Host directives should execute first so the host has a chance to override changes
|
|
13115
|
+
// to the DOM made by them.
|
|
13116
|
+
matches.unshift(...hostDirectiveMatches, def);
|
|
13117
|
+
// Component is offset starting from the beginning of the host directives array.
|
|
13118
|
+
const componentOffset = hostDirectiveMatches.length;
|
|
13119
|
+
markAsComponentHost(tView, tNode, componentOffset);
|
|
13120
|
+
}
|
|
13121
|
+
else {
|
|
13122
|
+
// No host directives on this component, just add the
|
|
13123
|
+
// component def to the beginning of the matches.
|
|
13124
|
+
matches.unshift(def);
|
|
13125
|
+
markAsComponentHost(tView, tNode, 0);
|
|
13126
|
+
}
|
|
13095
13127
|
}
|
|
13096
13128
|
else {
|
|
13129
|
+
// Append any host directives to the matches first.
|
|
13130
|
+
(_a = def.findHostDirectiveDefs) === null || _a === void 0 ? void 0 : _a.call(def, matches, def, tView, lView, tNode);
|
|
13097
13131
|
matches.push(def);
|
|
13098
13132
|
}
|
|
13099
|
-
(_a = def.applyHostDirectives) === null || _a === void 0 ? void 0 : _a.call(def, tView, viewData, tNode, matches);
|
|
13100
13133
|
}
|
|
13101
13134
|
}
|
|
13102
13135
|
}
|
|
@@ -13104,12 +13137,13 @@ function findDirectiveDefMatches(tView, viewData, tNode) {
|
|
|
13104
13137
|
}
|
|
13105
13138
|
/**
|
|
13106
13139
|
* Marks a given TNode as a component's host. This consists of:
|
|
13107
|
-
* - setting
|
|
13140
|
+
* - setting the component offset on the TNode.
|
|
13108
13141
|
* - storing index of component's host element so it will be queued for view refresh during CD.
|
|
13109
13142
|
*/
|
|
13110
|
-
function markAsComponentHost(tView, hostTNode) {
|
|
13143
|
+
function markAsComponentHost(tView, hostTNode, componentOffset) {
|
|
13111
13144
|
ngDevMode && assertFirstCreatePass(tView);
|
|
13112
|
-
|
|
13145
|
+
ngDevMode && assertGreaterThan(componentOffset, -1, 'componentOffset must be great than -1');
|
|
13146
|
+
hostTNode.componentOffset = componentOffset;
|
|
13113
13147
|
(tView.components || (tView.components = ngDevMode ? new TViewComponents() : []))
|
|
13114
13148
|
.push(hostTNode.index);
|
|
13115
13149
|
}
|
|
@@ -13180,7 +13214,7 @@ function configureViewWithDirective(tView, tNode, lView, directiveIndex, def) {
|
|
|
13180
13214
|
const nodeInjectorFactory = new NodeInjectorFactory(directiveFactory, isComponentDef(def), ɵɵdirectiveInject);
|
|
13181
13215
|
tView.blueprint[directiveIndex] = nodeInjectorFactory;
|
|
13182
13216
|
lView[directiveIndex] = nodeInjectorFactory;
|
|
13183
|
-
registerHostBindingOpCodes(tView, tNode,
|
|
13217
|
+
registerHostBindingOpCodes(tView, tNode, directiveIndex, allocExpando(tView, lView, def.hostVars, NO_CHANGE), def);
|
|
13184
13218
|
}
|
|
13185
13219
|
function addComponentLogic(lView, hostTNode, def) {
|
|
13186
13220
|
const native = getNativeByTNode(hostTNode, lView);
|
|
@@ -13255,10 +13289,11 @@ function setInputsFromAttrs(lView, directiveIndex, instance, def, tNode, initial
|
|
|
13255
13289
|
*
|
|
13256
13290
|
* <my-component name="Bess"></my-component>
|
|
13257
13291
|
*
|
|
13258
|
-
* @param inputs
|
|
13259
|
-
* @param
|
|
13292
|
+
* @param inputs Input alias map that was generated from the directive def inputs.
|
|
13293
|
+
* @param directiveIndex Index of the directive that is currently being processed.
|
|
13294
|
+
* @param attrs Static attrs on this node.
|
|
13260
13295
|
*/
|
|
13261
|
-
function generateInitialInputs(inputs, attrs) {
|
|
13296
|
+
function generateInitialInputs(inputs, directiveIndex, attrs) {
|
|
13262
13297
|
let inputsToStore = null;
|
|
13263
13298
|
let i = 0;
|
|
13264
13299
|
while (i < attrs.length) {
|
|
@@ -13279,7 +13314,17 @@ function generateInitialInputs(inputs, attrs) {
|
|
|
13279
13314
|
if (inputs.hasOwnProperty(attrName)) {
|
|
13280
13315
|
if (inputsToStore === null)
|
|
13281
13316
|
inputsToStore = [];
|
|
13282
|
-
|
|
13317
|
+
// Find the input's public name from the input store. Note that we can be found easier
|
|
13318
|
+
// through the directive def, but we want to do it using the inputs store so that it can
|
|
13319
|
+
// account for host directive aliases.
|
|
13320
|
+
const inputConfig = inputs[attrName];
|
|
13321
|
+
for (let j = 0; j < inputConfig.length; j += 2) {
|
|
13322
|
+
if (inputConfig[j] === directiveIndex) {
|
|
13323
|
+
inputsToStore.push(attrName, inputConfig[j + 1], attrs[i + 1]);
|
|
13324
|
+
// A directive can't have multiple inputs with the same name so we can break here.
|
|
13325
|
+
break;
|
|
13326
|
+
}
|
|
13327
|
+
}
|
|
13283
13328
|
}
|
|
13284
13329
|
i += 2;
|
|
13285
13330
|
}
|
|
@@ -14092,6 +14137,7 @@ class ChainedInjector {
|
|
|
14092
14137
|
this.parentInjector = parentInjector;
|
|
14093
14138
|
}
|
|
14094
14139
|
get(token, notFoundValue, flags) {
|
|
14140
|
+
flags = convertToBitFlags(flags);
|
|
14095
14141
|
const value = this.injector.get(token, NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR, flags);
|
|
14096
14142
|
if (value !== NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR ||
|
|
14097
14143
|
notFoundValue === NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR) {
|
|
@@ -14168,42 +14214,23 @@ class ComponentFactory extends ComponentFactory$1 {
|
|
|
14168
14214
|
let component;
|
|
14169
14215
|
let tElementNode;
|
|
14170
14216
|
try {
|
|
14171
|
-
const
|
|
14217
|
+
const rootDirectives = [this.componentDef];
|
|
14218
|
+
const hostTNode = createRootComponentTNode(rootLView, hostRNode);
|
|
14219
|
+
const componentView = createRootComponentView(hostTNode, hostRNode, this.componentDef, rootDirectives, rootLView, rendererFactory, hostRenderer);
|
|
14220
|
+
tElementNode = getTNode(rootTView, HEADER_OFFSET);
|
|
14221
|
+
// TODO(crisbeto): in practice `hostRNode` should always be defined, but there are some tests
|
|
14222
|
+
// where the renderer is mocked out and `undefined` is returned. We should update the tests so
|
|
14223
|
+
// that this check can be removed.
|
|
14172
14224
|
if (hostRNode) {
|
|
14173
|
-
|
|
14174
|
-
setUpAttributes(hostRenderer, hostRNode, ['ng-version', VERSION.full]);
|
|
14175
|
-
}
|
|
14176
|
-
else {
|
|
14177
|
-
// If host element is created as a part of this function call (i.e. `rootSelectorOrNode`
|
|
14178
|
-
// is not defined), also apply attributes and classes extracted from component selector.
|
|
14179
|
-
// Extract attributes and classes from the first selector only to match VE behavior.
|
|
14180
|
-
const { attrs, classes } = extractAttrsAndClassesFromSelector(this.componentDef.selectors[0]);
|
|
14181
|
-
if (attrs) {
|
|
14182
|
-
setUpAttributes(hostRenderer, hostRNode, attrs);
|
|
14183
|
-
}
|
|
14184
|
-
if (classes && classes.length > 0) {
|
|
14185
|
-
writeDirectClass(hostRenderer, hostRNode, classes.join(' '));
|
|
14186
|
-
}
|
|
14187
|
-
}
|
|
14225
|
+
setRootNodeAttributes(hostRenderer, this.componentDef, hostRNode, rootSelectorOrNode);
|
|
14188
14226
|
}
|
|
14189
|
-
tElementNode = getTNode(rootTView, HEADER_OFFSET);
|
|
14190
14227
|
if (projectableNodes !== undefined) {
|
|
14191
|
-
|
|
14192
|
-
for (let i = 0; i < this.ngContentSelectors.length; i++) {
|
|
14193
|
-
const nodesforSlot = projectableNodes[i];
|
|
14194
|
-
// Projectable nodes can be passed as array of arrays or an array of iterables (ngUpgrade
|
|
14195
|
-
// case). Here we do normalize passed data structure to be an array of arrays to avoid
|
|
14196
|
-
// complex checks down the line.
|
|
14197
|
-
// We also normalize the length of the passed in projectable nodes (to match the number of
|
|
14198
|
-
// <ng-container> slots defined by a component).
|
|
14199
|
-
projection.push(nodesforSlot != null ? Array.from(nodesforSlot) : null);
|
|
14200
|
-
}
|
|
14228
|
+
projectNodes(tElementNode, this.ngContentSelectors, projectableNodes);
|
|
14201
14229
|
}
|
|
14202
14230
|
// TODO: should LifecycleHooksFeature and other host features be generated by the compiler and
|
|
14203
14231
|
// executed here?
|
|
14204
14232
|
// Angular 5 reference: https://stackblitz.com/edit/lifecycle-hooks-vcref
|
|
14205
|
-
component =
|
|
14206
|
-
createRootComponent(componentView, this.componentDef, rootLView, [LifecycleHooksFeature]);
|
|
14233
|
+
component = createRootComponent(componentView, this.componentDef, rootDirectives, rootLView, [LifecycleHooksFeature]);
|
|
14207
14234
|
renderView(rootTView, rootLView, null);
|
|
14208
14235
|
}
|
|
14209
14236
|
finally {
|
|
@@ -14274,11 +14301,22 @@ const NULL_INJECTOR = {
|
|
|
14274
14301
|
throwProviderNotFoundError(token, 'NullInjector');
|
|
14275
14302
|
}
|
|
14276
14303
|
};
|
|
14304
|
+
/** Creates a TNode that can be used to instantiate a root component. */
|
|
14305
|
+
function createRootComponentTNode(lView, rNode) {
|
|
14306
|
+
const tView = lView[TVIEW];
|
|
14307
|
+
const index = HEADER_OFFSET;
|
|
14308
|
+
ngDevMode && assertIndexInRange(lView, index);
|
|
14309
|
+
lView[index] = rNode;
|
|
14310
|
+
// '#host' is added here as we don't know the real host DOM name (we don't want to read it) and at
|
|
14311
|
+
// the same time we want to communicate the debug `TNode` that this is a special `TNode`
|
|
14312
|
+
// representing a host element.
|
|
14313
|
+
return getOrCreateTNode(tView, index, 2 /* TNodeType.Element */, '#host', null);
|
|
14314
|
+
}
|
|
14277
14315
|
/**
|
|
14278
14316
|
* Creates the root component view and the root component node.
|
|
14279
14317
|
*
|
|
14280
14318
|
* @param rNode Render host element.
|
|
14281
|
-
* @param
|
|
14319
|
+
* @param rootComponentDef ComponentDef
|
|
14282
14320
|
* @param rootView The parent view where the host node is stored
|
|
14283
14321
|
* @param rendererFactory Factory to be used for creating child renderers.
|
|
14284
14322
|
* @param hostRenderer The current renderer
|
|
@@ -14286,72 +14324,96 @@ const NULL_INJECTOR = {
|
|
|
14286
14324
|
*
|
|
14287
14325
|
* @returns Component view created
|
|
14288
14326
|
*/
|
|
14289
|
-
function createRootComponentView(rNode,
|
|
14327
|
+
function createRootComponentView(tNode, rNode, rootComponentDef, rootDirectives, rootView, rendererFactory, hostRenderer, sanitizer) {
|
|
14290
14328
|
const tView = rootView[TVIEW];
|
|
14291
|
-
|
|
14292
|
-
|
|
14293
|
-
rootView[index]
|
|
14294
|
-
// '#host' is added here as we don't know the real host DOM name (we don't want to read it) and at
|
|
14295
|
-
// the same time we want to communicate the debug `TNode` that this is a special `TNode`
|
|
14296
|
-
// representing a host element.
|
|
14297
|
-
const tNode = getOrCreateTNode(tView, index, 2 /* TNodeType.Element */, '#host', null);
|
|
14298
|
-
const mergedAttrs = tNode.mergedAttrs = def.hostAttrs;
|
|
14299
|
-
if (mergedAttrs !== null) {
|
|
14300
|
-
computeStaticStyling(tNode, mergedAttrs, true);
|
|
14301
|
-
if (rNode !== null) {
|
|
14302
|
-
setUpAttributes(hostRenderer, rNode, mergedAttrs);
|
|
14303
|
-
if (tNode.classes !== null) {
|
|
14304
|
-
writeDirectClass(hostRenderer, rNode, tNode.classes);
|
|
14305
|
-
}
|
|
14306
|
-
if (tNode.styles !== null) {
|
|
14307
|
-
writeDirectStyle(hostRenderer, rNode, tNode.styles);
|
|
14308
|
-
}
|
|
14309
|
-
}
|
|
14310
|
-
}
|
|
14311
|
-
const viewRenderer = rendererFactory.createRenderer(rNode, def);
|
|
14312
|
-
const componentView = createLView(rootView, getOrCreateComponentTView(def), null, def.onPush ? 32 /* LViewFlags.Dirty */ : 16 /* LViewFlags.CheckAlways */, rootView[index], tNode, rendererFactory, viewRenderer, sanitizer || null, null, null);
|
|
14329
|
+
applyRootComponentStyling(rootDirectives, tNode, rNode, hostRenderer);
|
|
14330
|
+
const viewRenderer = rendererFactory.createRenderer(rNode, rootComponentDef);
|
|
14331
|
+
const componentView = createLView(rootView, getOrCreateComponentTView(rootComponentDef), null, rootComponentDef.onPush ? 32 /* LViewFlags.Dirty */ : 16 /* LViewFlags.CheckAlways */, rootView[tNode.index], tNode, rendererFactory, viewRenderer, sanitizer || null, null, null);
|
|
14313
14332
|
if (tView.firstCreatePass) {
|
|
14314
|
-
diPublicInInjector(getOrCreateNodeInjectorForNode(tNode, rootView), tView,
|
|
14315
|
-
markAsComponentHost(tView, tNode);
|
|
14316
|
-
initTNodeFlags(tNode, rootView.length, 1);
|
|
14333
|
+
diPublicInInjector(getOrCreateNodeInjectorForNode(tNode, rootView), tView, rootComponentDef.type);
|
|
14334
|
+
markAsComponentHost(tView, tNode, 0);
|
|
14317
14335
|
}
|
|
14318
14336
|
addToViewTree(rootView, componentView);
|
|
14319
14337
|
// Store component view at node index, with node as the HOST
|
|
14320
|
-
return rootView[index] = componentView;
|
|
14338
|
+
return rootView[tNode.index] = componentView;
|
|
14339
|
+
}
|
|
14340
|
+
/** Sets up the styling information on a root component. */
|
|
14341
|
+
function applyRootComponentStyling(rootDirectives, tNode, rNode, hostRenderer) {
|
|
14342
|
+
for (const def of rootDirectives) {
|
|
14343
|
+
tNode.mergedAttrs = mergeHostAttrs(tNode.mergedAttrs, def.hostAttrs);
|
|
14344
|
+
}
|
|
14345
|
+
if (tNode.mergedAttrs !== null) {
|
|
14346
|
+
computeStaticStyling(tNode, tNode.mergedAttrs, true);
|
|
14347
|
+
if (rNode !== null) {
|
|
14348
|
+
setupStaticAttributes(hostRenderer, rNode, tNode);
|
|
14349
|
+
}
|
|
14350
|
+
}
|
|
14321
14351
|
}
|
|
14322
14352
|
/**
|
|
14323
14353
|
* Creates a root component and sets it up with features and host bindings.Shared by
|
|
14324
14354
|
* renderComponent() and ViewContainerRef.createComponent().
|
|
14325
14355
|
*/
|
|
14326
|
-
function createRootComponent(componentView,
|
|
14356
|
+
function createRootComponent(componentView, rootComponentDef, rootDirectives, rootLView, hostFeatures) {
|
|
14357
|
+
const rootTNode = getCurrentTNode();
|
|
14358
|
+
ngDevMode && assertDefined(rootTNode, 'tNode should have been already created');
|
|
14327
14359
|
const tView = rootLView[TVIEW];
|
|
14328
|
-
|
|
14329
|
-
|
|
14330
|
-
|
|
14331
|
-
|
|
14360
|
+
const native = getNativeByTNode(rootTNode, rootLView);
|
|
14361
|
+
initializeDirectives(tView, rootLView, rootTNode, rootDirectives, null);
|
|
14362
|
+
for (let i = 0; i < rootDirectives.length; i++) {
|
|
14363
|
+
const directiveIndex = rootTNode.directiveStart + i;
|
|
14364
|
+
const directiveInstance = getNodeInjectable(rootLView, tView, directiveIndex, rootTNode);
|
|
14365
|
+
attachPatchData(directiveInstance, rootLView);
|
|
14366
|
+
}
|
|
14367
|
+
invokeDirectivesHostBindings(tView, rootLView, rootTNode);
|
|
14368
|
+
if (native) {
|
|
14369
|
+
attachPatchData(native, rootLView);
|
|
14370
|
+
}
|
|
14371
|
+
// We're guaranteed for the `componentOffset` to be positive here
|
|
14372
|
+
// since a root component always matches a component def.
|
|
14373
|
+
ngDevMode &&
|
|
14374
|
+
assertGreaterThan(rootTNode.componentOffset, -1, 'componentOffset must be great than -1');
|
|
14375
|
+
const component = getNodeInjectable(rootLView, tView, rootTNode.directiveStart + rootTNode.componentOffset, rootTNode);
|
|
14332
14376
|
componentView[CONTEXT] = rootLView[CONTEXT] = component;
|
|
14333
14377
|
if (hostFeatures !== null) {
|
|
14334
14378
|
for (const feature of hostFeatures) {
|
|
14335
|
-
feature(component,
|
|
14379
|
+
feature(component, rootComponentDef);
|
|
14336
14380
|
}
|
|
14337
14381
|
}
|
|
14338
14382
|
// We want to generate an empty QueryList for root content queries for backwards
|
|
14339
14383
|
// compatibility with ViewEngine.
|
|
14340
|
-
|
|
14341
|
-
|
|
14342
|
-
|
|
14343
|
-
|
|
14384
|
+
executeContentQueries(tView, rootTNode, componentView);
|
|
14385
|
+
return component;
|
|
14386
|
+
}
|
|
14387
|
+
/** Sets the static attributes on a root component. */
|
|
14388
|
+
function setRootNodeAttributes(hostRenderer, componentDef, hostRNode, rootSelectorOrNode) {
|
|
14389
|
+
if (rootSelectorOrNode) {
|
|
14390
|
+
setUpAttributes(hostRenderer, hostRNode, ['ng-version', VERSION.full]);
|
|
14344
14391
|
}
|
|
14345
|
-
|
|
14346
|
-
|
|
14347
|
-
|
|
14348
|
-
|
|
14349
|
-
|
|
14350
|
-
|
|
14351
|
-
|
|
14352
|
-
|
|
14392
|
+
else {
|
|
14393
|
+
// If host element is created as a part of this function call (i.e. `rootSelectorOrNode`
|
|
14394
|
+
// is not defined), also apply attributes and classes extracted from component selector.
|
|
14395
|
+
// Extract attributes and classes from the first selector only to match VE behavior.
|
|
14396
|
+
const { attrs, classes } = extractAttrsAndClassesFromSelector(componentDef.selectors[0]);
|
|
14397
|
+
if (attrs) {
|
|
14398
|
+
setUpAttributes(hostRenderer, hostRNode, attrs);
|
|
14399
|
+
}
|
|
14400
|
+
if (classes && classes.length > 0) {
|
|
14401
|
+
writeDirectClass(hostRenderer, hostRNode, classes.join(' '));
|
|
14402
|
+
}
|
|
14403
|
+
}
|
|
14404
|
+
}
|
|
14405
|
+
/** Projects the `projectableNodes` that were specified when creating a root component. */
|
|
14406
|
+
function projectNodes(tNode, ngContentSelectors, projectableNodes) {
|
|
14407
|
+
const projection = tNode.projection = [];
|
|
14408
|
+
for (let i = 0; i < ngContentSelectors.length; i++) {
|
|
14409
|
+
const nodesforSlot = projectableNodes[i];
|
|
14410
|
+
// Projectable nodes can be passed as array of arrays or an array of iterables (ngUpgrade
|
|
14411
|
+
// case). Here we do normalize passed data structure to be an array of arrays to avoid
|
|
14412
|
+
// complex checks down the line.
|
|
14413
|
+
// We also normalize the length of the passed in projectable nodes (to match the number of
|
|
14414
|
+
// <ng-container> slots defined by a component).
|
|
14415
|
+
projection.push(nodesforSlot != null ? Array.from(nodesforSlot) : null);
|
|
14353
14416
|
}
|
|
14354
|
-
return component;
|
|
14355
14417
|
}
|
|
14356
14418
|
/**
|
|
14357
14419
|
* Used to enable lifecycle hooks on the root component.
|
|
@@ -14609,6 +14671,13 @@ function ɵɵCopyDefinitionFeature(definition) {
|
|
|
14609
14671
|
}
|
|
14610
14672
|
}
|
|
14611
14673
|
|
|
14674
|
+
/**
|
|
14675
|
+
* @license
|
|
14676
|
+
* Copyright Google LLC All Rights Reserved.
|
|
14677
|
+
*
|
|
14678
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
14679
|
+
* found in the LICENSE file at https://angular.io/license
|
|
14680
|
+
*/
|
|
14612
14681
|
/**
|
|
14613
14682
|
* This feature add the host directives behavior to a directive definition by patching a
|
|
14614
14683
|
* function onto it. The expectation is that the runtime will invoke the function during
|
|
@@ -14630,29 +14699,42 @@ function ɵɵCopyDefinitionFeature(definition) {
|
|
|
14630
14699
|
* @codeGenApi
|
|
14631
14700
|
*/
|
|
14632
14701
|
function ɵɵHostDirectivesFeature(rawHostDirectives) {
|
|
14633
|
-
const unwrappedHostDirectives = Array.isArray(rawHostDirectives) ? rawHostDirectives : rawHostDirectives();
|
|
14634
|
-
const hostDirectives = unwrappedHostDirectives.map(dir => typeof dir === 'function' ? { directive: dir, inputs: EMPTY_OBJ, outputs: EMPTY_OBJ } : {
|
|
14635
|
-
directive: dir.directive,
|
|
14636
|
-
inputs: bindingArrayToMap(dir.inputs),
|
|
14637
|
-
outputs: bindingArrayToMap(dir.outputs)
|
|
14638
|
-
});
|
|
14639
14702
|
return (definition) => {
|
|
14640
|
-
|
|
14641
|
-
definition.
|
|
14642
|
-
(
|
|
14703
|
+
definition.findHostDirectiveDefs = findHostDirectiveDefs;
|
|
14704
|
+
definition.hostDirectives =
|
|
14705
|
+
(Array.isArray(rawHostDirectives) ? rawHostDirectives : rawHostDirectives()).map(dir => {
|
|
14706
|
+
return typeof dir === 'function' ?
|
|
14707
|
+
{ directive: resolveForwardRef(dir), inputs: EMPTY_OBJ, outputs: EMPTY_OBJ } :
|
|
14708
|
+
{
|
|
14709
|
+
directive: resolveForwardRef(dir.directive),
|
|
14710
|
+
inputs: bindingArrayToMap(dir.inputs),
|
|
14711
|
+
outputs: bindingArrayToMap(dir.outputs)
|
|
14712
|
+
};
|
|
14713
|
+
});
|
|
14643
14714
|
};
|
|
14644
14715
|
}
|
|
14716
|
+
function findHostDirectiveDefs(matches, def, tView, lView, tNode) {
|
|
14717
|
+
if (def.hostDirectives !== null) {
|
|
14718
|
+
for (const hostDirectiveConfig of def.hostDirectives) {
|
|
14719
|
+
const hostDirectiveDef = getDirectiveDef(hostDirectiveConfig.directive);
|
|
14720
|
+
// TODO(crisbeto): assert that the def exists.
|
|
14721
|
+
// Host directives execute before the host so that its host bindings can be overwritten.
|
|
14722
|
+
findHostDirectiveDefs(matches, hostDirectiveDef, tView, lView, tNode);
|
|
14723
|
+
matches.push(hostDirectiveDef);
|
|
14724
|
+
}
|
|
14725
|
+
}
|
|
14726
|
+
}
|
|
14645
14727
|
/**
|
|
14646
14728
|
* Converts an array in the form of `['publicName', 'alias', 'otherPublicName', 'otherAlias']` into
|
|
14647
14729
|
* a map in the form of `{publicName: 'alias', otherPublicName: 'otherAlias'}`.
|
|
14648
14730
|
*/
|
|
14649
14731
|
function bindingArrayToMap(bindings) {
|
|
14650
|
-
if (
|
|
14732
|
+
if (bindings === undefined || bindings.length === 0) {
|
|
14651
14733
|
return EMPTY_OBJ;
|
|
14652
14734
|
}
|
|
14653
14735
|
const result = {};
|
|
14654
|
-
for (let i =
|
|
14655
|
-
result[bindings[i
|
|
14736
|
+
for (let i = 0; i < bindings.length; i += 2) {
|
|
14737
|
+
result[bindings[i]] = bindings[i + 1];
|
|
14656
14738
|
}
|
|
14657
14739
|
return result;
|
|
14658
14740
|
}
|
|
@@ -15599,19 +15681,8 @@ function ɵɵelementStart(index, name, attrsIndex, localRefsIndex) {
|
|
|
15599
15681
|
elementStartFirstCreatePass(adjustedIndex, tView, lView, native, name, attrsIndex, localRefsIndex) :
|
|
15600
15682
|
tView.data[adjustedIndex];
|
|
15601
15683
|
setCurrentTNode(tNode, true);
|
|
15602
|
-
|
|
15603
|
-
if (
|
|
15604
|
-
setUpAttributes(renderer, native, mergedAttrs);
|
|
15605
|
-
}
|
|
15606
|
-
const classes = tNode.classes;
|
|
15607
|
-
if (classes !== null) {
|
|
15608
|
-
writeDirectClass(renderer, native, classes);
|
|
15609
|
-
}
|
|
15610
|
-
const styles = tNode.styles;
|
|
15611
|
-
if (styles !== null) {
|
|
15612
|
-
writeDirectStyle(renderer, native, styles);
|
|
15613
|
-
}
|
|
15614
|
-
if ((tNode.flags & 64 /* TNodeFlags.isDetached */) !== 64 /* TNodeFlags.isDetached */) {
|
|
15684
|
+
setupStaticAttributes(renderer, native, tNode);
|
|
15685
|
+
if ((tNode.flags & 32 /* TNodeFlags.isDetached */) !== 32 /* TNodeFlags.isDetached */) {
|
|
15615
15686
|
// In the i18n case, the translation may have removed this element, so only add it if it is not
|
|
15616
15687
|
// detached. See `TNodeType.Placeholder` and `LFrame.inI18n` for more context.
|
|
15617
15688
|
appendChild(tView, lView, native, tNode);
|
|
@@ -16049,9 +16120,7 @@ function wrapListener(tNode, lView, context, listenerFn, wrapWithPreventDefault)
|
|
|
16049
16120
|
}
|
|
16050
16121
|
// In order to be backwards compatible with View Engine, events on component host nodes
|
|
16051
16122
|
// must also mark the component view itself dirty (i.e. the view that it owns).
|
|
16052
|
-
const startView = tNode.
|
|
16053
|
-
getComponentLViewByIndex(tNode.index, lView) :
|
|
16054
|
-
lView;
|
|
16123
|
+
const startView = tNode.componentOffset > -1 ? getComponentLViewByIndex(tNode.index, lView) : lView;
|
|
16055
16124
|
markViewDirty(startView);
|
|
16056
16125
|
let result = executeListenerWithErrorHandling(lView, context, listenerFn, e);
|
|
16057
16126
|
// A just-invoked listener function might have coalesced listeners so we need to check for
|
|
@@ -16208,7 +16277,7 @@ function ɵɵprojection(nodeIndex, selectorIndex = 0, attrs) {
|
|
|
16208
16277
|
tProjectionNode.projection = selectorIndex;
|
|
16209
16278
|
// `<ng-content>` has no content
|
|
16210
16279
|
setCurrentTNodeAsNotParent();
|
|
16211
|
-
if ((tProjectionNode.flags &
|
|
16280
|
+
if ((tProjectionNode.flags & 32 /* TNodeFlags.isDetached */) !== 32 /* TNodeFlags.isDetached */) {
|
|
16212
16281
|
// re-distribution of projectable nodes is stored on a component's view level
|
|
16213
16282
|
applyProjection(tView, lView, tProjectionNode);
|
|
16214
16283
|
}
|
|
@@ -18122,7 +18191,7 @@ function normalizeSuffix(value, suffix) {
|
|
|
18122
18191
|
* @param isClassBased `true` if `class` (`false` if `style`)
|
|
18123
18192
|
*/
|
|
18124
18193
|
function hasStylingInputShadow(tNode, isClassBased) {
|
|
18125
|
-
return (tNode.flags & (isClassBased ?
|
|
18194
|
+
return (tNode.flags & (isClassBased ? 8 /* TNodeFlags.hasClassInput */ : 16 /* TNodeFlags.hasStyleInput */)) !== 0;
|
|
18126
18195
|
}
|
|
18127
18196
|
|
|
18128
18197
|
/**
|
|
@@ -19814,7 +19883,7 @@ function processI18nInsertBefore(renderer, childTNode, lView, childRNode, parent
|
|
|
19814
19883
|
anchorRNode = i18nParent;
|
|
19815
19884
|
i18nParent = parentRElement;
|
|
19816
19885
|
}
|
|
19817
|
-
if (i18nParent !== null &&
|
|
19886
|
+
if (i18nParent !== null && childTNode.componentOffset === -1) {
|
|
19818
19887
|
for (let i = 1; i < tNodeInsertBeforeIndex.length; i++) {
|
|
19819
19888
|
// No need to `unwrapRNode` because all of the indexes point to i18n text nodes.
|
|
19820
19889
|
// see `assertDomNode` below.
|
|
@@ -22302,7 +22371,7 @@ function getDirectives(node) {
|
|
|
22302
22371
|
return [];
|
|
22303
22372
|
}
|
|
22304
22373
|
if (context.directives === undefined) {
|
|
22305
|
-
context.directives = getDirectivesAtNodeIndex(nodeIndex, lView
|
|
22374
|
+
context.directives = getDirectivesAtNodeIndex(nodeIndex, lView);
|
|
22306
22375
|
}
|
|
22307
22376
|
// The `directives` in this case are a named array called `LComponentView`. Clone the
|
|
22308
22377
|
// result so we don't expose an internal data structure in the user's console.
|
|
@@ -26085,7 +26154,7 @@ class TestBedImpl {
|
|
|
26085
26154
|
return TestBedImpl.INSTANCE.overrideProvider(token, provider);
|
|
26086
26155
|
}
|
|
26087
26156
|
static inject(token, notFoundValue, flags) {
|
|
26088
|
-
return TestBedImpl.INSTANCE.inject(token, notFoundValue, flags);
|
|
26157
|
+
return TestBedImpl.INSTANCE.inject(token, notFoundValue, ɵconvertToBitFlags(flags));
|
|
26089
26158
|
}
|
|
26090
26159
|
/** @deprecated from v9.0.0 use TestBed.inject */
|
|
26091
26160
|
static get(token, notFoundValue = Injector$1.THROW_IF_NOT_FOUND, flags = InjectFlags$1.Default) {
|
|
@@ -26219,7 +26288,7 @@ class TestBedImpl {
|
|
|
26219
26288
|
return this;
|
|
26220
26289
|
}
|
|
26221
26290
|
const UNDEFINED = {};
|
|
26222
|
-
const result = this.testModuleRef.injector.get(token, UNDEFINED, flags);
|
|
26291
|
+
const result = this.testModuleRef.injector.get(token, UNDEFINED, ɵconvertToBitFlags(flags));
|
|
26223
26292
|
return result === UNDEFINED ? this.compiler.injector.get(token, notFoundValue, flags) :
|
|
26224
26293
|
result;
|
|
26225
26294
|
}
|