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

Side by Side Diff: lib/merge.ts

Issue 2416003003: Update package name, update and lock clang-format and tslint versions, and format all source files … (Closed)
Patch Set: Use ES6 Map and Set instead of Object literals to avoid ordering instability across different Node … Created 4 years, 2 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') | test/facade_converter_test.ts » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 import ts = require('typescript'); 1 import ts = require('typescript');
2 import base = require('./base'); 2 import base = require('./base');
3 import {FacadeConverter} from './facade_converter'; 3 import {FacadeConverter} from './facade_converter';
4 4
5 /** 5 /**
6 * To support arbitrary d.ts files in Dart we often have to merge two TypeScript 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 7 * types into a single Dart type because Dart lacks features such as method
8 * overloads, type aliases, and union types. 8 * overloads, type aliases, and union types.
9 */ 9 */
10 export class MergedType { 10 export class MergedType {
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
44 } 44 }
45 45
46 this.merge(alias.type); 46 this.merge(alias.type);
47 } 47 }
48 return; 48 return;
49 } 49 }
50 break; 50 break;
51 default: 51 default:
52 break; 52 break;
53 } 53 }
54 this.types[this.fc.generateDartTypeName(t, {insideComment: true})] = t; 54 this.types.set(this.fc.generateDartTypeName(t, {insideComment: true}), t);
55 } 55 }
56 } 56 }
57 57
58 toTypeNode(): ts.TypeNode { 58 toTypeNode(): ts.TypeNode {
59 let names = Object.getOwnPropertyNames(this.types); 59 let names = Array.from(this.types.keys());
60 if (names.length === 0) { 60 if (names.length === 0) {
61 return null; 61 return null;
62 } 62 }
63 if (names.length === 1) { 63 if (names.length === 1) {
64 return this.types[names[0]]; 64 return this.types.get(names[0]);
65 } 65 }
66 let union = <ts.UnionTypeNode>ts.createNode(ts.SyntaxKind.UnionType); 66 let union = <ts.UnionTypeNode>ts.createNode(ts.SyntaxKind.UnionType);
67 base.copyLocation(this.types[names[0]], union); 67 base.copyLocation(this.types.get(names[0]), union);
68 68
69 union.types = <ts.NodeArray<ts.TypeNode>>[]; 69 union.types = Array.from(this.types.values()) as ts.NodeArray<ts.TypeNode>;
70 for (let i = 0; i < names.length; ++i) {
71 union.types.push(this.types[names[i]]);
72 }
73 return union; 70 return union;
74 } 71 }
75 72
76 /** 73 /**
77 * Generate a type node where we have stripped out type features that Dart doe s not support. 74 * Generate a type node where we have stripped out type features that Dart doe s not support.
78 * Currently this means stripping out union types. 75 * Currently this means stripping out union types.
79 */ 76 */
80 toSimpleTypeNode(): ts.TypeNode { 77 toSimpleTypeNode(): ts.TypeNode {
81 let merged = this.toTypeNode(); 78 let merged = this.toTypeNode();
82 if (merged == null) return null; 79 if (merged == null) return null;
83 80
84 if (merged.kind === ts.SyntaxKind.UnionType) { 81 if (merged.kind === ts.SyntaxKind.UnionType) {
85 // For union types find a Dart type that satisfies all the types. 82 // For union types find a Dart type that satisfies all the types.
86 let types = (<ts.UnionTypeNode>merged).types; 83 let types = (<ts.UnionTypeNode>merged).types;
87 // Generate a common base type for an array of types. 84 // Generate a common base type for an array of types.
88 // The implemented is currently incomplete often returning null when there 85 // The implemented is currently incomplete often returning null when there
89 // might really be a valid common base type. 86 // might really be a valid common base type.
90 let common: ts.TypeNode = types[0]; 87 let common: ts.TypeNode = types[0];
91 for (let i = 1; i < types.length && common != null; ++i) { 88 for (let i = 1; i < types.length && common != null; ++i) {
92 let type = types[i]; 89 let type = types[i];
93 common = this.fc.findCommonType(type, common); 90 common = this.fc.findCommonType(type, common);
94 } 91 }
95 return common; 92 return common;
96 } 93 }
97 return merged; 94 return merged;
98 } 95 }
99 96
100 private types: {[name: string]: ts.TypeNode} = {}; 97 private types: Map<string, ts.TypeNode> = new Map();
101 } 98 }
102 99
103 /** 100 /**
104 * Handle a parameter that is the result of merging parameter declarations from 101 * Handle a parameter that is the result of merging parameter declarations from
105 * multiple method overloads. 102 * multiple method overloads.
106 */ 103 */
107 export class MergedParameter { 104 export class MergedParameter {
108 constructor(param: ts.ParameterDeclaration, fc: FacadeConverter) { 105 constructor(param: ts.ParameterDeclaration, fc: FacadeConverter) {
109 this.type = new MergedType(fc); 106 this.type = new MergedType(fc);
110 this.textRange = param; 107 this.textRange = param;
111 this.merge(param); 108 this.merge(param);
112 } 109 }
113 110
114 merge(param: ts.ParameterDeclaration) { 111 merge(param: ts.ParameterDeclaration) {
115 this.name[base.ident(param.name)] = true; 112 this.name.add(base.ident(param.name));
116 if (!this.optional) { 113 if (!this.optional) {
117 this.optional = !!param.questionToken; 114 this.optional = !!param.questionToken;
118 } 115 }
119 this.type.merge(param.type); 116 this.type.merge(param.type);
120 } 117 }
121 118
122 toParameterDeclaration(): ts.ParameterDeclaration { 119 toParameterDeclaration(): ts.ParameterDeclaration {
123 let ret = <ts.ParameterDeclaration>ts.createNode(ts.SyntaxKind.Parameter); 120 let ret = <ts.ParameterDeclaration>ts.createNode(ts.SyntaxKind.Parameter);
124 let nameIdentifier = <ts.Identifier>ts.createNode(ts.SyntaxKind.Identifier); 121 let nameIdentifier = <ts.Identifier>ts.createNode(ts.SyntaxKind.Identifier);
125 nameIdentifier.text = Object.getOwnPropertyNames(this.name).join('_'); 122 nameIdentifier.text = Array.from(this.name).join('_');
126 ret.name = nameIdentifier; 123 ret.name = nameIdentifier;
127 if (this.optional) { 124 if (this.optional) {
128 ret.questionToken = ts.createNode(ts.SyntaxKind.QuestionToken); 125 ret.questionToken = ts.createNode(ts.SyntaxKind.QuestionToken);
129 } 126 }
130 base.copyLocation(this.textRange, ret); 127 base.copyLocation(this.textRange, ret);
131 ret.type = this.type.toTypeNode(); 128 ret.type = this.type.toTypeNode();
132 return ret; 129 return ret;
133 } 130 }
134 131
135 setOptional() { 132 setOptional() {
136 this.optional = true; 133 this.optional = true;
137 } 134 }
138 135
139 private name: {[s: string]: boolean} = {}; 136 private name: Set<string> = new Set();
140 private type: MergedType; 137 private type: MergedType;
141 private optional: boolean = false; 138 private optional: boolean = false;
142 private textRange: ts.TextRange; 139 private textRange: ts.TextRange;
143 } 140 }
144 141
145 /** 142 /**
146 * Handle a parameter that is the result of merging parameter declarations from 143 * Handle a parameter that is the result of merging parameter declarations from
147 * multiple method overloads. 144 * multiple method overloads.
148 */ 145 */
149 export class MergedTypeParameter { 146 export class MergedTypeParameter {
(...skipping 28 matching lines...) Expand all
178 private name: string; 175 private name: string;
179 private constraint: MergedType; 176 private constraint: MergedType;
180 private textRange: ts.TextRange; 177 private textRange: ts.TextRange;
181 } 178 }
182 179
183 /** 180 /**
184 * Handle a parameter that is the result of merging parameter declarations from 181 * Handle a parameter that is the result of merging parameter declarations from
185 * multiple method overloads. 182 * multiple method overloads.
186 */ 183 */
187 export class MergedTypeParameters { 184 export class MergedTypeParameters {
188 private mergedParameters: {[s: string]: MergedTypeParameter} = {}; 185 private mergedParameters: Map<string, MergedTypeParameter> = new Map();
189 private textRange: ts.TextRange; 186 private textRange: ts.TextRange;
190 187
191 constructor(private fc: FacadeConverter) {} 188 constructor(private fc: FacadeConverter) {}
192 189
193 merge(params: ts.NodeArray<ts.TypeParameterDeclaration>) { 190 merge(params: ts.NodeArray<ts.TypeParameterDeclaration>) {
194 if (!params) return; 191 if (!params) return;
195 if (!this.textRange) { 192 if (!this.textRange) {
196 this.textRange = params; 193 this.textRange = params;
197 } 194 }
198 for (let i = 0; i < params.length; i++) { 195 for (let i = 0; i < params.length; i++) {
199 let param = params[i]; 196 let param = params[i];
200 let name = base.ident(param.name); 197 let name = base.ident(param.name);
201 if (Object.hasOwnProperty.call(this.mergedParameters, name)) { 198 if (this.mergedParameters.has(name)) {
202 let merged = this.mergedParameters[name]; 199 let merged = this.mergedParameters.get(name);
203 if (merged) { 200 if (merged) {
204 merged.merge(param); 201 merged.merge(param);
205 } 202 }
206 } else { 203 } else {
207 this.mergedParameters[name] = new MergedTypeParameter(param, this.fc); 204 this.mergedParameters.set(name, new MergedTypeParameter(param, this.fc)) ;
208 } 205 }
209 } 206 }
210 } 207 }
211 208
212 toTypeParameters(): ts.NodeArray<ts.TypeParameterDeclaration> { 209 toTypeParameters(): ts.NodeArray<ts.TypeParameterDeclaration> {
213 let names = Object.getOwnPropertyNames(this.mergedParameters); 210 if (this.mergedParameters.size === 0) {
214 if (names.length === 0) {
215 return undefined; 211 return undefined;
216 } 212 }
217 213
218 let ret = [] as ts.NodeArray<ts.TypeParameterDeclaration>; 214 let ret = [] as ts.NodeArray<ts.TypeParameterDeclaration>;
219 base.copyLocation(this.textRange, ret); 215 base.copyLocation(this.textRange, ret);
220 for (let i = 0; i < names.length; ++i) { 216 this.mergedParameters.forEach((mergedParameter) => {
221 ret.push(this.mergedParameters[names[i]].toTypeParameterDeclaration()); 217 ret.push(mergedParameter.toTypeParameterDeclaration());
222 } 218 });
219
223 return ret; 220 return ret;
224 } 221 }
225 } 222 }
226 223
227 /** 224 /**
228 * Normalize a SourceFile 225 * Normalize a SourceFile
229 */ 226 */
230 export function normalizeSourceFile(f: ts.SourceFile, fc: FacadeConverter) { 227 export function normalizeSourceFile(f: ts.SourceFile, fc: FacadeConverter) {
231 let modules: {[name: string]: ts.ModuleDeclaration} = {}; 228 let modules: Map<string, ts.ModuleDeclaration> = new Map();
232 229
233 // Merge top level modules. 230 // Merge top level modules.
234 for (let i = 0; i < f.statements.length; ++i) { 231 for (let i = 0; i < f.statements.length; ++i) {
235 let statement = f.statements[i]; 232 let statement = f.statements[i];
236 if (statement.kind !== ts.SyntaxKind.ModuleDeclaration) continue; 233 if (statement.kind !== ts.SyntaxKind.ModuleDeclaration) continue;
237 let moduleDecl = <ts.ModuleDeclaration>statement; 234 let moduleDecl = <ts.ModuleDeclaration>statement;
238 let name = moduleDecl.name.text; 235 let name = moduleDecl.name.text;
239 if (Object.hasOwnProperty.call(modules, name)) { 236 if (modules.has(name)) {
240 let srcBody = modules[name].body; 237 let srcBody = modules.get(name).body;
241 let srcBodyBlock: ts.ModuleBlock; 238 let srcBodyBlock: ts.ModuleBlock;
242 239
243 if (srcBody.kind !== ts.SyntaxKind.ModuleBlock) { 240 if (srcBody.kind !== ts.SyntaxKind.ModuleBlock) {
244 throw 'Module body must be a module block.'; 241 throw 'Module body must be a module block.';
245 } 242 }
246 srcBodyBlock = <ts.ModuleBlock>srcBody; 243 srcBodyBlock = <ts.ModuleBlock>srcBody;
247 244
248 let body = moduleDecl.body; 245 let body = moduleDecl.body;
249 if (body.kind === ts.SyntaxKind.ModuleBlock) { 246 if (body.kind === ts.SyntaxKind.ModuleBlock) {
250 let bodyBlock = <ts.ModuleBlock>body; 247 let bodyBlock = <ts.ModuleBlock>body;
251 Array.prototype.push.apply(srcBodyBlock.statements, bodyBlock.statements ); 248 Array.prototype.push.apply(srcBodyBlock.statements, bodyBlock.statements );
252 } else { 249 } else {
253 // moduleDecl.body is a ModuleDeclaration. 250 // moduleDecl.body is a ModuleDeclaration.
254 srcBodyBlock.statements.push(moduleDecl.body); 251 srcBodyBlock.statements.push(moduleDecl.body);
255 } 252 }
256 253
257 f.statements.splice(i, 1); 254 f.statements.splice(i, 1);
258 i--; 255 i--;
259 } else { 256 } else {
260 modules[name] = moduleDecl; 257 modules.set(name, moduleDecl);
261 } 258 }
262 } 259 }
263 260
264 function addModifier(n: ts.Node, modifier: ts.Node) { 261 function addModifier(n: ts.Node, modifier: ts.Node) {
265 if (!n.modifiers) { 262 if (!n.modifiers) {
266 n.modifiers = <ts.ModifiersArray>[]; 263 n.modifiers = <ts.ModifiersArray>[];
267 n.modifiers.flags = 0; 264 n.modifiers.flags = 0;
268 } 265 }
269 modifier.parent = n; 266 modifier.parent = n;
270 n.modifiers.push(modifier); 267 n.modifiers.push(modifier);
271 } 268 }
272 269
273 function mergeVariablesIntoClasses(n: ts.Node, classes: {[name: string]: base. ClassLike}) { 270 function mergeVariablesIntoClasses(n: ts.Node, classes: Map<string, base.Class Like>) {
274 switch (n.kind) { 271 switch (n.kind) {
275 case ts.SyntaxKind.VariableStatement: 272 case ts.SyntaxKind.VariableStatement:
276 let statement = <ts.VariableStatement>n; 273 let statement = <ts.VariableStatement>n;
277 statement.declarationList.declarations.forEach(function( 274 statement.declarationList.declarations.forEach(function(
278 declaration: ts.VariableDeclaration) { 275 declaration: ts.VariableDeclaration) {
279 if (declaration.name.kind === ts.SyntaxKind.Identifier) { 276 if (declaration.name.kind === ts.SyntaxKind.Identifier) {
280 let name: string = (<ts.Identifier>(declaration.name)).text; 277 let name: string = (<ts.Identifier>(declaration.name)).text;
281 let existingClass = Object.hasOwnProperty.call(classes, name); 278 let existingClass = classes.has(name);
282 let hasConstructor = false; 279 let hasConstructor = false;
283 if (declaration.type) { 280 if (declaration.type) {
284 let type: ts.TypeNode = declaration.type; 281 let type: ts.TypeNode = declaration.type;
285 if (type.kind === ts.SyntaxKind.TypeLiteral) { 282 if (type.kind === ts.SyntaxKind.TypeLiteral) {
286 let literal = <ts.TypeLiteralNode>type; 283 let literal = <ts.TypeLiteralNode>type;
287 hasConstructor = literal.members.some((member: ts.Node) => { 284 hasConstructor = literal.members.some((member: ts.Node) => {
288 return member.kind === ts.SyntaxKind.ConstructSignature; 285 return member.kind === ts.SyntaxKind.ConstructSignature;
289 }); 286 });
290 } else if (type.kind === ts.SyntaxKind.TypeReference) { 287 } else if (type.kind === ts.SyntaxKind.TypeReference) {
291 // Handle interfaces with constructors. As Dart does not support calling arbitrary 288 // Handle interfaces with constructors. As Dart does not support calling arbitrary
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
327 if (existingClass || hasConstructor) { 324 if (existingClass || hasConstructor) {
328 if (!existingClass) { 325 if (!existingClass) {
329 // Create a stub existing class to upgrade the object literal to if there is not an 326 // Create a stub existing class to upgrade the object literal to if there is not an
330 // existing class with the same name. 327 // existing class with the same name.
331 let clazz = <ts.ClassDeclaration>ts.createNode(ts.SyntaxKind.Cla ssDeclaration); 328 let clazz = <ts.ClassDeclaration>ts.createNode(ts.SyntaxKind.Cla ssDeclaration);
332 base.copyLocation(declaration, clazz); 329 base.copyLocation(declaration, clazz);
333 clazz.name = declaration.name as ts.Identifier; 330 clazz.name = declaration.name as ts.Identifier;
334 clazz.members = <ts.NodeArray<ts.ClassElement>>[]; 331 clazz.members = <ts.NodeArray<ts.ClassElement>>[];
335 base.copyLocation(declaration, clazz.members); 332 base.copyLocation(declaration, clazz.members);
336 replaceNode(n, clazz); 333 replaceNode(n, clazz);
337 classes[name] = clazz; 334 classes.set(name, clazz);
338 } 335 }
339 336
340 let existing = classes[name]; 337 let existing = classes.get(name);
341 if (existing.kind === ts.SyntaxKind.InterfaceDeclaration) { 338 if (existing.kind === ts.SyntaxKind.InterfaceDeclaration) {
342 let interfaceDecl = existing as base.ExtendedInterfaceDeclaratio n; 339 let interfaceDecl = existing as base.ExtendedInterfaceDeclaratio n;
343 // It is completely safe to assume that we know the precise clas s like variable 340 // It is completely safe to assume that we know the precise clas s like variable
344 // declaration for the interface in this case as they have the s ame exact name. 341 // declaration for the interface in this case as they have the s ame exact name.
345 interfaceDecl.classLikeVariableDeclaration = declaration; 342 interfaceDecl.classLikeVariableDeclaration = declaration;
346 } 343 }
347 let members = existing.members as Array<ts.ClassElement>; 344 let members = existing.members as Array<ts.ClassElement>;
348 if (declaration.type) { 345 if (declaration.type) {
349 let type: ts.TypeNode = declaration.type; 346 let type: ts.TypeNode = declaration.type;
350 if (type.kind === ts.SyntaxKind.TypeLiteral) { 347 if (type.kind === ts.SyntaxKind.TypeLiteral) {
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after
450 break; 447 break;
451 case ts.SyntaxKind.SourceFile: 448 case ts.SyntaxKind.SourceFile:
452 let sourceFile = <ts.SourceFile>parent; 449 let sourceFile = <ts.SourceFile>parent;
453 replaceInArray(sourceFile.statements, n, replacement); 450 replaceInArray(sourceFile.statements, n, replacement);
454 break; 451 break;
455 default: 452 default:
456 throw 'replaceNode not implemented for kind:' + parent.kind; 453 throw 'replaceNode not implemented for kind:' + parent.kind;
457 } 454 }
458 } 455 }
459 456
460 function gatherClasses(n: ts.Node, classes: {[name: string]: base.ClassLike}) { 457 function gatherClasses(n: ts.Node, classes: Map<string, base.ClassLike>) {
461 switch (n.kind) { 458 switch (n.kind) {
462 case ts.SyntaxKind.ClassDeclaration: 459 case ts.SyntaxKind.ClassDeclaration:
463 case ts.SyntaxKind.InterfaceDeclaration: 460 case ts.SyntaxKind.InterfaceDeclaration:
464 let classDecl = <base.ClassLike>n; 461 let classDecl = <base.ClassLike>n;
465 let name = classDecl.name.text; 462 let name = classDecl.name.text;
466 // TODO(jacobr): validate that the classes have consistent 463 // TODO(jacobr): validate that the classes have consistent
467 // modifiers, etc. 464 // modifiers, etc.
468 if (Object.hasOwnProperty.call(classes, name)) { 465 if (classes.has(name)) {
469 let existing = classes[name]; 466 let existing = classes.get(name);
470 (classDecl.members as Array<ts.ClassElement>).forEach((e: ts.ClassElem ent) => { 467 (classDecl.members as Array<ts.ClassElement>).forEach((e: ts.ClassElem ent) => {
471 (existing.members as Array<ts.ClassElement>).push(e); 468 (existing.members as Array<ts.ClassElement>).push(e);
472 e.parent = existing; 469 e.parent = existing;
473 }); 470 });
474 removeNode(classDecl); 471 removeNode(classDecl);
475 } else { 472 } else {
476 classes[name] = classDecl; 473 classes.set(name, classDecl);
477 // Perform other class level post processing here. 474 // Perform other class level post processing here.
478 } 475 }
479 break; 476 break;
480 case ts.SyntaxKind.ModuleDeclaration: 477 case ts.SyntaxKind.ModuleDeclaration:
481 case ts.SyntaxKind.SourceFile: 478 case ts.SyntaxKind.SourceFile:
482 let moduleClasses: {[name: string]: base.ClassLike} = {}; 479 let moduleClasses: Map<string, base.ClassLike> = new Map();
483 ts.forEachChild(n, (child) => gatherClasses(child, moduleClasses)); 480 ts.forEachChild(n, (child) => gatherClasses(child, moduleClasses));
484 ts.forEachChild(n, (child) => mergeVariablesIntoClasses(child, moduleCla sses)); 481 ts.forEachChild(n, (child) => mergeVariablesIntoClasses(child, moduleCla sses));
485 482
486 break; 483 break;
487 case ts.SyntaxKind.ModuleBlock: 484 case ts.SyntaxKind.ModuleBlock:
488 ts.forEachChild(n, (child) => gatherClasses(child, classes)); 485 ts.forEachChild(n, (child) => gatherClasses(child, classes));
489 break; 486 break;
490 default: 487 default:
491 break; 488 break;
492 } 489 }
493 } 490 }
494 gatherClasses(f, {}); 491 gatherClasses(f, new Map());
495 } 492 }
OLDNEW
« no previous file with comments | « lib/main.ts ('k') | test/facade_converter_test.ts » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698