@angular/core 15.0.0-next.3 → 15.0.0-next.5
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/di/index.mjs +1 -1
- package/esm2020/src/di/injectable.mjs +1 -1
- package/esm2020/src/di/injection_token.mjs +6 -3
- 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/errors.mjs +1 -1
- package/esm2020/src/metadata/directives.mjs +1 -1
- package/esm2020/src/render3/component_ref.mjs +113 -84
- package/esm2020/src/render3/context_discovery.mjs +7 -7
- package/esm2020/src/render3/di.mjs +3 -2
- package/esm2020/src/render3/features/host_directives_feature.mjs +101 -10
- package/esm2020/src/render3/features/ng_onchanges_feature.mjs +4 -2
- package/esm2020/src/render3/instructions/element.mjs +3 -15
- package/esm2020/src/render3/instructions/shared.mjs +151 -128
- package/esm2020/src/render3/interfaces/definition.mjs +1 -1
- package/esm2020/src/render3/jit/module.mjs +2 -2
- package/esm2020/src/render3/ng_module_ref.mjs +1 -1
- package/esm2020/src/render3/node_manipulation.mjs +15 -1
- 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 +1789 -1613
- package/fesm2015/core.mjs.map +1 -1
- package/fesm2015/testing.mjs +1055 -904
- package/fesm2015/testing.mjs.map +1 -1
- package/fesm2020/core.mjs +1788 -1614
- package/fesm2020/core.mjs.map +1 -1
- package/fesm2020/testing.mjs +1052 -902
- package/fesm2020/testing.mjs.map +1 -1
- package/index.d.ts +105 -24
- 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.5
|
|
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 = [];
|
|
@@ -3160,11 +3164,12 @@ function rememberChangeHistoryAndInvokeOnChangesHook() {
|
|
|
3160
3164
|
}
|
|
3161
3165
|
}
|
|
3162
3166
|
function ngOnChangesSetInput(instance, value, publicName, privateName) {
|
|
3167
|
+
const declaredName = this.declaredInputs[publicName];
|
|
3168
|
+
ngDevMode && assertString(declaredName, 'Name of input in ngOnChanges has to be a string');
|
|
3163
3169
|
const simpleChangesStore = getSimpleChangesStore(instance) ||
|
|
3164
3170
|
setSimpleChangesStore(instance, { previous: EMPTY_OBJ, current: null });
|
|
3165
3171
|
const current = simpleChangesStore.current || (simpleChangesStore.current = {});
|
|
3166
3172
|
const previous = simpleChangesStore.previous;
|
|
3167
|
-
const declaredName = this.declaredInputs[publicName];
|
|
3168
3173
|
const previousChange = previous[declaredName];
|
|
3169
3174
|
current[declaredName] = new SimpleChange(previousChange && previousChange.currentValue, value, previous === EMPTY_OBJ);
|
|
3170
3175
|
instance[privateName] = value;
|
|
@@ -5233,7 +5238,7 @@ class NodeInjector {
|
|
|
5233
5238
|
this._lView = _lView;
|
|
5234
5239
|
}
|
|
5235
5240
|
get(token, notFoundValue, flags) {
|
|
5236
|
-
return getOrCreateInjectable(this._tNode, this._lView, token, flags, notFoundValue);
|
|
5241
|
+
return getOrCreateInjectable(this._tNode, this._lView, token, convertToBitFlags(flags), notFoundValue);
|
|
5237
5242
|
}
|
|
5238
5243
|
}
|
|
5239
5244
|
/** Creates a `NodeInjector` for the current node. */
|
|
@@ -6635,8 +6640,11 @@ function getSanitizer() {
|
|
|
6635
6640
|
* As you can see in the Tree-shakable InjectionToken example below.
|
|
6636
6641
|
*
|
|
6637
6642
|
* Additionally, if a `factory` is specified you can also specify the `providedIn` option, which
|
|
6638
|
-
* overrides the above behavior and marks the token as belonging to a particular `@NgModule
|
|
6639
|
-
* mentioned above, `'root'` is the default value for
|
|
6643
|
+
* overrides the above behavior and marks the token as belonging to a particular `@NgModule` (note:
|
|
6644
|
+
* this option is now deprecated). As mentioned above, `'root'` is the default value for
|
|
6645
|
+
* `providedIn`.
|
|
6646
|
+
*
|
|
6647
|
+
* The `providedIn: NgModule` and `providedIn: 'any'` options are deprecated.
|
|
6640
6648
|
*
|
|
6641
6649
|
* @usageNotes
|
|
6642
6650
|
* ### Basic Examples
|
|
@@ -7136,6 +7144,7 @@ class R3Injector extends EnvironmentInjector {
|
|
|
7136
7144
|
}
|
|
7137
7145
|
get(token, notFoundValue = THROW_IF_NOT_FOUND, flags = InjectFlags.Default) {
|
|
7138
7146
|
this.assertNotDestroyed();
|
|
7147
|
+
flags = convertToBitFlags(flags);
|
|
7139
7148
|
// Set the injection context.
|
|
7140
7149
|
const previousInjector = setCurrentInjector(this);
|
|
7141
7150
|
const previousInjectImplementation = setInjectImplementation(undefined);
|
|
@@ -7637,7 +7646,7 @@ class Version {
|
|
|
7637
7646
|
/**
|
|
7638
7647
|
* @publicApi
|
|
7639
7648
|
*/
|
|
7640
|
-
const VERSION = new Version('15.0.0-next.
|
|
7649
|
+
const VERSION = new Version('15.0.0-next.5');
|
|
7641
7650
|
|
|
7642
7651
|
/**
|
|
7643
7652
|
* @license
|
|
@@ -7672,29 +7681,70 @@ const NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR = {};
|
|
|
7672
7681
|
* Use of this source code is governed by an MIT-style license that can be
|
|
7673
7682
|
* found in the LICENSE file at https://angular.io/license
|
|
7674
7683
|
*/
|
|
7684
|
+
// Keeps track of the currently-active LViews.
|
|
7685
|
+
const TRACKED_LVIEWS = new Map();
|
|
7686
|
+
// Used for generating unique IDs for LViews.
|
|
7687
|
+
let uniqueIdCounter = 0;
|
|
7688
|
+
/** Gets a unique ID that can be assigned to an LView. */
|
|
7689
|
+
function getUniqueLViewId() {
|
|
7690
|
+
return uniqueIdCounter++;
|
|
7691
|
+
}
|
|
7692
|
+
/** Starts tracking an LView. */
|
|
7693
|
+
function registerLView(lView) {
|
|
7694
|
+
ngDevMode && assertNumber(lView[ID], 'LView must have an ID in order to be registered');
|
|
7695
|
+
TRACKED_LVIEWS.set(lView[ID], lView);
|
|
7696
|
+
}
|
|
7697
|
+
/** Gets an LView by its unique ID. */
|
|
7698
|
+
function getLViewById(id) {
|
|
7699
|
+
ngDevMode && assertNumber(id, 'ID used for LView lookup must be a number');
|
|
7700
|
+
return TRACKED_LVIEWS.get(id) || null;
|
|
7701
|
+
}
|
|
7702
|
+
/** Stops tracking an LView. */
|
|
7703
|
+
function unregisterLView(lView) {
|
|
7704
|
+
ngDevMode && assertNumber(lView[ID], 'Cannot stop tracking an LView that does not have an ID');
|
|
7705
|
+
TRACKED_LVIEWS.delete(lView[ID]);
|
|
7706
|
+
}
|
|
7707
|
+
|
|
7675
7708
|
/**
|
|
7676
|
-
*
|
|
7677
|
-
*
|
|
7678
|
-
* - Element properties named with dash case (`-`).
|
|
7679
|
-
* Dash case is the naming convention for custom elements.
|
|
7709
|
+
* @license
|
|
7710
|
+
* Copyright Google LLC All Rights Reserved.
|
|
7680
7711
|
*
|
|
7681
|
-
*
|
|
7712
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
7713
|
+
* found in the LICENSE file at https://angular.io/license
|
|
7682
7714
|
*/
|
|
7683
|
-
const CUSTOM_ELEMENTS_SCHEMA = {
|
|
7684
|
-
name: 'custom-elements'
|
|
7685
|
-
};
|
|
7686
7715
|
/**
|
|
7687
|
-
*
|
|
7688
|
-
*
|
|
7689
|
-
*
|
|
7690
|
-
*
|
|
7691
|
-
* and may hide real errors in your template. Consider using the `CUSTOM_ELEMENTS_SCHEMA` instead.
|
|
7716
|
+
* The internal view context which is specific to a given DOM element, directive or
|
|
7717
|
+
* component instance. Each value in here (besides the LView and element node details)
|
|
7718
|
+
* can be present, null or undefined. If undefined then it implies the value has not been
|
|
7719
|
+
* looked up yet, otherwise, if null, then a lookup was executed and nothing was found.
|
|
7692
7720
|
*
|
|
7693
|
-
*
|
|
7721
|
+
* Each value will get filled when the respective value is examined within the getContext
|
|
7722
|
+
* function. The component, element and each directive instance will share the same instance
|
|
7723
|
+
* of the context.
|
|
7694
7724
|
*/
|
|
7695
|
-
|
|
7696
|
-
|
|
7697
|
-
|
|
7725
|
+
class LContext {
|
|
7726
|
+
constructor(
|
|
7727
|
+
/**
|
|
7728
|
+
* ID of the component's parent view data.
|
|
7729
|
+
*/
|
|
7730
|
+
lViewId,
|
|
7731
|
+
/**
|
|
7732
|
+
* The index instance of the node.
|
|
7733
|
+
*/
|
|
7734
|
+
nodeIndex,
|
|
7735
|
+
/**
|
|
7736
|
+
* The instance of the DOM node that is attached to the lNode.
|
|
7737
|
+
*/
|
|
7738
|
+
native) {
|
|
7739
|
+
this.lViewId = lViewId;
|
|
7740
|
+
this.nodeIndex = nodeIndex;
|
|
7741
|
+
this.native = native;
|
|
7742
|
+
}
|
|
7743
|
+
/** Component's parent view data. */
|
|
7744
|
+
get lView() {
|
|
7745
|
+
return getLViewById(this.lViewId);
|
|
7746
|
+
}
|
|
7747
|
+
}
|
|
7698
7748
|
|
|
7699
7749
|
/**
|
|
7700
7750
|
* @license
|
|
@@ -7703,337 +7753,305 @@ const NO_ERRORS_SCHEMA = {
|
|
|
7703
7753
|
* Use of this source code is governed by an MIT-style license that can be
|
|
7704
7754
|
* found in the LICENSE file at https://angular.io/license
|
|
7705
7755
|
*/
|
|
7706
|
-
let shouldThrowErrorOnUnknownElement = false;
|
|
7707
|
-
/**
|
|
7708
|
-
* Sets a strict mode for JIT-compiled components to throw an error on unknown elements,
|
|
7709
|
-
* instead of just logging the error.
|
|
7710
|
-
* (for AOT-compiled ones this check happens at build time).
|
|
7711
|
-
*/
|
|
7712
|
-
function ɵsetUnknownElementStrictMode(shouldThrow) {
|
|
7713
|
-
shouldThrowErrorOnUnknownElement = shouldThrow;
|
|
7714
|
-
}
|
|
7715
|
-
/**
|
|
7716
|
-
* Gets the current value of the strict mode.
|
|
7717
|
-
*/
|
|
7718
|
-
function ɵgetUnknownElementStrictMode() {
|
|
7719
|
-
return shouldThrowErrorOnUnknownElement;
|
|
7720
|
-
}
|
|
7721
|
-
let shouldThrowErrorOnUnknownProperty = false;
|
|
7722
|
-
/**
|
|
7723
|
-
* Sets a strict mode for JIT-compiled components to throw an error on unknown properties,
|
|
7724
|
-
* instead of just logging the error.
|
|
7725
|
-
* (for AOT-compiled ones this check happens at build time).
|
|
7726
|
-
*/
|
|
7727
|
-
function ɵsetUnknownPropertyStrictMode(shouldThrow) {
|
|
7728
|
-
shouldThrowErrorOnUnknownProperty = shouldThrow;
|
|
7729
|
-
}
|
|
7730
|
-
/**
|
|
7731
|
-
* Gets the current value of the strict mode.
|
|
7732
|
-
*/
|
|
7733
|
-
function ɵgetUnknownPropertyStrictMode() {
|
|
7734
|
-
return shouldThrowErrorOnUnknownProperty;
|
|
7735
|
-
}
|
|
7736
7756
|
/**
|
|
7737
|
-
*
|
|
7738
|
-
* an error if it's not the case.
|
|
7739
|
-
* This check is relevant for JIT-compiled components (for AOT-compiled
|
|
7740
|
-
* ones this check happens at build time).
|
|
7757
|
+
* Returns the matching `LContext` data for a given DOM node, directive or component instance.
|
|
7741
7758
|
*
|
|
7742
|
-
*
|
|
7743
|
-
* -
|
|
7744
|
-
*
|
|
7745
|
-
* - the element matches any directive
|
|
7746
|
-
* - the element is allowed by one of the schemas
|
|
7759
|
+
* This function will examine the provided DOM element, component, or directive instance\'s
|
|
7760
|
+
* monkey-patched property to derive the `LContext` data. Once called then the monkey-patched
|
|
7761
|
+
* value will be that of the newly created `LContext`.
|
|
7747
7762
|
*
|
|
7748
|
-
*
|
|
7749
|
-
*
|
|
7750
|
-
*
|
|
7751
|
-
*
|
|
7752
|
-
*
|
|
7763
|
+
* If the monkey-patched value is the `LView` instance then the context value for that
|
|
7764
|
+
* target will be created and the monkey-patch reference will be updated. Therefore when this
|
|
7765
|
+
* function is called it may mutate the provided element\'s, component\'s or any of the associated
|
|
7766
|
+
* directive\'s monkey-patch values.
|
|
7767
|
+
*
|
|
7768
|
+
* If the monkey-patch value is not detected then the code will walk up the DOM until an element
|
|
7769
|
+
* is found which contains a monkey-patch reference. When that occurs then the provided element
|
|
7770
|
+
* will be updated with a new context (which is then returned). If the monkey-patch value is not
|
|
7771
|
+
* detected for a component/directive instance then it will throw an error (all components and
|
|
7772
|
+
* directives should be automatically monkey-patched by ivy).
|
|
7773
|
+
*
|
|
7774
|
+
* @param target Component, Directive or DOM Node.
|
|
7753
7775
|
*/
|
|
7754
|
-
function
|
|
7755
|
-
|
|
7756
|
-
|
|
7757
|
-
|
|
7758
|
-
|
|
7759
|
-
|
|
7760
|
-
|
|
7761
|
-
|
|
7762
|
-
|
|
7763
|
-
|
|
7764
|
-
|
|
7765
|
-
|
|
7766
|
-
|
|
7767
|
-
|
|
7768
|
-
|
|
7769
|
-
|
|
7770
|
-
|
|
7771
|
-
|
|
7772
|
-
|
|
7773
|
-
|
|
7774
|
-
|
|
7775
|
-
|
|
7776
|
-
|
|
7777
|
-
let message = `'${tagName}' is not a known element${templateLocation}:\n`;
|
|
7778
|
-
message += `1. If '${tagName}' is an Angular component, then verify that it is ${isHostStandalone ? 'included in the \'@Component.imports\' of this component' :
|
|
7779
|
-
'a part of an @NgModule where this component is declared'}.\n`;
|
|
7780
|
-
if (tagName && tagName.indexOf('-') > -1) {
|
|
7781
|
-
message +=
|
|
7782
|
-
`2. If '${tagName}' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the ${schemas} of this component to suppress this message.`;
|
|
7776
|
+
function getLContext(target) {
|
|
7777
|
+
let mpValue = readPatchedData(target);
|
|
7778
|
+
if (mpValue) {
|
|
7779
|
+
// only when it's an array is it considered an LView instance
|
|
7780
|
+
// ... otherwise it's an already constructed LContext instance
|
|
7781
|
+
if (isLView(mpValue)) {
|
|
7782
|
+
const lView = mpValue;
|
|
7783
|
+
let nodeIndex;
|
|
7784
|
+
let component = undefined;
|
|
7785
|
+
let directives = undefined;
|
|
7786
|
+
if (isComponentInstance(target)) {
|
|
7787
|
+
nodeIndex = findViaComponent(lView, target);
|
|
7788
|
+
if (nodeIndex == -1) {
|
|
7789
|
+
throw new Error('The provided component was not found in the application');
|
|
7790
|
+
}
|
|
7791
|
+
component = target;
|
|
7792
|
+
}
|
|
7793
|
+
else if (isDirectiveInstance(target)) {
|
|
7794
|
+
nodeIndex = findViaDirective(lView, target);
|
|
7795
|
+
if (nodeIndex == -1) {
|
|
7796
|
+
throw new Error('The provided directive was not found in the application');
|
|
7797
|
+
}
|
|
7798
|
+
directives = getDirectivesAtNodeIndex(nodeIndex, lView);
|
|
7783
7799
|
}
|
|
7784
7800
|
else {
|
|
7785
|
-
|
|
7786
|
-
|
|
7801
|
+
nodeIndex = findViaNativeElement(lView, target);
|
|
7802
|
+
if (nodeIndex == -1) {
|
|
7803
|
+
return null;
|
|
7804
|
+
}
|
|
7787
7805
|
}
|
|
7788
|
-
|
|
7789
|
-
|
|
7806
|
+
// the goal is not to fill the entire context full of data because the lookups
|
|
7807
|
+
// are expensive. Instead, only the target data (the element, component, container, ICU
|
|
7808
|
+
// expression or directive details) are filled into the context. If called multiple times
|
|
7809
|
+
// with different target values then the missing target data will be filled in.
|
|
7810
|
+
const native = unwrapRNode(lView[nodeIndex]);
|
|
7811
|
+
const existingCtx = readPatchedData(native);
|
|
7812
|
+
const context = (existingCtx && !Array.isArray(existingCtx)) ?
|
|
7813
|
+
existingCtx :
|
|
7814
|
+
createLContext(lView, nodeIndex, native);
|
|
7815
|
+
// only when the component has been discovered then update the monkey-patch
|
|
7816
|
+
if (component && context.component === undefined) {
|
|
7817
|
+
context.component = component;
|
|
7818
|
+
attachPatchData(context.component, context);
|
|
7790
7819
|
}
|
|
7791
|
-
|
|
7792
|
-
|
|
7820
|
+
// only when the directives have been discovered then update the monkey-patch
|
|
7821
|
+
if (directives && context.directives === undefined) {
|
|
7822
|
+
context.directives = directives;
|
|
7823
|
+
for (let i = 0; i < directives.length; i++) {
|
|
7824
|
+
attachPatchData(directives[i], context);
|
|
7825
|
+
}
|
|
7826
|
+
}
|
|
7827
|
+
attachPatchData(context.native, context);
|
|
7828
|
+
mpValue = context;
|
|
7829
|
+
}
|
|
7830
|
+
}
|
|
7831
|
+
else {
|
|
7832
|
+
const rElement = target;
|
|
7833
|
+
ngDevMode && assertDomNode(rElement);
|
|
7834
|
+
// if the context is not found then we need to traverse upwards up the DOM
|
|
7835
|
+
// to find the nearest element that has already been monkey patched with data
|
|
7836
|
+
let parent = rElement;
|
|
7837
|
+
while (parent = parent.parentNode) {
|
|
7838
|
+
const parentContext = readPatchedData(parent);
|
|
7839
|
+
if (parentContext) {
|
|
7840
|
+
const lView = Array.isArray(parentContext) ? parentContext : parentContext.lView;
|
|
7841
|
+
// the edge of the app was also reached here through another means
|
|
7842
|
+
// (maybe because the DOM was changed manually).
|
|
7843
|
+
if (!lView) {
|
|
7844
|
+
return null;
|
|
7845
|
+
}
|
|
7846
|
+
const index = findViaNativeElement(lView, rElement);
|
|
7847
|
+
if (index >= 0) {
|
|
7848
|
+
const native = unwrapRNode(lView[index]);
|
|
7849
|
+
const context = createLContext(lView, index, native);
|
|
7850
|
+
attachPatchData(native, context);
|
|
7851
|
+
mpValue = context;
|
|
7852
|
+
break;
|
|
7853
|
+
}
|
|
7793
7854
|
}
|
|
7794
7855
|
}
|
|
7795
7856
|
}
|
|
7857
|
+
return mpValue || null;
|
|
7796
7858
|
}
|
|
7797
7859
|
/**
|
|
7798
|
-
*
|
|
7799
|
-
* false if it's not the case.
|
|
7800
|
-
* This check is relevant for JIT-compiled components (for AOT-compiled
|
|
7801
|
-
* ones this check happens at build time).
|
|
7802
|
-
*
|
|
7803
|
-
* The property is considered known if either:
|
|
7804
|
-
* - it's a known property of the element
|
|
7805
|
-
* - the element is allowed by one of the schemas
|
|
7806
|
-
* - the property is used for animations
|
|
7807
|
-
*
|
|
7808
|
-
* @param element Element to validate
|
|
7809
|
-
* @param propName Name of the property to check
|
|
7810
|
-
* @param tagName Name of the tag hosting the property
|
|
7811
|
-
* @param schemas Array of schemas
|
|
7860
|
+
* Creates an empty instance of a `LContext` context
|
|
7812
7861
|
*/
|
|
7813
|
-
function
|
|
7814
|
-
|
|
7815
|
-
// mode where this check happens at compile time. In JIT mode, `schemas` is always present and
|
|
7816
|
-
// defined as an array (as an empty array in case `schemas` field is not defined) and we should
|
|
7817
|
-
// execute the check below.
|
|
7818
|
-
if (schemas === null)
|
|
7819
|
-
return true;
|
|
7820
|
-
// The property is considered valid if the element matches the schema, it exists on the element,
|
|
7821
|
-
// or it is synthetic, and we are in a browser context (web worker nodes should be skipped).
|
|
7822
|
-
if (matchingSchemas(schemas, tagName) || propName in element || isAnimationProp(propName)) {
|
|
7823
|
-
return true;
|
|
7824
|
-
}
|
|
7825
|
-
// Note: `typeof Node` returns 'function' in most browsers, but on IE it is 'object' so we
|
|
7826
|
-
// need to account for both here, while being careful with `typeof null` also returning 'object'.
|
|
7827
|
-
return typeof Node === 'undefined' || Node === null || !(element instanceof Node);
|
|
7862
|
+
function createLContext(lView, nodeIndex, native) {
|
|
7863
|
+
return new LContext(lView[ID], nodeIndex, native);
|
|
7828
7864
|
}
|
|
7829
7865
|
/**
|
|
7830
|
-
*
|
|
7866
|
+
* Takes a component instance and returns the view for that component.
|
|
7831
7867
|
*
|
|
7832
|
-
* @param
|
|
7833
|
-
* @
|
|
7834
|
-
* @param nodeType Type of the node hosting the property
|
|
7835
|
-
* @param lView An `LView` that represents a current component
|
|
7868
|
+
* @param componentInstance
|
|
7869
|
+
* @returns The component's view
|
|
7836
7870
|
*/
|
|
7837
|
-
function
|
|
7838
|
-
|
|
7839
|
-
|
|
7840
|
-
|
|
7841
|
-
|
|
7842
|
-
|
|
7843
|
-
|
|
7844
|
-
|
|
7845
|
-
|
|
7846
|
-
|
|
7847
|
-
|
|
7848
|
-
const templateLocation = getTemplateLocationDetails(lView);
|
|
7849
|
-
let message = `Can't bind to '${propName}' since it isn't a known property of '${tagName}'${templateLocation}.`;
|
|
7850
|
-
const schemas = `'${isHostStandalone ? '@Component' : '@NgModule'}.schemas'`;
|
|
7851
|
-
const importLocation = isHostStandalone ?
|
|
7852
|
-
'included in the \'@Component.imports\' of this component' :
|
|
7853
|
-
'a part of an @NgModule where this component is declared';
|
|
7854
|
-
if (KNOWN_CONTROL_FLOW_DIRECTIVES.has(propName)) {
|
|
7855
|
-
// Most likely this is a control flow directive (such as `*ngIf`) used in
|
|
7856
|
-
// a template, but the directive or the `CommonModule` is not imported.
|
|
7857
|
-
const correspondingImport = KNOWN_CONTROL_FLOW_DIRECTIVES.get(propName);
|
|
7858
|
-
message += `\nIf the '${propName}' is an Angular control flow directive, ` +
|
|
7859
|
-
`please make sure that either the '${correspondingImport}' directive or the 'CommonModule' is ${importLocation}.`;
|
|
7871
|
+
function getComponentViewByInstance(componentInstance) {
|
|
7872
|
+
let patchedData = readPatchedData(componentInstance);
|
|
7873
|
+
let lView;
|
|
7874
|
+
if (isLView(patchedData)) {
|
|
7875
|
+
const contextLView = patchedData;
|
|
7876
|
+
const nodeIndex = findViaComponent(contextLView, componentInstance);
|
|
7877
|
+
lView = getComponentLViewByIndex(nodeIndex, contextLView);
|
|
7878
|
+
const context = createLContext(contextLView, nodeIndex, lView[HOST]);
|
|
7879
|
+
context.component = componentInstance;
|
|
7880
|
+
attachPatchData(componentInstance, context);
|
|
7881
|
+
attachPatchData(context.native, context);
|
|
7860
7882
|
}
|
|
7861
7883
|
else {
|
|
7862
|
-
|
|
7863
|
-
|
|
7864
|
-
|
|
7865
|
-
|
|
7866
|
-
if (tagName && tagName.indexOf('-') > -1) {
|
|
7867
|
-
message += `\n2. If '${tagName}' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' ` +
|
|
7868
|
-
`to the ${schemas} of this component to suppress this message.`;
|
|
7869
|
-
message += `\n3. To allow any property add 'NO_ERRORS_SCHEMA' to ` +
|
|
7870
|
-
`the ${schemas} of this component.`;
|
|
7871
|
-
}
|
|
7872
|
-
else {
|
|
7873
|
-
// If it's expected, the error can be suppressed by the `NO_ERRORS_SCHEMA` schema.
|
|
7874
|
-
message += `\n2. To allow any property add 'NO_ERRORS_SCHEMA' to ` +
|
|
7875
|
-
`the ${schemas} of this component.`;
|
|
7876
|
-
}
|
|
7884
|
+
const context = patchedData;
|
|
7885
|
+
const contextLView = context.lView;
|
|
7886
|
+
ngDevMode && assertLView(contextLView);
|
|
7887
|
+
lView = getComponentLViewByIndex(context.nodeIndex, contextLView);
|
|
7877
7888
|
}
|
|
7878
|
-
|
|
7889
|
+
return lView;
|
|
7879
7890
|
}
|
|
7880
|
-
|
|
7881
|
-
|
|
7882
|
-
|
|
7891
|
+
/**
|
|
7892
|
+
* This property will be monkey-patched on elements, components and directives.
|
|
7893
|
+
*/
|
|
7894
|
+
const MONKEY_PATCH_KEY_NAME = '__ngContext__';
|
|
7895
|
+
/**
|
|
7896
|
+
* Assigns the given data to the given target (which could be a component,
|
|
7897
|
+
* directive or DOM node instance) using monkey-patching.
|
|
7898
|
+
*/
|
|
7899
|
+
function attachPatchData(target, data) {
|
|
7900
|
+
ngDevMode && assertDefined(target, 'Target expected');
|
|
7901
|
+
// Only attach the ID of the view in order to avoid memory leaks (see #41047). We only do this
|
|
7902
|
+
// for `LView`, because we have control over when an `LView` is created and destroyed, whereas
|
|
7903
|
+
// we can't know when to remove an `LContext`.
|
|
7904
|
+
if (isLView(data)) {
|
|
7905
|
+
target[MONKEY_PATCH_KEY_NAME] = data[ID];
|
|
7906
|
+
registerLView(data);
|
|
7883
7907
|
}
|
|
7884
7908
|
else {
|
|
7885
|
-
|
|
7909
|
+
target[MONKEY_PATCH_KEY_NAME] = data;
|
|
7886
7910
|
}
|
|
7887
7911
|
}
|
|
7888
7912
|
/**
|
|
7889
|
-
*
|
|
7890
|
-
*
|
|
7891
|
-
* be too slow for production mode and also it relies on the constructor function being available.
|
|
7892
|
-
*
|
|
7893
|
-
* Gets a reference to the host component def (where a current component is declared).
|
|
7894
|
-
*
|
|
7895
|
-
* @param lView An `LView` that represents a current component that is being rendered.
|
|
7913
|
+
* Returns the monkey-patch value data present on the target (which could be
|
|
7914
|
+
* a component, directive or a DOM node).
|
|
7896
7915
|
*/
|
|
7897
|
-
function
|
|
7898
|
-
|
|
7899
|
-
const
|
|
7900
|
-
|
|
7901
|
-
|
|
7902
|
-
|
|
7903
|
-
|
|
7904
|
-
|
|
7916
|
+
function readPatchedData(target) {
|
|
7917
|
+
ngDevMode && assertDefined(target, 'Target expected');
|
|
7918
|
+
const data = target[MONKEY_PATCH_KEY_NAME];
|
|
7919
|
+
return (typeof data === 'number') ? getLViewById(data) : data || null;
|
|
7920
|
+
}
|
|
7921
|
+
function readPatchedLView(target) {
|
|
7922
|
+
const value = readPatchedData(target);
|
|
7923
|
+
if (value) {
|
|
7924
|
+
return (isLView(value) ? value : value.lView);
|
|
7925
|
+
}
|
|
7926
|
+
return null;
|
|
7927
|
+
}
|
|
7928
|
+
function isComponentInstance(instance) {
|
|
7929
|
+
return instance && instance.constructor && instance.constructor.ɵcmp;
|
|
7930
|
+
}
|
|
7931
|
+
function isDirectiveInstance(instance) {
|
|
7932
|
+
return instance && instance.constructor && instance.constructor.ɵdir;
|
|
7905
7933
|
}
|
|
7906
7934
|
/**
|
|
7907
|
-
*
|
|
7908
|
-
* and must **not** be used in production bundles. The function makes megamorphic reads, which might
|
|
7909
|
-
* be too slow for production mode.
|
|
7910
|
-
*
|
|
7911
|
-
* Checks if the current component is declared inside of a standalone component template.
|
|
7912
|
-
*
|
|
7913
|
-
* @param lView An `LView` that represents a current component that is being rendered.
|
|
7935
|
+
* Locates the element within the given LView and returns the matching index
|
|
7914
7936
|
*/
|
|
7915
|
-
function
|
|
7916
|
-
|
|
7917
|
-
|
|
7918
|
-
|
|
7919
|
-
|
|
7937
|
+
function findViaNativeElement(lView, target) {
|
|
7938
|
+
const tView = lView[TVIEW];
|
|
7939
|
+
for (let i = HEADER_OFFSET; i < tView.bindingStartIndex; i++) {
|
|
7940
|
+
if (unwrapRNode(lView[i]) === target) {
|
|
7941
|
+
return i;
|
|
7942
|
+
}
|
|
7943
|
+
}
|
|
7944
|
+
return -1;
|
|
7920
7945
|
}
|
|
7921
7946
|
/**
|
|
7922
|
-
*
|
|
7923
|
-
* and must **not** be used in production bundles. The function makes megamorphic reads, which might
|
|
7924
|
-
* be too slow for production mode.
|
|
7925
|
-
*
|
|
7926
|
-
* Constructs a string describing the location of the host component template. The function is used
|
|
7927
|
-
* in dev mode to produce error messages.
|
|
7928
|
-
*
|
|
7929
|
-
* @param lView An `LView` that represents a current component that is being rendered.
|
|
7947
|
+
* Locates the next tNode (child, sibling or parent).
|
|
7930
7948
|
*/
|
|
7931
|
-
function
|
|
7932
|
-
|
|
7933
|
-
|
|
7934
|
-
|
|
7935
|
-
|
|
7936
|
-
|
|
7949
|
+
function traverseNextElement(tNode) {
|
|
7950
|
+
if (tNode.child) {
|
|
7951
|
+
return tNode.child;
|
|
7952
|
+
}
|
|
7953
|
+
else if (tNode.next) {
|
|
7954
|
+
return tNode.next;
|
|
7955
|
+
}
|
|
7956
|
+
else {
|
|
7957
|
+
// Let's take the following template: <div><span>text</span></div><component/>
|
|
7958
|
+
// After checking the text node, we need to find the next parent that has a "next" TNode,
|
|
7959
|
+
// in this case the parent `div`, so that we can find the component.
|
|
7960
|
+
while (tNode.parent && !tNode.parent.next) {
|
|
7961
|
+
tNode = tNode.parent;
|
|
7962
|
+
}
|
|
7963
|
+
return tNode.parent && tNode.parent.next;
|
|
7964
|
+
}
|
|
7937
7965
|
}
|
|
7938
7966
|
/**
|
|
7939
|
-
*
|
|
7940
|
-
* We use this set to produce a more precises error message with a note
|
|
7941
|
-
* that the `CommonModule` should also be included.
|
|
7967
|
+
* Locates the component within the given LView and returns the matching index
|
|
7942
7968
|
*/
|
|
7943
|
-
|
|
7944
|
-
|
|
7945
|
-
|
|
7946
|
-
|
|
7969
|
+
function findViaComponent(lView, componentInstance) {
|
|
7970
|
+
const componentIndices = lView[TVIEW].components;
|
|
7971
|
+
if (componentIndices) {
|
|
7972
|
+
for (let i = 0; i < componentIndices.length; i++) {
|
|
7973
|
+
const elementComponentIndex = componentIndices[i];
|
|
7974
|
+
const componentView = getComponentLViewByIndex(elementComponentIndex, lView);
|
|
7975
|
+
if (componentView[CONTEXT] === componentInstance) {
|
|
7976
|
+
return elementComponentIndex;
|
|
7977
|
+
}
|
|
7978
|
+
}
|
|
7979
|
+
}
|
|
7980
|
+
else {
|
|
7981
|
+
const rootComponentView = getComponentLViewByIndex(HEADER_OFFSET, lView);
|
|
7982
|
+
const rootComponent = rootComponentView[CONTEXT];
|
|
7983
|
+
if (rootComponent === componentInstance) {
|
|
7984
|
+
// we are dealing with the root element here therefore we know that the
|
|
7985
|
+
// element is the very first element after the HEADER data in the lView
|
|
7986
|
+
return HEADER_OFFSET;
|
|
7987
|
+
}
|
|
7988
|
+
}
|
|
7989
|
+
return -1;
|
|
7990
|
+
}
|
|
7947
7991
|
/**
|
|
7948
|
-
*
|
|
7949
|
-
* @param schemas Array of schemas
|
|
7950
|
-
* @param tagName Name of the tag
|
|
7992
|
+
* Locates the directive within the given LView and returns the matching index
|
|
7951
7993
|
*/
|
|
7952
|
-
function
|
|
7953
|
-
if (
|
|
7954
|
-
|
|
7955
|
-
|
|
7956
|
-
|
|
7957
|
-
|
|
7958
|
-
|
|
7994
|
+
function findViaDirective(lView, directiveInstance) {
|
|
7995
|
+
// if a directive is monkey patched then it will (by default)
|
|
7996
|
+
// have a reference to the LView of the current view. The
|
|
7997
|
+
// element bound to the directive being search lives somewhere
|
|
7998
|
+
// in the view data. We loop through the nodes and check their
|
|
7999
|
+
// list of directives for the instance.
|
|
8000
|
+
let tNode = lView[TVIEW].firstChild;
|
|
8001
|
+
while (tNode) {
|
|
8002
|
+
const directiveIndexStart = tNode.directiveStart;
|
|
8003
|
+
const directiveIndexEnd = tNode.directiveEnd;
|
|
8004
|
+
for (let i = directiveIndexStart; i < directiveIndexEnd; i++) {
|
|
8005
|
+
if (lView[i] === directiveInstance) {
|
|
8006
|
+
return tNode.index;
|
|
7959
8007
|
}
|
|
7960
8008
|
}
|
|
8009
|
+
tNode = traverseNextElement(tNode);
|
|
7961
8010
|
}
|
|
7962
|
-
return
|
|
8011
|
+
return -1;
|
|
7963
8012
|
}
|
|
7964
|
-
|
|
7965
8013
|
/**
|
|
7966
|
-
*
|
|
7967
|
-
*
|
|
8014
|
+
* Returns a list of directives applied to a node at a specific index. The list includes
|
|
8015
|
+
* directives matched by selector and any host directives, but it excludes components.
|
|
8016
|
+
* Use `getComponentAtNodeIndex` to find the component applied to a node.
|
|
7968
8017
|
*
|
|
7969
|
-
*
|
|
7970
|
-
*
|
|
7971
|
-
*/
|
|
7972
|
-
|
|
7973
|
-
|
|
7974
|
-
|
|
7975
|
-
|
|
7976
|
-
|
|
7977
|
-
|
|
8018
|
+
* @param nodeIndex The node index
|
|
8019
|
+
* @param lView The target view data
|
|
8020
|
+
*/
|
|
8021
|
+
function getDirectivesAtNodeIndex(nodeIndex, lView) {
|
|
8022
|
+
const tNode = lView[TVIEW].data[nodeIndex];
|
|
8023
|
+
if (tNode.directiveStart === 0)
|
|
8024
|
+
return EMPTY_ARRAY;
|
|
8025
|
+
const results = [];
|
|
8026
|
+
for (let i = tNode.directiveStart; i < tNode.directiveEnd; i++) {
|
|
8027
|
+
const directiveInstance = lView[i];
|
|
8028
|
+
if (!isComponentInstance(directiveInstance)) {
|
|
8029
|
+
results.push(directiveInstance);
|
|
8030
|
+
}
|
|
8031
|
+
}
|
|
8032
|
+
return results;
|
|
7978
8033
|
}
|
|
7979
|
-
function
|
|
7980
|
-
|
|
8034
|
+
function getComponentAtNodeIndex(nodeIndex, lView) {
|
|
8035
|
+
const tNode = lView[TVIEW].data[nodeIndex];
|
|
8036
|
+
const { directiveStart, componentOffset } = tNode;
|
|
8037
|
+
return componentOffset > -1 ? lView[directiveStart + componentOffset] : null;
|
|
7981
8038
|
}
|
|
7982
|
-
|
|
7983
|
-
/**
|
|
7984
|
-
* @license
|
|
7985
|
-
* Copyright Google LLC All Rights Reserved.
|
|
7986
|
-
*
|
|
7987
|
-
* Use of this source code is governed by an MIT-style license that can be
|
|
7988
|
-
* found in the LICENSE file at https://angular.io/license
|
|
7989
|
-
*/
|
|
7990
8039
|
/**
|
|
7991
|
-
*
|
|
7992
|
-
*
|
|
7993
|
-
* The default implementation of `ErrorHandler` prints error messages to the `console`. To
|
|
7994
|
-
* intercept error handling, write a custom exception handler that replaces this default as
|
|
7995
|
-
* appropriate for your app.
|
|
7996
|
-
*
|
|
7997
|
-
* @usageNotes
|
|
7998
|
-
* ### Example
|
|
7999
|
-
*
|
|
8000
|
-
* ```
|
|
8001
|
-
* class MyErrorHandler implements ErrorHandler {
|
|
8002
|
-
* handleError(error) {
|
|
8003
|
-
* // do something with the exception
|
|
8004
|
-
* }
|
|
8005
|
-
* }
|
|
8006
|
-
*
|
|
8007
|
-
* @NgModule({
|
|
8008
|
-
* providers: [{provide: ErrorHandler, useClass: MyErrorHandler}]
|
|
8009
|
-
* })
|
|
8010
|
-
* class MyModule {}
|
|
8011
|
-
* ```
|
|
8012
|
-
*
|
|
8013
|
-
* @publicApi
|
|
8040
|
+
* Returns a map of local references (local reference name => element or directive instance) that
|
|
8041
|
+
* exist on a given element.
|
|
8014
8042
|
*/
|
|
8015
|
-
|
|
8016
|
-
|
|
8017
|
-
|
|
8018
|
-
|
|
8019
|
-
|
|
8020
|
-
|
|
8021
|
-
|
|
8022
|
-
|
|
8023
|
-
const originalError = this._findOriginalError(error);
|
|
8024
|
-
this._console.error('ERROR', error);
|
|
8025
|
-
if (originalError) {
|
|
8026
|
-
this._console.error('ORIGINAL ERROR', originalError);
|
|
8027
|
-
}
|
|
8028
|
-
}
|
|
8029
|
-
/** @internal */
|
|
8030
|
-
_findOriginalError(error) {
|
|
8031
|
-
let e = error && getOriginalError(error);
|
|
8032
|
-
while (e && getOriginalError(e)) {
|
|
8033
|
-
e = getOriginalError(e);
|
|
8043
|
+
function discoverLocalRefs(lView, nodeIndex) {
|
|
8044
|
+
const tNode = lView[TVIEW].data[nodeIndex];
|
|
8045
|
+
if (tNode && tNode.localNames) {
|
|
8046
|
+
const result = {};
|
|
8047
|
+
let localIndex = tNode.index + 1;
|
|
8048
|
+
for (let i = 0; i < tNode.localNames.length; i += 2) {
|
|
8049
|
+
result[tNode.localNames[i]] = lView[localIndex];
|
|
8050
|
+
localIndex++;
|
|
8034
8051
|
}
|
|
8035
|
-
return
|
|
8052
|
+
return result;
|
|
8036
8053
|
}
|
|
8054
|
+
return null;
|
|
8037
8055
|
}
|
|
8038
8056
|
|
|
8039
8057
|
/**
|
|
@@ -8044,46 +8062,28 @@ class ErrorHandler {
|
|
|
8044
8062
|
* found in the LICENSE file at https://angular.io/license
|
|
8045
8063
|
*/
|
|
8046
8064
|
/**
|
|
8047
|
-
*
|
|
8065
|
+
* Defines a schema that allows an NgModule to contain the following:
|
|
8066
|
+
* - Non-Angular elements named with dash case (`-`).
|
|
8067
|
+
* - Element properties named with dash case (`-`).
|
|
8068
|
+
* Dash case is the naming convention for custom elements.
|
|
8048
8069
|
*
|
|
8049
|
-
*
|
|
8050
|
-
*/
|
|
8051
|
-
const COMMENT_DISALLOWED = /^>|^->|<!--|-->|--!>|<!-$/g;
|
|
8052
|
-
/**
|
|
8053
|
-
* Delimiter in the disallowed strings which needs to be wrapped with zero with character.
|
|
8070
|
+
* @publicApi
|
|
8054
8071
|
*/
|
|
8055
|
-
const
|
|
8056
|
-
|
|
8072
|
+
const CUSTOM_ELEMENTS_SCHEMA = {
|
|
8073
|
+
name: 'custom-elements'
|
|
8074
|
+
};
|
|
8057
8075
|
/**
|
|
8058
|
-
*
|
|
8059
|
-
*
|
|
8060
|
-
* The issue is that HTML does not specify any way to escape comment end text inside the comment.
|
|
8061
|
-
* Consider: `<!-- The way you close a comment is with ">", and "->" at the beginning or by "-->" or
|
|
8062
|
-
* "--!>" at the end. -->`. Above the `"-->"` is meant to be text not an end to the comment. This
|
|
8063
|
-
* can be created programmatically through DOM APIs. (`<!--` are also disallowed.)
|
|
8064
|
-
*
|
|
8065
|
-
* see: https://html.spec.whatwg.org/multipage/syntax.html#comments
|
|
8066
|
-
*
|
|
8067
|
-
* ```
|
|
8068
|
-
* div.innerHTML = div.innerHTML
|
|
8069
|
-
* ```
|
|
8070
|
-
*
|
|
8071
|
-
* One would expect that the above code would be safe to do, but it turns out that because comment
|
|
8072
|
-
* text is not escaped, the comment may contain text which will prematurely close the comment
|
|
8073
|
-
* opening up the application for XSS attack. (In SSR we programmatically create comment nodes which
|
|
8074
|
-
* may contain such text and expect them to be safe.)
|
|
8076
|
+
* Defines a schema that allows any property on any element.
|
|
8075
8077
|
*
|
|
8076
|
-
* This
|
|
8077
|
-
*
|
|
8078
|
-
*
|
|
8079
|
-
* text it will render normally but it will not cause the HTML parser to close/open the comment.
|
|
8078
|
+
* This schema allows you to ignore the errors related to any unknown elements or properties in a
|
|
8079
|
+
* template. The usage of this schema is generally discouraged because it prevents useful validation
|
|
8080
|
+
* and may hide real errors in your template. Consider using the `CUSTOM_ELEMENTS_SCHEMA` instead.
|
|
8080
8081
|
*
|
|
8081
|
-
* @
|
|
8082
|
-
* sequence.
|
|
8082
|
+
* @publicApi
|
|
8083
8083
|
*/
|
|
8084
|
-
|
|
8085
|
-
|
|
8086
|
-
}
|
|
8084
|
+
const NO_ERRORS_SCHEMA = {
|
|
8085
|
+
name: 'no-errors-schema'
|
|
8086
|
+
};
|
|
8087
8087
|
|
|
8088
8088
|
/**
|
|
8089
8089
|
* @license
|
|
@@ -8092,403 +8092,412 @@ function escapeCommentText(value) {
|
|
|
8092
8092
|
* Use of this source code is governed by an MIT-style license that can be
|
|
8093
8093
|
* found in the LICENSE file at https://angular.io/license
|
|
8094
8094
|
*/
|
|
8095
|
-
|
|
8096
|
-
// Attribute names with `$` (eg `x-y$`) are valid per spec, but unsupported by some browsers
|
|
8097
|
-
name = camelCaseToDashCase(name.replace(/[$@]/g, '_'));
|
|
8098
|
-
return `ng-reflect-${name}`;
|
|
8099
|
-
}
|
|
8100
|
-
const CAMEL_CASE_REGEXP = /([A-Z])/g;
|
|
8101
|
-
function camelCaseToDashCase(input) {
|
|
8102
|
-
return input.replace(CAMEL_CASE_REGEXP, (...m) => '-' + m[1].toLowerCase());
|
|
8103
|
-
}
|
|
8104
|
-
function normalizeDebugBindingValue(value) {
|
|
8105
|
-
try {
|
|
8106
|
-
// Limit the size of the value as otherwise the DOM just gets polluted.
|
|
8107
|
-
return value != null ? value.toString().slice(0, 30) : value;
|
|
8108
|
-
}
|
|
8109
|
-
catch (e) {
|
|
8110
|
-
return '[ERROR] Exception while trying to serialize the value';
|
|
8111
|
-
}
|
|
8112
|
-
}
|
|
8113
|
-
|
|
8095
|
+
let shouldThrowErrorOnUnknownElement = false;
|
|
8114
8096
|
/**
|
|
8115
|
-
*
|
|
8116
|
-
*
|
|
8117
|
-
*
|
|
8118
|
-
* Use of this source code is governed by an MIT-style license that can be
|
|
8119
|
-
* found in the LICENSE file at https://angular.io/license
|
|
8097
|
+
* Sets a strict mode for JIT-compiled components to throw an error on unknown elements,
|
|
8098
|
+
* instead of just logging the error.
|
|
8099
|
+
* (for AOT-compiled ones this check happens at build time).
|
|
8120
8100
|
*/
|
|
8121
|
-
|
|
8122
|
-
|
|
8123
|
-
// Used for generating unique IDs for LViews.
|
|
8124
|
-
let uniqueIdCounter = 0;
|
|
8125
|
-
/** Gets a unique ID that can be assigned to an LView. */
|
|
8126
|
-
function getUniqueLViewId() {
|
|
8127
|
-
return uniqueIdCounter++;
|
|
8128
|
-
}
|
|
8129
|
-
/** Starts tracking an LView. */
|
|
8130
|
-
function registerLView(lView) {
|
|
8131
|
-
ngDevMode && assertNumber(lView[ID], 'LView must have an ID in order to be registered');
|
|
8132
|
-
TRACKED_LVIEWS.set(lView[ID], lView);
|
|
8133
|
-
}
|
|
8134
|
-
/** Gets an LView by its unique ID. */
|
|
8135
|
-
function getLViewById(id) {
|
|
8136
|
-
ngDevMode && assertNumber(id, 'ID used for LView lookup must be a number');
|
|
8137
|
-
return TRACKED_LVIEWS.get(id) || null;
|
|
8138
|
-
}
|
|
8139
|
-
/** Stops tracking an LView. */
|
|
8140
|
-
function unregisterLView(lView) {
|
|
8141
|
-
ngDevMode && assertNumber(lView[ID], 'Cannot stop tracking an LView that does not have an ID');
|
|
8142
|
-
TRACKED_LVIEWS.delete(lView[ID]);
|
|
8101
|
+
function ɵsetUnknownElementStrictMode(shouldThrow) {
|
|
8102
|
+
shouldThrowErrorOnUnknownElement = shouldThrow;
|
|
8143
8103
|
}
|
|
8144
|
-
|
|
8145
8104
|
/**
|
|
8146
|
-
*
|
|
8147
|
-
* Copyright Google LLC All Rights Reserved.
|
|
8148
|
-
*
|
|
8149
|
-
* Use of this source code is governed by an MIT-style license that can be
|
|
8150
|
-
* found in the LICENSE file at https://angular.io/license
|
|
8105
|
+
* Gets the current value of the strict mode.
|
|
8151
8106
|
*/
|
|
8107
|
+
function ɵgetUnknownElementStrictMode() {
|
|
8108
|
+
return shouldThrowErrorOnUnknownElement;
|
|
8109
|
+
}
|
|
8110
|
+
let shouldThrowErrorOnUnknownProperty = false;
|
|
8152
8111
|
/**
|
|
8153
|
-
*
|
|
8154
|
-
*
|
|
8155
|
-
*
|
|
8156
|
-
* looked up yet, otherwise, if null, then a lookup was executed and nothing was found.
|
|
8157
|
-
*
|
|
8158
|
-
* Each value will get filled when the respective value is examined within the getContext
|
|
8159
|
-
* function. The component, element and each directive instance will share the same instance
|
|
8160
|
-
* of the context.
|
|
8112
|
+
* Sets a strict mode for JIT-compiled components to throw an error on unknown properties,
|
|
8113
|
+
* instead of just logging the error.
|
|
8114
|
+
* (for AOT-compiled ones this check happens at build time).
|
|
8161
8115
|
*/
|
|
8162
|
-
|
|
8163
|
-
|
|
8164
|
-
/**
|
|
8165
|
-
* ID of the component's parent view data.
|
|
8166
|
-
*/
|
|
8167
|
-
lViewId,
|
|
8168
|
-
/**
|
|
8169
|
-
* The index instance of the node.
|
|
8170
|
-
*/
|
|
8171
|
-
nodeIndex,
|
|
8172
|
-
/**
|
|
8173
|
-
* The instance of the DOM node that is attached to the lNode.
|
|
8174
|
-
*/
|
|
8175
|
-
native) {
|
|
8176
|
-
this.lViewId = lViewId;
|
|
8177
|
-
this.nodeIndex = nodeIndex;
|
|
8178
|
-
this.native = native;
|
|
8179
|
-
}
|
|
8180
|
-
/** Component's parent view data. */
|
|
8181
|
-
get lView() {
|
|
8182
|
-
return getLViewById(this.lViewId);
|
|
8183
|
-
}
|
|
8116
|
+
function ɵsetUnknownPropertyStrictMode(shouldThrow) {
|
|
8117
|
+
shouldThrowErrorOnUnknownProperty = shouldThrow;
|
|
8184
8118
|
}
|
|
8185
|
-
|
|
8186
8119
|
/**
|
|
8187
|
-
*
|
|
8188
|
-
* Copyright Google LLC All Rights Reserved.
|
|
8189
|
-
*
|
|
8190
|
-
* Use of this source code is governed by an MIT-style license that can be
|
|
8191
|
-
* found in the LICENSE file at https://angular.io/license
|
|
8120
|
+
* Gets the current value of the strict mode.
|
|
8192
8121
|
*/
|
|
8122
|
+
function ɵgetUnknownPropertyStrictMode() {
|
|
8123
|
+
return shouldThrowErrorOnUnknownProperty;
|
|
8124
|
+
}
|
|
8193
8125
|
/**
|
|
8194
|
-
*
|
|
8195
|
-
*
|
|
8196
|
-
* This
|
|
8197
|
-
*
|
|
8198
|
-
* value will be that of the newly created `LContext`.
|
|
8126
|
+
* Validates that the element is known at runtime and produces
|
|
8127
|
+
* an error if it's not the case.
|
|
8128
|
+
* This check is relevant for JIT-compiled components (for AOT-compiled
|
|
8129
|
+
* ones this check happens at build time).
|
|
8199
8130
|
*
|
|
8200
|
-
*
|
|
8201
|
-
*
|
|
8202
|
-
*
|
|
8203
|
-
*
|
|
8204
|
-
*
|
|
8205
|
-
* If the monkey-patch value is not detected then the code will walk up the DOM until an element
|
|
8206
|
-
* is found which contains a monkey-patch reference. When that occurs then the provided element
|
|
8207
|
-
* will be updated with a new context (which is then returned). If the monkey-patch value is not
|
|
8208
|
-
* detected for a component/directive instance then it will throw an error (all components and
|
|
8209
|
-
* directives should be automatically monkey-patched by ivy).
|
|
8131
|
+
* The element is considered known if either:
|
|
8132
|
+
* - it's a known HTML element
|
|
8133
|
+
* - it's a known custom element
|
|
8134
|
+
* - the element matches any directive
|
|
8135
|
+
* - the element is allowed by one of the schemas
|
|
8210
8136
|
*
|
|
8211
|
-
* @param
|
|
8137
|
+
* @param element Element to validate
|
|
8138
|
+
* @param lView An `LView` that represents a current component that is being rendered
|
|
8139
|
+
* @param tagName Name of the tag to check
|
|
8140
|
+
* @param schemas Array of schemas
|
|
8141
|
+
* @param hasDirectives Boolean indicating that the element matches any directive
|
|
8212
8142
|
*/
|
|
8213
|
-
function
|
|
8214
|
-
|
|
8215
|
-
|
|
8216
|
-
|
|
8217
|
-
|
|
8218
|
-
|
|
8219
|
-
|
|
8220
|
-
|
|
8221
|
-
|
|
8222
|
-
|
|
8223
|
-
|
|
8224
|
-
|
|
8225
|
-
|
|
8226
|
-
|
|
8227
|
-
|
|
8228
|
-
|
|
8229
|
-
|
|
8230
|
-
|
|
8231
|
-
|
|
8232
|
-
|
|
8233
|
-
|
|
8234
|
-
|
|
8235
|
-
|
|
8143
|
+
function validateElementIsKnown(element, lView, tagName, schemas, hasDirectives) {
|
|
8144
|
+
// If `schemas` is set to `null`, that's an indication that this Component was compiled in AOT
|
|
8145
|
+
// mode where this check happens at compile time. In JIT mode, `schemas` is always present and
|
|
8146
|
+
// defined as an array (as an empty array in case `schemas` field is not defined) and we should
|
|
8147
|
+
// execute the check below.
|
|
8148
|
+
if (schemas === null)
|
|
8149
|
+
return;
|
|
8150
|
+
// If the element matches any directive, it's considered as valid.
|
|
8151
|
+
if (!hasDirectives && tagName !== null) {
|
|
8152
|
+
// The element is unknown if it's an instance of HTMLUnknownElement, or it isn't registered
|
|
8153
|
+
// as a custom element. Note that unknown elements with a dash in their name won't be instances
|
|
8154
|
+
// of HTMLUnknownElement in browsers that support web components.
|
|
8155
|
+
const isUnknown =
|
|
8156
|
+
// Note that we can't check for `typeof HTMLUnknownElement === 'function'`,
|
|
8157
|
+
// because while most browsers return 'function', IE returns 'object'.
|
|
8158
|
+
(typeof HTMLUnknownElement !== 'undefined' && HTMLUnknownElement &&
|
|
8159
|
+
element instanceof HTMLUnknownElement) ||
|
|
8160
|
+
(typeof customElements !== 'undefined' && tagName.indexOf('-') > -1 &&
|
|
8161
|
+
!customElements.get(tagName));
|
|
8162
|
+
if (isUnknown && !matchingSchemas(schemas, tagName)) {
|
|
8163
|
+
const isHostStandalone = isHostComponentStandalone(lView);
|
|
8164
|
+
const templateLocation = getTemplateLocationDetails(lView);
|
|
8165
|
+
const schemas = `'${isHostStandalone ? '@Component' : '@NgModule'}.schemas'`;
|
|
8166
|
+
let message = `'${tagName}' is not a known element${templateLocation}:\n`;
|
|
8167
|
+
message += `1. If '${tagName}' is an Angular component, then verify that it is ${isHostStandalone ? 'included in the \'@Component.imports\' of this component' :
|
|
8168
|
+
'a part of an @NgModule where this component is declared'}.\n`;
|
|
8169
|
+
if (tagName && tagName.indexOf('-') > -1) {
|
|
8170
|
+
message +=
|
|
8171
|
+
`2. If '${tagName}' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the ${schemas} of this component to suppress this message.`;
|
|
8236
8172
|
}
|
|
8237
8173
|
else {
|
|
8238
|
-
|
|
8239
|
-
|
|
8240
|
-
return null;
|
|
8241
|
-
}
|
|
8242
|
-
}
|
|
8243
|
-
// the goal is not to fill the entire context full of data because the lookups
|
|
8244
|
-
// are expensive. Instead, only the target data (the element, component, container, ICU
|
|
8245
|
-
// expression or directive details) are filled into the context. If called multiple times
|
|
8246
|
-
// with different target values then the missing target data will be filled in.
|
|
8247
|
-
const native = unwrapRNode(lView[nodeIndex]);
|
|
8248
|
-
const existingCtx = readPatchedData(native);
|
|
8249
|
-
const context = (existingCtx && !Array.isArray(existingCtx)) ?
|
|
8250
|
-
existingCtx :
|
|
8251
|
-
createLContext(lView, nodeIndex, native);
|
|
8252
|
-
// only when the component has been discovered then update the monkey-patch
|
|
8253
|
-
if (component && context.component === undefined) {
|
|
8254
|
-
context.component = component;
|
|
8255
|
-
attachPatchData(context.component, context);
|
|
8174
|
+
message +=
|
|
8175
|
+
`2. To allow any element add 'NO_ERRORS_SCHEMA' to the ${schemas} of this component.`;
|
|
8256
8176
|
}
|
|
8257
|
-
|
|
8258
|
-
|
|
8259
|
-
context.directives = directives;
|
|
8260
|
-
for (let i = 0; i < directives.length; i++) {
|
|
8261
|
-
attachPatchData(directives[i], context);
|
|
8262
|
-
}
|
|
8177
|
+
if (shouldThrowErrorOnUnknownElement) {
|
|
8178
|
+
throw new RuntimeError(304 /* RuntimeErrorCode.UNKNOWN_ELEMENT */, message);
|
|
8263
8179
|
}
|
|
8264
|
-
|
|
8265
|
-
|
|
8266
|
-
}
|
|
8267
|
-
}
|
|
8268
|
-
else {
|
|
8269
|
-
const rElement = target;
|
|
8270
|
-
ngDevMode && assertDomNode(rElement);
|
|
8271
|
-
// if the context is not found then we need to traverse upwards up the DOM
|
|
8272
|
-
// to find the nearest element that has already been monkey patched with data
|
|
8273
|
-
let parent = rElement;
|
|
8274
|
-
while (parent = parent.parentNode) {
|
|
8275
|
-
const parentContext = readPatchedData(parent);
|
|
8276
|
-
if (parentContext) {
|
|
8277
|
-
const lView = Array.isArray(parentContext) ? parentContext : parentContext.lView;
|
|
8278
|
-
// the edge of the app was also reached here through another means
|
|
8279
|
-
// (maybe because the DOM was changed manually).
|
|
8280
|
-
if (!lView) {
|
|
8281
|
-
return null;
|
|
8282
|
-
}
|
|
8283
|
-
const index = findViaNativeElement(lView, rElement);
|
|
8284
|
-
if (index >= 0) {
|
|
8285
|
-
const native = unwrapRNode(lView[index]);
|
|
8286
|
-
const context = createLContext(lView, index, native);
|
|
8287
|
-
attachPatchData(native, context);
|
|
8288
|
-
mpValue = context;
|
|
8289
|
-
break;
|
|
8290
|
-
}
|
|
8180
|
+
else {
|
|
8181
|
+
console.error(formatRuntimeError(304 /* RuntimeErrorCode.UNKNOWN_ELEMENT */, message));
|
|
8291
8182
|
}
|
|
8292
8183
|
}
|
|
8293
8184
|
}
|
|
8294
|
-
return mpValue || null;
|
|
8295
8185
|
}
|
|
8296
8186
|
/**
|
|
8297
|
-
*
|
|
8187
|
+
* Validates that the property of the element is known at runtime and returns
|
|
8188
|
+
* false if it's not the case.
|
|
8189
|
+
* This check is relevant for JIT-compiled components (for AOT-compiled
|
|
8190
|
+
* ones this check happens at build time).
|
|
8191
|
+
*
|
|
8192
|
+
* The property is considered known if either:
|
|
8193
|
+
* - it's a known property of the element
|
|
8194
|
+
* - the element is allowed by one of the schemas
|
|
8195
|
+
* - the property is used for animations
|
|
8196
|
+
*
|
|
8197
|
+
* @param element Element to validate
|
|
8198
|
+
* @param propName Name of the property to check
|
|
8199
|
+
* @param tagName Name of the tag hosting the property
|
|
8200
|
+
* @param schemas Array of schemas
|
|
8298
8201
|
*/
|
|
8299
|
-
function
|
|
8300
|
-
|
|
8202
|
+
function isPropertyValid(element, propName, tagName, schemas) {
|
|
8203
|
+
// If `schemas` is set to `null`, that's an indication that this Component was compiled in AOT
|
|
8204
|
+
// mode where this check happens at compile time. In JIT mode, `schemas` is always present and
|
|
8205
|
+
// defined as an array (as an empty array in case `schemas` field is not defined) and we should
|
|
8206
|
+
// execute the check below.
|
|
8207
|
+
if (schemas === null)
|
|
8208
|
+
return true;
|
|
8209
|
+
// The property is considered valid if the element matches the schema, it exists on the element,
|
|
8210
|
+
// or it is synthetic, and we are in a browser context (web worker nodes should be skipped).
|
|
8211
|
+
if (matchingSchemas(schemas, tagName) || propName in element || isAnimationProp(propName)) {
|
|
8212
|
+
return true;
|
|
8213
|
+
}
|
|
8214
|
+
// Note: `typeof Node` returns 'function' in most browsers, but on IE it is 'object' so we
|
|
8215
|
+
// need to account for both here, while being careful with `typeof null` also returning 'object'.
|
|
8216
|
+
return typeof Node === 'undefined' || Node === null || !(element instanceof Node);
|
|
8301
8217
|
}
|
|
8302
8218
|
/**
|
|
8303
|
-
*
|
|
8219
|
+
* Logs or throws an error that a property is not supported on an element.
|
|
8304
8220
|
*
|
|
8305
|
-
* @param
|
|
8306
|
-
* @
|
|
8221
|
+
* @param propName Name of the invalid property
|
|
8222
|
+
* @param tagName Name of the tag hosting the property
|
|
8223
|
+
* @param nodeType Type of the node hosting the property
|
|
8224
|
+
* @param lView An `LView` that represents a current component
|
|
8307
8225
|
*/
|
|
8308
|
-
function
|
|
8309
|
-
|
|
8310
|
-
|
|
8311
|
-
|
|
8312
|
-
|
|
8313
|
-
|
|
8314
|
-
|
|
8315
|
-
|
|
8316
|
-
|
|
8317
|
-
|
|
8318
|
-
|
|
8226
|
+
function handleUnknownPropertyError(propName, tagName, nodeType, lView) {
|
|
8227
|
+
// Special-case a situation when a structural directive is applied to
|
|
8228
|
+
// an `<ng-template>` element, for example: `<ng-template *ngIf="true">`.
|
|
8229
|
+
// In this case the compiler generates the `ɵɵtemplate` instruction with
|
|
8230
|
+
// the `null` as the tagName. The directive matching logic at runtime relies
|
|
8231
|
+
// on this effect (see `isInlineTemplate`), thus using the 'ng-template' as
|
|
8232
|
+
// a default value of the `tNode.value` is not feasible at this moment.
|
|
8233
|
+
if (!tagName && nodeType === 4 /* TNodeType.Container */) {
|
|
8234
|
+
tagName = 'ng-template';
|
|
8235
|
+
}
|
|
8236
|
+
const isHostStandalone = isHostComponentStandalone(lView);
|
|
8237
|
+
const templateLocation = getTemplateLocationDetails(lView);
|
|
8238
|
+
let message = `Can't bind to '${propName}' since it isn't a known property of '${tagName}'${templateLocation}.`;
|
|
8239
|
+
const schemas = `'${isHostStandalone ? '@Component' : '@NgModule'}.schemas'`;
|
|
8240
|
+
const importLocation = isHostStandalone ?
|
|
8241
|
+
'included in the \'@Component.imports\' of this component' :
|
|
8242
|
+
'a part of an @NgModule where this component is declared';
|
|
8243
|
+
if (KNOWN_CONTROL_FLOW_DIRECTIVES.has(propName)) {
|
|
8244
|
+
// Most likely this is a control flow directive (such as `*ngIf`) used in
|
|
8245
|
+
// a template, but the directive or the `CommonModule` is not imported.
|
|
8246
|
+
const correspondingImport = KNOWN_CONTROL_FLOW_DIRECTIVES.get(propName);
|
|
8247
|
+
message += `\nIf the '${propName}' is an Angular control flow directive, ` +
|
|
8248
|
+
`please make sure that either the '${correspondingImport}' directive or the 'CommonModule' is ${importLocation}.`;
|
|
8319
8249
|
}
|
|
8320
8250
|
else {
|
|
8321
|
-
|
|
8322
|
-
|
|
8323
|
-
|
|
8324
|
-
|
|
8251
|
+
// May be an Angular component, which is not imported/declared?
|
|
8252
|
+
message += `\n1. If '${tagName}' is an Angular component and it has the ` +
|
|
8253
|
+
`'${propName}' input, then verify that it is ${importLocation}.`;
|
|
8254
|
+
// May be a Web Component?
|
|
8255
|
+
if (tagName && tagName.indexOf('-') > -1) {
|
|
8256
|
+
message += `\n2. If '${tagName}' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' ` +
|
|
8257
|
+
`to the ${schemas} of this component to suppress this message.`;
|
|
8258
|
+
message += `\n3. To allow any property add 'NO_ERRORS_SCHEMA' to ` +
|
|
8259
|
+
`the ${schemas} of this component.`;
|
|
8260
|
+
}
|
|
8261
|
+
else {
|
|
8262
|
+
// If it's expected, the error can be suppressed by the `NO_ERRORS_SCHEMA` schema.
|
|
8263
|
+
message += `\n2. To allow any property add 'NO_ERRORS_SCHEMA' to ` +
|
|
8264
|
+
`the ${schemas} of this component.`;
|
|
8265
|
+
}
|
|
8325
8266
|
}
|
|
8326
|
-
|
|
8267
|
+
reportUnknownPropertyError(message);
|
|
8327
8268
|
}
|
|
8328
|
-
|
|
8329
|
-
|
|
8330
|
-
|
|
8331
|
-
const MONKEY_PATCH_KEY_NAME = '__ngContext__';
|
|
8332
|
-
/**
|
|
8333
|
-
* Assigns the given data to the given target (which could be a component,
|
|
8334
|
-
* directive or DOM node instance) using monkey-patching.
|
|
8335
|
-
*/
|
|
8336
|
-
function attachPatchData(target, data) {
|
|
8337
|
-
ngDevMode && assertDefined(target, 'Target expected');
|
|
8338
|
-
// Only attach the ID of the view in order to avoid memory leaks (see #41047). We only do this
|
|
8339
|
-
// for `LView`, because we have control over when an `LView` is created and destroyed, whereas
|
|
8340
|
-
// we can't know when to remove an `LContext`.
|
|
8341
|
-
if (isLView(data)) {
|
|
8342
|
-
target[MONKEY_PATCH_KEY_NAME] = data[ID];
|
|
8343
|
-
registerLView(data);
|
|
8269
|
+
function reportUnknownPropertyError(message) {
|
|
8270
|
+
if (shouldThrowErrorOnUnknownProperty) {
|
|
8271
|
+
throw new RuntimeError(303 /* RuntimeErrorCode.UNKNOWN_BINDING */, message);
|
|
8344
8272
|
}
|
|
8345
8273
|
else {
|
|
8346
|
-
|
|
8274
|
+
console.error(formatRuntimeError(303 /* RuntimeErrorCode.UNKNOWN_BINDING */, message));
|
|
8347
8275
|
}
|
|
8348
8276
|
}
|
|
8349
8277
|
/**
|
|
8350
|
-
*
|
|
8351
|
-
*
|
|
8278
|
+
* WARNING: this is a **dev-mode only** function (thus should always be guarded by the `ngDevMode`)
|
|
8279
|
+
* and must **not** be used in production bundles. The function makes megamorphic reads, which might
|
|
8280
|
+
* be too slow for production mode and also it relies on the constructor function being available.
|
|
8281
|
+
*
|
|
8282
|
+
* Gets a reference to the host component def (where a current component is declared).
|
|
8283
|
+
*
|
|
8284
|
+
* @param lView An `LView` that represents a current component that is being rendered.
|
|
8352
8285
|
*/
|
|
8353
|
-
function
|
|
8354
|
-
ngDevMode &&
|
|
8355
|
-
const
|
|
8356
|
-
|
|
8357
|
-
|
|
8358
|
-
|
|
8359
|
-
|
|
8360
|
-
|
|
8361
|
-
return (isLView(value) ? value : value.lView);
|
|
8362
|
-
}
|
|
8363
|
-
return null;
|
|
8286
|
+
function getDeclarationComponentDef(lView) {
|
|
8287
|
+
!ngDevMode && throwError('Must never be called in production mode');
|
|
8288
|
+
const declarationLView = lView[DECLARATION_COMPONENT_VIEW];
|
|
8289
|
+
const context = declarationLView[CONTEXT];
|
|
8290
|
+
// Unable to obtain a context.
|
|
8291
|
+
if (!context)
|
|
8292
|
+
return null;
|
|
8293
|
+
return context.constructor ? getComponentDef$1(context.constructor) : null;
|
|
8364
8294
|
}
|
|
8365
|
-
|
|
8366
|
-
|
|
8295
|
+
/**
|
|
8296
|
+
* WARNING: this is a **dev-mode only** function (thus should always be guarded by the `ngDevMode`)
|
|
8297
|
+
* and must **not** be used in production bundles. The function makes megamorphic reads, which might
|
|
8298
|
+
* be too slow for production mode.
|
|
8299
|
+
*
|
|
8300
|
+
* Checks if the current component is declared inside of a standalone component template.
|
|
8301
|
+
*
|
|
8302
|
+
* @param lView An `LView` that represents a current component that is being rendered.
|
|
8303
|
+
*/
|
|
8304
|
+
function isHostComponentStandalone(lView) {
|
|
8305
|
+
!ngDevMode && throwError('Must never be called in production mode');
|
|
8306
|
+
const componentDef = getDeclarationComponentDef(lView);
|
|
8307
|
+
// Treat host component as non-standalone if we can't obtain the def.
|
|
8308
|
+
return !!(componentDef === null || componentDef === void 0 ? void 0 : componentDef.standalone);
|
|
8367
8309
|
}
|
|
8368
|
-
|
|
8369
|
-
|
|
8310
|
+
/**
|
|
8311
|
+
* WARNING: this is a **dev-mode only** function (thus should always be guarded by the `ngDevMode`)
|
|
8312
|
+
* and must **not** be used in production bundles. The function makes megamorphic reads, which might
|
|
8313
|
+
* be too slow for production mode.
|
|
8314
|
+
*
|
|
8315
|
+
* Constructs a string describing the location of the host component template. The function is used
|
|
8316
|
+
* in dev mode to produce error messages.
|
|
8317
|
+
*
|
|
8318
|
+
* @param lView An `LView` that represents a current component that is being rendered.
|
|
8319
|
+
*/
|
|
8320
|
+
function getTemplateLocationDetails(lView) {
|
|
8321
|
+
var _a;
|
|
8322
|
+
!ngDevMode && throwError('Must never be called in production mode');
|
|
8323
|
+
const hostComponentDef = getDeclarationComponentDef(lView);
|
|
8324
|
+
const componentClassName = (_a = hostComponentDef === null || hostComponentDef === void 0 ? void 0 : hostComponentDef.type) === null || _a === void 0 ? void 0 : _a.name;
|
|
8325
|
+
return componentClassName ? ` (used in the '${componentClassName}' component template)` : '';
|
|
8370
8326
|
}
|
|
8371
8327
|
/**
|
|
8372
|
-
*
|
|
8328
|
+
* The set of known control flow directives and their corresponding imports.
|
|
8329
|
+
* We use this set to produce a more precises error message with a note
|
|
8330
|
+
* that the `CommonModule` should also be included.
|
|
8373
8331
|
*/
|
|
8374
|
-
|
|
8375
|
-
|
|
8376
|
-
|
|
8377
|
-
|
|
8378
|
-
|
|
8332
|
+
const KNOWN_CONTROL_FLOW_DIRECTIVES = new Map([
|
|
8333
|
+
['ngIf', 'NgIf'], ['ngFor', 'NgFor'], ['ngSwitchCase', 'NgSwitchCase'],
|
|
8334
|
+
['ngSwitchDefault', 'NgSwitchDefault']
|
|
8335
|
+
]);
|
|
8336
|
+
/**
|
|
8337
|
+
* Returns true if the tag name is allowed by specified schemas.
|
|
8338
|
+
* @param schemas Array of schemas
|
|
8339
|
+
* @param tagName Name of the tag
|
|
8340
|
+
*/
|
|
8341
|
+
function matchingSchemas(schemas, tagName) {
|
|
8342
|
+
if (schemas !== null) {
|
|
8343
|
+
for (let i = 0; i < schemas.length; i++) {
|
|
8344
|
+
const schema = schemas[i];
|
|
8345
|
+
if (schema === NO_ERRORS_SCHEMA ||
|
|
8346
|
+
schema === CUSTOM_ELEMENTS_SCHEMA && tagName && tagName.indexOf('-') > -1) {
|
|
8347
|
+
return true;
|
|
8348
|
+
}
|
|
8379
8349
|
}
|
|
8380
8350
|
}
|
|
8381
|
-
return
|
|
8351
|
+
return false;
|
|
8382
8352
|
}
|
|
8353
|
+
|
|
8383
8354
|
/**
|
|
8384
|
-
*
|
|
8355
|
+
* @license
|
|
8356
|
+
* Copyright Google LLC All Rights Reserved.
|
|
8357
|
+
*
|
|
8358
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
8359
|
+
* found in the LICENSE file at https://angular.io/license
|
|
8385
8360
|
*/
|
|
8386
|
-
|
|
8387
|
-
|
|
8388
|
-
|
|
8389
|
-
|
|
8390
|
-
|
|
8391
|
-
|
|
8392
|
-
|
|
8393
|
-
|
|
8394
|
-
|
|
8395
|
-
// After checking the text node, we need to find the next parent that has a "next" TNode,
|
|
8396
|
-
// in this case the parent `div`, so that we can find the component.
|
|
8397
|
-
while (tNode.parent && !tNode.parent.next) {
|
|
8398
|
-
tNode = tNode.parent;
|
|
8399
|
-
}
|
|
8400
|
-
return tNode.parent && tNode.parent.next;
|
|
8401
|
-
}
|
|
8361
|
+
const ERROR_ORIGINAL_ERROR = 'ngOriginalError';
|
|
8362
|
+
function wrappedError(message, originalError) {
|
|
8363
|
+
const msg = `${message} caused by: ${originalError instanceof Error ? originalError.message : originalError}`;
|
|
8364
|
+
const error = Error(msg);
|
|
8365
|
+
error[ERROR_ORIGINAL_ERROR] = originalError;
|
|
8366
|
+
return error;
|
|
8367
|
+
}
|
|
8368
|
+
function getOriginalError(error) {
|
|
8369
|
+
return error[ERROR_ORIGINAL_ERROR];
|
|
8402
8370
|
}
|
|
8371
|
+
|
|
8403
8372
|
/**
|
|
8404
|
-
*
|
|
8373
|
+
* @license
|
|
8374
|
+
* Copyright Google LLC All Rights Reserved.
|
|
8375
|
+
*
|
|
8376
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
8377
|
+
* found in the LICENSE file at https://angular.io/license
|
|
8405
8378
|
*/
|
|
8406
|
-
|
|
8407
|
-
|
|
8408
|
-
|
|
8409
|
-
|
|
8410
|
-
|
|
8411
|
-
|
|
8412
|
-
|
|
8413
|
-
|
|
8414
|
-
|
|
8379
|
+
/**
|
|
8380
|
+
* Provides a hook for centralized exception handling.
|
|
8381
|
+
*
|
|
8382
|
+
* The default implementation of `ErrorHandler` prints error messages to the `console`. To
|
|
8383
|
+
* intercept error handling, write a custom exception handler that replaces this default as
|
|
8384
|
+
* appropriate for your app.
|
|
8385
|
+
*
|
|
8386
|
+
* @usageNotes
|
|
8387
|
+
* ### Example
|
|
8388
|
+
*
|
|
8389
|
+
* ```
|
|
8390
|
+
* class MyErrorHandler implements ErrorHandler {
|
|
8391
|
+
* handleError(error) {
|
|
8392
|
+
* // do something with the exception
|
|
8393
|
+
* }
|
|
8394
|
+
* }
|
|
8395
|
+
*
|
|
8396
|
+
* @NgModule({
|
|
8397
|
+
* providers: [{provide: ErrorHandler, useClass: MyErrorHandler}]
|
|
8398
|
+
* })
|
|
8399
|
+
* class MyModule {}
|
|
8400
|
+
* ```
|
|
8401
|
+
*
|
|
8402
|
+
* @publicApi
|
|
8403
|
+
*/
|
|
8404
|
+
class ErrorHandler {
|
|
8405
|
+
constructor() {
|
|
8406
|
+
/**
|
|
8407
|
+
* @internal
|
|
8408
|
+
*/
|
|
8409
|
+
this._console = console;
|
|
8410
|
+
}
|
|
8411
|
+
handleError(error) {
|
|
8412
|
+
const originalError = this._findOriginalError(error);
|
|
8413
|
+
this._console.error('ERROR', error);
|
|
8414
|
+
if (originalError) {
|
|
8415
|
+
this._console.error('ORIGINAL ERROR', originalError);
|
|
8415
8416
|
}
|
|
8416
8417
|
}
|
|
8417
|
-
|
|
8418
|
-
|
|
8419
|
-
|
|
8420
|
-
|
|
8421
|
-
|
|
8422
|
-
// element is the very first element after the HEADER data in the lView
|
|
8423
|
-
return HEADER_OFFSET;
|
|
8418
|
+
/** @internal */
|
|
8419
|
+
_findOriginalError(error) {
|
|
8420
|
+
let e = error && getOriginalError(error);
|
|
8421
|
+
while (e && getOriginalError(e)) {
|
|
8422
|
+
e = getOriginalError(e);
|
|
8424
8423
|
}
|
|
8424
|
+
return e || null;
|
|
8425
8425
|
}
|
|
8426
|
-
return -1;
|
|
8427
8426
|
}
|
|
8427
|
+
|
|
8428
8428
|
/**
|
|
8429
|
-
*
|
|
8429
|
+
* @license
|
|
8430
|
+
* Copyright Google LLC All Rights Reserved.
|
|
8431
|
+
*
|
|
8432
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
8433
|
+
* found in the LICENSE file at https://angular.io/license
|
|
8430
8434
|
*/
|
|
8431
|
-
function findViaDirective(lView, directiveInstance) {
|
|
8432
|
-
// if a directive is monkey patched then it will (by default)
|
|
8433
|
-
// have a reference to the LView of the current view. The
|
|
8434
|
-
// element bound to the directive being search lives somewhere
|
|
8435
|
-
// in the view data. We loop through the nodes and check their
|
|
8436
|
-
// list of directives for the instance.
|
|
8437
|
-
let tNode = lView[TVIEW].firstChild;
|
|
8438
|
-
while (tNode) {
|
|
8439
|
-
const directiveIndexStart = tNode.directiveStart;
|
|
8440
|
-
const directiveIndexEnd = tNode.directiveEnd;
|
|
8441
|
-
for (let i = directiveIndexStart; i < directiveIndexEnd; i++) {
|
|
8442
|
-
if (lView[i] === directiveInstance) {
|
|
8443
|
-
return tNode.index;
|
|
8444
|
-
}
|
|
8445
|
-
}
|
|
8446
|
-
tNode = traverseNextElement(tNode);
|
|
8447
|
-
}
|
|
8448
|
-
return -1;
|
|
8449
|
-
}
|
|
8450
8435
|
/**
|
|
8451
|
-
*
|
|
8452
|
-
* provided list of directive index values.
|
|
8436
|
+
* Disallowed strings in the comment.
|
|
8453
8437
|
*
|
|
8454
|
-
*
|
|
8455
|
-
* @param lView The target view data
|
|
8456
|
-
* @param includeComponents Whether or not to include components in returned directives
|
|
8438
|
+
* see: https://html.spec.whatwg.org/multipage/syntax.html#comments
|
|
8457
8439
|
*/
|
|
8458
|
-
|
|
8459
|
-
|
|
8460
|
-
|
|
8461
|
-
|
|
8462
|
-
|
|
8463
|
-
|
|
8464
|
-
|
|
8465
|
-
|
|
8466
|
-
|
|
8467
|
-
|
|
8468
|
-
|
|
8469
|
-
|
|
8470
|
-
|
|
8471
|
-
|
|
8472
|
-
|
|
8473
|
-
|
|
8474
|
-
|
|
8440
|
+
const COMMENT_DISALLOWED = /^>|^->|<!--|-->|--!>|<!-$/g;
|
|
8441
|
+
/**
|
|
8442
|
+
* Delimiter in the disallowed strings which needs to be wrapped with zero with character.
|
|
8443
|
+
*/
|
|
8444
|
+
const COMMENT_DELIMITER = /(<|>)/;
|
|
8445
|
+
const COMMENT_DELIMITER_ESCAPED = '\u200B$1\u200B';
|
|
8446
|
+
/**
|
|
8447
|
+
* Escape the content of comment strings so that it can be safely inserted into a comment node.
|
|
8448
|
+
*
|
|
8449
|
+
* The issue is that HTML does not specify any way to escape comment end text inside the comment.
|
|
8450
|
+
* Consider: `<!-- The way you close a comment is with ">", and "->" at the beginning or by "-->" or
|
|
8451
|
+
* "--!>" at the end. -->`. Above the `"-->"` is meant to be text not an end to the comment. This
|
|
8452
|
+
* can be created programmatically through DOM APIs. (`<!--` are also disallowed.)
|
|
8453
|
+
*
|
|
8454
|
+
* see: https://html.spec.whatwg.org/multipage/syntax.html#comments
|
|
8455
|
+
*
|
|
8456
|
+
* ```
|
|
8457
|
+
* div.innerHTML = div.innerHTML
|
|
8458
|
+
* ```
|
|
8459
|
+
*
|
|
8460
|
+
* One would expect that the above code would be safe to do, but it turns out that because comment
|
|
8461
|
+
* text is not escaped, the comment may contain text which will prematurely close the comment
|
|
8462
|
+
* opening up the application for XSS attack. (In SSR we programmatically create comment nodes which
|
|
8463
|
+
* may contain such text and expect them to be safe.)
|
|
8464
|
+
*
|
|
8465
|
+
* This function escapes the comment text by looking for comment delimiters (`<` and `>`) and
|
|
8466
|
+
* surrounding them with `_>_` where the `_` is a zero width space `\u200B`. The result is that if a
|
|
8467
|
+
* comment contains any of the comment start/end delimiters (such as `<!--`, `-->` or `--!>`) the
|
|
8468
|
+
* text it will render normally but it will not cause the HTML parser to close/open the comment.
|
|
8469
|
+
*
|
|
8470
|
+
* @param value text to make safe for comment node by escaping the comment open/close character
|
|
8471
|
+
* sequence.
|
|
8472
|
+
*/
|
|
8473
|
+
function escapeCommentText(value) {
|
|
8474
|
+
return value.replace(COMMENT_DISALLOWED, (text) => text.replace(COMMENT_DELIMITER, COMMENT_DELIMITER_ESCAPED));
|
|
8475
8475
|
}
|
|
8476
|
+
|
|
8476
8477
|
/**
|
|
8477
|
-
*
|
|
8478
|
-
*
|
|
8478
|
+
* @license
|
|
8479
|
+
* Copyright Google LLC All Rights Reserved.
|
|
8480
|
+
*
|
|
8481
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
8482
|
+
* found in the LICENSE file at https://angular.io/license
|
|
8479
8483
|
*/
|
|
8480
|
-
function
|
|
8481
|
-
|
|
8482
|
-
|
|
8483
|
-
|
|
8484
|
-
|
|
8485
|
-
|
|
8486
|
-
|
|
8487
|
-
|
|
8488
|
-
|
|
8489
|
-
|
|
8484
|
+
function normalizeDebugBindingName(name) {
|
|
8485
|
+
// Attribute names with `$` (eg `x-y$`) are valid per spec, but unsupported by some browsers
|
|
8486
|
+
name = camelCaseToDashCase(name.replace(/[$@]/g, '_'));
|
|
8487
|
+
return `ng-reflect-${name}`;
|
|
8488
|
+
}
|
|
8489
|
+
const CAMEL_CASE_REGEXP = /([A-Z])/g;
|
|
8490
|
+
function camelCaseToDashCase(input) {
|
|
8491
|
+
return input.replace(CAMEL_CASE_REGEXP, (...m) => '-' + m[1].toLowerCase());
|
|
8492
|
+
}
|
|
8493
|
+
function normalizeDebugBindingValue(value) {
|
|
8494
|
+
try {
|
|
8495
|
+
// Limit the size of the value as otherwise the DOM just gets polluted.
|
|
8496
|
+
return value != null ? value.toString().slice(0, 30) : value;
|
|
8497
|
+
}
|
|
8498
|
+
catch (e) {
|
|
8499
|
+
return '[ERROR] Exception while trying to serialize the value';
|
|
8490
8500
|
}
|
|
8491
|
-
return null;
|
|
8492
8501
|
}
|
|
8493
8502
|
|
|
8494
8503
|
/**
|
|
@@ -9652,6 +9661,19 @@ function writeDirectClass(renderer, element, newValue) {
|
|
|
9652
9661
|
}
|
|
9653
9662
|
ngDevMode && ngDevMode.rendererSetClassName++;
|
|
9654
9663
|
}
|
|
9664
|
+
/** Sets up the static DOM attributes on an `RNode`. */
|
|
9665
|
+
function setupStaticAttributes(renderer, element, tNode) {
|
|
9666
|
+
const { mergedAttrs, classes, styles } = tNode;
|
|
9667
|
+
if (mergedAttrs !== null) {
|
|
9668
|
+
setUpAttributes(renderer, element, mergedAttrs);
|
|
9669
|
+
}
|
|
9670
|
+
if (classes !== null) {
|
|
9671
|
+
writeDirectClass(renderer, element, classes);
|
|
9672
|
+
}
|
|
9673
|
+
if (styles !== null) {
|
|
9674
|
+
writeDirectStyle(renderer, element, styles);
|
|
9675
|
+
}
|
|
9676
|
+
}
|
|
9655
9677
|
|
|
9656
9678
|
/**
|
|
9657
9679
|
* @license
|
|
@@ -12594,9 +12616,6 @@ function createViewBlueprint(bindingStartIndex, initialViewLength) {
|
|
|
12594
12616
|
}
|
|
12595
12617
|
return blueprint;
|
|
12596
12618
|
}
|
|
12597
|
-
function createError(text, token) {
|
|
12598
|
-
return new Error(`Renderer: ${text} [${stringifyForError(token)}]`);
|
|
12599
|
-
}
|
|
12600
12619
|
/**
|
|
12601
12620
|
* Locates the host native element, used for bootstrapping existing nodes into rendering pipeline.
|
|
12602
12621
|
*
|
|
@@ -12720,26 +12739,49 @@ function createTNode(tView, tParent, type, index, value, attrs) {
|
|
|
12720
12739
|
}
|
|
12721
12740
|
return tNode;
|
|
12722
12741
|
}
|
|
12723
|
-
|
|
12724
|
-
|
|
12725
|
-
|
|
12726
|
-
|
|
12727
|
-
|
|
12728
|
-
|
|
12729
|
-
|
|
12742
|
+
/**
|
|
12743
|
+
* Generates the `PropertyAliases` data structure from the provided input/output mapping.
|
|
12744
|
+
* @param aliasMap Input/output mapping from the directive definition.
|
|
12745
|
+
* @param directiveIndex Index of the directive.
|
|
12746
|
+
* @param propertyAliases Object in which to store the results.
|
|
12747
|
+
* @param hostDirectiveAliasMap Object used to alias or filter out properties for host directives.
|
|
12748
|
+
* If the mapping is provided, it'll act as an allowlist, as well as a mapping of what public
|
|
12749
|
+
* name inputs/outputs should be exposed under.
|
|
12750
|
+
*/
|
|
12751
|
+
function generatePropertyAliases(aliasMap, directiveIndex, propertyAliases, hostDirectiveAliasMap) {
|
|
12752
|
+
for (let publicName in aliasMap) {
|
|
12753
|
+
if (aliasMap.hasOwnProperty(publicName)) {
|
|
12754
|
+
propertyAliases = propertyAliases === null ? {} : propertyAliases;
|
|
12755
|
+
const internalName = aliasMap[publicName];
|
|
12756
|
+
// If there are no host directive mappings, we want to remap using the alias map from the
|
|
12757
|
+
// definition itself. If there is an alias map, it has two functions:
|
|
12758
|
+
// 1. It serves as an allowlist of bindings that are exposed by the host directives. Only the
|
|
12759
|
+
// ones inside the host directive map will be exposed on the host.
|
|
12760
|
+
// 2. The public name of the property is aliased using the host directive alias map, rather
|
|
12761
|
+
// than the alias map from the definition.
|
|
12762
|
+
if (hostDirectiveAliasMap === null) {
|
|
12763
|
+
addPropertyAlias(propertyAliases, directiveIndex, publicName, internalName);
|
|
12730
12764
|
}
|
|
12731
|
-
else {
|
|
12732
|
-
(
|
|
12765
|
+
else if (hostDirectiveAliasMap.hasOwnProperty(publicName)) {
|
|
12766
|
+
addPropertyAlias(propertyAliases, directiveIndex, hostDirectiveAliasMap[publicName], internalName);
|
|
12733
12767
|
}
|
|
12734
12768
|
}
|
|
12735
12769
|
}
|
|
12736
|
-
return
|
|
12770
|
+
return propertyAliases;
|
|
12771
|
+
}
|
|
12772
|
+
function addPropertyAlias(propertyAliases, directiveIndex, publicName, internalName) {
|
|
12773
|
+
if (propertyAliases.hasOwnProperty(publicName)) {
|
|
12774
|
+
propertyAliases[publicName].push(directiveIndex, internalName);
|
|
12775
|
+
}
|
|
12776
|
+
else {
|
|
12777
|
+
propertyAliases[publicName] = [directiveIndex, internalName];
|
|
12778
|
+
}
|
|
12737
12779
|
}
|
|
12738
12780
|
/**
|
|
12739
12781
|
* Initializes data structures required to work with directive inputs and outputs.
|
|
12740
12782
|
* Initialization is done for all directives matched on a given TNode.
|
|
12741
12783
|
*/
|
|
12742
|
-
function initializeInputAndOutputAliases(tView, tNode) {
|
|
12784
|
+
function initializeInputAndOutputAliases(tView, tNode, hostDirectiveDefinitionMap) {
|
|
12743
12785
|
ngDevMode && assertFirstCreatePass(tView);
|
|
12744
12786
|
const start = tNode.directiveStart;
|
|
12745
12787
|
const end = tNode.directiveEnd;
|
|
@@ -12748,16 +12790,21 @@ function initializeInputAndOutputAliases(tView, tNode) {
|
|
|
12748
12790
|
const inputsFromAttrs = ngDevMode ? new TNodeInitialInputs() : [];
|
|
12749
12791
|
let inputsStore = null;
|
|
12750
12792
|
let outputsStore = null;
|
|
12751
|
-
for (let
|
|
12752
|
-
const directiveDef = tViewData[
|
|
12753
|
-
|
|
12754
|
-
|
|
12793
|
+
for (let directiveIndex = start; directiveIndex < end; directiveIndex++) {
|
|
12794
|
+
const directiveDef = tViewData[directiveIndex];
|
|
12795
|
+
const aliasData = hostDirectiveDefinitionMap ? hostDirectiveDefinitionMap.get(directiveDef) : null;
|
|
12796
|
+
const aliasedInputs = aliasData ? aliasData.inputs : null;
|
|
12797
|
+
const aliasedOutputs = aliasData ? aliasData.outputs : null;
|
|
12798
|
+
inputsStore =
|
|
12799
|
+
generatePropertyAliases(directiveDef.inputs, directiveIndex, inputsStore, aliasedInputs);
|
|
12800
|
+
outputsStore =
|
|
12801
|
+
generatePropertyAliases(directiveDef.outputs, directiveIndex, outputsStore, aliasedOutputs);
|
|
12755
12802
|
// Do not use unbound attributes as inputs to structural directives, since structural
|
|
12756
12803
|
// directive inputs can only be set using microsyntax (e.g. `<div *dir="exp">`).
|
|
12757
12804
|
// TODO(FW-1930): microsyntax expressions may also contain unbound/static attributes, which
|
|
12758
12805
|
// should be set for inline templates.
|
|
12759
12806
|
const initialInputs = (inputsStore !== null && tNodeAttrs !== null && !isInlineTemplate(tNode)) ?
|
|
12760
|
-
generateInitialInputs(inputsStore,
|
|
12807
|
+
generateInitialInputs(inputsStore, directiveIndex, tNodeAttrs) :
|
|
12761
12808
|
null;
|
|
12762
12809
|
inputsFromAttrs.push(initialInputs);
|
|
12763
12810
|
}
|
|
@@ -12873,28 +12920,6 @@ function setNgReflectProperties(lView, element, type, dataValue, value) {
|
|
|
12873
12920
|
}
|
|
12874
12921
|
}
|
|
12875
12922
|
}
|
|
12876
|
-
/**
|
|
12877
|
-
* Instantiate a root component.
|
|
12878
|
-
*/
|
|
12879
|
-
function instantiateRootComponent(tView, lView, def) {
|
|
12880
|
-
const rootTNode = getCurrentTNode();
|
|
12881
|
-
if (tView.firstCreatePass) {
|
|
12882
|
-
if (def.providersResolver)
|
|
12883
|
-
def.providersResolver(def);
|
|
12884
|
-
const directiveIndex = allocExpando(tView, lView, 1, null);
|
|
12885
|
-
ngDevMode &&
|
|
12886
|
-
assertEqual(directiveIndex, rootTNode.directiveStart, 'Because this is a root component the allocated expando should match the TNode component.');
|
|
12887
|
-
configureViewWithDirective(tView, rootTNode, lView, directiveIndex, def);
|
|
12888
|
-
initializeInputAndOutputAliases(tView, rootTNode);
|
|
12889
|
-
}
|
|
12890
|
-
const directive = getNodeInjectable(lView, tView, rootTNode.directiveStart + rootTNode.componentOffset, rootTNode);
|
|
12891
|
-
attachPatchData(directive, lView);
|
|
12892
|
-
const native = getNativeByTNode(rootTNode, lView);
|
|
12893
|
-
if (native) {
|
|
12894
|
-
attachPatchData(native, lView);
|
|
12895
|
-
}
|
|
12896
|
-
return directive;
|
|
12897
|
-
}
|
|
12898
12923
|
/**
|
|
12899
12924
|
* Resolve the matched directives on a node.
|
|
12900
12925
|
*/
|
|
@@ -12904,59 +12929,19 @@ function resolveDirectives(tView, lView, tNode, localRefs) {
|
|
|
12904
12929
|
ngDevMode && assertFirstCreatePass(tView);
|
|
12905
12930
|
let hasDirectives = false;
|
|
12906
12931
|
if (getBindingsEnabled()) {
|
|
12907
|
-
const directiveDefsMatchedBySelectors = findDirectiveDefMatches(tView, lView, tNode);
|
|
12908
|
-
const directiveDefs = directiveDefsMatchedBySelectors ?
|
|
12909
|
-
findHostDirectiveDefs$1(directiveDefsMatchedBySelectors, tView, lView, tNode) :
|
|
12910
|
-
null;
|
|
12911
12932
|
const exportsMap = localRefs === null ? null : { '': -1 };
|
|
12933
|
+
const matchResult = findDirectiveDefMatches(tView, tNode);
|
|
12934
|
+
let directiveDefs;
|
|
12935
|
+
let hostDirectiveDefs;
|
|
12936
|
+
if (matchResult === null) {
|
|
12937
|
+
directiveDefs = hostDirectiveDefs = null;
|
|
12938
|
+
}
|
|
12939
|
+
else {
|
|
12940
|
+
[directiveDefs, hostDirectiveDefs] = matchResult;
|
|
12941
|
+
}
|
|
12912
12942
|
if (directiveDefs !== null) {
|
|
12913
12943
|
hasDirectives = true;
|
|
12914
|
-
|
|
12915
|
-
// When the same token is provided by several directives on the same node, some rules apply in
|
|
12916
|
-
// the viewEngine:
|
|
12917
|
-
// - viewProviders have priority over providers
|
|
12918
|
-
// - the last directive in NgModule.declarations has priority over the previous one
|
|
12919
|
-
// So to match these rules, the order in which providers are added in the arrays is very
|
|
12920
|
-
// important.
|
|
12921
|
-
for (let i = 0; i < directiveDefs.length; i++) {
|
|
12922
|
-
const def = directiveDefs[i];
|
|
12923
|
-
if (def.providersResolver)
|
|
12924
|
-
def.providersResolver(def);
|
|
12925
|
-
}
|
|
12926
|
-
let preOrderHooksFound = false;
|
|
12927
|
-
let preOrderCheckHooksFound = false;
|
|
12928
|
-
let directiveIdx = allocExpando(tView, lView, directiveDefs.length, null);
|
|
12929
|
-
ngDevMode &&
|
|
12930
|
-
assertSame(directiveIdx, tNode.directiveStart, 'TNode.directiveStart should point to just allocated space');
|
|
12931
|
-
for (let i = 0; i < directiveDefs.length; i++) {
|
|
12932
|
-
const def = directiveDefs[i];
|
|
12933
|
-
// Merge the attrs in the order of matches. This assumes that the first directive is the
|
|
12934
|
-
// component itself, so that the component has the least priority.
|
|
12935
|
-
tNode.mergedAttrs = mergeHostAttrs(tNode.mergedAttrs, def.hostAttrs);
|
|
12936
|
-
configureViewWithDirective(tView, tNode, lView, directiveIdx, def);
|
|
12937
|
-
saveNameToExportMap(directiveIdx, def, exportsMap);
|
|
12938
|
-
if (def.contentQueries !== null)
|
|
12939
|
-
tNode.flags |= 4 /* TNodeFlags.hasContentQuery */;
|
|
12940
|
-
if (def.hostBindings !== null || def.hostAttrs !== null || def.hostVars !== 0)
|
|
12941
|
-
tNode.flags |= 64 /* TNodeFlags.hasHostBindings */;
|
|
12942
|
-
const lifeCycleHooks = def.type.prototype;
|
|
12943
|
-
// Only push a node index into the preOrderHooks array if this is the first
|
|
12944
|
-
// pre-order hook found on this node.
|
|
12945
|
-
if (!preOrderHooksFound &&
|
|
12946
|
-
(lifeCycleHooks.ngOnChanges || lifeCycleHooks.ngOnInit || lifeCycleHooks.ngDoCheck)) {
|
|
12947
|
-
// We will push the actual hook function into this array later during dir instantiation.
|
|
12948
|
-
// We cannot do it now because we must ensure hooks are registered in the same
|
|
12949
|
-
// order that directives are created (i.e. injection order).
|
|
12950
|
-
(tView.preOrderHooks || (tView.preOrderHooks = [])).push(tNode.index);
|
|
12951
|
-
preOrderHooksFound = true;
|
|
12952
|
-
}
|
|
12953
|
-
if (!preOrderCheckHooksFound && (lifeCycleHooks.ngOnChanges || lifeCycleHooks.ngDoCheck)) {
|
|
12954
|
-
(tView.preOrderCheckHooks || (tView.preOrderCheckHooks = [])).push(tNode.index);
|
|
12955
|
-
preOrderCheckHooksFound = true;
|
|
12956
|
-
}
|
|
12957
|
-
directiveIdx++;
|
|
12958
|
-
}
|
|
12959
|
-
initializeInputAndOutputAliases(tView, tNode);
|
|
12944
|
+
initializeDirectives(tView, lView, tNode, directiveDefs, exportsMap, hostDirectiveDefs);
|
|
12960
12945
|
}
|
|
12961
12946
|
if (exportsMap)
|
|
12962
12947
|
cacheMatchingLocalNames(tNode, localRefs, exportsMap);
|
|
@@ -12965,17 +12950,71 @@ function resolveDirectives(tView, lView, tNode, localRefs) {
|
|
|
12965
12950
|
tNode.mergedAttrs = mergeHostAttrs(tNode.mergedAttrs, tNode.attrs);
|
|
12966
12951
|
return hasDirectives;
|
|
12967
12952
|
}
|
|
12953
|
+
/** Initializes the data structures necessary for a list of directives to be instantiated. */
|
|
12954
|
+
function initializeDirectives(tView, lView, tNode, directives, exportsMap, hostDirectiveDefs) {
|
|
12955
|
+
ngDevMode && assertFirstCreatePass(tView);
|
|
12956
|
+
// Publishes the directive types to DI so they can be injected. Needs to
|
|
12957
|
+
// happen in a separate pass before the TNode flags have been initialized.
|
|
12958
|
+
for (let i = 0; i < directives.length; i++) {
|
|
12959
|
+
diPublicInInjector(getOrCreateNodeInjectorForNode(tNode, lView), tView, directives[i].type);
|
|
12960
|
+
}
|
|
12961
|
+
initTNodeFlags(tNode, tView.data.length, directives.length);
|
|
12962
|
+
// When the same token is provided by several directives on the same node, some rules apply in
|
|
12963
|
+
// the viewEngine:
|
|
12964
|
+
// - viewProviders have priority over providers
|
|
12965
|
+
// - the last directive in NgModule.declarations has priority over the previous one
|
|
12966
|
+
// So to match these rules, the order in which providers are added in the arrays is very
|
|
12967
|
+
// important.
|
|
12968
|
+
for (let i = 0; i < directives.length; i++) {
|
|
12969
|
+
const def = directives[i];
|
|
12970
|
+
if (def.providersResolver)
|
|
12971
|
+
def.providersResolver(def);
|
|
12972
|
+
}
|
|
12973
|
+
let preOrderHooksFound = false;
|
|
12974
|
+
let preOrderCheckHooksFound = false;
|
|
12975
|
+
let directiveIdx = allocExpando(tView, lView, directives.length, null);
|
|
12976
|
+
ngDevMode &&
|
|
12977
|
+
assertSame(directiveIdx, tNode.directiveStart, 'TNode.directiveStart should point to just allocated space');
|
|
12978
|
+
for (let i = 0; i < directives.length; i++) {
|
|
12979
|
+
const def = directives[i];
|
|
12980
|
+
// Merge the attrs in the order of matches. This assumes that the first directive is the
|
|
12981
|
+
// component itself, so that the component has the least priority.
|
|
12982
|
+
tNode.mergedAttrs = mergeHostAttrs(tNode.mergedAttrs, def.hostAttrs);
|
|
12983
|
+
configureViewWithDirective(tView, tNode, lView, directiveIdx, def);
|
|
12984
|
+
saveNameToExportMap(directiveIdx, def, exportsMap);
|
|
12985
|
+
if (def.contentQueries !== null)
|
|
12986
|
+
tNode.flags |= 4 /* TNodeFlags.hasContentQuery */;
|
|
12987
|
+
if (def.hostBindings !== null || def.hostAttrs !== null || def.hostVars !== 0)
|
|
12988
|
+
tNode.flags |= 64 /* TNodeFlags.hasHostBindings */;
|
|
12989
|
+
const lifeCycleHooks = def.type.prototype;
|
|
12990
|
+
// Only push a node index into the preOrderHooks array if this is the first
|
|
12991
|
+
// pre-order hook found on this node.
|
|
12992
|
+
if (!preOrderHooksFound &&
|
|
12993
|
+
(lifeCycleHooks.ngOnChanges || lifeCycleHooks.ngOnInit || lifeCycleHooks.ngDoCheck)) {
|
|
12994
|
+
// We will push the actual hook function into this array later during dir instantiation.
|
|
12995
|
+
// We cannot do it now because we must ensure hooks are registered in the same
|
|
12996
|
+
// order that directives are created (i.e. injection order).
|
|
12997
|
+
(tView.preOrderHooks || (tView.preOrderHooks = [])).push(tNode.index);
|
|
12998
|
+
preOrderHooksFound = true;
|
|
12999
|
+
}
|
|
13000
|
+
if (!preOrderCheckHooksFound && (lifeCycleHooks.ngOnChanges || lifeCycleHooks.ngDoCheck)) {
|
|
13001
|
+
(tView.preOrderCheckHooks || (tView.preOrderCheckHooks = [])).push(tNode.index);
|
|
13002
|
+
preOrderCheckHooksFound = true;
|
|
13003
|
+
}
|
|
13004
|
+
directiveIdx++;
|
|
13005
|
+
}
|
|
13006
|
+
initializeInputAndOutputAliases(tView, tNode, hostDirectiveDefs);
|
|
13007
|
+
}
|
|
12968
13008
|
/**
|
|
12969
13009
|
* Add `hostBindings` to the `TView.hostBindingOpCodes`.
|
|
12970
13010
|
*
|
|
12971
13011
|
* @param tView `TView` to which the `hostBindings` should be added.
|
|
12972
13012
|
* @param tNode `TNode` the element which contains the directive
|
|
12973
|
-
* @param lView `LView` current `LView`
|
|
12974
13013
|
* @param directiveIdx Directive index in view.
|
|
12975
13014
|
* @param directiveVarsIdx Where will the directive's vars be stored
|
|
12976
13015
|
* @param def `ComponentDef`/`DirectiveDef`, which contains the `hostVars`/`hostBindings` to add.
|
|
12977
13016
|
*/
|
|
12978
|
-
function registerHostBindingOpCodes(tView, tNode,
|
|
13017
|
+
function registerHostBindingOpCodes(tView, tNode, directiveIdx, directiveVarsIdx, def) {
|
|
12979
13018
|
ngDevMode && assertFirstCreatePass(tView);
|
|
12980
13019
|
const hostBindings = def.hostBindings;
|
|
12981
13020
|
if (hostBindings) {
|
|
@@ -13076,38 +13115,65 @@ function invokeHostBindingsInCreationMode(def, directive) {
|
|
|
13076
13115
|
* Matches the current node against all available selectors.
|
|
13077
13116
|
* If a component is matched (at most one), it is returned in first position in the array.
|
|
13078
13117
|
*/
|
|
13079
|
-
function findDirectiveDefMatches(tView,
|
|
13118
|
+
function findDirectiveDefMatches(tView, tNode) {
|
|
13119
|
+
var _a;
|
|
13080
13120
|
ngDevMode && assertFirstCreatePass(tView);
|
|
13081
13121
|
ngDevMode && assertTNodeType(tNode, 3 /* TNodeType.AnyRNode */ | 12 /* TNodeType.AnyContainer */);
|
|
13082
13122
|
const registry = tView.directiveRegistry;
|
|
13083
13123
|
let matches = null;
|
|
13124
|
+
let hostDirectiveDefs = null;
|
|
13084
13125
|
if (registry) {
|
|
13085
13126
|
for (let i = 0; i < registry.length; i++) {
|
|
13086
13127
|
const def = registry[i];
|
|
13087
13128
|
if (isNodeMatchingSelectorList(tNode, def.selectors, /* isProjectionMode */ false)) {
|
|
13088
13129
|
matches || (matches = ngDevMode ? new MatchesArray() : []);
|
|
13089
|
-
diPublicInInjector(getOrCreateNodeInjectorForNode(tNode, viewData), tView, def.type);
|
|
13090
13130
|
if (isComponentDef(def)) {
|
|
13091
13131
|
if (ngDevMode) {
|
|
13092
13132
|
assertTNodeType(tNode, 2 /* TNodeType.Element */, `"${tNode.value}" tags cannot be used as component hosts. ` +
|
|
13093
13133
|
`Please use a different tag to activate the ${stringify(def.type)} component.`);
|
|
13094
13134
|
if (isComponentHost(tNode)) {
|
|
13095
|
-
|
|
13096
|
-
// `matches` array, see how we store components/directives in `matches` below.
|
|
13097
|
-
throwMultipleComponentError(tNode, matches[0].type, def.type);
|
|
13135
|
+
throwMultipleComponentError(tNode, matches.find(isComponentDef).type, def.type);
|
|
13098
13136
|
}
|
|
13099
13137
|
}
|
|
13100
|
-
|
|
13101
|
-
//
|
|
13102
|
-
|
|
13138
|
+
// Components are inserted at the front of the matches array so that their lifecycle
|
|
13139
|
+
// hooks run before any directive lifecycle hooks. This appears to be for ViewEngine
|
|
13140
|
+
// compatibility. This logic doesn't make sense with host directives, because it
|
|
13141
|
+
// would allow the host directives to undo any overrides the host may have made.
|
|
13142
|
+
// To handle this case, the host directives of components are inserted at the beginning
|
|
13143
|
+
// of the array, followed by the component. As such, the insertion order is as follows:
|
|
13144
|
+
// 1. Host directives belonging to the selector-matched component.
|
|
13145
|
+
// 2. Selector-matched component.
|
|
13146
|
+
// 3. Host directives belonging to selector-matched directives.
|
|
13147
|
+
// 4. Selector-matched directives.
|
|
13148
|
+
if (def.findHostDirectiveDefs !== null) {
|
|
13149
|
+
const hostDirectiveMatches = [];
|
|
13150
|
+
hostDirectiveDefs = hostDirectiveDefs || new Map();
|
|
13151
|
+
def.findHostDirectiveDefs(def, hostDirectiveMatches, hostDirectiveDefs);
|
|
13152
|
+
// Add all host directives declared on this component, followed by the component itself.
|
|
13153
|
+
// Host directives should execute first so the host has a chance to override changes
|
|
13154
|
+
// to the DOM made by them.
|
|
13155
|
+
matches.unshift(...hostDirectiveMatches, def);
|
|
13156
|
+
// Component is offset starting from the beginning of the host directives array.
|
|
13157
|
+
const componentOffset = hostDirectiveMatches.length;
|
|
13158
|
+
markAsComponentHost(tView, tNode, componentOffset);
|
|
13159
|
+
}
|
|
13160
|
+
else {
|
|
13161
|
+
// No host directives on this component, just add the
|
|
13162
|
+
// component def to the beginning of the matches.
|
|
13163
|
+
matches.unshift(def);
|
|
13164
|
+
markAsComponentHost(tView, tNode, 0);
|
|
13165
|
+
}
|
|
13103
13166
|
}
|
|
13104
13167
|
else {
|
|
13168
|
+
// Append any host directives to the matches first.
|
|
13169
|
+
hostDirectiveDefs = hostDirectiveDefs || new Map();
|
|
13170
|
+
(_a = def.findHostDirectiveDefs) === null || _a === void 0 ? void 0 : _a.call(def, def, matches, hostDirectiveDefs);
|
|
13105
13171
|
matches.push(def);
|
|
13106
13172
|
}
|
|
13107
13173
|
}
|
|
13108
13174
|
}
|
|
13109
13175
|
}
|
|
13110
|
-
return matches;
|
|
13176
|
+
return matches === null ? null : [matches, hostDirectiveDefs];
|
|
13111
13177
|
}
|
|
13112
13178
|
/**
|
|
13113
13179
|
* Marks a given TNode as a component's host. This consists of:
|
|
@@ -13121,26 +13187,6 @@ function markAsComponentHost(tView, hostTNode, componentOffset) {
|
|
|
13121
13187
|
(tView.components || (tView.components = ngDevMode ? new TViewComponents() : []))
|
|
13122
13188
|
.push(hostTNode.index);
|
|
13123
13189
|
}
|
|
13124
|
-
/**
|
|
13125
|
-
* Given an array of directives that were matched by their selectors, this function
|
|
13126
|
-
* produces a new array that also includes any host directives that have to be applied.
|
|
13127
|
-
* @param selectorMatches Directives matched in a template based on their selectors.
|
|
13128
|
-
* @param tView Current TView.
|
|
13129
|
-
* @param lView Current LView.
|
|
13130
|
-
* @param tNode Current TNode that is being matched.
|
|
13131
|
-
*/
|
|
13132
|
-
function findHostDirectiveDefs$1(selectorMatches, tView, lView, tNode) {
|
|
13133
|
-
const matches = [];
|
|
13134
|
-
for (const def of selectorMatches) {
|
|
13135
|
-
if (def.findHostDirectiveDefs === null) {
|
|
13136
|
-
matches.push(def);
|
|
13137
|
-
}
|
|
13138
|
-
else {
|
|
13139
|
-
def.findHostDirectiveDefs(matches, def, tView, lView, tNode);
|
|
13140
|
-
}
|
|
13141
|
-
}
|
|
13142
|
-
return matches;
|
|
13143
|
-
}
|
|
13144
13190
|
/** Caches local names and their matching directive indices for query and template lookups. */
|
|
13145
13191
|
function cacheMatchingLocalNames(tNode, localRefs, exportsMap) {
|
|
13146
13192
|
if (localRefs) {
|
|
@@ -13208,7 +13254,7 @@ function configureViewWithDirective(tView, tNode, lView, directiveIndex, def) {
|
|
|
13208
13254
|
const nodeInjectorFactory = new NodeInjectorFactory(directiveFactory, isComponentDef(def), ɵɵdirectiveInject);
|
|
13209
13255
|
tView.blueprint[directiveIndex] = nodeInjectorFactory;
|
|
13210
13256
|
lView[directiveIndex] = nodeInjectorFactory;
|
|
13211
|
-
registerHostBindingOpCodes(tView, tNode,
|
|
13257
|
+
registerHostBindingOpCodes(tView, tNode, directiveIndex, allocExpando(tView, lView, def.hostVars, NO_CHANGE), def);
|
|
13212
13258
|
}
|
|
13213
13259
|
function addComponentLogic(lView, hostTNode, def) {
|
|
13214
13260
|
const native = getNativeByTNode(hostTNode, lView);
|
|
@@ -14131,6 +14177,7 @@ class ChainedInjector {
|
|
|
14131
14177
|
this.parentInjector = parentInjector;
|
|
14132
14178
|
}
|
|
14133
14179
|
get(token, notFoundValue, flags) {
|
|
14180
|
+
flags = convertToBitFlags(flags);
|
|
14134
14181
|
const value = this.injector.get(token, NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR, flags);
|
|
14135
14182
|
if (value !== NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR ||
|
|
14136
14183
|
notFoundValue === NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR) {
|
|
@@ -14207,42 +14254,34 @@ class ComponentFactory extends ComponentFactory$1 {
|
|
|
14207
14254
|
let component;
|
|
14208
14255
|
let tElementNode;
|
|
14209
14256
|
try {
|
|
14210
|
-
const
|
|
14211
|
-
|
|
14212
|
-
|
|
14213
|
-
|
|
14214
|
-
|
|
14215
|
-
|
|
14216
|
-
|
|
14217
|
-
|
|
14218
|
-
|
|
14219
|
-
|
|
14220
|
-
|
|
14221
|
-
setUpAttributes(hostRenderer, hostRNode, attrs);
|
|
14222
|
-
}
|
|
14223
|
-
if (classes && classes.length > 0) {
|
|
14224
|
-
writeDirectClass(hostRenderer, hostRNode, classes.join(' '));
|
|
14225
|
-
}
|
|
14226
|
-
}
|
|
14257
|
+
const rootComponentDef = this.componentDef;
|
|
14258
|
+
let rootDirectives;
|
|
14259
|
+
let hostDirectiveDefs = null;
|
|
14260
|
+
if (rootComponentDef.findHostDirectiveDefs) {
|
|
14261
|
+
rootDirectives = [];
|
|
14262
|
+
hostDirectiveDefs = new Map();
|
|
14263
|
+
rootComponentDef.findHostDirectiveDefs(rootComponentDef, rootDirectives, hostDirectiveDefs);
|
|
14264
|
+
rootDirectives.push(rootComponentDef);
|
|
14265
|
+
}
|
|
14266
|
+
else {
|
|
14267
|
+
rootDirectives = [rootComponentDef];
|
|
14227
14268
|
}
|
|
14269
|
+
const hostTNode = createRootComponentTNode(rootLView, hostRNode);
|
|
14270
|
+
const componentView = createRootComponentView(hostTNode, hostRNode, rootComponentDef, rootDirectives, rootLView, rendererFactory, hostRenderer);
|
|
14228
14271
|
tElementNode = getTNode(rootTView, HEADER_OFFSET);
|
|
14272
|
+
// TODO(crisbeto): in practice `hostRNode` should always be defined, but there are some tests
|
|
14273
|
+
// where the renderer is mocked out and `undefined` is returned. We should update the tests so
|
|
14274
|
+
// that this check can be removed.
|
|
14275
|
+
if (hostRNode) {
|
|
14276
|
+
setRootNodeAttributes(hostRenderer, rootComponentDef, hostRNode, rootSelectorOrNode);
|
|
14277
|
+
}
|
|
14229
14278
|
if (projectableNodes !== undefined) {
|
|
14230
|
-
|
|
14231
|
-
for (let i = 0; i < this.ngContentSelectors.length; i++) {
|
|
14232
|
-
const nodesforSlot = projectableNodes[i];
|
|
14233
|
-
// Projectable nodes can be passed as array of arrays or an array of iterables (ngUpgrade
|
|
14234
|
-
// case). Here we do normalize passed data structure to be an array of arrays to avoid
|
|
14235
|
-
// complex checks down the line.
|
|
14236
|
-
// We also normalize the length of the passed in projectable nodes (to match the number of
|
|
14237
|
-
// <ng-container> slots defined by a component).
|
|
14238
|
-
projection.push(nodesforSlot != null ? Array.from(nodesforSlot) : null);
|
|
14239
|
-
}
|
|
14279
|
+
projectNodes(tElementNode, this.ngContentSelectors, projectableNodes);
|
|
14240
14280
|
}
|
|
14241
14281
|
// TODO: should LifecycleHooksFeature and other host features be generated by the compiler and
|
|
14242
14282
|
// executed here?
|
|
14243
14283
|
// Angular 5 reference: https://stackblitz.com/edit/lifecycle-hooks-vcref
|
|
14244
|
-
component =
|
|
14245
|
-
createRootComponent(componentView, this.componentDef, rootLView, [LifecycleHooksFeature]);
|
|
14284
|
+
component = createRootComponent(componentView, rootComponentDef, rootDirectives, hostDirectiveDefs, rootLView, [LifecycleHooksFeature]);
|
|
14246
14285
|
renderView(rootTView, rootLView, null);
|
|
14247
14286
|
}
|
|
14248
14287
|
finally {
|
|
@@ -14313,11 +14352,22 @@ const NULL_INJECTOR = {
|
|
|
14313
14352
|
throwProviderNotFoundError(token, 'NullInjector');
|
|
14314
14353
|
}
|
|
14315
14354
|
};
|
|
14355
|
+
/** Creates a TNode that can be used to instantiate a root component. */
|
|
14356
|
+
function createRootComponentTNode(lView, rNode) {
|
|
14357
|
+
const tView = lView[TVIEW];
|
|
14358
|
+
const index = HEADER_OFFSET;
|
|
14359
|
+
ngDevMode && assertIndexInRange(lView, index);
|
|
14360
|
+
lView[index] = rNode;
|
|
14361
|
+
// '#host' is added here as we don't know the real host DOM name (we don't want to read it) and at
|
|
14362
|
+
// the same time we want to communicate the debug `TNode` that this is a special `TNode`
|
|
14363
|
+
// representing a host element.
|
|
14364
|
+
return getOrCreateTNode(tView, index, 2 /* TNodeType.Element */, '#host', null);
|
|
14365
|
+
}
|
|
14316
14366
|
/**
|
|
14317
14367
|
* Creates the root component view and the root component node.
|
|
14318
14368
|
*
|
|
14319
14369
|
* @param rNode Render host element.
|
|
14320
|
-
* @param
|
|
14370
|
+
* @param rootComponentDef ComponentDef
|
|
14321
14371
|
* @param rootView The parent view where the host node is stored
|
|
14322
14372
|
* @param rendererFactory Factory to be used for creating child renderers.
|
|
14323
14373
|
* @param hostRenderer The current renderer
|
|
@@ -14325,72 +14375,95 @@ const NULL_INJECTOR = {
|
|
|
14325
14375
|
*
|
|
14326
14376
|
* @returns Component view created
|
|
14327
14377
|
*/
|
|
14328
|
-
function createRootComponentView(rNode,
|
|
14378
|
+
function createRootComponentView(tNode, rNode, rootComponentDef, rootDirectives, rootView, rendererFactory, hostRenderer, sanitizer) {
|
|
14329
14379
|
const tView = rootView[TVIEW];
|
|
14330
|
-
|
|
14331
|
-
|
|
14332
|
-
rootView[index]
|
|
14333
|
-
// '#host' is added here as we don't know the real host DOM name (we don't want to read it) and at
|
|
14334
|
-
// the same time we want to communicate the debug `TNode` that this is a special `TNode`
|
|
14335
|
-
// representing a host element.
|
|
14336
|
-
const tNode = getOrCreateTNode(tView, index, 2 /* TNodeType.Element */, '#host', null);
|
|
14337
|
-
const mergedAttrs = tNode.mergedAttrs = def.hostAttrs;
|
|
14338
|
-
if (mergedAttrs !== null) {
|
|
14339
|
-
computeStaticStyling(tNode, mergedAttrs, true);
|
|
14340
|
-
if (rNode !== null) {
|
|
14341
|
-
setUpAttributes(hostRenderer, rNode, mergedAttrs);
|
|
14342
|
-
if (tNode.classes !== null) {
|
|
14343
|
-
writeDirectClass(hostRenderer, rNode, tNode.classes);
|
|
14344
|
-
}
|
|
14345
|
-
if (tNode.styles !== null) {
|
|
14346
|
-
writeDirectStyle(hostRenderer, rNode, tNode.styles);
|
|
14347
|
-
}
|
|
14348
|
-
}
|
|
14349
|
-
}
|
|
14350
|
-
const viewRenderer = rendererFactory.createRenderer(rNode, def);
|
|
14351
|
-
const componentView = createLView(rootView, getOrCreateComponentTView(def), null, def.onPush ? 32 /* LViewFlags.Dirty */ : 16 /* LViewFlags.CheckAlways */, rootView[index], tNode, rendererFactory, viewRenderer, sanitizer || null, null, null);
|
|
14380
|
+
applyRootComponentStyling(rootDirectives, tNode, rNode, hostRenderer);
|
|
14381
|
+
const viewRenderer = rendererFactory.createRenderer(rNode, rootComponentDef);
|
|
14382
|
+
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);
|
|
14352
14383
|
if (tView.firstCreatePass) {
|
|
14353
|
-
|
|
14354
|
-
markAsComponentHost(tView, tNode, 0);
|
|
14355
|
-
initTNodeFlags(tNode, rootView.length, 1);
|
|
14384
|
+
markAsComponentHost(tView, tNode, rootDirectives.length - 1);
|
|
14356
14385
|
}
|
|
14357
14386
|
addToViewTree(rootView, componentView);
|
|
14358
14387
|
// Store component view at node index, with node as the HOST
|
|
14359
|
-
return rootView[index] = componentView;
|
|
14388
|
+
return rootView[tNode.index] = componentView;
|
|
14389
|
+
}
|
|
14390
|
+
/** Sets up the styling information on a root component. */
|
|
14391
|
+
function applyRootComponentStyling(rootDirectives, tNode, rNode, hostRenderer) {
|
|
14392
|
+
for (const def of rootDirectives) {
|
|
14393
|
+
tNode.mergedAttrs = mergeHostAttrs(tNode.mergedAttrs, def.hostAttrs);
|
|
14394
|
+
}
|
|
14395
|
+
if (tNode.mergedAttrs !== null) {
|
|
14396
|
+
computeStaticStyling(tNode, tNode.mergedAttrs, true);
|
|
14397
|
+
if (rNode !== null) {
|
|
14398
|
+
setupStaticAttributes(hostRenderer, rNode, tNode);
|
|
14399
|
+
}
|
|
14400
|
+
}
|
|
14360
14401
|
}
|
|
14361
14402
|
/**
|
|
14362
14403
|
* Creates a root component and sets it up with features and host bindings.Shared by
|
|
14363
14404
|
* renderComponent() and ViewContainerRef.createComponent().
|
|
14364
14405
|
*/
|
|
14365
|
-
function createRootComponent(componentView,
|
|
14406
|
+
function createRootComponent(componentView, rootComponentDef, rootDirectives, hostDirectiveDefs, rootLView, hostFeatures) {
|
|
14407
|
+
const rootTNode = getCurrentTNode();
|
|
14408
|
+
ngDevMode && assertDefined(rootTNode, 'tNode should have been already created');
|
|
14366
14409
|
const tView = rootLView[TVIEW];
|
|
14367
|
-
|
|
14368
|
-
|
|
14369
|
-
|
|
14370
|
-
|
|
14410
|
+
const native = getNativeByTNode(rootTNode, rootLView);
|
|
14411
|
+
initializeDirectives(tView, rootLView, rootTNode, rootDirectives, null, hostDirectiveDefs);
|
|
14412
|
+
for (let i = 0; i < rootDirectives.length; i++) {
|
|
14413
|
+
const directiveIndex = rootTNode.directiveStart + i;
|
|
14414
|
+
const directiveInstance = getNodeInjectable(rootLView, tView, directiveIndex, rootTNode);
|
|
14415
|
+
attachPatchData(directiveInstance, rootLView);
|
|
14416
|
+
}
|
|
14417
|
+
invokeDirectivesHostBindings(tView, rootLView, rootTNode);
|
|
14418
|
+
if (native) {
|
|
14419
|
+
attachPatchData(native, rootLView);
|
|
14420
|
+
}
|
|
14421
|
+
// We're guaranteed for the `componentOffset` to be positive here
|
|
14422
|
+
// since a root component always matches a component def.
|
|
14423
|
+
ngDevMode &&
|
|
14424
|
+
assertGreaterThan(rootTNode.componentOffset, -1, 'componentOffset must be great than -1');
|
|
14425
|
+
const component = getNodeInjectable(rootLView, tView, rootTNode.directiveStart + rootTNode.componentOffset, rootTNode);
|
|
14371
14426
|
componentView[CONTEXT] = rootLView[CONTEXT] = component;
|
|
14372
14427
|
if (hostFeatures !== null) {
|
|
14373
14428
|
for (const feature of hostFeatures) {
|
|
14374
|
-
feature(component,
|
|
14429
|
+
feature(component, rootComponentDef);
|
|
14375
14430
|
}
|
|
14376
14431
|
}
|
|
14377
14432
|
// We want to generate an empty QueryList for root content queries for backwards
|
|
14378
14433
|
// compatibility with ViewEngine.
|
|
14379
|
-
|
|
14380
|
-
|
|
14381
|
-
|
|
14382
|
-
|
|
14434
|
+
executeContentQueries(tView, rootTNode, componentView);
|
|
14435
|
+
return component;
|
|
14436
|
+
}
|
|
14437
|
+
/** Sets the static attributes on a root component. */
|
|
14438
|
+
function setRootNodeAttributes(hostRenderer, componentDef, hostRNode, rootSelectorOrNode) {
|
|
14439
|
+
if (rootSelectorOrNode) {
|
|
14440
|
+
setUpAttributes(hostRenderer, hostRNode, ['ng-version', VERSION.full]);
|
|
14383
14441
|
}
|
|
14384
|
-
|
|
14385
|
-
|
|
14386
|
-
|
|
14387
|
-
|
|
14388
|
-
|
|
14389
|
-
|
|
14390
|
-
|
|
14391
|
-
|
|
14442
|
+
else {
|
|
14443
|
+
// If host element is created as a part of this function call (i.e. `rootSelectorOrNode`
|
|
14444
|
+
// is not defined), also apply attributes and classes extracted from component selector.
|
|
14445
|
+
// Extract attributes and classes from the first selector only to match VE behavior.
|
|
14446
|
+
const { attrs, classes } = extractAttrsAndClassesFromSelector(componentDef.selectors[0]);
|
|
14447
|
+
if (attrs) {
|
|
14448
|
+
setUpAttributes(hostRenderer, hostRNode, attrs);
|
|
14449
|
+
}
|
|
14450
|
+
if (classes && classes.length > 0) {
|
|
14451
|
+
writeDirectClass(hostRenderer, hostRNode, classes.join(' '));
|
|
14452
|
+
}
|
|
14453
|
+
}
|
|
14454
|
+
}
|
|
14455
|
+
/** Projects the `projectableNodes` that were specified when creating a root component. */
|
|
14456
|
+
function projectNodes(tNode, ngContentSelectors, projectableNodes) {
|
|
14457
|
+
const projection = tNode.projection = [];
|
|
14458
|
+
for (let i = 0; i < ngContentSelectors.length; i++) {
|
|
14459
|
+
const nodesforSlot = projectableNodes[i];
|
|
14460
|
+
// Projectable nodes can be passed as array of arrays or an array of iterables (ngUpgrade
|
|
14461
|
+
// case). Here we do normalize passed data structure to be an array of arrays to avoid
|
|
14462
|
+
// complex checks down the line.
|
|
14463
|
+
// We also normalize the length of the passed in projectable nodes (to match the number of
|
|
14464
|
+
// <ng-container> slots defined by a component).
|
|
14465
|
+
projection.push(nodesforSlot != null ? Array.from(nodesforSlot) : null);
|
|
14392
14466
|
}
|
|
14393
|
-
return component;
|
|
14394
14467
|
}
|
|
14395
14468
|
/**
|
|
14396
14469
|
* Used to enable lifecycle hooks on the root component.
|
|
@@ -14656,7 +14729,7 @@ function ɵɵCopyDefinitionFeature(definition) {
|
|
|
14656
14729
|
* found in the LICENSE file at https://angular.io/license
|
|
14657
14730
|
*/
|
|
14658
14731
|
/**
|
|
14659
|
-
* This feature
|
|
14732
|
+
* This feature adds the host directives behavior to a directive definition by patching a
|
|
14660
14733
|
* function onto it. The expectation is that the runtime will invoke the function during
|
|
14661
14734
|
* directive matching.
|
|
14662
14735
|
*
|
|
@@ -14690,17 +14763,22 @@ function ɵɵHostDirectivesFeature(rawHostDirectives) {
|
|
|
14690
14763
|
});
|
|
14691
14764
|
};
|
|
14692
14765
|
}
|
|
14693
|
-
function findHostDirectiveDefs(
|
|
14694
|
-
if (
|
|
14695
|
-
for (const hostDirectiveConfig of
|
|
14766
|
+
function findHostDirectiveDefs(currentDef, matchedDefs, hostDirectiveDefs) {
|
|
14767
|
+
if (currentDef.hostDirectives !== null) {
|
|
14768
|
+
for (const hostDirectiveConfig of currentDef.hostDirectives) {
|
|
14696
14769
|
const hostDirectiveDef = getDirectiveDef(hostDirectiveConfig.directive);
|
|
14697
|
-
|
|
14770
|
+
if (typeof ngDevMode === 'undefined' || ngDevMode) {
|
|
14771
|
+
validateHostDirective(hostDirectiveConfig, hostDirectiveDef, matchedDefs);
|
|
14772
|
+
}
|
|
14773
|
+
// We need to patch the `declaredInputs` so that
|
|
14774
|
+
// `ngOnChanges` can map the properties correctly.
|
|
14775
|
+
patchDeclaredInputs(hostDirectiveDef.declaredInputs, hostDirectiveConfig.inputs);
|
|
14698
14776
|
// Host directives execute before the host so that its host bindings can be overwritten.
|
|
14699
|
-
findHostDirectiveDefs(
|
|
14777
|
+
findHostDirectiveDefs(hostDirectiveDef, matchedDefs, hostDirectiveDefs);
|
|
14778
|
+
hostDirectiveDefs.set(hostDirectiveDef, hostDirectiveConfig);
|
|
14779
|
+
matchedDefs.push(hostDirectiveDef);
|
|
14700
14780
|
}
|
|
14701
14781
|
}
|
|
14702
|
-
// Push the def itself at the end since it needs to execute after the host directives.
|
|
14703
|
-
matches.push(def);
|
|
14704
14782
|
}
|
|
14705
14783
|
/**
|
|
14706
14784
|
* Converts an array in the form of `['publicName', 'alias', 'otherPublicName', 'otherAlias']` into
|
|
@@ -14716,6 +14794,90 @@ function bindingArrayToMap(bindings) {
|
|
|
14716
14794
|
}
|
|
14717
14795
|
return result;
|
|
14718
14796
|
}
|
|
14797
|
+
/**
|
|
14798
|
+
* `ngOnChanges` has some leftover legacy ViewEngine behavior where the keys inside the
|
|
14799
|
+
* `SimpleChanges` event refer to the *declared* name of the input, not its public name or its
|
|
14800
|
+
* minified name. E.g. in `@Input('alias') foo: string`, the name in the `SimpleChanges` object
|
|
14801
|
+
* will always be `foo`, and not `alias` or the minified name of `foo` in apps using property
|
|
14802
|
+
* minification.
|
|
14803
|
+
*
|
|
14804
|
+
* This is achieved through the `DirectiveDef.declaredInputs` map that is constructed when the
|
|
14805
|
+
* definition is declared. When a property is written to the directive instance, the
|
|
14806
|
+
* `NgOnChangesFeature` will try to remap the property name being written to using the
|
|
14807
|
+
* `declaredInputs`.
|
|
14808
|
+
*
|
|
14809
|
+
* Since the host directive input remapping happens during directive matching, `declaredInputs`
|
|
14810
|
+
* won't contain the new alias that the input is available under. This function addresses the
|
|
14811
|
+
* issue by patching the host directive aliases to the `declaredInputs`. There is *not* a risk of
|
|
14812
|
+
* this patching accidentally introducing new inputs to the host directive, because `declaredInputs`
|
|
14813
|
+
* is used *only* by the `NgOnChangesFeature` when determining what name is used in the
|
|
14814
|
+
* `SimpleChanges` object which won't be reached if an input doesn't exist.
|
|
14815
|
+
*/
|
|
14816
|
+
function patchDeclaredInputs(declaredInputs, exposedInputs) {
|
|
14817
|
+
for (const publicName in exposedInputs) {
|
|
14818
|
+
if (exposedInputs.hasOwnProperty(publicName)) {
|
|
14819
|
+
const remappedPublicName = exposedInputs[publicName];
|
|
14820
|
+
const privateName = declaredInputs[publicName];
|
|
14821
|
+
// We *technically* shouldn't be able to hit this case because we can't have multiple
|
|
14822
|
+
// inputs on the same property and we have validations against conflicting aliases in
|
|
14823
|
+
// `validateMappings`. If we somehow did, it would lead to `ngOnChanges` being invoked
|
|
14824
|
+
// with the wrong name so we have a non-user-friendly assertion here just in case.
|
|
14825
|
+
if ((typeof ngDevMode === 'undefined' || ngDevMode) &&
|
|
14826
|
+
declaredInputs.hasOwnProperty(remappedPublicName)) {
|
|
14827
|
+
assertEqual(declaredInputs[remappedPublicName], declaredInputs[publicName], `Conflicting host directive input alias ${publicName}.`);
|
|
14828
|
+
}
|
|
14829
|
+
declaredInputs[remappedPublicName] = privateName;
|
|
14830
|
+
}
|
|
14831
|
+
}
|
|
14832
|
+
}
|
|
14833
|
+
/**
|
|
14834
|
+
* Verifies that the host directive has been configured correctly.
|
|
14835
|
+
* @param hostDirectiveConfig Host directive configuration object.
|
|
14836
|
+
* @param directiveDef Directive definition of the host directive.
|
|
14837
|
+
* @param matchedDefs Directives that have been matched so far.
|
|
14838
|
+
*/
|
|
14839
|
+
function validateHostDirective(hostDirectiveConfig, directiveDef, matchedDefs) {
|
|
14840
|
+
// TODO(crisbeto): implement more of these checks in the compiler.
|
|
14841
|
+
const type = hostDirectiveConfig.directive;
|
|
14842
|
+
if (directiveDef === null) {
|
|
14843
|
+
if (getComponentDef$1(type) !== null) {
|
|
14844
|
+
throw new RuntimeError(310 /* RuntimeErrorCode.HOST_DIRECTIVE_COMPONENT */, `Host directive ${type.name} cannot be a component.`);
|
|
14845
|
+
}
|
|
14846
|
+
throw new RuntimeError(307 /* RuntimeErrorCode.HOST_DIRECTIVE_UNRESOLVABLE */, `Could not resolve metadata for host directive ${type.name}. ` +
|
|
14847
|
+
`Make sure that the ${type.name} class is annotated with an @Directive decorator.`);
|
|
14848
|
+
}
|
|
14849
|
+
if (!directiveDef.standalone) {
|
|
14850
|
+
throw new RuntimeError(308 /* RuntimeErrorCode.HOST_DIRECTIVE_NOT_STANDALONE */, `Host directive ${directiveDef.type.name} must be standalone.`);
|
|
14851
|
+
}
|
|
14852
|
+
if (matchedDefs.indexOf(directiveDef) > -1) {
|
|
14853
|
+
throw new RuntimeError(309 /* RuntimeErrorCode.DUPLICATE_DIRECTITVE */, `Directive ${directiveDef.type.name} matches multiple times on the same element. ` +
|
|
14854
|
+
`Directives can only match an element once.`);
|
|
14855
|
+
}
|
|
14856
|
+
validateMappings('input', directiveDef, hostDirectiveConfig.inputs);
|
|
14857
|
+
validateMappings('output', directiveDef, hostDirectiveConfig.outputs);
|
|
14858
|
+
}
|
|
14859
|
+
/**
|
|
14860
|
+
* Checks that the host directive inputs/outputs configuration is valid.
|
|
14861
|
+
* @param bindingType Kind of binding that is being validated. Used in the error message.
|
|
14862
|
+
* @param def Definition of the host directive that is being validated against.
|
|
14863
|
+
* @param hostDirectiveDefs Host directive mapping object that shold be validated.
|
|
14864
|
+
*/
|
|
14865
|
+
function validateMappings(bindingType, def, hostDirectiveDefs) {
|
|
14866
|
+
const className = def.type.name;
|
|
14867
|
+
const bindings = bindingType === 'input' ? def.inputs : def.outputs;
|
|
14868
|
+
for (const publicName in hostDirectiveDefs) {
|
|
14869
|
+
if (hostDirectiveDefs.hasOwnProperty(publicName)) {
|
|
14870
|
+
if (!bindings.hasOwnProperty(publicName)) {
|
|
14871
|
+
throw new RuntimeError(311 /* RuntimeErrorCode.HOST_DIRECTIVE_UNDEFINED_BINDING */, `Directive ${className} does not have an ${bindingType} with a public name of ${publicName}.`);
|
|
14872
|
+
}
|
|
14873
|
+
const remappedPublicName = hostDirectiveDefs[publicName];
|
|
14874
|
+
if (bindings.hasOwnProperty(remappedPublicName) &&
|
|
14875
|
+
bindings[remappedPublicName] !== publicName) {
|
|
14876
|
+
throw new RuntimeError(312 /* RuntimeErrorCode.HOST_DIRECTIVE_CONFLICTING_ALIAS */, `Cannot alias ${bindingType} ${publicName} of host directive ${className} to ${remappedPublicName}, because it already has a different ${bindingType} with the same public name.`);
|
|
14877
|
+
}
|
|
14878
|
+
}
|
|
14879
|
+
}
|
|
14880
|
+
}
|
|
14719
14881
|
|
|
14720
14882
|
/**
|
|
14721
14883
|
* @license
|
|
@@ -15659,18 +15821,7 @@ function ɵɵelementStart(index, name, attrsIndex, localRefsIndex) {
|
|
|
15659
15821
|
elementStartFirstCreatePass(adjustedIndex, tView, lView, native, name, attrsIndex, localRefsIndex) :
|
|
15660
15822
|
tView.data[adjustedIndex];
|
|
15661
15823
|
setCurrentTNode(tNode, true);
|
|
15662
|
-
|
|
15663
|
-
if (mergedAttrs !== null) {
|
|
15664
|
-
setUpAttributes(renderer, native, mergedAttrs);
|
|
15665
|
-
}
|
|
15666
|
-
const classes = tNode.classes;
|
|
15667
|
-
if (classes !== null) {
|
|
15668
|
-
writeDirectClass(renderer, native, classes);
|
|
15669
|
-
}
|
|
15670
|
-
const styles = tNode.styles;
|
|
15671
|
-
if (styles !== null) {
|
|
15672
|
-
writeDirectStyle(renderer, native, styles);
|
|
15673
|
-
}
|
|
15824
|
+
setupStaticAttributes(renderer, native, tNode);
|
|
15674
15825
|
if ((tNode.flags & 32 /* TNodeFlags.isDetached */) !== 32 /* TNodeFlags.isDetached */) {
|
|
15675
15826
|
// In the i18n case, the translation may have removed this element, so only add it if it is not
|
|
15676
15827
|
// detached. See `TNodeType.Placeholder` and `LFrame.inI18n` for more context.
|
|
@@ -22360,7 +22511,7 @@ function getDirectives(node) {
|
|
|
22360
22511
|
return [];
|
|
22361
22512
|
}
|
|
22362
22513
|
if (context.directives === undefined) {
|
|
22363
|
-
context.directives = getDirectivesAtNodeIndex(nodeIndex, lView
|
|
22514
|
+
context.directives = getDirectivesAtNodeIndex(nodeIndex, lView);
|
|
22364
22515
|
}
|
|
22365
22516
|
// The `directives` in this case are a named array called `LComponentView`. Clone the
|
|
22366
22517
|
// result so we don't expose an internal data structure in the user's console.
|
|
@@ -24630,7 +24781,7 @@ function generateStandaloneInDeclarationsError(type, location) {
|
|
|
24630
24781
|
function verifySemanticsOfNgModuleDef(moduleType, allowDuplicateDeclarationsInRoot, importingModule) {
|
|
24631
24782
|
if (verifiedNgModule.get(moduleType))
|
|
24632
24783
|
return;
|
|
24633
|
-
// skip verifications of standalone components, directives and pipes
|
|
24784
|
+
// skip verifications of standalone components, directives, and pipes
|
|
24634
24785
|
if (isStandalone(moduleType))
|
|
24635
24786
|
return;
|
|
24636
24787
|
verifiedNgModule.set(moduleType, true);
|
|
@@ -26143,7 +26294,7 @@ class TestBedImpl {
|
|
|
26143
26294
|
return TestBedImpl.INSTANCE.overrideProvider(token, provider);
|
|
26144
26295
|
}
|
|
26145
26296
|
static inject(token, notFoundValue, flags) {
|
|
26146
|
-
return TestBedImpl.INSTANCE.inject(token, notFoundValue, flags);
|
|
26297
|
+
return TestBedImpl.INSTANCE.inject(token, notFoundValue, ɵconvertToBitFlags(flags));
|
|
26147
26298
|
}
|
|
26148
26299
|
/** @deprecated from v9.0.0 use TestBed.inject */
|
|
26149
26300
|
static get(token, notFoundValue = Injector$1.THROW_IF_NOT_FOUND, flags = InjectFlags$1.Default) {
|
|
@@ -26277,7 +26428,7 @@ class TestBedImpl {
|
|
|
26277
26428
|
return this;
|
|
26278
26429
|
}
|
|
26279
26430
|
const UNDEFINED = {};
|
|
26280
|
-
const result = this.testModuleRef.injector.get(token, UNDEFINED, flags);
|
|
26431
|
+
const result = this.testModuleRef.injector.get(token, UNDEFINED, ɵconvertToBitFlags(flags));
|
|
26281
26432
|
return result === UNDEFINED ? this.compiler.injector.get(token, notFoundValue, flags) :
|
|
26282
26433
|
result;
|
|
26283
26434
|
}
|