blob: b92a6e92bbaf96a707e353669c5a32b281b7f5f9 [file] [log] [blame]
Dmitrii Filippovf0d5b6e2019-10-14 17:32:55 +02001// Copyright (C) 2019 The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15import {LegacyLifecycleMethodsArray, LegacyPolymerComponent} from './polymerComponentParser';
16import {LifecycleMethodsBuilder} from './lifecycleMethodsBuilder';
17import {ClassBasedPolymerElement, PolymerElementBuilder} from './polymerElementBuilder';
18import * as codeUtils from '../utils/codeUtils';
19import * as ts from 'typescript';
20
21export class PolymerFuncToClassBasedConverter {
22 public static convert(component: LegacyPolymerComponent): ClassBasedPolymerElement {
23 const legacySettings = component.componentSettings;
24 const reservedDeclarations = legacySettings.reservedDeclarations;
25
26 if(!reservedDeclarations.is) {
27 throw new Error("Legacy component doesn't have 'is' property");
28 }
29 const className = this.generateClassNameFromTagName(reservedDeclarations.is.data);
30 const updater = new PolymerElementBuilder(component, className);
31 updater.addIsAccessor(reservedDeclarations.is.data);
32
33 if(reservedDeclarations.properties) {
34 updater.addPolymerPropertiesAccessor(reservedDeclarations.properties);
35 }
36
37 updater.addMixin("Polymer.Element");
38 updater.addMixin("Polymer.LegacyElementMixin");
39 updater.addMixin("Polymer.GestureEventListeners");
40
41 if(reservedDeclarations._legacyUndefinedCheck) {
42 updater.addMixin("Polymer.LegacyDataMixin");
43 }
44
45 if(reservedDeclarations.behaviors) {
46 updater.addMixin("Polymer.mixinBehaviors", [reservedDeclarations.behaviors.data]);
47 const mixinNames = this.getMixinNamesFromBehaviors(reservedDeclarations.behaviors.data);
48 const jsDocLines = mixinNames.map(mixinName => {
49 return `@appliesMixin ${mixinName}`;
50 });
51 updater.addClassJSDocComments(jsDocLines);
52 }
53
54 if(reservedDeclarations.observers) {
55 updater.addPolymerPropertiesObservers(reservedDeclarations.observers.data);
56 }
57
58 if(reservedDeclarations.keyBindings) {
59 updater.addKeyBindings(reservedDeclarations.keyBindings.data);
60 }
61
62
63 const lifecycleBuilder = new LifecycleMethodsBuilder();
64 if (reservedDeclarations.listeners) {
65 lifecycleBuilder.addListeners(reservedDeclarations.listeners.data, legacySettings.ordinaryMethods);
66 }
67
68 if (reservedDeclarations.hostAttributes) {
69 lifecycleBuilder.addHostAttributes(reservedDeclarations.hostAttributes.data);
70 }
71
72 for(const name of LegacyLifecycleMethodsArray) {
73 const existingMethod = legacySettings.lifecycleMethods.get(name);
74 if(existingMethod) {
75 lifecycleBuilder.addLegacyLifecycleMethod(name, existingMethod)
76 }
77 }
78
79 const newLifecycleMethods = lifecycleBuilder.buildNewMethods();
80 updater.addLifecycleMethods(newLifecycleMethods);
81
82
83 updater.addOrdinaryMethods(legacySettings.ordinaryMethods);
84 updater.addOrdinaryGetAccessors(legacySettings.ordinaryGetAccessors);
85 updater.addOrdinaryShorthandProperties(legacySettings.ordinaryShorthandProperties);
86 updater.addOrdinaryPropertyAssignments(legacySettings.ordinaryPropertyAssignments);
87
88 return updater.build();
89 }
90
91 private static generateClassNameFromTagName(tagName: string) {
92 let result = "";
93 let nextUppercase = true;
94 for(const ch of tagName) {
95 if (ch === '-') {
96 nextUppercase = true;
97 continue;
98 }
99 result += nextUppercase ? ch.toUpperCase() : ch;
100 nextUppercase = false;
101 }
102 return result;
103 }
104
105 private static getMixinNamesFromBehaviors(behaviors: ts.ArrayLiteralExpression): string[] {
106 return behaviors.elements.map((expression) => {
107 const propertyAccessExpression = codeUtils.assertNodeKind(expression, ts.SyntaxKind.PropertyAccessExpression) as ts.PropertyAccessExpression;
108 const namespaceName = codeUtils.assertNodeKind(propertyAccessExpression.expression, ts.SyntaxKind.Identifier) as ts.Identifier;
109 const behaviorName = propertyAccessExpression.name;
110 if(namespaceName.text === 'Gerrit') {
111 let behaviorNameText = behaviorName.text;
112 const suffix = 'Behavior';
113 if(behaviorNameText.endsWith(suffix)) {
114 behaviorNameText =
115 behaviorNameText.substr(0, behaviorNameText.length - suffix.length);
116 }
117 const mixinName = behaviorNameText + 'Mixin';
118 return `${namespaceName.text}.${mixinName}`
119 } else if(namespaceName.text === 'Polymer') {
120 let behaviorNameText = behaviorName.text;
121 if(behaviorNameText === "IronFitBehavior") {
122 return "Polymer.IronFitMixin";
123 } else if(behaviorNameText === "IronOverlayBehavior") {
124 return "";
125 }
126 throw new Error(`Unsupported behavior: ${propertyAccessExpression.getText()}`);
127 }
128 throw new Error(`Unsupported behavior name ${expression.getFullText()}`)
129 }).filter(name => name.length > 0);
130 }
131}