@angular/core 19.2.0-rc.0 → 20.0.0-next.0
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/fesm2022/core.mjs +474 -290
- package/fesm2022/core.mjs.map +1 -1
- package/fesm2022/primitives/event-dispatch.mjs +1 -1
- package/fesm2022/primitives/signals.mjs +1 -1
- package/fesm2022/rxjs-interop.mjs +1 -1
- package/fesm2022/testing.mjs +707 -5
- package/fesm2022/testing.mjs.map +1 -1
- package/index.d.ts +197 -22
- package/package.json +1 -1
- package/primitives/event-dispatch/index.d.ts +1 -1
- package/primitives/signals/index.d.ts +1 -1
- package/rxjs-interop/index.d.ts +1 -1
- package/schematics/bundles/{apply_import_manager-a930fcf1.js → apply_import_manager-0959b78c.js} +3 -3
- package/schematics/bundles/{checker-2eecc677.js → checker-cf6f7980.js} +121 -16
- package/schematics/bundles/cleanup-unused-imports.js +7 -7
- package/schematics/bundles/{compiler_host-c280a924.js → compiler_host-cc1379e9.js} +2 -2
- package/schematics/bundles/control-flow-migration.js +3 -3
- package/schematics/bundles/explicit-standalone-flag.js +5 -5
- package/schematics/bundles/{imports-abe29092.js → imports-31a38653.js} +1 -1
- package/schematics/bundles/{index-24a2ad1e.js → index-42d84d69.js} +4 -4
- package/schematics/bundles/{index-3891dd55.js → index-6675d6bc.js} +4 -4
- package/schematics/bundles/inject-migration.js +7 -7
- package/schematics/bundles/{leading_space-d190b83b.js → leading_space-6e7a8ec6.js} +1 -1
- package/schematics/bundles/{migrate_ts_type_references-71b3a951.js → migrate_ts_type_references-5089e4ef.js} +10 -6
- package/schematics/bundles/{ng_decorators-e699c081.js → ng_decorators-6878e227.js} +2 -2
- package/schematics/bundles/{nodes-a535b2be.js → nodes-ffdce442.js} +1 -1
- package/schematics/bundles/output-migration.js +7 -7
- package/schematics/bundles/pending-tasks.js +5 -5
- package/schematics/bundles/{program-24da9092.js → program-362689f0.js} +148 -148
- package/schematics/bundles/{project_paths-b073c4d6.js → project_paths-7d2daa1e.js} +3 -3
- package/schematics/bundles/{project_tsconfig_paths-e9ccccbf.js → project_tsconfig_paths-6c9cde78.js} +1 -1
- package/schematics/bundles/{property_name-7c8433f5.js → property_name-42030525.js} +1 -1
- package/schematics/bundles/provide-initializer.js +5 -5
- package/schematics/bundles/route-lazy-loading.js +5 -5
- package/schematics/bundles/self-closing-tags-migration.js +8 -8
- package/schematics/bundles/signal-input-migration.js +9 -9
- package/schematics/bundles/signal-queries-migration.js +9 -9
- package/schematics/bundles/signals.js +9 -9
- package/schematics/bundles/standalone-migration.js +9 -9
- package/testing/index.d.ts +297 -1
package/fesm2022/core.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @license Angular
|
|
2
|
+
* @license Angular v20.0.0-next.0
|
|
3
3
|
* (c) 2010-2024 Google LLC. https://angular.io/
|
|
4
4
|
* License: MIT
|
|
5
5
|
*/
|
|
@@ -967,8 +967,9 @@ function stringifyTypeFromDebugInfo(debugInfo) {
|
|
|
967
967
|
|
|
968
968
|
/** Called when directives inject each other (creating a circular dependency) */
|
|
969
969
|
function throwCyclicDependencyError(token, path) {
|
|
970
|
-
|
|
971
|
-
|
|
970
|
+
throw new RuntimeError(-200 /* RuntimeErrorCode.CYCLIC_DI_DEPENDENCY */, ngDevMode
|
|
971
|
+
? `Circular dependency in DI detected for ${token}${path ? `. Dependency path: ${path.join(' > ')} > ${token}` : ''}`
|
|
972
|
+
: token);
|
|
972
973
|
}
|
|
973
974
|
function throwMixedMultiProviderError() {
|
|
974
975
|
throw new Error(`Cannot mix multi providers and regular providers`);
|
|
@@ -7106,23 +7107,6 @@ function unwrapElementRef(value) {
|
|
|
7106
7107
|
return value instanceof ElementRef ? value.nativeElement : value;
|
|
7107
7108
|
}
|
|
7108
7109
|
|
|
7109
|
-
const markedFeatures = new Set();
|
|
7110
|
-
// tslint:disable:ban
|
|
7111
|
-
/**
|
|
7112
|
-
* A guarded `performance.mark` for feature marking.
|
|
7113
|
-
*
|
|
7114
|
-
* This method exists because while all supported browser and node.js version supported by Angular
|
|
7115
|
-
* support performance.mark API. This is not the case for other environments such as JSDOM and
|
|
7116
|
-
* Cloudflare workers.
|
|
7117
|
-
*/
|
|
7118
|
-
function performanceMarkFeature(feature) {
|
|
7119
|
-
if (markedFeatures.has(feature)) {
|
|
7120
|
-
return;
|
|
7121
|
-
}
|
|
7122
|
-
markedFeatures.add(feature);
|
|
7123
|
-
performance?.mark?.('mark_feature_usage', { detail: { feature } });
|
|
7124
|
-
}
|
|
7125
|
-
|
|
7126
7110
|
/**
|
|
7127
7111
|
* Checks if the given `value` is a reactive `Signal`.
|
|
7128
7112
|
*/
|
|
@@ -7145,7 +7129,6 @@ function ɵunwrapWritableSignal(value) {
|
|
|
7145
7129
|
* Create a `Signal` that can be set or updated directly.
|
|
7146
7130
|
*/
|
|
7147
7131
|
function signal(initialValue, options) {
|
|
7148
|
-
performanceMarkFeature('NgSignals');
|
|
7149
7132
|
const signalFn = createSignal$1(initialValue);
|
|
7150
7133
|
const node = signalFn[SIGNAL$1];
|
|
7151
7134
|
if (options?.equal) {
|
|
@@ -8625,6 +8608,23 @@ var TracingAction;
|
|
|
8625
8608
|
*/
|
|
8626
8609
|
const TracingService = new InjectionToken(ngDevMode ? 'TracingService' : '');
|
|
8627
8610
|
|
|
8611
|
+
const markedFeatures = new Set();
|
|
8612
|
+
// tslint:disable:ban
|
|
8613
|
+
/**
|
|
8614
|
+
* A guarded `performance.mark` for feature marking.
|
|
8615
|
+
*
|
|
8616
|
+
* This method exists because while all supported browser and node.js version supported by Angular
|
|
8617
|
+
* support performance.mark API. This is not the case for other environments such as JSDOM and
|
|
8618
|
+
* Cloudflare workers.
|
|
8619
|
+
*/
|
|
8620
|
+
function performanceMarkFeature(feature) {
|
|
8621
|
+
if (markedFeatures.has(feature)) {
|
|
8622
|
+
return;
|
|
8623
|
+
}
|
|
8624
|
+
markedFeatures.add(feature);
|
|
8625
|
+
performance?.mark?.('mark_feature_usage', { detail: { feature } });
|
|
8626
|
+
}
|
|
8627
|
+
|
|
8628
8628
|
/**
|
|
8629
8629
|
* Asserts that the current stack frame is not within a reactive context. Useful
|
|
8630
8630
|
* to disallow certain code from running inside a reactive context (see {@link toSignal}).
|
|
@@ -12559,15 +12559,6 @@ function executeTemplate(tView, lView, templateFn, rf, context) {
|
|
|
12559
12559
|
profiler(postHookType, context);
|
|
12560
12560
|
}
|
|
12561
12561
|
}
|
|
12562
|
-
/**
|
|
12563
|
-
* Creates directive instances.
|
|
12564
|
-
*/
|
|
12565
|
-
function createDirectivesInstancesInInstruction(tView, lView, tNode) {
|
|
12566
|
-
if (!getBindingsEnabled())
|
|
12567
|
-
return;
|
|
12568
|
-
attachPatchData(getNativeByTNode(tNode, lView), lView);
|
|
12569
|
-
createDirectivesInstances(tView, lView, tNode);
|
|
12570
|
-
}
|
|
12571
12562
|
/**
|
|
12572
12563
|
* Creates directive instances.
|
|
12573
12564
|
*/
|
|
@@ -12685,17 +12676,15 @@ function mapPropName(name) {
|
|
|
12685
12676
|
}
|
|
12686
12677
|
function elementPropertyInternal(tView, tNode, lView, propName, value, renderer, sanitizer, nativeOnly) {
|
|
12687
12678
|
ngDevMode && assertNotSame(value, NO_CHANGE, 'Incoming value should never be NO_CHANGE.');
|
|
12688
|
-
|
|
12689
|
-
|
|
12690
|
-
|
|
12691
|
-
|
|
12692
|
-
|
|
12693
|
-
|
|
12694
|
-
if (ngDevMode) {
|
|
12695
|
-
setNgReflectProperties(lView, tView, tNode, dataValue, value);
|
|
12679
|
+
if (!nativeOnly) {
|
|
12680
|
+
const hasSetInput = setAllInputsForProperty(tNode, tView, lView, propName, value);
|
|
12681
|
+
if (hasSetInput) {
|
|
12682
|
+
isComponentHost(tNode) && markDirtyIfOnPush(lView, tNode.index);
|
|
12683
|
+
ngDevMode && setNgReflectProperties(lView, tView, tNode, propName, value);
|
|
12684
|
+
return; // Stop propcessing if we've matched at least one input.
|
|
12696
12685
|
}
|
|
12697
12686
|
}
|
|
12698
|
-
|
|
12687
|
+
if (tNode.type & 3 /* TNodeType.AnyRNode */) {
|
|
12699
12688
|
const element = getNativeByTNode(tNode, lView);
|
|
12700
12689
|
propName = mapPropName(propName);
|
|
12701
12690
|
if (ngDevMode) {
|
|
@@ -12744,14 +12733,25 @@ function setNgReflectProperty(lView, tNode, attrName, value) {
|
|
|
12744
12733
|
renderer.setValue(element, textContent);
|
|
12745
12734
|
}
|
|
12746
12735
|
}
|
|
12747
|
-
function setNgReflectProperties(lView, tView, tNode,
|
|
12748
|
-
if (tNode.type & (3 /* TNodeType.AnyRNode */ | 4 /* TNodeType.Container */)) {
|
|
12749
|
-
|
|
12750
|
-
|
|
12751
|
-
|
|
12752
|
-
|
|
12736
|
+
function setNgReflectProperties(lView, tView, tNode, publicName, value) {
|
|
12737
|
+
if (!(tNode.type & (3 /* TNodeType.AnyRNode */ | 4 /* TNodeType.Container */))) {
|
|
12738
|
+
return;
|
|
12739
|
+
}
|
|
12740
|
+
const inputConfig = tNode.inputs?.[publicName];
|
|
12741
|
+
const hostInputConfig = tNode.hostDirectiveInputs?.[publicName];
|
|
12742
|
+
if (hostInputConfig) {
|
|
12743
|
+
for (let i = 0; i < hostInputConfig.length; i += 2) {
|
|
12744
|
+
const index = hostInputConfig[i];
|
|
12745
|
+
const publicName = hostInputConfig[i + 1];
|
|
12746
|
+
const def = tView.data[index];
|
|
12747
|
+
setNgReflectProperty(lView, tNode, def.inputs[publicName][0], value);
|
|
12748
|
+
}
|
|
12749
|
+
}
|
|
12750
|
+
// Note: we set the private name of the input as the reflected property, not the public one.
|
|
12751
|
+
if (inputConfig) {
|
|
12752
|
+
for (const index of inputConfig) {
|
|
12753
12753
|
const def = tView.data[index];
|
|
12754
|
-
setNgReflectProperty(lView, tNode, def.inputs[
|
|
12754
|
+
setNgReflectProperty(lView, tNode, def.inputs[publicName][0], value);
|
|
12755
12755
|
}
|
|
12756
12756
|
}
|
|
12757
12757
|
}
|
|
@@ -12920,7 +12920,7 @@ function storePropertyBindingMetadata(tData, tNode, propertyName, bindingIndex,
|
|
|
12920
12920
|
// Since we don't have a concept of the "first update pass" we need to check for presence of the
|
|
12921
12921
|
// binding meta-data to decide if one should be stored (or if was stored already).
|
|
12922
12922
|
if (tData[bindingIndex] === null) {
|
|
12923
|
-
if (tNode.inputs
|
|
12923
|
+
if (!tNode.inputs?.[propertyName] && !tNode.hostDirectiveInputs?.[propertyName]) {
|
|
12924
12924
|
const propBindingIdxs = tNode.propertyBindings || (tNode.propertyBindings = []);
|
|
12925
12925
|
propBindingIdxs.push(bindingIndex);
|
|
12926
12926
|
let bindingMetadata = propertyName;
|
|
@@ -12955,23 +12955,88 @@ function handleError(lView, error) {
|
|
|
12955
12955
|
errorHandler && errorHandler.handleError(error);
|
|
12956
12956
|
}
|
|
12957
12957
|
/**
|
|
12958
|
-
* Set
|
|
12958
|
+
* Set all directive inputs with the specific public name on the node.
|
|
12959
12959
|
*
|
|
12960
|
-
* @param
|
|
12961
|
-
* @param
|
|
12962
|
-
* @param
|
|
12963
|
-
*
|
|
12960
|
+
* @param tNode TNode on which the input is being set.
|
|
12961
|
+
* @param tView Current TView
|
|
12962
|
+
* @param lView `LView` which contains the directives.
|
|
12963
|
+
* @param publicName Public name of the input being set.
|
|
12964
12964
|
* @param value Value to set.
|
|
12965
12965
|
*/
|
|
12966
|
-
function
|
|
12967
|
-
|
|
12968
|
-
|
|
12969
|
-
|
|
12970
|
-
|
|
12971
|
-
|
|
12972
|
-
|
|
12973
|
-
|
|
12966
|
+
function setAllInputsForProperty(tNode, tView, lView, publicName, value) {
|
|
12967
|
+
const inputs = tNode.inputs?.[publicName];
|
|
12968
|
+
const hostDirectiveInputs = tNode.hostDirectiveInputs?.[publicName];
|
|
12969
|
+
let hasMatch = false;
|
|
12970
|
+
if (hostDirectiveInputs) {
|
|
12971
|
+
for (let i = 0; i < hostDirectiveInputs.length; i += 2) {
|
|
12972
|
+
const index = hostDirectiveInputs[i];
|
|
12973
|
+
ngDevMode && assertIndexInRange(lView, index);
|
|
12974
|
+
const publicName = hostDirectiveInputs[i + 1];
|
|
12975
|
+
const def = tView.data[index];
|
|
12976
|
+
writeToDirectiveInput(def, lView[index], publicName, value);
|
|
12977
|
+
hasMatch = true;
|
|
12978
|
+
}
|
|
12974
12979
|
}
|
|
12980
|
+
if (inputs) {
|
|
12981
|
+
for (const index of inputs) {
|
|
12982
|
+
ngDevMode && assertIndexInRange(lView, index);
|
|
12983
|
+
const instance = lView[index];
|
|
12984
|
+
const def = tView.data[index];
|
|
12985
|
+
writeToDirectiveInput(def, instance, publicName, value);
|
|
12986
|
+
hasMatch = true;
|
|
12987
|
+
}
|
|
12988
|
+
}
|
|
12989
|
+
return hasMatch;
|
|
12990
|
+
}
|
|
12991
|
+
/**
|
|
12992
|
+
* Sets an input value only on a specific directive and its host directives.
|
|
12993
|
+
* @param tNode TNode on which the input is being set.
|
|
12994
|
+
* @param tView Current TView
|
|
12995
|
+
* @param lView `LView` which contains the directives.
|
|
12996
|
+
* @param target Directive on which to set the input.
|
|
12997
|
+
* @param publicName Public name of the input being set.
|
|
12998
|
+
* @param value Value to set.
|
|
12999
|
+
*/
|
|
13000
|
+
function setDirectiveInput(tNode, tView, lView, target, publicName, value) {
|
|
13001
|
+
let hostIndex = null;
|
|
13002
|
+
let hostDirectivesStart = null;
|
|
13003
|
+
let hostDirectivesEnd = null;
|
|
13004
|
+
let hasSet = false;
|
|
13005
|
+
if (ngDevMode && !tNode.directiveToIndex?.has(target.type)) {
|
|
13006
|
+
throw new Error(`Node does not have a directive with type ${target.type.name}`);
|
|
13007
|
+
}
|
|
13008
|
+
const data = tNode.directiveToIndex.get(target.type);
|
|
13009
|
+
if (typeof data === 'number') {
|
|
13010
|
+
hostIndex = data;
|
|
13011
|
+
}
|
|
13012
|
+
else {
|
|
13013
|
+
[hostIndex, hostDirectivesStart, hostDirectivesEnd] = data;
|
|
13014
|
+
}
|
|
13015
|
+
if (hostDirectivesStart !== null &&
|
|
13016
|
+
hostDirectivesEnd !== null &&
|
|
13017
|
+
tNode.hostDirectiveInputs?.hasOwnProperty(publicName)) {
|
|
13018
|
+
const hostDirectiveInputs = tNode.hostDirectiveInputs[publicName];
|
|
13019
|
+
for (let i = 0; i < hostDirectiveInputs.length; i += 2) {
|
|
13020
|
+
const index = hostDirectiveInputs[i];
|
|
13021
|
+
if (index >= hostDirectivesStart && index <= hostDirectivesEnd) {
|
|
13022
|
+
ngDevMode && assertIndexInRange(lView, index);
|
|
13023
|
+
const def = tView.data[index];
|
|
13024
|
+
const hostDirectivePublicName = hostDirectiveInputs[i + 1];
|
|
13025
|
+
writeToDirectiveInput(def, lView[index], hostDirectivePublicName, value);
|
|
13026
|
+
hasSet = true;
|
|
13027
|
+
}
|
|
13028
|
+
else if (index > hostDirectivesEnd) {
|
|
13029
|
+
// Directives here are in ascending order so we can stop looking once we're past the range.
|
|
13030
|
+
break;
|
|
13031
|
+
}
|
|
13032
|
+
}
|
|
13033
|
+
}
|
|
13034
|
+
if (hostIndex !== null) {
|
|
13035
|
+
ngDevMode && assertIndexInRange(lView, hostIndex);
|
|
13036
|
+
writeToDirectiveInput(target, lView[hostIndex], publicName, value);
|
|
13037
|
+
hasSet = true;
|
|
13038
|
+
}
|
|
13039
|
+
return hasSet;
|
|
12975
13040
|
}
|
|
12976
13041
|
|
|
12977
13042
|
function renderComponent(hostLView, componentHostIdx) {
|
|
@@ -14102,7 +14167,7 @@ function runEffectsInView(view) {
|
|
|
14102
14167
|
* The maximum number of times the change detection traversal will rerun before throwing an error.
|
|
14103
14168
|
*/
|
|
14104
14169
|
const MAXIMUM_REFRESH_RERUNS$1 = 100;
|
|
14105
|
-
function detectChangesInternal(lView,
|
|
14170
|
+
function detectChangesInternal(lView, mode = 0 /* ChangeDetectionMode.Global */) {
|
|
14106
14171
|
const environment = lView[ENVIRONMENT];
|
|
14107
14172
|
const rendererFactory = environment.rendererFactory;
|
|
14108
14173
|
// Check no changes mode is a dev only mode used to verify that bindings have not changed
|
|
@@ -14115,12 +14180,6 @@ function detectChangesInternal(lView, notifyErrorHandler = true, mode = 0 /* Cha
|
|
|
14115
14180
|
try {
|
|
14116
14181
|
detectChangesInViewWhileDirty(lView, mode);
|
|
14117
14182
|
}
|
|
14118
|
-
catch (error) {
|
|
14119
|
-
if (notifyErrorHandler) {
|
|
14120
|
-
handleError(lView, error);
|
|
14121
|
-
}
|
|
14122
|
-
throw error;
|
|
14123
|
-
}
|
|
14124
14183
|
finally {
|
|
14125
14184
|
if (!checkNoChangesMode) {
|
|
14126
14185
|
rendererFactory.end?.();
|
|
@@ -14161,10 +14220,10 @@ function detectChangesInViewWhileDirty(lView, mode) {
|
|
|
14161
14220
|
setIsRefreshingViews(lastIsRefreshingViewsValue);
|
|
14162
14221
|
}
|
|
14163
14222
|
}
|
|
14164
|
-
function checkNoChangesInternal(lView, mode
|
|
14223
|
+
function checkNoChangesInternal(lView, mode) {
|
|
14165
14224
|
setIsInCheckNoChangesMode(mode);
|
|
14166
14225
|
try {
|
|
14167
|
-
detectChangesInternal(lView
|
|
14226
|
+
detectChangesInternal(lView);
|
|
14168
14227
|
}
|
|
14169
14228
|
finally {
|
|
14170
14229
|
setIsInCheckNoChangesMode(CheckNoChangesMode.Off);
|
|
@@ -14718,7 +14777,6 @@ function trackMovedView(declarationContainer, lView) {
|
|
|
14718
14777
|
class ViewRef$1 {
|
|
14719
14778
|
_lView;
|
|
14720
14779
|
_cdRefInjectingView;
|
|
14721
|
-
notifyErrorHandler;
|
|
14722
14780
|
_appRef = null;
|
|
14723
14781
|
_attachedToViewContainer = false;
|
|
14724
14782
|
get rootNodes() {
|
|
@@ -14745,10 +14803,9 @@ class ViewRef$1 {
|
|
|
14745
14803
|
*
|
|
14746
14804
|
* This may be different from `_lView` if the `_cdRefInjectingView` is an embedded view.
|
|
14747
14805
|
*/
|
|
14748
|
-
_cdRefInjectingView
|
|
14806
|
+
_cdRefInjectingView) {
|
|
14749
14807
|
this._lView = _lView;
|
|
14750
14808
|
this._cdRefInjectingView = _cdRefInjectingView;
|
|
14751
|
-
this.notifyErrorHandler = notifyErrorHandler;
|
|
14752
14809
|
}
|
|
14753
14810
|
get context() {
|
|
14754
14811
|
return this._lView[CONTEXT];
|
|
@@ -14980,7 +15037,7 @@ class ViewRef$1 {
|
|
|
14980
15037
|
// until the end of the refresh. Using `RefreshView` prevents creating a potential difference
|
|
14981
15038
|
// in the state of the LViewFlags during template execution.
|
|
14982
15039
|
this._lView[FLAGS] |= 1024 /* LViewFlags.RefreshView */;
|
|
14983
|
-
detectChangesInternal(this._lView
|
|
15040
|
+
detectChangesInternal(this._lView);
|
|
14984
15041
|
}
|
|
14985
15042
|
/**
|
|
14986
15043
|
* Checks the change detector and its children, and throws if any changes are detected.
|
|
@@ -14990,7 +15047,7 @@ class ViewRef$1 {
|
|
|
14990
15047
|
*/
|
|
14991
15048
|
checkNoChanges() {
|
|
14992
15049
|
if (ngDevMode) {
|
|
14993
|
-
checkNoChangesInternal(this._lView, CheckNoChangesMode.OnlyDirtyViews
|
|
15050
|
+
checkNoChangesInternal(this._lView, CheckNoChangesMode.OnlyDirtyViews);
|
|
14994
15051
|
}
|
|
14995
15052
|
}
|
|
14996
15053
|
attachToViewContainerRef() {
|
|
@@ -15624,9 +15681,12 @@ function createTNode(tView, tParent, type, index, value, attrs) {
|
|
|
15624
15681
|
attrs: attrs,
|
|
15625
15682
|
mergedAttrs: null,
|
|
15626
15683
|
localNames: null,
|
|
15627
|
-
initialInputs:
|
|
15684
|
+
initialInputs: null,
|
|
15628
15685
|
inputs: null,
|
|
15686
|
+
hostDirectiveInputs: null,
|
|
15629
15687
|
outputs: null,
|
|
15688
|
+
hostDirectiveOutputs: null,
|
|
15689
|
+
directiveToIndex: null,
|
|
15630
15690
|
tView: null,
|
|
15631
15691
|
next: null,
|
|
15632
15692
|
prev: null,
|
|
@@ -15934,7 +15994,7 @@ function createIcuIterator(tIcu, lView) {
|
|
|
15934
15994
|
* - the `b` char which indicates that the lookup should start from the `document.body`
|
|
15935
15995
|
* - the `h` char to start lookup from the component host node (`lView[HOST]`)
|
|
15936
15996
|
*/
|
|
15937
|
-
const REF_EXTRACTOR_REGEXP = new RegExp(`^(\\d+)*(${REFERENCE_NODE_BODY}|${REFERENCE_NODE_HOST})*(.*)`);
|
|
15997
|
+
const REF_EXTRACTOR_REGEXP = /* @__PURE__ */ new RegExp(`^(\\d+)*(${REFERENCE_NODE_BODY}|${REFERENCE_NODE_HOST})*(.*)`);
|
|
15938
15998
|
/**
|
|
15939
15999
|
* Helper function that takes a reference node location and a set of navigation steps
|
|
15940
16000
|
* (from the reference node) to a target node and outputs a string that represents
|
|
@@ -16814,6 +16874,18 @@ function removeDehydratedViews(lContainer) {
|
|
|
16814
16874
|
// once again in case a `ViewContainerRef` is created later).
|
|
16815
16875
|
lContainer[DEHYDRATED_VIEWS] = retainedViews;
|
|
16816
16876
|
}
|
|
16877
|
+
function removeDehydratedViewList(deferBlock) {
|
|
16878
|
+
const { lContainer } = deferBlock;
|
|
16879
|
+
const dehydratedViews = lContainer[DEHYDRATED_VIEWS];
|
|
16880
|
+
if (dehydratedViews === null)
|
|
16881
|
+
return;
|
|
16882
|
+
const parentLView = lContainer[PARENT];
|
|
16883
|
+
const renderer = parentLView[RENDERER];
|
|
16884
|
+
for (const view of dehydratedViews) {
|
|
16885
|
+
removeDehydratedView(view, renderer);
|
|
16886
|
+
ngDevMode && ngDevMode.dehydratedViewsRemoved++;
|
|
16887
|
+
}
|
|
16888
|
+
}
|
|
16817
16889
|
/**
|
|
16818
16890
|
* Helper function to remove all nodes from a dehydrated view.
|
|
16819
16891
|
*/
|
|
@@ -17453,14 +17525,22 @@ function ɵɵinvalidFactory() {
|
|
|
17453
17525
|
* Resolve the matched directives on a node.
|
|
17454
17526
|
*/
|
|
17455
17527
|
function resolveDirectives(tView, lView, tNode, localRefs, directiveMatcher) {
|
|
17456
|
-
// Please make sure to have explicit type for `exportsMap`. Inferred type triggers bug in
|
|
17457
|
-
// tsickle.
|
|
17528
|
+
// Please make sure to have explicit type for `exportsMap`. Inferred type triggers bug in tsickle.
|
|
17458
17529
|
ngDevMode && assertFirstCreatePass(tView);
|
|
17459
17530
|
const exportsMap = localRefs === null ? null : { '': -1 };
|
|
17460
17531
|
const matchedDirectiveDefs = directiveMatcher(tView, tNode);
|
|
17461
17532
|
if (matchedDirectiveDefs !== null) {
|
|
17462
|
-
|
|
17463
|
-
|
|
17533
|
+
let directiveDefs;
|
|
17534
|
+
let hostDirectiveDefs = null;
|
|
17535
|
+
let hostDirectiveRanges = null;
|
|
17536
|
+
const hostDirectiveResolution = resolveHostDirectives(matchedDirectiveDefs);
|
|
17537
|
+
if (hostDirectiveResolution === null) {
|
|
17538
|
+
directiveDefs = matchedDirectiveDefs;
|
|
17539
|
+
}
|
|
17540
|
+
else {
|
|
17541
|
+
[directiveDefs, hostDirectiveDefs, hostDirectiveRanges] = hostDirectiveResolution;
|
|
17542
|
+
}
|
|
17543
|
+
initializeDirectives(tView, lView, tNode, directiveDefs, exportsMap, hostDirectiveDefs, hostDirectiveRanges);
|
|
17464
17544
|
}
|
|
17465
17545
|
if (exportsMap !== null && localRefs !== null) {
|
|
17466
17546
|
cacheMatchingLocalNames(tNode, localRefs, exportsMap);
|
|
@@ -17479,40 +17559,63 @@ function cacheMatchingLocalNames(tNode, localRefs, exportsMap) {
|
|
|
17479
17559
|
localNames.push(localRefs[i], index);
|
|
17480
17560
|
}
|
|
17481
17561
|
}
|
|
17482
|
-
function resolveHostDirectives(
|
|
17483
|
-
|
|
17562
|
+
function resolveHostDirectives(matches) {
|
|
17563
|
+
let componentDef = null;
|
|
17564
|
+
let hasHostDirectives = false;
|
|
17565
|
+
for (let i = 0; i < matches.length; i++) {
|
|
17566
|
+
const def = matches[i];
|
|
17567
|
+
if (i === 0 && isComponentDef(def)) {
|
|
17568
|
+
componentDef = def;
|
|
17569
|
+
}
|
|
17570
|
+
if (def.findHostDirectiveDefs !== null) {
|
|
17571
|
+
hasHostDirectives = true;
|
|
17572
|
+
break;
|
|
17573
|
+
}
|
|
17574
|
+
}
|
|
17575
|
+
if (!hasHostDirectives) {
|
|
17576
|
+
return null;
|
|
17577
|
+
}
|
|
17578
|
+
let allDirectiveDefs = null;
|
|
17484
17579
|
let hostDirectiveDefs = null;
|
|
17580
|
+
let hostDirectiveRanges = null;
|
|
17581
|
+
// Components are inserted at the front of the matches array so that their lifecycle
|
|
17582
|
+
// hooks run before any directive lifecycle hooks. This appears to be for ViewEngine
|
|
17583
|
+
// compatibility. This logic doesn't make sense with host directives, because it
|
|
17584
|
+
// would allow the host directives to undo any overrides the host may have made.
|
|
17585
|
+
// To handle this case, the host directives of components are inserted at the beginning
|
|
17586
|
+
// of the array, followed by the component. As such, the insertion order is as follows:
|
|
17587
|
+
// 1. Host directives belonging to the selector-matched component.
|
|
17588
|
+
// 2. Selector-matched component.
|
|
17589
|
+
// 3. Host directives belonging to selector-matched directives.
|
|
17590
|
+
// 4. Selector-matched dir
|
|
17485
17591
|
for (const def of matches) {
|
|
17486
17592
|
if (def.findHostDirectiveDefs !== null) {
|
|
17487
|
-
|
|
17593
|
+
allDirectiveDefs ??= [];
|
|
17488
17594
|
hostDirectiveDefs ??= new Map();
|
|
17489
|
-
|
|
17490
|
-
|
|
17491
|
-
// compatibility. This logic doesn't make sense with host directives, because it
|
|
17492
|
-
// would allow the host directives to undo any overrides the host may have made.
|
|
17493
|
-
// To handle this case, the host directives of components are inserted at the beginning
|
|
17494
|
-
// of the array, followed by the component. As such, the insertion order is as follows:
|
|
17495
|
-
// 1. Host directives belonging to the selector-matched component.
|
|
17496
|
-
// 2. Selector-matched component.
|
|
17497
|
-
// 3. Host directives belonging to selector-matched directives.
|
|
17498
|
-
// 4. Selector-matched directives.
|
|
17499
|
-
def.findHostDirectiveDefs(def, allDirectiveDefs, hostDirectiveDefs);
|
|
17595
|
+
hostDirectiveRanges ??= new Map();
|
|
17596
|
+
resolveHostDirectivesForDef(def, allDirectiveDefs, hostDirectiveRanges, hostDirectiveDefs);
|
|
17500
17597
|
}
|
|
17501
|
-
|
|
17598
|
+
// Component definition needs to be pushed early to maintain the correct ordering.
|
|
17599
|
+
if (def === componentDef) {
|
|
17600
|
+
allDirectiveDefs ??= [];
|
|
17502
17601
|
allDirectiveDefs.push(def);
|
|
17503
|
-
markAsComponentHost(tView, tNode, allDirectiveDefs.length - 1);
|
|
17504
17602
|
}
|
|
17505
17603
|
}
|
|
17506
|
-
if (
|
|
17507
|
-
allDirectiveDefs.push(...matches.slice(1));
|
|
17508
|
-
|
|
17509
|
-
|
|
17510
|
-
allDirectiveDefs.push(...matches);
|
|
17604
|
+
if (allDirectiveDefs !== null) {
|
|
17605
|
+
allDirectiveDefs.push(...(componentDef === null ? matches : matches.slice(1)));
|
|
17606
|
+
ngDevMode && assertNoDuplicateDirectives(allDirectiveDefs);
|
|
17607
|
+
return [allDirectiveDefs, hostDirectiveDefs, hostDirectiveRanges];
|
|
17511
17608
|
}
|
|
17512
|
-
|
|
17513
|
-
|
|
17514
|
-
|
|
17515
|
-
|
|
17609
|
+
return null;
|
|
17610
|
+
}
|
|
17611
|
+
function resolveHostDirectivesForDef(def, allDirectiveDefs, hostDirectiveRanges, hostDirectiveDefs) {
|
|
17612
|
+
ngDevMode && assertDefined(def.findHostDirectiveDefs, 'Expected host directive resolve function');
|
|
17613
|
+
const start = allDirectiveDefs.length;
|
|
17614
|
+
// TODO(pk): probably could return matches instead of taking in an array to fill in?
|
|
17615
|
+
def.findHostDirectiveDefs(def, allDirectiveDefs, hostDirectiveDefs);
|
|
17616
|
+
// Note that these indexes are within the offset by `directiveStart`. We can't do the
|
|
17617
|
+
// offsetting here, because `directiveStart` hasn't been initialized on the TNode yet.
|
|
17618
|
+
hostDirectiveRanges.set(def, [start, allDirectiveDefs.length - 1]);
|
|
17516
17619
|
}
|
|
17517
17620
|
/**
|
|
17518
17621
|
* Marks a given TNode as a component's host. This consists of:
|
|
@@ -17526,37 +17629,62 @@ function markAsComponentHost(tView, hostTNode, componentOffset) {
|
|
|
17526
17629
|
(tView.components ??= []).push(hostTNode.index);
|
|
17527
17630
|
}
|
|
17528
17631
|
/** Initializes the data structures necessary for a list of directives to be instantiated. */
|
|
17529
|
-
function initializeDirectives(tView, lView, tNode, directives, exportsMap, hostDirectiveDefs) {
|
|
17632
|
+
function initializeDirectives(tView, lView, tNode, directives, exportsMap, hostDirectiveDefs, hostDirectiveRanges) {
|
|
17530
17633
|
ngDevMode && assertFirstCreatePass(tView);
|
|
17634
|
+
const directivesLength = directives.length;
|
|
17635
|
+
let hasSeenComponent = false;
|
|
17531
17636
|
// Publishes the directive types to DI so they can be injected. Needs to
|
|
17532
17637
|
// happen in a separate pass before the TNode flags have been initialized.
|
|
17533
|
-
for (let i = 0; i <
|
|
17534
|
-
|
|
17638
|
+
for (let i = 0; i < directivesLength; i++) {
|
|
17639
|
+
const def = directives[i];
|
|
17640
|
+
if (!hasSeenComponent && isComponentDef(def)) {
|
|
17641
|
+
hasSeenComponent = true;
|
|
17642
|
+
markAsComponentHost(tView, tNode, i);
|
|
17643
|
+
}
|
|
17644
|
+
diPublicInInjector(getOrCreateNodeInjectorForNode(tNode, lView), tView, def.type);
|
|
17535
17645
|
}
|
|
17536
|
-
initTNodeFlags(tNode, tView.data.length,
|
|
17646
|
+
initTNodeFlags(tNode, tView.data.length, directivesLength);
|
|
17537
17647
|
// When the same token is provided by several directives on the same node, some rules apply in
|
|
17538
17648
|
// the viewEngine:
|
|
17539
17649
|
// - viewProviders have priority over providers
|
|
17540
17650
|
// - the last directive in NgModule.declarations has priority over the previous one
|
|
17541
17651
|
// So to match these rules, the order in which providers are added in the arrays is very
|
|
17542
17652
|
// important.
|
|
17543
|
-
for (let i = 0; i <
|
|
17653
|
+
for (let i = 0; i < directivesLength; i++) {
|
|
17544
17654
|
const def = directives[i];
|
|
17545
17655
|
if (def.providersResolver)
|
|
17546
17656
|
def.providersResolver(def);
|
|
17547
17657
|
}
|
|
17548
17658
|
let preOrderHooksFound = false;
|
|
17549
17659
|
let preOrderCheckHooksFound = false;
|
|
17550
|
-
let directiveIdx = allocExpando(tView, lView,
|
|
17660
|
+
let directiveIdx = allocExpando(tView, lView, directivesLength, null);
|
|
17551
17661
|
ngDevMode &&
|
|
17552
17662
|
assertSame(directiveIdx, tNode.directiveStart, 'TNode.directiveStart should point to just allocated space');
|
|
17553
|
-
|
|
17663
|
+
// If there's at least one directive, we'll have to track it so initialize the map.
|
|
17664
|
+
if (directivesLength > 0) {
|
|
17665
|
+
tNode.directiveToIndex = new Map();
|
|
17666
|
+
}
|
|
17667
|
+
for (let i = 0; i < directivesLength; i++) {
|
|
17554
17668
|
const def = directives[i];
|
|
17555
17669
|
// Merge the attrs in the order of matches. This assumes that the first directive is the
|
|
17556
17670
|
// component itself, so that the component has the least priority.
|
|
17557
17671
|
tNode.mergedAttrs = mergeHostAttrs(tNode.mergedAttrs, def.hostAttrs);
|
|
17558
17672
|
configureViewWithDirective(tView, tNode, lView, directiveIdx, def);
|
|
17559
17673
|
saveNameToExportMap(directiveIdx, def, exportsMap);
|
|
17674
|
+
// If a directive has host directives, we need to track both its index and the range within
|
|
17675
|
+
// the host directives are declared. Host directives are not tracked, but should be resolved
|
|
17676
|
+
// by looking up the host and getting its indexes from there.
|
|
17677
|
+
if (hostDirectiveRanges !== null && hostDirectiveRanges.has(def)) {
|
|
17678
|
+
const [start, end] = hostDirectiveRanges.get(def);
|
|
17679
|
+
tNode.directiveToIndex.set(def.type, [
|
|
17680
|
+
directiveIdx,
|
|
17681
|
+
start + tNode.directiveStart,
|
|
17682
|
+
end + tNode.directiveStart,
|
|
17683
|
+
]);
|
|
17684
|
+
}
|
|
17685
|
+
else if (hostDirectiveDefs === null || !hostDirectiveDefs.has(def)) {
|
|
17686
|
+
tNode.directiveToIndex.set(def.type, directiveIdx);
|
|
17687
|
+
}
|
|
17560
17688
|
if (def.contentQueries !== null)
|
|
17561
17689
|
tNode.flags |= 4 /* TNodeFlags.hasContentQuery */;
|
|
17562
17690
|
if (def.hostBindings !== null || def.hostAttrs !== null || def.hostVars !== 0)
|
|
@@ -17584,87 +17712,84 @@ function initializeDirectives(tView, lView, tNode, directives, exportsMap, hostD
|
|
|
17584
17712
|
* Initializes data structures required to work with directive inputs and outputs.
|
|
17585
17713
|
* Initialization is done for all directives matched on a given TNode.
|
|
17586
17714
|
*/
|
|
17587
|
-
function initializeInputAndOutputAliases(tView, tNode,
|
|
17715
|
+
function initializeInputAndOutputAliases(tView, tNode, hostDirectiveDefs) {
|
|
17588
17716
|
ngDevMode && assertFirstCreatePass(tView);
|
|
17589
|
-
|
|
17590
|
-
|
|
17591
|
-
|
|
17592
|
-
|
|
17593
|
-
|
|
17594
|
-
|
|
17595
|
-
let outputsStore = null;
|
|
17596
|
-
for (let directiveIndex = start; directiveIndex < end; directiveIndex++) {
|
|
17597
|
-
const directiveDef = tViewData[directiveIndex];
|
|
17598
|
-
const aliasData = hostDirectiveDefinitionMap
|
|
17599
|
-
? hostDirectiveDefinitionMap.get(directiveDef)
|
|
17600
|
-
: null;
|
|
17601
|
-
const aliasedInputs = aliasData ? aliasData.inputs : null;
|
|
17602
|
-
const aliasedOutputs = aliasData ? aliasData.outputs : null;
|
|
17603
|
-
inputsStore = captureNodeBindings(0 /* CaptureNodeBindingMode.Inputs */, directiveDef.inputs, directiveIndex, inputsStore, aliasedInputs);
|
|
17604
|
-
outputsStore = captureNodeBindings(1 /* CaptureNodeBindingMode.Outputs */, directiveDef.outputs, directiveIndex, outputsStore, aliasedOutputs);
|
|
17605
|
-
// Do not use unbound attributes as inputs to structural directives, since structural
|
|
17606
|
-
// directive inputs can only be set using microsyntax (e.g. `<div *dir="exp">`).
|
|
17607
|
-
const initialInputs = inputsStore !== null && tNodeAttrs !== null && !isInlineTemplate(tNode)
|
|
17608
|
-
? generateInitialInputs(inputsStore, directiveIndex, tNodeAttrs)
|
|
17609
|
-
: null;
|
|
17610
|
-
inputsFromAttrs.push(initialInputs);
|
|
17611
|
-
}
|
|
17612
|
-
if (inputsStore !== null) {
|
|
17613
|
-
if (inputsStore.hasOwnProperty('class')) {
|
|
17614
|
-
tNode.flags |= 8 /* TNodeFlags.hasClassInput */;
|
|
17717
|
+
for (let index = tNode.directiveStart; index < tNode.directiveEnd; index++) {
|
|
17718
|
+
const directiveDef = tView.data[index];
|
|
17719
|
+
if (hostDirectiveDefs === null || !hostDirectiveDefs.has(directiveDef)) {
|
|
17720
|
+
setupSelectorMatchedInputsOrOutputs(0 /* BindingType.Inputs */, tNode, directiveDef, index);
|
|
17721
|
+
setupSelectorMatchedInputsOrOutputs(1 /* BindingType.Outputs */, tNode, directiveDef, index);
|
|
17722
|
+
setupInitialInputs(tNode, index, false);
|
|
17615
17723
|
}
|
|
17616
|
-
|
|
17617
|
-
|
|
17724
|
+
else {
|
|
17725
|
+
const hostDirectiveDef = hostDirectiveDefs.get(directiveDef);
|
|
17726
|
+
setupHostDirectiveInputsOrOutputs(0 /* BindingType.Inputs */, tNode, hostDirectiveDef, index);
|
|
17727
|
+
setupHostDirectiveInputsOrOutputs(1 /* BindingType.Outputs */, tNode, hostDirectiveDef, index);
|
|
17728
|
+
setupInitialInputs(tNode, index, true);
|
|
17618
17729
|
}
|
|
17619
17730
|
}
|
|
17620
|
-
tNode.initialInputs = inputsFromAttrs;
|
|
17621
|
-
tNode.inputs = inputsStore;
|
|
17622
|
-
tNode.outputs = outputsStore;
|
|
17623
17731
|
}
|
|
17624
|
-
|
|
17625
|
-
|
|
17626
|
-
|
|
17627
|
-
|
|
17628
|
-
|
|
17629
|
-
|
|
17630
|
-
|
|
17631
|
-
|
|
17632
|
-
|
|
17633
|
-
|
|
17634
|
-
|
|
17635
|
-
|
|
17636
|
-
|
|
17637
|
-
|
|
17638
|
-
|
|
17639
|
-
|
|
17640
|
-
let finalPublicName = publicName;
|
|
17641
|
-
if (hostDirectiveAliasMap !== null) {
|
|
17642
|
-
// If there is no mapping, it's not part of the allowlist and this input/output
|
|
17643
|
-
// is not captured and should be ignored.
|
|
17644
|
-
if (!hostDirectiveAliasMap.hasOwnProperty(publicName)) {
|
|
17645
|
-
continue;
|
|
17732
|
+
/**
|
|
17733
|
+
* Sets up the input/output bindings for a directive that was matched in the template through its
|
|
17734
|
+
* selector. This method is called repeatedly to build up all of the available inputs on a node.
|
|
17735
|
+
*
|
|
17736
|
+
* @param mode Whether inputs or outputs are being contructed.
|
|
17737
|
+
* @param tNode Node on which the bindings are being set up.
|
|
17738
|
+
* @param def Directive definition for which the bindings are being set up.
|
|
17739
|
+
* @param directiveIndex Index at which the directive instance will be stored in the LView.
|
|
17740
|
+
*/
|
|
17741
|
+
function setupSelectorMatchedInputsOrOutputs(mode, tNode, def, directiveIndex) {
|
|
17742
|
+
const aliasMap = mode === 0 /* BindingType.Inputs */ ? def.inputs : def.outputs;
|
|
17743
|
+
for (const publicName in aliasMap) {
|
|
17744
|
+
if (aliasMap.hasOwnProperty(publicName)) {
|
|
17745
|
+
let bindings;
|
|
17746
|
+
if (mode === 0 /* BindingType.Inputs */) {
|
|
17747
|
+
bindings = tNode.inputs ??= {};
|
|
17646
17748
|
}
|
|
17647
|
-
|
|
17648
|
-
|
|
17649
|
-
|
|
17650
|
-
|
|
17749
|
+
else {
|
|
17750
|
+
bindings = tNode.outputs ??= {};
|
|
17751
|
+
}
|
|
17752
|
+
bindings[publicName] ??= [];
|
|
17753
|
+
bindings[publicName].push(directiveIndex);
|
|
17754
|
+
setShadowStylingInputFlags(tNode, publicName);
|
|
17651
17755
|
}
|
|
17652
|
-
|
|
17653
|
-
|
|
17756
|
+
}
|
|
17757
|
+
}
|
|
17758
|
+
/**
|
|
17759
|
+
* Sets up input/output bindings that were defined through host directives on a specific node.
|
|
17760
|
+
* @param mode Whether inputs or outputs are being contructed.
|
|
17761
|
+
* @param tNode Node on which the bindings are being set up.
|
|
17762
|
+
* @param config Host directive definition that is being set up.
|
|
17763
|
+
* @param directiveIndex Index at which the directive instance will be stored in the LView.
|
|
17764
|
+
*/
|
|
17765
|
+
function setupHostDirectiveInputsOrOutputs(mode, tNode, config, directiveIndex) {
|
|
17766
|
+
const aliasMap = mode === 0 /* BindingType.Inputs */ ? config.inputs : config.outputs;
|
|
17767
|
+
for (const initialName in aliasMap) {
|
|
17768
|
+
if (aliasMap.hasOwnProperty(initialName)) {
|
|
17769
|
+
const publicName = aliasMap[initialName];
|
|
17770
|
+
let bindings;
|
|
17771
|
+
if (mode === 0 /* BindingType.Inputs */) {
|
|
17772
|
+
bindings = tNode.hostDirectiveInputs ??= {};
|
|
17773
|
+
}
|
|
17774
|
+
else {
|
|
17775
|
+
bindings = tNode.hostDirectiveOutputs ??= {};
|
|
17776
|
+
}
|
|
17777
|
+
bindings[publicName] ??= [];
|
|
17778
|
+
bindings[publicName].push(directiveIndex, initialName);
|
|
17779
|
+
setShadowStylingInputFlags(tNode, publicName);
|
|
17654
17780
|
}
|
|
17655
17781
|
}
|
|
17656
|
-
return bindingsResult;
|
|
17657
17782
|
}
|
|
17658
|
-
function
|
|
17659
|
-
if (
|
|
17660
|
-
|
|
17783
|
+
function setShadowStylingInputFlags(tNode, publicName) {
|
|
17784
|
+
if (publicName === 'class') {
|
|
17785
|
+
tNode.flags |= 8 /* TNodeFlags.hasClassInput */;
|
|
17661
17786
|
}
|
|
17662
|
-
else {
|
|
17663
|
-
|
|
17787
|
+
else if (publicName === 'style') {
|
|
17788
|
+
tNode.flags |= 16 /* TNodeFlags.hasStyleInput */;
|
|
17664
17789
|
}
|
|
17665
17790
|
}
|
|
17666
17791
|
/**
|
|
17667
|
-
*
|
|
17792
|
+
* Sets up the initialInputData for a node and stores it in the template's static storage
|
|
17668
17793
|
* so subsequent template invocations don't have to recalculate it.
|
|
17669
17794
|
*
|
|
17670
17795
|
* initialInputData is an array containing values that need to be set as input properties
|
|
@@ -17674,11 +17799,21 @@ function addPropertyBinding(bindings, directiveIndex, publicName, lookupName) {
|
|
|
17674
17799
|
*
|
|
17675
17800
|
* <my-component name="Bess"></my-component>
|
|
17676
17801
|
*
|
|
17677
|
-
* @param
|
|
17802
|
+
* @param tNode TNode on which to set up the initial inputs.
|
|
17678
17803
|
* @param directiveIndex Index of the directive that is currently being processed.
|
|
17679
|
-
* @param attrs Static attrs on this node.
|
|
17680
17804
|
*/
|
|
17681
|
-
function
|
|
17805
|
+
function setupInitialInputs(tNode, directiveIndex, isHostDirective) {
|
|
17806
|
+
const { attrs, inputs, hostDirectiveInputs } = tNode;
|
|
17807
|
+
if (attrs === null ||
|
|
17808
|
+
(!isHostDirective && inputs === null) ||
|
|
17809
|
+
(isHostDirective && hostDirectiveInputs === null) ||
|
|
17810
|
+
// Do not use unbound attributes as inputs to structural directives, since structural
|
|
17811
|
+
// directive inputs can only be set using microsyntax (e.g. `<div *dir="exp">`).
|
|
17812
|
+
isInlineTemplate(tNode)) {
|
|
17813
|
+
tNode.initialInputs ??= [];
|
|
17814
|
+
tNode.initialInputs.push(null);
|
|
17815
|
+
return;
|
|
17816
|
+
}
|
|
17682
17817
|
let inputsToStore = null;
|
|
17683
17818
|
let i = 0;
|
|
17684
17819
|
while (i < attrs.length) {
|
|
@@ -17693,26 +17828,38 @@ function generateInitialInputs(inputs, directiveIndex, attrs) {
|
|
|
17693
17828
|
i += 2;
|
|
17694
17829
|
continue;
|
|
17695
17830
|
}
|
|
17696
|
-
|
|
17697
|
-
|
|
17831
|
+
else if (typeof attrName === 'number') {
|
|
17832
|
+
// If we hit any other attribute markers, we're done anyway. None of those are valid inputs.
|
|
17698
17833
|
break;
|
|
17699
|
-
|
|
17834
|
+
}
|
|
17835
|
+
if (!isHostDirective && inputs.hasOwnProperty(attrName)) {
|
|
17700
17836
|
// Find the input's public name from the input store. Note that we can be found easier
|
|
17701
17837
|
// through the directive def, but we want to do it using the inputs store so that it can
|
|
17702
17838
|
// account for host directive aliases.
|
|
17703
17839
|
const inputConfig = inputs[attrName];
|
|
17704
|
-
for (
|
|
17705
|
-
if (
|
|
17840
|
+
for (const index of inputConfig) {
|
|
17841
|
+
if (index === directiveIndex) {
|
|
17706
17842
|
inputsToStore ??= [];
|
|
17707
|
-
inputsToStore.push(
|
|
17843
|
+
inputsToStore.push(attrName, attrs[i + 1]);
|
|
17708
17844
|
// A directive can't have multiple inputs with the same name so we can break here.
|
|
17709
17845
|
break;
|
|
17710
17846
|
}
|
|
17711
17847
|
}
|
|
17712
17848
|
}
|
|
17849
|
+
else if (isHostDirective && hostDirectiveInputs.hasOwnProperty(attrName)) {
|
|
17850
|
+
const config = hostDirectiveInputs[attrName];
|
|
17851
|
+
for (let j = 0; j < config.length; j += 2) {
|
|
17852
|
+
if (config[j] === directiveIndex) {
|
|
17853
|
+
inputsToStore ??= [];
|
|
17854
|
+
inputsToStore.push(config[j + 1], attrs[i + 1]);
|
|
17855
|
+
break;
|
|
17856
|
+
}
|
|
17857
|
+
}
|
|
17858
|
+
}
|
|
17713
17859
|
i += 2;
|
|
17714
17860
|
}
|
|
17715
|
-
|
|
17861
|
+
tNode.initialInputs ??= [];
|
|
17862
|
+
tNode.initialInputs.push(inputsToStore);
|
|
17716
17863
|
}
|
|
17717
17864
|
/**
|
|
17718
17865
|
* Setup directive for instantiation.
|
|
@@ -17972,7 +18119,7 @@ class ComponentFactory extends ComponentFactory$1 {
|
|
|
17972
18119
|
const cmpDef = this.componentDef;
|
|
17973
18120
|
ngDevMode && verifyNotAnOrphanComponent(cmpDef);
|
|
17974
18121
|
const tAttributes = rootSelectorOrNode
|
|
17975
|
-
? ['ng-version', '
|
|
18122
|
+
? ['ng-version', '20.0.0-next.0']
|
|
17976
18123
|
: // Extract attributes and classes from the first selector only to match VE behavior.
|
|
17977
18124
|
extractAttrsAndClassesFromSelector(this.componentDef.selectors[0]);
|
|
17978
18125
|
// Create the root view. Uses empty TView and ContentTemplate.
|
|
@@ -18057,33 +18204,28 @@ class ComponentRef extends ComponentRef$1 {
|
|
|
18057
18204
|
this._tNode = getTNode(_rootLView[TVIEW], HEADER_OFFSET);
|
|
18058
18205
|
this.location = createElementRef(this._tNode, _rootLView);
|
|
18059
18206
|
this.instance = getComponentLViewByIndex(this._tNode.index, _rootLView)[CONTEXT];
|
|
18060
|
-
this.hostView = this.changeDetectorRef = new ViewRef$1(_rootLView, undefined /* _cdRefInjectingView
|
|
18207
|
+
this.hostView = this.changeDetectorRef = new ViewRef$1(_rootLView, undefined /* _cdRefInjectingView */);
|
|
18061
18208
|
this.componentType = componentType;
|
|
18062
18209
|
}
|
|
18063
18210
|
setInput(name, value) {
|
|
18064
|
-
const
|
|
18065
|
-
|
|
18066
|
-
if
|
|
18067
|
-
|
|
18068
|
-
|
|
18069
|
-
|
|
18070
|
-
|
|
18071
|
-
Object.is(this.previousInputValues.get(name), value)) {
|
|
18072
|
-
return;
|
|
18073
|
-
}
|
|
18074
|
-
const lView = this._rootLView;
|
|
18075
|
-
setInputsForProperty(lView[TVIEW], lView, dataValue, name, value);
|
|
18076
|
-
this.previousInputValues.set(name, value);
|
|
18077
|
-
const childComponentLView = getComponentLViewByIndex(this._tNode.index, lView);
|
|
18078
|
-
markViewDirty(childComponentLView, 1 /* NotificationSource.SetInput */);
|
|
18211
|
+
const tNode = this._tNode;
|
|
18212
|
+
this.previousInputValues ??= new Map();
|
|
18213
|
+
// Do not set the input if it is the same as the last value
|
|
18214
|
+
// This behavior matches `bindingUpdated` when binding inputs in templates.
|
|
18215
|
+
if (this.previousInputValues.has(name) &&
|
|
18216
|
+
Object.is(this.previousInputValues.get(name), value)) {
|
|
18217
|
+
return;
|
|
18079
18218
|
}
|
|
18080
|
-
|
|
18081
|
-
|
|
18082
|
-
|
|
18083
|
-
|
|
18084
|
-
|
|
18085
|
-
|
|
18086
|
-
|
|
18219
|
+
const lView = this._rootLView;
|
|
18220
|
+
const hasSetInput = setAllInputsForProperty(tNode, lView[TVIEW], lView, name, value);
|
|
18221
|
+
this.previousInputValues.set(name, value);
|
|
18222
|
+
const childComponentLView = getComponentLViewByIndex(tNode.index, lView);
|
|
18223
|
+
markViewDirty(childComponentLView, 1 /* NotificationSource.SetInput */);
|
|
18224
|
+
if (ngDevMode && !hasSetInput) {
|
|
18225
|
+
const cmpNameForError = stringifyForError(this.componentType);
|
|
18226
|
+
let message = `Can't set value of the '${name}' input on the '${cmpNameForError}' component. `;
|
|
18227
|
+
message += `Make sure that the '${name}' property is annotated with @Input() or a mapped @Input('${name}') exists.`;
|
|
18228
|
+
reportUnknownPropertyError(message);
|
|
18087
18229
|
}
|
|
18088
18230
|
}
|
|
18089
18231
|
get injector() {
|
|
@@ -20705,7 +20847,7 @@ function declareTemplate(declarationLView, declarationTView, index, templateFn,
|
|
|
20705
20847
|
// In client-only mode, this function is a noop.
|
|
20706
20848
|
populateDehydratedViewsInLContainer(lContainer, tNode, declarationLView);
|
|
20707
20849
|
if (isDirectiveHost(tNode)) {
|
|
20708
|
-
|
|
20850
|
+
createDirectivesInstances(declarationTView, declarationLView, tNode);
|
|
20709
20851
|
}
|
|
20710
20852
|
if (localRefsIndex != null) {
|
|
20711
20853
|
saveResolvedLocalsInData(declarationLView, tNode, localRefExtractor);
|
|
@@ -21240,8 +21382,9 @@ function renderDeferBlockState(newState, tNode, lContainer, skipTimerScheduling
|
|
|
21240
21382
|
}
|
|
21241
21383
|
}
|
|
21242
21384
|
function findMatchingDehydratedViewForDeferBlock(lContainer, lDetails) {
|
|
21243
|
-
|
|
21244
|
-
|
|
21385
|
+
const dehydratedViewIx = lContainer[DEHYDRATED_VIEWS]?.findIndex((view) => view.data[DEFER_BLOCK_STATE$1] === lDetails[DEFER_BLOCK_STATE]) ?? -1;
|
|
21386
|
+
const dehydratedView = dehydratedViewIx > -1 ? lContainer[DEHYDRATED_VIEWS][dehydratedViewIx] : null;
|
|
21387
|
+
return { dehydratedView, dehydratedViewIx };
|
|
21245
21388
|
}
|
|
21246
21389
|
/**
|
|
21247
21390
|
* Applies changes to the DOM to reflect a given state.
|
|
@@ -21273,21 +21416,23 @@ function applyDeferBlockState(newState, lDetails, lContainer, tNode, hostLView)
|
|
|
21273
21416
|
injector = createDeferBlockInjector(hostLView[INJECTOR], tDetails, providers);
|
|
21274
21417
|
}
|
|
21275
21418
|
}
|
|
21276
|
-
const dehydratedView = findMatchingDehydratedViewForDeferBlock(lContainer, lDetails);
|
|
21277
|
-
// Erase dehydrated view info, so that it's not removed later
|
|
21278
|
-
// by post-hydration cleanup process.
|
|
21279
|
-
lContainer[DEHYDRATED_VIEWS] = null;
|
|
21419
|
+
const { dehydratedView, dehydratedViewIx } = findMatchingDehydratedViewForDeferBlock(lContainer, lDetails);
|
|
21280
21420
|
const embeddedLView = createAndRenderEmbeddedLView(hostLView, activeBlockTNode, null, {
|
|
21281
21421
|
injector,
|
|
21282
21422
|
dehydratedView,
|
|
21283
21423
|
});
|
|
21284
21424
|
addLViewToLContainer(lContainer, embeddedLView, viewIndex, shouldAddViewToDom(activeBlockTNode, dehydratedView));
|
|
21285
21425
|
markViewDirty(embeddedLView, 2 /* NotificationSource.DeferBlockStateUpdate */);
|
|
21286
|
-
|
|
21287
|
-
|
|
21288
|
-
|
|
21289
|
-
|
|
21290
|
-
|
|
21426
|
+
if (dehydratedViewIx > -1) {
|
|
21427
|
+
// Erase dehydrated view info in a given LContainer, so that the view is not
|
|
21428
|
+
// removed later by post-hydration cleanup process (which iterates over all
|
|
21429
|
+
// dehydrated views in component tree). This clears only the dehydrated view
|
|
21430
|
+
// that was found for this render, which in most cases will be the only view.
|
|
21431
|
+
// In the case that there was control flow that changed, there may be either
|
|
21432
|
+
// more than one or the views would not match up due to the server rendered
|
|
21433
|
+
// content being a different branch of the control flow.
|
|
21434
|
+
lContainer[DEHYDRATED_VIEWS]?.splice(dehydratedViewIx, 1);
|
|
21435
|
+
}
|
|
21291
21436
|
if ((newState === DeferBlockState.Complete || newState === DeferBlockState.Error) &&
|
|
21292
21437
|
Array.isArray(lDetails[ON_COMPLETE_FNS])) {
|
|
21293
21438
|
for (const callback of lDetails[ON_COMPLETE_FNS]) {
|
|
@@ -23700,8 +23845,8 @@ class ApplicationRef {
|
|
|
23700
23845
|
// Set the AfterRender bit, as we're checking views and will need to run afterRender hooks.
|
|
23701
23846
|
this.dirtyFlags |= 8 /* ApplicationRefDirtyFlags.AfterRender */;
|
|
23702
23847
|
// Check all potentially dirty views.
|
|
23703
|
-
for (let { _lView
|
|
23704
|
-
detectChangesInViewIfRequired(_lView,
|
|
23848
|
+
for (let { _lView } of this.allViews) {
|
|
23849
|
+
detectChangesInViewIfRequired(_lView, useGlobalCheck, this.zonelessEnabled);
|
|
23705
23850
|
}
|
|
23706
23851
|
// If `markForCheck()` was called during view checking, it will have set the `ViewTreeCheck`
|
|
23707
23852
|
// flag. We clear the flag here because, for backwards compatibility, `markForCheck()`
|
|
@@ -23860,7 +24005,7 @@ function remove(list, el) {
|
|
|
23860
24005
|
list.splice(index, 1);
|
|
23861
24006
|
}
|
|
23862
24007
|
}
|
|
23863
|
-
function detectChangesInViewIfRequired(lView,
|
|
24008
|
+
function detectChangesInViewIfRequired(lView, isFirstPass, zonelessEnabled) {
|
|
23864
24009
|
// When re-checking, only check views which actually need it.
|
|
23865
24010
|
if (!isFirstPass && !requiresRefreshOrTraversal(lView)) {
|
|
23866
24011
|
return;
|
|
@@ -23870,7 +24015,7 @@ function detectChangesInViewIfRequired(lView, notifyErrorHandler, isFirstPass, z
|
|
|
23870
24015
|
0 /* ChangeDetectionMode.Global */
|
|
23871
24016
|
: // Only refresh views with the `RefreshView` flag or views is a changed signal
|
|
23872
24017
|
1 /* ChangeDetectionMode.Targeted */;
|
|
23873
|
-
detectChangesInternal(lView,
|
|
24018
|
+
detectChangesInternal(lView, mode);
|
|
23874
24019
|
}
|
|
23875
24020
|
|
|
23876
24021
|
/**
|
|
@@ -24136,16 +24281,36 @@ async function triggerHydrationFromBlockName(injector, blockName, replayQueuedEv
|
|
|
24136
24281
|
await parentBlockPromise;
|
|
24137
24282
|
}
|
|
24138
24283
|
// Actually do the triggering and hydration of the queue of blocks
|
|
24139
|
-
for (
|
|
24140
|
-
|
|
24141
|
-
|
|
24142
|
-
|
|
24143
|
-
|
|
24144
|
-
|
|
24145
|
-
|
|
24146
|
-
|
|
24147
|
-
|
|
24148
|
-
|
|
24284
|
+
for (let blockQueueIdx = 0; blockQueueIdx < hydrationQueue.length; blockQueueIdx++) {
|
|
24285
|
+
const dehydratedBlockId = hydrationQueue[blockQueueIdx];
|
|
24286
|
+
const dehydratedDeferBlock = dehydratedBlockRegistry.get(dehydratedBlockId);
|
|
24287
|
+
if (dehydratedDeferBlock != null) {
|
|
24288
|
+
// trigger the block resources and await next render for hydration. This should result
|
|
24289
|
+
// in the next block ɵɵdefer instruction being called and that block being added to the dehydrated registry.
|
|
24290
|
+
await triggerResourceLoadingForHydration(dehydratedDeferBlock);
|
|
24291
|
+
await nextRender(injector);
|
|
24292
|
+
// if the content has changed since server rendering, we need to check for the expected block
|
|
24293
|
+
// being in the registry or if errors occurred. In that case, we need to clean up the remaining expected
|
|
24294
|
+
// content that won't be rendered or fetched.
|
|
24295
|
+
if (deferBlockHasErrored(dehydratedDeferBlock)) {
|
|
24296
|
+
// Either the expected block has not yet had its ɵɵdefer instruction called or the block errored out when fetching
|
|
24297
|
+
// resources. In the former case, either we're hydrating too soon or the client and server differ. In both cases,
|
|
24298
|
+
// we need to clean up child content and promises.
|
|
24299
|
+
removeDehydratedViewList(dehydratedDeferBlock);
|
|
24300
|
+
cleanupRemainingHydrationQueue(hydrationQueue.slice(blockQueueIdx), dehydratedBlockRegistry);
|
|
24301
|
+
break;
|
|
24302
|
+
}
|
|
24303
|
+
// The defer block has not errored and we've finished fetching resources and rendering.
|
|
24304
|
+
// At this point it is safe to resolve the hydration promise.
|
|
24305
|
+
blocksBeingHydrated.get(dehydratedBlockId).resolve();
|
|
24306
|
+
}
|
|
24307
|
+
else {
|
|
24308
|
+
// The expected block has not yet had its ɵɵdefer instruction called. This is likely due to content changing between
|
|
24309
|
+
// client and server. We need to clean up the dehydrated DOM in the container since it no longer is valid.
|
|
24310
|
+
cleanupParentContainer(blockQueueIdx, hydrationQueue, dehydratedBlockRegistry);
|
|
24311
|
+
cleanupRemainingHydrationQueue(hydrationQueue.slice(blockQueueIdx), dehydratedBlockRegistry);
|
|
24312
|
+
break;
|
|
24313
|
+
}
|
|
24149
24314
|
}
|
|
24150
24315
|
// Await hydration completion for the requested block.
|
|
24151
24316
|
await blocksBeingHydrated.get(blockName)?.promise;
|
|
@@ -24158,6 +24323,33 @@ async function triggerHydrationFromBlockName(injector, blockName, replayQueuedEv
|
|
|
24158
24323
|
// Cleanup after hydration of all affected defer blocks.
|
|
24159
24324
|
cleanupHydratedDeferBlocks(dehydratedBlockRegistry.get(blockName), hydrationQueue, dehydratedBlockRegistry, injector.get(ApplicationRef));
|
|
24160
24325
|
}
|
|
24326
|
+
function deferBlockHasErrored(deferBlock) {
|
|
24327
|
+
return (getLDeferBlockDetails(deferBlock.lView, deferBlock.tNode)[DEFER_BLOCK_STATE] ===
|
|
24328
|
+
DeferBlockState.Error);
|
|
24329
|
+
}
|
|
24330
|
+
/**
|
|
24331
|
+
* Clean up the parent container of a block where content changed between server and client.
|
|
24332
|
+
* The parent of a block going through `triggerHydrationFromBlockName` will contain the
|
|
24333
|
+
* dehydrated content that needs to be cleaned up. So we have to do the clean up from that location
|
|
24334
|
+
* in the tree.
|
|
24335
|
+
*/
|
|
24336
|
+
function cleanupParentContainer(currentBlockIdx, hydrationQueue, dehydratedBlockRegistry) {
|
|
24337
|
+
// If a parent block exists, it's in the hydration queue in front of the current block.
|
|
24338
|
+
const parentDeferBlockIdx = currentBlockIdx - 1;
|
|
24339
|
+
const parentDeferBlock = parentDeferBlockIdx > -1
|
|
24340
|
+
? dehydratedBlockRegistry.get(hydrationQueue[parentDeferBlockIdx])
|
|
24341
|
+
: null;
|
|
24342
|
+
if (parentDeferBlock) {
|
|
24343
|
+
cleanupLContainer(parentDeferBlock.lContainer);
|
|
24344
|
+
}
|
|
24345
|
+
}
|
|
24346
|
+
function cleanupRemainingHydrationQueue(hydrationQueue, dehydratedBlockRegistry) {
|
|
24347
|
+
const blocksBeingHydrated = dehydratedBlockRegistry.hydrating;
|
|
24348
|
+
for (const dehydratedBlockId in hydrationQueue) {
|
|
24349
|
+
blocksBeingHydrated.get(dehydratedBlockId)?.reject();
|
|
24350
|
+
}
|
|
24351
|
+
dehydratedBlockRegistry.cleanup(hydrationQueue);
|
|
24352
|
+
}
|
|
24161
24353
|
/**
|
|
24162
24354
|
* Generates a new promise for every defer block in the hydrating queue
|
|
24163
24355
|
*/
|
|
@@ -24170,18 +24362,8 @@ function populateHydratingStateForQueue(registry, queue) {
|
|
|
24170
24362
|
function nextRender(injector) {
|
|
24171
24363
|
return new Promise((resolveFn) => afterNextRender(resolveFn, { injector }));
|
|
24172
24364
|
}
|
|
24173
|
-
async function triggerResourceLoadingForHydration(
|
|
24174
|
-
const
|
|
24175
|
-
// Since we trigger hydration for nested defer blocks in a sequence (parent -> child),
|
|
24176
|
-
// there is a chance that a defer block may not be present at hydration time. For example,
|
|
24177
|
-
// when a nested block was in an `@if` condition, which has changed.
|
|
24178
|
-
if (deferBlock === null) {
|
|
24179
|
-
// TODO(incremental-hydration): handle the cleanup for cases when
|
|
24180
|
-
// defer block is no longer present during hydration (e.g. `@if` condition
|
|
24181
|
-
// has changed during hydration/rendering).
|
|
24182
|
-
return;
|
|
24183
|
-
}
|
|
24184
|
-
const { tNode, lView } = deferBlock;
|
|
24365
|
+
async function triggerResourceLoadingForHydration(dehydratedBlock) {
|
|
24366
|
+
const { tNode, lView } = dehydratedBlock;
|
|
24185
24367
|
const lDetails = getLDeferBlockDetails(lView, tNode);
|
|
24186
24368
|
return new Promise((resolve) => {
|
|
24187
24369
|
onDeferBlockCompletion(lDetails, resolve);
|
|
@@ -26234,10 +26416,8 @@ function ɵɵproperty(propName, value, sanitizer) {
|
|
|
26234
26416
|
* directive input.
|
|
26235
26417
|
*/
|
|
26236
26418
|
function setDirectiveInputsWhichShadowsStyling(tView, tNode, lView, value, isClassBased) {
|
|
26237
|
-
const inputs = tNode.inputs;
|
|
26238
|
-
const property = isClassBased ? 'class' : 'style';
|
|
26239
26419
|
// We support both 'class' and `className` hence the fallback.
|
|
26240
|
-
|
|
26420
|
+
setAllInputsForProperty(tNode, tView, lView, isClassBased ? 'class' : 'style', value);
|
|
26241
26421
|
}
|
|
26242
26422
|
|
|
26243
26423
|
/**
|
|
@@ -28061,12 +28241,12 @@ function ɵɵelementStart(index, name, attrsIndex, localRefsIndex) {
|
|
|
28061
28241
|
// any immediate children of a component or template container must be pre-emptively
|
|
28062
28242
|
// monkey-patched with the component view data so that the element can be inspected
|
|
28063
28243
|
// later on using any element discovery utility methods (see `element_discovery.ts`)
|
|
28064
|
-
if (getElementDepthCount() === 0) {
|
|
28244
|
+
if (getElementDepthCount() === 0 || hasDirectives) {
|
|
28065
28245
|
attachPatchData(native, lView);
|
|
28066
28246
|
}
|
|
28067
28247
|
increaseElementDepthCount();
|
|
28068
28248
|
if (hasDirectives) {
|
|
28069
|
-
|
|
28249
|
+
createDirectivesInstances(tView, lView, tNode);
|
|
28070
28250
|
executeContentQueries(tView, tNode, lView);
|
|
28071
28251
|
}
|
|
28072
28252
|
if (localRefsIndex !== null) {
|
|
@@ -28238,7 +28418,7 @@ function ɵɵelementContainerStart(index, attrsIndex, localRefsIndex) {
|
|
|
28238
28418
|
}
|
|
28239
28419
|
attachPatchData(comment, lView);
|
|
28240
28420
|
if (isDirectiveHost(tNode)) {
|
|
28241
|
-
|
|
28421
|
+
createDirectivesInstances(tView, lView, tNode);
|
|
28242
28422
|
executeContentQueries(tView, tNode, lView);
|
|
28243
28423
|
}
|
|
28244
28424
|
if (localRefsIndex != null) {
|
|
@@ -30293,7 +30473,7 @@ function findExistingListener(tView, lView, eventName, tNodeIdx) {
|
|
|
30293
30473
|
function listenerInternal(tView, lView, renderer, tNode, eventName, listenerFn, eventTargetResolver) {
|
|
30294
30474
|
const isTNodeDirectiveHost = isDirectiveHost(tNode);
|
|
30295
30475
|
const firstCreatePass = tView.firstCreatePass;
|
|
30296
|
-
const tCleanup = firstCreatePass
|
|
30476
|
+
const tCleanup = firstCreatePass ? getOrCreateTViewCleanup(tView) : null;
|
|
30297
30477
|
const context = lView[CONTEXT];
|
|
30298
30478
|
// When the ɵɵlistener instruction was generated and is executed we know that there is either a
|
|
30299
30479
|
// native listener or a directive output on this element. As such we we know that we will have to
|
|
@@ -30358,29 +30538,37 @@ function listenerInternal(tView, lView, renderer, tNode, eventName, listenerFn,
|
|
|
30358
30538
|
// ancestors are marked dirty when an event occurs.
|
|
30359
30539
|
listenerFn = wrapListener(tNode, lView, context, listenerFn);
|
|
30360
30540
|
}
|
|
30361
|
-
|
|
30362
|
-
|
|
30363
|
-
|
|
30364
|
-
|
|
30365
|
-
|
|
30366
|
-
|
|
30367
|
-
|
|
30368
|
-
|
|
30369
|
-
|
|
30370
|
-
|
|
30371
|
-
|
|
30372
|
-
|
|
30373
|
-
|
|
30374
|
-
throw new Error(`@Output ${minifiedName} not initialized in '${directiveInstance.constructor.name}'.`);
|
|
30375
|
-
}
|
|
30376
|
-
const subscription = output.subscribe(listenerFn);
|
|
30377
|
-
const idx = lCleanup.length;
|
|
30378
|
-
lCleanup.push(listenerFn, subscription);
|
|
30379
|
-
tCleanup && tCleanup.push(eventName, tNode.index, idx, -(idx + 1));
|
|
30541
|
+
if (processOutputs) {
|
|
30542
|
+
const outputConfig = tNode.outputs?.[eventName];
|
|
30543
|
+
const hostDirectiveOutputConfig = tNode.hostDirectiveOutputs?.[eventName];
|
|
30544
|
+
if (hostDirectiveOutputConfig && hostDirectiveOutputConfig.length) {
|
|
30545
|
+
for (let i = 0; i < hostDirectiveOutputConfig.length; i += 2) {
|
|
30546
|
+
const index = hostDirectiveOutputConfig[i];
|
|
30547
|
+
const lookupName = hostDirectiveOutputConfig[i + 1];
|
|
30548
|
+
listenToOutput(tNode, tView, lView, index, lookupName, eventName, listenerFn, lCleanup, tCleanup);
|
|
30549
|
+
}
|
|
30550
|
+
}
|
|
30551
|
+
if (outputConfig && outputConfig.length) {
|
|
30552
|
+
for (const index of outputConfig) {
|
|
30553
|
+
listenToOutput(tNode, tView, lView, index, eventName, eventName, listenerFn, lCleanup, tCleanup);
|
|
30380
30554
|
}
|
|
30381
30555
|
}
|
|
30382
30556
|
}
|
|
30383
30557
|
}
|
|
30558
|
+
function listenToOutput(tNode, tView, lView, index, lookupName, eventName, listenerFn, lCleanup, tCleanup) {
|
|
30559
|
+
ngDevMode && assertIndexInRange(lView, index);
|
|
30560
|
+
const instance = lView[index];
|
|
30561
|
+
const def = tView.data[index];
|
|
30562
|
+
const propertyName = def.outputs[lookupName];
|
|
30563
|
+
const output = instance[propertyName];
|
|
30564
|
+
if (ngDevMode && !isOutputSubscribable(output)) {
|
|
30565
|
+
throw new Error(`@Output ${propertyName} not initialized in '${instance.constructor.name}'.`);
|
|
30566
|
+
}
|
|
30567
|
+
const subscription = output.subscribe(listenerFn);
|
|
30568
|
+
const idx = lCleanup.length;
|
|
30569
|
+
lCleanup.push(listenerFn, subscription);
|
|
30570
|
+
tCleanup && tCleanup.push(eventName, tNode.index, idx, -(idx + 1));
|
|
30571
|
+
}
|
|
30384
30572
|
function executeListenerWithErrorHandling(lView, context, listenerFn, e) {
|
|
30385
30573
|
const prevConsumer = setActiveConsumer$1(null);
|
|
30386
30574
|
try {
|
|
@@ -33544,11 +33732,12 @@ function executeWithInvalidateFallback(importMeta, id, callback) {
|
|
|
33544
33732
|
callback();
|
|
33545
33733
|
}
|
|
33546
33734
|
catch (e) {
|
|
33547
|
-
const
|
|
33735
|
+
const error = e;
|
|
33548
33736
|
// If we have all the necessary information and APIs to send off the invalidation
|
|
33549
33737
|
// request, send it before rethrowing so the dev server can decide what to do.
|
|
33550
|
-
if (id !== null &&
|
|
33551
|
-
|
|
33738
|
+
if (id !== null && error.message) {
|
|
33739
|
+
const toLog = error.message + (error.stack ? '\n' + error.stack : '');
|
|
33740
|
+
importMeta?.hot?.send?.('angular:invalidate', { id, message: toLog, error: true });
|
|
33552
33741
|
}
|
|
33553
33742
|
// Throw the error in case the page doesn't get refreshed.
|
|
33554
33743
|
throw e;
|
|
@@ -34978,7 +35167,7 @@ class Version {
|
|
|
34978
35167
|
/**
|
|
34979
35168
|
* @publicApi
|
|
34980
35169
|
*/
|
|
34981
|
-
const VERSION = new Version('
|
|
35170
|
+
const VERSION = new Version('20.0.0-next.0');
|
|
34982
35171
|
|
|
34983
35172
|
/**
|
|
34984
35173
|
* Combination of NgModuleFactory and ComponentFactories.
|
|
@@ -35812,10 +36001,9 @@ class ImagePerformanceWarning {
|
|
|
35812
36001
|
window = null;
|
|
35813
36002
|
observer = null;
|
|
35814
36003
|
options = inject(IMAGE_CONFIG);
|
|
35815
|
-
isBrowser = inject(PLATFORM_ID) === 'browser';
|
|
35816
36004
|
lcpImageUrl;
|
|
35817
36005
|
start() {
|
|
35818
|
-
if (
|
|
36006
|
+
if ((typeof ngServerMode !== 'undefined' && ngServerMode) ||
|
|
35819
36007
|
typeof PerformanceObserver === 'undefined' ||
|
|
35820
36008
|
(this.options?.disableImageSizeWarning && this.options?.disableImageLazyLoadWarning)) {
|
|
35821
36009
|
return;
|
|
@@ -35823,7 +36011,7 @@ class ImagePerformanceWarning {
|
|
|
35823
36011
|
this.observer = this.initPerformanceObserver();
|
|
35824
36012
|
const doc = getDocument();
|
|
35825
36013
|
const win = doc.defaultView;
|
|
35826
|
-
if (
|
|
36014
|
+
if (win) {
|
|
35827
36015
|
this.window = win;
|
|
35828
36016
|
// Wait to avoid race conditions where LCP image triggers
|
|
35829
36017
|
// load event before it's recorded by the performance observer
|
|
@@ -36489,7 +36677,7 @@ class DebugNgZoneForCheckNoChanges extends NgZone {
|
|
|
36489
36677
|
this.applicationRef ||= this.injector.get(ApplicationRef);
|
|
36490
36678
|
for (const view of this.applicationRef.allViews) {
|
|
36491
36679
|
try {
|
|
36492
|
-
checkNoChangesInternal(view._lView, this.checkNoChangesMode
|
|
36680
|
+
checkNoChangesInternal(view._lView, this.checkNoChangesMode);
|
|
36493
36681
|
}
|
|
36494
36682
|
catch (e) {
|
|
36495
36683
|
this.errorHandler ||= this.injector.get(ErrorHandler);
|
|
@@ -36520,7 +36708,7 @@ function exhaustiveCheckNoChangesInterval(interval, checkNoChangesMode) {
|
|
|
36520
36708
|
}
|
|
36521
36709
|
for (const view of applicationRef.allViews) {
|
|
36522
36710
|
try {
|
|
36523
|
-
checkNoChangesInternal(view._lView, checkNoChangesMode
|
|
36711
|
+
checkNoChangesInternal(view._lView, checkNoChangesMode);
|
|
36524
36712
|
}
|
|
36525
36713
|
catch (e) {
|
|
36526
36714
|
errorHandler.handleError(e);
|
|
@@ -40428,7 +40616,6 @@ function untracked(nonReactiveReadsFn) {
|
|
|
40428
40616
|
* Create a computed `Signal` which derives a reactive value from an expression.
|
|
40429
40617
|
*/
|
|
40430
40618
|
function computed(computation, options) {
|
|
40431
|
-
performanceMarkFeature('NgSignals');
|
|
40432
40619
|
const getter = createComputed$1(computation);
|
|
40433
40620
|
if (options?.equal) {
|
|
40434
40621
|
getter[SIGNAL$1].equal = options.equal;
|
|
@@ -40526,7 +40713,6 @@ function effect$1() { }
|
|
|
40526
40713
|
* Create a global `Effect` for the given reactive function.
|
|
40527
40714
|
*/
|
|
40528
40715
|
function microtaskEffect(effectFn, options) {
|
|
40529
|
-
performanceMarkFeature('NgSignals');
|
|
40530
40716
|
ngDevMode &&
|
|
40531
40717
|
assertNotInReactiveContext(effect$1, 'Call `effect` outside of a reactive context. For example, schedule the ' +
|
|
40532
40718
|
'effect inside the component constructor.');
|
|
@@ -40599,7 +40785,6 @@ function effect(effectFn, options) {
|
|
|
40599
40785
|
}
|
|
40600
40786
|
return microtaskEffect(effectFn, options);
|
|
40601
40787
|
}
|
|
40602
|
-
performanceMarkFeature('NgSignals');
|
|
40603
40788
|
ngDevMode &&
|
|
40604
40789
|
assertNotInReactiveContext(effect, 'Call `effect` outside of a reactive context. For example, schedule the ' +
|
|
40605
40790
|
'effect inside the component constructor.');
|
|
@@ -40796,7 +40981,6 @@ var ResourceStatus;
|
|
|
40796
40981
|
|
|
40797
40982
|
const identityFn = (v) => v;
|
|
40798
40983
|
function linkedSignal(optionsOrComputation, options) {
|
|
40799
|
-
performanceMarkFeature('NgSignals');
|
|
40800
40984
|
if (typeof optionsOrComputation === 'function') {
|
|
40801
40985
|
const getter = createLinkedSignal$1(optionsOrComputation, (identityFn), options?.equal);
|
|
40802
40986
|
return upgradeLinkedSignalGetter(getter);
|