@angular/language-service 11.2.5 → 11.2.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bundles/ivy.js +1306 -628
- package/bundles/language-service.js +121 -51
- package/ivy/compiler_factory.js +9 -3
- package/ivy/language_service.d.ts +20 -1
- package/ivy/language_service.js +158 -124
- package/ivy/references.js +98 -82
- 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.9
|
|
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;
|
|
@@ -11388,6 +11403,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
11388
11403
|
*/
|
|
11389
11404
|
function combineHostContextSelectors(contextSelectors, otherSelectors) {
|
|
11390
11405
|
const hostMarker = _polyfillHostNoCombinator;
|
|
11406
|
+
_polyfillHostRe.lastIndex = 0; // reset the regex to ensure we get an accurate test
|
|
11391
11407
|
const otherSelectorsHasHost = _polyfillHostRe.test(otherSelectors);
|
|
11392
11408
|
// If there are no context selectors then just output a host marker
|
|
11393
11409
|
if (contextSelectors.length === 0) {
|
|
@@ -11517,7 +11533,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
11517
11533
|
return visitor.visitElement(this, context);
|
|
11518
11534
|
}
|
|
11519
11535
|
}
|
|
11520
|
-
class Comment {
|
|
11536
|
+
class Comment$1 {
|
|
11521
11537
|
constructor(value, sourceSpan) {
|
|
11522
11538
|
this.value = value;
|
|
11523
11539
|
this.sourceSpan = sourceSpan;
|
|
@@ -12547,7 +12563,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
12547
12563
|
const text = this._advanceIf(TokenType.RAW_TEXT);
|
|
12548
12564
|
this._advanceIf(TokenType.COMMENT_END);
|
|
12549
12565
|
const value = text != null ? text.parts[0].trim() : null;
|
|
12550
|
-
this._addToParent(new Comment(value, token.sourceSpan));
|
|
12566
|
+
this._addToParent(new Comment$1(value, token.sourceSpan));
|
|
12551
12567
|
}
|
|
12552
12568
|
_consumeExpansion(token) {
|
|
12553
12569
|
const switchValue = this._advance();
|
|
@@ -13755,7 +13771,11 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
13755
13771
|
if (isEmptyExpression(value)) {
|
|
13756
13772
|
return null;
|
|
13757
13773
|
}
|
|
13758
|
-
|
|
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
|
+
}
|
|
13759
13779
|
const { property, hasOverrideFlag, suffix: bindingSuffix } = parseProperty(name);
|
|
13760
13780
|
suffix = typeof suffix === 'string' && suffix.length !== 0 ? suffix : bindingSuffix;
|
|
13761
13781
|
const entry = { name: property, suffix: suffix, value, sourceSpan, hasOverrideFlag };
|
|
@@ -13779,9 +13799,6 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
13779
13799
|
const { property, hasOverrideFlag } = parseProperty(name);
|
|
13780
13800
|
const entry = { name: property, value, sourceSpan, hasOverrideFlag, suffix: null };
|
|
13781
13801
|
if (isMapBased) {
|
|
13782
|
-
if (this._classMapInput) {
|
|
13783
|
-
throw new Error('[class] and [className] bindings cannot be used on the same element simultaneously');
|
|
13784
|
-
}
|
|
13785
13802
|
this._classMapInput = entry;
|
|
13786
13803
|
}
|
|
13787
13804
|
else {
|
|
@@ -14103,8 +14120,12 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
14103
14120
|
return Identifiers$1.stylePropInterpolateV;
|
|
14104
14121
|
}
|
|
14105
14122
|
}
|
|
14106
|
-
|
|
14107
|
-
|
|
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('--');
|
|
14108
14129
|
}
|
|
14109
14130
|
|
|
14110
14131
|
/**
|
|
@@ -16222,26 +16243,33 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
16222
16243
|
EVENT: { start: '(', end: ')' },
|
|
16223
16244
|
};
|
|
16224
16245
|
const TEMPLATE_ATTR_PREFIX$1 = '*';
|
|
16225
|
-
function htmlAstToRender3Ast(htmlNodes, bindingParser) {
|
|
16226
|
-
const transformer = new HtmlAstToIvyAst(bindingParser);
|
|
16246
|
+
function htmlAstToRender3Ast(htmlNodes, bindingParser, options) {
|
|
16247
|
+
const transformer = new HtmlAstToIvyAst(bindingParser, options);
|
|
16227
16248
|
const ivyNodes = visitAll$1(transformer, htmlNodes);
|
|
16228
16249
|
// Errors might originate in either the binding parser or the html to ivy transformer
|
|
16229
16250
|
const allErrors = bindingParser.errors.concat(transformer.errors);
|
|
16230
|
-
|
|
16251
|
+
const result = {
|
|
16231
16252
|
nodes: ivyNodes,
|
|
16232
16253
|
errors: allErrors,
|
|
16233
16254
|
styleUrls: transformer.styleUrls,
|
|
16234
16255
|
styles: transformer.styles,
|
|
16235
|
-
ngContentSelectors: transformer.ngContentSelectors
|
|
16256
|
+
ngContentSelectors: transformer.ngContentSelectors
|
|
16236
16257
|
};
|
|
16258
|
+
if (options.collectCommentNodes) {
|
|
16259
|
+
result.commentNodes = transformer.commentNodes;
|
|
16260
|
+
}
|
|
16261
|
+
return result;
|
|
16237
16262
|
}
|
|
16238
16263
|
class HtmlAstToIvyAst {
|
|
16239
|
-
constructor(bindingParser) {
|
|
16264
|
+
constructor(bindingParser, options) {
|
|
16240
16265
|
this.bindingParser = bindingParser;
|
|
16266
|
+
this.options = options;
|
|
16241
16267
|
this.errors = [];
|
|
16242
16268
|
this.styles = [];
|
|
16243
16269
|
this.styleUrls = [];
|
|
16244
16270
|
this.ngContentSelectors = [];
|
|
16271
|
+
// This array will be populated if `Render3ParseOptions['collectCommentNodes']` is true
|
|
16272
|
+
this.commentNodes = [];
|
|
16245
16273
|
this.inI18nBlock = false;
|
|
16246
16274
|
}
|
|
16247
16275
|
// HTML visitor
|
|
@@ -16410,6 +16438,9 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
16410
16438
|
return null;
|
|
16411
16439
|
}
|
|
16412
16440
|
visitComment(comment) {
|
|
16441
|
+
if (this.options.collectCommentNodes) {
|
|
16442
|
+
this.commentNodes.push(new Comment(comment.value || '', comment.sourceSpan));
|
|
16443
|
+
}
|
|
16413
16444
|
return null;
|
|
16414
16445
|
}
|
|
16415
16446
|
// convert view engine `ParsedProperty` to a format suitable for IVY
|
|
@@ -16601,7 +16632,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
16601
16632
|
return node instanceof Text$2 && node.value.trim().length == 0;
|
|
16602
16633
|
}
|
|
16603
16634
|
function isCommentNode(node) {
|
|
16604
|
-
return node instanceof Comment;
|
|
16635
|
+
return node instanceof Comment$1;
|
|
16605
16636
|
}
|
|
16606
16637
|
function textContents(node) {
|
|
16607
16638
|
if (node.children.length !== 1 || !(node.children[0] instanceof Text$2)) {
|
|
@@ -19178,7 +19209,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
19178
19209
|
const parseResult = htmlParser.parse(template, templateUrl, Object.assign(Object.assign({ leadingTriviaChars: LEADING_TRIVIA_CHARS }, options), { tokenizeExpansionForms: true }));
|
|
19179
19210
|
if (!options.alwaysAttemptHtmlToR3AstConversion && parseResult.errors &&
|
|
19180
19211
|
parseResult.errors.length > 0) {
|
|
19181
|
-
|
|
19212
|
+
const parsedTemplate = {
|
|
19182
19213
|
interpolationConfig,
|
|
19183
19214
|
preserveWhitespaces,
|
|
19184
19215
|
template,
|
|
@@ -19190,6 +19221,10 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
19190
19221
|
styles: [],
|
|
19191
19222
|
ngContentSelectors: []
|
|
19192
19223
|
};
|
|
19224
|
+
if (options.collectCommentNodes) {
|
|
19225
|
+
parsedTemplate.commentNodes = [];
|
|
19226
|
+
}
|
|
19227
|
+
return parsedTemplate;
|
|
19193
19228
|
}
|
|
19194
19229
|
let rootNodes = parseResult.rootNodes;
|
|
19195
19230
|
// process i18n meta information (scan attributes, generate ids)
|
|
@@ -19200,7 +19235,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
19200
19235
|
const i18nMetaResult = i18nMetaVisitor.visitAllWithErrors(rootNodes);
|
|
19201
19236
|
if (!options.alwaysAttemptHtmlToR3AstConversion && i18nMetaResult.errors &&
|
|
19202
19237
|
i18nMetaResult.errors.length > 0) {
|
|
19203
|
-
|
|
19238
|
+
const parsedTemplate = {
|
|
19204
19239
|
interpolationConfig,
|
|
19205
19240
|
preserveWhitespaces,
|
|
19206
19241
|
template,
|
|
@@ -19212,6 +19247,10 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
19212
19247
|
styles: [],
|
|
19213
19248
|
ngContentSelectors: []
|
|
19214
19249
|
};
|
|
19250
|
+
if (options.collectCommentNodes) {
|
|
19251
|
+
parsedTemplate.commentNodes = [];
|
|
19252
|
+
}
|
|
19253
|
+
return parsedTemplate;
|
|
19215
19254
|
}
|
|
19216
19255
|
rootNodes = i18nMetaResult.rootNodes;
|
|
19217
19256
|
if (!preserveWhitespaces) {
|
|
@@ -19224,9 +19263,9 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
19224
19263
|
rootNodes = visitAll$1(new I18nMetaVisitor(interpolationConfig, /* keepI18nAttrs */ false), rootNodes);
|
|
19225
19264
|
}
|
|
19226
19265
|
}
|
|
19227
|
-
const { nodes, errors, styleUrls, styles, ngContentSelectors } = htmlAstToRender3Ast(rootNodes, bindingParser);
|
|
19266
|
+
const { nodes, errors, styleUrls, styles, ngContentSelectors, commentNodes } = htmlAstToRender3Ast(rootNodes, bindingParser, { collectCommentNodes: !!options.collectCommentNodes });
|
|
19228
19267
|
errors.push(...parseResult.errors, ...i18nMetaResult.errors);
|
|
19229
|
-
|
|
19268
|
+
const parsedTemplate = {
|
|
19230
19269
|
interpolationConfig,
|
|
19231
19270
|
preserveWhitespaces,
|
|
19232
19271
|
errors: errors.length > 0 ? errors : null,
|
|
@@ -19238,6 +19277,10 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
19238
19277
|
styles,
|
|
19239
19278
|
ngContentSelectors
|
|
19240
19279
|
};
|
|
19280
|
+
if (options.collectCommentNodes) {
|
|
19281
|
+
parsedTemplate.commentNodes = commentNodes;
|
|
19282
|
+
}
|
|
19283
|
+
return parsedTemplate;
|
|
19241
19284
|
}
|
|
19242
19285
|
const elementRegistry = new DomElementSchemaRegistry();
|
|
19243
19286
|
/**
|
|
@@ -20356,7 +20399,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
20356
20399
|
* Use of this source code is governed by an MIT-style license that can be
|
|
20357
20400
|
* found in the LICENSE file at https://angular.io/license
|
|
20358
20401
|
*/
|
|
20359
|
-
const VERSION$1 = new Version('11.2.
|
|
20402
|
+
const VERSION$1 = new Version('11.2.9');
|
|
20360
20403
|
|
|
20361
20404
|
/**
|
|
20362
20405
|
* @license
|
|
@@ -21013,7 +21056,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
21013
21056
|
*/
|
|
21014
21057
|
function createDirectiveDefinitionMap(meta) {
|
|
21015
21058
|
const definitionMap = new DefinitionMap();
|
|
21016
|
-
definitionMap.set('version', literal('11.2.
|
|
21059
|
+
definitionMap.set('version', literal('11.2.9'));
|
|
21017
21060
|
// e.g. `type: MyDirective`
|
|
21018
21061
|
definitionMap.set('type', meta.internalType);
|
|
21019
21062
|
// e.g. `selector: 'some-dir'`
|
|
@@ -21234,7 +21277,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
21234
21277
|
*/
|
|
21235
21278
|
function createPipeDefinitionMap(meta) {
|
|
21236
21279
|
const definitionMap = new DefinitionMap();
|
|
21237
|
-
definitionMap.set('version', literal('11.2.
|
|
21280
|
+
definitionMap.set('version', literal('11.2.9'));
|
|
21238
21281
|
definitionMap.set('ngImport', importExpr(Identifiers$1.core));
|
|
21239
21282
|
// e.g. `type: MyPipe`
|
|
21240
21283
|
definitionMap.set('type', meta.internalType);
|
|
@@ -21266,7 +21309,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
21266
21309
|
* Use of this source code is governed by an MIT-style license that can be
|
|
21267
21310
|
* found in the LICENSE file at https://angular.io/license
|
|
21268
21311
|
*/
|
|
21269
|
-
const VERSION$2 = new Version('11.2.
|
|
21312
|
+
const VERSION$2 = new Version('11.2.9');
|
|
21270
21313
|
|
|
21271
21314
|
/**
|
|
21272
21315
|
* @license
|
|
@@ -21468,14 +21511,20 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
21468
21511
|
* An injectable already has a `ɵprov` property.
|
|
21469
21512
|
*/
|
|
21470
21513
|
ErrorCode[ErrorCode["INJECTABLE_DUPLICATE_PROV"] = 9001] = "INJECTABLE_DUPLICATE_PROV";
|
|
21471
|
-
// 10XXX error codes are reserved for diagnostics with
|
|
21472
|
-
// `ts.DiagnosticCategory.
|
|
21473
|
-
//
|
|
21514
|
+
// 10XXX error codes are reserved for diagnostics with categories other than
|
|
21515
|
+
// `ts.DiagnosticCategory.Error`. These diagnostics are generated by the compiler when configured
|
|
21516
|
+
// to do so by a tool such as the Language Service, or by the Language Service itself.
|
|
21474
21517
|
/**
|
|
21475
21518
|
* Suggest users to enable `strictTemplates` to make use of full capabilities
|
|
21476
21519
|
* provided by Angular language service.
|
|
21477
21520
|
*/
|
|
21478
21521
|
ErrorCode[ErrorCode["SUGGEST_STRICT_TEMPLATES"] = 10001] = "SUGGEST_STRICT_TEMPLATES";
|
|
21522
|
+
/**
|
|
21523
|
+
* Indicates that a particular structural directive provides advanced type narrowing
|
|
21524
|
+
* functionality, but the current template type-checking configuration does not allow its usage in
|
|
21525
|
+
* type inference.
|
|
21526
|
+
*/
|
|
21527
|
+
ErrorCode[ErrorCode["SUGGEST_SUBOPTIMAL_TYPE_INFERENCE"] = 10002] = "SUGGEST_SUBOPTIMAL_TYPE_INFERENCE";
|
|
21479
21528
|
})(ErrorCode || (ErrorCode = {}));
|
|
21480
21529
|
/**
|
|
21481
21530
|
* @internal
|
|
@@ -25488,6 +25537,417 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
25488
25537
|
}
|
|
25489
25538
|
}
|
|
25490
25539
|
|
|
25540
|
+
/**
|
|
25541
|
+
* @license
|
|
25542
|
+
* Copyright Google LLC All Rights Reserved.
|
|
25543
|
+
*
|
|
25544
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
25545
|
+
* found in the LICENSE file at https://angular.io/license
|
|
25546
|
+
*/
|
|
25547
|
+
/**
|
|
25548
|
+
* A phase of compilation for which time is tracked in a distinct bucket.
|
|
25549
|
+
*/
|
|
25550
|
+
var PerfPhase;
|
|
25551
|
+
(function (PerfPhase) {
|
|
25552
|
+
/**
|
|
25553
|
+
* The "default" phase which tracks time not spent in any other phase.
|
|
25554
|
+
*/
|
|
25555
|
+
PerfPhase[PerfPhase["Unaccounted"] = 0] = "Unaccounted";
|
|
25556
|
+
/**
|
|
25557
|
+
* Time spent setting up the compiler, before a TypeScript program is created.
|
|
25558
|
+
*
|
|
25559
|
+
* This includes operations like configuring the `ts.CompilerHost` and any wrappers.
|
|
25560
|
+
*/
|
|
25561
|
+
PerfPhase[PerfPhase["Setup"] = 1] = "Setup";
|
|
25562
|
+
/**
|
|
25563
|
+
* Time spent in `ts.createProgram`, including reading and parsing `ts.SourceFile`s in the
|
|
25564
|
+
* `ts.CompilerHost`.
|
|
25565
|
+
*
|
|
25566
|
+
* This might be an incremental program creation operation.
|
|
25567
|
+
*/
|
|
25568
|
+
PerfPhase[PerfPhase["TypeScriptProgramCreate"] = 2] = "TypeScriptProgramCreate";
|
|
25569
|
+
/**
|
|
25570
|
+
* Time spent reconciling the contents of an old `ts.Program` with the new incremental one.
|
|
25571
|
+
*
|
|
25572
|
+
* Only present in incremental compilations.
|
|
25573
|
+
*/
|
|
25574
|
+
PerfPhase[PerfPhase["Reconciliation"] = 3] = "Reconciliation";
|
|
25575
|
+
/**
|
|
25576
|
+
* Time spent updating an `NgCompiler` instance with a resource-only change.
|
|
25577
|
+
*
|
|
25578
|
+
* Only present in incremental compilations where the change was resource-only.
|
|
25579
|
+
*/
|
|
25580
|
+
PerfPhase[PerfPhase["ResourceUpdate"] = 4] = "ResourceUpdate";
|
|
25581
|
+
/**
|
|
25582
|
+
* Time spent calculating the plain TypeScript diagnostics (structural and semantic).
|
|
25583
|
+
*/
|
|
25584
|
+
PerfPhase[PerfPhase["TypeScriptDiagnostics"] = 5] = "TypeScriptDiagnostics";
|
|
25585
|
+
/**
|
|
25586
|
+
* Time spent in Angular analysis of individual classes in the program.
|
|
25587
|
+
*/
|
|
25588
|
+
PerfPhase[PerfPhase["Analysis"] = 6] = "Analysis";
|
|
25589
|
+
/**
|
|
25590
|
+
* Time spent in Angular global analysis (synthesis of analysis information into a complete
|
|
25591
|
+
* understanding of the program).
|
|
25592
|
+
*/
|
|
25593
|
+
PerfPhase[PerfPhase["Resolve"] = 7] = "Resolve";
|
|
25594
|
+
/**
|
|
25595
|
+
* Time spent building the import graph of the program in order to perform cycle detection.
|
|
25596
|
+
*/
|
|
25597
|
+
PerfPhase[PerfPhase["CycleDetection"] = 8] = "CycleDetection";
|
|
25598
|
+
/**
|
|
25599
|
+
* Time spent generating the text of Type Check Blocks in order to perform template type checking.
|
|
25600
|
+
*/
|
|
25601
|
+
PerfPhase[PerfPhase["TcbGeneration"] = 9] = "TcbGeneration";
|
|
25602
|
+
/**
|
|
25603
|
+
* Time spent updating the `ts.Program` with new Type Check Block code.
|
|
25604
|
+
*/
|
|
25605
|
+
PerfPhase[PerfPhase["TcbUpdateProgram"] = 10] = "TcbUpdateProgram";
|
|
25606
|
+
/**
|
|
25607
|
+
* Time spent by TypeScript performing its emit operations, including downleveling and writing
|
|
25608
|
+
* output files.
|
|
25609
|
+
*/
|
|
25610
|
+
PerfPhase[PerfPhase["TypeScriptEmit"] = 11] = "TypeScriptEmit";
|
|
25611
|
+
/**
|
|
25612
|
+
* Time spent by Angular performing code transformations of ASTs as they're about to be emitted.
|
|
25613
|
+
*
|
|
25614
|
+
* This includes the actual code generation step for templates, and occurs during the emit phase
|
|
25615
|
+
* (but is tracked separately from `TypeScriptEmit` time).
|
|
25616
|
+
*/
|
|
25617
|
+
PerfPhase[PerfPhase["Compile"] = 12] = "Compile";
|
|
25618
|
+
/**
|
|
25619
|
+
* Time spent performing a `TemplateTypeChecker` autocompletion operation.
|
|
25620
|
+
*/
|
|
25621
|
+
PerfPhase[PerfPhase["TtcAutocompletion"] = 13] = "TtcAutocompletion";
|
|
25622
|
+
/**
|
|
25623
|
+
* Time spent computing template type-checking diagnostics.
|
|
25624
|
+
*/
|
|
25625
|
+
PerfPhase[PerfPhase["TtcDiagnostics"] = 14] = "TtcDiagnostics";
|
|
25626
|
+
/**
|
|
25627
|
+
* Time spent getting a `Symbol` from the `TemplateTypeChecker`.
|
|
25628
|
+
*/
|
|
25629
|
+
PerfPhase[PerfPhase["TtcSymbol"] = 15] = "TtcSymbol";
|
|
25630
|
+
/**
|
|
25631
|
+
* Time spent by the Angular Language Service calculating a "get references" or a renaming
|
|
25632
|
+
* operation.
|
|
25633
|
+
*/
|
|
25634
|
+
PerfPhase[PerfPhase["LsReferencesAndRenames"] = 16] = "LsReferencesAndRenames";
|
|
25635
|
+
/**
|
|
25636
|
+
* Time spent by the Angular Language Service calculating a "quick info" operation.
|
|
25637
|
+
*/
|
|
25638
|
+
PerfPhase[PerfPhase["LsQuickInfo"] = 17] = "LsQuickInfo";
|
|
25639
|
+
/**
|
|
25640
|
+
* Time spent by the Angular Language Service calculating a "get type definition" or "get
|
|
25641
|
+
* definition" operation.
|
|
25642
|
+
*/
|
|
25643
|
+
PerfPhase[PerfPhase["LsDefinition"] = 18] = "LsDefinition";
|
|
25644
|
+
/**
|
|
25645
|
+
* Time spent by the Angular Language Service calculating a "get completions" (AKA autocomplete)
|
|
25646
|
+
* operation.
|
|
25647
|
+
*/
|
|
25648
|
+
PerfPhase[PerfPhase["LsCompletions"] = 19] = "LsCompletions";
|
|
25649
|
+
/**
|
|
25650
|
+
* Time spent by the Angular Language Service calculating a "view template typecheck block"
|
|
25651
|
+
* operation.
|
|
25652
|
+
*/
|
|
25653
|
+
PerfPhase[PerfPhase["LsTcb"] = 20] = "LsTcb";
|
|
25654
|
+
/**
|
|
25655
|
+
* Time spent by the Angular Language Service calculating diagnostics.
|
|
25656
|
+
*/
|
|
25657
|
+
PerfPhase[PerfPhase["LsDiagnostics"] = 21] = "LsDiagnostics";
|
|
25658
|
+
/**
|
|
25659
|
+
* Time spent by the Angular Language Service calculating a "get component locations for template"
|
|
25660
|
+
* operation.
|
|
25661
|
+
*/
|
|
25662
|
+
PerfPhase[PerfPhase["LsComponentLocations"] = 22] = "LsComponentLocations";
|
|
25663
|
+
/**
|
|
25664
|
+
* Tracks the number of `PerfPhase`s, and must appear at the end of the list.
|
|
25665
|
+
*/
|
|
25666
|
+
PerfPhase[PerfPhase["LAST"] = 23] = "LAST";
|
|
25667
|
+
})(PerfPhase || (PerfPhase = {}));
|
|
25668
|
+
/**
|
|
25669
|
+
* Represents some occurrence during compilation, and is tracked with a counter.
|
|
25670
|
+
*/
|
|
25671
|
+
var PerfEvent;
|
|
25672
|
+
(function (PerfEvent) {
|
|
25673
|
+
/**
|
|
25674
|
+
* Counts the number of `.d.ts` files in the program.
|
|
25675
|
+
*/
|
|
25676
|
+
PerfEvent[PerfEvent["InputDtsFile"] = 0] = "InputDtsFile";
|
|
25677
|
+
/**
|
|
25678
|
+
* Counts the number of non-`.d.ts` files in the program.
|
|
25679
|
+
*/
|
|
25680
|
+
PerfEvent[PerfEvent["InputTsFile"] = 1] = "InputTsFile";
|
|
25681
|
+
/**
|
|
25682
|
+
* An `@Component` class was analyzed.
|
|
25683
|
+
*/
|
|
25684
|
+
PerfEvent[PerfEvent["AnalyzeComponent"] = 2] = "AnalyzeComponent";
|
|
25685
|
+
/**
|
|
25686
|
+
* An `@Directive` class was analyzed.
|
|
25687
|
+
*/
|
|
25688
|
+
PerfEvent[PerfEvent["AnalyzeDirective"] = 3] = "AnalyzeDirective";
|
|
25689
|
+
/**
|
|
25690
|
+
* An `@Injectable` class was analyzed.
|
|
25691
|
+
*/
|
|
25692
|
+
PerfEvent[PerfEvent["AnalyzeInjectable"] = 4] = "AnalyzeInjectable";
|
|
25693
|
+
/**
|
|
25694
|
+
* An `@NgModule` class was analyzed.
|
|
25695
|
+
*/
|
|
25696
|
+
PerfEvent[PerfEvent["AnalyzeNgModule"] = 5] = "AnalyzeNgModule";
|
|
25697
|
+
/**
|
|
25698
|
+
* An `@Pipe` class was analyzed.
|
|
25699
|
+
*/
|
|
25700
|
+
PerfEvent[PerfEvent["AnalyzePipe"] = 6] = "AnalyzePipe";
|
|
25701
|
+
/**
|
|
25702
|
+
* A trait was analyzed.
|
|
25703
|
+
*
|
|
25704
|
+
* In theory, this should be the sum of the `Analyze` counters for each decorator type.
|
|
25705
|
+
*/
|
|
25706
|
+
PerfEvent[PerfEvent["TraitAnalyze"] = 7] = "TraitAnalyze";
|
|
25707
|
+
/**
|
|
25708
|
+
* A trait had a prior analysis available from an incremental program, and did not need to be
|
|
25709
|
+
* re-analyzed.
|
|
25710
|
+
*/
|
|
25711
|
+
PerfEvent[PerfEvent["TraitReuseAnalysis"] = 8] = "TraitReuseAnalysis";
|
|
25712
|
+
/**
|
|
25713
|
+
* A `ts.SourceFile` directly changed between the prior program and a new incremental compilation.
|
|
25714
|
+
*/
|
|
25715
|
+
PerfEvent[PerfEvent["SourceFilePhysicalChange"] = 9] = "SourceFilePhysicalChange";
|
|
25716
|
+
/**
|
|
25717
|
+
* A `ts.SourceFile` did not physically changed, but according to the file dependency graph, has
|
|
25718
|
+
* logically changed between the prior program and a new incremental compilation.
|
|
25719
|
+
*/
|
|
25720
|
+
PerfEvent[PerfEvent["SourceFileLogicalChange"] = 10] = "SourceFileLogicalChange";
|
|
25721
|
+
/**
|
|
25722
|
+
* A `ts.SourceFile` has not logically changed and all of its analysis results were thus available
|
|
25723
|
+
* for reuse.
|
|
25724
|
+
*/
|
|
25725
|
+
PerfEvent[PerfEvent["SourceFileReuseAnalysis"] = 11] = "SourceFileReuseAnalysis";
|
|
25726
|
+
/**
|
|
25727
|
+
* A Type Check Block (TCB) was generated.
|
|
25728
|
+
*/
|
|
25729
|
+
PerfEvent[PerfEvent["GenerateTcb"] = 12] = "GenerateTcb";
|
|
25730
|
+
/**
|
|
25731
|
+
* A Type Check Block (TCB) could not be generated because inlining was disabled, and the block
|
|
25732
|
+
* would've required inlining.
|
|
25733
|
+
*/
|
|
25734
|
+
PerfEvent[PerfEvent["SkipGenerateTcbNoInline"] = 13] = "SkipGenerateTcbNoInline";
|
|
25735
|
+
/**
|
|
25736
|
+
* A `.ngtypecheck.ts` file could be reused from the previous program and did not need to be
|
|
25737
|
+
* regenerated.
|
|
25738
|
+
*/
|
|
25739
|
+
PerfEvent[PerfEvent["ReuseTypeCheckFile"] = 14] = "ReuseTypeCheckFile";
|
|
25740
|
+
/**
|
|
25741
|
+
* The template type-checking program required changes and had to be updated in an incremental
|
|
25742
|
+
* step.
|
|
25743
|
+
*/
|
|
25744
|
+
PerfEvent[PerfEvent["UpdateTypeCheckProgram"] = 15] = "UpdateTypeCheckProgram";
|
|
25745
|
+
/**
|
|
25746
|
+
* The compiler was able to prove that a `ts.SourceFile` did not need to be re-emitted.
|
|
25747
|
+
*/
|
|
25748
|
+
PerfEvent[PerfEvent["EmitSkipSourceFile"] = 16] = "EmitSkipSourceFile";
|
|
25749
|
+
/**
|
|
25750
|
+
* A `ts.SourceFile` was emitted.
|
|
25751
|
+
*/
|
|
25752
|
+
PerfEvent[PerfEvent["EmitSourceFile"] = 17] = "EmitSourceFile";
|
|
25753
|
+
/**
|
|
25754
|
+
* Tracks the number of `PrefEvent`s, and must appear at the end of the list.
|
|
25755
|
+
*/
|
|
25756
|
+
PerfEvent[PerfEvent["LAST"] = 18] = "LAST";
|
|
25757
|
+
})(PerfEvent || (PerfEvent = {}));
|
|
25758
|
+
/**
|
|
25759
|
+
* Represents a checkpoint during compilation at which the memory usage of the compiler should be
|
|
25760
|
+
* recorded.
|
|
25761
|
+
*/
|
|
25762
|
+
var PerfCheckpoint;
|
|
25763
|
+
(function (PerfCheckpoint) {
|
|
25764
|
+
/**
|
|
25765
|
+
* The point at which the `PerfRecorder` was created, and ideally tracks memory used before any
|
|
25766
|
+
* compilation structures are created.
|
|
25767
|
+
*/
|
|
25768
|
+
PerfCheckpoint[PerfCheckpoint["Initial"] = 0] = "Initial";
|
|
25769
|
+
/**
|
|
25770
|
+
* The point just after the `ts.Program` has been created.
|
|
25771
|
+
*/
|
|
25772
|
+
PerfCheckpoint[PerfCheckpoint["TypeScriptProgramCreate"] = 1] = "TypeScriptProgramCreate";
|
|
25773
|
+
/**
|
|
25774
|
+
* The point just before Angular analysis starts.
|
|
25775
|
+
*
|
|
25776
|
+
* In the main usage pattern for the compiler, TypeScript diagnostics have been calculated at this
|
|
25777
|
+
* point, so the `ts.TypeChecker` has fully ingested the current program, all `ts.Type` structures
|
|
25778
|
+
* and `ts.Symbol`s have been created.
|
|
25779
|
+
*/
|
|
25780
|
+
PerfCheckpoint[PerfCheckpoint["PreAnalysis"] = 2] = "PreAnalysis";
|
|
25781
|
+
/**
|
|
25782
|
+
* The point just after Angular analysis completes.
|
|
25783
|
+
*/
|
|
25784
|
+
PerfCheckpoint[PerfCheckpoint["Analysis"] = 3] = "Analysis";
|
|
25785
|
+
/**
|
|
25786
|
+
* The point just after Angular resolution is complete.
|
|
25787
|
+
*/
|
|
25788
|
+
PerfCheckpoint[PerfCheckpoint["Resolve"] = 4] = "Resolve";
|
|
25789
|
+
/**
|
|
25790
|
+
* The point just after Type Check Blocks (TCBs) have been generated.
|
|
25791
|
+
*/
|
|
25792
|
+
PerfCheckpoint[PerfCheckpoint["TtcGeneration"] = 5] = "TtcGeneration";
|
|
25793
|
+
/**
|
|
25794
|
+
* The point just after the template type-checking program has been updated with any new TCBs.
|
|
25795
|
+
*/
|
|
25796
|
+
PerfCheckpoint[PerfCheckpoint["TtcUpdateProgram"] = 6] = "TtcUpdateProgram";
|
|
25797
|
+
/**
|
|
25798
|
+
* The point just before emit begins.
|
|
25799
|
+
*
|
|
25800
|
+
* In the main usage pattern for the compiler, all template type-checking diagnostics have been
|
|
25801
|
+
* requested at this point.
|
|
25802
|
+
*/
|
|
25803
|
+
PerfCheckpoint[PerfCheckpoint["PreEmit"] = 7] = "PreEmit";
|
|
25804
|
+
/**
|
|
25805
|
+
* The point just after the program has been fully emitted.
|
|
25806
|
+
*/
|
|
25807
|
+
PerfCheckpoint[PerfCheckpoint["Emit"] = 8] = "Emit";
|
|
25808
|
+
/**
|
|
25809
|
+
* Tracks the number of `PerfCheckpoint`s, and must appear at the end of the list.
|
|
25810
|
+
*/
|
|
25811
|
+
PerfCheckpoint[PerfCheckpoint["LAST"] = 9] = "LAST";
|
|
25812
|
+
})(PerfCheckpoint || (PerfCheckpoint = {}));
|
|
25813
|
+
|
|
25814
|
+
/**
|
|
25815
|
+
* @license
|
|
25816
|
+
* Copyright Google LLC All Rights Reserved.
|
|
25817
|
+
*
|
|
25818
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
25819
|
+
* found in the LICENSE file at https://angular.io/license
|
|
25820
|
+
*/
|
|
25821
|
+
function mark() {
|
|
25822
|
+
return process.hrtime();
|
|
25823
|
+
}
|
|
25824
|
+
function timeSinceInMicros(mark) {
|
|
25825
|
+
const delta = process.hrtime(mark);
|
|
25826
|
+
return (delta[0] * 1000000) + Math.floor(delta[1] / 1000);
|
|
25827
|
+
}
|
|
25828
|
+
|
|
25829
|
+
/**
|
|
25830
|
+
* @license
|
|
25831
|
+
* Copyright Google LLC All Rights Reserved.
|
|
25832
|
+
*
|
|
25833
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
25834
|
+
* found in the LICENSE file at https://angular.io/license
|
|
25835
|
+
*/
|
|
25836
|
+
/**
|
|
25837
|
+
* A `PerfRecorder` that actively tracks performance statistics.
|
|
25838
|
+
*/
|
|
25839
|
+
class ActivePerfRecorder {
|
|
25840
|
+
constructor(zeroTime) {
|
|
25841
|
+
this.zeroTime = zeroTime;
|
|
25842
|
+
this.currentPhase = PerfPhase.Unaccounted;
|
|
25843
|
+
this.currentPhaseEntered = this.zeroTime;
|
|
25844
|
+
this.counters = Array(PerfEvent.LAST).fill(0);
|
|
25845
|
+
this.phaseTime = Array(PerfPhase.LAST).fill(0);
|
|
25846
|
+
this.bytes = Array(PerfCheckpoint.LAST).fill(0);
|
|
25847
|
+
// Take an initial memory snapshot before any other compilation work begins.
|
|
25848
|
+
this.memory(PerfCheckpoint.Initial);
|
|
25849
|
+
}
|
|
25850
|
+
/**
|
|
25851
|
+
* Creates an `ActivePerfRecoder` with its zero point set to the current time.
|
|
25852
|
+
*/
|
|
25853
|
+
static zeroedToNow() {
|
|
25854
|
+
return new ActivePerfRecorder(mark());
|
|
25855
|
+
}
|
|
25856
|
+
reset() {
|
|
25857
|
+
this.counters = Array(PerfEvent.LAST).fill(0);
|
|
25858
|
+
this.phaseTime = Array(PerfPhase.LAST).fill(0);
|
|
25859
|
+
this.bytes = Array(PerfCheckpoint.LAST).fill(0);
|
|
25860
|
+
this.zeroTime = mark();
|
|
25861
|
+
this.currentPhase = PerfPhase.Unaccounted;
|
|
25862
|
+
this.currentPhaseEntered = this.zeroTime;
|
|
25863
|
+
}
|
|
25864
|
+
memory(after) {
|
|
25865
|
+
this.bytes[after] = process.memoryUsage().heapUsed;
|
|
25866
|
+
}
|
|
25867
|
+
phase(phase) {
|
|
25868
|
+
const previous = this.currentPhase;
|
|
25869
|
+
this.phaseTime[this.currentPhase] += timeSinceInMicros(this.currentPhaseEntered);
|
|
25870
|
+
this.currentPhase = phase;
|
|
25871
|
+
this.currentPhaseEntered = mark();
|
|
25872
|
+
return previous;
|
|
25873
|
+
}
|
|
25874
|
+
inPhase(phase, fn) {
|
|
25875
|
+
const previousPhase = this.phase(phase);
|
|
25876
|
+
try {
|
|
25877
|
+
return fn();
|
|
25878
|
+
}
|
|
25879
|
+
finally {
|
|
25880
|
+
this.phase(previousPhase);
|
|
25881
|
+
}
|
|
25882
|
+
}
|
|
25883
|
+
eventCount(counter, incrementBy = 1) {
|
|
25884
|
+
this.counters[counter] += incrementBy;
|
|
25885
|
+
}
|
|
25886
|
+
/**
|
|
25887
|
+
* Return the current performance metrics as a serializable object.
|
|
25888
|
+
*/
|
|
25889
|
+
finalize() {
|
|
25890
|
+
// Track the last segment of time spent in `this.currentPhase` in the time array.
|
|
25891
|
+
this.phase(PerfPhase.Unaccounted);
|
|
25892
|
+
const results = {
|
|
25893
|
+
events: {},
|
|
25894
|
+
phases: {},
|
|
25895
|
+
memory: {},
|
|
25896
|
+
};
|
|
25897
|
+
for (let i = 0; i < this.phaseTime.length; i++) {
|
|
25898
|
+
if (this.phaseTime[i] > 0) {
|
|
25899
|
+
results.phases[PerfPhase[i]] = this.phaseTime[i];
|
|
25900
|
+
}
|
|
25901
|
+
}
|
|
25902
|
+
for (let i = 0; i < this.phaseTime.length; i++) {
|
|
25903
|
+
if (this.counters[i] > 0) {
|
|
25904
|
+
results.events[PerfEvent[i]] = this.counters[i];
|
|
25905
|
+
}
|
|
25906
|
+
}
|
|
25907
|
+
for (let i = 0; i < this.bytes.length; i++) {
|
|
25908
|
+
if (this.bytes[i] > 0) {
|
|
25909
|
+
results.memory[PerfCheckpoint[i]] = this.bytes[i];
|
|
25910
|
+
}
|
|
25911
|
+
}
|
|
25912
|
+
return results;
|
|
25913
|
+
}
|
|
25914
|
+
}
|
|
25915
|
+
/**
|
|
25916
|
+
* A `PerfRecorder` that delegates to a target `PerfRecorder` which can be updated later.
|
|
25917
|
+
*
|
|
25918
|
+
* `DelegatingPerfRecorder` is useful when a compiler class that needs a `PerfRecorder` can outlive
|
|
25919
|
+
* the current compilation. This is true for most compiler classes as resource-only changes reuse
|
|
25920
|
+
* the same `NgCompiler` for a new compilation.
|
|
25921
|
+
*/
|
|
25922
|
+
class DelegatingPerfRecorder {
|
|
25923
|
+
constructor(target) {
|
|
25924
|
+
this.target = target;
|
|
25925
|
+
}
|
|
25926
|
+
eventCount(counter, incrementBy) {
|
|
25927
|
+
this.target.eventCount(counter, incrementBy);
|
|
25928
|
+
}
|
|
25929
|
+
phase(phase) {
|
|
25930
|
+
return this.target.phase(phase);
|
|
25931
|
+
}
|
|
25932
|
+
inPhase(phase, fn) {
|
|
25933
|
+
// Note: this doesn't delegate to `this.target.inPhase` but instead is implemented manually here
|
|
25934
|
+
// to avoid adding an additional frame of noise to the stack when debugging.
|
|
25935
|
+
const previousPhase = this.target.phase(phase);
|
|
25936
|
+
try {
|
|
25937
|
+
return fn();
|
|
25938
|
+
}
|
|
25939
|
+
finally {
|
|
25940
|
+
this.target.phase(previousPhase);
|
|
25941
|
+
}
|
|
25942
|
+
}
|
|
25943
|
+
memory(after) {
|
|
25944
|
+
this.target.memory(after);
|
|
25945
|
+
}
|
|
25946
|
+
reset() {
|
|
25947
|
+
this.target.reset();
|
|
25948
|
+
}
|
|
25949
|
+
}
|
|
25950
|
+
|
|
25491
25951
|
/**
|
|
25492
25952
|
* @license
|
|
25493
25953
|
* Copyright Google LLC All Rights Reserved.
|
|
@@ -25738,6 +26198,8 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
25738
26198
|
for (const priorRecord of priorWork) {
|
|
25739
26199
|
this.adopt(priorRecord);
|
|
25740
26200
|
}
|
|
26201
|
+
this.perf.eventCount(PerfEvent.SourceFileReuseAnalysis);
|
|
26202
|
+
this.perf.eventCount(PerfEvent.TraitReuseAnalysis, priorWork.length);
|
|
25741
26203
|
// Skip the rest of analysis, as this file's prior traits are being reused.
|
|
25742
26204
|
return;
|
|
25743
26205
|
}
|
|
@@ -25941,6 +26403,7 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
25941
26403
|
if (trait.state !== TraitState.Pending) {
|
|
25942
26404
|
throw new Error(`Attempt to analyze trait of ${clazz.name.text} in state ${TraitState[trait.state]} (expected DETECTED)`);
|
|
25943
26405
|
}
|
|
26406
|
+
this.perf.eventCount(PerfEvent.TraitAnalyze);
|
|
25944
26407
|
// Attempt analysis. This could fail with a `FatalDiagnosticError`; catch it if it does.
|
|
25945
26408
|
let result;
|
|
25946
26409
|
try {
|
|
@@ -26079,7 +26542,6 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
26079
26542
|
// Cannot compile a trait that is not resolved, or had any errors in its declaration.
|
|
26080
26543
|
continue;
|
|
26081
26544
|
}
|
|
26082
|
-
const compileSpan = this.perf.start('compileClass', original);
|
|
26083
26545
|
// `trait.resolution` is non-null asserted here because TypeScript does not recognize that
|
|
26084
26546
|
// `Readonly<unknown>` is nullable (as `unknown` itself is nullable) due to the way that
|
|
26085
26547
|
// `Readonly` works.
|
|
@@ -26093,7 +26555,6 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
26093
26555
|
trait.handler.compileFull(clazz, trait.analysis, trait.resolution, constantPool);
|
|
26094
26556
|
}
|
|
26095
26557
|
const compileMatchRes = compileRes;
|
|
26096
|
-
this.perf.stop(compileSpan);
|
|
26097
26558
|
if (Array.isArray(compileMatchRes)) {
|
|
26098
26559
|
for (const result of compileMatchRes) {
|
|
26099
26560
|
if (!res.some(r => r.name === result.name)) {
|
|
@@ -27345,11 +27806,11 @@ define(['exports', 'typescript/lib/tsserverlibrary', 'os', 'typescript', 'fs', '
|
|
|
27345
27806
|
*/
|
|
27346
27807
|
const NO_DECORATORS = new Set();
|
|
27347
27808
|
const CLOSURE_FILE_OVERVIEW_REGEXP = /\s+@fileoverview\s+/i;
|
|
27348
|
-
function ivyTransformFactory(compilation, reflector, importRewriter, defaultImportRecorder, isCore, isClosureCompilerEnabled) {
|
|
27809
|
+
function ivyTransformFactory(compilation, reflector, importRewriter, defaultImportRecorder, perf, isCore, isClosureCompilerEnabled) {
|
|
27349
27810
|
const recordWrappedNodeExpr = createRecorderFn(defaultImportRecorder);
|
|
27350
27811
|
return (context) => {
|
|
27351
27812
|
return (file) => {
|
|
27352
|
-
return transformIvySourceFile(compilation, context, reflector, importRewriter, file, isCore, isClosureCompilerEnabled, recordWrappedNodeExpr);
|
|
27813
|
+
return perf.inPhase(PerfPhase.Compile, () => transformIvySourceFile(compilation, context, reflector, importRewriter, file, isCore, isClosureCompilerEnabled, recordWrappedNodeExpr));
|
|
27353
27814
|
};
|
|
27354
27815
|
};
|
|
27355
27816
|
}
|
|
@@ -28596,7 +29057,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
28596
29057
|
return isSymbolEqual(current, previous);
|
|
28597
29058
|
}
|
|
28598
29059
|
class DirectiveDecoratorHandler {
|
|
28599
|
-
constructor(reflector, evaluator, metaRegistry, scopeRegistry, metaReader, defaultImportRecorder, injectableRegistry, isCore, semanticDepGraphUpdater, annotateForClosureCompiler, compileUndecoratedClassesWithAngularFeatures) {
|
|
29060
|
+
constructor(reflector, evaluator, metaRegistry, scopeRegistry, metaReader, defaultImportRecorder, injectableRegistry, isCore, semanticDepGraphUpdater, annotateForClosureCompiler, compileUndecoratedClassesWithAngularFeatures, perf) {
|
|
28600
29061
|
this.reflector = reflector;
|
|
28601
29062
|
this.evaluator = evaluator;
|
|
28602
29063
|
this.metaRegistry = metaRegistry;
|
|
@@ -28608,6 +29069,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
28608
29069
|
this.semanticDepGraphUpdater = semanticDepGraphUpdater;
|
|
28609
29070
|
this.annotateForClosureCompiler = annotateForClosureCompiler;
|
|
28610
29071
|
this.compileUndecoratedClassesWithAngularFeatures = compileUndecoratedClassesWithAngularFeatures;
|
|
29072
|
+
this.perf = perf;
|
|
28611
29073
|
this.precedence = HandlerPrecedence.PRIMARY;
|
|
28612
29074
|
this.name = DirectiveDecoratorHandler.name;
|
|
28613
29075
|
}
|
|
@@ -28634,6 +29096,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
28634
29096
|
if (this.compileUndecoratedClassesWithAngularFeatures === false && decorator === null) {
|
|
28635
29097
|
return { diagnostics: [getUndecoratedClassWithAngularFeaturesDiagnostic(node)] };
|
|
28636
29098
|
}
|
|
29099
|
+
this.perf.eventCount(PerfEvent.AnalyzeDirective);
|
|
28637
29100
|
const directiveResult = extractDirectiveMetadata(node, decorator, this.reflector, this.evaluator, this.defaultImportRecorder, this.isCore, flags, this.annotateForClosureCompiler);
|
|
28638
29101
|
if (directiveResult === undefined) {
|
|
28639
29102
|
return {};
|
|
@@ -29231,7 +29694,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
29231
29694
|
* Compiles @NgModule annotations to ngModuleDef fields.
|
|
29232
29695
|
*/
|
|
29233
29696
|
class NgModuleDecoratorHandler {
|
|
29234
|
-
constructor(reflector, evaluator, metaReader, metaRegistry, scopeRegistry, referencesRegistry, isCore, routeAnalyzer, refEmitter, factoryTracker, defaultImportRecorder, annotateForClosureCompiler, injectableRegistry, localeId) {
|
|
29697
|
+
constructor(reflector, evaluator, metaReader, metaRegistry, scopeRegistry, referencesRegistry, isCore, routeAnalyzer, refEmitter, factoryTracker, defaultImportRecorder, annotateForClosureCompiler, injectableRegistry, perf, localeId) {
|
|
29235
29698
|
this.reflector = reflector;
|
|
29236
29699
|
this.evaluator = evaluator;
|
|
29237
29700
|
this.metaReader = metaReader;
|
|
@@ -29245,6 +29708,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
29245
29708
|
this.defaultImportRecorder = defaultImportRecorder;
|
|
29246
29709
|
this.annotateForClosureCompiler = annotateForClosureCompiler;
|
|
29247
29710
|
this.injectableRegistry = injectableRegistry;
|
|
29711
|
+
this.perf = perf;
|
|
29248
29712
|
this.localeId = localeId;
|
|
29249
29713
|
this.precedence = HandlerPrecedence.PRIMARY;
|
|
29250
29714
|
this.name = NgModuleDecoratorHandler.name;
|
|
@@ -29266,6 +29730,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
29266
29730
|
}
|
|
29267
29731
|
}
|
|
29268
29732
|
analyze(node, decorator) {
|
|
29733
|
+
this.perf.eventCount(PerfEvent.AnalyzeNgModule);
|
|
29269
29734
|
const name = node.name.text;
|
|
29270
29735
|
if (decorator.args === null || decorator.args.length > 1) {
|
|
29271
29736
|
throw new FatalDiagnosticError(ErrorCode.DECORATOR_ARITY_WRONG, Decorator.nodeForError(decorator), `Incorrect number of arguments to @NgModule decorator`);
|
|
@@ -29758,7 +30223,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
29758
30223
|
* `DecoratorHandler` which handles the `@Component` annotation.
|
|
29759
30224
|
*/
|
|
29760
30225
|
class ComponentDecoratorHandler {
|
|
29761
|
-
constructor(reflector, evaluator, metaRegistry, metaReader, scopeReader, scopeRegistry, typeCheckScopeRegistry, resourceRegistry, isCore, resourceLoader, rootDirs, defaultPreserveWhitespaces, i18nUseExternalIds, enableI18nLegacyMessageIdFormat, usePoisonedData, i18nNormalizeLineEndingsInICUs, moduleResolver, cycleAnalyzer, cycleHandlingStrategy, refEmitter, defaultImportRecorder, depTracker, injectableRegistry, semanticDepGraphUpdater, annotateForClosureCompiler) {
|
|
30226
|
+
constructor(reflector, evaluator, metaRegistry, metaReader, scopeReader, scopeRegistry, typeCheckScopeRegistry, resourceRegistry, isCore, resourceLoader, rootDirs, defaultPreserveWhitespaces, i18nUseExternalIds, enableI18nLegacyMessageIdFormat, usePoisonedData, i18nNormalizeLineEndingsInICUs, moduleResolver, cycleAnalyzer, cycleHandlingStrategy, refEmitter, defaultImportRecorder, depTracker, injectableRegistry, semanticDepGraphUpdater, annotateForClosureCompiler, perf) {
|
|
29762
30227
|
this.reflector = reflector;
|
|
29763
30228
|
this.evaluator = evaluator;
|
|
29764
30229
|
this.metaRegistry = metaRegistry;
|
|
@@ -29784,6 +30249,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
29784
30249
|
this.injectableRegistry = injectableRegistry;
|
|
29785
30250
|
this.semanticDepGraphUpdater = semanticDepGraphUpdater;
|
|
29786
30251
|
this.annotateForClosureCompiler = annotateForClosureCompiler;
|
|
30252
|
+
this.perf = perf;
|
|
29787
30253
|
this.literalCache = new Map();
|
|
29788
30254
|
this.elementSchemaRegistry = new DomElementSchemaRegistry();
|
|
29789
30255
|
/**
|
|
@@ -29829,9 +30295,16 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
29829
30295
|
const meta = this._resolveLiteral(decorator);
|
|
29830
30296
|
const component = reflectObjectLiteral(meta);
|
|
29831
30297
|
const containingFile = node.getSourceFile().fileName;
|
|
29832
|
-
const resolveStyleUrl = (styleUrl
|
|
29833
|
-
|
|
29834
|
-
|
|
30298
|
+
const resolveStyleUrl = (styleUrl) => {
|
|
30299
|
+
try {
|
|
30300
|
+
const resourceUrl = this.resourceLoader.resolve(styleUrl, containingFile);
|
|
30301
|
+
return this.resourceLoader.preload(resourceUrl);
|
|
30302
|
+
}
|
|
30303
|
+
catch (_a) {
|
|
30304
|
+
// Don't worry about failures to preload. We can handle this problem during analysis by
|
|
30305
|
+
// producing a diagnostic.
|
|
30306
|
+
return undefined;
|
|
30307
|
+
}
|
|
29835
30308
|
};
|
|
29836
30309
|
// A Promise that waits for the template and all <link>ed styles within it to be preloaded.
|
|
29837
30310
|
const templateAndTemplateStyleResources = this._preloadAndParseTemplate(node, decorator, component, containingFile)
|
|
@@ -29839,9 +30312,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
29839
30312
|
if (template === null) {
|
|
29840
30313
|
return undefined;
|
|
29841
30314
|
}
|
|
29842
|
-
|
|
29843
|
-
return Promise
|
|
29844
|
-
.all(template.styleUrls.map(styleUrl => resolveStyleUrl(styleUrl, nodeForError, 1 /* StylesheetFromTemplate */)))
|
|
30315
|
+
return Promise.all(template.styleUrls.map(styleUrl => resolveStyleUrl(styleUrl)))
|
|
29845
30316
|
.then(() => undefined);
|
|
29846
30317
|
});
|
|
29847
30318
|
// Extract all the styleUrls in the decorator.
|
|
@@ -29856,15 +30327,18 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
29856
30327
|
return Promise
|
|
29857
30328
|
.all([
|
|
29858
30329
|
templateAndTemplateStyleResources,
|
|
29859
|
-
...componentStyleUrls.map(styleUrl => resolveStyleUrl(styleUrl.url
|
|
30330
|
+
...componentStyleUrls.map(styleUrl => resolveStyleUrl(styleUrl.url))
|
|
29860
30331
|
])
|
|
29861
30332
|
.then(() => undefined);
|
|
29862
30333
|
}
|
|
29863
30334
|
}
|
|
29864
30335
|
analyze(node, decorator, flags = HandlerFlags.NONE) {
|
|
29865
30336
|
var _a;
|
|
30337
|
+
this.perf.eventCount(PerfEvent.AnalyzeComponent);
|
|
29866
30338
|
const containingFile = node.getSourceFile().fileName;
|
|
29867
30339
|
this.literalCache.delete(decorator);
|
|
30340
|
+
let diagnostics;
|
|
30341
|
+
let isPoisoned = false;
|
|
29868
30342
|
// @Component inherits @Directive, so begin by extracting the @Directive metadata and building
|
|
29869
30343
|
// on it.
|
|
29870
30344
|
const directiveResult = extractDirectiveMetadata(node, decorator, this.reflector, this.evaluator, this.defaultImportRecorder, this.isCore, flags, this.annotateForClosureCompiler, this.elementSchemaRegistry.getDefaultComponentElementName());
|
|
@@ -29932,14 +30406,23 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
29932
30406
|
...this._extractComponentStyleUrls(component), ...this._extractTemplateStyleUrls(template)
|
|
29933
30407
|
];
|
|
29934
30408
|
for (const styleUrl of styleUrls) {
|
|
29935
|
-
|
|
29936
|
-
|
|
29937
|
-
|
|
29938
|
-
|
|
29939
|
-
|
|
29940
|
-
|
|
29941
|
-
|
|
29942
|
-
|
|
30409
|
+
try {
|
|
30410
|
+
const resourceUrl = this.resourceLoader.resolve(styleUrl.url, containingFile);
|
|
30411
|
+
const resourceStr = this.resourceLoader.load(resourceUrl);
|
|
30412
|
+
styles.push(resourceStr);
|
|
30413
|
+
if (this.depTracker !== null) {
|
|
30414
|
+
this.depTracker.addResourceDependency(node.getSourceFile(), absoluteFrom(resourceUrl));
|
|
30415
|
+
}
|
|
30416
|
+
}
|
|
30417
|
+
catch (_b) {
|
|
30418
|
+
if (diagnostics === undefined) {
|
|
30419
|
+
diagnostics = [];
|
|
30420
|
+
}
|
|
30421
|
+
const resourceType = styleUrl.source === 2 /* StylesheetFromDecorator */ ?
|
|
30422
|
+
2 /* StylesheetFromDecorator */ :
|
|
30423
|
+
1 /* StylesheetFromTemplate */;
|
|
30424
|
+
diagnostics.push(this.makeResourceNotFoundError(styleUrl.url, styleUrl.nodeForError, resourceType)
|
|
30425
|
+
.toDiagnostic());
|
|
29943
30426
|
}
|
|
29944
30427
|
}
|
|
29945
30428
|
let inlineStyles = null;
|
|
@@ -29982,8 +30465,9 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
29982
30465
|
styles: styleResources,
|
|
29983
30466
|
template: templateResource,
|
|
29984
30467
|
},
|
|
29985
|
-
isPoisoned
|
|
30468
|
+
isPoisoned,
|
|
29986
30469
|
},
|
|
30470
|
+
diagnostics,
|
|
29987
30471
|
};
|
|
29988
30472
|
if (changeDetection !== null) {
|
|
29989
30473
|
output.analysis.meta.changeDetection = changeDetection;
|
|
@@ -30212,12 +30696,15 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
30212
30696
|
let styles = [];
|
|
30213
30697
|
if (analysis.styleUrls !== null) {
|
|
30214
30698
|
for (const styleUrl of analysis.styleUrls) {
|
|
30215
|
-
|
|
30216
|
-
|
|
30217
|
-
|
|
30218
|
-
|
|
30219
|
-
|
|
30220
|
-
|
|
30699
|
+
try {
|
|
30700
|
+
const resolvedStyleUrl = this.resourceLoader.resolve(styleUrl.url, containingFile);
|
|
30701
|
+
const styleText = this.resourceLoader.load(resolvedStyleUrl);
|
|
30702
|
+
styles.push(styleText);
|
|
30703
|
+
}
|
|
30704
|
+
catch (e) {
|
|
30705
|
+
// Resource resolve failures should already be in the diagnostics list from the analyze
|
|
30706
|
+
// stage. We do not need to do anything with them when updating resources.
|
|
30707
|
+
}
|
|
30221
30708
|
}
|
|
30222
30709
|
}
|
|
30223
30710
|
if (analysis.inlineStyles !== null) {
|
|
@@ -30339,8 +30826,15 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
30339
30826
|
const styleUrlsExpr = component.get('styleUrls');
|
|
30340
30827
|
if (styleUrlsExpr !== undefined && ts$1.isArrayLiteralExpression(styleUrlsExpr)) {
|
|
30341
30828
|
for (const expression of stringLiteralElements(styleUrlsExpr)) {
|
|
30342
|
-
|
|
30343
|
-
|
|
30829
|
+
try {
|
|
30830
|
+
const resourceUrl = this.resourceLoader.resolve(expression.text, containingFile);
|
|
30831
|
+
styles.add({ path: absoluteFrom(resourceUrl), expression });
|
|
30832
|
+
}
|
|
30833
|
+
catch (_a) {
|
|
30834
|
+
// Errors in style resource extraction do not need to be handled here. We will produce
|
|
30835
|
+
// diagnostics for each one that fails in the analysis, after we evaluate the `styleUrls`
|
|
30836
|
+
// expression to determine _all_ style resources, not just the string literals.
|
|
30837
|
+
}
|
|
30344
30838
|
}
|
|
30345
30839
|
}
|
|
30346
30840
|
const stylesExpr = component.get('styles');
|
|
@@ -30359,20 +30853,25 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
30359
30853
|
if (typeof templateUrl !== 'string') {
|
|
30360
30854
|
throw createValueHasWrongTypeError(templateUrlExpr, templateUrl, 'templateUrl must be a string');
|
|
30361
30855
|
}
|
|
30362
|
-
|
|
30363
|
-
|
|
30364
|
-
|
|
30365
|
-
|
|
30366
|
-
|
|
30367
|
-
|
|
30368
|
-
|
|
30369
|
-
|
|
30370
|
-
|
|
30371
|
-
|
|
30372
|
-
|
|
30856
|
+
try {
|
|
30857
|
+
const resourceUrl = this.resourceLoader.resolve(templateUrl, containingFile);
|
|
30858
|
+
const templatePromise = this.resourceLoader.preload(resourceUrl);
|
|
30859
|
+
// If the preload worked, then actually load and parse the template, and wait for any style
|
|
30860
|
+
// URLs to resolve.
|
|
30861
|
+
if (templatePromise !== undefined) {
|
|
30862
|
+
return templatePromise.then(() => {
|
|
30863
|
+
const templateDecl = this.parseTemplateDeclaration(decorator, component, containingFile);
|
|
30864
|
+
const template = this.extractTemplate(node, templateDecl);
|
|
30865
|
+
this.preanalyzeTemplateCache.set(node, template);
|
|
30866
|
+
return template;
|
|
30867
|
+
});
|
|
30868
|
+
}
|
|
30869
|
+
else {
|
|
30870
|
+
return Promise.resolve(null);
|
|
30871
|
+
}
|
|
30373
30872
|
}
|
|
30374
|
-
|
|
30375
|
-
|
|
30873
|
+
catch (e) {
|
|
30874
|
+
throw this.makeResourceNotFoundError(templateUrl, templateUrlExpr, 0 /* Template */);
|
|
30376
30875
|
}
|
|
30377
30876
|
}
|
|
30378
30877
|
else {
|
|
@@ -30504,16 +31003,21 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
30504
31003
|
if (typeof templateUrl !== 'string') {
|
|
30505
31004
|
throw createValueHasWrongTypeError(templateUrlExpr, templateUrl, 'templateUrl must be a string');
|
|
30506
31005
|
}
|
|
30507
|
-
|
|
30508
|
-
|
|
30509
|
-
|
|
30510
|
-
|
|
30511
|
-
|
|
30512
|
-
|
|
30513
|
-
|
|
30514
|
-
|
|
30515
|
-
|
|
30516
|
-
|
|
31006
|
+
try {
|
|
31007
|
+
const resourceUrl = this.resourceLoader.resolve(templateUrl, containingFile);
|
|
31008
|
+
return {
|
|
31009
|
+
isInline: false,
|
|
31010
|
+
interpolationConfig,
|
|
31011
|
+
preserveWhitespaces,
|
|
31012
|
+
templateUrl,
|
|
31013
|
+
templateUrlExpression: templateUrlExpr,
|
|
31014
|
+
resolvedTemplateUrl: resourceUrl,
|
|
31015
|
+
sourceMapUrl: sourceMapUrl(resourceUrl),
|
|
31016
|
+
};
|
|
31017
|
+
}
|
|
31018
|
+
catch (e) {
|
|
31019
|
+
throw this.makeResourceNotFoundError(templateUrl, templateUrlExpr, 0 /* Template */);
|
|
31020
|
+
}
|
|
30517
31021
|
}
|
|
30518
31022
|
else if (component.has('template')) {
|
|
30519
31023
|
return {
|
|
@@ -30566,30 +31070,20 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
30566
31070
|
}
|
|
30567
31071
|
this.cycleAnalyzer.recordSyntheticImport(origin, imported);
|
|
30568
31072
|
}
|
|
30569
|
-
|
|
30570
|
-
|
|
30571
|
-
|
|
30572
|
-
|
|
30573
|
-
|
|
30574
|
-
|
|
30575
|
-
|
|
30576
|
-
|
|
30577
|
-
|
|
30578
|
-
|
|
30579
|
-
|
|
30580
|
-
|
|
30581
|
-
case 0 /* Template */:
|
|
30582
|
-
errorText = `Could not find template file '${file}'.`;
|
|
30583
|
-
break;
|
|
30584
|
-
case 1 /* StylesheetFromTemplate */:
|
|
30585
|
-
errorText = `Could not find stylesheet file '${file}' linked from the template.`;
|
|
30586
|
-
break;
|
|
30587
|
-
case 2 /* StylesheetFromDecorator */:
|
|
30588
|
-
errorText = `Could not find stylesheet file '${file}'.`;
|
|
30589
|
-
break;
|
|
30590
|
-
}
|
|
30591
|
-
throw new FatalDiagnosticError(ErrorCode.COMPONENT_RESOURCE_NOT_FOUND, nodeForError, errorText);
|
|
31073
|
+
makeResourceNotFoundError(file, nodeForError, resourceType) {
|
|
31074
|
+
let errorText;
|
|
31075
|
+
switch (resourceType) {
|
|
31076
|
+
case 0 /* Template */:
|
|
31077
|
+
errorText = `Could not find template file '${file}'.`;
|
|
31078
|
+
break;
|
|
31079
|
+
case 1 /* StylesheetFromTemplate */:
|
|
31080
|
+
errorText = `Could not find stylesheet file '${file}' linked from the template.`;
|
|
31081
|
+
break;
|
|
31082
|
+
case 2 /* StylesheetFromDecorator */:
|
|
31083
|
+
errorText = `Could not find stylesheet file '${file}'.`;
|
|
31084
|
+
break;
|
|
30592
31085
|
}
|
|
31086
|
+
return new FatalDiagnosticError(ErrorCode.COMPONENT_RESOURCE_NOT_FOUND, nodeForError, errorText);
|
|
30593
31087
|
}
|
|
30594
31088
|
_extractTemplateStyleUrls(template) {
|
|
30595
31089
|
if (template.styleUrls === null) {
|
|
@@ -30657,7 +31151,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
30657
31151
|
* Adapts the `compileIvyInjectable` compiler for `@Injectable` decorators to the Ivy compiler.
|
|
30658
31152
|
*/
|
|
30659
31153
|
class InjectableDecoratorHandler {
|
|
30660
|
-
constructor(reflector, defaultImportRecorder, isCore, strictCtorDeps, injectableRegistry,
|
|
31154
|
+
constructor(reflector, defaultImportRecorder, isCore, strictCtorDeps, injectableRegistry, perf,
|
|
30661
31155
|
/**
|
|
30662
31156
|
* What to do if the injectable already contains a ɵprov property.
|
|
30663
31157
|
*
|
|
@@ -30670,6 +31164,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
30670
31164
|
this.isCore = isCore;
|
|
30671
31165
|
this.strictCtorDeps = strictCtorDeps;
|
|
30672
31166
|
this.injectableRegistry = injectableRegistry;
|
|
31167
|
+
this.perf = perf;
|
|
30673
31168
|
this.errorOnDuplicateProv = errorOnDuplicateProv;
|
|
30674
31169
|
this.precedence = HandlerPrecedence.SHARED;
|
|
30675
31170
|
this.name = InjectableDecoratorHandler.name;
|
|
@@ -30691,6 +31186,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
30691
31186
|
}
|
|
30692
31187
|
}
|
|
30693
31188
|
analyze(node, decorator) {
|
|
31189
|
+
this.perf.eventCount(PerfEvent.AnalyzeInjectable);
|
|
30694
31190
|
const meta = extractInjectableMetadata(node, decorator, this.reflector);
|
|
30695
31191
|
const decorators = this.reflector.getDecoratorsOfDeclaration(node);
|
|
30696
31192
|
return {
|
|
@@ -30946,7 +31442,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
30946
31442
|
}
|
|
30947
31443
|
}
|
|
30948
31444
|
class PipeDecoratorHandler {
|
|
30949
|
-
constructor(reflector, evaluator, metaRegistry, scopeRegistry, defaultImportRecorder, injectableRegistry, isCore) {
|
|
31445
|
+
constructor(reflector, evaluator, metaRegistry, scopeRegistry, defaultImportRecorder, injectableRegistry, isCore, perf) {
|
|
30950
31446
|
this.reflector = reflector;
|
|
30951
31447
|
this.evaluator = evaluator;
|
|
30952
31448
|
this.metaRegistry = metaRegistry;
|
|
@@ -30954,6 +31450,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
30954
31450
|
this.defaultImportRecorder = defaultImportRecorder;
|
|
30955
31451
|
this.injectableRegistry = injectableRegistry;
|
|
30956
31452
|
this.isCore = isCore;
|
|
31453
|
+
this.perf = perf;
|
|
30957
31454
|
this.precedence = HandlerPrecedence.PRIMARY;
|
|
30958
31455
|
this.name = PipeDecoratorHandler.name;
|
|
30959
31456
|
}
|
|
@@ -30974,6 +31471,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
30974
31471
|
}
|
|
30975
31472
|
}
|
|
30976
31473
|
analyze(clazz, decorator) {
|
|
31474
|
+
this.perf.eventCount(PerfEvent.AnalyzePipe);
|
|
30977
31475
|
const name = clazz.name.text;
|
|
30978
31476
|
const type = wrapTypeReference(this.reflector, clazz);
|
|
30979
31477
|
const internalType = new WrappedNodeExpr(this.reflector.getInternalNameOfClass(clazz));
|
|
@@ -31152,8 +31650,9 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
31152
31650
|
* dependencies within the same program are tracked; imports into packages on NPM are not.
|
|
31153
31651
|
*/
|
|
31154
31652
|
class ImportGraph {
|
|
31155
|
-
constructor(checker) {
|
|
31653
|
+
constructor(checker, perf) {
|
|
31156
31654
|
this.checker = checker;
|
|
31655
|
+
this.perf = perf;
|
|
31157
31656
|
this.map = new Map();
|
|
31158
31657
|
}
|
|
31159
31658
|
/**
|
|
@@ -31229,25 +31728,27 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
31229
31728
|
}
|
|
31230
31729
|
}
|
|
31231
31730
|
scanImports(sf) {
|
|
31232
|
-
|
|
31233
|
-
|
|
31234
|
-
|
|
31235
|
-
|
|
31236
|
-
stmt
|
|
31237
|
-
|
|
31238
|
-
|
|
31239
|
-
|
|
31240
|
-
|
|
31241
|
-
|
|
31242
|
-
|
|
31243
|
-
|
|
31244
|
-
|
|
31245
|
-
|
|
31246
|
-
|
|
31247
|
-
|
|
31731
|
+
return this.perf.inPhase(PerfPhase.CycleDetection, () => {
|
|
31732
|
+
const imports = new Set();
|
|
31733
|
+
// Look through the source file for import and export statements.
|
|
31734
|
+
for (const stmt of sf.statements) {
|
|
31735
|
+
if ((!ts$1.isImportDeclaration(stmt) && !ts$1.isExportDeclaration(stmt)) ||
|
|
31736
|
+
stmt.moduleSpecifier === undefined) {
|
|
31737
|
+
continue;
|
|
31738
|
+
}
|
|
31739
|
+
const symbol = this.checker.getSymbolAtLocation(stmt.moduleSpecifier);
|
|
31740
|
+
if (symbol === undefined || symbol.valueDeclaration === undefined) {
|
|
31741
|
+
// No symbol could be found to skip over this import/export.
|
|
31742
|
+
continue;
|
|
31743
|
+
}
|
|
31744
|
+
const moduleFile = symbol.valueDeclaration;
|
|
31745
|
+
if (ts$1.isSourceFile(moduleFile) && isLocalFile(moduleFile)) {
|
|
31746
|
+
// Record this local import.
|
|
31747
|
+
imports.add(moduleFile);
|
|
31748
|
+
}
|
|
31248
31749
|
}
|
|
31249
|
-
|
|
31250
|
-
|
|
31750
|
+
return imports;
|
|
31751
|
+
});
|
|
31251
31752
|
}
|
|
31252
31753
|
}
|
|
31253
31754
|
function isLocalFile(sf) {
|
|
@@ -31609,103 +32110,107 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
31609
32110
|
* The previous build's `BuildState` is reconciled with the new program's changes, and the results
|
|
31610
32111
|
* are merged into the new build's `PendingBuildState`.
|
|
31611
32112
|
*/
|
|
31612
|
-
static reconcile(oldProgram, oldDriver, newProgram, modifiedResourceFiles) {
|
|
31613
|
-
|
|
31614
|
-
|
|
31615
|
-
|
|
31616
|
-
|
|
31617
|
-
|
|
31618
|
-
|
|
31619
|
-
|
|
31620
|
-
else {
|
|
31621
|
-
let priorGraph = null;
|
|
31622
|
-
if (oldDriver.state.lastGood !== null) {
|
|
31623
|
-
priorGraph = oldDriver.state.lastGood.semanticDepGraph;
|
|
31624
|
-
}
|
|
31625
|
-
// The previous build was successfully analyzed. `pendingEmit` is the only state carried
|
|
31626
|
-
// forward into this build.
|
|
31627
|
-
state = {
|
|
31628
|
-
kind: BuildStateKind.Pending,
|
|
31629
|
-
pendingEmit: oldDriver.state.pendingEmit,
|
|
31630
|
-
pendingTypeCheckEmit: oldDriver.state.pendingTypeCheckEmit,
|
|
31631
|
-
changedResourcePaths: new Set(),
|
|
31632
|
-
changedTsPaths: new Set(),
|
|
31633
|
-
lastGood: oldDriver.state.lastGood,
|
|
31634
|
-
semanticDepGraphUpdater: new SemanticDepGraphUpdater(priorGraph),
|
|
31635
|
-
};
|
|
31636
|
-
}
|
|
31637
|
-
// Merge the freshly modified resource files with any prior ones.
|
|
31638
|
-
if (modifiedResourceFiles !== null) {
|
|
31639
|
-
for (const resFile of modifiedResourceFiles) {
|
|
31640
|
-
state.changedResourcePaths.add(absoluteFrom(resFile));
|
|
31641
|
-
}
|
|
31642
|
-
}
|
|
31643
|
-
// Next, process the files in the new program, with a couple of goals:
|
|
31644
|
-
// 1) Determine which TS files have changed, if any, and merge them into `changedTsFiles`.
|
|
31645
|
-
// 2) Produce a list of TS files which no longer exist in the program (they've been deleted
|
|
31646
|
-
// since the previous compilation). These need to be removed from the state tracking to avoid
|
|
31647
|
-
// leaking memory.
|
|
31648
|
-
// All files in the old program, for easy detection of changes.
|
|
31649
|
-
const oldFiles = new Set(oldProgram.getSourceFiles());
|
|
31650
|
-
// Assume all the old files were deleted to begin with. Only TS files are tracked.
|
|
31651
|
-
const deletedTsPaths = new Set(tsOnlyFiles(oldProgram).map(sf => sf.fileName));
|
|
31652
|
-
for (const newFile of newProgram.getSourceFiles()) {
|
|
31653
|
-
if (!newFile.isDeclarationFile) {
|
|
31654
|
-
// This file exists in the new program, so remove it from `deletedTsPaths`.
|
|
31655
|
-
deletedTsPaths.delete(newFile.fileName);
|
|
31656
|
-
}
|
|
31657
|
-
if (oldFiles.has(newFile)) {
|
|
31658
|
-
// This file hasn't changed; no need to look at it further.
|
|
31659
|
-
continue;
|
|
31660
|
-
}
|
|
31661
|
-
// The file has changed since the last successful build. The appropriate reaction depends on
|
|
31662
|
-
// what kind of file it is.
|
|
31663
|
-
if (!newFile.isDeclarationFile) {
|
|
31664
|
-
// It's a .ts file, so track it as a change.
|
|
31665
|
-
state.changedTsPaths.add(newFile.fileName);
|
|
32113
|
+
static reconcile(oldProgram, oldDriver, newProgram, modifiedResourceFiles, perf) {
|
|
32114
|
+
return perf.inPhase(PerfPhase.Reconciliation, () => {
|
|
32115
|
+
// Initialize the state of the current build based on the previous one.
|
|
32116
|
+
let state;
|
|
32117
|
+
if (oldDriver.state.kind === BuildStateKind.Pending) {
|
|
32118
|
+
// The previous build never made it past the pending state. Reuse it as the starting state
|
|
32119
|
+
// for this build.
|
|
32120
|
+
state = oldDriver.state;
|
|
31666
32121
|
}
|
|
31667
32122
|
else {
|
|
31668
|
-
|
|
31669
|
-
|
|
31670
|
-
|
|
31671
|
-
|
|
31672
|
-
|
|
31673
|
-
|
|
31674
|
-
|
|
31675
|
-
|
|
31676
|
-
|
|
31677
|
-
|
|
31678
|
-
|
|
31679
|
-
|
|
31680
|
-
|
|
31681
|
-
|
|
31682
|
-
|
|
31683
|
-
// dependency graph to determine logically changed files.
|
|
31684
|
-
const depGraph = new FileDependencyGraph();
|
|
31685
|
-
// If a previous compilation exists, use its dependency graph to determine the set of logically
|
|
31686
|
-
// changed files.
|
|
31687
|
-
let logicalChanges = null;
|
|
31688
|
-
if (state.lastGood !== null) {
|
|
31689
|
-
// Extract the set of logically changed files. At the same time, this operation populates the
|
|
31690
|
-
// current (fresh) dependency graph with information about those files which have not
|
|
31691
|
-
// logically changed.
|
|
31692
|
-
logicalChanges = depGraph.updateWithPhysicalChanges(state.lastGood.depGraph, state.changedTsPaths, deletedTsPaths, state.changedResourcePaths);
|
|
31693
|
-
for (const fileName of state.changedTsPaths) {
|
|
31694
|
-
logicalChanges.add(fileName);
|
|
31695
|
-
}
|
|
31696
|
-
// Any logically changed files need to be re-emitted. Most of the time this would happen
|
|
31697
|
-
// regardless because the new dependency graph would _also_ identify the file as stale.
|
|
31698
|
-
// However there are edge cases such as removing a component from an NgModule without adding
|
|
31699
|
-
// it to another one, where the previous graph identifies the file as logically changed, but
|
|
31700
|
-
// the new graph (which does not have that edge) fails to identify that the file should be
|
|
31701
|
-
// re-emitted.
|
|
31702
|
-
for (const change of logicalChanges) {
|
|
31703
|
-
state.pendingEmit.add(change);
|
|
31704
|
-
state.pendingTypeCheckEmit.add(change);
|
|
32123
|
+
let priorGraph = null;
|
|
32124
|
+
if (oldDriver.state.lastGood !== null) {
|
|
32125
|
+
priorGraph = oldDriver.state.lastGood.semanticDepGraph;
|
|
32126
|
+
}
|
|
32127
|
+
// The previous build was successfully analyzed. `pendingEmit` is the only state carried
|
|
32128
|
+
// forward into this build.
|
|
32129
|
+
state = {
|
|
32130
|
+
kind: BuildStateKind.Pending,
|
|
32131
|
+
pendingEmit: oldDriver.state.pendingEmit,
|
|
32132
|
+
pendingTypeCheckEmit: oldDriver.state.pendingTypeCheckEmit,
|
|
32133
|
+
changedResourcePaths: new Set(),
|
|
32134
|
+
changedTsPaths: new Set(),
|
|
32135
|
+
lastGood: oldDriver.state.lastGood,
|
|
32136
|
+
semanticDepGraphUpdater: new SemanticDepGraphUpdater(priorGraph),
|
|
32137
|
+
};
|
|
31705
32138
|
}
|
|
31706
|
-
|
|
31707
|
-
|
|
31708
|
-
|
|
32139
|
+
// Merge the freshly modified resource files with any prior ones.
|
|
32140
|
+
if (modifiedResourceFiles !== null) {
|
|
32141
|
+
for (const resFile of modifiedResourceFiles) {
|
|
32142
|
+
state.changedResourcePaths.add(absoluteFrom(resFile));
|
|
32143
|
+
}
|
|
32144
|
+
}
|
|
32145
|
+
// Next, process the files in the new program, with a couple of goals:
|
|
32146
|
+
// 1) Determine which TS files have changed, if any, and merge them into `changedTsFiles`.
|
|
32147
|
+
// 2) Produce a list of TS files which no longer exist in the program (they've been deleted
|
|
32148
|
+
// since the previous compilation). These need to be removed from the state tracking to
|
|
32149
|
+
// avoid leaking memory.
|
|
32150
|
+
// All files in the old program, for easy detection of changes.
|
|
32151
|
+
const oldFiles = new Set(oldProgram.getSourceFiles());
|
|
32152
|
+
// Assume all the old files were deleted to begin with. Only TS files are tracked.
|
|
32153
|
+
const deletedTsPaths = new Set(tsOnlyFiles(oldProgram).map(sf => sf.fileName));
|
|
32154
|
+
for (const newFile of newProgram.getSourceFiles()) {
|
|
32155
|
+
if (!newFile.isDeclarationFile) {
|
|
32156
|
+
// This file exists in the new program, so remove it from `deletedTsPaths`.
|
|
32157
|
+
deletedTsPaths.delete(newFile.fileName);
|
|
32158
|
+
}
|
|
32159
|
+
if (oldFiles.has(newFile)) {
|
|
32160
|
+
// This file hasn't changed; no need to look at it further.
|
|
32161
|
+
continue;
|
|
32162
|
+
}
|
|
32163
|
+
// The file has changed since the last successful build. The appropriate reaction depends on
|
|
32164
|
+
// what kind of file it is.
|
|
32165
|
+
if (!newFile.isDeclarationFile) {
|
|
32166
|
+
// It's a .ts file, so track it as a change.
|
|
32167
|
+
state.changedTsPaths.add(newFile.fileName);
|
|
32168
|
+
}
|
|
32169
|
+
else {
|
|
32170
|
+
// It's a .d.ts file. Currently the compiler does not do a great job of tracking
|
|
32171
|
+
// dependencies on .d.ts files, so bail out of incremental builds here and do a full
|
|
32172
|
+
// build. This usually only happens if something in node_modules changes.
|
|
32173
|
+
return IncrementalDriver.fresh(newProgram);
|
|
32174
|
+
}
|
|
32175
|
+
}
|
|
32176
|
+
// The next step is to remove any deleted files from the state.
|
|
32177
|
+
for (const filePath of deletedTsPaths) {
|
|
32178
|
+
state.pendingEmit.delete(filePath);
|
|
32179
|
+
state.pendingTypeCheckEmit.delete(filePath);
|
|
32180
|
+
// Even if the file doesn't exist in the current compilation, it still might have been
|
|
32181
|
+
// changed in a previous one, so delete it from the set of changed TS files, just in case.
|
|
32182
|
+
state.changedTsPaths.delete(filePath);
|
|
32183
|
+
}
|
|
32184
|
+
perf.eventCount(PerfEvent.SourceFilePhysicalChange, state.changedTsPaths.size);
|
|
32185
|
+
// Now, changedTsPaths contains physically changed TS paths. Use the previous program's
|
|
32186
|
+
// logical dependency graph to determine logically changed files.
|
|
32187
|
+
const depGraph = new FileDependencyGraph();
|
|
32188
|
+
// If a previous compilation exists, use its dependency graph to determine the set of
|
|
32189
|
+
// logically changed files.
|
|
32190
|
+
let logicalChanges = null;
|
|
32191
|
+
if (state.lastGood !== null) {
|
|
32192
|
+
// Extract the set of logically changed files. At the same time, this operation populates
|
|
32193
|
+
// the current (fresh) dependency graph with information about those files which have not
|
|
32194
|
+
// logically changed.
|
|
32195
|
+
logicalChanges = depGraph.updateWithPhysicalChanges(state.lastGood.depGraph, state.changedTsPaths, deletedTsPaths, state.changedResourcePaths);
|
|
32196
|
+
perf.eventCount(PerfEvent.SourceFileLogicalChange, logicalChanges.size);
|
|
32197
|
+
for (const fileName of state.changedTsPaths) {
|
|
32198
|
+
logicalChanges.add(fileName);
|
|
32199
|
+
}
|
|
32200
|
+
// Any logically changed files need to be re-emitted. Most of the time this would happen
|
|
32201
|
+
// regardless because the new dependency graph would _also_ identify the file as stale.
|
|
32202
|
+
// However there are edge cases such as removing a component from an NgModule without adding
|
|
32203
|
+
// it to another one, where the previous graph identifies the file as logically changed, but
|
|
32204
|
+
// the new graph (which does not have that edge) fails to identify that the file should be
|
|
32205
|
+
// re-emitted.
|
|
32206
|
+
for (const change of logicalChanges) {
|
|
32207
|
+
state.pendingEmit.add(change);
|
|
32208
|
+
state.pendingTypeCheckEmit.add(change);
|
|
32209
|
+
}
|
|
32210
|
+
}
|
|
32211
|
+
// `state` now reflects the initial pending state of the current compilation.
|
|
32212
|
+
return new IncrementalDriver(state, depGraph, logicalChanges);
|
|
32213
|
+
});
|
|
31709
32214
|
}
|
|
31710
32215
|
static fresh(program) {
|
|
31711
32216
|
// Initialize the set of files which need to be emitted to the set of all TS files in the
|
|
@@ -32390,29 +32895,6 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
32390
32895
|
node.modifiers.some(mod => mod.kind === ts$1.SyntaxKind.StaticKeyword);
|
|
32391
32896
|
}
|
|
32392
32897
|
|
|
32393
|
-
const NOOP_PERF_RECORDER = {
|
|
32394
|
-
enabled: false,
|
|
32395
|
-
mark: (name, node, category, detail) => { },
|
|
32396
|
-
start: (name, node, category, detail) => {
|
|
32397
|
-
return 0;
|
|
32398
|
-
},
|
|
32399
|
-
stop: (span) => { },
|
|
32400
|
-
};
|
|
32401
|
-
|
|
32402
|
-
/**
|
|
32403
|
-
* @license
|
|
32404
|
-
* Copyright Google LLC All Rights Reserved.
|
|
32405
|
-
*
|
|
32406
|
-
* Use of this source code is governed by an MIT-style license that can be
|
|
32407
|
-
* found in the LICENSE file at https://angular.io/license
|
|
32408
|
-
*/
|
|
32409
|
-
var PerfLogEventType;
|
|
32410
|
-
(function (PerfLogEventType) {
|
|
32411
|
-
PerfLogEventType[PerfLogEventType["SPAN_OPEN"] = 0] = "SPAN_OPEN";
|
|
32412
|
-
PerfLogEventType[PerfLogEventType["SPAN_CLOSE"] = 1] = "SPAN_CLOSE";
|
|
32413
|
-
PerfLogEventType[PerfLogEventType["MARK"] = 2] = "MARK";
|
|
32414
|
-
})(PerfLogEventType || (PerfLogEventType = {}));
|
|
32415
|
-
|
|
32416
32898
|
/**
|
|
32417
32899
|
* @license
|
|
32418
32900
|
* Copyright Google LLC All Rights Reserved.
|
|
@@ -35333,6 +35815,30 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
35333
35815
|
}
|
|
35334
35816
|
this._diagnostics.push(makeInlineDiagnostic(templateId, ErrorCode.INLINE_TYPE_CTOR_REQUIRED, node.name, message, directives.map(dir => makeRelatedInformation(dir.name, `Requires an inline type constructor.`))));
|
|
35335
35817
|
}
|
|
35818
|
+
suboptimalTypeInference(templateId, variables) {
|
|
35819
|
+
const mapping = this.resolver.getSourceMapping(templateId);
|
|
35820
|
+
// Select one of the template variables that's most suitable for reporting the diagnostic. Any
|
|
35821
|
+
// variable will do, but prefer one bound to the context's $implicit if present.
|
|
35822
|
+
let diagnosticVar = null;
|
|
35823
|
+
for (const variable of variables) {
|
|
35824
|
+
if (diagnosticVar === null || (variable.value === '' || variable.value === '$implicit')) {
|
|
35825
|
+
diagnosticVar = variable;
|
|
35826
|
+
}
|
|
35827
|
+
}
|
|
35828
|
+
if (diagnosticVar === null) {
|
|
35829
|
+
// There is no variable on which to report the diagnostic.
|
|
35830
|
+
return;
|
|
35831
|
+
}
|
|
35832
|
+
let varIdentification = `'${diagnosticVar.name}'`;
|
|
35833
|
+
if (variables.length === 2) {
|
|
35834
|
+
varIdentification += ` (and 1 other)`;
|
|
35835
|
+
}
|
|
35836
|
+
else if (variables.length > 2) {
|
|
35837
|
+
varIdentification += ` (and ${variables.length - 1} others)`;
|
|
35838
|
+
}
|
|
35839
|
+
const message = `This structural directive supports advanced type inference, but the current compiler configuration prevents its usage. The variable ${varIdentification} will have type 'any' as a result.\n\nConsider enabling the 'strictTemplates' option in your tsconfig.json for better type inference within this template.`;
|
|
35840
|
+
this._diagnostics.push(makeTemplateDiagnostic(templateId, mapping, diagnosticVar.keySpan, ts$1.DiagnosticCategory.Suggestion, ngErrorCode(ErrorCode.SUGGEST_SUBOPTIMAL_TYPE_INFERENCE), message));
|
|
35841
|
+
}
|
|
35336
35842
|
}
|
|
35337
35843
|
function makeInlineDiagnostic(templateId, code, node, messageText, relatedInformation) {
|
|
35338
35844
|
return Object.assign(Object.assign({}, makeDiagnostic(code, node, messageText, relatedInformation)), { componentFile: node.getSourceFile(), templateId });
|
|
@@ -36184,11 +36690,20 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
36184
36690
|
});
|
|
36185
36691
|
// The second kind of guard is a template context guard. This guard narrows the template
|
|
36186
36692
|
// rendering context variable `ctx`.
|
|
36187
|
-
if (dir.hasNgTemplateContextGuard
|
|
36188
|
-
|
|
36189
|
-
|
|
36190
|
-
|
|
36191
|
-
|
|
36693
|
+
if (dir.hasNgTemplateContextGuard) {
|
|
36694
|
+
if (this.tcb.env.config.applyTemplateContextGuards) {
|
|
36695
|
+
const ctx = this.scope.resolve(this.template);
|
|
36696
|
+
const guardInvoke = tsCallMethod(dirId, 'ngTemplateContextGuard', [dirInstId, ctx]);
|
|
36697
|
+
addParseSpanInfo(guardInvoke, this.template.sourceSpan);
|
|
36698
|
+
directiveGuards.push(guardInvoke);
|
|
36699
|
+
}
|
|
36700
|
+
else if (this.template.variables.length > 0 &&
|
|
36701
|
+
this.tcb.env.config.suggestionsForSuboptimalTypeInference) {
|
|
36702
|
+
// The compiler could have inferred a better type for the variables in this template,
|
|
36703
|
+
// but was prevented from doing so by the type-checking configuration. Issue a warning
|
|
36704
|
+
// diagnostic.
|
|
36705
|
+
this.tcb.oobRecorder.suboptimalTypeInference(this.tcb.id, this.template.variables);
|
|
36706
|
+
}
|
|
36192
36707
|
}
|
|
36193
36708
|
}
|
|
36194
36709
|
}
|
|
@@ -36246,15 +36761,10 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
36246
36761
|
}
|
|
36247
36762
|
}
|
|
36248
36763
|
/**
|
|
36249
|
-
* A `TcbOp` which constructs an instance of a directive
|
|
36250
|
-
* are
|
|
36251
|
-
* this way as opposed to `TcbDirectiveCtorOp` which is only necessary when the directive is
|
|
36252
|
-
* generic.
|
|
36253
|
-
*
|
|
36254
|
-
* Executing this operation returns a reference to the directive instance variable with its inferred
|
|
36255
|
-
* type.
|
|
36764
|
+
* A `TcbOp` which constructs an instance of a directive. For generic directives, generic
|
|
36765
|
+
* parameters are set to `any` type.
|
|
36256
36766
|
*/
|
|
36257
|
-
class
|
|
36767
|
+
class TcbDirectiveTypeOpBase extends TcbOp {
|
|
36258
36768
|
constructor(tcb, scope, node, dir) {
|
|
36259
36769
|
super();
|
|
36260
36770
|
this.tcb = tcb;
|
|
@@ -36269,14 +36779,65 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
36269
36779
|
return true;
|
|
36270
36780
|
}
|
|
36271
36781
|
execute() {
|
|
36782
|
+
const dirRef = this.dir.ref;
|
|
36783
|
+
const rawType = this.tcb.env.referenceType(this.dir.ref);
|
|
36784
|
+
let type;
|
|
36785
|
+
if (this.dir.isGeneric === false || dirRef.node.typeParameters === undefined) {
|
|
36786
|
+
type = rawType;
|
|
36787
|
+
}
|
|
36788
|
+
else {
|
|
36789
|
+
if (!ts$1.isTypeReferenceNode(rawType)) {
|
|
36790
|
+
throw new Error(`Expected TypeReferenceNode when referencing the type for ${this.dir.ref.debugName}`);
|
|
36791
|
+
}
|
|
36792
|
+
const typeArguments = dirRef.node.typeParameters.map(() => ts$1.factory.createKeywordTypeNode(ts$1.SyntaxKind.AnyKeyword));
|
|
36793
|
+
type = ts$1.factory.createTypeReferenceNode(rawType.typeName, typeArguments);
|
|
36794
|
+
}
|
|
36272
36795
|
const id = this.tcb.allocateId();
|
|
36273
|
-
const type = this.tcb.env.referenceType(this.dir.ref);
|
|
36274
36796
|
addExpressionIdentifier(type, ExpressionIdentifier.DIRECTIVE);
|
|
36275
36797
|
addParseSpanInfo(type, this.node.startSourceSpan || this.node.sourceSpan);
|
|
36276
36798
|
this.scope.addStatement(tsDeclareVariable(id, type));
|
|
36277
36799
|
return id;
|
|
36278
36800
|
}
|
|
36279
36801
|
}
|
|
36802
|
+
/**
|
|
36803
|
+
* A `TcbOp` which constructs an instance of a non-generic directive _without_ setting any of its
|
|
36804
|
+
* inputs. Inputs are later set in the `TcbDirectiveInputsOp`. Type checking was found to be
|
|
36805
|
+
* faster when done in this way as opposed to `TcbDirectiveCtorOp` which is only necessary when the
|
|
36806
|
+
* directive is generic.
|
|
36807
|
+
*
|
|
36808
|
+
* Executing this operation returns a reference to the directive instance variable with its inferred
|
|
36809
|
+
* type.
|
|
36810
|
+
*/
|
|
36811
|
+
class TcbNonGenericDirectiveTypeOp extends TcbDirectiveTypeOpBase {
|
|
36812
|
+
/**
|
|
36813
|
+
* Creates a variable declaration for this op's directive of the argument type. Returns the id of
|
|
36814
|
+
* the newly created variable.
|
|
36815
|
+
*/
|
|
36816
|
+
execute() {
|
|
36817
|
+
const dirRef = this.dir.ref;
|
|
36818
|
+
if (this.dir.isGeneric) {
|
|
36819
|
+
throw new Error(`Assertion Error: expected ${dirRef.debugName} not to be generic.`);
|
|
36820
|
+
}
|
|
36821
|
+
return super.execute();
|
|
36822
|
+
}
|
|
36823
|
+
}
|
|
36824
|
+
/**
|
|
36825
|
+
* A `TcbOp` which constructs an instance of a generic directive with its generic parameters set
|
|
36826
|
+
* to `any` type. This op is like `TcbDirectiveTypeOp`, except that generic parameters are set to
|
|
36827
|
+
* `any` type. This is used for situations where we want to avoid inlining.
|
|
36828
|
+
*
|
|
36829
|
+
* Executing this operation returns a reference to the directive instance variable with its generic
|
|
36830
|
+
* type parameters set to `any`.
|
|
36831
|
+
*/
|
|
36832
|
+
class TcbGenericDirectiveTypeWithAnyParamsOp extends TcbDirectiveTypeOpBase {
|
|
36833
|
+
execute() {
|
|
36834
|
+
const dirRef = this.dir.ref;
|
|
36835
|
+
if (dirRef.node.typeParameters === undefined) {
|
|
36836
|
+
throw new Error(`Assertion Error: expected typeParameters when creating a declaration for ${dirRef.debugName}`);
|
|
36837
|
+
}
|
|
36838
|
+
return super.execute();
|
|
36839
|
+
}
|
|
36840
|
+
}
|
|
36280
36841
|
/**
|
|
36281
36842
|
* A `TcbOp` which creates a variable for a local ref in a template.
|
|
36282
36843
|
* The initializer for the variable is the variable expression for the directive, template, or
|
|
@@ -37198,8 +37759,26 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
37198
37759
|
}
|
|
37199
37760
|
const dirMap = new Map();
|
|
37200
37761
|
for (const dir of directives) {
|
|
37201
|
-
|
|
37202
|
-
|
|
37762
|
+
let directiveOp;
|
|
37763
|
+
const host = this.tcb.env.reflector;
|
|
37764
|
+
const dirRef = dir.ref;
|
|
37765
|
+
if (!dir.isGeneric) {
|
|
37766
|
+
// The most common case is that when a directive is not generic, we use the normal
|
|
37767
|
+
// `TcbNonDirectiveTypeOp`.
|
|
37768
|
+
directiveOp = new TcbNonGenericDirectiveTypeOp(this.tcb, this, node, dir);
|
|
37769
|
+
}
|
|
37770
|
+
else if (!requiresInlineTypeCtor(dirRef.node, host) ||
|
|
37771
|
+
this.tcb.env.config.useInlineTypeConstructors) {
|
|
37772
|
+
// For generic directives, we use a type constructor to infer types. If a directive requires
|
|
37773
|
+
// an inline type constructor, then inlining must be available to use the
|
|
37774
|
+
// `TcbDirectiveCtorOp`. If not we, we fallback to using `any` – see below.
|
|
37775
|
+
directiveOp = new TcbDirectiveCtorOp(this.tcb, this, node, dir);
|
|
37776
|
+
}
|
|
37777
|
+
else {
|
|
37778
|
+
// If inlining is not available, then we give up on infering the generic params, and use
|
|
37779
|
+
// `any` type for the directive's generic parameters.
|
|
37780
|
+
directiveOp = new TcbGenericDirectiveTypeWithAnyParamsOp(this.tcb, this, node, dir);
|
|
37781
|
+
}
|
|
37203
37782
|
const dirIndex = this.opQueue.push(directiveOp) - 1;
|
|
37204
37783
|
dirMap.set(dir, dirIndex);
|
|
37205
37784
|
this.opQueue.push(new TcbDirectiveInputsOp(this.tcb, this, node, dir));
|
|
@@ -37623,12 +38202,12 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
37623
38202
|
const fn = generateTypeCheckBlock(this, ref, fnId, meta, domSchemaChecker, oobRecorder);
|
|
37624
38203
|
this.tcbStatements.push(fn);
|
|
37625
38204
|
}
|
|
37626
|
-
render() {
|
|
38205
|
+
render(removeComments) {
|
|
37627
38206
|
let source = this.importManager.getAllImports(this.contextFile.fileName)
|
|
37628
38207
|
.map(i => `import * as ${i.qualifier.text} from '${i.specifier}';`)
|
|
37629
38208
|
.join('\n') +
|
|
37630
38209
|
'\n\n';
|
|
37631
|
-
const printer = ts$1.createPrinter();
|
|
38210
|
+
const printer = ts$1.createPrinter({ removeComments });
|
|
37632
38211
|
source += '\n';
|
|
37633
38212
|
for (const stmt of this.pipeInstStatements) {
|
|
37634
38213
|
source += printer.printNode(ts$1.EmitHint.Unspecified, stmt, this.contextFile) + '\n';
|
|
@@ -37679,7 +38258,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
37679
38258
|
* type checked.
|
|
37680
38259
|
*/
|
|
37681
38260
|
class TypeCheckContextImpl {
|
|
37682
|
-
constructor(config, compilerHost, componentMappingStrategy, refEmitter, reflector, host, inlining) {
|
|
38261
|
+
constructor(config, compilerHost, componentMappingStrategy, refEmitter, reflector, host, inlining, perf) {
|
|
37683
38262
|
this.config = config;
|
|
37684
38263
|
this.compilerHost = compilerHost;
|
|
37685
38264
|
this.componentMappingStrategy = componentMappingStrategy;
|
|
@@ -37687,6 +38266,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
37687
38266
|
this.reflector = reflector;
|
|
37688
38267
|
this.host = host;
|
|
37689
38268
|
this.inlining = inlining;
|
|
38269
|
+
this.perf = perf;
|
|
37690
38270
|
this.fileMap = new Map();
|
|
37691
38271
|
/**
|
|
37692
38272
|
* A `Map` of `ts.SourceFile`s that the context has seen to the operations (additions of methods
|
|
@@ -37698,6 +38278,10 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
37698
38278
|
* queued.
|
|
37699
38279
|
*/
|
|
37700
38280
|
this.typeCtorPending = new Set();
|
|
38281
|
+
if (inlining === InliningMode.Error && config.useInlineTypeConstructors) {
|
|
38282
|
+
// We cannot use inlining for type checking since this environment does not support it.
|
|
38283
|
+
throw new Error(`AssertionError: invalid inlining configuration.`);
|
|
38284
|
+
}
|
|
37701
38285
|
}
|
|
37702
38286
|
/**
|
|
37703
38287
|
* Register a template to potentially be type-checked.
|
|
@@ -37715,20 +38299,18 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
37715
38299
|
if (parseErrors !== null) {
|
|
37716
38300
|
templateDiagnostics.push(...this.getTemplateDiagnostics(parseErrors, templateId, sourceMapping));
|
|
37717
38301
|
}
|
|
37718
|
-
// Accumulate a list of any directives which could not have type constructors generated due to
|
|
37719
|
-
// unsupported inlining operations.
|
|
37720
|
-
let missingInlines = [];
|
|
37721
38302
|
const boundTarget = binder.bind({ template });
|
|
37722
|
-
|
|
37723
|
-
|
|
37724
|
-
|
|
37725
|
-
const
|
|
37726
|
-
|
|
37727
|
-
|
|
37728
|
-
|
|
38303
|
+
if (this.inlining === InliningMode.InlineOps) {
|
|
38304
|
+
// Get all of the directives used in the template and record inline type constructors when
|
|
38305
|
+
// required.
|
|
38306
|
+
for (const dir of boundTarget.getUsedDirectives()) {
|
|
38307
|
+
const dirRef = dir.ref;
|
|
38308
|
+
const dirNode = dirRef.node;
|
|
38309
|
+
if (!dir.isGeneric || !requiresInlineTypeCtor(dirNode, this.reflector)) {
|
|
38310
|
+
// inlining not required
|
|
37729
38311
|
continue;
|
|
37730
38312
|
}
|
|
37731
|
-
// Add
|
|
38313
|
+
// Add an inline type constructor operation for the directive.
|
|
37732
38314
|
this.addInlineTypeCtor(fileData, dirNode.getSourceFile(), dirRef, {
|
|
37733
38315
|
fnName: 'ngTypeCtor',
|
|
37734
38316
|
// The constructor should have a body if the directive comes from a .ts file, but not if
|
|
@@ -37752,17 +38334,13 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
37752
38334
|
const tcbRequiresInline = requiresInlineTypeCheckBlock(ref.node, pipes);
|
|
37753
38335
|
// If inlining is not supported, but is required for either the TCB or one of its directive
|
|
37754
38336
|
// dependencies, then exit here with an error.
|
|
37755
|
-
if (this.inlining === InliningMode.Error &&
|
|
38337
|
+
if (this.inlining === InliningMode.Error && tcbRequiresInline) {
|
|
37756
38338
|
// This template cannot be supported because the underlying strategy does not support inlining
|
|
37757
38339
|
// and inlining would be required.
|
|
37758
38340
|
// Record diagnostics to indicate the issues with this template.
|
|
37759
|
-
|
|
37760
|
-
shimData.oobRecorder.requiresInlineTcb(templateId, ref.node);
|
|
37761
|
-
}
|
|
37762
|
-
if (missingInlines.length > 0) {
|
|
37763
|
-
shimData.oobRecorder.requiresInlineTypeConstructors(templateId, ref.node, missingInlines);
|
|
37764
|
-
}
|
|
38341
|
+
shimData.oobRecorder.requiresInlineTcb(templateId, ref.node);
|
|
37765
38342
|
// Checking this template would be unsupported, so don't try.
|
|
38343
|
+
this.perf.eventCount(PerfEvent.SkipGenerateTcbNoInline);
|
|
37766
38344
|
return;
|
|
37767
38345
|
}
|
|
37768
38346
|
const meta = {
|
|
@@ -37771,6 +38349,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
37771
38349
|
pipes,
|
|
37772
38350
|
schemas,
|
|
37773
38351
|
};
|
|
38352
|
+
this.perf.eventCount(PerfEvent.GenerateTcb);
|
|
37774
38353
|
if (tcbRequiresInline) {
|
|
37775
38354
|
// This class didn't meet the requirements for external type checking, so generate an inline
|
|
37776
38355
|
// TCB for the class.
|
|
@@ -37857,7 +38436,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
37857
38436
|
path: pendingShimData.file.fileName,
|
|
37858
38437
|
templates: pendingShimData.templates,
|
|
37859
38438
|
});
|
|
37860
|
-
updates.set(pendingShimData.file.fileName, pendingShimData.file.render());
|
|
38439
|
+
updates.set(pendingShimData.file.fileName, pendingShimData.file.render(false /* removeComments */));
|
|
37861
38440
|
}
|
|
37862
38441
|
}
|
|
37863
38442
|
return updates;
|
|
@@ -38587,7 +39166,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
38587
39166
|
* `ProgramTypeCheckAdapter` for generation of template type-checking code.
|
|
38588
39167
|
*/
|
|
38589
39168
|
class TemplateTypeCheckerImpl {
|
|
38590
|
-
constructor(originalProgram, typeCheckingStrategy, typeCheckAdapter, config, refEmitter, reflector, compilerHost, priorBuild, componentScopeReader, typeCheckScopeRegistry) {
|
|
39169
|
+
constructor(originalProgram, typeCheckingStrategy, typeCheckAdapter, config, refEmitter, reflector, compilerHost, priorBuild, componentScopeReader, typeCheckScopeRegistry, perf) {
|
|
38591
39170
|
this.originalProgram = originalProgram;
|
|
38592
39171
|
this.typeCheckingStrategy = typeCheckingStrategy;
|
|
38593
39172
|
this.typeCheckAdapter = typeCheckAdapter;
|
|
@@ -38598,6 +39177,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
38598
39177
|
this.priorBuild = priorBuild;
|
|
38599
39178
|
this.componentScopeReader = componentScopeReader;
|
|
38600
39179
|
this.typeCheckScopeRegistry = typeCheckScopeRegistry;
|
|
39180
|
+
this.perf = perf;
|
|
38601
39181
|
this.state = new Map();
|
|
38602
39182
|
/**
|
|
38603
39183
|
* Stores the `CompletionEngine` which powers autocompletion for each component class.
|
|
@@ -38709,48 +39289,52 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
38709
39289
|
this.ensureAllShimsForOneFile(sf);
|
|
38710
39290
|
break;
|
|
38711
39291
|
}
|
|
38712
|
-
|
|
38713
|
-
|
|
38714
|
-
|
|
38715
|
-
|
|
38716
|
-
|
|
38717
|
-
|
|
38718
|
-
|
|
38719
|
-
|
|
38720
|
-
|
|
39292
|
+
return this.perf.inPhase(PerfPhase.TtcDiagnostics, () => {
|
|
39293
|
+
const sfPath = absoluteFromSourceFile(sf);
|
|
39294
|
+
const fileRecord = this.state.get(sfPath);
|
|
39295
|
+
const typeCheckProgram = this.typeCheckingStrategy.getProgram();
|
|
39296
|
+
const diagnostics = [];
|
|
39297
|
+
if (fileRecord.hasInlines) {
|
|
39298
|
+
const inlineSf = getSourceFileOrError(typeCheckProgram, sfPath);
|
|
39299
|
+
diagnostics.push(...typeCheckProgram.getSemanticDiagnostics(inlineSf).map(diag => convertDiagnostic(diag, fileRecord.sourceManager)));
|
|
39300
|
+
}
|
|
39301
|
+
for (const [shimPath, shimRecord] of fileRecord.shimData) {
|
|
39302
|
+
const shimSf = getSourceFileOrError(typeCheckProgram, shimPath);
|
|
39303
|
+
diagnostics.push(...typeCheckProgram.getSemanticDiagnostics(shimSf).map(diag => convertDiagnostic(diag, fileRecord.sourceManager)));
|
|
39304
|
+
diagnostics.push(...shimRecord.genesisDiagnostics);
|
|
39305
|
+
for (const templateData of shimRecord.templates.values()) {
|
|
39306
|
+
diagnostics.push(...templateData.templateDiagnostics);
|
|
39307
|
+
}
|
|
39308
|
+
}
|
|
39309
|
+
return diagnostics.filter((diag) => diag !== null);
|
|
39310
|
+
});
|
|
39311
|
+
}
|
|
39312
|
+
getDiagnosticsForComponent(component) {
|
|
39313
|
+
this.ensureShimForComponent(component);
|
|
39314
|
+
return this.perf.inPhase(PerfPhase.TtcDiagnostics, () => {
|
|
39315
|
+
const sf = component.getSourceFile();
|
|
39316
|
+
const sfPath = absoluteFromSourceFile(sf);
|
|
39317
|
+
const shimPath = this.typeCheckingStrategy.shimPathForComponent(component);
|
|
39318
|
+
const fileRecord = this.getFileData(sfPath);
|
|
39319
|
+
if (!fileRecord.shimData.has(shimPath)) {
|
|
39320
|
+
return [];
|
|
39321
|
+
}
|
|
39322
|
+
const templateId = fileRecord.sourceManager.getTemplateId(component);
|
|
39323
|
+
const shimRecord = fileRecord.shimData.get(shimPath);
|
|
39324
|
+
const typeCheckProgram = this.typeCheckingStrategy.getProgram();
|
|
39325
|
+
const diagnostics = [];
|
|
39326
|
+
if (shimRecord.hasInlines) {
|
|
39327
|
+
const inlineSf = getSourceFileOrError(typeCheckProgram, sfPath);
|
|
39328
|
+
diagnostics.push(...typeCheckProgram.getSemanticDiagnostics(inlineSf).map(diag => convertDiagnostic(diag, fileRecord.sourceManager)));
|
|
39329
|
+
}
|
|
38721
39330
|
const shimSf = getSourceFileOrError(typeCheckProgram, shimPath);
|
|
38722
39331
|
diagnostics.push(...typeCheckProgram.getSemanticDiagnostics(shimSf).map(diag => convertDiagnostic(diag, fileRecord.sourceManager)));
|
|
38723
39332
|
diagnostics.push(...shimRecord.genesisDiagnostics);
|
|
38724
39333
|
for (const templateData of shimRecord.templates.values()) {
|
|
38725
39334
|
diagnostics.push(...templateData.templateDiagnostics);
|
|
38726
39335
|
}
|
|
38727
|
-
|
|
38728
|
-
|
|
38729
|
-
}
|
|
38730
|
-
getDiagnosticsForComponent(component) {
|
|
38731
|
-
this.ensureShimForComponent(component);
|
|
38732
|
-
const sf = component.getSourceFile();
|
|
38733
|
-
const sfPath = absoluteFromSourceFile(sf);
|
|
38734
|
-
const shimPath = this.typeCheckingStrategy.shimPathForComponent(component);
|
|
38735
|
-
const fileRecord = this.getFileData(sfPath);
|
|
38736
|
-
if (!fileRecord.shimData.has(shimPath)) {
|
|
38737
|
-
return [];
|
|
38738
|
-
}
|
|
38739
|
-
const templateId = fileRecord.sourceManager.getTemplateId(component);
|
|
38740
|
-
const shimRecord = fileRecord.shimData.get(shimPath);
|
|
38741
|
-
const typeCheckProgram = this.typeCheckingStrategy.getProgram();
|
|
38742
|
-
const diagnostics = [];
|
|
38743
|
-
if (shimRecord.hasInlines) {
|
|
38744
|
-
const inlineSf = getSourceFileOrError(typeCheckProgram, sfPath);
|
|
38745
|
-
diagnostics.push(...typeCheckProgram.getSemanticDiagnostics(inlineSf).map(diag => convertDiagnostic(diag, fileRecord.sourceManager)));
|
|
38746
|
-
}
|
|
38747
|
-
const shimSf = getSourceFileOrError(typeCheckProgram, shimPath);
|
|
38748
|
-
diagnostics.push(...typeCheckProgram.getSemanticDiagnostics(shimSf).map(diag => convertDiagnostic(diag, fileRecord.sourceManager)));
|
|
38749
|
-
diagnostics.push(...shimRecord.genesisDiagnostics);
|
|
38750
|
-
for (const templateData of shimRecord.templates.values()) {
|
|
38751
|
-
diagnostics.push(...templateData.templateDiagnostics);
|
|
38752
|
-
}
|
|
38753
|
-
return diagnostics.filter((diag) => diag !== null && diag.templateId === templateId);
|
|
39336
|
+
return diagnostics.filter((diag) => diag !== null && diag.templateId === templateId);
|
|
39337
|
+
});
|
|
38754
39338
|
}
|
|
38755
39339
|
getTypeCheckBlock(component) {
|
|
38756
39340
|
return this.getLatestComponentState(component).tcb;
|
|
@@ -38760,14 +39344,14 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
38760
39344
|
if (engine === null) {
|
|
38761
39345
|
return null;
|
|
38762
39346
|
}
|
|
38763
|
-
return engine.getGlobalCompletions(context);
|
|
39347
|
+
return this.perf.inPhase(PerfPhase.TtcAutocompletion, () => engine.getGlobalCompletions(context));
|
|
38764
39348
|
}
|
|
38765
39349
|
getExpressionCompletionLocation(ast, component) {
|
|
38766
39350
|
const engine = this.getOrCreateCompletionEngine(component);
|
|
38767
39351
|
if (engine === null) {
|
|
38768
39352
|
return null;
|
|
38769
39353
|
}
|
|
38770
|
-
return engine.getExpressionCompletionLocation(ast);
|
|
39354
|
+
return this.perf.inPhase(PerfPhase.TtcAutocompletion, () => engine.getExpressionCompletionLocation(ast));
|
|
38771
39355
|
}
|
|
38772
39356
|
invalidateClass(clazz) {
|
|
38773
39357
|
this.completionCache.delete(clazz);
|
|
@@ -38808,43 +39392,48 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
38808
39392
|
if (previousResults === null || !previousResults.isComplete) {
|
|
38809
39393
|
return;
|
|
38810
39394
|
}
|
|
39395
|
+
this.perf.eventCount(PerfEvent.ReuseTypeCheckFile);
|
|
38811
39396
|
this.state.set(sfPath, previousResults);
|
|
38812
39397
|
}
|
|
38813
39398
|
ensureAllShimsForAllFiles() {
|
|
38814
39399
|
if (this.isComplete) {
|
|
38815
39400
|
return;
|
|
38816
39401
|
}
|
|
38817
|
-
|
|
38818
|
-
|
|
38819
|
-
|
|
38820
|
-
|
|
38821
|
-
|
|
39402
|
+
this.perf.inPhase(PerfPhase.TcbGeneration, () => {
|
|
39403
|
+
const host = new WholeProgramTypeCheckingHost(this);
|
|
39404
|
+
const ctx = this.newContext(host);
|
|
39405
|
+
for (const sf of this.originalProgram.getSourceFiles()) {
|
|
39406
|
+
if (sf.isDeclarationFile || isShim(sf)) {
|
|
39407
|
+
continue;
|
|
39408
|
+
}
|
|
39409
|
+
this.maybeAdoptPriorResultsForFile(sf);
|
|
39410
|
+
const sfPath = absoluteFromSourceFile(sf);
|
|
39411
|
+
const fileData = this.getFileData(sfPath);
|
|
39412
|
+
if (fileData.isComplete) {
|
|
39413
|
+
continue;
|
|
39414
|
+
}
|
|
39415
|
+
this.typeCheckAdapter.typeCheck(sf, ctx);
|
|
39416
|
+
fileData.isComplete = true;
|
|
38822
39417
|
}
|
|
39418
|
+
this.updateFromContext(ctx);
|
|
39419
|
+
this.isComplete = true;
|
|
39420
|
+
});
|
|
39421
|
+
}
|
|
39422
|
+
ensureAllShimsForOneFile(sf) {
|
|
39423
|
+
this.perf.inPhase(PerfPhase.TcbGeneration, () => {
|
|
38823
39424
|
this.maybeAdoptPriorResultsForFile(sf);
|
|
38824
39425
|
const sfPath = absoluteFromSourceFile(sf);
|
|
38825
39426
|
const fileData = this.getFileData(sfPath);
|
|
38826
39427
|
if (fileData.isComplete) {
|
|
38827
|
-
|
|
39428
|
+
// All data for this file is present and accounted for already.
|
|
39429
|
+
return;
|
|
38828
39430
|
}
|
|
39431
|
+
const host = new SingleFileTypeCheckingHost(sfPath, fileData, this.typeCheckingStrategy, this);
|
|
39432
|
+
const ctx = this.newContext(host);
|
|
38829
39433
|
this.typeCheckAdapter.typeCheck(sf, ctx);
|
|
38830
39434
|
fileData.isComplete = true;
|
|
38831
|
-
|
|
38832
|
-
|
|
38833
|
-
this.isComplete = true;
|
|
38834
|
-
}
|
|
38835
|
-
ensureAllShimsForOneFile(sf) {
|
|
38836
|
-
this.maybeAdoptPriorResultsForFile(sf);
|
|
38837
|
-
const sfPath = absoluteFromSourceFile(sf);
|
|
38838
|
-
const fileData = this.getFileData(sfPath);
|
|
38839
|
-
if (fileData.isComplete) {
|
|
38840
|
-
// All data for this file is present and accounted for already.
|
|
38841
|
-
return;
|
|
38842
|
-
}
|
|
38843
|
-
const host = new SingleFileTypeCheckingHost(sfPath, fileData, this.typeCheckingStrategy, this);
|
|
38844
|
-
const ctx = this.newContext(host);
|
|
38845
|
-
this.typeCheckAdapter.typeCheck(sf, ctx);
|
|
38846
|
-
fileData.isComplete = true;
|
|
38847
|
-
this.updateFromContext(ctx);
|
|
39435
|
+
this.updateFromContext(ctx);
|
|
39436
|
+
});
|
|
38848
39437
|
}
|
|
38849
39438
|
ensureShimForComponent(component) {
|
|
38850
39439
|
const sf = component.getSourceFile();
|
|
@@ -38864,7 +39453,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
38864
39453
|
newContext(host) {
|
|
38865
39454
|
const inlining = this.typeCheckingStrategy.supportsInlineOperations ? InliningMode.InlineOps :
|
|
38866
39455
|
InliningMode.Error;
|
|
38867
|
-
return new TypeCheckContextImpl(this.config, this.compilerHost, this.typeCheckingStrategy, this.refEmitter, this.reflector, host, inlining);
|
|
39456
|
+
return new TypeCheckContextImpl(this.config, this.compilerHost, this.typeCheckingStrategy, this.refEmitter, this.reflector, host, inlining, this.perf);
|
|
38868
39457
|
}
|
|
38869
39458
|
/**
|
|
38870
39459
|
* Remove any shim data that depends on inline operations applied to the type-checking program.
|
|
@@ -38889,8 +39478,14 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
38889
39478
|
}
|
|
38890
39479
|
updateFromContext(ctx) {
|
|
38891
39480
|
const updates = ctx.finalize();
|
|
38892
|
-
this.
|
|
38893
|
-
|
|
39481
|
+
return this.perf.inPhase(PerfPhase.TcbUpdateProgram, () => {
|
|
39482
|
+
if (updates.size > 0) {
|
|
39483
|
+
this.perf.eventCount(PerfEvent.UpdateTypeCheckProgram);
|
|
39484
|
+
}
|
|
39485
|
+
this.typeCheckingStrategy.updateFiles(updates, UpdateMode.Incremental);
|
|
39486
|
+
this.priorBuild.recordSuccessfulTypeCheck(this.state);
|
|
39487
|
+
this.perf.memory(PerfCheckpoint.TtcUpdateProgram);
|
|
39488
|
+
});
|
|
38894
39489
|
}
|
|
38895
39490
|
getFileData(path) {
|
|
38896
39491
|
if (!this.state.has(path)) {
|
|
@@ -38908,7 +39503,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
38908
39503
|
if (builder === null) {
|
|
38909
39504
|
return null;
|
|
38910
39505
|
}
|
|
38911
|
-
return builder.getSymbol(node);
|
|
39506
|
+
return this.perf.inPhase(PerfPhase.TtcSymbol, () => builder.getSymbol(node));
|
|
38912
39507
|
}
|
|
38913
39508
|
getOrCreateSymbolBuilder(component) {
|
|
38914
39509
|
if (this.symbolBuilderCache.has(component)) {
|
|
@@ -39167,7 +39762,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
39167
39762
|
/**
|
|
39168
39763
|
* Create a `CompilationTicket` for a brand new compilation, using no prior state.
|
|
39169
39764
|
*/
|
|
39170
|
-
function freshCompilationTicket(tsProgram, options, incrementalBuildStrategy, typeCheckingProgramStrategy, enableTemplateTypeChecker, usePoisonedData) {
|
|
39765
|
+
function freshCompilationTicket(tsProgram, options, incrementalBuildStrategy, typeCheckingProgramStrategy, perfRecorder, enableTemplateTypeChecker, usePoisonedData) {
|
|
39171
39766
|
return {
|
|
39172
39767
|
kind: CompilationTicketKind.Fresh,
|
|
39173
39768
|
tsProgram,
|
|
@@ -39176,21 +39771,25 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
39176
39771
|
typeCheckingProgramStrategy,
|
|
39177
39772
|
enableTemplateTypeChecker,
|
|
39178
39773
|
usePoisonedData,
|
|
39774
|
+
perfRecorder: perfRecorder !== null && perfRecorder !== void 0 ? perfRecorder : ActivePerfRecorder.zeroedToNow(),
|
|
39179
39775
|
};
|
|
39180
39776
|
}
|
|
39181
39777
|
/**
|
|
39182
39778
|
* Create a `CompilationTicket` as efficiently as possible, based on a previous `NgCompiler`
|
|
39183
39779
|
* instance and a new `ts.Program`.
|
|
39184
39780
|
*/
|
|
39185
|
-
function incrementalFromCompilerTicket(oldCompiler, newProgram, incrementalBuildStrategy, typeCheckingProgramStrategy, modifiedResourceFiles) {
|
|
39781
|
+
function incrementalFromCompilerTicket(oldCompiler, newProgram, incrementalBuildStrategy, typeCheckingProgramStrategy, modifiedResourceFiles, perfRecorder) {
|
|
39186
39782
|
const oldProgram = oldCompiler.getNextProgram();
|
|
39187
39783
|
const oldDriver = oldCompiler.incrementalStrategy.getIncrementalDriver(oldProgram);
|
|
39188
39784
|
if (oldDriver === null) {
|
|
39189
39785
|
// No incremental step is possible here, since no IncrementalDriver was found for the old
|
|
39190
39786
|
// program.
|
|
39191
|
-
return freshCompilationTicket(newProgram, oldCompiler.options, incrementalBuildStrategy, typeCheckingProgramStrategy, oldCompiler.enableTemplateTypeChecker, oldCompiler.usePoisonedData);
|
|
39787
|
+
return freshCompilationTicket(newProgram, oldCompiler.options, incrementalBuildStrategy, typeCheckingProgramStrategy, perfRecorder, oldCompiler.enableTemplateTypeChecker, oldCompiler.usePoisonedData);
|
|
39788
|
+
}
|
|
39789
|
+
if (perfRecorder === null) {
|
|
39790
|
+
perfRecorder = ActivePerfRecorder.zeroedToNow();
|
|
39192
39791
|
}
|
|
39193
|
-
const newDriver = IncrementalDriver.reconcile(oldProgram, oldDriver, newProgram, modifiedResourceFiles);
|
|
39792
|
+
const newDriver = IncrementalDriver.reconcile(oldProgram, oldDriver, newProgram, modifiedResourceFiles, perfRecorder);
|
|
39194
39793
|
return {
|
|
39195
39794
|
kind: CompilationTicketKind.IncrementalTypeScript,
|
|
39196
39795
|
enableTemplateTypeChecker: oldCompiler.enableTemplateTypeChecker,
|
|
@@ -39201,6 +39800,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
39201
39800
|
newDriver,
|
|
39202
39801
|
oldProgram,
|
|
39203
39802
|
newProgram,
|
|
39803
|
+
perfRecorder,
|
|
39204
39804
|
};
|
|
39205
39805
|
}
|
|
39206
39806
|
function resourceChangeTicket(compiler, modifiedResourceFiles) {
|
|
@@ -39208,6 +39808,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
39208
39808
|
kind: CompilationTicketKind.IncrementalResource,
|
|
39209
39809
|
compiler,
|
|
39210
39810
|
modifiedResourceFiles,
|
|
39811
|
+
perfRecorder: ActivePerfRecorder.zeroedToNow(),
|
|
39211
39812
|
};
|
|
39212
39813
|
}
|
|
39213
39814
|
/**
|
|
@@ -39223,7 +39824,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
39223
39824
|
* See the README.md for more information.
|
|
39224
39825
|
*/
|
|
39225
39826
|
class NgCompiler {
|
|
39226
|
-
constructor(adapter, options, tsProgram, typeCheckingProgramStrategy, incrementalStrategy, incrementalDriver, enableTemplateTypeChecker, usePoisonedData,
|
|
39827
|
+
constructor(adapter, options, tsProgram, typeCheckingProgramStrategy, incrementalStrategy, incrementalDriver, enableTemplateTypeChecker, usePoisonedData, livePerfRecorder) {
|
|
39227
39828
|
this.adapter = adapter;
|
|
39228
39829
|
this.options = options;
|
|
39229
39830
|
this.tsProgram = tsProgram;
|
|
@@ -39232,7 +39833,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
39232
39833
|
this.incrementalDriver = incrementalDriver;
|
|
39233
39834
|
this.enableTemplateTypeChecker = enableTemplateTypeChecker;
|
|
39234
39835
|
this.usePoisonedData = usePoisonedData;
|
|
39235
|
-
this.
|
|
39836
|
+
this.livePerfRecorder = livePerfRecorder;
|
|
39236
39837
|
/**
|
|
39237
39838
|
* Lazily evaluated state of the compilation.
|
|
39238
39839
|
*
|
|
@@ -39252,6 +39853,13 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
39252
39853
|
* This is set by (and memoizes) `getNonTemplateDiagnostics`.
|
|
39253
39854
|
*/
|
|
39254
39855
|
this.nonTemplateDiagnostics = null;
|
|
39856
|
+
/**
|
|
39857
|
+
* `NgCompiler` can be reused for multiple compilations (for resource-only changes), and each
|
|
39858
|
+
* new compilation uses a fresh `PerfRecorder`. Thus, classes created with a lifespan of the
|
|
39859
|
+
* `NgCompiler` use a `DelegatingPerfRecorder` so the `PerfRecorder` they write to can be updated
|
|
39860
|
+
* with each fresh compilation.
|
|
39861
|
+
*/
|
|
39862
|
+
this.delegatingPerfRecorder = new DelegatingPerfRecorder(this.perfRecorder);
|
|
39255
39863
|
this.constructionDiagnostics.push(...this.adapter.constructionDiagnostics);
|
|
39256
39864
|
const incompatibleTypeCheckOptionsDiagnostic = verifyCompatibleTypeCheckOptions(this.options);
|
|
39257
39865
|
if (incompatibleTypeCheckOptionsDiagnostic !== null) {
|
|
@@ -39262,9 +39870,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
39262
39870
|
this.entryPoint =
|
|
39263
39871
|
adapter.entryPoint !== null ? getSourceFileOrNull(tsProgram, adapter.entryPoint) : null;
|
|
39264
39872
|
const moduleResolutionCache = ts$1.createModuleResolutionCache(this.adapter.getCurrentDirectory(),
|
|
39265
|
-
//
|
|
39266
|
-
// strange behaviors with retaining the lexical scope of the closure. Even if this function
|
|
39267
|
-
// doesn't retain a reference to `this`, if other closures in the constructor here reference
|
|
39873
|
+
// doen't retain a reference to `this`, if other closures in the constructor here reference
|
|
39268
39874
|
// `this` internally then a closure created here would retain them. This can cause major
|
|
39269
39875
|
// memory leak issues since the `moduleResolutionCache` is a long-lived object and finds its
|
|
39270
39876
|
// way into all kinds of places inside TS internal objects.
|
|
@@ -39272,55 +39878,75 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
39272
39878
|
this.moduleResolver =
|
|
39273
39879
|
new ModuleResolver(tsProgram, this.options, this.adapter, moduleResolutionCache);
|
|
39274
39880
|
this.resourceManager = new AdapterResourceLoader(adapter, this.options);
|
|
39275
|
-
this.cycleAnalyzer =
|
|
39881
|
+
this.cycleAnalyzer =
|
|
39882
|
+
new CycleAnalyzer(new ImportGraph(tsProgram.getTypeChecker(), this.delegatingPerfRecorder));
|
|
39276
39883
|
this.incrementalStrategy.setIncrementalDriver(this.incrementalDriver, tsProgram);
|
|
39277
39884
|
this.ignoreForDiagnostics =
|
|
39278
39885
|
new Set(tsProgram.getSourceFiles().filter(sf => this.adapter.isShim(sf)));
|
|
39279
39886
|
this.ignoreForEmit = this.adapter.ignoreForEmit;
|
|
39887
|
+
let dtsFileCount = 0;
|
|
39888
|
+
let nonDtsFileCount = 0;
|
|
39889
|
+
for (const sf of tsProgram.getSourceFiles()) {
|
|
39890
|
+
if (sf.isDeclarationFile) {
|
|
39891
|
+
dtsFileCount++;
|
|
39892
|
+
}
|
|
39893
|
+
else {
|
|
39894
|
+
nonDtsFileCount++;
|
|
39895
|
+
}
|
|
39896
|
+
}
|
|
39897
|
+
livePerfRecorder.eventCount(PerfEvent.InputDtsFile, dtsFileCount);
|
|
39898
|
+
livePerfRecorder.eventCount(PerfEvent.InputTsFile, nonDtsFileCount);
|
|
39280
39899
|
}
|
|
39281
39900
|
/**
|
|
39282
39901
|
* Convert a `CompilationTicket` into an `NgCompiler` instance for the requested compilation.
|
|
39283
39902
|
*
|
|
39284
39903
|
* Depending on the nature of the compilation request, the `NgCompiler` instance may be reused
|
|
39285
39904
|
* from a previous compilation and updated with any changes, it may be a new instance which
|
|
39286
|
-
* incrementally reuses state from a previous compilation, or it may represent a fresh
|
|
39287
|
-
* entirely.
|
|
39905
|
+
* incrementally reuses state from a previous compilation, or it may represent a fresh
|
|
39906
|
+
* compilation entirely.
|
|
39288
39907
|
*/
|
|
39289
|
-
static fromTicket(ticket, adapter
|
|
39908
|
+
static fromTicket(ticket, adapter) {
|
|
39290
39909
|
switch (ticket.kind) {
|
|
39291
39910
|
case CompilationTicketKind.Fresh:
|
|
39292
|
-
return new NgCompiler(adapter, ticket.options, ticket.tsProgram, ticket.typeCheckingProgramStrategy, ticket.incrementalBuildStrategy, IncrementalDriver.fresh(ticket.tsProgram), ticket.enableTemplateTypeChecker, ticket.usePoisonedData, perfRecorder);
|
|
39911
|
+
return new NgCompiler(adapter, ticket.options, ticket.tsProgram, ticket.typeCheckingProgramStrategy, ticket.incrementalBuildStrategy, IncrementalDriver.fresh(ticket.tsProgram), ticket.enableTemplateTypeChecker, ticket.usePoisonedData, ticket.perfRecorder);
|
|
39293
39912
|
case CompilationTicketKind.IncrementalTypeScript:
|
|
39294
|
-
return new NgCompiler(adapter, ticket.options, ticket.newProgram, ticket.typeCheckingProgramStrategy, ticket.incrementalBuildStrategy, ticket.newDriver, ticket.enableTemplateTypeChecker, ticket.usePoisonedData, perfRecorder);
|
|
39913
|
+
return new NgCompiler(adapter, ticket.options, ticket.newProgram, ticket.typeCheckingProgramStrategy, ticket.incrementalBuildStrategy, ticket.newDriver, ticket.enableTemplateTypeChecker, ticket.usePoisonedData, ticket.perfRecorder);
|
|
39295
39914
|
case CompilationTicketKind.IncrementalResource:
|
|
39296
39915
|
const compiler = ticket.compiler;
|
|
39297
|
-
compiler.updateWithChangedResources(ticket.modifiedResourceFiles);
|
|
39916
|
+
compiler.updateWithChangedResources(ticket.modifiedResourceFiles, ticket.perfRecorder);
|
|
39298
39917
|
return compiler;
|
|
39299
39918
|
}
|
|
39300
39919
|
}
|
|
39301
|
-
|
|
39302
|
-
|
|
39303
|
-
|
|
39304
|
-
|
|
39305
|
-
|
|
39306
|
-
|
|
39307
|
-
|
|
39308
|
-
|
|
39309
|
-
|
|
39310
|
-
|
|
39311
|
-
|
|
39920
|
+
get perfRecorder() {
|
|
39921
|
+
return this.livePerfRecorder;
|
|
39922
|
+
}
|
|
39923
|
+
updateWithChangedResources(changedResources, perfRecorder) {
|
|
39924
|
+
this.livePerfRecorder = perfRecorder;
|
|
39925
|
+
this.delegatingPerfRecorder.target = perfRecorder;
|
|
39926
|
+
perfRecorder.inPhase(PerfPhase.ResourceUpdate, () => {
|
|
39927
|
+
if (this.compilation === null) {
|
|
39928
|
+
// Analysis hasn't happened yet, so no update is necessary - any changes to resources will
|
|
39929
|
+
// be captured by the inital analysis pass itself.
|
|
39930
|
+
return;
|
|
39312
39931
|
}
|
|
39313
|
-
|
|
39314
|
-
|
|
39932
|
+
this.resourceManager.invalidate();
|
|
39933
|
+
const classesToUpdate = new Set();
|
|
39934
|
+
for (const resourceFile of changedResources) {
|
|
39935
|
+
for (const templateClass of this.getComponentsWithTemplateFile(resourceFile)) {
|
|
39936
|
+
classesToUpdate.add(templateClass);
|
|
39937
|
+
}
|
|
39938
|
+
for (const styleClass of this.getComponentsWithStyleFile(resourceFile)) {
|
|
39939
|
+
classesToUpdate.add(styleClass);
|
|
39940
|
+
}
|
|
39315
39941
|
}
|
|
39316
|
-
|
|
39317
|
-
|
|
39318
|
-
|
|
39319
|
-
|
|
39320
|
-
|
|
39942
|
+
for (const clazz of classesToUpdate) {
|
|
39943
|
+
this.compilation.traitCompiler.updateResources(clazz);
|
|
39944
|
+
if (!ts$1.isClassDeclaration(clazz)) {
|
|
39945
|
+
continue;
|
|
39946
|
+
}
|
|
39947
|
+
this.compilation.templateTypeChecker.invalidateClass(clazz);
|
|
39321
39948
|
}
|
|
39322
|
-
|
|
39323
|
-
}
|
|
39949
|
+
});
|
|
39324
39950
|
}
|
|
39325
39951
|
/**
|
|
39326
39952
|
* Get the resource dependencies of a file.
|
|
@@ -39427,29 +40053,23 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
39427
40053
|
if (this.compilation !== null) {
|
|
39428
40054
|
return;
|
|
39429
40055
|
}
|
|
39430
|
-
this.
|
|
39431
|
-
|
|
39432
|
-
|
|
39433
|
-
|
|
39434
|
-
|
|
39435
|
-
|
|
39436
|
-
|
|
39437
|
-
|
|
39438
|
-
|
|
39439
|
-
|
|
39440
|
-
|
|
39441
|
-
|
|
39442
|
-
}
|
|
39443
|
-
else if (this.perfRecorder.enabled) {
|
|
39444
|
-
analysisPromise = analysisPromise.then(() => this.perfRecorder.stop(analyzeFileSpan));
|
|
39445
|
-
}
|
|
39446
|
-
if (analysisPromise !== undefined) {
|
|
39447
|
-
promises.push(analysisPromise);
|
|
40056
|
+
yield this.perfRecorder.inPhase(PerfPhase.Analysis, () => __awaiter(this, void 0, void 0, function* () {
|
|
40057
|
+
this.compilation = this.makeCompilation();
|
|
40058
|
+
const promises = [];
|
|
40059
|
+
for (const sf of this.tsProgram.getSourceFiles()) {
|
|
40060
|
+
if (sf.isDeclarationFile) {
|
|
40061
|
+
continue;
|
|
40062
|
+
}
|
|
40063
|
+
let analysisPromise = this.compilation.traitCompiler.analyzeAsync(sf);
|
|
40064
|
+
this.scanForMwp(sf);
|
|
40065
|
+
if (analysisPromise !== undefined) {
|
|
40066
|
+
promises.push(analysisPromise);
|
|
40067
|
+
}
|
|
39448
40068
|
}
|
|
39449
|
-
|
|
39450
|
-
|
|
39451
|
-
|
|
39452
|
-
|
|
40069
|
+
yield Promise.all(promises);
|
|
40070
|
+
this.perfRecorder.memory(PerfCheckpoint.Analysis);
|
|
40071
|
+
this.resolveCompilation(this.compilation.traitCompiler);
|
|
40072
|
+
}));
|
|
39453
40073
|
});
|
|
39454
40074
|
}
|
|
39455
40075
|
/**
|
|
@@ -39459,9 +40079,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
39459
40079
|
*/
|
|
39460
40080
|
listLazyRoutes(entryRoute) {
|
|
39461
40081
|
if (entryRoute) {
|
|
39462
|
-
//
|
|
39463
|
-
// This resolution step is here to match the implementation of the old `AotCompilerHost` (see
|
|
39464
|
-
// https://github.com/angular/angular/blob/50732e156/packages/compiler-cli/src/transformers/compiler_host.ts#L175-L188).
|
|
40082
|
+
// htts://github.com/angular/angular/blob/50732e156/packages/compiler-cli/src/transformers/compiler_host.ts#L175-L188).
|
|
39465
40083
|
//
|
|
39466
40084
|
// `@angular/cli` will always call this API with an absolute path, so the resolution step is
|
|
39467
40085
|
// not necessary, but keeping it backwards compatible in case someone else is using the API.
|
|
@@ -39503,7 +40121,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
39503
40121
|
importRewriter = new NoopImportRewriter();
|
|
39504
40122
|
}
|
|
39505
40123
|
const before = [
|
|
39506
|
-
ivyTransformFactory(compilation.traitCompiler, compilation.reflector, importRewriter, compilation.defaultImportTracker, compilation.isCore, this.closureCompilerEnabled),
|
|
40124
|
+
ivyTransformFactory(compilation.traitCompiler, compilation.reflector, importRewriter, compilation.defaultImportTracker, this.delegatingPerfRecorder, compilation.isCore, this.closureCompilerEnabled),
|
|
39507
40125
|
aliasTransformFactory(compilation.traitCompiler.exportStatements),
|
|
39508
40126
|
compilation.defaultImportTracker.importPreservingTransformer(),
|
|
39509
40127
|
];
|
|
@@ -39539,25 +40157,27 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
39539
40157
|
return this.compilation;
|
|
39540
40158
|
}
|
|
39541
40159
|
analyzeSync() {
|
|
39542
|
-
|
|
39543
|
-
|
|
39544
|
-
|
|
39545
|
-
|
|
39546
|
-
|
|
40160
|
+
this.perfRecorder.inPhase(PerfPhase.Analysis, () => {
|
|
40161
|
+
this.compilation = this.makeCompilation();
|
|
40162
|
+
for (const sf of this.tsProgram.getSourceFiles()) {
|
|
40163
|
+
if (sf.isDeclarationFile) {
|
|
40164
|
+
continue;
|
|
40165
|
+
}
|
|
40166
|
+
this.compilation.traitCompiler.analyzeSync(sf);
|
|
40167
|
+
this.scanForMwp(sf);
|
|
39547
40168
|
}
|
|
39548
|
-
|
|
39549
|
-
this.compilation.traitCompiler
|
|
39550
|
-
|
|
39551
|
-
this.perfRecorder.stop(analyzeFileSpan);
|
|
39552
|
-
}
|
|
39553
|
-
this.perfRecorder.stop(analyzeSpan);
|
|
39554
|
-
this.resolveCompilation(this.compilation.traitCompiler);
|
|
40169
|
+
this.perfRecorder.memory(PerfCheckpoint.Analysis);
|
|
40170
|
+
this.resolveCompilation(this.compilation.traitCompiler);
|
|
40171
|
+
});
|
|
39555
40172
|
}
|
|
39556
40173
|
resolveCompilation(traitCompiler) {
|
|
39557
|
-
|
|
39558
|
-
|
|
39559
|
-
|
|
39560
|
-
|
|
40174
|
+
this.perfRecorder.inPhase(PerfPhase.Resolve, () => {
|
|
40175
|
+
traitCompiler.resolve();
|
|
40176
|
+
// At this point, analysis is complete and the compiler can now calculate which files need to
|
|
40177
|
+
// be emitted, so do that.
|
|
40178
|
+
this.incrementalDriver.recordSuccessfulAnalysis(traitCompiler);
|
|
40179
|
+
this.perfRecorder.memory(PerfCheckpoint.Resolve);
|
|
40180
|
+
});
|
|
39561
40181
|
}
|
|
39562
40182
|
get fullTemplateTypeCheck() {
|
|
39563
40183
|
// Determine the strictness level of type checking based on compiler options. As
|
|
@@ -39573,6 +40193,7 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
39573
40193
|
// Also see `verifyCompatibleTypeCheckOptions` where it is verified that `fullTemplateTypeCheck`
|
|
39574
40194
|
// is not disabled when `strictTemplates` is enabled.
|
|
39575
40195
|
const strictTemplates = !!this.options.strictTemplates;
|
|
40196
|
+
const useInlineTypeConstructors = this.typeCheckingProgramStrategy.supportsInlineOperations;
|
|
39576
40197
|
// First select a type-checking configuration, based on whether full template type-checking is
|
|
39577
40198
|
// requested.
|
|
39578
40199
|
let typeCheckingConfig;
|
|
@@ -39604,6 +40225,11 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
39604
40225
|
useContextGenericType: strictTemplates,
|
|
39605
40226
|
strictLiteralTypes: true,
|
|
39606
40227
|
enableTemplateTypeChecker: this.enableTemplateTypeChecker,
|
|
40228
|
+
useInlineTypeConstructors,
|
|
40229
|
+
// Warnings for suboptimal type inference are only enabled if in Language Service mode
|
|
40230
|
+
// (providing the full TemplateTypeChecker API) and if strict mode is not enabled. In strict
|
|
40231
|
+
// mode, the user is in full control of type inference.
|
|
40232
|
+
suggestionsForSuboptimalTypeInference: this.enableTemplateTypeChecker && !strictTemplates,
|
|
39607
40233
|
};
|
|
39608
40234
|
}
|
|
39609
40235
|
else {
|
|
@@ -39629,6 +40255,10 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
39629
40255
|
useContextGenericType: false,
|
|
39630
40256
|
strictLiteralTypes: false,
|
|
39631
40257
|
enableTemplateTypeChecker: this.enableTemplateTypeChecker,
|
|
40258
|
+
useInlineTypeConstructors,
|
|
40259
|
+
// In "basic" template type-checking mode, no warnings are produced since most things are
|
|
40260
|
+
// not checked anyways.
|
|
40261
|
+
suggestionsForSuboptimalTypeInference: false,
|
|
39632
40262
|
};
|
|
39633
40263
|
}
|
|
39634
40264
|
// Apply explicitly configured strictness flags on top of the default configuration
|
|
@@ -39671,7 +40301,6 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
39671
40301
|
getTemplateDiagnostics() {
|
|
39672
40302
|
const compilation = this.ensureAnalyzed();
|
|
39673
40303
|
// Get the diagnostics.
|
|
39674
|
-
const typeCheckSpan = this.perfRecorder.start('typeCheckDiagnostics');
|
|
39675
40304
|
const diagnostics = [];
|
|
39676
40305
|
for (const sf of this.tsProgram.getSourceFiles()) {
|
|
39677
40306
|
if (sf.isDeclarationFile || this.adapter.isShim(sf)) {
|
|
@@ -39680,7 +40309,6 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
39680
40309
|
diagnostics.push(...compilation.templateTypeChecker.getDiagnosticsForFile(sf, OptimizeFor.WholeProgram));
|
|
39681
40310
|
}
|
|
39682
40311
|
const program = this.typeCheckingProgramStrategy.getProgram();
|
|
39683
|
-
this.perfRecorder.stop(typeCheckSpan);
|
|
39684
40312
|
this.incrementalStrategy.setIncrementalDriver(this.incrementalDriver, program);
|
|
39685
40313
|
this.nextProgram = program;
|
|
39686
40314
|
return diagnostics;
|
|
@@ -39688,13 +40316,11 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
39688
40316
|
getTemplateDiagnosticsForFile(sf, optimizeFor) {
|
|
39689
40317
|
const compilation = this.ensureAnalyzed();
|
|
39690
40318
|
// Get the diagnostics.
|
|
39691
|
-
const typeCheckSpan = this.perfRecorder.start('typeCheckDiagnostics');
|
|
39692
40319
|
const diagnostics = [];
|
|
39693
40320
|
if (!sf.isDeclarationFile && !this.adapter.isShim(sf)) {
|
|
39694
40321
|
diagnostics.push(...compilation.templateTypeChecker.getDiagnosticsForFile(sf, optimizeFor));
|
|
39695
40322
|
}
|
|
39696
40323
|
const program = this.typeCheckingProgramStrategy.getProgram();
|
|
39697
|
-
this.perfRecorder.stop(typeCheckSpan);
|
|
39698
40324
|
this.incrementalStrategy.setIncrementalDriver(this.incrementalDriver, program);
|
|
39699
40325
|
this.nextProgram = program;
|
|
39700
40326
|
return diagnostics;
|
|
@@ -39813,20 +40439,20 @@ Either add the @Injectable() decorator to '${provider.node.name
|
|
|
39813
40439
|
1 /* Error */;
|
|
39814
40440
|
// Set up the IvyCompilation, which manages state for the Ivy transformer.
|
|
39815
40441
|
const handlers = [
|
|
39816
|
-
new ComponentDecoratorHandler(reflector, evaluator, metaRegistry, metaReader, scopeReader, scopeRegistry, typeCheckScopeRegistry, resourceRegistry, isCore, this.resourceManager, this.adapter.rootDirs, this.options.preserveWhitespaces || false, this.options.i18nUseExternalIds !== false, this.options.enableI18nLegacyMessageIdFormat !== false, this.usePoisonedData, this.options.i18nNormalizeLineEndingsInICUs, this.moduleResolver, this.cycleAnalyzer, cycleHandlingStrategy, refEmitter, defaultImportTracker, this.incrementalDriver.depGraph, injectableRegistry, semanticDepGraphUpdater, this.closureCompilerEnabled),
|
|
40442
|
+
new ComponentDecoratorHandler(reflector, evaluator, metaRegistry, metaReader, scopeReader, scopeRegistry, typeCheckScopeRegistry, resourceRegistry, isCore, this.resourceManager, this.adapter.rootDirs, this.options.preserveWhitespaces || false, this.options.i18nUseExternalIds !== false, this.options.enableI18nLegacyMessageIdFormat !== false, this.usePoisonedData, this.options.i18nNormalizeLineEndingsInICUs, this.moduleResolver, this.cycleAnalyzer, cycleHandlingStrategy, refEmitter, defaultImportTracker, this.incrementalDriver.depGraph, injectableRegistry, semanticDepGraphUpdater, this.closureCompilerEnabled, this.delegatingPerfRecorder),
|
|
39817
40443
|
// TODO(alxhub): understand why the cast here is necessary (something to do with `null`
|
|
39818
40444
|
// not being assignable to `unknown` when wrapped in `Readonly`).
|
|
39819
40445
|
// clang-format off
|
|
39820
|
-
new DirectiveDecoratorHandler(reflector, evaluator, metaRegistry, scopeRegistry, metaReader, defaultImportTracker, injectableRegistry, isCore, semanticDepGraphUpdater, this.closureCompilerEnabled, compileUndecoratedClassesWithAngularFeatures),
|
|
40446
|
+
new DirectiveDecoratorHandler(reflector, evaluator, metaRegistry, scopeRegistry, metaReader, defaultImportTracker, injectableRegistry, isCore, semanticDepGraphUpdater, this.closureCompilerEnabled, compileUndecoratedClassesWithAngularFeatures, this.delegatingPerfRecorder),
|
|
39821
40447
|
// clang-format on
|
|
39822
40448
|
// Pipe handler must be before injectable handler in list so pipe factories are printed
|
|
39823
40449
|
// before injectable factories (so injectable factories can delegate to them)
|
|
39824
|
-
new PipeDecoratorHandler(reflector, evaluator, metaRegistry, scopeRegistry, defaultImportTracker, injectableRegistry, isCore),
|
|
39825
|
-
new InjectableDecoratorHandler(reflector, defaultImportTracker, isCore, this.options.strictInjectionParameters || false, injectableRegistry),
|
|
39826
|
-
new NgModuleDecoratorHandler(reflector, evaluator, metaReader, metaRegistry, scopeRegistry, referencesRegistry, isCore, routeAnalyzer, refEmitter, this.adapter.factoryTracker, defaultImportTracker, this.closureCompilerEnabled, injectableRegistry, this.options.i18nInLocale),
|
|
40450
|
+
new PipeDecoratorHandler(reflector, evaluator, metaRegistry, scopeRegistry, defaultImportTracker, injectableRegistry, isCore, this.delegatingPerfRecorder),
|
|
40451
|
+
new InjectableDecoratorHandler(reflector, defaultImportTracker, isCore, this.options.strictInjectionParameters || false, injectableRegistry, this.delegatingPerfRecorder),
|
|
40452
|
+
new NgModuleDecoratorHandler(reflector, evaluator, metaReader, metaRegistry, scopeRegistry, referencesRegistry, isCore, routeAnalyzer, refEmitter, this.adapter.factoryTracker, defaultImportTracker, this.closureCompilerEnabled, injectableRegistry, this.delegatingPerfRecorder, this.options.i18nInLocale),
|
|
39827
40453
|
];
|
|
39828
|
-
const traitCompiler = new TraitCompiler(handlers, reflector, this.
|
|
39829
|
-
const templateTypeChecker = new TemplateTypeCheckerImpl(this.tsProgram, this.typeCheckingProgramStrategy, traitCompiler, this.getTypeCheckingConfig(), refEmitter, reflector, this.adapter, this.incrementalDriver, scopeRegistry, typeCheckScopeRegistry);
|
|
40454
|
+
const traitCompiler = new TraitCompiler(handlers, reflector, this.delegatingPerfRecorder, this.incrementalDriver, this.options.compileNonExportedClasses !== false, compilationMode, dtsTransforms, semanticDepGraphUpdater);
|
|
40455
|
+
const templateTypeChecker = new TemplateTypeCheckerImpl(this.tsProgram, this.typeCheckingProgramStrategy, traitCompiler, this.getTypeCheckingConfig(), refEmitter, reflector, this.adapter, this.incrementalDriver, scopeRegistry, typeCheckScopeRegistry, this.delegatingPerfRecorder);
|
|
39830
40456
|
return {
|
|
39831
40457
|
isCore,
|
|
39832
40458
|
traitCompiler,
|
|
@@ -40019,24 +40645,30 @@ https://v9.angular.io/guide/template-typecheck#template-type-checking`,
|
|
|
40019
40645
|
};
|
|
40020
40646
|
}
|
|
40021
40647
|
function getExtendedConfigPath(configFile, extendsValue, host, fs) {
|
|
40022
|
-
|
|
40648
|
+
const result = getExtendedConfigPathWorker(configFile, extendsValue, host, fs);
|
|
40649
|
+
if (result !== null) {
|
|
40650
|
+
return result;
|
|
40651
|
+
}
|
|
40652
|
+
// Try to resolve the paths with a json extension append a json extension to the file in case if
|
|
40653
|
+
// it is missing and the resolution failed. This is to replicate TypeScript behaviour, see:
|
|
40654
|
+
// https://github.com/microsoft/TypeScript/blob/294a5a7d784a5a95a8048ee990400979a6bc3a1c/src/compiler/commandLineParser.ts#L2806
|
|
40655
|
+
return getExtendedConfigPathWorker(configFile, `${extendsValue}.json`, host, fs);
|
|
40656
|
+
}
|
|
40657
|
+
function getExtendedConfigPathWorker(configFile, extendsValue, host, fs) {
|
|
40023
40658
|
if (extendsValue.startsWith('.') || fs.isRooted(extendsValue)) {
|
|
40024
|
-
extendedConfigPath = host.resolve(host.dirname(configFile), extendsValue);
|
|
40025
|
-
|
|
40026
|
-
extendedConfigPath
|
|
40027
|
-
|
|
40659
|
+
const extendedConfigPath = host.resolve(host.dirname(configFile), extendsValue);
|
|
40660
|
+
if (host.exists(extendedConfigPath)) {
|
|
40661
|
+
return extendedConfigPath;
|
|
40662
|
+
}
|
|
40028
40663
|
}
|
|
40029
40664
|
else {
|
|
40030
40665
|
const parseConfigHost = createParseConfigHost(host, fs);
|
|
40031
40666
|
// Path isn't a rooted or relative path, resolve like a module.
|
|
40032
40667
|
const { resolvedModule, } = ts$1.nodeModuleNameResolver(extendsValue, configFile, { moduleResolution: ts$1.ModuleResolutionKind.NodeJs, resolveJsonModule: true }, parseConfigHost);
|
|
40033
40668
|
if (resolvedModule) {
|
|
40034
|
-
|
|
40669
|
+
return absoluteFrom(resolvedModule.resolvedFileName);
|
|
40035
40670
|
}
|
|
40036
40671
|
}
|
|
40037
|
-
if (extendedConfigPath !== null && host.exists(extendedConfigPath)) {
|
|
40038
|
-
return extendedConfigPath;
|
|
40039
|
-
}
|
|
40040
40672
|
return null;
|
|
40041
40673
|
}
|
|
40042
40674
|
|
|
@@ -40745,14 +41377,20 @@ https://v9.angular.io/guide/template-typecheck#template-type-checking`,
|
|
|
40745
41377
|
const ticket = resourceChangeTicket(this.compiler, modifiedResourceFiles);
|
|
40746
41378
|
this.compiler = NgCompiler.fromTicket(ticket, this.adapter);
|
|
40747
41379
|
}
|
|
41380
|
+
else {
|
|
41381
|
+
// The previous NgCompiler is being reused, but we still want to reset its performance
|
|
41382
|
+
// tracker to capture only the operations that are needed to service the current request.
|
|
41383
|
+
this.compiler.perfRecorder.reset();
|
|
41384
|
+
}
|
|
40748
41385
|
return this.compiler;
|
|
40749
41386
|
}
|
|
40750
41387
|
let ticket;
|
|
40751
41388
|
if (this.compiler === null || this.lastKnownProgram === null) {
|
|
40752
|
-
ticket = freshCompilationTicket(program, this.options, this.incrementalStrategy, this.programStrategy,
|
|
41389
|
+
ticket = freshCompilationTicket(program, this.options, this.incrementalStrategy, this.programStrategy,
|
|
41390
|
+
/* perfRecorder */ null, true, true);
|
|
40753
41391
|
}
|
|
40754
41392
|
else {
|
|
40755
|
-
ticket = incrementalFromCompilerTicket(this.compiler, program, this.incrementalStrategy, this.programStrategy, modifiedResourceFiles);
|
|
41393
|
+
ticket = incrementalFromCompilerTicket(this.compiler, program, this.incrementalStrategy, this.programStrategy, modifiedResourceFiles, /* perfRecorder */ null);
|
|
40756
41394
|
}
|
|
40757
41395
|
this.compiler = NgCompiler.fromTicket(ticket, this.adapter);
|
|
40758
41396
|
this.lastKnownProgram = program;
|
|
@@ -42556,43 +43194,50 @@ https://v9.angular.io/guide/template-typecheck#template-type-checking`,
|
|
|
42556
43194
|
this.ttc = this.compiler.getTemplateTypeChecker();
|
|
42557
43195
|
}
|
|
42558
43196
|
getRenameInfo(filePath, position) {
|
|
42559
|
-
|
|
42560
|
-
|
|
42561
|
-
|
|
42562
|
-
|
|
42563
|
-
|
|
42564
|
-
|
|
42565
|
-
|
|
42566
|
-
|
|
42567
|
-
|
|
42568
|
-
|
|
42569
|
-
|
|
42570
|
-
|
|
42571
|
-
|
|
42572
|
-
|
|
42573
|
-
|
|
42574
|
-
|
|
42575
|
-
|
|
42576
|
-
|
|
42577
|
-
|
|
42578
|
-
|
|
42579
|
-
|
|
42580
|
-
|
|
43197
|
+
return this.compiler.perfRecorder.inPhase(PerfPhase.LsReferencesAndRenames, () => {
|
|
43198
|
+
const templateInfo = getTemplateInfoAtPosition(filePath, position, this.compiler);
|
|
43199
|
+
// We could not get a template at position so we assume the request came from outside the
|
|
43200
|
+
// template.
|
|
43201
|
+
if (templateInfo === undefined) {
|
|
43202
|
+
return this.tsLS.getRenameInfo(filePath, position);
|
|
43203
|
+
}
|
|
43204
|
+
const allTargetDetails = this.getTargetDetailsAtTemplatePosition(templateInfo, position);
|
|
43205
|
+
if (allTargetDetails === null) {
|
|
43206
|
+
return {
|
|
43207
|
+
canRename: false,
|
|
43208
|
+
localizedErrorMessage: 'Could not find template node at position.',
|
|
43209
|
+
};
|
|
43210
|
+
}
|
|
43211
|
+
const { templateTarget } = allTargetDetails[0];
|
|
43212
|
+
const templateTextAndSpan = getRenameTextAndSpanAtPosition(templateTarget, position);
|
|
43213
|
+
if (templateTextAndSpan === null) {
|
|
43214
|
+
return { canRename: false, localizedErrorMessage: 'Could not determine template node text.' };
|
|
43215
|
+
}
|
|
43216
|
+
const { text, span } = templateTextAndSpan;
|
|
43217
|
+
return {
|
|
43218
|
+
canRename: true,
|
|
43219
|
+
displayName: text,
|
|
43220
|
+
fullDisplayName: text,
|
|
43221
|
+
triggerSpan: span,
|
|
43222
|
+
};
|
|
43223
|
+
});
|
|
42581
43224
|
}
|
|
42582
43225
|
findRenameLocations(filePath, position) {
|
|
42583
43226
|
this.ttc.generateAllTypeCheckBlocks();
|
|
42584
|
-
|
|
42585
|
-
|
|
42586
|
-
|
|
42587
|
-
|
|
42588
|
-
|
|
42589
|
-
|
|
42590
|
-
|
|
43227
|
+
return this.compiler.perfRecorder.inPhase(PerfPhase.LsReferencesAndRenames, () => {
|
|
43228
|
+
const templateInfo = getTemplateInfoAtPosition(filePath, position, this.compiler);
|
|
43229
|
+
// We could not get a template at position so we assume the request came from outside the
|
|
43230
|
+
// template.
|
|
43231
|
+
if (templateInfo === undefined) {
|
|
43232
|
+
const requestNode = this.getTsNodeAtPosition(filePath, position);
|
|
43233
|
+
if (requestNode === null) {
|
|
43234
|
+
return undefined;
|
|
43235
|
+
}
|
|
43236
|
+
const requestOrigin = { kind: RequestKind.TypeScript, requestNode };
|
|
43237
|
+
return this.findRenameLocationsAtTypescriptPosition(filePath, position, requestOrigin);
|
|
42591
43238
|
}
|
|
42592
|
-
|
|
42593
|
-
|
|
42594
|
-
}
|
|
42595
|
-
return this.findRenameLocationsAtTemplatePosition(templateInfo, position);
|
|
43239
|
+
return this.findRenameLocationsAtTemplatePosition(templateInfo, position);
|
|
43240
|
+
});
|
|
42596
43241
|
}
|
|
42597
43242
|
findRenameLocationsAtTemplatePosition(templateInfo, position) {
|
|
42598
43243
|
const allTargetDetails = this.getTargetDetailsAtTemplatePosition(templateInfo, position);
|
|
@@ -42627,52 +43272,56 @@ https://v9.angular.io/guide/template-typecheck#template-type-checking`,
|
|
|
42627
43272
|
return (_a = findTightestNode(sf, position)) !== null && _a !== void 0 ? _a : null;
|
|
42628
43273
|
}
|
|
42629
43274
|
findRenameLocationsAtTypescriptPosition(filePath, position, requestOrigin) {
|
|
42630
|
-
|
|
42631
|
-
|
|
42632
|
-
|
|
42633
|
-
|
|
42634
|
-
else {
|
|
42635
|
-
const templateNodeText = getRenameTextAndSpanAtPosition(requestOrigin.requestNode, requestOrigin.position);
|
|
42636
|
-
if (templateNodeText === null) {
|
|
42637
|
-
return undefined;
|
|
43275
|
+
return this.compiler.perfRecorder.inPhase(PerfPhase.LsReferencesAndRenames, () => {
|
|
43276
|
+
let originalNodeText;
|
|
43277
|
+
if (requestOrigin.kind === RequestKind.TypeScript) {
|
|
43278
|
+
originalNodeText = requestOrigin.requestNode.getText();
|
|
42638
43279
|
}
|
|
42639
|
-
|
|
42640
|
-
|
|
42641
|
-
|
|
42642
|
-
if (locations === undefined) {
|
|
42643
|
-
return undefined;
|
|
42644
|
-
}
|
|
42645
|
-
const entries = new Map();
|
|
42646
|
-
for (const location of locations) {
|
|
42647
|
-
// TODO(atscott): Determine if a file is a shim file in a more robust way and make the API
|
|
42648
|
-
// available in an appropriate location.
|
|
42649
|
-
if (this.ttc.isTrackedTypeCheckFile(absoluteFrom(location.fileName))) {
|
|
42650
|
-
const entry = this.convertToTemplateDocumentSpan(location, this.ttc, originalNodeText);
|
|
42651
|
-
// There is no template node whose text matches the original rename request. Bail on
|
|
42652
|
-
// renaming completely rather than providing incomplete results.
|
|
42653
|
-
if (entry === null) {
|
|
43280
|
+
else {
|
|
43281
|
+
const templateNodeText = getRenameTextAndSpanAtPosition(requestOrigin.requestNode, requestOrigin.position);
|
|
43282
|
+
if (templateNodeText === null) {
|
|
42654
43283
|
return undefined;
|
|
42655
43284
|
}
|
|
42656
|
-
|
|
43285
|
+
originalNodeText = templateNodeText.text;
|
|
42657
43286
|
}
|
|
42658
|
-
|
|
42659
|
-
|
|
42660
|
-
|
|
42661
|
-
|
|
42662
|
-
|
|
43287
|
+
const locations = this.tsLS.findRenameLocations(filePath, position, /*findInStrings*/ false, /*findInComments*/ false);
|
|
43288
|
+
if (locations === undefined) {
|
|
43289
|
+
return undefined;
|
|
43290
|
+
}
|
|
43291
|
+
const entries = new Map();
|
|
43292
|
+
for (const location of locations) {
|
|
43293
|
+
// TODO(atscott): Determine if a file is a shim file in a more robust way and make the API
|
|
43294
|
+
// available in an appropriate location.
|
|
43295
|
+
if (this.ttc.isTrackedTypeCheckFile(absoluteFrom(location.fileName))) {
|
|
43296
|
+
const entry = this.convertToTemplateDocumentSpan(location, this.ttc, originalNodeText);
|
|
43297
|
+
// There is no template node whose text matches the original rename request. Bail on
|
|
43298
|
+
// renaming completely rather than providing incomplete results.
|
|
43299
|
+
if (entry === null) {
|
|
43300
|
+
return undefined;
|
|
43301
|
+
}
|
|
43302
|
+
entries.set(createLocationKey(entry), entry);
|
|
43303
|
+
}
|
|
43304
|
+
else {
|
|
43305
|
+
// Ensure we only allow renaming a TS result with matching text
|
|
43306
|
+
const refNode = this.getTsNodeAtPosition(location.fileName, location.textSpan.start);
|
|
43307
|
+
if (refNode === null || refNode.getText() !== originalNodeText) {
|
|
43308
|
+
return undefined;
|
|
43309
|
+
}
|
|
43310
|
+
entries.set(createLocationKey(location), location);
|
|
42663
43311
|
}
|
|
42664
|
-
entries.set(createLocationKey(location), location);
|
|
42665
43312
|
}
|
|
42666
|
-
|
|
42667
|
-
|
|
43313
|
+
return Array.from(entries.values());
|
|
43314
|
+
});
|
|
42668
43315
|
}
|
|
42669
43316
|
getReferencesAtPosition(filePath, position) {
|
|
42670
43317
|
this.ttc.generateAllTypeCheckBlocks();
|
|
42671
|
-
|
|
42672
|
-
|
|
42673
|
-
|
|
42674
|
-
|
|
42675
|
-
|
|
43318
|
+
return this.compiler.perfRecorder.inPhase(PerfPhase.LsReferencesAndRenames, () => {
|
|
43319
|
+
const templateInfo = getTemplateInfoAtPosition(filePath, position, this.compiler);
|
|
43320
|
+
if (templateInfo === undefined) {
|
|
43321
|
+
return this.getReferencesAtTypescriptPosition(filePath, position);
|
|
43322
|
+
}
|
|
43323
|
+
return this.getReferencesAtTemplatePosition(templateInfo, position);
|
|
43324
|
+
});
|
|
42676
43325
|
}
|
|
42677
43326
|
getReferencesAtTemplatePosition(templateInfo, position) {
|
|
42678
43327
|
const allTargetDetails = this.getTargetDetailsAtTemplatePosition(templateInfo, position);
|
|
@@ -42913,49 +43562,52 @@ https://v9.angular.io/guide/template-typecheck#template-type-checking`,
|
|
|
42913
43562
|
return this.options;
|
|
42914
43563
|
}
|
|
42915
43564
|
getSemanticDiagnostics(fileName) {
|
|
42916
|
-
|
|
42917
|
-
|
|
42918
|
-
|
|
42919
|
-
|
|
42920
|
-
|
|
42921
|
-
|
|
42922
|
-
|
|
42923
|
-
|
|
42924
|
-
|
|
42925
|
-
|
|
42926
|
-
|
|
42927
|
-
|
|
42928
|
-
|
|
42929
|
-
|
|
42930
|
-
|
|
42931
|
-
|
|
42932
|
-
|
|
42933
|
-
|
|
42934
|
-
|
|
42935
|
-
|
|
42936
|
-
|
|
42937
|
-
|
|
42938
|
-
|
|
42939
|
-
|
|
42940
|
-
|
|
42941
|
-
|
|
42942
|
-
|
|
42943
|
-
|
|
43565
|
+
return this.withCompilerAndPerfTracing(PerfPhase.LsDiagnostics, (compiler) => {
|
|
43566
|
+
const ttc = compiler.getTemplateTypeChecker();
|
|
43567
|
+
const diagnostics = [];
|
|
43568
|
+
if (isTypeScriptFile(fileName)) {
|
|
43569
|
+
const program = compiler.getNextProgram();
|
|
43570
|
+
const sourceFile = program.getSourceFile(fileName);
|
|
43571
|
+
if (sourceFile) {
|
|
43572
|
+
const ngDiagnostics = compiler.getDiagnosticsForFile(sourceFile, OptimizeFor.SingleFile);
|
|
43573
|
+
// There are several kinds of diagnostics returned by `NgCompiler` for a source file:
|
|
43574
|
+
//
|
|
43575
|
+
// 1. Angular-related non-template diagnostics from decorated classes within that
|
|
43576
|
+
// file.
|
|
43577
|
+
// 2. Template diagnostics for components with direct inline templates (a string
|
|
43578
|
+
// literal).
|
|
43579
|
+
// 3. Template diagnostics for components with indirect inline templates (templates
|
|
43580
|
+
// computed
|
|
43581
|
+
// by expression).
|
|
43582
|
+
// 4. Template diagnostics for components with external templates.
|
|
43583
|
+
//
|
|
43584
|
+
// When showing diagnostics for a TS source file, we want to only include kinds 1 and
|
|
43585
|
+
// 2 - those diagnostics which are reported at a location within the TS file itself.
|
|
43586
|
+
// Diagnostics for external templates will be shown when editing that template file
|
|
43587
|
+
// (the `else` block) below.
|
|
43588
|
+
//
|
|
43589
|
+
// Currently, indirect inline template diagnostics (kind 3) are not shown at all by
|
|
43590
|
+
// the Language Service, because there is no sensible location in the user's code for
|
|
43591
|
+
// them. Such templates are an edge case, though, and should not be common.
|
|
43592
|
+
//
|
|
43593
|
+
// TODO(alxhub): figure out a good user experience for indirect template diagnostics
|
|
43594
|
+
// and show them from within the Language Service.
|
|
43595
|
+
diagnostics.push(...ngDiagnostics.filter(diag => diag.file !== undefined && diag.file.fileName === sourceFile.fileName));
|
|
43596
|
+
}
|
|
42944
43597
|
}
|
|
42945
|
-
|
|
42946
|
-
|
|
42947
|
-
|
|
42948
|
-
|
|
42949
|
-
|
|
42950
|
-
|
|
43598
|
+
else {
|
|
43599
|
+
const components = compiler.getComponentsWithTemplateFile(fileName);
|
|
43600
|
+
for (const component of components) {
|
|
43601
|
+
if (ts.isClassDeclaration(component)) {
|
|
43602
|
+
diagnostics.push(...ttc.getDiagnosticsForComponent(component));
|
|
43603
|
+
}
|
|
42951
43604
|
}
|
|
42952
43605
|
}
|
|
42953
|
-
|
|
42954
|
-
|
|
42955
|
-
return diagnostics;
|
|
43606
|
+
return diagnostics;
|
|
43607
|
+
});
|
|
42956
43608
|
}
|
|
42957
43609
|
getDefinitionAndBoundSpan(fileName, position) {
|
|
42958
|
-
return this.
|
|
43610
|
+
return this.withCompilerAndPerfTracing(PerfPhase.LsDefinition, (compiler) => {
|
|
42959
43611
|
if (!isInAngularContext(compiler.getNextProgram(), fileName, position)) {
|
|
42960
43612
|
return undefined;
|
|
42961
43613
|
}
|
|
@@ -42964,7 +43616,7 @@ https://v9.angular.io/guide/template-typecheck#template-type-checking`,
|
|
|
42964
43616
|
});
|
|
42965
43617
|
}
|
|
42966
43618
|
getTypeDefinitionAtPosition(fileName, position) {
|
|
42967
|
-
return this.
|
|
43619
|
+
return this.withCompilerAndPerfTracing(PerfPhase.LsDefinition, (compiler) => {
|
|
42968
43620
|
if (!isTemplateContext(compiler.getNextProgram(), fileName, position)) {
|
|
42969
43621
|
return undefined;
|
|
42970
43622
|
}
|
|
@@ -42973,56 +43625,57 @@ https://v9.angular.io/guide/template-typecheck#template-type-checking`,
|
|
|
42973
43625
|
});
|
|
42974
43626
|
}
|
|
42975
43627
|
getQuickInfoAtPosition(fileName, position) {
|
|
42976
|
-
return this.
|
|
42977
|
-
|
|
42978
|
-
return undefined;
|
|
42979
|
-
}
|
|
42980
|
-
const templateInfo = getTemplateInfoAtPosition(fileName, position, compiler);
|
|
42981
|
-
if (templateInfo === undefined) {
|
|
42982
|
-
return undefined;
|
|
42983
|
-
}
|
|
42984
|
-
const positionDetails = getTargetAtPosition(templateInfo.template, position);
|
|
42985
|
-
if (positionDetails === null) {
|
|
42986
|
-
return undefined;
|
|
42987
|
-
}
|
|
42988
|
-
// Because we can only show 1 quick info, just use the bound attribute if the target is a two
|
|
42989
|
-
// way binding. We may consider concatenating additional display parts from the other target
|
|
42990
|
-
// nodes or representing the two way binding in some other manner in the future.
|
|
42991
|
-
const node = positionDetails.context.kind === TargetNodeKind.TwoWayBindingContext ?
|
|
42992
|
-
positionDetails.context.nodes[0] :
|
|
42993
|
-
positionDetails.context.node;
|
|
42994
|
-
return new QuickInfoBuilder(this.tsLS, compiler, templateInfo.component, node).get();
|
|
43628
|
+
return this.withCompilerAndPerfTracing(PerfPhase.LsQuickInfo, (compiler) => {
|
|
43629
|
+
return this.getQuickInfoAtPositionImpl(fileName, position, compiler);
|
|
42995
43630
|
});
|
|
42996
43631
|
}
|
|
43632
|
+
getQuickInfoAtPositionImpl(fileName, position, compiler) {
|
|
43633
|
+
if (!isTemplateContext(compiler.getNextProgram(), fileName, position)) {
|
|
43634
|
+
return undefined;
|
|
43635
|
+
}
|
|
43636
|
+
const templateInfo = getTemplateInfoAtPosition(fileName, position, compiler);
|
|
43637
|
+
if (templateInfo === undefined) {
|
|
43638
|
+
return undefined;
|
|
43639
|
+
}
|
|
43640
|
+
const positionDetails = getTargetAtPosition(templateInfo.template, position);
|
|
43641
|
+
if (positionDetails === null) {
|
|
43642
|
+
return undefined;
|
|
43643
|
+
}
|
|
43644
|
+
// Because we can only show 1 quick info, just use the bound attribute if the target is a two
|
|
43645
|
+
// way binding. We may consider concatenating additional display parts from the other target
|
|
43646
|
+
// nodes or representing the two way binding in some other manner in the future.
|
|
43647
|
+
const node = positionDetails.context.kind === TargetNodeKind.TwoWayBindingContext ?
|
|
43648
|
+
positionDetails.context.nodes[0] :
|
|
43649
|
+
positionDetails.context.node;
|
|
43650
|
+
return new QuickInfoBuilder(this.tsLS, compiler, templateInfo.component, node).get();
|
|
43651
|
+
}
|
|
42997
43652
|
getReferencesAtPosition(fileName, position) {
|
|
42998
|
-
|
|
42999
|
-
|
|
43000
|
-
|
|
43001
|
-
|
|
43002
|
-
return results;
|
|
43653
|
+
return this.withCompilerAndPerfTracing(PerfPhase.LsReferencesAndRenames, (compiler) => {
|
|
43654
|
+
return new ReferencesAndRenameBuilder(this.strategy, this.tsLS, compiler)
|
|
43655
|
+
.getReferencesAtPosition(fileName, position);
|
|
43656
|
+
});
|
|
43003
43657
|
}
|
|
43004
43658
|
getRenameInfo(fileName, position) {
|
|
43005
|
-
|
|
43006
|
-
|
|
43007
|
-
|
|
43008
|
-
|
|
43009
|
-
|
|
43010
|
-
|
|
43011
|
-
|
|
43012
|
-
|
|
43013
|
-
|
|
43014
|
-
|
|
43015
|
-
|
|
43659
|
+
return this.withCompilerAndPerfTracing(PerfPhase.LsReferencesAndRenames, (compiler) => {
|
|
43660
|
+
var _a, _b, _c;
|
|
43661
|
+
const renameInfo = new ReferencesAndRenameBuilder(this.strategy, this.tsLS, compiler)
|
|
43662
|
+
.getRenameInfo(absoluteFrom(fileName), position);
|
|
43663
|
+
if (!renameInfo.canRename) {
|
|
43664
|
+
return renameInfo;
|
|
43665
|
+
}
|
|
43666
|
+
const quickInfo = (_a = this.getQuickInfoAtPositionImpl(fileName, position, compiler)) !== null && _a !== void 0 ? _a : this.tsLS.getQuickInfoAtPosition(fileName, position);
|
|
43667
|
+
const kind = (_b = quickInfo === null || quickInfo === void 0 ? void 0 : quickInfo.kind) !== null && _b !== void 0 ? _b : ts.ScriptElementKind.unknown;
|
|
43668
|
+
const kindModifiers = (_c = quickInfo === null || quickInfo === void 0 ? void 0 : quickInfo.kindModifiers) !== null && _c !== void 0 ? _c : ts.ScriptElementKind.unknown;
|
|
43669
|
+
return Object.assign(Object.assign({}, renameInfo), { kind, kindModifiers });
|
|
43670
|
+
});
|
|
43016
43671
|
}
|
|
43017
43672
|
findRenameLocations(fileName, position) {
|
|
43018
|
-
|
|
43019
|
-
|
|
43020
|
-
|
|
43021
|
-
|
|
43022
|
-
return results;
|
|
43673
|
+
return this.withCompilerAndPerfTracing(PerfPhase.LsReferencesAndRenames, (compiler) => {
|
|
43674
|
+
return new ReferencesAndRenameBuilder(this.strategy, this.tsLS, compiler)
|
|
43675
|
+
.findRenameLocations(fileName, position);
|
|
43676
|
+
});
|
|
43023
43677
|
}
|
|
43024
|
-
getCompletionBuilder(fileName, position) {
|
|
43025
|
-
const compiler = this.compilerFactory.getOrCreate();
|
|
43678
|
+
getCompletionBuilder(fileName, position, compiler) {
|
|
43026
43679
|
const templateInfo = getTemplateInfoAtPosition(fileName, position, compiler);
|
|
43027
43680
|
if (templateInfo === undefined) {
|
|
43028
43681
|
return null;
|
|
@@ -43039,23 +43692,26 @@ https://v9.angular.io/guide/template-typecheck#template-type-checking`,
|
|
|
43039
43692
|
return new CompletionBuilder(this.tsLS, compiler, templateInfo.component, node, positionDetails, isTypeScriptFile(fileName));
|
|
43040
43693
|
}
|
|
43041
43694
|
getCompletionsAtPosition(fileName, position, options) {
|
|
43042
|
-
return this.
|
|
43043
|
-
|
|
43044
|
-
return undefined;
|
|
43045
|
-
}
|
|
43046
|
-
const builder = this.getCompletionBuilder(fileName, position);
|
|
43047
|
-
if (builder === null) {
|
|
43048
|
-
return undefined;
|
|
43049
|
-
}
|
|
43050
|
-
return builder.getCompletionsAtPosition(options);
|
|
43695
|
+
return this.withCompilerAndPerfTracing(PerfPhase.LsCompletions, (compiler) => {
|
|
43696
|
+
return this.getCompletionsAtPositionImpl(fileName, position, options, compiler);
|
|
43051
43697
|
});
|
|
43052
43698
|
}
|
|
43699
|
+
getCompletionsAtPositionImpl(fileName, position, options, compiler) {
|
|
43700
|
+
if (!isTemplateContext(compiler.getNextProgram(), fileName, position)) {
|
|
43701
|
+
return undefined;
|
|
43702
|
+
}
|
|
43703
|
+
const builder = this.getCompletionBuilder(fileName, position, compiler);
|
|
43704
|
+
if (builder === null) {
|
|
43705
|
+
return undefined;
|
|
43706
|
+
}
|
|
43707
|
+
return builder.getCompletionsAtPosition(options);
|
|
43708
|
+
}
|
|
43053
43709
|
getCompletionEntryDetails(fileName, position, entryName, formatOptions, preferences) {
|
|
43054
|
-
return this.
|
|
43710
|
+
return this.withCompilerAndPerfTracing(PerfPhase.LsCompletions, (compiler) => {
|
|
43055
43711
|
if (!isTemplateContext(compiler.getNextProgram(), fileName, position)) {
|
|
43056
43712
|
return undefined;
|
|
43057
43713
|
}
|
|
43058
|
-
const builder = this.getCompletionBuilder(fileName, position);
|
|
43714
|
+
const builder = this.getCompletionBuilder(fileName, position, compiler);
|
|
43059
43715
|
if (builder === null) {
|
|
43060
43716
|
return undefined;
|
|
43061
43717
|
}
|
|
@@ -43063,11 +43719,11 @@ https://v9.angular.io/guide/template-typecheck#template-type-checking`,
|
|
|
43063
43719
|
});
|
|
43064
43720
|
}
|
|
43065
43721
|
getCompletionEntrySymbol(fileName, position, entryName) {
|
|
43066
|
-
return this.
|
|
43722
|
+
return this.withCompilerAndPerfTracing(PerfPhase.LsCompletions, (compiler) => {
|
|
43067
43723
|
if (!isTemplateContext(compiler.getNextProgram(), fileName, position)) {
|
|
43068
43724
|
return undefined;
|
|
43069
43725
|
}
|
|
43070
|
-
const builder = this.getCompletionBuilder(fileName, position);
|
|
43726
|
+
const builder = this.getCompletionBuilder(fileName, position, compiler);
|
|
43071
43727
|
if (builder === null) {
|
|
43072
43728
|
return undefined;
|
|
43073
43729
|
}
|
|
@@ -43077,7 +43733,7 @@ https://v9.angular.io/guide/template-typecheck#template-type-checking`,
|
|
|
43077
43733
|
});
|
|
43078
43734
|
}
|
|
43079
43735
|
getTcb(fileName, position) {
|
|
43080
|
-
return this.
|
|
43736
|
+
return this.withCompilerAndPerfTracing(PerfPhase.LsTcb, compiler => {
|
|
43081
43737
|
const templateInfo = getTemplateInfoAtPosition(fileName, position, compiler);
|
|
43082
43738
|
if (templateInfo === undefined) {
|
|
43083
43739
|
return undefined;
|
|
@@ -43117,10 +43773,31 @@ https://v9.angular.io/guide/template-typecheck#template-type-checking`,
|
|
|
43117
43773
|
};
|
|
43118
43774
|
});
|
|
43119
43775
|
}
|
|
43120
|
-
|
|
43776
|
+
/**
|
|
43777
|
+
* Provides an instance of the `NgCompiler` and traces perf results. Perf results are logged only
|
|
43778
|
+
* if the log level is verbose or higher. This method is intended to be called once per public
|
|
43779
|
+
* method call.
|
|
43780
|
+
*
|
|
43781
|
+
* Here is an example of the log output.
|
|
43782
|
+
*
|
|
43783
|
+
* Perf 245 [16:16:39.353] LanguageService#getQuickInfoAtPosition(): {"events":{},"phases":{
|
|
43784
|
+
* "Unaccounted":379,"TtcSymbol":4},"memory":{}}
|
|
43785
|
+
*
|
|
43786
|
+
* Passing name of caller instead of using `arguments.caller` because 'caller', 'callee', and
|
|
43787
|
+
* 'arguments' properties may not be accessed in strict mode.
|
|
43788
|
+
*
|
|
43789
|
+
* @param phase the `PerfPhase` to execute the `p` callback in
|
|
43790
|
+
* @param p callback to be run synchronously with an instance of the `NgCompiler` as argument
|
|
43791
|
+
* @return the result of running the `p` callback
|
|
43792
|
+
*/
|
|
43793
|
+
withCompilerAndPerfTracing(phase, p) {
|
|
43121
43794
|
const compiler = this.compilerFactory.getOrCreate();
|
|
43122
|
-
const result = p(compiler);
|
|
43795
|
+
const result = compiler.perfRecorder.inPhase(phase, () => p(compiler));
|
|
43123
43796
|
this.compilerFactory.registerLastKnownProgram();
|
|
43797
|
+
const logger = this.project.projectService.logger;
|
|
43798
|
+
if (logger.hasLevel(ts.server.LogLevel.verbose)) {
|
|
43799
|
+
logger.perftrc(`LanguageService#${PerfPhase[phase]}: ${JSON.stringify(compiler.perfRecorder.finalize())}`);
|
|
43800
|
+
}
|
|
43124
43801
|
return result;
|
|
43125
43802
|
}
|
|
43126
43803
|
getCompilerOptionsDiagnostics() {
|
|
@@ -43128,22 +43805,23 @@ https://v9.angular.io/guide/template-typecheck#template-type-checking`,
|
|
|
43128
43805
|
if (!(project instanceof ts.server.ConfiguredProject)) {
|
|
43129
43806
|
return [];
|
|
43130
43807
|
}
|
|
43131
|
-
|
|
43132
|
-
|
|
43133
|
-
|
|
43134
|
-
|
|
43135
|
-
|
|
43136
|
-
'
|
|
43137
|
-
|
|
43138
|
-
|
|
43139
|
-
|
|
43140
|
-
|
|
43141
|
-
|
|
43142
|
-
|
|
43143
|
-
|
|
43144
|
-
|
|
43145
|
-
|
|
43146
|
-
|
|
43808
|
+
return this.withCompilerAndPerfTracing(PerfPhase.LsDiagnostics, (compiler) => {
|
|
43809
|
+
const diagnostics = [];
|
|
43810
|
+
const configSourceFile = ts.readJsonConfigFile(project.getConfigFilePath(), (path) => project.readFile(path));
|
|
43811
|
+
if (!this.options.strictTemplates && !this.options.fullTemplateTypeCheck) {
|
|
43812
|
+
diagnostics.push({
|
|
43813
|
+
messageText: 'Some language features are not available. ' +
|
|
43814
|
+
'To access all features, enable `strictTemplates` in `angularCompilerOptions`.',
|
|
43815
|
+
category: ts.DiagnosticCategory.Suggestion,
|
|
43816
|
+
code: ngErrorCode(ErrorCode.SUGGEST_STRICT_TEMPLATES),
|
|
43817
|
+
file: configSourceFile,
|
|
43818
|
+
start: undefined,
|
|
43819
|
+
length: undefined,
|
|
43820
|
+
});
|
|
43821
|
+
}
|
|
43822
|
+
diagnostics.push(...compiler.getOptionDiagnostics());
|
|
43823
|
+
return diagnostics;
|
|
43824
|
+
});
|
|
43147
43825
|
}
|
|
43148
43826
|
watchConfigFile(project) {
|
|
43149
43827
|
// TODO: Check the case when the project is disposed. An InferredProject
|