| OLD | NEW |
| (Empty) |
| 1 import * as ts from 'typescript'; | |
| 2 import * as base from './base'; | |
| 3 import {Transpiler} from './main'; | |
| 4 import {FacadeConverter} from './facade_converter'; | |
| 5 | |
| 6 export default class LiteralTranspiler extends base.TranspilerBase { | |
| 7 constructor(tr: Transpiler, private fc: FacadeConverter) { super(tr); } | |
| 8 | |
| 9 visitNode(node: ts.Node): boolean { | |
| 10 switch (node.kind) { | |
| 11 // Literals. | |
| 12 case ts.SyntaxKind.NumericLiteral: | |
| 13 let nLit = <ts.LiteralExpression>node; | |
| 14 this.emit(nLit.getText()); | |
| 15 break; | |
| 16 case ts.SyntaxKind.StringLiteral: | |
| 17 let sLit = <ts.LiteralExpression>node; | |
| 18 let text = JSON.stringify(sLit.text); | |
| 19 // Escape dollar sign since dart will interpolate in double quoted liter
al | |
| 20 text = text.replace(/\$/, '\\$'); | |
| 21 this.emit(text); | |
| 22 break; | |
| 23 case ts.SyntaxKind.NoSubstitutionTemplateLiteral: | |
| 24 this.emit(`'''${this.escapeTextForTemplateString(node)}'''`); | |
| 25 break; | |
| 26 case ts.SyntaxKind.TemplateMiddle: | |
| 27 this.emitNoSpace(this.escapeTextForTemplateString(node)); | |
| 28 break; | |
| 29 case ts.SyntaxKind.TemplateExpression: | |
| 30 let tmpl = <ts.TemplateExpression>node; | |
| 31 if (tmpl.head) this.visit(tmpl.head); | |
| 32 if (tmpl.templateSpans) this.visitEach(tmpl.templateSpans); | |
| 33 break; | |
| 34 case ts.SyntaxKind.TemplateHead: | |
| 35 this.emit(`'''${this.escapeTextForTemplateString(node)}`); // highlight
ing bug:' | |
| 36 break; | |
| 37 case ts.SyntaxKind.TemplateTail: | |
| 38 this.emitNoSpace(this.escapeTextForTemplateString(node)); | |
| 39 this.emitNoSpace(`'''`); | |
| 40 break; | |
| 41 case ts.SyntaxKind.TemplateSpan: | |
| 42 let span = <ts.TemplateSpan>node; | |
| 43 if (span.expression) { | |
| 44 // Do not emit extra whitespace inside the string template | |
| 45 this.emitNoSpace('${'); | |
| 46 this.visit(span.expression); | |
| 47 this.emitNoSpace('}'); | |
| 48 } | |
| 49 if (span.literal) this.visit(span.literal); | |
| 50 break; | |
| 51 case ts.SyntaxKind.ArrayLiteralExpression: | |
| 52 if (this.shouldBeConst(node)) this.emit('const'); | |
| 53 let ale = <ts.ArrayLiteralExpression>node; | |
| 54 this.handleReifiedArray(ale); | |
| 55 this.emit('['); | |
| 56 this.visitList(ale.elements); | |
| 57 this.emit(']'); | |
| 58 break; | |
| 59 case ts.SyntaxKind.ObjectLiteralExpression: | |
| 60 if (this.shouldBeConst(node)) this.emit('const'); | |
| 61 let ole = <ts.ObjectLiteralExpression>node; | |
| 62 this.handleReifiedMap(ole); | |
| 63 this.emit('{'); | |
| 64 this.visitList(ole.properties); | |
| 65 this.emit('}'); | |
| 66 break; | |
| 67 case ts.SyntaxKind.PropertyAssignment: | |
| 68 let propAssign = <ts.PropertyAssignment>node; | |
| 69 if (propAssign.name.kind === ts.SyntaxKind.Identifier) { | |
| 70 // Dart identifiers in Map literals need quoting. | |
| 71 this.emitNoSpace(' "'); | |
| 72 this.emitNoSpace((<ts.Identifier>propAssign.name).text); | |
| 73 this.emitNoSpace('"'); | |
| 74 } else { | |
| 75 this.visit(propAssign.name); | |
| 76 } | |
| 77 this.emit(':'); | |
| 78 this.visit(propAssign.initializer); | |
| 79 break; | |
| 80 case ts.SyntaxKind.ShorthandPropertyAssignment: | |
| 81 let shorthand = <ts.ShorthandPropertyAssignment>node; | |
| 82 this.emitNoSpace(' "'); | |
| 83 this.emitNoSpace(shorthand.name.text); | |
| 84 this.emitNoSpace('"'); | |
| 85 this.emit(':'); | |
| 86 this.visit(shorthand.name); | |
| 87 break; | |
| 88 | |
| 89 case ts.SyntaxKind.TrueKeyword: | |
| 90 this.emit('true'); | |
| 91 break; | |
| 92 case ts.SyntaxKind.FalseKeyword: | |
| 93 this.emit('false'); | |
| 94 break; | |
| 95 case ts.SyntaxKind.NullKeyword: | |
| 96 this.emit('null'); | |
| 97 break; | |
| 98 case ts.SyntaxKind.RegularExpressionLiteral: | |
| 99 this.emit('new RegExp ('); | |
| 100 this.emit('r\''); | |
| 101 let regExp = (<ts.LiteralExpression>node).text; | |
| 102 let slashIdx = regExp.lastIndexOf('/'); | |
| 103 let flags = regExp.substring(slashIdx + 1); | |
| 104 regExp = regExp.substring(1, slashIdx); // cut off /.../ char
s. | |
| 105 regExp = regExp.replace(/'/g, '\' + "\'" + r\''); // handle nested quot
es by concatenation. | |
| 106 this.emitNoSpace(regExp); | |
| 107 this.emitNoSpace('\''); | |
| 108 if (flags.indexOf('g') === -1) { | |
| 109 // Dart RegExps are always global, so JS regexps must use 'g' so that
semantics match. | |
| 110 this.reportError(node, 'Regular Expressions must use the //g flag'); | |
| 111 } | |
| 112 if (flags.indexOf('m') !== -1) { | |
| 113 this.emit(', multiLine: true'); | |
| 114 } | |
| 115 if (flags.indexOf('i') !== -1) { | |
| 116 this.emit(', caseSensitive: false'); | |
| 117 } | |
| 118 this.emit(')'); | |
| 119 break; | |
| 120 case ts.SyntaxKind.ThisKeyword: | |
| 121 this.emit('this'); | |
| 122 break; | |
| 123 | |
| 124 default: | |
| 125 return false; | |
| 126 } | |
| 127 return true; | |
| 128 } | |
| 129 | |
| 130 private shouldBeConst(n: ts.Node): boolean { | |
| 131 return this.hasAncestor(n, ts.SyntaxKind.Decorator) || this.fc.isInsideConst
Expr(n); | |
| 132 } | |
| 133 | |
| 134 private escapeTextForTemplateString(n: ts.Node): string { | |
| 135 return (<ts.StringLiteral>n).text.replace(/\\/g, '\\\\').replace(/([$'])/g,
'\\$1'); | |
| 136 } | |
| 137 | |
| 138 private handleReifiedArray(node: ts.ArrayLiteralExpression) { | |
| 139 if (node.parent.kind !== ts.SyntaxKind.TypeAssertionExpression) return; | |
| 140 let ta = <ts.TypeAssertion>node.parent; | |
| 141 if (ta.type.kind !== ts.SyntaxKind.ArrayType) return; | |
| 142 this.emit('<'); | |
| 143 this.visit((<ts.ArrayTypeNode>ta.type).elementType); | |
| 144 this.emit('>'); | |
| 145 return true; | |
| 146 } | |
| 147 | |
| 148 | |
| 149 private handleReifiedMap(node: ts.ObjectLiteralExpression) { | |
| 150 if (node.parent.kind !== ts.SyntaxKind.TypeAssertionExpression) return; | |
| 151 let ta = <ts.TypeAssertion>node.parent; | |
| 152 if (ta.type.kind !== ts.SyntaxKind.TypeLiteral) return; | |
| 153 let it = this.maybeDestructureIndexType(<ts.TypeLiteralNode>ta.type); | |
| 154 if (!it) { | |
| 155 this.reportError(node, 'expected {[k]: v} type on object literal'); | |
| 156 return; | |
| 157 } | |
| 158 this.emit('<'); | |
| 159 this.visit(it[0]); | |
| 160 this.emit(','); | |
| 161 this.visit(it[1]); | |
| 162 this.emit('>'); | |
| 163 } | |
| 164 } | |
| OLD | NEW |