@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.
Files changed (40) hide show
  1. package/fesm2022/core.mjs +474 -290
  2. package/fesm2022/core.mjs.map +1 -1
  3. package/fesm2022/primitives/event-dispatch.mjs +1 -1
  4. package/fesm2022/primitives/signals.mjs +1 -1
  5. package/fesm2022/rxjs-interop.mjs +1 -1
  6. package/fesm2022/testing.mjs +707 -5
  7. package/fesm2022/testing.mjs.map +1 -1
  8. package/index.d.ts +197 -22
  9. package/package.json +1 -1
  10. package/primitives/event-dispatch/index.d.ts +1 -1
  11. package/primitives/signals/index.d.ts +1 -1
  12. package/rxjs-interop/index.d.ts +1 -1
  13. package/schematics/bundles/{apply_import_manager-a930fcf1.js → apply_import_manager-0959b78c.js} +3 -3
  14. package/schematics/bundles/{checker-2eecc677.js → checker-cf6f7980.js} +121 -16
  15. package/schematics/bundles/cleanup-unused-imports.js +7 -7
  16. package/schematics/bundles/{compiler_host-c280a924.js → compiler_host-cc1379e9.js} +2 -2
  17. package/schematics/bundles/control-flow-migration.js +3 -3
  18. package/schematics/bundles/explicit-standalone-flag.js +5 -5
  19. package/schematics/bundles/{imports-abe29092.js → imports-31a38653.js} +1 -1
  20. package/schematics/bundles/{index-24a2ad1e.js → index-42d84d69.js} +4 -4
  21. package/schematics/bundles/{index-3891dd55.js → index-6675d6bc.js} +4 -4
  22. package/schematics/bundles/inject-migration.js +7 -7
  23. package/schematics/bundles/{leading_space-d190b83b.js → leading_space-6e7a8ec6.js} +1 -1
  24. package/schematics/bundles/{migrate_ts_type_references-71b3a951.js → migrate_ts_type_references-5089e4ef.js} +10 -6
  25. package/schematics/bundles/{ng_decorators-e699c081.js → ng_decorators-6878e227.js} +2 -2
  26. package/schematics/bundles/{nodes-a535b2be.js → nodes-ffdce442.js} +1 -1
  27. package/schematics/bundles/output-migration.js +7 -7
  28. package/schematics/bundles/pending-tasks.js +5 -5
  29. package/schematics/bundles/{program-24da9092.js → program-362689f0.js} +148 -148
  30. package/schematics/bundles/{project_paths-b073c4d6.js → project_paths-7d2daa1e.js} +3 -3
  31. package/schematics/bundles/{project_tsconfig_paths-e9ccccbf.js → project_tsconfig_paths-6c9cde78.js} +1 -1
  32. package/schematics/bundles/{property_name-7c8433f5.js → property_name-42030525.js} +1 -1
  33. package/schematics/bundles/provide-initializer.js +5 -5
  34. package/schematics/bundles/route-lazy-loading.js +5 -5
  35. package/schematics/bundles/self-closing-tags-migration.js +8 -8
  36. package/schematics/bundles/signal-input-migration.js +9 -9
  37. package/schematics/bundles/signal-queries-migration.js +9 -9
  38. package/schematics/bundles/signals.js +9 -9
  39. package/schematics/bundles/standalone-migration.js +9 -9
  40. package/testing/index.d.ts +297 -1
