@angular/core 19.2.0-next.1 → 19.2.0-next.3

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 (36) hide show
  1. package/fesm2022/core.mjs +865 -805
  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 +2 -1
  6. package/fesm2022/rxjs-interop.mjs.map +1 -1
  7. package/fesm2022/testing.mjs +5 -5
  8. package/index.d.ts +41 -12
  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-5ea49df9.js → apply_import_manager-f4d044b2.js} +3 -3
  14. package/schematics/bundles/{checker-78667e44.js → checker-32db85a6.js} +90 -52
  15. package/schematics/bundles/cleanup-unused-imports.js +6 -6
  16. package/schematics/bundles/{compiler_host-b22de7db.js → compiler_host-540e221c.js} +2 -2
  17. package/schematics/bundles/control-flow-migration.js +10 -3
  18. package/schematics/bundles/explicit-standalone-flag.js +5 -5
  19. package/schematics/bundles/{imports-31a38653.js → imports-abe29092.js} +1 -1
  20. package/schematics/bundles/{index-de135c2f.js → index-7ee8967e.js} +4 -4
  21. package/schematics/bundles/{index-3e744c38.js → index-d5020c9c.js} +4 -4
  22. package/schematics/bundles/inject-migration.js +6 -6
  23. package/schematics/bundles/{leading_space-6e7a8ec6.js → leading_space-d190b83b.js} +1 -1
  24. package/schematics/bundles/{migrate_ts_type_references-60e2a469.js → migrate_ts_type_references-26986908.js} +6 -6
  25. package/schematics/bundles/{nodes-88c2157f.js → nodes-a9f0b985.js} +2 -2
  26. package/schematics/bundles/output-migration.js +6 -6
  27. package/schematics/bundles/pending-tasks.js +5 -5
  28. package/schematics/bundles/{program-b0d98952.js → program-507de2f1.js} +124 -36
  29. package/schematics/bundles/{project_tsconfig_paths-6c9cde78.js → project_tsconfig_paths-e9ccccbf.js} +1 -1
  30. package/schematics/bundles/provide-initializer.js +5 -5
  31. package/schematics/bundles/route-lazy-loading.js +4 -4
  32. package/schematics/bundles/signal-input-migration.js +8 -8
  33. package/schematics/bundles/signal-queries-migration.js +8 -8
  34. package/schematics/bundles/signals.js +8 -8
  35. package/schematics/bundles/standalone-migration.js +8 -8
  36. package/testing/index.d.ts +1 -1
package/fesm2022/core.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Angular v19.2.0-next.1
2
+ * @license Angular v19.2.0-next.3
3
3
  * (c) 2010-2024 Google LLC. https://angular.io/
4
4
  * License: MIT
5
5
  */
@@ -377,13 +377,11 @@ function stringify(token) {
377
377
  * @returns concatenated string.
378
378
  */
379
379
  function concatStringsWithSpace(before, after) {
380
- return before == null || before === ''
381
- ? after === null
382
- ? ''
383
- : after
384
- : after == null || after === ''
385
- ? before
386
- : before + ' ' + after;
380
+ if (!before)
381
+ return after || '';
382
+ if (!after)
383
+ return before;
384
+ return `${before} ${after}`;
387
385
  }
388
386
  /**
389
387
  * Ellipses the string in the middle when longer than the max length
@@ -2902,6 +2900,7 @@ const ON_DESTROY_HOOKS = 21;
2902
2900
  const EFFECTS_TO_SCHEDULE = 22;
2903
2901
  const EFFECTS = 23;
2904
2902
  const REACTIVE_TEMPLATE_CONSUMER = 24;
2903
+ const AFTER_RENDER_SEQUENCES_TO_ADD = 25;
2905
2904
  /**
2906
2905
  * Size of LView's header. Necessary to adjust for it when setting slots.
2907
2906
  *
@@ -2909,7 +2908,7 @@ const REACTIVE_TEMPLATE_CONSUMER = 24;
2909
2908
  * instruction index into `LView` index. All other indexes should be in the `LView` index space and
2910
2909
  * there should be no need to refer to `HEADER_OFFSET` anywhere else.
2911
2910
  */
2912
- const HEADER_OFFSET = 25;
2911
+ const HEADER_OFFSET = 26;
2913
2912
 
2914
2913
  /**
2915
2914
  * Special location which allows easy identification of type. If we have an array which was
@@ -3067,7 +3066,7 @@ function assertProjectionSlots(lView, errMessage) {
3067
3066
  function assertParentView(lView, errMessage) {
3068
3067
  assertDefined(lView, errMessage || "Component views should always have a parent view (component's host view)");
3069
3068
  }
3070
- function assertNoDuplicateDirectives(directives) {
3069
+ function assertNoDuplicateDirectives$1(directives) {
3071
3070
  // The array needs at least two elements in order to have duplicates.
3072
3071
  if (directives.length < 2) {
3073
3072
  return;
@@ -3419,7 +3418,7 @@ function requiresRefreshOrTraversal(lView) {
3419
3418
  * parents above.
3420
3419
  */
3421
3420
  function updateAncestorTraversalFlagsOnAttach(lView) {
3422
- lView[ENVIRONMENT].changeDetectionScheduler?.notify(9 /* NotificationSource.ViewAttached */);
3421
+ lView[ENVIRONMENT].changeDetectionScheduler?.notify(8 /* NotificationSource.ViewAttached */);
3423
3422
  if (lView[FLAGS] & 64 /* LViewFlags.Dirty */) {
3424
3423
  lView[FLAGS] |= 1024 /* LViewFlags.RefreshView */;
3425
3424
  }
@@ -4060,7 +4059,7 @@ function ɵɵnamespaceHTML() {
4060
4059
  function namespaceHTMLInternal() {
4061
4060
  instructionState.lFrame.currentNamespace = null;
4062
4061
  }
4063
- function getNamespace$1() {
4062
+ function getNamespace() {
4064
4063
  return instructionState.lFrame.currentNamespace;
4065
4064
  }
4066
4065
  let _wasLastNodeCreated = true;
@@ -6162,7 +6161,7 @@ class PendingTasks {
6162
6161
  return;
6163
6162
  }
6164
6163
  // Notifying the scheduler will hold application stability open until the next tick.
6165
- this.scheduler.notify(12 /* NotificationSource.PendingTaskRemoved */);
6164
+ this.scheduler.notify(11 /* NotificationSource.PendingTaskRemoved */);
6166
6165
  this.internalPendingTasks.remove(taskId);
6167
6166
  };
6168
6167
  }
@@ -8656,6 +8655,23 @@ function assertNotInReactiveContext(debugFn, extraContext) {
8656
8655
  }
8657
8656
  }
8658
8657
 
8658
+ class ViewContext {
8659
+ view;
8660
+ node;
8661
+ constructor(view, node) {
8662
+ this.view = view;
8663
+ this.node = node;
8664
+ }
8665
+ /**
8666
+ * @internal
8667
+ * @nocollapse
8668
+ */
8669
+ static __NG_ELEMENT_ID__ = injectViewContext;
8670
+ }
8671
+ function injectViewContext() {
8672
+ return new ViewContext(getLView(), getCurrentTNode());
8673
+ }
8674
+
8659
8675
  /**
8660
8676
  * The phase to run an `afterRender` or `afterNextRender` callback in.
8661
8677
  *
@@ -8794,7 +8810,7 @@ class AfterRenderImpl {
8794
8810
  this.sequences.add(sequence);
8795
8811
  }
8796
8812
  if (this.deferredRegistrations.size > 0) {
8797
- this.scheduler.notify(8 /* NotificationSource.DeferredRenderHook */);
8813
+ this.scheduler.notify(7 /* NotificationSource.RenderHook */);
8798
8814
  }
8799
8815
  this.deferredRegistrations.clear();
8800
8816
  if (hasSequencesToExecute) {
@@ -8802,16 +8818,27 @@ class AfterRenderImpl {
8802
8818
  }
8803
8819
  }
