@angular/core 16.0.0 → 16.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm2022/src/application_ref.mjs +60 -55
- package/esm2022/src/change_detection/change_detector_ref.mjs +2 -2
- package/esm2022/src/core_private_export.mjs +1 -2
- package/esm2022/src/di/injectable.mjs +2 -1
- package/esm2022/src/di/metadata.mjs +6 -5
- package/esm2022/src/di/metadata_attr.mjs +2 -1
- package/esm2022/src/di/r3_injector.mjs +6 -3
- package/esm2022/src/errors.mjs +1 -1
- package/esm2022/src/hydration/annotate.mjs +1 -1
- package/esm2022/src/hydration/api.mjs +32 -4
- package/esm2022/src/hydration/skip_hydration.mjs +12 -1
- package/esm2022/src/hydration/utils.mjs +9 -3
- package/esm2022/src/i18n/locale_data_api.mjs +2 -2
- package/esm2022/src/linker/element_ref.mjs +1 -1
- package/esm2022/src/linker/view_container_ref.mjs +16 -6
- package/esm2022/src/metadata/di.mjs +5 -4
- package/esm2022/src/metadata/directives.mjs +7 -7
- package/esm2022/src/metadata/ng_module.mjs +2 -1
- package/esm2022/src/render/api.mjs +1 -1
- package/esm2022/src/render3/bindings.mjs +2 -2
- package/esm2022/src/render3/component.mjs +4 -4
- package/esm2022/src/render3/definition.mjs +5 -2
- package/esm2022/src/render3/errors.mjs +6 -3
- package/esm2022/src/render3/instructions/element_validation.mjs +2 -2
- package/esm2022/src/render3/instructions/listener.mjs +1 -3
- package/esm2022/src/render3/instructions/shared.mjs +7 -3
- package/esm2022/src/render3/interfaces/document.mjs +6 -4
- package/esm2022/src/render3/interfaces/node.mjs +1 -1
- package/esm2022/src/render3/node_manipulation.mjs +10 -2
- package/esm2022/src/signals/src/api.mjs +5 -3
- package/esm2022/src/transfer_state.mjs +13 -28
- package/esm2022/src/util/assert.mjs +2 -5
- package/esm2022/src/version.mjs +1 -1
- package/esm2022/testing/src/logger.mjs +3 -3
- package/esm2022/testing/src/test_bed.mjs +4 -4
- package/esm2022/testing/src/test_bed_common.mjs +1 -1
- package/fesm2022/core.mjs +237 -171
- package/fesm2022/core.mjs.map +1 -1
- package/fesm2022/rxjs-interop.mjs +5 -3
- package/fesm2022/rxjs-interop.mjs.map +1 -1
- package/fesm2022/testing.mjs +134 -102
- package/fesm2022/testing.mjs.map +1 -1
- package/index.d.ts +48 -43
- package/package.json +1 -1
- package/rxjs-interop/index.d.ts +1 -1
- package/schematics/migrations/guard-and-resolve-interfaces/bundle.js +13 -13
- package/schematics/migrations/remove-module-id/bundle.js +14 -14
- package/schematics/ng-generate/standalone-migration/bundle.js +415 -361
- package/schematics/ng-generate/standalone-migration/bundle.js.map +3 -3
- package/testing/index.d.ts +5 -5
package/fesm2022/testing.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @license Angular v16.0.
|
|
2
|
+
* @license Angular v16.0.2
|
|
3
3
|
* (c) 2010-2022 Google LLC. https://angular.io/
|
|
4
4
|
* License: MIT
|
|
5
5
|
*/
|
|
@@ -941,10 +941,7 @@ function throwError(msg, actual, expected, comparison) {
|
|
|
941
941
|
(comparison == null ? '' : ` [Expected=> ${expected} ${comparison} ${actual} <=Actual]`));
|
|
942
942
|
}
|
|
943
943
|
function assertDomNode(node) {
|
|
944
|
-
|
|
945
|
-
if (!(typeof Node !== 'undefined' && node instanceof Node) &&
|
|
946
|
-
!(typeof node === 'object' && node != null &&
|
|
947
|
-
node.constructor.name === 'WebWorkerRenderNode')) {
|
|
944
|
+
if (!(node instanceof Node)) {
|
|
948
945
|
throwError(`The provided value must be an instance of a DOM Node but got ${stringify(node)}`);
|
|
949
946
|
}
|
|
950
947
|
}
|
|
@@ -2042,6 +2039,7 @@ function formatError(text, obj, injectorErrorName, source = null) {
|
|
|
2042
2039
|
/**
|
|
2043
2040
|
* Inject decorator and metadata.
|
|
2044
2041
|
*
|
|
2042
|
+
* @Annotation
|
|
2045
2043
|
* @publicApi
|
|
2046
2044
|
*/
|
|
2047
2045
|
const Inject = attachInjectFlag(
|
|
@@ -2051,7 +2049,7 @@ makeParamDecorator('Inject', (token) => ({ token })), -1 /* DecoratorFlags.Injec
|
|
|
2051
2049
|
/**
|
|
2052
2050
|
* Optional decorator and metadata.
|
|
2053
2051
|
*
|
|
2054
|
-
|
|
2052
|
+
* @Annotation
|
|
2055
2053
|
* @publicApi
|
|
2056
2054
|
*/
|
|
2057
2055
|
const Optional =
|
|
@@ -2061,7 +2059,7 @@ attachInjectFlag(makeParamDecorator('Optional'), 8 /* InternalInjectFlags.Option
|
|
|
2061
2059
|
/**
|
|
2062
2060
|
* Self decorator and metadata.
|
|
2063
2061
|
*
|
|
2064
|
-
|
|
2062
|
+
* @Annotation
|
|
2065
2063
|
* @publicApi
|
|
2066
2064
|
*/
|
|
2067
2065
|
const Self =
|
|
@@ -2071,7 +2069,7 @@ attachInjectFlag(makeParamDecorator('Self'), 2 /* InternalInjectFlags.Self */);
|
|
|
2071
2069
|
/**
|
|
2072
2070
|
* `SkipSelf` decorator and metadata.
|
|
2073
2071
|
*
|
|
2074
|
-
|
|
2072
|
+
* @Annotation
|
|
2075
2073
|
* @publicApi
|
|
2076
2074
|
*/
|
|
2077
2075
|
const SkipSelf =
|
|
@@ -2081,7 +2079,7 @@ attachInjectFlag(makeParamDecorator('SkipSelf'), 4 /* InternalInjectFlags.SkipSe
|
|
|
2081
2079
|
/**
|
|
2082
2080
|
* Host decorator and metadata.
|
|
2083
2081
|
*
|
|
2084
|
-
|
|
2082
|
+
* @Annotation
|
|
2085
2083
|
* @publicApi
|
|
2086
2084
|
*/
|
|
2087
2085
|
const Host =
|
|
@@ -3086,7 +3084,7 @@ function getPipeDef$1(type) {
|
|
|
3086
3084
|
/**
|
|
3087
3085
|
* Checks whether a given Component, Directive or Pipe is marked as standalone.
|
|
3088
3086
|
* This will return false if passed anything other than a Component, Directive, or Pipe class
|
|
3089
|
-
* See this guide for additional information:
|
|
3087
|
+
* See [this guide](/guide/standalone-components) for additional information:
|
|
3090
3088
|
*
|
|
3091
3089
|
* @param type A reference to a Component, Directive or Pipe.
|
|
3092
3090
|
* @publicApi
|
|
@@ -3166,6 +3164,9 @@ function getComponentId(componentDef) {
|
|
|
3166
3164
|
componentDef.decls,
|
|
3167
3165
|
componentDef.encapsulation,
|
|
3168
3166
|
componentDef.standalone,
|
|
3167
|
+
componentDef.exportAs,
|
|
3168
|
+
JSON.stringify(componentDef.inputs),
|
|
3169
|
+
JSON.stringify(componentDef.outputs),
|
|
3169
3170
|
// We cannot use 'componentDef.type.name' as the name of the symbol will change and will not
|
|
3170
3171
|
// match in the server and browser bundles.
|
|
3171
3172
|
Object.getOwnPropertyNames(componentDef.type.prototype),
|
|
@@ -3429,10 +3430,12 @@ function getFactoryDef(type, throwNotFound) {
|
|
|
3429
3430
|
*/
|
|
3430
3431
|
const SIGNAL = Symbol('SIGNAL');
|
|
3431
3432
|
/**
|
|
3432
|
-
* Checks if the given `value`
|
|
3433
|
+
* Checks if the given `value` is a reactive `Signal`.
|
|
3434
|
+
*
|
|
3435
|
+
* @developerPreview
|
|
3433
3436
|
*/
|
|
3434
3437
|
function isSignal(value) {
|
|
3435
|
-
return value[SIGNAL] !== undefined;
|
|
3438
|
+
return typeof value === 'function' && value[SIGNAL] !== undefined;
|
|
3436
3439
|
}
|
|
3437
3440
|
/**
|
|
3438
3441
|
* Converts `fn` into a marked signal function (where `isSignal(fn)` will be `true`), and
|
|
@@ -6083,6 +6086,7 @@ function ɵɵinjectAttribute(attrNameToInject) {
|
|
|
6083
6086
|
/**
|
|
6084
6087
|
* Attribute decorator and metadata.
|
|
6085
6088
|
*
|
|
6089
|
+
* @Annotation
|
|
6086
6090
|
* @publicApi
|
|
6087
6091
|
*/
|
|
6088
6092
|
const Attribute = makeParamDecorator('Attribute', (attributeName) => ({ attributeName, __NG_ELEMENT_ID__: () => ɵɵinjectAttribute(attributeName) }));
|
|
@@ -6383,7 +6387,7 @@ function isPropertyValid(element, propName, tagName, schemas) {
|
|
|
6383
6387
|
if (schemas === null)
|
|
6384
6388
|
return true;
|
|
6385
6389
|
// The property is considered valid if the element matches the schema, it exists on the element,
|
|
6386
|
-
// or it is synthetic
|
|
6390
|
+
// or it is synthetic.
|
|
6387
6391
|
if (matchingSchemas(schemas, tagName) || propName in element || isAnimationProp(propName)) {
|
|
6388
6392
|
return true;
|
|
6389
6393
|
}
|
|
@@ -6525,6 +6529,59 @@ function matchingSchemas(schemas, tagName) {
|
|
|
6525
6529
|
return false;
|
|
6526
6530
|
}
|
|
6527
6531
|
|
|
6532
|
+
/**
|
|
6533
|
+
* The name of an attribute that can be added to the hydration boundary node
|
|
6534
|
+
* (component host node) to disable hydration for the content within that boundary.
|
|
6535
|
+
*/
|
|
6536
|
+
const SKIP_HYDRATION_ATTR_NAME = 'ngSkipHydration';
|
|
6537
|
+
/**
|
|
6538
|
+
* Helper function to check if a given node has the 'ngSkipHydration' attribute
|
|
6539
|
+
*/
|
|
6540
|
+
function hasNgSkipHydrationAttr(tNode) {
|
|
6541
|
+
const SKIP_HYDRATION_ATTR_NAME_LOWER_CASE = SKIP_HYDRATION_ATTR_NAME.toLowerCase();
|
|
6542
|
+
const attrs = tNode.mergedAttrs;
|
|
6543
|
+
if (attrs === null)
|
|
6544
|
+
return false;
|
|
6545
|
+
// only ever look at the attribute name and skip the values
|
|
6546
|
+
for (let i = 0; i < attrs.length; i += 2) {
|
|
6547
|
+
const value = attrs[i];
|
|
6548
|
+
// This is a marker, which means that the static attributes section is over,
|
|
6549
|
+
// so we can exit early.
|
|
6550
|
+
if (typeof value === 'number')
|
|
6551
|
+
return false;
|
|
6552
|
+
if (typeof value === 'string' && value.toLowerCase() === SKIP_HYDRATION_ATTR_NAME_LOWER_CASE) {
|
|
6553
|
+
return true;
|
|
6554
|
+
}
|
|
6555
|
+
}
|
|
6556
|
+
return false;
|
|
6557
|
+
}
|
|
6558
|
+
/**
|
|
6559
|
+
* Checks whether a TNode has a flag to indicate that it's a part of
|
|
6560
|
+
* a skip hydration block.
|
|
6561
|
+
*/
|
|
6562
|
+
function hasInSkipHydrationBlockFlag(tNode) {
|
|
6563
|
+
return (tNode.flags & 128 /* TNodeFlags.inSkipHydrationBlock */) === 128 /* TNodeFlags.inSkipHydrationBlock */;
|
|
6564
|
+
}
|
|
6565
|
+
/**
|
|
6566
|
+
* Helper function that determines if a given node is within a skip hydration block
|
|
6567
|
+
* by navigating up the TNode tree to see if any parent nodes have skip hydration
|
|
6568
|
+
* attribute.
|
|
6569
|
+
*
|
|
6570
|
+
* TODO(akushnir): this function should contain the logic of `hasInSkipHydrationBlockFlag`,
|
|
6571
|
+
* there is no need to traverse parent nodes when we have a TNode flag (which would also
|
|
6572
|
+
* make this lookup O(1)).
|
|
6573
|
+
*/
|
|
6574
|
+
function isInSkipHydrationBlock(tNode) {
|
|
6575
|
+
let currentTNode = tNode.parent;
|
|
6576
|
+
while (currentTNode) {
|
|
6577
|
+
if (hasNgSkipHydrationAttr(currentTNode)) {
|
|
6578
|
+
return true;
|
|
6579
|
+
}
|
|
6580
|
+
currentTNode = currentTNode.parent;
|
|
6581
|
+
}
|
|
6582
|
+
return false;
|
|
6583
|
+
}
|
|
6584
|
+
|
|
6528
6585
|
/**
|
|
6529
6586
|
* Flags for renderer-specific style modifiers.
|
|
6530
6587
|
* @publicApi
|
|
@@ -7404,12 +7461,14 @@ function processCleanups(tView, lView) {
|
|
|
7404
7461
|
}
|
|
7405
7462
|
const destroyHooks = lView[ON_DESTROY_HOOKS];
|
|
7406
7463
|
if (destroyHooks !== null) {
|
|
7464
|
+
// Reset the ON_DESTROY_HOOKS array before iterating over it to prevent hooks that unregister
|
|
7465
|
+
// themselves from mutating the array during iteration.
|
|
7466
|
+
lView[ON_DESTROY_HOOKS] = null;
|
|
7407
7467
|
for (let i = 0; i < destroyHooks.length; i++) {
|
|
7408
7468
|
const destroyHooksFn = destroyHooks[i];
|
|
7409
7469
|
ngDevMode && assertFunction(destroyHooksFn, 'Expecting destroy hook to be a function.');
|
|
7410
7470
|
destroyHooksFn();
|
|
7411
7471
|
}
|
|
7412
|
-
lView[ON_DESTROY_HOOKS] = null;
|
|
7413
7472
|
}
|
|
7414
7473
|
}
|
|
7415
7474
|
/** Calls onDestroy hooks for this view */
|
|
@@ -7824,6 +7883,11 @@ function applyProjectionRecursive(renderer, action, lView, tProjectionNode, pare
|
|
|
7824
7883
|
else {
|
|
7825
7884
|
let nodeToProject = nodeToProjectOrRNodes;
|
|
7826
7885
|
const projectedComponentLView = componentLView[PARENT];
|
|
7886
|
+
// If a parent <ng-content> is located within a skip hydration block,
|
|
7887
|
+
// annotate an actual node that is being projected with the same flag too.
|
|
7888
|
+
if (hasInSkipHydrationBlockFlag(tProjectionNode)) {
|
|
7889
|
+
nodeToProject.flags |= 128 /* TNodeFlags.inSkipHydrationBlock */;
|
|
7890
|
+
}
|
|
7827
7891
|
applyNodes(renderer, action, nodeToProject, projectedComponentLView, parentRElement, beforeNode, true);
|
|
7828
7892
|
}
|
|
7829
7893
|
}
|
|
@@ -8124,7 +8188,7 @@ function ɵɵvalidateIframeAttribute(attrValue, tagName, attrName) {
|
|
|
8124
8188
|
* When running ivy outside of a browser environment, it is necessary to call `setDocument()` to
|
|
8125
8189
|
* tell ivy what the global `document` is.
|
|
8126
8190
|
*
|
|
8127
|
-
* Angular does this for us in each of the standard platforms (`Browser
|
|
8191
|
+
* Angular does this for us in each of the standard platforms (`Browser` and `Server`)
|
|
8128
8192
|
* by calling `setDocument()` when providing the `DOCUMENT` token.
|
|
8129
8193
|
*/
|
|
8130
8194
|
let DOCUMENT = undefined;
|
|
@@ -8151,12 +8215,13 @@ function getDocument() {
|
|
|
8151
8215
|
else if (typeof document !== 'undefined') {
|
|
8152
8216
|
return document;
|
|
8153
8217
|
}
|
|
8218
|
+
throw new RuntimeError(210 /* RuntimeErrorCode.MISSING_DOCUMENT */, (typeof ngDevMode === 'undefined' || ngDevMode) &&
|
|
8219
|
+
`The document object is not available in this context. Make sure the DOCUMENT injection token is provided.`);
|
|
8154
8220
|
// No "document" can be found. This should only happen if we are running ivy outside Angular and
|
|
8155
8221
|
// the current platform is not a browser. Since this is not a supported scenario at the moment
|
|
8156
8222
|
// this should not happen in Angular apps.
|
|
8157
8223
|
// Once we support running ivy outside of Angular we will need to publish `setDocument()` as a
|
|
8158
|
-
// public API.
|
|
8159
|
-
return undefined;
|
|
8224
|
+
// public API.
|
|
8160
8225
|
}
|
|
8161
8226
|
|
|
8162
8227
|
/**
|
|
@@ -9400,7 +9465,11 @@ class R3Injector extends EnvironmentInjector {
|
|
|
9400
9465
|
for (const service of this._ngOnDestroyHooks) {
|
|
9401
9466
|
service.ngOnDestroy();
|
|
9402
9467
|
}
|
|
9403
|
-
|
|
9468
|
+
const onDestroyHooks = this._onDestroyHooks;
|
|
9469
|
+
// Reset the _onDestroyHooks array before iterating over it to prevent hooks that unregister
|
|
9470
|
+
// themselves from mutating the array during iteration.
|
|
9471
|
+
this._onDestroyHooks = [];
|
|
9472
|
+
for (const hook of onDestroyHooks) {
|
|
9404
9473
|
hook();
|
|
9405
9474
|
}
|
|
9406
9475
|
}
|
|
@@ -9409,7 +9478,6 @@ class R3Injector extends EnvironmentInjector {
|
|
|
9409
9478
|
this.records.clear();
|
|
9410
9479
|
this._ngOnDestroyHooks.clear();
|
|
9411
9480
|
this.injectorDefTypes.clear();
|
|
9412
|
-
this._onDestroyHooks.length = 0;
|
|
9413
9481
|
}
|
|
9414
9482
|
}
|
|
9415
9483
|
onDestroy(callback) {
|
|
@@ -9823,26 +9891,6 @@ const ENABLED_SSR_FEATURES = new InjectionToken((typeof ngDevMode === 'undefined
|
|
|
9823
9891
|
factory: () => new Set(),
|
|
9824
9892
|
});
|
|
9825
9893
|
|
|
9826
|
-
function escapeTransferStateContent(text) {
|
|
9827
|
-
const escapedText = {
|
|
9828
|
-
'&': '&a;',
|
|
9829
|
-
'"': '&q;',
|
|
9830
|
-
'\'': '&s;',
|
|
9831
|
-
'<': '&l;',
|
|
9832
|
-
'>': '&g;',
|
|
9833
|
-
};
|
|
9834
|
-
return text.replace(/[&"'<>]/g, s => escapedText[s]);
|
|
9835
|
-
}
|
|
9836
|
-
function unescapeTransferStateContent(text) {
|
|
9837
|
-
const unescapedText = {
|
|
9838
|
-
'&a;': '&',
|
|
9839
|
-
'&q;': '"',
|
|
9840
|
-
'&s;': '\'',
|
|
9841
|
-
'&l;': '<',
|
|
9842
|
-
'&g;': '>',
|
|
9843
|
-
};
|
|
9844
|
-
return text.replace(/&[^;]+;/g, s => unescapedText[s]);
|
|
9845
|
-
}
|
|
9846
9894
|
/**
|
|
9847
9895
|
* Create a `StateKey<T>` that can be used to store value of type T with `TransferState`.
|
|
9848
9896
|
*
|
|
@@ -9862,7 +9910,9 @@ function makeStateKey(key) {
|
|
|
9862
9910
|
}
|
|
9863
9911
|
function initTransferState() {
|
|
9864
9912
|
const transferState = new TransferState();
|
|
9865
|
-
|
|
9913
|
+
if (inject$1(PLATFORM_ID) === 'browser') {
|
|
9914
|
+
transferState.store = retrieveTransferredState(getDocument(), inject$1(APP_ID));
|
|
9915
|
+
}
|
|
9866
9916
|
return transferState;
|
|
9867
9917
|
}
|
|
9868
9918
|
/**
|
|
@@ -9944,24 +9994,27 @@ class TransferState {
|
|
|
9944
9994
|
}
|
|
9945
9995
|
}
|
|
9946
9996
|
}
|
|
9947
|
-
|
|
9997
|
+
// Escape script tag to avoid break out of <script> tag in serialized output.
|
|
9998
|
+
// Encoding of `<` is the same behaviour as G3 script_builders.
|
|
9999
|
+
return JSON.stringify(this.store).replace(/</g, '\\u003C');
|
|
9948
10000
|
}
|
|
9949
10001
|
}
|
|
9950
10002
|
function retrieveTransferredState(doc, appId) {
|
|
9951
10003
|
// Locate the script tag with the JSON data transferred from the server.
|
|
9952
10004
|
// The id of the script tag is set to the Angular appId + 'state'.
|
|
9953
10005
|
const script = doc.getElementById(appId + '-state');
|
|
9954
|
-
|
|
9955
|
-
if (script && script.textContent) {
|
|
10006
|
+
if (script?.textContent) {
|
|
9956
10007
|
try {
|
|
9957
10008
|
// Avoid using any here as it triggers lint errors in google3 (any is not allowed).
|
|
9958
|
-
|
|
10009
|
+
// Decoding of `<` is done of the box by browsers and node.js, same behaviour as G3
|
|
10010
|
+
// script_builders.
|
|
10011
|
+
return JSON.parse(script.textContent);
|
|
9959
10012
|
}
|
|
9960
10013
|
catch (e) {
|
|
9961
10014
|
console.warn('Exception while restoring TransferState for app ' + appId, e);
|
|
9962
10015
|
}
|
|
9963
10016
|
}
|
|
9964
|
-
return
|
|
10017
|
+
return {};
|
|
9965
10018
|
}
|
|
9966
10019
|
|
|
9967
10020
|
/** Encodes that the node lookup should start from the host node of this component. */
|
|
@@ -10080,6 +10133,12 @@ function getComponentLViewForHydration(viewRef) {
|
|
|
10080
10133
|
if (isRootView(lView)) {
|
|
10081
10134
|
lView = lView[HEADER_OFFSET];
|
|
10082
10135
|
}
|
|
10136
|
+
// If a `ViewContainerRef` was injected in a component class, this resulted
|
|
10137
|
+
// in an LContainer creation at that location. In this case, the component
|
|
10138
|
+
// LView is in the LContainer's `HOST` slot.
|
|
10139
|
+
if (isLContainer(lView)) {
|
|
10140
|
+
lView = lView[HOST];
|
|
10141
|
+
}
|
|
10083
10142
|
return lView;
|
|
10084
10143
|
}
|
|
10085
10144
|
function getTextNodeContent(node) {
|
|
@@ -10375,7 +10434,7 @@ class Version {
|
|
|
10375
10434
|
/**
|
|
10376
10435
|
* @publicApi
|
|
10377
10436
|
*/
|
|
10378
|
-
const VERSION = new Version('16.0.
|
|
10437
|
+
const VERSION = new Version('16.0.2');
|
|
10379
10438
|
|
|
10380
10439
|
// This default value is when checking the hierarchy for a token.
|
|
10381
10440
|
//
|
|
@@ -10481,48 +10540,6 @@ class ErrorHandler {
|
|
|
10481
10540
|
}
|
|
10482
10541
|
}
|
|
10483
10542
|
|
|
10484
|
-
/**
|
|
10485
|
-
* The name of an attribute that can be added to the hydration boundary node
|
|
10486
|
-
* (component host node) to disable hydration for the content within that boundary.
|
|
10487
|
-
*/
|
|
10488
|
-
const SKIP_HYDRATION_ATTR_NAME = 'ngSkipHydration';
|
|
10489
|
-
/**
|
|
10490
|
-
* Helper function to check if a given node has the 'ngSkipHydration' attribute
|
|
10491
|
-
*/
|
|
10492
|
-
function hasNgSkipHydrationAttr(tNode) {
|
|
10493
|
-
const SKIP_HYDRATION_ATTR_NAME_LOWER_CASE = SKIP_HYDRATION_ATTR_NAME.toLowerCase();
|
|
10494
|
-
const attrs = tNode.mergedAttrs;
|
|
10495
|
-
if (attrs === null)
|
|
10496
|
-
return false;
|
|
10497
|
-
// only ever look at the attribute name and skip the values
|
|
10498
|
-
for (let i = 0; i < attrs.length; i += 2) {
|
|
10499
|
-
const value = attrs[i];
|
|
10500
|
-
// This is a marker, which means that the static attributes section is over,
|
|
10501
|
-
// so we can exit early.
|
|
10502
|
-
if (typeof value === 'number')
|
|
10503
|
-
return false;
|
|
10504
|
-
if (typeof value === 'string' && value.toLowerCase() === SKIP_HYDRATION_ATTR_NAME_LOWER_CASE) {
|
|
10505
|
-
return true;
|
|
10506
|
-
}
|
|
10507
|
-
}
|
|
10508
|
-
return false;
|
|
10509
|
-
}
|
|
10510
|
-
/**
|
|
10511
|
-
* Helper function that determines if a given node is within a skip hydration block
|
|
10512
|
-
* by navigating up the TNode tree to see if any parent nodes have skip hydration
|
|
10513
|
-
* attribute.
|
|
10514
|
-
*/
|
|
10515
|
-
function isInSkipHydrationBlock(tNode) {
|
|
10516
|
-
let currentTNode = tNode.parent;
|
|
10517
|
-
while (currentTNode) {
|
|
10518
|
-
if (hasNgSkipHydrationAttr(currentTNode)) {
|
|
10519
|
-
return true;
|
|
10520
|
-
}
|
|
10521
|
-
currentTNode = currentTNode.parent;
|
|
10522
|
-
}
|
|
10523
|
-
return false;
|
|
10524
|
-
}
|
|
10525
|
-
|
|
10526
10543
|
/**
|
|
10527
10544
|
* Internal token that specifies whether DOM reuse logic
|
|
10528
10545
|
* during hydration is enabled.
|
|
@@ -10584,9 +10601,11 @@ function throwMultipleComponentError(tNode, first, second) {
|
|
|
10584
10601
|
`${stringifyForError(second)}`);
|
|
10585
10602
|
}
|
|
10586
10603
|
/** Throws an ExpressionChangedAfterChecked error if checkNoChanges mode is on. */
|
|
10587
|
-
function throwErrorIfNoChangesMode(creationMode, oldValue, currValue, propName) {
|
|
10604
|
+
function throwErrorIfNoChangesMode(creationMode, oldValue, currValue, propName, lView) {
|
|
10605
|
+
const hostComponentDef = getDeclarationComponentDef(lView);
|
|
10606
|
+
const componentClassName = hostComponentDef?.type?.name;
|
|
10588
10607
|
const field = propName ? ` for '${propName}'` : '';
|
|
10589
|
-
let msg = `ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value${field}: '${oldValue}'. Current value: '${currValue}'
|
|
10608
|
+
let msg = `ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value${field}: '${oldValue}'. Current value: '${currValue}'.${componentClassName ? ` Expression location: ${componentClassName} component` : ''}`;
|
|
10590
10609
|
if (creationMode) {
|
|
10591
10610
|
msg +=
|
|
10592
10611
|
` It seems like the view has been created after its parent and its children have been dirty checked.` +
|
|
@@ -10912,6 +10931,7 @@ function getInjectableMetadata(type, srcMeta) {
|
|
|
10912
10931
|
/**
|
|
10913
10932
|
* Injectable decorator and metadata.
|
|
10914
10933
|
*
|
|
10934
|
+
* @Annotation
|
|
10915
10935
|
* @publicApi
|
|
10916
10936
|
*/
|
|
10917
10937
|
const Injectable = makeDecorator('Injectable', undefined, undefined, undefined, (type, meta) => compileInjectable(type, meta));
|
|
@@ -11468,6 +11488,10 @@ function createTNode(tView, tParent, type, index, value, attrs) {
|
|
|
11468
11488
|
ngDevMode && ngDevMode.tNode++;
|
|
11469
11489
|
ngDevMode && tParent && assertTNodeForTView(tParent, tView);
|
|
11470
11490
|
let injectorIndex = tParent ? tParent.injectorIndex : -1;
|
|
11491
|
+
let flags = 0;
|
|
11492
|
+
if (isInSkipHydrationBlock$1()) {
|
|
11493
|
+
flags |= 128 /* TNodeFlags.inSkipHydrationBlock */;
|
|
11494
|
+
}
|
|
11471
11495
|
const tNode = {
|
|
11472
11496
|
type,
|
|
11473
11497
|
index,
|
|
@@ -11478,7 +11502,7 @@ function createTNode(tView, tParent, type, index, value, attrs) {
|
|
|
11478
11502
|
directiveStylingLast: -1,
|
|
11479
11503
|
componentOffset: -1,
|
|
11480
11504
|
propertyBindings: null,
|
|
11481
|
-
flags
|
|
11505
|
+
flags,
|
|
11482
11506
|
providerIndexes: 0,
|
|
11483
11507
|
value: value,
|
|
11484
11508
|
attrs: attrs,
|
|
@@ -14032,7 +14056,7 @@ function bindingUpdated(lView, bindingIndex, value) {
|
|
|
14032
14056
|
const oldValueToCompare = oldValue !== NO_CHANGE ? oldValue : undefined;
|
|
14033
14057
|
if (!devModeEqual(oldValueToCompare, value)) {
|
|
14034
14058
|
const details = getExpressionChangedErrorDetails(lView, bindingIndex, oldValueToCompare, value);
|
|
14035
|
-
throwErrorIfNoChangesMode(oldValue === NO_CHANGE, details.oldValue, details.newValue, details.propName);
|
|
14059
|
+
throwErrorIfNoChangesMode(oldValue === NO_CHANGE, details.oldValue, details.newValue, details.propName, lView);
|
|
14036
14060
|
}
|
|
14037
14061
|
// There was a change, but the `devModeEqual` decided that the change is exempt from an error.
|
|
14038
14062
|
// For this reason we exit as if no change. The early exit is needed to prevent the changed
|
|
@@ -16017,8 +16041,6 @@ function wrapListener(tNode, lView, context, listenerFn, wrapWithPreventDefault)
|
|
|
16017
16041
|
}
|
|
16018
16042
|
if (wrapWithPreventDefault && result === false) {
|
|
16019
16043
|
e.preventDefault();
|
|
16020
|
-
// Necessary for legacy browsers that don't support preventDefault (e.g. IE)
|
|
16021
|
-
e.returnValue = false;
|
|
16022
16044
|
}
|
|
16023
16045
|
return result;
|
|
16024
16046
|
};
|
|
@@ -19551,7 +19573,7 @@ function getLocaleCurrencyCode(locale) {
|
|
|
19551
19573
|
* @param locale A locale code for the locale format rules to use.
|
|
19552
19574
|
* @returns The plural function for the locale.
|
|
19553
19575
|
* @see `NgPlural`
|
|
19554
|
-
* @see [Internationalization (i18n) Guide](
|
|
19576
|
+
* @see [Internationalization (i18n) Guide](/guide/i18n-overview)
|
|
19555
19577
|
*/
|
|
19556
19578
|
function getLocalePluralCase(locale) {
|
|
19557
19579
|
const data = findLocaleData(locale);
|
|
@@ -23466,7 +23488,11 @@ const R3ViewContainerRef = class ViewContainerRef extends VE_ViewContainerRef {
|
|
|
23466
23488
|
}
|
|
23467
23489
|
const hydrationInfo = findMatchingDehydratedView(this._lContainer, templateRef.ssrId);
|
|
23468
23490
|
const viewRef = templateRef.createEmbeddedViewImpl(context || {}, injector, hydrationInfo);
|
|
23469
|
-
|
|
23491
|
+
// If there is a matching dehydrated view, but the host TNode is located in the skip
|
|
23492
|
+
// hydration block, this means that the content was detached (as a part of the skip
|
|
23493
|
+
// hydration logic) and it needs to be appended into the DOM.
|
|
23494
|
+
const skipDomInsertion = !!hydrationInfo && !hasInSkipHydrationBlockFlag(this._hostTNode);
|
|
23495
|
+
this.insertImpl(viewRef, index, skipDomInsertion);
|
|
23470
23496
|
return viewRef;
|
|
23471
23497
|
}
|
|
23472
23498
|
createComponent(componentFactoryOrType, indexOrOptions, injector, projectableNodes, environmentInjector) {
|
|
@@ -23540,7 +23566,11 @@ const R3ViewContainerRef = class ViewContainerRef extends VE_ViewContainerRef {
|
|
|
23540
23566
|
const dehydratedView = findMatchingDehydratedView(this._lContainer, componentDef?.id ?? null);
|
|
23541
23567
|
const rNode = dehydratedView?.firstChild ?? null;
|
|
23542
23568
|
const componentRef = componentFactory.create(contextInjector, projectableNodes, rNode, environmentInjector);
|
|
23543
|
-
|
|
23569
|
+
// If there is a matching dehydrated view, but the host TNode is located in the skip
|
|
23570
|
+
// hydration block, this means that the content was detached (as a part of the skip
|
|
23571
|
+
// hydration logic) and it needs to be appended into the DOM.
|
|
23572
|
+
const skipDomInsertion = !!dehydratedView && !hasInSkipHydrationBlockFlag(this._hostTNode);
|
|
23573
|
+
this.insertImpl(componentRef.hostView, index, skipDomInsertion);
|
|
23544
23574
|
return componentRef;
|
|
23545
23575
|
}
|
|
23546
23576
|
insert(viewRef, index) {
|
|
@@ -23714,8 +23744,10 @@ function locateOrCreateAnchorNode(lContainer, hostLView, hostTNode, slotValue) {
|
|
|
23714
23744
|
return;
|
|
23715
23745
|
const hydrationInfo = hostLView[HYDRATION];
|
|
23716
23746
|
const noOffsetIndex = hostTNode.index - HEADER_OFFSET;
|
|
23717
|
-
|
|
23718
|
-
|
|
23747
|
+
// TODO(akushnir): this should really be a single condition, refactor the code
|
|
23748
|
+
// to use `hasInSkipHydrationBlockFlag` logic inside `isInSkipHydrationBlock`.
|
|
23749
|
+
const skipHydration = isInSkipHydrationBlock(hostTNode) || hasInSkipHydrationBlockFlag(hostTNode);
|
|
23750
|
+
const isNodeCreationMode = !hydrationInfo || skipHydration || isDisconnectedNode(hydrationInfo, noOffsetIndex);
|
|
23719
23751
|
// Regular creation mode.
|
|
23720
23752
|
if (isNodeCreationMode) {
|
|
23721
23753
|
return createAnchorNode(lContainer, hostLView, hostTNode, slotValue);
|
|
@@ -26127,7 +26159,7 @@ class TestBedImpl {
|
|
|
26127
26159
|
}
|
|
26128
26160
|
configureCompiler(config) {
|
|
26129
26161
|
if (config.useJit != null) {
|
|
26130
|
-
throw new Error('
|
|
26162
|
+
throw new Error('JIT compiler is not configurable via TestBed APIs.');
|
|
26131
26163
|
}
|
|
26132
26164
|
if (config.providers !== undefined) {
|
|
26133
26165
|
this.compiler.setCompilerProviders(config.providers);
|
|
@@ -26135,7 +26167,7 @@ class TestBedImpl {
|
|
|
26135
26167
|
return this;
|
|
26136
26168
|
}
|
|
26137
26169
|
configureTestingModule(moduleDef) {
|
|
26138
|
-
this.assertNotInstantiated('
|
|
26170
|
+
this.assertNotInstantiated('TestBed.configureTestingModule', 'configure the test module');
|
|
26139
26171
|
// Trigger module scoping queue flush before executing other TestBed operations in a test.
|
|
26140
26172
|
// This is needed for the first test invocation to ensure that globally declared modules have
|
|
26141
26173
|
// their components scoped properly. See the `checkGlobalCompilationFinished` function
|
|
@@ -26189,7 +26221,7 @@ class TestBedImpl {
|
|
|
26189
26221
|
return this;
|
|
26190
26222
|
}
|
|
26191
26223
|
overrideTemplateUsingTestingModule(component, template) {
|
|
26192
|
-
this.assertNotInstantiated('
|
|
26224
|
+
this.assertNotInstantiated('TestBed.overrideTemplateUsingTestingModule', 'Cannot override template when the test module has already been instantiated');
|
|
26193
26225
|
this.compiler.overrideTemplateUsingTestingModule(component, template);
|
|
26194
26226
|
return this;
|
|
26195
26227
|
}
|