@angular/core 19.2.0-next.1 → 19.2.0-next.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/fesm2022/core.mjs +928 -913
- package/fesm2022/core.mjs.map +1 -1
- package/fesm2022/primitives/event-dispatch.mjs +1 -1
- package/fesm2022/primitives/signals.mjs +1 -1
- package/fesm2022/rxjs-interop.mjs +2 -1
- package/fesm2022/rxjs-interop.mjs.map +1 -1
- package/fesm2022/testing.mjs +4 -4
- package/index.d.ts +17 -3
- package/package.json +1 -1
- package/primitives/event-dispatch/index.d.ts +1 -1
- package/primitives/signals/index.d.ts +1 -1
- package/rxjs-interop/index.d.ts +1 -1
- package/schematics/bundles/{apply_import_manager-5ea49df9.js → apply_import_manager-d8ea426b.js} +3 -3
- package/schematics/bundles/{checker-78667e44.js → checker-9af84be9.js} +6 -5
- package/schematics/bundles/cleanup-unused-imports.js +5 -5
- package/schematics/bundles/{compiler_host-b22de7db.js → compiler_host-dbff2781.js} +2 -2
- package/schematics/bundles/control-flow-migration.js +3 -3
- package/schematics/bundles/explicit-standalone-flag.js +3 -3
- package/schematics/bundles/imports-31a38653.js +1 -1
- package/schematics/bundles/{index-3e744c38.js → index-23b503a4.js} +4 -4
- package/schematics/bundles/{index-de135c2f.js → index-93e324de.js} +4 -4
- package/schematics/bundles/inject-migration.js +3 -3
- package/schematics/bundles/leading_space-6e7a8ec6.js +1 -1
- package/schematics/bundles/{migrate_ts_type_references-60e2a469.js → migrate_ts_type_references-c6615b87.js} +5 -5
- package/schematics/bundles/nodes-88c2157f.js +1 -1
- package/schematics/bundles/output-migration.js +5 -5
- package/schematics/bundles/pending-tasks.js +3 -3
- package/schematics/bundles/{program-b0d98952.js → program-66386e72.js} +101 -27
- package/schematics/bundles/project_tsconfig_paths-6c9cde78.js +1 -1
- package/schematics/bundles/provide-initializer.js +3 -3
- package/schematics/bundles/route-lazy-loading.js +3 -3
- package/schematics/bundles/signal-input-migration.js +6 -6
- package/schematics/bundles/signal-queries-migration.js +6 -6
- package/schematics/bundles/signals.js +6 -6
- package/schematics/bundles/standalone-migration.js +5 -5
- 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.
|
|
2
|
+
* @license Angular v19.2.0-next.2
|
|
3
3
|
* (c) 2010-2024 Google LLC. https://angular.io/
|
|
4
4
|
* License: MIT
|
|
5
5
|
*/
|
|
@@ -3067,7 +3067,7 @@ function assertProjectionSlots(lView, errMessage) {
|
|
|
3067
3067
|
function assertParentView(lView, errMessage) {
|
|
3068
3068
|
assertDefined(lView, errMessage || "Component views should always have a parent view (component's host view)");
|
|
3069
3069
|
}
|
|
3070
|
-
function assertNoDuplicateDirectives(directives) {
|
|
3070
|
+
function assertNoDuplicateDirectives$1(directives) {
|
|
3071
3071
|
// The array needs at least two elements in order to have duplicates.
|
|
3072
3072
|
if (directives.length < 2) {
|
|
3073
3073
|
return;
|
|
@@ -4060,7 +4060,7 @@ function ɵɵnamespaceHTML() {
|
|
|
4060
4060
|
function namespaceHTMLInternal() {
|
|
4061
4061
|
instructionState.lFrame.currentNamespace = null;
|
|
4062
4062
|
}
|
|
4063
|
-
function getNamespace
|
|
4063
|
+
function getNamespace() {
|
|
4064
4064
|
return instructionState.lFrame.currentNamespace;
|
|
4065
4065
|
}
|
|
4066
4066
|
let _wasLastNodeCreated = true;
|
|
@@ -11648,14 +11648,6 @@ function getExpressionChangedErrorDetails(lView, bindingIndex, oldValue, newValu
|
|
|
11648
11648
|
return { propName: undefined, oldValue, newValue };
|
|
11649
11649
|
}
|
|
11650
11650
|
|
|
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
11651
|
/**
|
|
11660
11652
|
* Returns an index of `classToSearch` in `className` taking token boundaries into account.
|
|
11661
11653
|
*
|
|
@@ -12265,38 +12257,13 @@ function selectIndexInternal(tView, lView, index, checkNoChangesMode) {
|
|
|
12265
12257
|
setSelectedIndex(index);
|
|
12266
12258
|
}
|
|
12267
12259
|
|
|
12268
|
-
|
|
12269
|
-
|
|
12270
|
-
|
|
12271
|
-
|
|
12272
|
-
|
|
12273
|
-
|
|
12274
|
-
|
|
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
|
-
}
|
|
12260
|
+
/** Flags describing an input for a directive. */
|
|
12261
|
+
var InputFlags;
|
|
12262
|
+
(function (InputFlags) {
|
|
12263
|
+
InputFlags[InputFlags["None"] = 0] = "None";
|
|
12264
|
+
InputFlags[InputFlags["SignalBased"] = 1] = "SignalBased";
|
|
12265
|
+
InputFlags[InputFlags["HasDecoratorInputTransform"] = 2] = "HasDecoratorInputTransform";
|
|
12266
|
+
})(InputFlags || (InputFlags = {}));
|
|
12300
12267
|
|
|
12301
12268
|
function writeToDirectiveInput(def, instance, publicName, privateName, flags, value) {
|
|
12302
12269
|
const prevConsumer = setActiveConsumer$1(null);
|
|
@@ -12364,34 +12331,6 @@ function createLView(parentLView, tView, context, flags, host, tHostNode, enviro
|
|
|
12364
12331
|
tView.type == 2 /* TViewType.Embedded */ ? parentLView[DECLARATION_COMPONENT_VIEW] : lView;
|
|
12365
12332
|
return lView;
|
|
12366
12333
|
}
|
|
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
12334
|
function executeTemplate(tView, lView, templateFn, rf, context) {
|
|
12396
12335
|
const prevSelectedIndex = getSelectedIndex();
|
|
12397
12336
|
const isUpdatePhase = rf & 2 /* RenderFlags.Update */;
|
|
@@ -12604,106 +12543,6 @@ function applyRootElementTransformImpl(rootElement) {
|
|
|
12604
12543
|
function enableApplyRootElementTransformImpl() {
|
|
12605
12544
|
_applyRootElementTransformImpl = applyRootElementTransformImpl;
|
|
12606
12545
|
}
|
|
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
12546
|
/**
|
|
12708
12547
|
* Mapping between attributes names that don't correspond to their element property names.
|
|
12709
12548
|
*
|
|
@@ -12804,126 +12643,6 @@ function setNgReflectProperties(lView, element, type, dataValue, value) {
|
|
|
12804
12643
|
}
|
|
12805
12644
|
}
|
|
12806
12645
|
}
|
|
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
12646
|
/**
|
|
12928
12647
|
* Instantiate all the directives that were previously resolved on the current node.
|
|
12929
12648
|
*/
|
|
@@ -13017,121 +12736,6 @@ function findDirectiveDefMatches(tView, tNode) {
|
|
|
13017
12736
|
}
|
|
13018
12737
|
return matches;
|
|
13019
12738
|
}
|
|
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
12739
|
/**
|
|
13136
12740
|
* Gets the initial set of LView flags based on the component definition that the LView represents.
|
|
13137
12741
|
* @param def Component definition from which to determine the flags.
|
|
@@ -13203,58 +12807,6 @@ function setInputsFromAttrs(lView, directiveIndex, instance, def, tNode, initial
|
|
|
13203
12807
|
}
|
|
13204
12808
|
}
|
|
13205
12809
|
}
|
|
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
12810
|
//////////////////////////
|
|
13259
12811
|
//// ViewContainer & View
|
|
13260
12812
|
//////////////////////////
|
|
@@ -17793,6 +17345,492 @@ function computeStaticStyling(tNode, attrs, writeToHost) {
|
|
|
17793
17345
|
writeToHost ? (tNode.classes = classes) : (tNode.classesWithoutHost = classes);
|
|
17794
17346
|
}
|
|
17795
17347
|
|
|
17348
|
+
function ɵɵdirectiveInject(token, flags = InjectFlags.Default) {
|
|
17349
|
+
const lView = getLView();
|
|
17350
|
+
// Fall back to inject() if view hasn't been created. This situation can happen in tests
|
|
17351
|
+
// if inject utilities are used before bootstrapping.
|
|
17352
|
+
if (lView === null) {
|
|
17353
|
+
// Verify that we will not get into infinite loop.
|
|
17354
|
+
ngDevMode && assertInjectImplementationNotEqual(ɵɵdirectiveInject);
|
|
17355
|
+
return ɵɵinject(token, flags);
|
|
17356
|
+
}
|
|
17357
|
+
const tNode = getCurrentTNode();
|
|
17358
|
+
const value = getOrCreateInjectable(tNode, lView, resolveForwardRef(token), flags);
|
|
17359
|
+
ngDevMode && emitInjectEvent(token, value, flags);
|
|
17360
|
+
return value;
|
|
17361
|
+
}
|
|
17362
|
+
/**
|
|
17363
|
+
* Throws an error indicating that a factory function could not be generated by the compiler for a
|
|
17364
|
+
* particular class.
|
|
17365
|
+
*
|
|
17366
|
+
* This instruction allows the actual error message to be optimized away when ngDevMode is turned
|
|
17367
|
+
* off, saving bytes of generated code while still providing a good experience in dev mode.
|
|
17368
|
+
*
|
|
17369
|
+
* The name of the class is not mentioned here, but will be in the generated factory function name
|
|
17370
|
+
* and thus in the stack trace.
|
|
17371
|
+
*
|
|
17372
|
+
* @codeGenApi
|
|
17373
|
+
*/
|
|
17374
|
+
function ɵɵinvalidFactory() {
|
|
17375
|
+
const msg = ngDevMode
|
|
17376
|
+
? `This constructor was not compatible with Dependency Injection.`
|
|
17377
|
+
: 'invalid';
|
|
17378
|
+
throw new Error(msg);
|
|
17379
|
+
}
|
|
17380
|
+
|
|
17381
|
+
/**
|
|
17382
|
+
* When elements are created dynamically after a view blueprint is created (e.g. through
|
|
17383
|
+
* i18nApply()), we need to adjust the blueprint for future template passes.
|
|
17384
|
+
*
|
|
17385
|
+
* @param tView `TView` associated with `LView`
|
|
17386
|
+
* @param lView The `LView` containing the blueprint to adjust
|
|
17387
|
+
* @param numSlotsToAlloc The number of slots to alloc in the LView, should be >0
|
|
17388
|
+
* @param initialValue Initial value to store in blueprint
|
|
17389
|
+
*/
|
|
17390
|
+
function allocExpando(tView, lView, numSlotsToAlloc, initialValue) {
|
|
17391
|
+
if (numSlotsToAlloc === 0)
|
|
17392
|
+
return -1;
|
|
17393
|
+
if (ngDevMode) {
|
|
17394
|
+
assertFirstCreatePass(tView);
|
|
17395
|
+
assertSame(tView, lView[TVIEW], '`LView` must be associated with `TView`!');
|
|
17396
|
+
assertEqual(tView.data.length, lView.length, 'Expecting LView to be same size as TView');
|
|
17397
|
+
assertEqual(tView.data.length, tView.blueprint.length, 'Expecting Blueprint to be same size as TView');
|
|
17398
|
+
assertFirstUpdatePass(tView);
|
|
17399
|
+
}
|
|
17400
|
+
const allocIdx = lView.length;
|
|
17401
|
+
for (let i = 0; i < numSlotsToAlloc; i++) {
|
|
17402
|
+
lView.push(initialValue);
|
|
17403
|
+
tView.blueprint.push(initialValue);
|
|
17404
|
+
tView.data.push(null);
|
|
17405
|
+
}
|
|
17406
|
+
return allocIdx;
|
|
17407
|
+
}
|
|
17408
|
+
|
|
17409
|
+
/**
|
|
17410
|
+
* Resolve the matched directives on a node.
|
|
17411
|
+
*/
|
|
17412
|
+
function resolveDirectives(tView, lView, tNode, localRefs, directiveMatcher) {
|
|
17413
|
+
// Please make sure to have explicit type for `exportsMap`. Inferred type triggers bug in
|
|
17414
|
+
// tsickle.
|
|
17415
|
+
ngDevMode && assertFirstCreatePass(tView);
|
|
17416
|
+
const exportsMap = localRefs === null ? null : { '': -1 };
|
|
17417
|
+
const matchedDirectiveDefs = directiveMatcher(tView, tNode);
|
|
17418
|
+
if (matchedDirectiveDefs !== null) {
|
|
17419
|
+
const [directiveDefs, hostDirectiveDefs] = resolveHostDirectives(tView, tNode, matchedDirectiveDefs);
|
|
17420
|
+
initializeDirectives(tView, lView, tNode, directiveDefs, exportsMap, hostDirectiveDefs);
|
|
17421
|
+
}
|
|
17422
|
+
if (exportsMap !== null && localRefs !== null) {
|
|
17423
|
+
cacheMatchingLocalNames(tNode, localRefs, exportsMap);
|
|
17424
|
+
}
|
|
17425
|
+
}
|
|
17426
|
+
/** Caches local names and their matching directive indices for query and template lookups. */
|
|
17427
|
+
function cacheMatchingLocalNames(tNode, localRefs, exportsMap) {
|
|
17428
|
+
const localNames = (tNode.localNames = []);
|
|
17429
|
+
// Local names must be stored in tNode in the same order that localRefs are defined
|
|
17430
|
+
// in the template to ensure the data is loaded in the same slots as their refs
|
|
17431
|
+
// in the template (for template queries).
|
|
17432
|
+
for (let i = 0; i < localRefs.length; i += 2) {
|
|
17433
|
+
const index = exportsMap[localRefs[i + 1]];
|
|
17434
|
+
if (index == null)
|
|
17435
|
+
throw new RuntimeError(-301 /* RuntimeErrorCode.EXPORT_NOT_FOUND */, ngDevMode && `Export of name '${localRefs[i + 1]}' not found!`);
|
|
17436
|
+
localNames.push(localRefs[i], index);
|
|
17437
|
+
}
|
|
17438
|
+
}
|
|
17439
|
+
function resolveHostDirectives(tView, tNode, matches) {
|
|
17440
|
+
const allDirectiveDefs = [];
|
|
17441
|
+
let hostDirectiveDefs = null;
|
|
17442
|
+
for (const def of matches) {
|
|
17443
|
+
if (def.findHostDirectiveDefs !== null) {
|
|
17444
|
+
// TODO(pk): probably could return matches instead of taking in an array to fill in?
|
|
17445
|
+
hostDirectiveDefs ??= new Map();
|
|
17446
|
+
// Components are inserted at the front of the matches array so that their lifecycle
|
|
17447
|
+
// hooks run before any directive lifecycle hooks. This appears to be for ViewEngine
|
|
17448
|
+
// compatibility. This logic doesn't make sense with host directives, because it
|
|
17449
|
+
// would allow the host directives to undo any overrides the host may have made.
|
|
17450
|
+
// To handle this case, the host directives of components are inserted at the beginning
|
|
17451
|
+
// of the array, followed by the component. As such, the insertion order is as follows:
|
|
17452
|
+
// 1. Host directives belonging to the selector-matched component.
|
|
17453
|
+
// 2. Selector-matched component.
|
|
17454
|
+
// 3. Host directives belonging to selector-matched directives.
|
|
17455
|
+
// 4. Selector-matched directives.
|
|
17456
|
+
def.findHostDirectiveDefs(def, allDirectiveDefs, hostDirectiveDefs);
|
|
17457
|
+
}
|
|
17458
|
+
if (isComponentDef(def)) {
|
|
17459
|
+
allDirectiveDefs.push(def);
|
|
17460
|
+
markAsComponentHost(tView, tNode, allDirectiveDefs.length - 1);
|
|
17461
|
+
}
|
|
17462
|
+
}
|
|
17463
|
+
if (isComponentHost(tNode)) {
|
|
17464
|
+
allDirectiveDefs.push(...matches.slice(1));
|
|
17465
|
+
}
|
|
17466
|
+
else {
|
|
17467
|
+
allDirectiveDefs.push(...matches);
|
|
17468
|
+
}
|
|
17469
|
+
if (ngDevMode) {
|
|
17470
|
+
assertNoDuplicateDirectives(allDirectiveDefs);
|
|
17471
|
+
}
|
|
17472
|
+
return [allDirectiveDefs, hostDirectiveDefs];
|
|
17473
|
+
}
|
|
17474
|
+
/**
|
|
17475
|
+
* Marks a given TNode as a component's host. This consists of:
|
|
17476
|
+
* - setting the component offset on the TNode.
|
|
17477
|
+
* - storing index of component's host element so it will be queued for view refresh during CD.
|
|
17478
|
+
*/
|
|
17479
|
+
function markAsComponentHost(tView, hostTNode, componentOffset) {
|
|
17480
|
+
ngDevMode && assertFirstCreatePass(tView);
|
|
17481
|
+
ngDevMode && assertGreaterThan(componentOffset, -1, 'componentOffset must be great than -1');
|
|
17482
|
+
hostTNode.componentOffset = componentOffset;
|
|
17483
|
+
(tView.components ??= []).push(hostTNode.index);
|
|
17484
|
+
}
|
|
17485
|
+
/** Initializes the data structures necessary for a list of directives to be instantiated. */
|
|
17486
|
+
function initializeDirectives(tView, lView, tNode, directives, exportsMap, hostDirectiveDefs) {
|
|
17487
|
+
ngDevMode && assertFirstCreatePass(tView);
|
|
17488
|
+
// Publishes the directive types to DI so they can be injected. Needs to
|
|
17489
|
+
// happen in a separate pass before the TNode flags have been initialized.
|
|
17490
|
+
for (let i = 0; i < directives.length; i++) {
|
|
17491
|
+
diPublicInInjector(getOrCreateNodeInjectorForNode(tNode, lView), tView, directives[i].type);
|
|
17492
|
+
}
|
|
17493
|
+
initTNodeFlags(tNode, tView.data.length, directives.length);
|
|
17494
|
+
// When the same token is provided by several directives on the same node, some rules apply in
|
|
17495
|
+
// the viewEngine:
|
|
17496
|
+
// - viewProviders have priority over providers
|
|
17497
|
+
// - the last directive in NgModule.declarations has priority over the previous one
|
|
17498
|
+
// So to match these rules, the order in which providers are added in the arrays is very
|
|
17499
|
+
// important.
|
|
17500
|
+
for (let i = 0; i < directives.length; i++) {
|
|
17501
|
+
const def = directives[i];
|
|
17502
|
+
if (def.providersResolver)
|
|
17503
|
+
def.providersResolver(def);
|
|
17504
|
+
}
|
|
17505
|
+
let preOrderHooksFound = false;
|
|
17506
|
+
let preOrderCheckHooksFound = false;
|
|
17507
|
+
let directiveIdx = allocExpando(tView, lView, directives.length, null);
|
|
17508
|
+
ngDevMode &&
|
|
17509
|
+
assertSame(directiveIdx, tNode.directiveStart, 'TNode.directiveStart should point to just allocated space');
|
|
17510
|
+
for (let i = 0; i < directives.length; i++) {
|
|
17511
|
+
const def = directives[i];
|
|
17512
|
+
// Merge the attrs in the order of matches. This assumes that the first directive is the
|
|
17513
|
+
// component itself, so that the component has the least priority.
|
|
17514
|
+
tNode.mergedAttrs = mergeHostAttrs(tNode.mergedAttrs, def.hostAttrs);
|
|
17515
|
+
configureViewWithDirective(tView, tNode, lView, directiveIdx, def);
|
|
17516
|
+
saveNameToExportMap(directiveIdx, def, exportsMap);
|
|
17517
|
+
if (def.contentQueries !== null)
|
|
17518
|
+
tNode.flags |= 4 /* TNodeFlags.hasContentQuery */;
|
|
17519
|
+
if (def.hostBindings !== null || def.hostAttrs !== null || def.hostVars !== 0)
|
|
17520
|
+
tNode.flags |= 64 /* TNodeFlags.hasHostBindings */;
|
|
17521
|
+
const lifeCycleHooks = def.type.prototype;
|
|
17522
|
+
// Only push a node index into the preOrderHooks array if this is the first
|
|
17523
|
+
// pre-order hook found on this node.
|
|
17524
|
+
if (!preOrderHooksFound &&
|
|
17525
|
+
(lifeCycleHooks.ngOnChanges || lifeCycleHooks.ngOnInit || lifeCycleHooks.ngDoCheck)) {
|
|
17526
|
+
// We will push the actual hook function into this array later during dir instantiation.
|
|
17527
|
+
// We cannot do it now because we must ensure hooks are registered in the same
|
|
17528
|
+
// order that directives are created (i.e. injection order).
|
|
17529
|
+
(tView.preOrderHooks ??= []).push(tNode.index);
|
|
17530
|
+
preOrderHooksFound = true;
|
|
17531
|
+
}
|
|
17532
|
+
if (!preOrderCheckHooksFound && (lifeCycleHooks.ngOnChanges || lifeCycleHooks.ngDoCheck)) {
|
|
17533
|
+
(tView.preOrderCheckHooks ??= []).push(tNode.index);
|
|
17534
|
+
preOrderCheckHooksFound = true;
|
|
17535
|
+
}
|
|
17536
|
+
directiveIdx++;
|
|
17537
|
+
}
|
|
17538
|
+
initializeInputAndOutputAliases(tView, tNode, hostDirectiveDefs);
|
|
17539
|
+
}
|
|
17540
|
+
/**
|
|
17541
|
+
* Initializes data structures required to work with directive inputs and outputs.
|
|
17542
|
+
* Initialization is done for all directives matched on a given TNode.
|
|
17543
|
+
*/
|
|
17544
|
+
function initializeInputAndOutputAliases(tView, tNode, hostDirectiveDefinitionMap) {
|
|
17545
|
+
ngDevMode && assertFirstCreatePass(tView);
|
|
17546
|
+
const start = tNode.directiveStart;
|
|
17547
|
+
const end = tNode.directiveEnd;
|
|
17548
|
+
const tViewData = tView.data;
|
|
17549
|
+
const tNodeAttrs = tNode.attrs;
|
|
17550
|
+
const inputsFromAttrs = [];
|
|
17551
|
+
let inputsStore = null;
|
|
17552
|
+
let outputsStore = null;
|
|
17553
|
+
for (let directiveIndex = start; directiveIndex < end; directiveIndex++) {
|
|
17554
|
+
const directiveDef = tViewData[directiveIndex];
|
|
17555
|
+
const aliasData = hostDirectiveDefinitionMap
|
|
17556
|
+
? hostDirectiveDefinitionMap.get(directiveDef)
|
|
17557
|
+
: null;
|
|
17558
|
+
const aliasedInputs = aliasData ? aliasData.inputs : null;
|
|
17559
|
+
const aliasedOutputs = aliasData ? aliasData.outputs : null;
|
|
17560
|
+
inputsStore = captureNodeBindings(0 /* CaptureNodeBindingMode.Inputs */, directiveDef.inputs, directiveIndex, inputsStore, aliasedInputs);
|
|
17561
|
+
outputsStore = captureNodeBindings(1 /* CaptureNodeBindingMode.Outputs */, directiveDef.outputs, directiveIndex, outputsStore, aliasedOutputs);
|
|
17562
|
+
// Do not use unbound attributes as inputs to structural directives, since structural
|
|
17563
|
+
// directive inputs can only be set using microsyntax (e.g. `<div *dir="exp">`).
|
|
17564
|
+
const initialInputs = inputsStore !== null && tNodeAttrs !== null && !isInlineTemplate(tNode)
|
|
17565
|
+
? generateInitialInputs(inputsStore, directiveIndex, tNodeAttrs)
|
|
17566
|
+
: null;
|
|
17567
|
+
inputsFromAttrs.push(initialInputs);
|
|
17568
|
+
}
|
|
17569
|
+
if (inputsStore !== null) {
|
|
17570
|
+
if (inputsStore.hasOwnProperty('class')) {
|
|
17571
|
+
tNode.flags |= 8 /* TNodeFlags.hasClassInput */;
|
|
17572
|
+
}
|
|
17573
|
+
if (inputsStore.hasOwnProperty('style')) {
|
|
17574
|
+
tNode.flags |= 16 /* TNodeFlags.hasStyleInput */;
|
|
17575
|
+
}
|
|
17576
|
+
}
|
|
17577
|
+
tNode.initialInputs = inputsFromAttrs;
|
|
17578
|
+
tNode.inputs = inputsStore;
|
|
17579
|
+
tNode.outputs = outputsStore;
|
|
17580
|
+
}
|
|
17581
|
+
function captureNodeBindings(mode, aliasMap, directiveIndex, bindingsResult, hostDirectiveAliasMap) {
|
|
17582
|
+
for (let publicName in aliasMap) {
|
|
17583
|
+
if (!aliasMap.hasOwnProperty(publicName)) {
|
|
17584
|
+
continue;
|
|
17585
|
+
}
|
|
17586
|
+
const value = aliasMap[publicName];
|
|
17587
|
+
if (value === undefined) {
|
|
17588
|
+
continue;
|
|
17589
|
+
}
|
|
17590
|
+
bindingsResult ??= {};
|
|
17591
|
+
let internalName;
|
|
17592
|
+
let inputFlags = InputFlags.None;
|
|
17593
|
+
// For inputs, the value might be an array capturing additional
|
|
17594
|
+
// input flags.
|
|
17595
|
+
if (Array.isArray(value)) {
|
|
17596
|
+
internalName = value[0];
|
|
17597
|
+
inputFlags = value[1];
|
|
17598
|
+
}
|
|
17599
|
+
else {
|
|
17600
|
+
internalName = value;
|
|
17601
|
+
}
|
|
17602
|
+
// If there are no host directive mappings, we want to remap using the alias map from the
|
|
17603
|
+
// definition itself. If there is an alias map, it has two functions:
|
|
17604
|
+
// 1. It serves as an allowlist of bindings that are exposed by the host directives. Only the
|
|
17605
|
+
// ones inside the host directive map will be exposed on the host.
|
|
17606
|
+
// 2. The public name of the property is aliased using the host directive alias map, rather
|
|
17607
|
+
// than the alias map from the definition.
|
|
17608
|
+
let finalPublicName = publicName;
|
|
17609
|
+
if (hostDirectiveAliasMap !== null) {
|
|
17610
|
+
// If there is no mapping, it's not part of the allowlist and this input/output
|
|
17611
|
+
// is not captured and should be ignored.
|
|
17612
|
+
if (!hostDirectiveAliasMap.hasOwnProperty(publicName)) {
|
|
17613
|
+
continue;
|
|
17614
|
+
}
|
|
17615
|
+
finalPublicName = hostDirectiveAliasMap[publicName];
|
|
17616
|
+
}
|
|
17617
|
+
if (mode === 0 /* CaptureNodeBindingMode.Inputs */) {
|
|
17618
|
+
addPropertyBinding(bindingsResult, directiveIndex, finalPublicName, internalName, inputFlags);
|
|
17619
|
+
}
|
|
17620
|
+
else {
|
|
17621
|
+
addPropertyBinding(bindingsResult, directiveIndex, finalPublicName, internalName);
|
|
17622
|
+
}
|
|
17623
|
+
}
|
|
17624
|
+
return bindingsResult;
|
|
17625
|
+
}
|
|
17626
|
+
function addPropertyBinding(bindings, directiveIndex, publicName, internalName, inputFlags) {
|
|
17627
|
+
let values;
|
|
17628
|
+
if (bindings.hasOwnProperty(publicName)) {
|
|
17629
|
+
(values = bindings[publicName]).push(directiveIndex, internalName);
|
|
17630
|
+
}
|
|
17631
|
+
else {
|
|
17632
|
+
values = bindings[publicName] = [directiveIndex, internalName];
|
|
17633
|
+
}
|
|
17634
|
+
if (inputFlags !== undefined) {
|
|
17635
|
+
values.push(inputFlags);
|
|
17636
|
+
}
|
|
17637
|
+
}
|
|
17638
|
+
/**
|
|
17639
|
+
* Generates initialInputData for a node and stores it in the template's static storage
|
|
17640
|
+
* so subsequent template invocations don't have to recalculate it.
|
|
17641
|
+
*
|
|
17642
|
+
* initialInputData is an array containing values that need to be set as input properties
|
|
17643
|
+
* for directives on this node, but only once on creation. We need this array to support
|
|
17644
|
+
* the case where you set an @Input property of a directive using attribute-like syntax.
|
|
17645
|
+
* e.g. if you have a `name` @Input, you can set it once like this:
|
|
17646
|
+
*
|
|
17647
|
+
* <my-component name="Bess"></my-component>
|
|
17648
|
+
*
|
|
17649
|
+
* @param inputs Input alias map that was generated from the directive def inputs.
|
|
17650
|
+
* @param directiveIndex Index of the directive that is currently being processed.
|
|
17651
|
+
* @param attrs Static attrs on this node.
|
|
17652
|
+
*/
|
|
17653
|
+
function generateInitialInputs(inputs, directiveIndex, attrs) {
|
|
17654
|
+
let inputsToStore = null;
|
|
17655
|
+
let i = 0;
|
|
17656
|
+
while (i < attrs.length) {
|
|
17657
|
+
const attrName = attrs[i];
|
|
17658
|
+
if (attrName === 0 /* AttributeMarker.NamespaceURI */) {
|
|
17659
|
+
// We do not allow inputs on namespaced attributes.
|
|
17660
|
+
i += 4;
|
|
17661
|
+
continue;
|
|
17662
|
+
}
|
|
17663
|
+
else if (attrName === 5 /* AttributeMarker.ProjectAs */) {
|
|
17664
|
+
// Skip over the `ngProjectAs` value.
|
|
17665
|
+
i += 2;
|
|
17666
|
+
continue;
|
|
17667
|
+
}
|
|
17668
|
+
// If we hit any other attribute markers, we're done anyway. None of those are valid inputs.
|
|
17669
|
+
if (typeof attrName === 'number')
|
|
17670
|
+
break;
|
|
17671
|
+
if (inputs.hasOwnProperty(attrName)) {
|
|
17672
|
+
if (inputsToStore === null)
|
|
17673
|
+
inputsToStore = [];
|
|
17674
|
+
// Find the input's public name from the input store. Note that we can be found easier
|
|
17675
|
+
// through the directive def, but we want to do it using the inputs store so that it can
|
|
17676
|
+
// account for host directive aliases.
|
|
17677
|
+
const inputConfig = inputs[attrName];
|
|
17678
|
+
for (let j = 0; j < inputConfig.length; j += 3) {
|
|
17679
|
+
if (inputConfig[j] === directiveIndex) {
|
|
17680
|
+
inputsToStore.push(attrName, inputConfig[j + 1], inputConfig[j + 2], attrs[i + 1]);
|
|
17681
|
+
// A directive can't have multiple inputs with the same name so we can break here.
|
|
17682
|
+
break;
|
|
17683
|
+
}
|
|
17684
|
+
}
|
|
17685
|
+
}
|
|
17686
|
+
i += 2;
|
|
17687
|
+
}
|
|
17688
|
+
return inputsToStore;
|
|
17689
|
+
}
|
|
17690
|
+
/**
|
|
17691
|
+
* Setup directive for instantiation.
|
|
17692
|
+
*
|
|
17693
|
+
* We need to create a `NodeInjectorFactory` which is then inserted in both the `Blueprint` as well
|
|
17694
|
+
* as `LView`. `TView` gets the `DirectiveDef`.
|
|
17695
|
+
*
|
|
17696
|
+
* @param tView `TView`
|
|
17697
|
+
* @param tNode `TNode`
|
|
17698
|
+
* @param lView `LView`
|
|
17699
|
+
* @param directiveIndex Index where the directive will be stored in the Expando.
|
|
17700
|
+
* @param def `DirectiveDef`
|
|
17701
|
+
*/
|
|
17702
|
+
function configureViewWithDirective(tView, tNode, lView, directiveIndex, def) {
|
|
17703
|
+
ngDevMode &&
|
|
17704
|
+
assertGreaterThanOrEqual(directiveIndex, HEADER_OFFSET, 'Must be in Expando section');
|
|
17705
|
+
tView.data[directiveIndex] = def;
|
|
17706
|
+
const directiveFactory = def.factory || (def.factory = getFactoryDef(def.type, true));
|
|
17707
|
+
// Even though `directiveFactory` will already be using `ɵɵdirectiveInject` in its generated code,
|
|
17708
|
+
// we also want to support `inject()` directly from the directive constructor context so we set
|
|
17709
|
+
// `ɵɵdirectiveInject` as the inject implementation here too.
|
|
17710
|
+
const nodeInjectorFactory = new NodeInjectorFactory(directiveFactory, isComponentDef(def), ɵɵdirectiveInject);
|
|
17711
|
+
tView.blueprint[directiveIndex] = nodeInjectorFactory;
|
|
17712
|
+
lView[directiveIndex] = nodeInjectorFactory;
|
|
17713
|
+
registerHostBindingOpCodes(tView, tNode, directiveIndex, allocExpando(tView, lView, def.hostVars, NO_CHANGE), def);
|
|
17714
|
+
}
|
|
17715
|
+
/**
|
|
17716
|
+
* Add `hostBindings` to the `TView.hostBindingOpCodes`.
|
|
17717
|
+
*
|
|
17718
|
+
* @param tView `TView` to which the `hostBindings` should be added.
|
|
17719
|
+
* @param tNode `TNode` the element which contains the directive
|
|
17720
|
+
* @param directiveIdx Directive index in view.
|
|
17721
|
+
* @param directiveVarsIdx Where will the directive's vars be stored
|
|
17722
|
+
* @param def `ComponentDef`/`DirectiveDef`, which contains the `hostVars`/`hostBindings` to add.
|
|
17723
|
+
*/
|
|
17724
|
+
function registerHostBindingOpCodes(tView, tNode, directiveIdx, directiveVarsIdx, def) {
|
|
17725
|
+
ngDevMode && assertFirstCreatePass(tView);
|
|
17726
|
+
const hostBindings = def.hostBindings;
|
|
17727
|
+
if (hostBindings) {
|
|
17728
|
+
let hostBindingOpCodes = tView.hostBindingOpCodes;
|
|
17729
|
+
if (hostBindingOpCodes === null) {
|
|
17730
|
+
hostBindingOpCodes = tView.hostBindingOpCodes = [];
|
|
17731
|
+
}
|
|
17732
|
+
const elementIndx = ~tNode.index;
|
|
17733
|
+
if (lastSelectedElementIdx(hostBindingOpCodes) != elementIndx) {
|
|
17734
|
+
// Conditionally add select element so that we are more efficient in execution.
|
|
17735
|
+
// NOTE: this is strictly not necessary and it trades code size for runtime perf.
|
|
17736
|
+
// (We could just always add it.)
|
|
17737
|
+
hostBindingOpCodes.push(elementIndx);
|
|
17738
|
+
}
|
|
17739
|
+
hostBindingOpCodes.push(directiveIdx, directiveVarsIdx, hostBindings);
|
|
17740
|
+
}
|
|
17741
|
+
}
|
|
17742
|
+
/**
|
|
17743
|
+
* Returns the last selected element index in the `HostBindingOpCodes`
|
|
17744
|
+
*
|
|
17745
|
+
* For perf reasons we don't need to update the selected element index in `HostBindingOpCodes` only
|
|
17746
|
+
* if it changes. This method returns the last index (or '0' if not found.)
|
|
17747
|
+
*
|
|
17748
|
+
* Selected element index are only the ones which are negative.
|
|
17749
|
+
*/
|
|
17750
|
+
function lastSelectedElementIdx(hostBindingOpCodes) {
|
|
17751
|
+
let i = hostBindingOpCodes.length;
|
|
17752
|
+
while (i > 0) {
|
|
17753
|
+
const value = hostBindingOpCodes[--i];
|
|
17754
|
+
if (typeof value === 'number' && value < 0) {
|
|
17755
|
+
return value;
|
|
17756
|
+
}
|
|
17757
|
+
}
|
|
17758
|
+
return 0;
|
|
17759
|
+
}
|
|
17760
|
+
/**
|
|
17761
|
+
* Builds up an export map as directives are created, so local refs can be quickly mapped
|
|
17762
|
+
* to their directive instances.
|
|
17763
|
+
*/
|
|
17764
|
+
function saveNameToExportMap(directiveIdx, def, exportsMap) {
|
|
17765
|
+
if (exportsMap) {
|
|
17766
|
+
if (def.exportAs) {
|
|
17767
|
+
for (let i = 0; i < def.exportAs.length; i++) {
|
|
17768
|
+
exportsMap[def.exportAs[i]] = directiveIdx;
|
|
17769
|
+
}
|
|
17770
|
+
}
|
|
17771
|
+
if (isComponentDef(def))
|
|
17772
|
+
exportsMap[''] = directiveIdx;
|
|
17773
|
+
}
|
|
17774
|
+
}
|
|
17775
|
+
/**
|
|
17776
|
+
* Initializes the flags on the current node, setting all indices to the initial index,
|
|
17777
|
+
* the directive count to 0, and adding the isComponent flag.
|
|
17778
|
+
* @param index the initial index
|
|
17779
|
+
*/
|
|
17780
|
+
function initTNodeFlags(tNode, index, numberOfDirectives) {
|
|
17781
|
+
ngDevMode &&
|
|
17782
|
+
assertNotEqual(numberOfDirectives, tNode.directiveEnd - tNode.directiveStart, 'Reached the max number of directives');
|
|
17783
|
+
tNode.flags |= 1 /* TNodeFlags.isDirectiveHost */;
|
|
17784
|
+
// When the first directive is created on a node, save the index
|
|
17785
|
+
tNode.directiveStart = index;
|
|
17786
|
+
tNode.directiveEnd = index + numberOfDirectives;
|
|
17787
|
+
tNode.providerIndexes = index;
|
|
17788
|
+
}
|
|
17789
|
+
function assertNoDuplicateDirectives(directives) {
|
|
17790
|
+
// The array needs at least two elements in order to have duplicates.
|
|
17791
|
+
if (directives.length < 2) {
|
|
17792
|
+
return;
|
|
17793
|
+
}
|
|
17794
|
+
const seenDirectives = new Set();
|
|
17795
|
+
for (const current of directives) {
|
|
17796
|
+
if (seenDirectives.has(current)) {
|
|
17797
|
+
throw new RuntimeError(309 /* RuntimeErrorCode.DUPLICATE_DIRECTIVE */, `Directive ${current.type.name} matches multiple times on the same element. ` +
|
|
17798
|
+
`Directives can only match an element once.`);
|
|
17799
|
+
}
|
|
17800
|
+
seenDirectives.add(current);
|
|
17801
|
+
}
|
|
17802
|
+
}
|
|
17803
|
+
|
|
17804
|
+
function elementStartFirstCreatePass(index, tView, lView, name, directiveMatcher, bindingsEnabled, attrsIndex, localRefsIndex) {
|
|
17805
|
+
ngDevMode && assertFirstCreatePass(tView);
|
|
17806
|
+
ngDevMode && ngDevMode.firstCreatePass++;
|
|
17807
|
+
const tViewConsts = tView.consts;
|
|
17808
|
+
const attrs = getConstant(tViewConsts, attrsIndex);
|
|
17809
|
+
const tNode = getOrCreateTNode(tView, index, 2 /* TNodeType.Element */, name, attrs);
|
|
17810
|
+
if (bindingsEnabled) {
|
|
17811
|
+
resolveDirectives(tView, lView, tNode, getConstant(tViewConsts, localRefsIndex), directiveMatcher);
|
|
17812
|
+
}
|
|
17813
|
+
// Merge the template attrs last so that they have the highest priority.
|
|
17814
|
+
tNode.mergedAttrs = mergeHostAttrs(tNode.mergedAttrs, tNode.attrs);
|
|
17815
|
+
if (tNode.attrs !== null) {
|
|
17816
|
+
computeStaticStyling(tNode, tNode.attrs, false);
|
|
17817
|
+
}
|
|
17818
|
+
if (tNode.mergedAttrs !== null) {
|
|
17819
|
+
computeStaticStyling(tNode, tNode.mergedAttrs, true);
|
|
17820
|
+
}
|
|
17821
|
+
if (tView.queries !== null) {
|
|
17822
|
+
tView.queries.elementStart(tView, tNode);
|
|
17823
|
+
}
|
|
17824
|
+
return tNode;
|
|
17825
|
+
}
|
|
17826
|
+
function elementEndFirstCreatePass(tView, tNode) {
|
|
17827
|
+
ngDevMode && assertFirstCreatePass(tView);
|
|
17828
|
+
registerPostOrderHooks(tView, tNode);
|
|
17829
|
+
if (isContentQueryHost(tNode)) {
|
|
17830
|
+
tView.queries.elementEnd(tNode);
|
|
17831
|
+
}
|
|
17832
|
+
}
|
|
17833
|
+
|
|
17796
17834
|
class ComponentFactoryResolver extends ComponentFactoryResolver$1 {
|
|
17797
17835
|
ngModule;
|
|
17798
17836
|
/**
|
|
@@ -17837,9 +17875,51 @@ function toRefArray(map, isInputMap) {
|
|
|
17837
17875
|
}
|
|
17838
17876
|
return array;
|
|
17839
17877
|
}
|
|
17840
|
-
function
|
|
17841
|
-
|
|
17842
|
-
|
|
17878
|
+
function verifyNotAnOrphanComponent(componentDef) {
|
|
17879
|
+
// TODO(pk): create assert that verifies ngDevMode
|
|
17880
|
+
if ((typeof ngJitMode === 'undefined' || ngJitMode) &&
|
|
17881
|
+
componentDef.debugInfo?.forbidOrphanRendering) {
|
|
17882
|
+
if (depsTracker.isOrphanComponent(componentDef.type)) {
|
|
17883
|
+
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.`);
|
|
17884
|
+
}
|
|
17885
|
+
}
|
|
17886
|
+
}
|
|
17887
|
+
function createRootViewInjector(componentDef, environmentInjector, injector) {
|
|
17888
|
+
let realEnvironmentInjector = environmentInjector instanceof EnvironmentInjector
|
|
17889
|
+
? environmentInjector
|
|
17890
|
+
: environmentInjector?.injector;
|
|
17891
|
+
if (realEnvironmentInjector && componentDef.getStandaloneInjector !== null) {
|
|
17892
|
+
realEnvironmentInjector =
|
|
17893
|
+
componentDef.getStandaloneInjector(realEnvironmentInjector) || realEnvironmentInjector;
|
|
17894
|
+
}
|
|
17895
|
+
const rootViewInjector = realEnvironmentInjector
|
|
17896
|
+
? new ChainedInjector(injector, realEnvironmentInjector)
|
|
17897
|
+
: injector;
|
|
17898
|
+
return rootViewInjector;
|
|
17899
|
+
}
|
|
17900
|
+
function createRootLViewEnvironment(rootLViewInjector) {
|
|
17901
|
+
const rendererFactory = rootLViewInjector.get(RendererFactory2, null);
|
|
17902
|
+
if (rendererFactory === null) {
|
|
17903
|
+
throw new RuntimeError(407 /* RuntimeErrorCode.RENDERER_NOT_FOUND */, ngDevMode &&
|
|
17904
|
+
'Angular was not able to inject a renderer (RendererFactory2). ' +
|
|
17905
|
+
'Likely this is due to a broken DI hierarchy. ' +
|
|
17906
|
+
'Make sure that any injector used to create this component has a correct parent.');
|
|
17907
|
+
}
|
|
17908
|
+
const sanitizer = rootLViewInjector.get(Sanitizer, null);
|
|
17909
|
+
const changeDetectionScheduler = rootLViewInjector.get(ChangeDetectionScheduler, null);
|
|
17910
|
+
return {
|
|
17911
|
+
rendererFactory,
|
|
17912
|
+
sanitizer,
|
|
17913
|
+
changeDetectionScheduler,
|
|
17914
|
+
};
|
|
17915
|
+
}
|
|
17916
|
+
function createHostElement(componentDef, render) {
|
|
17917
|
+
// Determine a tag name used for creating host elements when this component is created
|
|
17918
|
+
// dynamically. Default to 'div' if this component did not specify any tag name in its
|
|
17919
|
+
// selector.
|
|
17920
|
+
const tagName = (componentDef.selectors[0][0] || 'div').toLowerCase();
|
|
17921
|
+
const namespace = tagName === 'svg' ? SVG_NAMESPACE : tagName === 'math' ? MATH_ML_NAMESPACE : null;
|
|
17922
|
+
return createElementNode(render, tagName, namespace);
|
|
17843
17923
|
}
|
|
17844
17924
|
/**
|
|
17845
17925
|
* ComponentFactory interface implementation.
|
|
@@ -17884,63 +17964,22 @@ class ComponentFactory extends ComponentFactory$1 {
|
|
|
17884
17964
|
profiler(22 /* ProfilerEvent.DynamicComponentStart */);
|
|
17885
17965
|
const prevConsumer = setActiveConsumer$1(null);
|
|
17886
17966
|
try {
|
|
17887
|
-
|
|
17888
|
-
|
|
17889
|
-
|
|
17890
|
-
|
|
17891
|
-
|
|
17892
|
-
|
|
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
|
-
}
|
|
17967
|
+
const cmpDef = this.componentDef;
|
|
17968
|
+
ngDevMode && verifyNotAnOrphanComponent(cmpDef);
|
|
17969
|
+
const tAttributes = rootSelectorOrNode
|
|
17970
|
+
? ['ng-version', '19.2.0-next.2']
|
|
17971
|
+
: // Extract attributes and classes from the first selector only to match VE behavior.
|
|
17972
|
+
extractAttrsAndClassesFromSelector(this.componentDef.selectors[0]);
|
|
17940
17973
|
// Create the root view. Uses empty TView and ContentTemplate.
|
|
17941
|
-
const rootTView = createTView(0 /* TViewType.Root */, null, null, 1, 0, null, null, null, null,
|
|
17942
|
-
const
|
|
17943
|
-
|
|
17974
|
+
const rootTView = createTView(0 /* TViewType.Root */, null, null, 1, 0, null, null, null, null, [tAttributes], null);
|
|
17975
|
+
const rootViewInjector = createRootViewInjector(cmpDef, environmentInjector || this.ngModule, injector);
|
|
17976
|
+
const environment = createRootLViewEnvironment(rootViewInjector);
|
|
17977
|
+
const hostRenderer = environment.rendererFactory.createRenderer(null, cmpDef);
|
|
17978
|
+
const hostElement = rootSelectorOrNode
|
|
17979
|
+
? locateHostElement(hostRenderer, rootSelectorOrNode, cmpDef.encapsulation, rootViewInjector)
|
|
17980
|
+
: createHostElement(cmpDef, hostRenderer);
|
|
17981
|
+
const rootLView = createLView(null, rootTView, null, 512 /* LViewFlags.IsRoot */ | getInitialLViewFlagsFromDef(cmpDef), null, null, environment, hostRenderer, rootViewInjector, null, retrieveHydrationInfo(hostElement, rootViewInjector, true /* isRootView */));
|
|
17982
|
+
rootLView[HEADER_OFFSET] = hostElement;
|
|
17944
17983
|
// rootView is the parent when bootstrapping
|
|
17945
17984
|
// TODO(misko): it looks like we are entering view here but we don't really need to as
|
|
17946
17985
|
// `renderView` does that. However as the code is written it is needed because
|
|
@@ -17949,37 +17988,22 @@ class ComponentFactory extends ComponentFactory$1 {
|
|
|
17949
17988
|
enterView(rootLView);
|
|
17950
17989
|
let componentView = null;
|
|
17951
17990
|
try {
|
|
17952
|
-
|
|
17953
|
-
|
|
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);
|
|
17991
|
+
const hostTNode = elementStartFirstCreatePass(HEADER_OFFSET, rootTView, rootLView, '#host', () => [this.componentDef], true, 0);
|
|
17992
|
+
// ---- element instruction
|
|
17968
17993
|
// TODO(crisbeto): in practice `hostRNode` should always be defined, but there are some
|
|
17969
17994
|
// tests where the renderer is mocked out and `undefined` is returned. We should update the
|
|
17970
17995
|
// tests so that this check can be removed.
|
|
17971
|
-
if (
|
|
17972
|
-
setupStaticAttributes(hostRenderer,
|
|
17973
|
-
attachPatchData(
|
|
17974
|
-
}
|
|
17975
|
-
if (projectableNodes !== undefined) {
|
|
17976
|
-
projectNodes(hostTNode, this.ngContentSelectors, projectableNodes);
|
|
17996
|
+
if (hostElement) {
|
|
17997
|
+
setupStaticAttributes(hostRenderer, hostElement, hostTNode);
|
|
17998
|
+
attachPatchData(hostElement, rootLView);
|
|
17977
17999
|
}
|
|
17978
18000
|
// TODO(pk): this logic is similar to the instruction code where a node can have directives
|
|
17979
18001
|
createDirectivesInstances(rootTView, rootLView, hostTNode);
|
|
17980
18002
|
executeContentQueries(rootTView, hostTNode, rootLView);
|
|
17981
|
-
|
|
17982
|
-
|
|
18003
|
+
elementEndFirstCreatePass(rootTView, hostTNode);
|
|
18004
|
+
if (projectableNodes !== undefined) {
|
|
18005
|
+
projectNodes(hostTNode, this.ngContentSelectors, projectableNodes);
|
|
18006
|
+
}
|
|
17983
18007
|
componentView = getComponentLViewByIndex(hostTNode.index, rootLView);
|
|
17984
18008
|
// TODO(pk): why do we need this logic?
|
|
17985
18009
|
rootLView[CONTEXT] = componentView[CONTEXT];
|
|
@@ -20595,7 +20619,11 @@ function templateFirstCreatePass(index, tView, lView, templateFn, decls, vars, t
|
|
|
20595
20619
|
const tViewConsts = tView.consts;
|
|
20596
20620
|
// TODO(pk): refactor getOrCreateTNode to have the "create" only version
|
|
20597
20621
|
const tNode = getOrCreateTNode(tView, index, 4 /* TNodeType.Container */, tagName || null, attrs || null);
|
|
20598
|
-
|
|
20622
|
+
if (getBindingsEnabled()) {
|
|
20623
|
+
resolveDirectives(tView, lView, tNode, getConstant(tViewConsts, localRefsIndex), findDirectiveDefMatches);
|
|
20624
|
+
}
|
|
20625
|
+
// Merge the template attrs last so that they have the highest priority.
|
|
20626
|
+
tNode.mergedAttrs = mergeHostAttrs(tNode.mergedAttrs, tNode.attrs);
|
|
20599
20627
|
registerPostOrderHooks(tView, tNode);
|
|
20600
20628
|
const embeddedTView = (tNode.tView = createTView(2 /* TViewType.Embedded */, tNode, templateFn, decls, vars, tView.directiveRegistry, tView.pipeRegistry, null, tView.schemas, tViewConsts, null /* ssrId */));
|
|
20601
20629
|
if (tView.queries !== null) {
|
|
@@ -22898,265 +22926,6 @@ function setTestabilityGetter(getter) {
|
|
|
22898
22926
|
}
|
|
22899
22927
|
let _testabilityGetter;
|
|
22900
22928
|
|
|
22901
|
-
/**
|
|
22902
|
-
* Determine if the argument is shaped like a Promise
|
|
22903
|
-
*/
|
|
22904
|
-
function isPromise(obj) {
|
|
22905
|
-
// allow any Promise/A+ compliant thenable.
|
|
22906
|
-
// It's up to the caller to ensure that obj.then conforms to the spec
|
|
22907
|
-
return !!obj && typeof obj.then === 'function';
|
|
22908
|
-
}
|
|
22909
|
-
/**
|
|
22910
|
-
* Determine if the argument is a Subscribable
|
|
22911
|
-
*/
|
|
22912
|
-
function isSubscribable(obj) {
|
|
22913
|
-
return !!obj && typeof obj.subscribe === 'function';
|
|
22914
|
-
}
|
|
22915
|
-
|
|
22916
|
-
/**
|
|
22917
|
-
* A DI token that you can use to provide
|
|
22918
|
-
* one or more initialization functions.
|
|
22919
|
-
*
|
|
22920
|
-
* The provided functions are injected at application startup and executed during
|
|
22921
|
-
* app initialization. If any of these functions returns a Promise or an Observable, initialization
|
|
22922
|
-
* does not complete until the Promise is resolved or the Observable is completed.
|
|
22923
|
-
*
|
|
22924
|
-
* You can, for example, create a factory function that loads language data
|
|
22925
|
-
* or an external configuration, and provide that function to the `APP_INITIALIZER` token.
|
|
22926
|
-
* The function is executed during the application bootstrap process,
|
|
22927
|
-
* and the needed data is available on startup.
|
|
22928
|
-
*
|
|
22929
|
-
* Note that the provided initializer is run in the injection context.
|
|
22930
|
-
*
|
|
22931
|
-
* @deprecated from v19.0.0, use provideAppInitializer instead
|
|
22932
|
-
*
|
|
22933
|
-
* @see {@link ApplicationInitStatus}
|
|
22934
|
-
* @see {@link provideAppInitializer}
|
|
22935
|
-
*
|
|
22936
|
-
* @usageNotes
|
|
22937
|
-
*
|
|
22938
|
-
* The following example illustrates how to configure a multi-provider using `APP_INITIALIZER` token
|
|
22939
|
-
* and a function returning a promise.
|
|
22940
|
-
* ### Example with NgModule-based application
|
|
22941
|
-
* ```ts
|
|
22942
|
-
* function initializeApp(): Promise<any> {
|
|
22943
|
-
* const http = inject(HttpClient);
|
|
22944
|
-
* return firstValueFrom(
|
|
22945
|
-
* http
|
|
22946
|
-
* .get("https://someUrl.com/api/user")
|
|
22947
|
-
* .pipe(tap(user => { ... }))
|
|
22948
|
-
* );
|
|
22949
|
-
* }
|
|
22950
|
-
*
|
|
22951
|
-
* @NgModule({
|
|
22952
|
-
* imports: [BrowserModule],
|
|
22953
|
-
* declarations: [AppComponent],
|
|
22954
|
-
* bootstrap: [AppComponent],
|
|
22955
|
-
* providers: [{
|
|
22956
|
-
* provide: APP_INITIALIZER,
|
|
22957
|
-
* useValue: initializeApp,
|
|
22958
|
-
* multi: true,
|
|
22959
|
-
* }]
|
|
22960
|
-
* })
|
|
22961
|
-
* export class AppModule {}
|
|
22962
|
-
* ```
|
|
22963
|
-
*
|
|
22964
|
-
* ### Example with standalone application
|
|
22965
|
-
* ```ts
|
|
22966
|
-
* function initializeApp() {
|
|
22967
|
-
* const http = inject(HttpClient);
|
|
22968
|
-
* return firstValueFrom(
|
|
22969
|
-
* http
|
|
22970
|
-
* .get("https://someUrl.com/api/user")
|
|
22971
|
-
* .pipe(tap(user => { ... }))
|
|
22972
|
-
* );
|
|
22973
|
-
* }
|
|
22974
|
-
*
|
|
22975
|
-
* bootstrapApplication(App, {
|
|
22976
|
-
* providers: [
|
|
22977
|
-
* provideHttpClient(),
|
|
22978
|
-
* {
|
|
22979
|
-
* provide: APP_INITIALIZER,
|
|
22980
|
-
* useValue: initializeApp,
|
|
22981
|
-
* multi: true,
|
|
22982
|
-
* },
|
|
22983
|
-
* ],
|
|
22984
|
-
* });
|
|
22985
|
-
|
|
22986
|
-
* ```
|
|
22987
|
-
*
|
|
22988
|
-
*
|
|
22989
|
-
* It's also possible to configure a multi-provider using `APP_INITIALIZER` token and a function
|
|
22990
|
-
* returning an observable, see an example below. Note: the `HttpClient` in this example is used for
|
|
22991
|
-
* demo purposes to illustrate how the factory function can work with other providers available
|
|
22992
|
-
* through DI.
|
|
22993
|
-
*
|
|
22994
|
-
* ### Example with NgModule-based application
|
|
22995
|
-
* ```ts
|
|
22996
|
-
* function initializeApp() {
|
|
22997
|
-
* const http = inject(HttpClient);
|
|
22998
|
-
* return firstValueFrom(
|
|
22999
|
-
* http
|
|
23000
|
-
* .get("https://someUrl.com/api/user")
|
|
23001
|
-
* .pipe(tap(user => { ... }))
|
|
23002
|
-
* );
|
|
23003
|
-
* }
|
|
23004
|
-
*
|
|
23005
|
-
* @NgModule({
|
|
23006
|
-
* imports: [BrowserModule, HttpClientModule],
|
|
23007
|
-
* declarations: [AppComponent],
|
|
23008
|
-
* bootstrap: [AppComponent],
|
|
23009
|
-
* providers: [{
|
|
23010
|
-
* provide: APP_INITIALIZER,
|
|
23011
|
-
* useValue: initializeApp,
|
|
23012
|
-
* multi: true,
|
|
23013
|
-
* }]
|
|
23014
|
-
* })
|
|
23015
|
-
* export class AppModule {}
|
|
23016
|
-
* ```
|
|
23017
|
-
*
|
|
23018
|
-
* ### Example with standalone application
|
|
23019
|
-
* ```ts
|
|
23020
|
-
* function initializeApp() {
|
|
23021
|
-
* const http = inject(HttpClient);
|
|
23022
|
-
* return firstValueFrom(
|
|
23023
|
-
* http
|
|
23024
|
-
* .get("https://someUrl.com/api/user")
|
|
23025
|
-
* .pipe(tap(user => { ... }))
|
|
23026
|
-
* );
|
|
23027
|
-
* }
|
|
23028
|
-
*
|
|
23029
|
-
* bootstrapApplication(App, {
|
|
23030
|
-
* providers: [
|
|
23031
|
-
* provideHttpClient(),
|
|
23032
|
-
* {
|
|
23033
|
-
* provide: APP_INITIALIZER,
|
|
23034
|
-
* useValue: initializeApp,
|
|
23035
|
-
* multi: true,
|
|
23036
|
-
* },
|
|
23037
|
-
* ],
|
|
23038
|
-
* });
|
|
23039
|
-
* ```
|
|
23040
|
-
*
|
|
23041
|
-
* @publicApi
|
|
23042
|
-
*/
|
|
23043
|
-
const APP_INITIALIZER = new InjectionToken(ngDevMode ? 'Application Initializer' : '');
|
|
23044
|
-
/**
|
|
23045
|
-
* @description
|
|
23046
|
-
* The provided function is injected at application startup and executed during
|
|
23047
|
-
* app initialization. If the function returns a Promise or an Observable, initialization
|
|
23048
|
-
* does not complete until the Promise is resolved or the Observable is completed.
|
|
23049
|
-
*
|
|
23050
|
-
* You can, for example, create a function that loads language data
|
|
23051
|
-
* or an external configuration, and provide that function using `provideAppInitializer()`.
|
|
23052
|
-
* The function is executed during the application bootstrap process,
|
|
23053
|
-
* and the needed data is available on startup.
|
|
23054
|
-
*
|
|
23055
|
-
* Note that the provided initializer is run in the injection context.
|
|
23056
|
-
*
|
|
23057
|
-
* Previously, this was achieved using the `APP_INITIALIZER` token which is now deprecated.
|
|
23058
|
-
*
|
|
23059
|
-
* @see {@link APP_INITIALIZER}
|
|
23060
|
-
*
|
|
23061
|
-
* @usageNotes
|
|
23062
|
-
* The following example illustrates how to configure an initialization function using
|
|
23063
|
-
* `provideAppInitializer()`
|
|
23064
|
-
* ```ts
|
|
23065
|
-
* bootstrapApplication(App, {
|
|
23066
|
-
* providers: [
|
|
23067
|
-
* provideAppInitializer(() => {
|
|
23068
|
-
* const http = inject(HttpClient);
|
|
23069
|
-
* return firstValueFrom(
|
|
23070
|
-
* http
|
|
23071
|
-
* .get("https://someUrl.com/api/user")
|
|
23072
|
-
* .pipe(tap(user => { ... }))
|
|
23073
|
-
* );
|
|
23074
|
-
* }),
|
|
23075
|
-
* provideHttpClient(),
|
|
23076
|
-
* ],
|
|
23077
|
-
* });
|
|
23078
|
-
* ```
|
|
23079
|
-
*
|
|
23080
|
-
* @publicApi
|
|
23081
|
-
*/
|
|
23082
|
-
function provideAppInitializer(initializerFn) {
|
|
23083
|
-
return makeEnvironmentProviders([
|
|
23084
|
-
{
|
|
23085
|
-
provide: APP_INITIALIZER,
|
|
23086
|
-
multi: true,
|
|
23087
|
-
useValue: initializerFn,
|
|
23088
|
-
},
|
|
23089
|
-
]);
|
|
23090
|
-
}
|
|
23091
|
-
/**
|
|
23092
|
-
* A class that reflects the state of running {@link APP_INITIALIZER} functions.
|
|
23093
|
-
*
|
|
23094
|
-
* @publicApi
|
|
23095
|
-
*/
|
|
23096
|
-
class ApplicationInitStatus {
|
|
23097
|
-
// Using non null assertion, these fields are defined below
|
|
23098
|
-
// within the `new Promise` callback (synchronously).
|
|
23099
|
-
resolve;
|
|
23100
|
-
reject;
|
|
23101
|
-
initialized = false;
|
|
23102
|
-
done = false;
|
|
23103
|
-
donePromise = new Promise((res, rej) => {
|
|
23104
|
-
this.resolve = res;
|
|
23105
|
-
this.reject = rej;
|
|
23106
|
-
});
|
|
23107
|
-
appInits = inject(APP_INITIALIZER, { optional: true }) ?? [];
|
|
23108
|
-
injector = inject(Injector);
|
|
23109
|
-
constructor() {
|
|
23110
|
-
if ((typeof ngDevMode === 'undefined' || ngDevMode) && !Array.isArray(this.appInits)) {
|
|
23111
|
-
throw new RuntimeError(-209 /* RuntimeErrorCode.INVALID_MULTI_PROVIDER */, 'Unexpected type of the `APP_INITIALIZER` token value ' +
|
|
23112
|
-
`(expected an array, but got ${typeof this.appInits}). ` +
|
|
23113
|
-
'Please check that the `APP_INITIALIZER` token is configured as a ' +
|
|
23114
|
-
'`multi: true` provider.');
|
|
23115
|
-
}
|
|
23116
|
-
}
|
|
23117
|
-
/** @internal */
|
|
23118
|
-
runInitializers() {
|
|
23119
|
-
if (this.initialized) {
|
|
23120
|
-
return;
|
|
23121
|
-
}
|
|
23122
|
-
const asyncInitPromises = [];
|
|
23123
|
-
for (const appInits of this.appInits) {
|
|
23124
|
-
const initResult = runInInjectionContext(this.injector, appInits);
|
|
23125
|
-
if (isPromise(initResult)) {
|
|
23126
|
-
asyncInitPromises.push(initResult);
|
|
23127
|
-
}
|
|
23128
|
-
else if (isSubscribable(initResult)) {
|
|
23129
|
-
const observableAsPromise = new Promise((resolve, reject) => {
|
|
23130
|
-
initResult.subscribe({ complete: resolve, error: reject });
|
|
23131
|
-
});
|
|
23132
|
-
asyncInitPromises.push(observableAsPromise);
|
|
23133
|
-
}
|
|
23134
|
-
}
|
|
23135
|
-
const complete = () => {
|
|
23136
|
-
// @ts-expect-error overwriting a readonly
|
|
23137
|
-
this.done = true;
|
|
23138
|
-
this.resolve();
|
|
23139
|
-
};
|
|
23140
|
-
Promise.all(asyncInitPromises)
|
|
23141
|
-
.then(() => {
|
|
23142
|
-
complete();
|
|
23143
|
-
})
|
|
23144
|
-
.catch((e) => {
|
|
23145
|
-
this.reject(e);
|
|
23146
|
-
});
|
|
23147
|
-
if (asyncInitPromises.length === 0) {
|
|
23148
|
-
complete();
|
|
23149
|
-
}
|
|
23150
|
-
this.initialized = true;
|
|
23151
|
-
}
|
|
23152
|
-
static ɵfac = function ApplicationInitStatus_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ApplicationInitStatus)(); };
|
|
23153
|
-
static ɵprov = /*@__PURE__*/ ɵɵdefineInjectable({ token: ApplicationInitStatus, factory: ApplicationInitStatus.ɵfac, providedIn: 'root' });
|
|
23154
|
-
}
|
|
23155
|
-
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(ApplicationInitStatus, [{
|
|
23156
|
-
type: Injectable,
|
|
23157
|
-
args: [{ providedIn: 'root' }]
|
|
23158
|
-
}], () => [], null); })();
|
|
23159
|
-
|
|
23160
22929
|
/**
|
|
23161
22930
|
* A scheduler which manages the execution of effects.
|
|
23162
22931
|
*/
|
|
@@ -23228,6 +22997,265 @@ class ZoneAwareEffectScheduler {
|
|
|
23228
22997
|
}
|
|
23229
22998
|
}
|
|
23230
22999
|
|
|
23000
|
+
/**
|
|
23001
|
+
* Determine if the argument is shaped like a Promise
|
|
23002
|
+
*/
|
|
23003
|
+
function isPromise(obj) {
|
|
23004
|
+
// allow any Promise/A+ compliant thenable.
|
|
23005
|
+
// It's up to the caller to ensure that obj.then conforms to the spec
|
|
23006
|
+
return !!obj && typeof obj.then === 'function';
|
|
23007
|
+
}
|
|
23008
|
+
/**
|
|
23009
|
+
* Determine if the argument is a Subscribable
|
|
23010
|
+
*/
|
|
23011
|
+
function isSubscribable(obj) {
|
|
23012
|
+
return !!obj && typeof obj.subscribe === 'function';
|
|
23013
|
+
}
|
|
23014
|
+
|
|
23015
|
+
/**
|
|
23016
|
+
* A DI token that you can use to provide
|
|
23017
|
+
* one or more initialization functions.
|
|
23018
|
+
*
|
|
23019
|
+
* The provided functions are injected at application startup and executed during
|
|
23020
|
+
* app initialization. If any of these functions returns a Promise or an Observable, initialization
|
|
23021
|
+
* does not complete until the Promise is resolved or the Observable is completed.
|
|
23022
|
+
*
|
|
23023
|
+
* You can, for example, create a factory function that loads language data
|
|
23024
|
+
* or an external configuration, and provide that function to the `APP_INITIALIZER` token.
|
|
23025
|
+
* The function is executed during the application bootstrap process,
|
|
23026
|
+
* and the needed data is available on startup.
|
|
23027
|
+
*
|
|
23028
|
+
* Note that the provided initializer is run in the injection context.
|
|
23029
|
+
*
|
|
23030
|
+
* @deprecated from v19.0.0, use provideAppInitializer instead
|
|
23031
|
+
*
|
|
23032
|
+
* @see {@link ApplicationInitStatus}
|
|
23033
|
+
* @see {@link provideAppInitializer}
|
|
23034
|
+
*
|
|
23035
|
+
* @usageNotes
|
|
23036
|
+
*
|
|
23037
|
+
* The following example illustrates how to configure a multi-provider using `APP_INITIALIZER` token
|
|
23038
|
+
* and a function returning a promise.
|
|
23039
|
+
* ### Example with NgModule-based application
|
|
23040
|
+
* ```ts
|
|
23041
|
+
* function initializeApp(): Promise<any> {
|
|
23042
|
+
* const http = inject(HttpClient);
|
|
23043
|
+
* return firstValueFrom(
|
|
23044
|
+
* http
|
|
23045
|
+
* .get("https://someUrl.com/api/user")
|
|
23046
|
+
* .pipe(tap(user => { ... }))
|
|
23047
|
+
* );
|
|
23048
|
+
* }
|
|
23049
|
+
*
|
|
23050
|
+
* @NgModule({
|
|
23051
|
+
* imports: [BrowserModule],
|
|
23052
|
+
* declarations: [AppComponent],
|
|
23053
|
+
* bootstrap: [AppComponent],
|
|
23054
|
+
* providers: [{
|
|
23055
|
+
* provide: APP_INITIALIZER,
|
|
23056
|
+
* useValue: initializeApp,
|
|
23057
|
+
* multi: true,
|
|
23058
|
+
* }]
|
|
23059
|
+
* })
|
|
23060
|
+
* export class AppModule {}
|
|
23061
|
+
* ```
|
|
23062
|
+
*
|
|
23063
|
+
* ### Example with standalone application
|
|
23064
|
+
* ```ts
|
|
23065
|
+
* function initializeApp() {
|
|
23066
|
+
* const http = inject(HttpClient);
|
|
23067
|
+
* return firstValueFrom(
|
|
23068
|
+
* http
|
|
23069
|
+
* .get("https://someUrl.com/api/user")
|
|
23070
|
+
* .pipe(tap(user => { ... }))
|
|
23071
|
+
* );
|
|
23072
|
+
* }
|
|
23073
|
+
*
|
|
23074
|
+
* bootstrapApplication(App, {
|
|
23075
|
+
* providers: [
|
|
23076
|
+
* provideHttpClient(),
|
|
23077
|
+
* {
|
|
23078
|
+
* provide: APP_INITIALIZER,
|
|
23079
|
+
* useValue: initializeApp,
|
|
23080
|
+
* multi: true,
|
|
23081
|
+
* },
|
|
23082
|
+
* ],
|
|
23083
|
+
* });
|
|
23084
|
+
|
|
23085
|
+
* ```
|
|
23086
|
+
*
|
|
23087
|
+
*
|
|
23088
|
+
* It's also possible to configure a multi-provider using `APP_INITIALIZER` token and a function
|
|
23089
|
+
* returning an observable, see an example below. Note: the `HttpClient` in this example is used for
|
|
23090
|
+
* demo purposes to illustrate how the factory function can work with other providers available
|
|
23091
|
+
* through DI.
|
|
23092
|
+
*
|
|
23093
|
+
* ### Example with NgModule-based application
|
|
23094
|
+
* ```ts
|
|
23095
|
+
* function initializeApp() {
|
|
23096
|
+
* const http = inject(HttpClient);
|
|
23097
|
+
* return firstValueFrom(
|
|
23098
|
+
* http
|
|
23099
|
+
* .get("https://someUrl.com/api/user")
|
|
23100
|
+
* .pipe(tap(user => { ... }))
|
|
23101
|
+
* );
|
|
23102
|
+
* }
|
|
23103
|
+
*
|
|
23104
|
+
* @NgModule({
|
|
23105
|
+
* imports: [BrowserModule, HttpClientModule],
|
|
23106
|
+
* declarations: [AppComponent],
|
|
23107
|
+
* bootstrap: [AppComponent],
|
|
23108
|
+
* providers: [{
|
|
23109
|
+
* provide: APP_INITIALIZER,
|
|
23110
|
+
* useValue: initializeApp,
|
|
23111
|
+
* multi: true,
|
|
23112
|
+
* }]
|
|
23113
|
+
* })
|
|
23114
|
+
* export class AppModule {}
|
|
23115
|
+
* ```
|
|
23116
|
+
*
|
|
23117
|
+
* ### Example with standalone application
|
|
23118
|
+
* ```ts
|
|
23119
|
+
* function initializeApp() {
|
|
23120
|
+
* const http = inject(HttpClient);
|
|
23121
|
+
* return firstValueFrom(
|
|
23122
|
+
* http
|
|
23123
|
+
* .get("https://someUrl.com/api/user")
|
|
23124
|
+
* .pipe(tap(user => { ... }))
|
|
23125
|
+
* );
|
|
23126
|
+
* }
|
|
23127
|
+
*
|
|
23128
|
+
* bootstrapApplication(App, {
|
|
23129
|
+
* providers: [
|
|
23130
|
+
* provideHttpClient(),
|
|
23131
|
+
* {
|
|
23132
|
+
* provide: APP_INITIALIZER,
|
|
23133
|
+
* useValue: initializeApp,
|
|
23134
|
+
* multi: true,
|
|
23135
|
+
* },
|
|
23136
|
+
* ],
|
|
23137
|
+
* });
|
|
23138
|
+
* ```
|
|
23139
|
+
*
|
|
23140
|
+
* @publicApi
|
|
23141
|
+
*/
|
|
23142
|
+
const APP_INITIALIZER = new InjectionToken(ngDevMode ? 'Application Initializer' : '');
|
|
23143
|
+
/**
|
|
23144
|
+
* @description
|
|
23145
|
+
* The provided function is injected at application startup and executed during
|
|
23146
|
+
* app initialization. If the function returns a Promise or an Observable, initialization
|
|
23147
|
+
* does not complete until the Promise is resolved or the Observable is completed.
|
|
23148
|
+
*
|
|
23149
|
+
* You can, for example, create a function that loads language data
|
|
23150
|
+
* or an external configuration, and provide that function using `provideAppInitializer()`.
|
|
23151
|
+
* The function is executed during the application bootstrap process,
|
|
23152
|
+
* and the needed data is available on startup.
|
|
23153
|
+
*
|
|
23154
|
+
* Note that the provided initializer is run in the injection context.
|
|
23155
|
+
*
|
|
23156
|
+
* Previously, this was achieved using the `APP_INITIALIZER` token which is now deprecated.
|
|
23157
|
+
*
|
|
23158
|
+
* @see {@link APP_INITIALIZER}
|
|
23159
|
+
*
|
|
23160
|
+
* @usageNotes
|
|
23161
|
+
* The following example illustrates how to configure an initialization function using
|
|
23162
|
+
* `provideAppInitializer()`
|
|
23163
|
+
* ```ts
|
|
23164
|
+
* bootstrapApplication(App, {
|
|
23165
|
+
* providers: [
|
|
23166
|
+
* provideAppInitializer(() => {
|
|
23167
|
+
* const http = inject(HttpClient);
|
|
23168
|
+
* return firstValueFrom(
|
|
23169
|
+
* http
|
|
23170
|
+
* .get("https://someUrl.com/api/user")
|
|
23171
|
+
* .pipe(tap(user => { ... }))
|
|
23172
|
+
* );
|
|
23173
|
+
* }),
|
|
23174
|
+
* provideHttpClient(),
|
|
23175
|
+
* ],
|
|
23176
|
+
* });
|
|
23177
|
+
* ```
|
|
23178
|
+
*
|
|
23179
|
+
* @publicApi
|
|
23180
|
+
*/
|
|
23181
|
+
function provideAppInitializer(initializerFn) {
|
|
23182
|
+
return makeEnvironmentProviders([
|
|
23183
|
+
{
|
|
23184
|
+
provide: APP_INITIALIZER,
|
|
23185
|
+
multi: true,
|
|
23186
|
+
useValue: initializerFn,
|
|
23187
|
+
},
|
|
23188
|
+
]);
|
|
23189
|
+
}
|
|
23190
|
+
/**
|
|
23191
|
+
* A class that reflects the state of running {@link APP_INITIALIZER} functions.
|
|
23192
|
+
*
|
|
23193
|
+
* @publicApi
|
|
23194
|
+
*/
|
|
23195
|
+
class ApplicationInitStatus {
|
|
23196
|
+
// Using non null assertion, these fields are defined below
|
|
23197
|
+
// within the `new Promise` callback (synchronously).
|
|
23198
|
+
resolve;
|
|
23199
|
+
reject;
|
|
23200
|
+
initialized = false;
|
|
23201
|
+
done = false;
|
|
23202
|
+
donePromise = new Promise((res, rej) => {
|
|
23203
|
+
this.resolve = res;
|
|
23204
|
+
this.reject = rej;
|
|
23205
|
+
});
|
|
23206
|
+
appInits = inject(APP_INITIALIZER, { optional: true }) ?? [];
|
|
23207
|
+
injector = inject(Injector);
|
|
23208
|
+
constructor() {
|
|
23209
|
+
if ((typeof ngDevMode === 'undefined' || ngDevMode) && !Array.isArray(this.appInits)) {
|
|
23210
|
+
throw new RuntimeError(-209 /* RuntimeErrorCode.INVALID_MULTI_PROVIDER */, 'Unexpected type of the `APP_INITIALIZER` token value ' +
|
|
23211
|
+
`(expected an array, but got ${typeof this.appInits}). ` +
|
|
23212
|
+
'Please check that the `APP_INITIALIZER` token is configured as a ' +
|
|
23213
|
+
'`multi: true` provider.');
|
|
23214
|
+
}
|
|
23215
|
+
}
|
|
23216
|
+
/** @internal */
|
|
23217
|
+
runInitializers() {
|
|
23218
|
+
if (this.initialized) {
|
|
23219
|
+
return;
|
|
23220
|
+
}
|
|
23221
|
+
const asyncInitPromises = [];
|
|
23222
|
+
for (const appInits of this.appInits) {
|
|
23223
|
+
const initResult = runInInjectionContext(this.injector, appInits);
|
|
23224
|
+
if (isPromise(initResult)) {
|
|
23225
|
+
asyncInitPromises.push(initResult);
|
|
23226
|
+
}
|
|
23227
|
+
else if (isSubscribable(initResult)) {
|
|
23228
|
+
const observableAsPromise = new Promise((resolve, reject) => {
|
|
23229
|
+
initResult.subscribe({ complete: resolve, error: reject });
|
|
23230
|
+
});
|
|
23231
|
+
asyncInitPromises.push(observableAsPromise);
|
|
23232
|
+
}
|
|
23233
|
+
}
|
|
23234
|
+
const complete = () => {
|
|
23235
|
+
// @ts-expect-error overwriting a readonly
|
|
23236
|
+
this.done = true;
|
|
23237
|
+
this.resolve();
|
|
23238
|
+
};
|
|
23239
|
+
Promise.all(asyncInitPromises)
|
|
23240
|
+
.then(() => {
|
|
23241
|
+
complete();
|
|
23242
|
+
})
|
|
23243
|
+
.catch((e) => {
|
|
23244
|
+
this.reject(e);
|
|
23245
|
+
});
|
|
23246
|
+
if (asyncInitPromises.length === 0) {
|
|
23247
|
+
complete();
|
|
23248
|
+
}
|
|
23249
|
+
this.initialized = true;
|
|
23250
|
+
}
|
|
23251
|
+
static ɵfac = function ApplicationInitStatus_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ApplicationInitStatus)(); };
|
|
23252
|
+
static ɵprov = /*@__PURE__*/ ɵɵdefineInjectable({ token: ApplicationInitStatus, factory: ApplicationInitStatus.ɵfac, providedIn: 'root' });
|
|
23253
|
+
}
|
|
23254
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(ApplicationInitStatus, [{
|
|
23255
|
+
type: Injectable,
|
|
23256
|
+
args: [{ providedIn: 'root' }]
|
|
23257
|
+
}], () => [], null); })();
|
|
23258
|
+
|
|
23231
23259
|
/**
|
|
23232
23260
|
* A DI token that provides a set of callbacks to
|
|
23233
23261
|
* be called for every component that is bootstrapped.
|
|
@@ -23269,24 +23297,6 @@ class NgProbeToken {
|
|
|
23269
23297
|
}
|
|
23270
23298
|
/** Maximum number of times ApplicationRef will refresh all attached views in a single tick. */
|
|
23271
23299
|
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
23300
|
function optionsReducer(dst, objs) {
|
|
23291
23301
|
if (Array.isArray(objs)) {
|
|
23292
23302
|
return objs.reduce(optionsReducer, dst);
|
|
@@ -23576,18 +23586,19 @@ class ApplicationRef {
|
|
|
23576
23586
|
this._tick();
|
|
23577
23587
|
}
|
|
23578
23588
|
/** @internal */
|
|
23579
|
-
_tick
|
|
23589
|
+
_tick() {
|
|
23580
23590
|
profiler(12 /* ProfilerEvent.ChangeDetectionStart */);
|
|
23581
23591
|
if (this.tracingSnapshot !== null) {
|
|
23582
|
-
|
|
23583
|
-
this.tracingSnapshot = null;
|
|
23584
|
-
// Ensure we always run `_tick()` in the context of the most recent snapshot,
|
|
23592
|
+
// Ensure we always run `tickImpl()` in the context of the most recent snapshot,
|
|
23585
23593
|
// if one exists. Snapshots may be reference counted by the implementation so
|
|
23586
23594
|
// we want to ensure that if we request a snapshot that we use it.
|
|
23587
|
-
|
|
23588
|
-
snapshot.dispose();
|
|
23589
|
-
return;
|
|
23595
|
+
this.tracingSnapshot.run(TracingAction.CHANGE_DETECTION, this.tickImpl);
|
|
23590
23596
|
}
|
|
23597
|
+
else {
|
|
23598
|
+
this.tickImpl();
|
|
23599
|
+
}
|
|
23600
|
+
}
|
|
23601
|
+
tickImpl = () => {
|
|
23591
23602
|
(typeof ngDevMode === 'undefined' || ngDevMode) && warnIfDestroyed(this._destroyed);
|
|
23592
23603
|
if (this._runningTick) {
|
|
23593
23604
|
throw new RuntimeError(101 /* RuntimeErrorCode.RECURSIVE_APPLICATION_REF_TICK */, ngDevMode && 'ApplicationRef.tick is called recursively');
|
|
@@ -23608,6 +23619,8 @@ class ApplicationRef {
|
|
|
23608
23619
|
}
|
|
23609
23620
|
finally {
|
|
23610
23621
|
this._runningTick = false;
|
|
23622
|
+
this.tracingSnapshot?.dispose();
|
|
23623
|
+
this.tracingSnapshot = null;
|
|
23611
23624
|
setActiveConsumer$1(prevConsumer);
|
|
23612
23625
|
this.afterTick.next();
|
|
23613
23626
|
profiler(13 /* ProfilerEvent.ChangeDetectionEnd */);
|
|
@@ -27979,24 +27992,6 @@ function getExistingTNode(tView, index) {
|
|
|
27979
27992
|
return tNode;
|
|
27980
27993
|
}
|
|
27981
27994
|
|
|
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
27995
|
/**
|
|
28001
27996
|
* Create DOM element. The instruction must later be followed by `elementEnd()` call.
|
|
28002
27997
|
*
|
|
@@ -28021,7 +28016,7 @@ function ɵɵelementStart(index, name, attrsIndex, localRefsIndex) {
|
|
|
28021
28016
|
ngDevMode && assertIndexInRange(lView, adjustedIndex);
|
|
28022
28017
|
const renderer = lView[RENDERER];
|
|
28023
28018
|
const tNode = tView.firstCreatePass
|
|
28024
|
-
? elementStartFirstCreatePass(adjustedIndex, tView, lView, name, attrsIndex, localRefsIndex)
|
|
28019
|
+
? elementStartFirstCreatePass(adjustedIndex, tView, lView, name, findDirectiveDefMatches, getBindingsEnabled(), attrsIndex, localRefsIndex)
|
|
28025
28020
|
: tView.data[adjustedIndex];
|
|
28026
28021
|
const native = _locateOrCreateElementNode(tView, lView, tNode, renderer, name, index);
|
|
28027
28022
|
lView[adjustedIndex] = native;
|
|
@@ -28077,10 +28072,7 @@ function ɵɵelementEnd() {
|
|
|
28077
28072
|
decreaseElementDepthCount();
|
|
28078
28073
|
const tView = getTView();
|
|
28079
28074
|
if (tView.firstCreatePass) {
|
|
28080
|
-
|
|
28081
|
-
if (isContentQueryHost(currentTNode)) {
|
|
28082
|
-
tView.queries.elementEnd(currentTNode);
|
|
28083
|
-
}
|
|
28075
|
+
elementEndFirstCreatePass(tView, tNode);
|
|
28084
28076
|
}
|
|
28085
28077
|
if (tNode.classesWithoutHost != null && hasClassInput(tNode)) {
|
|
28086
28078
|
setDirectiveInputsWhichShadowsStyling(tView, tNode, getLView(), tNode.classesWithoutHost, true);
|
|
@@ -28108,7 +28100,7 @@ function ɵɵelement(index, name, attrsIndex, localRefsIndex) {
|
|
|
28108
28100
|
}
|
|
28109
28101
|
let _locateOrCreateElementNode = (tView, lView, tNode, renderer, name, index) => {
|
|
28110
28102
|
lastNodeWasCreated(true);
|
|
28111
|
-
return createElementNode(renderer, name, getNamespace
|
|
28103
|
+
return createElementNode(renderer, name, getNamespace());
|
|
28112
28104
|
};
|
|
28113
28105
|
/**
|
|
28114
28106
|
* Enables hydration code path (to lookup existing elements in DOM)
|
|
@@ -28123,7 +28115,7 @@ function locateOrCreateElementNodeImpl(tView, lView, tNode, renderer, name, inde
|
|
|
28123
28115
|
lastNodeWasCreated(isNodeCreationMode);
|
|
28124
28116
|
// Regular creation mode.
|
|
28125
28117
|
if (isNodeCreationMode) {
|
|
28126
|
-
return createElementNode(renderer, name, getNamespace
|
|
28118
|
+
return createElementNode(renderer, name, getNamespace());
|
|
28127
28119
|
}
|
|
28128
28120
|
// Hydration mode, looking up an existing element in DOM.
|
|
28129
28121
|
const native = locateNextRNode(hydrationInfo, tView, lView, tNode);
|
|
@@ -28176,7 +28168,11 @@ function elementContainerStartFirstCreatePass(index, tView, lView, attrsIndex, l
|
|
|
28176
28168
|
computeStaticStyling(tNode, attrs, true);
|
|
28177
28169
|
}
|
|
28178
28170
|
const localRefs = getConstant(tViewConsts, localRefsIndex);
|
|
28179
|
-
|
|
28171
|
+
if (getBindingsEnabled()) {
|
|
28172
|
+
resolveDirectives(tView, lView, tNode, localRefs, findDirectiveDefMatches);
|
|
28173
|
+
}
|
|
28174
|
+
// Merge the template attrs last so that they have the highest priority.
|
|
28175
|
+
tNode.mergedAttrs = mergeHostAttrs(tNode.mergedAttrs, tNode.attrs);
|
|
28180
28176
|
if (tView.queries !== null) {
|
|
28181
28177
|
tView.queries.elementStart(tView, tNode);
|
|
28182
28178
|
}
|
|
@@ -34929,7 +34925,7 @@ class Version {
|
|
|
34929
34925
|
/**
|
|
34930
34926
|
* @publicApi
|
|
34931
34927
|
*/
|
|
34932
|
-
const VERSION = new Version('19.2.0-next.
|
|
34928
|
+
const VERSION = new Version('19.2.0-next.2');
|
|
34933
34929
|
|
|
34934
34930
|
/**
|
|
34935
34931
|
* Combination of NgModuleFactory and ComponentFactories.
|
|
@@ -36078,6 +36074,24 @@ function moduleDoBootstrap(moduleRef, allPlatformModules) {
|
|
|
36078
36074
|
}
|
|
36079
36075
|
allPlatformModules.push(moduleRef);
|
|
36080
36076
|
}
|
|
36077
|
+
function _callAndReportToErrorHandler(errorHandler, ngZone, callback) {
|
|
36078
|
+
try {
|
|
36079
|
+
const result = callback();
|
|
36080
|
+
if (isPromise(result)) {
|
|
36081
|
+
return result.catch((e) => {
|
|
36082
|
+
ngZone.runOutsideAngular(() => errorHandler.handleError(e));
|
|
36083
|
+
// rethrow as the exception handler might not do it
|
|
36084
|
+
throw e;
|
|
36085
|
+
});
|
|
36086
|
+
}
|
|
36087
|
+
return result;
|
|
36088
|
+
}
|
|
36089
|
+
catch (e) {
|
|
36090
|
+
ngZone.runOutsideAngular(() => errorHandler.handleError(e));
|
|
36091
|
+
// rethrow as the exception handler might not do it
|
|
36092
|
+
throw e;
|
|
36093
|
+
}
|
|
36094
|
+
}
|
|
36081
36095
|
|
|
36082
36096
|
/**
|
|
36083
36097
|
* The Angular platform is the entry point for Angular on a web page.
|
|
@@ -41136,16 +41150,16 @@ class ResourceImpl extends BaseWritableResource {
|
|
|
41136
41150
|
loaderFn;
|
|
41137
41151
|
defaultValue;
|
|
41138
41152
|
equal;
|
|
41153
|
+
pendingTasks;
|
|
41139
41154
|
/**
|
|
41140
41155
|
* The current state of the resource. Status, value, and error are derived from this.
|
|
41141
41156
|
*/
|
|
41142
41157
|
state;
|
|
41143
41158
|
/**
|
|
41144
|
-
*
|
|
41145
|
-
*
|
|
41159
|
+
* Combines the current request with a reload counter which allows the resource to be reloaded on
|
|
41160
|
+
* imperative command.
|
|
41146
41161
|
*/
|
|
41147
|
-
|
|
41148
|
-
pendingTasks;
|
|
41162
|
+
extRequest;
|
|
41149
41163
|
effectRef;
|
|
41150
41164
|
pendingController;
|
|
41151
41165
|
resolvePendingTask = undefined;
|
|
@@ -41155,56 +41169,55 @@ class ResourceImpl extends BaseWritableResource {
|
|
|
41155
41169
|
// Feed a computed signal for the value to `BaseWritableResource`, which will upgrade it to a
|
|
41156
41170
|
// `WritableSignal` that delegates to `ResourceImpl.set`.
|
|
41157
41171
|
computed(() => {
|
|
41158
|
-
const
|
|
41159
|
-
return
|
|
41172
|
+
const streamValue = this.state().stream?.();
|
|
41173
|
+
return streamValue && isResolved(streamValue) ? streamValue.value : this.defaultValue;
|
|
41160
41174
|
}, { equal }));
|
|
41161
41175
|
this.loaderFn = loaderFn;
|
|
41162
41176
|
this.defaultValue = defaultValue;
|
|
41163
41177
|
this.equal = equal;
|
|
41164
|
-
this.pendingTasks = injector.get(PendingTasks);
|
|
41165
41178
|
// Extend `request()` to include a writable reload signal.
|
|
41166
|
-
this.
|
|
41167
|
-
|
|
41168
|
-
reload:
|
|
41169
|
-
})
|
|
41179
|
+
this.extRequest = linkedSignal({
|
|
41180
|
+
source: request,
|
|
41181
|
+
computation: (request) => ({ request, reload: 0 }),
|
|
41182
|
+
});
|
|
41170
41183
|
// The main resource state is managed in a `linkedSignal`, which allows the resource to change
|
|
41171
41184
|
// state instantaneously when the request signal changes.
|
|
41172
41185
|
this.state = linkedSignal({
|
|
41173
|
-
//
|
|
41174
|
-
|
|
41175
|
-
//
|
|
41176
|
-
|
|
41177
|
-
|
|
41178
|
-
|
|
41179
|
-
|
|
41180
|
-
|
|
41186
|
+
// Whenever the request changes,
|
|
41187
|
+
source: this.extRequest,
|
|
41188
|
+
// Compute the state of the resource given a change in status.
|
|
41189
|
+
computation: (extRequest, previous) => {
|
|
41190
|
+
const status = extRequest.request === undefined ? ResourceStatus.Idle : ResourceStatus.Loading;
|
|
41191
|
+
if (!previous) {
|
|
41192
|
+
return {
|
|
41193
|
+
extRequest,
|
|
41194
|
+
status,
|
|
41195
|
+
previousStatus: ResourceStatus.Idle,
|
|
41196
|
+
stream: undefined,
|
|
41197
|
+
};
|
|
41198
|
+
}
|
|
41199
|
+
else {
|
|
41200
|
+
return {
|
|
41201
|
+
extRequest,
|
|
41202
|
+
status,
|
|
41203
|
+
previousStatus: projectStatusOfState(previous.value),
|
|
41204
|
+
// If the request hasn't changed, keep the previous stream.
|
|
41205
|
+
stream: previous.value.extRequest.request === extRequest.request
|
|
41206
|
+
? previous.value.stream
|
|
41207
|
+
: undefined,
|
|
41208
|
+
};
|
|
41181
41209
|
}
|
|
41182
|
-
return reload() === 0 ? ResourceStatus.Loading : ResourceStatus.Reloading;
|
|
41183
41210
|
},
|
|
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
41211
|
});
|
|
41195
41212
|
this.effectRef = effect(this.loadEffect.bind(this), {
|
|
41196
41213
|
injector,
|
|
41197
41214
|
manualCleanup: true,
|
|
41198
41215
|
});
|
|
41216
|
+
this.pendingTasks = injector.get(PendingTasks);
|
|
41199
41217
|
// Cancel any pending request when the resource itself is destroyed.
|
|
41200
41218
|
injector.get(DestroyRef).onDestroy(() => this.destroy());
|
|
41201
41219
|
}
|
|
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
|
-
});
|
|
41220
|
+
status = computed(() => projectStatusOfState(this.state()));
|
|
41208
41221
|
error = computed(() => {
|
|
41209
41222
|
const stream = this.state().stream?.();
|
|
41210
41223
|
return stream && !isResolved(stream) ? stream.error : undefined;
|
|
@@ -41217,12 +41230,14 @@ class ResourceImpl extends BaseWritableResource {
|
|
|
41217
41230
|
return;
|
|
41218
41231
|
}
|
|
41219
41232
|
const current = untracked(this.value);
|
|
41220
|
-
|
|
41233
|
+
const state = untracked(this.state);
|
|
41234
|
+
if (state.status === ResourceStatus.Local &&
|
|
41221
41235
|
(this.equal ? this.equal(current, value) : current === value)) {
|
|
41222
41236
|
return;
|
|
41223
41237
|
}
|
|
41224
41238
|
// Enter Local state with the user-defined value.
|
|
41225
41239
|
this.state.set({
|
|
41240
|
+
extRequest: state.extRequest,
|
|
41226
41241
|
status: ResourceStatus.Local,
|
|
41227
41242
|
previousStatus: ResourceStatus.Local,
|
|
41228
41243
|
stream: signal({ value }),
|
|
@@ -41233,14 +41248,12 @@ class ResourceImpl extends BaseWritableResource {
|
|
|
41233
41248
|
}
|
|
41234
41249
|
reload() {
|
|
41235
41250
|
// We don't want to restart in-progress loads.
|
|
41236
|
-
const status = untracked(this.
|
|
41237
|
-
if (status === ResourceStatus.Idle ||
|
|
41238
|
-
status === ResourceStatus.Loading ||
|
|
41239
|
-
status === ResourceStatus.Reloading) {
|
|
41251
|
+
const { status } = untracked(this.state);
|
|
41252
|
+
if (status === ResourceStatus.Idle || status === ResourceStatus.Loading) {
|
|
41240
41253
|
return false;
|
|
41241
41254
|
}
|
|
41242
|
-
// Increment the reload
|
|
41243
|
-
|
|
41255
|
+
// Increment the request reload to trigger the `state` linked signal to switch us to `Reload`
|
|
41256
|
+
this.extRequest.update(({ request, reload }) => ({ request, reload: reload + 1 }));
|
|
41244
41257
|
return true;
|
|
41245
41258
|
}
|
|
41246
41259
|
destroy() {
|
|
@@ -41249,28 +41262,23 @@ class ResourceImpl extends BaseWritableResource {
|
|
|
41249
41262
|
this.abortInProgressLoad();
|
|
41250
41263
|
// Destroyed resources enter Idle state.
|
|
41251
41264
|
this.state.set({
|
|
41265
|
+
extRequest: { request: undefined, reload: 0 },
|
|
41252
41266
|
status: ResourceStatus.Idle,
|
|
41253
41267
|
previousStatus: ResourceStatus.Idle,
|
|
41254
41268
|
stream: undefined,
|
|
41255
41269
|
});
|
|
41256
41270
|
}
|
|
41257
41271
|
async loadEffect() {
|
|
41272
|
+
const extRequest = this.extRequest();
|
|
41258
41273
|
// Capture the previous status before any state transitions. Note that this is `untracked` since
|
|
41259
41274
|
// we do not want the effect to depend on the state of the resource, only on the request.
|
|
41260
41275
|
const { status: currentStatus, previousStatus } = untracked(this.state);
|
|
41261
|
-
|
|
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) {
|
|
41276
|
+
if (extRequest.request === undefined) {
|
|
41266
41277
|
// Nothing to load (and we should already be in a non-loading state).
|
|
41267
41278
|
return;
|
|
41268
41279
|
}
|
|
41269
|
-
else if (currentStatus !== ResourceStatus.Loading
|
|
41270
|
-
|
|
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.
|
|
41280
|
+
else if (currentStatus !== ResourceStatus.Loading) {
|
|
41281
|
+
// We're not in a loading or reloading state, so this loading request is stale.
|
|
41274
41282
|
return;
|
|
41275
41283
|
}
|
|
41276
41284
|
// Cancel any previous loading attempts.
|
|
@@ -41293,27 +41301,31 @@ class ResourceImpl extends BaseWritableResource {
|
|
|
41293
41301
|
// which side of the `await` they are.
|
|
41294
41302
|
const stream = await untracked(() => {
|
|
41295
41303
|
return this.loaderFn({
|
|
41296
|
-
request: request,
|
|
41304
|
+
request: extRequest.request,
|
|
41297
41305
|
abortSignal,
|
|
41298
41306
|
previous: {
|
|
41299
41307
|
status: previousStatus,
|
|
41300
41308
|
},
|
|
41301
41309
|
});
|
|
41302
41310
|
});
|
|
41303
|
-
|
|
41311
|
+
// If this request has been aborted, or the current request no longer
|
|
41312
|
+
// matches this load, then we should ignore this resolution.
|
|
41313
|
+
if (abortSignal.aborted || untracked(this.extRequest) !== extRequest) {
|
|
41304
41314
|
return;
|
|
41305
41315
|
}
|
|
41306
41316
|
this.state.set({
|
|
41317
|
+
extRequest,
|
|
41307
41318
|
status: ResourceStatus.Resolved,
|
|
41308
41319
|
previousStatus: ResourceStatus.Resolved,
|
|
41309
41320
|
stream,
|
|
41310
41321
|
});
|
|
41311
41322
|
}
|
|
41312
41323
|
catch (err) {
|
|
41313
|
-
if (abortSignal.aborted) {
|
|
41324
|
+
if (abortSignal.aborted || untracked(this.extRequest) !== extRequest) {
|
|
41314
41325
|
return;
|
|
41315
41326
|
}
|
|
41316
41327
|
this.state.set({
|
|
41328
|
+
extRequest,
|
|
41317
41329
|
status: ResourceStatus.Resolved,
|
|
41318
41330
|
previousStatus: ResourceStatus.Error,
|
|
41319
41331
|
stream: signal({ error: err }),
|
|
@@ -41355,10 +41367,13 @@ function getLoader(options) {
|
|
|
41355
41367
|
function isStreamingResourceOptions(options) {
|
|
41356
41368
|
return !!options.stream;
|
|
41357
41369
|
}
|
|
41358
|
-
|
|
41359
|
-
|
|
41360
|
-
|
|
41361
|
-
|
|
41370
|
+
/**
|
|
41371
|
+
* Project from a state with `ResourceInternalStatus` to the user-facing `ResourceStatus`
|
|
41372
|
+
*/
|
|
41373
|
+
function projectStatusOfState(state) {
|
|
41374
|
+
switch (state.status) {
|
|
41375
|
+
case ResourceStatus.Loading:
|
|
41376
|
+
return state.extRequest.reload === 0 ? ResourceStatus.Loading : ResourceStatus.Reloading;
|
|
41362
41377
|
case ResourceStatus.Resolved:
|
|
41363
41378
|
return isResolved(untracked(state.stream)) ? ResourceStatus.Resolved : ResourceStatus.Error;
|
|
41364
41379
|
default:
|