Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(57)

Side by Side Diff: lib/merge.ts

Issue 2225953002: Strip more unused features. (Closed) Base URL: git@github.com:dart-lang/js_facade_gen.git@master
Patch Set: Fix types Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « lib/main.ts ('k') | lib/module.ts » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 import ts = require('typescript');
2 import base = require('./base');
3 import {FacadeConverter} from './facade_converter';
4
5 /**
6 * To support arbitrary d.ts files in Dart we often have to merge two TypeScript
7 * types into a single Dart type because Dart lacks features such as method
8 * overloads, type aliases, and union types.
9 */
10 export class MergedType {
11 constructor(private fc: FacadeConverter) {}
12
13 merge(t?: ts.TypeNode) {
14 if (t) {
15 // TODO(jacobr): get a better unique name for a type.
16 switch (t.kind) {
17 case ts.SyntaxKind.UnionType:
18 let union = <ts.UnionTypeNode>t;
19 union.types.forEach(this.merge.bind(this));
20 return;
21 case ts.SyntaxKind.LastTypeNode:
22 this.merge((t as ts.ParenthesizedTypeNode).type);
23 return;
24 case ts.SyntaxKind.TypePredicate:
25 this.merge((t as ts.TypePredicateNode).type);
26 return;
27 case ts.SyntaxKind.TypeReference:
28 // We need to follow Alais types as Dart does not support them for non
29 // function types. TODO(jacobr): handle them for Function types?
30 let typeRef = <ts.TypeReferenceNode>t;
31 let decl = this.fc.getDeclaration(typeRef.typeName);
32 if (decl !== null && decl.kind === ts.SyntaxKind.TypeAliasDeclaration) {
33 let alias = <ts.TypeAliasDeclaration>decl;
34
35 if (typeRef.typeArguments) {
36 throw 'TypeReference with arguements not supported yet:' + t.getTe xt();
37 }
38
39 this.merge(alias.type);
40 return;
41 }
42 break;
43 default:
44 break;
45 }
46 this.types[this.fc.generateDartTypeName(t, true)] = t;
47 }
48 }
49
50 toTypeNode(): ts.TypeNode {
51 let names = Object.getOwnPropertyNames(this.types);
52 if (names.length === 0) {
53 return null;
54 }
55 if (names.length === 1) {
56 return this.types[names[0]];
57 }
58 let union = <ts.UnionTypeNode>ts.createNode(ts.SyntaxKind.UnionType);
59 base.copyLocation(this.types[names[0]], union);
60
61 union.types = <ts.NodeArray<ts.TypeNode>>[];
62 for (let i = 0; i < names.length; ++i) {
63 union.types.push(this.types[names[i]]);
64 }
65 return union;
66 }
67
68 private types: {[name: string]: ts.TypeNode} = {};
69 }
70
71 /**
72 * Handle a parameter that is the result of merging parameter declarations from
73 * multiple method overloads.
74 */
75 export class MergedParameter {
76 constructor(param: ts.ParameterDeclaration, fc: FacadeConverter) {
77 this.type = new MergedType(fc);
78 this.textRange = param;
79 this.merge(param);
80 }
81
82 merge(param: ts.ParameterDeclaration) {
83 this.name[base.ident(param.name)] = true;
84 if (!this.optional) {
85 this.optional = !!param.questionToken;
86 }
87 this.type.merge(param.type);
88 }
89
90 toParameterDeclaration(): ts.ParameterDeclaration {
91 let ret = <ts.ParameterDeclaration>ts.createNode(ts.SyntaxKind.Parameter);
92 let nameIdentifier = <ts.Identifier>ts.createNode(ts.SyntaxKind.Identifier);
93 nameIdentifier.text = Object.getOwnPropertyNames(this.name).join('_');
94 ret.name = nameIdentifier;
95 if (this.optional) {
96 ret.questionToken = ts.createNode(ts.SyntaxKind.QuestionToken);
97 }
98 base.copyLocation(this.textRange, ret);
99 ret.type = this.type.toTypeNode();
100 return ret;
101 }
102
103 setOptional() { this.optional = true; }
104
105 private name: {[s: string]: boolean} = {};
106 private type: MergedType;
107 private optional: boolean = false;
108 private textRange: ts.TextRange;
109 }
110
111 /**
112 * Normalize a SourceFile
113 */
114 export function normalizeSourceFile(f: ts.SourceFile) {
115 let modules: {[name: string]: ts.ModuleDeclaration} = {};
116
117 // Merge top level modules.
118 for (let i = 0; i < f.statements.length; ++i) {
119 let statement = f.statements[i];
120 if (statement.kind !== ts.SyntaxKind.ModuleDeclaration) continue;
121 let moduleDecl = <ts.ModuleDeclaration>statement;
122 let name = moduleDecl.name.text;
123 if (modules.hasOwnProperty(name)) {
124 let srcBody = modules[name].body;
125 let srcBodyBlock: ts.ModuleBlock;
126
127 if (srcBody.kind !== ts.SyntaxKind.ModuleBlock) {
128 throw 'Module body must be a module block.';
129 }
130 srcBodyBlock = <ts.ModuleBlock>srcBody;
131
132 let body = moduleDecl.body;
133 if (body.kind === ts.SyntaxKind.ModuleBlock) {
134 let bodyBlock = <ts.ModuleBlock>body;
135 Array.prototype.push.apply(srcBodyBlock.statements, bodyBlock.statements );
136 } else {
137 // moduleDecl.body is a ModuleDeclaration.
138 srcBodyBlock.statements.push(moduleDecl.body);
139 }
140
141 f.statements.splice(i, 1);
142 i--;
143 } else {
144 modules[name] = moduleDecl;
145 }
146 }
147
148 function addModifier(n: ts.Node, modifier: ts.Node) {
149 if (!n.modifiers) {
150 n.modifiers = <ts.ModifiersArray>[];
151 n.modifiers.flags = 0;
152 }
153 modifier.parent = n;
154 n.modifiers.push(modifier);
155 }
156
157 function mergeVariablesIntoClasses(n: ts.Node, classes: {[name: string]: base. ClassLike}) {
158 switch (n.kind) {
159 case ts.SyntaxKind.VariableStatement:
160 let statement = <ts.VariableStatement>n;
161 statement.declarationList.declarations.forEach(function(
162 declaration: ts.VariableDeclaration) {
163 if (declaration.name.kind === ts.SyntaxKind.Identifier) {
164 let name: string = (<ts.Identifier>(declaration.name)).text;
165 if (classes.hasOwnProperty(name)) {
166 let existing = classes[name];
167 let members = existing.members as Array<ts.ClassElement>;
168 if (declaration.type) {
169 let type: ts.TypeNode = declaration.type;
170 if (type.kind === ts.SyntaxKind.TypeLiteral) {
171 removeNode(n);
172 let literal = <ts.TypeLiteralNode>type;
173 literal.members.forEach((member: ts.Node) => {
174 switch (member.kind) {
175 case ts.SyntaxKind.ConstructSignature:
176 let signature: any = member;
177 let constructor =
178 <ts.ConstructorDeclaration>ts.createNode(ts.SyntaxKi nd.Constructor);
179 constructor.parameters = signature.parameters;
180 constructor.type = signature.type;
181 base.copyLocation(signature, constructor);
182 constructor.typeParameters = signature.typeParameters;
183 constructor.parent = existing;
184 members.push(<ts.ClassElement>constructor);
185 break;
186 case ts.SyntaxKind.Constructor:
187 member.parent = existing.parent;
188 members.push(<ts.ClassElement>member);
189 break;
190 case ts.SyntaxKind.MethodSignature:
191 member.parent = existing.parent;
192 members.push(<ts.ClassElement>member);
193 break;
194 case ts.SyntaxKind.PropertySignature:
195 addModifier(member, ts.createNode(ts.SyntaxKind.StaticKe yword));
196 member.parent = existing;
197 members.push(<ts.ClassElement>member);
198 break;
199 case ts.SyntaxKind.IndexSignature:
200 member.parent = existing.parent;
201 members.push(<ts.ClassElement>member);
202 break;
203 case ts.SyntaxKind.CallSignature:
204 member.parent = existing.parent;
205 members.push(<ts.ClassElement>member);
206 break;
207 default:
208 throw 'Unhandled TypeLiteral member type:' + member.kind ;
209 }
210 });
211 }
212 }
213 }
214 } else {
215 throw 'Unexpected VariableStatement identifier kind';
216 }
217 });
218 break;
219 case ts.SyntaxKind.ModuleBlock:
220 ts.forEachChild(n, (child) => mergeVariablesIntoClasses(child, classes)) ;
221 break;
222 default:
223 break;
224 }
225 }
226
227 function removeFromArray(nodes: ts.NodeArray<ts.Node>, v: ts.Node) {
228 for (let i = 0, len = nodes.length; i < len; ++i) {
229 if (nodes[i] === v) {
230 nodes.splice(i, 1);
231 break;
232 }
233 }
234 }
235
236 function removeNode(n: ts.Node) {
237 let parent = n.parent;
238 switch (parent.kind) {
239 case ts.SyntaxKind.ModuleBlock:
240 let block = <ts.ModuleBlock>parent;
241 removeFromArray(block.statements, n);
242 break;
243 case ts.SyntaxKind.SourceFile:
244 let sourceFile = <ts.SourceFile>parent;
245 removeFromArray(sourceFile.statements, n);
246 break;
247 default:
248 throw 'removeNode not implemented for kind:' + parent.kind;
249 }
250 }
251
252 function makeCallableClassesImplementFunction(decl: base.ClassLike) {
253 if (base.isCallable(decl)) {
254 // Modify the AST to explicitly state that the class implements Function
255 if (!decl.heritageClauses) {
256 decl.heritageClauses = <ts.NodeArray<ts.HeritageClause>>[];
257 base.copyLocation(decl, decl.heritageClauses);
258 }
259 let clauses = decl.heritageClauses;
260 let clause = base.arrayFindPolyfill(
261 clauses, (c) => c.token !== ts.SyntaxKind.ExtendsKeyword ||
262 decl.kind === ts.SyntaxKind.InterfaceDeclaration);
263 if (clause == null) {
264 clause = <ts.HeritageClause>ts.createNode(ts.SyntaxKind.HeritageClause);
265 clause.token = decl.kind === ts.SyntaxKind.InterfaceDeclaration ?
266 ts.SyntaxKind.ExtendsKeyword :
267 ts.SyntaxKind.ImplementsKeyword;
268 clause.types = <ts.NodeArray<ts.ExpressionWithTypeArguments>>[];
269 clause.parent = decl;
270 base.copyLocation(decl, clause);
271 clauses.push(clause);
272 }
273 let functionType =
274 <ts.ExpressionWithTypeArguments>ts.createNode(ts.SyntaxKind.Expression WithTypeArguments);
275 functionType.parent = clause;
276 base.copyLocation(clause, functionType);
277 let fn = <ts.Identifier>ts.createNode(ts.SyntaxKind.Identifier);
278 fn.text = 'Function';
279 fn.parent = functionType;
280 base.copyLocation(functionType, fn);
281 functionType.expression = fn;
282 clause.types.push(functionType);
283 }
284 }
285
286 function gatherClasses(n: ts.Node, classes: {[name: string]: base.ClassLike}) {
287 switch (n.kind) {
288 case ts.SyntaxKind.ClassDeclaration:
289 case ts.SyntaxKind.InterfaceDeclaration:
290 let classDecl = <base.ClassLike>n;
291 let name = classDecl.name.text;
292 // TODO(jacobr): validate that the classes have consistent
293 // modifiers, etc.
294 if (classes.hasOwnProperty(name)) {
295 let existing = classes[name];
296 (classDecl.members as Array<ts.ClassElement>).forEach((e: ts.ClassElem ent) => {
297 (existing.members as Array<ts.ClassElement>).push(e);
298 e.parent = existing;
299 });
300 removeNode(classDecl);
301 } else {
302 classes[name] = classDecl;
303 // Perform other class level post processing here.
304 makeCallableClassesImplementFunction(classDecl);
305 }
306 break;
307 case ts.SyntaxKind.ModuleDeclaration:
308 case ts.SyntaxKind.SourceFile:
309 let moduleClasses: {[name: string]: base.ClassLike} = {};
310 ts.forEachChild(n, (child) => gatherClasses(child, moduleClasses));
311 ts.forEachChild(n, (child) => mergeVariablesIntoClasses(child, moduleCla sses));
312
313 break;
314 case ts.SyntaxKind.ModuleBlock:
315 ts.forEachChild(n, (child) => gatherClasses(child, classes));
316 break;
317 default:
318 break;
319 }
320 }
321 gatherClasses(f, {});
322 }
OLDNEW
« no previous file with comments | « lib/main.ts ('k') | lib/module.ts » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698