1
- /// <reference path="../typings/node/node.d.ts" />
1
+ /// <reference path='../typings/node/node.d.ts' />
2
+ /// <reference path='../typings/source-map/source-map.d.ts' />
2
3
// Use HEAD version of typescript, installed by npm
3
- /// <reference path=" ../node_modules/typescript/bin/typescript.d.ts" />
4
+ /// <reference path=' ../node_modules/typescript/bin/typescript.d.ts' />
4
5
require ( 'source-map-support' ) . install ( ) ;
5
- import ts = require( "typescript" ) ;
6
- import fs = require( "fs" ) ;
6
+ import fs = require( 'fs' ) ;
7
+ import SourceMap = require( 'source-map' ) ;
8
+ import ts = require( 'typescript' ) ;
7
9
8
10
export type ClassLike = ts . ClassDeclaration | ts . InterfaceDeclaration ;
9
11
12
+ export interface TranspilerOptions {
13
+ failFast ?: boolean ;
14
+ generateLibraryName ?: boolean ;
15
+ generateSourceMap ?: boolean ;
16
+ }
17
+
10
18
export class Transpiler {
19
+ // Position information.
20
+ generateSourceMap : boolean ;
21
+ sourceMap : SourceMap . SourceMapGenerator ;
22
+
23
+ generateLibraryName : boolean ;
24
+ relativeFileName : string ;
25
+ currentFile : ts . SourceFile ;
26
+
11
27
result : string = '' ;
28
+ column : number = 1 ;
29
+ line : number = 1 ;
30
+
12
31
// Comments attach to all following AST nodes before the next 'physical' token. Track the earliest
13
32
// offset to avoid printing comments multiple times.
14
33
lastCommentIdx : number = - 1 ;
15
- currentFile : ts . SourceFile ;
16
- relativeFileName : string ;
34
+
35
+ failFast : boolean ;
17
36
errors : string [ ] = [ ] ;
18
37
19
- constructor ( private failFast : boolean = false , private generateLibraryName : boolean = false ) { }
38
+ constructor ( opts : TranspilerOptions = { } ) {
39
+ this . failFast = ! ! opts . failFast ;
40
+ this . generateLibraryName = ! ! opts . generateLibraryName ;
41
+ this . generateSourceMap = ! ! opts . generateSourceMap ;
42
+ }
20
43
21
44
static OPTIONS : ts . CompilerOptions = {
22
45
target : ts . ScriptTarget . ES6 ,
@@ -26,11 +49,18 @@ export class Transpiler {
26
49
27
50
translateProgram ( program : ts . Program , relativeFileName : string ) : string {
28
51
this . relativeFileName = relativeFileName ;
29
- return program . getSourceFiles ( )
30
- . filter ( ( sourceFile : ts . SourceFile ) => ! sourceFile . fileName . match ( / \. d \. t s $ / ) &&
31
- ! ! sourceFile . fileName . match ( / \. [ j t ] s $ / ) )
32
- . map ( ( f ) => this . translate ( f ) )
33
- . join ( '\n' ) ;
52
+ var src = program . getSourceFiles ( )
53
+ . filter ( ( sourceFile : ts . SourceFile ) => ! sourceFile . fileName . match ( / \. d \. t s $ / ) &&
54
+ ! ! sourceFile . fileName . match ( / \. [ j t ] s $ / ) )
55
+ . map ( ( f ) => this . translate ( f ) )
56
+ . join ( '\n' ) ;
57
+ if ( this . sourceMap ) src += this . generateSourceMapComment ( ) ;
58
+ return src ;
59
+ }
60
+
61
+ generateSourceMapComment ( ) {
62
+ var base64map = new Buffer ( JSON . stringify ( this . sourceMap ) ) . toString ( 'base64' ) ;
63
+ return '\n\n//# sourceMappingURL=data:application/json;base64,' + base64map ;
34
64
}
35
65
36
66
createCompilerHost ( files : string [ ] ) : ts . CompilerHost {
@@ -80,19 +110,51 @@ export class Transpiler {
80
110
this . result = '' ;
81
111
this . errors = [ ] ;
82
112
this . lastCommentIdx = - 1 ;
83
- this . currentFile = sourceFile . getSourceFile ( ) ;
113
+ this . currentFile = sourceFile ;
114
+ if ( this . generateSourceMap ) {
115
+ this . sourceMap = new SourceMap . SourceMapGenerator ( { file : this . relativeFileName + '.dart' } ) ;
116
+ this . sourceMap . setSourceContent ( this . relativeFileName , this . currentFile . text ) ;
117
+ }
84
118
this . visit ( sourceFile ) ;
85
119
if ( this . errors . length ) {
86
120
var e = new Error ( this . errors . join ( '\n' ) ) ;
87
121
e . name = 'TS2DartError' ;
88
122
throw e ;
89
123
}
124
+
90
125
return this . result ;
91
126
}
92
127
128
+ enterNode ( n : ts . Node ) {
129
+ if ( ! this . sourceMap ) return ; // source maps disabled.
130
+ var file = n . getSourceFile ( ) || this . currentFile ;
131
+ var start = n . getStart ( file ) ;
132
+ var pos = file . getLineAndCharacterOfPosition ( start ) ;
133
+
134
+ var mapping : SourceMap . Mapping = {
135
+ original : { line : pos . line + 1 , column : pos . character } ,
136
+ generated : { line : this . line , column : this . column } ,
137
+ source : this . relativeFileName ,
138
+ } ;
139
+
140
+ this . sourceMap . addMapping ( mapping ) ;
141
+ }
142
+
93
143
emit ( str : string ) {
94
- this . result += ' ' ;
144
+ this . emitNoSpace ( ' ' ) ;
145
+ this . emitNoSpace ( str ) ;
146
+ }
147
+
148
+ emitNoSpace ( str : string ) {
95
149
this . result += str ;
150
+ for ( var i = 0 ; i < str . length ; i ++ ) {
151
+ if ( str [ i ] === '\n' ) {
152
+ this . line ++ ;
153
+ this . column = 0 ;
154
+ } else {
155
+ this . column ++ ;
156
+ }
157
+ }
96
158
}
97
159
98
160
visitEach ( nodes : ts . Node [ ] ) { nodes . forEach ( ( n ) => this . visit ( n ) ) ; }
@@ -144,7 +206,7 @@ export class Transpiler {
144
206
this . visitParameters ( fn ) ;
145
207
} else {
146
208
if ( fn . parameters && fn . parameters . length > 0 ) {
147
- this . reportError ( fn , " getter should not accept parameters" ) ;
209
+ this . reportError ( fn , ' getter should not accept parameters' ) ;
148
210
}
149
211
}
150
212
if ( fn . body ) {
@@ -583,14 +645,15 @@ export class Transpiler {
583
645
}
584
646
585
647
visit ( node : ts . Node ) {
648
+ this . enterNode ( node ) ;
586
649
var comments = ts . getLeadingCommentRanges ( this . currentFile . text , node . getFullStart ( ) ) ;
587
650
if ( comments ) {
588
651
comments . forEach ( ( c ) => {
589
652
if ( c . pos <= this . lastCommentIdx ) return ;
590
653
this . lastCommentIdx = c . pos ;
591
654
var text = this . currentFile . text . substring ( c . pos , c . end ) ;
592
655
this . emit ( text ) ;
593
- if ( c . hasTrailingNewLine ) this . result += '\n' ;
656
+ if ( c . hasTrailingNewLine ) this . emitNoSpace ( '\n' ) ;
594
657
} ) ;
595
658
}
596
659
@@ -773,7 +836,7 @@ export class Transpiler {
773
836
this . emit ( `'''${ this . escapeTextForTemplateString ( node ) } '''` ) ;
774
837
break ;
775
838
case ts . SyntaxKind . TemplateMiddle :
776
- this . result += this . escapeTextForTemplateString ( node ) ;
839
+ this . emitNoSpace ( this . escapeTextForTemplateString ( node ) ) ;
777
840
break ;
778
841
case ts . SyntaxKind . TemplateExpression :
779
842
var tmpl = < ts . TemplateExpression > node ;
@@ -784,16 +847,16 @@ export class Transpiler {
784
847
this . emit ( `'''${ this . escapeTextForTemplateString ( node ) } ` ) ; //highlighting bug:'
785
848
break ;
786
849
case ts . SyntaxKind . TemplateTail :
787
- this . result += this . escapeTextForTemplateString ( node ) ;
788
- this . result += `'''` ;
850
+ this . emitNoSpace ( this . escapeTextForTemplateString ( node ) ) ;
851
+ this . emitNoSpace ( `'''` ) ;
789
852
break ;
790
853
case ts . SyntaxKind . TemplateSpan :
791
854
var span = < ts . TemplateSpan > node ;
792
855
if ( span . expression ) {
793
856
// Do not emit extra whitespace inside the string template
794
- this . result += '${' ;
857
+ this . emitNoSpace ( '${' ) ;
795
858
this . visit ( span . expression ) ;
796
- this . result += '}' ;
859
+ this . emitNoSpace ( '}' ) ;
797
860
}
798
861
if ( span . literal ) this . visit ( span . literal ) ;
799
862
break ;
@@ -813,9 +876,9 @@ export class Transpiler {
813
876
var propAssign = < ts . PropertyAssignment > node ;
814
877
if ( propAssign . name . kind === ts . SyntaxKind . Identifier ) {
815
878
// Dart identifiers in Map literals need quoting.
816
- this . result += ' "' ;
817
- this . result += ( < ts . Identifier > propAssign . name ) . text ;
818
- this . result += '"' ;
879
+ this . emitNoSpace ( ' "' ) ;
880
+ this . emitNoSpace ( ( < ts . Identifier > propAssign . name ) . text ) ;
881
+ this . emitNoSpace ( '"' ) ;
819
882
} else {
820
883
this . visit ( propAssign . name ) ;
821
884
}
@@ -824,9 +887,9 @@ export class Transpiler {
824
887
break ;
825
888
case ts . SyntaxKind . ShorthandPropertyAssignment :
826
889
var shorthand = < ts . ShorthandPropertyAssignment > node ;
827
- this . result += ' "' ;
828
- this . result += shorthand . name . text ;
829
- this . result += '"' ;
890
+ this . emitNoSpace ( ' "' ) ;
891
+ this . emitNoSpace ( shorthand . name . text ) ;
892
+ this . emitNoSpace ( '"' ) ;
830
893
this . emit ( ':' ) ;
831
894
this . visit ( shorthand . name ) ;
832
895
break ;
0 commit comments