8804
8820
  register(sequence) {
8805
- if (!this.executing) {
8806
- this.sequences.add(sequence);
8807
- // Trigger an `ApplicationRef.tick()` if one is not already pending/running, because we have a
8808
- // new render hook that needs to run.
8809
- this.scheduler.notify(7 /* NotificationSource.RenderHook */);
8821
+ const { view } = sequence;
8822
+ if (view !== undefined) {
8823
+ // Delay adding it to the manager, add it to the view instead.
8824
+ (view[AFTER_RENDER_SEQUENCES_TO_ADD] ??= []).push(sequence);
8825
+ // Mark the view for traversal to ensure we eventually schedule the afterNextRender.
8826
+ markAncestorsForTraversal(view);
8827
+ view[FLAGS] |= 8192 /* LViewFlags.HasChildViewsToRefresh */;
8828
+ }
8829
+ else if (!this.executing) {
8830
+ this.addSequence(sequence);
8810
8831
  }
8811
8832
  else {
8812
8833
  this.deferredRegistrations.add(sequence);
8813
8834
  }
8814
8835
  }
8836
+ addSequence(sequence) {
8837
+ this.sequences.add(sequence);
8838
+ // Trigger an `ApplicationRef.tick()` if one is not already pending/running, because we have a
8839
+ // new render hook that needs to run.
8840
+ this.scheduler.notify(7 /* NotificationSource.RenderHook */);
8841
+ }
8815
8842
  unregister(sequence) {
8816
8843
  if (this.executing && this.sequences.has(sequence)) {
8817
8844
  // We can't remove an `AfterRenderSequence` in the middle of iteration.
@@ -8841,6 +8868,7 @@ class AfterRenderImpl {
8841
8868
  class AfterRenderSequence {
8842
8869
  impl;
8843
8870
  hooks;
8871
+ view;
8844
8872
  once;
8845
8873
  snapshot;
8846
8874
  /**
@@ -8854,9 +8882,10 @@ class AfterRenderSequence {
8854
8882
  */
8855
8883
  pipelinedValue = undefined;
8856
8884
  unregisterOnDestroy;
8857
- constructor(impl, hooks, once, destroyRef, snapshot = null) {
8885
+ constructor(impl, hooks, view, once, destroyRef, snapshot = null) {
8858
8886
  this.impl = impl;
8859
8887
  this.hooks = hooks;
8888
+ this.view = view;
8860
8889
  this.once = once;
8861
8890
  this.snapshot = snapshot;
8862
8891
  this.unregisterOnDestroy = destroyRef?.onDestroy(() => this.destroy());
@@ -8874,6 +8903,10 @@ class AfterRenderSequence {
8874
8903
  destroy() {
8875
8904
  this.impl.unregister(this);
8876
8905
  this.unregisterOnDestroy?.();
8906
+ const scheduled = this.view?.[AFTER_RENDER_SEQUENCES_TO_ADD];
8907
+ if (scheduled) {
8908
+ this.view[AFTER_RENDER_SEQUENCES_TO_ADD] = scheduled.filter((s) => s !== this);
8909
+ }
8877
8910
  }
8878
8911
  }
8879
8912
 
@@ -8924,7 +8957,8 @@ function afterRenderImpl(callbackOrSpec, injector, options, once) {
8924
8957
  const tracing = injector.get(TracingService, null, { optional: true });
8925
8958
  const hooks = options?.phase ?? AfterRenderPhase.MixedReadWrite;
8926
8959
  const destroyRef = options?.manualCleanup !== true ? injector.get(DestroyRef) : null;
8927
- const sequence = new AfterRenderSequence(manager.impl, getHooks(callbackOrSpec, hooks), once, destroyRef, tracing?.snapshot(null));
8960
+ const viewContext = injector.get(ViewContext, null, { optional: true });
8961
+ const sequence = new AfterRenderSequence(manager.impl, getHooks(callbackOrSpec, hooks), viewContext?.view, once, destroyRef, tracing?.snapshot(null));
8928
8962
  manager.impl.register(sequence);
8929
8963
  return sequence;
8930
8964
  }
@@ -9396,9 +9430,11 @@ function getTriggerElement(triggerLView, triggerIndex) {
9396
9430
  function registerDomTrigger(initialLView, tNode, triggerIndex, walkUpTimes, registerFn, callback, type) {
9397
9431
  const injector = initialLView[INJECTOR];
9398
9432
  const zone = injector.get(NgZone);
9433
+ let poll;
9399
9434
  function pollDomTrigger() {
9400
9435
  // If the initial view was destroyed, we don't need to do anything.
9401
9436
  if (isDestroyed(initialLView)) {
9437
+ poll.destroy();
9402
9438
  return;
9403
9439
  }
9404
9440
  const lDetails = getLDeferBlockDetails(initialLView, tNode);
@@ -9406,14 +9442,16 @@ function registerDomTrigger(initialLView, tNode, triggerIndex, walkUpTimes, regi
9406
9442
  // If the block was loaded before the trigger was resolved, we don't need to do anything.
9407
9443
  if (renderedState !== DeferBlockInternalState.Initial &&
9408
9444
  renderedState !== DeferBlockState.Placeholder) {
9445
+ poll.destroy();
9409
9446
  return;
9410
9447
  }
9411
9448
  const triggerLView = getTriggerLView(initialLView, tNode, walkUpTimes);
9412
9449
  // Keep polling until we resolve the trigger's LView.
9413
9450
  if (!triggerLView) {
9414
- afterNextRender({ read: pollDomTrigger }, { injector });
9451
+ // Keep polling.
9415
9452
  return;
9416
9453
  }
9454
+ poll.destroy();
9417
9455
  // It's possible that the trigger's view was destroyed before we resolved the trigger element.
9418
9456
  if (isDestroyed(triggerLView)) {
9419
9457
  return;
@@ -9440,7 +9478,7 @@ function registerDomTrigger(initialLView, tNode, triggerIndex, walkUpTimes, regi
9440
9478
  storeTriggerCleanupFn(type, lDetails, cleanup);
9441
9479
  }
9442
9480
  // Begin polling for the trigger.
9443
- afterNextRender({ read: pollDomTrigger }, { injector });
9481
+ poll = afterRender({ read: pollDomTrigger }, { injector });
9444
9482
  }
9445
9483
 
9446
9484
  const DEFER_BLOCK_SSR_ID_ATTRIBUTE = 'ngb';
@@ -11648,14 +11686,6 @@ function getExpressionChangedErrorDetails(lView, bindingIndex, oldValue, newValu
11648
11686
  return { propName: undefined, oldValue, newValue };
11649
11687
  }
11650
11688
 
11651
- /** Flags describing an input for a directive. */
11652
- var InputFlags;
11653
- (function (InputFlags) {
11654
- InputFlags[InputFlags["None"] = 0] = "None";
11655
- InputFlags[InputFlags["SignalBased"] = 1] = "SignalBased";
11656
- InputFlags[InputFlags["HasDecoratorInputTransform"] = 2] = "HasDecoratorInputTransform";
11657
- })(InputFlags || (InputFlags = {}));
11658
-
11659
11689
  /**
11660
11690
  * Returns an index of `classToSearch` in `className` taking token boundaries into account.
11661
11691
  *
@@ -12265,38 +12295,13 @@ function selectIndexInternal(tView, lView, index, checkNoChangesMode) {
12265
12295
  setSelectedIndex(index);
12266
12296
  }
12267
12297
 
12268
- function ɵɵdirectiveInject(token, flags = InjectFlags.Default) {
12269
- const lView = getLView();
12270
- // Fall back to inject() if view hasn't been created. This situation can happen in tests
12271
- // if inject utilities are used before bootstrapping.
12272
- if (lView === null) {
12273
- // Verify that we will not get into infinite loop.
12274
- ngDevMode && assertInjectImplementationNotEqual(ɵɵdirectiveInject);
12275
- return ɵɵinject(token, flags);
12276
- }
12277
- const tNode = getCurrentTNode();
12278
- const value = getOrCreateInjectable(tNode, lView, resolveForwardRef(token), flags);
12279
- ngDevMode && emitInjectEvent(token, value, flags);
12280
- return value;
12281
- }
12282
- /**
12283
- * Throws an error indicating that a factory function could not be generated by the compiler for a
12284
- * particular class.
12285
- *
12286
- * This instruction allows the actual error message to be optimized away when ngDevMode is turned
12287
- * off, saving bytes of generated code while still providing a good experience in dev mode.
12288
- *
12289
- * The name of the class is not mentioned here, but will be in the generated factory function name
12290
- * and thus in the stack trace.
12291
- *
12292
- * @codeGenApi
12293
- */
12294
- function ɵɵinvalidFactory() {
12295
- const msg = ngDevMode
12296
- ? `This constructor was not compatible with Dependency Injection.`
12297
- : 'invalid';
12298
- throw new Error(msg);
12299
- }
12298
+ /** Flags describing an input for a directive. */
12299
+ var InputFlags;
12300
+ (function (InputFlags) {
12301
+ InputFlags[InputFlags["None"] = 0] = "None";
12302
+ InputFlags[InputFlags["SignalBased"] = 1] = "SignalBased";
12303
+ InputFlags[InputFlags["HasDecoratorInputTransform"] = 2] = "HasDecoratorInputTransform";
12304
+ })(InputFlags || (InputFlags = {}));
12300
12305
 
12301
12306
  function writeToDirectiveInput(def, instance, publicName, privateName, flags, value) {
12302
12307
  const prevConsumer = setActiveConsumer$1(null);
@@ -12364,34 +12369,6 @@ function createLView(parentLView, tView, context, flags, host, tHostNode, enviro
12364
12369
  tView.type == 2 /* TViewType.Embedded */ ? parentLView[DECLARATION_COMPONENT_VIEW] : lView;
12365
12370
  return lView;
12366
12371
  }
12367
- /**
12368
- * When elements are created dynamically after a view blueprint is created (e.g. through
12369
- * i18nApply()), we need to adjust the blueprint for future
12370
- * template passes.
12371
- *
12372
- * @param tView `TView` associated with `LView`
12373
- * @param lView The `LView` containing the blueprint to adjust
12374
- * @param numSlotsToAlloc The number of slots to alloc in the LView, should be >0
12375
- * @param initialValue Initial value to store in blueprint
12376
- */
12377
- function allocExpando(tView, lView, numSlotsToAlloc, initialValue) {
12378
- if (numSlotsToAlloc === 0)
12379
- return -1;
12380
- if (ngDevMode) {
12381
- assertFirstCreatePass(tView);
12382
- assertSame(tView, lView[TVIEW], '`LView` must be associated with `TView`!');
12383
- assertEqual(tView.data.length, lView.length, 'Expecting LView to be same size as TView');
12384
- assertEqual(tView.data.length, tView.blueprint.length, 'Expecting Blueprint to be same size as TView');
12385
- assertFirstUpdatePass(tView);
12386
- }
12387
- const allocIdx = lView.length;
12388
- for (let i = 0; i < numSlotsToAlloc; i++) {
12389
- lView.push(initialValue);
12390
- tView.blueprint.push(initialValue);
12391
- tView.data.push(null);
12392
- }
12393
- return allocIdx;
12394
- }
12395
12372
  function executeTemplate(tView, lView, templateFn, rf, context) {
12396
12373
  const prevSelectedIndex = getSelectedIndex();
12397
12374
  const isUpdatePhase = rf & 2 /* RenderFlags.Update */;
@@ -12604,106 +12581,6 @@ function applyRootElementTransformImpl(rootElement) {
12604
12581
  function enableApplyRootElementTransformImpl() {
12605
12582
  _applyRootElementTransformImpl = applyRootElementTransformImpl;
12606
12583
  }
12607
- function captureNodeBindings(mode, aliasMap, directiveIndex, bindingsResult, hostDirectiveAliasMap) {
12608
- for (let publicName in aliasMap) {
12609
- if (!aliasMap.hasOwnProperty(publicName)) {
12610
- continue;
12611
- }
12612
- const value = aliasMap[publicName];
12613
- if (value === undefined) {
12614
- continue;
12615
- }
12616
- bindingsResult ??= {};
12617
- let internalName;
12618
- let inputFlags = InputFlags.None;
12619
- // For inputs, the value might be an array capturing additional
12620
- // input flags.
12621
- if (Array.isArray(value)) {
12622
- internalName = value[0];
12623
- inputFlags = value[1];
12624
- }
12625
- else {
12626
- internalName = value;
12627
- }
12628
- // If there are no host directive mappings, we want to remap using the alias map from the
12629
- // definition itself. If there is an alias map, it has two functions:
12630
- // 1. It serves as an allowlist of bindings that are exposed by the host directives. Only the
12631
- // ones inside the host directive map will be exposed on the host.
12632
- // 2. The public name of the property is aliased using the host directive alias map, rather
12633
- // than the alias map from the definition.
12634
- let finalPublicName = publicName;
12635
- if (hostDirectiveAliasMap !== null) {
12636
- // If there is no mapping, it's not part of the allowlist and this input/output
12637
- // is not captured and should be ignored.
12638
- if (!hostDirectiveAliasMap.hasOwnProperty(publicName)) {
12639
- continue;
12640
- }
12641
- finalPublicName = hostDirectiveAliasMap[publicName];
12642
- }
12643
- if (mode === 0 /* CaptureNodeBindingMode.Inputs */) {
12644
- addPropertyBinding(bindingsResult, directiveIndex, finalPublicName, internalName, inputFlags);
12645
- }
12646
- else {
12647
- addPropertyBinding(bindingsResult, directiveIndex, finalPublicName, internalName);
12648
- }
12649
- }
12650
- return bindingsResult;
12651
- }
12652
- function addPropertyBinding(bindings, directiveIndex, publicName, internalName, inputFlags) {
12653
- let values;
12654
- if (bindings.hasOwnProperty(publicName)) {
12655
- (values = bindings[publicName]).push(directiveIndex, internalName);
12656
- }
12657
- else {
12658
- values = bindings[publicName] = [directiveIndex, internalName];
12659
- }
12660
- if (inputFlags !== undefined) {
12661
- values.push(inputFlags);
12662
- }
12663
- }
12664
- /**
12665
- * Initializes data structures required to work with directive inputs and outputs.
12666
- * Initialization is done for all directives matched on a given TNode.
12667
- */
12668
- function initializeInputAndOutputAliases(tView, tNode, hostDirectiveDefinitionMap) {
12669
- ngDevMode && assertFirstCreatePass(tView);
12670
- const start = tNode.directiveStart;
12671
- const end = tNode.directiveEnd;
12672
- const tViewData = tView.data;
12673
- const tNodeAttrs = tNode.attrs;
12674
- const inputsFromAttrs = [];
12675
- let inputsStore = null;
12676
- let outputsStore = null;
12677
- for (let directiveIndex = start; directiveIndex < end; directiveIndex++) {
12678
- const directiveDef = tViewData[directiveIndex];
12679
- const aliasData = hostDirectiveDefinitionMap
12680
- ? hostDirectiveDefinitionMap.get(directiveDef)
12681
- : null;
12682
- const aliasedInputs = aliasData ? aliasData.inputs : null;
12683
- const aliasedOutputs = aliasData ? aliasData.outputs : null;
12684
- inputsStore = captureNodeBindings(0 /* CaptureNodeBindingMode.Inputs */, directiveDef.inputs, directiveIndex, inputsStore, aliasedInputs);
12685
- outputsStore = captureNodeBindings(1 /* CaptureNodeBindingMode.Outputs */, directiveDef.outputs, directiveIndex, outputsStore, aliasedOutputs);
12686
- // Do not use unbound attributes as inputs to structural directives, since structural
12687
- // directive inputs can only be set using microsyntax (e.g. `<div *dir="exp">`).
12688
- // TODO(FW-1930): microsyntax expressions may also contain unbound/static attributes, which
12689
- // should be set for inline templates.
12690
- const initialInputs = inputsStore !== null && tNodeAttrs !== null && !isInlineTemplate(tNode)
12691
- ? generateInitialInputs(inputsStore, directiveIndex, tNodeAttrs)
12692
- : null;
12693
- inputsFromAttrs.push(initialInputs);
12694
- }
12695
- if (inputsStore !== null) {
12696
- if (inputsStore.hasOwnProperty('class')) {
12697
- tNode.flags |= 8 /* TNodeFlags.hasClassInput */;
12698
- }
12699
- if (inputsStore.hasOwnProperty('style')) {
12700
- tNode.flags |= 16 /* TNodeFlags.hasStyleInput */;
12701
- }
12702
- }
12703
- tNode.initialInputs = inputsFromAttrs;
12704
- tNode.inputs = inputsStore;
12705
- tNode.outputs = outputsStore;
12706
- }
12707
12584
  /**
12708
12585
  * Mapping between attributes names that don't correspond to their element property names.
12709
12586
  *
@@ -12804,126 +12681,6 @@ function setNgReflectProperties(lView, element, type, dataValue, value) {
12804
12681
  }
12805
12682
  }
12806
12683
  }
12807
- /**
12808
- * Resolve the matched directives on a node.
12809
- */
12810
- function resolveDirectives(tView, lView, tNode, localRefs) {
12811
- // Please make sure to have explicit type for `exportsMap`. Inferred type triggers bug in
12812
- // tsickle.
12813
- ngDevMode && assertFirstCreatePass(tView);
12814
- if (getBindingsEnabled()) {
12815
- const exportsMap = localRefs === null ? null : { '': -1 };
12816
- const matchedDirectiveDefs = findDirectiveDefMatches(tView, tNode);
12817
- if (matchedDirectiveDefs !== null) {
12818
- const [directiveDefs, hostDirectiveDefs] = resolveHostDirectives(tView, tNode, matchedDirectiveDefs);
12819
- initializeDirectives(tView, lView, tNode, directiveDefs, exportsMap, hostDirectiveDefs);
12820
- }
12821
- if (exportsMap)
12822
- cacheMatchingLocalNames(tNode, localRefs, exportsMap);
12823
- }
12824
- // Merge the template attrs last so that they have the highest priority.
12825
- tNode.mergedAttrs = mergeHostAttrs(tNode.mergedAttrs, tNode.attrs);
12826
- }
12827
- /** Initializes the data structures necessary for a list of directives to be instantiated. */
12828
- function initializeDirectives(tView, lView, tNode, directives, exportsMap, hostDirectiveDefs) {
12829
- ngDevMode && assertFirstCreatePass(tView);
12830
- // Publishes the directive types to DI so they can be injected. Needs to
12831
- // happen in a separate pass before the TNode flags have been initialized.
12832
- for (let i = 0; i < directives.length; i++) {
12833
- diPublicInInjector(getOrCreateNodeInjectorForNode(tNode, lView), tView, directives[i].type);
12834
- }
12835
- initTNodeFlags(tNode, tView.data.length, directives.length);
12836
- // When the same token is provided by several directives on the same node, some rules apply in
12837
- // the viewEngine:
12838
- // - viewProviders have priority over providers
12839
- // - the last directive in NgModule.declarations has priority over the previous one
12840
- // So to match these rules, the order in which providers are added in the arrays is very
12841
- // important.
12842
- for (let i = 0; i < directives.length; i++) {
12843
- const def = directives[i];
12844
- if (def.providersResolver)
12845
- def.providersResolver(def);
12846
- }
12847
- let preOrderHooksFound = false;
12848
- let preOrderCheckHooksFound = false;
12849
- let directiveIdx = allocExpando(tView, lView, directives.length, null);
12850
- ngDevMode &&
12851
- assertSame(directiveIdx, tNode.directiveStart, 'TNode.directiveStart should point to just allocated space');
12852
- for (let i = 0; i < directives.length; i++) {
12853
- const def = directives[i];
12854
- // Merge the attrs in the order of matches. This assumes that the first directive is the
12855
- // component itself, so that the component has the least priority.
12856
- tNode.mergedAttrs = mergeHostAttrs(tNode.mergedAttrs, def.hostAttrs);
12857
- configureViewWithDirective(tView, tNode, lView, directiveIdx, def);
12858
- saveNameToExportMap(directiveIdx, def, exportsMap);
12859
- if (def.contentQueries !== null)
12860
- tNode.flags |= 4 /* TNodeFlags.hasContentQuery */;
12861
- if (def.hostBindings !== null || def.hostAttrs !== null || def.hostVars !== 0)
12862
- tNode.flags |= 64 /* TNodeFlags.hasHostBindings */;
12863
- const lifeCycleHooks = def.type.prototype;
12864
- // Only push a node index into the preOrderHooks array if this is the first
12865
- // pre-order hook found on this node.
12866
- if (!preOrderHooksFound &&
12867
- (lifeCycleHooks.ngOnChanges || lifeCycleHooks.ngOnInit || lifeCycleHooks.ngDoCheck)) {
12868
- // We will push the actual hook function into this array later during dir instantiation.
12869
- // We cannot do it now because we must ensure hooks are registered in the same
12870
- // order that directives are created (i.e. injection order).
12871
- (tView.preOrderHooks ??= []).push(tNode.index);
12872
- preOrderHooksFound = true;
12873
- }
12874
- if (!preOrderCheckHooksFound && (lifeCycleHooks.ngOnChanges || lifeCycleHooks.ngDoCheck)) {
12875
- (tView.preOrderCheckHooks ??= []).push(tNode.index);
12876
- preOrderCheckHooksFound = true;
12877
- }
12878
- directiveIdx++;
12879
- }
12880
- initializeInputAndOutputAliases(tView, tNode, hostDirectiveDefs);
12881
- }
12882
- /**
12883
- * Add `hostBindings` to the `TView.hostBindingOpCodes`.
12884
- *
12885
- * @param tView `TView` to which the `hostBindings` should be added.
12886
- * @param tNode `TNode` the element which contains the directive
12887
- * @param directiveIdx Directive index in view.
12888
- * @param directiveVarsIdx Where will the directive's vars be stored
12889
- * @param def `ComponentDef`/`DirectiveDef`, which contains the `hostVars`/`hostBindings` to add.
12890
- */
12891
- function registerHostBindingOpCodes(tView, tNode, directiveIdx, directiveVarsIdx, def) {
12892
- ngDevMode && assertFirstCreatePass(tView);
12893
- const hostBindings = def.hostBindings;
12894
- if (hostBindings) {
12895
- let hostBindingOpCodes = tView.hostBindingOpCodes;
12896
- if (hostBindingOpCodes === null) {
12897
- hostBindingOpCodes = tView.hostBindingOpCodes = [];
12898
- }
12899
- const elementIndx = ~tNode.index;
12900
- if (lastSelectedElementIdx(hostBindingOpCodes) != elementIndx) {
12901
- // Conditionally add select element so that we are more efficient in execution.
12902
- // NOTE: this is strictly not necessary and it trades code size for runtime perf.
12903
- // (We could just always add it.)
12904
- hostBindingOpCodes.push(elementIndx);
12905
- }
12906
- hostBindingOpCodes.push(directiveIdx, directiveVarsIdx, hostBindings);
12907
- }
12908
- }
12909
- /**
12910
- * Returns the last selected element index in the `HostBindingOpCodes`
12911
- *
12912
- * For perf reasons we don't need to update the selected element index in `HostBindingOpCodes` only
12913
- * if it changes. This method returns the last index (or '0' if not found.)
12914
- *
12915
- * Selected element index are only the ones which are negative.
12916
- */
12917
- function lastSelectedElementIdx(hostBindingOpCodes) {
12918
- let i = hostBindingOpCodes.length;
12919
- while (i > 0) {
12920
- const value = hostBindingOpCodes[--i];
12921
- if (typeof value === 'number' && value < 0) {
12922
- return value;
12923
- }
12924
- }
12925
- return 0;
12926
- }
12927
12684
  /**
12928
12685
  * Instantiate all the directives that were previously resolved on the current node.
12929
12686
  */
@@ -13017,121 +12774,6 @@ function findDirectiveDefMatches(tView, tNode) {
13017
12774
  }
13018
12775
  return matches;
13019
12776
  }
13020
- function resolveHostDirectives(tView, tNode, matches) {
13021
- const allDirectiveDefs = [];
13022
- let hostDirectiveDefs = null;
13023
- for (const def of matches) {
13024
- if (def.findHostDirectiveDefs !== null) {
13025
- // TODO(pk): probably could return matches instead of taking in an array to fill in?
13026
- hostDirectiveDefs ??= new Map();
13027
- // Components are inserted at the front of the matches array so that their lifecycle
13028
- // hooks run before any directive lifecycle hooks. This appears to be for ViewEngine
13029
- // compatibility. This logic doesn't make sense with host directives, because it
13030
- // would allow the host directives to undo any overrides the host may have made.
13031
- // To handle this case, the host directives of components are inserted at the beginning
13032
- // of the array, followed by the component. As such, the insertion order is as follows:
13033
- // 1. Host directives belonging to the selector-matched component.
13034
- // 2. Selector-matched component.
13035
- // 3. Host directives belonging to selector-matched directives.
13036
- // 4. Selector-matched directives.
13037
- def.findHostDirectiveDefs(def, allDirectiveDefs, hostDirectiveDefs);
13038
- }
13039
- if (isComponentDef(def)) {
13040
- allDirectiveDefs.push(def);
13041
- markAsComponentHost(tView, tNode, allDirectiveDefs.length - 1);
13042
- }
13043
- }
13044
- if (isComponentHost(tNode)) {
13045
- allDirectiveDefs.push(...matches.slice(1));
13046
- }
13047
- else {
13048
- allDirectiveDefs.push(...matches);
13049
- }
13050
- if (ngDevMode) {
13051
- assertNoDuplicateDirectives(allDirectiveDefs);
13052
- }
13053
- return [allDirectiveDefs, hostDirectiveDefs];
13054
- }
13055
- /**
13056
- * Marks a given TNode as a component's host. This consists of:
13057
- * - setting the component offset on the TNode.
13058
- * - storing index of component's host element so it will be queued for view refresh during CD.
13059
- */
13060
- function markAsComponentHost(tView, hostTNode, componentOffset) {
13061
- ngDevMode && assertFirstCreatePass(tView);
13062
- ngDevMode && assertGreaterThan(componentOffset, -1, 'componentOffset must be great than -1');
13063
- hostTNode.componentOffset = componentOffset;
13064
- (tView.components ??= []).push(hostTNode.index);
13065
- }
13066
- /** Caches local names and their matching directive indices for query and template lookups. */
13067
- function cacheMatchingLocalNames(tNode, localRefs, exportsMap) {
13068
- if (localRefs) {
13069
- const localNames = (tNode.localNames = []);
13070
- // Local names must be stored in tNode in the same order that localRefs are defined
13071
- // in the template to ensure the data is loaded in the same slots as their refs
13072
- // in the template (for template queries).
13073
- for (let i = 0; i < localRefs.length; i += 2) {
13074
- const index = exportsMap[localRefs[i + 1]];
13075
- if (index == null)
13076
- throw new RuntimeError(-301 /* RuntimeErrorCode.EXPORT_NOT_FOUND */, ngDevMode && `Export of name '${localRefs[i + 1]}' not found!`);
13077
- localNames.push(localRefs[i], index);
13078
- }
13079
- }
13080
- }
13081
- /**
13082
- * Builds up an export map as directives are created, so local refs can be quickly mapped
13083
- * to their directive instances.
13084
- */
13085
- function saveNameToExportMap(directiveIdx, def, exportsMap) {
13086
- if (exportsMap) {
13087
- if (def.exportAs) {
13088
- for (let i = 0; i < def.exportAs.length; i++) {
13089
- exportsMap[def.exportAs[i]] = directiveIdx;
13090
- }
13091
- }
13092
- if (isComponentDef(def))
13093
- exportsMap[''] = directiveIdx;
13094
- }
13095
- }
13096
- /**
13097
- * Initializes the flags on the current node, setting all indices to the initial index,
13098
- * the directive count to 0, and adding the isComponent flag.
13099
- * @param index the initial index
13100
- */
13101
- function initTNodeFlags(tNode, index, numberOfDirectives) {
13102
- ngDevMode &&
13103
- assertNotEqual(numberOfDirectives, tNode.directiveEnd - tNode.directiveStart, 'Reached the max number of directives');
13104
- tNode.flags |= 1 /* TNodeFlags.isDirectiveHost */;
13105
- // When the first directive is created on a node, save the index
13106
- tNode.directiveStart = index;
13107
- tNode.directiveEnd = index + numberOfDirectives;
13108
- tNode.providerIndexes = index;
13109
- }
13110
- /**
13111
- * Setup directive for instantiation.
13112
- *
13113
- * We need to create a `NodeInjectorFactory` which is then inserted in both the `Blueprint` as well
13114
- * as `LView`. `TView` gets the `DirectiveDef`.
13115
- *
13116
- * @param tView `TView`
13117
- * @param tNode `TNode`
13118
- * @param lView `LView`
13119
- * @param directiveIndex Index where the directive will be stored in the Expando.
13120
- * @param def `DirectiveDef`
13121
- */
13122
- function configureViewWithDirective(tView, tNode, lView, directiveIndex, def) {
13123
- ngDevMode &&
13124
- assertGreaterThanOrEqual(directiveIndex, HEADER_OFFSET, 'Must be in Expando section');
13125
- tView.data[directiveIndex] = def;
13126
- const directiveFactory = def.factory || (def.factory = getFactoryDef(def.type, true));
13127
- // Even though `directiveFactory` will already be using `ɵɵdirectiveInject` in its generated code,
13128
- // we also want to support `inject()` directly from the directive constructor context so we set
13129
- // `ɵɵdirectiveInject` as the inject implementation here too.
13130
- const nodeInjectorFactory = new NodeInjectorFactory(directiveFactory, isComponentDef(def), ɵɵdirectiveInject);
13131
- tView.blueprint[directiveIndex] = nodeInjectorFactory;
13132
- lView[directiveIndex] = nodeInjectorFactory;
13133
- registerHostBindingOpCodes(tView, tNode, directiveIndex, allocExpando(tView, lView, def.hostVars, NO_CHANGE), def);
13134
- }
13135
12777
  /**
13136
12778
  * Gets the initial set of LView flags based on the component definition that the LView represents.
13137
12779
  * @param def Component definition from which to determine the flags.
@@ -13203,58 +12845,6 @@ function setInputsFromAttrs(lView, directiveIndex, instance, def, tNode, initial
13203
12845
  }
13204
12846
  }
13205
12847
  }
13206
- /**
13207
- * Generates initialInputData for a node and stores it in the template's static storage
13208
- * so subsequent template invocations don't have to recalculate it.
13209
- *
13210
- * initialInputData is an array containing values that need to be set as input properties
13211
- * for directives on this node, but only once on creation. We need this array to support
13212
- * the case where you set an @Input property of a directive using attribute-like syntax.
13213
- * e.g. if you have a `name` @Input, you can set it once like this:
13214
- *
13215
- * <my-component name="Bess"></my-component>
13216
- *
13217
- * @param inputs Input alias map that was generated from the directive def inputs.
13218
- * @param directiveIndex Index of the directive that is currently being processed.
13219
- * @param attrs Static attrs on this node.
13220
- */
13221
- function generateInitialInputs(inputs, directiveIndex, attrs) {
13222
- let inputsToStore = null;
13223
- let i = 0;
13224
- while (i < attrs.length) {
13225
- const attrName = attrs[i];
13226
- if (attrName === 0 /* AttributeMarker.NamespaceURI */) {
13227
- // We do not allow inputs on namespaced attributes.
13228
- i += 4;
13229
- continue;
13230
- }
13231
- else if (attrName === 5 /* AttributeMarker.ProjectAs */) {
13232
- // Skip over the `ngProjectAs` value.
13233
- i += 2;
13234
- continue;
13235
- }
13236
- // If we hit any other attribute markers, we're done anyway. None of those are valid inputs.
13237
- if (typeof attrName === 'number')
13238
- break;
13239
- if (inputs.hasOwnProperty(attrName)) {
13240
- if (inputsToStore === null)
13241
- inputsToStore = [];
13242
- // Find the input's public name from the input store. Note that we can be found easier
13243
- // through the directive def, but we want to do it using the inputs store so that it can
13244
- // account for host directive aliases.
13245
- const inputConfig = inputs[attrName];
13246
- for (let j = 0; j < inputConfig.length; j += 3) {
13247
- if (inputConfig[j] === directiveIndex) {
13248
- inputsToStore.push(attrName, inputConfig[j + 1], inputConfig[j + 2], attrs[i + 1]);
13249
- // A directive can't have multiple inputs with the same name so we can break here.
13250
- break;
13251
- }
13252
- }
13253
- }
13254
- i += 2;
13255
- }
13256
- return inputsToStore;
13257
- }
13258
12848
  //////////////////////////
13259
12849
  //// ViewContainer & View
13260
12850
  //////////////////////////
@@ -13653,7 +13243,7 @@ function detachViewFromDOM(tView, lView) {
13653
13243
  // When we remove a view from the DOM, we need to rerun afterRender hooks
13654
13244
  // We don't necessarily needs to run change detection. DOM removal only requires
13655
13245
  // change detection if animations are enabled (this notification is handled by animations).
13656
- lView[ENVIRONMENT].changeDetectionScheduler?.notify(10 /* NotificationSource.ViewDetachedFromDOM */);
13246
+ lView[ENVIRONMENT].changeDetectionScheduler?.notify(9 /* NotificationSource.ViewDetachedFromDOM */);
13657
13247
  applyView(tView, lView, lView[RENDERER], 2 /* WalkTNodeTreeAction.Detach */, null, null);
13658
13248
  }
13659
13249
  /**
@@ -14543,6 +14133,15 @@ function collectNativeNodesInLContainer(lContainer, result) {
14543
14133
  }
14544
14134
  }
14545
14135
 
14136
+ function addAfterRenderSequencesForView(lView) {
14137
+ if (lView[AFTER_RENDER_SEQUENCES_TO_ADD] !== null) {
14138
+ for (const sequence of lView[AFTER_RENDER_SEQUENCES_TO_ADD]) {
14139
+ sequence.impl.addSequence(sequence);
14140
+ }
14141
+ lView[AFTER_RENDER_SEQUENCES_TO_ADD].length = 0;
14142
+ }
14143
+ }
14144
+
14546
14145
  let freeConsumers = [];
14547
14146
  /**
14548
14147
  * Create a new template consumer pointing at the specified LView.
@@ -14888,6 +14487,7 @@ function refreshView(tView, lView, templateFn, context) {
14888
14487
  // no changes cycle, the component would be not be dirty for the next update pass. This would
14889
14488
  // be different in production mode where the component dirty state is not reset.
14890
14489
  if (!isInCheckNoChangesPass) {
14490
+ addAfterRenderSequencesForView(lView);
14891
14491
  lView[FLAGS] &= ~(64 /* LViewFlags.Dirty */ | 8 /* LViewFlags.FirstLViewPass */);
14892
14492
  }
14893
14493
  }
@@ -15005,12 +14605,17 @@ function detectChangesInView(lView, mode) {
15005
14605
  refreshView(tView, lView, tView.template, lView[CONTEXT]);
15006
14606
  }
15007
14607
  else if (flags & 8192 /* LViewFlags.HasChildViewsToRefresh */) {
15008
- runEffectsInView(lView);
14608
+ if (!isInCheckNoChangesPass) {
14609
+ runEffectsInView(lView);
14610
+ }
15009
14611
  detectChangesInEmbeddedViews(lView, 1 /* ChangeDetectionMode.Targeted */);
15010
14612
  const components = tView.components;
15011
14613
  if (components !== null) {
15012
14614
  detectChangesInChildComponents(lView, components, 1 /* ChangeDetectionMode.Targeted */);
15013
14615
  }
14616
+ if (!isInCheckNoChangesPass) {
14617
+ addAfterRenderSequencesForView(lView);
14618
+ }
15014
14619
  }
15015
14620
  }
15016
14621
  /** Refreshes child components in the current view (update mode). */
@@ -17793,6 +17398,492 @@ function computeStaticStyling(tNode, attrs, writeToHost) {
17793
17398
  writeToHost ? (tNode.classes = classes) : (tNode.classesWithoutHost = classes);
17794
17399
  }
17795
17400
 
17401
+ function ɵɵdirectiveInject(token, flags = InjectFlags.Default) {
17402
+ const lView = getLView();
17403
+ // Fall back to inject() if view hasn't been created. This situation can happen in tests
17404
+ // if inject utilities are used before bootstrapping.
17405
+ if (lView === null) {
17406
+ // Verify that we will not get into infinite loop.
17407
+ ngDevMode && assertInjectImplementationNotEqual(ɵɵdirectiveInject);
17408
+ return ɵɵinject(token, flags);
17409
+ }
17410
+ const tNode = getCurrentTNode();
17411
+ const value = getOrCreateInjectable(tNode, lView, resolveForwardRef(token), flags);
17412
+ ngDevMode && emitInjectEvent(token, value, flags);
17413
+ return value;
17414
+ }
17415
+ /**
17416
+ * Throws an error indicating that a factory function could not be generated by the compiler for a
17417
+ * particular class.
17418
+ *
17419
+ * This instruction allows the actual error message to be optimized away when ngDevMode is turned
17420
+ * off, saving bytes of generated code while still providing a good experience in dev mode.
17421
+ *
17422
+ * The name of the class is not mentioned here, but will be in the generated factory function name
17423
+ * and thus in the stack trace.
17424
+ *
17425
+ * @codeGenApi
17426
+ */
17427
+ function ɵɵinvalidFactory() {
17428
+ const msg = ngDevMode
17429
+ ? `This constructor was not compatible with Dependency Injection.`
17430
+ : 'invalid';
17431
+ throw new Error(msg);
17432
+ }
17433
+
17434
+ /**
17435
+ * When elements are created dynamically after a view blueprint is created (e.g. through
17436
+ * i18nApply()), we need to adjust the blueprint for future template passes.
17437
+ *
17438
+ * @param tView `TView` associated with `LView`
17439
+ * @param lView The `LView` containing the blueprint to adjust
17440
+ * @param numSlotsToAlloc The number of slots to alloc in the LView, should be >0
17441
+ * @param initialValue Initial value to store in blueprint
17442
+ */
17443
+ function allocExpando(tView, lView, numSlotsToAlloc, initialValue) {
17444
+ if (numSlotsToAlloc === 0)
17445
+ return -1;
17446
+ if (ngDevMode) {
17447
+ assertFirstCreatePass(tView);
17448
+ assertSame(tView, lView[TVIEW], '`LView` must be associated with `TView`!');
17449
+ assertEqual(tView.data.length, lView.length, 'Expecting LView to be same size as TView');
17450
+ assertEqual(tView.data.length, tView.blueprint.length, 'Expecting Blueprint to be same size as TView');
17451
+ assertFirstUpdatePass(tView);
17452
+ }
17453
+ const allocIdx = lView.length;
17454
+ for (let i = 0; i < numSlotsToAlloc; i++) {
17455
+ lView.push(initialValue);
17456
+ tView.blueprint.push(initialValue);
17457
+ tView.data.push(null);
17458
+ }
17459
+ return allocIdx;
17460
+ }
17461
+
17462
+ /**
17463
+ * Resolve the matched directives on a node.
17464
+ */
17465
+ function resolveDirectives(tView, lView, tNode, localRefs, directiveMatcher) {
17466
+ // Please make sure to have explicit type for `exportsMap`. Inferred type triggers bug in
17467
+ // tsickle.
17468
+ ngDevMode && assertFirstCreatePass(tView);
17469
+ const exportsMap = localRefs === null ? null : { '': -1 };
17470
+ const matchedDirectiveDefs = directiveMatcher(tView, tNode);
17471
+ if (matchedDirectiveDefs !== null) {
17472
+ const [directiveDefs, hostDirectiveDefs] = resolveHostDirectives(tView, tNode, matchedDirectiveDefs);
17473
+ initializeDirectives(tView, lView, tNode, directiveDefs, exportsMap, hostDirectiveDefs);
17474
+ }
17475
+ if (exportsMap !== null && localRefs !== null) {
17476
+ cacheMatchingLocalNames(tNode, localRefs, exportsMap);
17477
+ }
17478
+ }
17479
+ /** Caches local names and their matching directive indices for query and template lookups. */
17480
+ function cacheMatchingLocalNames(tNode, localRefs, exportsMap) {
17481
+ const localNames = (tNode.localNames = []);
17482
+ // Local names must be stored in tNode in the same order that localRefs are defined
17483
+ // in the template to ensure the data is loaded in the same slots as their refs
17484
+ // in the template (for template queries).
17485
+ for (let i = 0; i < localRefs.length; i += 2) {
17486
+ const index = exportsMap[localRefs[i + 1]];
17487
+ if (index == null)
17488
+ throw new RuntimeError(-301 /* RuntimeErrorCode.EXPORT_NOT_FOUND */, ngDevMode && `Export of name '${localRefs[i + 1]}' not found!`);
17489
+ localNames.push(localRefs[i], index);
17490
+ }
17491
+ }
17492
+ function resolveHostDirectives(tView, tNode, matches) {
17493
+ const allDirectiveDefs = [];
17494
+ let hostDirectiveDefs = null;
17495
+ for (const def of matches) {
17496
+ if (def.findHostDirectiveDefs !== null) {
17497
+ // TODO(pk): probably could return matches instead of taking in an array to fill in?
17498
+ hostDirectiveDefs ??= new Map();
17499
+ // Components are inserted at the front of the matches array so that their lifecycle
17500
+ // hooks run before any directive lifecycle hooks. This appears to be for ViewEngine
17501
+ // compatibility. This logic doesn't make sense with host directives, because it
17502
+ // would allow the host directives to undo any overrides the host may have made.
17503
+ // To handle this case, the host directives of components are inserted at the beginning
17504
+ // of the array, followed by the component. As such, the insertion order is as follows:
17505
+ // 1. Host directives belonging to the selector-matched component.
17506
+ // 2. Selector-matched component.
17507
+ // 3. Host directives belonging to selector-matched directives.
17508
+ // 4. Selector-matched directives.
17509
+ def.findHostDirectiveDefs(def, allDirectiveDefs, hostDirectiveDefs);
17510
+ }
17511
+ if (isComponentDef(def)) {
17512
+ allDirectiveDefs.push(def);
17513
+ markAsComponentHost(tView, tNode, allDirectiveDefs.length - 1);
17514
+ }
17515
+ }
17516
+ if (isComponentHost(tNode)) {
17517
+ allDirectiveDefs.push(...matches.slice(1));
17518
+ }
17519
+ else {
17520
+ allDirectiveDefs.push(...matches);
17521
+ }
17522
+ if (ngDevMode) {
17523
+ assertNoDuplicateDirectives(allDirectiveDefs);
17524
+ }
17525
+ return [allDirectiveDefs, hostDirectiveDefs];
17526
+ }
17527
+ /**
17528
+ * Marks a given TNode as a component's host. This consists of:
17529
+ * - setting the component offset on the TNode.
17530
+ * - storing index of component's host element so it will be queued for view refresh during CD.
17531
+ */
17532
+ function markAsComponentHost(tView, hostTNode, componentOffset) {
17533
+ ngDevMode && assertFirstCreatePass(tView);
17534
+ ngDevMode && assertGreaterThan(componentOffset, -1, 'componentOffset must be great than -1');
17535
+ hostTNode.componentOffset = componentOffset;
17536
+ (tView.components ??= []).push(hostTNode.index);
17537
+ }
17538
+ /** Initializes the data structures necessary for a list of directives to be instantiated. */
17539
+ function initializeDirectives(tView, lView, tNode, directives, exportsMap, hostDirectiveDefs) {
17540
+ ngDevMode && assertFirstCreatePass(tView);
17541
+ // Publishes the directive types to DI so they can be injected. Needs to
17542
+ // happen in a separate pass before the TNode flags have been initialized.
17543
+ for (let i = 0; i < directives.length; i++) {
17544
+ diPublicInInjector(getOrCreateNodeInjectorForNode(tNode, lView), tView, directives[i].type);
17545
+ }
17546
+ initTNodeFlags(tNode, tView.data.length, directives.length);
17547
+ // When the same token is provided by several directives on the same node, some rules apply in
17548
+ // the viewEngine:
17549
+ // - viewProviders have priority over providers
17550
+ // - the last directive in NgModule.declarations has priority over the previous one
17551
+ // So to match these rules, the order in which providers are added in the arrays is very
17552
+ // important.
17553
+ for (let i = 0; i < directives.length; i++) {
17554
+ const def = directives[i];
17555
+ if (def.providersResolver)
17556
+ def.providersResolver(def);
17557
+ }
17558
+ let preOrderHooksFound = false;
17559
+ let preOrderCheckHooksFound = false;
17560
+ let directiveIdx = allocExpando(tView, lView, directives.length, null);
17561
+ ngDevMode &&
17562
+ assertSame(directiveIdx, tNode.directiveStart, 'TNode.directiveStart should point to just allocated space');
17563
+ for (let i = 0; i < directives.length; i++) {
17564
+ const def = directives[i];
17565
+ // Merge the attrs in the order of matches. This assumes that the first directive is the
17566
+ // component itself, so that the component has the least priority.
17567
+ tNode.mergedAttrs = mergeHostAttrs(tNode.mergedAttrs, def.hostAttrs);
17568
+ configureViewWithDirective(tView, tNode, lView, directiveIdx, def);
17569
+ saveNameToExportMap(directiveIdx, def, exportsMap);
17570
+ if (def.contentQueries !== null)
17571
+ tNode.flags |= 4 /* TNodeFlags.hasContentQuery */;
17572
+ if (def.hostBindings !== null || def.hostAttrs !== null || def.hostVars !== 0)
17573
+ tNode.flags |= 64 /* TNodeFlags.hasHostBindings */;
17574
+ const lifeCycleHooks = def.type.prototype;
17575
+ // Only push a node index into the preOrderHooks array if this is the first
17576
+ // pre-order hook found on this node.
17577
+ if (!preOrderHooksFound &&
17578
+ (lifeCycleHooks.ngOnChanges || lifeCycleHooks.ngOnInit || lifeCycleHooks.ngDoCheck)) {
17579
+ // We will push the actual hook function into this array later during dir instantiation.
17580
+ // We cannot do it now because we must ensure hooks are registered in the same
17581
+ // order that directives are created (i.e. injection order).
17582
+ (tView.preOrderHooks ??= []).push(tNode.index);
17583
+ preOrderHooksFound = true;
17584
+ }
17585
+ if (!preOrderCheckHooksFound && (lifeCycleHooks.ngOnChanges || lifeCycleHooks.ngDoCheck)) {
17586
+ (tView.preOrderCheckHooks ??= []).push(tNode.index);
17587
+ preOrderCheckHooksFound = true;
17588
+ }
17589
+ directiveIdx++;
17590
+ }
17591
+ initializeInputAndOutputAliases(tView, tNode, hostDirectiveDefs);
17592
+ }
17593
+ /**
17594
+ * Initializes data structures required to work with directive inputs and outputs.
17595
+ * Initialization is done for all directives matched on a given TNode.
17596
+ */
17597
+ function initializeInputAndOutputAliases(tView, tNode, hostDirectiveDefinitionMap) {
17598
+ ngDevMode && assertFirstCreatePass(tView);
17599
+ const start = tNode.directiveStart;
17600
+ const end = tNode.directiveEnd;
17601
+ const tViewData = tView.data;
17602
+ const tNodeAttrs = tNode.attrs;
17603
+ const inputsFromAttrs = [];
17604
+ let inputsStore = null;
17605
+ let outputsStore = null;
17606
+ for (let directiveIndex = start; directiveIndex < end; directiveIndex++) {
17607
+ const directiveDef = tViewData[directiveIndex];
17608
+ const aliasData = hostDirectiveDefinitionMap
17609
+ ? hostDirectiveDefinitionMap.get(directiveDef)
17610
+ : null;
17611
+ const aliasedInputs = aliasData ? aliasData.inputs : null;
17612
+ const aliasedOutputs = aliasData ? aliasData.outputs : null;
17613
+ inputsStore = captureNodeBindings(0 /* CaptureNodeBindingMode.Inputs */, directiveDef.inputs, directiveIndex, inputsStore, aliasedInputs);
17614
+ outputsStore = captureNodeBindings(1 /* CaptureNodeBindingMode.Outputs */, directiveDef.outputs, directiveIndex, outputsStore, aliasedOutputs);
17615
+ // Do not use unbound attributes as inputs to structural directives, since structural
17616
+ // directive inputs can only be set using microsyntax (e.g. `<div *dir="exp">`).
17617
+ const initialInputs = inputsStore !== null && tNodeAttrs !== null && !isInlineTemplate(tNode)
17618
+ ? generateInitialInputs(inputsStore, directiveIndex, tNodeAttrs)
17619
+ : null;
17620
+ inputsFromAttrs.push(initialInputs);
17621
+ }
17622
+ if (inputsStore !== null) {
17623
+ if (inputsStore.hasOwnProperty('class')) {
17624
+ tNode.flags |= 8 /* TNodeFlags.hasClassInput */;
17625
+ }
17626
+ if (inputsStore.hasOwnProperty('style')) {
17627
+ tNode.flags |= 16 /* TNodeFlags.hasStyleInput */;
17628
+ }
17629
+ }
17630
+ tNode.initialInputs = inputsFromAttrs;
17631
+ tNode.inputs = inputsStore;
17632
+ tNode.outputs = outputsStore;
17633
+ }
17634
+ function captureNodeBindings(mode, aliasMap, directiveIndex, bindingsResult, hostDirectiveAliasMap) {
17635
+ for (let publicName in aliasMap) {
17636
+ if (!aliasMap.hasOwnProperty(publicName)) {
17637
+ continue;
17638
+ }
17639
+ const value = aliasMap[publicName];
17640
+ if (value === undefined) {
17641
+ continue;
17642
+ }
17643
+ bindingsResult ??= {};
17644
+ let internalName;
17645
+ let inputFlags = InputFlags.None;
17646
+ // For inputs, the value might be an array capturing additional
17647
+ // input flags.
17648
+ if (Array.isArray(value)) {
17649
+ internalName = value[0];
17650
+ inputFlags = value[1];
17651
+ }
17652
+ else {
17653
+ internalName = value;
17654
+ }
17655
+ // If there are no host directive mappings, we want to remap using the alias map from the
17656
+ // definition itself. If there is an alias map, it has two functions:
17657
+ // 1. It serves as an allowlist of bindings that are exposed by the host directives. Only the
17658
+ // ones inside the host directive map will be exposed on the host.
17659
+ // 2. The public name of the property is aliased using the host directive alias map, rather
17660
+ // than the alias map from the definition.
17661
+ let finalPublicName = publicName;
17662
+ if (hostDirectiveAliasMap !== null) {
17663
+ // If there is no mapping, it's not part of the allowlist and this input/output
17664
+ // is not captured and should be ignored.
17665
+ if (!hostDirectiveAliasMap.hasOwnProperty(publicName)) {
17666
+ continue;
17667
+ }
17668
+ finalPublicName = hostDirectiveAliasMap[publicName];
17669
+ }
17670
+ if (mode === 0 /* CaptureNodeBindingMode.Inputs */) {
17671
+ addPropertyBinding(bindingsResult, directiveIndex, finalPublicName, internalName, inputFlags);
17672
+ }
17673
+ else {
17674
+ addPropertyBinding(bindingsResult, directiveIndex, finalPublicName, internalName);
17675
+ }
17676
+ }
17677
+ return bindingsResult;
17678
+ }
17679
+ function addPropertyBinding(bindings, directiveIndex, publicName, internalName, inputFlags) {
17680
+ let values;
17681
+ if (bindings.hasOwnProperty(publicName)) {
17682
+ (values = bindings[publicName]).push(directiveIndex, internalName);
17683
+ }
17684
+ else {
17685
+ values = bindings[publicName] = [directiveIndex, internalName];
17686
+ }
17687
+ if (inputFlags !== undefined) {
17688
+ values.push(inputFlags);
17689
+ }
17690
+ }
17691
+ /**
17692
+ * Generates initialInputData for a node and stores it in the template's static storage
17693
+ * so subsequent template invocations don't have to recalculate it.
17694
+ *
17695
+ * initialInputData is an array containing values that need to be set as input properties
17696
+ * for directives on this node, but only once on creation. We need this array to support
17697
+ * the case where you set an @Input property of a directive using attribute-like syntax.
17698
+ * e.g. if you have a `name` @Input, you can set it once like this:
17699
+ *
17700
+ * <my-component name="Bess"></my-component>
17701
+ *
17702
+ * @param inputs Input alias map that was generated from the directive def inputs.
17703
+ * @param directiveIndex Index of the directive that is currently being processed.
17704
+ * @param attrs Static attrs on this node.
17705
+ */
17706
+ function generateInitialInputs(inputs, directiveIndex, attrs) {
17707
+ let inputsToStore = null;
17708
+ let i = 0;
17709
+ while (i < attrs.length) {
17710
+ const attrName = attrs[i];
17711
+ if (attrName === 0 /* AttributeMarker.NamespaceURI */) {
17712
+ // We do not allow inputs on namespaced attributes.
17713
+ i += 4;
17714
+ continue;
17715
+ }
17716
+ else if (attrName === 5 /* AttributeMarker.ProjectAs */) {
17717
+ // Skip over the `ngProjectAs` value.
17718
+ i += 2;
17719
+ continue;
17720
+ }
17721
+ // If we hit any other attribute markers, we're done anyway. None of those are valid inputs.
17722
+ if (typeof attrName === 'number')
17723
+ break;
17724
+ if (inputs.hasOwnProperty(attrName)) {
17725
+ if (inputsToStore === null)
17726
+ inputsToStore = [];
17727
+ // Find the input's public name from the input store. Note that we can be found easier
17728
+ // through the directive def, but we want to do it using the inputs store so that it can
17729
+ // account for host directive aliases.
17730
+ const inputConfig = inputs[attrName];
17731
+ for (let j = 0; j < inputConfig.length; j += 3) {
17732
+ if (inputConfig[j] === directiveIndex) {
17733
+ inputsToStore.push(attrName, inputConfig[j + 1], inputConfig[j + 2], attrs[i + 1]);
17734
+ // A directive can't have multiple inputs with the same name so we can break here.
17735
+ break;
17736
+ }
17737
+ }
17738
+ }
17739
+ i += 2;
17740
+ }
17741
+ return inputsToStore;
17742
+ }
17743
+ /**
17744
+ * Setup directive for instantiation.
17745
+ *
17746
+ * We need to create a `NodeInjectorFactory` which is then inserted in both the `Blueprint` as well
17747
+ * as `LView`. `TView` gets the `DirectiveDef`.
17748
+ *
17749
+ * @param tView `TView`
17750
+ * @param tNode `TNode`
17751
+ * @param lView `LView`
17752
+ * @param directiveIndex Index where the directive will be stored in the Expando.
17753
+ * @param def `DirectiveDef`
17754
+ */
17755
+ function configureViewWithDirective(tView, tNode, lView, directiveIndex, def) {
17756
+ ngDevMode &&
17757
+ assertGreaterThanOrEqual(directiveIndex, HEADER_OFFSET, 'Must be in Expando section');
17758
+ tView.data[directiveIndex] = def;
17759
+ const directiveFactory = def.factory || (def.factory = getFactoryDef(def.type, true));
17760
+ // Even though `directiveFactory` will already be using `ɵɵdirectiveInject` in its generated code,
17761
+ // we also want to support `inject()` directly from the directive constructor context so we set
17762
+ // `ɵɵdirectiveInject` as the inject implementation here too.
17763
+ const nodeInjectorFactory = new NodeInjectorFactory(directiveFactory, isComponentDef(def), ɵɵdirectiveInject);
17764
+ tView.blueprint[directiveIndex] = nodeInjectorFactory;
17765
+ lView[directiveIndex] = nodeInjectorFactory;
17766
+ registerHostBindingOpCodes(tView, tNode, directiveIndex, allocExpando(tView, lView, def.hostVars, NO_CHANGE), def);
17767
+ }
17768
+ /**
17769
+ * Add `hostBindings` to the `TView.hostBindingOpCodes`.
17770
+ *
17771
+ * @param tView `TView` to which the `hostBindings` should be added.
17772
+ * @param tNode `TNode` the element which contains the directive
17773
+ * @param directiveIdx Directive index in view.
17774
+ * @param directiveVarsIdx Where will the directive's vars be stored
17775
+ * @param def `ComponentDef`/`DirectiveDef`, which contains the `hostVars`/`hostBindings` to add.
17776
+ */
17777
+ function registerHostBindingOpCodes(tView, tNode, directiveIdx, directiveVarsIdx, def) {
17778
+ ngDevMode && assertFirstCreatePass(tView);
17779
+ const hostBindings = def.hostBindings;
17780
+ if (hostBindings) {
17781
+ let hostBindingOpCodes = tView.hostBindingOpCodes;
17782
+ if (hostBindingOpCodes === null) {
17783
+ hostBindingOpCodes = tView.hostBindingOpCodes = [];
17784
+ }
17785
+ const elementIndx = ~tNode.index;
17786
+ if (lastSelectedElementIdx(hostBindingOpCodes) != elementIndx) {
17787
+ // Conditionally add select element so that we are more efficient in execution.
17788
+ // NOTE: this is strictly not necessary and it trades code size for runtime perf.
17789
+ // (We could just always add it.)
17790
+ hostBindingOpCodes.push(elementIndx);
17791
+ }
17792
+ hostBindingOpCodes.push(directiveIdx, directiveVarsIdx, hostBindings);
17793
+ }
17794
+ }
17795
+ /**
17796
+ * Returns the last selected element index in the `HostBindingOpCodes`
17797
+ *
17798
+ * For perf reasons we don't need to update the selected element index in `HostBindingOpCodes` only
17799
+ * if it changes. This method returns the last index (or '0' if not found.)
17800
+ *
17801
+ * Selected element index are only the ones which are negative.
17802
+ */
17803
+ function lastSelectedElementIdx(hostBindingOpCodes) {
17804
+ let i = hostBindingOpCodes.length;
17805
+ while (i > 0) {
17806
+ const value = hostBindingOpCodes[--i];
17807
+ if (typeof value === 'number' && value < 0) {
17808
+ return value;
17809
+ }
17810
+ }
17811
+ return 0;
17812
+ }
17813
+ /**
17814
+ * Builds up an export map as directives are created, so local refs can be quickly mapped
17815
+ * to their directive instances.
17816
+ */
17817
+ function saveNameToExportMap(directiveIdx, def, exportsMap) {
17818
+ if (exportsMap) {
17819
+ if (def.exportAs) {
17820
+ for (let i = 0; i < def.exportAs.length; i++) {
17821
+ exportsMap[def.exportAs[i]] = directiveIdx;
17822
+ }
17823
+ }
17824
+ if (isComponentDef(def))
17825
+ exportsMap[''] = directiveIdx;
17826
+ }
17827
+ }
17828
+ /**
17829
+ * Initializes the flags on the current node, setting all indices to the initial index,
17830
+ * the directive count to 0, and adding the isComponent flag.
17831
+ * @param index the initial index
17832
+ */
17833
+ function initTNodeFlags(tNode, index, numberOfDirectives) {
17834
+ ngDevMode &&
17835
+ assertNotEqual(numberOfDirectives, tNode.directiveEnd - tNode.directiveStart, 'Reached the max number of directives');
17836
+ tNode.flags |= 1 /* TNodeFlags.isDirectiveHost */;
17837
+ // When the first directive is created on a node, save the index
17838
+ tNode.directiveStart = index;
17839
+ tNode.directiveEnd = index + numberOfDirectives;
17840
+ tNode.providerIndexes = index;
17841
+ }
17842
+ function assertNoDuplicateDirectives(directives) {
17843
+ // The array needs at least two elements in order to have duplicates.
17844
+ if (directives.length < 2) {
17845
+ return;
17846
+ }
17847
+ const seenDirectives = new Set();
17848
+ for (const current of directives) {
17849
+ if (seenDirectives.has(current)) {
17850
+ throw new RuntimeError(309 /* RuntimeErrorCode.DUPLICATE_DIRECTIVE */, `Directive ${current.type.name} matches multiple times on the same element. ` +
17851
+ `Directives can only match an element once.`);
17852
+ }
17853
+ seenDirectives.add(current);
17854
+ }
17855
+ }
17856
+
17857
+ function elementStartFirstCreatePass(index, tView, lView, name, directiveMatcher, bindingsEnabled, attrsIndex, localRefsIndex) {
17858
+ ngDevMode && assertFirstCreatePass(tView);
17859
+ ngDevMode && ngDevMode.firstCreatePass++;
17860
+ const tViewConsts = tView.consts;
17861
+ const attrs = getConstant(tViewConsts, attrsIndex);
17862
+ const tNode = getOrCreateTNode(tView, index, 2 /* TNodeType.Element */, name, attrs);
17863
+ if (bindingsEnabled) {
17864
+ resolveDirectives(tView, lView, tNode, getConstant(tViewConsts, localRefsIndex), directiveMatcher);
17865
+ }
17866
+ // Merge the template attrs last so that they have the highest priority.
17867
+ tNode.mergedAttrs = mergeHostAttrs(tNode.mergedAttrs, tNode.attrs);
17868
+ if (tNode.attrs !== null) {
17869
+ computeStaticStyling(tNode, tNode.attrs, false);
17870
+ }
17871
+ if (tNode.mergedAttrs !== null) {
17872
+ computeStaticStyling(tNode, tNode.mergedAttrs, true);
17873
+ }
17874
+ if (tView.queries !== null) {
17875
+ tView.queries.elementStart(tView, tNode);
17876
+ }
17877
+ return tNode;
17878
+ }
17879
+ function elementEndFirstCreatePass(tView, tNode) {
17880
+ ngDevMode && assertFirstCreatePass(tView);
17881
+ registerPostOrderHooks(tView, tNode);
17882
+ if (isContentQueryHost(tNode)) {
17883
+ tView.queries.elementEnd(tNode);
17884
+ }
17885
+ }
17886
+
17796
17887
  class ComponentFactoryResolver extends ComponentFactoryResolver$1 {
17797
17888
  ngModule;
17798
17889
  /**
@@ -17837,9 +17928,51 @@ function toRefArray(map, isInputMap) {
17837
17928
  }
17838
17929
  return array;
17839
17930
  }
17840
- function getNamespace(elementName) {
17841
- const name = elementName.toLowerCase();
17842
- return name === 'svg' ? SVG_NAMESPACE : name === 'math' ? MATH_ML_NAMESPACE : null;
17931
+ function verifyNotAnOrphanComponent(componentDef) {
17932
+ // TODO(pk): create assert that verifies ngDevMode
17933
+ if ((typeof ngJitMode === 'undefined' || ngJitMode) &&
17934
+ componentDef.debugInfo?.forbidOrphanRendering) {
17935
+ if (depsTracker.isOrphanComponent(componentDef.type)) {
17936
+ throw new RuntimeError(981 /* RuntimeErrorCode.RUNTIME_DEPS_ORPHAN_COMPONENT */, `Orphan component found! Trying to render the component ${debugStringifyTypeForError(componentDef.type)} without first loading the NgModule that declares it. It is recommended to make this component standalone in order to avoid this error. If this is not possible now, import the component's NgModule in the appropriate NgModule, or the standalone component in which you are trying to render this component. If this is a lazy import, load the NgModule lazily as well and use its module injector.`);
17937
+ }
17938
+ }
17939
+ }
17940
+ function createRootViewInjector(componentDef, environmentInjector, injector) {
17941
+ let realEnvironmentInjector = environmentInjector instanceof EnvironmentInjector
17942
+ ? environmentInjector
17943
+ : environmentInjector?.injector;
17944
+ if (realEnvironmentInjector && componentDef.getStandaloneInjector !== null) {
17945
+ realEnvironmentInjector =
17946
+ componentDef.getStandaloneInjector(realEnvironmentInjector) || realEnvironmentInjector;
17947
+ }
17948
+ const rootViewInjector = realEnvironmentInjector
17949
+ ? new ChainedInjector(injector, realEnvironmentInjector)
17950
+ : injector;
17951
+ return rootViewInjector;
17952
+ }
17953
+ function createRootLViewEnvironment(rootLViewInjector) {
17954
+ const rendererFactory = rootLViewInjector.get(RendererFactory2, null);
17955
+ if (rendererFactory === null) {
17956
+ throw new RuntimeError(407 /* RuntimeErrorCode.RENDERER_NOT_FOUND */, ngDevMode &&
17957
+ 'Angular was not able to inject a renderer (RendererFactory2). ' +
17958
+ 'Likely this is due to a broken DI hierarchy. ' +
17959
+ 'Make sure that any injector used to create this component has a correct parent.');
17960
+ }
17961
+ const sanitizer = rootLViewInjector.get(Sanitizer, null);
17962
+ const changeDetectionScheduler = rootLViewInjector.get(ChangeDetectionScheduler, null);
17963
+ return {
17964
+ rendererFactory,
17965
+ sanitizer,
17966
+ changeDetectionScheduler,
17967
+ };
17968
+ }
17969
+ function createHostElement(componentDef, render) {
17970
+ // Determine a tag name used for creating host elements when this component is created
17971
+ // dynamically. Default to 'div' if this component did not specify any tag name in its
17972
+ // selector.
17973
+ const tagName = (componentDef.selectors[0][0] || 'div').toLowerCase();
17974
+ const namespace = tagName === 'svg' ? SVG_NAMESPACE : tagName === 'math' ? MATH_ML_NAMESPACE : null;
17975
+ return createElementNode(render, tagName, namespace);
17843
17976
  }
17844
17977
  /**
17845
17978
  * ComponentFactory interface implementation.
@@ -17884,63 +18017,22 @@ class ComponentFactory extends ComponentFactory$1 {
17884
18017
  profiler(22 /* ProfilerEvent.DynamicComponentStart */);
17885
18018
  const prevConsumer = setActiveConsumer$1(null);
17886
18019
  try {
17887
- // Check if the component is orphan
17888
- if (ngDevMode &&
17889
- (typeof ngJitMode === 'undefined' || ngJitMode) &&
17890
- this.componentDef.debugInfo?.forbidOrphanRendering) {
17891
- if (depsTracker.isOrphanComponent(this.componentType)) {
17892
- throw new RuntimeError(981 /* RuntimeErrorCode.RUNTIME_DEPS_ORPHAN_COMPONENT */, `Orphan component found! Trying to render the component ${debugStringifyTypeForError(this.componentType)} without first loading the NgModule that declares it. It is recommended to make this component standalone in order to avoid this error. If this is not possible now, import the component's NgModule in the appropriate NgModule, or the standalone component in which you are trying to render this component. If this is a lazy import, load the NgModule lazily as well and use its module injector.`);
17893
- }
17894
- }
17895
- environmentInjector = environmentInjector || this.ngModule;
17896
- let realEnvironmentInjector = environmentInjector instanceof EnvironmentInjector
17897
- ? environmentInjector
17898
- : environmentInjector?.injector;
17899
- if (realEnvironmentInjector && this.componentDef.getStandaloneInjector !== null) {
17900
- realEnvironmentInjector =
17901
- this.componentDef.getStandaloneInjector(realEnvironmentInjector) ||
17902
- realEnvironmentInjector;
17903
- }
17904
- const rootViewInjector = realEnvironmentInjector
17905
- ? new ChainedInjector(injector, realEnvironmentInjector)
17906
- : injector;
17907
- const rendererFactory = rootViewInjector.get(RendererFactory2, null);
17908
- if (rendererFactory === null) {
17909
- throw new RuntimeError(407 /* RuntimeErrorCode.RENDERER_NOT_FOUND */, ngDevMode &&
17910
- 'Angular was not able to inject a renderer (RendererFactory2). ' +
17911
- 'Likely this is due to a broken DI hierarchy. ' +
17912
- 'Make sure that any injector used to create this component has a correct parent.');
17913
- }
17914
- const sanitizer = rootViewInjector.get(Sanitizer, null);
17915
- const changeDetectionScheduler = rootViewInjector.get(ChangeDetectionScheduler, null);
17916
- const environment = {
17917
- rendererFactory,
17918
- sanitizer,
17919
- changeDetectionScheduler,
17920
- };
17921
- const hostRenderer = rendererFactory.createRenderer(null, this.componentDef);
17922
- // Determine a tag name used for creating host elements when this component is created
17923
- // dynamically. Default to 'div' if this component did not specify any tag name in its
17924
- // selector.
17925
- const elementName = this.componentDef.selectors[0][0] || 'div';
17926
- const hostRNode = rootSelectorOrNode
17927
- ? locateHostElement(hostRenderer, rootSelectorOrNode, this.componentDef.encapsulation, rootViewInjector)
17928
- : createElementNode(hostRenderer, elementName, getNamespace(elementName));
17929
- let rootFlags = 512 /* LViewFlags.IsRoot */;
17930
- if (this.componentDef.signals) {
17931
- rootFlags |= 4096 /* LViewFlags.SignalView */;
17932
- }
17933
- else if (!this.componentDef.onPush) {
17934
- rootFlags |= 16 /* LViewFlags.CheckAlways */;
17935
- }
17936
- let hydrationInfo = null;
17937
- if (hostRNode !== null) {
17938
- hydrationInfo = retrieveHydrationInfo(hostRNode, rootViewInjector, true /* isRootView */);
17939
- }
18020
+ const cmpDef = this.componentDef;
18021
+ ngDevMode && verifyNotAnOrphanComponent(cmpDef);
18022
+ const tAttributes = rootSelectorOrNode
18023
+ ? ['ng-version', '19.2.0-next.3']
18024
+ : // Extract attributes and classes from the first selector only to match VE behavior.
18025
+ extractAttrsAndClassesFromSelector(this.componentDef.selectors[0]);
17940
18026
  // Create the root view. Uses empty TView and ContentTemplate.
17941
- const rootTView = createTView(0 /* TViewType.Root */, null, null, 1, 0, null, null, null, null, null, null);
17942
- const rootLView = createLView(null, rootTView, null, rootFlags, null, null, environment, hostRenderer, rootViewInjector, null, hydrationInfo);
17943
- rootLView[HEADER_OFFSET] = hostRNode;
18027
+ const rootTView = createTView(0 /* TViewType.Root */, null, null, 1, 0, null, null, null, null, [tAttributes], null);
18028
+ const rootViewInjector = createRootViewInjector(cmpDef, environmentInjector || this.ngModule, injector);
18029
+ const environment = createRootLViewEnvironment(rootViewInjector);
18030
+ const hostRenderer = environment.rendererFactory.createRenderer(null, cmpDef);
18031
+ const hostElement = rootSelectorOrNode
18032
+ ? locateHostElement(hostRenderer, rootSelectorOrNode, cmpDef.encapsulation, rootViewInjector)
18033
+ : createHostElement(cmpDef, hostRenderer);
18034
+ const rootLView = createLView(null, rootTView, null, 512 /* LViewFlags.IsRoot */ | getInitialLViewFlagsFromDef(cmpDef), null, null, environment, hostRenderer, rootViewInjector, null, retrieveHydrationInfo(hostElement, rootViewInjector, true /* isRootView */));
18035
+ rootLView[HEADER_OFFSET] = hostElement;
17944
18036
  // rootView is the parent when bootstrapping
17945
18037
  // TODO(misko): it looks like we are entering view here but we don't really need to as
17946
18038
  // `renderView` does that. However as the code is written it is needed because
@@ -17949,37 +18041,22 @@ class ComponentFactory extends ComponentFactory$1 {
17949
18041
  enterView(rootLView);
17950
18042
  let componentView = null;
17951
18043
  try {
17952
- // If host dom element is created (instead of being provided as part of the dynamic component creation), also apply attributes and classes extracted from component selector.
17953
- const tAttributes = rootSelectorOrNode
17954
- ? ['ng-version', '19.2.0-next.1']
17955
- : // Extract attributes and classes from the first selector only to match VE behavior.
17956
- extractAttrsAndClassesFromSelector(this.componentDef.selectors[0]);
17957
- // TODO: this logic is shared with the element instruction first create pass
17958
- const hostTNode = getOrCreateTNode(rootTView, HEADER_OFFSET, 2 /* TNodeType.Element */, '#host', tAttributes);
17959
- const [directiveDefs, hostDirectiveDefs] = resolveHostDirectives(rootTView, hostTNode, [
17960
- this.componentDef,
17961
- ]);
17962
- initializeDirectives(rootTView, rootLView, hostTNode, directiveDefs, {}, hostDirectiveDefs);
17963
- for (const def of directiveDefs) {
17964
- hostTNode.mergedAttrs = mergeHostAttrs(hostTNode.mergedAttrs, def.hostAttrs);
17965
- }
17966
- hostTNode.mergedAttrs = mergeHostAttrs(hostTNode.mergedAttrs, tAttributes);
17967
- computeStaticStyling(hostTNode, hostTNode.mergedAttrs, true);
18044
+ const hostTNode = elementStartFirstCreatePass(HEADER_OFFSET, rootTView, rootLView, '#host', () => [this.componentDef], true, 0);
18045
+ // ---- element instruction
17968
18046
  // TODO(crisbeto): in practice `hostRNode` should always be defined, but there are some
17969
18047
  // tests where the renderer is mocked out and `undefined` is returned. We should update the
17970
18048
  // tests so that this check can be removed.
17971
- if (hostRNode) {
17972
- setupStaticAttributes(hostRenderer, hostRNode, hostTNode);
17973
- attachPatchData(hostRNode, rootLView);
17974
- }
17975
- if (projectableNodes !== undefined) {
17976
- projectNodes(hostTNode, this.ngContentSelectors, projectableNodes);
18049
+ if (hostElement) {
18050
+ setupStaticAttributes(hostRenderer, hostElement, hostTNode);
18051
+ attachPatchData(hostElement, rootLView);
17977
18052
  }
17978
18053
  // TODO(pk): this logic is similar to the instruction code where a node can have directives
17979
18054
  createDirectivesInstances(rootTView, rootLView, hostTNode);
17980
18055
  executeContentQueries(rootTView, hostTNode, rootLView);
17981
- // TODO(pk): code / logic duplication with the elementEnd and similar instructions
17982
- registerPostOrderHooks(rootTView, hostTNode);
18056
+ elementEndFirstCreatePass(rootTView, hostTNode);
18057
+ if (projectableNodes !== undefined) {
18058
+ projectNodes(hostTNode, this.ngContentSelectors, projectableNodes);
18059
+ }
17983
18060
  componentView = getComponentLViewByIndex(hostTNode.index, rootLView);
17984
18061
  // TODO(pk): why do we need this logic?
17985
18062
  rootLView[CONTEXT] = componentView[CONTEXT];
@@ -20595,7 +20672,11 @@ function templateFirstCreatePass(index, tView, lView, templateFn, decls, vars, t
20595
20672
  const tViewConsts = tView.consts;
20596
20673
  // TODO(pk): refactor getOrCreateTNode to have the "create" only version
20597
20674
  const tNode = getOrCreateTNode(tView, index, 4 /* TNodeType.Container */, tagName || null, attrs || null);
20598
- resolveDirectives(tView, lView, tNode, getConstant(tViewConsts, localRefsIndex));
20675
+ if (getBindingsEnabled()) {
20676
+ resolveDirectives(tView, lView, tNode, getConstant(tViewConsts, localRefsIndex), findDirectiveDefMatches);
20677
+ }
20678
+ // Merge the template attrs last so that they have the highest priority.
20679
+ tNode.mergedAttrs = mergeHostAttrs(tNode.mergedAttrs, tNode.attrs);
20599
20680
  registerPostOrderHooks(tView, tNode);
20600
20681
  const embeddedTView = (tNode.tView = createTView(2 /* TViewType.Embedded */, tNode, templateFn, decls, vars, tView.directiveRegistry, tView.pipeRegistry, null, tView.schemas, tViewConsts, null /* ssrId */));
20601
20682
  if (tView.queries !== null) {
@@ -22898,6 +22979,77 @@ function setTestabilityGetter(getter) {
22898
22979
  }
22899
22980
  let _testabilityGetter;
22900
22981
 
22982
+ /**
22983
+ * A scheduler which manages the execution of effects.
22984
+ */
22985
+ class EffectScheduler {
22986
+ /** @nocollapse */
22987
+ static ɵprov = /** @pureOrBreakMyCode */ /* @__PURE__ */ ɵɵdefineInjectable({
22988
+ token: EffectScheduler,
22989
+ providedIn: 'root',
22990
+ factory: () => new ZoneAwareEffectScheduler(),
22991
+ });
22992
+ }
22993
+ /**
22994
+ * A wrapper around `ZoneAwareQueueingScheduler` that schedules flushing via the microtask queue
22995
+ * when.
22996
+ */
22997
+ class ZoneAwareEffectScheduler {
22998
+ queuedEffectCount = 0;
22999
+ queues = new Map();
23000
+ schedule(handle) {
23001
+ this.enqueue(handle);
23002
+ }
23003
+ remove(handle) {
23004
+ const zone = handle.zone;
23005
+ const queue = this.queues.get(zone);
23006
+ if (!queue.has(handle)) {
23007
+ return;
23008
+ }
23009
+ queue.delete(handle);
23010
+ this.queuedEffectCount--;
23011
+ }
23012
+ enqueue(handle) {
23013
+ const zone = handle.zone;
23014
+ if (!this.queues.has(zone)) {
23015
+ this.queues.set(zone, new Set());
23016
+ }
23017
+ const queue = this.queues.get(zone);
23018
+ if (queue.has(handle)) {
23019
+ return;
23020
+ }
23021
+ this.queuedEffectCount++;
23022
+ queue.add(handle);
23023
+ }
23024
+ /**
23025
+ * Run all scheduled effects.
23026
+ *
23027
+ * Execution order of effects within the same zone is guaranteed to be FIFO, but there is no
23028
+ * ordering guarantee between effects scheduled in different zones.
23029
+ */
23030
+ flush() {
23031
+ while (this.queuedEffectCount > 0) {
23032
+ for (const [zone, queue] of this.queues) {
23033
+ // `zone` here must be defined.
23034
+ if (zone === null) {
23035
+ this.flushQueue(queue);
23036
+ }
23037
+ else {
23038
+ zone.run(() => this.flushQueue(queue));
23039
+ }
23040
+ }
23041
+ }
23042
+ }
23043
+ flushQueue(queue) {
23044
+ for (const handle of queue) {
23045
+ queue.delete(handle);
23046
+ this.queuedEffectCount--;
23047
+ // TODO: what happens if this throws an error?
23048
+ handle.run();
23049
+ }
23050
+ }
23051
+ }
23052
+
22901
23053
  /**
22902
23054
  * Determine if the argument is shaped like a Promise
22903
23055
  */
@@ -23157,77 +23309,6 @@ class ApplicationInitStatus {
23157
23309
  args: [{ providedIn: 'root' }]
23158
23310
  }], () => [], null); })();
23159
23311
 
23160
- /**
23161
- * A scheduler which manages the execution of effects.
23162
- */
23163
- class EffectScheduler {
23164
- /** @nocollapse */
23165
- static ɵprov = /** @pureOrBreakMyCode */ /* @__PURE__ */ ɵɵdefineInjectable({
23166
- token: EffectScheduler,
23167
- providedIn: 'root',
23168
- factory: () => new ZoneAwareEffectScheduler(),
23169
- });
23170
- }
23171
- /**
23172
- * A wrapper around `ZoneAwareQueueingScheduler` that schedules flushing via the microtask queue
23173
- * when.
23174
- */
23175
- class ZoneAwareEffectScheduler {
23176
- queuedEffectCount = 0;
23177
- queues = new Map();
23178
- schedule(handle) {
23179
- this.enqueue(handle);
23180
- }
23181
- remove(handle) {
23182
- const zone = handle.zone;
23183
- const queue = this.queues.get(zone);
23184
- if (!queue.has(handle)) {
23185
- return;
23186
- }
23187
- queue.delete(handle);
23188
- this.queuedEffectCount--;
23189
- }
23190
- enqueue(handle) {
23191
- const zone = handle.zone;
23192
- if (!this.queues.has(zone)) {
23193
- this.queues.set(zone, new Set());
23194
- }
23195
- const queue = this.queues.get(zone);
23196
- if (queue.has(handle)) {
23197
- return;
23198
- }
23199
- this.queuedEffectCount++;
23200
- queue.add(handle);
23201
- }
23202
- /**
23203
- * Run all scheduled effects.
23204
- *
23205
- * Execution order of effects within the same zone is guaranteed to be FIFO, but there is no
23206
- * ordering guarantee between effects scheduled in different zones.
23207
- */
23208
- flush() {
23209
- while (this.queuedEffectCount > 0) {
23210
- for (const [zone, queue] of this.queues) {
23211
- // `zone` here must be defined.
23212
- if (zone === null) {
23213
- this.flushQueue(queue);
23214
- }
23215
- else {
23216
- zone.run(() => this.flushQueue(queue));
23217
- }
23218
- }
23219
- }
23220
- }
23221
- flushQueue(queue) {
23222
- for (const handle of queue) {
23223
- queue.delete(handle);
23224
- this.queuedEffectCount--;
23225
- // TODO: what happens if this throws an error?
23226
- handle.run();
23227
- }
23228
- }
23229
- }
23230
-
23231
23312
  /**
23232
23313
  * A DI token that provides a set of callbacks to
23233
23314
  * be called for every component that is bootstrapped.
@@ -23269,24 +23350,6 @@ class NgProbeToken {
23269
23350
  }
23270
23351
  /** Maximum number of times ApplicationRef will refresh all attached views in a single tick. */
23271
23352
  const MAXIMUM_REFRESH_RERUNS = 10;
23272
- function _callAndReportToErrorHandler(errorHandler, ngZone, callback) {
23273
- try {
23274
- const result = callback();
23275
- if (isPromise(result)) {
23276
- return result.catch((e) => {
23277
- ngZone.runOutsideAngular(() => errorHandler.handleError(e));
23278
- // rethrow as the exception handler might not do it
23279
- throw e;
23280
- });
23281
- }
23282
- return result;
23283
- }
23284
- catch (e) {
23285
- ngZone.runOutsideAngular(() => errorHandler.handleError(e));
23286
- // rethrow as the exception handler might not do it
23287
- throw e;
23288
- }
23289
- }
23290
23353
  function optionsReducer(dst, objs) {
23291
23354
  if (Array.isArray(objs)) {
23292
23355
  return objs.reduce(optionsReducer, dst);
@@ -23405,12 +23468,6 @@ class ApplicationRef {
23405
23468
  * @internal
23406
23469
  */
23407
23470
  dirtyFlags = 0 /* ApplicationRefDirtyFlags.None */;
23408
- /**
23409
- * Like `dirtyFlags` but don't cause `tick()` to loop.
23410
- *
23411
- * @internal
23412
- */
23413
- deferredDirtyFlags = 0 /* ApplicationRefDirtyFlags.None */;
23414
23471
  /**
23415
23472
  * Most recent snapshot from the `TracingService`, if any.
23416
23473
  *
@@ -23576,18 +23633,19 @@ class ApplicationRef {
23576
23633
  this._tick();
23577
23634
  }
23578
23635
  /** @internal */
23579
- _tick = () => {
23636
+ _tick() {
23580
23637
  profiler(12 /* ProfilerEvent.ChangeDetectionStart */);
23581
23638
  if (this.tracingSnapshot !== null) {
23582
- const snapshot = this.tracingSnapshot;
23583
- this.tracingSnapshot = null;
23584
- // Ensure we always run `_tick()` in the context of the most recent snapshot,
23639
+ // Ensure we always run `tickImpl()` in the context of the most recent snapshot,
23585
23640
  // if one exists. Snapshots may be reference counted by the implementation so
23586
23641
  // we want to ensure that if we request a snapshot that we use it.
23587
- snapshot.run(TracingAction.CHANGE_DETECTION, this._tick);
23588
- snapshot.dispose();
23589
- return;
23642
+ this.tracingSnapshot.run(TracingAction.CHANGE_DETECTION, this.tickImpl);
23643
+ }
23644
+ else {
23645
+ this.tickImpl();
23590
23646
  }
23647
+ }
23648
+ tickImpl = () => {
23591
23649
  (typeof ngDevMode === 'undefined' || ngDevMode) && warnIfDestroyed(this._destroyed);
23592
23650
  if (this._runningTick) {
23593
23651
  throw new RuntimeError(101 /* RuntimeErrorCode.RECURSIVE_APPLICATION_REF_TICK */, ngDevMode && 'ApplicationRef.tick is called recursively');
@@ -23608,6 +23666,8 @@ class ApplicationRef {
23608
23666
  }
23609
23667
  finally {
23610
23668
  this._runningTick = false;
23669
+ this.tracingSnapshot?.dispose();
23670
+ this.tracingSnapshot = null;
23611
23671
  setActiveConsumer$1(prevConsumer);
23612
23672
  this.afterTick.next();
23613
23673
  profiler(13 /* ProfilerEvent.ChangeDetectionEnd */);
@@ -23621,9 +23681,6 @@ class ApplicationRef {
23621
23681
  if (this._rendererFactory === null && !this._injector.destroyed) {
23622
23682
  this._rendererFactory = this._injector.get(RendererFactory2, null, { optional: true });
23623
23683
  }
23624
- // When beginning synchronization, all deferred dirtiness becomes active dirtiness.
23625
- this.dirtyFlags |= this.deferredDirtyFlags;
23626
- this.deferredDirtyFlags = 0 /* ApplicationRefDirtyFlags.None */;
23627
23684
  let runs = 0;
23628
23685
  while (this.dirtyFlags !== 0 /* ApplicationRefDirtyFlags.None */ && runs++ < MAXIMUM_REFRESH_RERUNS) {
23629
23686
  profiler(14 /* ProfilerEvent.ChangeDetectionSyncStart */);
@@ -23641,9 +23698,6 @@ class ApplicationRef {
23641
23698
  * Perform a single synchronization pass.
23642
23699
  */
23643
23700
  synchronizeOnce() {
23644
- // If we happened to loop, deferred dirtiness can be processed as active dirtiness again.
23645
- this.dirtyFlags |= this.deferredDirtyFlags;
23646
- this.deferredDirtyFlags = 0 /* ApplicationRefDirtyFlags.None */;
23647
23701
  // First, process any dirty root effects.
23648
23702
  if (this.dirtyFlags & 16 /* ApplicationRefDirtyFlags.RootEffects */) {
23649
23703
  this.dirtyFlags &= ~16 /* ApplicationRefDirtyFlags.RootEffects */;
@@ -27979,24 +28033,6 @@ function getExistingTNode(tView, index) {
27979
28033
  return tNode;
27980
28034
  }
27981
28035
 
27982
- function elementStartFirstCreatePass(index, tView, lView, name, attrsIndex, localRefsIndex) {
27983
- ngDevMode && assertFirstCreatePass(tView);
27984
- ngDevMode && ngDevMode.firstCreatePass++;
27985
- const tViewConsts = tView.consts;
27986
- const attrs = getConstant(tViewConsts, attrsIndex);
27987
- const tNode = getOrCreateTNode(tView, index, 2 /* TNodeType.Element */, name, attrs);
27988
- resolveDirectives(tView, lView, tNode, getConstant(tViewConsts, localRefsIndex));
27989
- if (tNode.attrs !== null) {
27990
- computeStaticStyling(tNode, tNode.attrs, false);
27991
- }
27992
- if (tNode.mergedAttrs !== null) {
27993
- computeStaticStyling(tNode, tNode.mergedAttrs, true);
27994
- }
27995
- if (tView.queries !== null) {
27996
- tView.queries.elementStart(tView, tNode);
27997
- }
27998
- return tNode;
27999
- }
28000
28036
  /**
28001
28037
  * Create DOM element. The instruction must later be followed by `elementEnd()` call.
28002
28038
  *
@@ -28021,7 +28057,7 @@ function ɵɵelementStart(index, name, attrsIndex, localRefsIndex) {
28021
28057
  ngDevMode && assertIndexInRange(lView, adjustedIndex);
28022
28058
  const renderer = lView[RENDERER];
28023
28059
  const tNode = tView.firstCreatePass
28024
- ? elementStartFirstCreatePass(adjustedIndex, tView, lView, name, attrsIndex, localRefsIndex)
28060
+ ? elementStartFirstCreatePass(adjustedIndex, tView, lView, name, findDirectiveDefMatches, getBindingsEnabled(), attrsIndex, localRefsIndex)
28025
28061
  : tView.data[adjustedIndex];
28026
28062
  const native = _locateOrCreateElementNode(tView, lView, tNode, renderer, name, index);
28027
28063
  lView[adjustedIndex] = native;
@@ -28077,10 +28113,7 @@ function ɵɵelementEnd() {
28077
28113
  decreaseElementDepthCount();
28078
28114
  const tView = getTView();
28079
28115
  if (tView.firstCreatePass) {
28080
- registerPostOrderHooks(tView, currentTNode);
28081
- if (isContentQueryHost(currentTNode)) {
28082
- tView.queries.elementEnd(currentTNode);
28083
- }
28116
+ elementEndFirstCreatePass(tView, tNode);
28084
28117
  }
28085
28118
  if (tNode.classesWithoutHost != null && hasClassInput(tNode)) {
28086
28119
  setDirectiveInputsWhichShadowsStyling(tView, tNode, getLView(), tNode.classesWithoutHost, true);
@@ -28108,7 +28141,7 @@ function ɵɵelement(index, name, attrsIndex, localRefsIndex) {
28108
28141
  }
28109
28142
  let _locateOrCreateElementNode = (tView, lView, tNode, renderer, name, index) => {
28110
28143
  lastNodeWasCreated(true);
28111
- return createElementNode(renderer, name, getNamespace$1());
28144
+ return createElementNode(renderer, name, getNamespace());
28112
28145
  };
28113
28146
  /**
28114
28147
  * Enables hydration code path (to lookup existing elements in DOM)
@@ -28123,7 +28156,7 @@ function locateOrCreateElementNodeImpl(tView, lView, tNode, renderer, name, inde
28123
28156
  lastNodeWasCreated(isNodeCreationMode);
28124
28157
  // Regular creation mode.
28125
28158
  if (isNodeCreationMode) {
28126
- return createElementNode(renderer, name, getNamespace$1());
28159
+ return createElementNode(renderer, name, getNamespace());
28127
28160
  }
28128
28161
  // Hydration mode, looking up an existing element in DOM.
28129
28162
  const native = locateNextRNode(hydrationInfo, tView, lView, tNode);
@@ -28176,7 +28209,11 @@ function elementContainerStartFirstCreatePass(index, tView, lView, attrsIndex, l
28176
28209
  computeStaticStyling(tNode, attrs, true);
28177
28210
  }
28178
28211
  const localRefs = getConstant(tViewConsts, localRefsIndex);
28179
- resolveDirectives(tView, lView, tNode, localRefs);
28212
+ if (getBindingsEnabled()) {
28213
+ resolveDirectives(tView, lView, tNode, localRefs, findDirectiveDefMatches);
28214
+ }
28215
+ // Merge the template attrs last so that they have the highest priority.
28216
+ tNode.mergedAttrs = mergeHostAttrs(tNode.mergedAttrs, tNode.attrs);
28180
28217
  if (tView.queries !== null) {
28181
28218
  tView.queries.elementStart(tView, tNode);
28182
28219
  }
@@ -33337,9 +33374,13 @@ function ɵsetClassDebugInfo(type, debugInfo) {
33337
33374
  * @param applyMetadata Callback that will apply a new set of metadata on the `type` when invoked.
33338
33375
  * @param environment Syntehtic namespace imports that need to be passed along to the callback.
33339
33376
  * @param locals Local symbols from the source location that have to be exposed to the callback.
33377
+ * @param importMeta `import.meta` from the call site of the replacement function. Optional since
33378
+ * it isn't used internally.
33379
+ * @param id ID to the class being replaced. **Not** the same as the component definition ID.
33380
+ * Optional since the ID might not be available internally.
33340
33381
  * @codeGenApi
33341
33382
  */
33342
- function ɵɵreplaceMetadata(type, applyMetadata, namespaces, locals) {
33383
+ function ɵɵreplaceMetadata(type, applyMetadata, namespaces, locals, importMeta = null, id = null) {
33343
33384
  ngDevMode && assertComponentDef(type);
33344
33385
  const currentDef = getComponentDef(type);
33345
33386
  // The reason `applyMetadata` is a callback that is invoked (almost) immediately is because
@@ -33361,7 +33402,7 @@ function ɵɵreplaceMetadata(type, applyMetadata, namespaces, locals) {
33361
33402
  // Note: we have the additional check, because `IsRoot` can also indicate
33362
33403
  // a component created through something like `createComponent`.
33363
33404
  if (isRootView(root) && root[PARENT] === null) {
33364
- recreateMatchingLViews(newDef, oldDef, root);
33405
+ recreateMatchingLViews(importMeta, id, newDef, oldDef, root);
33365
33406
  }
33366
33407
  }
33367
33408
  }
@@ -33397,10 +33438,12 @@ function mergeWithExistingDefinition(currentDef, newDef) {
33397
33438
  }
33398
33439
  /**
33399
33440
  * Finds all LViews matching a specific component definition and recreates them.
33441
+ * @param importMeta `import.meta` information.
33442
+ * @param id HMR ID of the component.
33400
33443
  * @param oldDef Component definition to search for.
33401
33444
  * @param rootLView View from which to start the search.
33402
33445
  */
33403
- function recreateMatchingLViews(newDef, oldDef, rootLView) {
33446
+ function recreateMatchingLViews(importMeta, id, newDef, oldDef, rootLView) {
33404
33447
  ngDevMode &&
33405
33448
  assertDefined(oldDef.tView, 'Expected a component definition that has been instantiated at least once');
33406
33449
  const tView = rootLView[TVIEW];
@@ -33408,7 +33451,7 @@ function recreateMatchingLViews(newDef, oldDef, rootLView) {
33408
33451
  // produce false positives when using inheritance.
33409
33452
  if (tView === oldDef.tView) {
33410
33453
  ngDevMode && assertComponentDef(oldDef.type);
33411
- recreateLView(newDef, oldDef, rootLView);
33454
+ recreateLView(importMeta, id, newDef, oldDef, rootLView);
33412
33455
  return;
33413
33456
  }
33414
33457
  for (let i = HEADER_OFFSET; i < tView.bindingStartIndex; i++) {
@@ -33416,14 +33459,14 @@ function recreateMatchingLViews(newDef, oldDef, rootLView) {
33416
33459
  if (isLContainer(current)) {
33417
33460
  // The host can be an LView if a component is injecting `ViewContainerRef`.
33418
33461
  if (isLView(current[HOST])) {
33419
- recreateMatchingLViews(newDef, oldDef, current[HOST]);
33462
+ recreateMatchingLViews(importMeta, id, newDef, oldDef, current[HOST]);
33420
33463
  }
33421
33464
  for (let j = CONTAINER_HEADER_OFFSET; j < current.length; j++) {
33422
- recreateMatchingLViews(newDef, oldDef, current[j]);
33465
+ recreateMatchingLViews(importMeta, id, newDef, oldDef, current[j]);
33423
33466
  }
33424
33467
  }
33425
33468
  else if (isLView(current)) {
33426
- recreateMatchingLViews(newDef, oldDef, current);
33469
+ recreateMatchingLViews(importMeta, id, newDef, oldDef, current);
33427
33470
  }
33428
33471
  }
33429
33472
  }
@@ -33442,11 +33485,13 @@ function clearRendererCache(factory, def) {
33442
33485
  }
33443
33486
  /**
33444
33487
  * Recreates an LView in-place from a new component definition.
33488
+ * @param importMeta `import.meta` information.
33489
+ * @param id HMR ID for the component.
33445
33490
  * @param newDef Definition from which to recreate the view.
33446
33491
  * @param oldDef Previous component definition being swapped out.
33447
33492
  * @param lView View to be recreated.
33448
33493
  */
33449
- function recreateLView(newDef, oldDef, lView) {
33494
+ function recreateLView(importMeta, id, newDef, oldDef, lView) {
33450
33495
  const instance = lView[CONTEXT];
33451
33496
  let host = lView[HOST];
33452
33497
  // In theory the parent can also be an LContainer, but it appears like that's
@@ -33498,10 +33543,29 @@ function recreateLView(newDef, oldDef, lView) {
33498
33543
  };
33499
33544
  // The callback isn't guaranteed to be inside the Zone so we need to bring it in ourselves.
33500
33545
  if (zone === null) {
33501
- recreate();
33546
+ executeWithInvalidateFallback(importMeta, id, recreate);
33502
33547
  }
33503
33548
  else {
33504
- zone.run(recreate);
33549
+ zone.run(() => executeWithInvalidateFallback(importMeta, id, recreate));
33550
+ }
33551
+ }
33552
+ /**
33553
+ * Runs an HMR-related function and falls back to
33554
+ * invalidating the HMR data if it throws an error.
33555
+ */
33556
+ function executeWithInvalidateFallback(importMeta, id, callback) {
33557
+ try {
33558
+ callback();
33559
+ }
33560
+ catch (e) {
33561
+ const errorMessage = e.message;
33562
+ // If we have all the necessary information and APIs to send off the invalidation
33563
+ // request, send it before rethrowing so the dev server can decide what to do.
33564
+ if (id !== null && errorMessage) {
33565
+ importMeta?.hot?.send?.('angular:invalidate', { id, message: errorMessage, error: true });
33566
+ }
33567
+ // Throw the error in case the page doesn't get refreshed.
33568
+ throw e;
33505
33569
  }
33506
33570
  }
33507
33571
  /**
@@ -34929,7 +34993,7 @@ class Version {
34929
34993
  /**
34930
34994
  * @publicApi
34931
34995
  */
34932
- const VERSION = new Version('19.2.0-next.1');
34996
+ const VERSION = new Version('19.2.0-next.3');
34933
34997
 
34934
34998
  /**
34935
34999
  * Combination of NgModuleFactory and ComponentFactories.
@@ -35339,13 +35403,6 @@ class ChangeDetectionSchedulerImpl {
35339
35403
  this.appRef.dirtyFlags |= 4 /* ApplicationRefDirtyFlags.ViewTreeCheck */;
35340
35404
  break;
35341
35405
  }
35342
- case 8 /* NotificationSource.DeferredRenderHook */: {
35343
- // Render hooks are "deferred" when they're triggered from other render hooks. Using the
35344
- // deferred dirty flags ensures that adding new hooks doesn't automatically trigger a loop
35345
- // inside tick().
35346
- this.appRef.deferredDirtyFlags |= 8 /* ApplicationRefDirtyFlags.AfterRender */;
35347
- break;
35348
- }
35349
35406
  case 6 /* NotificationSource.CustomElement */: {
35350
35407
  // We use `ViewTreeTraversal` to ensure we refresh the element even if this is triggered
35351
35408
  // during CD. In practice this is a no-op since the elements code also calls via a
@@ -35354,7 +35411,7 @@ class ChangeDetectionSchedulerImpl {
35354
35411
  force = true;
35355
35412
  break;
35356
35413
  }
35357
- case 13 /* NotificationSource.RootEffect */: {
35414
+ case 12 /* NotificationSource.RootEffect */: {
35358
35415
  this.appRef.dirtyFlags |= 16 /* ApplicationRefDirtyFlags.RootEffects */;
35359
35416
  // Root effects still force a CD, even if the scheduler is disabled. This ensures that
35360
35417
  // effects always run, even when triggered from outside the zone when the scheduler is
@@ -35362,7 +35419,7 @@ class ChangeDetectionSchedulerImpl {
35362
35419
  force = true;
35363
35420
  break;
35364
35421
  }
35365
- case 14 /* NotificationSource.ViewEffect */: {
35422
+ case 13 /* NotificationSource.ViewEffect */: {
35366
35423
  // This is technically a no-op, since view effects will also send a
35367
35424
  // `MarkAncestorsForTraversal` notification. Still, we set this for logical consistency.
35368
35425
  this.appRef.dirtyFlags |= 2 /* ApplicationRefDirtyFlags.ViewTreeTraversal */;
@@ -35372,7 +35429,7 @@ class ChangeDetectionSchedulerImpl {
35372
35429
  force = true;
35373
35430
  break;
35374
35431
  }
35375
- case 12 /* NotificationSource.PendingTaskRemoved */: {
35432
+ case 11 /* NotificationSource.PendingTaskRemoved */: {
35376
35433
  // Removing a pending task via the public API forces a scheduled tick, ensuring that
35377
35434
  // stability is async and delayed until there was at least an opportunity to run
35378
35435
  // application synchronization. This prevents some footguns when working with the
@@ -35381,10 +35438,10 @@ class ChangeDetectionSchedulerImpl {
35381
35438
  force = true;
35382
35439
  break;
35383
35440
  }
35384
- case 10 /* NotificationSource.ViewDetachedFromDOM */:
35385
- case 9 /* NotificationSource.ViewAttached */:
35441
+ case 9 /* NotificationSource.ViewDetachedFromDOM */:
35442
+ case 8 /* NotificationSource.ViewAttached */:
35386
35443
  case 7 /* NotificationSource.RenderHook */:
35387
- case 11 /* NotificationSource.AsyncAnimationsLoaded */:
35444
+ case 10 /* NotificationSource.AsyncAnimationsLoaded */:
35388
35445
  default: {
35389
35446
  // These notifications only schedule a tick but do not change whether we should refresh
35390
35447
  // views. Instead, we only need to run render hooks unless another notification from the
@@ -36078,6 +36135,24 @@ function moduleDoBootstrap(moduleRef, allPlatformModules) {
36078
36135
  }
36079
36136
  allPlatformModules.push(moduleRef);
36080
36137
  }
36138
+ function _callAndReportToErrorHandler(errorHandler, ngZone, callback) {
36139
+ try {
36140
+ const result = callback();
36141
+ if (isPromise(result)) {
36142
+ return result.catch((e) => {
36143
+ ngZone.runOutsideAngular(() => errorHandler.handleError(e));
36144
+ // rethrow as the exception handler might not do it
36145
+ throw e;
36146
+ });
36147
+ }
36148
+ return result;
36149
+ }
36150
+ catch (e) {
36151
+ ngZone.runOutsideAngular(() => errorHandler.handleError(e));
36152
+ // rethrow as the exception handler might not do it
36153
+ throw e;
36154
+ }
36155
+ }
36081
36156
 
36082
36157
  /**
36083
36158
  * The Angular platform is the entry point for Angular on a web page.
@@ -40575,23 +40650,6 @@ function untracked(nonReactiveReadsFn) {
40575
40650
  }
40576
40651
  }
40577
40652
 
40578
- class ViewContext {
40579
- view;
40580
- node;
40581
- constructor(view, node) {
40582
- this.view = view;
40583
- this.node = node;
40584
- }
40585
- /**
40586
- * @internal
40587
- * @nocollapse
40588
- */
40589
- static __NG_ELEMENT_ID__ = injectViewContext;
40590
- }
40591
- function injectViewContext() {
40592
- return new ViewContext(getLView(), getCurrentTNode());
40593
- }
40594
-
40595
40653
  /**
40596
40654
  * Controls whether effects use the legacy `microtaskEffect` by default.
40597
40655
  */
@@ -40859,7 +40917,7 @@ const ROOT_EFFECT_NODE =
40859
40917
  ...BASE_EFFECT_NODE,
40860
40918
  consumerMarkedDirty() {
40861
40919
  this.scheduler.schedule(this);
40862
- this.notifier.notify(13 /* NotificationSource.RootEffect */);
40920
+ this.notifier.notify(12 /* NotificationSource.RootEffect */);
40863
40921
  },
40864
40922
  destroy() {
40865
40923
  consumerDestroy$1(this);
@@ -40874,7 +40932,7 @@ const VIEW_EFFECT_NODE =
40874
40932
  consumerMarkedDirty() {
40875
40933
  this.view[FLAGS] |= 8192 /* LViewFlags.HasChildViewsToRefresh */;
40876
40934
  markAncestorsForTraversal(this.view);
40877
- this.notifier.notify(14 /* NotificationSource.ViewEffect */);
40935
+ this.notifier.notify(13 /* NotificationSource.ViewEffect */);
40878
40936
  },
40879
40937
  destroy() {
40880
40938
  consumerDestroy$1(this);
@@ -40901,7 +40959,7 @@ function createRootEffect(fn, scheduler, notifier) {
40901
40959
  node.notifier = notifier;
40902
40960
  node.zone = typeof Zone !== 'undefined' ? Zone.current : null;
40903
40961
  node.scheduler.schedule(node);
40904
- node.notifier.notify(13 /* NotificationSource.RootEffect */);
40962
+ node.notifier.notify(12 /* NotificationSource.RootEffect */);
40905
40963
  return node;
40906
40964
  }
40907
40965
 
@@ -40992,10 +41050,10 @@ class AfterRenderEffectSequence extends AfterRenderSequence {
40992
41050
  * These are initialized to `undefined` but set in the constructor.
40993
41051
  */
40994
41052
  nodes = [undefined, undefined, undefined, undefined];
40995
- constructor(impl, effectHooks, scheduler, destroyRef, snapshot = null) {
41053
+ constructor(impl, effectHooks, view, scheduler, destroyRef, snapshot = null) {
40996
41054
  // Note that we also initialize the underlying `AfterRenderSequence` hooks to `undefined` and
40997
41055
  // populate them as we create reactive nodes below.
40998
- super(impl, [undefined, undefined, undefined, undefined], false, destroyRef, snapshot);
41056
+ super(impl, [undefined, undefined, undefined, undefined], view, false, destroyRef, snapshot);
40999
41057
  this.scheduler = scheduler;
41000
41058
  // Setup a reactive node for each phase.
41001
41059
  for (const phase of AFTER_RENDER_PHASES) {
@@ -41054,7 +41112,8 @@ function afterRenderEffect(callbackOrSpec, options) {
41054
41112
  if (typeof spec === 'function') {
41055
41113
  spec = { mixedReadWrite: callbackOrSpec };
41056
41114
  }
41057
- const sequence = new AfterRenderEffectSequence(manager.impl, [spec.earlyRead, spec.write, spec.mixedReadWrite, spec.read], scheduler, injector.get(DestroyRef), tracing?.snapshot(null));
41115
+ const viewContext = injector.get(ViewContext, null, { optional: true });
41116
+ const sequence = new AfterRenderEffectSequence(manager.impl, [spec.earlyRead, spec.write, spec.mixedReadWrite, spec.read], viewContext?.view, scheduler, injector.get(DestroyRef), tracing?.snapshot(null));
41058
41117
  manager.impl.register(sequence);
41059
41118
  return sequence;
41060
41119
  }
@@ -41136,16 +41195,16 @@ class ResourceImpl extends BaseWritableResource {
41136
41195
  loaderFn;
41137
41196
  defaultValue;
41138
41197
  equal;
41198
+ pendingTasks;
41139
41199
  /**
41140
41200
  * The current state of the resource. Status, value, and error are derived from this.
41141
41201
  */
41142
41202
  state;
41143
41203
  /**
41144
- * Signal of both the request value `R` and a writable `reload` signal that's linked/associated
41145
- * to the given request. Changing the value of the `reload` signal causes the resource to reload.
41204
+ * Combines the current request with a reload counter which allows the resource to be reloaded on
41205
+ * imperative command.
41146
41206
  */
41147
- extendedRequest;
41148
- pendingTasks;
41207
+ extRequest;
41149
41208
  effectRef;
41150
41209
  pendingController;
41151
41210
  resolvePendingTask = undefined;
@@ -41155,56 +41214,55 @@ class ResourceImpl extends BaseWritableResource {
41155
41214
  // Feed a computed signal for the value to `BaseWritableResource`, which will upgrade it to a
41156
41215
  // `WritableSignal` that delegates to `ResourceImpl.set`.
41157
41216
  computed(() => {
41158
- const stream = this.state()?.stream?.();
41159
- return stream && isResolved(stream) ? stream.value : this.defaultValue;
41217
+ const streamValue = this.state().stream?.();
41218
+ return streamValue && isResolved(streamValue) ? streamValue.value : this.defaultValue;
41160
41219
  }, { equal }));
41161
41220
  this.loaderFn = loaderFn;
41162
41221
  this.defaultValue = defaultValue;
41163
41222
  this.equal = equal;
41164
- this.pendingTasks = injector.get(PendingTasks);
41165
41223
  // Extend `request()` to include a writable reload signal.
41166
- this.extendedRequest = computed(() => ({
41167
- request: request(),
41168
- reload: signal(0),
41169
- }));
41224
+ this.extRequest = linkedSignal({
41225
+ source: request,
41226
+ computation: (request) => ({ request, reload: 0 }),
41227
+ });
41170
41228
  // The main resource state is managed in a `linkedSignal`, which allows the resource to change
41171
41229
  // state instantaneously when the request signal changes.
41172
41230
  this.state = linkedSignal({
41173
- // We use the request (as well as its reload signal) to derive the initial status of the
41174
- // resource (Idle, Loading, or Reloading) in response to request changes. From this initial
41175
- // status, the resource's effect will then trigger the loader and update to a Resolved or
41176
- // Error state as appropriate.
41177
- source: () => {
41178
- const { request, reload } = this.extendedRequest();
41179
- if (request === undefined || this.destroyed) {
41180
- return ResourceStatus.Idle;
41231
+ // Whenever the request changes,
41232
+ source: this.extRequest,
41233
+ // Compute the state of the resource given a change in status.
41234
+ computation: (extRequest, previous) => {
41235
+ const status = extRequest.request === undefined ? ResourceStatus.Idle : ResourceStatus.Loading;
41236
+ if (!previous) {
41237
+ return {
41238
+ extRequest,
41239
+ status,
41240
+ previousStatus: ResourceStatus.Idle,
41241
+ stream: undefined,
41242
+ };
41243
+ }
41244
+ else {
41245
+ return {
41246
+ extRequest,
41247
+ status,
41248
+ previousStatus: projectStatusOfState(previous.value),
41249
+ // If the request hasn't changed, keep the previous stream.
41250
+ stream: previous.value.extRequest.request === extRequest.request
41251
+ ? previous.value.stream
41252
+ : undefined,
41253
+ };
41181
41254
  }
41182
- return reload() === 0 ? ResourceStatus.Loading : ResourceStatus.Reloading;
41183
41255
  },
41184
- // Compute the state of the resource given a change in status.
41185
- computation: (status, previous) => ({
41186
- status,
41187
- // When the state of the resource changes due to the request, remember the previous status
41188
- // for the loader to consider.
41189
- previousStatus: computeStatusOfState(previous?.value),
41190
- // In `Reloading` state, we keep the previous value if there is one, since the identity of
41191
- // the request hasn't changed. Otherwise, we switch back to the default value.
41192
- stream: previous && status === ResourceStatus.Reloading ? previous.value.stream : undefined,
41193
- }),
41194
41256
  });
41195
41257
  this.effectRef = effect(this.loadEffect.bind(this), {
41196
41258
  injector,
41197
41259
  manualCleanup: true,
41198
41260
  });
41261
+ this.pendingTasks = injector.get(PendingTasks);
41199
41262
  // Cancel any pending request when the resource itself is destroyed.
41200
41263
  injector.get(DestroyRef).onDestroy(() => this.destroy());
41201
41264
  }
41202
- status = computed(() => {
41203
- if (this.state().status !== ResourceStatus.Resolved) {
41204
- return this.state().status;
41205
- }
41206
- return isResolved(this.state().stream()) ? ResourceStatus.Resolved : ResourceStatus.Error;
41207
- });
41265
+ status = computed(() => projectStatusOfState(this.state()));
41208
41266
  error = computed(() => {
41209
41267
  const stream = this.state().stream?.();
41210
41268
  return stream && !isResolved(stream) ? stream.error : undefined;
@@ -41217,12 +41275,14 @@ class ResourceImpl extends BaseWritableResource {
41217
41275
  return;
41218
41276
  }
41219
41277
  const current = untracked(this.value);
41220
- if (untracked(this.status) === ResourceStatus.Local &&
41278
+ const state = untracked(this.state);
41279
+ if (state.status === ResourceStatus.Local &&
41221
41280
  (this.equal ? this.equal(current, value) : current === value)) {
41222
41281
  return;
41223
41282
  }
41224
41283
  // Enter Local state with the user-defined value.
41225
41284
  this.state.set({
41285
+ extRequest: state.extRequest,
41226
41286
  status: ResourceStatus.Local,
41227
41287
  previousStatus: ResourceStatus.Local,
41228
41288
  stream: signal({ value }),
@@ -41233,14 +41293,12 @@ class ResourceImpl extends BaseWritableResource {
41233
41293
  }
41234
41294
  reload() {
41235
41295
  // We don't want to restart in-progress loads.
41236
- const status = untracked(this.status);
41237
- if (status === ResourceStatus.Idle ||
41238
- status === ResourceStatus.Loading ||
41239
- status === ResourceStatus.Reloading) {
41296
+ const { status } = untracked(this.state);
41297
+ if (status === ResourceStatus.Idle || status === ResourceStatus.Loading) {
41240
41298
  return false;
41241
41299
  }
41242
- // Increment the reload signal to trigger the `state` linked signal to switch us to `Reload`
41243
- untracked(this.extendedRequest).reload.update((v) => v + 1);
41300
+ // Increment the request reload to trigger the `state` linked signal to switch us to `Reload`
41301
+ this.extRequest.update(({ request, reload }) => ({ request, reload: reload + 1 }));
41244
41302
  return true;
41245
41303
  }
41246
41304
  destroy() {
@@ -41249,28 +41307,23 @@ class ResourceImpl extends BaseWritableResource {
41249
41307
  this.abortInProgressLoad();
41250
41308
  // Destroyed resources enter Idle state.
41251
41309
  this.state.set({
41310
+ extRequest: { request: undefined, reload: 0 },
41252
41311
  status: ResourceStatus.Idle,
41253
41312
  previousStatus: ResourceStatus.Idle,
41254
41313
  stream: undefined,
41255
41314
  });
41256
41315
  }
41257
41316
  async loadEffect() {
41317
+ const extRequest = this.extRequest();
41258
41318
  // Capture the previous status before any state transitions. Note that this is `untracked` since
41259
41319
  // we do not want the effect to depend on the state of the resource, only on the request.
41260
41320
  const { status: currentStatus, previousStatus } = untracked(this.state);
41261
- const { request, reload: reloadCounter } = this.extendedRequest();
41262
- // Subscribe side-effectfully to `reloadCounter`, although we don't actually care about its
41263
- // value. This is used to rerun the effect when `reload()` is triggered.
41264
- reloadCounter();
41265
- if (request === undefined) {
41321
+ if (extRequest.request === undefined) {
41266
41322
  // Nothing to load (and we should already be in a non-loading state).
41267
41323
  return;
41268
41324
  }
41269
- else if (currentStatus !== ResourceStatus.Loading &&
41270
- currentStatus !== ResourceStatus.Reloading) {
41271
- // We might've transitioned into a loading state, but has since been overwritten (likely via
41272
- // `.set`).
41273
- // In this case, the resource has nothing to do.
41325
+ else if (currentStatus !== ResourceStatus.Loading) {
41326
+ // We're not in a loading or reloading state, so this loading request is stale.
41274
41327
  return;
41275
41328
  }
41276
41329
  // Cancel any previous loading attempts.
@@ -41293,27 +41346,31 @@ class ResourceImpl extends BaseWritableResource {
41293
41346
  // which side of the `await` they are.
41294
41347
  const stream = await untracked(() => {
41295
41348
  return this.loaderFn({
41296
- request: request,
41349
+ request: extRequest.request,
41297
41350
  abortSignal,
41298
41351
  previous: {
41299
41352
  status: previousStatus,
41300
41353
  },
41301
41354
  });
41302
41355
  });
41303
- if (abortSignal.aborted) {
41356
+ // If this request has been aborted, or the current request no longer
41357
+ // matches this load, then we should ignore this resolution.
41358
+ if (abortSignal.aborted || untracked(this.extRequest) !== extRequest) {
41304
41359
  return;
41305
41360
  }
41306
41361
  this.state.set({
41362
+ extRequest,
41307
41363
  status: ResourceStatus.Resolved,
41308
41364
  previousStatus: ResourceStatus.Resolved,
41309
41365
  stream,
41310
41366
  });
41311
41367
  }
41312
41368
  catch (err) {
41313
- if (abortSignal.aborted) {
41369
+ if (abortSignal.aborted || untracked(this.extRequest) !== extRequest) {
41314
41370
  return;
41315
41371
  }
41316
41372
  this.state.set({
41373
+ extRequest,
41317
41374
  status: ResourceStatus.Resolved,
41318
41375
  previousStatus: ResourceStatus.Error,
41319
41376
  stream: signal({ error: err }),
@@ -41355,10 +41412,13 @@ function getLoader(options) {
41355
41412
  function isStreamingResourceOptions(options) {
41356
41413
  return !!options.stream;
41357
41414
  }
41358
- function computeStatusOfState(state) {
41359
- switch (state?.status) {
41360
- case undefined:
41361
- return ResourceStatus.Idle;
41415
+ /**
41416
+ * Project from a state with `ResourceInternalStatus` to the user-facing `ResourceStatus`
41417
+ */
41418
+ function projectStatusOfState(state) {
41419
+ switch (state.status) {
41420
+ case ResourceStatus.Loading:
41421
+ return state.extRequest.reload === 0 ? ResourceStatus.Loading : ResourceStatus.Reloading;
41362
41422
  case ResourceStatus.Resolved:
41363
41423
  return isResolved(untracked(state.stream)) ? ResourceStatus.Resolved : ResourceStatus.Error;
41364
41424
  default: