@angular/language-service 11.2.4 → 11.2.5
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/bundles/ivy.js +1303 -690
- package/bundles/language-service.js +27 -64
- package/ivy/attribute_completions.d.ts +1 -1
- package/ivy/attribute_completions.js +3 -3
- package/ivy/completions.d.ts +2 -1
- package/ivy/completions.js +16 -7
- package/ivy/language_service.js +2 -2
- package/package.json +1 -1
package/bundles/ivy.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @license Angular v11.2.
|
|
2
|
+
* @license Angular v11.2.5
|
|
3
3
|
* Copyright Google LLC All Rights Reserved.
|
|
4
4
|
* License: MIT
|
|
5
5
|
*/
|
|
@@ -5903,10 +5903,6 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
5903
5903
|
Identifiers$1.CopyDefinitionFeature = { name: 'ɵɵCopyDefinitionFeature', moduleName: CORE$1 };
|
|
5904
5904
|
Identifiers$1.ProvidersFeature = { name: 'ɵɵProvidersFeature', moduleName: CORE$1 };
|
|
5905
5905
|
Identifiers$1.listener = { name: 'ɵɵlistener', moduleName: CORE$1 };
|
|
5906
|
-
Identifiers$1.getFactoryOf = {
|
|
5907
|
-
name: 'ɵɵgetFactoryOf',
|
|
5908
|
-
moduleName: CORE$1,
|
|
5909
|
-
};
|
|
5910
5906
|
Identifiers$1.getInheritedFactory = {
|
|
5911
5907
|
name: 'ɵɵgetInheritedFactory',
|
|
5912
5908
|
moduleName: CORE$1,
|
|
@@ -7886,7 +7882,6 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
7886
7882
|
(function (R3FactoryDelegateType) {
|
|
7887
7883
|
R3FactoryDelegateType[R3FactoryDelegateType["Class"] = 0] = "Class";
|
|
7888
7884
|
R3FactoryDelegateType[R3FactoryDelegateType["Function"] = 1] = "Function";
|
|
7889
|
-
R3FactoryDelegateType[R3FactoryDelegateType["Factory"] = 2] = "Factory";
|
|
7890
7885
|
})(R3FactoryDelegateType || (R3FactoryDelegateType = {}));
|
|
7891
7886
|
var R3FactoryTarget;
|
|
7892
7887
|
(function (R3FactoryTarget) {
|
|
@@ -7974,19 +7969,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
7974
7969
|
body.push(ifStmt(t, [ctorStmt], [r.set(nonCtorExpr).toStmt()]));
|
|
7975
7970
|
return r;
|
|
7976
7971
|
}
|
|
7977
|
-
if (isDelegatedMetadata(meta)
|
|
7978
|
-
const delegateFactory = variable(`ɵ${meta.name}_BaseFactory`);
|
|
7979
|
-
const getFactoryOf = importExpr(Identifiers$1.getFactoryOf);
|
|
7980
|
-
if (meta.delegate.isEquivalent(meta.internalType)) {
|
|
7981
|
-
throw new Error(`Illegal state: compiling factory that delegates to itself`);
|
|
7982
|
-
}
|
|
7983
|
-
const delegateFactoryStmt = delegateFactory.set(getFactoryOf.callFn([meta.delegate])).toDeclStmt(INFERRED_TYPE, [
|
|
7984
|
-
StmtModifier.Exported, StmtModifier.Final
|
|
7985
|
-
]);
|
|
7986
|
-
statements.push(delegateFactoryStmt);
|
|
7987
|
-
retExpr = makeConditionalFactory(delegateFactory.callFn([]));
|
|
7988
|
-
}
|
|
7989
|
-
else if (isDelegatedMetadata(meta)) {
|
|
7972
|
+
if (isDelegatedMetadata(meta)) {
|
|
7990
7973
|
// This type is created with a delegated factory. If a type parameter is not specified, call
|
|
7991
7974
|
// the factory instead.
|
|
7992
7975
|
const delegateArgs = injectDependencies(meta.delegateDeps, meta.injectFn, meta.target === R3FactoryTarget.Pipe);
|
|
@@ -8995,21 +8978,6 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
8995
8978
|
}
|
|
8996
8979
|
}
|
|
8997
8980
|
|
|
8998
|
-
/**
|
|
8999
|
-
* @license
|
|
9000
|
-
* Copyright Google LLC All Rights Reserved.
|
|
9001
|
-
*
|
|
9002
|
-
* Use of this source code is governed by an MIT-style license that can be
|
|
9003
|
-
* found in the LICENSE file at https://angular.io/license
|
|
9004
|
-
*/
|
|
9005
|
-
function mapLiteral(obj, quoted = false) {
|
|
9006
|
-
return literalMap(Object.keys(obj).map(key => ({
|
|
9007
|
-
key,
|
|
9008
|
-
quoted,
|
|
9009
|
-
value: obj[key],
|
|
9010
|
-
})));
|
|
9011
|
-
}
|
|
9012
|
-
|
|
9013
8981
|
/**
|
|
9014
8982
|
* @license
|
|
9015
8983
|
* Copyright Google LLC All Rights Reserved.
|
|
@@ -9100,18 +9068,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
9100
9068
|
return iifeCall.toStmt();
|
|
9101
9069
|
}
|
|
9102
9070
|
function compileInjector(meta) {
|
|
9103
|
-
const
|
|
9104
|
-
name: meta.name,
|
|
9105
|
-
type: meta.type,
|
|
9106
|
-
internalType: meta.internalType,
|
|
9107
|
-
typeArgumentCount: 0,
|
|
9108
|
-
deps: meta.deps,
|
|
9109
|
-
injectFn: Identifiers$1.inject,
|
|
9110
|
-
target: R3FactoryTarget.NgModule,
|
|
9111
|
-
});
|
|
9112
|
-
const definitionMap = {
|
|
9113
|
-
factory: result.factory,
|
|
9114
|
-
};
|
|
9071
|
+
const definitionMap = {};
|
|
9115
9072
|
if (meta.providers !== null) {
|
|
9116
9073
|
definitionMap.providers = meta.providers;
|
|
9117
9074
|
}
|
|
@@ -9120,7 +9077,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
9120
9077
|
}
|
|
9121
9078
|
const expression = importExpr(Identifiers$1.defineInjector).callFn([mapToMapExpression(definitionMap)]);
|
|
9122
9079
|
const type = new ExpressionType(importExpr(Identifiers$1.InjectorDef, [new ExpressionType(meta.type.type)]));
|
|
9123
|
-
return { expression, type
|
|
9080
|
+
return { expression, type };
|
|
9124
9081
|
}
|
|
9125
9082
|
function tupleTypeOf(exp) {
|
|
9126
9083
|
const types = exp.map(ref => typeofExpr(ref.type));
|
|
@@ -15685,6 +15642,21 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
15685
15642
|
}
|
|
15686
15643
|
}
|
|
15687
15644
|
|
|
15645
|
+
/**
|
|
15646
|
+
* @license
|
|
15647
|
+
* Copyright Google LLC All Rights Reserved.
|
|
15648
|
+
*
|
|
15649
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
15650
|
+
* found in the LICENSE file at https://angular.io/license
|
|
15651
|
+
*/
|
|
15652
|
+
function mapLiteral(obj, quoted = false) {
|
|
15653
|
+
return literalMap(Object.keys(obj).map(key => ({
|
|
15654
|
+
key,
|
|
15655
|
+
quoted,
|
|
15656
|
+
value: obj[key],
|
|
15657
|
+
})));
|
|
15658
|
+
}
|
|
15659
|
+
|
|
15688
15660
|
/**
|
|
15689
15661
|
* @license
|
|
15690
15662
|
* Copyright Google LLC All Rights Reserved.
|
|
@@ -20052,12 +20024,11 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
20052
20024
|
name: facade.name,
|
|
20053
20025
|
type: wrapReference(facade.type),
|
|
20054
20026
|
internalType: new WrappedNodeExpr(facade.type),
|
|
20055
|
-
deps: convertR3DependencyMetadataArray(facade.deps),
|
|
20056
20027
|
providers: new WrappedNodeExpr(facade.providers),
|
|
20057
20028
|
imports: facade.imports.map(i => new WrappedNodeExpr(i)),
|
|
20058
20029
|
};
|
|
20059
20030
|
const res = compileInjector(meta);
|
|
20060
|
-
return this.jitExpression(res.expression, angularCoreEnv, sourceMapUrl,
|
|
20031
|
+
return this.jitExpression(res.expression, angularCoreEnv, sourceMapUrl, []);
|
|
20061
20032
|
}
|
|
20062
20033
|
compileNgModule(angularCoreEnv, sourceMapUrl, facade) {
|
|
20063
20034
|
const meta = {
|
|
@@ -20385,7 +20356,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
20385
20356
|
* Use of this source code is governed by an MIT-style license that can be
|
|
20386
20357
|
* found in the LICENSE file at https://angular.io/license
|
|
20387
20358
|
*/
|
|
20388
|
-
const VERSION$1 = new Version('11.2.
|
|
20359
|
+
const VERSION$1 = new Version('11.2.5');
|
|
20389
20360
|
|
|
20390
20361
|
/**
|
|
20391
20362
|
* @license
|
|
@@ -21042,7 +21013,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
21042
21013
|
*/
|
|
21043
21014
|
function createDirectiveDefinitionMap(meta) {
|
|
21044
21015
|
const definitionMap = new DefinitionMap();
|
|
21045
|
-
definitionMap.set('version', literal('11.2.
|
|
21016
|
+
definitionMap.set('version', literal('11.2.5'));
|
|
21046
21017
|
// e.g. `type: MyDirective`
|
|
21047
21018
|
definitionMap.set('type', meta.internalType);
|
|
21048
21019
|
// e.g. `selector: 'some-dir'`
|
|
@@ -21263,7 +21234,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
21263
21234
|
*/
|
|
21264
21235
|
function createPipeDefinitionMap(meta) {
|
|
21265
21236
|
const definitionMap = new DefinitionMap();
|
|
21266
|
-
definitionMap.set('version', literal('11.2.
|
|
21237
|
+
definitionMap.set('version', literal('11.2.5'));
|
|
21267
21238
|
definitionMap.set('ngImport', importExpr(Identifiers$1.core));
|
|
21268
21239
|
// e.g. `type: MyPipe`
|
|
21269
21240
|
definitionMap.set('type', meta.internalType);
|
|
@@ -21295,7 +21266,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
21295
21266
|
* Use of this source code is governed by an MIT-style license that can be
|
|
21296
21267
|
* found in the LICENSE file at https://angular.io/license
|
|
21297
21268
|
*/
|
|
21298
|
-
const VERSION$2 = new Version('11.2.
|
|
21269
|
+
const VERSION$2 = new Version('11.2.5');
|
|
21299
21270
|
|
|
21300
21271
|
/**
|
|
21301
21272
|
* @license
|
|
@@ -21786,13 +21757,19 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
21786
21757
|
// such a case, the reference's `identities` property would be `[foo]`, which would result in an
|
|
21787
21758
|
// invalid emission of a free-standing `foo` identifier, rather than `exports.foo`.
|
|
21788
21759
|
if (!isDeclaration(ref.node) && refSf === context) {
|
|
21789
|
-
return
|
|
21760
|
+
return {
|
|
21761
|
+
expression: new WrappedNodeExpr(ref.node),
|
|
21762
|
+
importedFile: null,
|
|
21763
|
+
};
|
|
21790
21764
|
}
|
|
21791
21765
|
// A Reference can have multiple identities in different files, so it may already have an
|
|
21792
21766
|
// Identifier in the requested context file.
|
|
21793
21767
|
const identifier = ref.getIdentityIn(context);
|
|
21794
21768
|
if (identifier !== null) {
|
|
21795
|
-
return
|
|
21769
|
+
return {
|
|
21770
|
+
expression: new WrappedNodeExpr(identifier),
|
|
21771
|
+
importedFile: null,
|
|
21772
|
+
};
|
|
21796
21773
|
}
|
|
21797
21774
|
else {
|
|
21798
21775
|
return null;
|
|
@@ -21835,22 +21812,17 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
21835
21812
|
}
|
|
21836
21813
|
// Try to find the exported name of the declaration, if one is available.
|
|
21837
21814
|
const { specifier, resolutionContext } = ref.bestGuessOwningModule;
|
|
21838
|
-
const
|
|
21839
|
-
if (
|
|
21815
|
+
const exports = this.getExportsOfModule(specifier, resolutionContext);
|
|
21816
|
+
if (exports === null || !exports.exportMap.has(ref.node)) {
|
|
21840
21817
|
// TODO(alxhub): make this error a ts.Diagnostic pointing at whatever caused this import to be
|
|
21841
21818
|
// triggered.
|
|
21842
21819
|
throw new Error(`Symbol ${ref.debugName} declared in ${getSourceFile(ref.node).fileName} is not exported from ${specifier} (import into ${context.fileName})`);
|
|
21843
21820
|
}
|
|
21844
|
-
|
|
21845
|
-
|
|
21846
|
-
|
|
21847
|
-
|
|
21848
|
-
|
|
21849
|
-
return exports.get(target);
|
|
21850
|
-
}
|
|
21851
|
-
else {
|
|
21852
|
-
return null;
|
|
21853
|
-
}
|
|
21821
|
+
const symbolName = exports.exportMap.get(ref.node);
|
|
21822
|
+
return {
|
|
21823
|
+
expression: new ExternalExpr(new ExternalReference(specifier, symbolName)),
|
|
21824
|
+
importedFile: exports.module,
|
|
21825
|
+
};
|
|
21854
21826
|
}
|
|
21855
21827
|
getExportsOfModule(moduleName, fromFile) {
|
|
21856
21828
|
if (!this.moduleExportsCache.has(moduleName)) {
|
|
@@ -21872,7 +21844,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
21872
21844
|
exports.forEach((declaration, name) => {
|
|
21873
21845
|
exportMap.set(declaration.node, name);
|
|
21874
21846
|
});
|
|
21875
|
-
return exportMap;
|
|
21847
|
+
return { module: entryPointFile, exportMap };
|
|
21876
21848
|
}
|
|
21877
21849
|
}
|
|
21878
21850
|
/**
|
|
@@ -21913,7 +21885,10 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
21913
21885
|
// With both files expressed as LogicalProjectPaths, getting the module specifier as a relative
|
|
21914
21886
|
// path is now straightforward.
|
|
21915
21887
|
const moduleName = LogicalProjectPath.relativePathBetween(originPath, destPath);
|
|
21916
|
-
return
|
|
21888
|
+
return {
|
|
21889
|
+
expression: new ExternalExpr({ moduleName, name }),
|
|
21890
|
+
importedFile: destSf,
|
|
21891
|
+
};
|
|
21917
21892
|
}
|
|
21918
21893
|
}
|
|
21919
21894
|
/**
|
|
@@ -21931,7 +21906,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
21931
21906
|
const relativePath = relative(dirname(absoluteFromSourceFile(context)), absoluteFromSourceFile(destSf));
|
|
21932
21907
|
const moduleName = toRelativeImport(stripExtension(relativePath));
|
|
21933
21908
|
const name = findExportedNameOfNode(ref.node, destSf, this.reflector);
|
|
21934
|
-
return new ExternalExpr({ moduleName, name });
|
|
21909
|
+
return { expression: new ExternalExpr({ moduleName, name }), importedFile: destSf };
|
|
21935
21910
|
}
|
|
21936
21911
|
}
|
|
21937
21912
|
/**
|
|
@@ -21950,7 +21925,10 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
21950
21925
|
return null;
|
|
21951
21926
|
}
|
|
21952
21927
|
const moduleName = this.unifiedModulesHost.fileNameToModuleName(destSf.fileName, context.fileName);
|
|
21953
|
-
return
|
|
21928
|
+
return {
|
|
21929
|
+
expression: new ExternalExpr({ moduleName, name }),
|
|
21930
|
+
importedFile: destSf,
|
|
21931
|
+
};
|
|
21954
21932
|
}
|
|
21955
21933
|
}
|
|
21956
21934
|
|
|
@@ -22082,10 +22060,10 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
22082
22060
|
*/
|
|
22083
22061
|
class AliasStrategy {
|
|
22084
22062
|
emit(ref, context, importMode) {
|
|
22085
|
-
if (importMode & ImportFlags.NoAliasing) {
|
|
22063
|
+
if (importMode & ImportFlags.NoAliasing || ref.alias === null) {
|
|
22086
22064
|
return null;
|
|
22087
22065
|
}
|
|
22088
|
-
return ref.alias;
|
|
22066
|
+
return { expression: ref.alias, importedFile: 'unknown' };
|
|
22089
22067
|
}
|
|
22090
22068
|
}
|
|
22091
22069
|
|
|
@@ -22476,6 +22454,382 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
22476
22454
|
}
|
|
22477
22455
|
}
|
|
22478
22456
|
|
|
22457
|
+
/**
|
|
22458
|
+
* @license
|
|
22459
|
+
* Copyright Google LLC All Rights Reserved.
|
|
22460
|
+
*
|
|
22461
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
22462
|
+
* found in the LICENSE file at https://angular.io/license
|
|
22463
|
+
*/
|
|
22464
|
+
/**
|
|
22465
|
+
* Represents a symbol that is recognizable across incremental rebuilds, which enables the captured
|
|
22466
|
+
* metadata to be compared to the prior compilation. This allows for semantic understanding of
|
|
22467
|
+
* the changes that have been made in a rebuild, which potentially enables more reuse of work
|
|
22468
|
+
* from the prior compilation.
|
|
22469
|
+
*/
|
|
22470
|
+
class SemanticSymbol {
|
|
22471
|
+
constructor(
|
|
22472
|
+
/**
|
|
22473
|
+
* The declaration for this symbol.
|
|
22474
|
+
*/
|
|
22475
|
+
decl) {
|
|
22476
|
+
this.decl = decl;
|
|
22477
|
+
this.path = absoluteFromSourceFile(decl.getSourceFile());
|
|
22478
|
+
this.identifier = getSymbolIdentifier(decl);
|
|
22479
|
+
}
|
|
22480
|
+
}
|
|
22481
|
+
function getSymbolIdentifier(decl) {
|
|
22482
|
+
if (!ts$1.isSourceFile(decl.parent)) {
|
|
22483
|
+
return null;
|
|
22484
|
+
}
|
|
22485
|
+
// If this is a top-level class declaration, the class name is used as unique identifier.
|
|
22486
|
+
// Other scenarios are currently not supported and causes the symbol not to be identified
|
|
22487
|
+
// across rebuilds, unless the declaration node has not changed.
|
|
22488
|
+
return decl.name.text;
|
|
22489
|
+
}
|
|
22490
|
+
|
|
22491
|
+
/**
|
|
22492
|
+
* @license
|
|
22493
|
+
* Copyright Google LLC All Rights Reserved.
|
|
22494
|
+
*
|
|
22495
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
22496
|
+
* found in the LICENSE file at https://angular.io/license
|
|
22497
|
+
*/
|
|
22498
|
+
/**
|
|
22499
|
+
* Represents a declaration for which no semantic symbol has been registered. For example,
|
|
22500
|
+
* declarations from external dependencies have not been explicitly registered and are represented
|
|
22501
|
+
* by this symbol. This allows the unresolved symbol to still be compared to a symbol from a prior
|
|
22502
|
+
* compilation.
|
|
22503
|
+
*/
|
|
22504
|
+
class OpaqueSymbol extends SemanticSymbol {
|
|
22505
|
+
isPublicApiAffected() {
|
|
22506
|
+
return false;
|
|
22507
|
+
}
|
|
22508
|
+
isTypeCheckApiAffected() {
|
|
22509
|
+
return false;
|
|
22510
|
+
}
|
|
22511
|
+
}
|
|
22512
|
+
/**
|
|
22513
|
+
* The semantic dependency graph of a single compilation.
|
|
22514
|
+
*/
|
|
22515
|
+
class SemanticDepGraph {
|
|
22516
|
+
constructor() {
|
|
22517
|
+
this.files = new Map();
|
|
22518
|
+
this.symbolByDecl = new Map();
|
|
22519
|
+
}
|
|
22520
|
+
/**
|
|
22521
|
+
* Registers a symbol in the graph. The symbol is given a unique identifier if possible, such that
|
|
22522
|
+
* its equivalent symbol can be obtained from a prior graph even if its declaration node has
|
|
22523
|
+
* changed across rebuilds. Symbols without an identifier are only able to find themselves in a
|
|
22524
|
+
* prior graph if their declaration node is identical.
|
|
22525
|
+
*/
|
|
22526
|
+
registerSymbol(symbol) {
|
|
22527
|
+
this.symbolByDecl.set(symbol.decl, symbol);
|
|
22528
|
+
if (symbol.identifier !== null) {
|
|
22529
|
+
// If the symbol has a unique identifier, record it in the file that declares it. This enables
|
|
22530
|
+
// the symbol to be requested by its unique name.
|
|
22531
|
+
if (!this.files.has(symbol.path)) {
|
|
22532
|
+
this.files.set(symbol.path, new Map());
|
|
22533
|
+
}
|
|
22534
|
+
this.files.get(symbol.path).set(symbol.identifier, symbol);
|
|
22535
|
+
}
|
|
22536
|
+
}
|
|
22537
|
+
/**
|
|
22538
|
+
* Attempts to resolve a symbol in this graph that represents the given symbol from another graph.
|
|
22539
|
+
* If no matching symbol could be found, null is returned.
|
|
22540
|
+
*
|
|
22541
|
+
* @param symbol The symbol from another graph for which its equivalent in this graph should be
|
|
22542
|
+
* found.
|
|
22543
|
+
*/
|
|
22544
|
+
getEquivalentSymbol(symbol) {
|
|
22545
|
+
// First lookup the symbol by its declaration. It is typical for the declaration to not have
|
|
22546
|
+
// changed across rebuilds, so this is likely to find the symbol. Using the declaration also
|
|
22547
|
+
// allows to diff symbols for which no unique identifier could be determined.
|
|
22548
|
+
let previousSymbol = this.getSymbolByDecl(symbol.decl);
|
|
22549
|
+
if (previousSymbol === null && symbol.identifier !== null) {
|
|
22550
|
+
// The declaration could not be resolved to a symbol in a prior compilation, which may
|
|
22551
|
+
// happen because the file containing the declaration has changed. In that case we want to
|
|
22552
|
+
// lookup the symbol based on its unique identifier, as that allows us to still compare the
|
|
22553
|
+
// changed declaration to the prior compilation.
|
|
22554
|
+
previousSymbol = this.getSymbolByName(symbol.path, symbol.identifier);
|
|
22555
|
+
}
|
|
22556
|
+
return previousSymbol;
|
|
22557
|
+
}
|
|
22558
|
+
/**
|
|
22559
|
+
* Attempts to find the symbol by its identifier.
|
|
22560
|
+
*/
|
|
22561
|
+
getSymbolByName(path, identifier) {
|
|
22562
|
+
if (!this.files.has(path)) {
|
|
22563
|
+
return null;
|
|
22564
|
+
}
|
|
22565
|
+
const file = this.files.get(path);
|
|
22566
|
+
if (!file.has(identifier)) {
|
|
22567
|
+
return null;
|
|
22568
|
+
}
|
|
22569
|
+
return file.get(identifier);
|
|
22570
|
+
}
|
|
22571
|
+
/**
|
|
22572
|
+
* Attempts to resolve the declaration to its semantic symbol.
|
|
22573
|
+
*/
|
|
22574
|
+
getSymbolByDecl(decl) {
|
|
22575
|
+
if (!this.symbolByDecl.has(decl)) {
|
|
22576
|
+
return null;
|
|
22577
|
+
}
|
|
22578
|
+
return this.symbolByDecl.get(decl);
|
|
22579
|
+
}
|
|
22580
|
+
}
|
|
22581
|
+
/**
|
|
22582
|
+
* Implements the logic to go from a previous dependency graph to a new one, along with information
|
|
22583
|
+
* on which files have been affected.
|
|
22584
|
+
*/
|
|
22585
|
+
class SemanticDepGraphUpdater {
|
|
22586
|
+
constructor(
|
|
22587
|
+
/**
|
|
22588
|
+
* The semantic dependency graph of the most recently succeeded compilation, or null if this
|
|
22589
|
+
* is the initial build.
|
|
22590
|
+
*/
|
|
22591
|
+
priorGraph) {
|
|
22592
|
+
this.priorGraph = priorGraph;
|
|
22593
|
+
this.newGraph = new SemanticDepGraph();
|
|
22594
|
+
/**
|
|
22595
|
+
* Contains opaque symbols that were created for declarations for which there was no symbol
|
|
22596
|
+
* registered, which happens for e.g. external declarations.
|
|
22597
|
+
*/
|
|
22598
|
+
this.opaqueSymbols = new Map();
|
|
22599
|
+
}
|
|
22600
|
+
/**
|
|
22601
|
+
* Registers the symbol in the new graph that is being created.
|
|
22602
|
+
*/
|
|
22603
|
+
registerSymbol(symbol) {
|
|
22604
|
+
this.newGraph.registerSymbol(symbol);
|
|
22605
|
+
}
|
|
22606
|
+
/**
|
|
22607
|
+
* Takes all facts that have been gathered to create a new semantic dependency graph. In this
|
|
22608
|
+
* process, the semantic impact of the changes is determined which results in a set of files that
|
|
22609
|
+
* need to be emitted and/or type-checked.
|
|
22610
|
+
*/
|
|
22611
|
+
finalize() {
|
|
22612
|
+
if (this.priorGraph === null) {
|
|
22613
|
+
// If no prior dependency graph is available then this was the initial build, in which case
|
|
22614
|
+
// we don't need to determine the semantic impact as everything is already considered
|
|
22615
|
+
// logically changed.
|
|
22616
|
+
return {
|
|
22617
|
+
needsEmit: new Set(),
|
|
22618
|
+
needsTypeCheckEmit: new Set(),
|
|
22619
|
+
newGraph: this.newGraph,
|
|
22620
|
+
};
|
|
22621
|
+
}
|
|
22622
|
+
const needsEmit = this.determineInvalidatedFiles(this.priorGraph);
|
|
22623
|
+
const needsTypeCheckEmit = this.determineInvalidatedTypeCheckFiles(this.priorGraph);
|
|
22624
|
+
return {
|
|
22625
|
+
needsEmit,
|
|
22626
|
+
needsTypeCheckEmit,
|
|
22627
|
+
newGraph: this.newGraph,
|
|
22628
|
+
};
|
|
22629
|
+
}
|
|
22630
|
+
determineInvalidatedFiles(priorGraph) {
|
|
22631
|
+
const isPublicApiAffected = new Set();
|
|
22632
|
+
// The first phase is to collect all symbols which have their public API affected. Any symbols
|
|
22633
|
+
// that cannot be matched up with a symbol from the prior graph are considered affected.
|
|
22634
|
+
for (const symbol of this.newGraph.symbolByDecl.values()) {
|
|
22635
|
+
const previousSymbol = priorGraph.getEquivalentSymbol(symbol);
|
|
22636
|
+
if (previousSymbol === null || symbol.isPublicApiAffected(previousSymbol)) {
|
|
22637
|
+
isPublicApiAffected.add(symbol);
|
|
22638
|
+
}
|
|
22639
|
+
}
|
|
22640
|
+
// The second phase is to find all symbols for which the emit result is affected, either because
|
|
22641
|
+
// their used declarations have changed or any of those used declarations has had its public API
|
|
22642
|
+
// affected as determined in the first phase.
|
|
22643
|
+
const needsEmit = new Set();
|
|
22644
|
+
for (const symbol of this.newGraph.symbolByDecl.values()) {
|
|
22645
|
+
if (symbol.isEmitAffected === undefined) {
|
|
22646
|
+
continue;
|
|
22647
|
+
}
|
|
22648
|
+
const previousSymbol = priorGraph.getEquivalentSymbol(symbol);
|
|
22649
|
+
if (previousSymbol === null || symbol.isEmitAffected(previousSymbol, isPublicApiAffected)) {
|
|
22650
|
+
needsEmit.add(symbol.path);
|
|
22651
|
+
}
|
|
22652
|
+
}
|
|
22653
|
+
return needsEmit;
|
|
22654
|
+
}
|
|
22655
|
+
determineInvalidatedTypeCheckFiles(priorGraph) {
|
|
22656
|
+
const isTypeCheckApiAffected = new Set();
|
|
22657
|
+
// The first phase is to collect all symbols which have their public API affected. Any symbols
|
|
22658
|
+
// that cannot be matched up with a symbol from the prior graph are considered affected.
|
|
22659
|
+
for (const symbol of this.newGraph.symbolByDecl.values()) {
|
|
22660
|
+
const previousSymbol = priorGraph.getEquivalentSymbol(symbol);
|
|
22661
|
+
if (previousSymbol === null || symbol.isTypeCheckApiAffected(previousSymbol)) {
|
|
22662
|
+
isTypeCheckApiAffected.add(symbol);
|
|
22663
|
+
}
|
|
22664
|
+
}
|
|
22665
|
+
// The second phase is to find all symbols for which the emit result is affected, either because
|
|
22666
|
+
// their used declarations have changed or any of those used declarations has had its public API
|
|
22667
|
+
// affected as determined in the first phase.
|
|
22668
|
+
const needsTypeCheckEmit = new Set();
|
|
22669
|
+
for (const symbol of this.newGraph.symbolByDecl.values()) {
|
|
22670
|
+
if (symbol.isTypeCheckBlockAffected === undefined) {
|
|
22671
|
+
continue;
|
|
22672
|
+
}
|
|
22673
|
+
const previousSymbol = priorGraph.getEquivalentSymbol(symbol);
|
|
22674
|
+
if (previousSymbol === null ||
|
|
22675
|
+
symbol.isTypeCheckBlockAffected(previousSymbol, isTypeCheckApiAffected)) {
|
|
22676
|
+
needsTypeCheckEmit.add(symbol.path);
|
|
22677
|
+
}
|
|
22678
|
+
}
|
|
22679
|
+
return needsTypeCheckEmit;
|
|
22680
|
+
}
|
|
22681
|
+
/**
|
|
22682
|
+
* Creates a `SemanticReference` for the reference to `decl` using the expression `expr`. See
|
|
22683
|
+
* the documentation of `SemanticReference` for details.
|
|
22684
|
+
*/
|
|
22685
|
+
getSemanticReference(decl, expr) {
|
|
22686
|
+
return {
|
|
22687
|
+
symbol: this.getSymbol(decl),
|
|
22688
|
+
importPath: getImportPath(expr),
|
|
22689
|
+
};
|
|
22690
|
+
}
|
|
22691
|
+
/**
|
|
22692
|
+
* Gets the `SemanticSymbol` that was registered for `decl` during the current compilation, or
|
|
22693
|
+
* returns an opaque symbol that represents `decl`.
|
|
22694
|
+
*/
|
|
22695
|
+
getSymbol(decl) {
|
|
22696
|
+
const symbol = this.newGraph.getSymbolByDecl(decl);
|
|
22697
|
+
if (symbol === null) {
|
|
22698
|
+
// No symbol has been recorded for the provided declaration, which would be the case if the
|
|
22699
|
+
// declaration is external. Return an opaque symbol in that case, to allow the external
|
|
22700
|
+
// declaration to be compared to a prior compilation.
|
|
22701
|
+
return this.getOpaqueSymbol(decl);
|
|
22702
|
+
}
|
|
22703
|
+
return symbol;
|
|
22704
|
+
}
|
|
22705
|
+
/**
|
|
22706
|
+
* Gets or creates an `OpaqueSymbol` for the provided class declaration.
|
|
22707
|
+
*/
|
|
22708
|
+
getOpaqueSymbol(decl) {
|
|
22709
|
+
if (this.opaqueSymbols.has(decl)) {
|
|
22710
|
+
return this.opaqueSymbols.get(decl);
|
|
22711
|
+
}
|
|
22712
|
+
const symbol = new OpaqueSymbol(decl);
|
|
22713
|
+
this.opaqueSymbols.set(decl, symbol);
|
|
22714
|
+
return symbol;
|
|
22715
|
+
}
|
|
22716
|
+
}
|
|
22717
|
+
function getImportPath(expr) {
|
|
22718
|
+
if (expr instanceof ExternalExpr) {
|
|
22719
|
+
return `${expr.value.moduleName}\$${expr.value.name}`;
|
|
22720
|
+
}
|
|
22721
|
+
else {
|
|
22722
|
+
return null;
|
|
22723
|
+
}
|
|
22724
|
+
}
|
|
22725
|
+
|
|
22726
|
+
/**
|
|
22727
|
+
* Determines whether the provided symbols represent the same declaration.
|
|
22728
|
+
*/
|
|
22729
|
+
function isSymbolEqual(a, b) {
|
|
22730
|
+
if (a.decl === b.decl) {
|
|
22731
|
+
// If the declaration is identical then it must represent the same symbol.
|
|
22732
|
+
return true;
|
|
22733
|
+
}
|
|
22734
|
+
if (a.identifier === null || b.identifier === null) {
|
|
22735
|
+
// Unidentifiable symbols are assumed to be different.
|
|
22736
|
+
return false;
|
|
22737
|
+
}
|
|
22738
|
+
return a.path === b.path && a.identifier === b.identifier;
|
|
22739
|
+
}
|
|
22740
|
+
/**
|
|
22741
|
+
* Determines whether the provided references to a semantic symbol are still equal, i.e. represent
|
|
22742
|
+
* the same symbol and are imported by the same path.
|
|
22743
|
+
*/
|
|
22744
|
+
function isReferenceEqual(a, b) {
|
|
22745
|
+
if (!isSymbolEqual(a.symbol, b.symbol)) {
|
|
22746
|
+
// If the reference's target symbols are different, the reference itself is different.
|
|
22747
|
+
return false;
|
|
22748
|
+
}
|
|
22749
|
+
// The reference still corresponds with the same symbol, now check that the path by which it is
|
|
22750
|
+
// imported has not changed.
|
|
22751
|
+
return a.importPath === b.importPath;
|
|
22752
|
+
}
|
|
22753
|
+
function referenceEquality(a, b) {
|
|
22754
|
+
return a === b;
|
|
22755
|
+
}
|
|
22756
|
+
/**
|
|
22757
|
+
* Determines if the provided arrays are equal to each other, using the provided equality tester
|
|
22758
|
+
* that is called for all entries in the array.
|
|
22759
|
+
*/
|
|
22760
|
+
function isArrayEqual(a, b, equalityTester = referenceEquality) {
|
|
22761
|
+
if (a === null || b === null) {
|
|
22762
|
+
return a === b;
|
|
22763
|
+
}
|
|
22764
|
+
if (a.length !== b.length) {
|
|
22765
|
+
return false;
|
|
22766
|
+
}
|
|
22767
|
+
return !a.some((item, index) => !equalityTester(item, b[index]));
|
|
22768
|
+
}
|
|
22769
|
+
/**
|
|
22770
|
+
* Determines if the provided sets are equal to each other, using the provided equality tester.
|
|
22771
|
+
* Sets that only differ in ordering are considered equal.
|
|
22772
|
+
*/
|
|
22773
|
+
function isSetEqual(a, b, equalityTester = referenceEquality) {
|
|
22774
|
+
if (a === null || b === null) {
|
|
22775
|
+
return a === b;
|
|
22776
|
+
}
|
|
22777
|
+
if (a.size !== b.size) {
|
|
22778
|
+
return false;
|
|
22779
|
+
}
|
|
22780
|
+
for (const itemA of a) {
|
|
22781
|
+
let found = false;
|
|
22782
|
+
for (const itemB of b) {
|
|
22783
|
+
if (equalityTester(itemA, itemB)) {
|
|
22784
|
+
found = true;
|
|
22785
|
+
break;
|
|
22786
|
+
}
|
|
22787
|
+
}
|
|
22788
|
+
if (!found) {
|
|
22789
|
+
return false;
|
|
22790
|
+
}
|
|
22791
|
+
}
|
|
22792
|
+
return true;
|
|
22793
|
+
}
|
|
22794
|
+
|
|
22795
|
+
/**
|
|
22796
|
+
* @license
|
|
22797
|
+
* Copyright Google LLC All Rights Reserved.
|
|
22798
|
+
*
|
|
22799
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
22800
|
+
* found in the LICENSE file at https://angular.io/license
|
|
22801
|
+
*/
|
|
22802
|
+
/**
|
|
22803
|
+
* Converts the type parameters of the given class into their semantic representation. If the class
|
|
22804
|
+
* does not have any type parameters, then `null` is returned.
|
|
22805
|
+
*/
|
|
22806
|
+
function extractSemanticTypeParameters(node) {
|
|
22807
|
+
if (!ts$1.isClassDeclaration(node) || node.typeParameters === undefined) {
|
|
22808
|
+
return null;
|
|
22809
|
+
}
|
|
22810
|
+
return node.typeParameters.map(typeParam => ({ hasGenericTypeBound: typeParam.constraint !== undefined }));
|
|
22811
|
+
}
|
|
22812
|
+
/**
|
|
22813
|
+
* Compares the list of type parameters to determine if they can be considered equal.
|
|
22814
|
+
*/
|
|
22815
|
+
function areTypeParametersEqual(current, previous) {
|
|
22816
|
+
// First compare all type parameters one-to-one; any differences mean that the list of type
|
|
22817
|
+
// parameters has changed.
|
|
22818
|
+
if (!isArrayEqual(current, previous, isTypeParameterEqual)) {
|
|
22819
|
+
return false;
|
|
22820
|
+
}
|
|
22821
|
+
// If there is a current list of type parameters and if any of them has a generic type constraint,
|
|
22822
|
+
// then the meaning of that type parameter may have changed without us being aware; as such we
|
|
22823
|
+
// have to assume that the type parameters have in fact changed.
|
|
22824
|
+
if (current !== null && current.some(typeParam => typeParam.hasGenericTypeBound)) {
|
|
22825
|
+
return false;
|
|
22826
|
+
}
|
|
22827
|
+
return true;
|
|
22828
|
+
}
|
|
22829
|
+
function isTypeParameterEqual(a, b) {
|
|
22830
|
+
return a.hasGenericTypeBound === b.hasGenericTypeBound;
|
|
22831
|
+
}
|
|
22832
|
+
|
|
22479
22833
|
/**
|
|
22480
22834
|
* @license
|
|
22481
22835
|
* Copyright Google LLC All Rights Reserved.
|
|
@@ -25267,17 +25621,19 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
25267
25621
|
constructor(handler, detected) {
|
|
25268
25622
|
this.state = TraitState.Pending;
|
|
25269
25623
|
this.analysis = null;
|
|
25624
|
+
this.symbol = null;
|
|
25270
25625
|
this.resolution = null;
|
|
25271
25626
|
this.analysisDiagnostics = null;
|
|
25272
25627
|
this.resolveDiagnostics = null;
|
|
25273
25628
|
this.handler = handler;
|
|
25274
25629
|
this.detected = detected;
|
|
25275
25630
|
}
|
|
25276
|
-
toAnalyzed(analysis, diagnostics) {
|
|
25631
|
+
toAnalyzed(analysis, diagnostics, symbol) {
|
|
25277
25632
|
// Only pending traits can be analyzed.
|
|
25278
25633
|
this.assertTransitionLegal(TraitState.Pending, TraitState.Analyzed);
|
|
25279
25634
|
this.analysis = analysis;
|
|
25280
25635
|
this.analysisDiagnostics = diagnostics;
|
|
25636
|
+
this.symbol = symbol;
|
|
25281
25637
|
this.state = TraitState.Analyzed;
|
|
25282
25638
|
return this;
|
|
25283
25639
|
}
|
|
@@ -25338,7 +25694,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
25338
25694
|
* class (like adding fields or type declarations).
|
|
25339
25695
|
*/
|
|
25340
25696
|
class TraitCompiler {
|
|
25341
|
-
constructor(handlers, reflector, perf, incrementalBuild, compileNonExportedClasses, compilationMode, dtsTransforms) {
|
|
25697
|
+
constructor(handlers, reflector, perf, incrementalBuild, compileNonExportedClasses, compilationMode, dtsTransforms, semanticDepGraphUpdater) {
|
|
25342
25698
|
this.handlers = handlers;
|
|
25343
25699
|
this.reflector = reflector;
|
|
25344
25700
|
this.perf = perf;
|
|
@@ -25346,6 +25702,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
25346
25702
|
this.compileNonExportedClasses = compileNonExportedClasses;
|
|
25347
25703
|
this.compilationMode = compilationMode;
|
|
25348
25704
|
this.dtsTransforms = dtsTransforms;
|
|
25705
|
+
this.semanticDepGraphUpdater = semanticDepGraphUpdater;
|
|
25349
25706
|
/**
|
|
25350
25707
|
* Maps class declarations to their `ClassRecord`, which tracks the Ivy traits being applied to
|
|
25351
25708
|
* those classes.
|
|
@@ -25436,7 +25793,8 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
25436
25793
|
const handler = this.handlersByName.get(priorTrait.handler.name);
|
|
25437
25794
|
let trait = Trait.pending(handler, priorTrait.detected);
|
|
25438
25795
|
if (priorTrait.state === TraitState.Analyzed || priorTrait.state === TraitState.Resolved) {
|
|
25439
|
-
|
|
25796
|
+
const symbol = this.makeSymbolForTrait(handler, record.node, priorTrait.analysis);
|
|
25797
|
+
trait = trait.toAnalyzed(priorTrait.analysis, priorTrait.analysisDiagnostics, symbol);
|
|
25440
25798
|
if (trait.analysis !== null && trait.handler.register !== undefined) {
|
|
25441
25799
|
trait.handler.register(record.node, trait.analysis);
|
|
25442
25800
|
}
|
|
@@ -25531,6 +25889,20 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
25531
25889
|
}
|
|
25532
25890
|
return foundTraits.length > 0 ? foundTraits : null;
|
|
25533
25891
|
}
|
|
25892
|
+
makeSymbolForTrait(handler, decl, analysis) {
|
|
25893
|
+
if (analysis === null) {
|
|
25894
|
+
return null;
|
|
25895
|
+
}
|
|
25896
|
+
const symbol = handler.symbol(decl, analysis);
|
|
25897
|
+
if (symbol !== null && this.semanticDepGraphUpdater !== null) {
|
|
25898
|
+
const isPrimary = handler.precedence === HandlerPrecedence.PRIMARY;
|
|
25899
|
+
if (!isPrimary) {
|
|
25900
|
+
throw new Error(`AssertionError: ${handler.name} returned a symbol but is not a primary handler.`);
|
|
25901
|
+
}
|
|
25902
|
+
this.semanticDepGraphUpdater.registerSymbol(symbol);
|
|
25903
|
+
}
|
|
25904
|
+
return symbol;
|
|
25905
|
+
}
|
|
25534
25906
|
analyzeClass(clazz, preanalyzeQueue) {
|
|
25535
25907
|
const traits = this.scanClassForTraits(clazz);
|
|
25536
25908
|
if (traits === null) {
|
|
@@ -25548,7 +25920,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
25548
25920
|
}
|
|
25549
25921
|
catch (err) {
|
|
25550
25922
|
if (err instanceof FatalDiagnosticError) {
|
|
25551
|
-
trait.toAnalyzed(null, [err.toDiagnostic()]);
|
|
25923
|
+
trait.toAnalyzed(null, [err.toDiagnostic()], null);
|
|
25552
25924
|
return;
|
|
25553
25925
|
}
|
|
25554
25926
|
else {
|
|
@@ -25565,7 +25937,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
25565
25937
|
}
|
|
25566
25938
|
}
|
|
25567
25939
|
analyzeTrait(clazz, trait, flags) {
|
|
25568
|
-
var _a, _b;
|
|
25940
|
+
var _a, _b, _c;
|
|
25569
25941
|
if (trait.state !== TraitState.Pending) {
|
|
25570
25942
|
throw new Error(`Attempt to analyze trait of ${clazz.name.text} in state ${TraitState[trait.state]} (expected DETECTED)`);
|
|
25571
25943
|
}
|
|
@@ -25576,17 +25948,18 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
25576
25948
|
}
|
|
25577
25949
|
catch (err) {
|
|
25578
25950
|
if (err instanceof FatalDiagnosticError) {
|
|
25579
|
-
trait.toAnalyzed(null, [err.toDiagnostic()]);
|
|
25951
|
+
trait.toAnalyzed(null, [err.toDiagnostic()], null);
|
|
25580
25952
|
return;
|
|
25581
25953
|
}
|
|
25582
25954
|
else {
|
|
25583
25955
|
throw err;
|
|
25584
25956
|
}
|
|
25585
25957
|
}
|
|
25958
|
+
const symbol = this.makeSymbolForTrait(trait.handler, clazz, (_a = result.analysis) !== null && _a !== void 0 ? _a : null);
|
|
25586
25959
|
if (result.analysis !== undefined && trait.handler.register !== undefined) {
|
|
25587
25960
|
trait.handler.register(clazz, result.analysis);
|
|
25588
25961
|
}
|
|
25589
|
-
trait = trait.toAnalyzed((
|
|
25962
|
+
trait = trait.toAnalyzed((_b = result.analysis) !== null && _b !== void 0 ? _b : null, (_c = result.diagnostics) !== null && _c !== void 0 ? _c : null, symbol);
|
|
25590
25963
|
}
|
|
25591
25964
|
resolve() {
|
|
25592
25965
|
var _a, _b;
|
|
@@ -25614,7 +25987,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
25614
25987
|
}
|
|
25615
25988
|
let result;
|
|
25616
25989
|
try {
|
|
25617
|
-
result = handler.resolve(clazz, trait.analysis);
|
|
25990
|
+
result = handler.resolve(clazz, trait.analysis, trait.symbol);
|
|
25618
25991
|
}
|
|
25619
25992
|
catch (err) {
|
|
25620
25993
|
if (err instanceof FatalDiagnosticError) {
|
|
@@ -27545,12 +27918,12 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
27545
27918
|
return new FatalDiagnosticError(ErrorCode.PARAM_MISSING_TOKEN, param.nameNode, chain, hints);
|
|
27546
27919
|
}
|
|
27547
27920
|
function toR3Reference(valueRef, typeRef, valueContext, typeContext, refEmitter) {
|
|
27548
|
-
|
|
27549
|
-
|
|
27550
|
-
|
|
27551
|
-
|
|
27552
|
-
|
|
27553
|
-
|
|
27921
|
+
return {
|
|
27922
|
+
value: refEmitter.emit(valueRef, valueContext).expression,
|
|
27923
|
+
type: refEmitter
|
|
27924
|
+
.emit(typeRef, typeContext, ImportFlags.ForceNewImport | ImportFlags.AllowTypeImports)
|
|
27925
|
+
.expression,
|
|
27926
|
+
};
|
|
27554
27927
|
}
|
|
27555
27928
|
function isAngularCore(decorator) {
|
|
27556
27929
|
return decorator.import !== null && decorator.import.from === '@angular/core';
|
|
@@ -28118,8 +28491,112 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
28118
28491
|
'ngOnChanges', 'ngOnInit', 'ngOnDestroy', 'ngDoCheck', 'ngAfterViewInit', 'ngAfterViewChecked',
|
|
28119
28492
|
'ngAfterContentInit', 'ngAfterContentChecked'
|
|
28120
28493
|
]);
|
|
28494
|
+
/**
|
|
28495
|
+
* Represents an Angular directive. Components are represented by `ComponentSymbol`, which inherits
|
|
28496
|
+
* from this symbol.
|
|
28497
|
+
*/
|
|
28498
|
+
class DirectiveSymbol extends SemanticSymbol {
|
|
28499
|
+
constructor(decl, selector, inputs, outputs, exportAs, typeCheckMeta, typeParameters) {
|
|
28500
|
+
super(decl);
|
|
28501
|
+
this.selector = selector;
|
|
28502
|
+
this.inputs = inputs;
|
|
28503
|
+
this.outputs = outputs;
|
|
28504
|
+
this.exportAs = exportAs;
|
|
28505
|
+
this.typeCheckMeta = typeCheckMeta;
|
|
28506
|
+
this.typeParameters = typeParameters;
|
|
28507
|
+
this.baseClass = null;
|
|
28508
|
+
}
|
|
28509
|
+
isPublicApiAffected(previousSymbol) {
|
|
28510
|
+
// Note: since components and directives have exactly the same items contributing to their
|
|
28511
|
+
// public API, it is okay for a directive to change into a component and vice versa without
|
|
28512
|
+
// the API being affected.
|
|
28513
|
+
if (!(previousSymbol instanceof DirectiveSymbol)) {
|
|
28514
|
+
return true;
|
|
28515
|
+
}
|
|
28516
|
+
// Directives and components have a public API of:
|
|
28517
|
+
// 1. Their selector.
|
|
28518
|
+
// 2. The binding names of their inputs and outputs; a change in ordering is also considered
|
|
28519
|
+
// to be a change in public API.
|
|
28520
|
+
// 3. The list of exportAs names and its ordering.
|
|
28521
|
+
return this.selector !== previousSymbol.selector ||
|
|
28522
|
+
!isArrayEqual(this.inputs.propertyNames, previousSymbol.inputs.propertyNames) ||
|
|
28523
|
+
!isArrayEqual(this.outputs.propertyNames, previousSymbol.outputs.propertyNames) ||
|
|
28524
|
+
!isArrayEqual(this.exportAs, previousSymbol.exportAs);
|
|
28525
|
+
}
|
|
28526
|
+
isTypeCheckApiAffected(previousSymbol) {
|
|
28527
|
+
// If the public API of the directive has changed, then so has its type-check API.
|
|
28528
|
+
if (this.isPublicApiAffected(previousSymbol)) {
|
|
28529
|
+
return true;
|
|
28530
|
+
}
|
|
28531
|
+
if (!(previousSymbol instanceof DirectiveSymbol)) {
|
|
28532
|
+
return true;
|
|
28533
|
+
}
|
|
28534
|
+
// The type-check block also depends on the class property names, as writes property bindings
|
|
28535
|
+
// directly into the backing fields.
|
|
28536
|
+
if (!isArrayEqual(Array.from(this.inputs), Array.from(previousSymbol.inputs), isInputMappingEqual) ||
|
|
28537
|
+
!isArrayEqual(Array.from(this.outputs), Array.from(previousSymbol.outputs), isInputMappingEqual)) {
|
|
28538
|
+
return true;
|
|
28539
|
+
}
|
|
28540
|
+
// The type parameters of a directive are emitted into the type constructors in the type-check
|
|
28541
|
+
// block of a component, so if the type parameters are not considered equal then consider the
|
|
28542
|
+
// type-check API of this directive to be affected.
|
|
28543
|
+
if (!areTypeParametersEqual(this.typeParameters, previousSymbol.typeParameters)) {
|
|
28544
|
+
return true;
|
|
28545
|
+
}
|
|
28546
|
+
// The type-check metadata is used during TCB code generation, so any changes should invalidate
|
|
28547
|
+
// prior type-check files.
|
|
28548
|
+
if (!isTypeCheckMetaEqual(this.typeCheckMeta, previousSymbol.typeCheckMeta)) {
|
|
28549
|
+
return true;
|
|
28550
|
+
}
|
|
28551
|
+
// Changing the base class of a directive means that its inputs/outputs etc may have changed,
|
|
28552
|
+
// so the type-check block of components that use this directive needs to be regenerated.
|
|
28553
|
+
if (!isBaseClassEqual(this.baseClass, previousSymbol.baseClass)) {
|
|
28554
|
+
return true;
|
|
28555
|
+
}
|
|
28556
|
+
return false;
|
|
28557
|
+
}
|
|
28558
|
+
}
|
|
28559
|
+
function isInputMappingEqual(current, previous) {
|
|
28560
|
+
return current[0] === previous[0] && current[1] === previous[1];
|
|
28561
|
+
}
|
|
28562
|
+
function isTypeCheckMetaEqual(current, previous) {
|
|
28563
|
+
if (current.hasNgTemplateContextGuard !== previous.hasNgTemplateContextGuard) {
|
|
28564
|
+
return false;
|
|
28565
|
+
}
|
|
28566
|
+
if (current.isGeneric !== previous.isGeneric) {
|
|
28567
|
+
// Note: changes in the number of type parameters is also considered in `areTypeParametersEqual`
|
|
28568
|
+
// so this check is technically not needed; it is done anyway for completeness in terms of
|
|
28569
|
+
// whether the `DirectiveTypeCheckMeta` struct itself compares equal or not.
|
|
28570
|
+
return false;
|
|
28571
|
+
}
|
|
28572
|
+
if (!isArrayEqual(current.ngTemplateGuards, previous.ngTemplateGuards, isTemplateGuardEqual)) {
|
|
28573
|
+
return false;
|
|
28574
|
+
}
|
|
28575
|
+
if (!isSetEqual(current.coercedInputFields, previous.coercedInputFields)) {
|
|
28576
|
+
return false;
|
|
28577
|
+
}
|
|
28578
|
+
if (!isSetEqual(current.restrictedInputFields, previous.restrictedInputFields)) {
|
|
28579
|
+
return false;
|
|
28580
|
+
}
|
|
28581
|
+
if (!isSetEqual(current.stringLiteralInputFields, previous.stringLiteralInputFields)) {
|
|
28582
|
+
return false;
|
|
28583
|
+
}
|
|
28584
|
+
if (!isSetEqual(current.undeclaredInputFields, previous.undeclaredInputFields)) {
|
|
28585
|
+
return false;
|
|
28586
|
+
}
|
|
28587
|
+
return true;
|
|
28588
|
+
}
|
|
28589
|
+
function isTemplateGuardEqual(current, previous) {
|
|
28590
|
+
return current.inputName === previous.inputName && current.type === previous.type;
|
|
28591
|
+
}
|
|
28592
|
+
function isBaseClassEqual(current, previous) {
|
|
28593
|
+
if (current === null || previous === null) {
|
|
28594
|
+
return current === previous;
|
|
28595
|
+
}
|
|
28596
|
+
return isSymbolEqual(current, previous);
|
|
28597
|
+
}
|
|
28121
28598
|
class DirectiveDecoratorHandler {
|
|
28122
|
-
constructor(reflector, evaluator, metaRegistry, scopeRegistry, metaReader, defaultImportRecorder, injectableRegistry, isCore, annotateForClosureCompiler, compileUndecoratedClassesWithAngularFeatures) {
|
|
28599
|
+
constructor(reflector, evaluator, metaRegistry, scopeRegistry, metaReader, defaultImportRecorder, injectableRegistry, isCore, semanticDepGraphUpdater, annotateForClosureCompiler, compileUndecoratedClassesWithAngularFeatures) {
|
|
28123
28600
|
this.reflector = reflector;
|
|
28124
28601
|
this.evaluator = evaluator;
|
|
28125
28602
|
this.metaRegistry = metaRegistry;
|
|
@@ -28128,6 +28605,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
28128
28605
|
this.defaultImportRecorder = defaultImportRecorder;
|
|
28129
28606
|
this.injectableRegistry = injectableRegistry;
|
|
28130
28607
|
this.isCore = isCore;
|
|
28608
|
+
this.semanticDepGraphUpdater = semanticDepGraphUpdater;
|
|
28131
28609
|
this.annotateForClosureCompiler = annotateForClosureCompiler;
|
|
28132
28610
|
this.compileUndecoratedClassesWithAngularFeatures = compileUndecoratedClassesWithAngularFeatures;
|
|
28133
28611
|
this.precedence = HandlerPrecedence.PRIMARY;
|
|
@@ -28179,6 +28657,10 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
28179
28657
|
}
|
|
28180
28658
|
};
|
|
28181
28659
|
}
|
|
28660
|
+
symbol(node, analysis) {
|
|
28661
|
+
const typeParameters = extractSemanticTypeParameters(node);
|
|
28662
|
+
return new DirectiveSymbol(node, analysis.meta.selector, analysis.inputs, analysis.outputs, analysis.meta.exportAs, analysis.typeCheckMeta, typeParameters);
|
|
28663
|
+
}
|
|
28182
28664
|
register(node, analysis) {
|
|
28183
28665
|
// Register this directive's information with the `MetadataRegistry`. This ensures that
|
|
28184
28666
|
// the information about the directive is available during the compile() phase.
|
|
@@ -28186,7 +28668,10 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
28186
28668
|
this.metaRegistry.registerDirectiveMetadata(Object.assign(Object.assign({ ref, name: node.name.text, selector: analysis.meta.selector, exportAs: analysis.meta.exportAs, inputs: analysis.inputs, outputs: analysis.outputs, queries: analysis.meta.queries.map(query => query.propertyName), isComponent: false, baseClass: analysis.baseClass }, analysis.typeCheckMeta), { isPoisoned: analysis.isPoisoned, isStructural: analysis.isStructural }));
|
|
28187
28669
|
this.injectableRegistry.registerInjectable(node);
|
|
28188
28670
|
}
|
|
28189
|
-
resolve(node, analysis) {
|
|
28671
|
+
resolve(node, analysis, symbol) {
|
|
28672
|
+
if (this.semanticDepGraphUpdater !== null && analysis.baseClass instanceof Reference$1) {
|
|
28673
|
+
symbol.baseClass = this.semanticDepGraphUpdater.getSymbol(analysis.baseClass.node);
|
|
28674
|
+
}
|
|
28190
28675
|
const diagnostics = [];
|
|
28191
28676
|
if (analysis.providersRequiringFactory !== null &&
|
|
28192
28677
|
analysis.meta.providers instanceof WrappedNodeExpr) {
|
|
@@ -28679,6 +29164,525 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
28679
29164
|
'ViewChildren',
|
|
28680
29165
|
]);
|
|
28681
29166
|
|
|
29167
|
+
/**
|
|
29168
|
+
* @license
|
|
29169
|
+
* Copyright Google LLC All Rights Reserved.
|
|
29170
|
+
*
|
|
29171
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
29172
|
+
* found in the LICENSE file at https://angular.io/license
|
|
29173
|
+
*/
|
|
29174
|
+
/**
|
|
29175
|
+
* Represents an Angular NgModule.
|
|
29176
|
+
*/
|
|
29177
|
+
class NgModuleSymbol extends SemanticSymbol {
|
|
29178
|
+
constructor() {
|
|
29179
|
+
super(...arguments);
|
|
29180
|
+
this.remotelyScopedComponents = [];
|
|
29181
|
+
}
|
|
29182
|
+
isPublicApiAffected(previousSymbol) {
|
|
29183
|
+
if (!(previousSymbol instanceof NgModuleSymbol)) {
|
|
29184
|
+
return true;
|
|
29185
|
+
}
|
|
29186
|
+
// NgModules don't have a public API that could affect emit of Angular decorated classes.
|
|
29187
|
+
return false;
|
|
29188
|
+
}
|
|
29189
|
+
isEmitAffected(previousSymbol) {
|
|
29190
|
+
if (!(previousSymbol instanceof NgModuleSymbol)) {
|
|
29191
|
+
return true;
|
|
29192
|
+
}
|
|
29193
|
+
// compare our remotelyScopedComponents to the previous symbol
|
|
29194
|
+
if (previousSymbol.remotelyScopedComponents.length !== this.remotelyScopedComponents.length) {
|
|
29195
|
+
return true;
|
|
29196
|
+
}
|
|
29197
|
+
for (const currEntry of this.remotelyScopedComponents) {
|
|
29198
|
+
const prevEntry = previousSymbol.remotelyScopedComponents.find(prevEntry => {
|
|
29199
|
+
return isSymbolEqual(prevEntry.component, currEntry.component);
|
|
29200
|
+
});
|
|
29201
|
+
if (prevEntry === undefined) {
|
|
29202
|
+
// No previous entry was found, which means that this component became remotely scoped and
|
|
29203
|
+
// hence this NgModule needs to be re-emitted.
|
|
29204
|
+
return true;
|
|
29205
|
+
}
|
|
29206
|
+
if (!isArrayEqual(currEntry.usedDirectives, prevEntry.usedDirectives, isReferenceEqual)) {
|
|
29207
|
+
// The list of used directives or their order has changed. Since this NgModule emits
|
|
29208
|
+
// references to the list of used directives, it should be re-emitted to update this list.
|
|
29209
|
+
// Note: the NgModule does not have to be re-emitted when any of the directives has had
|
|
29210
|
+
// their public API changed, as the NgModule only emits a reference to the symbol by its
|
|
29211
|
+
// name. Therefore, testing for symbol equality is sufficient.
|
|
29212
|
+
return true;
|
|
29213
|
+
}
|
|
29214
|
+
if (!isArrayEqual(currEntry.usedPipes, prevEntry.usedPipes, isReferenceEqual)) {
|
|
29215
|
+
return true;
|
|
29216
|
+
}
|
|
29217
|
+
}
|
|
29218
|
+
return false;
|
|
29219
|
+
}
|
|
29220
|
+
isTypeCheckApiAffected(previousSymbol) {
|
|
29221
|
+
if (!(previousSymbol instanceof NgModuleSymbol)) {
|
|
29222
|
+
return true;
|
|
29223
|
+
}
|
|
29224
|
+
return false;
|
|
29225
|
+
}
|
|
29226
|
+
addRemotelyScopedComponent(component, usedDirectives, usedPipes) {
|
|
29227
|
+
this.remotelyScopedComponents.push({ component, usedDirectives, usedPipes });
|
|
29228
|
+
}
|
|
29229
|
+
}
|
|
29230
|
+
/**
|
|
29231
|
+
* Compiles @NgModule annotations to ngModuleDef fields.
|
|
29232
|
+
*/
|
|
29233
|
+
class NgModuleDecoratorHandler {
|
|
29234
|
+
constructor(reflector, evaluator, metaReader, metaRegistry, scopeRegistry, referencesRegistry, isCore, routeAnalyzer, refEmitter, factoryTracker, defaultImportRecorder, annotateForClosureCompiler, injectableRegistry, localeId) {
|
|
29235
|
+
this.reflector = reflector;
|
|
29236
|
+
this.evaluator = evaluator;
|
|
29237
|
+
this.metaReader = metaReader;
|
|
29238
|
+
this.metaRegistry = metaRegistry;
|
|
29239
|
+
this.scopeRegistry = scopeRegistry;
|
|
29240
|
+
this.referencesRegistry = referencesRegistry;
|
|
29241
|
+
this.isCore = isCore;
|
|
29242
|
+
this.routeAnalyzer = routeAnalyzer;
|
|
29243
|
+
this.refEmitter = refEmitter;
|
|
29244
|
+
this.factoryTracker = factoryTracker;
|
|
29245
|
+
this.defaultImportRecorder = defaultImportRecorder;
|
|
29246
|
+
this.annotateForClosureCompiler = annotateForClosureCompiler;
|
|
29247
|
+
this.injectableRegistry = injectableRegistry;
|
|
29248
|
+
this.localeId = localeId;
|
|
29249
|
+
this.precedence = HandlerPrecedence.PRIMARY;
|
|
29250
|
+
this.name = NgModuleDecoratorHandler.name;
|
|
29251
|
+
}
|
|
29252
|
+
detect(node, decorators) {
|
|
29253
|
+
if (!decorators) {
|
|
29254
|
+
return undefined;
|
|
29255
|
+
}
|
|
29256
|
+
const decorator = findAngularDecorator(decorators, 'NgModule', this.isCore);
|
|
29257
|
+
if (decorator !== undefined) {
|
|
29258
|
+
return {
|
|
29259
|
+
trigger: decorator.node,
|
|
29260
|
+
decorator: decorator,
|
|
29261
|
+
metadata: decorator,
|
|
29262
|
+
};
|
|
29263
|
+
}
|
|
29264
|
+
else {
|
|
29265
|
+
return undefined;
|
|
29266
|
+
}
|
|
29267
|
+
}
|
|
29268
|
+
analyze(node, decorator) {
|
|
29269
|
+
const name = node.name.text;
|
|
29270
|
+
if (decorator.args === null || decorator.args.length > 1) {
|
|
29271
|
+
throw new FatalDiagnosticError(ErrorCode.DECORATOR_ARITY_WRONG, Decorator.nodeForError(decorator), `Incorrect number of arguments to @NgModule decorator`);
|
|
29272
|
+
}
|
|
29273
|
+
// @NgModule can be invoked without arguments. In case it is, pretend as if a blank object
|
|
29274
|
+
// literal was specified. This simplifies the code below.
|
|
29275
|
+
const meta = decorator.args.length === 1 ? unwrapExpression(decorator.args[0]) :
|
|
29276
|
+
ts$1.createObjectLiteral([]);
|
|
29277
|
+
if (!ts$1.isObjectLiteralExpression(meta)) {
|
|
29278
|
+
throw new FatalDiagnosticError(ErrorCode.DECORATOR_ARG_NOT_LITERAL, meta, '@NgModule argument must be an object literal');
|
|
29279
|
+
}
|
|
29280
|
+
const ngModule = reflectObjectLiteral(meta);
|
|
29281
|
+
if (ngModule.has('jit')) {
|
|
29282
|
+
// The only allowed value is true, so there's no need to expand further.
|
|
29283
|
+
return {};
|
|
29284
|
+
}
|
|
29285
|
+
const moduleResolvers = combineResolvers([
|
|
29286
|
+
ref => this._extractModuleFromModuleWithProvidersFn(ref.node),
|
|
29287
|
+
forwardRefResolver,
|
|
29288
|
+
]);
|
|
29289
|
+
const diagnostics = [];
|
|
29290
|
+
// Extract the module declarations, imports, and exports.
|
|
29291
|
+
let declarationRefs = [];
|
|
29292
|
+
let rawDeclarations = null;
|
|
29293
|
+
if (ngModule.has('declarations')) {
|
|
29294
|
+
rawDeclarations = ngModule.get('declarations');
|
|
29295
|
+
const declarationMeta = this.evaluator.evaluate(rawDeclarations, forwardRefResolver);
|
|
29296
|
+
declarationRefs =
|
|
29297
|
+
this.resolveTypeList(rawDeclarations, declarationMeta, name, 'declarations');
|
|
29298
|
+
// Look through the declarations to make sure they're all a part of the current compilation.
|
|
29299
|
+
for (const ref of declarationRefs) {
|
|
29300
|
+
if (ref.node.getSourceFile().isDeclarationFile) {
|
|
29301
|
+
const errorNode = ref.getOriginForDiagnostics(rawDeclarations);
|
|
29302
|
+
diagnostics.push(makeDiagnostic(ErrorCode.NGMODULE_INVALID_DECLARATION, errorNode, `Cannot declare '${ref.node.name
|
|
29303
|
+
.text}' in an NgModule as it's not a part of the current compilation.`, [makeRelatedInformation(ref.node.name, `'${ref.node.name.text}' is declared here.`)]));
|
|
29304
|
+
}
|
|
29305
|
+
}
|
|
29306
|
+
}
|
|
29307
|
+
if (diagnostics.length > 0) {
|
|
29308
|
+
return { diagnostics };
|
|
29309
|
+
}
|
|
29310
|
+
let importRefs = [];
|
|
29311
|
+
let rawImports = null;
|
|
29312
|
+
if (ngModule.has('imports')) {
|
|
29313
|
+
rawImports = ngModule.get('imports');
|
|
29314
|
+
const importsMeta = this.evaluator.evaluate(rawImports, moduleResolvers);
|
|
29315
|
+
importRefs = this.resolveTypeList(rawImports, importsMeta, name, 'imports');
|
|
29316
|
+
}
|
|
29317
|
+
let exportRefs = [];
|
|
29318
|
+
let rawExports = null;
|
|
29319
|
+
if (ngModule.has('exports')) {
|
|
29320
|
+
rawExports = ngModule.get('exports');
|
|
29321
|
+
const exportsMeta = this.evaluator.evaluate(rawExports, moduleResolvers);
|
|
29322
|
+
exportRefs = this.resolveTypeList(rawExports, exportsMeta, name, 'exports');
|
|
29323
|
+
this.referencesRegistry.add(node, ...exportRefs);
|
|
29324
|
+
}
|
|
29325
|
+
let bootstrapRefs = [];
|
|
29326
|
+
if (ngModule.has('bootstrap')) {
|
|
29327
|
+
const expr = ngModule.get('bootstrap');
|
|
29328
|
+
const bootstrapMeta = this.evaluator.evaluate(expr, forwardRefResolver);
|
|
29329
|
+
bootstrapRefs = this.resolveTypeList(expr, bootstrapMeta, name, 'bootstrap');
|
|
29330
|
+
}
|
|
29331
|
+
const schemas = [];
|
|
29332
|
+
if (ngModule.has('schemas')) {
|
|
29333
|
+
const rawExpr = ngModule.get('schemas');
|
|
29334
|
+
const result = this.evaluator.evaluate(rawExpr);
|
|
29335
|
+
if (!Array.isArray(result)) {
|
|
29336
|
+
throw createValueHasWrongTypeError(rawExpr, result, `NgModule.schemas must be an array`);
|
|
29337
|
+
}
|
|
29338
|
+
for (const schemaRef of result) {
|
|
29339
|
+
if (!(schemaRef instanceof Reference$1)) {
|
|
29340
|
+
throw createValueHasWrongTypeError(rawExpr, result, 'NgModule.schemas must be an array of schemas');
|
|
29341
|
+
}
|
|
29342
|
+
const id = schemaRef.getIdentityIn(schemaRef.node.getSourceFile());
|
|
29343
|
+
if (id === null || schemaRef.ownedByModuleGuess !== '@angular/core') {
|
|
29344
|
+
throw createValueHasWrongTypeError(rawExpr, result, 'NgModule.schemas must be an array of schemas');
|
|
29345
|
+
}
|
|
29346
|
+
// Since `id` is the `ts.Identifer` within the schema ref's declaration file, it's safe to
|
|
29347
|
+
// use `id.text` here to figure out which schema is in use. Even if the actual reference was
|
|
29348
|
+
// renamed when the user imported it, these names will match.
|
|
29349
|
+
switch (id.text) {
|
|
29350
|
+
case 'CUSTOM_ELEMENTS_SCHEMA':
|
|
29351
|
+
schemas.push(CUSTOM_ELEMENTS_SCHEMA);
|
|
29352
|
+
break;
|
|
29353
|
+
case 'NO_ERRORS_SCHEMA':
|
|
29354
|
+
schemas.push(NO_ERRORS_SCHEMA);
|
|
29355
|
+
break;
|
|
29356
|
+
default:
|
|
29357
|
+
throw createValueHasWrongTypeError(rawExpr, schemaRef, `'${schemaRef.debugName}' is not a valid NgModule schema`);
|
|
29358
|
+
}
|
|
29359
|
+
}
|
|
29360
|
+
}
|
|
29361
|
+
const id = ngModule.has('id') ? new WrappedNodeExpr(ngModule.get('id')) : null;
|
|
29362
|
+
const valueContext = node.getSourceFile();
|
|
29363
|
+
let typeContext = valueContext;
|
|
29364
|
+
const typeNode = this.reflector.getDtsDeclaration(node);
|
|
29365
|
+
if (typeNode !== null) {
|
|
29366
|
+
typeContext = typeNode.getSourceFile();
|
|
29367
|
+
}
|
|
29368
|
+
const bootstrap = bootstrapRefs.map(bootstrap => this._toR3Reference(bootstrap, valueContext, typeContext));
|
|
29369
|
+
const declarations = declarationRefs.map(decl => this._toR3Reference(decl, valueContext, typeContext));
|
|
29370
|
+
const imports = importRefs.map(imp => this._toR3Reference(imp, valueContext, typeContext));
|
|
29371
|
+
const exports = exportRefs.map(exp => this._toR3Reference(exp, valueContext, typeContext));
|
|
29372
|
+
const isForwardReference = (ref) => isExpressionForwardReference(ref.value, node.name, valueContext);
|
|
29373
|
+
const containsForwardDecls = bootstrap.some(isForwardReference) ||
|
|
29374
|
+
declarations.some(isForwardReference) || imports.some(isForwardReference) ||
|
|
29375
|
+
exports.some(isForwardReference);
|
|
29376
|
+
const type = wrapTypeReference(this.reflector, node);
|
|
29377
|
+
const internalType = new WrappedNodeExpr(this.reflector.getInternalNameOfClass(node));
|
|
29378
|
+
const adjacentType = new WrappedNodeExpr(this.reflector.getAdjacentNameOfClass(node));
|
|
29379
|
+
const ngModuleDef = {
|
|
29380
|
+
type,
|
|
29381
|
+
internalType,
|
|
29382
|
+
adjacentType,
|
|
29383
|
+
bootstrap,
|
|
29384
|
+
declarations,
|
|
29385
|
+
exports,
|
|
29386
|
+
imports,
|
|
29387
|
+
containsForwardDecls,
|
|
29388
|
+
id,
|
|
29389
|
+
emitInline: false,
|
|
29390
|
+
// TODO: to be implemented as a part of FW-1004.
|
|
29391
|
+
schemas: [],
|
|
29392
|
+
};
|
|
29393
|
+
const rawProviders = ngModule.has('providers') ? ngModule.get('providers') : null;
|
|
29394
|
+
const wrapperProviders = rawProviders !== null ?
|
|
29395
|
+
new WrappedNodeExpr(this.annotateForClosureCompiler ? wrapFunctionExpressionsInParens(rawProviders) :
|
|
29396
|
+
rawProviders) :
|
|
29397
|
+
null;
|
|
29398
|
+
// At this point, only add the module's imports as the injectors' imports. Any exported modules
|
|
29399
|
+
// are added during `resolve`, as we need scope information to be able to filter out directives
|
|
29400
|
+
// and pipes from the module exports.
|
|
29401
|
+
const injectorImports = [];
|
|
29402
|
+
if (ngModule.has('imports')) {
|
|
29403
|
+
injectorImports.push(new WrappedNodeExpr(ngModule.get('imports')));
|
|
29404
|
+
}
|
|
29405
|
+
if (this.routeAnalyzer !== null) {
|
|
29406
|
+
this.routeAnalyzer.add(node.getSourceFile(), name, rawImports, rawExports, rawProviders);
|
|
29407
|
+
}
|
|
29408
|
+
const ngInjectorDef = {
|
|
29409
|
+
name,
|
|
29410
|
+
type,
|
|
29411
|
+
internalType,
|
|
29412
|
+
providers: wrapperProviders,
|
|
29413
|
+
imports: injectorImports,
|
|
29414
|
+
};
|
|
29415
|
+
return {
|
|
29416
|
+
analysis: {
|
|
29417
|
+
id,
|
|
29418
|
+
schemas: schemas,
|
|
29419
|
+
mod: ngModuleDef,
|
|
29420
|
+
inj: ngInjectorDef,
|
|
29421
|
+
deps: getValidConstructorDependencies(node, this.reflector, this.defaultImportRecorder, this.isCore),
|
|
29422
|
+
declarations: declarationRefs,
|
|
29423
|
+
rawDeclarations,
|
|
29424
|
+
imports: importRefs,
|
|
29425
|
+
exports: exportRefs,
|
|
29426
|
+
providers: rawProviders,
|
|
29427
|
+
providersRequiringFactory: rawProviders ?
|
|
29428
|
+
resolveProvidersRequiringFactory(rawProviders, this.reflector, this.evaluator) :
|
|
29429
|
+
null,
|
|
29430
|
+
metadataStmt: generateSetClassMetadataCall(node, this.reflector, this.defaultImportRecorder, this.isCore, this.annotateForClosureCompiler),
|
|
29431
|
+
factorySymbolName: node.name.text,
|
|
29432
|
+
},
|
|
29433
|
+
};
|
|
29434
|
+
}
|
|
29435
|
+
symbol(node) {
|
|
29436
|
+
return new NgModuleSymbol(node);
|
|
29437
|
+
}
|
|
29438
|
+
register(node, analysis) {
|
|
29439
|
+
// Register this module's information with the LocalModuleScopeRegistry. This ensures that
|
|
29440
|
+
// during the compile() phase, the module's metadata is available for selector scope
|
|
29441
|
+
// computation.
|
|
29442
|
+
this.metaRegistry.registerNgModuleMetadata({
|
|
29443
|
+
ref: new Reference$1(node),
|
|
29444
|
+
schemas: analysis.schemas,
|
|
29445
|
+
declarations: analysis.declarations,
|
|
29446
|
+
imports: analysis.imports,
|
|
29447
|
+
exports: analysis.exports,
|
|
29448
|
+
rawDeclarations: analysis.rawDeclarations,
|
|
29449
|
+
});
|
|
29450
|
+
if (this.factoryTracker !== null) {
|
|
29451
|
+
this.factoryTracker.track(node.getSourceFile(), {
|
|
29452
|
+
name: analysis.factorySymbolName,
|
|
29453
|
+
hasId: analysis.id !== null,
|
|
29454
|
+
});
|
|
29455
|
+
}
|
|
29456
|
+
this.injectableRegistry.registerInjectable(node);
|
|
29457
|
+
}
|
|
29458
|
+
resolve(node, analysis) {
|
|
29459
|
+
const scope = this.scopeRegistry.getScopeOfModule(node);
|
|
29460
|
+
const diagnostics = [];
|
|
29461
|
+
const scopeDiagnostics = this.scopeRegistry.getDiagnosticsOfModule(node);
|
|
29462
|
+
if (scopeDiagnostics !== null) {
|
|
29463
|
+
diagnostics.push(...scopeDiagnostics);
|
|
29464
|
+
}
|
|
29465
|
+
if (analysis.providersRequiringFactory !== null) {
|
|
29466
|
+
const providerDiagnostics = getProviderDiagnostics(analysis.providersRequiringFactory, analysis.providers, this.injectableRegistry);
|
|
29467
|
+
diagnostics.push(...providerDiagnostics);
|
|
29468
|
+
}
|
|
29469
|
+
const data = {
|
|
29470
|
+
injectorImports: [],
|
|
29471
|
+
};
|
|
29472
|
+
if (scope !== null && !scope.compilation.isPoisoned) {
|
|
29473
|
+
// Using the scope information, extend the injector's imports using the modules that are
|
|
29474
|
+
// specified as module exports.
|
|
29475
|
+
const context = getSourceFile(node);
|
|
29476
|
+
for (const exportRef of analysis.exports) {
|
|
29477
|
+
if (isNgModule(exportRef.node, scope.compilation)) {
|
|
29478
|
+
data.injectorImports.push(this.refEmitter.emit(exportRef, context).expression);
|
|
29479
|
+
}
|
|
29480
|
+
}
|
|
29481
|
+
for (const decl of analysis.declarations) {
|
|
29482
|
+
const metadata = this.metaReader.getDirectiveMetadata(decl);
|
|
29483
|
+
if (metadata !== null && metadata.selector === null) {
|
|
29484
|
+
throw new FatalDiagnosticError(ErrorCode.DIRECTIVE_MISSING_SELECTOR, decl.node, `Directive ${decl.node.name.text} has no selector, please add it!`);
|
|
29485
|
+
}
|
|
29486
|
+
}
|
|
29487
|
+
}
|
|
29488
|
+
if (diagnostics.length > 0) {
|
|
29489
|
+
return { diagnostics };
|
|
29490
|
+
}
|
|
29491
|
+
if (scope === null || scope.compilation.isPoisoned || scope.exported.isPoisoned ||
|
|
29492
|
+
scope.reexports === null) {
|
|
29493
|
+
return { data };
|
|
29494
|
+
}
|
|
29495
|
+
else {
|
|
29496
|
+
return {
|
|
29497
|
+
data,
|
|
29498
|
+
reexports: scope.reexports,
|
|
29499
|
+
};
|
|
29500
|
+
}
|
|
29501
|
+
}
|
|
29502
|
+
compileFull(node, { inj, mod, deps, metadataStmt, declarations }, resolution) {
|
|
29503
|
+
// Merge the injector imports (which are 'exports' that were later found to be NgModules)
|
|
29504
|
+
// computed during resolution with the ones from analysis.
|
|
29505
|
+
const ngInjectorDef = compileInjector(Object.assign(Object.assign({}, inj), { imports: [...inj.imports, ...resolution.injectorImports] }));
|
|
29506
|
+
const ngModuleDef = compileNgModule(mod);
|
|
29507
|
+
const ngModuleStatements = ngModuleDef.additionalStatements;
|
|
29508
|
+
if (metadataStmt !== null) {
|
|
29509
|
+
ngModuleStatements.push(metadataStmt);
|
|
29510
|
+
}
|
|
29511
|
+
const context = getSourceFile(node);
|
|
29512
|
+
for (const decl of declarations) {
|
|
29513
|
+
const remoteScope = this.scopeRegistry.getRemoteScope(decl.node);
|
|
29514
|
+
if (remoteScope !== null) {
|
|
29515
|
+
const directives = remoteScope.directives.map(directive => this.refEmitter.emit(directive, context).expression);
|
|
29516
|
+
const pipes = remoteScope.pipes.map(pipe => this.refEmitter.emit(pipe, context).expression);
|
|
29517
|
+
const directiveArray = new LiteralArrayExpr(directives);
|
|
29518
|
+
const pipesArray = new LiteralArrayExpr(pipes);
|
|
29519
|
+
const declExpr = this.refEmitter.emit(decl, context).expression;
|
|
29520
|
+
const setComponentScope = new ExternalExpr(Identifiers$1.setComponentScope);
|
|
29521
|
+
const callExpr = new InvokeFunctionExpr(setComponentScope, [declExpr, directiveArray, pipesArray]);
|
|
29522
|
+
ngModuleStatements.push(callExpr.toStmt());
|
|
29523
|
+
}
|
|
29524
|
+
}
|
|
29525
|
+
const res = [
|
|
29526
|
+
compileNgFactoryDefField({
|
|
29527
|
+
name: inj.name,
|
|
29528
|
+
type: inj.type,
|
|
29529
|
+
internalType: inj.internalType,
|
|
29530
|
+
typeArgumentCount: 0,
|
|
29531
|
+
deps,
|
|
29532
|
+
injectFn: Identifiers.inject,
|
|
29533
|
+
target: R3FactoryTarget.NgModule,
|
|
29534
|
+
}),
|
|
29535
|
+
{
|
|
29536
|
+
name: 'ɵmod',
|
|
29537
|
+
initializer: ngModuleDef.expression,
|
|
29538
|
+
statements: ngModuleStatements,
|
|
29539
|
+
type: ngModuleDef.type,
|
|
29540
|
+
},
|
|
29541
|
+
{
|
|
29542
|
+
name: 'ɵinj',
|
|
29543
|
+
initializer: ngInjectorDef.expression,
|
|
29544
|
+
statements: [],
|
|
29545
|
+
type: ngInjectorDef.type,
|
|
29546
|
+
},
|
|
29547
|
+
];
|
|
29548
|
+
if (this.localeId) {
|
|
29549
|
+
res.push({
|
|
29550
|
+
name: 'ɵloc',
|
|
29551
|
+
initializer: new LiteralExpr(this.localeId),
|
|
29552
|
+
statements: [],
|
|
29553
|
+
type: STRING_TYPE
|
|
29554
|
+
});
|
|
29555
|
+
}
|
|
29556
|
+
return res;
|
|
29557
|
+
}
|
|
29558
|
+
_toR3Reference(valueRef, valueContext, typeContext) {
|
|
29559
|
+
if (valueRef.hasOwningModuleGuess) {
|
|
29560
|
+
return toR3Reference(valueRef, valueRef, valueContext, valueContext, this.refEmitter);
|
|
29561
|
+
}
|
|
29562
|
+
else {
|
|
29563
|
+
let typeRef = valueRef;
|
|
29564
|
+
let typeNode = this.reflector.getDtsDeclaration(typeRef.node);
|
|
29565
|
+
if (typeNode !== null && isNamedClassDeclaration(typeNode)) {
|
|
29566
|
+
typeRef = new Reference$1(typeNode);
|
|
29567
|
+
}
|
|
29568
|
+
return toR3Reference(valueRef, typeRef, valueContext, typeContext, this.refEmitter);
|
|
29569
|
+
}
|
|
29570
|
+
}
|
|
29571
|
+
/**
|
|
29572
|
+
* Given a `FunctionDeclaration`, `MethodDeclaration` or `FunctionExpression`, check if it is
|
|
29573
|
+
* typed as a `ModuleWithProviders` and return an expression referencing the module if available.
|
|
29574
|
+
*/
|
|
29575
|
+
_extractModuleFromModuleWithProvidersFn(node) {
|
|
29576
|
+
const type = node.type || null;
|
|
29577
|
+
return type &&
|
|
29578
|
+
(this._reflectModuleFromTypeParam(type, node) || this._reflectModuleFromLiteralType(type));
|
|
29579
|
+
}
|
|
29580
|
+
/**
|
|
29581
|
+
* Retrieve an `NgModule` identifier (T) from the specified `type`, if it is of the form:
|
|
29582
|
+
* `ModuleWithProviders<T>`
|
|
29583
|
+
* @param type The type to reflect on.
|
|
29584
|
+
* @returns the identifier of the NgModule type if found, or null otherwise.
|
|
29585
|
+
*/
|
|
29586
|
+
_reflectModuleFromTypeParam(type, node) {
|
|
29587
|
+
// Examine the type of the function to see if it's a ModuleWithProviders reference.
|
|
29588
|
+
if (!ts$1.isTypeReferenceNode(type)) {
|
|
29589
|
+
return null;
|
|
29590
|
+
}
|
|
29591
|
+
const typeName = type &&
|
|
29592
|
+
(ts$1.isIdentifier(type.typeName) && type.typeName ||
|
|
29593
|
+
ts$1.isQualifiedName(type.typeName) && type.typeName.right) ||
|
|
29594
|
+
null;
|
|
29595
|
+
if (typeName === null) {
|
|
29596
|
+
return null;
|
|
29597
|
+
}
|
|
29598
|
+
// Look at the type itself to see where it comes from.
|
|
29599
|
+
const id = this.reflector.getImportOfIdentifier(typeName);
|
|
29600
|
+
// If it's not named ModuleWithProviders, bail.
|
|
29601
|
+
if (id === null || id.name !== 'ModuleWithProviders') {
|
|
29602
|
+
return null;
|
|
29603
|
+
}
|
|
29604
|
+
// If it's not from @angular/core, bail.
|
|
29605
|
+
if (!this.isCore && id.from !== '@angular/core') {
|
|
29606
|
+
return null;
|
|
29607
|
+
}
|
|
29608
|
+
// If there's no type parameter specified, bail.
|
|
29609
|
+
if (type.typeArguments === undefined || type.typeArguments.length !== 1) {
|
|
29610
|
+
const parent = ts$1.isMethodDeclaration(node) && ts$1.isClassDeclaration(node.parent) ? node.parent : null;
|
|
29611
|
+
const symbolName = (parent && parent.name ? parent.name.getText() + '.' : '') +
|
|
29612
|
+
(node.name ? node.name.getText() : 'anonymous');
|
|
29613
|
+
throw new FatalDiagnosticError(ErrorCode.NGMODULE_MODULE_WITH_PROVIDERS_MISSING_GENERIC, type, `${symbolName} returns a ModuleWithProviders type without a generic type argument. ` +
|
|
29614
|
+
`Please add a generic type argument to the ModuleWithProviders type. If this ` +
|
|
29615
|
+
`occurrence is in library code you don't control, please contact the library authors.`);
|
|
29616
|
+
}
|
|
29617
|
+
const arg = type.typeArguments[0];
|
|
29618
|
+
return typeNodeToValueExpr(arg);
|
|
29619
|
+
}
|
|
29620
|
+
/**
|
|
29621
|
+
* Retrieve an `NgModule` identifier (T) from the specified `type`, if it is of the form:
|
|
29622
|
+
* `A|B|{ngModule: T}|C`.
|
|
29623
|
+
* @param type The type to reflect on.
|
|
29624
|
+
* @returns the identifier of the NgModule type if found, or null otherwise.
|
|
29625
|
+
*/
|
|
29626
|
+
_reflectModuleFromLiteralType(type) {
|
|
29627
|
+
if (!ts$1.isIntersectionTypeNode(type)) {
|
|
29628
|
+
return null;
|
|
29629
|
+
}
|
|
29630
|
+
for (const t of type.types) {
|
|
29631
|
+
if (ts$1.isTypeLiteralNode(t)) {
|
|
29632
|
+
for (const m of t.members) {
|
|
29633
|
+
const ngModuleType = ts$1.isPropertySignature(m) && ts$1.isIdentifier(m.name) &&
|
|
29634
|
+
m.name.text === 'ngModule' && m.type ||
|
|
29635
|
+
null;
|
|
29636
|
+
const ngModuleExpression = ngModuleType && typeNodeToValueExpr(ngModuleType);
|
|
29637
|
+
if (ngModuleExpression) {
|
|
29638
|
+
return ngModuleExpression;
|
|
29639
|
+
}
|
|
29640
|
+
}
|
|
29641
|
+
}
|
|
29642
|
+
}
|
|
29643
|
+
return null;
|
|
29644
|
+
}
|
|
29645
|
+
// Verify that a "Declaration" reference is a `ClassDeclaration` reference.
|
|
29646
|
+
isClassDeclarationReference(ref) {
|
|
29647
|
+
return this.reflector.isClass(ref.node);
|
|
29648
|
+
}
|
|
29649
|
+
/**
|
|
29650
|
+
* Compute a list of `Reference`s from a resolved metadata value.
|
|
29651
|
+
*/
|
|
29652
|
+
resolveTypeList(expr, resolvedList, className, arrayName) {
|
|
29653
|
+
const refList = [];
|
|
29654
|
+
if (!Array.isArray(resolvedList)) {
|
|
29655
|
+
throw createValueHasWrongTypeError(expr, resolvedList, `Expected array when reading the NgModule.${arrayName} of ${className}`);
|
|
29656
|
+
}
|
|
29657
|
+
resolvedList.forEach((entry, idx) => {
|
|
29658
|
+
// Unwrap ModuleWithProviders for modules that are locally declared (and thus static
|
|
29659
|
+
// resolution was able to descend into the function and return an object literal, a Map).
|
|
29660
|
+
if (entry instanceof Map && entry.has('ngModule')) {
|
|
29661
|
+
entry = entry.get('ngModule');
|
|
29662
|
+
}
|
|
29663
|
+
if (Array.isArray(entry)) {
|
|
29664
|
+
// Recurse into nested arrays.
|
|
29665
|
+
refList.push(...this.resolveTypeList(expr, entry, className, arrayName));
|
|
29666
|
+
}
|
|
29667
|
+
else if (entry instanceof Reference$1) {
|
|
29668
|
+
if (!this.isClassDeclarationReference(entry)) {
|
|
29669
|
+
throw createValueHasWrongTypeError(entry.node, entry, `Value at position ${idx} in the NgModule.${arrayName} of ${className} is not a class`);
|
|
29670
|
+
}
|
|
29671
|
+
refList.push(entry);
|
|
29672
|
+
}
|
|
29673
|
+
else {
|
|
29674
|
+
// TODO(alxhub): Produce a better diagnostic here - the array index may be an inner array.
|
|
29675
|
+
throw createValueHasWrongTypeError(expr, entry, `Value at position ${idx} in the NgModule.${arrayName} of ${className} is not a reference`);
|
|
29676
|
+
}
|
|
29677
|
+
});
|
|
29678
|
+
return refList;
|
|
29679
|
+
}
|
|
29680
|
+
}
|
|
29681
|
+
function isNgModule(node, compilation) {
|
|
29682
|
+
return !compilation.directives.some(directive => directive.ref.node === node) &&
|
|
29683
|
+
!compilation.pipes.some(pipe => pipe.ref.node === node);
|
|
29684
|
+
}
|
|
29685
|
+
|
|
28682
29686
|
/**
|
|
28683
29687
|
* @license
|
|
28684
29688
|
* Copyright Google LLC All Rights Reserved.
|
|
@@ -28688,11 +29692,73 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
28688
29692
|
*/
|
|
28689
29693
|
const EMPTY_MAP = new Map();
|
|
28690
29694
|
const EMPTY_ARRAY = [];
|
|
29695
|
+
/**
|
|
29696
|
+
* Represents an Angular component.
|
|
29697
|
+
*/
|
|
29698
|
+
class ComponentSymbol extends DirectiveSymbol {
|
|
29699
|
+
constructor() {
|
|
29700
|
+
super(...arguments);
|
|
29701
|
+
this.usedDirectives = [];
|
|
29702
|
+
this.usedPipes = [];
|
|
29703
|
+
this.isRemotelyScoped = false;
|
|
29704
|
+
}
|
|
29705
|
+
isEmitAffected(previousSymbol, publicApiAffected) {
|
|
29706
|
+
if (!(previousSymbol instanceof ComponentSymbol)) {
|
|
29707
|
+
return true;
|
|
29708
|
+
}
|
|
29709
|
+
// Create an equality function that considers symbols equal if they represent the same
|
|
29710
|
+
// declaration, but only if the symbol in the current compilation does not have its public API
|
|
29711
|
+
// affected.
|
|
29712
|
+
const isSymbolUnaffected = (current, previous) => isReferenceEqual(current, previous) && !publicApiAffected.has(current.symbol);
|
|
29713
|
+
// The emit of a component is affected if either of the following is true:
|
|
29714
|
+
// 1. The component used to be remotely scoped but no longer is, or vice versa.
|
|
29715
|
+
// 2. The list of used directives has changed or any of those directives have had their public
|
|
29716
|
+
// API changed. If the used directives have been reordered but not otherwise affected then
|
|
29717
|
+
// the component must still be re-emitted, as this may affect directive instantiation order.
|
|
29718
|
+
// 3. The list of used pipes has changed, or any of those pipes have had their public API
|
|
29719
|
+
// changed.
|
|
29720
|
+
return this.isRemotelyScoped !== previousSymbol.isRemotelyScoped ||
|
|
29721
|
+
!isArrayEqual(this.usedDirectives, previousSymbol.usedDirectives, isSymbolUnaffected) ||
|
|
29722
|
+
!isArrayEqual(this.usedPipes, previousSymbol.usedPipes, isSymbolUnaffected);
|
|
29723
|
+
}
|
|
29724
|
+
isTypeCheckBlockAffected(previousSymbol, typeCheckApiAffected) {
|
|
29725
|
+
if (!(previousSymbol instanceof ComponentSymbol)) {
|
|
29726
|
+
return true;
|
|
29727
|
+
}
|
|
29728
|
+
// To verify that a used directive is not affected we need to verify that its full inheritance
|
|
29729
|
+
// chain is not present in `typeCheckApiAffected`.
|
|
29730
|
+
const isInheritanceChainAffected = (symbol) => {
|
|
29731
|
+
let currentSymbol = symbol;
|
|
29732
|
+
while (currentSymbol instanceof DirectiveSymbol) {
|
|
29733
|
+
if (typeCheckApiAffected.has(currentSymbol)) {
|
|
29734
|
+
return true;
|
|
29735
|
+
}
|
|
29736
|
+
currentSymbol = currentSymbol.baseClass;
|
|
29737
|
+
}
|
|
29738
|
+
return false;
|
|
29739
|
+
};
|
|
29740
|
+
// Create an equality function that considers directives equal if they represent the same
|
|
29741
|
+
// declaration and if the symbol and all symbols it inherits from in the current compilation
|
|
29742
|
+
// do not have their type-check API affected.
|
|
29743
|
+
const isDirectiveUnaffected = (current, previous) => isReferenceEqual(current, previous) && !isInheritanceChainAffected(current.symbol);
|
|
29744
|
+
// Create an equality function that considers pipes equal if they represent the same
|
|
29745
|
+
// declaration and if the symbol in the current compilation does not have its type-check
|
|
29746
|
+
// API affected.
|
|
29747
|
+
const isPipeUnaffected = (current, previous) => isReferenceEqual(current, previous) && !typeCheckApiAffected.has(current.symbol);
|
|
29748
|
+
// The emit of a type-check block of a component is affected if either of the following is true:
|
|
29749
|
+
// 1. The list of used directives has changed or any of those directives have had their
|
|
29750
|
+
// type-check API changed.
|
|
29751
|
+
// 2. The list of used pipes has changed, or any of those pipes have had their type-check API
|
|
29752
|
+
// changed.
|
|
29753
|
+
return !isArrayEqual(this.usedDirectives, previousSymbol.usedDirectives, isDirectiveUnaffected) ||
|
|
29754
|
+
!isArrayEqual(this.usedPipes, previousSymbol.usedPipes, isPipeUnaffected);
|
|
29755
|
+
}
|
|
29756
|
+
}
|
|
28691
29757
|
/**
|
|
28692
29758
|
* `DecoratorHandler` which handles the `@Component` annotation.
|
|
28693
29759
|
*/
|
|
28694
29760
|
class ComponentDecoratorHandler {
|
|
28695
|
-
constructor(reflector, evaluator, metaRegistry, metaReader, scopeReader, scopeRegistry, typeCheckScopeRegistry, resourceRegistry, isCore, resourceLoader, rootDirs, defaultPreserveWhitespaces, i18nUseExternalIds, enableI18nLegacyMessageIdFormat, usePoisonedData, i18nNormalizeLineEndingsInICUs, moduleResolver, cycleAnalyzer, cycleHandlingStrategy, refEmitter, defaultImportRecorder, depTracker, injectableRegistry, annotateForClosureCompiler) {
|
|
29761
|
+
constructor(reflector, evaluator, metaRegistry, metaReader, scopeReader, scopeRegistry, typeCheckScopeRegistry, resourceRegistry, isCore, resourceLoader, rootDirs, defaultPreserveWhitespaces, i18nUseExternalIds, enableI18nLegacyMessageIdFormat, usePoisonedData, i18nNormalizeLineEndingsInICUs, moduleResolver, cycleAnalyzer, cycleHandlingStrategy, refEmitter, defaultImportRecorder, depTracker, injectableRegistry, semanticDepGraphUpdater, annotateForClosureCompiler) {
|
|
28696
29762
|
this.reflector = reflector;
|
|
28697
29763
|
this.evaluator = evaluator;
|
|
28698
29764
|
this.metaRegistry = metaRegistry;
|
|
@@ -28716,6 +29782,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
28716
29782
|
this.defaultImportRecorder = defaultImportRecorder;
|
|
28717
29783
|
this.depTracker = depTracker;
|
|
28718
29784
|
this.injectableRegistry = injectableRegistry;
|
|
29785
|
+
this.semanticDepGraphUpdater = semanticDepGraphUpdater;
|
|
28719
29786
|
this.annotateForClosureCompiler = annotateForClosureCompiler;
|
|
28720
29787
|
this.literalCache = new Map();
|
|
28721
29788
|
this.elementSchemaRegistry = new DomElementSchemaRegistry();
|
|
@@ -28923,6 +29990,10 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
28923
29990
|
}
|
|
28924
29991
|
return output;
|
|
28925
29992
|
}
|
|
29993
|
+
symbol(node, analysis) {
|
|
29994
|
+
const typeParameters = extractSemanticTypeParameters(node);
|
|
29995
|
+
return new ComponentSymbol(node, analysis.meta.selector, analysis.inputs, analysis.outputs, analysis.meta.exportAs, analysis.typeCheckMeta, typeParameters);
|
|
29996
|
+
}
|
|
28926
29997
|
register(node, analysis) {
|
|
28927
29998
|
// Register this component's information with the `MetadataRegistry`. This ensures that
|
|
28928
29999
|
// the information about the component is available during the compile() phase.
|
|
@@ -28977,7 +30048,10 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
28977
30048
|
const binder = new R3TargetBinder(scope.matcher);
|
|
28978
30049
|
ctx.addTemplate(new Reference$1(node), binder, meta.template.diagNodes, scope.pipes, scope.schemas, meta.template.sourceMapping, meta.template.file, meta.template.errors);
|
|
28979
30050
|
}
|
|
28980
|
-
resolve(node, analysis) {
|
|
30051
|
+
resolve(node, analysis, symbol) {
|
|
30052
|
+
if (this.semanticDepGraphUpdater !== null && analysis.baseClass instanceof Reference$1) {
|
|
30053
|
+
symbol.baseClass = this.semanticDepGraphUpdater.getSymbol(analysis.baseClass.node);
|
|
30054
|
+
}
|
|
28981
30055
|
if (analysis.isPoisoned && !this.usePoisonedData) {
|
|
28982
30056
|
return {};
|
|
28983
30057
|
}
|
|
@@ -29007,9 +30081,11 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
29007
30081
|
const binder = new R3TargetBinder(matcher);
|
|
29008
30082
|
const bound = binder.bind({ template: metadata.template.nodes });
|
|
29009
30083
|
const usedDirectives = bound.getUsedDirectives().map(directive => {
|
|
30084
|
+
const type = this.refEmitter.emit(directive.ref, context);
|
|
29010
30085
|
return {
|
|
29011
30086
|
ref: directive.ref,
|
|
29012
|
-
type:
|
|
30087
|
+
type: type.expression,
|
|
30088
|
+
importedFile: type.importedFile,
|
|
29013
30089
|
selector: directive.selector,
|
|
29014
30090
|
inputs: directive.inputs.propertyNames,
|
|
29015
30091
|
outputs: directive.outputs.propertyNames,
|
|
@@ -29023,36 +30099,43 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
29023
30099
|
continue;
|
|
29024
30100
|
}
|
|
29025
30101
|
const pipe = pipes.get(pipeName);
|
|
30102
|
+
const type = this.refEmitter.emit(pipe, context);
|
|
29026
30103
|
usedPipes.push({
|
|
29027
30104
|
ref: pipe,
|
|
29028
30105
|
pipeName,
|
|
29029
|
-
expression:
|
|
30106
|
+
expression: type.expression,
|
|
30107
|
+
importedFile: type.importedFile,
|
|
29030
30108
|
});
|
|
29031
30109
|
}
|
|
30110
|
+
if (this.semanticDepGraphUpdater !== null) {
|
|
30111
|
+
symbol.usedDirectives = usedDirectives.map(dir => this.semanticDepGraphUpdater.getSemanticReference(dir.ref.node, dir.type));
|
|
30112
|
+
symbol.usedPipes = usedPipes.map(pipe => this.semanticDepGraphUpdater.getSemanticReference(pipe.ref.node, pipe.expression));
|
|
30113
|
+
}
|
|
29032
30114
|
// Scan through the directives/pipes actually used in the template and check whether any
|
|
29033
30115
|
// import which needs to be generated would create a cycle.
|
|
29034
30116
|
const cyclesFromDirectives = new Map();
|
|
29035
30117
|
for (const usedDirective of usedDirectives) {
|
|
29036
|
-
const cycle = this._checkForCyclicImport(usedDirective.
|
|
30118
|
+
const cycle = this._checkForCyclicImport(usedDirective.importedFile, usedDirective.type, context);
|
|
29037
30119
|
if (cycle !== null) {
|
|
29038
30120
|
cyclesFromDirectives.set(usedDirective, cycle);
|
|
29039
30121
|
}
|
|
29040
30122
|
}
|
|
29041
30123
|
const cyclesFromPipes = new Map();
|
|
29042
30124
|
for (const usedPipe of usedPipes) {
|
|
29043
|
-
const cycle = this._checkForCyclicImport(usedPipe.
|
|
30125
|
+
const cycle = this._checkForCyclicImport(usedPipe.importedFile, usedPipe.expression, context);
|
|
29044
30126
|
if (cycle !== null) {
|
|
29045
30127
|
cyclesFromPipes.set(usedPipe, cycle);
|
|
29046
30128
|
}
|
|
29047
30129
|
}
|
|
29048
|
-
|
|
30130
|
+
const cycleDetected = cyclesFromDirectives.size !== 0 || cyclesFromPipes.size !== 0;
|
|
30131
|
+
if (!cycleDetected) {
|
|
29049
30132
|
// No cycle was detected. Record the imports that need to be created in the cycle detector
|
|
29050
30133
|
// so that future cyclic import checks consider their production.
|
|
29051
|
-
for (const { type } of usedDirectives) {
|
|
29052
|
-
this._recordSyntheticImport(type, context);
|
|
30134
|
+
for (const { type, importedFile } of usedDirectives) {
|
|
30135
|
+
this._recordSyntheticImport(importedFile, type, context);
|
|
29053
30136
|
}
|
|
29054
|
-
for (const { expression } of usedPipes) {
|
|
29055
|
-
this._recordSyntheticImport(expression, context);
|
|
30137
|
+
for (const { expression, importedFile } of usedPipes) {
|
|
30138
|
+
this._recordSyntheticImport(importedFile, expression, context);
|
|
29056
30139
|
}
|
|
29057
30140
|
// Check whether the directive/pipe arrays in ɵcmp need to be wrapped in closures.
|
|
29058
30141
|
// This is required if any directive/pipe reference is to a declaration in the same file
|
|
@@ -29071,6 +30154,17 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
29071
30154
|
// create a cycle. Instead, mark this component as requiring remote scoping, so that the
|
|
29072
30155
|
// NgModule file will take care of setting the directives for the component.
|
|
29073
30156
|
this.scopeRegistry.setComponentRemoteScope(node, usedDirectives.map(dir => dir.ref), usedPipes.map(pipe => pipe.ref));
|
|
30157
|
+
symbol.isRemotelyScoped = true;
|
|
30158
|
+
// If a semantic graph is being tracked, record the fact that this component is remotely
|
|
30159
|
+
// scoped with the declaring NgModule symbol as the NgModule's emit becomes dependent on
|
|
30160
|
+
// the directive/pipe usages of this component.
|
|
30161
|
+
if (this.semanticDepGraphUpdater !== null) {
|
|
30162
|
+
const moduleSymbol = this.semanticDepGraphUpdater.getSymbol(scope.ngModule);
|
|
30163
|
+
if (!(moduleSymbol instanceof NgModuleSymbol)) {
|
|
30164
|
+
throw new Error(`AssertionError: Expected ${scope.ngModule.name} to be an NgModuleSymbol.`);
|
|
30165
|
+
}
|
|
30166
|
+
moduleSymbol.addRemotelyScopedComponent(symbol, symbol.usedDirectives, symbol.usedPipes);
|
|
30167
|
+
}
|
|
29074
30168
|
}
|
|
29075
30169
|
else {
|
|
29076
30170
|
// We are not able to handle this cycle so throw an error.
|
|
@@ -29436,7 +30530,15 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
29436
30530
|
throw new FatalDiagnosticError(ErrorCode.COMPONENT_MISSING_TEMPLATE, Decorator.nodeForError(decorator), 'component is missing a template');
|
|
29437
30531
|
}
|
|
29438
30532
|
}
|
|
29439
|
-
|
|
30533
|
+
_resolveImportedFile(importedFile, expr, origin) {
|
|
30534
|
+
// If `importedFile` is not 'unknown' then it accurately reflects the source file that is
|
|
30535
|
+
// being imported.
|
|
30536
|
+
if (importedFile !== 'unknown') {
|
|
30537
|
+
return importedFile;
|
|
30538
|
+
}
|
|
30539
|
+
// Otherwise `expr` has to be inspected to determine the file that is being imported. If `expr`
|
|
30540
|
+
// is not an `ExternalExpr` then it does not correspond with an import, so return null in that
|
|
30541
|
+
// case.
|
|
29440
30542
|
if (!(expr instanceof ExternalExpr)) {
|
|
29441
30543
|
return null;
|
|
29442
30544
|
}
|
|
@@ -29449,16 +30551,16 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
29449
30551
|
*
|
|
29450
30552
|
* @returns a `Cycle` object if a cycle would be created, otherwise `null`.
|
|
29451
30553
|
*/
|
|
29452
|
-
_checkForCyclicImport(
|
|
29453
|
-
const
|
|
29454
|
-
if (
|
|
30554
|
+
_checkForCyclicImport(importedFile, expr, origin) {
|
|
30555
|
+
const imported = this._resolveImportedFile(importedFile, expr, origin);
|
|
30556
|
+
if (imported === null) {
|
|
29455
30557
|
return null;
|
|
29456
30558
|
}
|
|
29457
30559
|
// Check whether the import is legal.
|
|
29458
|
-
return this.cycleAnalyzer.wouldCreateCycle(origin,
|
|
30560
|
+
return this.cycleAnalyzer.wouldCreateCycle(origin, imported);
|
|
29459
30561
|
}
|
|
29460
|
-
_recordSyntheticImport(expr, origin) {
|
|
29461
|
-
const imported = this.
|
|
30562
|
+
_recordSyntheticImport(importedFile, expr, origin) {
|
|
30563
|
+
const imported = this._resolveImportedFile(importedFile, expr, origin);
|
|
29462
30564
|
if (imported === null) {
|
|
29463
30565
|
return;
|
|
29464
30566
|
}
|
|
@@ -29603,6 +30705,9 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
29603
30705
|
},
|
|
29604
30706
|
};
|
|
29605
30707
|
}
|
|
30708
|
+
symbol() {
|
|
30709
|
+
return null;
|
|
30710
|
+
}
|
|
29606
30711
|
register(node) {
|
|
29607
30712
|
this.injectableRegistry.registerInjectable(node);
|
|
29608
30713
|
}
|
|
@@ -29823,458 +30928,23 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
29823
30928
|
* found in the LICENSE file at https://angular.io/license
|
|
29824
30929
|
*/
|
|
29825
30930
|
/**
|
|
29826
|
-
*
|
|
29827
|
-
*
|
|
29828
|
-
* TODO(alxhub): handle injector side of things as well.
|
|
30931
|
+
* Represents an Angular pipe.
|
|
29829
30932
|
*/
|
|
29830
|
-
class
|
|
29831
|
-
constructor(
|
|
29832
|
-
|
|
29833
|
-
this.
|
|
29834
|
-
this.metaReader = metaReader;
|
|
29835
|
-
this.metaRegistry = metaRegistry;
|
|
29836
|
-
this.scopeRegistry = scopeRegistry;
|
|
29837
|
-
this.referencesRegistry = referencesRegistry;
|
|
29838
|
-
this.isCore = isCore;
|
|
29839
|
-
this.routeAnalyzer = routeAnalyzer;
|
|
29840
|
-
this.refEmitter = refEmitter;
|
|
29841
|
-
this.factoryTracker = factoryTracker;
|
|
29842
|
-
this.defaultImportRecorder = defaultImportRecorder;
|
|
29843
|
-
this.annotateForClosureCompiler = annotateForClosureCompiler;
|
|
29844
|
-
this.injectableRegistry = injectableRegistry;
|
|
29845
|
-
this.localeId = localeId;
|
|
29846
|
-
this.precedence = HandlerPrecedence.PRIMARY;
|
|
29847
|
-
this.name = NgModuleDecoratorHandler.name;
|
|
29848
|
-
}
|
|
29849
|
-
detect(node, decorators) {
|
|
29850
|
-
if (!decorators) {
|
|
29851
|
-
return undefined;
|
|
29852
|
-
}
|
|
29853
|
-
const decorator = findAngularDecorator(decorators, 'NgModule', this.isCore);
|
|
29854
|
-
if (decorator !== undefined) {
|
|
29855
|
-
return {
|
|
29856
|
-
trigger: decorator.node,
|
|
29857
|
-
decorator: decorator,
|
|
29858
|
-
metadata: decorator,
|
|
29859
|
-
};
|
|
29860
|
-
}
|
|
29861
|
-
else {
|
|
29862
|
-
return undefined;
|
|
29863
|
-
}
|
|
29864
|
-
}
|
|
29865
|
-
analyze(node, decorator) {
|
|
29866
|
-
const name = node.name.text;
|
|
29867
|
-
if (decorator.args === null || decorator.args.length > 1) {
|
|
29868
|
-
throw new FatalDiagnosticError(ErrorCode.DECORATOR_ARITY_WRONG, Decorator.nodeForError(decorator), `Incorrect number of arguments to @NgModule decorator`);
|
|
29869
|
-
}
|
|
29870
|
-
// @NgModule can be invoked without arguments. In case it is, pretend as if a blank object
|
|
29871
|
-
// literal was specified. This simplifies the code below.
|
|
29872
|
-
const meta = decorator.args.length === 1 ? unwrapExpression(decorator.args[0]) :
|
|
29873
|
-
ts$1.createObjectLiteral([]);
|
|
29874
|
-
if (!ts$1.isObjectLiteralExpression(meta)) {
|
|
29875
|
-
throw new FatalDiagnosticError(ErrorCode.DECORATOR_ARG_NOT_LITERAL, meta, '@NgModule argument must be an object literal');
|
|
29876
|
-
}
|
|
29877
|
-
const ngModule = reflectObjectLiteral(meta);
|
|
29878
|
-
if (ngModule.has('jit')) {
|
|
29879
|
-
// The only allowed value is true, so there's no need to expand further.
|
|
29880
|
-
return {};
|
|
29881
|
-
}
|
|
29882
|
-
const moduleResolvers = combineResolvers([
|
|
29883
|
-
ref => this._extractModuleFromModuleWithProvidersFn(ref.node),
|
|
29884
|
-
forwardRefResolver,
|
|
29885
|
-
]);
|
|
29886
|
-
const diagnostics = [];
|
|
29887
|
-
// Extract the module declarations, imports, and exports.
|
|
29888
|
-
let declarationRefs = [];
|
|
29889
|
-
let rawDeclarations = null;
|
|
29890
|
-
if (ngModule.has('declarations')) {
|
|
29891
|
-
rawDeclarations = ngModule.get('declarations');
|
|
29892
|
-
const declarationMeta = this.evaluator.evaluate(rawDeclarations, forwardRefResolver);
|
|
29893
|
-
declarationRefs =
|
|
29894
|
-
this.resolveTypeList(rawDeclarations, declarationMeta, name, 'declarations');
|
|
29895
|
-
// Look through the declarations to make sure they're all a part of the current compilation.
|
|
29896
|
-
for (const ref of declarationRefs) {
|
|
29897
|
-
if (ref.node.getSourceFile().isDeclarationFile) {
|
|
29898
|
-
const errorNode = ref.getOriginForDiagnostics(rawDeclarations);
|
|
29899
|
-
diagnostics.push(makeDiagnostic(ErrorCode.NGMODULE_INVALID_DECLARATION, errorNode, `Cannot declare '${ref.node.name
|
|
29900
|
-
.text}' in an NgModule as it's not a part of the current compilation.`, [makeRelatedInformation(ref.node.name, `'${ref.node.name.text}' is declared here.`)]));
|
|
29901
|
-
}
|
|
29902
|
-
}
|
|
29903
|
-
}
|
|
29904
|
-
if (diagnostics.length > 0) {
|
|
29905
|
-
return { diagnostics };
|
|
29906
|
-
}
|
|
29907
|
-
let importRefs = [];
|
|
29908
|
-
let rawImports = null;
|
|
29909
|
-
if (ngModule.has('imports')) {
|
|
29910
|
-
rawImports = ngModule.get('imports');
|
|
29911
|
-
const importsMeta = this.evaluator.evaluate(rawImports, moduleResolvers);
|
|
29912
|
-
importRefs = this.resolveTypeList(rawImports, importsMeta, name, 'imports');
|
|
29913
|
-
}
|
|
29914
|
-
let exportRefs = [];
|
|
29915
|
-
let rawExports = null;
|
|
29916
|
-
if (ngModule.has('exports')) {
|
|
29917
|
-
rawExports = ngModule.get('exports');
|
|
29918
|
-
const exportsMeta = this.evaluator.evaluate(rawExports, moduleResolvers);
|
|
29919
|
-
exportRefs = this.resolveTypeList(rawExports, exportsMeta, name, 'exports');
|
|
29920
|
-
this.referencesRegistry.add(node, ...exportRefs);
|
|
29921
|
-
}
|
|
29922
|
-
let bootstrapRefs = [];
|
|
29923
|
-
if (ngModule.has('bootstrap')) {
|
|
29924
|
-
const expr = ngModule.get('bootstrap');
|
|
29925
|
-
const bootstrapMeta = this.evaluator.evaluate(expr, forwardRefResolver);
|
|
29926
|
-
bootstrapRefs = this.resolveTypeList(expr, bootstrapMeta, name, 'bootstrap');
|
|
29927
|
-
}
|
|
29928
|
-
const schemas = [];
|
|
29929
|
-
if (ngModule.has('schemas')) {
|
|
29930
|
-
const rawExpr = ngModule.get('schemas');
|
|
29931
|
-
const result = this.evaluator.evaluate(rawExpr);
|
|
29932
|
-
if (!Array.isArray(result)) {
|
|
29933
|
-
throw createValueHasWrongTypeError(rawExpr, result, `NgModule.schemas must be an array`);
|
|
29934
|
-
}
|
|
29935
|
-
for (const schemaRef of result) {
|
|
29936
|
-
if (!(schemaRef instanceof Reference$1)) {
|
|
29937
|
-
throw createValueHasWrongTypeError(rawExpr, result, 'NgModule.schemas must be an array of schemas');
|
|
29938
|
-
}
|
|
29939
|
-
const id = schemaRef.getIdentityIn(schemaRef.node.getSourceFile());
|
|
29940
|
-
if (id === null || schemaRef.ownedByModuleGuess !== '@angular/core') {
|
|
29941
|
-
throw createValueHasWrongTypeError(rawExpr, result, 'NgModule.schemas must be an array of schemas');
|
|
29942
|
-
}
|
|
29943
|
-
// Since `id` is the `ts.Identifer` within the schema ref's declaration file, it's safe to
|
|
29944
|
-
// use `id.text` here to figure out which schema is in use. Even if the actual reference was
|
|
29945
|
-
// renamed when the user imported it, these names will match.
|
|
29946
|
-
switch (id.text) {
|
|
29947
|
-
case 'CUSTOM_ELEMENTS_SCHEMA':
|
|
29948
|
-
schemas.push(CUSTOM_ELEMENTS_SCHEMA);
|
|
29949
|
-
break;
|
|
29950
|
-
case 'NO_ERRORS_SCHEMA':
|
|
29951
|
-
schemas.push(NO_ERRORS_SCHEMA);
|
|
29952
|
-
break;
|
|
29953
|
-
default:
|
|
29954
|
-
throw createValueHasWrongTypeError(rawExpr, schemaRef, `'${schemaRef.debugName}' is not a valid NgModule schema`);
|
|
29955
|
-
}
|
|
29956
|
-
}
|
|
29957
|
-
}
|
|
29958
|
-
const id = ngModule.has('id') ? new WrappedNodeExpr(ngModule.get('id')) : null;
|
|
29959
|
-
const valueContext = node.getSourceFile();
|
|
29960
|
-
let typeContext = valueContext;
|
|
29961
|
-
const typeNode = this.reflector.getDtsDeclaration(node);
|
|
29962
|
-
if (typeNode !== null) {
|
|
29963
|
-
typeContext = typeNode.getSourceFile();
|
|
29964
|
-
}
|
|
29965
|
-
const bootstrap = bootstrapRefs.map(bootstrap => this._toR3Reference(bootstrap, valueContext, typeContext));
|
|
29966
|
-
const declarations = declarationRefs.map(decl => this._toR3Reference(decl, valueContext, typeContext));
|
|
29967
|
-
const imports = importRefs.map(imp => this._toR3Reference(imp, valueContext, typeContext));
|
|
29968
|
-
const exports = exportRefs.map(exp => this._toR3Reference(exp, valueContext, typeContext));
|
|
29969
|
-
const isForwardReference = (ref) => isExpressionForwardReference(ref.value, node.name, valueContext);
|
|
29970
|
-
const containsForwardDecls = bootstrap.some(isForwardReference) ||
|
|
29971
|
-
declarations.some(isForwardReference) || imports.some(isForwardReference) ||
|
|
29972
|
-
exports.some(isForwardReference);
|
|
29973
|
-
const type = wrapTypeReference(this.reflector, node);
|
|
29974
|
-
const internalType = new WrappedNodeExpr(this.reflector.getInternalNameOfClass(node));
|
|
29975
|
-
const adjacentType = new WrappedNodeExpr(this.reflector.getAdjacentNameOfClass(node));
|
|
29976
|
-
const ngModuleDef = {
|
|
29977
|
-
type,
|
|
29978
|
-
internalType,
|
|
29979
|
-
adjacentType,
|
|
29980
|
-
bootstrap,
|
|
29981
|
-
declarations,
|
|
29982
|
-
exports,
|
|
29983
|
-
imports,
|
|
29984
|
-
containsForwardDecls,
|
|
29985
|
-
id,
|
|
29986
|
-
emitInline: false,
|
|
29987
|
-
// TODO: to be implemented as a part of FW-1004.
|
|
29988
|
-
schemas: [],
|
|
29989
|
-
};
|
|
29990
|
-
const rawProviders = ngModule.has('providers') ? ngModule.get('providers') : null;
|
|
29991
|
-
const wrapperProviders = rawProviders !== null ?
|
|
29992
|
-
new WrappedNodeExpr(this.annotateForClosureCompiler ? wrapFunctionExpressionsInParens(rawProviders) :
|
|
29993
|
-
rawProviders) :
|
|
29994
|
-
null;
|
|
29995
|
-
// At this point, only add the module's imports as the injectors' imports. Any exported modules
|
|
29996
|
-
// are added during `resolve`, as we need scope information to be able to filter out directives
|
|
29997
|
-
// and pipes from the module exports.
|
|
29998
|
-
const injectorImports = [];
|
|
29999
|
-
if (ngModule.has('imports')) {
|
|
30000
|
-
injectorImports.push(new WrappedNodeExpr(ngModule.get('imports')));
|
|
30001
|
-
}
|
|
30002
|
-
if (this.routeAnalyzer !== null) {
|
|
30003
|
-
this.routeAnalyzer.add(node.getSourceFile(), name, rawImports, rawExports, rawProviders);
|
|
30004
|
-
}
|
|
30005
|
-
const ngInjectorDef = {
|
|
30006
|
-
name,
|
|
30007
|
-
type,
|
|
30008
|
-
internalType,
|
|
30009
|
-
deps: getValidConstructorDependencies(node, this.reflector, this.defaultImportRecorder, this.isCore),
|
|
30010
|
-
providers: wrapperProviders,
|
|
30011
|
-
imports: injectorImports,
|
|
30012
|
-
};
|
|
30013
|
-
return {
|
|
30014
|
-
analysis: {
|
|
30015
|
-
id,
|
|
30016
|
-
schemas: schemas,
|
|
30017
|
-
mod: ngModuleDef,
|
|
30018
|
-
inj: ngInjectorDef,
|
|
30019
|
-
declarations: declarationRefs,
|
|
30020
|
-
rawDeclarations,
|
|
30021
|
-
imports: importRefs,
|
|
30022
|
-
exports: exportRefs,
|
|
30023
|
-
providers: rawProviders,
|
|
30024
|
-
providersRequiringFactory: rawProviders ?
|
|
30025
|
-
resolveProvidersRequiringFactory(rawProviders, this.reflector, this.evaluator) :
|
|
30026
|
-
null,
|
|
30027
|
-
metadataStmt: generateSetClassMetadataCall(node, this.reflector, this.defaultImportRecorder, this.isCore, this.annotateForClosureCompiler),
|
|
30028
|
-
factorySymbolName: node.name.text,
|
|
30029
|
-
},
|
|
30030
|
-
};
|
|
30031
|
-
}
|
|
30032
|
-
register(node, analysis) {
|
|
30033
|
-
// Register this module's information with the LocalModuleScopeRegistry. This ensures that
|
|
30034
|
-
// during the compile() phase, the module's metadata is available for selector scope
|
|
30035
|
-
// computation.
|
|
30036
|
-
this.metaRegistry.registerNgModuleMetadata({
|
|
30037
|
-
ref: new Reference$1(node),
|
|
30038
|
-
schemas: analysis.schemas,
|
|
30039
|
-
declarations: analysis.declarations,
|
|
30040
|
-
imports: analysis.imports,
|
|
30041
|
-
exports: analysis.exports,
|
|
30042
|
-
rawDeclarations: analysis.rawDeclarations,
|
|
30043
|
-
});
|
|
30044
|
-
if (this.factoryTracker !== null) {
|
|
30045
|
-
this.factoryTracker.track(node.getSourceFile(), {
|
|
30046
|
-
name: analysis.factorySymbolName,
|
|
30047
|
-
hasId: analysis.id !== null,
|
|
30048
|
-
});
|
|
30049
|
-
}
|
|
30050
|
-
this.injectableRegistry.registerInjectable(node);
|
|
30051
|
-
}
|
|
30052
|
-
resolve(node, analysis) {
|
|
30053
|
-
const scope = this.scopeRegistry.getScopeOfModule(node);
|
|
30054
|
-
const diagnostics = [];
|
|
30055
|
-
const scopeDiagnostics = this.scopeRegistry.getDiagnosticsOfModule(node);
|
|
30056
|
-
if (scopeDiagnostics !== null) {
|
|
30057
|
-
diagnostics.push(...scopeDiagnostics);
|
|
30058
|
-
}
|
|
30059
|
-
if (analysis.providersRequiringFactory !== null) {
|
|
30060
|
-
const providerDiagnostics = getProviderDiagnostics(analysis.providersRequiringFactory, analysis.providers, this.injectableRegistry);
|
|
30061
|
-
diagnostics.push(...providerDiagnostics);
|
|
30062
|
-
}
|
|
30063
|
-
const data = {
|
|
30064
|
-
injectorImports: [],
|
|
30065
|
-
};
|
|
30066
|
-
if (scope !== null && !scope.compilation.isPoisoned) {
|
|
30067
|
-
// Using the scope information, extend the injector's imports using the modules that are
|
|
30068
|
-
// specified as module exports.
|
|
30069
|
-
const context = getSourceFile(node);
|
|
30070
|
-
for (const exportRef of analysis.exports) {
|
|
30071
|
-
if (isNgModule(exportRef.node, scope.compilation)) {
|
|
30072
|
-
data.injectorImports.push(this.refEmitter.emit(exportRef, context));
|
|
30073
|
-
}
|
|
30074
|
-
}
|
|
30075
|
-
for (const decl of analysis.declarations) {
|
|
30076
|
-
const metadata = this.metaReader.getDirectiveMetadata(decl);
|
|
30077
|
-
if (metadata !== null && metadata.selector === null) {
|
|
30078
|
-
throw new FatalDiagnosticError(ErrorCode.DIRECTIVE_MISSING_SELECTOR, decl.node, `Directive ${decl.node.name.text} has no selector, please add it!`);
|
|
30079
|
-
}
|
|
30080
|
-
}
|
|
30081
|
-
}
|
|
30082
|
-
if (diagnostics.length > 0) {
|
|
30083
|
-
return { diagnostics };
|
|
30084
|
-
}
|
|
30085
|
-
if (scope === null || scope.compilation.isPoisoned || scope.exported.isPoisoned ||
|
|
30086
|
-
scope.reexports === null) {
|
|
30087
|
-
return { data };
|
|
30088
|
-
}
|
|
30089
|
-
else {
|
|
30090
|
-
return {
|
|
30091
|
-
data,
|
|
30092
|
-
reexports: scope.reexports,
|
|
30093
|
-
};
|
|
30094
|
-
}
|
|
30095
|
-
}
|
|
30096
|
-
compileFull(node, analysis, resolution) {
|
|
30097
|
-
// Merge the injector imports (which are 'exports' that were later found to be NgModules)
|
|
30098
|
-
// computed during resolution with the ones from analysis.
|
|
30099
|
-
const ngInjectorDef = compileInjector(Object.assign(Object.assign({}, analysis.inj), { imports: [...analysis.inj.imports, ...resolution.injectorImports] }));
|
|
30100
|
-
const ngModuleDef = compileNgModule(analysis.mod);
|
|
30101
|
-
const ngModuleStatements = ngModuleDef.additionalStatements;
|
|
30102
|
-
if (analysis.metadataStmt !== null) {
|
|
30103
|
-
ngModuleStatements.push(analysis.metadataStmt);
|
|
30104
|
-
}
|
|
30105
|
-
const context = getSourceFile(node);
|
|
30106
|
-
for (const decl of analysis.declarations) {
|
|
30107
|
-
const remoteScope = this.scopeRegistry.getRemoteScope(decl.node);
|
|
30108
|
-
if (remoteScope !== null) {
|
|
30109
|
-
const directives = remoteScope.directives.map(directive => this.refEmitter.emit(directive, context));
|
|
30110
|
-
const pipes = remoteScope.pipes.map(pipe => this.refEmitter.emit(pipe, context));
|
|
30111
|
-
const directiveArray = new LiteralArrayExpr(directives);
|
|
30112
|
-
const pipesArray = new LiteralArrayExpr(pipes);
|
|
30113
|
-
const declExpr = this.refEmitter.emit(decl, context);
|
|
30114
|
-
const setComponentScope = new ExternalExpr(Identifiers$1.setComponentScope);
|
|
30115
|
-
const callExpr = new InvokeFunctionExpr(setComponentScope, [declExpr, directiveArray, pipesArray]);
|
|
30116
|
-
ngModuleStatements.push(callExpr.toStmt());
|
|
30117
|
-
}
|
|
30118
|
-
}
|
|
30119
|
-
const res = [
|
|
30120
|
-
{
|
|
30121
|
-
name: 'ɵmod',
|
|
30122
|
-
initializer: ngModuleDef.expression,
|
|
30123
|
-
statements: ngModuleStatements,
|
|
30124
|
-
type: ngModuleDef.type,
|
|
30125
|
-
},
|
|
30126
|
-
{
|
|
30127
|
-
name: 'ɵinj',
|
|
30128
|
-
initializer: ngInjectorDef.expression,
|
|
30129
|
-
statements: ngInjectorDef.statements,
|
|
30130
|
-
type: ngInjectorDef.type,
|
|
30131
|
-
}
|
|
30132
|
-
];
|
|
30133
|
-
if (this.localeId) {
|
|
30134
|
-
res.push({
|
|
30135
|
-
name: 'ɵloc',
|
|
30136
|
-
initializer: new LiteralExpr(this.localeId),
|
|
30137
|
-
statements: [],
|
|
30138
|
-
type: STRING_TYPE
|
|
30139
|
-
});
|
|
30140
|
-
}
|
|
30141
|
-
return res;
|
|
30142
|
-
}
|
|
30143
|
-
_toR3Reference(valueRef, valueContext, typeContext) {
|
|
30144
|
-
if (valueRef.hasOwningModuleGuess) {
|
|
30145
|
-
return toR3Reference(valueRef, valueRef, valueContext, valueContext, this.refEmitter);
|
|
30146
|
-
}
|
|
30147
|
-
else {
|
|
30148
|
-
let typeRef = valueRef;
|
|
30149
|
-
let typeNode = this.reflector.getDtsDeclaration(typeRef.node);
|
|
30150
|
-
if (typeNode !== null && isNamedClassDeclaration(typeNode)) {
|
|
30151
|
-
typeRef = new Reference$1(typeNode);
|
|
30152
|
-
}
|
|
30153
|
-
return toR3Reference(valueRef, typeRef, valueContext, typeContext, this.refEmitter);
|
|
30154
|
-
}
|
|
30155
|
-
}
|
|
30156
|
-
/**
|
|
30157
|
-
* Given a `FunctionDeclaration`, `MethodDeclaration` or `FunctionExpression`, check if it is
|
|
30158
|
-
* typed as a `ModuleWithProviders` and return an expression referencing the module if available.
|
|
30159
|
-
*/
|
|
30160
|
-
_extractModuleFromModuleWithProvidersFn(node) {
|
|
30161
|
-
const type = node.type || null;
|
|
30162
|
-
return type &&
|
|
30163
|
-
(this._reflectModuleFromTypeParam(type, node) || this._reflectModuleFromLiteralType(type));
|
|
30164
|
-
}
|
|
30165
|
-
/**
|
|
30166
|
-
* Retrieve an `NgModule` identifier (T) from the specified `type`, if it is of the form:
|
|
30167
|
-
* `ModuleWithProviders<T>`
|
|
30168
|
-
* @param type The type to reflect on.
|
|
30169
|
-
* @returns the identifier of the NgModule type if found, or null otherwise.
|
|
30170
|
-
*/
|
|
30171
|
-
_reflectModuleFromTypeParam(type, node) {
|
|
30172
|
-
// Examine the type of the function to see if it's a ModuleWithProviders reference.
|
|
30173
|
-
if (!ts$1.isTypeReferenceNode(type)) {
|
|
30174
|
-
return null;
|
|
30175
|
-
}
|
|
30176
|
-
const typeName = type &&
|
|
30177
|
-
(ts$1.isIdentifier(type.typeName) && type.typeName ||
|
|
30178
|
-
ts$1.isQualifiedName(type.typeName) && type.typeName.right) ||
|
|
30179
|
-
null;
|
|
30180
|
-
if (typeName === null) {
|
|
30181
|
-
return null;
|
|
30182
|
-
}
|
|
30183
|
-
// Look at the type itself to see where it comes from.
|
|
30184
|
-
const id = this.reflector.getImportOfIdentifier(typeName);
|
|
30185
|
-
// If it's not named ModuleWithProviders, bail.
|
|
30186
|
-
if (id === null || id.name !== 'ModuleWithProviders') {
|
|
30187
|
-
return null;
|
|
30188
|
-
}
|
|
30189
|
-
// If it's not from @angular/core, bail.
|
|
30190
|
-
if (!this.isCore && id.from !== '@angular/core') {
|
|
30191
|
-
return null;
|
|
30192
|
-
}
|
|
30193
|
-
// If there's no type parameter specified, bail.
|
|
30194
|
-
if (type.typeArguments === undefined || type.typeArguments.length !== 1) {
|
|
30195
|
-
const parent = ts$1.isMethodDeclaration(node) && ts$1.isClassDeclaration(node.parent) ? node.parent : null;
|
|
30196
|
-
const symbolName = (parent && parent.name ? parent.name.getText() + '.' : '') +
|
|
30197
|
-
(node.name ? node.name.getText() : 'anonymous');
|
|
30198
|
-
throw new FatalDiagnosticError(ErrorCode.NGMODULE_MODULE_WITH_PROVIDERS_MISSING_GENERIC, type, `${symbolName} returns a ModuleWithProviders type without a generic type argument. ` +
|
|
30199
|
-
`Please add a generic type argument to the ModuleWithProviders type. If this ` +
|
|
30200
|
-
`occurrence is in library code you don't control, please contact the library authors.`);
|
|
30201
|
-
}
|
|
30202
|
-
const arg = type.typeArguments[0];
|
|
30203
|
-
return typeNodeToValueExpr(arg);
|
|
30933
|
+
class PipeSymbol extends SemanticSymbol {
|
|
30934
|
+
constructor(decl, name) {
|
|
30935
|
+
super(decl);
|
|
30936
|
+
this.name = name;
|
|
30204
30937
|
}
|
|
30205
|
-
|
|
30206
|
-
|
|
30207
|
-
|
|
30208
|
-
* @param type The type to reflect on.
|
|
30209
|
-
* @returns the identifier of the NgModule type if found, or null otherwise.
|
|
30210
|
-
*/
|
|
30211
|
-
_reflectModuleFromLiteralType(type) {
|
|
30212
|
-
if (!ts$1.isIntersectionTypeNode(type)) {
|
|
30213
|
-
return null;
|
|
30214
|
-
}
|
|
30215
|
-
for (const t of type.types) {
|
|
30216
|
-
if (ts$1.isTypeLiteralNode(t)) {
|
|
30217
|
-
for (const m of t.members) {
|
|
30218
|
-
const ngModuleType = ts$1.isPropertySignature(m) && ts$1.isIdentifier(m.name) &&
|
|
30219
|
-
m.name.text === 'ngModule' && m.type ||
|
|
30220
|
-
null;
|
|
30221
|
-
const ngModuleExpression = ngModuleType && typeNodeToValueExpr(ngModuleType);
|
|
30222
|
-
if (ngModuleExpression) {
|
|
30223
|
-
return ngModuleExpression;
|
|
30224
|
-
}
|
|
30225
|
-
}
|
|
30226
|
-
}
|
|
30938
|
+
isPublicApiAffected(previousSymbol) {
|
|
30939
|
+
if (!(previousSymbol instanceof PipeSymbol)) {
|
|
30940
|
+
return true;
|
|
30227
30941
|
}
|
|
30228
|
-
return
|
|
30942
|
+
return this.name !== previousSymbol.name;
|
|
30229
30943
|
}
|
|
30230
|
-
|
|
30231
|
-
|
|
30232
|
-
return this.reflector.isClass(ref.node);
|
|
30233
|
-
}
|
|
30234
|
-
/**
|
|
30235
|
-
* Compute a list of `Reference`s from a resolved metadata value.
|
|
30236
|
-
*/
|
|
30237
|
-
resolveTypeList(expr, resolvedList, className, arrayName) {
|
|
30238
|
-
const refList = [];
|
|
30239
|
-
if (!Array.isArray(resolvedList)) {
|
|
30240
|
-
throw createValueHasWrongTypeError(expr, resolvedList, `Expected array when reading the NgModule.${arrayName} of ${className}`);
|
|
30241
|
-
}
|
|
30242
|
-
resolvedList.forEach((entry, idx) => {
|
|
30243
|
-
// Unwrap ModuleWithProviders for modules that are locally declared (and thus static
|
|
30244
|
-
// resolution was able to descend into the function and return an object literal, a Map).
|
|
30245
|
-
if (entry instanceof Map && entry.has('ngModule')) {
|
|
30246
|
-
entry = entry.get('ngModule');
|
|
30247
|
-
}
|
|
30248
|
-
if (Array.isArray(entry)) {
|
|
30249
|
-
// Recurse into nested arrays.
|
|
30250
|
-
refList.push(...this.resolveTypeList(expr, entry, className, arrayName));
|
|
30251
|
-
}
|
|
30252
|
-
else if (entry instanceof Reference$1) {
|
|
30253
|
-
if (!this.isClassDeclarationReference(entry)) {
|
|
30254
|
-
throw createValueHasWrongTypeError(entry.node, entry, `Value at position ${idx} in the NgModule.${arrayName} of ${className} is not a class`);
|
|
30255
|
-
}
|
|
30256
|
-
refList.push(entry);
|
|
30257
|
-
}
|
|
30258
|
-
else {
|
|
30259
|
-
// TODO(alxhub): Produce a better diagnostic here - the array index may be an inner array.
|
|
30260
|
-
throw createValueHasWrongTypeError(expr, entry, `Value at position ${idx} in the NgModule.${arrayName} of ${className} is not a reference`);
|
|
30261
|
-
}
|
|
30262
|
-
});
|
|
30263
|
-
return refList;
|
|
30944
|
+
isTypeCheckApiAffected(previousSymbol) {
|
|
30945
|
+
return this.isPublicApiAffected(previousSymbol);
|
|
30264
30946
|
}
|
|
30265
30947
|
}
|
|
30266
|
-
function isNgModule(node, compilation) {
|
|
30267
|
-
return !compilation.directives.some(directive => directive.ref.node === node) &&
|
|
30268
|
-
!compilation.pipes.some(pipe => pipe.ref.node === node);
|
|
30269
|
-
}
|
|
30270
|
-
|
|
30271
|
-
/**
|
|
30272
|
-
* @license
|
|
30273
|
-
* Copyright Google LLC All Rights Reserved.
|
|
30274
|
-
*
|
|
30275
|
-
* Use of this source code is governed by an MIT-style license that can be
|
|
30276
|
-
* found in the LICENSE file at https://angular.io/license
|
|
30277
|
-
*/
|
|
30278
30948
|
class PipeDecoratorHandler {
|
|
30279
30949
|
constructor(reflector, evaluator, metaRegistry, scopeRegistry, defaultImportRecorder, injectableRegistry, isCore) {
|
|
30280
30950
|
this.reflector = reflector;
|
|
@@ -30350,6 +31020,9 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
30350
31020
|
},
|
|
30351
31021
|
};
|
|
30352
31022
|
}
|
|
31023
|
+
symbol(node, analysis) {
|
|
31024
|
+
return new PipeSymbol(node, analysis.meta.name);
|
|
31025
|
+
}
|
|
30353
31026
|
register(node, analysis) {
|
|
30354
31027
|
const ref = new Reference$1(node);
|
|
30355
31028
|
this.metaRegistry.registerPipeMetadata({ ref, name: analysis.meta.pipeName });
|
|
@@ -30479,8 +31152,8 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
30479
31152
|
* dependencies within the same program are tracked; imports into packages on NPM are not.
|
|
30480
31153
|
*/
|
|
30481
31154
|
class ImportGraph {
|
|
30482
|
-
constructor(
|
|
30483
|
-
this.
|
|
31155
|
+
constructor(checker) {
|
|
31156
|
+
this.checker = checker;
|
|
30484
31157
|
this.map = new Map();
|
|
30485
31158
|
}
|
|
30486
31159
|
/**
|
|
@@ -30557,24 +31230,28 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
30557
31230
|
}
|
|
30558
31231
|
scanImports(sf) {
|
|
30559
31232
|
const imports = new Set();
|
|
30560
|
-
// Look through the source file for import statements.
|
|
30561
|
-
sf.statements
|
|
30562
|
-
if ((ts$1.isImportDeclaration(stmt)
|
|
30563
|
-
stmt.moduleSpecifier
|
|
30564
|
-
|
|
30565
|
-
const moduleName = stmt.moduleSpecifier.text;
|
|
30566
|
-
const moduleFile = this.resolver.resolveModule(moduleName, sf.fileName);
|
|
30567
|
-
if (moduleFile !== null && isLocalFile(moduleFile)) {
|
|
30568
|
-
// Record this local import.
|
|
30569
|
-
imports.add(moduleFile);
|
|
30570
|
-
}
|
|
31233
|
+
// Look through the source file for import and export statements.
|
|
31234
|
+
for (const stmt of sf.statements) {
|
|
31235
|
+
if ((!ts$1.isImportDeclaration(stmt) && !ts$1.isExportDeclaration(stmt)) ||
|
|
31236
|
+
stmt.moduleSpecifier === undefined) {
|
|
31237
|
+
continue;
|
|
30571
31238
|
}
|
|
30572
|
-
|
|
31239
|
+
const symbol = this.checker.getSymbolAtLocation(stmt.moduleSpecifier);
|
|
31240
|
+
if (symbol === undefined || symbol.valueDeclaration === undefined) {
|
|
31241
|
+
// No symbol could be found to skip over this import/export.
|
|
31242
|
+
continue;
|
|
31243
|
+
}
|
|
31244
|
+
const moduleFile = symbol.valueDeclaration;
|
|
31245
|
+
if (ts$1.isSourceFile(moduleFile) && isLocalFile(moduleFile)) {
|
|
31246
|
+
// Record this local import.
|
|
31247
|
+
imports.add(moduleFile);
|
|
31248
|
+
}
|
|
31249
|
+
}
|
|
30573
31250
|
return imports;
|
|
30574
31251
|
}
|
|
30575
31252
|
}
|
|
30576
31253
|
function isLocalFile(sf) {
|
|
30577
|
-
return !sf.
|
|
31254
|
+
return !sf.isDeclarationFile;
|
|
30578
31255
|
}
|
|
30579
31256
|
/**
|
|
30580
31257
|
* A helper class to track which SourceFiles are being processed when searching for a path in
|
|
@@ -30824,21 +31501,6 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
30824
31501
|
addResourceDependency(from, resource) {
|
|
30825
31502
|
this.nodeFor(from).usesResources.add(resource);
|
|
30826
31503
|
}
|
|
30827
|
-
addTransitiveDependency(from, on) {
|
|
30828
|
-
const nodeFrom = this.nodeFor(from);
|
|
30829
|
-
nodeFrom.dependsOn.add(on.fileName);
|
|
30830
|
-
const nodeOn = this.nodeFor(on);
|
|
30831
|
-
for (const dep of nodeOn.dependsOn) {
|
|
30832
|
-
nodeFrom.dependsOn.add(dep);
|
|
30833
|
-
}
|
|
30834
|
-
}
|
|
30835
|
-
addTransitiveResources(from, resourcesOf) {
|
|
30836
|
-
const nodeFrom = this.nodeFor(from);
|
|
30837
|
-
const nodeOn = this.nodeFor(resourcesOf);
|
|
30838
|
-
for (const dep of nodeOn.usesResources) {
|
|
30839
|
-
nodeFrom.usesResources.add(dep);
|
|
30840
|
-
}
|
|
30841
|
-
}
|
|
30842
31504
|
recordDependencyAnalysisFailure(file) {
|
|
30843
31505
|
this.nodeFor(file).failedAnalysis = true;
|
|
30844
31506
|
}
|
|
@@ -30846,9 +31508,6 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
30846
31508
|
const node = this.nodes.get(from);
|
|
30847
31509
|
return node ? [...node.usesResources] : [];
|
|
30848
31510
|
}
|
|
30849
|
-
isStale(sf, changedTsPaths, changedResources) {
|
|
30850
|
-
return isLogicallyChanged(sf, this.nodeFor(sf), changedTsPaths, EMPTY_SET, changedResources);
|
|
30851
|
-
}
|
|
30852
31511
|
/**
|
|
30853
31512
|
* Update the current dependency graph from a previous one, incorporating a set of physical
|
|
30854
31513
|
* changes.
|
|
@@ -30926,7 +31585,6 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
30926
31585
|
}
|
|
30927
31586
|
return false;
|
|
30928
31587
|
}
|
|
30929
|
-
const EMPTY_SET = new Set();
|
|
30930
31588
|
|
|
30931
31589
|
/**
|
|
30932
31590
|
* @license
|
|
@@ -30939,8 +31597,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
30939
31597
|
* Drives an incremental build, by tracking changes and determining which files need to be emitted.
|
|
30940
31598
|
*/
|
|
30941
31599
|
class IncrementalDriver {
|
|
30942
|
-
constructor(state,
|
|
30943
|
-
this.allTsFiles = allTsFiles;
|
|
31600
|
+
constructor(state, depGraph, logicalChanges) {
|
|
30944
31601
|
this.depGraph = depGraph;
|
|
30945
31602
|
this.logicalChanges = logicalChanges;
|
|
30946
31603
|
this.state = state;
|
|
@@ -30961,14 +31618,20 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
30961
31618
|
state = oldDriver.state;
|
|
30962
31619
|
}
|
|
30963
31620
|
else {
|
|
31621
|
+
let priorGraph = null;
|
|
31622
|
+
if (oldDriver.state.lastGood !== null) {
|
|
31623
|
+
priorGraph = oldDriver.state.lastGood.semanticDepGraph;
|
|
31624
|
+
}
|
|
30964
31625
|
// The previous build was successfully analyzed. `pendingEmit` is the only state carried
|
|
30965
31626
|
// forward into this build.
|
|
30966
31627
|
state = {
|
|
30967
31628
|
kind: BuildStateKind.Pending,
|
|
30968
31629
|
pendingEmit: oldDriver.state.pendingEmit,
|
|
31630
|
+
pendingTypeCheckEmit: oldDriver.state.pendingTypeCheckEmit,
|
|
30969
31631
|
changedResourcePaths: new Set(),
|
|
30970
31632
|
changedTsPaths: new Set(),
|
|
30971
31633
|
lastGood: oldDriver.state.lastGood,
|
|
31634
|
+
semanticDepGraphUpdater: new SemanticDepGraphUpdater(priorGraph),
|
|
30972
31635
|
};
|
|
30973
31636
|
}
|
|
30974
31637
|
// Merge the freshly modified resource files with any prior ones.
|
|
@@ -31011,6 +31674,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
31011
31674
|
// The next step is to remove any deleted files from the state.
|
|
31012
31675
|
for (const filePath of deletedTsPaths) {
|
|
31013
31676
|
state.pendingEmit.delete(filePath);
|
|
31677
|
+
state.pendingTypeCheckEmit.delete(filePath);
|
|
31014
31678
|
// Even if the file doesn't exist in the current compilation, it still might have been changed
|
|
31015
31679
|
// in a previous one, so delete it from the set of changed TS files, just in case.
|
|
31016
31680
|
state.changedTsPaths.delete(filePath);
|
|
@@ -31037,10 +31701,11 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
31037
31701
|
// re-emitted.
|
|
31038
31702
|
for (const change of logicalChanges) {
|
|
31039
31703
|
state.pendingEmit.add(change);
|
|
31704
|
+
state.pendingTypeCheckEmit.add(change);
|
|
31040
31705
|
}
|
|
31041
31706
|
}
|
|
31042
31707
|
// `state` now reflects the initial pending state of the current compilation.
|
|
31043
|
-
return new IncrementalDriver(state,
|
|
31708
|
+
return new IncrementalDriver(state, depGraph, logicalChanges);
|
|
31044
31709
|
}
|
|
31045
31710
|
static fresh(program) {
|
|
31046
31711
|
// Initialize the set of files which need to be emitted to the set of all TS files in the
|
|
@@ -31049,33 +31714,44 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
31049
31714
|
const state = {
|
|
31050
31715
|
kind: BuildStateKind.Pending,
|
|
31051
31716
|
pendingEmit: new Set(tsFiles.map(sf => sf.fileName)),
|
|
31717
|
+
pendingTypeCheckEmit: new Set(tsFiles.map(sf => sf.fileName)),
|
|
31052
31718
|
changedResourcePaths: new Set(),
|
|
31053
31719
|
changedTsPaths: new Set(),
|
|
31054
31720
|
lastGood: null,
|
|
31721
|
+
semanticDepGraphUpdater: new SemanticDepGraphUpdater(/* priorGraph */ null),
|
|
31055
31722
|
};
|
|
31056
|
-
return new IncrementalDriver(state, new
|
|
31723
|
+
return new IncrementalDriver(state, new FileDependencyGraph(), /* logicalChanges */ null);
|
|
31724
|
+
}
|
|
31725
|
+
getSemanticDepGraphUpdater() {
|
|
31726
|
+
if (this.state.kind !== BuildStateKind.Pending) {
|
|
31727
|
+
throw new Error('Semantic dependency updater is only available when pending analysis');
|
|
31728
|
+
}
|
|
31729
|
+
return this.state.semanticDepGraphUpdater;
|
|
31057
31730
|
}
|
|
31058
31731
|
recordSuccessfulAnalysis(traitCompiler) {
|
|
31059
31732
|
if (this.state.kind !== BuildStateKind.Pending) {
|
|
31060
31733
|
// Changes have already been incorporated.
|
|
31061
31734
|
return;
|
|
31062
31735
|
}
|
|
31736
|
+
const { needsEmit, needsTypeCheckEmit, newGraph } = this.state.semanticDepGraphUpdater.finalize();
|
|
31063
31737
|
const pendingEmit = this.state.pendingEmit;
|
|
31064
|
-
const
|
|
31065
|
-
|
|
31066
|
-
|
|
31067
|
-
|
|
31068
|
-
|
|
31069
|
-
|
|
31738
|
+
for (const path of needsEmit) {
|
|
31739
|
+
pendingEmit.add(path);
|
|
31740
|
+
}
|
|
31741
|
+
const pendingTypeCheckEmit = this.state.pendingTypeCheckEmit;
|
|
31742
|
+
for (const path of needsTypeCheckEmit) {
|
|
31743
|
+
pendingTypeCheckEmit.add(path);
|
|
31070
31744
|
}
|
|
31071
31745
|
// Update the state to an `AnalyzedBuildState`.
|
|
31072
31746
|
this.state = {
|
|
31073
31747
|
kind: BuildStateKind.Analyzed,
|
|
31074
31748
|
pendingEmit,
|
|
31749
|
+
pendingTypeCheckEmit,
|
|
31075
31750
|
// Since this compilation was successfully analyzed, update the "last good" artifacts to the
|
|
31076
31751
|
// ones from the current compilation.
|
|
31077
31752
|
lastGood: {
|
|
31078
31753
|
depGraph: this.depGraph,
|
|
31754
|
+
semanticDepGraph: newGraph,
|
|
31079
31755
|
traitCompiler: traitCompiler,
|
|
31080
31756
|
typeCheckingResults: null,
|
|
31081
31757
|
},
|
|
@@ -31087,6 +31763,11 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
31087
31763
|
return;
|
|
31088
31764
|
}
|
|
31089
31765
|
this.state.lastGood.typeCheckingResults = results;
|
|
31766
|
+
// Delete the files for which type-check code was generated from the set of pending type-check
|
|
31767
|
+
// files.
|
|
31768
|
+
for (const fileName of results.keys()) {
|
|
31769
|
+
this.state.pendingTypeCheckEmit.delete(fileName);
|
|
31770
|
+
}
|
|
31090
31771
|
}
|
|
31091
31772
|
recordSuccessfulEmit(sf) {
|
|
31092
31773
|
this.state.pendingEmit.delete(sf.fileName);
|
|
@@ -31113,7 +31794,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
31113
31794
|
this.state.priorTypeCheckingResults === null || this.logicalChanges === null) {
|
|
31114
31795
|
return null;
|
|
31115
31796
|
}
|
|
31116
|
-
if (this.logicalChanges.has(sf.fileName)) {
|
|
31797
|
+
if (this.logicalChanges.has(sf.fileName) || this.state.pendingTypeCheckEmit.has(sf.fileName)) {
|
|
31117
31798
|
return null;
|
|
31118
31799
|
}
|
|
31119
31800
|
const fileName = absoluteFromSourceFile(sf);
|
|
@@ -31651,7 +32332,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
31651
32332
|
return;
|
|
31652
32333
|
}
|
|
31653
32334
|
const ngModuleExpr = this.emitter.emit(ngModule, decl.getSourceFile(), ImportFlags.ForceNewImport);
|
|
31654
|
-
const ngModuleType = new ExpressionType(ngModuleExpr);
|
|
32335
|
+
const ngModuleType = new ExpressionType(ngModuleExpr.expression);
|
|
31655
32336
|
const mwpNgType = new ExpressionType(new ExternalExpr(Identifiers$1.ModuleWithProviders), [ /* modifiers */], [ngModuleType]);
|
|
31656
32337
|
dts.addTypeReplacement(decl, mwpNgType);
|
|
31657
32338
|
}
|
|
@@ -32487,19 +33168,6 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
32487
33168
|
return null;
|
|
32488
33169
|
}
|
|
32489
33170
|
}
|
|
32490
|
-
/**
|
|
32491
|
-
* Returns a collection of the compilation scope for each registered declaration.
|
|
32492
|
-
*/
|
|
32493
|
-
getCompilationScopes() {
|
|
32494
|
-
const scopes = [];
|
|
32495
|
-
this.declarationToModule.forEach((declData, declaration) => {
|
|
32496
|
-
const scope = this.getScopeOfModule(declData.ngModule);
|
|
32497
|
-
if (scope !== null) {
|
|
32498
|
-
scopes.push(Object.assign({ declaration, ngModule: declData.ngModule }, scope.compilation));
|
|
32499
|
-
}
|
|
32500
|
-
});
|
|
32501
|
-
return scopes;
|
|
32502
|
-
}
|
|
32503
33171
|
registerDeclarationOfModule(ngModule, decl, rawDeclarations) {
|
|
32504
33172
|
const declData = {
|
|
32505
33173
|
ngModule,
|
|
@@ -32795,7 +33463,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
32795
33463
|
});
|
|
32796
33464
|
}
|
|
32797
33465
|
else {
|
|
32798
|
-
const expr = this.refEmitter.emit(exportRef.cloneWithNoIdentifiers(), sourceFile);
|
|
33466
|
+
const expr = this.refEmitter.emit(exportRef.cloneWithNoIdentifiers(), sourceFile).expression;
|
|
32799
33467
|
if (!(expr instanceof ExternalExpr) || expr.value.moduleName === null ||
|
|
32800
33468
|
expr.value.name === null) {
|
|
32801
33469
|
throw new Error('Expected ExternalExpr');
|
|
@@ -34550,7 +35218,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
34550
35218
|
// pass.
|
|
34551
35219
|
const ngExpr = this.refEmitter.emit(ref, this.contextFile, ImportFlags.NoAliasing);
|
|
34552
35220
|
// Use `translateExpression` to convert the `Expression` into a `ts.Expression`.
|
|
34553
|
-
return translateExpression(ngExpr, this.importManager);
|
|
35221
|
+
return translateExpression(ngExpr.expression, this.importManager);
|
|
34554
35222
|
}
|
|
34555
35223
|
/**
|
|
34556
35224
|
* Generate a `ts.TypeNode` that references the given node as a type.
|
|
@@ -34561,7 +35229,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
34561
35229
|
const ngExpr = this.refEmitter.emit(ref, this.contextFile, ImportFlags.NoAliasing | ImportFlags.AllowTypeImports);
|
|
34562
35230
|
// Create an `ExpressionType` from the `Expression` and translate it via `translateType`.
|
|
34563
35231
|
// TODO(alxhub): support references to types with generic arguments in a clean way.
|
|
34564
|
-
return translateType(new ExpressionType(ngExpr), this.importManager);
|
|
35232
|
+
return translateType(new ExpressionType(ngExpr.expression), this.importManager);
|
|
34565
35233
|
}
|
|
34566
35234
|
emitTypeParameters(declaration) {
|
|
34567
35235
|
const emitter = new TypeParameterEmitter(declaration.typeParameters, this.reflector);
|
|
@@ -38604,7 +39272,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
38604
39272
|
this.moduleResolver =
|
|
38605
39273
|
new ModuleResolver(tsProgram, this.options, this.adapter, moduleResolutionCache);
|
|
38606
39274
|
this.resourceManager = new AdapterResourceLoader(adapter, this.options);
|
|
38607
|
-
this.cycleAnalyzer = new CycleAnalyzer(new ImportGraph(
|
|
39275
|
+
this.cycleAnalyzer = new CycleAnalyzer(new ImportGraph(tsProgram.getTypeChecker()));
|
|
38608
39276
|
this.incrementalStrategy.setIncrementalDriver(this.incrementalDriver, tsProgram);
|
|
38609
39277
|
this.ignoreForDiagnostics =
|
|
38610
39278
|
new Set(tsProgram.getSourceFiles().filter(sf => this.adapter.isShim(sf)));
|
|
@@ -38887,7 +39555,6 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
38887
39555
|
}
|
|
38888
39556
|
resolveCompilation(traitCompiler) {
|
|
38889
39557
|
traitCompiler.resolve();
|
|
38890
|
-
this.recordNgModuleScopeDependencies();
|
|
38891
39558
|
// At this point, analysis is complete and the compiler can now calculate which files need to
|
|
38892
39559
|
// be emitted, so do that.
|
|
38893
39560
|
this.incrementalDriver.recordSuccessfulAnalysis(traitCompiler);
|
|
@@ -39042,67 +39709,6 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
39042
39709
|
}
|
|
39043
39710
|
return this.nonTemplateDiagnostics;
|
|
39044
39711
|
}
|
|
39045
|
-
/**
|
|
39046
|
-
* Reifies the inter-dependencies of NgModules and the components within their compilation scopes
|
|
39047
|
-
* into the `IncrementalDriver`'s dependency graph.
|
|
39048
|
-
*/
|
|
39049
|
-
recordNgModuleScopeDependencies() {
|
|
39050
|
-
const recordSpan = this.perfRecorder.start('recordDependencies');
|
|
39051
|
-
const depGraph = this.incrementalDriver.depGraph;
|
|
39052
|
-
for (const scope of this.compilation.scopeRegistry.getCompilationScopes()) {
|
|
39053
|
-
const file = scope.declaration.getSourceFile();
|
|
39054
|
-
const ngModuleFile = scope.ngModule.getSourceFile();
|
|
39055
|
-
// A change to any dependency of the declaration causes the declaration to be invalidated,
|
|
39056
|
-
// which requires the NgModule to be invalidated as well.
|
|
39057
|
-
depGraph.addTransitiveDependency(ngModuleFile, file);
|
|
39058
|
-
// A change to the NgModule file should cause the declaration itself to be invalidated.
|
|
39059
|
-
depGraph.addDependency(file, ngModuleFile);
|
|
39060
|
-
const meta = this.compilation.metaReader.getDirectiveMetadata(new Reference$1(scope.declaration));
|
|
39061
|
-
if (meta !== null && meta.isComponent) {
|
|
39062
|
-
// If a component's template changes, it might have affected the import graph, and thus the
|
|
39063
|
-
// remote scoping feature which is activated in the event of potential import cycles. Thus,
|
|
39064
|
-
// the module depends not only on the transitive dependencies of the component, but on its
|
|
39065
|
-
// resources as well.
|
|
39066
|
-
depGraph.addTransitiveResources(ngModuleFile, file);
|
|
39067
|
-
// A change to any directive/pipe in the compilation scope should cause the component to be
|
|
39068
|
-
// invalidated.
|
|
39069
|
-
for (const directive of scope.directives) {
|
|
39070
|
-
// When a directive in scope is updated, the component needs to be recompiled as e.g. a
|
|
39071
|
-
// selector may have changed.
|
|
39072
|
-
depGraph.addTransitiveDependency(file, directive.ref.node.getSourceFile());
|
|
39073
|
-
}
|
|
39074
|
-
for (const pipe of scope.pipes) {
|
|
39075
|
-
// When a pipe in scope is updated, the component needs to be recompiled as e.g. the
|
|
39076
|
-
// pipe's name may have changed.
|
|
39077
|
-
depGraph.addTransitiveDependency(file, pipe.ref.node.getSourceFile());
|
|
39078
|
-
}
|
|
39079
|
-
// Components depend on the entire export scope. In addition to transitive dependencies on
|
|
39080
|
-
// all directives/pipes in the export scope, they also depend on every NgModule in the
|
|
39081
|
-
// scope, as changes to a module may add new directives/pipes to the scope.
|
|
39082
|
-
for (const depModule of scope.ngModules) {
|
|
39083
|
-
// There is a correctness issue here. To be correct, this should be a transitive
|
|
39084
|
-
// dependency on the depModule file, since the depModule's exports might change via one of
|
|
39085
|
-
// its dependencies, even if depModule's file itself doesn't change. However, doing this
|
|
39086
|
-
// would also trigger recompilation if a non-exported component or directive changed,
|
|
39087
|
-
// which causes performance issues for rebuilds.
|
|
39088
|
-
//
|
|
39089
|
-
// Given the rebuild issue is an edge case, currently we err on the side of performance
|
|
39090
|
-
// instead of correctness. A correct and performant design would distinguish between
|
|
39091
|
-
// changes to the depModule which affect its export scope and changes which do not, and
|
|
39092
|
-
// only add a dependency for the former. This concept is currently in development.
|
|
39093
|
-
//
|
|
39094
|
-
// TODO(alxhub): fix correctness issue by understanding the semantics of the dependency.
|
|
39095
|
-
depGraph.addDependency(file, depModule.getSourceFile());
|
|
39096
|
-
}
|
|
39097
|
-
}
|
|
39098
|
-
else {
|
|
39099
|
-
// Directives (not components) and pipes only depend on the NgModule which directly declares
|
|
39100
|
-
// them.
|
|
39101
|
-
depGraph.addDependency(file, ngModuleFile);
|
|
39102
|
-
}
|
|
39103
|
-
}
|
|
39104
|
-
this.perfRecorder.stop(recordSpan);
|
|
39105
|
-
}
|
|
39106
39712
|
scanForMwp(sf) {
|
|
39107
39713
|
this.compilation.mwpScanner.scan(sf, {
|
|
39108
39714
|
addTypeReplacement: (node, type) => {
|
|
@@ -39175,6 +39781,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
39175
39781
|
const depScopeReader = new MetadataDtsModuleScopeResolver(dtsReader, aliasingHost);
|
|
39176
39782
|
const scopeRegistry = new LocalModuleScopeRegistry(localMetaReader, depScopeReader, refEmitter, aliasingHost);
|
|
39177
39783
|
const scopeReader = scopeRegistry;
|
|
39784
|
+
const semanticDepGraphUpdater = this.incrementalDriver.getSemanticDepGraphUpdater();
|
|
39178
39785
|
const metaRegistry = new CompoundMetadataRegistry([localMetaRegistry, scopeRegistry]);
|
|
39179
39786
|
const injectableRegistry = new InjectableClassRegistry(reflector);
|
|
39180
39787
|
const metaReader = new CompoundMetadataReader([localMetaReader, dtsReader]);
|
|
@@ -39206,11 +39813,11 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
39206
39813
|
1 /* Error */;
|
|
39207
39814
|
// Set up the IvyCompilation, which manages state for the Ivy transformer.
|
|
39208
39815
|
const handlers = [
|
|
39209
|
-
new ComponentDecoratorHandler(reflector, evaluator, metaRegistry, metaReader, scopeReader, scopeRegistry, typeCheckScopeRegistry, resourceRegistry, isCore, this.resourceManager, this.adapter.rootDirs, this.options.preserveWhitespaces || false, this.options.i18nUseExternalIds !== false, this.options.enableI18nLegacyMessageIdFormat !== false, this.usePoisonedData, this.options.i18nNormalizeLineEndingsInICUs, this.moduleResolver, this.cycleAnalyzer, cycleHandlingStrategy, refEmitter, defaultImportTracker, this.incrementalDriver.depGraph, injectableRegistry, this.closureCompilerEnabled),
|
|
39816
|
+
new ComponentDecoratorHandler(reflector, evaluator, metaRegistry, metaReader, scopeReader, scopeRegistry, typeCheckScopeRegistry, resourceRegistry, isCore, this.resourceManager, this.adapter.rootDirs, this.options.preserveWhitespaces || false, this.options.i18nUseExternalIds !== false, this.options.enableI18nLegacyMessageIdFormat !== false, this.usePoisonedData, this.options.i18nNormalizeLineEndingsInICUs, this.moduleResolver, this.cycleAnalyzer, cycleHandlingStrategy, refEmitter, defaultImportTracker, this.incrementalDriver.depGraph, injectableRegistry, semanticDepGraphUpdater, this.closureCompilerEnabled),
|
|
39210
39817
|
// TODO(alxhub): understand why the cast here is necessary (something to do with `null`
|
|
39211
39818
|
// not being assignable to `unknown` when wrapped in `Readonly`).
|
|
39212
39819
|
// clang-format off
|
|
39213
|
-
new DirectiveDecoratorHandler(reflector, evaluator, metaRegistry, scopeRegistry, metaReader, defaultImportTracker, injectableRegistry, isCore, this.closureCompilerEnabled, compileUndecoratedClassesWithAngularFeatures),
|
|
39820
|
+
new DirectiveDecoratorHandler(reflector, evaluator, metaRegistry, scopeRegistry, metaReader, defaultImportTracker, injectableRegistry, isCore, semanticDepGraphUpdater, this.closureCompilerEnabled, compileUndecoratedClassesWithAngularFeatures),
|
|
39214
39821
|
// clang-format on
|
|
39215
39822
|
// Pipe handler must be before injectable handler in list so pipe factories are printed
|
|
39216
39823
|
// before injectable factories (so injectable factories can delegate to them)
|
|
@@ -39218,7 +39825,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
39218
39825
|
new InjectableDecoratorHandler(reflector, defaultImportTracker, isCore, this.options.strictInjectionParameters || false, injectableRegistry),
|
|
39219
39826
|
new NgModuleDecoratorHandler(reflector, evaluator, metaReader, metaRegistry, scopeRegistry, referencesRegistry, isCore, routeAnalyzer, refEmitter, this.adapter.factoryTracker, defaultImportTracker, this.closureCompilerEnabled, injectableRegistry, this.options.i18nInLocale),
|
|
39220
39827
|
];
|
|
39221
|
-
const traitCompiler = new TraitCompiler(handlers, reflector, this.perfRecorder, this.incrementalDriver, this.options.compileNonExportedClasses !== false, compilationMode, dtsTransforms);
|
|
39828
|
+
const traitCompiler = new TraitCompiler(handlers, reflector, this.perfRecorder, this.incrementalDriver, this.options.compileNonExportedClasses !== false, compilationMode, dtsTransforms, semanticDepGraphUpdater);
|
|
39222
39829
|
const templateTypeChecker = new TemplateTypeCheckerImpl(this.tsProgram, this.typeCheckingProgramStrategy, traitCompiler, this.getTypeCheckingConfig(), refEmitter, reflector, this.adapter, this.incrementalDriver, scopeRegistry, typeCheckScopeRegistry);
|
|
39223
39830
|
return {
|
|
39224
39831
|
isCore,
|
|
@@ -40215,7 +40822,7 @@ https://v9.angular.io/guide/template-typecheck#template-type-checking`,
|
|
|
40215
40822
|
* input shares the same name as a DOM attribute, the `Map` will reflect the directive input
|
|
40216
40823
|
* completion, not the DOM completion for that name.
|
|
40217
40824
|
*/
|
|
40218
|
-
function buildAttributeCompletionTable(component, element, checker) {
|
|
40825
|
+
function buildAttributeCompletionTable(component, element, checker, includeDomSchemaAttributes) {
|
|
40219
40826
|
const table = new Map();
|
|
40220
40827
|
// Use the `ElementSymbol` or `TemplateSymbol` to iterate over directives present on the node, and
|
|
40221
40828
|
// their inputs/outputs. These have the highest priority of completion results.
|
|
@@ -40351,7 +40958,7 @@ https://v9.angular.io/guide/template-typecheck#template-type-checking`,
|
|
|
40351
40958
|
}
|
|
40352
40959
|
}
|
|
40353
40960
|
// Finally, add any DOM attributes not already covered by inputs.
|
|
40354
|
-
if (element instanceof Element) {
|
|
40961
|
+
if (element instanceof Element && includeDomSchemaAttributes) {
|
|
40355
40962
|
for (const { attribute, property } of checker.getPotentialDomBindings(element.name)) {
|
|
40356
40963
|
const isAlsoProperty = attribute === property;
|
|
40357
40964
|
if (!table.has(attribute)) {
|
|
@@ -40900,12 +41507,13 @@ https://v9.angular.io/guide/template-typecheck#template-type-checking`,
|
|
|
40900
41507
|
* @param N type of the template node in question, narrowed accordingly.
|
|
40901
41508
|
*/
|
|
40902
41509
|
class CompletionBuilder {
|
|
40903
|
-
constructor(tsLS, compiler, component, node, targetDetails) {
|
|
41510
|
+
constructor(tsLS, compiler, component, node, targetDetails, inlineTemplate) {
|
|
40904
41511
|
this.tsLS = tsLS;
|
|
40905
41512
|
this.compiler = compiler;
|
|
40906
41513
|
this.component = component;
|
|
40907
41514
|
this.node = node;
|
|
40908
41515
|
this.targetDetails = targetDetails;
|
|
41516
|
+
this.inlineTemplate = inlineTemplate;
|
|
40909
41517
|
this.typeChecker = this.compiler.getNextProgram().getTypeChecker();
|
|
40910
41518
|
this.templateTypeChecker = this.compiler.getTemplateTypeChecker();
|
|
40911
41519
|
this.nodeParent = this.targetDetails.parent;
|
|
@@ -41172,8 +41780,13 @@ https://v9.angular.io/guide/template-typecheck#template-type-checking`,
|
|
|
41172
41780
|
length = 0;
|
|
41173
41781
|
}
|
|
41174
41782
|
const replacementSpan = { start, length };
|
|
41175
|
-
|
|
41176
|
-
|
|
41783
|
+
let potentialTags = Array.from(templateTypeChecker.getPotentialElementTags(this.component));
|
|
41784
|
+
if (!this.inlineTemplate) {
|
|
41785
|
+
// If we are in an external template, don't provide non-Angular tags (directive === null)
|
|
41786
|
+
// because we expect other extensions (i.e. Emmet) to provide those for HTML files.
|
|
41787
|
+
potentialTags = potentialTags.filter(([_, directive]) => directive !== null);
|
|
41788
|
+
}
|
|
41789
|
+
const entries = potentialTags.map(([tag, directive]) => ({
|
|
41177
41790
|
kind: tagCompletionKind(directive),
|
|
41178
41791
|
name: tag,
|
|
41179
41792
|
sortText: tag,
|
|
@@ -41244,7 +41857,7 @@ https://v9.angular.io/guide/template-typecheck#template-type-checking`,
|
|
|
41244
41857
|
this.node.keySpan !== undefined) {
|
|
41245
41858
|
replacementSpan = makeReplacementSpanFromParseSourceSpan(this.node.keySpan);
|
|
41246
41859
|
}
|
|
41247
|
-
const attrTable = buildAttributeCompletionTable(this.component, element, this.compiler.getTemplateTypeChecker());
|
|
41860
|
+
const attrTable = buildAttributeCompletionTable(this.component, element, this.compiler.getTemplateTypeChecker(), this.inlineTemplate);
|
|
41248
41861
|
let entries = [];
|
|
41249
41862
|
for (const completion of attrTable.values()) {
|
|
41250
41863
|
// First, filter out completions that don't make sense for the current node. For example, if
|
|
@@ -41306,7 +41919,7 @@ https://v9.angular.io/guide/template-typecheck#template-type-checking`,
|
|
|
41306
41919
|
// Nothing to do without an element to process.
|
|
41307
41920
|
return undefined;
|
|
41308
41921
|
}
|
|
41309
|
-
const attrTable = buildAttributeCompletionTable(this.component, element, this.compiler.getTemplateTypeChecker());
|
|
41922
|
+
const attrTable = buildAttributeCompletionTable(this.component, element, this.compiler.getTemplateTypeChecker(), this.inlineTemplate);
|
|
41310
41923
|
if (!attrTable.has(name)) {
|
|
41311
41924
|
return undefined;
|
|
41312
41925
|
}
|
|
@@ -41363,7 +41976,7 @@ https://v9.angular.io/guide/template-typecheck#template-type-checking`,
|
|
|
41363
41976
|
// Nothing to do without an element to process.
|
|
41364
41977
|
return undefined;
|
|
41365
41978
|
}
|
|
41366
|
-
const attrTable = buildAttributeCompletionTable(this.component, element, this.compiler.getTemplateTypeChecker());
|
|
41979
|
+
const attrTable = buildAttributeCompletionTable(this.component, element, this.compiler.getTemplateTypeChecker(), this.inlineTemplate);
|
|
41367
41980
|
if (!attrTable.has(name)) {
|
|
41368
41981
|
return undefined;
|
|
41369
41982
|
}
|
|
@@ -42423,7 +43036,7 @@ https://v9.angular.io/guide/template-typecheck#template-type-checking`,
|
|
|
42423
43036
|
const node = positionDetails.context.kind === TargetNodeKind.TwoWayBindingContext ?
|
|
42424
43037
|
positionDetails.context.nodes[0] :
|
|
42425
43038
|
positionDetails.context.node;
|
|
42426
|
-
return new CompletionBuilder(this.tsLS, compiler, templateInfo.component, node, positionDetails);
|
|
43039
|
+
return new CompletionBuilder(this.tsLS, compiler, templateInfo.component, node, positionDetails, isTypeScriptFile(fileName));
|
|
42427
43040
|
}
|
|
42428
43041
|
getCompletionsAtPosition(fileName, position, options) {
|
|
42429
43042
|
return this.withCompiler((compiler) => {
|