package/fesm2022/core.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Angular v19.2.0-rc.0
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
- const depPath = path ? `. Dependency path: ${path.join(' > ')} > ${token}` : '';
971
- throw new RuntimeError(-200 /* RuntimeErrorCode.CYCLIC_DI_DEPENDENCY */, ngDevMode ? `Circular dependency in DI detected for ${token}${depPath}` : token);
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
- let inputData = tNode.inputs;
12689
- let dataValue;
12690
- if (!nativeOnly && inputData != null && (dataValue = inputData[propName])) {
12691
- setInputsForProperty(tView, lView, dataValue, propName, value);
12692
- if (isComponentHost(tNode))
12693
- markDirtyIfOnPush(lView, tNode.index);
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
- else if (tNode.type & 3 /* TNodeType.AnyRNode */) {
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, inputConfig, value) {
12748
- if (tNode.type & (3 /* TNodeType.AnyRNode */ | 4 /* TNodeType.Container */)) {
12749
- // Note: we set the private name of the input as the reflected property, not the public one.
12750
- for (let i = 0; i < inputConfig.length; i += 2) {
12751
- const index = inputConfig[i];
12752
- const lookupName = inputConfig[i + 1];
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[lookupName][0], value);
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 == null || !tNode.inputs[propertyName]) {
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 the inputs of directives at the current node to corresponding value.
12958
+ * Set all directive inputs with the specific public name on the node.
12959
12959
  *
12960
- * @param tView The current TView
12961
- * @param lView the `LView` which contains the directives.
12962
- * @param inputs mapping between the public "input" name and privately-known,
12963
- * possibly minified, property names to write to.
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 setInputsForProperty(tView, lView, inputs, publicName, value) {
12967
- for (let i = 0; i < inputs.length; i += 2) {
12968
- const index = inputs[i];
12969
- ngDevMode && assertIndexInRange(lView, index);
12970
- const privateName = inputs[i + 1];
12971
- const instance = lView[index];
12972
- const def = tView.data[index];
12973
- writeToDirectiveInput(def, instance, privateName, value);
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, notifyErrorHandler = true, mode = 0 /* ChangeDetectionMode.Global */) {
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, notifyErrorHandler = true) {
14223
+ function checkNoChangesInternal(lView, mode) {
14165
14224
  setIsInCheckNoChangesMode(mode);
14166
14225
  try {
14167
- detectChangesInternal(lView, notifyErrorHandler);
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, notifyErrorHandler = true) {
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, this.notifyErrorHandler);
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, this.notifyErrorHandler);
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: undefined,
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
- const [directiveDefs, hostDirectiveDefs] = resolveHostDirectives(tView, tNode, matchedDirectiveDefs);
17463
- initializeDirectives(tView, lView, tNode, directiveDefs, exportsMap, hostDirectiveDefs);
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(tView, tNode, matches) {
17483
- const allDirectiveDefs = [];
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
- // TODO(pk): probably could return matches instead of taking in an array to fill in?
17593
+ allDirectiveDefs ??= [];
17488
17594
  hostDirectiveDefs ??= new Map();
17489
- // Components are inserted at the front of the matches array so that their lifecycle
17490
- // hooks run before any directive lifecycle hooks. This appears to be for ViewEngine
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
- if (isComponentDef(def)) {
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 (isComponentHost(tNode)) {
17507
- allDirectiveDefs.push(...matches.slice(1));
17508
- }
17509
- else {
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
- if (ngDevMode) {
17513
- assertNoDuplicateDirectives(allDirectiveDefs);
17514
- }
17515
- return [allDirectiveDefs, hostDirectiveDefs];
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 < directives.length; i++) {
17534
- diPublicInInjector(getOrCreateNodeInjectorForNode(tNode, lView), tView, directives[i].type);
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, directives.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 < directives.length; 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, directives.length, null);
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
- for (let i = 0; i < directives.length; i++) {
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, hostDirectiveDefinitionMap) {
17715
+ function initializeInputAndOutputAliases(tView, tNode, hostDirectiveDefs) {
17588
17716
  ngDevMode && assertFirstCreatePass(tView);
17589
- const start = tNode.directiveStart;
17590
- const end = tNode.directiveEnd;
17591
- const tViewData = tView.data;
17592
- const tNodeAttrs = tNode.attrs;
17593
- const inputsFromAttrs = [];
17594
- let inputsStore = null;
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
- if (inputsStore.hasOwnProperty('style')) {
17617
- tNode.flags |= 16 /* TNodeFlags.hasStyleInput */;
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
- function captureNodeBindings(mode, aliasMap, directiveIndex, bindingsResult, hostDirectiveAliasMap) {
17625
- for (let publicName in aliasMap) {
17626
- if (!aliasMap.hasOwnProperty(publicName)) {
17627
- continue;
17628
- }
17629
- const value = aliasMap[publicName];
17630
- if (value === undefined) {
17631
- continue;
17632
- }
17633
- bindingsResult ??= {};
17634
- // If there are no host directive mappings, we want to remap using the alias map from the
17635
- // definition itself. If there is an alias map, it has two functions:
17636
- // 1. It serves as an allowlist of bindings that are exposed by the host directives. Only the
17637
- // ones inside the host directive map will be exposed on the host.
17638
- // 2. The public name of the property is aliased using the host directive alias map, rather
17639
- // than the alias map from the definition.
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
- finalPublicName = hostDirectiveAliasMap[publicName];
17648
- }
17649
- if (mode === 0 /* CaptureNodeBindingMode.Inputs */) {
17650
- addPropertyBinding(bindingsResult, directiveIndex, finalPublicName, publicName);
17749
+ else {
17750
+ bindings = tNode.outputs ??= {};
17751
+ }
17752
+ bindings[publicName] ??= [];
17753
+ bindings[publicName].push(directiveIndex);
17754
+ setShadowStylingInputFlags(tNode, publicName);
17651
17755
  }
17652
- else {
17653
- addPropertyBinding(bindingsResult, directiveIndex, finalPublicName, value);
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 addPropertyBinding(bindings, directiveIndex, publicName, lookupName) {
17659
- if (bindings.hasOwnProperty(publicName)) {
17660
- bindings[publicName].push(directiveIndex, lookupName);
17783
+ function setShadowStylingInputFlags(tNode, publicName) {
17784
+ if (publicName === 'class') {
17785
+ tNode.flags |= 8 /* TNodeFlags.hasClassInput */;
17661
17786
  }
17662
- else {
17663
- bindings[publicName] = [directiveIndex, lookupName];
17787
+ else if (publicName === 'style') {
17788
+ tNode.flags |= 16 /* TNodeFlags.hasStyleInput */;
17664
17789
  }
17665
17790
  }
17666
17791
  /**
17667
- * Generates initialInputData for a node and stores it in the template's static storage
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 inputs Input alias map that was generated from the directive def inputs.
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 generateInitialInputs(inputs, directiveIndex, attrs) {
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
- // If we hit any other attribute markers, we're done anyway. None of those are valid inputs.
17697
- if (typeof attrName === 'number')
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
- if (inputs.hasOwnProperty(attrName)) {
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 (let j = 0; j < inputConfig.length; j += 2) {
17705
- if (inputConfig[j] === directiveIndex) {
17840
+ for (const index of inputConfig) {
17841
+ if (index === directiveIndex) {
17706
17842
  inputsToStore ??= [];
17707
- inputsToStore.push(inputConfig[j + 1], attrs[i + 1]);
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
- return inputsToStore;
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', '19.2.0-rc.0']
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 */, false /* notifyErrorHandler */);
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 inputData = this._tNode.inputs;
18065
- let dataValue;
18066
- if (inputData !== null && (dataValue = inputData[name])) {
18067
- this.previousInputValues ??= new Map();
18068
- // Do not set the input if it is the same as the last value
18069
- // This behavior matches `bindingUpdated` when binding inputs in templates.
18070
- if (this.previousInputValues.has(name) &&
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
- else {
18081
- if (ngDevMode) {
18082
- const cmpNameForError = stringifyForError(this.componentType);
18083
- let message = `Can't set value of the '${name}' input on the '${cmpNameForError}' component. `;
18084
- message += `Make sure that the '${name}' property is annotated with @Input() or a mapped @Input('${name}') exists.`;
18085
- reportUnknownPropertyError(message);
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
- createDirectivesInstancesInInstruction(declarationTView, declarationLView, tNode);
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
- // Find matching view based on serialized defer block state.
21244
- return (lContainer[DEHYDRATED_VIEWS]?.find((view) => view.data[DEFER_BLOCK_STATE$1] === lDetails[DEFER_BLOCK_STATE]) ?? null);
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
- // TODO(incremental-hydration):
21287
- // - what if we had some views in `lContainer[DEHYDRATED_VIEWS]`, but
21288
- // we didn't find a view that matches the expected state?
21289
- // - for example, handle a situation when a block was in the "completed" state
21290
- // on the server, but the loading failing on the client. How do we reconcile and cleanup?
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, notifyErrorHandler } of this.allViews) {
23704
- detectChangesInViewIfRequired(_lView, notifyErrorHandler, useGlobalCheck, this.zonelessEnabled);
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, notifyErrorHandler, isFirstPass, zonelessEnabled) {
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, notifyErrorHandler, mode);
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 (const dehydratedBlockId of hydrationQueue) {
24140
- await triggerResourceLoadingForHydration(dehydratedBlockId, dehydratedBlockRegistry);
24141
- await nextRender(injector);
24142
- // TODO(incremental-hydration): assert (in dev mode) that a defer block is present in the dehydrated registry
24143
- // at this point. If not - it means that the block has not been hydrated, for example due to different
24144
- // `@if` conditions on the client and the server. If we detect this case, we should also do the cleanup
24145
- // of all child block (promises, registry state, etc).
24146
- // TODO(incremental-hydration): call `rejectFn` when lDetails[DEFER_BLOCK_STATE] is `DeferBlockState.Error`.
24147
- blocksBeingHydrated.get(dehydratedBlockId).resolve();
24148
- // TODO(incremental-hydration): consider adding a wait for stability here
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(dehydratedBlockId, dehydratedBlockRegistry) {
24174
- const deferBlock = dehydratedBlockRegistry.get(dehydratedBlockId);
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
- setInputsForProperty(tView, lView, inputs[property], property, value);
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
- createDirectivesInstancesInInstruction(tView, lView, tNode);
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
- createDirectivesInstancesInInstruction(tView, lView, tNode);
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 && getOrCreateTViewCleanup(tView);
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
- // subscribe to directive outputs
30362
- const outputs = tNode.outputs;
30363
- let props;
30364
- if (processOutputs && outputs !== null && (props = outputs[eventName])) {
30365
- const propsLength = props.length;
30366
- if (propsLength) {
30367
- for (let i = 0; i < propsLength; i += 2) {
30368
- const index = props[i];
30369
- ngDevMode && assertIndexInRange(lView, index);
30370
- const minifiedName = props[i + 1];
30371
- const directiveInstance = lView[index];
30372
- const output = directiveInstance[minifiedName];
30373
- if (ngDevMode && !isOutputSubscribable(output)) {
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 errorMessage = e.message;
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 && errorMessage) {
33551
- importMeta?.hot?.send?.('angular:invalidate', { id, message: errorMessage, error: true });
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('19.2.0-rc.0');
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 (!this.isBrowser ||
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 (typeof win !== 'undefined') {
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, view.notifyErrorHandler);
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, view.notifyErrorHandler);
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);