| "use strict"; |
| /** |
| * @license |
| * Copyright Google LLC 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 |
| */ |
| Object.defineProperty(exports, "__esModule", { value: true }); |
| const schematics_1 = require("@angular/cdk/schematics"); |
| const ts = require("typescript"); |
| const ripple_speed_factor_1 = require("./ripple-speed-factor"); |
| /** Regular expression that matches [matRippleSpeedFactor]="$NUMBER" in templates. */ |
| const speedFactorNumberRegex = /\[matRippleSpeedFactor]="(\d+(?:\.\d+)?)"/g; |
| /** Regular expression that matches [matRippleSpeedFactor]="$NOT_A_NUMBER" in templates. */ |
| const speedFactorNotParseable = /\[matRippleSpeedFactor]="(?!\d+(?:\.\d+)?")(.*)"/g; |
| /** |
| * Note that will be added whenever a speed factor expression has been converted to calculate |
| * the according duration. This note should encourage people to clean up their code by switching |
| * away from the speed factors to explicit durations. |
| */ |
| const removeNote = `TODO: Cleanup duration calculation.`; |
| /** |
| * Rule that walks through every property assignment and switches the global `baseSpeedFactor` |
| * ripple option to the new global animation config. Also updates every class member assignment |
| * that refers to MatRipple#speedFactor. |
| */ |
| class RippleSpeedFactorRule extends schematics_1.MigrationRule { |
| constructor() { |
| super(...arguments); |
| // Only enable this rule if the migration targets version 7 as the ripple |
| // speed factor has been removed in that version. |
| this.ruleEnabled = this.targetVersion === schematics_1.TargetVersion.V7; |
| } |
| visitNode(node) { |
| if (ts.isBinaryExpression(node)) { |
| this._visitBinaryExpression(node); |
| } |
| else if (ts.isPropertyAssignment(node)) { |
| this._visitPropertyAssignment(node); |
| } |
| } |
| visitTemplate(template) { |
| let match; |
| while ((match = speedFactorNumberRegex.exec(template.content)) !== null) { |
| const newEnterDuration = ripple_speed_factor_1.convertSpeedFactorToDuration(parseFloat(match[1])); |
| this._replaceText(template.filePath, template.start + match.index, match[0].length, `[matRippleAnimation]="{enterDuration: ${newEnterDuration}}"`); |
| } |
| while ((match = speedFactorNotParseable.exec(template.content)) !== null) { |
| const newDurationExpression = ripple_speed_factor_1.createSpeedFactorConvertExpression(match[1]); |
| this._replaceText(template.filePath, template.start + match.index, match[0].length, `[matRippleAnimation]="{enterDuration: (${newDurationExpression})}"`); |
| } |
| } |
| /** Switches binary expressions (e.g. myRipple.speedFactor = 0.5) to the new animation config. */ |
| _visitBinaryExpression(expression) { |
| if (!ts.isPropertyAccessExpression(expression.left)) { |
| return; |
| } |
| // Left side expression consists of target object and property name (e.g. myInstance.val) |
| const leftExpression = expression.left; |
| const targetTypeNode = this.typeChecker.getTypeAtLocation(leftExpression.expression); |
| if (!targetTypeNode.symbol) { |
| return; |
| } |
| const targetTypeName = targetTypeNode.symbol.getName(); |
| const propertyName = leftExpression.name.getText(); |
| const filePath = leftExpression.getSourceFile().fileName; |
| if (targetTypeName === 'MatRipple' && propertyName === 'speedFactor') { |
| if (ts.isNumericLiteral(expression.right)) { |
| const numericValue = parseFloat(expression.right.text); |
| const newEnterDurationValue = ripple_speed_factor_1.convertSpeedFactorToDuration(numericValue); |
| // Replace the `speedFactor` property name with `animation`. |
| this._replaceText(filePath, leftExpression.name.getStart(), leftExpression.name.getWidth(), 'animation'); |
| // Replace the value assignment with the new animation config. |
| this._replaceText(filePath, expression.right.getStart(), expression.right.getWidth(), `{enterDuration: ${newEnterDurationValue}}`); |
| } |
| else { |
| // Handle the right expression differently if the previous speed factor value can't |
| // be resolved statically. In that case, we just create a TypeScript expression that |
| // calculates the explicit duration based on the non-static speed factor expression. |
| const newExpression = ripple_speed_factor_1.createSpeedFactorConvertExpression(expression.right.getText()); |
| // Replace the `speedFactor` property name with `animation`. |
| this._replaceText(filePath, leftExpression.name.getStart(), leftExpression.name.getWidth(), 'animation'); |
| // Replace the value assignment with the new animation config and remove TODO. |
| this._replaceText(filePath, expression.right.getStart(), expression.right.getWidth(), `/** ${removeNote} */ {enterDuration: ${newExpression}}`); |
| } |
| } |
| } |
| /** |
| * Switches the global option `baseSpeedFactor` to the new animation config. For this |
| * we assume that the `baseSpeedFactor` is not used in combination with individual |
| * speed factors. |
| */ |
| _visitPropertyAssignment(assignment) { |
| // For switching the `baseSpeedFactor` global option we expect the property assignment |
| // to be inside of a normal object literal. Custom ripple global options cannot be |
| // witched automatically. |
| if (!ts.isObjectLiteralExpression(assignment.parent)) { |
| return; |
| } |
| // The assignment consists of a name (key) and initializer (value). |
| if (assignment.name.getText() !== 'baseSpeedFactor') { |
| return; |
| } |
| // We could technically lazily check for the MAT_RIPPLE_GLOBAL_OPTIONS injection token to |
| // be present, but it's not right to assume that everyone sets the ripple global options |
| // immediately in the provider object (e.g. it can happen that someone just imports the |
| // config from a separate file). |
| const { initializer, name } = assignment; |
| const filePath = assignment.getSourceFile().fileName; |
| if (ts.isNumericLiteral(initializer)) { |
| const numericValue = parseFloat(initializer.text); |
| const newEnterDurationValue = ripple_speed_factor_1.convertSpeedFactorToDuration(numericValue); |
| // Replace the `baseSpeedFactor` property name with `animation`. |
| this._replaceText(filePath, name.getStart(), name.getWidth(), 'animation'); |
| // Replace the value assignment initializer with the new animation config. |
| this._replaceText(filePath, initializer.getStart(), initializer.getWidth(), `{enterDuration: ${newEnterDurationValue}}`); |
| } |
| else { |
| // Handle the right expression differently if the previous speed factor value can't |
| // be resolved statically. In that case, we just create a TypeScript expression that |
| // calculates the explicit duration based on the non-static speed factor expression. |
| const newExpression = ripple_speed_factor_1.createSpeedFactorConvertExpression(initializer.getText()); |
| // Replace the `baseSpeedFactor` property name with `animation`. |
| this._replaceText(filePath, name.getStart(), name.getWidth(), 'animation'); |
| // Replace the value assignment with the new animation config and remove TODO. |
| this._replaceText(filePath, initializer.getStart(), initializer.getWidth(), `/** ${removeNote} */ {enterDuration: ${newExpression}}`); |
| } |
| } |
| _replaceText(filePath, start, width, newText) { |
| const recorder = this.getUpdateRecorder(filePath); |
| recorder.remove(start, width); |
| recorder.insertRight(start, newText); |
| } |
| } |
| exports.RippleSpeedFactorRule = RippleSpeedFactorRule; |
| //# sourceMappingURL=ripple-speed-factor-rule.js.map |