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