@angular/core 19.1.7 → 19.1.8

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 +115 -67
  2. package/fesm2022/core.mjs.map +1 -1
  3. package/fesm2022/primitives/event-dispatch.mjs +1 -1
  4. package/fesm2022/primitives/signals.mjs +1 -1
  5. package/fesm2022/rxjs-interop.mjs +1 -1
  6. package/fesm2022/testing.mjs +696 -5
  7. package/fesm2022/testing.mjs.map +1 -1
  8. package/index.d.ts +132 -1
  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-3220dafc.js → apply_import_manager-0648daae.js} +1 -1
  14. package/schematics/bundles/checker-2bdbb582.js +2 -2
  15. package/schematics/bundles/cleanup-unused-imports.js +3 -3
  16. package/schematics/bundles/{compiler_host-833d3812.js → compiler_host-9208f64f.js} +1 -1
  17. package/schematics/bundles/control-flow-migration.js +2 -2
  18. package/schematics/bundles/explicit-standalone-flag.js +4 -4
  19. package/schematics/bundles/{imports-abe29092.js → imports-31a38653.js} +1 -1
  20. package/schematics/bundles/index-4978a91a.js +2 -2
  21. package/schematics/bundles/{index-be586082.js → index-4f59e07e.js} +2 -2
  22. package/schematics/bundles/inject-migration.js +5 -5
  23. package/schematics/bundles/{leading_space-d190b83b.js → leading_space-6e7a8ec6.js} +1 -1
  24. package/schematics/bundles/{migrate_ts_type_references-d2b2e8f1.js → migrate_ts_type_references-8541f425.js} +4 -4
  25. package/schematics/bundles/{nodes-a9f0b985.js → nodes-88c2157f.js} +2 -2
  26. package/schematics/bundles/output-migration.js +4 -4
  27. package/schematics/bundles/pending-tasks.js +4 -4
  28. package/schematics/bundles/program-f43dcb10.js +10 -10
  29. package/schematics/bundles/{project_tsconfig_paths-e9ccccbf.js → project_tsconfig_paths-6c9cde78.js} +1 -1
  30. package/schematics/bundles/provide-initializer.js +4 -4
  31. package/schematics/bundles/route-lazy-loading.js +3 -3
  32. package/schematics/bundles/signal-input-migration.js +6 -6
  33. package/schematics/bundles/signal-queries-migration.js +6 -6
  34. package/schematics/bundles/signals.js +6 -6
  35. package/schematics/bundles/standalone-migration.js +5 -5
  36. package/testing/index.d.ts +297 -1
package/fesm2022/core.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Angular v19.1.7
2
+ * @license Angular v19.1.8
3
3
  * (c) 2010-2024 Google LLC. https://angular.io/
4
4
  * License: MIT
5
5
  */
