@angular/core 20.0.0-next.7 → 20.0.0-next.9
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/{api.d-KjtSQajV.d.ts → api.d-B58KU5QT.d.ts} +25 -40
- package/chrome_dev_tools_performance.d-qv7drdAl.d.ts +1 -1
- package/{discovery.d-D6xf1HH-.d.ts → discovery.d-BCmtv8-u.d.ts} +21 -7
- package/event_dispatcher.d-DlbccpYq.d.ts +1 -1
- package/fesm2022/attribute-BWp59EjE.mjs +1 -1
- package/fesm2022/core.mjs +60 -159
- package/fesm2022/core.mjs.map +1 -1
- package/fesm2022/{debug_node-B3CixwNH.mjs → debug_node-sP8Ihhla.mjs} +191 -56
- package/fesm2022/debug_node-sP8Ihhla.mjs.map +1 -0
- package/fesm2022/primitives/di.mjs +1 -1
- package/fesm2022/primitives/event-dispatch.mjs +1 -1
- package/fesm2022/primitives/signals.mjs +4 -4
- package/fesm2022/{resource-DtpS_sTw.mjs → resource-aJC_NNLX.mjs} +29 -76
- package/fesm2022/resource-aJC_NNLX.mjs.map +1 -0
- package/fesm2022/{root_effect_scheduler-BK3l7wIO.mjs → root_effect_scheduler-C95A9imp.mjs} +25 -10
- package/fesm2022/root_effect_scheduler-C95A9imp.mjs.map +1 -0
- package/fesm2022/rxjs-interop.mjs +12 -7
- package/fesm2022/rxjs-interop.mjs.map +1 -1
- package/fesm2022/{signal-B6pMq7KS.mjs → signal-CVVPheSN.mjs} +13 -3
- package/fesm2022/{signal-B6pMq7KS.mjs.map → signal-CVVPheSN.mjs.map} +1 -1
- package/fesm2022/testing.mjs +40 -21
- package/fesm2022/testing.mjs.map +1 -1
- package/fesm2022/{untracked-Bz5WMeU1.mjs → untracked-BLZYODu2.mjs} +3 -3
- package/fesm2022/{untracked-Bz5WMeU1.mjs.map → untracked-BLZYODu2.mjs.map} +1 -1
- package/fesm2022/weak_ref-BaIq-pgY.mjs +1 -1
- package/graph.d-BcIOep_B.d.ts +1 -1
- package/index.d.ts +190 -127
- package/package.json +2 -2
- package/primitives/di/index.d.ts +1 -1
- package/primitives/event-dispatch/index.d.ts +1 -1
- package/primitives/signals/index.d.ts +3 -3
- package/rxjs-interop/index.d.ts +4 -4
- package/schematics/bundles/{apply_import_manager-DczRKpTm.js → apply_import_manager-CxaTw_Wy.js} +3 -3
- package/schematics/bundles/{change_tracker-CWLh-wes.js → change_tracker-CkPYZ_km.js} +3 -3
- package/schematics/bundles/{checker-_f5wM7PH.js → checker-Crz1jSZM.js} +389 -122
- package/schematics/bundles/cleanup-unused-imports.js +6 -6
- package/schematics/bundles/{compiler-BaCbbux6.js → compiler-B4MK7BP9.js} +193 -88
- package/schematics/bundles/compiler_host-CAfDJO3W.js +1 -1
- package/schematics/bundles/control-flow-migration.js +2 -2
- package/schematics/bundles/document-core.js +6 -6
- package/schematics/bundles/imports-CIX-JgAN.js +1 -1
- package/schematics/bundles/{index--W6S49uu.js → index-BbZ6cSR1.js} +6 -5
- package/schematics/bundles/{index-rsJ8I_hu.js → index-Bk_3geTg.js} +463 -327
- package/schematics/bundles/inject-flags.js +6 -6
- package/schematics/bundles/inject-migration.js +14 -11
- package/schematics/bundles/leading_space-D9nQ8UQC.js +1 -1
- package/schematics/bundles/{migrate_ts_type_references-C4D_SzJk.js → migrate_ts_type_references-D6T3FlkH.js} +7 -6
- package/schematics/bundles/ng_decorators-DznZ5jMl.js +1 -1
- package/schematics/bundles/nodes-B16H9JUd.js +1 -1
- package/schematics/bundles/output-migration.js +7 -7
- package/schematics/bundles/{project_paths-Ce0O2u-M.js → project_paths-CQ4-VKlW.js} +4 -4
- package/schematics/bundles/project_tsconfig_paths-CDVxT6Ov.js +1 -1
- package/schematics/bundles/property_name-BBwFuqMe.js +1 -1
- package/schematics/bundles/route-lazy-loading.js +4 -4
- package/schematics/bundles/self-closing-tags-migration.js +5 -5
- package/schematics/bundles/signal-input-migration.js +8 -8
- package/schematics/bundles/signal-queries-migration.js +8 -8
- package/schematics/bundles/signals.js +8 -8
- package/schematics/bundles/standalone-migration.js +5 -5
- package/schematics/bundles/symbol-VPWguRxr.js +1 -1
- package/schematics/bundles/test-bed-get.js +5 -5
- package/{signal.d-E0e5nW1p.d.ts → signal.d-D6VJ67xi.d.ts} +8 -2
- package/testing/index.d.ts +12 -9
- package/weak_ref.d-eGOEP9S1.d.ts +1 -1
- package/fesm2022/debug_node-B3CixwNH.mjs.map +0 -1
- package/fesm2022/resource-DtpS_sTw.mjs.map +0 -1
- package/fesm2022/root_effect_scheduler-BK3l7wIO.mjs.map +0 -1
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
/**
|
|
3
|
-
* @license Angular v20.0.0-next.
|
|
3
|
+
* @license Angular v20.0.0-next.9
|
|
4
4
|
* (c) 2010-2025 Google LLC. https://angular.io/
|
|
5
5
|
* License: MIT
|
|
6
6
|
*/
|
|
7
7
|
'use strict';
|
|
8
8
|
|
|
9
|
-
var compiler = require('./compiler-
|
|
9
|
+
var compiler = require('./compiler-B4MK7BP9.js');
|
|
10
10
|
var ts = require('typescript');
|
|
11
11
|
var p = require('path');
|
|
12
|
-
var checker = require('./checker-
|
|
12
|
+
var checker = require('./checker-Crz1jSZM.js');
|
|
13
13
|
require('os');
|
|
14
14
|
|
|
15
15
|
function _interopNamespaceDefault(e) {
|
|
@@ -892,7 +892,7 @@ const MINIMUM_PARTIAL_LINKER_DEFER_SUPPORT_VERSION = '18.0.0';
|
|
|
892
892
|
function compileDeclareClassMetadata(metadata) {
|
|
893
893
|
const definitionMap = new compiler.DefinitionMap();
|
|
894
894
|
definitionMap.set('minVersion', compiler.literal(MINIMUM_PARTIAL_LINKER_VERSION$5));
|
|
895
|
-
definitionMap.set('version', compiler.literal('20.0.0-next.
|
|
895
|
+
definitionMap.set('version', compiler.literal('20.0.0-next.9'));
|
|
896
896
|
definitionMap.set('ngImport', compiler.importExpr(compiler.Identifiers.core));
|
|
897
897
|
definitionMap.set('type', metadata.type);
|
|
898
898
|
definitionMap.set('decorators', metadata.decorators);
|
|
@@ -910,7 +910,7 @@ function compileComponentDeclareClassMetadata(metadata, dependencies) {
|
|
|
910
910
|
callbackReturnDefinitionMap.set('ctorParameters', metadata.ctorParameters ?? compiler.literal(null));
|
|
911
911
|
callbackReturnDefinitionMap.set('propDecorators', metadata.propDecorators ?? compiler.literal(null));
|
|
912
912
|
definitionMap.set('minVersion', compiler.literal(MINIMUM_PARTIAL_LINKER_DEFER_SUPPORT_VERSION));
|
|
913
|
-
definitionMap.set('version', compiler.literal('20.0.0-next.
|
|
913
|
+
definitionMap.set('version', compiler.literal('20.0.0-next.9'));
|
|
914
914
|
definitionMap.set('ngImport', compiler.importExpr(compiler.Identifiers.core));
|
|
915
915
|
definitionMap.set('type', metadata.type);
|
|
916
916
|
definitionMap.set('resolveDeferredDeps', compileComponentMetadataAsyncResolver(dependencies));
|
|
@@ -1005,7 +1005,7 @@ function createDirectiveDefinitionMap(meta) {
|
|
|
1005
1005
|
const definitionMap = new compiler.DefinitionMap();
|
|
1006
1006
|
const minVersion = getMinimumVersionForPartialOutput(meta);
|
|
1007
1007
|
definitionMap.set('minVersion', compiler.literal(minVersion));
|
|
1008
|
-
definitionMap.set('version', compiler.literal('20.0.0-next.
|
|
1008
|
+
definitionMap.set('version', compiler.literal('20.0.0-next.9'));
|
|
1009
1009
|
// e.g. `type: MyDirective`
|
|
1010
1010
|
definitionMap.set('type', meta.type.value);
|
|
1011
1011
|
if (meta.isStandalone !== undefined) {
|
|
@@ -1421,7 +1421,7 @@ const MINIMUM_PARTIAL_LINKER_VERSION$4 = '12.0.0';
|
|
|
1421
1421
|
function compileDeclareFactoryFunction(meta) {
|
|
1422
1422
|
const definitionMap = new compiler.DefinitionMap();
|
|
1423
1423
|
definitionMap.set('minVersion', compiler.literal(MINIMUM_PARTIAL_LINKER_VERSION$4));
|
|
1424
|
-
definitionMap.set('version', compiler.literal('20.0.0-next.
|
|
1424
|
+
definitionMap.set('version', compiler.literal('20.0.0-next.9'));
|
|
1425
1425
|
definitionMap.set('ngImport', compiler.importExpr(compiler.Identifiers.core));
|
|
1426
1426
|
definitionMap.set('type', meta.type.value);
|
|
1427
1427
|
definitionMap.set('deps', compileDependencies(meta.deps));
|
|
@@ -1456,7 +1456,7 @@ function compileDeclareInjectableFromMetadata(meta) {
|
|
|
1456
1456
|
function createInjectableDefinitionMap(meta) {
|
|
1457
1457
|
const definitionMap = new compiler.DefinitionMap();
|
|
1458
1458
|
definitionMap.set('minVersion', compiler.literal(MINIMUM_PARTIAL_LINKER_VERSION$3));
|
|
1459
|
-
definitionMap.set('version', compiler.literal('20.0.0-next.
|
|
1459
|
+
definitionMap.set('version', compiler.literal('20.0.0-next.9'));
|
|
1460
1460
|
definitionMap.set('ngImport', compiler.importExpr(compiler.Identifiers.core));
|
|
1461
1461
|
definitionMap.set('type', meta.type.value);
|
|
1462
1462
|
// Only generate providedIn property if it has a non-null value
|
|
@@ -1507,7 +1507,7 @@ function compileDeclareInjectorFromMetadata(meta) {
|
|
|
1507
1507
|
function createInjectorDefinitionMap(meta) {
|
|
1508
1508
|
const definitionMap = new compiler.DefinitionMap();
|
|
1509
1509
|
definitionMap.set('minVersion', compiler.literal(MINIMUM_PARTIAL_LINKER_VERSION$2));
|
|
1510
|
-
definitionMap.set('version', compiler.literal('20.0.0-next.
|
|
1510
|
+
definitionMap.set('version', compiler.literal('20.0.0-next.9'));
|
|
1511
1511
|
definitionMap.set('ngImport', compiler.importExpr(compiler.Identifiers.core));
|
|
1512
1512
|
definitionMap.set('type', meta.type.value);
|
|
1513
1513
|
definitionMap.set('providers', meta.providers);
|
|
@@ -1540,7 +1540,7 @@ function createNgModuleDefinitionMap(meta) {
|
|
|
1540
1540
|
throw new Error('Invalid path! Local compilation mode should not get into the partial compilation path');
|
|
1541
1541
|
}
|
|
1542
1542
|
definitionMap.set('minVersion', compiler.literal(MINIMUM_PARTIAL_LINKER_VERSION$1));
|
|
1543
|
-
definitionMap.set('version', compiler.literal('20.0.0-next.
|
|
1543
|
+
definitionMap.set('version', compiler.literal('20.0.0-next.9'));
|
|
1544
1544
|
definitionMap.set('ngImport', compiler.importExpr(compiler.Identifiers.core));
|
|
1545
1545
|
definitionMap.set('type', meta.type.value);
|
|
1546
1546
|
// We only generate the keys in the metadata if the arrays contain values.
|
|
@@ -1591,7 +1591,7 @@ function compileDeclarePipeFromMetadata(meta) {
|
|
|
1591
1591
|
function createPipeDefinitionMap(meta) {
|
|
1592
1592
|
const definitionMap = new compiler.DefinitionMap();
|
|
1593
1593
|
definitionMap.set('minVersion', compiler.literal(MINIMUM_PARTIAL_LINKER_VERSION));
|
|
1594
|
-
definitionMap.set('version', compiler.literal('20.0.0-next.
|
|
1594
|
+
definitionMap.set('version', compiler.literal('20.0.0-next.9'));
|
|
1595
1595
|
definitionMap.set('ngImport', compiler.importExpr(compiler.Identifiers.core));
|
|
1596
1596
|
// e.g. `type: MyPipe`
|
|
1597
1597
|
definitionMap.set('type', meta.type.value);
|
|
@@ -2582,6 +2582,7 @@ class DtsMetadataReader {
|
|
|
2582
2582
|
name,
|
|
2583
2583
|
nameExpr: null,
|
|
2584
2584
|
isStandalone,
|
|
2585
|
+
isPure: null, // The DTS has no idea about that
|
|
2585
2586
|
decorator: null,
|
|
2586
2587
|
isExplicitlyDeferred: false,
|
|
2587
2588
|
};
|
|
@@ -7916,6 +7917,7 @@ function parseExtractedTemplate(template, sourceStr, sourceParseRange, escapedSt
|
|
|
7916
7917
|
escapedString,
|
|
7917
7918
|
enableBlockSyntax: options.enableBlockSyntax,
|
|
7918
7919
|
enableLetSyntax: options.enableLetSyntax,
|
|
7920
|
+
enableSelectorless: options.enableSelectorless,
|
|
7919
7921
|
};
|
|
7920
7922
|
const parsedTemplate = compiler.parseTemplate(sourceStr, sourceMapUrl ?? '', {
|
|
7921
7923
|
...commonParseOptions,
|
|
@@ -8879,7 +8881,8 @@ class ComponentDecoratorHandler {
|
|
|
8879
8881
|
enableHmr;
|
|
8880
8882
|
implicitStandaloneValue;
|
|
8881
8883
|
typeCheckHostBindings;
|
|
8882
|
-
|
|
8884
|
+
enableSelectorless;
|
|
8885
|
+
constructor(reflector, evaluator, metaRegistry, metaReader, scopeReader, compilerHost, scopeRegistry, typeCheckScopeRegistry, resourceRegistry, isCore, strictCtorDeps, resourceLoader, rootDirs, defaultPreserveWhitespaces, i18nUseExternalIds, enableI18nLegacyMessageIdFormat, usePoisonedData, i18nNormalizeLineEndingsInICUs, moduleResolver, cycleAnalyzer, cycleHandlingStrategy, refEmitter, referencesRegistry, depTracker, injectableRegistry, semanticDepGraphUpdater, annotateForClosureCompiler, perf, hostDirectivesResolver, importTracker, includeClassMetadata, compilationMode, deferredSymbolTracker, forbidOrphanRendering, enableBlockSyntax, enableLetSyntax, externalRuntimeStyles, localCompilationExtraImportsTracker, jitDeclarationRegistry, i18nPreserveSignificantWhitespace, strictStandalone, enableHmr, implicitStandaloneValue, typeCheckHostBindings, enableSelectorless) {
|
|
8883
8886
|
this.reflector = reflector;
|
|
8884
8887
|
this.evaluator = evaluator;
|
|
8885
8888
|
this.metaRegistry = metaRegistry;
|
|
@@ -8924,12 +8927,14 @@ class ComponentDecoratorHandler {
|
|
|
8924
8927
|
this.enableHmr = enableHmr;
|
|
8925
8928
|
this.implicitStandaloneValue = implicitStandaloneValue;
|
|
8926
8929
|
this.typeCheckHostBindings = typeCheckHostBindings;
|
|
8930
|
+
this.enableSelectorless = enableSelectorless;
|
|
8927
8931
|
this.extractTemplateOptions = {
|
|
8928
8932
|
enableI18nLegacyMessageIdFormat: this.enableI18nLegacyMessageIdFormat,
|
|
8929
8933
|
i18nNormalizeLineEndingsInICUs: this.i18nNormalizeLineEndingsInICUs,
|
|
8930
8934
|
usePoisonedData: this.usePoisonedData,
|
|
8931
8935
|
enableBlockSyntax: this.enableBlockSyntax,
|
|
8932
8936
|
enableLetSyntax: this.enableLetSyntax,
|
|
8937
|
+
enableSelectorless: this.enableSelectorless,
|
|
8933
8938
|
preserveSignificantWhitespace: this.i18nPreserveSignificantWhitespace,
|
|
8934
8939
|
};
|
|
8935
8940
|
// Dependencies can't be deferred during HMR, because the HMR update module can't have
|
|
@@ -9198,6 +9203,7 @@ class ComponentDecoratorHandler {
|
|
|
9198
9203
|
usePoisonedData: this.usePoisonedData,
|
|
9199
9204
|
enableBlockSyntax: this.enableBlockSyntax,
|
|
9200
9205
|
enableLetSyntax: this.enableLetSyntax,
|
|
9206
|
+
enableSelectorless: this.enableSelectorless,
|
|
9201
9207
|
preserveSignificantWhitespace: this.i18nPreserveSignificantWhitespace,
|
|
9202
9208
|
}, this.compilationMode);
|
|
9203
9209
|
if (this.compilationMode === checker.CompilationMode.LOCAL &&
|
|
@@ -9471,6 +9477,7 @@ class ComponentDecoratorHandler {
|
|
|
9471
9477
|
}
|
|
9472
9478
|
}
|
|
9473
9479
|
}
|
|
9480
|
+
// TODO(crisbeto): implement for selectorless.
|
|
9474
9481
|
const binder = new compiler.R3TargetBinder(matcher);
|
|
9475
9482
|
const boundTemplate = binder.bind({ template: analysis.template.diagNodes });
|
|
9476
9483
|
context.addComponent({
|
|
@@ -9493,6 +9500,7 @@ class ComponentDecoratorHandler {
|
|
|
9493
9500
|
// Don't type-check components that had errors in their scopes, unless requested.
|
|
9494
9501
|
return;
|
|
9495
9502
|
}
|
|
9503
|
+
// TODO(crisbeto): implement for selectorless.
|
|
9496
9504
|
const binder = new compiler.R3TargetBinder(scope.matcher);
|
|
9497
9505
|
const templateContext = {
|
|
9498
9506
|
nodes: meta.template.diagNodes,
|
|
@@ -9577,168 +9585,16 @@ class ComponentDecoratorHandler {
|
|
|
9577
9585
|
return {};
|
|
9578
9586
|
}
|
|
9579
9587
|
const scope = this.scopeReader.getScopeForComponent(node);
|
|
9580
|
-
if (scope
|
|
9581
|
-
//
|
|
9582
|
-
//
|
|
9583
|
-
|
|
9584
|
-
|
|
9585
|
-
|
|
9586
|
-
|
|
9587
|
-
|
|
9588
|
-
// module file sets the directives/pipes on the ɵcmp of the component, without
|
|
9589
|
-
// requiring new imports (but also in a way that breaks tree shaking).
|
|
9590
|
-
//
|
|
9591
|
-
// Determining this is challenging, because the TemplateDefinitionBuilder is responsible for
|
|
9592
|
-
// matching directives and pipes in the template; however, that doesn't run until the actual
|
|
9593
|
-
// compile() step. It's not possible to run template compilation sooner as it requires the
|
|
9594
|
-
// ConstantPool for the overall file being compiled (which isn't available until the
|
|
9595
|
-
// transform step).
|
|
9596
|
-
//
|
|
9597
|
-
// Instead, directives/pipes are matched independently here, using the R3TargetBinder. This
|
|
9598
|
-
// is an alternative implementation of template matching which is used for template
|
|
9599
|
-
// type-checking and will eventually replace matching in the TemplateDefinitionBuilder.
|
|
9600
|
-
const isModuleScope = scope.kind === checker.ComponentScopeKind.NgModule;
|
|
9601
|
-
// Dependencies coming from the regular `imports` field.
|
|
9602
|
-
const dependencies = isModuleScope ? scope.compilation.dependencies : scope.dependencies;
|
|
9603
|
-
// Dependencies from the `@Component.deferredImports` field.
|
|
9604
|
-
const explicitlyDeferredDependencies = getExplicitlyDeferredDeps(scope);
|
|
9605
|
-
// Mark the component is an NgModule-based component with its NgModule in a different file
|
|
9606
|
-
// then mark this file for extra import generation
|
|
9607
|
-
if (isModuleScope && context.fileName !== checker.getSourceFile(scope.ngModule).fileName) {
|
|
9608
|
-
this.localCompilationExtraImportsTracker?.markFileForExtraImportGeneration(context);
|
|
9609
|
-
}
|
|
9610
|
-
// Make sure that `@Component.imports` and `@Component.deferredImports` do not have
|
|
9611
|
-
// the same dependencies.
|
|
9612
|
-
if (metadata.isStandalone &&
|
|
9613
|
-
analysis.rawDeferredImports !== null &&
|
|
9614
|
-
explicitlyDeferredDependencies.length > 0) {
|
|
9615
|
-
const diagnostic = validateNoImportOverlap(dependencies, explicitlyDeferredDependencies, analysis.rawDeferredImports);
|
|
9616
|
-
if (diagnostic !== null) {
|
|
9617
|
-
diagnostics.push(diagnostic);
|
|
9618
|
-
}
|
|
9619
|
-
}
|
|
9620
|
-
// Set up the R3TargetBinder.
|
|
9621
|
-
const binder = createTargetBinder(dependencies);
|
|
9622
|
-
let allDependencies = dependencies;
|
|
9623
|
-
let deferBlockBinder = binder;
|
|
9624
|
-
// If there are any explicitly deferred dependencies (via `@Component.deferredImports`),
|
|
9625
|
-
// re-compute the list of dependencies and create a new binder for defer blocks. This
|
|
9626
|
-
// is because we have deferred dependencies that are not in the standard imports list
|
|
9627
|
-
// and need to be referenced later when determining what dependencies need to be in a
|
|
9628
|
-
// defer function / instruction call. Otherwise they end up treated as a standard
|
|
9629
|
-
// import, which is wrong.
|
|
9630
|
-
if (explicitlyDeferredDependencies.length > 0) {
|
|
9631
|
-
allDependencies = [...explicitlyDeferredDependencies, ...dependencies];
|
|
9632
|
-
deferBlockBinder = createTargetBinder(allDependencies);
|
|
9633
|
-
}
|
|
9634
|
-
// Set up the pipes map that is later used to determine which dependencies are used in
|
|
9635
|
-
// the template.
|
|
9636
|
-
const pipes = extractPipes(allDependencies);
|
|
9637
|
-
// Next, the component template AST is bound using the R3TargetBinder. This produces a
|
|
9638
|
-
// BoundTarget, which is similar to a ts.TypeChecker.
|
|
9639
|
-
const bound = binder.bind({ template: metadata.template.nodes });
|
|
9640
|
-
// Find all defer blocks used in the template and for each block
|
|
9641
|
-
// bind its own scope.
|
|
9642
|
-
const deferBlocks = new Map();
|
|
9643
|
-
for (const deferBlock of bound.getDeferBlocks()) {
|
|
9644
|
-
deferBlocks.set(deferBlock, deferBlockBinder.bind({ template: deferBlock.children }));
|
|
9645
|
-
}
|
|
9646
|
-
// Register all Directives and Pipes used at the top level (outside
|
|
9647
|
-
// of any defer blocks), which would be eagerly referenced.
|
|
9648
|
-
const eagerlyUsed = new Set();
|
|
9649
|
-
if (this.enableHmr) {
|
|
9650
|
-
// In HMR we need to preserve all the dependencies, because they have to remain consistent
|
|
9651
|
-
// with the initially-generated code no matter what the template looks like.
|
|
9652
|
-
for (const dep of dependencies) {
|
|
9653
|
-
if (dep.ref.node !== node) {
|
|
9654
|
-
eagerlyUsed.add(dep.ref.node);
|
|
9655
|
-
}
|
|
9656
|
-
else {
|
|
9657
|
-
const used = bound.getEagerlyUsedDirectives();
|
|
9658
|
-
if (used.some((current) => current.ref.node === node)) {
|
|
9659
|
-
eagerlyUsed.add(node);
|
|
9660
|
-
}
|
|
9661
|
-
}
|
|
9662
|
-
}
|
|
9663
|
-
}
|
|
9664
|
-
else {
|
|
9665
|
-
for (const dir of bound.getEagerlyUsedDirectives()) {
|
|
9666
|
-
eagerlyUsed.add(dir.ref.node);
|
|
9667
|
-
}
|
|
9668
|
-
for (const name of bound.getEagerlyUsedPipes()) {
|
|
9669
|
-
if (!pipes.has(name)) {
|
|
9670
|
-
continue;
|
|
9671
|
-
}
|
|
9672
|
-
eagerlyUsed.add(pipes.get(name).ref.node);
|
|
9673
|
-
}
|
|
9674
|
-
}
|
|
9675
|
-
// Set of Directives and Pipes used across the entire template,
|
|
9676
|
-
// including all defer blocks.
|
|
9677
|
-
const wholeTemplateUsed = new Set(eagerlyUsed);
|
|
9678
|
-
for (const bound of deferBlocks.values()) {
|
|
9679
|
-
for (const dir of bound.getUsedDirectives()) {
|
|
9680
|
-
wholeTemplateUsed.add(dir.ref.node);
|
|
9681
|
-
}
|
|
9682
|
-
for (const name of bound.getUsedPipes()) {
|
|
9683
|
-
if (!pipes.has(name)) {
|
|
9684
|
-
continue;
|
|
9685
|
-
}
|
|
9686
|
-
wholeTemplateUsed.add(pipes.get(name).ref.node);
|
|
9687
|
-
}
|
|
9688
|
-
}
|
|
9689
|
-
const declarations = new Map();
|
|
9690
|
-
// Transform the dependencies list, filtering out unused dependencies.
|
|
9691
|
-
for (const dep of allDependencies) {
|
|
9692
|
-
// Only emit references to each dependency once.
|
|
9693
|
-
if (declarations.has(dep.ref.node)) {
|
|
9694
|
-
continue;
|
|
9695
|
-
}
|
|
9696
|
-
switch (dep.kind) {
|
|
9697
|
-
case checker.MetaKind.Directive:
|
|
9698
|
-
if (!wholeTemplateUsed.has(dep.ref.node) || dep.matchSource !== checker.MatchSource.Selector) {
|
|
9699
|
-
continue;
|
|
9700
|
-
}
|
|
9701
|
-
const dirType = this.refEmitter.emit(dep.ref, context);
|
|
9702
|
-
checker.assertSuccessfulReferenceEmit(dirType, node.name, dep.isComponent ? 'component' : 'directive');
|
|
9703
|
-
declarations.set(dep.ref.node, {
|
|
9704
|
-
kind: compiler.R3TemplateDependencyKind.Directive,
|
|
9705
|
-
ref: dep.ref,
|
|
9706
|
-
type: dirType.expression,
|
|
9707
|
-
importedFile: dirType.importedFile,
|
|
9708
|
-
selector: dep.selector,
|
|
9709
|
-
inputs: dep.inputs.propertyNames,
|
|
9710
|
-
outputs: dep.outputs.propertyNames,
|
|
9711
|
-
exportAs: dep.exportAs,
|
|
9712
|
-
isComponent: dep.isComponent,
|
|
9713
|
-
});
|
|
9714
|
-
break;
|
|
9715
|
-
case checker.MetaKind.Pipe:
|
|
9716
|
-
if (!wholeTemplateUsed.has(dep.ref.node)) {
|
|
9717
|
-
continue;
|
|
9718
|
-
}
|
|
9719
|
-
const pipeType = this.refEmitter.emit(dep.ref, context);
|
|
9720
|
-
checker.assertSuccessfulReferenceEmit(pipeType, node.name, 'pipe');
|
|
9721
|
-
declarations.set(dep.ref.node, {
|
|
9722
|
-
kind: compiler.R3TemplateDependencyKind.Pipe,
|
|
9723
|
-
type: pipeType.expression,
|
|
9724
|
-
name: dep.name,
|
|
9725
|
-
ref: dep.ref,
|
|
9726
|
-
importedFile: pipeType.importedFile,
|
|
9727
|
-
});
|
|
9728
|
-
break;
|
|
9729
|
-
case checker.MetaKind.NgModule:
|
|
9730
|
-
const ngModuleType = this.refEmitter.emit(dep.ref, context);
|
|
9731
|
-
checker.assertSuccessfulReferenceEmit(ngModuleType, node.name, 'NgModule');
|
|
9732
|
-
declarations.set(dep.ref.node, {
|
|
9733
|
-
kind: compiler.R3TemplateDependencyKind.NgModule,
|
|
9734
|
-
type: ngModuleType.expression,
|
|
9735
|
-
importedFile: ngModuleType.importedFile,
|
|
9736
|
-
});
|
|
9737
|
-
break;
|
|
9738
|
-
}
|
|
9739
|
-
}
|
|
9740
|
-
const getSemanticReference = (decl) => this.semanticDepGraphUpdater.getSemanticReference(decl.ref.node, decl.type);
|
|
9588
|
+
if (scope === null) {
|
|
9589
|
+
// If there is no scope, we can still use the binder to retrieve *some* information about the
|
|
9590
|
+
// deferred blocks.
|
|
9591
|
+
data.deferPerBlockDependencies = this.locateDeferBlocksWithoutScope(metadata.template);
|
|
9592
|
+
}
|
|
9593
|
+
else {
|
|
9594
|
+
const { eagerlyUsed, deferBlocks, allDependencies, wholeTemplateUsed } = this.resolveComponentDependencies(node, context, analysis, scope, metadata, diagnostics);
|
|
9595
|
+
const declarations = this.componentDependenciesToDeclarations(node, context, allDependencies, wholeTemplateUsed);
|
|
9741
9596
|
if (this.semanticDepGraphUpdater !== null) {
|
|
9597
|
+
const getSemanticReference = (decl) => this.semanticDepGraphUpdater.getSemanticReference(decl.ref.node, decl.type);
|
|
9742
9598
|
symbol.usedDirectives = Array.from(declarations.values())
|
|
9743
9599
|
.filter(isUsedDirective)
|
|
9744
9600
|
.map(getSemanticReference);
|
|
@@ -9746,142 +9602,17 @@ class ComponentDecoratorHandler {
|
|
|
9746
9602
|
.filter(isUsedPipe)
|
|
9747
9603
|
.map(getSemanticReference);
|
|
9748
9604
|
}
|
|
9749
|
-
const eagerDeclarations = Array.from(declarations.values()).filter((decl) => decl.kind === compiler.R3TemplateDependencyKind.NgModule || eagerlyUsed.has(decl.ref.node));
|
|
9750
9605
|
// Process information related to defer blocks
|
|
9751
9606
|
if (this.compilationMode !== checker.CompilationMode.LOCAL) {
|
|
9752
9607
|
this.resolveDeferBlocks(node, deferBlocks, declarations, data, analysis, eagerlyUsed);
|
|
9753
9608
|
}
|
|
9754
|
-
|
|
9755
|
-
const cyclesFromPipes = new Map();
|
|
9756
|
-
// Scan through the directives/pipes actually used in the template and check whether any
|
|
9757
|
-
// import which needs to be generated would create a cycle. This check is skipped for
|
|
9758
|
-
// standalone components as the dependencies of a standalone component have already been
|
|
9759
|
-
// imported directly by the user, so Angular won't introduce any imports that aren't already
|
|
9760
|
-
// in the user's program.
|
|
9761
|
-
if (!metadata.isStandalone) {
|
|
9762
|
-
for (const usedDep of eagerDeclarations) {
|
|
9763
|
-
const cycle = this._checkForCyclicImport(usedDep.importedFile, usedDep.type, context);
|
|
9764
|
-
if (cycle !== null) {
|
|
9765
|
-
switch (usedDep.kind) {
|
|
9766
|
-
case compiler.R3TemplateDependencyKind.Directive:
|
|
9767
|
-
cyclesFromDirectives.set(usedDep, cycle);
|
|
9768
|
-
break;
|
|
9769
|
-
case compiler.R3TemplateDependencyKind.Pipe:
|
|
9770
|
-
cyclesFromPipes.set(usedDep, cycle);
|
|
9771
|
-
break;
|
|
9772
|
-
}
|
|
9773
|
-
}
|
|
9774
|
-
}
|
|
9775
|
-
}
|
|
9776
|
-
// Check whether any usages of standalone components in imports requires the dependencies
|
|
9777
|
-
// array to be wrapped in a closure. This check is technically a heuristic as there's no
|
|
9778
|
-
// direct way to check whether a `Reference` came from a `forwardRef`. Instead, we check if
|
|
9779
|
-
// the reference is `synthetic`, implying it came from _any_ foreign function resolver,
|
|
9780
|
-
// including the `forwardRef` resolver.
|
|
9781
|
-
const standaloneImportMayBeForwardDeclared = analysis.resolvedImports !== null && analysis.resolvedImports.some((ref) => ref.synthetic);
|
|
9782
|
-
const cycleDetected = cyclesFromDirectives.size !== 0 || cyclesFromPipes.size !== 0;
|
|
9783
|
-
if (!cycleDetected) {
|
|
9784
|
-
// No cycle was detected. Record the imports that need to be created in the cycle detector
|
|
9785
|
-
// so that future cyclic import checks consider their production.
|
|
9786
|
-
for (const { type, importedFile } of eagerDeclarations) {
|
|
9787
|
-
this.maybeRecordSyntheticImport(importedFile, type, context);
|
|
9788
|
-
}
|
|
9789
|
-
// Check whether the dependencies arrays in ɵcmp need to be wrapped in a closure.
|
|
9790
|
-
// This is required if any dependency reference is to a declaration in the same file
|
|
9791
|
-
// but declared after this component.
|
|
9792
|
-
const declarationIsForwardDeclared = eagerDeclarations.some((decl) => checker.isExpressionForwardReference(decl.type, node.name, context));
|
|
9793
|
-
if (this.compilationMode !== checker.CompilationMode.LOCAL &&
|
|
9794
|
-
(declarationIsForwardDeclared || standaloneImportMayBeForwardDeclared)) {
|
|
9795
|
-
data.declarationListEmitMode = 1 /* DeclarationListEmitMode.Closure */;
|
|
9796
|
-
}
|
|
9797
|
-
data.declarations = eagerDeclarations;
|
|
9798
|
-
// Register extra local imports.
|
|
9799
|
-
if (this.compilationMode === checker.CompilationMode.LOCAL &&
|
|
9800
|
-
this.localCompilationExtraImportsTracker !== null) {
|
|
9801
|
-
// In global compilation mode `eagerDeclarations` contains "all" the component
|
|
9802
|
-
// dependencies, whose import statements will be added to the file. In local compilation
|
|
9803
|
-
// mode `eagerDeclarations` only includes the "local" dependencies, meaning those that are
|
|
9804
|
-
// declared inside this compilation unit.Here the import info of these local dependencies
|
|
9805
|
-
// are added to the tracker so that we can generate extra imports representing these local
|
|
9806
|
-
// dependencies. For non-local dependencies we use another technique of adding some
|
|
9807
|
-
// best-guess extra imports globally to all files using
|
|
9808
|
-
// `localCompilationExtraImportsTracker.addGlobalImportFromIdentifier`.
|
|
9809
|
-
for (const { type } of eagerDeclarations) {
|
|
9810
|
-
if (type instanceof compiler.ExternalExpr && type.value.moduleName) {
|
|
9811
|
-
this.localCompilationExtraImportsTracker.addImportForFile(context, type.value.moduleName);
|
|
9812
|
-
}
|
|
9813
|
-
}
|
|
9814
|
-
}
|
|
9815
|
-
}
|
|
9816
|
-
else {
|
|
9817
|
-
if (this.cycleHandlingStrategy === 0 /* CycleHandlingStrategy.UseRemoteScoping */) {
|
|
9818
|
-
// Declaring the directiveDefs/pipeDefs arrays directly would require imports that would
|
|
9819
|
-
// create a cycle. Instead, mark this component as requiring remote scoping, so that the
|
|
9820
|
-
// NgModule file will take care of setting the directives for the component.
|
|
9821
|
-
this.scopeRegistry.setComponentRemoteScope(node, eagerDeclarations.filter(isUsedDirective).map((dir) => dir.ref), eagerDeclarations.filter(isUsedPipe).map((pipe) => pipe.ref));
|
|
9822
|
-
symbol.isRemotelyScoped = true;
|
|
9823
|
-
// If a semantic graph is being tracked, record the fact that this component is remotely
|
|
9824
|
-
// scoped with the declaring NgModule symbol as the NgModule's emit becomes dependent on
|
|
9825
|
-
// the directive/pipe usages of this component.
|
|
9826
|
-
if (this.semanticDepGraphUpdater !== null &&
|
|
9827
|
-
scope.kind === checker.ComponentScopeKind.NgModule &&
|
|
9828
|
-
scope.ngModule !== null) {
|
|
9829
|
-
const moduleSymbol = this.semanticDepGraphUpdater.getSymbol(scope.ngModule);
|
|
9830
|
-
if (!(moduleSymbol instanceof NgModuleSymbol)) {
|
|
9831
|
-
throw new Error(`AssertionError: Expected ${scope.ngModule.name} to be an NgModuleSymbol.`);
|
|
9832
|
-
}
|
|
9833
|
-
moduleSymbol.addRemotelyScopedComponent(symbol, symbol.usedDirectives, symbol.usedPipes);
|
|
9834
|
-
}
|
|
9835
|
-
}
|
|
9836
|
-
else {
|
|
9837
|
-
// We are not able to handle this cycle so throw an error.
|
|
9838
|
-
const relatedMessages = [];
|
|
9839
|
-
for (const [dir, cycle] of cyclesFromDirectives) {
|
|
9840
|
-
relatedMessages.push(makeCyclicImportInfo(dir.ref, dir.isComponent ? 'component' : 'directive', cycle));
|
|
9841
|
-
}
|
|
9842
|
-
for (const [pipe, cycle] of cyclesFromPipes) {
|
|
9843
|
-
relatedMessages.push(makeCyclicImportInfo(pipe.ref, 'pipe', cycle));
|
|
9844
|
-
}
|
|
9845
|
-
throw new checker.FatalDiagnosticError(checker.ErrorCode.IMPORT_CYCLE_DETECTED, node, 'One or more import cycles would need to be created to compile this component, ' +
|
|
9846
|
-
'which is not supported by the current compiler configuration.', relatedMessages);
|
|
9847
|
-
}
|
|
9848
|
-
}
|
|
9849
|
-
}
|
|
9850
|
-
else {
|
|
9851
|
-
// If there is no scope, we can still use the binder to retrieve *some* information about the
|
|
9852
|
-
// deferred blocks.
|
|
9853
|
-
data.deferPerBlockDependencies = this.locateDeferBlocksWithoutScope(metadata.template);
|
|
9609
|
+
this.handleDependencyCycles(node, context, scope, data, analysis, metadata, declarations, eagerlyUsed, symbol);
|
|
9854
9610
|
}
|
|
9855
9611
|
// Run diagnostics only in global mode.
|
|
9856
9612
|
if (this.compilationMode !== checker.CompilationMode.LOCAL) {
|
|
9857
|
-
|
|
9858
|
-
if (
|
|
9859
|
-
|
|
9860
|
-
diagnostics.push(...importDiagnostics);
|
|
9861
|
-
}
|
|
9862
|
-
if (analysis.resolvedDeferredImports !== null && analysis.rawDeferredImports !== null) {
|
|
9863
|
-
const importDiagnostics = validateStandaloneImports(analysis.resolvedDeferredImports, analysis.rawDeferredImports, this.metaReader, this.scopeReader, true /* isDeferredImport */);
|
|
9864
|
-
diagnostics.push(...importDiagnostics);
|
|
9865
|
-
}
|
|
9866
|
-
if (analysis.providersRequiringFactory !== null &&
|
|
9867
|
-
analysis.meta.providers instanceof compiler.WrappedNodeExpr) {
|
|
9868
|
-
const providerDiagnostics = checker.getProviderDiagnostics(analysis.providersRequiringFactory, analysis.meta.providers.node, this.injectableRegistry);
|
|
9869
|
-
diagnostics.push(...providerDiagnostics);
|
|
9870
|
-
}
|
|
9871
|
-
if (analysis.viewProvidersRequiringFactory !== null &&
|
|
9872
|
-
analysis.meta.viewProviders instanceof compiler.WrappedNodeExpr) {
|
|
9873
|
-
const viewProviderDiagnostics = checker.getProviderDiagnostics(analysis.viewProvidersRequiringFactory, analysis.meta.viewProviders.node, this.injectableRegistry);
|
|
9874
|
-
diagnostics.push(...viewProviderDiagnostics);
|
|
9875
|
-
}
|
|
9876
|
-
const directiveDiagnostics = checker.getDirectiveDiagnostics(node, this.injectableRegistry, this.evaluator, this.reflector, this.scopeRegistry, this.strictCtorDeps, 'Component');
|
|
9877
|
-
if (directiveDiagnostics !== null) {
|
|
9878
|
-
diagnostics.push(...directiveDiagnostics);
|
|
9879
|
-
}
|
|
9880
|
-
const hostDirectivesDiagnostics = analysis.hostDirectives && analysis.rawHostDirectives
|
|
9881
|
-
? checker.validateHostDirectives(analysis.rawHostDirectives, analysis.hostDirectives, this.metaReader)
|
|
9882
|
-
: null;
|
|
9883
|
-
if (hostDirectivesDiagnostics !== null) {
|
|
9884
|
-
diagnostics.push(...hostDirectivesDiagnostics);
|
|
9613
|
+
const nonLocalDiagnostics = this.getNonLocalDiagnostics(node, analysis);
|
|
9614
|
+
if (nonLocalDiagnostics !== null) {
|
|
9615
|
+
diagnostics.push(...nonLocalDiagnostics);
|
|
9885
9616
|
}
|
|
9886
9617
|
}
|
|
9887
9618
|
if (diagnostics.length > 0) {
|
|
@@ -10056,13 +9787,328 @@ class ComponentDecoratorHandler {
|
|
|
10056
9787
|
? null
|
|
10057
9788
|
: getHmrUpdateDeclaration(res, pool.statements, hmrMeta, node);
|
|
10058
9789
|
}
|
|
9790
|
+
/**
|
|
9791
|
+
* Determines the dependencies of a component and
|
|
9792
|
+
* categorizes them based on how they were introduced.
|
|
9793
|
+
*/
|
|
9794
|
+
resolveComponentDependencies(node, context, analysis, scope, metadata, diagnostics) {
|
|
9795
|
+
// Replace the empty components and directives from the analyze() step with a fully expanded
|
|
9796
|
+
// scope. This is possible now because during resolve() the whole compilation unit has been
|
|
9797
|
+
// fully analyzed.
|
|
9798
|
+
//
|
|
9799
|
+
// First it needs to be determined if actually importing the directives/pipes used in the
|
|
9800
|
+
// template would create a cycle. Currently ngtsc refuses to generate cycles, so an option
|
|
9801
|
+
// known as "remote scoping" is used if a cycle would be created. In remote scoping, the
|
|
9802
|
+
// module file sets the directives/pipes on the ɵcmp of the component, without
|
|
9803
|
+
// requiring new imports (but also in a way that breaks tree shaking).
|
|
9804
|
+
//
|
|
9805
|
+
// Determining this is challenging, because the TemplateDefinitionBuilder is responsible for
|
|
9806
|
+
// matching directives and pipes in the template; however, that doesn't run until the actual
|
|
9807
|
+
// compile() step. It's not possible to run template compilation sooner as it requires the
|
|
9808
|
+
// ConstantPool for the overall file being compiled (which isn't available until the
|
|
9809
|
+
// transform step).
|
|
9810
|
+
//
|
|
9811
|
+
// Instead, directives/pipes are matched independently here, using the R3TargetBinder. This
|
|
9812
|
+
// is an alternative implementation of template matching which is used for template
|
|
9813
|
+
// type-checking and will eventually replace matching in the TemplateDefinitionBuilder.
|
|
9814
|
+
const isModuleScope = scope.kind === checker.ComponentScopeKind.NgModule;
|
|
9815
|
+
// Dependencies coming from the regular `imports` field.
|
|
9816
|
+
const dependencies = isModuleScope ? scope.compilation.dependencies : scope.dependencies;
|
|
9817
|
+
// Dependencies from the `@Component.deferredImports` field.
|
|
9818
|
+
const explicitlyDeferredDependencies = getExplicitlyDeferredDeps(scope);
|
|
9819
|
+
// Mark the component is an NgModule-based component with its NgModule in a different file
|
|
9820
|
+
// then mark this file for extra import generation
|
|
9821
|
+
if (isModuleScope && context.fileName !== checker.getSourceFile(scope.ngModule).fileName) {
|
|
9822
|
+
this.localCompilationExtraImportsTracker?.markFileForExtraImportGeneration(context);
|
|
9823
|
+
}
|
|
9824
|
+
// Make sure that `@Component.imports` and `@Component.deferredImports` do not have
|
|
9825
|
+
// the same dependencies.
|
|
9826
|
+
if (metadata.isStandalone &&
|
|
9827
|
+
analysis.rawDeferredImports !== null &&
|
|
9828
|
+
explicitlyDeferredDependencies.length > 0) {
|
|
9829
|
+
const diagnostic = validateNoImportOverlap(dependencies, explicitlyDeferredDependencies, analysis.rawDeferredImports);
|
|
9830
|
+
if (diagnostic !== null) {
|
|
9831
|
+
diagnostics.push(diagnostic);
|
|
9832
|
+
}
|
|
9833
|
+
}
|
|
9834
|
+
// Set up the R3TargetBinder.
|
|
9835
|
+
const binder = createTargetBinder(dependencies);
|
|
9836
|
+
let allDependencies = dependencies;
|
|
9837
|
+
let deferBlockBinder = binder;
|
|
9838
|
+
// If there are any explicitly deferred dependencies (via `@Component.deferredImports`),
|
|
9839
|
+
// re-compute the list of dependencies and create a new binder for defer blocks. This
|
|
9840
|
+
// is because we have deferred dependencies that are not in the standard imports list
|
|
9841
|
+
// and need to be referenced later when determining what dependencies need to be in a
|
|
9842
|
+
// defer function / instruction call. Otherwise they end up treated as a standard
|
|
9843
|
+
// import, which is wrong.
|
|
9844
|
+
if (explicitlyDeferredDependencies.length > 0) {
|
|
9845
|
+
allDependencies = [...explicitlyDeferredDependencies, ...dependencies];
|
|
9846
|
+
deferBlockBinder = createTargetBinder(allDependencies);
|
|
9847
|
+
}
|
|
9848
|
+
// Set up the pipes map that is later used to determine which dependencies are used in
|
|
9849
|
+
// the template.
|
|
9850
|
+
const pipes = extractPipes(allDependencies);
|
|
9851
|
+
// Next, the component template AST is bound using the R3TargetBinder. This produces a
|
|
9852
|
+
// BoundTarget, which is similar to a ts.TypeChecker.
|
|
9853
|
+
const bound = binder.bind({ template: metadata.template.nodes });
|
|
9854
|
+
// Find all defer blocks used in the template and for each block
|
|
9855
|
+
// bind its own scope.
|
|
9856
|
+
const deferBlocks = new Map();
|
|
9857
|
+
for (const deferBlock of bound.getDeferBlocks()) {
|
|
9858
|
+
deferBlocks.set(deferBlock, deferBlockBinder.bind({ template: deferBlock.children }));
|
|
9859
|
+
}
|
|
9860
|
+
// Register all Directives and Pipes used at the top level (outside
|
|
9861
|
+
// of any defer blocks), which would be eagerly referenced.
|
|
9862
|
+
const eagerlyUsed = new Set();
|
|
9863
|
+
if (this.enableHmr) {
|
|
9864
|
+
// In HMR we need to preserve all the dependencies, because they have to remain consistent
|
|
9865
|
+
// with the initially-generated code no matter what the template looks like.
|
|
9866
|
+
for (const dep of dependencies) {
|
|
9867
|
+
if (dep.ref.node !== node) {
|
|
9868
|
+
eagerlyUsed.add(dep.ref.node);
|
|
9869
|
+
}
|
|
9870
|
+
else {
|
|
9871
|
+
const used = bound.getEagerlyUsedDirectives();
|
|
9872
|
+
if (used.some((current) => current.ref.node === node)) {
|
|
9873
|
+
eagerlyUsed.add(node);
|
|
9874
|
+
}
|
|
9875
|
+
}
|
|
9876
|
+
}
|
|
9877
|
+
}
|
|
9878
|
+
else {
|
|
9879
|
+
for (const dir of bound.getEagerlyUsedDirectives()) {
|
|
9880
|
+
eagerlyUsed.add(dir.ref.node);
|
|
9881
|
+
}
|
|
9882
|
+
for (const name of bound.getEagerlyUsedPipes()) {
|
|
9883
|
+
if (pipes.has(name)) {
|
|
9884
|
+
eagerlyUsed.add(pipes.get(name).ref.node);
|
|
9885
|
+
}
|
|
9886
|
+
}
|
|
9887
|
+
}
|
|
9888
|
+
// Set of Directives and Pipes used across the entire template,
|
|
9889
|
+
// including all defer blocks.
|
|
9890
|
+
const wholeTemplateUsed = new Set(eagerlyUsed);
|
|
9891
|
+
for (const bound of deferBlocks.values()) {
|
|
9892
|
+
for (const dir of bound.getUsedDirectives()) {
|
|
9893
|
+
wholeTemplateUsed.add(dir.ref.node);
|
|
9894
|
+
}
|
|
9895
|
+
for (const name of bound.getUsedPipes()) {
|
|
9896
|
+
if (!pipes.has(name)) {
|
|
9897
|
+
continue;
|
|
9898
|
+
}
|
|
9899
|
+
wholeTemplateUsed.add(pipes.get(name).ref.node);
|
|
9900
|
+
}
|
|
9901
|
+
}
|
|
9902
|
+
return { allDependencies, eagerlyUsed, wholeTemplateUsed, deferBlocks };
|
|
9903
|
+
}
|
|
9904
|
+
/**
|
|
9905
|
+
* Converts component dependencies into declarations by
|
|
9906
|
+
* resolving their metadata and deduplicating them.
|
|
9907
|
+
*/
|
|
9908
|
+
componentDependenciesToDeclarations(node, context, allDependencies, wholeTemplateUsed) {
|
|
9909
|
+
const declarations = new Map();
|
|
9910
|
+
// Transform the dependencies list, filtering out unused dependencies.
|
|
9911
|
+
for (const dep of allDependencies) {
|
|
9912
|
+
// Only emit references to each dependency once.
|
|
9913
|
+
if (declarations.has(dep.ref.node)) {
|
|
9914
|
+
continue;
|
|
9915
|
+
}
|
|
9916
|
+
switch (dep.kind) {
|
|
9917
|
+
case checker.MetaKind.Directive:
|
|
9918
|
+
if (!wholeTemplateUsed.has(dep.ref.node) || dep.matchSource !== checker.MatchSource.Selector) {
|
|
9919
|
+
continue;
|
|
9920
|
+
}
|
|
9921
|
+
const dirType = this.refEmitter.emit(dep.ref, context);
|
|
9922
|
+
checker.assertSuccessfulReferenceEmit(dirType, node.name, dep.isComponent ? 'component' : 'directive');
|
|
9923
|
+
declarations.set(dep.ref.node, {
|
|
9924
|
+
kind: compiler.R3TemplateDependencyKind.Directive,
|
|
9925
|
+
ref: dep.ref,
|
|
9926
|
+
type: dirType.expression,
|
|
9927
|
+
importedFile: dirType.importedFile,
|
|
9928
|
+
selector: dep.selector,
|
|
9929
|
+
inputs: dep.inputs.propertyNames,
|
|
9930
|
+
outputs: dep.outputs.propertyNames,
|
|
9931
|
+
exportAs: dep.exportAs,
|
|
9932
|
+
isComponent: dep.isComponent,
|
|
9933
|
+
});
|
|
9934
|
+
break;
|
|
9935
|
+
case checker.MetaKind.Pipe:
|
|
9936
|
+
if (!wholeTemplateUsed.has(dep.ref.node)) {
|
|
9937
|
+
continue;
|
|
9938
|
+
}
|
|
9939
|
+
const pipeType = this.refEmitter.emit(dep.ref, context);
|
|
9940
|
+
checker.assertSuccessfulReferenceEmit(pipeType, node.name, 'pipe');
|
|
9941
|
+
declarations.set(dep.ref.node, {
|
|
9942
|
+
kind: compiler.R3TemplateDependencyKind.Pipe,
|
|
9943
|
+
type: pipeType.expression,
|
|
9944
|
+
name: dep.name,
|
|
9945
|
+
ref: dep.ref,
|
|
9946
|
+
importedFile: pipeType.importedFile,
|
|
9947
|
+
});
|
|
9948
|
+
break;
|
|
9949
|
+
case checker.MetaKind.NgModule:
|
|
9950
|
+
const ngModuleType = this.refEmitter.emit(dep.ref, context);
|
|
9951
|
+
checker.assertSuccessfulReferenceEmit(ngModuleType, node.name, 'NgModule');
|
|
9952
|
+
declarations.set(dep.ref.node, {
|
|
9953
|
+
kind: compiler.R3TemplateDependencyKind.NgModule,
|
|
9954
|
+
type: ngModuleType.expression,
|
|
9955
|
+
importedFile: ngModuleType.importedFile,
|
|
9956
|
+
});
|
|
9957
|
+
break;
|
|
9958
|
+
}
|
|
9959
|
+
}
|
|
9960
|
+
return declarations;
|
|
9961
|
+
}
|
|
9962
|
+
/** Handles any cycles in the dependencies of a component. */
|
|
9963
|
+
handleDependencyCycles(node, context, scope, data, analysis, metadata, declarations, eagerlyUsed, symbol) {
|
|
9964
|
+
const eagerDeclarations = Array.from(declarations.values()).filter((decl) => {
|
|
9965
|
+
return decl.kind === compiler.R3TemplateDependencyKind.NgModule || eagerlyUsed.has(decl.ref.node);
|
|
9966
|
+
});
|
|
9967
|
+
const cyclesFromDirectives = new Map();
|
|
9968
|
+
const cyclesFromPipes = new Map();
|
|
9969
|
+
// Scan through the directives/pipes actually used in the template and check whether any
|
|
9970
|
+
// import which needs to be generated would create a cycle. This check is skipped for
|
|
9971
|
+
// standalone components as the dependencies of a standalone component have already been
|
|
9972
|
+
// imported directly by the user, so Angular won't introduce any imports that aren't already
|
|
9973
|
+
// in the user's program.
|
|
9974
|
+
if (!metadata.isStandalone) {
|
|
9975
|
+
for (const usedDep of eagerDeclarations) {
|
|
9976
|
+
const cycle = this._checkForCyclicImport(usedDep.importedFile, usedDep.type, context);
|
|
9977
|
+
if (cycle !== null) {
|
|
9978
|
+
switch (usedDep.kind) {
|
|
9979
|
+
case compiler.R3TemplateDependencyKind.Directive:
|
|
9980
|
+
cyclesFromDirectives.set(usedDep, cycle);
|
|
9981
|
+
break;
|
|
9982
|
+
case compiler.R3TemplateDependencyKind.Pipe:
|
|
9983
|
+
cyclesFromPipes.set(usedDep, cycle);
|
|
9984
|
+
break;
|
|
9985
|
+
}
|
|
9986
|
+
}
|
|
9987
|
+
}
|
|
9988
|
+
}
|
|
9989
|
+
// Check whether any usages of standalone components in imports requires the dependencies
|
|
9990
|
+
// array to be wrapped in a closure. This check is technically a heuristic as there's no
|
|
9991
|
+
// direct way to check whether a `Reference` came from a `forwardRef`. Instead, we check if
|
|
9992
|
+
// the reference is `synthetic`, implying it came from _any_ foreign function resolver,
|
|
9993
|
+
// including the `forwardRef` resolver.
|
|
9994
|
+
const standaloneImportMayBeForwardDeclared = analysis.resolvedImports !== null && analysis.resolvedImports.some((ref) => ref.synthetic);
|
|
9995
|
+
const cycleDetected = cyclesFromDirectives.size !== 0 || cyclesFromPipes.size !== 0;
|
|
9996
|
+
if (!cycleDetected) {
|
|
9997
|
+
// No cycle was detected. Record the imports that need to be created in the cycle detector
|
|
9998
|
+
// so that future cyclic import checks consider their production.
|
|
9999
|
+
for (const { type, importedFile } of eagerDeclarations) {
|
|
10000
|
+
this.maybeRecordSyntheticImport(importedFile, type, context);
|
|
10001
|
+
}
|
|
10002
|
+
// Check whether the dependencies arrays in ɵcmp need to be wrapped in a closure.
|
|
10003
|
+
// This is required if any dependency reference is to a declaration in the same file
|
|
10004
|
+
// but declared after this component.
|
|
10005
|
+
const declarationIsForwardDeclared = eagerDeclarations.some((decl) => checker.isExpressionForwardReference(decl.type, node.name, context));
|
|
10006
|
+
if (this.compilationMode !== checker.CompilationMode.LOCAL &&
|
|
10007
|
+
(declarationIsForwardDeclared || standaloneImportMayBeForwardDeclared)) {
|
|
10008
|
+
data.declarationListEmitMode = 1 /* DeclarationListEmitMode.Closure */;
|
|
10009
|
+
}
|
|
10010
|
+
data.declarations = eagerDeclarations;
|
|
10011
|
+
// Register extra local imports.
|
|
10012
|
+
if (this.compilationMode === checker.CompilationMode.LOCAL &&
|
|
10013
|
+
this.localCompilationExtraImportsTracker !== null) {
|
|
10014
|
+
// In global compilation mode `eagerDeclarations` contains "all" the component
|
|
10015
|
+
// dependencies, whose import statements will be added to the file. In local compilation
|
|
10016
|
+
// mode `eagerDeclarations` only includes the "local" dependencies, meaning those that are
|
|
10017
|
+
// declared inside this compilation unit.Here the import info of these local dependencies
|
|
10018
|
+
// are added to the tracker so that we can generate extra imports representing these local
|
|
10019
|
+
// dependencies. For non-local dependencies we use another technique of adding some
|
|
10020
|
+
// best-guess extra imports globally to all files using
|
|
10021
|
+
// `localCompilationExtraImportsTracker.addGlobalImportFromIdentifier`.
|
|
10022
|
+
for (const { type } of eagerDeclarations) {
|
|
10023
|
+
if (type instanceof compiler.ExternalExpr && type.value.moduleName) {
|
|
10024
|
+
this.localCompilationExtraImportsTracker.addImportForFile(context, type.value.moduleName);
|
|
10025
|
+
}
|
|
10026
|
+
}
|
|
10027
|
+
}
|
|
10028
|
+
}
|
|
10029
|
+
else if (this.cycleHandlingStrategy === 0 /* CycleHandlingStrategy.UseRemoteScoping */) {
|
|
10030
|
+
// Declaring the directiveDefs/pipeDefs arrays directly would require imports that would
|
|
10031
|
+
// create a cycle. Instead, mark this component as requiring remote scoping, so that the
|
|
10032
|
+
// NgModule file will take care of setting the directives for the component.
|
|
10033
|
+
this.scopeRegistry.setComponentRemoteScope(node, eagerDeclarations.filter(isUsedDirective).map((dir) => dir.ref), eagerDeclarations.filter(isUsedPipe).map((pipe) => pipe.ref));
|
|
10034
|
+
symbol.isRemotelyScoped = true;
|
|
10035
|
+
// If a semantic graph is being tracked, record the fact that this component is remotely
|
|
10036
|
+
// scoped with the declaring NgModule symbol as the NgModule's emit becomes dependent on
|
|
10037
|
+
// the directive/pipe usages of this component.
|
|
10038
|
+
if (this.semanticDepGraphUpdater !== null &&
|
|
10039
|
+
scope.kind === checker.ComponentScopeKind.NgModule &&
|
|
10040
|
+
scope.ngModule !== null) {
|
|
10041
|
+
const moduleSymbol = this.semanticDepGraphUpdater.getSymbol(scope.ngModule);
|
|
10042
|
+
if (!(moduleSymbol instanceof NgModuleSymbol)) {
|
|
10043
|
+
throw new Error(`AssertionError: Expected ${scope.ngModule.name} to be an NgModuleSymbol.`);
|
|
10044
|
+
}
|
|
10045
|
+
moduleSymbol.addRemotelyScopedComponent(symbol, symbol.usedDirectives, symbol.usedPipes);
|
|
10046
|
+
}
|
|
10047
|
+
}
|
|
10048
|
+
else {
|
|
10049
|
+
// We are not able to handle this cycle so throw an error.
|
|
10050
|
+
const relatedMessages = [];
|
|
10051
|
+
for (const [dir, cycle] of cyclesFromDirectives) {
|
|
10052
|
+
relatedMessages.push(makeCyclicImportInfo(dir.ref, dir.isComponent ? 'component' : 'directive', cycle));
|
|
10053
|
+
}
|
|
10054
|
+
for (const [pipe, cycle] of cyclesFromPipes) {
|
|
10055
|
+
relatedMessages.push(makeCyclicImportInfo(pipe.ref, 'pipe', cycle));
|
|
10056
|
+
}
|
|
10057
|
+
throw new checker.FatalDiagnosticError(checker.ErrorCode.IMPORT_CYCLE_DETECTED, node, 'One or more import cycles would need to be created to compile this component, ' +
|
|
10058
|
+
'which is not supported by the current compiler configuration.', relatedMessages);
|
|
10059
|
+
}
|
|
10060
|
+
}
|
|
10061
|
+
/** Produces diagnostics that require more than local information. */
|
|
10062
|
+
getNonLocalDiagnostics(node, analysis) {
|
|
10063
|
+
// We shouldn't be able to hit this, but add an assertion just in case the call site changes.
|
|
10064
|
+
if (this.compilationMode === checker.CompilationMode.LOCAL) {
|
|
10065
|
+
throw new Error('Method cannot be called in local compilation mode.');
|
|
10066
|
+
}
|
|
10067
|
+
let diagnostics = null;
|
|
10068
|
+
// Validate `@Component.imports` and `@Component.deferredImports` fields.
|
|
10069
|
+
if (analysis.resolvedImports !== null && analysis.rawImports !== null) {
|
|
10070
|
+
const importDiagnostics = validateStandaloneImports(analysis.resolvedImports, analysis.rawImports, this.metaReader, this.scopeReader, false /* isDeferredImport */);
|
|
10071
|
+
diagnostics ??= [];
|
|
10072
|
+
diagnostics.push(...importDiagnostics);
|
|
10073
|
+
}
|
|
10074
|
+
if (analysis.resolvedDeferredImports !== null && analysis.rawDeferredImports !== null) {
|
|
10075
|
+
const importDiagnostics = validateStandaloneImports(analysis.resolvedDeferredImports, analysis.rawDeferredImports, this.metaReader, this.scopeReader, true /* isDeferredImport */);
|
|
10076
|
+
diagnostics ??= [];
|
|
10077
|
+
diagnostics.push(...importDiagnostics);
|
|
10078
|
+
}
|
|
10079
|
+
if (analysis.providersRequiringFactory !== null &&
|
|
10080
|
+
analysis.meta.providers instanceof compiler.WrappedNodeExpr) {
|
|
10081
|
+
const providerDiagnostics = checker.getProviderDiagnostics(analysis.providersRequiringFactory, analysis.meta.providers.node, this.injectableRegistry);
|
|
10082
|
+
diagnostics ??= [];
|
|
10083
|
+
diagnostics.push(...providerDiagnostics);
|
|
10084
|
+
}
|
|
10085
|
+
if (analysis.viewProvidersRequiringFactory !== null &&
|
|
10086
|
+
analysis.meta.viewProviders instanceof compiler.WrappedNodeExpr) {
|
|
10087
|
+
const viewProviderDiagnostics = checker.getProviderDiagnostics(analysis.viewProvidersRequiringFactory, analysis.meta.viewProviders.node, this.injectableRegistry);
|
|
10088
|
+
diagnostics ??= [];
|
|
10089
|
+
diagnostics.push(...viewProviderDiagnostics);
|
|
10090
|
+
}
|
|
10091
|
+
const directiveDiagnostics = checker.getDirectiveDiagnostics(node, this.injectableRegistry, this.evaluator, this.reflector, this.scopeRegistry, this.strictCtorDeps, 'Component');
|
|
10092
|
+
if (directiveDiagnostics !== null) {
|
|
10093
|
+
diagnostics ??= [];
|
|
10094
|
+
diagnostics.push(...directiveDiagnostics);
|
|
10095
|
+
}
|
|
10096
|
+
const hostDirectivesDiagnostics = analysis.hostDirectives && analysis.rawHostDirectives
|
|
10097
|
+
? checker.validateHostDirectives(analysis.rawHostDirectives, analysis.hostDirectives, this.metaReader)
|
|
10098
|
+
: null;
|
|
10099
|
+
if (hostDirectivesDiagnostics !== null) {
|
|
10100
|
+
diagnostics ??= [];
|
|
10101
|
+
diagnostics.push(...hostDirectivesDiagnostics);
|
|
10102
|
+
}
|
|
10103
|
+
return diagnostics;
|
|
10104
|
+
}
|
|
10059
10105
|
/**
|
|
10060
10106
|
* Locates defer blocks in case scope information is not available.
|
|
10061
10107
|
* For example, this happens in the local compilation mode.
|
|
10062
10108
|
*/
|
|
10063
10109
|
locateDeferBlocksWithoutScope(template) {
|
|
10064
10110
|
const deferBlocks = new Map();
|
|
10065
|
-
const directivelessBinder = new compiler.R3TargetBinder(
|
|
10111
|
+
const directivelessBinder = new compiler.R3TargetBinder(null);
|
|
10066
10112
|
const bound = directivelessBinder.bind({ template: template.nodes });
|
|
10067
10113
|
const deferredBlocks = bound.getDeferBlocks();
|
|
10068
10114
|
for (const block of deferredBlocks) {
|
|
@@ -10295,6 +10341,7 @@ function createTargetBinder(dependencies) {
|
|
|
10295
10341
|
matcher.addSelectables(compiler.CssSelector.parse(dep.selector), [dep]);
|
|
10296
10342
|
}
|
|
10297
10343
|
}
|
|
10344
|
+
// TODO(crisbeto): implement for selectorless.
|
|
10298
10345
|
return new compiler.R3TargetBinder(matcher);
|
|
10299
10346
|
}
|
|
10300
10347
|
/**
|
|
@@ -10821,6 +10868,7 @@ class PipeDecoratorHandler {
|
|
|
10821
10868
|
isStandalone: analysis.meta.isStandalone,
|
|
10822
10869
|
decorator: analysis.decorator,
|
|
10823
10870
|
isExplicitlyDeferred: false,
|
|
10871
|
+
isPure: analysis.meta.pure,
|
|
10824
10872
|
});
|
|
10825
10873
|
this.injectableRegistry.registerInjectable(node, {
|
|
10826
10874
|
ctorDeps: analysis.meta.deps,
|
|
@@ -10870,7 +10918,7 @@ class PipeDecoratorHandler {
|
|
|
10870
10918
|
* @description
|
|
10871
10919
|
* Entry point for all public APIs of the compiler-cli package.
|
|
10872
10920
|
*/
|
|
10873
|
-
new compiler.Version('20.0.0-next.
|
|
10921
|
+
new compiler.Version('20.0.0-next.9');
|
|
10874
10922
|
|
|
10875
10923
|
/**
|
|
10876
10924
|
* Whether a given decorator should be treated as an Angular decorator.
|
|
@@ -12159,11 +12207,7 @@ class FunctionExtractor {
|
|
|
12159
12207
|
// TODO: is there any real situation in which the signature would not be available here?
|
|
12160
12208
|
// Is void a better type?
|
|
12161
12209
|
const signature = this.typeChecker.getSignatureFromDeclaration(this.exportDeclaration);
|
|
12162
|
-
const returnType = signature
|
|
12163
|
-
? this.typeChecker.typeToString(this.typeChecker.getReturnTypeOfSignature(signature), undefined,
|
|
12164
|
-
// This ensures that e.g. `T | undefined` is not reduced to `T`.
|
|
12165
|
-
ts.TypeFormatFlags.NoTypeReduction | ts.TypeFormatFlags.NoTruncation)
|
|
12166
|
-
: 'unknown';
|
|
12210
|
+
const returnType = signature ? extractReturnType(signature, this.typeChecker) : 'unknown';
|
|
12167
12211
|
const implementation = findImplementationOfFunction(this.exportDeclaration, this.typeChecker) ??
|
|
12168
12212
|
this.exportDeclaration;
|
|
12169
12213
|
const type = this.typeChecker.getTypeAtLocation(this.exportDeclaration);
|
|
@@ -12247,11 +12291,18 @@ function extractCallSignatures(name, typeChecker, type) {
|
|
|
12247
12291
|
jsdocTags: extractJsDocTags(decl),
|
|
12248
12292
|
params: extractAllParams(decl.parameters, typeChecker),
|
|
12249
12293
|
rawComment: extractRawJsDoc(decl),
|
|
12250
|
-
returnType:
|
|
12251
|
-
// This ensures that e.g. `T | undefined` is not reduced to `T`.
|
|
12252
|
-
ts.TypeFormatFlags.NoTypeReduction | ts.TypeFormatFlags.NoTruncation),
|
|
12294
|
+
returnType: extractReturnType(signature, typeChecker),
|
|
12253
12295
|
}));
|
|
12254
12296
|
}
|
|
12297
|
+
function extractReturnType(signature, typeChecker) {
|
|
12298
|
+
// Handling Type Predicates
|
|
12299
|
+
if (signature?.declaration?.type && ts.isTypePredicateNode(signature.declaration.type)) {
|
|
12300
|
+
return signature.declaration.type.getText();
|
|
12301
|
+
}
|
|
12302
|
+
return typeChecker.typeToString(typeChecker.getReturnTypeOfSignature(signature), undefined,
|
|
12303
|
+
// This ensures that e.g. `T | undefined` is not reduced to `T`.
|
|
12304
|
+
ts.TypeFormatFlags.NoTypeReduction | ts.TypeFormatFlags.NoTruncation);
|
|
12305
|
+
}
|
|
12255
12306
|
/** Finds the implementation of the given function declaration overload signature. */
|
|
12256
12307
|
function findImplementationOfFunction(node, typeChecker) {
|
|
12257
12308
|
if (node.body !== undefined || node.name === undefined) {
|
|
@@ -12331,7 +12382,8 @@ class ClassExtractor {
|
|
|
12331
12382
|
else if (ts.isAccessor(memberDeclaration)) {
|
|
12332
12383
|
return this.extractGetterSetter(memberDeclaration);
|
|
12333
12384
|
}
|
|
12334
|
-
else if (ts.isConstructorDeclaration(memberDeclaration)
|
|
12385
|
+
else if (ts.isConstructorDeclaration(memberDeclaration) &&
|
|
12386
|
+
memberDeclaration.parameters.length > 0) {
|
|
12335
12387
|
return this.extractConstructor(memberDeclaration);
|
|
12336
12388
|
}
|
|
12337
12389
|
// We only expect methods, properties, and accessors. If we encounter something else,
|
|
@@ -12633,6 +12685,8 @@ class PipeExtractor extends ClassExtractor {
|
|
|
12633
12685
|
pipeName: this.metadata.name,
|
|
12634
12686
|
entryType: EntryType.Pipe,
|
|
12635
12687
|
isStandalone: this.metadata.isStandalone,
|
|
12688
|
+
usage: extractPipeSyntax(this.metadata, this.declaration),
|
|
12689
|
+
isPure: this.metadata.isPure,
|
|
12636
12690
|
};
|
|
12637
12691
|
}
|
|
12638
12692
|
}
|
|
@@ -12678,6 +12732,21 @@ function extractInterface(declaration, typeChecker) {
|
|
|
12678
12732
|
const extractor = new ClassExtractor(declaration, typeChecker);
|
|
12679
12733
|
return extractor.extract();
|
|
12680
12734
|
}
|
|
12735
|
+
function extractPipeSyntax(metadata, classDeclaration) {
|
|
12736
|
+
const transformParams = classDeclaration.members.find((member) => {
|
|
12737
|
+
return (ts.isMethodDeclaration(member) &&
|
|
12738
|
+
member.name &&
|
|
12739
|
+
ts.isIdentifier(member.name) &&
|
|
12740
|
+
member.name.getText() === 'transform');
|
|
12741
|
+
});
|
|
12742
|
+
let paramNames = transformParams.parameters
|
|
12743
|
+
// value is the first argument, it's already referenced before the pipe
|
|
12744
|
+
.slice(1)
|
|
12745
|
+
.map((param) => {
|
|
12746
|
+
return param.name.getText();
|
|
12747
|
+
});
|
|
12748
|
+
return `{{ value_expression | ${metadata.name}${paramNames.length ? ':' + paramNames.join(':') : ''} }}`;
|
|
12749
|
+
}
|
|
12681
12750
|
|
|
12682
12751
|
/** Name of the tag indicating that an object literal should be shown as an enum in docs. */
|
|
12683
12752
|
const LITERAL_AS_ENUM_TAG = 'object-literal-as-enum';
|
|
@@ -14183,6 +14252,9 @@ let TemplateVisitor$1 = class TemplateVisitor extends compiler.RecursiveVisitor
|
|
|
14183
14252
|
}
|
|
14184
14253
|
/** Creates an identifier for a template element or template node. */
|
|
14185
14254
|
elementOrTemplateToIdentifier(node) {
|
|
14255
|
+
if (node instanceof compiler.Component || node instanceof compiler.Directive) {
|
|
14256
|
+
throw new Error('TODO');
|
|
14257
|
+
}
|
|
14186
14258
|
// If this node has already been seen, return the cached result.
|
|
14187
14259
|
if (this.elementAndTemplateIdentifierCache.has(node)) {
|
|
14188
14260
|
return this.elementAndTemplateIdentifierCache.get(node);
|
|
@@ -14260,7 +14332,10 @@ let TemplateVisitor$1 = class TemplateVisitor extends compiler.RecursiveVisitor
|
|
|
14260
14332
|
if (refTarget) {
|
|
14261
14333
|
let node = null;
|
|
14262
14334
|
let directive = null;
|
|
14263
|
-
if (refTarget instanceof compiler.Element ||
|
|
14335
|
+
if (refTarget instanceof compiler.Element ||
|
|
14336
|
+
refTarget instanceof compiler.Template ||
|
|
14337
|
+
refTarget instanceof compiler.Component ||
|
|
14338
|
+
refTarget instanceof compiler.Directive) {
|
|
14264
14339
|
node = this.elementOrTemplateToIdentifier(refTarget);
|
|
14265
14340
|
}
|
|
14266
14341
|
else {
|
|
@@ -14869,7 +14944,10 @@ function isSignalSymbol(symbol) {
|
|
|
14869
14944
|
const fileName = decl.getSourceFile().fileName;
|
|
14870
14945
|
return ((ts.isInterfaceDeclaration(decl) || ts.isTypeAliasDeclaration(decl)) &&
|
|
14871
14946
|
SIGNAL_FNS.has(decl.name.text) &&
|
|
14872
|
-
(fileName.includes('@angular/core') ||
|
|
14947
|
+
(fileName.includes('@angular/core') ||
|
|
14948
|
+
fileName.includes('angular2/rc/packages/core') ||
|
|
14949
|
+
fileName.includes('bin/packages/core')) // for local usage in some tests
|
|
14950
|
+
);
|
|
14873
14951
|
}));
|
|
14874
14952
|
}
|
|
14875
14953
|
|
|
@@ -15120,7 +15198,7 @@ function buildDiagnosticForSignal(ctx, node, component) {
|
|
|
15120
15198
|
}
|
|
15121
15199
|
return [];
|
|
15122
15200
|
}
|
|
15123
|
-
const factory$
|
|
15201
|
+
const factory$d = {
|
|
15124
15202
|
code: checker.ErrorCode.INTERPOLATED_SIGNAL_NOT_INVOKED,
|
|
15125
15203
|
name: checker.ExtendedTemplateDiagnosticName.INTERPOLATED_SIGNAL_NOT_INVOKED,
|
|
15126
15204
|
create: () => new InterpolatedSignalCheck(),
|
|
@@ -15146,7 +15224,7 @@ class InvalidBananaInBoxCheck extends TemplateCheckWithVisitor {
|
|
|
15146
15224
|
return [diagnostic];
|
|
15147
15225
|
}
|
|
15148
15226
|
}
|
|
15149
|
-
const factory$
|
|
15227
|
+
const factory$c = {
|
|
15150
15228
|
code: checker.ErrorCode.INVALID_BANANA_IN_BOX,
|
|
15151
15229
|
name: checker.ExtendedTemplateDiagnosticName.INVALID_BANANA_IN_BOX,
|
|
15152
15230
|
create: () => new InvalidBananaInBoxCheck(),
|
|
@@ -15161,7 +15239,7 @@ const factory$b = {
|
|
|
15161
15239
|
* are used as structural directives and a warning would be generated. Once the
|
|
15162
15240
|
* `CommonModule` is included, the `ngSwitch` would also be covered.
|
|
15163
15241
|
*/
|
|
15164
|
-
const KNOWN_CONTROL_FLOW_DIRECTIVES = new Map([
|
|
15242
|
+
const KNOWN_CONTROL_FLOW_DIRECTIVES$1 = new Map([
|
|
15165
15243
|
['ngIf', { directive: 'NgIf', builtIn: '@if' }],
|
|
15166
15244
|
['ngFor', { directive: 'NgFor', builtIn: '@for' }],
|
|
15167
15245
|
['ngSwitchCase', { directive: 'NgSwitchCase', builtIn: '@switch with @case' }],
|
|
@@ -15189,7 +15267,7 @@ class MissingControlFlowDirectiveCheck extends TemplateCheckWithVisitor {
|
|
|
15189
15267
|
visitNode(ctx, component, node) {
|
|
15190
15268
|
if (!(node instanceof compiler.Template))
|
|
15191
15269
|
return [];
|
|
15192
|
-
const controlFlowAttr = node.templateAttrs.find((attr) => KNOWN_CONTROL_FLOW_DIRECTIVES.has(attr.name));
|
|
15270
|
+
const controlFlowAttr = node.templateAttrs.find((attr) => KNOWN_CONTROL_FLOW_DIRECTIVES$1.has(attr.name));
|
|
15193
15271
|
if (!controlFlowAttr)
|
|
15194
15272
|
return [];
|
|
15195
15273
|
const symbol = ctx.templateTypeChecker.getSymbolOfNode(node, component);
|
|
@@ -15197,7 +15275,7 @@ class MissingControlFlowDirectiveCheck extends TemplateCheckWithVisitor {
|
|
|
15197
15275
|
return [];
|
|
15198
15276
|
}
|
|
15199
15277
|
const sourceSpan = controlFlowAttr.keySpan || controlFlowAttr.sourceSpan;
|
|
15200
|
-
const directiveAndBuiltIn = KNOWN_CONTROL_FLOW_DIRECTIVES.get(controlFlowAttr.name);
|
|
15278
|
+
const directiveAndBuiltIn = KNOWN_CONTROL_FLOW_DIRECTIVES$1.get(controlFlowAttr.name);
|
|
15201
15279
|
const errorMessage = `The \`*${controlFlowAttr.name}\` directive was used in the template, ` +
|
|
15202
15280
|
`but neither the \`${directiveAndBuiltIn?.directive}\` directive nor the \`CommonModule\` was imported. ` +
|
|
15203
15281
|
`Use Angular's built-in control flow ${directiveAndBuiltIn?.builtIn} or ` +
|
|
@@ -15207,7 +15285,7 @@ class MissingControlFlowDirectiveCheck extends TemplateCheckWithVisitor {
|
|
|
15207
15285
|
return [diagnostic];
|
|
15208
15286
|
}
|
|
15209
15287
|
}
|
|
15210
|
-
const factory$
|
|
15288
|
+
const factory$b = {
|
|
15211
15289
|
code: checker.ErrorCode.MISSING_CONTROL_FLOW_DIRECTIVE,
|
|
15212
15290
|
name: checker.ExtendedTemplateDiagnosticName.MISSING_CONTROL_FLOW_DIRECTIVE,
|
|
15213
15291
|
create: (options) => {
|
|
@@ -15240,12 +15318,67 @@ class MissingNgForOfLetCheck extends TemplateCheckWithVisitor {
|
|
|
15240
15318
|
return [diagnostic];
|
|
15241
15319
|
}
|
|
15242
15320
|
}
|
|
15243
|
-
const factory$
|
|
15321
|
+
const factory$a = {
|
|
15244
15322
|
code: checker.ErrorCode.MISSING_NGFOROF_LET,
|
|
15245
15323
|
name: checker.ExtendedTemplateDiagnosticName.MISSING_NGFOROF_LET,
|
|
15246
15324
|
create: () => new MissingNgForOfLetCheck(),
|
|
15247
15325
|
};
|
|
15248
15326
|
|
|
15327
|
+
/**
|
|
15328
|
+
* The list of known control flow directives present in the `CommonModule`.
|
|
15329
|
+
*
|
|
15330
|
+
* If these control flow directives are missing they will be reported by a separate diagnostic.
|
|
15331
|
+
*/
|
|
15332
|
+
const KNOWN_CONTROL_FLOW_DIRECTIVES = new Set([
|
|
15333
|
+
'ngIf',
|
|
15334
|
+
'ngFor',
|
|
15335
|
+
'ngForOf',
|
|
15336
|
+
'ngForTrackBy',
|
|
15337
|
+
'ngSwitchCase',
|
|
15338
|
+
'ngSwitchDefault',
|
|
15339
|
+
]);
|
|
15340
|
+
/**
|
|
15341
|
+
* Ensures that there are no structural directives (something like *select or *featureFlag)
|
|
15342
|
+
* used in a template of a *standalone* component without importing the directive. Returns
|
|
15343
|
+
* diagnostics in case such a directive is detected.
|
|
15344
|
+
*
|
|
15345
|
+
* Note: this check only handles the cases when structural directive syntax is used (e.g. `*featureFlag`).
|
|
15346
|
+
* Regular binding syntax (e.g. `[featureFlag]`) is handled separately in type checker and treated as a
|
|
15347
|
+
* hard error instead of a warning.
|
|
15348
|
+
*/
|
|
15349
|
+
class MissingStructuralDirectiveCheck extends TemplateCheckWithVisitor {
|
|
15350
|
+
code = checker.ErrorCode.MISSING_STRUCTURAL_DIRECTIVE;
|
|
15351
|
+
run(ctx, component, template) {
|
|
15352
|
+
const componentMetadata = ctx.templateTypeChecker.getDirectiveMetadata(component);
|
|
15353
|
+
// Avoid running this check for non-standalone components.
|
|
15354
|
+
if (!componentMetadata || !componentMetadata.isStandalone) {
|
|
15355
|
+
return [];
|
|
15356
|
+
}
|
|
15357
|
+
return super.run(ctx, component, template);
|
|
15358
|
+
}
|
|
15359
|
+
visitNode(ctx, component, node) {
|
|
15360
|
+
if (!(node instanceof compiler.Template))
|
|
15361
|
+
return [];
|
|
15362
|
+
const customStructuralDirective = node.templateAttrs.find((attr) => !KNOWN_CONTROL_FLOW_DIRECTIVES.has(attr.name));
|
|
15363
|
+
if (!customStructuralDirective)
|
|
15364
|
+
return [];
|
|
15365
|
+
const symbol = ctx.templateTypeChecker.getSymbolOfNode(node, component);
|
|
15366
|
+
if (symbol?.directives.length) {
|
|
15367
|
+
return [];
|
|
15368
|
+
}
|
|
15369
|
+
const sourceSpan = customStructuralDirective.keySpan || customStructuralDirective.sourceSpan;
|
|
15370
|
+
const errorMessage = `A structural directive \`${customStructuralDirective.name}\` was used in the template ` +
|
|
15371
|
+
`without a corresponding import in the component. ` +
|
|
15372
|
+
`Make sure that the directive is included in the \`@Component.imports\` array of this component.`;
|
|
15373
|
+
return [ctx.makeTemplateDiagnostic(sourceSpan, errorMessage)];
|
|
15374
|
+
}
|
|
15375
|
+
}
|
|
15376
|
+
const factory$9 = {
|
|
15377
|
+
code: checker.ErrorCode.MISSING_STRUCTURAL_DIRECTIVE,
|
|
15378
|
+
name: checker.ExtendedTemplateDiagnosticName.MISSING_STRUCTURAL_DIRECTIVE,
|
|
15379
|
+
create: () => new MissingStructuralDirectiveCheck(),
|
|
15380
|
+
};
|
|
15381
|
+
|
|
15249
15382
|
/**
|
|
15250
15383
|
* Ensures the left side of a nullish coalescing operation is nullable.
|
|
15251
15384
|
* Returns diagnostics for the cases where the operator is useless.
|
|
@@ -15719,14 +15852,15 @@ function assertNever(value) {
|
|
|
15719
15852
|
}
|
|
15720
15853
|
|
|
15721
15854
|
const ALL_DIAGNOSTIC_FACTORIES = [
|
|
15722
|
-
factory$
|
|
15855
|
+
factory$c,
|
|
15723
15856
|
factory$8,
|
|
15724
15857
|
factory$7,
|
|
15725
|
-
factory$
|
|
15858
|
+
factory$b,
|
|
15726
15859
|
factory$4,
|
|
15860
|
+
factory$a,
|
|
15727
15861
|
factory$9,
|
|
15728
15862
|
factory$5,
|
|
15729
|
-
factory$
|
|
15863
|
+
factory$d,
|
|
15730
15864
|
factory$3,
|
|
15731
15865
|
factory$1,
|
|
15732
15866
|
factory$6,
|
|
@@ -18779,7 +18913,7 @@ var semver = /*@__PURE__*/getDefaultExportFromCjs(semverExports);
|
|
|
18779
18913
|
* @param minVersion Minimum required version for the feature.
|
|
18780
18914
|
*/
|
|
18781
18915
|
function coreVersionSupportsFeature(coreVersion, minVersion) {
|
|
18782
|
-
// A version of `20.0.0-next.
|
|
18916
|
+
// A version of `20.0.0-next.9` usually means that core is at head so it supports
|
|
18783
18917
|
// all features. Use string interpolation prevent the placeholder from being replaced
|
|
18784
18918
|
// with the current version during build time.
|
|
18785
18919
|
if (coreVersion === `0.0.0-${'PLACEHOLDER'}`) {
|
|
@@ -18894,6 +19028,7 @@ class NgCompiler {
|
|
|
18894
19028
|
angularCoreVersion;
|
|
18895
19029
|
enableHmr;
|
|
18896
19030
|
implicitStandaloneValue;
|
|
19031
|
+
enableSelectorless;
|
|
18897
19032
|
/**
|
|
18898
19033
|
* `NgCompiler` can be reused for multiple compilations (for resource-only changes), and each
|
|
18899
19034
|
* new compilation uses a fresh `PerfRecorder`. Thus, classes created with a lifespan of the
|
|
@@ -18938,6 +19073,7 @@ class NgCompiler {
|
|
|
18938
19073
|
// TODO(crisbeto): remove this flag and base `enableBlockSyntax` on the `angularCoreVersion`.
|
|
18939
19074
|
this.enableBlockSyntax = options['_enableBlockSyntax'] ?? true;
|
|
18940
19075
|
this.enableLetSyntax = options['_enableLetSyntax'] ?? true;
|
|
19076
|
+
this.enableSelectorless = options['_enableSelectorless'] ?? false;
|
|
18941
19077
|
// Standalone by default is enabled since v19. We need to toggle it here,
|
|
18942
19078
|
// because the language service extension may be running with the latest
|
|
18943
19079
|
// version of the compiler against an older version of Angular.
|
|
@@ -19718,7 +19854,7 @@ class NgCompiler {
|
|
|
19718
19854
|
const jitDeclarationRegistry = new JitDeclarationRegistry();
|
|
19719
19855
|
// Set up the IvyCompilation, which manages state for the Ivy transformer.
|
|
19720
19856
|
const handlers = [
|
|
19721
|
-
new ComponentDecoratorHandler(reflector, evaluator, metaRegistry, metaReader, scopeReader, this.adapter, ngModuleScopeRegistry, typeCheckScopeRegistry, resourceRegistry, isCore, strictCtorDeps, this.resourceManager, this.adapter.rootDirs, this.options.preserveWhitespaces || false, this.options.i18nUseExternalIds !== false, this.options.enableI18nLegacyMessageIdFormat !== false, this.usePoisonedData, this.options.i18nNormalizeLineEndingsInICUs === true, this.moduleResolver, this.cycleAnalyzer, cycleHandlingStrategy, refEmitter, referencesRegistry, this.incrementalCompilation.depGraph, injectableRegistry, semanticDepGraphUpdater, this.closureCompilerEnabled, this.delegatingPerfRecorder, hostDirectivesResolver, importTracker, supportTestBed, compilationMode, deferredSymbolsTracker, !!this.options.forbidOrphanComponents, this.enableBlockSyntax, this.enableLetSyntax, externalRuntimeStyles, localCompilationExtraImportsTracker, jitDeclarationRegistry, this.options.i18nPreserveWhitespaceForLegacyExtraction ?? true, !!this.options.strictStandalone, this.enableHmr, this.implicitStandaloneValue, typeCheckHostBindings),
|
|
19857
|
+
new ComponentDecoratorHandler(reflector, evaluator, metaRegistry, metaReader, scopeReader, this.adapter, ngModuleScopeRegistry, typeCheckScopeRegistry, resourceRegistry, isCore, strictCtorDeps, this.resourceManager, this.adapter.rootDirs, this.options.preserveWhitespaces || false, this.options.i18nUseExternalIds !== false, this.options.enableI18nLegacyMessageIdFormat !== false, this.usePoisonedData, this.options.i18nNormalizeLineEndingsInICUs === true, this.moduleResolver, this.cycleAnalyzer, cycleHandlingStrategy, refEmitter, referencesRegistry, this.incrementalCompilation.depGraph, injectableRegistry, semanticDepGraphUpdater, this.closureCompilerEnabled, this.delegatingPerfRecorder, hostDirectivesResolver, importTracker, supportTestBed, compilationMode, deferredSymbolsTracker, !!this.options.forbidOrphanComponents, this.enableBlockSyntax, this.enableLetSyntax, externalRuntimeStyles, localCompilationExtraImportsTracker, jitDeclarationRegistry, this.options.i18nPreserveWhitespaceForLegacyExtraction ?? true, !!this.options.strictStandalone, this.enableHmr, this.implicitStandaloneValue, typeCheckHostBindings, this.enableSelectorless),
|
|
19722
19858
|
// TODO(alxhub): understand why the cast here is necessary (something to do with `null`
|
|
19723
19859
|
// not being assignable to `unknown` when wrapped in `Readonly`).
|
|
19724
19860
|
new DirectiveDecoratorHandler(reflector, evaluator, metaRegistry, ngModuleScopeRegistry, metaReader, injectableRegistry, refEmitter, referencesRegistry, isCore, strictCtorDeps, semanticDepGraphUpdater, this.closureCompilerEnabled, this.delegatingPerfRecorder, importTracker, supportTestBed, typeCheckScopeRegistry, compilationMode, jitDeclarationRegistry, resourceRegistry, !!this.options.strictStandalone, this.implicitStandaloneValue, this.usePoisonedData, typeCheckHostBindings),
|