refactor(core): static-query schematic should check templates (#29713)
Queries can technically be also accessed within component templates e.g. ```html <my-comp [binding]="myQuery"></my-comp> ``` In that case the query with the property "myQuery" is accessed statically and needs to be marked with `static: true`. There are other edge cases that need to be handled as the template property read doesn't necessarily resolve to the actual query property. For example: ```html <foo #myQuery></foo> <my-comp [binding]="myQuery"></my-comp> ``` In this scenario the binding doesn't refer to the actual query because the template reference variable takes precedence. The query doesn't need to be marked with "static: true" this time. This commit ensures that the `static-query` migration schematic now handles this cases properly. Also template property reads that access queries from within a `<ng-template>` are ignored as these can't access the query before the view has been initialized. Resolves FW-1216 PR Close #29713
This commit is contained in:

committed by
Igor Minar

parent
b507d076be
commit
5b32f55a3a
@ -7,6 +7,7 @@ ts_library(
|
||||
visibility = ["//packages/core/schematics/test:__pkg__"],
|
||||
deps = [
|
||||
"//packages/core/schematics/migrations/static-queries",
|
||||
"//packages/core/schematics/utils",
|
||||
"@npm//tslint",
|
||||
],
|
||||
)
|
||||
|
@ -8,6 +8,9 @@
|
||||
|
||||
import {Replacement, RuleFailure, Rules} from 'tslint';
|
||||
import * as ts from 'typescript';
|
||||
|
||||
import {NgComponentTemplateVisitor} from '../../../utils/ng_component_template';
|
||||
import {visitAllNodes} from '../../../utils/typescript/visit_nodes';
|
||||
import {analyzeNgQueryUsage} from '../angular/analyze_query_usage';
|
||||
import {NgQueryResolveVisitor} from '../angular/ng_query_visitor';
|
||||
import {QueryTiming} from '../angular/query-definition';
|
||||
@ -25,14 +28,29 @@ export class Rule extends Rules.TypedRule {
|
||||
applyWithProgram(sourceFile: ts.SourceFile, program: ts.Program): RuleFailure[] {
|
||||
const typeChecker = program.getTypeChecker();
|
||||
const queryVisitor = new NgQueryResolveVisitor(program.getTypeChecker());
|
||||
const templateVisitor = new NgComponentTemplateVisitor(typeChecker);
|
||||
const rootSourceFiles = program.getRootFileNames().map(f => program.getSourceFile(f) !);
|
||||
const printer = ts.createPrinter();
|
||||
const failures: RuleFailure[] = [];
|
||||
|
||||
// Analyze source files by detecting queries and class relations.
|
||||
rootSourceFiles.forEach(sourceFile => queryVisitor.visitNode(sourceFile));
|
||||
// Analyze source files by detecting queries, class relations and component templates.
|
||||
rootSourceFiles.forEach(sourceFile => {
|
||||
// The visit utility function only traverses the source file once. We don't want to
|
||||
// traverse through all source files multiple times for each visitor as this could be
|
||||
// slow.
|
||||
visitAllNodes(sourceFile, [queryVisitor, templateVisitor]);
|
||||
});
|
||||
|
||||
const {resolvedQueries, classMetadata} = queryVisitor;
|
||||
|
||||
// Add all resolved templates to the class metadata so that we can also
|
||||
// check component templates for static query usage.
|
||||
templateVisitor.resolvedTemplates.forEach(template => {
|
||||
if (classMetadata.has(template.container)) {
|
||||
classMetadata.get(template.container) !.template = template;
|
||||
}
|
||||
});
|
||||
|
||||
const queries = resolvedQueries.get(sourceFile);
|
||||
|
||||
// No queries detected for the given source file.
|
||||
|
Reference in New Issue
Block a user