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'));
							 | 
						||
| 
								 | 
							
								}
							 |