@angular/core 16.0.0 → 16.1.0-next.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm2022/src/application_ref.mjs +60 -55
- package/esm2022/src/compiler/compiler_facade_interface.mjs +1 -1
- 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/errors.mjs +1 -1
- package/esm2022/src/hydration/annotate.mjs +1 -1
- package/esm2022/src/hydration/api.mjs +2 -2
- package/esm2022/src/hydration/skip_hydration.mjs +12 -1
- package/esm2022/src/hydration/utils.mjs +9 -3
- package/esm2022/src/linker/element_ref.mjs +1 -1
- package/esm2022/src/linker/template_ref.mjs +6 -3
- 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/component.mjs +4 -1
- package/esm2022/src/render3/component_ref.mjs +14 -3
- package/esm2022/src/render3/definition.mjs +9 -3
- package/esm2022/src/render3/di.mjs +2 -2
- package/esm2022/src/render3/hooks.mjs +3 -3
- package/esm2022/src/render3/instructions/change_detection.mjs +37 -53
- package/esm2022/src/render3/instructions/element_validation.mjs +2 -2
- package/esm2022/src/render3/instructions/shared.mjs +15 -4
- package/esm2022/src/render3/interfaces/definition.mjs +1 -1
- package/esm2022/src/render3/interfaces/document.mjs +6 -4
- package/esm2022/src/render3/interfaces/node.mjs +1 -1
- package/esm2022/src/render3/interfaces/public_definitions.mjs +1 -1
- package/esm2022/src/render3/interfaces/view.mjs +1 -1
- package/esm2022/src/render3/jit/directive.mjs +2 -1
- package/esm2022/src/render3/node_manipulation.mjs +7 -1
- package/esm2022/src/transfer_state.mjs +8 -7
- 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/fesm2022/core.mjs +252 -192
- package/fesm2022/core.mjs.map +1 -1
- package/fesm2022/rxjs-interop.mjs +1 -1
- package/fesm2022/rxjs-interop.mjs.map +1 -1
- package/fesm2022/testing.mjs +179 -130
- package/fesm2022/testing.mjs.map +1 -1
- package/index.d.ts +54 -35
- 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 +614 -411
- package/schematics/ng-generate/standalone-migration/bundle.js.map +4 -4
- package/testing/index.d.ts +1 -1
package/fesm2022/testing.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @license Angular v16.0.0
|
|
2
|
+
* @license Angular v16.1.0-next.0
|
|
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 =
|
|
@@ -2873,6 +2871,7 @@ function ɵɵdefineComponent(componentDefinition) {
|
|
|
2873
2871
|
pipeDefs: null,
|
|
2874
2872
|
dependencies: baseDef.standalone && componentDefinition.dependencies || null,
|
|
2875
2873
|
getStandaloneInjector: null,
|
|
2874
|
+
signals: componentDefinition.signals ?? false,
|
|
2876
2875
|
data: componentDefinition.data || {},
|
|
2877
2876
|
encapsulation: componentDefinition.encapsulation || ViewEncapsulation.Emulated,
|
|
2878
2877
|
styles: componentDefinition.styles || EMPTY_ARRAY,
|
|
@@ -3115,6 +3114,7 @@ function getNgDirectiveDef(directiveDefinition) {
|
|
|
3115
3114
|
declaredInputs,
|
|
3116
3115
|
exportAs: directiveDefinition.exportAs || null,
|
|
3117
3116
|
standalone: directiveDefinition.standalone === true,
|
|
3117
|
+
signals: directiveDefinition.signals === true,
|
|
3118
3118
|
selectors: directiveDefinition.selectors || EMPTY_ARRAY,
|
|
3119
3119
|
viewQuery: directiveDefinition.viewQuery || null,
|
|
3120
3120
|
features: directiveDefinition.features || null,
|
|
@@ -3156,7 +3156,7 @@ function getComponentId(componentDef) {
|
|
|
3156
3156
|
// Example:
|
|
3157
3157
|
// https://github.com/angular/components/blob/d9f82c8f95309e77a6d82fd574c65871e91354c2/src/material/core/option/option.ts#L248
|
|
3158
3158
|
// https://github.com/angular/components/blob/285f46dc2b4c5b127d356cb7c4714b221f03ce50/src/material/legacy-core/option/option.ts#L32
|
|
3159
|
-
const hashSelectors = [
|
|
3159
|
+
const hashSelectors = JSON.stringify([
|
|
3160
3160
|
componentDef.selectors,
|
|
3161
3161
|
componentDef.ngContentSelectors,
|
|
3162
3162
|
componentDef.hostVars,
|
|
@@ -3166,12 +3166,16 @@ function getComponentId(componentDef) {
|
|
|
3166
3166
|
componentDef.decls,
|
|
3167
3167
|
componentDef.encapsulation,
|
|
3168
3168
|
componentDef.standalone,
|
|
3169
|
+
componentDef.signals,
|
|
3170
|
+
componentDef.exportAs,
|
|
3171
|
+
componentDef.inputs,
|
|
3172
|
+
componentDef.outputs,
|
|
3169
3173
|
// We cannot use 'componentDef.type.name' as the name of the symbol will change and will not
|
|
3170
3174
|
// match in the server and browser bundles.
|
|
3171
3175
|
Object.getOwnPropertyNames(componentDef.type.prototype),
|
|
3172
3176
|
!!componentDef.contentQueries,
|
|
3173
3177
|
!!componentDef.viewQuery,
|
|
3174
|
-
]
|
|
3178
|
+
]);
|
|
3175
3179
|
for (const char of hashSelectors) {
|
|
3176
3180
|
hash = Math.imul(31, hash) + char.charCodeAt(0) << 0;
|
|
3177
3181
|
}
|
|
@@ -5004,7 +5008,7 @@ function incrementInitPhaseFlags(lView, initPhase) {
|
|
|
5004
5008
|
assertNotEqual(initPhase, 3 /* InitPhaseState.InitPhaseCompleted */, 'Init hooks phase should not be incremented after all init hooks have been run.');
|
|
5005
5009
|
let flags = lView[FLAGS];
|
|
5006
5010
|
if ((flags & 3 /* LViewFlags.InitPhaseStateMask */) === initPhase) {
|
|
5007
|
-
flags &=
|
|
5011
|
+
flags &= 8191 /* LViewFlags.IndexWithinInitPhaseReset */;
|
|
5008
5012
|
flags += 1 /* LViewFlags.InitPhaseStateIncrementer */;
|
|
5009
5013
|
lView[FLAGS] = flags;
|
|
5010
5014
|
}
|
|
@@ -5085,12 +5089,12 @@ function callHook(currentView, initPhase, arr, i) {
|
|
|
5085
5089
|
const directiveIndex = isInitHook ? -arr[i] : arr[i];
|
|
5086
5090
|
const directive = currentView[directiveIndex];
|
|
5087
5091
|
if (isInitHook) {
|
|
5088
|
-
const indexWithintInitPhase = currentView[FLAGS] >>
|
|
5092
|
+
const indexWithintInitPhase = currentView[FLAGS] >> 13 /* LViewFlags.IndexWithinInitPhaseShift */;
|
|
5089
5093
|
// The init phase state must be always checked here as it may have been recursively updated.
|
|
5090
5094
|
if (indexWithintInitPhase <
|
|
5091
5095
|
(currentView[PREORDER_HOOK_FLAGS] >> 16 /* PreOrderHookFlags.NumberOfInitHooksCalledShift */) &&
|
|
5092
5096
|
(currentView[FLAGS] & 3 /* LViewFlags.InitPhaseStateMask */) === initPhase) {
|
|
5093
|
-
currentView[FLAGS] +=
|
|
5097
|
+
currentView[FLAGS] += 8192 /* LViewFlags.IndexWithinInitPhaseIncrementer */;
|
|
5094
5098
|
callHookInternal(directive, hook);
|
|
5095
5099
|
}
|
|
5096
5100
|
}
|
|
@@ -5991,7 +5995,7 @@ function ɵɵgetInheritedFactory(type) {
|
|
|
5991
5995
|
// (no Angular decorator on the superclass) or there is no constructor at all
|
|
5992
5996
|
// in the inheritance chain. Since the two cases cannot be distinguished, the
|
|
5993
5997
|
// latter has to be assumed.
|
|
5994
|
-
return t => new t();
|
|
5998
|
+
return (t) => new t();
|
|
5995
5999
|
});
|
|
5996
6000
|
}
|
|
5997
6001
|
function getFactoryOf(type) {
|
|
@@ -6083,6 +6087,7 @@ function ɵɵinjectAttribute(attrNameToInject) {
|
|
|
6083
6087
|
/**
|
|
6084
6088
|
* Attribute decorator and metadata.
|
|
6085
6089
|
*
|
|
6090
|
+
* @Annotation
|
|
6086
6091
|
* @publicApi
|
|
6087
6092
|
*/
|
|
6088
6093
|
const Attribute = makeParamDecorator('Attribute', (attributeName) => ({ attributeName, __NG_ELEMENT_ID__: () => ɵɵinjectAttribute(attributeName) }));
|
|
@@ -6383,7 +6388,7 @@ function isPropertyValid(element, propName, tagName, schemas) {
|
|
|
6383
6388
|
if (schemas === null)
|
|
6384
6389
|
return true;
|
|
6385
6390
|
// The property is considered valid if the element matches the schema, it exists on the element,
|
|
6386
|
-
// or it is synthetic
|
|
6391
|
+
// or it is synthetic.
|
|
6387
6392
|
if (matchingSchemas(schemas, tagName) || propName in element || isAnimationProp(propName)) {
|
|
6388
6393
|
return true;
|
|
6389
6394
|
}
|
|
@@ -6525,6 +6530,59 @@ function matchingSchemas(schemas, tagName) {
|
|
|
6525
6530
|
return false;
|
|
6526
6531
|
}
|
|
6527
6532
|
|
|
6533
|
+
/**
|
|
6534
|
+
* The name of an attribute that can be added to the hydration boundary node
|
|
6535
|
+
* (component host node) to disable hydration for the content within that boundary.
|
|
6536
|
+
*/
|
|
6537
|
+
const SKIP_HYDRATION_ATTR_NAME = 'ngSkipHydration';
|
|
6538
|
+
/**
|
|
6539
|
+
* Helper function to check if a given node has the 'ngSkipHydration' attribute
|
|
6540
|
+
*/
|
|
6541
|
+
function hasNgSkipHydrationAttr(tNode) {
|
|
6542
|
+
const SKIP_HYDRATION_ATTR_NAME_LOWER_CASE = SKIP_HYDRATION_ATTR_NAME.toLowerCase();
|
|
6543
|
+
const attrs = tNode.mergedAttrs;
|
|
6544
|
+
if (attrs === null)
|
|
6545
|
+
return false;
|
|
6546
|
+
// only ever look at the attribute name and skip the values
|
|
6547
|
+
for (let i = 0; i < attrs.length; i += 2) {
|
|
6548
|
+
const value = attrs[i];
|
|
6549
|
+
// This is a marker, which means that the static attributes section is over,
|
|
6550
|
+
// so we can exit early.
|
|
6551
|
+
if (typeof value === 'number')
|
|
6552
|
+
return false;
|
|
6553
|
+
if (typeof value === 'string' && value.toLowerCase() === SKIP_HYDRATION_ATTR_NAME_LOWER_CASE) {
|
|
6554
|
+
return true;
|
|
6555
|
+
}
|
|
6556
|
+
}
|
|
6557
|
+
return false;
|
|
6558
|
+
}
|
|
6559
|
+
/**
|
|
6560
|
+
* Checks whether a TNode has a flag to indicate that it's a part of
|
|
6561
|
+
* a skip hydration block.
|
|
6562
|
+
*/
|
|
6563
|
+
function hasInSkipHydrationBlockFlag(tNode) {
|
|
6564
|
+
return (tNode.flags & 128 /* TNodeFlags.inSkipHydrationBlock */) === 128 /* TNodeFlags.inSkipHydrationBlock */;
|
|
6565
|
+
}
|
|
6566
|
+
/**
|
|
6567
|
+
* Helper function that determines if a given node is within a skip hydration block
|
|
6568
|
+
* by navigating up the TNode tree to see if any parent nodes have skip hydration
|
|
6569
|
+
* attribute.
|
|
6570
|
+
*
|
|
6571
|
+
* TODO(akushnir): this function should contain the logic of `hasInSkipHydrationBlockFlag`,
|
|
6572
|
+
* there is no need to traverse parent nodes when we have a TNode flag (which would also
|
|
6573
|
+
* make this lookup O(1)).
|
|
6574
|
+
*/
|
|
6575
|
+
function isInSkipHydrationBlock(tNode) {
|
|
6576
|
+
let currentTNode = tNode.parent;
|
|
6577
|
+
while (currentTNode) {
|
|
6578
|
+
if (hasNgSkipHydrationAttr(currentTNode)) {
|
|
6579
|
+
return true;
|
|
6580
|
+
}
|
|
6581
|
+
currentTNode = currentTNode.parent;
|
|
6582
|
+
}
|
|
6583
|
+
return false;
|
|
6584
|
+
}
|
|
6585
|
+
|
|
6528
6586
|
/**
|
|
6529
6587
|
* Flags for renderer-specific style modifiers.
|
|
6530
6588
|
* @publicApi
|
|
@@ -7824,6 +7882,11 @@ function applyProjectionRecursive(renderer, action, lView, tProjectionNode, pare
|
|
|
7824
7882
|
else {
|
|
7825
7883
|
let nodeToProject = nodeToProjectOrRNodes;
|
|
7826
7884
|
const projectedComponentLView = componentLView[PARENT];
|
|
7885
|
+
// If a parent <ng-content> is located within a skip hydration block,
|
|
7886
|
+
// annotate an actual node that is being projected with the same flag too.
|
|
7887
|
+
if (hasInSkipHydrationBlockFlag(tProjectionNode)) {
|
|
7888
|
+
nodeToProject.flags |= 128 /* TNodeFlags.inSkipHydrationBlock */;
|
|
7889
|
+
}
|
|
7827
7890
|
applyNodes(renderer, action, nodeToProject, projectedComponentLView, parentRElement, beforeNode, true);
|
|
7828
7891
|
}
|
|
7829
7892
|
}
|
|
@@ -8124,7 +8187,7 @@ function ɵɵvalidateIframeAttribute(attrValue, tagName, attrName) {
|
|
|
8124
8187
|
* When running ivy outside of a browser environment, it is necessary to call `setDocument()` to
|
|
8125
8188
|
* tell ivy what the global `document` is.
|
|
8126
8189
|
*
|
|
8127
|
-
* Angular does this for us in each of the standard platforms (`Browser
|
|
8190
|
+
* Angular does this for us in each of the standard platforms (`Browser` and `Server`)
|
|
8128
8191
|
* by calling `setDocument()` when providing the `DOCUMENT` token.
|
|
8129
8192
|
*/
|
|
8130
8193
|
let DOCUMENT = undefined;
|
|
@@ -8151,12 +8214,13 @@ function getDocument() {
|
|
|
8151
8214
|
else if (typeof document !== 'undefined') {
|
|
8152
8215
|
return document;
|
|
8153
8216
|
}
|
|
8217
|
+
throw new RuntimeError(210 /* RuntimeErrorCode.MISSING_DOCUMENT */, (typeof ngDevMode === 'undefined' || ngDevMode) &&
|
|
8218
|
+
`The document object is not available in this context. Make sure the DOCUMENT injection token is provided.`);
|
|
8154
8219
|
// No "document" can be found. This should only happen if we are running ivy outside Angular and
|
|
8155
8220
|
// the current platform is not a browser. Since this is not a supported scenario at the moment
|
|
8156
8221
|
// this should not happen in Angular apps.
|
|
8157
8222
|
// Once we support running ivy outside of Angular we will need to publish `setDocument()` as a
|
|
8158
|
-
// public API.
|
|
8159
|
-
return undefined;
|
|
8223
|
+
// public API.
|
|
8160
8224
|
}
|
|
8161
8225
|
|
|
8162
8226
|
/**
|
|
@@ -9862,7 +9926,9 @@ function makeStateKey(key) {
|
|
|
9862
9926
|
}
|
|
9863
9927
|
function initTransferState() {
|
|
9864
9928
|
const transferState = new TransferState();
|
|
9865
|
-
|
|
9929
|
+
if (inject$1(PLATFORM_ID) === 'browser') {
|
|
9930
|
+
transferState.store = retrieveTransferredState(getDocument(), inject$1(APP_ID));
|
|
9931
|
+
}
|
|
9866
9932
|
return transferState;
|
|
9867
9933
|
}
|
|
9868
9934
|
/**
|
|
@@ -9951,17 +10017,16 @@ function retrieveTransferredState(doc, appId) {
|
|
|
9951
10017
|
// Locate the script tag with the JSON data transferred from the server.
|
|
9952
10018
|
// The id of the script tag is set to the Angular appId + 'state'.
|
|
9953
10019
|
const script = doc.getElementById(appId + '-state');
|
|
9954
|
-
|
|
9955
|
-
if (script && script.textContent) {
|
|
10020
|
+
if (script?.textContent) {
|
|
9956
10021
|
try {
|
|
9957
10022
|
// Avoid using any here as it triggers lint errors in google3 (any is not allowed).
|
|
9958
|
-
|
|
10023
|
+
return JSON.parse(unescapeTransferStateContent(script.textContent));
|
|
9959
10024
|
}
|
|
9960
10025
|
catch (e) {
|
|
9961
10026
|
console.warn('Exception while restoring TransferState for app ' + appId, e);
|
|
9962
10027
|
}
|
|
9963
10028
|
}
|
|
9964
|
-
return
|
|
10029
|
+
return {};
|
|
9965
10030
|
}
|
|
9966
10031
|
|
|
9967
10032
|
/** Encodes that the node lookup should start from the host node of this component. */
|
|
@@ -10080,6 +10145,12 @@ function getComponentLViewForHydration(viewRef) {
|
|
|
10080
10145
|
if (isRootView(lView)) {
|
|
10081
10146
|
lView = lView[HEADER_OFFSET];
|
|
10082
10147
|
}
|
|
10148
|
+
// If a `ViewContainerRef` was injected in a component class, this resulted
|
|
10149
|
+
// in an LContainer creation at that location. In this case, the component
|
|
10150
|
+
// LView is in the LContainer's `HOST` slot.
|
|
10151
|
+
if (isLContainer(lView)) {
|
|
10152
|
+
lView = lView[HOST];
|
|
10153
|
+
}
|
|
10083
10154
|
return lView;
|
|
10084
10155
|
}
|
|
10085
10156
|
function getTextNodeContent(node) {
|
|
@@ -10375,7 +10446,7 @@ class Version {
|
|
|
10375
10446
|
/**
|
|
10376
10447
|
* @publicApi
|
|
10377
10448
|
*/
|
|
10378
|
-
const VERSION = new Version('16.0.0');
|
|
10449
|
+
const VERSION = new Version('16.1.0-next.0');
|
|
10379
10450
|
|
|
10380
10451
|
// This default value is when checking the hierarchy for a token.
|
|
10381
10452
|
//
|
|
@@ -10481,48 +10552,6 @@ class ErrorHandler {
|
|
|
10481
10552
|
}
|
|
10482
10553
|
}
|
|
10483
10554
|
|
|
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
10555
|
/**
|
|
10527
10556
|
* Internal token that specifies whether DOM reuse logic
|
|
10528
10557
|
* during hydration is enabled.
|
|
@@ -10912,6 +10941,7 @@ function getInjectableMetadata(type, srcMeta) {
|
|
|
10912
10941
|
/**
|
|
10913
10942
|
* Injectable decorator and metadata.
|
|
10914
10943
|
*
|
|
10944
|
+
* @Annotation
|
|
10915
10945
|
* @publicApi
|
|
10916
10946
|
*/
|
|
10917
10947
|
const Injectable = makeDecorator('Injectable', undefined, undefined, undefined, (type, meta) => compileInjectable(type, meta));
|
|
@@ -11468,6 +11498,10 @@ function createTNode(tView, tParent, type, index, value, attrs) {
|
|
|
11468
11498
|
ngDevMode && ngDevMode.tNode++;
|
|
11469
11499
|
ngDevMode && tParent && assertTNodeForTView(tParent, tView);
|
|
11470
11500
|
let injectorIndex = tParent ? tParent.injectorIndex : -1;
|
|
11501
|
+
let flags = 0;
|
|
11502
|
+
if (isInSkipHydrationBlock$1()) {
|
|
11503
|
+
flags |= 128 /* TNodeFlags.inSkipHydrationBlock */;
|
|
11504
|
+
}
|
|
11471
11505
|
const tNode = {
|
|
11472
11506
|
type,
|
|
11473
11507
|
index,
|
|
@@ -11478,7 +11512,7 @@ function createTNode(tView, tParent, type, index, value, attrs) {
|
|
|
11478
11512
|
directiveStylingLast: -1,
|
|
11479
11513
|
componentOffset: -1,
|
|
11480
11514
|
propertyBindings: null,
|
|
11481
|
-
flags
|
|
11515
|
+
flags,
|
|
11482
11516
|
providerIndexes: 0,
|
|
11483
11517
|
value: value,
|
|
11484
11518
|
attrs: attrs,
|
|
@@ -12030,7 +12064,14 @@ function addComponentLogic(lView, hostTNode, def) {
|
|
|
12030
12064
|
// Only component views should be added to the view tree directly. Embedded views are
|
|
12031
12065
|
// accessed through their containers because they may be removed / re-added later.
|
|
12032
12066
|
const rendererFactory = lView[ENVIRONMENT].rendererFactory;
|
|
12033
|
-
|
|
12067
|
+
let lViewFlags = 16 /* LViewFlags.CheckAlways */;
|
|
12068
|
+
if (def.signals) {
|
|
12069
|
+
lViewFlags = 4096 /* LViewFlags.SignalView */;
|
|
12070
|
+
}
|
|
12071
|
+
else if (def.onPush) {
|
|
12072
|
+
lViewFlags = 64 /* LViewFlags.Dirty */;
|
|
12073
|
+
}
|
|
12074
|
+
const componentView = addToViewTree(lView, createLView(lView, tView, null, lViewFlags, native, hostTNode, null, rendererFactory.createRenderer(native, def), null, null, null));
|
|
12034
12075
|
// Component view will always be created before any injected LContainers,
|
|
12035
12076
|
// so this is a regular element, wrap it with the component view
|
|
12036
12077
|
lView[hostTNode.index] = componentView;
|
|
@@ -12740,7 +12781,7 @@ function refreshView(tView, lView, templateFn, context) {
|
|
|
12740
12781
|
// insertion points. This is needed to avoid the situation where the template is defined in this
|
|
12741
12782
|
// `LView` but its declaration appears after the insertion component.
|
|
12742
12783
|
markTransplantedViewsForRefresh(lView);
|
|
12743
|
-
|
|
12784
|
+
detectChangesInEmbeddedViews(lView, 2 /* ChangeDetectionMode.BugToForceRefreshAndIgnoreViewFlags */);
|
|
12744
12785
|
// Content query results must be refreshed before content hooks are called.
|
|
12745
12786
|
if (tView.contentQueries !== null) {
|
|
12746
12787
|
refreshContentQueries(tView, lView);
|
|
@@ -12766,7 +12807,7 @@ function refreshView(tView, lView, templateFn, context) {
|
|
|
12766
12807
|
// Refresh child component views.
|
|
12767
12808
|
const components = tView.components;
|
|
12768
12809
|
if (components !== null) {
|
|
12769
|
-
|
|
12810
|
+
detectChangesInChildComponents(lView, components, 0 /* ChangeDetectionMode.Global */);
|
|
12770
12811
|
}
|
|
12771
12812
|
// View queries must execute after refreshing child components because a template in this view
|
|
12772
12813
|
// could be inserted in a child component. If the view query executes before child component
|
|
@@ -12820,15 +12861,11 @@ function refreshView(tView, lView, templateFn, context) {
|
|
|
12820
12861
|
* Goes over embedded views (ones created through ViewContainerRef APIs) and refreshes
|
|
12821
12862
|
* them by executing an associated template function.
|
|
12822
12863
|
*/
|
|
12823
|
-
function
|
|
12864
|
+
function detectChangesInEmbeddedViews(lView, mode) {
|
|
12824
12865
|
for (let lContainer = getFirstLContainer(lView); lContainer !== null; lContainer = getNextLContainer(lContainer)) {
|
|
12825
12866
|
for (let i = CONTAINER_HEADER_OFFSET; i < lContainer.length; i++) {
|
|
12826
12867
|
const embeddedLView = lContainer[i];
|
|
12827
|
-
|
|
12828
|
-
ngDevMode && assertDefined(embeddedTView, 'TView must be allocated');
|
|
12829
|
-
if (viewAttachedToChangeDetector(embeddedLView)) {
|
|
12830
|
-
refreshView(embeddedTView, embeddedLView, embeddedTView.template, embeddedLView[CONTEXT]);
|
|
12831
|
-
}
|
|
12868
|
+
detectChangesInView(embeddedLView, mode);
|
|
12832
12869
|
}
|
|
12833
12870
|
}
|
|
12834
12871
|
}
|
|
@@ -12852,65 +12889,53 @@ function markTransplantedViewsForRefresh(lView) {
|
|
|
12852
12889
|
}
|
|
12853
12890
|
}
|
|
12854
12891
|
/**
|
|
12855
|
-
*
|
|
12892
|
+
* Detects changes in a component by entering the component view and processing its bindings,
|
|
12893
|
+
* queries, etc. if it is CheckAlways, OnPush and Dirty, etc.
|
|
12856
12894
|
*
|
|
12857
12895
|
* @param componentHostIdx Element index in LView[] (adjusted for HEADER_OFFSET)
|
|
12858
12896
|
*/
|
|
12859
|
-
function
|
|
12897
|
+
function detectChangesInComponent(hostLView, componentHostIdx, mode) {
|
|
12860
12898
|
ngDevMode && assertEqual(isCreationMode(hostLView), false, 'Should be run in update mode');
|
|
12861
12899
|
const componentView = getComponentLViewByIndex(componentHostIdx, hostLView);
|
|
12862
|
-
|
|
12863
|
-
if (viewAttachedToChangeDetector(componentView)) {
|
|
12864
|
-
const tView = componentView[TVIEW];
|
|
12865
|
-
if (componentView[FLAGS] & (16 /* LViewFlags.CheckAlways */ | 64 /* LViewFlags.Dirty */)) {
|
|
12866
|
-
refreshView(tView, componentView, tView.template, componentView[CONTEXT]);
|
|
12867
|
-
}
|
|
12868
|
-
else if (componentView[DESCENDANT_VIEWS_TO_REFRESH] > 0) {
|
|
12869
|
-
// Only attached components that are CheckAlways or OnPush and dirty should be refreshed
|
|
12870
|
-
refreshContainsDirtyView(componentView);
|
|
12871
|
-
}
|
|
12872
|
-
}
|
|
12900
|
+
detectChangesInView(componentView, mode);
|
|
12873
12901
|
}
|
|
12874
12902
|
/**
|
|
12875
|
-
*
|
|
12876
|
-
*
|
|
12903
|
+
* Visits a view as part of change detection traversal.
|
|
12904
|
+
*
|
|
12905
|
+
* - If the view is detached, no additional traversal happens.
|
|
12906
|
+
*
|
|
12907
|
+
* The view is refreshed if:
|
|
12908
|
+
* - If the view is CheckAlways or Dirty and ChangeDetectionMode is `Global`
|
|
12909
|
+
* - If the view has the `RefreshTransplantedView` flag
|
|
12910
|
+
*
|
|
12911
|
+
* The view is not refreshed, but descendants are traversed in `ChangeDetectionMode.Targeted` if the
|
|
12912
|
+
* view has a non-zero TRANSPLANTED_VIEWS_TO_REFRESH counter.
|
|
12877
12913
|
*
|
|
12878
|
-
* @param lView The lView which contains descendant transplanted views that need to be refreshed.
|
|
12879
12914
|
*/
|
|
12880
|
-
function
|
|
12881
|
-
|
|
12882
|
-
|
|
12883
|
-
const embeddedLView = lContainer[i];
|
|
12884
|
-
if (viewAttachedToChangeDetector(embeddedLView)) {
|
|
12885
|
-
if (embeddedLView[FLAGS] & 1024 /* LViewFlags.RefreshView */) {
|
|
12886
|
-
const embeddedTView = embeddedLView[TVIEW];
|
|
12887
|
-
ngDevMode && assertDefined(embeddedTView, 'TView must be allocated');
|
|
12888
|
-
refreshView(embeddedTView, embeddedLView, embeddedTView.template, embeddedLView[CONTEXT]);
|
|
12889
|
-
}
|
|
12890
|
-
else if (embeddedLView[DESCENDANT_VIEWS_TO_REFRESH] > 0) {
|
|
12891
|
-
refreshContainsDirtyView(embeddedLView);
|
|
12892
|
-
}
|
|
12893
|
-
}
|
|
12894
|
-
}
|
|
12915
|
+
function detectChangesInView(lView, mode) {
|
|
12916
|
+
if (!viewAttachedToChangeDetector(lView)) {
|
|
12917
|
+
return;
|
|
12895
12918
|
}
|
|
12896
12919
|
const tView = lView[TVIEW];
|
|
12897
|
-
|
|
12898
|
-
|
|
12899
|
-
|
|
12900
|
-
|
|
12901
|
-
|
|
12902
|
-
|
|
12903
|
-
|
|
12904
|
-
|
|
12905
|
-
|
|
12906
|
-
|
|
12920
|
+
if ((lView[FLAGS] & (16 /* LViewFlags.CheckAlways */ | 64 /* LViewFlags.Dirty */) &&
|
|
12921
|
+
mode === 0 /* ChangeDetectionMode.Global */) ||
|
|
12922
|
+
lView[FLAGS] & 1024 /* LViewFlags.RefreshView */ ||
|
|
12923
|
+
mode === 2 /* ChangeDetectionMode.BugToForceRefreshAndIgnoreViewFlags */) {
|
|
12924
|
+
refreshView(tView, lView, tView.template, lView[CONTEXT]);
|
|
12925
|
+
}
|
|
12926
|
+
else if (lView[DESCENDANT_VIEWS_TO_REFRESH] > 0) {
|
|
12927
|
+
detectChangesInEmbeddedViews(lView, 1 /* ChangeDetectionMode.Targeted */);
|
|
12928
|
+
const tView = lView[TVIEW];
|
|
12929
|
+
const components = tView.components;
|
|
12930
|
+
if (components !== null) {
|
|
12931
|
+
detectChangesInChildComponents(lView, components, 1 /* ChangeDetectionMode.Targeted */);
|
|
12907
12932
|
}
|
|
12908
12933
|
}
|
|
12909
12934
|
}
|
|
12910
12935
|
/** Refreshes child components in the current view (update mode). */
|
|
12911
|
-
function
|
|
12936
|
+
function detectChangesInChildComponents(hostLView, components, mode) {
|
|
12912
12937
|
for (let i = 0; i < components.length; i++) {
|
|
12913
|
-
|
|
12938
|
+
detectChangesInComponent(hostLView, components[i], mode);
|
|
12914
12939
|
}
|
|
12915
12940
|
}
|
|
12916
12941
|
|
|
@@ -13310,8 +13335,12 @@ class ComponentFactory extends ComponentFactory$1 {
|
|
|
13310
13335
|
const hostRNode = rootSelectorOrNode ?
|
|
13311
13336
|
locateHostElement(hostRenderer, rootSelectorOrNode, this.componentDef.encapsulation, rootViewInjector) :
|
|
13312
13337
|
createElementNode(hostRenderer, elementName, getNamespace(elementName));
|
|
13313
|
-
|
|
13338
|
+
// Signal components use the granular "RefreshView" for change detection
|
|
13339
|
+
const signalFlags = (4096 /* LViewFlags.SignalView */ | 512 /* LViewFlags.IsRoot */);
|
|
13340
|
+
// Non-signal components use the traditional "CheckAlways or OnPush/Dirty" change detection
|
|
13341
|
+
const nonSignalFlags = this.componentDef.onPush ? 64 /* LViewFlags.Dirty */ | 512 /* LViewFlags.IsRoot */ :
|
|
13314
13342
|
16 /* LViewFlags.CheckAlways */ | 512 /* LViewFlags.IsRoot */;
|
|
13343
|
+
const rootFlags = this.componentDef.signals ? signalFlags : nonSignalFlags;
|
|
13315
13344
|
// Create the root view. Uses empty TView and ContentTemplate.
|
|
13316
13345
|
const rootTView = createTView(0 /* TViewType.Root */, null, null, 1, 0, null, null, null, null, null, null);
|
|
13317
13346
|
const rootLView = createLView(null, rootTView, null, rootFlags, null, null, environment, hostRenderer, rootViewInjector, null, null);
|
|
@@ -13454,7 +13483,14 @@ function createRootComponentView(tNode, hostRNode, rootComponentDef, rootDirecti
|
|
|
13454
13483
|
hydrationInfo = retrieveHydrationInfo(hostRNode, rootView[INJECTOR$1]);
|
|
13455
13484
|
}
|
|
13456
13485
|
const viewRenderer = environment.rendererFactory.createRenderer(hostRNode, rootComponentDef);
|
|
13457
|
-
|
|
13486
|
+
let lViewFlags = 16 /* LViewFlags.CheckAlways */;
|
|
13487
|
+
if (rootComponentDef.signals) {
|
|
13488
|
+
lViewFlags = 4096 /* LViewFlags.SignalView */;
|
|
13489
|
+
}
|
|
13490
|
+
else if (rootComponentDef.onPush) {
|
|
13491
|
+
lViewFlags = 64 /* LViewFlags.Dirty */;
|
|
13492
|
+
}
|
|
13493
|
+
const componentView = createLView(rootView, getOrCreateComponentTView(rootComponentDef), null, lViewFlags, rootView[tNode.index], tNode, environment, viewRenderer, null, null, hydrationInfo);
|
|
13458
13494
|
if (tView.firstCreatePass) {
|
|
13459
13495
|
markAsComponentHost(tView, tNode, rootDirectives.length - 1);
|
|
13460
13496
|
}
|
|
@@ -23191,8 +23227,11 @@ const R3TemplateRef = class TemplateRef extends ViewEngineTemplateRef {
|
|
|
23191
23227
|
* @internal
|
|
23192
23228
|
*/
|
|
23193
23229
|
createEmbeddedViewImpl(context, injector, hydrationInfo) {
|
|
23230
|
+
// Embedded views follow the change detection strategy of the view they're declared in.
|
|
23231
|
+
const isSignalView = this._declarationLView[FLAGS] & 4096 /* LViewFlags.SignalView */;
|
|
23232
|
+
const viewFlags = isSignalView ? 4096 /* LViewFlags.SignalView */ : 16 /* LViewFlags.CheckAlways */;
|
|
23194
23233
|
const embeddedTView = this._declarationTContainer.tView;
|
|
23195
|
-
const embeddedLView = createLView(this._declarationLView, embeddedTView, context,
|
|
23234
|
+
const embeddedLView = createLView(this._declarationLView, embeddedTView, context, viewFlags, null, embeddedTView.declTNode, null, null, null, injector || null, hydrationInfo || null);
|
|
23196
23235
|
const declarationLContainer = this._declarationLView[this._declarationTContainer.index];
|
|
23197
23236
|
ngDevMode && assertLContainer(declarationLContainer);
|
|
23198
23237
|
embeddedLView[DECLARATION_LCONTAINER] = declarationLContainer;
|
|
@@ -23466,7 +23505,11 @@ const R3ViewContainerRef = class ViewContainerRef extends VE_ViewContainerRef {
|
|
|
23466
23505
|
}
|
|
23467
23506
|
const hydrationInfo = findMatchingDehydratedView(this._lContainer, templateRef.ssrId);
|
|
23468
23507
|
const viewRef = templateRef.createEmbeddedViewImpl(context || {}, injector, hydrationInfo);
|
|
23469
|
-
|
|
23508
|
+
// If there is a matching dehydrated view, but the host TNode is located in the skip
|
|
23509
|
+
// hydration block, this means that the content was detached (as a part of the skip
|
|
23510
|
+
// hydration logic) and it needs to be appended into the DOM.
|
|
23511
|
+
const skipDomInsertion = !!hydrationInfo && !hasInSkipHydrationBlockFlag(this._hostTNode);
|
|
23512
|
+
this.insertImpl(viewRef, index, skipDomInsertion);
|
|
23470
23513
|
return viewRef;
|
|
23471
23514
|
}
|
|
23472
23515
|
createComponent(componentFactoryOrType, indexOrOptions, injector, projectableNodes, environmentInjector) {
|
|
@@ -23540,7 +23583,11 @@ const R3ViewContainerRef = class ViewContainerRef extends VE_ViewContainerRef {
|
|
|
23540
23583
|
const dehydratedView = findMatchingDehydratedView(this._lContainer, componentDef?.id ?? null);
|
|
23541
23584
|
const rNode = dehydratedView?.firstChild ?? null;
|
|
23542
23585
|
const componentRef = componentFactory.create(contextInjector, projectableNodes, rNode, environmentInjector);
|
|
23543
|
-
|
|
23586
|
+
// If there is a matching dehydrated view, but the host TNode is located in the skip
|
|
23587
|
+
// hydration block, this means that the content was detached (as a part of the skip
|
|
23588
|
+
// hydration logic) and it needs to be appended into the DOM.
|
|
23589
|
+
const skipDomInsertion = !!dehydratedView && !hasInSkipHydrationBlockFlag(this._hostTNode);
|
|
23590
|
+
this.insertImpl(componentRef.hostView, index, skipDomInsertion);
|
|
23544
23591
|
return componentRef;
|
|
23545
23592
|
}
|
|
23546
23593
|
insert(viewRef, index) {
|
|
@@ -23714,8 +23761,10 @@ function locateOrCreateAnchorNode(lContainer, hostLView, hostTNode, slotValue) {
|
|
|
23714
23761
|
return;
|
|
23715
23762
|
const hydrationInfo = hostLView[HYDRATION];
|
|
23716
23763
|
const noOffsetIndex = hostTNode.index - HEADER_OFFSET;
|
|
23717
|
-
|
|
23718
|
-
|
|
23764
|
+
// TODO(akushnir): this should really be a single condition, refactor the code
|
|
23765
|
+
// to use `hasInSkipHydrationBlockFlag` logic inside `isInSkipHydrationBlock`.
|
|
23766
|
+
const skipHydration = isInSkipHydrationBlock(hostTNode) || hasInSkipHydrationBlockFlag(hostTNode);
|
|
23767
|
+
const isNodeCreationMode = !hydrationInfo || skipHydration || isDisconnectedNode(hydrationInfo, noOffsetIndex);
|
|
23719
23768
|
// Regular creation mode.
|
|
23720
23769
|
if (isNodeCreationMode) {
|
|
23721
23770
|
return createAnchorNode(lContainer, hostLView, hostTNode, slotValue);
|
|
@@ -26127,7 +26176,7 @@ class TestBedImpl {
|
|
|
26127
26176
|
}
|
|
26128
26177
|
configureCompiler(config) {
|
|
26129
26178
|
if (config.useJit != null) {
|
|
26130
|
-
throw new Error('
|
|
26179
|
+
throw new Error('JIT compiler is not configurable via TestBed APIs.');
|
|
26131
26180
|
}
|
|
26132
26181
|
if (config.providers !== undefined) {
|
|
26133
26182
|
this.compiler.setCompilerProviders(config.providers);
|
|
@@ -26135,7 +26184,7 @@ class TestBedImpl {
|
|
|
26135
26184
|
return this;
|
|
26136
26185
|
}
|
|
26137
26186
|
configureTestingModule(moduleDef) {
|
|
26138
|
-
this.assertNotInstantiated('
|
|
26187
|
+
this.assertNotInstantiated('TestBed.configureTestingModule', 'configure the test module');
|
|
26139
26188
|
// Trigger module scoping queue flush before executing other TestBed operations in a test.
|
|
26140
26189
|
// This is needed for the first test invocation to ensure that globally declared modules have
|
|
26141
26190
|
// their components scoped properly. See the `checkGlobalCompilationFinished` function
|
|
@@ -26189,7 +26238,7 @@ class TestBedImpl {
|
|
|
26189
26238
|
return this;
|
|
26190
26239
|
}
|
|
26191
26240
|
overrideTemplateUsingTestingModule(component, template) {
|
|
26192
|
-
this.assertNotInstantiated('
|
|
26241
|
+
this.assertNotInstantiated('TestBed.overrideTemplateUsingTestingModule', 'Cannot override template when the test module has already been instantiated');
|
|
26193
26242
|
this.compiler.overrideTemplateUsingTestingModule(component, template);
|
|
26194
26243
|
return this;
|
|
26195
26244
|
}
|