@angular/language-service 11.2.7 → 11.2.11
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 +1581 -856
- package/bundles/language-service.js +127 -63
- package/ivy/adapters.d.ts +1 -0
- package/ivy/adapters.js +32 -4
- package/ivy/compiler_factory.js +9 -3
- package/ivy/completions.d.ts +5 -0
- package/ivy/completions.js +60 -18
- package/ivy/language_service.d.ts +20 -1
- package/ivy/language_service.js +158 -124
- package/ivy/references.js +98 -82
- package/ivy/utils.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.11
|
|
3
3
|
* Copyright Google LLC All Rights Reserved.
|
|
4
4
|
* License: MIT
|
|
5
5
|
*/
|
|
@@ -6697,6 +6697,21 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
6697
6697
|
* Use of this source code is governed by an MIT-style license that can be
|
|
6698
6698
|
* found in the LICENSE file at https://angular.io/license
|
|
6699
6699
|
*/
|
|
6700
|
+
/**
|
|
6701
|
+
* This is an R3 `Node`-like wrapper for a raw `html.Comment` node. We do not currently
|
|
6702
|
+
* require the implementation of a visitor for Comments as they are only collected at
|
|
6703
|
+
* the top-level of the R3 AST, and only if `Render3ParseOptions['collectCommentNodes']`
|
|
6704
|
+
* is true.
|
|
6705
|
+
*/
|
|
6706
|
+
class Comment {
|
|
6707
|
+
constructor(value, sourceSpan) {
|
|
6708
|
+
this.value = value;
|
|
6709
|
+
this.sourceSpan = sourceSpan;
|
|
6710
|
+
}
|
|
6711
|
+
visit(_visitor) {
|
|
6712
|
+
throw new Error('visit() not implemented for Comment');
|
|
6713
|
+
}
|
|
6714
|
+
}
|
|
6700
6715
|
class Text {
|
|
6701
6716
|
constructor(value, sourceSpan) {
|
|
6702
6717
|
this.value = value;
|
|
@@ -11518,7 +11533,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
11518
11533
|
return visitor.visitElement(this, context);
|
|
11519
11534
|
}
|
|
11520
11535
|
}
|
|
11521
|
-
class Comment {
|
|
11536
|
+
class Comment$1 {
|
|
11522
11537
|
constructor(value, sourceSpan) {
|
|
11523
11538
|
this.value = value;
|
|
11524
11539
|
this.sourceSpan = sourceSpan;
|
|
@@ -12548,7 +12563,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
12548
12563
|
const text = this._advanceIf(TokenType.RAW_TEXT);
|
|
12549
12564
|
this._advanceIf(TokenType.COMMENT_END);
|
|
12550
12565
|
const value = text != null ? text.parts[0].trim() : null;
|
|
12551
|
-
this._addToParent(new Comment(value, token.sourceSpan));
|
|
12566
|
+
this._addToParent(new Comment$1(value, token.sourceSpan));
|
|
12552
12567
|
}
|
|
12553
12568
|
_consumeExpansion(token) {
|
|
12554
12569
|
const switchValue = this._advance();
|
|
@@ -13756,7 +13771,11 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
13756
13771
|
if (isEmptyExpression(value)) {
|
|
13757
13772
|
return null;
|
|
13758
13773
|
}
|
|
13759
|
-
|
|
13774
|
+
// CSS custom properties are case-sensitive so we shouldn't normalize them.
|
|
13775
|
+
// See: https://www.w3.org/TR/css-variables-1/#defining-variables
|
|
13776
|
+
if (!isCssCustomProperty(name)) {
|
|
13777
|
+
name = hyphenate(name);
|
|
13778
|
+
}
|
|
13760
13779
|
const { property, hasOverrideFlag, suffix: bindingSuffix } = parseProperty(name);
|
|
13761
13780
|
suffix = typeof suffix === 'string' && suffix.length !== 0 ? suffix : bindingSuffix;
|
|
13762
13781
|
const entry = { name: property, suffix: suffix, value, sourceSpan, hasOverrideFlag };
|
|
@@ -14101,8 +14120,12 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
14101
14120
|
return Identifiers$1.stylePropInterpolateV;
|
|
14102
14121
|
}
|
|
14103
14122
|
}
|
|
14104
|
-
|
|
14105
|
-
|
|
14123
|
+
/**
|
|
14124
|
+
* Checks whether property name is a custom CSS property.
|
|
14125
|
+
* See: https://www.w3.org/TR/css-variables-1
|
|
14126
|
+
*/
|
|
14127
|
+
function isCssCustomProperty(name) {
|
|
14128
|
+
return name.startsWith('--');
|
|
14106
14129
|
}
|
|
14107
14130
|
|
|
14108
14131
|
/**
|
|
@@ -16220,26 +16243,33 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
16220
16243
|
EVENT: { start: '(', end: ')' },
|
|
16221
16244
|
};
|
|
16222
16245
|
const TEMPLATE_ATTR_PREFIX$1 = '*';
|
|
16223
|
-
function htmlAstToRender3Ast(htmlNodes, bindingParser) {
|
|
16224
|
-
const transformer = new HtmlAstToIvyAst(bindingParser);
|
|
16246
|
+
function htmlAstToRender3Ast(htmlNodes, bindingParser, options) {
|
|
16247
|
+
const transformer = new HtmlAstToIvyAst(bindingParser, options);
|
|
16225
16248
|
const ivyNodes = visitAll$1(transformer, htmlNodes);
|
|
16226
16249
|
// Errors might originate in either the binding parser or the html to ivy transformer
|
|
16227
16250
|
const allErrors = bindingParser.errors.concat(transformer.errors);
|
|
16228
|
-
|
|
16251
|
+
const result = {
|
|
16229
16252
|
nodes: ivyNodes,
|
|
16230
16253
|
errors: allErrors,
|
|
16231
16254
|
styleUrls: transformer.styleUrls,
|
|
16232
16255
|
styles: transformer.styles,
|
|
16233
|
-
ngContentSelectors: transformer.ngContentSelectors
|
|
16256
|
+
ngContentSelectors: transformer.ngContentSelectors
|
|
16234
16257
|
};
|
|
16258
|
+
if (options.collectCommentNodes) {
|
|
16259
|
+
result.commentNodes = transformer.commentNodes;
|
|
16260
|
+
}
|
|
16261
|
+
return result;
|
|
16235
16262
|
}
|
|
16236
16263
|
class HtmlAstToIvyAst {
|
|
16237
|
-
constructor(bindingParser) {
|
|
16264
|
+
constructor(bindingParser, options) {
|
|
16238
16265
|
this.bindingParser = bindingParser;
|
|
16266
|
+
this.options = options;
|
|
16239
16267
|
this.errors = [];
|
|
16240
16268
|
this.styles = [];
|
|
16241
16269
|
this.styleUrls = [];
|
|
16242
16270
|
this.ngContentSelectors = [];
|
|
16271
|
+
// This array will be populated if `Render3ParseOptions['collectCommentNodes']` is true
|
|
16272
|
+
this.commentNodes = [];
|
|
16243
16273
|
this.inI18nBlock = false;
|
|
16244
16274
|
}
|
|
16245
16275
|
// HTML visitor
|
|
@@ -16408,6 +16438,9 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
16408
16438
|
return null;
|
|
16409
16439
|
}
|
|
16410
16440
|
visitComment(comment) {
|
|
16441
|
+
if (this.options.collectCommentNodes) {
|
|
16442
|
+
this.commentNodes.push(new Comment(comment.value || '', comment.sourceSpan));
|
|
16443
|
+
}
|
|
16411
16444
|
return null;
|
|
16412
16445
|
}
|
|
16413
16446
|
// convert view engine `ParsedProperty` to a format suitable for IVY
|
|
@@ -16599,7 +16632,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
16599
16632
|
return node instanceof Text$2 && node.value.trim().length == 0;
|
|
16600
16633
|
}
|
|
16601
16634
|
function isCommentNode(node) {
|
|
16602
|
-
return node instanceof Comment;
|
|
16635
|
+
return node instanceof Comment$1;
|
|
16603
16636
|
}
|
|
16604
16637
|
function textContents(node) {
|
|
16605
16638
|
if (node.children.length !== 1 || !(node.children[0] instanceof Text$2)) {
|
|
@@ -19176,7 +19209,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
19176
19209
|
const parseResult = htmlParser.parse(template, templateUrl, Object.assign(Object.assign({ leadingTriviaChars: LEADING_TRIVIA_CHARS }, options), { tokenizeExpansionForms: true }));
|
|
19177
19210
|
if (!options.alwaysAttemptHtmlToR3AstConversion && parseResult.errors &&
|
|
19178
19211
|
parseResult.errors.length > 0) {
|
|
19179
|
-
|
|
19212
|
+
const parsedTemplate = {
|
|
19180
19213
|
interpolationConfig,
|
|
19181
19214
|
preserveWhitespaces,
|
|
19182
19215
|
template,
|
|
@@ -19188,6 +19221,10 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
19188
19221
|
styles: [],
|
|
19189
19222
|
ngContentSelectors: []
|
|
19190
19223
|
};
|
|
19224
|
+
if (options.collectCommentNodes) {
|
|
19225
|
+
parsedTemplate.commentNodes = [];
|
|
19226
|
+
}
|
|
19227
|
+
return parsedTemplate;
|
|
19191
19228
|
}
|
|
19192
19229
|
let rootNodes = parseResult.rootNodes;
|
|
19193
19230
|
// process i18n meta information (scan attributes, generate ids)
|
|
@@ -19198,7 +19235,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
19198
19235
|
const i18nMetaResult = i18nMetaVisitor.visitAllWithErrors(rootNodes);
|
|
19199
19236
|
if (!options.alwaysAttemptHtmlToR3AstConversion && i18nMetaResult.errors &&
|
|
19200
19237
|
i18nMetaResult.errors.length > 0) {
|
|
19201
|
-
|
|
19238
|
+
const parsedTemplate = {
|
|
19202
19239
|
interpolationConfig,
|
|
19203
19240
|
preserveWhitespaces,
|
|
19204
19241
|
template,
|
|
@@ -19210,6 +19247,10 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
19210
19247
|
styles: [],
|
|
19211
19248
|
ngContentSelectors: []
|
|
19212
19249
|
};
|
|
19250
|
+
if (options.collectCommentNodes) {
|
|
19251
|
+
parsedTemplate.commentNodes = [];
|
|
19252
|
+
}
|
|
19253
|
+
return parsedTemplate;
|
|
19213
19254
|
}
|
|
19214
19255
|
rootNodes = i18nMetaResult.rootNodes;
|
|
19215
19256
|
if (!preserveWhitespaces) {
|
|
@@ -19222,9 +19263,9 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
19222
19263
|
rootNodes = visitAll$1(new I18nMetaVisitor(interpolationConfig, /* keepI18nAttrs */ false), rootNodes);
|
|
19223
19264
|
}
|
|
19224
19265
|
}
|
|
19225
|
-
const { nodes, errors, styleUrls, styles, ngContentSelectors } = htmlAstToRender3Ast(rootNodes, bindingParser);
|
|
19266
|
+
const { nodes, errors, styleUrls, styles, ngContentSelectors, commentNodes } = htmlAstToRender3Ast(rootNodes, bindingParser, { collectCommentNodes: !!options.collectCommentNodes });
|
|
19226
19267
|
errors.push(...parseResult.errors, ...i18nMetaResult.errors);
|
|
19227
|
-
|
|
19268
|
+
const parsedTemplate = {
|
|
19228
19269
|
interpolationConfig,
|
|
19229
19270
|
preserveWhitespaces,
|
|
19230
19271
|
errors: errors.length > 0 ? errors : null,
|
|
@@ -19236,6 +19277,10 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
19236
19277
|
styles,
|
|
19237
19278
|
ngContentSelectors
|
|
19238
19279
|
};
|
|
19280
|
+
if (options.collectCommentNodes) {
|
|
19281
|
+
parsedTemplate.commentNodes = commentNodes;
|
|
19282
|
+
}
|
|
19283
|
+
return parsedTemplate;
|
|
19239
19284
|
}
|
|
19240
19285
|
const elementRegistry = new DomElementSchemaRegistry();
|
|
19241
19286
|
/**
|
|
@@ -20354,7 +20399,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
20354
20399
|
* Use of this source code is governed by an MIT-style license that can be
|
|
20355
20400
|
* found in the LICENSE file at https://angular.io/license
|
|
20356
20401
|
*/
|
|
20357
|
-
const VERSION$1 = new Version('11.2.
|
|
20402
|
+
const VERSION$1 = new Version('11.2.11');
|
|
20358
20403
|
|
|
20359
20404
|
/**
|
|
20360
20405
|
* @license
|
|
@@ -21011,7 +21056,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
21011
21056
|
*/
|
|
21012
21057
|
function createDirectiveDefinitionMap(meta) {
|
|
21013
21058
|
const definitionMap = new DefinitionMap();
|
|
21014
|
-
definitionMap.set('version', literal('11.2.
|
|
21059
|
+
definitionMap.set('version', literal('11.2.11'));
|
|
21015
21060
|
// e.g. `type: MyDirective`
|
|
21016
21061
|
definitionMap.set('type', meta.internalType);
|
|
21017
21062
|
// e.g. `selector: 'some-dir'`
|
|
@@ -21232,7 +21277,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
21232
21277
|
*/
|
|
21233
21278
|
function createPipeDefinitionMap(meta) {
|
|
21234
21279
|
const definitionMap = new DefinitionMap();
|
|
21235
|
-
definitionMap.set('version', literal('11.2.
|
|
21280
|
+
definitionMap.set('version', literal('11.2.11'));
|
|
21236
21281
|
definitionMap.set('ngImport', importExpr(Identifiers$1.core));
|
|
21237
21282
|
// e.g. `type: MyPipe`
|
|
21238
21283
|
definitionMap.set('type', meta.internalType);
|
|
@@ -21264,7 +21309,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
21264
21309
|
* Use of this source code is governed by an MIT-style license that can be
|
|
21265
21310
|
* found in the LICENSE file at https://angular.io/license
|
|
21266
21311
|
*/
|
|
21267
|
-
const VERSION$2 = new Version('11.2.
|
|
21312
|
+
const VERSION$2 = new Version('11.2.11');
|
|
21268
21313
|
|
|
21269
21314
|
/**
|
|
21270
21315
|
* @license
|
|
@@ -21414,6 +21459,11 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
21414
21459
|
* Raised when a directive/pipe is part of the declarations of two or more NgModules.
|
|
21415
21460
|
*/
|
|
21416
21461
|
ErrorCode[ErrorCode["NGMODULE_DECLARATION_NOT_UNIQUE"] = 6007] = "NGMODULE_DECLARATION_NOT_UNIQUE";
|
|
21462
|
+
/**
|
|
21463
|
+
* Not actually raised by the compiler, but reserved for documentation of a View Engine error when
|
|
21464
|
+
* a View Engine build depends on an Ivy-compiled NgModule.
|
|
21465
|
+
*/
|
|
21466
|
+
ErrorCode[ErrorCode["NGMODULE_VE_DEPENDENCY_ON_IVY_LIB"] = 6999] = "NGMODULE_VE_DEPENDENCY_ON_IVY_LIB";
|
|
21417
21467
|
/**
|
|
21418
21468
|
* An element name failed validation against the DOM schema.
|
|
21419
21469
|
*/
|
|
@@ -21659,6 +21709,16 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
21659
21709
|
function isAssignment(node) {
|
|
21660
21710
|
return ts$1.isBinaryExpression(node) && node.operatorToken.kind === ts$1.SyntaxKind.EqualsToken;
|
|
21661
21711
|
}
|
|
21712
|
+
/**
|
|
21713
|
+
* Obtains the non-redirected source file for `sf`.
|
|
21714
|
+
*/
|
|
21715
|
+
function toUnredirectedSourceFile(sf) {
|
|
21716
|
+
const redirectInfo = sf.redirectInfo;
|
|
21717
|
+
if (redirectInfo === undefined) {
|
|
21718
|
+
return sf;
|
|
21719
|
+
}
|
|
21720
|
+
return redirectInfo.unredirected;
|
|
21721
|
+
}
|
|
21662
21722
|
|
|
21663
21723
|
/**
|
|
21664
21724
|
* @license
|
|
@@ -22167,6 +22227,22 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
22167
22227
|
* Use of this source code is governed by an MIT-style license that can be
|
|
22168
22228
|
* found in the LICENSE file at https://angular.io/license
|
|
22169
22229
|
*/
|
|
22230
|
+
const DefaultImportDeclaration = Symbol('DefaultImportDeclaration');
|
|
22231
|
+
/**
|
|
22232
|
+
* Attaches a default import declaration to `expr` to indicate the dependency of `expr` on the
|
|
22233
|
+
* default import.
|
|
22234
|
+
*/
|
|
22235
|
+
function attachDefaultImportDeclaration(expr, importDecl) {
|
|
22236
|
+
expr[DefaultImportDeclaration] = importDecl;
|
|
22237
|
+
}
|
|
22238
|
+
/**
|
|
22239
|
+
* Obtains the default import declaration that `expr` depends on, or `null` if there is no such
|
|
22240
|
+
* dependency.
|
|
22241
|
+
*/
|
|
22242
|
+
function getDefaultImportDeclaration(expr) {
|
|
22243
|
+
var _a;
|
|
22244
|
+
return (_a = expr[DefaultImportDeclaration]) !== null && _a !== void 0 ? _a : null;
|
|
22245
|
+
}
|
|
22170
22246
|
/**
|
|
22171
22247
|
* TypeScript has trouble with generating default imports inside of transformers for some module
|
|
22172
22248
|
* formats. The issue is that for the statement:
|
|
@@ -22199,47 +22275,25 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
22199
22275
|
*/
|
|
22200
22276
|
class DefaultImportTracker {
|
|
22201
22277
|
constructor() {
|
|
22202
|
-
/**
|
|
22203
|
-
* A `Map` which tracks the `Map` of default import `ts.Identifier`s to their
|
|
22204
|
-
* `ts.ImportDeclaration`s. These declarations are not guaranteed to be used.
|
|
22205
|
-
*/
|
|
22206
|
-
this.sourceFileToImportMap = new Map();
|
|
22207
22278
|
/**
|
|
22208
22279
|
* A `Map` which tracks the `Set` of `ts.ImportDeclaration`s for default imports that were used in
|
|
22209
22280
|
* a given `ts.SourceFile` and need to be preserved.
|
|
22210
22281
|
*/
|
|
22211
22282
|
this.sourceFileToUsedImports = new Map();
|
|
22212
22283
|
}
|
|
22213
|
-
|
|
22214
|
-
const sf = getSourceFile(
|
|
22215
|
-
if (!this.sourceFileToImportMap.has(sf)) {
|
|
22216
|
-
this.sourceFileToImportMap.set(sf, new Map());
|
|
22217
|
-
}
|
|
22218
|
-
this.sourceFileToImportMap.get(sf).set(id, decl);
|
|
22219
|
-
}
|
|
22220
|
-
recordUsedIdentifier(id) {
|
|
22221
|
-
const sf = getSourceFile(id);
|
|
22222
|
-
if (!this.sourceFileToImportMap.has(sf)) {
|
|
22223
|
-
// The identifier's source file has no registered default imports at all.
|
|
22224
|
-
return;
|
|
22225
|
-
}
|
|
22226
|
-
const identiferToDeclaration = this.sourceFileToImportMap.get(sf);
|
|
22227
|
-
if (!identiferToDeclaration.has(id)) {
|
|
22228
|
-
// The identifier isn't from a registered default import.
|
|
22229
|
-
return;
|
|
22230
|
-
}
|
|
22231
|
-
const decl = identiferToDeclaration.get(id);
|
|
22284
|
+
recordUsedImport(importDecl) {
|
|
22285
|
+
const sf = getSourceFile(importDecl);
|
|
22232
22286
|
// Add the default import declaration to the set of used import declarations for the file.
|
|
22233
22287
|
if (!this.sourceFileToUsedImports.has(sf)) {
|
|
22234
22288
|
this.sourceFileToUsedImports.set(sf, new Set());
|
|
22235
22289
|
}
|
|
22236
|
-
this.sourceFileToUsedImports.get(sf).add(
|
|
22290
|
+
this.sourceFileToUsedImports.get(sf).add(importDecl);
|
|
22237
22291
|
}
|
|
22238
22292
|
/**
|
|
22239
22293
|
* Get a `ts.TransformerFactory` which will preserve default imports that were previously marked
|
|
22240
22294
|
* as used.
|
|
22241
22295
|
*
|
|
22242
|
-
* This transformer must run after any other transformers which call `
|
|
22296
|
+
* This transformer must run after any other transformers which call `recordUsedImport`.
|
|
22243
22297
|
*/
|
|
22244
22298
|
importPreservingTransformer() {
|
|
22245
22299
|
return (context) => {
|
|
@@ -22294,7 +22348,6 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
22294
22348
|
});
|
|
22295
22349
|
// Save memory - there's no need to keep these around once the transform has run for the given
|
|
22296
22350
|
// file.
|
|
22297
|
-
this.sourceFileToImportMap.delete(originalSf);
|
|
22298
22351
|
this.sourceFileToUsedImports.delete(originalSf);
|
|
22299
22352
|
return ts$1.updateSourceFileNode(sf, statements);
|
|
22300
22353
|
}
|
|
@@ -25492,6 +25545,417 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
25492
25545
|
}
|
|
25493
25546
|
}
|
|
25494
25547
|
|
|
25548
|
+
/**
|
|
25549
|
+
* @license
|
|
25550
|
+
* Copyright Google LLC All Rights Reserved.
|
|
25551
|
+
*
|
|
25552
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
25553
|
+
* found in the LICENSE file at https://angular.io/license
|
|
25554
|
+
*/
|
|
25555
|
+
/**
|
|
25556
|
+
* A phase of compilation for which time is tracked in a distinct bucket.
|
|
25557
|
+
*/
|
|
25558
|
+
var PerfPhase;
|
|
25559
|
+
(function (PerfPhase) {
|
|
25560
|
+
/**
|
|
25561
|
+
* The "default" phase which tracks time not spent in any other phase.
|
|
25562
|
+
*/
|
|
25563
|
+
PerfPhase[PerfPhase["Unaccounted"] = 0] = "Unaccounted";
|
|
25564
|
+
/**
|
|
25565
|
+
* Time spent setting up the compiler, before a TypeScript program is created.
|
|
25566
|
+
*
|
|
25567
|
+
* This includes operations like configuring the `ts.CompilerHost` and any wrappers.
|
|
25568
|
+
*/
|
|
25569
|
+
PerfPhase[PerfPhase["Setup"] = 1] = "Setup";
|
|
25570
|
+
/**
|
|
25571
|
+
* Time spent in `ts.createProgram`, including reading and parsing `ts.SourceFile`s in the
|
|
25572
|
+
* `ts.CompilerHost`.
|
|
25573
|
+
*
|
|
25574
|
+
* This might be an incremental program creation operation.
|
|
25575
|
+
*/
|
|
25576
|
+
PerfPhase[PerfPhase["TypeScriptProgramCreate"] = 2] = "TypeScriptProgramCreate";
|
|
25577
|
+
/**
|
|
25578
|
+
* Time spent reconciling the contents of an old `ts.Program` with the new incremental one.
|
|
25579
|
+
*
|
|
25580
|
+
* Only present in incremental compilations.
|
|
25581
|
+
*/
|
|
25582
|
+
PerfPhase[PerfPhase["Reconciliation"] = 3] = "Reconciliation";
|
|
25583
|
+
/**
|
|
25584
|
+
* Time spent updating an `NgCompiler` instance with a resource-only change.
|
|
25585
|
+
*
|
|
25586
|
+
* Only present in incremental compilations where the change was resource-only.
|
|
25587
|
+
*/
|
|
25588
|
+
PerfPhase[PerfPhase["ResourceUpdate"] = 4] = "ResourceUpdate";
|
|
25589
|
+
/**
|
|
25590
|
+
* Time spent calculating the plain TypeScript diagnostics (structural and semantic).
|
|
25591
|
+
*/
|
|
25592
|
+
PerfPhase[PerfPhase["TypeScriptDiagnostics"] = 5] = "TypeScriptDiagnostics";
|
|
25593
|
+
/**
|
|
25594
|
+
* Time spent in Angular analysis of individual classes in the program.
|
|
25595
|
+
*/
|
|
25596
|
+
PerfPhase[PerfPhase["Analysis"] = 6] = "Analysis";
|
|
25597
|
+
/**
|
|
25598
|
+
* Time spent in Angular global analysis (synthesis of analysis information into a complete
|
|
25599
|
+
* understanding of the program).
|
|
25600
|
+
*/
|
|
25601
|
+
PerfPhase[PerfPhase["Resolve"] = 7] = "Resolve";
|
|
25602
|
+
/**
|
|
25603
|
+
* Time spent building the import graph of the program in order to perform cycle detection.
|
|
25604
|
+
*/
|
|
25605
|
+
PerfPhase[PerfPhase["CycleDetection"] = 8] = "CycleDetection";
|
|
25606
|
+
/**
|
|
25607
|
+
* Time spent generating the text of Type Check Blocks in order to perform template type checking.
|
|
25608
|
+
*/
|
|
25609
|
+
PerfPhase[PerfPhase["TcbGeneration"] = 9] = "TcbGeneration";
|
|
25610
|
+
/**
|
|
25611
|
+
* Time spent updating the `ts.Program` with new Type Check Block code.
|
|
25612
|
+
*/
|
|
25613
|
+
PerfPhase[PerfPhase["TcbUpdateProgram"] = 10] = "TcbUpdateProgram";
|
|
25614
|
+
/**
|
|
25615
|
+
* Time spent by TypeScript performing its emit operations, including downleveling and writing
|
|
25616
|
+
* output files.
|
|
25617
|
+
*/
|
|
25618
|
+
PerfPhase[PerfPhase["TypeScriptEmit"] = 11] = "TypeScriptEmit";
|
|
25619
|
+
/**
|
|
25620
|
+
* Time spent by Angular performing code transformations of ASTs as they're about to be emitted.
|
|
25621
|
+
*
|
|
25622
|
+
* This includes the actual code generation step for templates, and occurs during the emit phase
|
|
25623
|
+
* (but is tracked separately from `TypeScriptEmit` time).
|
|
25624
|
+
*/
|
|
25625
|
+
PerfPhase[PerfPhase["Compile"] = 12] = "Compile";
|
|
25626
|
+
/**
|
|
25627
|
+
* Time spent performing a `TemplateTypeChecker` autocompletion operation.
|
|
25628
|
+
*/
|
|
25629
|
+
PerfPhase[PerfPhase["TtcAutocompletion"] = 13] = "TtcAutocompletion";
|
|
25630
|
+
/**
|
|
25631
|
+
* Time spent computing template type-checking diagnostics.
|
|
25632
|
+
*/
|
|
25633
|
+
PerfPhase[PerfPhase["TtcDiagnostics"] = 14] = "TtcDiagnostics";
|
|
25634
|
+
/**
|
|
25635
|
+
* Time spent getting a `Symbol` from the `TemplateTypeChecker`.
|
|
25636
|
+
*/
|
|
25637
|
+
PerfPhase[PerfPhase["TtcSymbol"] = 15] = "TtcSymbol";
|
|
25638
|
+
/**
|
|
25639
|
+
* Time spent by the Angular Language Service calculating a "get references" or a renaming
|
|
25640
|
+
* operation.
|
|
25641
|
+
*/
|
|
25642
|
+
PerfPhase[PerfPhase["LsReferencesAndRenames"] = 16] = "LsReferencesAndRenames";
|
|
25643
|
+
/**
|
|
25644
|
+
* Time spent by the Angular Language Service calculating a "quick info" operation.
|
|
25645
|
+
*/
|
|
25646
|
+
PerfPhase[PerfPhase["LsQuickInfo"] = 17] = "LsQuickInfo";
|
|
25647
|
+
/**
|
|
25648
|
+
* Time spent by the Angular Language Service calculating a "get type definition" or "get
|
|
25649
|
+
* definition" operation.
|
|
25650
|
+
*/
|
|
25651
|
+
PerfPhase[PerfPhase["LsDefinition"] = 18] = "LsDefinition";
|
|
25652
|
+
/**
|
|
25653
|
+
* Time spent by the Angular Language Service calculating a "get completions" (AKA autocomplete)
|
|
25654
|
+
* operation.
|
|
25655
|
+
*/
|
|
25656
|
+
PerfPhase[PerfPhase["LsCompletions"] = 19] = "LsCompletions";
|
|
25657
|
+
/**
|
|
25658
|
+
* Time spent by the Angular Language Service calculating a "view template typecheck block"
|
|
25659
|
+
* operation.
|
|
25660
|
+
*/
|
|
25661
|
+
PerfPhase[PerfPhase["LsTcb"] = 20] = "LsTcb";
|
|
25662
|
+
/**
|
|
25663
|
+
* Time spent by the Angular Language Service calculating diagnostics.
|
|
25664
|
+
*/
|
|
25665
|
+
PerfPhase[PerfPhase["LsDiagnostics"] = 21] = "LsDiagnostics";
|
|
25666
|
+
/**
|
|
25667
|
+
* Time spent by the Angular Language Service calculating a "get component locations for template"
|
|
25668
|
+
* operation.
|
|
25669
|
+
*/
|
|
25670
|
+
PerfPhase[PerfPhase["LsComponentLocations"] = 22] = "LsComponentLocations";
|
|
25671
|
+
/**
|
|
25672
|
+
* Tracks the number of `PerfPhase`s, and must appear at the end of the list.
|
|
25673
|
+
*/
|
|
25674
|
+
PerfPhase[PerfPhase["LAST"] = 23] = "LAST";
|
|
25675
|
+
})(PerfPhase || (PerfPhase = {}));
|
|
25676
|
+
/**
|
|
25677
|
+
* Represents some occurrence during compilation, and is tracked with a counter.
|
|
25678
|
+
*/
|
|
25679
|
+
var PerfEvent;
|
|
25680
|
+
(function (PerfEvent) {
|
|
25681
|
+
/**
|
|
25682
|
+
* Counts the number of `.d.ts` files in the program.
|
|
25683
|
+
*/
|
|
25684
|
+
PerfEvent[PerfEvent["InputDtsFile"] = 0] = "InputDtsFile";
|
|
25685
|
+
/**
|
|
25686
|
+
* Counts the number of non-`.d.ts` files in the program.
|
|
25687
|
+
*/
|
|
25688
|
+
PerfEvent[PerfEvent["InputTsFile"] = 1] = "InputTsFile";
|
|
25689
|
+
/**
|
|
25690
|
+
* An `@Component` class was analyzed.
|
|
25691
|
+
*/
|
|
25692
|
+
PerfEvent[PerfEvent["AnalyzeComponent"] = 2] = "AnalyzeComponent";
|
|
25693
|
+
/**
|
|
25694
|
+
* An `@Directive` class was analyzed.
|
|
25695
|
+
*/
|
|
25696
|
+
PerfEvent[PerfEvent["AnalyzeDirective"] = 3] = "AnalyzeDirective";
|
|
25697
|
+
/**
|
|
25698
|
+
* An `@Injectable` class was analyzed.
|
|
25699
|
+
*/
|
|
25700
|
+
PerfEvent[PerfEvent["AnalyzeInjectable"] = 4] = "AnalyzeInjectable";
|
|
25701
|
+
/**
|
|
25702
|
+
* An `@NgModule` class was analyzed.
|
|
25703
|
+
*/
|
|
25704
|
+
PerfEvent[PerfEvent["AnalyzeNgModule"] = 5] = "AnalyzeNgModule";
|
|
25705
|
+
/**
|
|
25706
|
+
* An `@Pipe` class was analyzed.
|
|
25707
|
+
*/
|
|
25708
|
+
PerfEvent[PerfEvent["AnalyzePipe"] = 6] = "AnalyzePipe";
|
|
25709
|
+
/**
|
|
25710
|
+
* A trait was analyzed.
|
|
25711
|
+
*
|
|
25712
|
+
* In theory, this should be the sum of the `Analyze` counters for each decorator type.
|
|
25713
|
+
*/
|
|
25714
|
+
PerfEvent[PerfEvent["TraitAnalyze"] = 7] = "TraitAnalyze";
|
|
25715
|
+
/**
|
|
25716
|
+
* A trait had a prior analysis available from an incremental program, and did not need to be
|
|
25717
|
+
* re-analyzed.
|
|
25718
|
+
*/
|
|
25719
|
+
PerfEvent[PerfEvent["TraitReuseAnalysis"] = 8] = "TraitReuseAnalysis";
|
|
25720
|
+
/**
|
|
25721
|
+
* A `ts.SourceFile` directly changed between the prior program and a new incremental compilation.
|
|
25722
|
+
*/
|
|
25723
|
+
PerfEvent[PerfEvent["SourceFilePhysicalChange"] = 9] = "SourceFilePhysicalChange";
|
|
25724
|
+
/**
|
|
25725
|
+
* A `ts.SourceFile` did not physically changed, but according to the file dependency graph, has
|
|
25726
|
+
* logically changed between the prior program and a new incremental compilation.
|
|
25727
|
+
*/
|
|
25728
|
+
PerfEvent[PerfEvent["SourceFileLogicalChange"] = 10] = "SourceFileLogicalChange";
|
|
25729
|
+
/**
|
|
25730
|
+
* A `ts.SourceFile` has not logically changed and all of its analysis results were thus available
|
|
25731
|
+
* for reuse.
|
|
25732
|
+
*/
|
|
25733
|
+
PerfEvent[PerfEvent["SourceFileReuseAnalysis"] = 11] = "SourceFileReuseAnalysis";
|
|
25734
|
+
/**
|
|
25735
|
+
* A Type Check Block (TCB) was generated.
|
|
25736
|
+
*/
|
|
25737
|
+
PerfEvent[PerfEvent["GenerateTcb"] = 12] = "GenerateTcb";
|
|
25738
|
+
/**
|
|
25739
|
+
* A Type Check Block (TCB) could not be generated because inlining was disabled, and the block
|
|
25740
|
+
* would've required inlining.
|
|
25741
|
+
*/
|
|
25742
|
+
PerfEvent[PerfEvent["SkipGenerateTcbNoInline"] = 13] = "SkipGenerateTcbNoInline";
|
|
25743
|
+
/**
|
|
25744
|
+
* A `.ngtypecheck.ts` file could be reused from the previous program and did not need to be
|
|
25745
|
+
* regenerated.
|
|
25746
|
+
*/
|
|
25747
|
+
PerfEvent[PerfEvent["ReuseTypeCheckFile"] = 14] = "ReuseTypeCheckFile";
|
|
25748
|
+
/**
|
|
25749
|
+
* The template type-checking program required changes and had to be updated in an incremental
|
|
25750
|
+
* step.
|
|
25751
|
+
*/
|
|
25752
|
+
PerfEvent[PerfEvent["UpdateTypeCheckProgram"] = 15] = "UpdateTypeCheckProgram";
|
|
25753
|
+
/**
|
|
25754
|
+
* The compiler was able to prove that a `ts.SourceFile` did not need to be re-emitted.
|
|
25755
|
+
*/
|
|
25756
|
+
PerfEvent[PerfEvent["EmitSkipSourceFile"] = 16] = "EmitSkipSourceFile";
|
|
25757
|
+
/**
|
|
25758
|
+
* A `ts.SourceFile` was emitted.
|
|
25759
|
+
*/
|
|
25760
|
+
PerfEvent[PerfEvent["EmitSourceFile"] = 17] = "EmitSourceFile";
|
|
25761
|
+
/**
|
|
25762
|
+
* Tracks the number of `PrefEvent`s, and must appear at the end of the list.
|
|
25763
|
+
*/
|
|
25764
|
+
PerfEvent[PerfEvent["LAST"] = 18] = "LAST";
|
|
25765
|
+
})(PerfEvent || (PerfEvent = {}));
|
|
25766
|
+
/**
|
|
25767
|
+
* Represents a checkpoint during compilation at which the memory usage of the compiler should be
|
|
25768
|
+
* recorded.
|
|
25769
|
+
*/
|
|
25770
|
+
var PerfCheckpoint;
|
|
25771
|
+
(function (PerfCheckpoint) {
|
|
25772
|
+
/**
|
|
25773
|
+
* The point at which the `PerfRecorder` was created, and ideally tracks memory used before any
|
|
25774
|
+
* compilation structures are created.
|
|
25775
|
+
*/
|
|
25776
|
+
PerfCheckpoint[PerfCheckpoint["Initial"] = 0] = "Initial";
|
|
25777
|
+
/**
|
|
25778
|
+
* The point just after the `ts.Program` has been created.
|
|
25779
|
+
*/
|
|
25780
|
+
PerfCheckpoint[PerfCheckpoint["TypeScriptProgramCreate"] = 1] = "TypeScriptProgramCreate";
|
|
25781
|
+
/**
|
|
25782
|
+
* The point just before Angular analysis starts.
|
|
25783
|
+
*
|
|
25784
|
+
* In the main usage pattern for the compiler, TypeScript diagnostics have been calculated at this
|
|
25785
|
+
* point, so the `ts.TypeChecker` has fully ingested the current program, all `ts.Type` structures
|
|
25786
|
+
* and `ts.Symbol`s have been created.
|
|
25787
|
+
*/
|
|
25788
|
+
PerfCheckpoint[PerfCheckpoint["PreAnalysis"] = 2] = "PreAnalysis";
|
|
25789
|
+
/**
|
|
25790
|
+
* The point just after Angular analysis completes.
|
|
25791
|
+
*/
|
|
25792
|
+
PerfCheckpoint[PerfCheckpoint["Analysis"] = 3] = "Analysis";
|
|
25793
|
+
/**
|
|
25794
|
+
* The point just after Angular resolution is complete.
|
|
25795
|
+
*/
|
|
25796
|
+
PerfCheckpoint[PerfCheckpoint["Resolve"] = 4] = "Resolve";
|
|
25797
|
+
/**
|
|
25798
|
+
* The point just after Type Check Blocks (TCBs) have been generated.
|
|
25799
|
+
*/
|
|
25800
|
+
PerfCheckpoint[PerfCheckpoint["TtcGeneration"] = 5] = "TtcGeneration";
|
|
25801
|
+
/**
|
|
25802
|
+
* The point just after the template type-checking program has been updated with any new TCBs.
|
|
25803
|
+
*/
|
|
25804
|
+
PerfCheckpoint[PerfCheckpoint["TtcUpdateProgram"] = 6] = "TtcUpdateProgram";
|
|
25805
|
+
/**
|
|
25806
|
+
* The point just before emit begins.
|
|
25807
|
+
*
|
|
25808
|
+
* In the main usage pattern for the compiler, all template type-checking diagnostics have been
|
|
25809
|
+
* requested at this point.
|
|
25810
|
+
*/
|
|
25811
|
+
PerfCheckpoint[PerfCheckpoint["PreEmit"] = 7] = "PreEmit";
|
|
25812
|
+
/**
|
|
25813
|
+
* The point just after the program has been fully emitted.
|
|
25814
|
+
*/
|
|
25815
|
+
PerfCheckpoint[PerfCheckpoint["Emit"] = 8] = "Emit";
|
|
25816
|
+
/**
|
|
25817
|
+
* Tracks the number of `PerfCheckpoint`s, and must appear at the end of the list.
|
|
25818
|
+
*/
|
|
25819
|
+
PerfCheckpoint[PerfCheckpoint["LAST"] = 9] = "LAST";
|
|
25820
|
+
})(PerfCheckpoint || (PerfCheckpoint = {}));
|
|
25821
|
+
|
|
25822
|
+
/**
|
|
25823
|
+
* @license
|
|
25824
|
+
* Copyright Google LLC All Rights Reserved.
|
|
25825
|
+
*
|
|
25826
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
25827
|
+
* found in the LICENSE file at https://angular.io/license
|
|
25828
|
+
*/
|
|
25829
|
+
function mark() {
|
|
25830
|
+
return process.hrtime();
|
|
25831
|
+
}
|
|
25832
|
+
function timeSinceInMicros(mark) {
|
|
25833
|
+
const delta = process.hrtime(mark);
|
|
25834
|
+
return (delta[0] * 1000000) + Math.floor(delta[1] / 1000);
|
|
25835
|
+
}
|
|
25836
|
+
|
|
25837
|
+
/**
|
|
25838
|
+
* @license
|
|
25839
|
+
* Copyright Google LLC All Rights Reserved.
|
|
25840
|
+
*
|
|
25841
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
25842
|
+
* found in the LICENSE file at https://angular.io/license
|
|
25843
|
+
*/
|
|
25844
|
+
/**
|
|
25845
|
+
* A `PerfRecorder` that actively tracks performance statistics.
|
|
25846
|
+
*/
|
|
25847
|
+
class ActivePerfRecorder {
|
|
25848
|
+
constructor(zeroTime) {
|
|
25849
|
+
this.zeroTime = zeroTime;
|
|
25850
|
+
this.currentPhase = PerfPhase.Unaccounted;
|
|
25851
|
+
this.currentPhaseEntered = this.zeroTime;
|
|
25852
|
+
this.counters = Array(PerfEvent.LAST).fill(0);
|
|
25853
|
+
this.phaseTime = Array(PerfPhase.LAST).fill(0);
|
|
25854
|
+
this.bytes = Array(PerfCheckpoint.LAST).fill(0);
|
|
25855
|
+
// Take an initial memory snapshot before any other compilation work begins.
|
|
25856
|
+
this.memory(PerfCheckpoint.Initial);
|
|
25857
|
+
}
|
|
25858
|
+
/**
|
|
25859
|
+
* Creates an `ActivePerfRecoder` with its zero point set to the current time.
|
|
25860
|
+
*/
|
|
25861
|
+
static zeroedToNow() {
|
|
25862
|
+
return new ActivePerfRecorder(mark());
|
|
25863
|
+
}
|
|
25864
|
+
reset() {
|
|
25865
|
+
this.counters = Array(PerfEvent.LAST).fill(0);
|
|
25866
|
+
this.phaseTime = Array(PerfPhase.LAST).fill(0);
|
|
25867
|
+
this.bytes = Array(PerfCheckpoint.LAST).fill(0);
|
|
25868
|
+
this.zeroTime = mark();
|
|
25869
|
+
this.currentPhase = PerfPhase.Unaccounted;
|
|
25870
|
+
this.currentPhaseEntered = this.zeroTime;
|
|
25871
|
+
}
|
|
25872
|
+
memory(after) {
|
|
25873
|
+
this.bytes[after] = process.memoryUsage().heapUsed;
|
|
25874
|
+
}
|
|
25875
|
+
phase(phase) {
|
|
25876
|
+
const previous = this.currentPhase;
|
|
25877
|
+
this.phaseTime[this.currentPhase] += timeSinceInMicros(this.currentPhaseEntered);
|
|
25878
|
+
this.currentPhase = phase;
|
|
25879
|
+
this.currentPhaseEntered = mark();
|
|
25880
|
+
return previous;
|
|
25881
|
+
}
|
|
25882
|
+
inPhase(phase, fn) {
|
|
25883
|
+
const previousPhase = this.phase(phase);
|
|
25884
|
+
try {
|
|
25885
|
+
return fn();
|
|
25886
|
+
}
|
|
25887
|
+
finally {
|
|
25888
|
+
this.phase(previousPhase);
|
|
25889
|
+
}
|
|
25890
|
+
}
|
|
25891
|
+
eventCount(counter, incrementBy = 1) {
|
|
25892
|
+
this.counters[counter] += incrementBy;
|
|
25893
|
+
}
|
|
25894
|
+
/**
|
|
25895
|
+
* Return the current performance metrics as a serializable object.
|
|
25896
|
+
*/
|
|
25897
|
+
finalize() {
|
|
25898
|
+
// Track the last segment of time spent in `this.currentPhase` in the time array.
|
|
25899
|
+
this.phase(PerfPhase.Unaccounted);
|
|
25900
|
+
const results = {
|
|
25901
|
+
events: {},
|
|
25902
|
+
phases: {},
|
|
25903
|
+
memory: {},
|
|
25904
|
+
};
|
|
25905
|
+
for (let i = 0; i < this.phaseTime.length; i++) {
|
|
25906
|
+
if (this.phaseTime[i] > 0) {
|
|
25907
|
+
results.phases[PerfPhase[i]] = this.phaseTime[i];
|
|
25908
|
+
}
|
|
25909
|
+
}
|
|
25910
|
+
for (let i = 0; i < this.phaseTime.length; i++) {
|
|
25911
|
+
if (this.counters[i] > 0) {
|
|
25912
|
+
results.events[PerfEvent[i]] = this.counters[i];
|
|
25913
|
+
}
|
|
25914
|
+
}
|
|
25915
|
+
for (let i = 0; i < this.bytes.length; i++) {
|
|
25916
|
+
if (this.bytes[i] > 0) {
|
|
25917
|
+
results.memory[PerfCheckpoint[i]] = this.bytes[i];
|
|
25918
|
+
}
|
|
25919
|
+
}
|
|
25920
|
+
return results;
|
|
25921
|
+
}
|
|
25922
|
+
}
|
|
25923
|
+
/**
|
|
25924
|
+
* A `PerfRecorder` that delegates to a target `PerfRecorder` which can be updated later.
|
|
25925
|
+
*
|
|
25926
|
+
* `DelegatingPerfRecorder` is useful when a compiler class that needs a `PerfRecorder` can outlive
|
|
25927
|
+
* the current compilation. This is true for most compiler classes as resource-only changes reuse
|
|
25928
|
+
* the same `NgCompiler` for a new compilation.
|
|
25929
|
+
*/
|
|
25930
|
+
class DelegatingPerfRecorder {
|
|
25931
|
+
constructor(target) {
|
|
25932
|
+
this.target = target;
|
|
25933
|
+
}
|
|
25934
|
+
eventCount(counter, incrementBy) {
|
|
25935
|
+
this.target.eventCount(counter, incrementBy);
|
|
25936
|
+
}
|
|
25937
|
+
phase(phase) {
|
|
25938
|
+
return this.target.phase(phase);
|
|
25939
|
+
}
|
|
25940
|
+
inPhase(phase, fn) {
|
|
25941
|
+
// Note: this doesn't delegate to `this.target.inPhase` but instead is implemented manually here
|
|
25942
|
+
// to avoid adding an additional frame of noise to the stack when debugging.
|
|
25943
|
+
const previousPhase = this.target.phase(phase);
|
|
25944
|
+
try {
|
|
25945
|
+
return fn();
|
|
25946
|
+
}
|
|
25947
|
+
finally {
|
|
25948
|
+
this.target.phase(previousPhase);
|
|
25949
|
+
}
|
|
25950
|
+
}
|
|
25951
|
+
memory(after) {
|
|
25952
|
+
this.target.memory(after);
|
|
25953
|
+
}
|
|
25954
|
+
reset() {
|
|
25955
|
+
this.target.reset();
|
|
25956
|
+
}
|
|
25957
|
+
}
|
|
25958
|
+
|
|
25495
25959
|
/**
|
|
25496
25960
|
* @license
|
|
25497
25961
|
* Copyright Google LLC All Rights Reserved.
|
|
@@ -25742,6 +26206,8 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
25742
26206
|
for (const priorRecord of priorWork) {
|
|
25743
26207
|
this.adopt(priorRecord);
|
|
25744
26208
|
}
|
|
26209
|
+
this.perf.eventCount(PerfEvent.SourceFileReuseAnalysis);
|
|
26210
|
+
this.perf.eventCount(PerfEvent.TraitReuseAnalysis, priorWork.length);
|
|
25745
26211
|
// Skip the rest of analysis, as this file's prior traits are being reused.
|
|
25746
26212
|
return;
|
|
25747
26213
|
}
|
|
@@ -25945,6 +26411,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
25945
26411
|
if (trait.state !== TraitState.Pending) {
|
|
25946
26412
|
throw new Error(`Attempt to analyze trait of ${clazz.name.text} in state ${TraitState[trait.state]} (expected DETECTED)`);
|
|
25947
26413
|
}
|
|
26414
|
+
this.perf.eventCount(PerfEvent.TraitAnalyze);
|
|
25948
26415
|
// Attempt analysis. This could fail with a `FatalDiagnosticError`; catch it if it does.
|
|
25949
26416
|
let result;
|
|
25950
26417
|
try {
|
|
@@ -26083,7 +26550,6 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
26083
26550
|
// Cannot compile a trait that is not resolved, or had any errors in its declaration.
|
|
26084
26551
|
continue;
|
|
26085
26552
|
}
|
|
26086
|
-
const compileSpan = this.perf.start('compileClass', original);
|
|
26087
26553
|
// `trait.resolution` is non-null asserted here because TypeScript does not recognize that
|
|
26088
26554
|
// `Readonly<unknown>` is nullable (as `unknown` itself is nullable) due to the way that
|
|
26089
26555
|
// `Readonly` works.
|
|
@@ -26097,7 +26563,6 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
26097
26563
|
trait.handler.compileFull(clazz, trait.analysis, trait.resolution, constantPool);
|
|
26098
26564
|
}
|
|
26099
26565
|
const compileMatchRes = compileRes;
|
|
26100
|
-
this.perf.stop(compileSpan);
|
|
26101
26566
|
if (Array.isArray(compileMatchRes)) {
|
|
26102
26567
|
for (const result of compileMatchRes) {
|
|
26103
26568
|
if (!res.some(r => r.name === result.name)) {
|
|
@@ -26262,7 +26727,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
26262
26727
|
this.imports = imports;
|
|
26263
26728
|
this.downlevelTaggedTemplates = options.downlevelTaggedTemplates === true;
|
|
26264
26729
|
this.downlevelVariableDeclarations = options.downlevelVariableDeclarations === true;
|
|
26265
|
-
this.
|
|
26730
|
+
this.recordWrappedNode = options.recordWrappedNode || (() => { });
|
|
26266
26731
|
}
|
|
26267
26732
|
visitDeclareVarStmt(stmt, context) {
|
|
26268
26733
|
var _a;
|
|
@@ -26490,7 +26955,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
26490
26955
|
throw new Error('Method not implemented.');
|
|
26491
26956
|
}
|
|
26492
26957
|
visitWrappedNodeExpr(ast, _context) {
|
|
26493
|
-
this.
|
|
26958
|
+
this.recordWrappedNode(ast);
|
|
26494
26959
|
return ast.node;
|
|
26495
26960
|
}
|
|
26496
26961
|
visitTypeofExpr(ast, context) {
|
|
@@ -27349,11 +27814,11 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
27349
27814
|
*/
|
|
27350
27815
|
const NO_DECORATORS = new Set();
|
|
27351
27816
|
const CLOSURE_FILE_OVERVIEW_REGEXP = /\s+@fileoverview\s+/i;
|
|
27352
|
-
function ivyTransformFactory(compilation, reflector, importRewriter,
|
|
27353
|
-
const
|
|
27817
|
+
function ivyTransformFactory(compilation, reflector, importRewriter, defaultImportTracker, perf, isCore, isClosureCompilerEnabled) {
|
|
27818
|
+
const recordWrappedNode = createRecorderFn(defaultImportTracker);
|
|
27354
27819
|
return (context) => {
|
|
27355
27820
|
return (file) => {
|
|
27356
|
-
return transformIvySourceFile(compilation, context, reflector, importRewriter, file, isCore, isClosureCompilerEnabled,
|
|
27821
|
+
return perf.inPhase(PerfPhase.Compile, () => transformIvySourceFile(compilation, context, reflector, importRewriter, file, isCore, isClosureCompilerEnabled, recordWrappedNode));
|
|
27357
27822
|
};
|
|
27358
27823
|
};
|
|
27359
27824
|
}
|
|
@@ -27384,13 +27849,13 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
27384
27849
|
* compilation results (provided as an argument).
|
|
27385
27850
|
*/
|
|
27386
27851
|
class IvyTransformationVisitor extends Visitor {
|
|
27387
|
-
constructor(compilation, classCompilationMap, reflector, importManager,
|
|
27852
|
+
constructor(compilation, classCompilationMap, reflector, importManager, recordWrappedNode, isClosureCompilerEnabled, isCore) {
|
|
27388
27853
|
super();
|
|
27389
27854
|
this.compilation = compilation;
|
|
27390
27855
|
this.classCompilationMap = classCompilationMap;
|
|
27391
27856
|
this.reflector = reflector;
|
|
27392
27857
|
this.importManager = importManager;
|
|
27393
|
-
this.
|
|
27858
|
+
this.recordWrappedNode = recordWrappedNode;
|
|
27394
27859
|
this.isClosureCompilerEnabled = isClosureCompilerEnabled;
|
|
27395
27860
|
this.isCore = isCore;
|
|
27396
27861
|
}
|
|
@@ -27405,7 +27870,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
27405
27870
|
const members = [...node.members];
|
|
27406
27871
|
for (const field of this.classCompilationMap.get(node)) {
|
|
27407
27872
|
// Translate the initializer for the field into TS nodes.
|
|
27408
|
-
const exprNode = translateExpression(field.initializer, this.importManager, {
|
|
27873
|
+
const exprNode = translateExpression(field.initializer, this.importManager, { recordWrappedNode: this.recordWrappedNode });
|
|
27409
27874
|
// Create a static property declaration for the new field.
|
|
27410
27875
|
const property = ts$1.createProperty(undefined, [ts$1.createToken(ts$1.SyntaxKind.StaticKeyword)], field.name, undefined, undefined, exprNode);
|
|
27411
27876
|
if (this.isClosureCompilerEnabled) {
|
|
@@ -27417,7 +27882,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
27417
27882
|
/* hasTrailingNewLine */ false);
|
|
27418
27883
|
}
|
|
27419
27884
|
field.statements
|
|
27420
|
-
.map(stmt => translateStatement(stmt, this.importManager, {
|
|
27885
|
+
.map(stmt => translateStatement(stmt, this.importManager, { recordWrappedNode: this.recordWrappedNode }))
|
|
27421
27886
|
.forEach(stmt => statements.push(stmt));
|
|
27422
27887
|
members.push(property);
|
|
27423
27888
|
}
|
|
@@ -27521,7 +27986,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
27521
27986
|
/**
|
|
27522
27987
|
* A transformer which operates on ts.SourceFiles and applies changes from an `IvyCompilation`.
|
|
27523
27988
|
*/
|
|
27524
|
-
function transformIvySourceFile(compilation, context, reflector, importRewriter, file, isCore, isClosureCompilerEnabled,
|
|
27989
|
+
function transformIvySourceFile(compilation, context, reflector, importRewriter, file, isCore, isClosureCompilerEnabled, recordWrappedNode) {
|
|
27525
27990
|
const constantPool = new ConstantPool(isClosureCompilerEnabled);
|
|
27526
27991
|
const importManager = new ImportManager(importRewriter);
|
|
27527
27992
|
// The transformation process consists of 2 steps:
|
|
@@ -27538,13 +28003,13 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
27538
28003
|
visit(file, compilationVisitor, context);
|
|
27539
28004
|
// Step 2. Scan through the AST again and perform transformations based on Ivy compilation
|
|
27540
28005
|
// results obtained at Step 1.
|
|
27541
|
-
const transformationVisitor = new IvyTransformationVisitor(compilation, compilationVisitor.classCompilationMap, reflector, importManager,
|
|
28006
|
+
const transformationVisitor = new IvyTransformationVisitor(compilation, compilationVisitor.classCompilationMap, reflector, importManager, recordWrappedNode, isClosureCompilerEnabled, isCore);
|
|
27542
28007
|
let sf = visit(file, transformationVisitor, context);
|
|
27543
28008
|
// Generate the constant statements first, as they may involve adding additional imports
|
|
27544
28009
|
// to the ImportManager.
|
|
27545
28010
|
const downlevelTranslatedCode = getLocalizeCompileTarget(context) < ts$1.ScriptTarget.ES2015;
|
|
27546
28011
|
const constants = constantPool.statements.map(stmt => translateStatement(stmt, importManager, {
|
|
27547
|
-
|
|
28012
|
+
recordWrappedNode,
|
|
27548
28013
|
downlevelTaggedTemplates: downlevelTranslatedCode,
|
|
27549
28014
|
downlevelVariableDeclarations: downlevelTranslatedCode,
|
|
27550
28015
|
}));
|
|
@@ -27618,10 +28083,11 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
27618
28083
|
function isFromAngularCore(decorator) {
|
|
27619
28084
|
return decorator.import !== null && decorator.import.from === '@angular/core';
|
|
27620
28085
|
}
|
|
27621
|
-
function createRecorderFn(
|
|
27622
|
-
return
|
|
27623
|
-
|
|
27624
|
-
|
|
28086
|
+
function createRecorderFn(defaultImportTracker) {
|
|
28087
|
+
return node => {
|
|
28088
|
+
const importDecl = getDefaultImportDeclaration(node);
|
|
28089
|
+
if (importDecl !== null) {
|
|
28090
|
+
defaultImportTracker.recordUsedImport(importDecl);
|
|
27625
28091
|
}
|
|
27626
28092
|
};
|
|
27627
28093
|
}
|
|
@@ -27716,7 +28182,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
27716
28182
|
* Use of this source code is governed by an MIT-style license that can be
|
|
27717
28183
|
* found in the LICENSE file at https://angular.io/license
|
|
27718
28184
|
*/
|
|
27719
|
-
function getConstructorDependencies(clazz, reflector,
|
|
28185
|
+
function getConstructorDependencies(clazz, reflector, isCore) {
|
|
27720
28186
|
const deps = [];
|
|
27721
28187
|
const errors = [];
|
|
27722
28188
|
let ctorParams = reflector.getConstructorParameters(clazz);
|
|
@@ -27729,7 +28195,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
27729
28195
|
}
|
|
27730
28196
|
}
|
|
27731
28197
|
ctorParams.forEach((param, idx) => {
|
|
27732
|
-
let token = valueReferenceToExpression(param.typeValueReference
|
|
28198
|
+
let token = valueReferenceToExpression(param.typeValueReference);
|
|
27733
28199
|
let attribute = null;
|
|
27734
28200
|
let optional = false, self = false, skipSelf = false, host = false;
|
|
27735
28201
|
let resolved = R3ResolvedDependencyType.Token;
|
|
@@ -27796,16 +28262,16 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
27796
28262
|
return { deps: null, errors };
|
|
27797
28263
|
}
|
|
27798
28264
|
}
|
|
27799
|
-
function valueReferenceToExpression(valueRef
|
|
28265
|
+
function valueReferenceToExpression(valueRef) {
|
|
27800
28266
|
if (valueRef.kind === 2 /* UNAVAILABLE */) {
|
|
27801
28267
|
return null;
|
|
27802
28268
|
}
|
|
27803
28269
|
else if (valueRef.kind === 0 /* LOCAL */) {
|
|
27804
|
-
|
|
27805
|
-
|
|
27806
|
-
|
|
28270
|
+
const expr = new WrappedNodeExpr(valueRef.expression);
|
|
28271
|
+
if (valueRef.defaultImportStatement !== null) {
|
|
28272
|
+
attachDefaultImportDeclaration(expr, valueRef.defaultImportStatement);
|
|
27807
28273
|
}
|
|
27808
|
-
return
|
|
28274
|
+
return expr;
|
|
27809
28275
|
}
|
|
27810
28276
|
else {
|
|
27811
28277
|
let importExpr = new ExternalExpr({ moduleName: valueRef.moduleName, name: valueRef.importedName });
|
|
@@ -27836,8 +28302,8 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
27836
28302
|
return 'invalid';
|
|
27837
28303
|
}
|
|
27838
28304
|
}
|
|
27839
|
-
function getValidConstructorDependencies(clazz, reflector,
|
|
27840
|
-
return validateConstructorDependencies(clazz, getConstructorDependencies(clazz, reflector,
|
|
28305
|
+
function getValidConstructorDependencies(clazz, reflector, isCore) {
|
|
28306
|
+
return validateConstructorDependencies(clazz, getConstructorDependencies(clazz, reflector, isCore));
|
|
27841
28307
|
}
|
|
27842
28308
|
/**
|
|
27843
28309
|
* Validate that `ConstructorDeps` does not have any invalid dependencies and convert them into the
|
|
@@ -28345,7 +28811,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
28345
28811
|
* If no such metadata is present, this function returns `null`. Otherwise, the call is returned
|
|
28346
28812
|
* as a `Statement` for inclusion along with the class.
|
|
28347
28813
|
*/
|
|
28348
|
-
function generateSetClassMetadataCall(clazz, reflection,
|
|
28814
|
+
function generateSetClassMetadataCall(clazz, reflection, isCore, annotateForClosureCompiler) {
|
|
28349
28815
|
if (!reflection.isClass(clazz)) {
|
|
28350
28816
|
return null;
|
|
28351
28817
|
}
|
|
@@ -28372,7 +28838,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
28372
28838
|
let metaCtorParameters = new LiteralExpr(null);
|
|
28373
28839
|
const classCtorParameters = reflection.getConstructorParameters(clazz);
|
|
28374
28840
|
if (classCtorParameters !== null) {
|
|
28375
|
-
const ctorParameters = classCtorParameters.map(param => ctorParameterToMetadata(param,
|
|
28841
|
+
const ctorParameters = classCtorParameters.map(param => ctorParameterToMetadata(param, isCore));
|
|
28376
28842
|
metaCtorParameters = new FunctionExpr([], [
|
|
28377
28843
|
new ReturnStatement(new LiteralArrayExpr(ctorParameters)),
|
|
28378
28844
|
]);
|
|
@@ -28409,11 +28875,11 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
28409
28875
|
/**
|
|
28410
28876
|
* Convert a reflected constructor parameter to metadata.
|
|
28411
28877
|
*/
|
|
28412
|
-
function ctorParameterToMetadata(param,
|
|
28878
|
+
function ctorParameterToMetadata(param, isCore) {
|
|
28413
28879
|
// Parameters sometimes have a type that can be referenced. If so, then use it, otherwise
|
|
28414
28880
|
// its type is undefined.
|
|
28415
28881
|
const type = param.typeValueReference.kind !== 2 /* UNAVAILABLE */ ?
|
|
28416
|
-
valueReferenceToExpression(param.typeValueReference
|
|
28882
|
+
valueReferenceToExpression(param.typeValueReference) :
|
|
28417
28883
|
new LiteralExpr(undefined);
|
|
28418
28884
|
const mapEntries = [
|
|
28419
28885
|
{ key: 'type', value: type, quoted: false },
|
|
@@ -28600,18 +29066,18 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
28600
29066
|
return isSymbolEqual(current, previous);
|
|
28601
29067
|
}
|
|
28602
29068
|
class DirectiveDecoratorHandler {
|
|
28603
|
-
constructor(reflector, evaluator, metaRegistry, scopeRegistry, metaReader,
|
|
29069
|
+
constructor(reflector, evaluator, metaRegistry, scopeRegistry, metaReader, injectableRegistry, isCore, semanticDepGraphUpdater, annotateForClosureCompiler, compileUndecoratedClassesWithAngularFeatures, perf) {
|
|
28604
29070
|
this.reflector = reflector;
|
|
28605
29071
|
this.evaluator = evaluator;
|
|
28606
29072
|
this.metaRegistry = metaRegistry;
|
|
28607
29073
|
this.scopeRegistry = scopeRegistry;
|
|
28608
29074
|
this.metaReader = metaReader;
|
|
28609
|
-
this.defaultImportRecorder = defaultImportRecorder;
|
|
28610
29075
|
this.injectableRegistry = injectableRegistry;
|
|
28611
29076
|
this.isCore = isCore;
|
|
28612
29077
|
this.semanticDepGraphUpdater = semanticDepGraphUpdater;
|
|
28613
29078
|
this.annotateForClosureCompiler = annotateForClosureCompiler;
|
|
28614
29079
|
this.compileUndecoratedClassesWithAngularFeatures = compileUndecoratedClassesWithAngularFeatures;
|
|
29080
|
+
this.perf = perf;
|
|
28615
29081
|
this.precedence = HandlerPrecedence.PRIMARY;
|
|
28616
29082
|
this.name = DirectiveDecoratorHandler.name;
|
|
28617
29083
|
}
|
|
@@ -28638,7 +29104,8 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
28638
29104
|
if (this.compileUndecoratedClassesWithAngularFeatures === false && decorator === null) {
|
|
28639
29105
|
return { diagnostics: [getUndecoratedClassWithAngularFeaturesDiagnostic(node)] };
|
|
28640
29106
|
}
|
|
28641
|
-
|
|
29107
|
+
this.perf.eventCount(PerfEvent.AnalyzeDirective);
|
|
29108
|
+
const directiveResult = extractDirectiveMetadata(node, decorator, this.reflector, this.evaluator, this.isCore, flags, this.annotateForClosureCompiler);
|
|
28642
29109
|
if (directiveResult === undefined) {
|
|
28643
29110
|
return {};
|
|
28644
29111
|
}
|
|
@@ -28652,7 +29119,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
28652
29119
|
inputs: directiveResult.inputs,
|
|
28653
29120
|
outputs: directiveResult.outputs,
|
|
28654
29121
|
meta: analysis,
|
|
28655
|
-
metadataStmt: generateSetClassMetadataCall(node, this.reflector, this.
|
|
29122
|
+
metadataStmt: generateSetClassMetadataCall(node, this.reflector, this.isCore, this.annotateForClosureCompiler),
|
|
28656
29123
|
baseClass: readBaseClass$1(node, this.reflector, this.evaluator),
|
|
28657
29124
|
typeCheckMeta: extractDirectiveTypeCheckMeta(node, directiveResult.inputs, this.reflector),
|
|
28658
29125
|
providersRequiringFactory,
|
|
@@ -28735,7 +29202,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
28735
29202
|
* appear in the declarations of an `NgModule` and additional verification is done when processing
|
|
28736
29203
|
* the module.
|
|
28737
29204
|
*/
|
|
28738
|
-
function extractDirectiveMetadata(clazz, decorator, reflector, evaluator,
|
|
29205
|
+
function extractDirectiveMetadata(clazz, decorator, reflector, evaluator, isCore, flags, annotateForClosureCompiler, defaultSelector = null) {
|
|
28739
29206
|
let directive;
|
|
28740
29207
|
if (decorator === null || decorator.args === null || decorator.args.length === 0) {
|
|
28741
29208
|
directive = new Map();
|
|
@@ -28813,7 +29280,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
28813
29280
|
}
|
|
28814
29281
|
exportAs = resolved.split(',').map(part => part.trim());
|
|
28815
29282
|
}
|
|
28816
|
-
const rawCtorDeps = getConstructorDependencies(clazz, reflector,
|
|
29283
|
+
const rawCtorDeps = getConstructorDependencies(clazz, reflector, isCore);
|
|
28817
29284
|
let ctorDeps;
|
|
28818
29285
|
// Non-abstract directives (those with a selector) require valid constructor dependencies, whereas
|
|
28819
29286
|
// abstract directives are allowed to have invalid dependencies, given that a subclass may call
|
|
@@ -29235,7 +29702,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
29235
29702
|
* Compiles @NgModule annotations to ngModuleDef fields.
|
|
29236
29703
|
*/
|
|
29237
29704
|
class NgModuleDecoratorHandler {
|
|
29238
|
-
constructor(reflector, evaluator, metaReader, metaRegistry, scopeRegistry, referencesRegistry, isCore, routeAnalyzer, refEmitter, factoryTracker,
|
|
29705
|
+
constructor(reflector, evaluator, metaReader, metaRegistry, scopeRegistry, referencesRegistry, isCore, routeAnalyzer, refEmitter, factoryTracker, annotateForClosureCompiler, injectableRegistry, perf, localeId) {
|
|
29239
29706
|
this.reflector = reflector;
|
|
29240
29707
|
this.evaluator = evaluator;
|
|
29241
29708
|
this.metaReader = metaReader;
|
|
@@ -29246,9 +29713,9 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
29246
29713
|
this.routeAnalyzer = routeAnalyzer;
|
|
29247
29714
|
this.refEmitter = refEmitter;
|
|
29248
29715
|
this.factoryTracker = factoryTracker;
|
|
29249
|
-
this.defaultImportRecorder = defaultImportRecorder;
|
|
29250
29716
|
this.annotateForClosureCompiler = annotateForClosureCompiler;
|
|
29251
29717
|
this.injectableRegistry = injectableRegistry;
|
|
29718
|
+
this.perf = perf;
|
|
29252
29719
|
this.localeId = localeId;
|
|
29253
29720
|
this.precedence = HandlerPrecedence.PRIMARY;
|
|
29254
29721
|
this.name = NgModuleDecoratorHandler.name;
|
|
@@ -29270,6 +29737,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
29270
29737
|
}
|
|
29271
29738
|
}
|
|
29272
29739
|
analyze(node, decorator) {
|
|
29740
|
+
this.perf.eventCount(PerfEvent.AnalyzeNgModule);
|
|
29273
29741
|
const name = node.name.text;
|
|
29274
29742
|
if (decorator.args === null || decorator.args.length > 1) {
|
|
29275
29743
|
throw new FatalDiagnosticError(ErrorCode.DECORATOR_ARITY_WRONG, Decorator.nodeForError(decorator), `Incorrect number of arguments to @NgModule decorator`);
|
|
@@ -29422,7 +29890,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
29422
29890
|
schemas: schemas,
|
|
29423
29891
|
mod: ngModuleDef,
|
|
29424
29892
|
inj: ngInjectorDef,
|
|
29425
|
-
deps: getValidConstructorDependencies(node, this.reflector, this.
|
|
29893
|
+
deps: getValidConstructorDependencies(node, this.reflector, this.isCore),
|
|
29426
29894
|
declarations: declarationRefs,
|
|
29427
29895
|
rawDeclarations,
|
|
29428
29896
|
imports: importRefs,
|
|
@@ -29431,7 +29899,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
29431
29899
|
providersRequiringFactory: rawProviders ?
|
|
29432
29900
|
resolveProvidersRequiringFactory(rawProviders, this.reflector, this.evaluator) :
|
|
29433
29901
|
null,
|
|
29434
|
-
metadataStmt: generateSetClassMetadataCall(node, this.reflector, this.
|
|
29902
|
+
metadataStmt: generateSetClassMetadataCall(node, this.reflector, this.isCore, this.annotateForClosureCompiler),
|
|
29435
29903
|
factorySymbolName: node.name.text,
|
|
29436
29904
|
},
|
|
29437
29905
|
};
|
|
@@ -29762,7 +30230,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
29762
30230
|
* `DecoratorHandler` which handles the `@Component` annotation.
|
|
29763
30231
|
*/
|
|
29764
30232
|
class ComponentDecoratorHandler {
|
|
29765
|
-
constructor(reflector, evaluator, metaRegistry, metaReader, scopeReader, scopeRegistry, typeCheckScopeRegistry, resourceRegistry, isCore, resourceLoader, rootDirs, defaultPreserveWhitespaces, i18nUseExternalIds, enableI18nLegacyMessageIdFormat, usePoisonedData, i18nNormalizeLineEndingsInICUs, moduleResolver, cycleAnalyzer, cycleHandlingStrategy, refEmitter,
|
|
30233
|
+
constructor(reflector, evaluator, metaRegistry, metaReader, scopeReader, scopeRegistry, typeCheckScopeRegistry, resourceRegistry, isCore, resourceLoader, rootDirs, defaultPreserveWhitespaces, i18nUseExternalIds, enableI18nLegacyMessageIdFormat, usePoisonedData, i18nNormalizeLineEndingsInICUs, moduleResolver, cycleAnalyzer, cycleHandlingStrategy, refEmitter, depTracker, injectableRegistry, semanticDepGraphUpdater, annotateForClosureCompiler, perf) {
|
|
29766
30234
|
this.reflector = reflector;
|
|
29767
30235
|
this.evaluator = evaluator;
|
|
29768
30236
|
this.metaRegistry = metaRegistry;
|
|
@@ -29783,11 +30251,11 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
29783
30251
|
this.cycleAnalyzer = cycleAnalyzer;
|
|
29784
30252
|
this.cycleHandlingStrategy = cycleHandlingStrategy;
|
|
29785
30253
|
this.refEmitter = refEmitter;
|
|
29786
|
-
this.defaultImportRecorder = defaultImportRecorder;
|
|
29787
30254
|
this.depTracker = depTracker;
|
|
29788
30255
|
this.injectableRegistry = injectableRegistry;
|
|
29789
30256
|
this.semanticDepGraphUpdater = semanticDepGraphUpdater;
|
|
29790
30257
|
this.annotateForClosureCompiler = annotateForClosureCompiler;
|
|
30258
|
+
this.perf = perf;
|
|
29791
30259
|
this.literalCache = new Map();
|
|
29792
30260
|
this.elementSchemaRegistry = new DomElementSchemaRegistry();
|
|
29793
30261
|
/**
|
|
@@ -29833,9 +30301,16 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
29833
30301
|
const meta = this._resolveLiteral(decorator);
|
|
29834
30302
|
const component = reflectObjectLiteral(meta);
|
|
29835
30303
|
const containingFile = node.getSourceFile().fileName;
|
|
29836
|
-
const resolveStyleUrl = (styleUrl
|
|
29837
|
-
|
|
29838
|
-
|
|
30304
|
+
const resolveStyleUrl = (styleUrl) => {
|
|
30305
|
+
try {
|
|
30306
|
+
const resourceUrl = this.resourceLoader.resolve(styleUrl, containingFile);
|
|
30307
|
+
return this.resourceLoader.preload(resourceUrl);
|
|
30308
|
+
}
|
|
30309
|
+
catch (_a) {
|
|
30310
|
+
// Don't worry about failures to preload. We can handle this problem during analysis by
|
|
30311
|
+
// producing a diagnostic.
|
|
30312
|
+
return undefined;
|
|
30313
|
+
}
|
|
29839
30314
|
};
|
|
29840
30315
|
// A Promise that waits for the template and all <link>ed styles within it to be preloaded.
|
|
29841
30316
|
const templateAndTemplateStyleResources = this._preloadAndParseTemplate(node, decorator, component, containingFile)
|
|
@@ -29843,9 +30318,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
29843
30318
|
if (template === null) {
|
|
29844
30319
|
return undefined;
|
|
29845
30320
|
}
|
|
29846
|
-
|
|
29847
|
-
return Promise
|
|
29848
|
-
.all(template.styleUrls.map(styleUrl => resolveStyleUrl(styleUrl, nodeForError, 1 /* StylesheetFromTemplate */)))
|
|
30321
|
+
return Promise.all(template.styleUrls.map(styleUrl => resolveStyleUrl(styleUrl)))
|
|
29849
30322
|
.then(() => undefined);
|
|
29850
30323
|
});
|
|
29851
30324
|
// Extract all the styleUrls in the decorator.
|
|
@@ -29860,18 +30333,21 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
29860
30333
|
return Promise
|
|
29861
30334
|
.all([
|
|
29862
30335
|
templateAndTemplateStyleResources,
|
|
29863
|
-
...componentStyleUrls.map(styleUrl => resolveStyleUrl(styleUrl.url
|
|
30336
|
+
...componentStyleUrls.map(styleUrl => resolveStyleUrl(styleUrl.url))
|
|
29864
30337
|
])
|
|
29865
30338
|
.then(() => undefined);
|
|
29866
30339
|
}
|
|
29867
30340
|
}
|
|
29868
30341
|
analyze(node, decorator, flags = HandlerFlags.NONE) {
|
|
29869
30342
|
var _a;
|
|
30343
|
+
this.perf.eventCount(PerfEvent.AnalyzeComponent);
|
|
29870
30344
|
const containingFile = node.getSourceFile().fileName;
|
|
29871
30345
|
this.literalCache.delete(decorator);
|
|
30346
|
+
let diagnostics;
|
|
30347
|
+
let isPoisoned = false;
|
|
29872
30348
|
// @Component inherits @Directive, so begin by extracting the @Directive metadata and building
|
|
29873
30349
|
// on it.
|
|
29874
|
-
const directiveResult = extractDirectiveMetadata(node, decorator, this.reflector, this.evaluator, this.
|
|
30350
|
+
const directiveResult = extractDirectiveMetadata(node, decorator, this.reflector, this.evaluator, this.isCore, flags, this.annotateForClosureCompiler, this.elementSchemaRegistry.getDefaultComponentElementName());
|
|
29875
30351
|
if (directiveResult === undefined) {
|
|
29876
30352
|
// `extractDirectiveMetadata` returns undefined when the @Directive has `jit: true`. In this
|
|
29877
30353
|
// case, compilation of the decorator is skipped. Returning an empty object signifies
|
|
@@ -29936,14 +30412,23 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
29936
30412
|
...this._extractComponentStyleUrls(component), ...this._extractTemplateStyleUrls(template)
|
|
29937
30413
|
];
|
|
29938
30414
|
for (const styleUrl of styleUrls) {
|
|
29939
|
-
|
|
29940
|
-
|
|
29941
|
-
|
|
29942
|
-
|
|
29943
|
-
|
|
29944
|
-
|
|
29945
|
-
|
|
29946
|
-
|
|
30415
|
+
try {
|
|
30416
|
+
const resourceUrl = this.resourceLoader.resolve(styleUrl.url, containingFile);
|
|
30417
|
+
const resourceStr = this.resourceLoader.load(resourceUrl);
|
|
30418
|
+
styles.push(resourceStr);
|
|
30419
|
+
if (this.depTracker !== null) {
|
|
30420
|
+
this.depTracker.addResourceDependency(node.getSourceFile(), absoluteFrom(resourceUrl));
|
|
30421
|
+
}
|
|
30422
|
+
}
|
|
30423
|
+
catch (_b) {
|
|
30424
|
+
if (diagnostics === undefined) {
|
|
30425
|
+
diagnostics = [];
|
|
30426
|
+
}
|
|
30427
|
+
const resourceType = styleUrl.source === 2 /* StylesheetFromDecorator */ ?
|
|
30428
|
+
2 /* StylesheetFromDecorator */ :
|
|
30429
|
+
1 /* StylesheetFromTemplate */;
|
|
30430
|
+
diagnostics.push(this.makeResourceNotFoundError(styleUrl.url, styleUrl.nodeForError, resourceType)
|
|
30431
|
+
.toDiagnostic());
|
|
29947
30432
|
}
|
|
29948
30433
|
}
|
|
29949
30434
|
let inlineStyles = null;
|
|
@@ -29976,7 +30461,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
29976
30461
|
// analyzed and the full compilation scope for the component can be realized.
|
|
29977
30462
|
animations, viewProviders: wrappedViewProviders, i18nUseExternalIds: this.i18nUseExternalIds, relativeContextFilePath }),
|
|
29978
30463
|
typeCheckMeta: extractDirectiveTypeCheckMeta(node, inputs, this.reflector),
|
|
29979
|
-
metadataStmt: generateSetClassMetadataCall(node, this.reflector, this.
|
|
30464
|
+
metadataStmt: generateSetClassMetadataCall(node, this.reflector, this.isCore, this.annotateForClosureCompiler),
|
|
29980
30465
|
template,
|
|
29981
30466
|
providersRequiringFactory,
|
|
29982
30467
|
viewProvidersRequiringFactory,
|
|
@@ -29986,8 +30471,9 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
29986
30471
|
styles: styleResources,
|
|
29987
30472
|
template: templateResource,
|
|
29988
30473
|
},
|
|
29989
|
-
isPoisoned
|
|
30474
|
+
isPoisoned,
|
|
29990
30475
|
},
|
|
30476
|
+
diagnostics,
|
|
29991
30477
|
};
|
|
29992
30478
|
if (changeDetection !== null) {
|
|
29993
30479
|
output.analysis.meta.changeDetection = changeDetection;
|
|
@@ -30216,12 +30702,15 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
30216
30702
|
let styles = [];
|
|
30217
30703
|
if (analysis.styleUrls !== null) {
|
|
30218
30704
|
for (const styleUrl of analysis.styleUrls) {
|
|
30219
|
-
|
|
30220
|
-
|
|
30221
|
-
|
|
30222
|
-
|
|
30223
|
-
|
|
30224
|
-
|
|
30705
|
+
try {
|
|
30706
|
+
const resolvedStyleUrl = this.resourceLoader.resolve(styleUrl.url, containingFile);
|
|
30707
|
+
const styleText = this.resourceLoader.load(resolvedStyleUrl);
|
|
30708
|
+
styles.push(styleText);
|
|
30709
|
+
}
|
|
30710
|
+
catch (e) {
|
|
30711
|
+
// Resource resolve failures should already be in the diagnostics list from the analyze
|
|
30712
|
+
// stage. We do not need to do anything with them when updating resources.
|
|
30713
|
+
}
|
|
30225
30714
|
}
|
|
30226
30715
|
}
|
|
30227
30716
|
if (analysis.inlineStyles !== null) {
|
|
@@ -30343,8 +30832,15 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
30343
30832
|
const styleUrlsExpr = component.get('styleUrls');
|
|
30344
30833
|
if (styleUrlsExpr !== undefined && ts$1.isArrayLiteralExpression(styleUrlsExpr)) {
|
|
30345
30834
|
for (const expression of stringLiteralElements(styleUrlsExpr)) {
|
|
30346
|
-
|
|
30347
|
-
|
|
30835
|
+
try {
|
|
30836
|
+
const resourceUrl = this.resourceLoader.resolve(expression.text, containingFile);
|
|
30837
|
+
styles.add({ path: absoluteFrom(resourceUrl), expression });
|
|
30838
|
+
}
|
|
30839
|
+
catch (_a) {
|
|
30840
|
+
// Errors in style resource extraction do not need to be handled here. We will produce
|
|
30841
|
+
// diagnostics for each one that fails in the analysis, after we evaluate the `styleUrls`
|
|
30842
|
+
// expression to determine _all_ style resources, not just the string literals.
|
|
30843
|
+
}
|
|
30348
30844
|
}
|
|
30349
30845
|
}
|
|
30350
30846
|
const stylesExpr = component.get('styles');
|
|
@@ -30363,20 +30859,25 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
30363
30859
|
if (typeof templateUrl !== 'string') {
|
|
30364
30860
|
throw createValueHasWrongTypeError(templateUrlExpr, templateUrl, 'templateUrl must be a string');
|
|
30365
30861
|
}
|
|
30366
|
-
|
|
30367
|
-
|
|
30368
|
-
|
|
30369
|
-
|
|
30370
|
-
|
|
30371
|
-
|
|
30372
|
-
|
|
30373
|
-
|
|
30374
|
-
|
|
30375
|
-
|
|
30376
|
-
|
|
30862
|
+
try {
|
|
30863
|
+
const resourceUrl = this.resourceLoader.resolve(templateUrl, containingFile);
|
|
30864
|
+
const templatePromise = this.resourceLoader.preload(resourceUrl);
|
|
30865
|
+
// If the preload worked, then actually load and parse the template, and wait for any style
|
|
30866
|
+
// URLs to resolve.
|
|
30867
|
+
if (templatePromise !== undefined) {
|
|
30868
|
+
return templatePromise.then(() => {
|
|
30869
|
+
const templateDecl = this.parseTemplateDeclaration(decorator, component, containingFile);
|
|
30870
|
+
const template = this.extractTemplate(node, templateDecl);
|
|
30871
|
+
this.preanalyzeTemplateCache.set(node, template);
|
|
30872
|
+
return template;
|
|
30873
|
+
});
|
|
30874
|
+
}
|
|
30875
|
+
else {
|
|
30876
|
+
return Promise.resolve(null);
|
|
30877
|
+
}
|
|
30377
30878
|
}
|
|
30378
|
-
|
|
30379
|
-
|
|
30879
|
+
catch (e) {
|
|
30880
|
+
throw this.makeResourceNotFoundError(templateUrl, templateUrlExpr, 0 /* Template */);
|
|
30380
30881
|
}
|
|
30381
30882
|
}
|
|
30382
30883
|
else {
|
|
@@ -30508,16 +31009,21 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
30508
31009
|
if (typeof templateUrl !== 'string') {
|
|
30509
31010
|
throw createValueHasWrongTypeError(templateUrlExpr, templateUrl, 'templateUrl must be a string');
|
|
30510
31011
|
}
|
|
30511
|
-
|
|
30512
|
-
|
|
30513
|
-
|
|
30514
|
-
|
|
30515
|
-
|
|
30516
|
-
|
|
30517
|
-
|
|
30518
|
-
|
|
30519
|
-
|
|
30520
|
-
|
|
31012
|
+
try {
|
|
31013
|
+
const resourceUrl = this.resourceLoader.resolve(templateUrl, containingFile);
|
|
31014
|
+
return {
|
|
31015
|
+
isInline: false,
|
|
31016
|
+
interpolationConfig,
|
|
31017
|
+
preserveWhitespaces,
|
|
31018
|
+
templateUrl,
|
|
31019
|
+
templateUrlExpression: templateUrlExpr,
|
|
31020
|
+
resolvedTemplateUrl: resourceUrl,
|
|
31021
|
+
sourceMapUrl: sourceMapUrl(resourceUrl),
|
|
31022
|
+
};
|
|
31023
|
+
}
|
|
31024
|
+
catch (e) {
|
|
31025
|
+
throw this.makeResourceNotFoundError(templateUrl, templateUrlExpr, 0 /* Template */);
|
|
31026
|
+
}
|
|
30521
31027
|
}
|
|
30522
31028
|
else if (component.has('template')) {
|
|
30523
31029
|
return {
|
|
@@ -30570,30 +31076,20 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
30570
31076
|
}
|
|
30571
31077
|
this.cycleAnalyzer.recordSyntheticImport(origin, imported);
|
|
30572
31078
|
}
|
|
30573
|
-
|
|
30574
|
-
|
|
30575
|
-
|
|
30576
|
-
|
|
30577
|
-
|
|
30578
|
-
|
|
30579
|
-
|
|
30580
|
-
|
|
30581
|
-
|
|
30582
|
-
|
|
30583
|
-
|
|
30584
|
-
|
|
30585
|
-
case 0 /* Template */:
|
|
30586
|
-
errorText = `Could not find template file '${file}'.`;
|
|
30587
|
-
break;
|
|
30588
|
-
case 1 /* StylesheetFromTemplate */:
|
|
30589
|
-
errorText = `Could not find stylesheet file '${file}' linked from the template.`;
|
|
30590
|
-
break;
|
|
30591
|
-
case 2 /* StylesheetFromDecorator */:
|
|
30592
|
-
errorText = `Could not find stylesheet file '${file}'.`;
|
|
30593
|
-
break;
|
|
30594
|
-
}
|
|
30595
|
-
throw new FatalDiagnosticError(ErrorCode.COMPONENT_RESOURCE_NOT_FOUND, nodeForError, errorText);
|
|
31079
|
+
makeResourceNotFoundError(file, nodeForError, resourceType) {
|
|
31080
|
+
let errorText;
|
|
31081
|
+
switch (resourceType) {
|
|
31082
|
+
case 0 /* Template */:
|
|
31083
|
+
errorText = `Could not find template file '${file}'.`;
|
|
31084
|
+
break;
|
|
31085
|
+
case 1 /* StylesheetFromTemplate */:
|
|
31086
|
+
errorText = `Could not find stylesheet file '${file}' linked from the template.`;
|
|
31087
|
+
break;
|
|
31088
|
+
case 2 /* StylesheetFromDecorator */:
|
|
31089
|
+
errorText = `Could not find stylesheet file '${file}'.`;
|
|
31090
|
+
break;
|
|
30596
31091
|
}
|
|
31092
|
+
return new FatalDiagnosticError(ErrorCode.COMPONENT_RESOURCE_NOT_FOUND, nodeForError, errorText);
|
|
30597
31093
|
}
|
|
30598
31094
|
_extractTemplateStyleUrls(template) {
|
|
30599
31095
|
if (template.styleUrls === null) {
|
|
@@ -30661,7 +31157,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
30661
31157
|
* Adapts the `compileIvyInjectable` compiler for `@Injectable` decorators to the Ivy compiler.
|
|
30662
31158
|
*/
|
|
30663
31159
|
class InjectableDecoratorHandler {
|
|
30664
|
-
constructor(reflector,
|
|
31160
|
+
constructor(reflector, isCore, strictCtorDeps, injectableRegistry, perf,
|
|
30665
31161
|
/**
|
|
30666
31162
|
* What to do if the injectable already contains a ɵprov property.
|
|
30667
31163
|
*
|
|
@@ -30670,10 +31166,10 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
30670
31166
|
*/
|
|
30671
31167
|
errorOnDuplicateProv = true) {
|
|
30672
31168
|
this.reflector = reflector;
|
|
30673
|
-
this.defaultImportRecorder = defaultImportRecorder;
|
|
30674
31169
|
this.isCore = isCore;
|
|
30675
31170
|
this.strictCtorDeps = strictCtorDeps;
|
|
30676
31171
|
this.injectableRegistry = injectableRegistry;
|
|
31172
|
+
this.perf = perf;
|
|
30677
31173
|
this.errorOnDuplicateProv = errorOnDuplicateProv;
|
|
30678
31174
|
this.precedence = HandlerPrecedence.SHARED;
|
|
30679
31175
|
this.name = InjectableDecoratorHandler.name;
|
|
@@ -30695,13 +31191,14 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
30695
31191
|
}
|
|
30696
31192
|
}
|
|
30697
31193
|
analyze(node, decorator) {
|
|
31194
|
+
this.perf.eventCount(PerfEvent.AnalyzeInjectable);
|
|
30698
31195
|
const meta = extractInjectableMetadata(node, decorator, this.reflector);
|
|
30699
31196
|
const decorators = this.reflector.getDecoratorsOfDeclaration(node);
|
|
30700
31197
|
return {
|
|
30701
31198
|
analysis: {
|
|
30702
31199
|
meta,
|
|
30703
|
-
ctorDeps: extractInjectableCtorDeps(node, meta, decorator, this.reflector, this.
|
|
30704
|
-
metadataStmt: generateSetClassMetadataCall(node, this.reflector, this.
|
|
31200
|
+
ctorDeps: extractInjectableCtorDeps(node, meta, decorator, this.reflector, this.isCore, this.strictCtorDeps),
|
|
31201
|
+
metadataStmt: generateSetClassMetadataCall(node, this.reflector, this.isCore),
|
|
30705
31202
|
// Avoid generating multiple factories if a class has
|
|
30706
31203
|
// more Angular decorators, apart from Injectable.
|
|
30707
31204
|
needsFactory: !decorators ||
|
|
@@ -30843,7 +31340,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
30843
31340
|
throw new FatalDiagnosticError(ErrorCode.DECORATOR_ARITY_WRONG, decorator.args[2], 'Too many arguments to @Injectable');
|
|
30844
31341
|
}
|
|
30845
31342
|
}
|
|
30846
|
-
function extractInjectableCtorDeps(clazz, meta, decorator, reflector,
|
|
31343
|
+
function extractInjectableCtorDeps(clazz, meta, decorator, reflector, isCore, strictCtorDeps) {
|
|
30847
31344
|
if (decorator.args === null) {
|
|
30848
31345
|
throw new FatalDiagnosticError(ErrorCode.DECORATOR_NOT_CALLED, Decorator.nodeForError(decorator), '@Injectable must be called');
|
|
30849
31346
|
}
|
|
@@ -30858,15 +31355,16 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
30858
31355
|
// constructor signature does not work for DI then a factory definition (ɵfac) that throws is
|
|
30859
31356
|
// generated.
|
|
30860
31357
|
if (strictCtorDeps) {
|
|
30861
|
-
ctorDeps = getValidConstructorDependencies(clazz, reflector,
|
|
31358
|
+
ctorDeps = getValidConstructorDependencies(clazz, reflector, isCore);
|
|
30862
31359
|
}
|
|
30863
31360
|
else {
|
|
30864
|
-
ctorDeps =
|
|
31361
|
+
ctorDeps =
|
|
31362
|
+
unwrapConstructorDependencies(getConstructorDependencies(clazz, reflector, isCore));
|
|
30865
31363
|
}
|
|
30866
31364
|
return ctorDeps;
|
|
30867
31365
|
}
|
|
30868
31366
|
else if (decorator.args.length === 1) {
|
|
30869
|
-
const rawCtorDeps = getConstructorDependencies(clazz, reflector,
|
|
31367
|
+
const rawCtorDeps = getConstructorDependencies(clazz, reflector, isCore);
|
|
30870
31368
|
if (strictCtorDeps && meta.useValue === undefined && meta.useExisting === undefined &&
|
|
30871
31369
|
meta.useClass === undefined && meta.useFactory === undefined) {
|
|
30872
31370
|
// Since use* was not provided, validate the deps according to strictCtorDeps.
|
|
@@ -30950,14 +31448,14 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
30950
31448
|
}
|
|
30951
31449
|
}
|
|
30952
31450
|
class PipeDecoratorHandler {
|
|
30953
|
-
constructor(reflector, evaluator, metaRegistry, scopeRegistry,
|
|
31451
|
+
constructor(reflector, evaluator, metaRegistry, scopeRegistry, injectableRegistry, isCore, perf) {
|
|
30954
31452
|
this.reflector = reflector;
|
|
30955
31453
|
this.evaluator = evaluator;
|
|
30956
31454
|
this.metaRegistry = metaRegistry;
|
|
30957
31455
|
this.scopeRegistry = scopeRegistry;
|
|
30958
|
-
this.defaultImportRecorder = defaultImportRecorder;
|
|
30959
31456
|
this.injectableRegistry = injectableRegistry;
|
|
30960
31457
|
this.isCore = isCore;
|
|
31458
|
+
this.perf = perf;
|
|
30961
31459
|
this.precedence = HandlerPrecedence.PRIMARY;
|
|
30962
31460
|
this.name = PipeDecoratorHandler.name;
|
|
30963
31461
|
}
|
|
@@ -30978,6 +31476,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
30978
31476
|
}
|
|
30979
31477
|
}
|
|
30980
31478
|
analyze(clazz, decorator) {
|
|
31479
|
+
this.perf.eventCount(PerfEvent.AnalyzePipe);
|
|
30981
31480
|
const name = clazz.name.text;
|
|
30982
31481
|
const type = wrapTypeReference(this.reflector, clazz);
|
|
30983
31482
|
const internalType = new WrappedNodeExpr(this.reflector.getInternalNameOfClass(clazz));
|
|
@@ -31017,10 +31516,10 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
31017
31516
|
internalType,
|
|
31018
31517
|
typeArgumentCount: this.reflector.getGenericArityOfClass(clazz) || 0,
|
|
31019
31518
|
pipeName,
|
|
31020
|
-
deps: getValidConstructorDependencies(clazz, this.reflector, this.
|
|
31519
|
+
deps: getValidConstructorDependencies(clazz, this.reflector, this.isCore),
|
|
31021
31520
|
pure,
|
|
31022
31521
|
},
|
|
31023
|
-
metadataStmt: generateSetClassMetadataCall(clazz, this.reflector, this.
|
|
31522
|
+
metadataStmt: generateSetClassMetadataCall(clazz, this.reflector, this.isCore),
|
|
31024
31523
|
},
|
|
31025
31524
|
};
|
|
31026
31525
|
}
|
|
@@ -31156,8 +31655,9 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
31156
31655
|
* dependencies within the same program are tracked; imports into packages on NPM are not.
|
|
31157
31656
|
*/
|
|
31158
31657
|
class ImportGraph {
|
|
31159
|
-
constructor(checker) {
|
|
31658
|
+
constructor(checker, perf) {
|
|
31160
31659
|
this.checker = checker;
|
|
31660
|
+
this.perf = perf;
|
|
31161
31661
|
this.map = new Map();
|
|
31162
31662
|
}
|
|
31163
31663
|
/**
|
|
@@ -31233,25 +31733,27 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
31233
31733
|
}
|
|
31234
31734
|
}
|
|
31235
31735
|
scanImports(sf) {
|
|
31236
|
-
|
|
31237
|
-
|
|
31238
|
-
|
|
31239
|
-
|
|
31240
|
-
stmt
|
|
31241
|
-
|
|
31242
|
-
|
|
31243
|
-
|
|
31244
|
-
|
|
31245
|
-
|
|
31246
|
-
|
|
31247
|
-
|
|
31248
|
-
|
|
31249
|
-
|
|
31250
|
-
|
|
31251
|
-
|
|
31736
|
+
return this.perf.inPhase(PerfPhase.CycleDetection, () => {
|
|
31737
|
+
const imports = new Set();
|
|
31738
|
+
// Look through the source file for import and export statements.
|
|
31739
|
+
for (const stmt of sf.statements) {
|
|
31740
|
+
if ((!ts$1.isImportDeclaration(stmt) && !ts$1.isExportDeclaration(stmt)) ||
|
|
31741
|
+
stmt.moduleSpecifier === undefined) {
|
|
31742
|
+
continue;
|
|
31743
|
+
}
|
|
31744
|
+
const symbol = this.checker.getSymbolAtLocation(stmt.moduleSpecifier);
|
|
31745
|
+
if (symbol === undefined || symbol.valueDeclaration === undefined) {
|
|
31746
|
+
// No symbol could be found to skip over this import/export.
|
|
31747
|
+
continue;
|
|
31748
|
+
}
|
|
31749
|
+
const moduleFile = symbol.valueDeclaration;
|
|
31750
|
+
if (ts$1.isSourceFile(moduleFile) && isLocalFile(moduleFile)) {
|
|
31751
|
+
// Record this local import.
|
|
31752
|
+
imports.add(moduleFile);
|
|
31753
|
+
}
|
|
31252
31754
|
}
|
|
31253
|
-
|
|
31254
|
-
|
|
31755
|
+
return imports;
|
|
31756
|
+
});
|
|
31255
31757
|
}
|
|
31256
31758
|
}
|
|
31257
31759
|
function isLocalFile(sf) {
|
|
@@ -31613,103 +32115,108 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
31613
32115
|
* The previous build's `BuildState` is reconciled with the new program's changes, and the results
|
|
31614
32116
|
* are merged into the new build's `PendingBuildState`.
|
|
31615
32117
|
*/
|
|
31616
|
-
static reconcile(oldProgram, oldDriver, newProgram, modifiedResourceFiles) {
|
|
31617
|
-
|
|
31618
|
-
|
|
31619
|
-
|
|
31620
|
-
|
|
31621
|
-
|
|
31622
|
-
|
|
31623
|
-
|
|
31624
|
-
else {
|
|
31625
|
-
let priorGraph = null;
|
|
31626
|
-
if (oldDriver.state.lastGood !== null) {
|
|
31627
|
-
priorGraph = oldDriver.state.lastGood.semanticDepGraph;
|
|
31628
|
-
}
|
|
31629
|
-
// The previous build was successfully analyzed. `pendingEmit` is the only state carried
|
|
31630
|
-
// forward into this build.
|
|
31631
|
-
state = {
|
|
31632
|
-
kind: BuildStateKind.Pending,
|
|
31633
|
-
pendingEmit: oldDriver.state.pendingEmit,
|
|
31634
|
-
pendingTypeCheckEmit: oldDriver.state.pendingTypeCheckEmit,
|
|
31635
|
-
changedResourcePaths: new Set(),
|
|
31636
|
-
changedTsPaths: new Set(),
|
|
31637
|
-
lastGood: oldDriver.state.lastGood,
|
|
31638
|
-
semanticDepGraphUpdater: new SemanticDepGraphUpdater(priorGraph),
|
|
31639
|
-
};
|
|
31640
|
-
}
|
|
31641
|
-
// Merge the freshly modified resource files with any prior ones.
|
|
31642
|
-
if (modifiedResourceFiles !== null) {
|
|
31643
|
-
for (const resFile of modifiedResourceFiles) {
|
|
31644
|
-
state.changedResourcePaths.add(absoluteFrom(resFile));
|
|
31645
|
-
}
|
|
31646
|
-
}
|
|
31647
|
-
// Next, process the files in the new program, with a couple of goals:
|
|
31648
|
-
// 1) Determine which TS files have changed, if any, and merge them into `changedTsFiles`.
|
|
31649
|
-
// 2) Produce a list of TS files which no longer exist in the program (they've been deleted
|
|
31650
|
-
// since the previous compilation). These need to be removed from the state tracking to avoid
|
|
31651
|
-
// leaking memory.
|
|
31652
|
-
// All files in the old program, for easy detection of changes.
|
|
31653
|
-
const oldFiles = new Set(oldProgram.getSourceFiles());
|
|
31654
|
-
// Assume all the old files were deleted to begin with. Only TS files are tracked.
|
|
31655
|
-
const deletedTsPaths = new Set(tsOnlyFiles(oldProgram).map(sf => sf.fileName));
|
|
31656
|
-
for (const newFile of newProgram.getSourceFiles()) {
|
|
31657
|
-
if (!newFile.isDeclarationFile) {
|
|
31658
|
-
// This file exists in the new program, so remove it from `deletedTsPaths`.
|
|
31659
|
-
deletedTsPaths.delete(newFile.fileName);
|
|
31660
|
-
}
|
|
31661
|
-
if (oldFiles.has(newFile)) {
|
|
31662
|
-
// This file hasn't changed; no need to look at it further.
|
|
31663
|
-
continue;
|
|
31664
|
-
}
|
|
31665
|
-
// The file has changed since the last successful build. The appropriate reaction depends on
|
|
31666
|
-
// what kind of file it is.
|
|
31667
|
-
if (!newFile.isDeclarationFile) {
|
|
31668
|
-
// It's a .ts file, so track it as a change.
|
|
31669
|
-
state.changedTsPaths.add(newFile.fileName);
|
|
32118
|
+
static reconcile(oldProgram, oldDriver, newProgram, modifiedResourceFiles, perf) {
|
|
32119
|
+
return perf.inPhase(PerfPhase.Reconciliation, () => {
|
|
32120
|
+
// Initialize the state of the current build based on the previous one.
|
|
32121
|
+
let state;
|
|
32122
|
+
if (oldDriver.state.kind === BuildStateKind.Pending) {
|
|
32123
|
+
// The previous build never made it past the pending state. Reuse it as the starting state
|
|
32124
|
+
// for this build.
|
|
32125
|
+
state = oldDriver.state;
|
|
31670
32126
|
}
|
|
31671
32127
|
else {
|
|
31672
|
-
|
|
31673
|
-
|
|
31674
|
-
|
|
31675
|
-
|
|
31676
|
-
|
|
31677
|
-
|
|
31678
|
-
|
|
31679
|
-
|
|
31680
|
-
|
|
31681
|
-
|
|
31682
|
-
|
|
31683
|
-
|
|
31684
|
-
|
|
31685
|
-
|
|
31686
|
-
|
|
31687
|
-
// dependency graph to determine logically changed files.
|
|
31688
|
-
const depGraph = new FileDependencyGraph();
|
|
31689
|
-
// If a previous compilation exists, use its dependency graph to determine the set of logically
|
|
31690
|
-
// changed files.
|
|
31691
|
-
let logicalChanges = null;
|
|
31692
|
-
if (state.lastGood !== null) {
|
|
31693
|
-
// Extract the set of logically changed files. At the same time, this operation populates the
|
|
31694
|
-
// current (fresh) dependency graph with information about those files which have not
|
|
31695
|
-
// logically changed.
|
|
31696
|
-
logicalChanges = depGraph.updateWithPhysicalChanges(state.lastGood.depGraph, state.changedTsPaths, deletedTsPaths, state.changedResourcePaths);
|
|
31697
|
-
for (const fileName of state.changedTsPaths) {
|
|
31698
|
-
logicalChanges.add(fileName);
|
|
31699
|
-
}
|
|
31700
|
-
// Any logically changed files need to be re-emitted. Most of the time this would happen
|
|
31701
|
-
// regardless because the new dependency graph would _also_ identify the file as stale.
|
|
31702
|
-
// However there are edge cases such as removing a component from an NgModule without adding
|
|
31703
|
-
// it to another one, where the previous graph identifies the file as logically changed, but
|
|
31704
|
-
// the new graph (which does not have that edge) fails to identify that the file should be
|
|
31705
|
-
// re-emitted.
|
|
31706
|
-
for (const change of logicalChanges) {
|
|
31707
|
-
state.pendingEmit.add(change);
|
|
31708
|
-
state.pendingTypeCheckEmit.add(change);
|
|
32128
|
+
let priorGraph = null;
|
|
32129
|
+
if (oldDriver.state.lastGood !== null) {
|
|
32130
|
+
priorGraph = oldDriver.state.lastGood.semanticDepGraph;
|
|
32131
|
+
}
|
|
32132
|
+
// The previous build was successfully analyzed. `pendingEmit` is the only state carried
|
|
32133
|
+
// forward into this build.
|
|
32134
|
+
state = {
|
|
32135
|
+
kind: BuildStateKind.Pending,
|
|
32136
|
+
pendingEmit: oldDriver.state.pendingEmit,
|
|
32137
|
+
pendingTypeCheckEmit: oldDriver.state.pendingTypeCheckEmit,
|
|
32138
|
+
changedResourcePaths: new Set(),
|
|
32139
|
+
changedTsPaths: new Set(),
|
|
32140
|
+
lastGood: oldDriver.state.lastGood,
|
|
32141
|
+
semanticDepGraphUpdater: new SemanticDepGraphUpdater(priorGraph),
|
|
32142
|
+
};
|
|
31709
32143
|
}
|
|
31710
|
-
|
|
31711
|
-
|
|
31712
|
-
|
|
32144
|
+
// Merge the freshly modified resource files with any prior ones.
|
|
32145
|
+
if (modifiedResourceFiles !== null) {
|
|
32146
|
+
for (const resFile of modifiedResourceFiles) {
|
|
32147
|
+
state.changedResourcePaths.add(absoluteFrom(resFile));
|
|
32148
|
+
}
|
|
32149
|
+
}
|
|
32150
|
+
// Next, process the files in the new program, with a couple of goals:
|
|
32151
|
+
// 1) Determine which TS files have changed, if any, and merge them into `changedTsFiles`.
|
|
32152
|
+
// 2) Produce a list of TS files which no longer exist in the program (they've been deleted
|
|
32153
|
+
// since the previous compilation). These need to be removed from the state tracking to
|
|
32154
|
+
// avoid leaking memory.
|
|
32155
|
+
// All files in the old program, for easy detection of changes.
|
|
32156
|
+
const oldFiles = new Set(oldProgram.getSourceFiles().map(toUnredirectedSourceFile));
|
|
32157
|
+
// Assume all the old files were deleted to begin with. Only TS files are tracked.
|
|
32158
|
+
const deletedTsPaths = new Set(tsOnlyFiles(oldProgram).map(sf => sf.fileName));
|
|
32159
|
+
for (const possiblyRedirectedNewFile of newProgram.getSourceFiles()) {
|
|
32160
|
+
const newFile = toUnredirectedSourceFile(possiblyRedirectedNewFile);
|
|
32161
|
+
if (!newFile.isDeclarationFile) {
|
|
32162
|
+
// This file exists in the new program, so remove it from `deletedTsPaths`.
|
|
32163
|
+
deletedTsPaths.delete(newFile.fileName);
|
|
32164
|
+
}
|
|
32165
|
+
if (oldFiles.has(newFile)) {
|
|
32166
|
+
// This file hasn't changed; no need to look at it further.
|
|
32167
|
+
continue;
|
|
32168
|
+
}
|
|
32169
|
+
// The file has changed since the last successful build. The appropriate reaction depends on
|
|
32170
|
+
// what kind of file it is.
|
|
32171
|
+
if (!newFile.isDeclarationFile) {
|
|
32172
|
+
// It's a .ts file, so track it as a change.
|
|
32173
|
+
state.changedTsPaths.add(newFile.fileName);
|
|
32174
|
+
}
|
|
32175
|
+
else {
|
|
32176
|
+
// It's a .d.ts file. Currently the compiler does not do a great job of tracking
|
|
32177
|
+
// dependencies on .d.ts files, so bail out of incremental builds here and do a full
|
|
32178
|
+
// build. This usually only happens if something in node_modules changes.
|
|
32179
|
+
return IncrementalDriver.fresh(newProgram);
|
|
32180
|
+
}
|
|
32181
|
+
}
|
|
32182
|
+
// The next step is to remove any deleted files from the state.
|
|
32183
|
+
for (const filePath of deletedTsPaths) {
|
|
32184
|
+
state.pendingEmit.delete(filePath);
|
|
32185
|
+
state.pendingTypeCheckEmit.delete(filePath);
|
|
32186
|
+
// Even if the file doesn't exist in the current compilation, it still might have been
|
|
32187
|
+
// changed in a previous one, so delete it from the set of changed TS files, just in case.
|
|
32188
|
+
state.changedTsPaths.delete(filePath);
|
|
32189
|
+
}
|
|
32190
|
+
perf.eventCount(PerfEvent.SourceFilePhysicalChange, state.changedTsPaths.size);
|
|
32191
|
+
// Now, changedTsPaths contains physically changed TS paths. Use the previous program's
|
|
32192
|
+
// logical dependency graph to determine logically changed files.
|
|
32193
|
+
const depGraph = new FileDependencyGraph();
|
|
32194
|
+
// If a previous compilation exists, use its dependency graph to determine the set of
|
|
32195
|
+
// logically changed files.
|
|
32196
|
+
let logicalChanges = null;
|
|
32197
|
+
if (state.lastGood !== null) {
|
|
32198
|
+
// Extract the set of logically changed files. At the same time, this operation populates
|
|
32199
|
+
// the current (fresh) dependency graph with information about those files which have not
|
|
32200
|
+
// logically changed.
|
|
32201
|
+
logicalChanges = depGraph.updateWithPhysicalChanges(state.lastGood.depGraph, state.changedTsPaths, deletedTsPaths, state.changedResourcePaths);
|
|
32202
|
+
perf.eventCount(PerfEvent.SourceFileLogicalChange, logicalChanges.size);
|
|
32203
|
+
for (const fileName of state.changedTsPaths) {
|
|
32204
|
+
logicalChanges.add(fileName);
|
|
32205
|
+
}
|
|
32206
|
+
// Any logically changed files need to be re-emitted. Most of the time this would happen
|
|
32207
|
+
// regardless because the new dependency graph would _also_ identify the file as stale.
|
|
32208
|
+
// However there are edge cases such as removing a component from an NgModule without adding
|
|
32209
|
+
// it to another one, where the previous graph identifies the file as logically changed, but
|
|
32210
|
+
// the new graph (which does not have that edge) fails to identify that the file should be
|
|
32211
|
+
// re-emitted.
|
|
32212
|
+
for (const change of logicalChanges) {
|
|
32213
|
+
state.pendingEmit.add(change);
|
|
32214
|
+
state.pendingTypeCheckEmit.add(change);
|
|
32215
|
+
}
|
|
32216
|
+
}
|
|
32217
|
+
// `state` now reflects the initial pending state of the current compilation.
|
|
32218
|
+
return new IncrementalDriver(state, depGraph, logicalChanges);
|
|
32219
|
+
});
|
|
31713
32220
|
}
|
|
31714
32221
|
static fresh(program) {
|
|
31715
32222
|
// Initialize the set of files which need to be emitted to the set of all TS files in the
|
|
@@ -32394,29 +32901,6 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
32394
32901
|
node.modifiers.some(mod => mod.kind === ts$1.SyntaxKind.StaticKeyword);
|
|
32395
32902
|
}
|
|
32396
32903
|
|
|
32397
|
-
const NOOP_PERF_RECORDER = {
|
|
32398
|
-
enabled: false,
|
|
32399
|
-
mark: (name, node, category, detail) => { },
|
|
32400
|
-
start: (name, node, category, detail) => {
|
|
32401
|
-
return 0;
|
|
32402
|
-
},
|
|
32403
|
-
stop: (span) => { },
|
|
32404
|
-
};
|
|
32405
|
-
|
|
32406
|
-
/**
|
|
32407
|
-
* @license
|
|
32408
|
-
* Copyright Google LLC All Rights Reserved.
|
|
32409
|
-
*
|
|
32410
|
-
* Use of this source code is governed by an MIT-style license that can be
|
|
32411
|
-
* found in the LICENSE file at https://angular.io/license
|
|
32412
|
-
*/
|
|
32413
|
-
var PerfLogEventType;
|
|
32414
|
-
(function (PerfLogEventType) {
|
|
32415
|
-
PerfLogEventType[PerfLogEventType["SPAN_OPEN"] = 0] = "SPAN_OPEN";
|
|
32416
|
-
PerfLogEventType[PerfLogEventType["SPAN_CLOSE"] = 1] = "SPAN_CLOSE";
|
|
32417
|
-
PerfLogEventType[PerfLogEventType["MARK"] = 2] = "MARK";
|
|
32418
|
-
})(PerfLogEventType || (PerfLogEventType = {}));
|
|
32419
|
-
|
|
32420
32904
|
/**
|
|
32421
32905
|
* @license
|
|
32422
32906
|
* Copyright Google LLC All Rights Reserved.
|
|
@@ -32454,7 +32938,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
32454
32938
|
resolve(url, fromFile) {
|
|
32455
32939
|
let resolvedUrl = null;
|
|
32456
32940
|
if (this.adapter.resourceNameToFileName) {
|
|
32457
|
-
resolvedUrl = this.adapter.resourceNameToFileName(url, fromFile);
|
|
32941
|
+
resolvedUrl = this.adapter.resourceNameToFileName(url, fromFile, (url, fromFile) => this.fallbackResolve(url, fromFile));
|
|
32458
32942
|
}
|
|
32459
32943
|
else {
|
|
32460
32944
|
resolvedUrl = this.fallbackResolve(url, fromFile);
|
|
@@ -34242,56 +34726,63 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
34242
34726
|
this.data = data;
|
|
34243
34727
|
this.shimPath = shimPath;
|
|
34244
34728
|
/**
|
|
34245
|
-
* Cache of
|
|
34246
|
-
*
|
|
34729
|
+
* Cache of completions for various levels of the template, including the root template (`null`).
|
|
34730
|
+
* Memoizes `getTemplateContextCompletions`.
|
|
34247
34731
|
*/
|
|
34248
|
-
this.
|
|
34732
|
+
this.templateContextCache = new Map();
|
|
34249
34733
|
this.expressionCompletionCache = new Map();
|
|
34250
|
-
}
|
|
34251
|
-
/**
|
|
34252
|
-
* Get global completions within the given template context - either a `TmplAstTemplate` embedded
|
|
34253
|
-
* view, or `null` for the root template context.
|
|
34254
|
-
*/
|
|
34255
|
-
getGlobalCompletions(context) {
|
|
34256
|
-
if (this.globalCompletionCache.has(context)) {
|
|
34257
|
-
return this.globalCompletionCache.get(context);
|
|
34258
|
-
}
|
|
34259
34734
|
// Find the component completion expression within the TCB. This looks like: `ctx. /* ... */;`
|
|
34260
34735
|
const globalRead = findFirstMatchingNode(this.tcb, {
|
|
34261
34736
|
filter: ts$1.isPropertyAccessExpression,
|
|
34262
34737
|
withExpressionIdentifier: ExpressionIdentifier.COMPONENT_COMPLETION
|
|
34263
34738
|
});
|
|
34264
|
-
if (globalRead
|
|
34265
|
-
|
|
34266
|
-
}
|
|
34267
|
-
const completion = {
|
|
34268
|
-
componentContext: {
|
|
34739
|
+
if (globalRead !== null) {
|
|
34740
|
+
this.componentContext = {
|
|
34269
34741
|
shimPath: this.shimPath,
|
|
34270
34742
|
// `globalRead.name` is an empty `ts.Identifier`, so its start position immediately follows
|
|
34271
34743
|
// the `.` in `ctx.`. TS autocompletion APIs can then be used to access completion results
|
|
34272
34744
|
// for the component context.
|
|
34273
34745
|
positionInShimFile: globalRead.name.getStart(),
|
|
34274
|
-
}
|
|
34275
|
-
|
|
34276
|
-
|
|
34277
|
-
|
|
34278
|
-
|
|
34279
|
-
|
|
34280
|
-
|
|
34281
|
-
|
|
34282
|
-
|
|
34283
|
-
|
|
34284
|
-
|
|
34285
|
-
|
|
34286
|
-
|
|
34287
|
-
|
|
34288
|
-
|
|
34289
|
-
|
|
34290
|
-
|
|
34746
|
+
};
|
|
34747
|
+
}
|
|
34748
|
+
else {
|
|
34749
|
+
this.componentContext = null;
|
|
34750
|
+
}
|
|
34751
|
+
}
|
|
34752
|
+
/**
|
|
34753
|
+
* Get global completions within the given template context and AST node.
|
|
34754
|
+
*
|
|
34755
|
+
* @param context the given template context - either a `TmplAstTemplate` embedded view, or `null`
|
|
34756
|
+
* for the root
|
|
34757
|
+
* template context.
|
|
34758
|
+
* @param node the given AST node
|
|
34759
|
+
*/
|
|
34760
|
+
getGlobalCompletions(context, node) {
|
|
34761
|
+
if (this.componentContext === null) {
|
|
34762
|
+
return null;
|
|
34763
|
+
}
|
|
34764
|
+
const templateContext = this.getTemplateContextCompletions(context);
|
|
34765
|
+
if (templateContext === null) {
|
|
34766
|
+
return null;
|
|
34767
|
+
}
|
|
34768
|
+
let nodeContext = null;
|
|
34769
|
+
if (node instanceof EmptyExpr) {
|
|
34770
|
+
const nodeLocation = findFirstMatchingNode(this.tcb, {
|
|
34771
|
+
filter: ts$1.isIdentifier,
|
|
34772
|
+
withSpan: node.sourceSpan,
|
|
34773
|
+
});
|
|
34774
|
+
if (nodeLocation !== null) {
|
|
34775
|
+
nodeContext = {
|
|
34776
|
+
shimPath: this.shimPath,
|
|
34777
|
+
positionInShimFile: nodeLocation.getStart(),
|
|
34778
|
+
};
|
|
34291
34779
|
}
|
|
34292
34780
|
}
|
|
34293
|
-
|
|
34294
|
-
|
|
34781
|
+
return {
|
|
34782
|
+
componentContext: this.componentContext,
|
|
34783
|
+
templateContext,
|
|
34784
|
+
nodeContext,
|
|
34785
|
+
};
|
|
34295
34786
|
}
|
|
34296
34787
|
getExpressionCompletionLocation(expr) {
|
|
34297
34788
|
if (this.expressionCompletionCache.has(expr)) {
|
|
@@ -34336,6 +34827,34 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
34336
34827
|
this.expressionCompletionCache.set(expr, res);
|
|
34337
34828
|
return res;
|
|
34338
34829
|
}
|
|
34830
|
+
/**
|
|
34831
|
+
* Get global completions within the given template context - either a `TmplAstTemplate` embedded
|
|
34832
|
+
* view, or `null` for the root context.
|
|
34833
|
+
*/
|
|
34834
|
+
getTemplateContextCompletions(context) {
|
|
34835
|
+
if (this.templateContextCache.has(context)) {
|
|
34836
|
+
return this.templateContextCache.get(context);
|
|
34837
|
+
}
|
|
34838
|
+
const templateContext = new Map();
|
|
34839
|
+
// The bound template already has details about the references and variables in scope in the
|
|
34840
|
+
// `context` template - they just need to be converted to `Completion`s.
|
|
34841
|
+
for (const node of this.data.boundTarget.getEntitiesInTemplateScope(context)) {
|
|
34842
|
+
if (node instanceof Reference) {
|
|
34843
|
+
templateContext.set(node.name, {
|
|
34844
|
+
kind: CompletionKind.Reference,
|
|
34845
|
+
node,
|
|
34846
|
+
});
|
|
34847
|
+
}
|
|
34848
|
+
else {
|
|
34849
|
+
templateContext.set(node.name, {
|
|
34850
|
+
kind: CompletionKind.Variable,
|
|
34851
|
+
node,
|
|
34852
|
+
});
|
|
34853
|
+
}
|
|
34854
|
+
}
|
|
34855
|
+
this.templateContextCache.set(context, templateContext);
|
|
34856
|
+
return templateContext;
|
|
34857
|
+
}
|
|
34339
34858
|
}
|
|
34340
34859
|
|
|
34341
34860
|
/**
|
|
@@ -34665,12 +35184,6 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
34665
35184
|
}
|
|
34666
35185
|
return false;
|
|
34667
35186
|
}
|
|
34668
|
-
function checkIfGenericTypesAreUnbound(node) {
|
|
34669
|
-
if (node.typeParameters === undefined) {
|
|
34670
|
-
return true;
|
|
34671
|
-
}
|
|
34672
|
-
return node.typeParameters.every(param => param.constraint === undefined);
|
|
34673
|
-
}
|
|
34674
35187
|
function isAccessExpression(node) {
|
|
34675
35188
|
return ts$1.isPropertyAccessExpression(node) || ts$1.isElementAccessExpression(node);
|
|
34676
35189
|
}
|
|
@@ -34890,6 +35403,136 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
34890
35403
|
}
|
|
34891
35404
|
}
|
|
34892
35405
|
|
|
35406
|
+
/**
|
|
35407
|
+
* @license
|
|
35408
|
+
* Copyright Google LLC All Rights Reserved.
|
|
35409
|
+
*
|
|
35410
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
35411
|
+
* found in the LICENSE file at https://angular.io/license
|
|
35412
|
+
*/
|
|
35413
|
+
/**
|
|
35414
|
+
* Indicates whether a particular component requires an inline type check block.
|
|
35415
|
+
*
|
|
35416
|
+
* This is not a boolean state as inlining might only be required to get the best possible
|
|
35417
|
+
* type-checking, but the component could theoretically still be checked without it.
|
|
35418
|
+
*/
|
|
35419
|
+
var TcbInliningRequirement;
|
|
35420
|
+
(function (TcbInliningRequirement) {
|
|
35421
|
+
/**
|
|
35422
|
+
* There is no way to type check this component without inlining.
|
|
35423
|
+
*/
|
|
35424
|
+
TcbInliningRequirement[TcbInliningRequirement["MustInline"] = 0] = "MustInline";
|
|
35425
|
+
/**
|
|
35426
|
+
* Inlining should be used due to the component's generic bounds, but a non-inlining fallback
|
|
35427
|
+
* method can be used if that's not possible.
|
|
35428
|
+
*/
|
|
35429
|
+
TcbInliningRequirement[TcbInliningRequirement["ShouldInlineForGenericBounds"] = 1] = "ShouldInlineForGenericBounds";
|
|
35430
|
+
/**
|
|
35431
|
+
* There is no requirement for this component's TCB to be inlined.
|
|
35432
|
+
*/
|
|
35433
|
+
TcbInliningRequirement[TcbInliningRequirement["None"] = 2] = "None";
|
|
35434
|
+
})(TcbInliningRequirement || (TcbInliningRequirement = {}));
|
|
35435
|
+
function requiresInlineTypeCheckBlock(node, usedPipes, reflector) {
|
|
35436
|
+
// In order to qualify for a declared TCB (not inline) two conditions must be met:
|
|
35437
|
+
// 1) the class must be exported
|
|
35438
|
+
// 2) it must not have contextual generic type bounds
|
|
35439
|
+
if (!checkIfClassIsExported(node)) {
|
|
35440
|
+
// Condition 1 is false, the class is not exported.
|
|
35441
|
+
return TcbInliningRequirement.MustInline;
|
|
35442
|
+
}
|
|
35443
|
+
else if (!checkIfGenericTypeBoundsAreContextFree(node, reflector)) {
|
|
35444
|
+
// Condition 2 is false, the class has constrained generic types. It should be checked with an
|
|
35445
|
+
// inline TCB if possible, but can potentially use fallbacks to avoid inlining if not.
|
|
35446
|
+
return TcbInliningRequirement.ShouldInlineForGenericBounds;
|
|
35447
|
+
}
|
|
35448
|
+
else if (Array.from(usedPipes.values())
|
|
35449
|
+
.some(pipeRef => !checkIfClassIsExported(pipeRef.node))) {
|
|
35450
|
+
// If one of the pipes used by the component is not exported, a non-inline TCB will not be able
|
|
35451
|
+
// to import it, so this requires an inline TCB.
|
|
35452
|
+
return TcbInliningRequirement.MustInline;
|
|
35453
|
+
}
|
|
35454
|
+
else {
|
|
35455
|
+
return TcbInliningRequirement.None;
|
|
35456
|
+
}
|
|
35457
|
+
}
|
|
35458
|
+
/** Maps a shim position back to a template location. */
|
|
35459
|
+
function getTemplateMapping(shimSf, position, resolver, isDiagnosticRequest) {
|
|
35460
|
+
const node = getTokenAtPosition(shimSf, position);
|
|
35461
|
+
const sourceLocation = findSourceLocation(node, shimSf, isDiagnosticRequest);
|
|
35462
|
+
if (sourceLocation === null) {
|
|
35463
|
+
return null;
|
|
35464
|
+
}
|
|
35465
|
+
const mapping = resolver.getSourceMapping(sourceLocation.id);
|
|
35466
|
+
const span = resolver.toParseSourceSpan(sourceLocation.id, sourceLocation.span);
|
|
35467
|
+
if (span === null) {
|
|
35468
|
+
return null;
|
|
35469
|
+
}
|
|
35470
|
+
// TODO(atscott): Consider adding a context span by walking up from `node` until we get a
|
|
35471
|
+
// different span.
|
|
35472
|
+
return { sourceLocation, templateSourceMapping: mapping, span };
|
|
35473
|
+
}
|
|
35474
|
+
function findTypeCheckBlock(file, id, isDiagnosticRequest) {
|
|
35475
|
+
for (const stmt of file.statements) {
|
|
35476
|
+
if (ts$1.isFunctionDeclaration(stmt) && getTemplateId$1(stmt, file, isDiagnosticRequest) === id) {
|
|
35477
|
+
return stmt;
|
|
35478
|
+
}
|
|
35479
|
+
}
|
|
35480
|
+
return null;
|
|
35481
|
+
}
|
|
35482
|
+
/**
|
|
35483
|
+
* Traverses up the AST starting from the given node to extract the source location from comments
|
|
35484
|
+
* that have been emitted into the TCB. If the node does not exist within a TCB, or if an ignore
|
|
35485
|
+
* marker comment is found up the tree (and this is part of a diagnostic request), this function
|
|
35486
|
+
* returns null.
|
|
35487
|
+
*/
|
|
35488
|
+
function findSourceLocation(node, sourceFile, isDiagnosticsRequest) {
|
|
35489
|
+
// Search for comments until the TCB's function declaration is encountered.
|
|
35490
|
+
while (node !== undefined && !ts$1.isFunctionDeclaration(node)) {
|
|
35491
|
+
if (hasIgnoreForDiagnosticsMarker(node, sourceFile) && isDiagnosticsRequest) {
|
|
35492
|
+
// There's an ignore marker on this node, so the diagnostic should not be reported.
|
|
35493
|
+
return null;
|
|
35494
|
+
}
|
|
35495
|
+
const span = readSpanComment(node, sourceFile);
|
|
35496
|
+
if (span !== null) {
|
|
35497
|
+
// Once the positional information has been extracted, search further up the TCB to extract
|
|
35498
|
+
// the unique id that is attached with the TCB's function declaration.
|
|
35499
|
+
const id = getTemplateId$1(node, sourceFile, isDiagnosticsRequest);
|
|
35500
|
+
if (id === null) {
|
|
35501
|
+
return null;
|
|
35502
|
+
}
|
|
35503
|
+
return { id, span };
|
|
35504
|
+
}
|
|
35505
|
+
node = node.parent;
|
|
35506
|
+
}
|
|
35507
|
+
return null;
|
|
35508
|
+
}
|
|
35509
|
+
function getTemplateId$1(node, sourceFile, isDiagnosticRequest) {
|
|
35510
|
+
// Walk up to the function declaration of the TCB, the file information is attached there.
|
|
35511
|
+
while (!ts$1.isFunctionDeclaration(node)) {
|
|
35512
|
+
if (hasIgnoreForDiagnosticsMarker(node, sourceFile) && isDiagnosticRequest) {
|
|
35513
|
+
// There's an ignore marker on this node, so the diagnostic should not be reported.
|
|
35514
|
+
return null;
|
|
35515
|
+
}
|
|
35516
|
+
node = node.parent;
|
|
35517
|
+
// Bail once we have reached the root.
|
|
35518
|
+
if (node === undefined) {
|
|
35519
|
+
return null;
|
|
35520
|
+
}
|
|
35521
|
+
}
|
|
35522
|
+
const start = node.getFullStart();
|
|
35523
|
+
return ts$1.forEachLeadingCommentRange(sourceFile.text, start, (pos, end, kind) => {
|
|
35524
|
+
if (kind !== ts$1.SyntaxKind.MultiLineCommentTrivia) {
|
|
35525
|
+
return null;
|
|
35526
|
+
}
|
|
35527
|
+
const commentText = sourceFile.text.substring(pos + 2, end - 2);
|
|
35528
|
+
return commentText;
|
|
35529
|
+
}) || null;
|
|
35530
|
+
}
|
|
35531
|
+
function checkIfGenericTypeBoundsAreContextFree(node, reflector) {
|
|
35532
|
+
// Generic type parameters are considered context free if they can be emitted into any context.
|
|
35533
|
+
return new TypeParameterEmitter(node.typeParameters, reflector).canEmit();
|
|
35534
|
+
}
|
|
35535
|
+
|
|
34893
35536
|
/**
|
|
34894
35537
|
* @license
|
|
34895
35538
|
* Copyright Google LLC All Rights Reserved.
|
|
@@ -35054,10 +35697,6 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
35054
35697
|
// emitted into a different context.
|
|
35055
35698
|
return !checkIfGenericTypeBoundsAreContextFree(node, host);
|
|
35056
35699
|
}
|
|
35057
|
-
function checkIfGenericTypeBoundsAreContextFree(node, reflector) {
|
|
35058
|
-
// Generic type parameters are considered context free if they can be emitted into any context.
|
|
35059
|
-
return new TypeParameterEmitter(node.typeParameters, reflector).canEmit();
|
|
35060
|
-
}
|
|
35061
35700
|
/**
|
|
35062
35701
|
* Add a default `= any` to type parameters that don't have a default value already.
|
|
35063
35702
|
*
|
|
@@ -35366,109 +36005,6 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
35366
36005
|
return Object.assign(Object.assign({}, makeDiagnostic(code, node, messageText, relatedInformation)), { componentFile: node.getSourceFile(), templateId });
|
|
35367
36006
|
}
|
|
35368
36007
|
|
|
35369
|
-
/**
|
|
35370
|
-
* @license
|
|
35371
|
-
* Copyright Google LLC All Rights Reserved.
|
|
35372
|
-
*
|
|
35373
|
-
* Use of this source code is governed by an MIT-style license that can be
|
|
35374
|
-
* found in the LICENSE file at https://angular.io/license
|
|
35375
|
-
*/
|
|
35376
|
-
function requiresInlineTypeCheckBlock(node, usedPipes) {
|
|
35377
|
-
// In order to qualify for a declared TCB (not inline) two conditions must be met:
|
|
35378
|
-
// 1) the class must be exported
|
|
35379
|
-
// 2) it must not have constrained generic types
|
|
35380
|
-
if (!checkIfClassIsExported(node)) {
|
|
35381
|
-
// Condition 1 is false, the class is not exported.
|
|
35382
|
-
return true;
|
|
35383
|
-
}
|
|
35384
|
-
else if (!checkIfGenericTypesAreUnbound(node)) {
|
|
35385
|
-
// Condition 2 is false, the class has constrained generic types
|
|
35386
|
-
return true;
|
|
35387
|
-
}
|
|
35388
|
-
else if (Array.from(usedPipes.values())
|
|
35389
|
-
.some(pipeRef => !checkIfClassIsExported(pipeRef.node))) {
|
|
35390
|
-
// If one of the pipes used by the component is not exported, a non-inline TCB will not be able
|
|
35391
|
-
// to import it, so this requires an inline TCB.
|
|
35392
|
-
return true;
|
|
35393
|
-
}
|
|
35394
|
-
else {
|
|
35395
|
-
return false;
|
|
35396
|
-
}
|
|
35397
|
-
}
|
|
35398
|
-
/** Maps a shim position back to a template location. */
|
|
35399
|
-
function getTemplateMapping(shimSf, position, resolver, isDiagnosticRequest) {
|
|
35400
|
-
const node = getTokenAtPosition(shimSf, position);
|
|
35401
|
-
const sourceLocation = findSourceLocation(node, shimSf, isDiagnosticRequest);
|
|
35402
|
-
if (sourceLocation === null) {
|
|
35403
|
-
return null;
|
|
35404
|
-
}
|
|
35405
|
-
const mapping = resolver.getSourceMapping(sourceLocation.id);
|
|
35406
|
-
const span = resolver.toParseSourceSpan(sourceLocation.id, sourceLocation.span);
|
|
35407
|
-
if (span === null) {
|
|
35408
|
-
return null;
|
|
35409
|
-
}
|
|
35410
|
-
// TODO(atscott): Consider adding a context span by walking up from `node` until we get a
|
|
35411
|
-
// different span.
|
|
35412
|
-
return { sourceLocation, templateSourceMapping: mapping, span };
|
|
35413
|
-
}
|
|
35414
|
-
function findTypeCheckBlock(file, id, isDiagnosticRequest) {
|
|
35415
|
-
for (const stmt of file.statements) {
|
|
35416
|
-
if (ts$1.isFunctionDeclaration(stmt) && getTemplateId$1(stmt, file, isDiagnosticRequest) === id) {
|
|
35417
|
-
return stmt;
|
|
35418
|
-
}
|
|
35419
|
-
}
|
|
35420
|
-
return null;
|
|
35421
|
-
}
|
|
35422
|
-
/**
|
|
35423
|
-
* Traverses up the AST starting from the given node to extract the source location from comments
|
|
35424
|
-
* that have been emitted into the TCB. If the node does not exist within a TCB, or if an ignore
|
|
35425
|
-
* marker comment is found up the tree (and this is part of a diagnostic request), this function
|
|
35426
|
-
* returns null.
|
|
35427
|
-
*/
|
|
35428
|
-
function findSourceLocation(node, sourceFile, isDiagnosticsRequest) {
|
|
35429
|
-
// Search for comments until the TCB's function declaration is encountered.
|
|
35430
|
-
while (node !== undefined && !ts$1.isFunctionDeclaration(node)) {
|
|
35431
|
-
if (hasIgnoreForDiagnosticsMarker(node, sourceFile) && isDiagnosticsRequest) {
|
|
35432
|
-
// There's an ignore marker on this node, so the diagnostic should not be reported.
|
|
35433
|
-
return null;
|
|
35434
|
-
}
|
|
35435
|
-
const span = readSpanComment(node, sourceFile);
|
|
35436
|
-
if (span !== null) {
|
|
35437
|
-
// Once the positional information has been extracted, search further up the TCB to extract
|
|
35438
|
-
// the unique id that is attached with the TCB's function declaration.
|
|
35439
|
-
const id = getTemplateId$1(node, sourceFile, isDiagnosticsRequest);
|
|
35440
|
-
if (id === null) {
|
|
35441
|
-
return null;
|
|
35442
|
-
}
|
|
35443
|
-
return { id, span };
|
|
35444
|
-
}
|
|
35445
|
-
node = node.parent;
|
|
35446
|
-
}
|
|
35447
|
-
return null;
|
|
35448
|
-
}
|
|
35449
|
-
function getTemplateId$1(node, sourceFile, isDiagnosticRequest) {
|
|
35450
|
-
// Walk up to the function declaration of the TCB, the file information is attached there.
|
|
35451
|
-
while (!ts$1.isFunctionDeclaration(node)) {
|
|
35452
|
-
if (hasIgnoreForDiagnosticsMarker(node, sourceFile) && isDiagnosticRequest) {
|
|
35453
|
-
// There's an ignore marker on this node, so the diagnostic should not be reported.
|
|
35454
|
-
return null;
|
|
35455
|
-
}
|
|
35456
|
-
node = node.parent;
|
|
35457
|
-
// Bail once we have reached the root.
|
|
35458
|
-
if (node === undefined) {
|
|
35459
|
-
return null;
|
|
35460
|
-
}
|
|
35461
|
-
}
|
|
35462
|
-
const start = node.getFullStart();
|
|
35463
|
-
return ts$1.forEachLeadingCommentRange(sourceFile.text, start, (pos, end, kind) => {
|
|
35464
|
-
if (kind !== ts$1.SyntaxKind.MultiLineCommentTrivia) {
|
|
35465
|
-
return null;
|
|
35466
|
-
}
|
|
35467
|
-
const commentText = sourceFile.text.substring(pos + 2, end - 2);
|
|
35468
|
-
return commentText;
|
|
35469
|
-
}) || null;
|
|
35470
|
-
}
|
|
35471
|
-
|
|
35472
36008
|
/**
|
|
35473
36009
|
* @license
|
|
35474
36010
|
* Copyright Google LLC All Rights Reserved.
|
|
@@ -35613,7 +36149,9 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
35613
36149
|
}
|
|
35614
36150
|
// The `EmptyExpr` doesn't have a dedicated method on `AstVisitor`, so it's special cased here.
|
|
35615
36151
|
if (ast instanceof EmptyExpr) {
|
|
35616
|
-
|
|
36152
|
+
const res = ts$1.factory.createIdentifier('undefined');
|
|
36153
|
+
addParseSpanInfo(res, ast.sourceSpan);
|
|
36154
|
+
return res;
|
|
35617
36155
|
}
|
|
35618
36156
|
// First attempt to let any custom resolution logic provide a translation for the given node.
|
|
35619
36157
|
const resolved = this.maybeResolve(ast);
|
|
@@ -35977,6 +36515,32 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
35977
36515
|
* Use of this source code is governed by an MIT-style license that can be
|
|
35978
36516
|
* found in the LICENSE file at https://angular.io/license
|
|
35979
36517
|
*/
|
|
36518
|
+
/**
|
|
36519
|
+
* Controls how generics for the component context class will be handled during TCB generation.
|
|
36520
|
+
*/
|
|
36521
|
+
var TcbGenericContextBehavior;
|
|
36522
|
+
(function (TcbGenericContextBehavior) {
|
|
36523
|
+
/**
|
|
36524
|
+
* References to generic parameter bounds will be emitted via the `TypeParameterEmitter`.
|
|
36525
|
+
*
|
|
36526
|
+
* The caller must verify that all parameter bounds are emittable in order to use this mode.
|
|
36527
|
+
*/
|
|
36528
|
+
TcbGenericContextBehavior[TcbGenericContextBehavior["UseEmitter"] = 0] = "UseEmitter";
|
|
36529
|
+
/**
|
|
36530
|
+
* Generic parameter declarations will be copied directly from the `ts.ClassDeclaration` of the
|
|
36531
|
+
* component class.
|
|
36532
|
+
*
|
|
36533
|
+
* The caller must only use the generated TCB code in a context where such copies will still be
|
|
36534
|
+
* valid, such as an inline type check block.
|
|
36535
|
+
*/
|
|
36536
|
+
TcbGenericContextBehavior[TcbGenericContextBehavior["CopyClassNodes"] = 1] = "CopyClassNodes";
|
|
36537
|
+
/**
|
|
36538
|
+
* Any generic parameters for the component context class will be set to `any`.
|
|
36539
|
+
*
|
|
36540
|
+
* Produces a less useful type, but is always safe to use.
|
|
36541
|
+
*/
|
|
36542
|
+
TcbGenericContextBehavior[TcbGenericContextBehavior["FallbackToAny"] = 2] = "FallbackToAny";
|
|
36543
|
+
})(TcbGenericContextBehavior || (TcbGenericContextBehavior = {}));
|
|
35980
36544
|
/**
|
|
35981
36545
|
* Given a `ts.ClassDeclaration` for a component, and metadata regarding that component, compose a
|
|
35982
36546
|
* "type check block" function.
|
|
@@ -35998,15 +36562,39 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
35998
36562
|
* and bindings.
|
|
35999
36563
|
* @param oobRecorder used to record errors regarding template elements which could not be correctly
|
|
36000
36564
|
* translated into types during TCB generation.
|
|
36565
|
+
* @param genericContextBehavior controls how generic parameters (especially parameters with generic
|
|
36566
|
+
* bounds) will be referenced from the generated TCB code.
|
|
36001
36567
|
*/
|
|
36002
|
-
function generateTypeCheckBlock(env, ref, name, meta, domSchemaChecker, oobRecorder) {
|
|
36568
|
+
function generateTypeCheckBlock(env, ref, name, meta, domSchemaChecker, oobRecorder, genericContextBehavior) {
|
|
36003
36569
|
const tcb = new Context$1(env, domSchemaChecker, oobRecorder, meta.id, meta.boundTarget, meta.pipes, meta.schemas);
|
|
36004
36570
|
const scope = Scope$1.forNodes(tcb, null, tcb.boundTarget.target.template, /* guard */ null);
|
|
36005
36571
|
const ctxRawType = env.referenceType(ref);
|
|
36006
36572
|
if (!ts$1.isTypeReferenceNode(ctxRawType)) {
|
|
36007
36573
|
throw new Error(`Expected TypeReferenceNode when referencing the ctx param for ${ref.debugName}`);
|
|
36008
36574
|
}
|
|
36009
|
-
|
|
36575
|
+
let typeParameters = undefined;
|
|
36576
|
+
let typeArguments = undefined;
|
|
36577
|
+
if (ref.node.typeParameters !== undefined) {
|
|
36578
|
+
if (!env.config.useContextGenericType) {
|
|
36579
|
+
genericContextBehavior = TcbGenericContextBehavior.FallbackToAny;
|
|
36580
|
+
}
|
|
36581
|
+
switch (genericContextBehavior) {
|
|
36582
|
+
case TcbGenericContextBehavior.UseEmitter:
|
|
36583
|
+
// Guaranteed to emit type parameters since we checked that the class has them above.
|
|
36584
|
+
typeParameters = new TypeParameterEmitter(ref.node.typeParameters, env.reflector)
|
|
36585
|
+
.emit(typeRef => env.referenceType(typeRef));
|
|
36586
|
+
typeArguments = typeParameters.map(param => ts$1.factory.createTypeReferenceNode(param.name));
|
|
36587
|
+
break;
|
|
36588
|
+
case TcbGenericContextBehavior.CopyClassNodes:
|
|
36589
|
+
typeParameters = [...ref.node.typeParameters];
|
|
36590
|
+
typeArguments = typeParameters.map(param => ts$1.factory.createTypeReferenceNode(param.name));
|
|
36591
|
+
break;
|
|
36592
|
+
case TcbGenericContextBehavior.FallbackToAny:
|
|
36593
|
+
typeArguments = ref.node.typeParameters.map(() => ts$1.factory.createKeywordTypeNode(ts$1.SyntaxKind.AnyKeyword));
|
|
36594
|
+
break;
|
|
36595
|
+
}
|
|
36596
|
+
}
|
|
36597
|
+
const paramList = [tcbCtxParam(ref.node, ctxRawType.typeName, typeArguments)];
|
|
36010
36598
|
const scopeStatements = scope.render();
|
|
36011
36599
|
const innerBody = ts$1.createBlock([
|
|
36012
36600
|
...env.getPreludeStatements(),
|
|
@@ -36020,7 +36608,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
36020
36608
|
/* modifiers */ undefined,
|
|
36021
36609
|
/* asteriskToken */ undefined,
|
|
36022
36610
|
/* name */ name,
|
|
36023
|
-
/* typeParameters */ env.config.useContextGenericType ?
|
|
36611
|
+
/* typeParameters */ env.config.useContextGenericType ? typeParameters : undefined,
|
|
36024
36612
|
/* parameters */ paramList,
|
|
36025
36613
|
/* type */ undefined,
|
|
36026
36614
|
/* body */ body);
|
|
@@ -37389,26 +37977,11 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
37389
37977
|
}
|
|
37390
37978
|
}
|
|
37391
37979
|
/**
|
|
37392
|
-
* Create the `ctx` parameter to the top-level TCB function.
|
|
37393
|
-
*
|
|
37394
|
-
* This is a parameter with a type equivalent to the component type, with all generic type
|
|
37395
|
-
* parameters listed (without their generic bounds).
|
|
37980
|
+
* Create the `ctx` parameter to the top-level TCB function, with the given generic type arguments.
|
|
37396
37981
|
*/
|
|
37397
|
-
function tcbCtxParam(node, name,
|
|
37398
|
-
|
|
37399
|
-
|
|
37400
|
-
if (node.typeParameters !== undefined) {
|
|
37401
|
-
if (useGenericType) {
|
|
37402
|
-
typeArguments =
|
|
37403
|
-
node.typeParameters.map(param => ts$1.createTypeReferenceNode(param.name, undefined));
|
|
37404
|
-
}
|
|
37405
|
-
else {
|
|
37406
|
-
typeArguments =
|
|
37407
|
-
node.typeParameters.map(() => ts$1.createKeywordTypeNode(ts$1.SyntaxKind.AnyKeyword));
|
|
37408
|
-
}
|
|
37409
|
-
}
|
|
37410
|
-
const type = ts$1.createTypeReferenceNode(name, typeArguments);
|
|
37411
|
-
return ts$1.createParameter(
|
|
37982
|
+
function tcbCtxParam(node, name, typeArguments) {
|
|
37983
|
+
const type = ts$1.factory.createTypeReferenceNode(name, typeArguments);
|
|
37984
|
+
return ts$1.factory.createParameterDeclaration(
|
|
37412
37985
|
/* decorators */ undefined,
|
|
37413
37986
|
/* modifiers */ undefined,
|
|
37414
37987
|
/* dotDotDotToken */ undefined,
|
|
@@ -37719,9 +38292,9 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
37719
38292
|
this.nextTcbId = 1;
|
|
37720
38293
|
this.tcbStatements = [];
|
|
37721
38294
|
}
|
|
37722
|
-
addTypeCheckBlock(ref, meta, domSchemaChecker, oobRecorder) {
|
|
38295
|
+
addTypeCheckBlock(ref, meta, domSchemaChecker, oobRecorder, genericContextBehavior) {
|
|
37723
38296
|
const fnId = ts$1.createIdentifier(`_tcb${this.nextTcbId++}`);
|
|
37724
|
-
const fn = generateTypeCheckBlock(this, ref, fnId, meta, domSchemaChecker, oobRecorder);
|
|
38297
|
+
const fn = generateTypeCheckBlock(this, ref, fnId, meta, domSchemaChecker, oobRecorder, genericContextBehavior);
|
|
37725
38298
|
this.tcbStatements.push(fn);
|
|
37726
38299
|
}
|
|
37727
38300
|
render(removeComments) {
|
|
@@ -37780,7 +38353,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
37780
38353
|
* type checked.
|
|
37781
38354
|
*/
|
|
37782
38355
|
class TypeCheckContextImpl {
|
|
37783
|
-
constructor(config, compilerHost, componentMappingStrategy, refEmitter, reflector, host, inlining) {
|
|
38356
|
+
constructor(config, compilerHost, componentMappingStrategy, refEmitter, reflector, host, inlining, perf) {
|
|
37784
38357
|
this.config = config;
|
|
37785
38358
|
this.compilerHost = compilerHost;
|
|
37786
38359
|
this.componentMappingStrategy = componentMappingStrategy;
|
|
@@ -37788,6 +38361,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
37788
38361
|
this.reflector = reflector;
|
|
37789
38362
|
this.host = host;
|
|
37790
38363
|
this.inlining = inlining;
|
|
38364
|
+
this.perf = perf;
|
|
37791
38365
|
this.fileMap = new Map();
|
|
37792
38366
|
/**
|
|
37793
38367
|
* A `Map` of `ts.SourceFile`s that the context has seen to the operations (additions of methods
|
|
@@ -37852,15 +38426,17 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
37852
38426
|
boundTarget,
|
|
37853
38427
|
templateDiagnostics,
|
|
37854
38428
|
});
|
|
37855
|
-
const
|
|
38429
|
+
const inliningRequirement = requiresInlineTypeCheckBlock(ref.node, pipes, this.reflector);
|
|
37856
38430
|
// If inlining is not supported, but is required for either the TCB or one of its directive
|
|
37857
38431
|
// dependencies, then exit here with an error.
|
|
37858
|
-
if (this.inlining === InliningMode.Error &&
|
|
38432
|
+
if (this.inlining === InliningMode.Error &&
|
|
38433
|
+
inliningRequirement === TcbInliningRequirement.MustInline) {
|
|
37859
38434
|
// This template cannot be supported because the underlying strategy does not support inlining
|
|
37860
38435
|
// and inlining would be required.
|
|
37861
38436
|
// Record diagnostics to indicate the issues with this template.
|
|
37862
38437
|
shimData.oobRecorder.requiresInlineTcb(templateId, ref.node);
|
|
37863
38438
|
// Checking this template would be unsupported, so don't try.
|
|
38439
|
+
this.perf.eventCount(PerfEvent.SkipGenerateTcbNoInline);
|
|
37864
38440
|
return;
|
|
37865
38441
|
}
|
|
37866
38442
|
const meta = {
|
|
@@ -37869,14 +38445,24 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
37869
38445
|
pipes,
|
|
37870
38446
|
schemas,
|
|
37871
38447
|
};
|
|
37872
|
-
|
|
38448
|
+
this.perf.eventCount(PerfEvent.GenerateTcb);
|
|
38449
|
+
if (inliningRequirement !== TcbInliningRequirement.None &&
|
|
38450
|
+
this.inlining === InliningMode.InlineOps) {
|
|
37873
38451
|
// This class didn't meet the requirements for external type checking, so generate an inline
|
|
37874
38452
|
// TCB for the class.
|
|
37875
38453
|
this.addInlineTypeCheckBlock(fileData, shimData, ref, meta);
|
|
37876
38454
|
}
|
|
38455
|
+
else if (inliningRequirement === TcbInliningRequirement.ShouldInlineForGenericBounds &&
|
|
38456
|
+
this.inlining === InliningMode.Error) {
|
|
38457
|
+
// It's suggested that this TCB should be generated inline due to the component's generic
|
|
38458
|
+
// bounds, but inlining is not supported by the current environment. Use a non-inline type
|
|
38459
|
+
// check block, but fall back to `any` generic parameters since the generic bounds can't be
|
|
38460
|
+
// referenced in that context. This will infer a less useful type for the component, but allow
|
|
38461
|
+
// for type-checking it in an environment where that would not be possible otherwise.
|
|
38462
|
+
shimData.file.addTypeCheckBlock(ref, meta, shimData.domSchemaChecker, shimData.oobRecorder, TcbGenericContextBehavior.FallbackToAny);
|
|
38463
|
+
}
|
|
37877
38464
|
else {
|
|
37878
|
-
|
|
37879
|
-
shimData.file.addTypeCheckBlock(ref, meta, shimData.domSchemaChecker, shimData.oobRecorder);
|
|
38465
|
+
shimData.file.addTypeCheckBlock(ref, meta, shimData.domSchemaChecker, shimData.oobRecorder, TcbGenericContextBehavior.UseEmitter);
|
|
37880
38466
|
}
|
|
37881
38467
|
}
|
|
37882
38468
|
/**
|
|
@@ -37966,7 +38552,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
37966
38552
|
this.opMap.set(sf, []);
|
|
37967
38553
|
}
|
|
37968
38554
|
const ops = this.opMap.get(sf);
|
|
37969
|
-
ops.push(new
|
|
38555
|
+
ops.push(new InlineTcbOp(ref, tcbMeta, this.config, this.reflector, shimData.domSchemaChecker, shimData.oobRecorder));
|
|
37970
38556
|
fileData.hasInlines = true;
|
|
37971
38557
|
}
|
|
37972
38558
|
pendingShimForComponent(node) {
|
|
@@ -38009,9 +38595,9 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
38009
38595
|
}
|
|
38010
38596
|
}
|
|
38011
38597
|
/**
|
|
38012
|
-
* A type check block operation which produces type check code for a particular component.
|
|
38598
|
+
* A type check block operation which produces inline type check code for a particular component.
|
|
38013
38599
|
*/
|
|
38014
|
-
class
|
|
38600
|
+
class InlineTcbOp {
|
|
38015
38601
|
constructor(ref, meta, config, reflector, domSchemaChecker, oobRecorder) {
|
|
38016
38602
|
this.ref = ref;
|
|
38017
38603
|
this.meta = meta;
|
|
@@ -38029,7 +38615,9 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
38029
38615
|
execute(im, sf, refEmitter, printer) {
|
|
38030
38616
|
const env = new Environment(this.config, im, refEmitter, this.reflector, sf);
|
|
38031
38617
|
const fnName = ts$1.createIdentifier(`_tcb_${this.ref.node.pos}`);
|
|
38032
|
-
|
|
38618
|
+
// Inline TCBs should copy any generic type parameter nodes directly, as the TCB code is inlined
|
|
38619
|
+
// into the class in a context where that will always be legal.
|
|
38620
|
+
const fn = generateTypeCheckBlock(env, this.ref, fnName, this.meta, this.domSchemaChecker, this.oobRecorder, TcbGenericContextBehavior.CopyClassNodes);
|
|
38033
38621
|
return printer.printNode(ts$1.EmitHint.Unspecified, fn, sf);
|
|
38034
38622
|
}
|
|
38035
38623
|
}
|
|
@@ -38685,7 +39273,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
38685
39273
|
* `ProgramTypeCheckAdapter` for generation of template type-checking code.
|
|
38686
39274
|
*/
|
|
38687
39275
|
class TemplateTypeCheckerImpl {
|
|
38688
|
-
constructor(originalProgram, typeCheckingStrategy, typeCheckAdapter, config, refEmitter, reflector, compilerHost, priorBuild, componentScopeReader, typeCheckScopeRegistry) {
|
|
39276
|
+
constructor(originalProgram, typeCheckingStrategy, typeCheckAdapter, config, refEmitter, reflector, compilerHost, priorBuild, componentScopeReader, typeCheckScopeRegistry, perf) {
|
|
38689
39277
|
this.originalProgram = originalProgram;
|
|
38690
39278
|
this.typeCheckingStrategy = typeCheckingStrategy;
|
|
38691
39279
|
this.typeCheckAdapter = typeCheckAdapter;
|
|
@@ -38696,6 +39284,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
38696
39284
|
this.priorBuild = priorBuild;
|
|
38697
39285
|
this.componentScopeReader = componentScopeReader;
|
|
38698
39286
|
this.typeCheckScopeRegistry = typeCheckScopeRegistry;
|
|
39287
|
+
this.perf = perf;
|
|
38699
39288
|
this.state = new Map();
|
|
38700
39289
|
/**
|
|
38701
39290
|
* Stores the `CompletionEngine` which powers autocompletion for each component class.
|
|
@@ -38807,65 +39396,69 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
38807
39396
|
this.ensureAllShimsForOneFile(sf);
|
|
38808
39397
|
break;
|
|
38809
39398
|
}
|
|
38810
|
-
|
|
38811
|
-
|
|
38812
|
-
|
|
38813
|
-
|
|
38814
|
-
|
|
38815
|
-
|
|
38816
|
-
|
|
38817
|
-
|
|
38818
|
-
|
|
39399
|
+
return this.perf.inPhase(PerfPhase.TtcDiagnostics, () => {
|
|
39400
|
+
const sfPath = absoluteFromSourceFile(sf);
|
|
39401
|
+
const fileRecord = this.state.get(sfPath);
|
|
39402
|
+
const typeCheckProgram = this.typeCheckingStrategy.getProgram();
|
|
39403
|
+
const diagnostics = [];
|
|
39404
|
+
if (fileRecord.hasInlines) {
|
|
39405
|
+
const inlineSf = getSourceFileOrError(typeCheckProgram, sfPath);
|
|
39406
|
+
diagnostics.push(...typeCheckProgram.getSemanticDiagnostics(inlineSf).map(diag => convertDiagnostic(diag, fileRecord.sourceManager)));
|
|
39407
|
+
}
|
|
39408
|
+
for (const [shimPath, shimRecord] of fileRecord.shimData) {
|
|
39409
|
+
const shimSf = getSourceFileOrError(typeCheckProgram, shimPath);
|
|
39410
|
+
diagnostics.push(...typeCheckProgram.getSemanticDiagnostics(shimSf).map(diag => convertDiagnostic(diag, fileRecord.sourceManager)));
|
|
39411
|
+
diagnostics.push(...shimRecord.genesisDiagnostics);
|
|
39412
|
+
for (const templateData of shimRecord.templates.values()) {
|
|
39413
|
+
diagnostics.push(...templateData.templateDiagnostics);
|
|
39414
|
+
}
|
|
39415
|
+
}
|
|
39416
|
+
return diagnostics.filter((diag) => diag !== null);
|
|
39417
|
+
});
|
|
39418
|
+
}
|
|
39419
|
+
getDiagnosticsForComponent(component) {
|
|
39420
|
+
this.ensureShimForComponent(component);
|
|
39421
|
+
return this.perf.inPhase(PerfPhase.TtcDiagnostics, () => {
|
|
39422
|
+
const sf = component.getSourceFile();
|
|
39423
|
+
const sfPath = absoluteFromSourceFile(sf);
|
|
39424
|
+
const shimPath = this.typeCheckingStrategy.shimPathForComponent(component);
|
|
39425
|
+
const fileRecord = this.getFileData(sfPath);
|
|
39426
|
+
if (!fileRecord.shimData.has(shimPath)) {
|
|
39427
|
+
return [];
|
|
39428
|
+
}
|
|
39429
|
+
const templateId = fileRecord.sourceManager.getTemplateId(component);
|
|
39430
|
+
const shimRecord = fileRecord.shimData.get(shimPath);
|
|
39431
|
+
const typeCheckProgram = this.typeCheckingStrategy.getProgram();
|
|
39432
|
+
const diagnostics = [];
|
|
39433
|
+
if (shimRecord.hasInlines) {
|
|
39434
|
+
const inlineSf = getSourceFileOrError(typeCheckProgram, sfPath);
|
|
39435
|
+
diagnostics.push(...typeCheckProgram.getSemanticDiagnostics(inlineSf).map(diag => convertDiagnostic(diag, fileRecord.sourceManager)));
|
|
39436
|
+
}
|
|
38819
39437
|
const shimSf = getSourceFileOrError(typeCheckProgram, shimPath);
|
|
38820
39438
|
diagnostics.push(...typeCheckProgram.getSemanticDiagnostics(shimSf).map(diag => convertDiagnostic(diag, fileRecord.sourceManager)));
|
|
38821
39439
|
diagnostics.push(...shimRecord.genesisDiagnostics);
|
|
38822
39440
|
for (const templateData of shimRecord.templates.values()) {
|
|
38823
39441
|
diagnostics.push(...templateData.templateDiagnostics);
|
|
38824
39442
|
}
|
|
38825
|
-
|
|
38826
|
-
|
|
38827
|
-
}
|
|
38828
|
-
getDiagnosticsForComponent(component) {
|
|
38829
|
-
this.ensureShimForComponent(component);
|
|
38830
|
-
const sf = component.getSourceFile();
|
|
38831
|
-
const sfPath = absoluteFromSourceFile(sf);
|
|
38832
|
-
const shimPath = this.typeCheckingStrategy.shimPathForComponent(component);
|
|
38833
|
-
const fileRecord = this.getFileData(sfPath);
|
|
38834
|
-
if (!fileRecord.shimData.has(shimPath)) {
|
|
38835
|
-
return [];
|
|
38836
|
-
}
|
|
38837
|
-
const templateId = fileRecord.sourceManager.getTemplateId(component);
|
|
38838
|
-
const shimRecord = fileRecord.shimData.get(shimPath);
|
|
38839
|
-
const typeCheckProgram = this.typeCheckingStrategy.getProgram();
|
|
38840
|
-
const diagnostics = [];
|
|
38841
|
-
if (shimRecord.hasInlines) {
|
|
38842
|
-
const inlineSf = getSourceFileOrError(typeCheckProgram, sfPath);
|
|
38843
|
-
diagnostics.push(...typeCheckProgram.getSemanticDiagnostics(inlineSf).map(diag => convertDiagnostic(diag, fileRecord.sourceManager)));
|
|
38844
|
-
}
|
|
38845
|
-
const shimSf = getSourceFileOrError(typeCheckProgram, shimPath);
|
|
38846
|
-
diagnostics.push(...typeCheckProgram.getSemanticDiagnostics(shimSf).map(diag => convertDiagnostic(diag, fileRecord.sourceManager)));
|
|
38847
|
-
diagnostics.push(...shimRecord.genesisDiagnostics);
|
|
38848
|
-
for (const templateData of shimRecord.templates.values()) {
|
|
38849
|
-
diagnostics.push(...templateData.templateDiagnostics);
|
|
38850
|
-
}
|
|
38851
|
-
return diagnostics.filter((diag) => diag !== null && diag.templateId === templateId);
|
|
39443
|
+
return diagnostics.filter((diag) => diag !== null && diag.templateId === templateId);
|
|
39444
|
+
});
|
|
38852
39445
|
}
|
|
38853
39446
|
getTypeCheckBlock(component) {
|
|
38854
39447
|
return this.getLatestComponentState(component).tcb;
|
|
38855
39448
|
}
|
|
38856
|
-
getGlobalCompletions(context, component) {
|
|
39449
|
+
getGlobalCompletions(context, component, node) {
|
|
38857
39450
|
const engine = this.getOrCreateCompletionEngine(component);
|
|
38858
39451
|
if (engine === null) {
|
|
38859
39452
|
return null;
|
|
38860
39453
|
}
|
|
38861
|
-
return engine.getGlobalCompletions(context);
|
|
39454
|
+
return this.perf.inPhase(PerfPhase.TtcAutocompletion, () => engine.getGlobalCompletions(context, node));
|
|
38862
39455
|
}
|
|
38863
39456
|
getExpressionCompletionLocation(ast, component) {
|
|
38864
39457
|
const engine = this.getOrCreateCompletionEngine(component);
|
|
38865
39458
|
if (engine === null) {
|
|
38866
39459
|
return null;
|
|
38867
39460
|
}
|
|
38868
|
-
return engine.getExpressionCompletionLocation(ast);
|
|
39461
|
+
return this.perf.inPhase(PerfPhase.TtcAutocompletion, () => engine.getExpressionCompletionLocation(ast));
|
|
38869
39462
|
}
|
|
38870
39463
|
invalidateClass(clazz) {
|
|
38871
39464
|
this.completionCache.delete(clazz);
|
|
@@ -38906,43 +39499,48 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
38906
39499
|
if (previousResults === null || !previousResults.isComplete) {
|
|
38907
39500
|
return;
|
|
38908
39501
|
}
|
|
39502
|
+
this.perf.eventCount(PerfEvent.ReuseTypeCheckFile);
|
|
38909
39503
|
this.state.set(sfPath, previousResults);
|
|
38910
39504
|
}
|
|
38911
39505
|
ensureAllShimsForAllFiles() {
|
|
38912
39506
|
if (this.isComplete) {
|
|
38913
39507
|
return;
|
|
38914
39508
|
}
|
|
38915
|
-
|
|
38916
|
-
|
|
38917
|
-
|
|
38918
|
-
|
|
38919
|
-
|
|
39509
|
+
this.perf.inPhase(PerfPhase.TcbGeneration, () => {
|
|
39510
|
+
const host = new WholeProgramTypeCheckingHost(this);
|
|
39511
|
+
const ctx = this.newContext(host);
|
|
39512
|
+
for (const sf of this.originalProgram.getSourceFiles()) {
|
|
39513
|
+
if (sf.isDeclarationFile || isShim(sf)) {
|
|
39514
|
+
continue;
|
|
39515
|
+
}
|
|
39516
|
+
this.maybeAdoptPriorResultsForFile(sf);
|
|
39517
|
+
const sfPath = absoluteFromSourceFile(sf);
|
|
39518
|
+
const fileData = this.getFileData(sfPath);
|
|
39519
|
+
if (fileData.isComplete) {
|
|
39520
|
+
continue;
|
|
39521
|
+
}
|
|
39522
|
+
this.typeCheckAdapter.typeCheck(sf, ctx);
|
|
39523
|
+
fileData.isComplete = true;
|
|
38920
39524
|
}
|
|
39525
|
+
this.updateFromContext(ctx);
|
|
39526
|
+
this.isComplete = true;
|
|
39527
|
+
});
|
|
39528
|
+
}
|
|
39529
|
+
ensureAllShimsForOneFile(sf) {
|
|
39530
|
+
this.perf.inPhase(PerfPhase.TcbGeneration, () => {
|
|
38921
39531
|
this.maybeAdoptPriorResultsForFile(sf);
|
|
38922
39532
|
const sfPath = absoluteFromSourceFile(sf);
|
|
38923
39533
|
const fileData = this.getFileData(sfPath);
|
|
38924
39534
|
if (fileData.isComplete) {
|
|
38925
|
-
|
|
39535
|
+
// All data for this file is present and accounted for already.
|
|
39536
|
+
return;
|
|
38926
39537
|
}
|
|
39538
|
+
const host = new SingleFileTypeCheckingHost(sfPath, fileData, this.typeCheckingStrategy, this);
|
|
39539
|
+
const ctx = this.newContext(host);
|
|
38927
39540
|
this.typeCheckAdapter.typeCheck(sf, ctx);
|
|
38928
39541
|
fileData.isComplete = true;
|
|
38929
|
-
|
|
38930
|
-
|
|
38931
|
-
this.isComplete = true;
|
|
38932
|
-
}
|
|
38933
|
-
ensureAllShimsForOneFile(sf) {
|
|
38934
|
-
this.maybeAdoptPriorResultsForFile(sf);
|
|
38935
|
-
const sfPath = absoluteFromSourceFile(sf);
|
|
38936
|
-
const fileData = this.getFileData(sfPath);
|
|
38937
|
-
if (fileData.isComplete) {
|
|
38938
|
-
// All data for this file is present and accounted for already.
|
|
38939
|
-
return;
|
|
38940
|
-
}
|
|
38941
|
-
const host = new SingleFileTypeCheckingHost(sfPath, fileData, this.typeCheckingStrategy, this);
|
|
38942
|
-
const ctx = this.newContext(host);
|
|
38943
|
-
this.typeCheckAdapter.typeCheck(sf, ctx);
|
|
38944
|
-
fileData.isComplete = true;
|
|
38945
|
-
this.updateFromContext(ctx);
|
|
39542
|
+
this.updateFromContext(ctx);
|
|
39543
|
+
});
|
|
38946
39544
|
}
|
|
38947
39545
|
ensureShimForComponent(component) {
|
|
38948
39546
|
const sf = component.getSourceFile();
|
|
@@ -38962,7 +39560,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
38962
39560
|
newContext(host) {
|
|
38963
39561
|
const inlining = this.typeCheckingStrategy.supportsInlineOperations ? InliningMode.InlineOps :
|
|
38964
39562
|
InliningMode.Error;
|
|
38965
|
-
return new TypeCheckContextImpl(this.config, this.compilerHost, this.typeCheckingStrategy, this.refEmitter, this.reflector, host, inlining);
|
|
39563
|
+
return new TypeCheckContextImpl(this.config, this.compilerHost, this.typeCheckingStrategy, this.refEmitter, this.reflector, host, inlining, this.perf);
|
|
38966
39564
|
}
|
|
38967
39565
|
/**
|
|
38968
39566
|
* Remove any shim data that depends on inline operations applied to the type-checking program.
|
|
@@ -38987,8 +39585,14 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
38987
39585
|
}
|
|
38988
39586
|
updateFromContext(ctx) {
|
|
38989
39587
|
const updates = ctx.finalize();
|
|
38990
|
-
this.
|
|
38991
|
-
|
|
39588
|
+
return this.perf.inPhase(PerfPhase.TcbUpdateProgram, () => {
|
|
39589
|
+
if (updates.size > 0) {
|
|
39590
|
+
this.perf.eventCount(PerfEvent.UpdateTypeCheckProgram);
|
|
39591
|
+
}
|
|
39592
|
+
this.typeCheckingStrategy.updateFiles(updates, UpdateMode.Incremental);
|
|
39593
|
+
this.priorBuild.recordSuccessfulTypeCheck(this.state);
|
|
39594
|
+
this.perf.memory(PerfCheckpoint.TtcUpdateProgram);
|
|
39595
|
+
});
|
|
38992
39596
|
}
|
|
38993
39597
|
getFileData(path) {
|
|
38994
39598
|
if (!this.state.has(path)) {
|
|
@@ -39006,7 +39610,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
39006
39610
|
if (builder === null) {
|
|
39007
39611
|
return null;
|
|
39008
39612
|
}
|
|
39009
|
-
return builder.getSymbol(node);
|
|
39613
|
+
return this.perf.inPhase(PerfPhase.TtcSymbol, () => builder.getSymbol(node));
|
|
39010
39614
|
}
|
|
39011
39615
|
getOrCreateSymbolBuilder(component) {
|
|
39012
39616
|
if (this.symbolBuilderCache.has(component)) {
|
|
@@ -39265,7 +39869,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
39265
39869
|
/**
|
|
39266
39870
|
* Create a `CompilationTicket` for a brand new compilation, using no prior state.
|
|
39267
39871
|
*/
|
|
39268
|
-
function freshCompilationTicket(tsProgram, options, incrementalBuildStrategy, typeCheckingProgramStrategy, enableTemplateTypeChecker, usePoisonedData) {
|
|
39872
|
+
function freshCompilationTicket(tsProgram, options, incrementalBuildStrategy, typeCheckingProgramStrategy, perfRecorder, enableTemplateTypeChecker, usePoisonedData) {
|
|
39269
39873
|
return {
|
|
39270
39874
|
kind: CompilationTicketKind.Fresh,
|
|
39271
39875
|
tsProgram,
|
|
@@ -39274,21 +39878,25 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
39274
39878
|
typeCheckingProgramStrategy,
|
|
39275
39879
|
enableTemplateTypeChecker,
|
|
39276
39880
|
usePoisonedData,
|
|
39881
|
+
perfRecorder: perfRecorder !== null && perfRecorder !== void 0 ? perfRecorder : ActivePerfRecorder.zeroedToNow(),
|
|
39277
39882
|
};
|
|
39278
39883
|
}
|
|
39279
39884
|
/**
|
|
39280
39885
|
* Create a `CompilationTicket` as efficiently as possible, based on a previous `NgCompiler`
|
|
39281
39886
|
* instance and a new `ts.Program`.
|
|
39282
39887
|
*/
|
|
39283
|
-
function incrementalFromCompilerTicket(oldCompiler, newProgram, incrementalBuildStrategy, typeCheckingProgramStrategy, modifiedResourceFiles) {
|
|
39888
|
+
function incrementalFromCompilerTicket(oldCompiler, newProgram, incrementalBuildStrategy, typeCheckingProgramStrategy, modifiedResourceFiles, perfRecorder) {
|
|
39284
39889
|
const oldProgram = oldCompiler.getNextProgram();
|
|
39285
39890
|
const oldDriver = oldCompiler.incrementalStrategy.getIncrementalDriver(oldProgram);
|
|
39286
39891
|
if (oldDriver === null) {
|
|
39287
39892
|
// No incremental step is possible here, since no IncrementalDriver was found for the old
|
|
39288
39893
|
// program.
|
|
39289
|
-
return freshCompilationTicket(newProgram, oldCompiler.options, incrementalBuildStrategy, typeCheckingProgramStrategy, oldCompiler.enableTemplateTypeChecker, oldCompiler.usePoisonedData);
|
|
39894
|
+
return freshCompilationTicket(newProgram, oldCompiler.options, incrementalBuildStrategy, typeCheckingProgramStrategy, perfRecorder, oldCompiler.enableTemplateTypeChecker, oldCompiler.usePoisonedData);
|
|
39895
|
+
}
|
|
39896
|
+
if (perfRecorder === null) {
|
|
39897
|
+
perfRecorder = ActivePerfRecorder.zeroedToNow();
|
|
39290
39898
|
}
|
|
39291
|
-
const newDriver = IncrementalDriver.reconcile(oldProgram, oldDriver, newProgram, modifiedResourceFiles);
|
|
39899
|
+
const newDriver = IncrementalDriver.reconcile(oldProgram, oldDriver, newProgram, modifiedResourceFiles, perfRecorder);
|
|
39292
39900
|
return {
|
|
39293
39901
|
kind: CompilationTicketKind.IncrementalTypeScript,
|
|
39294
39902
|
enableTemplateTypeChecker: oldCompiler.enableTemplateTypeChecker,
|
|
@@ -39299,6 +39907,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
39299
39907
|
newDriver,
|
|
39300
39908
|
oldProgram,
|
|
39301
39909
|
newProgram,
|
|
39910
|
+
perfRecorder,
|
|
39302
39911
|
};
|
|
39303
39912
|
}
|
|
39304
39913
|
function resourceChangeTicket(compiler, modifiedResourceFiles) {
|
|
@@ -39306,6 +39915,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
39306
39915
|
kind: CompilationTicketKind.IncrementalResource,
|
|
39307
39916
|
compiler,
|
|
39308
39917
|
modifiedResourceFiles,
|
|
39918
|
+
perfRecorder: ActivePerfRecorder.zeroedToNow(),
|
|
39309
39919
|
};
|
|
39310
39920
|
}
|
|
39311
39921
|
/**
|
|
@@ -39321,7 +39931,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
39321
39931
|
* See the README.md for more information.
|
|
39322
39932
|
*/
|
|
39323
39933
|
class NgCompiler {
|
|
39324
|
-
constructor(adapter, options, tsProgram, typeCheckingProgramStrategy, incrementalStrategy, incrementalDriver, enableTemplateTypeChecker, usePoisonedData,
|
|
39934
|
+
constructor(adapter, options, tsProgram, typeCheckingProgramStrategy, incrementalStrategy, incrementalDriver, enableTemplateTypeChecker, usePoisonedData, livePerfRecorder) {
|
|
39325
39935
|
this.adapter = adapter;
|
|
39326
39936
|
this.options = options;
|
|
39327
39937
|
this.tsProgram = tsProgram;
|
|
@@ -39330,7 +39940,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
39330
39940
|
this.incrementalDriver = incrementalDriver;
|
|
39331
39941
|
this.enableTemplateTypeChecker = enableTemplateTypeChecker;
|
|
39332
39942
|
this.usePoisonedData = usePoisonedData;
|
|
39333
|
-
this.
|
|
39943
|
+
this.livePerfRecorder = livePerfRecorder;
|
|
39334
39944
|
/**
|
|
39335
39945
|
* Lazily evaluated state of the compilation.
|
|
39336
39946
|
*
|
|
@@ -39350,6 +39960,13 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
39350
39960
|
* This is set by (and memoizes) `getNonTemplateDiagnostics`.
|
|
39351
39961
|
*/
|
|
39352
39962
|
this.nonTemplateDiagnostics = null;
|
|
39963
|
+
/**
|
|
39964
|
+
* `NgCompiler` can be reused for multiple compilations (for resource-only changes), and each
|
|
39965
|
+
* new compilation uses a fresh `PerfRecorder`. Thus, classes created with a lifespan of the
|
|
39966
|
+
* `NgCompiler` use a `DelegatingPerfRecorder` so the `PerfRecorder` they write to can be updated
|
|
39967
|
+
* with each fresh compilation.
|
|
39968
|
+
*/
|
|
39969
|
+
this.delegatingPerfRecorder = new DelegatingPerfRecorder(this.perfRecorder);
|
|
39353
39970
|
this.constructionDiagnostics.push(...this.adapter.constructionDiagnostics);
|
|
39354
39971
|
const incompatibleTypeCheckOptionsDiagnostic = verifyCompatibleTypeCheckOptions(this.options);
|
|
39355
39972
|
if (incompatibleTypeCheckOptionsDiagnostic !== null) {
|
|
@@ -39360,9 +39977,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
39360
39977
|
this.entryPoint =
|
|
39361
39978
|
adapter.entryPoint !== null ? getSourceFileOrNull(tsProgram, adapter.entryPoint) : null;
|
|
39362
39979
|
const moduleResolutionCache = ts$1.createModuleResolutionCache(this.adapter.getCurrentDirectory(),
|
|
39363
|
-
//
|
|
39364
|
-
// strange behaviors with retaining the lexical scope of the closure. Even if this function
|
|
39365
|
-
// doesn't retain a reference to `this`, if other closures in the constructor here reference
|
|
39980
|
+
// doen't retain a reference to `this`, if other closures in the constructor here reference
|
|
39366
39981
|
// `this` internally then a closure created here would retain them. This can cause major
|
|
39367
39982
|
// memory leak issues since the `moduleResolutionCache` is a long-lived object and finds its
|
|
39368
39983
|
// way into all kinds of places inside TS internal objects.
|
|
@@ -39370,55 +39985,75 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
39370
39985
|
this.moduleResolver =
|
|
39371
39986
|
new ModuleResolver(tsProgram, this.options, this.adapter, moduleResolutionCache);
|
|
39372
39987
|
this.resourceManager = new AdapterResourceLoader(adapter, this.options);
|
|
39373
|
-
this.cycleAnalyzer =
|
|
39988
|
+
this.cycleAnalyzer =
|
|
39989
|
+
new CycleAnalyzer(new ImportGraph(tsProgram.getTypeChecker(), this.delegatingPerfRecorder));
|
|
39374
39990
|
this.incrementalStrategy.setIncrementalDriver(this.incrementalDriver, tsProgram);
|
|
39375
39991
|
this.ignoreForDiagnostics =
|
|
39376
39992
|
new Set(tsProgram.getSourceFiles().filter(sf => this.adapter.isShim(sf)));
|
|
39377
39993
|
this.ignoreForEmit = this.adapter.ignoreForEmit;
|
|
39994
|
+
let dtsFileCount = 0;
|
|
39995
|
+
let nonDtsFileCount = 0;
|
|
39996
|
+
for (const sf of tsProgram.getSourceFiles()) {
|
|
39997
|
+
if (sf.isDeclarationFile) {
|
|
39998
|
+
dtsFileCount++;
|
|
39999
|
+
}
|
|
40000
|
+
else {
|
|
40001
|
+
nonDtsFileCount++;
|
|
40002
|
+
}
|
|
40003
|
+
}
|
|
40004
|
+
livePerfRecorder.eventCount(PerfEvent.InputDtsFile, dtsFileCount);
|
|
40005
|
+
livePerfRecorder.eventCount(PerfEvent.InputTsFile, nonDtsFileCount);
|
|
39378
40006
|
}
|
|
39379
40007
|
/**
|
|
39380
40008
|
* Convert a `CompilationTicket` into an `NgCompiler` instance for the requested compilation.
|
|
39381
40009
|
*
|
|
39382
40010
|
* Depending on the nature of the compilation request, the `NgCompiler` instance may be reused
|
|
39383
40011
|
* from a previous compilation and updated with any changes, it may be a new instance which
|
|
39384
|
-
* incrementally reuses state from a previous compilation, or it may represent a fresh
|
|
39385
|
-
* entirely.
|
|
40012
|
+
* incrementally reuses state from a previous compilation, or it may represent a fresh
|
|
40013
|
+
* compilation entirely.
|
|
39386
40014
|
*/
|
|
39387
|
-
static fromTicket(ticket, adapter
|
|
40015
|
+
static fromTicket(ticket, adapter) {
|
|
39388
40016
|
switch (ticket.kind) {
|
|
39389
40017
|
case CompilationTicketKind.Fresh:
|
|
39390
|
-
return new NgCompiler(adapter, ticket.options, ticket.tsProgram, ticket.typeCheckingProgramStrategy, ticket.incrementalBuildStrategy, IncrementalDriver.fresh(ticket.tsProgram), ticket.enableTemplateTypeChecker, ticket.usePoisonedData, perfRecorder);
|
|
40018
|
+
return new NgCompiler(adapter, ticket.options, ticket.tsProgram, ticket.typeCheckingProgramStrategy, ticket.incrementalBuildStrategy, IncrementalDriver.fresh(ticket.tsProgram), ticket.enableTemplateTypeChecker, ticket.usePoisonedData, ticket.perfRecorder);
|
|
39391
40019
|
case CompilationTicketKind.IncrementalTypeScript:
|
|
39392
|
-
return new NgCompiler(adapter, ticket.options, ticket.newProgram, ticket.typeCheckingProgramStrategy, ticket.incrementalBuildStrategy, ticket.newDriver, ticket.enableTemplateTypeChecker, ticket.usePoisonedData, perfRecorder);
|
|
40020
|
+
return new NgCompiler(adapter, ticket.options, ticket.newProgram, ticket.typeCheckingProgramStrategy, ticket.incrementalBuildStrategy, ticket.newDriver, ticket.enableTemplateTypeChecker, ticket.usePoisonedData, ticket.perfRecorder);
|
|
39393
40021
|
case CompilationTicketKind.IncrementalResource:
|
|
39394
40022
|
const compiler = ticket.compiler;
|
|
39395
|
-
compiler.updateWithChangedResources(ticket.modifiedResourceFiles);
|
|
40023
|
+
compiler.updateWithChangedResources(ticket.modifiedResourceFiles, ticket.perfRecorder);
|
|
39396
40024
|
return compiler;
|
|
39397
40025
|
}
|
|
39398
40026
|
}
|
|
39399
|
-
|
|
39400
|
-
|
|
39401
|
-
|
|
39402
|
-
|
|
39403
|
-
|
|
39404
|
-
|
|
39405
|
-
|
|
39406
|
-
|
|
39407
|
-
|
|
39408
|
-
|
|
39409
|
-
|
|
40027
|
+
get perfRecorder() {
|
|
40028
|
+
return this.livePerfRecorder;
|
|
40029
|
+
}
|
|
40030
|
+
updateWithChangedResources(changedResources, perfRecorder) {
|
|
40031
|
+
this.livePerfRecorder = perfRecorder;
|
|
40032
|
+
this.delegatingPerfRecorder.target = perfRecorder;
|
|
40033
|
+
perfRecorder.inPhase(PerfPhase.ResourceUpdate, () => {
|
|
40034
|
+
if (this.compilation === null) {
|
|
40035
|
+
// Analysis hasn't happened yet, so no update is necessary - any changes to resources will
|
|
40036
|
+
// be captured by the inital analysis pass itself.
|
|
40037
|
+
return;
|
|
39410
40038
|
}
|
|
39411
|
-
|
|
39412
|
-
|
|
40039
|
+
this.resourceManager.invalidate();
|
|
40040
|
+
const classesToUpdate = new Set();
|
|
40041
|
+
for (const resourceFile of changedResources) {
|
|
40042
|
+
for (const templateClass of this.getComponentsWithTemplateFile(resourceFile)) {
|
|
40043
|
+
classesToUpdate.add(templateClass);
|
|
40044
|
+
}
|
|
40045
|
+
for (const styleClass of this.getComponentsWithStyleFile(resourceFile)) {
|
|
40046
|
+
classesToUpdate.add(styleClass);
|
|
40047
|
+
}
|
|
39413
40048
|
}
|
|
39414
|
-
|
|
39415
|
-
|
|
39416
|
-
|
|
39417
|
-
|
|
39418
|
-
|
|
40049
|
+
for (const clazz of classesToUpdate) {
|
|
40050
|
+
this.compilation.traitCompiler.updateResources(clazz);
|
|
40051
|
+
if (!ts$1.isClassDeclaration(clazz)) {
|
|
40052
|
+
continue;
|
|
40053
|
+
}
|
|
40054
|
+
this.compilation.templateTypeChecker.invalidateClass(clazz);
|
|
39419
40055
|
}
|
|
39420
|
-
|
|
39421
|
-
}
|
|
40056
|
+
});
|
|
39422
40057
|
}
|
|
39423
40058
|
/**
|
|
39424
40059
|
* Get the resource dependencies of a file.
|
|
@@ -39525,29 +40160,23 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
39525
40160
|
if (this.compilation !== null) {
|
|
39526
40161
|
return;
|
|
39527
40162
|
}
|
|
39528
|
-
this.
|
|
39529
|
-
|
|
39530
|
-
|
|
39531
|
-
|
|
39532
|
-
|
|
39533
|
-
|
|
39534
|
-
|
|
39535
|
-
|
|
39536
|
-
|
|
39537
|
-
|
|
39538
|
-
|
|
39539
|
-
|
|
39540
|
-
}
|
|
39541
|
-
else if (this.perfRecorder.enabled) {
|
|
39542
|
-
analysisPromise = analysisPromise.then(() => this.perfRecorder.stop(analyzeFileSpan));
|
|
39543
|
-
}
|
|
39544
|
-
if (analysisPromise !== undefined) {
|
|
39545
|
-
promises.push(analysisPromise);
|
|
40163
|
+
yield this.perfRecorder.inPhase(PerfPhase.Analysis, () => __awaiter(this, void 0, void 0, function* () {
|
|
40164
|
+
this.compilation = this.makeCompilation();
|
|
40165
|
+
const promises = [];
|
|
40166
|
+
for (const sf of this.tsProgram.getSourceFiles()) {
|
|
40167
|
+
if (sf.isDeclarationFile) {
|
|
40168
|
+
continue;
|
|
40169
|
+
}
|
|
40170
|
+
let analysisPromise = this.compilation.traitCompiler.analyzeAsync(sf);
|
|
40171
|
+
this.scanForMwp(sf);
|
|
40172
|
+
if (analysisPromise !== undefined) {
|
|
40173
|
+
promises.push(analysisPromise);
|
|
40174
|
+
}
|
|
39546
40175
|
}
|
|
39547
|
-
|
|
39548
|
-
|
|
39549
|
-
|
|
39550
|
-
|
|
40176
|
+
yield Promise.all(promises);
|
|
40177
|
+
this.perfRecorder.memory(PerfCheckpoint.Analysis);
|
|
40178
|
+
this.resolveCompilation(this.compilation.traitCompiler);
|
|
40179
|
+
}));
|
|
39551
40180
|
});
|
|
39552
40181
|
}
|
|
39553
40182
|
/**
|
|
@@ -39557,9 +40186,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
39557
40186
|
*/
|
|
39558
40187
|
listLazyRoutes(entryRoute) {
|
|
39559
40188
|
if (entryRoute) {
|
|
39560
|
-
//
|
|
39561
|
-
// This resolution step is here to match the implementation of the old `AotCompilerHost` (see
|
|
39562
|
-
// https://github.com/angular/angular/blob/50732e156/packages/compiler-cli/src/transformers/compiler_host.ts#L175-L188).
|
|
40189
|
+
// htts://github.com/angular/angular/blob/50732e156/packages/compiler-cli/src/transformers/compiler_host.ts#L175-L188).
|
|
39563
40190
|
//
|
|
39564
40191
|
// `@angular/cli` will always call this API with an absolute path, so the resolution step is
|
|
39565
40192
|
// not necessary, but keeping it backwards compatible in case someone else is using the API.
|
|
@@ -39600,10 +40227,11 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
39600
40227
|
else {
|
|
39601
40228
|
importRewriter = new NoopImportRewriter();
|
|
39602
40229
|
}
|
|
40230
|
+
const defaultImportTracker = new DefaultImportTracker();
|
|
39603
40231
|
const before = [
|
|
39604
|
-
ivyTransformFactory(compilation.traitCompiler, compilation.reflector, importRewriter,
|
|
40232
|
+
ivyTransformFactory(compilation.traitCompiler, compilation.reflector, importRewriter, defaultImportTracker, this.delegatingPerfRecorder, compilation.isCore, this.closureCompilerEnabled),
|
|
39605
40233
|
aliasTransformFactory(compilation.traitCompiler.exportStatements),
|
|
39606
|
-
|
|
40234
|
+
defaultImportTracker.importPreservingTransformer(),
|
|
39607
40235
|
];
|
|
39608
40236
|
const afterDeclarations = [];
|
|
39609
40237
|
if (compilation.dtsTransforms !== null) {
|
|
@@ -39637,25 +40265,27 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
39637
40265
|
return this.compilation;
|
|
39638
40266
|
}
|
|
39639
40267
|
analyzeSync() {
|
|
39640
|
-
|
|
39641
|
-
|
|
39642
|
-
|
|
39643
|
-
|
|
39644
|
-
|
|
40268
|
+
this.perfRecorder.inPhase(PerfPhase.Analysis, () => {
|
|
40269
|
+
this.compilation = this.makeCompilation();
|
|
40270
|
+
for (const sf of this.tsProgram.getSourceFiles()) {
|
|
40271
|
+
if (sf.isDeclarationFile) {
|
|
40272
|
+
continue;
|
|
40273
|
+
}
|
|
40274
|
+
this.compilation.traitCompiler.analyzeSync(sf);
|
|
40275
|
+
this.scanForMwp(sf);
|
|
39645
40276
|
}
|
|
39646
|
-
|
|
39647
|
-
this.compilation.traitCompiler
|
|
39648
|
-
|
|
39649
|
-
this.perfRecorder.stop(analyzeFileSpan);
|
|
39650
|
-
}
|
|
39651
|
-
this.perfRecorder.stop(analyzeSpan);
|
|
39652
|
-
this.resolveCompilation(this.compilation.traitCompiler);
|
|
40277
|
+
this.perfRecorder.memory(PerfCheckpoint.Analysis);
|
|
40278
|
+
this.resolveCompilation(this.compilation.traitCompiler);
|
|
40279
|
+
});
|
|
39653
40280
|
}
|
|
39654
40281
|
resolveCompilation(traitCompiler) {
|
|
39655
|
-
|
|
39656
|
-
|
|
39657
|
-
|
|
39658
|
-
|
|
40282
|
+
this.perfRecorder.inPhase(PerfPhase.Resolve, () => {
|
|
40283
|
+
traitCompiler.resolve();
|
|
40284
|
+
// At this point, analysis is complete and the compiler can now calculate which files need to
|
|
40285
|
+
// be emitted, so do that.
|
|
40286
|
+
this.incrementalDriver.recordSuccessfulAnalysis(traitCompiler);
|
|
40287
|
+
this.perfRecorder.memory(PerfCheckpoint.Resolve);
|
|
40288
|
+
});
|
|
39659
40289
|
}
|
|
39660
40290
|
get fullTemplateTypeCheck() {
|
|
39661
40291
|
// Determine the strictness level of type checking based on compiler options. As
|
|
@@ -39779,7 +40409,6 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
39779
40409
|
getTemplateDiagnostics() {
|
|
39780
40410
|
const compilation = this.ensureAnalyzed();
|
|
39781
40411
|
// Get the diagnostics.
|
|
39782
|
-
const typeCheckSpan = this.perfRecorder.start('typeCheckDiagnostics');
|
|
39783
40412
|
const diagnostics = [];
|
|
39784
40413
|
for (const sf of this.tsProgram.getSourceFiles()) {
|
|
39785
40414
|
if (sf.isDeclarationFile || this.adapter.isShim(sf)) {
|
|
@@ -39788,7 +40417,6 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
39788
40417
|
diagnostics.push(...compilation.templateTypeChecker.getDiagnosticsForFile(sf, OptimizeFor.WholeProgram));
|
|
39789
40418
|
}
|
|
39790
40419
|
const program = this.typeCheckingProgramStrategy.getProgram();
|
|
39791
|
-
this.perfRecorder.stop(typeCheckSpan);
|
|
39792
40420
|
this.incrementalStrategy.setIncrementalDriver(this.incrementalDriver, program);
|
|
39793
40421
|
this.nextProgram = program;
|
|
39794
40422
|
return diagnostics;
|
|
@@ -39796,13 +40424,11 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
39796
40424
|
getTemplateDiagnosticsForFile(sf, optimizeFor) {
|
|
39797
40425
|
const compilation = this.ensureAnalyzed();
|
|
39798
40426
|
// Get the diagnostics.
|
|
39799
|
-
const typeCheckSpan = this.perfRecorder.start('typeCheckDiagnostics');
|
|
39800
40427
|
const diagnostics = [];
|
|
39801
40428
|
if (!sf.isDeclarationFile && !this.adapter.isShim(sf)) {
|
|
39802
40429
|
diagnostics.push(...compilation.templateTypeChecker.getDiagnosticsForFile(sf, optimizeFor));
|
|
39803
40430
|
}
|
|
39804
40431
|
const program = this.typeCheckingProgramStrategy.getProgram();
|
|
39805
|
-
this.perfRecorder.stop(typeCheckSpan);
|
|
39806
40432
|
this.incrementalStrategy.setIncrementalDriver(this.incrementalDriver, program);
|
|
39807
40433
|
this.nextProgram = program;
|
|
39808
40434
|
return diagnostics;
|
|
@@ -39910,7 +40536,6 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
39910
40536
|
const dtsTransforms = new DtsTransformRegistry();
|
|
39911
40537
|
const mwpScanner = new ModuleWithProvidersScanner(reflector, evaluator, refEmitter);
|
|
39912
40538
|
const isCore = isAngularCorePackage(this.tsProgram);
|
|
39913
|
-
const defaultImportTracker = new DefaultImportTracker();
|
|
39914
40539
|
const resourceRegistry = new ResourceRegistry();
|
|
39915
40540
|
const compilationMode = this.options.compilationMode === 'partial' ? CompilationMode.PARTIAL : CompilationMode.FULL;
|
|
39916
40541
|
// Cycles are handled in full compilation mode by "remote scoping".
|
|
@@ -39921,20 +40546,20 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
39921
40546
|
1 /* Error */;
|
|
39922
40547
|
// Set up the IvyCompilation, which manages state for the Ivy transformer.
|
|
39923
40548
|
const handlers = [
|
|
39924
|
-
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,
|
|
40549
|
+
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, this.incrementalDriver.depGraph, injectableRegistry, semanticDepGraphUpdater, this.closureCompilerEnabled, this.delegatingPerfRecorder),
|
|
39925
40550
|
// TODO(alxhub): understand why the cast here is necessary (something to do with `null`
|
|
39926
40551
|
// not being assignable to `unknown` when wrapped in `Readonly`).
|
|
39927
40552
|
// clang-format off
|
|
39928
|
-
new DirectiveDecoratorHandler(reflector, evaluator, metaRegistry, scopeRegistry, metaReader,
|
|
40553
|
+
new DirectiveDecoratorHandler(reflector, evaluator, metaRegistry, scopeRegistry, metaReader, injectableRegistry, isCore, semanticDepGraphUpdater, this.closureCompilerEnabled, compileUndecoratedClassesWithAngularFeatures, this.delegatingPerfRecorder),
|
|
39929
40554
|
// clang-format on
|
|
39930
40555
|
// Pipe handler must be before injectable handler in list so pipe factories are printed
|
|
39931
40556
|
// before injectable factories (so injectable factories can delegate to them)
|
|
39932
|
-
new PipeDecoratorHandler(reflector, evaluator, metaRegistry, scopeRegistry,
|
|
39933
|
-
new InjectableDecoratorHandler(reflector,
|
|
39934
|
-
new NgModuleDecoratorHandler(reflector, evaluator, metaReader, metaRegistry, scopeRegistry, referencesRegistry, isCore, routeAnalyzer, refEmitter, this.adapter.factoryTracker,
|
|
40557
|
+
new PipeDecoratorHandler(reflector, evaluator, metaRegistry, scopeRegistry, injectableRegistry, isCore, this.delegatingPerfRecorder),
|
|
40558
|
+
new InjectableDecoratorHandler(reflector, isCore, this.options.strictInjectionParameters || false, injectableRegistry, this.delegatingPerfRecorder),
|
|
40559
|
+
new NgModuleDecoratorHandler(reflector, evaluator, metaReader, metaRegistry, scopeRegistry, referencesRegistry, isCore, routeAnalyzer, refEmitter, this.adapter.factoryTracker, this.closureCompilerEnabled, injectableRegistry, this.delegatingPerfRecorder, this.options.i18nInLocale),
|
|
39935
40560
|
];
|
|
39936
|
-
const traitCompiler = new TraitCompiler(handlers, reflector, this.
|
|
39937
|
-
const templateTypeChecker = new TemplateTypeCheckerImpl(this.tsProgram, this.typeCheckingProgramStrategy, traitCompiler, this.getTypeCheckingConfig(), refEmitter, reflector, this.adapter, this.incrementalDriver, scopeRegistry, typeCheckScopeRegistry);
|
|
40561
|
+
const traitCompiler = new TraitCompiler(handlers, reflector, this.delegatingPerfRecorder, this.incrementalDriver, this.options.compileNonExportedClasses !== false, compilationMode, dtsTransforms, semanticDepGraphUpdater);
|
|
40562
|
+
const templateTypeChecker = new TemplateTypeCheckerImpl(this.tsProgram, this.typeCheckingProgramStrategy, traitCompiler, this.getTypeCheckingConfig(), refEmitter, reflector, this.adapter, this.incrementalDriver, scopeRegistry, typeCheckScopeRegistry, this.delegatingPerfRecorder);
|
|
39938
40563
|
return {
|
|
39939
40564
|
isCore,
|
|
39940
40565
|
traitCompiler,
|
|
@@ -39946,7 +40571,6 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
39946
40571
|
mwpScanner,
|
|
39947
40572
|
metaReader,
|
|
39948
40573
|
typeCheckScopeRegistry,
|
|
39949
|
-
defaultImportTracker,
|
|
39950
40574
|
aliasingHost,
|
|
39951
40575
|
refEmitter,
|
|
39952
40576
|
templateTypeChecker,
|
|
@@ -40127,24 +40751,30 @@ https://v9.angular.io/guide/template-typecheck#template-type-checking`,
|
|
|
40127
40751
|
};
|
|
40128
40752
|
}
|
|
40129
40753
|
function getExtendedConfigPath(configFile, extendsValue, host, fs) {
|
|
40130
|
-
|
|
40754
|
+
const result = getExtendedConfigPathWorker(configFile, extendsValue, host, fs);
|
|
40755
|
+
if (result !== null) {
|
|
40756
|
+
return result;
|
|
40757
|
+
}
|
|
40758
|
+
// Try to resolve the paths with a json extension append a json extension to the file in case if
|
|
40759
|
+
// it is missing and the resolution failed. This is to replicate TypeScript behaviour, see:
|
|
40760
|
+
// https://github.com/microsoft/TypeScript/blob/294a5a7d784a5a95a8048ee990400979a6bc3a1c/src/compiler/commandLineParser.ts#L2806
|
|
40761
|
+
return getExtendedConfigPathWorker(configFile, `${extendsValue}.json`, host, fs);
|
|
40762
|
+
}
|
|
40763
|
+
function getExtendedConfigPathWorker(configFile, extendsValue, host, fs) {
|
|
40131
40764
|
if (extendsValue.startsWith('.') || fs.isRooted(extendsValue)) {
|
|
40132
|
-
extendedConfigPath = host.resolve(host.dirname(configFile), extendsValue);
|
|
40133
|
-
|
|
40134
|
-
extendedConfigPath
|
|
40135
|
-
|
|
40765
|
+
const extendedConfigPath = host.resolve(host.dirname(configFile), extendsValue);
|
|
40766
|
+
if (host.exists(extendedConfigPath)) {
|
|
40767
|
+
return extendedConfigPath;
|
|
40768
|
+
}
|
|
40136
40769
|
}
|
|
40137
40770
|
else {
|
|
40138
40771
|
const parseConfigHost = createParseConfigHost(host, fs);
|
|
40139
40772
|
// Path isn't a rooted or relative path, resolve like a module.
|
|
40140
40773
|
const { resolvedModule, } = ts$1.nodeModuleNameResolver(extendsValue, configFile, { moduleResolution: ts$1.ModuleResolutionKind.NodeJs, resolveJsonModule: true }, parseConfigHost);
|
|
40141
40774
|
if (resolvedModule) {
|
|
40142
|
-
|
|
40775
|
+
return absoluteFrom(resolvedModule.resolvedFileName);
|
|
40143
40776
|
}
|
|
40144
40777
|
}
|
|
40145
|
-
if (extendedConfigPath !== null && host.exists(extendedConfigPath)) {
|
|
40146
|
-
return extendedConfigPath;
|
|
40147
|
-
}
|
|
40148
40778
|
return null;
|
|
40149
40779
|
}
|
|
40150
40780
|
|
|
@@ -40515,7 +41145,7 @@ https://v9.angular.io/guide/template-typecheck#template-type-checking`,
|
|
|
40515
41145
|
*/
|
|
40516
41146
|
function toAttributeString(attribute) {
|
|
40517
41147
|
var _a, _b;
|
|
40518
|
-
if (attribute instanceof BoundEvent) {
|
|
41148
|
+
if (attribute instanceof BoundEvent || attribute instanceof BoundAttribute) {
|
|
40519
41149
|
return `[${attribute.name}]`;
|
|
40520
41150
|
}
|
|
40521
41151
|
else {
|
|
@@ -40693,6 +41323,7 @@ https://v9.angular.io/guide/template-typecheck#template-type-checking`,
|
|
|
40693
41323
|
* Use of this source code is governed by an MIT-style license that can be
|
|
40694
41324
|
* found in the LICENSE file at https://angular.io/license
|
|
40695
41325
|
*/
|
|
41326
|
+
const PRE_COMPILED_STYLE_EXTENSIONS = ['.scss', '.sass', '.less', '.styl'];
|
|
40696
41327
|
class LanguageServiceAdapter {
|
|
40697
41328
|
constructor(project) {
|
|
40698
41329
|
this.project = project;
|
|
@@ -40709,6 +41340,22 @@ https://v9.angular.io/guide/template-typecheck#template-type-checking`,
|
|
|
40709
41340
|
this.lastReadResourceVersion = new Map();
|
|
40710
41341
|
this.rootDirs = getRootDirs(this, project.getCompilationSettings());
|
|
40711
41342
|
}
|
|
41343
|
+
resourceNameToFileName(url, fromFile, fallbackResolve) {
|
|
41344
|
+
var _a;
|
|
41345
|
+
// If we are trying to resolve a `.css` file, see if we can find a pre-compiled file with the
|
|
41346
|
+
// same name instead. That way, we can provide go-to-definition for the pre-compiled files which
|
|
41347
|
+
// would generally be the desired behavior.
|
|
41348
|
+
if (url.endsWith('.css')) {
|
|
41349
|
+
const styleUrl = path.resolve(fromFile, '..', url);
|
|
41350
|
+
for (const ext of PRE_COMPILED_STYLE_EXTENSIONS) {
|
|
41351
|
+
const precompiledFileUrl = styleUrl.replace(/\.css$/, ext);
|
|
41352
|
+
if (this.fileExists(precompiledFileUrl)) {
|
|
41353
|
+
return precompiledFileUrl;
|
|
41354
|
+
}
|
|
41355
|
+
}
|
|
41356
|
+
}
|
|
41357
|
+
return (_a = fallbackResolve === null || fallbackResolve === void 0 ? void 0 : fallbackResolve(url, fromFile)) !== null && _a !== void 0 ? _a : null;
|
|
41358
|
+
}
|
|
40712
41359
|
isShim(sf) {
|
|
40713
41360
|
return isShim(sf);
|
|
40714
41361
|
}
|
|
@@ -40853,14 +41500,20 @@ https://v9.angular.io/guide/template-typecheck#template-type-checking`,
|
|
|
40853
41500
|
const ticket = resourceChangeTicket(this.compiler, modifiedResourceFiles);
|
|
40854
41501
|
this.compiler = NgCompiler.fromTicket(ticket, this.adapter);
|
|
40855
41502
|
}
|
|
41503
|
+
else {
|
|
41504
|
+
// The previous NgCompiler is being reused, but we still want to reset its performance
|
|
41505
|
+
// tracker to capture only the operations that are needed to service the current request.
|
|
41506
|
+
this.compiler.perfRecorder.reset();
|
|
41507
|
+
}
|
|
40856
41508
|
return this.compiler;
|
|
40857
41509
|
}
|
|
40858
41510
|
let ticket;
|
|
40859
41511
|
if (this.compiler === null || this.lastKnownProgram === null) {
|
|
40860
|
-
ticket = freshCompilationTicket(program, this.options, this.incrementalStrategy, this.programStrategy,
|
|
41512
|
+
ticket = freshCompilationTicket(program, this.options, this.incrementalStrategy, this.programStrategy,
|
|
41513
|
+
/* perfRecorder */ null, true, true);
|
|
40861
41514
|
}
|
|
40862
41515
|
else {
|
|
40863
|
-
ticket = incrementalFromCompilerTicket(this.compiler, program, this.incrementalStrategy, this.programStrategy, modifiedResourceFiles);
|
|
41516
|
+
ticket = incrementalFromCompilerTicket(this.compiler, program, this.incrementalStrategy, this.programStrategy, modifiedResourceFiles, /* perfRecorder */ null);
|
|
40864
41517
|
}
|
|
40865
41518
|
this.compiler = NgCompiler.fromTicket(ticket, this.adapter);
|
|
40866
41519
|
this.lastKnownProgram = program;
|
|
@@ -41762,17 +42415,17 @@ https://v9.angular.io/guide/template-typecheck#template-type-checking`,
|
|
|
41762
42415
|
* Get completions for a property expression in a global context (e.g. `{{y|}}`).
|
|
41763
42416
|
*/
|
|
41764
42417
|
getGlobalPropertyExpressionCompletion(options) {
|
|
41765
|
-
const completions = this.templateTypeChecker.getGlobalCompletions(this.template, this.component);
|
|
42418
|
+
const completions = this.templateTypeChecker.getGlobalCompletions(this.template, this.component, this.node);
|
|
41766
42419
|
if (completions === null) {
|
|
41767
42420
|
return undefined;
|
|
41768
42421
|
}
|
|
41769
|
-
const { componentContext, templateContext } = completions;
|
|
42422
|
+
const { componentContext, templateContext, nodeContext: astContext } = completions;
|
|
41770
42423
|
const replacementSpan = makeReplacementSpanFromAst(this.node);
|
|
41771
42424
|
// Merge TS completion results with results from the template scope.
|
|
41772
42425
|
let entries = [];
|
|
41773
|
-
const
|
|
41774
|
-
if (
|
|
41775
|
-
for (const tsCompletion of
|
|
42426
|
+
const componentCompletions = this.tsLS.getCompletionsAtPosition(componentContext.shimPath, componentContext.positionInShimFile, options);
|
|
42427
|
+
if (componentCompletions !== undefined) {
|
|
42428
|
+
for (const tsCompletion of componentCompletions.entries) {
|
|
41776
42429
|
// Skip completions that are shadowed by a template entity definition.
|
|
41777
42430
|
if (templateContext.has(tsCompletion.name)) {
|
|
41778
42431
|
continue;
|
|
@@ -41783,6 +42436,20 @@ https://v9.angular.io/guide/template-typecheck#template-type-checking`,
|
|
|
41783
42436
|
replacementSpan }));
|
|
41784
42437
|
}
|
|
41785
42438
|
}
|
|
42439
|
+
// Merge TS completion results with results from the ast context.
|
|
42440
|
+
if (astContext !== null) {
|
|
42441
|
+
const nodeCompletions = this.tsLS.getCompletionsAtPosition(astContext.shimPath, astContext.positionInShimFile, options);
|
|
42442
|
+
if (nodeCompletions !== undefined) {
|
|
42443
|
+
for (const tsCompletion of nodeCompletions.entries) {
|
|
42444
|
+
if (this.isValidNodeContextCompletion(tsCompletion)) {
|
|
42445
|
+
entries.push(Object.assign(Object.assign({}, tsCompletion), {
|
|
42446
|
+
// Substitute the TS completion's `replacementSpan` (which uses offsets within the
|
|
42447
|
+
// TCB) with the `replacementSpan` within the template source.
|
|
42448
|
+
replacementSpan }));
|
|
42449
|
+
}
|
|
42450
|
+
}
|
|
42451
|
+
}
|
|
42452
|
+
}
|
|
41786
42453
|
for (const [name, entity] of templateContext) {
|
|
41787
42454
|
entries.push({
|
|
41788
42455
|
name,
|
|
@@ -41808,7 +42475,7 @@ https://v9.angular.io/guide/template-typecheck#template-type-checking`,
|
|
|
41808
42475
|
* `{{y|}}`).
|
|
41809
42476
|
*/
|
|
41810
42477
|
getGlobalPropertyExpressionCompletionDetails(entryName, formatOptions, preferences) {
|
|
41811
|
-
const completions = this.templateTypeChecker.getGlobalCompletions(this.template, this.component);
|
|
42478
|
+
const completions = this.templateTypeChecker.getGlobalCompletions(this.template, this.component, this.node);
|
|
41812
42479
|
if (completions === null) {
|
|
41813
42480
|
return undefined;
|
|
41814
42481
|
}
|
|
@@ -41841,7 +42508,7 @@ https://v9.angular.io/guide/template-typecheck#template-type-checking`,
|
|
|
41841
42508
|
* `{{y|}}`).
|
|
41842
42509
|
*/
|
|
41843
42510
|
getGlobalPropertyExpressionCompletionSymbol(entryName) {
|
|
41844
|
-
const completions = this.templateTypeChecker.getGlobalCompletions(this.template, this.component);
|
|
42511
|
+
const completions = this.templateTypeChecker.getGlobalCompletions(this.template, this.component, this.node);
|
|
41845
42512
|
if (completions === null) {
|
|
41846
42513
|
return undefined;
|
|
41847
42514
|
}
|
|
@@ -42113,6 +42780,24 @@ https://v9.angular.io/guide/template-typecheck#template-type-checking`,
|
|
|
42113
42780
|
isNewIdentifierLocation: false,
|
|
42114
42781
|
};
|
|
42115
42782
|
}
|
|
42783
|
+
/**
|
|
42784
|
+
* From the AST node of the cursor position, include completion of string literals, number
|
|
42785
|
+
* literals, `true`, `false`, `null`, and `undefined`.
|
|
42786
|
+
*/
|
|
42787
|
+
isValidNodeContextCompletion(completion) {
|
|
42788
|
+
if (completion.kind === ts$1.ScriptElementKind.string) {
|
|
42789
|
+
// 'string' kind includes both string literals and number literals
|
|
42790
|
+
return true;
|
|
42791
|
+
}
|
|
42792
|
+
if (completion.kind === ts$1.ScriptElementKind.keyword) {
|
|
42793
|
+
return completion.name === 'true' || completion.name === 'false' ||
|
|
42794
|
+
completion.name === 'null';
|
|
42795
|
+
}
|
|
42796
|
+
if (completion.kind === ts$1.ScriptElementKind.variableElement) {
|
|
42797
|
+
return completion.name === 'undefined';
|
|
42798
|
+
}
|
|
42799
|
+
return false;
|
|
42800
|
+
}
|
|
42116
42801
|
}
|
|
42117
42802
|
function makeReplacementSpanFromParseSourceSpan(span) {
|
|
42118
42803
|
return {
|
|
@@ -42664,43 +43349,50 @@ https://v9.angular.io/guide/template-typecheck#template-type-checking`,
|
|
|
42664
43349
|
this.ttc = this.compiler.getTemplateTypeChecker();
|
|
42665
43350
|
}
|
|
42666
43351
|
getRenameInfo(filePath, position) {
|
|
42667
|
-
|
|
42668
|
-
|
|
42669
|
-
|
|
42670
|
-
|
|
42671
|
-
|
|
42672
|
-
|
|
42673
|
-
|
|
42674
|
-
|
|
42675
|
-
|
|
42676
|
-
|
|
42677
|
-
|
|
42678
|
-
|
|
42679
|
-
|
|
42680
|
-
|
|
42681
|
-
|
|
42682
|
-
|
|
42683
|
-
|
|
42684
|
-
|
|
42685
|
-
|
|
42686
|
-
|
|
42687
|
-
|
|
42688
|
-
|
|
43352
|
+
return this.compiler.perfRecorder.inPhase(PerfPhase.LsReferencesAndRenames, () => {
|
|
43353
|
+
const templateInfo = getTemplateInfoAtPosition(filePath, position, this.compiler);
|
|
43354
|
+
// We could not get a template at position so we assume the request came from outside the
|
|
43355
|
+
// template.
|
|
43356
|
+
if (templateInfo === undefined) {
|
|
43357
|
+
return this.tsLS.getRenameInfo(filePath, position);
|
|
43358
|
+
}
|
|
43359
|
+
const allTargetDetails = this.getTargetDetailsAtTemplatePosition(templateInfo, position);
|
|
43360
|
+
if (allTargetDetails === null) {
|
|
43361
|
+
return {
|
|
43362
|
+
canRename: false,
|
|
43363
|
+
localizedErrorMessage: 'Could not find template node at position.',
|
|
43364
|
+
};
|
|
43365
|
+
}
|
|
43366
|
+
const { templateTarget } = allTargetDetails[0];
|
|
43367
|
+
const templateTextAndSpan = getRenameTextAndSpanAtPosition(templateTarget, position);
|
|
43368
|
+
if (templateTextAndSpan === null) {
|
|
43369
|
+
return { canRename: false, localizedErrorMessage: 'Could not determine template node text.' };
|
|
43370
|
+
}
|
|
43371
|
+
const { text, span } = templateTextAndSpan;
|
|
43372
|
+
return {
|
|
43373
|
+
canRename: true,
|
|
43374
|
+
displayName: text,
|
|
43375
|
+
fullDisplayName: text,
|
|
43376
|
+
triggerSpan: span,
|
|
43377
|
+
};
|
|
43378
|
+
});
|
|
42689
43379
|
}
|
|
42690
43380
|
findRenameLocations(filePath, position) {
|
|
42691
43381
|
this.ttc.generateAllTypeCheckBlocks();
|
|
42692
|
-
|
|
42693
|
-
|
|
42694
|
-
|
|
42695
|
-
|
|
42696
|
-
|
|
42697
|
-
|
|
42698
|
-
|
|
43382
|
+
return this.compiler.perfRecorder.inPhase(PerfPhase.LsReferencesAndRenames, () => {
|
|
43383
|
+
const templateInfo = getTemplateInfoAtPosition(filePath, position, this.compiler);
|
|
43384
|
+
// We could not get a template at position so we assume the request came from outside the
|
|
43385
|
+
// template.
|
|
43386
|
+
if (templateInfo === undefined) {
|
|
43387
|
+
const requestNode = this.getTsNodeAtPosition(filePath, position);
|
|
43388
|
+
if (requestNode === null) {
|
|
43389
|
+
return undefined;
|
|
43390
|
+
}
|
|
43391
|
+
const requestOrigin = { kind: RequestKind.TypeScript, requestNode };
|
|
43392
|
+
return this.findRenameLocationsAtTypescriptPosition(filePath, position, requestOrigin);
|
|
42699
43393
|
}
|
|
42700
|
-
|
|
42701
|
-
|
|
42702
|
-
}
|
|
42703
|
-
return this.findRenameLocationsAtTemplatePosition(templateInfo, position);
|
|
43394
|
+
return this.findRenameLocationsAtTemplatePosition(templateInfo, position);
|
|
43395
|
+
});
|
|
42704
43396
|
}
|
|
42705
43397
|
findRenameLocationsAtTemplatePosition(templateInfo, position) {
|
|
42706
43398
|
const allTargetDetails = this.getTargetDetailsAtTemplatePosition(templateInfo, position);
|
|
@@ -42735,52 +43427,56 @@ https://v9.angular.io/guide/template-typecheck#template-type-checking`,
|
|
|
42735
43427
|
return (_a = findTightestNode(sf, position)) !== null && _a !== void 0 ? _a : null;
|
|
42736
43428
|
}
|
|
42737
43429
|
findRenameLocationsAtTypescriptPosition(filePath, position, requestOrigin) {
|
|
42738
|
-
|
|
42739
|
-
|
|
42740
|
-
|
|
42741
|
-
|
|
42742
|
-
else {
|
|
42743
|
-
const templateNodeText = getRenameTextAndSpanAtPosition(requestOrigin.requestNode, requestOrigin.position);
|
|
42744
|
-
if (templateNodeText === null) {
|
|
42745
|
-
return undefined;
|
|
43430
|
+
return this.compiler.perfRecorder.inPhase(PerfPhase.LsReferencesAndRenames, () => {
|
|
43431
|
+
let originalNodeText;
|
|
43432
|
+
if (requestOrigin.kind === RequestKind.TypeScript) {
|
|
43433
|
+
originalNodeText = requestOrigin.requestNode.getText();
|
|
42746
43434
|
}
|
|
42747
|
-
|
|
42748
|
-
|
|
42749
|
-
|
|
42750
|
-
if (locations === undefined) {
|
|
42751
|
-
return undefined;
|
|
42752
|
-
}
|
|
42753
|
-
const entries = new Map();
|
|
42754
|
-
for (const location of locations) {
|
|
42755
|
-
// TODO(atscott): Determine if a file is a shim file in a more robust way and make the API
|
|
42756
|
-
// available in an appropriate location.
|
|
42757
|
-
if (this.ttc.isTrackedTypeCheckFile(absoluteFrom(location.fileName))) {
|
|
42758
|
-
const entry = this.convertToTemplateDocumentSpan(location, this.ttc, originalNodeText);
|
|
42759
|
-
// There is no template node whose text matches the original rename request. Bail on
|
|
42760
|
-
// renaming completely rather than providing incomplete results.
|
|
42761
|
-
if (entry === null) {
|
|
43435
|
+
else {
|
|
43436
|
+
const templateNodeText = getRenameTextAndSpanAtPosition(requestOrigin.requestNode, requestOrigin.position);
|
|
43437
|
+
if (templateNodeText === null) {
|
|
42762
43438
|
return undefined;
|
|
42763
43439
|
}
|
|
42764
|
-
|
|
43440
|
+
originalNodeText = templateNodeText.text;
|
|
42765
43441
|
}
|
|
42766
|
-
|
|
42767
|
-
|
|
42768
|
-
|
|
42769
|
-
|
|
42770
|
-
|
|
43442
|
+
const locations = this.tsLS.findRenameLocations(filePath, position, /*findInStrings*/ false, /*findInComments*/ false);
|
|
43443
|
+
if (locations === undefined) {
|
|
43444
|
+
return undefined;
|
|
43445
|
+
}
|
|
43446
|
+
const entries = new Map();
|
|
43447
|
+
for (const location of locations) {
|
|
43448
|
+
// TODO(atscott): Determine if a file is a shim file in a more robust way and make the API
|
|
43449
|
+
// available in an appropriate location.
|
|
43450
|
+
if (this.ttc.isTrackedTypeCheckFile(absoluteFrom(location.fileName))) {
|
|
43451
|
+
const entry = this.convertToTemplateDocumentSpan(location, this.ttc, originalNodeText);
|
|
43452
|
+
// There is no template node whose text matches the original rename request. Bail on
|
|
43453
|
+
// renaming completely rather than providing incomplete results.
|
|
43454
|
+
if (entry === null) {
|
|
43455
|
+
return undefined;
|
|
43456
|
+
}
|
|
43457
|
+
entries.set(createLocationKey(entry), entry);
|
|
43458
|
+
}
|
|
43459
|
+
else {
|
|
43460
|
+
// Ensure we only allow renaming a TS result with matching text
|
|
43461
|
+
const refNode = this.getTsNodeAtPosition(location.fileName, location.textSpan.start);
|
|
43462
|
+
if (refNode === null || refNode.getText() !== originalNodeText) {
|
|
43463
|
+
return undefined;
|
|
43464
|
+
}
|
|
43465
|
+
entries.set(createLocationKey(location), location);
|
|
42771
43466
|
}
|
|
42772
|
-
entries.set(createLocationKey(location), location);
|
|
42773
43467
|
}
|
|
42774
|
-
|
|
42775
|
-
|
|
43468
|
+
return Array.from(entries.values());
|
|
43469
|
+
});
|
|
42776
43470
|
}
|
|
42777
43471
|
getReferencesAtPosition(filePath, position) {
|
|
42778
43472
|
this.ttc.generateAllTypeCheckBlocks();
|
|
42779
|
-
|
|
42780
|
-
|
|
42781
|
-
|
|
42782
|
-
|
|
42783
|
-
|
|
43473
|
+
return this.compiler.perfRecorder.inPhase(PerfPhase.LsReferencesAndRenames, () => {
|
|
43474
|
+
const templateInfo = getTemplateInfoAtPosition(filePath, position, this.compiler);
|
|
43475
|
+
if (templateInfo === undefined) {
|
|
43476
|
+
return this.getReferencesAtTypescriptPosition(filePath, position);
|
|
43477
|
+
}
|
|
43478
|
+
return this.getReferencesAtTemplatePosition(templateInfo, position);
|
|
43479
|
+
});
|
|
42784
43480
|
}
|
|
42785
43481
|
getReferencesAtTemplatePosition(templateInfo, position) {
|
|
42786
43482
|
const allTargetDetails = this.getTargetDetailsAtTemplatePosition(templateInfo, position);
|
|
@@ -43021,49 +43717,52 @@ https://v9.angular.io/guide/template-typecheck#template-type-checking`,
|
|
|
43021
43717
|
return this.options;
|
|
43022
43718
|
}
|
|
43023
43719
|
getSemanticDiagnostics(fileName) {
|
|
43024
|
-
|
|
43025
|
-
|
|
43026
|
-
|
|
43027
|
-
|
|
43028
|
-
|
|
43029
|
-
|
|
43030
|
-
|
|
43031
|
-
|
|
43032
|
-
|
|
43033
|
-
|
|
43034
|
-
|
|
43035
|
-
|
|
43036
|
-
|
|
43037
|
-
|
|
43038
|
-
|
|
43039
|
-
|
|
43040
|
-
|
|
43041
|
-
|
|
43042
|
-
|
|
43043
|
-
|
|
43044
|
-
|
|
43045
|
-
|
|
43046
|
-
|
|
43047
|
-
|
|
43048
|
-
|
|
43049
|
-
|
|
43050
|
-
|
|
43051
|
-
|
|
43720
|
+
return this.withCompilerAndPerfTracing(PerfPhase.LsDiagnostics, (compiler) => {
|
|
43721
|
+
const ttc = compiler.getTemplateTypeChecker();
|
|
43722
|
+
const diagnostics = [];
|
|
43723
|
+
if (isTypeScriptFile(fileName)) {
|
|
43724
|
+
const program = compiler.getNextProgram();
|
|
43725
|
+
const sourceFile = program.getSourceFile(fileName);
|
|
43726
|
+
if (sourceFile) {
|
|
43727
|
+
const ngDiagnostics = compiler.getDiagnosticsForFile(sourceFile, OptimizeFor.SingleFile);
|
|
43728
|
+
// There are several kinds of diagnostics returned by `NgCompiler` for a source file:
|
|
43729
|
+
//
|
|
43730
|
+
// 1. Angular-related non-template diagnostics from decorated classes within that
|
|
43731
|
+
// file.
|
|
43732
|
+
// 2. Template diagnostics for components with direct inline templates (a string
|
|
43733
|
+
// literal).
|
|
43734
|
+
// 3. Template diagnostics for components with indirect inline templates (templates
|
|
43735
|
+
// computed
|
|
43736
|
+
// by expression).
|
|
43737
|
+
// 4. Template diagnostics for components with external templates.
|
|
43738
|
+
//
|
|
43739
|
+
// When showing diagnostics for a TS source file, we want to only include kinds 1 and
|
|
43740
|
+
// 2 - those diagnostics which are reported at a location within the TS file itself.
|
|
43741
|
+
// Diagnostics for external templates will be shown when editing that template file
|
|
43742
|
+
// (the `else` block) below.
|
|
43743
|
+
//
|
|
43744
|
+
// Currently, indirect inline template diagnostics (kind 3) are not shown at all by
|
|
43745
|
+
// the Language Service, because there is no sensible location in the user's code for
|
|
43746
|
+
// them. Such templates are an edge case, though, and should not be common.
|
|
43747
|
+
//
|
|
43748
|
+
// TODO(alxhub): figure out a good user experience for indirect template diagnostics
|
|
43749
|
+
// and show them from within the Language Service.
|
|
43750
|
+
diagnostics.push(...ngDiagnostics.filter(diag => diag.file !== undefined && diag.file.fileName === sourceFile.fileName));
|
|
43751
|
+
}
|
|
43052
43752
|
}
|
|
43053
|
-
|
|
43054
|
-
|
|
43055
|
-
|
|
43056
|
-
|
|
43057
|
-
|
|
43058
|
-
|
|
43753
|
+
else {
|
|
43754
|
+
const components = compiler.getComponentsWithTemplateFile(fileName);
|
|
43755
|
+
for (const component of components) {
|
|
43756
|
+
if (ts.isClassDeclaration(component)) {
|
|
43757
|
+
diagnostics.push(...ttc.getDiagnosticsForComponent(component));
|
|
43758
|
+
}
|
|
43059
43759
|
}
|
|
43060
43760
|
}
|
|
43061
|
-
|
|
43062
|
-
|
|
43063
|
-
return diagnostics;
|
|
43761
|
+
return diagnostics;
|
|
43762
|
+
});
|
|
43064
43763
|
}
|
|
43065
43764
|
getDefinitionAndBoundSpan(fileName, position) {
|
|
43066
|
-
return this.
|
|
43765
|
+
return this.withCompilerAndPerfTracing(PerfPhase.LsDefinition, (compiler) => {
|
|
43067
43766
|
if (!isInAngularContext(compiler.getNextProgram(), fileName, position)) {
|
|
43068
43767
|
return undefined;
|
|
43069
43768
|
}
|
|
@@ -43072,7 +43771,7 @@ https://v9.angular.io/guide/template-typecheck#template-type-checking`,
|
|
|
43072
43771
|
});
|
|
43073
43772
|
}
|
|
43074
43773
|
getTypeDefinitionAtPosition(fileName, position) {
|
|
43075
|
-
return this.
|
|
43774
|
+
return this.withCompilerAndPerfTracing(PerfPhase.LsDefinition, (compiler) => {
|
|
43076
43775
|
if (!isTemplateContext(compiler.getNextProgram(), fileName, position)) {
|
|
43077
43776
|
return undefined;
|
|
43078
43777
|
}
|
|
@@ -43081,56 +43780,57 @@ https://v9.angular.io/guide/template-typecheck#template-type-checking`,
|
|
|
43081
43780
|
});
|
|
43082
43781
|
}
|
|
43083
43782
|
getQuickInfoAtPosition(fileName, position) {
|
|
43084
|
-
return this.
|
|
43085
|
-
|
|
43086
|
-
return undefined;
|
|
43087
|
-
}
|
|
43088
|
-
const templateInfo = getTemplateInfoAtPosition(fileName, position, compiler);
|
|
43089
|
-
if (templateInfo === undefined) {
|
|
43090
|
-
return undefined;
|
|
43091
|
-
}
|
|
43092
|
-
const positionDetails = getTargetAtPosition(templateInfo.template, position);
|
|
43093
|
-
if (positionDetails === null) {
|
|
43094
|
-
return undefined;
|
|
43095
|
-
}
|
|
43096
|
-
// Because we can only show 1 quick info, just use the bound attribute if the target is a two
|
|
43097
|
-
// way binding. We may consider concatenating additional display parts from the other target
|
|
43098
|
-
// nodes or representing the two way binding in some other manner in the future.
|
|
43099
|
-
const node = positionDetails.context.kind === TargetNodeKind.TwoWayBindingContext ?
|
|
43100
|
-
positionDetails.context.nodes[0] :
|
|
43101
|
-
positionDetails.context.node;
|
|
43102
|
-
return new QuickInfoBuilder(this.tsLS, compiler, templateInfo.component, node).get();
|
|
43783
|
+
return this.withCompilerAndPerfTracing(PerfPhase.LsQuickInfo, (compiler) => {
|
|
43784
|
+
return this.getQuickInfoAtPositionImpl(fileName, position, compiler);
|
|
43103
43785
|
});
|
|
43104
43786
|
}
|
|
43787
|
+
getQuickInfoAtPositionImpl(fileName, position, compiler) {
|
|
43788
|
+
if (!isTemplateContext(compiler.getNextProgram(), fileName, position)) {
|
|
43789
|
+
return undefined;
|
|
43790
|
+
}
|
|
43791
|
+
const templateInfo = getTemplateInfoAtPosition(fileName, position, compiler);
|
|
43792
|
+
if (templateInfo === undefined) {
|
|
43793
|
+
return undefined;
|
|
43794
|
+
}
|
|
43795
|
+
const positionDetails = getTargetAtPosition(templateInfo.template, position);
|
|
43796
|
+
if (positionDetails === null) {
|
|
43797
|
+
return undefined;
|
|
43798
|
+
}
|
|
43799
|
+
// Because we can only show 1 quick info, just use the bound attribute if the target is a two
|
|
43800
|
+
// way binding. We may consider concatenating additional display parts from the other target
|
|
43801
|
+
// nodes or representing the two way binding in some other manner in the future.
|
|
43802
|
+
const node = positionDetails.context.kind === TargetNodeKind.TwoWayBindingContext ?
|
|
43803
|
+
positionDetails.context.nodes[0] :
|
|
43804
|
+
positionDetails.context.node;
|
|
43805
|
+
return new QuickInfoBuilder(this.tsLS, compiler, templateInfo.component, node).get();
|
|
43806
|
+
}
|
|
43105
43807
|
getReferencesAtPosition(fileName, position) {
|
|
43106
|
-
|
|
43107
|
-
|
|
43108
|
-
|
|
43109
|
-
|
|
43110
|
-
return results;
|
|
43808
|
+
return this.withCompilerAndPerfTracing(PerfPhase.LsReferencesAndRenames, (compiler) => {
|
|
43809
|
+
return new ReferencesAndRenameBuilder(this.strategy, this.tsLS, compiler)
|
|
43810
|
+
.getReferencesAtPosition(fileName, position);
|
|
43811
|
+
});
|
|
43111
43812
|
}
|
|
43112
43813
|
getRenameInfo(fileName, position) {
|
|
43113
|
-
|
|
43114
|
-
|
|
43115
|
-
|
|
43116
|
-
|
|
43117
|
-
|
|
43118
|
-
|
|
43119
|
-
|
|
43120
|
-
|
|
43121
|
-
|
|
43122
|
-
|
|
43123
|
-
|
|
43814
|
+
return this.withCompilerAndPerfTracing(PerfPhase.LsReferencesAndRenames, (compiler) => {
|
|
43815
|
+
var _a, _b, _c;
|
|
43816
|
+
const renameInfo = new ReferencesAndRenameBuilder(this.strategy, this.tsLS, compiler)
|
|
43817
|
+
.getRenameInfo(absoluteFrom(fileName), position);
|
|
43818
|
+
if (!renameInfo.canRename) {
|
|
43819
|
+
return renameInfo;
|
|
43820
|
+
}
|
|
43821
|
+
const quickInfo = (_a = this.getQuickInfoAtPositionImpl(fileName, position, compiler)) !== null && _a !== void 0 ? _a : this.tsLS.getQuickInfoAtPosition(fileName, position);
|
|
43822
|
+
const kind = (_b = quickInfo === null || quickInfo === void 0 ? void 0 : quickInfo.kind) !== null && _b !== void 0 ? _b : ts.ScriptElementKind.unknown;
|
|
43823
|
+
const kindModifiers = (_c = quickInfo === null || quickInfo === void 0 ? void 0 : quickInfo.kindModifiers) !== null && _c !== void 0 ? _c : ts.ScriptElementKind.unknown;
|
|
43824
|
+
return Object.assign(Object.assign({}, renameInfo), { kind, kindModifiers });
|
|
43825
|
+
});
|
|
43124
43826
|
}
|
|
43125
43827
|
findRenameLocations(fileName, position) {
|
|
43126
|
-
|
|
43127
|
-
|
|
43128
|
-
|
|
43129
|
-
|
|
43130
|
-
return results;
|
|
43828
|
+
return this.withCompilerAndPerfTracing(PerfPhase.LsReferencesAndRenames, (compiler) => {
|
|
43829
|
+
return new ReferencesAndRenameBuilder(this.strategy, this.tsLS, compiler)
|
|
43830
|
+
.findRenameLocations(fileName, position);
|
|
43831
|
+
});
|
|
43131
43832
|
}
|
|
43132
|
-
getCompletionBuilder(fileName, position) {
|
|
43133
|
-
const compiler = this.compilerFactory.getOrCreate();
|
|
43833
|
+
getCompletionBuilder(fileName, position, compiler) {
|
|
43134
43834
|
const templateInfo = getTemplateInfoAtPosition(fileName, position, compiler);
|
|
43135
43835
|
if (templateInfo === undefined) {
|
|
43136
43836
|
return null;
|
|
@@ -43147,23 +43847,26 @@ https://v9.angular.io/guide/template-typecheck#template-type-checking`,
|
|
|
43147
43847
|
return new CompletionBuilder(this.tsLS, compiler, templateInfo.component, node, positionDetails, isTypeScriptFile(fileName));
|
|
43148
43848
|
}
|
|
43149
43849
|
getCompletionsAtPosition(fileName, position, options) {
|
|
43150
|
-
return this.
|
|
43151
|
-
|
|
43152
|
-
return undefined;
|
|
43153
|
-
}
|
|
43154
|
-
const builder = this.getCompletionBuilder(fileName, position);
|
|
43155
|
-
if (builder === null) {
|
|
43156
|
-
return undefined;
|
|
43157
|
-
}
|
|
43158
|
-
return builder.getCompletionsAtPosition(options);
|
|
43850
|
+
return this.withCompilerAndPerfTracing(PerfPhase.LsCompletions, (compiler) => {
|
|
43851
|
+
return this.getCompletionsAtPositionImpl(fileName, position, options, compiler);
|
|
43159
43852
|
});
|
|
43160
43853
|
}
|
|
43854
|
+
getCompletionsAtPositionImpl(fileName, position, options, compiler) {
|
|
43855
|
+
if (!isTemplateContext(compiler.getNextProgram(), fileName, position)) {
|
|
43856
|
+
return undefined;
|
|
43857
|
+
}
|
|
43858
|
+
const builder = this.getCompletionBuilder(fileName, position, compiler);
|
|
43859
|
+
if (builder === null) {
|
|
43860
|
+
return undefined;
|
|
43861
|
+
}
|
|
43862
|
+
return builder.getCompletionsAtPosition(options);
|
|
43863
|
+
}
|
|
43161
43864
|
getCompletionEntryDetails(fileName, position, entryName, formatOptions, preferences) {
|
|
43162
|
-
return this.
|
|
43865
|
+
return this.withCompilerAndPerfTracing(PerfPhase.LsCompletions, (compiler) => {
|
|
43163
43866
|
if (!isTemplateContext(compiler.getNextProgram(), fileName, position)) {
|
|
43164
43867
|
return undefined;
|
|
43165
43868
|
}
|
|
43166
|
-
const builder = this.getCompletionBuilder(fileName, position);
|
|
43869
|
+
const builder = this.getCompletionBuilder(fileName, position, compiler);
|
|
43167
43870
|
if (builder === null) {
|
|
43168
43871
|
return undefined;
|
|
43169
43872
|
}
|
|
@@ -43171,11 +43874,11 @@ https://v9.angular.io/guide/template-typecheck#template-type-checking`,
|
|
|
43171
43874
|
});
|
|
43172
43875
|
}
|
|
43173
43876
|
getCompletionEntrySymbol(fileName, position, entryName) {
|
|
43174
|
-
return this.
|
|
43877
|
+
return this.withCompilerAndPerfTracing(PerfPhase.LsCompletions, (compiler) => {
|
|
43175
43878
|
if (!isTemplateContext(compiler.getNextProgram(), fileName, position)) {
|
|
43176
43879
|
return undefined;
|
|
43177
43880
|
}
|
|
43178
|
-
const builder = this.getCompletionBuilder(fileName, position);
|
|
43881
|
+
const builder = this.getCompletionBuilder(fileName, position, compiler);
|
|
43179
43882
|
if (builder === null) {
|
|
43180
43883
|
return undefined;
|
|
43181
43884
|
}
|
|
@@ -43185,7 +43888,7 @@ https://v9.angular.io/guide/template-typecheck#template-type-checking`,
|
|
|
43185
43888
|
});
|
|
43186
43889
|
}
|
|
43187
43890
|
getTcb(fileName, position) {
|
|
43188
|
-
return this.
|
|
43891
|
+
return this.withCompilerAndPerfTracing(PerfPhase.LsTcb, compiler => {
|
|
43189
43892
|
const templateInfo = getTemplateInfoAtPosition(fileName, position, compiler);
|
|
43190
43893
|
if (templateInfo === undefined) {
|
|
43191
43894
|
return undefined;
|
|
@@ -43225,10 +43928,31 @@ https://v9.angular.io/guide/template-typecheck#template-type-checking`,
|
|
|
43225
43928
|
};
|
|
43226
43929
|
});
|
|
43227
43930
|
}
|
|
43228
|
-
|
|
43931
|
+
/**
|
|
43932
|
+
* Provides an instance of the `NgCompiler` and traces perf results. Perf results are logged only
|
|
43933
|
+
* if the log level is verbose or higher. This method is intended to be called once per public
|
|
43934
|
+
* method call.
|
|
43935
|
+
*
|
|
43936
|
+
* Here is an example of the log output.
|
|
43937
|
+
*
|
|
43938
|
+
* Perf 245 [16:16:39.353] LanguageService#getQuickInfoAtPosition(): {"events":{},"phases":{
|
|
43939
|
+
* "Unaccounted":379,"TtcSymbol":4},"memory":{}}
|
|
43940
|
+
*
|
|
43941
|
+
* Passing name of caller instead of using `arguments.caller` because 'caller', 'callee', and
|
|
43942
|
+
* 'arguments' properties may not be accessed in strict mode.
|
|
43943
|
+
*
|
|
43944
|
+
* @param phase the `PerfPhase` to execute the `p` callback in
|
|
43945
|
+
* @param p callback to be run synchronously with an instance of the `NgCompiler` as argument
|
|
43946
|
+
* @return the result of running the `p` callback
|
|
43947
|
+
*/
|
|
43948
|
+
withCompilerAndPerfTracing(phase, p) {
|
|
43229
43949
|
const compiler = this.compilerFactory.getOrCreate();
|
|
43230
|
-
const result = p(compiler);
|
|
43950
|
+
const result = compiler.perfRecorder.inPhase(phase, () => p(compiler));
|
|
43231
43951
|
this.compilerFactory.registerLastKnownProgram();
|
|
43952
|
+
const logger = this.project.projectService.logger;
|
|
43953
|
+
if (logger.hasLevel(ts.server.LogLevel.verbose)) {
|
|
43954
|
+
logger.perftrc(`LanguageService#${PerfPhase[phase]}: ${JSON.stringify(compiler.perfRecorder.finalize())}`);
|
|
43955
|
+
}
|
|
43232
43956
|
return result;
|
|
43233
43957
|
}
|
|
43234
43958
|
getCompilerOptionsDiagnostics() {
|
|
@@ -43236,22 +43960,23 @@ https://v9.angular.io/guide/template-typecheck#template-type-checking`,
|
|
|
43236
43960
|
if (!(project instanceof ts.server.ConfiguredProject)) {
|
|
43237
43961
|
return [];
|
|
43238
43962
|
}
|
|
43239
|
-
|
|
43240
|
-
|
|
43241
|
-
|
|
43242
|
-
|
|
43243
|
-
|
|
43244
|
-
'
|
|
43245
|
-
|
|
43246
|
-
|
|
43247
|
-
|
|
43248
|
-
|
|
43249
|
-
|
|
43250
|
-
|
|
43251
|
-
|
|
43252
|
-
|
|
43253
|
-
|
|
43254
|
-
|
|
43963
|
+
return this.withCompilerAndPerfTracing(PerfPhase.LsDiagnostics, (compiler) => {
|
|
43964
|
+
const diagnostics = [];
|
|
43965
|
+
const configSourceFile = ts.readJsonConfigFile(project.getConfigFilePath(), (path) => project.readFile(path));
|
|
43966
|
+
if (!this.options.strictTemplates && !this.options.fullTemplateTypeCheck) {
|
|
43967
|
+
diagnostics.push({
|
|
43968
|
+
messageText: 'Some language features are not available. ' +
|
|
43969
|
+
'To access all features, enable `strictTemplates` in `angularCompilerOptions`.',
|
|
43970
|
+
category: ts.DiagnosticCategory.Suggestion,
|
|
43971
|
+
code: ngErrorCode(ErrorCode.SUGGEST_STRICT_TEMPLATES),
|
|
43972
|
+
file: configSourceFile,
|
|
43973
|
+
start: undefined,
|
|
43974
|
+
length: undefined,
|
|
43975
|
+
});
|
|
43976
|
+
}
|
|
43977
|
+
diagnostics.push(...compiler.getOptionDiagnostics());
|
|
43978
|
+
return diagnostics;
|
|
43979
|
+
});
|
|
43255
43980
|
}
|
|
43256
43981
|
watchConfigFile(project) {
|
|
43257
43982
|
// TODO: Check the case when the project is disposed. An InferredProject
|