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

Side by Side Diff: lib/declaration.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/dart_libraries_for_browser_types.ts ('k') | lib/expression.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 * as ts from 'typescript'; 1 import * as ts from 'typescript';
2
2 import * as base from './base'; 3 import * as base from './base';
4 import {FacadeConverter} from './facade_converter';
3 import {Transpiler} from './main'; 5 import {Transpiler} from './main';
4 import {FacadeConverter} from './facade_converter'; 6 import {MergedParameter, MergedType} from './merge';
7
8 export function isFunctionLikeProperty(
9 decl: ts.PropertyDeclaration|ts.ParameterDeclaration, tc: ts.TypeChecker): b oolean {
10 if (!decl.type) return false;
11 let name = base.ident(decl.name);
12 if (name.match(/^on[A-Z]/)) return false;
13 return base.isFunctionType(decl.type, tc);
14 }
5 15
6 export default class DeclarationTranspiler extends base.TranspilerBase { 16 export default class DeclarationTranspiler extends base.TranspilerBase {
17 private tc: ts.TypeChecker;
18
19 private moduleStack: string[] = [];
20 private extendsClass: boolean = false;
21
22 static NUM_FAKE_REST_PARAMETERS = 5;
23
24 setTypeChecker(tc: ts.TypeChecker) { this.tc = tc; }
25 setFacadeConverter(fc: FacadeConverter) { this.fc = fc; }
26
27 getJsPath(node: ts.Node): string {
28 let path = [].concat(this.moduleStack);
29 let classDecl = base.getEnclosingClass(node);
30 if (classDecl) {
31 path.push(classDecl.name.text);
32 }
33
34 switch (node.kind) {
35 case ts.SyntaxKind.ModuleDeclaration:
36 break;
37 case ts.SyntaxKind.ClassDeclaration:
38 case ts.SyntaxKind.InterfaceDeclaration:
39 path.push((<base.ClassLike>node).name.text);
40 break;
41 case ts.SyntaxKind.EnumDeclaration:
42 path.push((<ts.EnumDeclaration>node).name.text);
43 break;
44 case ts.SyntaxKind.PropertyDeclaration:
45 case ts.SyntaxKind.VariableDeclaration:
46 case ts.SyntaxKind.MethodDeclaration:
47 case ts.SyntaxKind.FunctionDeclaration:
48 case ts.SyntaxKind.GetAccessor:
49 case ts.SyntaxKind.SetAccessor:
50 case ts.SyntaxKind.PropertySignature:
51 let memberName = base.ident((<base.NamedDeclaration>node).name);
52 if (!base.isStatic(node) && classDecl != null) return memberName;
53 path.push(memberName);
54 break;
55 default:
56 throw 'Internal error. Unexpected node kind:' + node.kind;
57 }
58 if (path.length === 1) {
59 // No need to specify the path if is simply the node name.
60 return '';
61 }
62 return path.join('.');
63 }
64
65 private isAnonymousInterface(node: ts.Node): boolean {
66 if (node.kind !== ts.SyntaxKind.InterfaceDeclaration) return false;
67 // This is a bit of a hack but for the purposes of Dart codegen,
68 // interfaces with static members or constructors have a known class name
69 // at least for the purposes of resolving static members.
70 // Example case that triggers this case:
71 // interface Foo {
72 // bar();
73 // }
74 // declare let Foo: {
75 // new(): Foo,
76 // SOME_STATIC : number;
77 // }
78 return (<ts.InterfaceDeclaration>node).members.every((m: ts.Declaration) => {
79 return m.kind !== ts.SyntaxKind.Constructor && !base.isStatic(m);
80 });
81 }
82
83 maybeEmitJsAnnotation(node: ts.Node) {
84 // No need to emit the annotations as an entity outside the code comment
85 // will already have the same annotation.
86 if (this.insideCodeComment) return;
87
88 if (this.isAnonymousInterface(node)) {
89 this.emit('@anonymous');
90 this.emit('@JS()');
91 return;
92 }
93 let name: String = this.getJsPath(node);
94 this.emit('@JS(');
95 if (name.length > 0) {
96 this.emit('"' + name + '"');
97 }
98 this.emit(')');
99 }
100
101 /**
102 * Emit fake constructors to placate the Dart Analyzer for JS Interop classes.
103 */
104 maybeEmitFakeConstructors(decl: base.ClassLike) {
105 if (decl.kind === ts.SyntaxKind.ClassDeclaration) {
106 // Required to avoid spurious dart errors involving base classes without
107 // default constructors.
108 this.emit('// @Ignore\n');
109 this.fc.visitTypeName(decl.name);
110 this.emit('.fakeConstructor$()');
111 if (this.extendsClass) {
112 // Required to keep the Dart Analyzer happy when a class has subclasses.
113 this.emit(': super.fakeConstructor$()');
114 }
115 this.emit(';\n');
116 }
117 }
118
119 private visitName(name: ts.Node) {
120 if (base.getEnclosingClass(name) != null) {
121 this.visit(name);
122 return;
123 }
124 // Have to rewrite names in this case as we could have conflicts
125 // due to needing to support multiple JS modules in a single JS module
126 if (name.kind !== ts.SyntaxKind.Identifier) {
127 throw 'Internal error: unexpected function name kind:' + name.kind;
128 }
129 let entry = this.fc.lookupCustomDartTypeName(<ts.Identifier>name, this.insid eCodeComment);
130 if (entry) {
131 this.emit(entry.name);
132 return;
133 }
134
135 this.visit(name);
136 }
137
138 private notSimpleBagOfProperties(type: ts.Type): boolean {
139 if (this.tc.getSignaturesOfType(type, ts.SignatureKind.Call).length > 0) ret urn true;
140 if (this.tc.getSignaturesOfType(type, ts.SignatureKind.Construct).length > 0 ) return true;
141 if (type.symbol) {
142 let declaration = <ts.InterfaceDeclaration>type.symbol.declarations[0];
143 // We have to check the actual declaration as
144 if (declaration && declaration.members) {
145 let members = declaration.members;
146 for (let i = 0; i < members.length; ++i) {
147 let node = members[i];
148 if (base.isStatic(node)) return true;
149 switch (node.kind) {
150 case ts.SyntaxKind.PropertyDeclaration:
151 case ts.SyntaxKind.PropertySignature:
152 case ts.SyntaxKind.VariableDeclaration:
153 break;
154 default:
155 return true;
156 }
157 }
158 }
159 }
160 return false;
161 }
162
163 /**
164 * Returns whether all members of the class and all base classes
165 */
166 hasOnlyProperties(decl: ts.InterfaceDeclaration, outProperties: ts.PropertyDec laration[]):
167 boolean {
168 let type = <ts.InterfaceType>this.tc.getTypeAtLocation(decl);
169
170 let properties = this.tc.getPropertiesOfType(type);
171 let baseTypes = this.tc.getBaseTypes(type);
172 if (this.notSimpleBagOfProperties(type)) return false;
173 for (let i = 0; i < baseTypes.length; ++i) {
174 let baseType = baseTypes[i];
175 if (this.notSimpleBagOfProperties(baseType)) return false;
176 }
177
178 for (let i = 0; i < properties.length; ++i) {
179 let symbol = properties[i];
180 let node = symbol.valueDeclaration;
181 switch (node.kind) {
182 case ts.SyntaxKind.PropertyDeclaration:
183 case ts.SyntaxKind.PropertySignature:
184 case ts.SyntaxKind.VariableDeclaration:
185 let prop = <ts.PropertyDeclaration>node;
186 if (this.promoteFunctionLikeMembers && isFunctionLikeProperty(prop, th is.tc)) {
187 return false;
188 }
189 outProperties.push(prop);
190 break;
191 default:
192 return false;
193 }
194 }
195 return outProperties.length > 0;
196 }
197
198 visitClassBody(decl: base.ClassLike) {
199 let properties: ts.PropertyDeclaration[] = [];
200 let isPropertyBag = decl.kind === ts.SyntaxKind.InterfaceDeclaration &&
201 this.hasOnlyProperties(<ts.InterfaceDeclaration>decl, properties);
202 this.visitMergingOverloads(decl.members);
203
204 if (isPropertyBag) {
205 this.emit('external factory');
206 this.fc.visitTypeName(decl.name);
207 this.emitNoSpace('({');
208 for (let i = 0; i < properties.length; i++) {
209 if (i > 0) this.emitNoSpace(',');
210 let p = properties[i];
211 this.visit(p.type);
212 this.visit(p.name);
213 }
214 this.emitNoSpace('});');
215 }
216 }
217
218 visitMergingOverloads(members: Array<ts.Node>) {
219 // TODO(jacobr): merge method overloads.
220 let groups: {[name: string]: Array<ts.Node>} = {};
221 let orderedGroups: Array<Array<ts.Node>> = [];
222 members.forEach((node) => {
223 let name = '';
224 switch (node.kind) {
225 case ts.SyntaxKind.Block:
226 // For JS interop we always skip the contents of a block.
227 break;
228 case ts.SyntaxKind.PropertyDeclaration:
229 case ts.SyntaxKind.PropertySignature:
230 case ts.SyntaxKind.VariableDeclaration: {
231 let propertyDecl = <ts.PropertyDeclaration|ts.VariableDeclaration>node ;
232 // We need to emit these as properties not fields.
233 if (!this.promoteFunctionLikeMembers || !isFunctionLikeProperty(proper tyDecl, this.tc)) {
234 orderedGroups.push([node]);
235 return;
236 }
237 // Convert to a Method.
238 let type = propertyDecl.type;
239 let funcDecl = <ts.FunctionLikeDeclaration>ts.createNode(ts.SyntaxKind .MethodDeclaration);
240 funcDecl.parent = node.parent;
241 funcDecl.name = propertyDecl.name as ts.Identifier;
242 switch (type.kind) {
243 case ts.SyntaxKind.FunctionType:
244 let callSignature = <ts.SignatureDeclaration>(<ts.Node>type);
245 funcDecl.parameters = <ts.NodeArray<ts.ParameterDeclaration>>callS ignature.parameters;
246 funcDecl.type = callSignature.type;
247 // Fall through to the function case using this node
248 node = funcDecl;
249 break;
250 case ts.SyntaxKind.UnionType:
251 case ts.SyntaxKind.TypeLiteral:
252 throw 'Not supported yet';
253 default:
254 throw 'Unexpected case';
255 }
256 name = base.ident((<ts.FunctionLikeDeclaration>node).name);
257 } break;
258 case ts.SyntaxKind.FunctionDeclaration:
259 case ts.SyntaxKind.MethodDeclaration:
260 case ts.SyntaxKind.MethodSignature:
261 case ts.SyntaxKind.FunctionExpression:
262 name = base.ident((<ts.FunctionLikeDeclaration>node).name);
263 break;
264 case ts.SyntaxKind.CallSignature:
265 name = 'call';
266 break;
267 case ts.SyntaxKind.Constructor:
268 break;
269 case ts.SyntaxKind.ConstructSignature:
270 break;
271 case ts.SyntaxKind.IndexSignature:
272 name = '[]';
273 break;
274 case ts.SyntaxKind.ClassDeclaration:
275 case ts.SyntaxKind.InterfaceDeclaration:
276 case ts.SyntaxKind.VariableStatement:
277 orderedGroups.push([node]);
278 return;
279 case ts.SyntaxKind.GetAccessor:
280 case ts.SyntaxKind.SetAccessor:
281 case ts.SyntaxKind.SemicolonClassElement:
282 case ts.SyntaxKind.ModuleDeclaration:
283 case ts.SyntaxKind.TypeAliasDeclaration:
284 case ts.SyntaxKind.ExportAssignment:
285 orderedGroups.push([node]);
286 return;
287 default:
288 console.log('Warning: unexpected type... overloads: ' + node.kind + ' ' + node.getText());
289 orderedGroups.push([node]);
290 return;
291 }
292 let group: Array<ts.Node>;
293 if (Object.prototype.hasOwnProperty.call(groups, name)) {
294 group = groups[name];
295 } else {
296 group = [];
297 groups[name] = group;
298 orderedGroups.push(group);
299 }
300 group.push(node);
301 });
302
303 orderedGroups.forEach((group: Array<ts.Node>) => {
304 if (group.length === 1) {
305 this.visit(group[0]);
306 return;
307 }
308 group.forEach((fn: ts.Node) => {
309 // Emit overrides in a comment that the Dart analyzer can at some point
310 // use to improve autocomplete.
311 this.maybeLineBreak();
312 this.enterCodeComment();
313 this.visit(fn);
314 this.exitCodeComment();
315 this.maybeLineBreak();
316 });
317 // TODO: actually merge.
318 let first = <ts.SignatureDeclaration>group[0];
319 let kind = first.kind;
320 let merged = <ts.SignatureDeclaration>ts.createNode(kind);
321 merged.parent = first.parent;
322 base.copyLocation(first, merged);
323 switch (kind) {
324 case ts.SyntaxKind.FunctionDeclaration:
325 case ts.SyntaxKind.MethodDeclaration:
326 case ts.SyntaxKind.MethodSignature:
327 case ts.SyntaxKind.FunctionExpression:
328 let fn = <ts.FunctionLikeDeclaration>first;
329 merged.name = fn.name;
330 break;
331 case ts.SyntaxKind.CallSignature:
332 break;
333 case ts.SyntaxKind.Constructor:
334 break;
335 case ts.SyntaxKind.ConstructSignature:
336 break;
337 case ts.SyntaxKind.IndexSignature:
338 break;
339 default:
340 throw 'Unexpected kind:' + kind;
341 }
342 let mergedParams = first.parameters.map(
343 (param: ts.ParameterDeclaration) => new MergedParameter(param, this.fc ));
344 let mergedType = new MergedType(this.fc);
345 mergedType.merge(first.type);
346
347 for (let i = 1; i < group.length; ++i) {
348 let signature = <ts.SignatureDeclaration>group[i];
349 mergedType.merge(signature.type);
350 let overlap = Math.min(signature.parameters.length, mergedParams.length) ;
351 for (let j = 0; j < overlap; ++j) {
352 mergedParams[j].merge(signature.parameters[j]);
353 }
354 for (let j = overlap; j < mergedParams.length; ++j) {
355 mergedParams[j].setOptional();
356 }
357 for (let j = mergedParams.length; j < signature.parameters.length; ++j) {
358 let param = new MergedParameter(signature.parameters[j], this.fc);
359 param.setOptional();
360 mergedParams.push(param);
361 }
362 }
363 merged.parameters = <ts.NodeArray<ts.ParameterDeclaration>>mergedParams.ma p(
364 (p) => p.toParameterDeclaration());
365 merged.type = mergedType.toTypeNode();
366
367 this.fc.visit(merged);
368 });
369 }
370
371
7 constructor( 372 constructor(
8 tr: Transpiler, private fc: FacadeConverter, private enforceUnderscoreConv entions: boolean) { 373 tr: Transpiler, private fc: FacadeConverter, private enforceUnderscoreConv entions: boolean,
374 private promoteFunctionLikeMembers: boolean) {
9 super(tr); 375 super(tr);
10 } 376 }
11 377
12 visitNode(node: ts.Node): boolean { 378 visitNode(node: ts.Node): boolean {
13 switch (node.kind) { 379 switch (node.kind) {
14 case ts.SyntaxKind.VariableDeclarationList: 380 case ts.SyntaxKind.ModuleDeclaration:
15 // Note: VariableDeclarationList can only occur as part of a for loop. 381 let moduleDecl = <ts.ModuleDeclaration>node;
16 let varDeclList = <ts.VariableDeclarationList>node; 382 this.emit('\n// Module ' + moduleDecl.name.text + '\n');
17 this.visitList(varDeclList.declarations); 383 this.moduleStack.push(moduleDecl.name.text);
18 break; 384
19 case ts.SyntaxKind.VariableDeclaration: 385 this.visit(moduleDecl.body);
20 let varDecl = <ts.VariableDeclaration>node; 386 this.emit('\n// End module ' + moduleDecl.name.text + '\n');
21 this.visitVariableDeclarationType(varDecl); 387 this.moduleStack.pop();
22 this.visit(varDecl.name); 388 break;
23 if (varDecl.initializer) { 389 case ts.SyntaxKind.ExportKeyword:
24 this.emit('='); 390 // TODO(jacobr): perhaps add a specific Dart annotation to indicate
25 this.visit(varDecl.initializer); 391 // exported members or provide a flag to only generate code for exported
26 } 392 // members.
27 break; 393 break;
28 394 case ts.SyntaxKind.EnumDeclaration: {
29 case ts.SyntaxKind.ClassDeclaration:
30 let classDecl = <ts.ClassDeclaration>node;
31 if (classDecl.modifiers && (classDecl.modifiers.flags & ts.NodeFlags.Abs tract)) {
32 this.visitClassLike('abstract class', classDecl);
33 } else {
34 this.visitClassLike('class', classDecl);
35 }
36 break;
37 case ts.SyntaxKind.InterfaceDeclaration:
38 let ifDecl = <ts.InterfaceDeclaration>node;
39 // Function type interface in an interface with a single declaration
40 // of a call signature (http://goo.gl/ROC5jN).
41 if (ifDecl.members.length === 1 && ifDecl.members[0].kind === ts.SyntaxK ind.CallSignature) {
42 let member = <ts.CallSignatureDeclaration>ifDecl.members[0];
43 this.visitFunctionTypedefInterface(ifDecl.name.text, member, ifDecl.ty peParameters);
44 } else {
45 this.visitClassLike('abstract class', ifDecl);
46 }
47 break;
48 case ts.SyntaxKind.HeritageClause:
49 let heritageClause = <ts.HeritageClause>node;
50 if (heritageClause.token === ts.SyntaxKind.ExtendsKeyword &&
51 heritageClause.parent.kind !== ts.SyntaxKind.InterfaceDeclaration) {
52 this.emit('extends');
53 } else {
54 this.emit('implements');
55 }
56 // Can only have one member for extends clauses.
57 this.visitList(heritageClause.types);
58 break;
59 case ts.SyntaxKind.ExpressionWithTypeArguments:
60 let exprWithTypeArgs = <ts.ExpressionWithTypeArguments>node;
61 this.visit(exprWithTypeArgs.expression);
62 this.maybeVisitTypeArguments(exprWithTypeArgs);
63 break;
64 case ts.SyntaxKind.EnumDeclaration:
65 let decl = <ts.EnumDeclaration>node; 395 let decl = <ts.EnumDeclaration>node;
66 // The only legal modifier for an enum decl is const. 396 // The only legal modifier for an enum decl is const.
67 let isConst = decl.modifiers && (decl.modifiers.flags & ts.NodeFlags.Con st); 397 let isConst = decl.modifiers && (decl.modifiers.flags & ts.NodeFlags.Con st);
68 if (isConst) { 398 if (isConst) {
69 this.reportError(node, 'const enums are not supported'); 399 this.reportError(node, 'const enums are not supported');
70 } 400 }
71 this.emit('enum'); 401 // In JS interop mode we have to treat enums as JavaScript classes
72 this.fc.visitTypeName(decl.name); 402 // with static members for each enum constant instead of as first
403 // class enums.
404 this.maybeEmitJsAnnotation(decl);
405 this.emit('class');
406 this.emit(decl.name.text);
73 this.emit('{'); 407 this.emit('{');
74 // Enums can be empty in TS ... 408 let nodes = decl.members;
75 if (decl.members.length === 0) { 409 for (let i = 0; i < nodes.length; i++) {
76 // ... but not in Dart. 410 this.emit('external static num get');
77 this.reportError(node, 'empty enums are not supported'); 411 this.visit(nodes[i]);
78 } 412 this.emitNoSpace(';');
79 this.visitList(decl.members); 413 }
80 this.emit('}'); 414 this.emit('}');
81 break; 415 } break;
82 case ts.SyntaxKind.EnumMember: 416 case ts.SyntaxKind.Parameter: {
417 let paramDecl = <ts.ParameterDeclaration>node;
418 if (paramDecl.type && paramDecl.type.kind === ts.SyntaxKind.FunctionType ) {
419 // Dart uses "returnType paramName ( parameters )" syntax.
420 let fnType = <ts.FunctionOrConstructorTypeNode>paramDecl.type;
421 let hasRestParameter = fnType.parameters.some(p => !!p.dotDotDotToken) ;
422 if (!hasRestParameter) {
423 // Dart does not support rest parameters/varargs, degenerate to just "Function".
424 // TODO(jacobr): also consider faking 0 - NUM_FAKE_REST_PARAMETERS
425 // instead.
426 this.visit(fnType.type);
427 this.visit(paramDecl.name);
428 this.visitParameters(fnType.parameters);
429 break;
430 }
431 }
432
433 if (paramDecl.dotDotDotToken) {
434 // Weak support of varargs that works ok if you have 5 of fewer args.
435 let paramType: ts.TypeNode;
436 let type = paramDecl.type;
437 if (type) {
438 if (type.kind === ts.SyntaxKind.ArrayType) {
439 let arrayType = <ts.ArrayTypeNode>type;
440 paramType = arrayType.elementType;
441 } else if (type.kind !== ts.SyntaxKind.AnyKeyword) {
442 throw 'Unexpected type for varargs: ' + type.kind;
443 }
444 }
445
446 for (let i = 1; i <= DeclarationTranspiler.NUM_FAKE_REST_PARAMETERS; + +i) {
447 if (i > 1) {
448 this.emitNoSpace(',');
449 }
450 this.visit(paramType);
451 this.emit(base.ident(paramDecl.name) + i);
452 }
453 break;
454 }
455 // TODO(jacobr): should we support
456 if (paramDecl.name.kind === ts.SyntaxKind.ObjectBindingPattern) {
457 this.emit('Object');
458 let pattern = paramDecl.name as ts.BindingPattern;
459 let elements = pattern.elements;
460 let name = elements.map((e) => base.ident(e.name)).join('_');
461 // Warning: this name is unlikely to but could possible overlap with
462 // other parameter names.
463 this.emit(name);
464 this.enterCodeComment();
465 this.emit(pattern.getText());
466 this.exitCodeComment();
467 break;
468 }
469
470 if (paramDecl.name.kind !== ts.SyntaxKind.Identifier) {
471 throw 'Unsupported parameter name kind: ' + paramDecl.name.kind;
472 }
473 this.visit(paramDecl.type);
474 this.visit(paramDecl.name);
475 } break;
476 case ts.SyntaxKind.EnumMember: {
83 let member = <ts.EnumMember>node; 477 let member = <ts.EnumMember>node;
84 this.visit(member.name); 478 this.visit(member.name);
85 if (member.initializer) { 479 } break;
86 this.reportError(node, 'enum initializers are not supported'); 480 case ts.SyntaxKind.ModuleBlock: {
87 } 481 let block = <ts.ModuleBlock>node;
88 break; 482 this.visitMergingOverloads(block.statements);
483 } break;
484 case ts.SyntaxKind.VariableDeclarationList: {
485 // We have to handle variable declaration lists differently in the case
486 // of JS interop because Dart does not support external variables.
487 let varDeclList = <ts.VariableDeclarationList>node;
488 this.visitList(varDeclList.declarations, ';');
489 } break;
490 case ts.SyntaxKind.VariableDeclaration: {
491 // We have to handle variable declarations differently in the case of JS
492 // interop because Dart does not support external variables.
493 let varDecl = <ts.VariableDeclaration>node;
494 this.maybeEmitJsAnnotation(varDecl);
495 this.emit('external');
496 this.visit(varDecl.type);
497 this.emit('get');
498 this.visitName(varDecl.name);
499 if (!this.hasFlag(varDecl.parent, ts.NodeFlags.Const)) {
500 this.emitNoSpace(';');
501 this.maybeEmitJsAnnotation(varDecl);
502 this.emit('external');
503 this.emit('set');
504 this.visitName(varDecl.name);
505 this.emitNoSpace('(');
506 this.visit(varDecl.type);
507 this.emit('v)');
508 }
509 } break;
510 case ts.SyntaxKind.StringLiteral: {
511 this.emit('String');
512 this.enterCodeComment();
513 let sLit = <ts.LiteralExpression>node;
514 let text = JSON.stringify(sLit.text);
515 this.emit(text);
516 this.exitCodeComment();
517 } break;
518 case ts.SyntaxKind.CallSignature: {
519 let fn = <ts.SignatureDeclaration>node;
520 this.emit('external');
521 this.visit(fn.type);
522 this.emit('call');
523 this.visitParameters(fn.parameters);
524 this.emitNoSpace(';');
525 } break;
526 case ts.SyntaxKind.IndexSignature:
527 this.emit('/* Index signature is not yet supported by JavaScript interop . */\n');
528 break;
529 case ts.SyntaxKind.ExportAssignment:
530 // let exportAssignment = <ts.ExportAssignment>node;
531 this.emit('/* WARNING: export assignment not yet supported. */\n');
532 break;
533 case ts.SyntaxKind.TypeAliasDeclaration:
534 // Dart does not provide special syntax for definning type alais
535 // declarations so we do not emit anything here and resolve alaises
536 // to their original types at each usage site.
537 break;
538 case ts.SyntaxKind.ClassDeclaration:
539 case ts.SyntaxKind.InterfaceDeclaration: {
540 this.extendsClass = false;
541 let classDecl = <ts.ClassDeclaration|ts.InterfaceDeclaration>node;
542 let isInterface = node.kind === ts.SyntaxKind.InterfaceDeclaration;
543 if (isInterface &&
544 base.isFunctionTypedefLikeInterface(classDecl as ts.InterfaceDeclara tion)) {
545 let member = <ts.CallSignatureDeclaration>classDecl.members[0];
546 this.visitFunctionTypedefInterface(classDecl.name.text, member, classD ecl.typeParameters);
547 break;
548 }
549
550 let customName = this.fc.lookupCustomDartTypeName(classDecl.name, this.i nsideCodeComment);
551 if (customName && !customName.keep) {
552 this.emit('\n/* Skipping class ' + base.ident(classDecl.name) + '*/\n' );
553 break;
554 }
555 this.maybeEmitJsAnnotation(node);
556
557 if (isInterface ||
558 (classDecl.modifiers && (classDecl.modifiers.flags & ts.NodeFlags.Ab stract))) {
559 this.visitClassLike('abstract class', classDecl);
560 } else {
561 this.visitClassLike('class', classDecl);
562 }
563 } break;
564 case ts.SyntaxKind.HeritageClause: {
565 let heritageClause = <ts.HeritageClause>node;
566 if (base.isExtendsClause(<ts.HeritageClause>heritageClause)) {
567 this.extendsClass = true;
568 }
569
570 if (base.isExtendsClause(heritageClause)) {
571 this.emit('extends');
572 } else {
573 this.emit('implements');
574 }
575 // Can only have one member for extends clauses.
576 this.visitList(heritageClause.types);
577 } break;
578 case ts.SyntaxKind.ExpressionWithTypeArguments: {
579 let exprWithTypeArgs = <ts.ExpressionWithTypeArguments>node;
580 this.visit(exprWithTypeArgs.expression);
581 this.maybeVisitTypeArguments(exprWithTypeArgs);
582 } break;
89 case ts.SyntaxKind.Constructor: 583 case ts.SyntaxKind.Constructor:
584 case ts.SyntaxKind.ConstructSignature: {
90 let ctorDecl = <ts.ConstructorDeclaration>node; 585 let ctorDecl = <ts.ConstructorDeclaration>node;
91 // Find containing class name. 586 // Find containing class name.
92 let className: ts.Identifier; 587 let classDecl = base.getEnclosingClass(ctorDecl);
93 for (let parent = ctorDecl.parent; parent; parent = parent.parent) { 588 if (!classDecl) this.reportError(ctorDecl, 'cannot find outer class node ');
94 if (parent.kind === ts.SyntaxKind.ClassDeclaration) {
95 className = (<ts.ClassDeclaration>parent).name;
96 break;
97 }
98 }
99 if (!className) this.reportError(ctorDecl, 'cannot find outer class node ');
100 this.visitDeclarationMetadata(ctorDecl); 589 this.visitDeclarationMetadata(ctorDecl);
101 if (this.isConst(<base.ClassLike>ctorDecl.parent)) { 590 this.fc.visitTypeName(classDecl.name);
102 this.emit('const');
103 }
104 this.visit(className);
105 this.visitParameters(ctorDecl.parameters); 591 this.visitParameters(ctorDecl.parameters);
106 this.visit(ctorDecl.body); 592 this.emitNoSpace(';');
107 break; 593 } break;
108 case ts.SyntaxKind.PropertyDeclaration: 594 case ts.SyntaxKind.PropertyDeclaration:
109 this.visitProperty(<ts.PropertyDeclaration>node); 595 this.visitProperty(<ts.PropertyDeclaration>node);
110 break; 596 break;
111 case ts.SyntaxKind.SemicolonClassElement: 597 case ts.SyntaxKind.SemicolonClassElement:
112 // No-op, don't emit useless declarations. 598 // No-op, don't emit useless declarations.
113 break; 599 break;
114 case ts.SyntaxKind.MethodDeclaration: 600 case ts.SyntaxKind.MethodDeclaration:
115 this.visitDeclarationMetadata(<ts.MethodDeclaration>node); 601 this.visitDeclarationMetadata(<ts.MethodDeclaration>node);
116 this.visitFunctionLike(<ts.MethodDeclaration>node); 602 this.visitFunctionLike(<ts.MethodDeclaration>node);
117 break; 603 break;
118 case ts.SyntaxKind.GetAccessor: 604 case ts.SyntaxKind.GetAccessor:
119 this.visitDeclarationMetadata(<ts.MethodDeclaration>node); 605 this.visitDeclarationMetadata(<ts.MethodDeclaration>node);
120 this.visitFunctionLike(<ts.AccessorDeclaration>node, 'get'); 606 this.visitFunctionLike(<ts.AccessorDeclaration>node, 'get');
121 break; 607 break;
122 case ts.SyntaxKind.SetAccessor: 608 case ts.SyntaxKind.SetAccessor:
123 this.visitDeclarationMetadata(<ts.MethodDeclaration>node); 609 this.visitDeclarationMetadata(<ts.MethodDeclaration>node);
124 this.visitFunctionLike(<ts.AccessorDeclaration>node, 'set'); 610 this.visitFunctionLike(<ts.AccessorDeclaration>node, 'set');
125 break; 611 break;
126 case ts.SyntaxKind.FunctionDeclaration: 612 case ts.SyntaxKind.FunctionDeclaration:
127 let funcDecl = <ts.FunctionDeclaration>node; 613 let funcDecl = <ts.FunctionDeclaration>node;
128 this.visitDecorators(funcDecl.decorators); 614 this.visitDeclarationMetadata(funcDecl);
129 this.visitFunctionLike(funcDecl); 615 this.visitFunctionLike(funcDecl);
130 break; 616 break;
131 case ts.SyntaxKind.ArrowFunction:
132 let arrowFunc = <ts.FunctionExpression>node;
133 // Dart only allows expressions following the fat arrow operator.
134 // If the body is a block, we have to drop the fat arrow and emit an
135 // anonymous function instead.
136 if (arrowFunc.body.kind === ts.SyntaxKind.Block) {
137 this.visitFunctionLike(arrowFunc);
138 } else {
139 this.visitParameters(arrowFunc.parameters);
140 this.emit('=>');
141 this.visit(arrowFunc.body);
142 }
143 break;
144 case ts.SyntaxKind.FunctionExpression: 617 case ts.SyntaxKind.FunctionExpression:
145 let funcExpr = <ts.FunctionExpression>node; 618 let funcExpr = <ts.FunctionExpression>node;
146 this.visitFunctionLike(funcExpr); 619 this.visitFunctionLike(funcExpr);
147 break; 620 break;
148 case ts.SyntaxKind.PropertySignature: 621 case ts.SyntaxKind.PropertySignature:
149 let propSig = <ts.PropertyDeclaration>node; 622 let propSig = <ts.PropertyDeclaration>node;
150 this.visitProperty(propSig); 623 this.visitProperty(propSig);
151 break; 624 break;
152 case ts.SyntaxKind.MethodSignature: 625 case ts.SyntaxKind.MethodSignature:
153 let methodSignatureDecl = <ts.FunctionLikeDeclaration>node; 626 let methodSignatureDecl = <ts.FunctionLikeDeclaration>node;
154 this.visitEachIfPresent(methodSignatureDecl.modifiers); 627 this.visitDeclarationMetadata(methodSignatureDecl);
155 this.visitFunctionLike(methodSignatureDecl); 628 this.visitFunctionLike(methodSignatureDecl);
156 break; 629 break;
157 case ts.SyntaxKind.Parameter:
158 let paramDecl = <ts.ParameterDeclaration>node;
159 // Property parameters will have an explicit property declaration, so we just
160 // need the dart assignment shorthand to reference the property.
161 if (this.hasFlag(paramDecl.modifiers, ts.NodeFlags.Public) ||
162 this.hasFlag(paramDecl.modifiers, ts.NodeFlags.Private) ||
163 this.hasFlag(paramDecl.modifiers, ts.NodeFlags.Protected)) {
164 this.visitDeclarationMetadata(paramDecl);
165 this.emit('this .');
166 this.visit(paramDecl.name);
167 if (paramDecl.initializer) {
168 this.emit('=');
169 this.visit(paramDecl.initializer);
170 }
171 break;
172 }
173 if (paramDecl.dotDotDotToken) this.reportError(node, 'rest parameters ar e unsupported');
174 if (paramDecl.name.kind === ts.SyntaxKind.ObjectBindingPattern) {
175 this.visitNamedParameter(paramDecl);
176 break;
177 }
178 this.visitDecorators(paramDecl.decorators);
179
180 if (paramDecl.type && paramDecl.type.kind === ts.SyntaxKind.FunctionType ) {
181 // Dart uses "returnType paramName ( parameters )" syntax.
182 let fnType = <ts.FunctionOrConstructorTypeNode>paramDecl.type;
183 let hasRestParameter = fnType.parameters.some(p => !!p.dotDotDotToken) ;
184 if (hasRestParameter) {
185 // Dart does not support rest parameters/varargs, degenerate to just "Function".
186 this.emit('Function');
187 this.visit(paramDecl.name);
188 } else {
189 this.visit(fnType.type);
190 this.visit(paramDecl.name);
191 this.visitParameters(fnType.parameters);
192 }
193 } else {
194 if (paramDecl.type) this.visit(paramDecl.type);
195 this.visit(paramDecl.name);
196 }
197 if (paramDecl.initializer) {
198 this.emit('=');
199 this.visit(paramDecl.initializer);
200 }
201 break;
202 case ts.SyntaxKind.StaticKeyword: 630 case ts.SyntaxKind.StaticKeyword:
203 this.emit('static'); 631 // n-op, handled in `visitFunctionLike` and `visitProperty` below.
204 break; 632 break;
205 case ts.SyntaxKind.AbstractKeyword: 633 case ts.SyntaxKind.AbstractKeyword:
206 // Abstract methods in Dart simply lack implementation, 634 // Abstract methods in Dart simply lack implementation,
207 // and don't use the 'abstract' modifier 635 // and don't use the 'abstract' modifier
208 // Abstract classes are handled in `case ts.SyntaxKind.ClassDeclaration` above. 636 // Abstract classes are handled in `case ts.SyntaxKind.ClassDeclaration` above.
209 break; 637 break;
210 case ts.SyntaxKind.PrivateKeyword: 638 case ts.SyntaxKind.PrivateKeyword:
211 // no-op, handled through '_' naming convention in Dart. 639 // no-op, handled through '_' naming convention in Dart.
212 break; 640 break;
213 case ts.SyntaxKind.PublicKeyword: 641 case ts.SyntaxKind.PublicKeyword:
214 // Handled in `visitDeclarationMetadata` below. 642 // Handled in `visitDeclarationMetadata` below.
215 break; 643 break;
216 case ts.SyntaxKind.ProtectedKeyword: 644 case ts.SyntaxKind.ProtectedKeyword:
217 // Handled in `visitDeclarationMetadata` below. 645 // Handled in `visitDeclarationMetadata` below.
218 break; 646 break;
219 647 case ts.SyntaxKind.VariableStatement:
648 let variableStmt = <ts.VariableStatement>node;
649 this.visit(variableStmt.declarationList);
650 this.emitNoSpace(';');
651 break;
652 case ts.SyntaxKind.SwitchStatement:
653 case ts.SyntaxKind.ArrayLiteralExpression:
654 case ts.SyntaxKind.ExpressionStatement:
655 case ts.SyntaxKind.EmptyStatement:
656 // No need to emit anything for these cases.
657 break;
220 default: 658 default:
221 return false; 659 return false;
222 } 660 }
223 return true; 661 return true;
224 } 662 }
225 663
226 private visitVariableDeclarationType(varDecl: ts.VariableDeclaration) {
227 /* Note: VariableDeclarationList can only occur as part of a for loop. This helper method
228 * is meant for processing for-loop variable declaration types only.
229 *
230 * In Dart, all variables in a variable declaration list must have the same type. Since
231 * we are doing syntax directed translation, we cannot reliably determine if distinct
232 * variables are declared with the same type or not. Hence we support the fo llowing cases:
233 *
234 * - A variable declaration list with a single variable can be explicitly ty ped.
235 * - When more than one variable is in the list, all must be implicitly type d.
236 */
237 let firstDecl = varDecl.parent.declarations[0];
238 let msg = 'Variables in a declaration list of more than one variable cannot by typed';
239 let isFinal = this.hasFlag(varDecl.parent, ts.NodeFlags.Const);
240 let isConst = false;
241 if (isFinal && varDecl.initializer) {
242 // "const" in TypeScript/ES6 corresponds to "final" in Dart, i.e. referenc e constness.
243 // If a "const" variable is immediately initialized to a CONST_EXPR(), spe cial case it to be
244 // a deeply const constant, and generate "const ...".
245 isConst = varDecl.initializer.kind === ts.SyntaxKind.StringLiteral ||
246 varDecl.initializer.kind === ts.SyntaxKind.NumericLiteral ||
247 this.fc.isConstCall(varDecl.initializer);
248 }
249 if (firstDecl === varDecl) {
250 if (isConst) {
251 this.emit('const');
252 } else if (isFinal) {
253 this.emit('final');
254 }
255 if (!varDecl.type) {
256 if (!isFinal) this.emit('var');
257 } else if (varDecl.parent.declarations.length > 1) {
258 this.reportError(varDecl, msg);
259 } else {
260 this.visit(varDecl.type);
261 }
262 } else if (varDecl.type) {
263 this.reportError(varDecl, msg);
264 }
265 }
266
267 private visitFunctionLike(fn: ts.FunctionLikeDeclaration, accessor?: string) { 664 private visitFunctionLike(fn: ts.FunctionLikeDeclaration, accessor?: string) {
268 this.fc.pushTypeParameterNames(fn); 665 this.fc.pushTypeParameterNames(fn);
666 if (base.isStatic(fn)) {
667 this.emit('static');
668 }
669
269 try { 670 try {
270 if (fn.type) { 671 this.visit(fn.type);
271 if (fn.kind === ts.SyntaxKind.ArrowFunction || 672 if (accessor) this.emit(accessor);
272 fn.kind === ts.SyntaxKind.FunctionExpression) { 673 let name = fn.name;
273 // The return type is silently dropped for function expressions (inclu ding arrow 674 if (name) {
274 // functions), it is not supported in Dart. 675 if (name.kind !== ts.SyntaxKind.Identifier) {
275 this.emit('/*'); 676 this.reportError(name, 'Unexpected name kind:' + name.kind);
276 this.visit(fn.type);
277 this.emit('*/');
278 } else {
279 this.visit(fn.type);
280 } 677 }
678 this.fc.visitTypeName(<ts.Identifier>name);
281 } 679 }
282 if (accessor) this.emit(accessor); 680
283 if (fn.name) this.visit(fn.name);
284 if (fn.typeParameters) { 681 if (fn.typeParameters) {
285 this.emit('/*<'); 682 let insideComment = this.insideCodeComment;
683 if (!insideComment) {
684 this.enterCodeComment();
685 }
686 this.emitNoSpace('<');
286 // Emit the names literally instead of visiting, otherwise they will be replaced with the 687 // Emit the names literally instead of visiting, otherwise they will be replaced with the
287 // comment hack themselves. 688 // comment hack themselves.
288 this.emit(fn.typeParameters.map(p => base.ident(p.name)).join(', ')); 689 // TODO(jacobr): we can use the regular type parameter visiting pattern
289 this.emit('>*/'); 690 // now that we properly track whether we are inside a comment.
691 this.emitNoSpace(fn.typeParameters.map(p => base.ident(p.name)).join(', '));
692 this.emitNoSpace('>');
693 if (!insideComment) {
694 this.exitCodeComment();
695 }
290 } 696 }
291 // Dart does not even allow the parens of an empty param list on getter 697 // Dart does not even allow the parens of an empty param list on getter
292 if (accessor !== 'get') { 698 if (accessor !== 'get') {
293 this.visitParameters(fn.parameters); 699 this.visitParameters(fn.parameters);
294 } else { 700 } else {
295 if (fn.parameters && fn.parameters.length > 0) { 701 if (fn.parameters && fn.parameters.length > 0) {
296 this.reportError(fn, 'getter should not accept parameters'); 702 this.reportError(fn, 'getter should not accept parameters');
297 } 703 }
298 } 704 }
299 if (fn.body) { 705 this.emitNoSpace(';');
300 this.visit(fn.body);
301 } else {
302 this.emit(';');
303 }
304 } finally { 706 } finally {
305 this.fc.popTypeParameterNames(fn); 707 this.fc.popTypeParameterNames(fn);
306 } 708 }
307 } 709 }
308 710
309 private visitParameters(parameters: ts.ParameterDeclaration[]) {
310 this.emit('(');
311 let firstInitParamIdx = 0;
312 for (; firstInitParamIdx < parameters.length; firstInitParamIdx++) {
313 // ObjectBindingPatterns are handled within the parameter visit.
314 let isOpt =
315 parameters[firstInitParamIdx].initializer || parameters[firstInitParam Idx].questionToken;
316 if (isOpt && parameters[firstInitParamIdx].name.kind !== ts.SyntaxKind.Obj ectBindingPattern) {
317 break;
318 }
319 }
320
321 if (firstInitParamIdx !== 0) {
322 let requiredParams = parameters.slice(0, firstInitParamIdx);
323 this.visitList(requiredParams);
324 }
325
326 if (firstInitParamIdx !== parameters.length) {
327 if (firstInitParamIdx !== 0) this.emit(',');
328 let positionalOptional = parameters.slice(firstInitParamIdx, parameters.le ngth);
329 this.emit('[');
330 this.visitList(positionalOptional);
331 this.emit(']');
332 }
333
334 this.emit(')');
335 }
336
337 /** 711 /**
338 * Visit a property declaration. 712 * Visit a property declaration.
713 * In the special case of property parameters in a constructor, we also allow
714 * a parameter to be emitted as a property.
715 * We have to emit properties as getter setter pairs as Dart does not support
716 * external fields.
339 * In the special case of property parameters in a constructor, we also allow a parameter to be 717 * In the special case of property parameters in a constructor, we also allow a parameter to be
340 * emitted as a property. 718 * emitted as a property.
341 */ 719 */
342 private visitProperty(decl: ts.PropertyDeclaration|ts.ParameterDeclaration, is Parameter = false) { 720 private visitProperty(decl: ts.PropertyDeclaration|ts.ParameterDeclaration, is Parameter = false) {
343 if (!isParameter) this.visitDeclarationMetadata(decl); 721 let isStatic = base.isStatic(decl);
344 let containingClass = <base.ClassLike>(isParameter ? decl.parent.parent : de cl.parent); 722 this.emit('external');
345 let isConstField = this.hasAnnotation(decl.decorators, 'CONST'); 723 if (isStatic) this.emit('static');
346 let hasConstCtor = this.isConst(containingClass); 724 this.visit(decl.type);
347 if (isConstField) { 725 this.emit('get');
348 // const implies final 726 this.visitName(decl.name);
349 this.emit('const'); 727 this.emitNoSpace(';');
350 } else { 728
351 if (hasConstCtor) { 729 this.emit('external');
352 this.emit('final'); 730 if (isStatic) this.emit('static');
353 } 731 this.emit('set');
354 } 732 this.visitName(decl.name);
355 if (decl.type) { 733 this.emitNoSpace('(');
356 this.visit(decl.type); 734 this.visit(decl.type);
357 } else if (!isConstField && !hasConstCtor) { 735 this.emit('v');
358 this.emit('var'); 736 this.emitNoSpace(')');
359 } 737 this.emitNoSpace(';');
360 this.visit(decl.name);
361 if (decl.initializer && !isParameter) {
362 this.emit('=');
363 this.visit(decl.initializer);
364 }
365 this.emit(';');
366 } 738 }
367 739
368 private visitClassLike(keyword: string, decl: base.ClassLike) { 740 private visitClassLike(keyword: string, decl: base.ClassLike) {
369 this.visitDecorators(decl.decorators);
370 this.emit(keyword); 741 this.emit(keyword);
371 this.fc.visitTypeName(decl.name); 742 this.fc.visitTypeName(decl.name);
372 if (decl.typeParameters) { 743 if (decl.typeParameters) {
373 this.emit('<'); 744 this.emit('<');
374 this.visitList(decl.typeParameters); 745 this.visitList(decl.typeParameters);
375 this.emit('>'); 746 this.emit('>');
376 } 747 }
748
377 this.visitEachIfPresent(decl.heritageClauses); 749 this.visitEachIfPresent(decl.heritageClauses);
378 this.emit('{'); 750 this.emit('{');
379 751
752 this.maybeEmitFakeConstructors(decl);
753
380 // Synthesize explicit properties for ctor with 'property parameters' 754 // Synthesize explicit properties for ctor with 'property parameters'
381 let synthesizePropertyParam = (param: ts.ParameterDeclaration) => { 755 let synthesizePropertyParam = (param: ts.ParameterDeclaration) => {
382 if (this.hasFlag(param.modifiers, ts.NodeFlags.Public) || 756 if (this.hasFlag(param.modifiers, ts.NodeFlags.Public) ||
383 this.hasFlag(param.modifiers, ts.NodeFlags.Private) || 757 this.hasFlag(param.modifiers, ts.NodeFlags.Private) ||
384 this.hasFlag(param.modifiers, ts.NodeFlags.Protected)) { 758 this.hasFlag(param.modifiers, ts.NodeFlags.Protected)) {
385 // TODO: we should enforce the underscore prefix on privates 759 // TODO: we should enforce the underscore prefix on privates
386 this.visitProperty(param, true); 760 this.visitProperty(param, true);
387 } 761 }
388 }; 762 };
389 (<ts.NodeArray<ts.Declaration>>decl.members) 763 (decl.members as ts.NodeArray<ts.Declaration>)
390 .filter((m) => m.kind === ts.SyntaxKind.Constructor) 764 .filter(base.isConstructor)
391 .forEach( 765 .forEach(
392 (ctor) => 766 (ctor) =>
393 (<ts.ConstructorDeclaration>ctor).parameters.forEach(synthesizeP ropertyParam)); 767 (<ts.ConstructorDeclaration>ctor).parameters.forEach(synthesizeP ropertyParam));
394 this.visitEachIfPresent(decl.members);
395 768
396 // Generate a constructor to host the const modifier, if needed 769 this.visitClassBody(decl);
397 if (this.isConst(decl) &&
398 !(<ts.NodeArray<ts.Declaration>>decl.members)
399 .some((m) => m.kind === ts.SyntaxKind.Constructor)) {
400 this.emit('const');
401 this.fc.visitTypeName(decl.name);
402 this.emit('();');
403 }
404 this.emit('}'); 770 this.emit('}');
405 } 771 }
406 772
407 private visitDecorators(decorators: ts.NodeArray<ts.Decorator>) {
408 if (!decorators) return;
409
410 decorators.forEach((d) => {
411 // Special case @CONST
412 let name = base.ident(d.expression);
413 if (!name && d.expression.kind === ts.SyntaxKind.CallExpression) {
414 // Unwrap @CONST()
415 let callExpr = (<ts.CallExpression>d.expression);
416 name = base.ident(callExpr.expression);
417 }
418 // Make sure these match IGNORED_ANNOTATIONS below.
419 if (name === 'CONST') {
420 // Ignore @CONST - it is handled above in visitClassLike.
421 return;
422 }
423 this.emit('@');
424 this.visit(d.expression);
425 });
426 }
427
428 private visitDeclarationMetadata(decl: ts.Declaration) { 773 private visitDeclarationMetadata(decl: ts.Declaration) {
429 this.visitDecorators(decl.decorators);
430 this.visitEachIfPresent(decl.modifiers); 774 this.visitEachIfPresent(decl.modifiers);
431 775
432 if (this.hasFlag(decl.modifiers, ts.NodeFlags.Protected)) { 776 switch (decl.kind) {
433 this.reportError(decl, 'protected declarations are unsupported'); 777 case ts.SyntaxKind.Constructor:
434 return; 778 case ts.SyntaxKind.ConstructSignature:
435 } 779 this.emit('external factory');
436 if (!this.enforceUnderscoreConventions) return; 780 break;
437 // Early return in case this is a decl with no name, such as a constructor 781 case ts.SyntaxKind.ArrowFunction:
438 if (!decl.name) return; 782 case ts.SyntaxKind.CallSignature:
439 let name = base.ident(decl.name); 783 case ts.SyntaxKind.MethodDeclaration:
440 if (!name) return; 784 case ts.SyntaxKind.SetAccessor:
441 let isPrivate = this.hasFlag(decl.modifiers, ts.NodeFlags.Private); 785 case ts.SyntaxKind.GetAccessor:
442 let matchesPrivate = !!name.match(/^_/); 786 case ts.SyntaxKind.MethodSignature:
443 if (isPrivate && !matchesPrivate) { 787 case ts.SyntaxKind.PropertySignature:
444 this.reportError(decl, 'private members must be prefixed with "_"'); 788 case ts.SyntaxKind.FunctionDeclaration:
445 } 789 if (!base.getEnclosingClass(decl)) {
446 if (!isPrivate && matchesPrivate) { 790 this.maybeEmitJsAnnotation(decl);
447 this.reportError(decl, 'public members must not be prefixed with "_"'); 791 }
792 this.emit('external');
793 break;
794 default:
795 throw 'Unexpected declaration kind:' + decl.kind;
448 } 796 }
449 } 797 }
450 798
451 private visitNamedParameter(paramDecl: ts.ParameterDeclaration) {
452 this.visitDecorators(paramDecl.decorators);
453 let bp = <ts.BindingPattern>paramDecl.name;
454 let propertyTypes = this.fc.resolvePropertyTypes(paramDecl.type);
455 let initMap = this.getInitializers(paramDecl);
456 this.emit('{');
457 for (let i = 0; i < bp.elements.length; i++) {
458 let elem = bp.elements[i];
459 let propDecl = propertyTypes[base.ident(elem.name)];
460 if (propDecl && propDecl.type) this.visit(propDecl.type);
461 this.visit(elem.name);
462 if (elem.initializer && initMap[base.ident(elem.name)]) {
463 this.reportError(elem, 'cannot have both an inner and outer initializer' );
464 }
465 let init = elem.initializer || initMap[base.ident(elem.name)];
466 if (init) {
467 this.emit(':');
468 this.visit(init);
469 }
470 if (i + 1 < bp.elements.length) this.emit(',');
471 }
472 this.emit('}');
473 }
474
475 private getInitializers(paramDecl: ts.ParameterDeclaration) {
476 let res: ts.Map<ts.Expression> = {};
477 if (!paramDecl.initializer) return res;
478 if (paramDecl.initializer.kind !== ts.SyntaxKind.ObjectLiteralExpression) {
479 this.reportError(paramDecl, 'initializers for named parameters must be obj ect literals');
480 return res;
481 }
482 for (let i of (<ts.ObjectLiteralExpression>paramDecl.initializer).properties ) {
483 if (i.kind !== ts.SyntaxKind.PropertyAssignment) {
484 this.reportError(i, 'named parameter initializers must be properties, go t ' + i.kind);
485 continue;
486 }
487 let ole = <ts.PropertyAssignment>i;
488 res[base.ident(ole.name)] = ole.initializer;
489 }
490 return res;
491 }
492
493 /** 799 /**
494 * Handles a function typedef-like interface, i.e. an interface that only decl ares a single 800 * Handles a function typedef-like interface, i.e. an interface that only decl ares a single
495 * call signature, by translating to a Dart `typedef`. 801 * call signature, by translating to a Dart `typedef`.
496 */ 802 */
497 private visitFunctionTypedefInterface( 803 private visitFunctionTypedefInterface(
498 name: string, signature: ts.CallSignatureDeclaration, 804 name: string, signature: ts.CallSignatureDeclaration,
499 typeParameters: ts.NodeArray<ts.TypeParameterDeclaration>) { 805 typeParameters: ts.NodeArray<ts.TypeParameterDeclaration>) {
500 this.emit('typedef'); 806 this.emit('typedef');
501 if (signature.type) { 807 if (signature.type) {
502 this.visit(signature.type); 808 this.visit(signature.type);
503 } 809 }
504 this.emit(name); 810 this.emit(name);
505 if (typeParameters) { 811 if (typeParameters) {
506 this.emit('<'); 812 this.emitNoSpace('<');
507 this.visitList(typeParameters); 813 this.visitList(typeParameters);
508 this.emit('>'); 814 this.emitNoSpace('>');
509 } 815 }
510 this.visitParameters(signature.parameters); 816 this.visitParameters(signature.parameters);
511 this.emit(';'); 817 this.emitNoSpace(';');
512 } 818 }
513 } 819 }
OLDNEW
« no previous file with comments | « lib/dart_libraries_for_browser_types.ts ('k') | lib/expression.ts » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698