Skip to content
This repository has been archived by the owner on Jun 27, 2018. It is now read-only.

supporting inline sourcemaps #7

Merged
merged 5 commits into from
Mar 8, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 12 additions & 4 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,31 @@ import ts = require('typescript');
declare function tss(code: string, options: ts.CompilerOptions): string;
declare module tss {
class TypeScriptSimple {
private doSemanticChecks;
private service;
private outputs;
private options;
private files;
/**
* @param {ts.CompilerOptions=} options TypeScript compile options (some options are ignored)
*/
constructor(options?: ts.CompilerOptions);
constructor(options?: ts.CompilerOptions, doSemanticChecks?: boolean);
/**
* @param {string} code TypeScript source code to compile
* @return {string}
* @param {string} only needed if you plan to use sourceMaps. Provide the complete filePath relevant to you
* @return {string} The JavaScript with inline sourceMaps if sourceMaps were enabled
*/
compile(code: string): string;
compile(code: string, filename?: string): string;
private createService();
private getTypeScriptBinDir();
private getDefaultLibFilename(options);
private toJavaScript(service);
/**
* converts {"version":3,"file":"file.js","sourceRoot":"","sources":["file.ts"],"names":[],"mappings":"AAAA,IAAI,CAAC,GAAG,MAAM,CAAC"}
* to {"version":3,"sources":["foo/test.ts"],"names":[],"mappings":"AAAA,IAAI,CAAC,GAAG,MAAM,CAAC","file":"foo/test.ts","sourcesContent":["var x = 'test';"]}
* derived from : https://github.com/thlorenz/convert-source-map
*/
private getInlineSourceMap(mapText, filename);
private toJavaScript(service, filename?);
private formatDiagnostics(diagnostics);
}
}
Expand Down
58 changes: 48 additions & 10 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@ var tss;
/**
* @param {ts.CompilerOptions=} options TypeScript compile options (some options are ignored)
*/
function TypeScriptSimple(options) {
function TypeScriptSimple(options, doSemanticChecks) {
if (options === void 0) { options = {}; }
if (doSemanticChecks === void 0) { doSemanticChecks = true; }
this.doSemanticChecks = doSemanticChecks;
this.service = null;
this.outputs = {};
this.files = {};
Expand All @@ -34,16 +36,18 @@ var tss;
}
/**
* @param {string} code TypeScript source code to compile
* @return {string}
* @param {string} only needed if you plan to use sourceMaps. Provide the complete filePath relevant to you
* @return {string} The JavaScript with inline sourceMaps if sourceMaps were enabled
*/
TypeScriptSimple.prototype.compile = function (code) {
TypeScriptSimple.prototype.compile = function (code, filename) {
if (filename === void 0) { filename = FILENAME_TS; }
if (!this.service) {
this.service = this.createService();
}
var file = this.files[FILENAME_TS];
file.text = code;
file.version++;
return this.toJavaScript(this.service);
return this.toJavaScript(this.service, filename);
};
TypeScriptSimple.prototype.createService = function () {
var _this = this;
Expand Down Expand Up @@ -84,15 +88,49 @@ var tss;
return 'lib.d.ts';
}
};
TypeScriptSimple.prototype.toJavaScript = function (service) {
/**
* converts {"version":3,"file":"file.js","sourceRoot":"","sources":["file.ts"],"names":[],"mappings":"AAAA,IAAI,CAAC,GAAG,MAAM,CAAC"}
* to {"version":3,"sources":["foo/test.ts"],"names":[],"mappings":"AAAA,IAAI,CAAC,GAAG,MAAM,CAAC","file":"foo/test.ts","sourcesContent":["var x = 'test';"]}
* derived from : https://github.com/thlorenz/convert-source-map
*/
TypeScriptSimple.prototype.getInlineSourceMap = function (mapText, filename) {
var sourceMap = JSON.parse(mapText);
sourceMap.file = filename;
sourceMap.sources = [filename];
sourceMap.sourcesContent = [this.files[FILENAME_TS].text];
delete sourceMap.sourceRoot;
return JSON.stringify(sourceMap);
};
TypeScriptSimple.prototype.toJavaScript = function (service, filename) {
if (filename === void 0) { filename = FILENAME_TS; }
var output = service.getEmitOutput(FILENAME_TS);
if (output.emitOutputStatus === 0 /* Succeeded */) {
var filename = FILENAME_TS.replace(/ts$/, 'js');
var file = output.outputFiles.filter(function (file) { return file.name === filename; })[0];
// Meaning of succeeded is driven by whether we need to check for semantic errors or not
var succeeded = output.emitOutputStatus === 0 /* Succeeded */;
if (!this.doSemanticChecks) {
// We have an output. It implies syntactic success
if (!succeeded)
succeeded = !!output.outputFiles.length;
}
if (succeeded) {
var outputFilename = FILENAME_TS.replace(/ts$/, 'js');
var file = output.outputFiles.filter(function (file) { return file.name === outputFilename; })[0];
// Fixed in v1.5 https://github.com/Microsoft/TypeScript/issues/1653
return file.text.replace(/\r\n/g, os.EOL);
var text = file.text.replace(/\r\n/g, os.EOL);
// If we have sourceMaps convert them to inline sourceMaps
if (this.options.sourceMap) {
var sourceMapFilename = FILENAME_TS.replace(/ts$/, 'js.map');
var sourceMapFile = output.outputFiles.filter(function (file) { return file.name === sourceMapFilename; })[0];
// Transform sourcemap
var sourceMapText = sourceMapFile.text;
sourceMapText = this.getInlineSourceMap(sourceMapText, filename);
var base64SourceMapText = new Buffer(sourceMapText).toString('base64');
text = text.replace('//# sourceMappingURL=' + sourceMapFilename, '//# sourceMappingURL=data:application/json;base64,' + base64SourceMapText);
}
return text;
}
var allDiagnostics = service.getCompilerOptionsDiagnostics().concat(service.getSyntacticDiagnostics(FILENAME_TS)).concat(service.getSemanticDiagnostics(FILENAME_TS));
var allDiagnostics = service.getCompilerOptionsDiagnostics().concat(service.getSyntacticDiagnostics(FILENAME_TS));
if (this.doSemanticChecks)
allDiagnostics = allDiagnostics.concat(service.getSemanticDiagnostics(FILENAME_TS));
throw new Error(this.formatDiagnostics(allDiagnostics));
};
TypeScriptSimple.prototype.formatDiagnostics = function (diagnostics) {
Expand Down
67 changes: 54 additions & 13 deletions index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ module tss {
private service: ts.LanguageService = null;
private outputs: ts.Map<string> = {};
private options: ts.CompilerOptions;
private files: ts.Map<{version: number; text: string;}> = {};
private files: ts.Map<{ version: number; text: string; }> = {};

/**
* @param {ts.CompilerOptions=} options TypeScript compile options (some options are ignored)
*/
constructor(options: ts.CompilerOptions = {}) {
constructor(options: ts.CompilerOptions = {}, private doSemanticChecks = true) {
if (options.target == null) {
options.target = ts.ScriptTarget.ES5;
}
Expand All @@ -36,12 +36,13 @@ module tss {
}
this.options = options;
}

/**
* @param {string} code TypeScript source code to compile
* @return {string}
* @param {string} only needed if you plan to use sourceMaps. Provide the complete filePath relevant to you
* @return {string} The JavaScript with inline sourceMaps if sourceMaps were enabled
*/
compile(code: string): string {
compile(code: string, filename = FILENAME_TS): string {
if (!this.service) {
this.service = this.createService();
}
Expand All @@ -50,7 +51,7 @@ module tss {
file.text = code;
file.version++;

return this.toJavaScript(this.service);
return this.toJavaScript(this.service, filename);
}

private createService(): ts.LanguageService {
Expand Down Expand Up @@ -95,18 +96,58 @@ module tss {
}
}

private toJavaScript(service: ts.LanguageService): string {
/**
* converts {"version":3,"file":"file.js","sourceRoot":"","sources":["file.ts"],"names":[],"mappings":"AAAA,IAAI,CAAC,GAAG,MAAM,CAAC"}
* to {"version":3,"sources":["foo/test.ts"],"names":[],"mappings":"AAAA,IAAI,CAAC,GAAG,MAAM,CAAC","file":"foo/test.ts","sourcesContent":["var x = 'test';"]}
* derived from : https://github.com/thlorenz/convert-source-map
*/
private getInlineSourceMap(mapText: string, filename: string): string {
var sourceMap = JSON.parse(mapText);
sourceMap.file = filename;
sourceMap.sources = [filename];
sourceMap.sourcesContent = [this.files[FILENAME_TS].text];
delete sourceMap.sourceRoot;
return JSON.stringify(sourceMap);
}

private toJavaScript(service: ts.LanguageService, filename = FILENAME_TS): string {
var output = service.getEmitOutput(FILENAME_TS);
if (output.emitOutputStatus === ts.EmitReturnStatus.Succeeded) {
var filename = FILENAME_TS.replace(/ts$/, 'js');
var file = output.outputFiles.filter((file) => file.name === filename)[0];

// Meaning of succeeded is driven by whether we need to check for semantic errors or not
var succeeded = output.emitOutputStatus === ts.EmitReturnStatus.Succeeded;
if (!this.doSemanticChecks) {
// We have an output. It implies syntactic success
if (!succeeded) succeeded = !!output.outputFiles.length;
}

if (succeeded) {
var outputFilename = FILENAME_TS.replace(/ts$/, 'js');
var file = output.outputFiles.filter((file) => file.name === outputFilename)[0];
// Fixed in v1.5 https://github.com/Microsoft/TypeScript/issues/1653
return file.text.replace(/\r\n/g, os.EOL);
var text = file.text.replace(/\r\n/g, os.EOL);

// If we have sourceMaps convert them to inline sourceMaps
if (this.options.sourceMap) {
var sourceMapFilename = FILENAME_TS.replace(/ts$/, 'js.map');
var sourceMapFile = output.outputFiles.filter((file) => file.name === sourceMapFilename)[0];

// Transform sourcemap
var sourceMapText = sourceMapFile.text;
sourceMapText = this.getInlineSourceMap(sourceMapText, filename);

var base64SourceMapText = new Buffer(sourceMapText).toString('base64');
text = text.replace('//# sourceMappingURL=' + sourceMapFilename, '//# sourceMappingURL=data:application/json;base64,' + base64SourceMapText);
}

return text;
}

var allDiagnostics = service.getCompilerOptionsDiagnostics()
.concat(service.getSyntacticDiagnostics(FILENAME_TS))
.concat(service.getSemanticDiagnostics(FILENAME_TS));
.concat(service.getSyntacticDiagnostics(FILENAME_TS));

if (this.doSemanticChecks)
allDiagnostics = allDiagnostics.concat(service.getSemanticDiagnostics(FILENAME_TS));

throw new Error(this.formatDiagnostics(allDiagnostics));
}

Expand Down
53 changes: 45 additions & 8 deletions test/test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
var assert = require('assert');
var fs = require('fs');
var path = require('path');
var eol = require('os').EOL;

var ts = require('typescript');
var tss = require('../');
Expand All @@ -10,27 +11,27 @@ describe('typescript-update', function() {
context('default target (ES5)', function() {
it('compiles correct code', function() {
var src = "var x: number = 1;";
var expected = 'var x = 1;\n';
var expected = 'var x = 1;' + eol;
assert.equal(tss(src), expected);
});

it('does not replace CRLF literal', function() {
var src = "var x: string = '\\r\\n';";
var expected = "var x = '\\r\\n';\n";
var expected = "var x = '\\r\\n';" + eol;
assert.equal(tss(src), expected);
});

it('compiles many times', function() {
var src = "var x: number = 1;";
var expected = 'var x = 1;\n';
var expected = 'var x = 1;' + eol;
assert.equal(tss(src), expected);

src = "var y: number = 2;";
expected = 'var y = 2;\n';
expected = 'var y = 2;' + eol;
assert.equal(tss(src), expected);

src = "var z: number = 3;";
expected = 'var z = 3;\n';
expected = 'var z = 3;' + eol;
assert.equal(tss(src), expected);
});

Expand Down Expand Up @@ -64,14 +65,50 @@ describe('typescript-update', function() {

it('compiles ES6 "let"', function() {
var src = "let x: number = 1;";
var expected = 'let x = 1;\n';
var expected = 'let x = 1;' + eol;
assert.equal(tss.compile(src), expected);
});

it('compiles ES6 Promise', function() {
var src = "var x = new Promise(function (resolve, reject) {\n});";
var expected = src + '\n';
var src = "var x = new Promise(function (resolve, reject) {" + eol + "});";
var expected = src + eol;
assert.equal(tss.compile(src), expected);
});
});

context('semantic vs. syntactic errors', function() {
var tss;
beforeEach(function() {
tss = new TypeScriptSimple({target: ts.ScriptTarget.ES5}, false);
});

it('semantic errors are ignored', function() {
var src = "var x: number = 'some string';";
var expected = "var x = 'some string';" + eol;
assert.equal(tss.compile(src), expected);
});

it('syntactic errors are not ignored', function() {
var src = "var x = 123 123;";
assert.throws(function() {
tss.compile(src);
}, /^Error: L1: ',' expected./);
});
});

context('sourceMaps', function() {
var tss;
beforeEach(function() {
tss = new TypeScriptSimple({target: ts.ScriptTarget.ES5, sourceMap: true}, false);
});

it('sourceMap:true should result in inline sourceMaps', function() {
var src = 'var x = "test";';
var srcFile = 'foo/test.ts';
var expected =
'var x = "test";' + eol
+ '//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZm9vL3Rlc3QudHMiLCJzb3VyY2VzIjpbImZvby90ZXN0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLElBQUksQ0FBQyxHQUFHLE1BQU0sQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbInZhciB4ID0gXCJ0ZXN0XCI7Il19';
assert.equal(tss.compile(src, srcFile), expected);
});
});
});
21 changes: 21 additions & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"version": "1.4.1",
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"declaration": true,
"noImplicitAny": true,
"removeComments": false,
"noLib": false
},
"filesGlob": [
"./**/*.ts",
"!./node_modules/**/*.ts"
],
"files": [
"./index.d.ts",
"./index.ts",
"./typings/bundle.d.ts",
"./typings/node/node.d.ts"
]
}