@@ -967,8 +967,9 @@ function stringifyTypeFromDebugInfo(debugInfo) {
967
967
 
968
968
  /** Called when directives inject each other (creating a circular dependency) */
969
969
  function throwCyclicDependencyError(token, path) {
970
- const depPath = path ? `. Dependency path: ${path.join(' > ')} > ${token}` : '';
971
- throw new RuntimeError(-200 /* RuntimeErrorCode.CYCLIC_DI_DEPENDENCY */, ngDevMode ? `Circular dependency in DI detected for ${token}${depPath}` : token);
970
+ throw new RuntimeError(-200 /* RuntimeErrorCode.CYCLIC_DI_DEPENDENCY */, ngDevMode
971
+ ? `Circular dependency in DI detected for ${token}${path ? `. Dependency path: ${path.join(' > ')} > ${token}` : ''}`
972
+ : token);
972
973
  }
973
974
  function throwMixedMultiProviderError() {
974
975
  throw new Error(`Cannot mix multi providers and regular providers`);
@@ -7105,23 +7106,6 @@ function unwrapElementRef(value) {
7105
7106
  return value instanceof ElementRef ? value.nativeElement : value;
7106
7107
  }
7107
7108
 
7108
- const markedFeatures = new Set();
7109
- // tslint:disable:ban
7110
- /**
7111
- * A guarded `performance.mark` for feature marking.
7112
- *
7113
- * This method exists because while all supported browser and node.js version supported by Angular
7114
- * support performance.mark API. This is not the case for other environments such as JSDOM and
7115
- * Cloudflare workers.
7116
- */
7117
- function performanceMarkFeature(feature) {
7118
- if (markedFeatures.has(feature)) {
7119
- return;
7120
- }
7121
- markedFeatures.add(feature);
7122
- performance?.mark?.('mark_feature_usage', { detail: { feature } });
7123
- }
7124
-
7125
7109
  /**
7126
7110
  * Checks if the given `value` is a reactive `Signal`.
7127
7111
  */
@@ -7144,7 +7128,6 @@ function ɵunwrapWritableSignal(value) {
7144
7128
  * Create a `Signal` that can be set or updated directly.
7145
7129
  */
7146
7130
  function signal(initialValue, options) {
7147
- performanceMarkFeature('NgSignals');
7148
7131
  const signalFn = createSignal$1(initialValue);
7149
7132
  const node = signalFn[SIGNAL$1];
7150
7133
  if (options?.equal) {
@@ -8624,6 +8607,23 @@ var TracingAction;
8624
8607
  */
8625
8608
  const TracingService = new InjectionToken(ngDevMode ? 'TracingService' : '');
8626
8609
 
8610
+ const markedFeatures = new Set();
8611
+ // tslint:disable:ban
8612
+ /**
8613
+ * A guarded `performance.mark` for feature marking.
8614
+ *
8615
+ * This method exists because while all supported browser and node.js version supported by Angular
8616
+ * support performance.mark API. This is not the case for other environments such as JSDOM and
8617
+ * Cloudflare workers.
8618
+ */
8619
+ function performanceMarkFeature(feature) {
8620
+ if (markedFeatures.has(feature)) {
8621
+ return;
8622
+ }
8623
+ markedFeatures.add(feature);
8624
+ performance?.mark?.('mark_feature_usage', { detail: { feature } });
8625
+ }
8626
+
8627
8627
  /**
8628
8628
  * Asserts that the current stack frame is not within a reactive context. Useful
8629
8629
  * to disallow certain code from running inside a reactive context (see {@link toSignal}).
@@ -15864,7 +15864,7 @@ function createIcuIterator(tIcu, lView) {
15864
15864
  * - the `b` char which indicates that the lookup should start from the `document.body`
15865
15865
  * - the `h` char to start lookup from the component host node (`lView[HOST]`)
15866
15866
  */
15867
- const REF_EXTRACTOR_REGEXP = new RegExp(`^(\\d+)*(${REFERENCE_NODE_BODY}|${REFERENCE_NODE_HOST})*(.*)`);
15867
+ const REF_EXTRACTOR_REGEXP = /* @__PURE__ */ new RegExp(`^(\\d+)*(${REFERENCE_NODE_BODY}|${REFERENCE_NODE_HOST})*(.*)`);
15868
15868
  /**
15869
15869
  * Helper function that takes a reference node location and a set of navigation steps
15870
15870
  * (from the reference node) to a target node and outputs a string that represents
@@ -16744,6 +16744,18 @@ function removeDehydratedViews(lContainer) {
16744
16744
  // once again in case a `ViewContainerRef` is created later).
16745
16745
  lContainer[DEHYDRATED_VIEWS] = retainedViews;
16746
16746
  }
16747
+ function removeDehydratedViewList(deferBlock) {
16748
+ const { lContainer } = deferBlock;
16749
+ const dehydratedViews = lContainer[DEHYDRATED_VIEWS];
16750
+ if (dehydratedViews === null)
16751
+ return;
16752
+ const parentLView = lContainer[PARENT];
16753
+ const renderer = parentLView[RENDERER];
16754
+ for (const view of dehydratedViews) {
16755
+ removeDehydratedView(view, renderer);
16756
+ ngDevMode && ngDevMode.dehydratedViewsRemoved++;
16757
+ }
16758
+ }
16747
16759
  /**
16748
16760
  * Helper function to remove all nodes from a dehydrated view.
16749
16761
  */
@@ -17901,7 +17913,7 @@ class ComponentFactory extends ComponentFactory$1 {
17901
17913
  const cmpDef = this.componentDef;
17902
17914
  ngDevMode && verifyNotAnOrphanComponent(cmpDef);
17903
17915
  const tAttributes = rootSelectorOrNode
17904
- ? ['ng-version', '19.1.7']
17916
+ ? ['ng-version', '19.1.8']
17905
17917
  : // Extract attributes and classes from the first selector only to match VE behavior.
17906
17918
  extractAttrsAndClassesFromSelector(this.componentDef.selectors[0]);
17907
17919
  // Create the root view. Uses empty TView and ContentTemplate.
@@ -21168,8 +21180,9 @@ function renderDeferBlockState(newState, tNode, lContainer, skipTimerScheduling
21168
21180
  }
21169
21181
  }
21170
21182
  function findMatchingDehydratedViewForDeferBlock(lContainer, lDetails) {
21171
- // Find matching view based on serialized defer block state.
21172
- return (lContainer[DEHYDRATED_VIEWS]?.find((view) => view.data[DEFER_BLOCK_STATE$1] === lDetails[DEFER_BLOCK_STATE]) ?? null);
21183
+ const dehydratedViewIx = lContainer[DEHYDRATED_VIEWS]?.findIndex((view) => view.data[DEFER_BLOCK_STATE$1] === lDetails[DEFER_BLOCK_STATE]) ?? -1;
21184
+ const dehydratedView = dehydratedViewIx > -1 ? lContainer[DEHYDRATED_VIEWS][dehydratedViewIx] : null;
21185
+ return { dehydratedView, dehydratedViewIx };
21173
21186
  }
21174
21187
  /**
21175
21188
  * Applies changes to the DOM to reflect a given state.
@@ -21200,21 +21213,23 @@ function applyDeferBlockState(newState, lDetails, lContainer, tNode, hostLView)
21200
21213
  injector = createDeferBlockInjector(hostLView[INJECTOR], tDetails, providers);
21201
21214
  }
21202
21215
  }
21203
- const dehydratedView = findMatchingDehydratedViewForDeferBlock(lContainer, lDetails);
21204
- // Erase dehydrated view info, so that it's not removed later
21205
- // by post-hydration cleanup process.
21206
- lContainer[DEHYDRATED_VIEWS] = null;
21216
+ const { dehydratedView, dehydratedViewIx } = findMatchingDehydratedViewForDeferBlock(lContainer, lDetails);
21207
21217
  const embeddedLView = createAndRenderEmbeddedLView(hostLView, activeBlockTNode, null, {
21208
21218
  injector,
21209
21219
  dehydratedView,
21210
21220
  });
21211
21221
  addLViewToLContainer(lContainer, embeddedLView, viewIndex, shouldAddViewToDom(activeBlockTNode, dehydratedView));
21212
21222
  markViewDirty(embeddedLView, 2 /* NotificationSource.DeferBlockStateUpdate */);
21213
- // TODO(incremental-hydration):
21214
- // - what if we had some views in `lContainer[DEHYDRATED_VIEWS]`, but
21215
- // we didn't find a view that matches the expected state?
21216
- // - for example, handle a situation when a block was in the "completed" state
21217
- // on the server, but the loading failing on the client. How do we reconcile and cleanup?
21223
+ if (dehydratedViewIx > -1) {
21224
+ // Erase dehydrated view info in a given LContainer, so that the view is not
21225
+ // removed later by post-hydration cleanup process (which iterates over all
21226
+ // dehydrated views in component tree). This clears only the dehydrated view
21227
+ // that was found for this render, which in most cases will be the only view.
21228
+ // In the case that there was control flow that changed, there may be either
21229
+ // more than one or the views would not match up due to the server rendered
21230
+ // content being a different branch of the control flow.
21231
+ lContainer[DEHYDRATED_VIEWS]?.splice(dehydratedViewIx, 1);
21232
+ }
21218
21233
  if ((newState === DeferBlockState.Complete || newState === DeferBlockState.Error) &&
21219
21234
  Array.isArray(lDetails[ON_COMPLETE_FNS])) {
21220
21235
  for (const callback of lDetails[ON_COMPLETE_FNS]) {
@@ -24065,16 +24080,36 @@ async function triggerHydrationFromBlockName(injector, blockName, replayQueuedEv
24065
24080
  await parentBlockPromise;
24066
24081
  }
24067
24082
  // Actually do the triggering and hydration of the queue of blocks
24068
- for (const dehydratedBlockId of hydrationQueue) {
24069
- await triggerResourceLoadingForHydration(dehydratedBlockId, dehydratedBlockRegistry);
24070
- await nextRender(injector);
24071
- // TODO(incremental-hydration): assert (in dev mode) that a defer block is present in the dehydrated registry
24072
- // at this point. If not - it means that the block has not been hydrated, for example due to different
24073
- // `@if` conditions on the client and the server. If we detect this case, we should also do the cleanup
24074
- // of all child block (promises, registry state, etc).
24075
- // TODO(incremental-hydration): call `rejectFn` when lDetails[DEFER_BLOCK_STATE] is `DeferBlockState.Error`.
24076
- blocksBeingHydrated.get(dehydratedBlockId).resolve();
24077
- // TODO(incremental-hydration): consider adding a wait for stability here
24083
+ for (let blockQueueIdx = 0; blockQueueIdx < hydrationQueue.length; blockQueueIdx++) {
24084
+ const dehydratedBlockId = hydrationQueue[blockQueueIdx];
24085
+ const dehydratedDeferBlock = dehydratedBlockRegistry.get(dehydratedBlockId);
24086
+ if (dehydratedDeferBlock != null) {
24087
+ // trigger the block resources and await next render for hydration. This should result
24088
+ // in the next block ɵɵdefer instruction being called and that block being added to the dehydrated registry.
24089
+ await triggerResourceLoadingForHydration(dehydratedDeferBlock);
24090
+ await nextRender(injector);
24091
+ // if the content has changed since server rendering, we need to check for the expected block
24092
+ // being in the registry or if errors occurred. In that case, we need to clean up the remaining expected
24093
+ // content that won't be rendered or fetched.
24094
+ if (deferBlockHasErrored(dehydratedDeferBlock)) {
24095
+ // Either the expected block has not yet had its ɵɵdefer instruction called or the block errored out when fetching
24096
+ // resources. In the former case, either we're hydrating too soon or the client and server differ. In both cases,
24097
+ // we need to clean up child content and promises.
24098
+ removeDehydratedViewList(dehydratedDeferBlock);
24099
+ cleanupRemainingHydrationQueue(hydrationQueue.slice(blockQueueIdx), dehydratedBlockRegistry);
24100
+ break;
24101
+ }
24102
+ // The defer block has not errored and we've finished fetching resources and rendering.
24103
+ // At this point it is safe to resolve the hydration promise.
24104
+ blocksBeingHydrated.get(dehydratedBlockId).resolve();
24105
+ }
24106
+ else {
24107
+ // The expected block has not yet had its ɵɵdefer instruction called. This is likely due to content changing between
24108
+ // client and server. We need to clean up the dehydrated DOM in the container since it no longer is valid.
24109
+ cleanupParentContainer(blockQueueIdx, hydrationQueue, dehydratedBlockRegistry);
24110
+ cleanupRemainingHydrationQueue(hydrationQueue.slice(blockQueueIdx), dehydratedBlockRegistry);
24111
+ break;
24112
+ }
24078
24113
  }
24079
24114
  // Await hydration completion for the requested block.
24080
24115
  await blocksBeingHydrated.get(blockName)?.promise;
@@ -24087,6 +24122,33 @@ async function triggerHydrationFromBlockName(injector, blockName, replayQueuedEv
24087
24122
  // Cleanup after hydration of all affected defer blocks.
24088
24123
  cleanupHydratedDeferBlocks(dehydratedBlockRegistry.get(blockName), hydrationQueue, dehydratedBlockRegistry, injector.get(ApplicationRef));
24089
24124
  }
24125
+ function deferBlockHasErrored(deferBlock) {
24126
+ return (getLDeferBlockDetails(deferBlock.lView, deferBlock.tNode)[DEFER_BLOCK_STATE] ===
24127
+ DeferBlockState.Error);
24128
+ }
24129
+ /**
24130
+ * Clean up the parent container of a block where content changed between server and client.
24131
+ * The parent of a block going through `triggerHydrationFromBlockName` will contain the
24132
+ * dehydrated content that needs to be cleaned up. So we have to do the clean up from that location
24133
+ * in the tree.
24134
+ */
24135
+ function cleanupParentContainer(currentBlockIdx, hydrationQueue, dehydratedBlockRegistry) {
24136
+ // If a parent block exists, it's in the hydration queue in front of the current block.
24137
+ const parentDeferBlockIdx = currentBlockIdx - 1;
24138
+ const parentDeferBlock = parentDeferBlockIdx > -1
24139
+ ? dehydratedBlockRegistry.get(hydrationQueue[parentDeferBlockIdx])
24140
+ : null;
24141
+ if (parentDeferBlock) {
24142
+ cleanupLContainer(parentDeferBlock.lContainer);
24143
+ }
24144
+ }
24145
+ function cleanupRemainingHydrationQueue(hydrationQueue, dehydratedBlockRegistry) {
24146
+ const blocksBeingHydrated = dehydratedBlockRegistry.hydrating;
24147
+ for (const dehydratedBlockId in hydrationQueue) {
24148
+ blocksBeingHydrated.get(dehydratedBlockId)?.reject();
24149
+ }
24150
+ dehydratedBlockRegistry.cleanup(hydrationQueue);
24151
+ }
24090
24152
  /**
24091
24153
  * Generates a new promise for every defer block in the hydrating queue
24092
24154
  */
@@ -24099,18 +24161,8 @@ function populateHydratingStateForQueue(registry, queue) {
24099
24161
  function nextRender(injector) {
24100
24162
  return new Promise((resolveFn) => afterNextRender(resolveFn, { injector }));
24101
24163
  }
24102
- async function triggerResourceLoadingForHydration(dehydratedBlockId, dehydratedBlockRegistry) {
24103
- const deferBlock = dehydratedBlockRegistry.get(dehydratedBlockId);
24104
- // Since we trigger hydration for nested defer blocks in a sequence (parent -> child),
24105
- // there is a chance that a defer block may not be present at hydration time. For example,
24106
- // when a nested block was in an `@if` condition, which has changed.
24107
- if (deferBlock === null) {
24108
- // TODO(incremental-hydration): handle the cleanup for cases when
24109
- // defer block is no longer present during hydration (e.g. `@if` condition
24110
- // has changed during hydration/rendering).
24111
- return;
24112
- }
24113
- const { tNode, lView } = deferBlock;
24164
+ async function triggerResourceLoadingForHydration(dehydratedBlock) {
24165
+ const { tNode, lView } = dehydratedBlock;
24114
24166
  const lDetails = getLDeferBlockDetails(lView, tNode);
24115
24167
  return new Promise((resolve) => {
24116
24168
  onDeferBlockCompletion(lDetails, resolve);
@@ -33473,11 +33525,12 @@ function executeWithInvalidateFallback(importMeta, id, callback) {
33473
33525
  callback();
33474
33526
  }
33475
33527
  catch (e) {
33476
- const errorMessage = e.message;
33528
+ const error = e;
33477
33529
  // If we have all the necessary information and APIs to send off the invalidation
33478
33530
  // request, send it before rethrowing so the dev server can decide what to do.
33479
- if (id !== null && errorMessage) {
33480
- importMeta?.hot?.send?.('angular:invalidate', { id, message: errorMessage, error: true });
33531
+ if (id !== null && error.message) {
33532
+ const toLog = error.message + (error.stack ? '\n' + error.stack : '');
33533
+ importMeta?.hot?.send?.('angular:invalidate', { id, message: toLog, error: true });
33481
33534
  }
33482
33535
  // Throw the error in case the page doesn't get refreshed.
33483
33536
  throw e;
@@ -34907,7 +34960,7 @@ class Version {
34907
34960
  /**
34908
34961
  * @publicApi
34909
34962
  */
34910
- const VERSION = new Version('19.1.7');
34963
+ const VERSION = new Version('19.1.8');
34911
34964
 
34912
34965
  /**
34913
34966
  * Combination of NgModuleFactory and ComponentFactories.
@@ -35748,10 +35801,9 @@ class ImagePerformanceWarning {
35748
35801
  window = null;
35749
35802
  observer = null;
35750
35803
  options = inject(IMAGE_CONFIG);
35751
- isBrowser = inject(PLATFORM_ID) === 'browser';
35752
35804
  lcpImageUrl;
35753
35805
  start() {
35754
- if (!this.isBrowser ||
35806
+ if ((typeof ngServerMode !== 'undefined' && ngServerMode) ||
35755
35807
  typeof PerformanceObserver === 'undefined' ||
35756
35808
  (this.options?.disableImageSizeWarning && this.options?.disableImageLazyLoadWarning)) {
35757
35809
  return;
@@ -35759,7 +35811,7 @@ class ImagePerformanceWarning {
35759
35811
  this.observer = this.initPerformanceObserver();
35760
35812
  const doc = getDocument();
35761
35813
  const win = doc.defaultView;
35762
- if (typeof win !== 'undefined') {
35814
+ if (win) {
35763
35815
  this.window = win;
35764
35816
  // Wait to avoid race conditions where LCP image triggers
35765
35817
  // load event before it's recorded by the performance observer
@@ -40515,7 +40567,6 @@ function ɵɵngDeclarePipe(decl) {
40515
40567
  * Create a computed `Signal` which derives a reactive value from an expression.
40516
40568
  */
40517
40569
  function computed(computation, options) {
40518
- performanceMarkFeature('NgSignals');
40519
40570
  const getter = createComputed$1(computation);
40520
40571
  if (options?.equal) {
40521
40572
  getter[SIGNAL$1].equal = options.equal;
@@ -40529,7 +40580,6 @@ function computed(computation, options) {
40529
40580
 
40530
40581
  const identityFn = (v) => v;
40531
40582
  function linkedSignal(optionsOrComputation, options) {
40532
- performanceMarkFeature('NgSignals');
40533
40583
  if (typeof optionsOrComputation === 'function') {
40534
40584
  const getter = createLinkedSignal$1(optionsOrComputation, (identityFn), options?.equal);
40535
40585
  return upgradeLinkedSignalGetter(getter);
@@ -40670,7 +40720,6 @@ function effect$1() { }
40670
40720
  * Create a global `Effect` for the given reactive function.
40671
40721
  */
40672
40722
  function microtaskEffect(effectFn, options) {
40673
- performanceMarkFeature('NgSignals');
40674
40723
  ngDevMode &&
40675
40724
  assertNotInReactiveContext(effect$1, 'Call `effect` outside of a reactive context. For example, schedule the ' +
40676
40725
  'effect inside the component constructor.');
@@ -40743,7 +40792,6 @@ function effect(effectFn, options) {
40743
40792
  }
40744
40793
  return microtaskEffect(effectFn, options);
40745
40794
  }
40746
- performanceMarkFeature('NgSignals');
40747
40795
  ngDevMode &&
40748
40796
  assertNotInReactiveContext(effect, 'Call `effect` outside of a reactive context. For example, schedule the ' +
40749
40797
  'effect inside the component constructor.');