| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 } |
| OLD | NEW |