Adds a schematic that will remove the explicit `static: false` flag from dynamic queries. E.g.
```ts
import { Directive, ViewChild, ContentChild, ElementRef } from '@angular/core';
@Directive()
export class MyDirective {
  @ViewChild('child', { static: false }) child: any;
  @ViewChild('secondChild', { read: ElementRef, static: false }) secondChild: ElementRef;
  @ContentChild('thirdChild', { static: false }) thirdChild: any;
}
```
```ts
import { Directive, ViewChild, ContentChild, ElementRef } from '@angular/core';
@Directive()
export class MyDirective {
  @ViewChild('child') child: any;
  @ViewChild('secondChild', { read: ElementRef }) secondChild: ElementRef;
  @ContentChild('thirdChild') thirdChild: any;
}
```
PR Close #32231
		
	
			
		
			
				
	
	
		
			78 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			78 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| /**
 | |
|  * @license
 | |
|  * Copyright Google Inc. All Rights Reserved.
 | |
|  *
 | |
|  * Use of this source code is governed by an MIT-style license that can be
 | |
|  * found in the LICENSE file at https://angular.io/license
 | |
|  */
 | |
| 
 | |
| import * as ts from 'typescript';
 | |
| import {getAngularDecorators} from '../../utils/ng_decorators';
 | |
| 
 | |
| /**
 | |
|  * Identifies the nodes that should be migrated by the dynamic
 | |
|  * queries schematic. Splits the nodes into the following categories:
 | |
|  * - `removeProperty` - queries from which we should only remove the `static` property of the
 | |
|  *  `options` parameter (e.g. `@ViewChild('child', {static: false, read: ElementRef})`).
 | |
|  * - `removeParameter` - queries from which we should drop the entire `options` parameter.
 | |
|  *  (e.g. `@ViewChild('child', {static: false})`).
 | |
|  */
 | |
| export function identifyDynamicQueryNodes(typeChecker: ts.TypeChecker, sourceFile: ts.SourceFile) {
 | |
|   const removeProperty: ts.ObjectLiteralExpression[] = [];
 | |
|   const removeParameter: ts.CallExpression[] = [];
 | |
| 
 | |
|   sourceFile.forEachChild(function walk(node: ts.Node) {
 | |
|     if (ts.isClassDeclaration(node)) {
 | |
|       node.members.forEach(member => {
 | |
|         const angularDecorators =
 | |
|             member.decorators && getAngularDecorators(typeChecker, member.decorators);
 | |
| 
 | |
|         if (angularDecorators) {
 | |
|           angularDecorators
 | |
|               // Filter out the queries that can have the `static` flag.
 | |
|               .filter(decorator => {
 | |
|                 return decorator.name === 'ViewChild' || decorator.name === 'ContentChild';
 | |
|               })
 | |
|               // Filter out the queries where the `static` flag is explicitly set to `false`.
 | |
|               .filter(decorator => {
 | |
|                 const options = decorator.node.expression.arguments[1];
 | |
|                 return options && ts.isObjectLiteralExpression(options) &&
 | |
|                     options.properties.some(
 | |
|                         property => ts.isPropertyAssignment(property) &&
 | |
|                             property.initializer.kind === ts.SyntaxKind.FalseKeyword);
 | |
|               })
 | |
|               .forEach(decorator => {
 | |
|                 const options =
 | |
|                     decorator.node.expression.arguments[1] as ts.ObjectLiteralExpression;
 | |
| 
 | |
|                 // At this point we know that at least one property is the `static` flag. If this is
 | |
|                 // the only property we can drop the entire object literal, otherwise we have to
 | |
|                 // drop only the property.
 | |
|                 if (options.properties.length === 1) {
 | |
|                   removeParameter.push(decorator.node.expression);
 | |
|                 } else {
 | |
|                   removeProperty.push(options);
 | |
|                 }
 | |
|               });
 | |
|         }
 | |
|       });
 | |
|     }
 | |
| 
 | |
|     node.forEachChild(walk);
 | |
|   });
 | |
| 
 | |
|   return {removeProperty, removeParameter};
 | |
| }
 | |
| 
 | |
| /** Removes the `options` parameter from the call expression of a query decorator. */
 | |
| export function removeOptionsParameter(node: ts.CallExpression): ts.CallExpression {
 | |
|   return ts.updateCall(node, node.expression, node.typeArguments, [node.arguments[0]]);
 | |
| }
 | |
| 
 | |
| /** Removes the `static` property from an object literal expression. */
 | |
| export function removeStaticFlag(node: ts.ObjectLiteralExpression): ts.ObjectLiteralExpression {
 | |
|   return ts.updateObjectLiteral(
 | |
|       node,
 | |
|       node.properties.filter(property => property.name && property.name.getText() !== 'static'));
 | |
| }
 |