UNPKG

6.01 kBPlain TextView Raw
1/// <reference path="node_modules/typescript-api/typescript-api.d.ts" />
2import ts = require('typescript-api');
3import path = require('path');
4import events = require('events');
5
6
7export function compile(files: string[], options?: any, callback?: Function) {
8 return new BatchCompiler().compile(files, options, callback);
9}
10
11export interface ICompilerOptions {
12 /**
13 * Generates corresponding .d.ts file.
14 */
15 declaration?: boolean;
16 /**
17 * Print this message.
18 */
19 help?: boolean;
20 /**
21 * Specifies the location where debugger should locate map files
22 * instead of generated locations.
23 */
24 mapRoot?: string;
25 /**
26 * Specify module code generation: 'commonjs' or 'amd'
27 */
28 module?: string;
29 /**
30 * Warn on expressions and declarations with any implied 'any' type.
31 */
32 noImplicitAny?: boolean;
33 /**
34 * Skip resolution and preprocessing.
35 */
36 noResolve?: boolean;
37 /**
38 * Concatenate and emit output to a single file.
39 */
40 out?: string;
41 /**
42 * Redirect output structure to the directory.
43 */
44 outDir?: string;
45 /**
46 * Do not emit comments to output.
47 */
48 removeComments?: boolean;
49 /**
50 * Generates corresponding .map file.
51 */
52 sourcemap?: boolean;
53 /**
54 * Specifies the location where debugger should locate TypeScript
55 * files instead of source locations.
56 */
57 sourceRoot?: string;
58 /**
59 * Specify ECMAScript target version: 'ES3' (default), or 'ES5'
60 */
61 target?: string;
62 /**
63 * Print the compiler's version: 0.9.5.0
64 */
65 version?: string;
66 /**
67 * Watch input files.
68 */
69 watch?: boolean;
70 /**
71 * Insert command line options and files from a file.
72 */
73 optionsFile?: string;
74 /**
75 * Skip writing the output files.
76 */
77 skipWrite?: boolean;
78}
79
80export class BatchCompiler extends events.EventEmitter {
81
82 private _skipWrite = false;
83 private _compiler: ts.BatchCompiler;
84
85 constructor() {
86 super();
87 this.redirectErrors();
88 this._compiler = new ts.BatchCompiler(ts.IO);
89 (<any>process).mainModule.filename = require.resolve('typescript');
90 }
91
92 private redirectErrors() {
93 ts.IO.stderr.Write = (s: string) => {
94 this.emit('error', s);
95 };
96 ts.IO.stderr.WriteLine = (s: string) => {
97 ts.IO.stderr.Write(s + '\n');
98 };
99 ts.IO.stdout.Write = (s: string) => {
100 this.emit('info', s);
101 };
102 ts.IO.stdout.WriteLine = (s: string) => {
103 ts.IO.stdout.Write(s + '\n');
104 };
105 (<any>ts.BatchCompiler).prototype.addDiagnostic = function(diagnostic: ts.Diagnostic) {
106 var diagnosticInfo = diagnostic.info();
107 if (diagnosticInfo.category === 1 /* Error */) {
108 this.hasErrors = true;
109 }
110 var errorLocation = '';
111 if (diagnostic.fileName()) {
112 errorLocation = diagnostic.fileName() + "(" + (diagnostic.line() + 1) + "," + (diagnostic.character() + 1) + "): ";
113 }
114 this.ioHost.stderr.WriteLine(errorLocation + diagnostic.message());
115 };
116 }
117
118 compile(files: string[], options?: any, callback?: Function) {
119 handleOverloads.call(this);
120 handleSkipWrite.call(this);
121 setupArguments(args => {
122 ts.IO.arguments = args;
123 this._batchCompile(callback);
124 });
125
126 function handleOverloads() {
127 if (typeof options === 'function') {
128 callback = options;
129 options = {};
130 } else if (typeof callback !== 'function') {
131 callback = () => {};
132 }
133 }
134
135 function handleSkipWrite() {
136 options = options || {};
137 this._skipWrite = options.skipWrite;
138 delete options.skipWrite;
139 }
140
141 function setupArguments(cb: Function) {
142 var args = argify(options);
143 args.push.apply(args, files);
144 cb(args);
145 }
146 }
147
148 private _batchCompile(callback: Function) {
149 var compiler = <any>this._compiler;
150
151 ts.CompilerDiagnostics.diagnosticWriter = { Alert: (s: string) => { compiler.ioHost.printLine(s); } };
152
153 if (compiler.parseOptions()) {
154 compiler.logger = compiler.compilationSettings.gatherDiagnostics() ? new DiagnosticsLogger((<any>this).ioHost) : new ts.NullLogger();
155
156 if (compiler.compilationSettings.watch()) {
157 // Watch will cause the program to stick around as long as the files exist
158 compiler.watchFiles();
159 callback(null);
160 return;
161 }
162
163 compiler.resolve();
164 this._compile(callback);
165 } else {
166 callback(new Error('Error parsing compiler options'));
167 }
168
169 if (compiler.hasErrors) {
170 callback(new Error('Unspecified error'));
171 }
172 }
173
174 private _compile(callback: Function) {
175 var compiler = <any>this._compiler;
176 var tsCompiler = new ts.TypeScriptCompiler(compiler.logger, compiler.compilationSettings);
177
178 compiler.resolvedFiles.forEach(resolvedFile => {
179 var sourceFile = compiler.getSourceFile(resolvedFile.path);
180 tsCompiler.addFile(resolvedFile.path, sourceFile.scriptSnapshot, sourceFile.byteOrderMark, /*version:*/ 0, /*isOpen:*/ false, resolvedFile.referencedFiles);
181 });
182
183 var results: ts.OutputFile[] = [];
184 for (var it = tsCompiler.compile((path: string) => compiler.resolvePath(path)); it.moveNext();) {
185 var result = it.current();
186
187 result.diagnostics.forEach(d => compiler.addDiagnostic(d));
188 if (!this._skipWrite && !compiler.tryWriteOutputFiles(result.outputFiles)) {
189 callback(new Error('Error writing to output file'));
190 }
191 Array.prototype.push.apply(results, result.outputFiles);
192 }
193 callback(null, results);
194 }
195}
196
197class DiagnosticsLogger implements ts.ILogger {
198 constructor(public ioHost: ts.IIO) {
199 }
200 public information(): boolean { return false; }
201 public debug(): boolean { return false; }
202 public warning(): boolean { return false; }
203 public error(): boolean { return false; }
204 public fatal(): boolean { return false; }
205 public log(s: string): void {
206 this.ioHost.stdout.WriteLine(s);
207 }
208}
209
210function argify(options: ICompilerOptions): string[] {
211 var args = [];
212 Object.keys(options).forEach(key => {
213 var value = options[key];
214 if (!value) {
215 return;
216 }
217 if (key === 'optionsFile') {
218 args.push('@' + value);
219 return;
220 }
221 var flag = '-';
222 if (key.length !== 1) {
223 flag += '-';
224 }
225 args.push(flag + key);
226 if (typeof value !== 'boolean') {
227 args.push(value);
228 }
229 });
230 return args;
231}
232
233export class OutputFile extends ts.OutputFile {
234
235}