OLD | NEW |
1 import * as ts from 'typescript'; | 1 import * as ts from 'typescript'; |
2 | 2 |
3 import * as base from './base'; | 3 import * as base from './base'; |
4 import {Set, TypeDisplayOptions} from './base'; | 4 import {TypeDisplayOptions} from './base'; |
5 import {DART_LIBRARIES_FOR_BROWSER_TYPES, TS_TO_DART_TYPENAMES} from './dart_lib
raries_for_browser_types'; | 5 import {DART_LIBRARIES_FOR_BROWSER_TYPES, TS_TO_DART_TYPENAMES} from './dart_lib
raries_for_browser_types'; |
6 import {Transpiler} from './main'; | 6 import {Transpiler} from './main'; |
7 import {MergedType} from './merge'; | 7 import {MergedType} from './merge'; |
8 | 8 |
9 const FACADE_DEBUG = false; | 9 const FACADE_DEBUG = false; |
10 const FACADE_NODE_MODULES_PREFIX = /^(\.\.\/)*node_modules\//; | 10 const FACADE_NODE_MODULES_PREFIX = /^(\.\.\/)*node_modules\//; |
11 | 11 |
12 // These constants must be kept in sync with package:func/func.dart which | 12 // These constants must be kept in sync with package:func/func.dart which |
13 // provides a cannonical set of typedefs defining commonly used function types | 13 // provides a cannonical set of typedefs defining commonly used function types |
14 // to simplify specifying function types in Dart. | 14 // to simplify specifying function types in Dart. |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
76 | 76 |
77 class DartNameRecord { | 77 class DartNameRecord { |
78 name: string; | 78 name: string; |
79 constructor(private node: ts.Node, name: string, private library: DartLibrary)
{ | 79 constructor(private node: ts.Node, name: string, private library: DartLibrary)
{ |
80 this.name = name; | 80 this.name = name; |
81 } | 81 } |
82 } | 82 } |
83 | 83 |
84 export class DartLibrary { | 84 export class DartLibrary { |
85 constructor(private fileName: string) { | 85 constructor(private fileName: string) { |
86 this.usedNames = {}; | 86 this.usedNames = new Set(); |
87 } | 87 } |
88 | 88 |
89 /** | 89 /** |
90 * @returns {boolean} whether the name was added. | 90 * @returns {boolean} whether the name was added. |
91 */ | 91 */ |
92 addName(name: string): boolean { | 92 addName(name: string): boolean { |
93 if (Object.prototype.hasOwnProperty.call(this.usedNames, name)) { | 93 if (this.usedNames.has(name)) { |
94 return false; | 94 return false; |
95 } | 95 } |
96 this.usedNames[name] = true; | 96 this.usedNames.add(name); |
97 return true; | 97 return true; |
98 } | 98 } |
99 | 99 |
100 private usedNames: Set; | 100 private usedNames: Set<String>; |
101 } | 101 } |
102 | 102 |
103 // TODO(jacobr): track name conflicts better and add library prefixes to avoid t
hem. | 103 // TODO(jacobr): track name conflicts better and add library prefixes to avoid t
hem. |
104 export class NameRewriter { | 104 export class NameRewriter { |
105 private dartTypes: ts.Map<DartNameRecord> = {}; | 105 private dartTypes: Map<String, DartNameRecord> = new Map(); |
106 // TODO(jacobr): we aren't really using this well. | 106 // TODO(jacobr): we aren't really using this well. |
107 private libraries: ts.Map<DartLibrary> = {}; | 107 private libraries: Map<String, DartLibrary> = new Map(); |
108 | 108 |
109 constructor(private fc: FacadeConverter) {} | 109 constructor(private fc: FacadeConverter) {} |
110 | 110 |
111 private computeName(node: base.NamedDeclaration): DartNameRecord { | 111 private computeName(node: base.NamedDeclaration): DartNameRecord { |
112 let fullPath = fullJsPath(node); | 112 let fullPath = fullJsPath(node); |
113 if (Object.prototype.hasOwnProperty.call(this.dartTypes, fullPath)) { | 113 if (this.dartTypes.has(fullPath)) { |
114 return this.dartTypes[fullPath]; | 114 return this.dartTypes.get(fullPath); |
115 } | 115 } |
116 let sourceFile = <ts.SourceFile>base.getAncestor(node, ts.SyntaxKind.SourceF
ile); | 116 let sourceFile = <ts.SourceFile>base.getAncestor(node, ts.SyntaxKind.SourceF
ile); |
117 let fileName = sourceFile.fileName; | 117 let fileName = sourceFile.fileName; |
118 let library: DartLibrary; | 118 let library: DartLibrary; |
119 if (Object.prototype.hasOwnProperty.call(this.libraries, fileName)) { | 119 if (this.libraries.has(fileName)) { |
120 library = this.libraries[fileName]; | 120 library = this.libraries.get(fileName); |
121 } else { | 121 } else { |
122 library = new DartLibrary(fileName); | 122 library = new DartLibrary(fileName); |
123 this.libraries[fileName] = library; | 123 this.libraries.set(fileName, library); |
124 } | 124 } |
125 let parts = fullPath.split('.'); | 125 let parts = fullPath.split('.'); |
126 for (let i = parts.length - 1; i >= 0; i--) { | 126 for (let i = parts.length - 1; i >= 0; i--) { |
127 // Find a unique name by including more of the module hierarchy in the | 127 // Find a unique name by including more of the module hierarchy in the |
128 // name. This is an arbitrary but hopefully unsurprising scheme to | 128 // name. This is an arbitrary but hopefully unsurprising scheme to |
129 // generate unique names. There may be classes or members with conflicting | 129 // generate unique names. There may be classes or members with conflicting |
130 // names due to a single d.ts file containing multiple modules. | 130 // names due to a single d.ts file containing multiple modules. |
131 let candidateName = fixupIdentifierName(parts.slice(i).join('_')); | 131 let candidateName = fixupIdentifierName(parts.slice(i).join('_')); |
132 if (library.addName(candidateName)) { | 132 if (library.addName(candidateName)) { |
133 // Able to add name to library. | 133 // Able to add name to library. |
134 let ret = new DartNameRecord(node, candidateName, library); | 134 let ret = new DartNameRecord(node, candidateName, library); |
135 this.dartTypes[fullPath] = ret; | 135 this.dartTypes.set(fullPath, ret); |
136 return ret; | 136 return ret; |
137 } | 137 } |
138 } | 138 } |
139 | 139 |
140 // Usually the module name prefixes should be sufficient to disambiguate | 140 // Usually the module name prefixes should be sufficient to disambiguate |
141 // names but sometimes we need to add a numeric prefix as well to | 141 // names but sometimes we need to add a numeric prefix as well to |
142 // disambiguate. We could alternately append the full module prefix as well | 142 // disambiguate. We could alternately append the full module prefix as well |
143 // to make the name choice completely unsurprising albeit even uglier. | 143 // to make the name choice completely unsurprising albeit even uglier. |
144 // This case should be very rarely hit. | 144 // This case should be very rarely hit. |
145 let i = 2; | 145 let i = 2; |
146 while (true) { | 146 while (true) { |
147 let candidateName = parts[parts.length - 1] + i; | 147 let candidateName = parts[parts.length - 1] + i; |
148 if (library.addName(candidateName)) { | 148 if (library.addName(candidateName)) { |
149 // Able to add name to library. | 149 // Able to add name to library. |
150 let ret = new DartNameRecord(node, candidateName, library); | 150 let ret = new DartNameRecord(node, candidateName, library); |
151 this.dartTypes[fullPath] = ret; | 151 this.dartTypes.set(fullPath, ret); |
152 return ret; | 152 return ret; |
153 } | 153 } |
154 i++; | 154 i++; |
155 } | 155 } |
156 } | 156 } |
157 | 157 |
158 lookupName(node: base.NamedDeclaration, context: ts.Node) { | 158 lookupName(node: base.NamedDeclaration, context: ts.Node) { |
159 let name = this.computeName(node).name; | 159 let name = this.computeName(node).name; |
160 return this.fc.resolveImportForSourceFile(node.getSourceFile(), context.getS
ourceFile(), name); | 160 return this.fc.resolveImportForSourceFile(node.getSourceFile(), context.getS
ourceFile(), name); |
161 } | 161 } |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
198 options: TypeDisplayOptions, typeArguments: ts.TypeNode[]): TypeDisplayOptio
ns { | 198 options: TypeDisplayOptions, typeArguments: ts.TypeNode[]): TypeDisplayOptio
ns { |
199 let ret = cloneOptions(options); | 199 let ret = cloneOptions(options); |
200 ret.typeArguments = typeArguments; | 200 ret.typeArguments = typeArguments; |
201 return ret; | 201 return ret; |
202 } | 202 } |
203 | 203 |
204 function resolveTypeArguments( | 204 function resolveTypeArguments( |
205 options: TypeDisplayOptions, parameters: ts.TypeParameterDeclaration[]) { | 205 options: TypeDisplayOptions, parameters: ts.TypeParameterDeclaration[]) { |
206 let ret = cloneOptions(options); | 206 let ret = cloneOptions(options); |
207 let typeArguments = options.typeArguments ? options.typeArguments : []; | 207 let typeArguments = options.typeArguments ? options.typeArguments : []; |
208 ret.resolvedTypeArguments = {}; | 208 ret.resolvedTypeArguments = new Map(); |
209 if (parameters) { | 209 if (parameters) { |
210 for (let i = 0; i < parameters.length; ++i) { | 210 for (let i = 0; i < parameters.length; ++i) { |
211 let param = parameters[i]; | 211 let param = parameters[i]; |
212 ret.resolvedTypeArguments[base.ident(param.name)] = typeArguments[i]; | 212 ret.resolvedTypeArguments.set(base.ident(param.name), typeArguments[i]); |
213 } | 213 } |
214 } | 214 } |
215 // Type arguments have been resolved forward so we don't need to emit them dir
ectly. | 215 // Type arguments have been resolved forward so we don't need to emit them dir
ectly. |
216 ret.typeArguments = null; | 216 ret.typeArguments = null; |
217 return ret; | 217 return ret; |
218 } | 218 } |
219 | 219 |
220 function removeResolvedTypeArguments(options: TypeDisplayOptions): TypeDisplayOp
tions { | 220 function removeResolvedTypeArguments(options: TypeDisplayOptions): TypeDisplayOp
tions { |
221 let ret = cloneOptions(options); | 221 let ret = cloneOptions(options); |
222 ret.resolvedTypeArguments = null; | 222 ret.resolvedTypeArguments = null; |
223 return ret; | 223 return ret; |
224 } | 224 } |
225 | 225 |
226 export class FacadeConverter extends base.TranspilerBase { | 226 export class FacadeConverter extends base.TranspilerBase { |
227 tc: ts.TypeChecker; | 227 tc: ts.TypeChecker; |
228 // For the Dart keyword list see | 228 // For the Dart keyword list see |
229 // https://www.dartlang.org/docs/dart-up-and-running/ch02.html#keywords | 229 // https://www.dartlang.org/docs/dart-up-and-running/ch02.html#keywords |
230 static DART_RESERVED_WORDS = | 230 static DART_RESERVED_WORDS = |
231 ('assert break case catch class const continue default do else enum extend
s false final ' + | 231 ('assert break case catch class const continue default do else enum extend
s false final ' + |
232 'finally for if in is new null rethrow return super switch this throw tru
e try let void ' + | 232 'finally for if in is new null rethrow return super switch this throw tru
e try let void ' + |
233 'while with') | 233 'while with') |
234 .split(/ /); | 234 .split(/ /); |
235 | 235 |
236 // These are the built-in and limited keywords. | 236 // These are the built-in and limited keywords. |
237 static DART_OTHER_KEYWORDS = | 237 static DART_OTHER_KEYWORDS = |
238 ('abstract as async await deferred dynamic export external factory get imp
lements import ' + | 238 ('abstract as async await deferred dynamic export external factory get imp
lements import ' + |
239 'library operator part set static sync typedef yield call') | 239 'library operator part set static sync typedef yield call') |
240 .split(/ /); | 240 .split(/ /); |
241 | 241 |
242 private candidateTypes: {[typeName: string]: boolean} = {}; | 242 private candidateTypes: Map<string, boolean> = new Map(); |
243 private typingsRootRegex: RegExp; | 243 private typingsRootRegex: RegExp; |
244 private genericMethodDeclDepth = 0; | 244 private genericMethodDeclDepth = 0; |
245 private nameRewriter: NameRewriter; | 245 private nameRewriter: NameRewriter; |
246 | 246 |
247 constructor(transpiler: Transpiler, typingsRoot = '') { | 247 constructor(transpiler: Transpiler, typingsRoot?: string) { |
248 super(transpiler); | 248 super(transpiler); |
| 249 typingsRoot = typingsRoot || ''; |
249 this.nameRewriter = new NameRewriter(this); | 250 this.nameRewriter = new NameRewriter(this); |
250 this.extractPropertyNames(TS_TO_DART_TYPENAMES, this.candidateTypes); | 251 this.extractPropertyNames(TS_TO_DART_TYPENAMES, this.candidateTypes); |
251 // Remove this line if decide to support generating code that avoids dart:ht
ml. | 252 // Remove this line if decide to support generating code that avoids dart:ht
ml. |
252 Object.keys(DART_LIBRARIES_FOR_BROWSER_TYPES) | 253 Object.keys(DART_LIBRARIES_FOR_BROWSER_TYPES) |
253 .forEach((propName) => this.candidateTypes[propName] = true); | 254 .forEach((propName) => this.candidateTypes.set(propName, true)); |
254 | 255 |
255 this.typingsRootRegex = new RegExp('^' + typingsRoot.replace('.', '\\.')); | 256 this.typingsRootRegex = new RegExp('^' + typingsRoot.replace('.', '\\.')); |
256 } | 257 } |
257 | 258 |
258 private extractPropertyNames(m: ts.Map<ts.Map<any>>, candidates: {[k: string]:
boolean}) { | 259 private extractPropertyNames(m: ts.Map<ts.Map<any>>, candidates: Map<string, b
oolean>) { |
259 for (let fileName of Object.keys(m)) { | 260 for (let fileName of Object.keys(m)) { |
260 const file = m[fileName]; | 261 const file = m[fileName]; |
261 if (file === undefined) { | 262 if (file === undefined) { |
262 return; | 263 return; |
263 } | 264 } |
264 Object.keys(file) | 265 Object.keys(file) |
265 .map((propName) => propName.substring(propName.lastIndexOf('.') + 1)) | 266 .map((propName) => propName.substring(propName.lastIndexOf('.') + 1)) |
266 .forEach((propName) => candidates[propName] = true); | 267 .forEach((propName) => candidates.set(propName, true)); |
267 } | 268 } |
268 } | 269 } |
269 | 270 |
270 setTypeChecker(tc: ts.TypeChecker) { | 271 setTypeChecker(tc: ts.TypeChecker) { |
271 this.tc = tc; | 272 this.tc = tc; |
272 } | 273 } |
273 | 274 |
274 pushTypeParameterNames(n: ts.FunctionLikeDeclaration) { | 275 pushTypeParameterNames(n: ts.FunctionLikeDeclaration) { |
275 if (!n.typeParameters) return; | 276 if (!n.typeParameters) return; |
276 this.genericMethodDeclDepth++; | 277 this.genericMethodDeclDepth++; |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
316 if (!t || (t.flags & ts.TypeFlags.TypeParameter) === 0) return false; | 317 if (!t || (t.flags & ts.TypeFlags.TypeParameter) === 0) return false; |
317 | 318 |
318 // Check if the symbol we're looking at is the type parameter. | 319 // Check if the symbol we're looking at is the type parameter. |
319 let symbol = this.tc.getSymbolAtLocation(name); | 320 let symbol = this.tc.getSymbolAtLocation(name); |
320 if (symbol !== t.symbol) return false; | 321 if (symbol !== t.symbol) return false; |
321 | 322 |
322 // Check that the Type Parameter has been declared by a function declaration
. | 323 // Check that the Type Parameter has been declared by a function declaration
. |
323 return symbol.declarations.some(d => d.parent.kind === ts.SyntaxKind.Functio
nDeclaration); | 324 return symbol.declarations.some(d => d.parent.kind === ts.SyntaxKind.Functio
nDeclaration); |
324 } | 325 } |
325 | 326 |
326 generateTypeList(types: ts.TypeNode[], options: TypeDisplayOptions, seperator
= ','): string { | 327 generateTypeList(types: ts.TypeNode[], options: TypeDisplayOptions, seperator?
: string): string { |
| 328 seperator = seperator || ','; |
327 let that = this; | 329 let that = this; |
328 return types | 330 return types |
329 .map((type) => { | 331 .map((type) => { |
330 return that.generateDartTypeName(type, addInsideTypeArgument(options))
; | 332 return that.generateDartTypeName(type, addInsideTypeArgument(options))
; |
331 }) | 333 }) |
332 .join(seperator); | 334 .join(seperator); |
333 } | 335 } |
334 | 336 |
335 generateDartTypeName(node: ts.TypeNode, options?: TypeDisplayOptions): string
{ | 337 generateDartTypeName(node: ts.TypeNode, options?: TypeDisplayOptions): string
{ |
336 if (!options) { | 338 if (!options) { |
(...skipping 280 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
617 options = { | 619 options = { |
618 insideComment: this.insideCodeComment, | 620 insideComment: this.insideCodeComment, |
619 insideTypeArgument: this.insideTypeArgument | 621 insideTypeArgument: this.insideTypeArgument |
620 }; | 622 }; |
621 } | 623 } |
622 let ident = base.ident(identifier); | 624 let ident = base.ident(identifier); |
623 let symbol: ts.Symbol = this.getSymbolAtLocation(identifier); | 625 let symbol: ts.Symbol = this.getSymbolAtLocation(identifier); |
624 let declaration = this.getSymbolDeclaration(symbol, identifier); | 626 let declaration = this.getSymbolDeclaration(symbol, identifier); |
625 if (symbol && symbol.flags & ts.SymbolFlags.TypeParameter) { | 627 if (symbol && symbol.flags & ts.SymbolFlags.TypeParameter) { |
626 let kind = declaration.parent.kind; | 628 let kind = declaration.parent.kind; |
627 if (options.resolvedTypeArguments && | 629 if (options.resolvedTypeArguments && options.resolvedTypeArguments.has(ide
nt)) { |
628 Object.hasOwnProperty.call(options.resolvedTypeArguments, ident)) { | |
629 return { | 630 return { |
630 name: this.generateDartTypeName( | 631 name: this.generateDartTypeName( |
631 options.resolvedTypeArguments[ident], removeResolvedTypeArguments(
options)) | 632 options.resolvedTypeArguments.get(ident), removeResolvedTypeArgume
nts(options)) |
632 }; | 633 }; |
633 } | 634 } |
634 // Only kinds of TypeParameters supported by Dart. | 635 // Only kinds of TypeParameters supported by Dart. |
635 if (kind !== ts.SyntaxKind.ClassDeclaration && kind !== ts.SyntaxKind.Inte
rfaceDeclaration && | 636 if (kind !== ts.SyntaxKind.ClassDeclaration && kind !== ts.SyntaxKind.Inte
rfaceDeclaration && |
636 kind !== ts.SyntaxKind.TypeAliasDeclaration) { | 637 kind !== ts.SyntaxKind.TypeAliasDeclaration) { |
637 return {name: 'dynamic', comment: ident}; | 638 return {name: 'dynamic', comment: ident}; |
638 } | 639 } |
639 } | 640 } |
640 | 641 |
641 if (this.candidateTypes.hasOwnProperty(ident)) { | 642 if (this.candidateTypes.has(ident)) { |
642 if (!symbol) { | 643 if (!symbol) { |
643 return null; | 644 return null; |
644 } | 645 } |
645 | 646 |
646 let fileAndName = this.getFileAndName(identifier, symbol); | 647 let fileAndName = this.getFileAndName(identifier, symbol); |
647 | 648 |
648 if (fileAndName) { | 649 if (fileAndName) { |
649 let fileSubs = TS_TO_DART_TYPENAMES[fileAndName.fileName]; | 650 let fileSubs = TS_TO_DART_TYPENAMES[fileAndName.fileName]; |
650 if (fileSubs) { | 651 if (fileSubs) { |
651 let name = fileAndName.qname; | 652 let name = fileAndName.qname; |
(...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
871 let qname = this.tc.getFullyQualifiedName(symbol); | 872 let qname = this.tc.getFullyQualifiedName(symbol); |
872 // Some Qualified Names include their file name. Might be a bug in TypeScrip
t, | 873 // Some Qualified Names include their file name. Might be a bug in TypeScrip
t, |
873 // for the time being just special case. | 874 // for the time being just special case. |
874 if (symbol.flags & (ts.SymbolFlags.Class | ts.SymbolFlags.Function | ts.Symb
olFlags.Variable)) { | 875 if (symbol.flags & (ts.SymbolFlags.Class | ts.SymbolFlags.Function | ts.Symb
olFlags.Variable)) { |
875 qname = symbol.getName(); | 876 qname = symbol.getName(); |
876 } | 877 } |
877 if (FACADE_DEBUG) console.error('fn:', fileName, 'cfn:', canonicalFileName,
'qn:', qname); | 878 if (FACADE_DEBUG) console.error('fn:', fileName, 'cfn:', canonicalFileName,
'qn:', qname); |
878 return {fileName: canonicalFileName, qname}; | 879 return {fileName: canonicalFileName, qname}; |
879 } | 880 } |
880 } | 881 } |
OLD | NEW |