2015-06-11 21:01:19 +02:00
|
|
|
/// <reference path="..\..\..\src\harness\harness.ts" />
|
2015-05-27 05:18:13 +02:00
|
|
|
|
|
|
|
module ts {
|
|
|
|
describe("Transpile", () => {
|
2015-07-22 20:58:27 +02:00
|
|
|
|
|
|
|
interface TranspileTestSettings {
|
|
|
|
options?: TranspileOptions;
|
|
|
|
expectedOutput?: string;
|
|
|
|
expectedDiagnosticCodes?: number[];
|
|
|
|
}
|
|
|
|
|
|
|
|
function checkDiagnostics(diagnostics: Diagnostic[], expectedDiagnosticCodes?: number[]) {
|
|
|
|
if(!expectedDiagnosticCodes) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-05-27 19:20:01 +02:00
|
|
|
for (let i = 0; i < expectedDiagnosticCodes.length; i++) {
|
|
|
|
assert.equal(expectedDiagnosticCodes[i], diagnostics[i] && diagnostics[i].code, `Could not find expeced diagnostic.`);
|
2015-05-27 05:18:13 +02:00
|
|
|
}
|
2015-07-22 20:58:27 +02:00
|
|
|
assert.equal(diagnostics.length, expectedDiagnosticCodes.length, "Resuting diagnostics count does not match expected");
|
2015-05-27 05:18:13 +02:00
|
|
|
}
|
2015-07-22 20:58:27 +02:00
|
|
|
|
|
|
|
function test(input: string, testSettings: TranspileTestSettings): void {
|
|
|
|
|
2015-08-14 22:00:41 +02:00
|
|
|
let transpileOptions: TranspileOptions = testSettings.options || {};
|
2015-08-21 20:57:07 +02:00
|
|
|
if (!transpileOptions.compilerOptions) {
|
|
|
|
transpileOptions.compilerOptions = {};
|
|
|
|
}
|
|
|
|
if(transpileOptions.compilerOptions.newLine === undefined) {
|
|
|
|
// use \r\n as default new line
|
|
|
|
transpileOptions.compilerOptions.newLine = ts.NewLineKind.CarriageReturnLineFeed;
|
|
|
|
}
|
2015-08-14 22:00:41 +02:00
|
|
|
|
|
|
|
let canUseOldTranspile = !transpileOptions.renamedDependencies;
|
2015-07-22 20:58:27 +02:00
|
|
|
|
|
|
|
transpileOptions.reportDiagnostics = true;
|
|
|
|
let transpileModuleResult = transpileModule(input, transpileOptions);
|
|
|
|
|
|
|
|
checkDiagnostics(transpileModuleResult.diagnostics, testSettings.expectedDiagnosticCodes);
|
|
|
|
|
|
|
|
if (testSettings.expectedOutput !== undefined) {
|
|
|
|
assert.equal(transpileModuleResult.outputText, testSettings.expectedOutput);
|
|
|
|
}
|
|
|
|
|
2015-08-14 22:00:41 +02:00
|
|
|
if (canUseOldTranspile) {
|
2015-10-07 19:37:28 +02:00
|
|
|
let diagnostics: Diagnostic[] = [];
|
2015-08-14 22:00:41 +02:00
|
|
|
let transpileResult = transpile(input, transpileOptions.compilerOptions, transpileOptions.fileName, diagnostics, transpileOptions.moduleName);
|
|
|
|
checkDiagnostics(diagnostics, testSettings.expectedDiagnosticCodes);
|
|
|
|
if (testSettings.expectedOutput) {
|
|
|
|
assert.equal(transpileResult, testSettings.expectedOutput);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-22 20:58:27 +02:00
|
|
|
// check source maps
|
|
|
|
if (!transpileOptions.compilerOptions) {
|
|
|
|
transpileOptions.compilerOptions = {};
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!transpileOptions.fileName) {
|
2015-10-07 19:37:28 +02:00
|
|
|
transpileOptions.fileName = transpileOptions.compilerOptions.jsx ? "file.tsx" : "file.ts";
|
2015-07-22 20:58:27 +02:00
|
|
|
}
|
|
|
|
|
2015-10-07 19:37:28 +02:00
|
|
|
transpileOptions.compilerOptions.sourceMap = true;
|
2015-07-22 20:58:27 +02:00
|
|
|
let transpileModuleResultWithSourceMap = transpileModule(input, transpileOptions);
|
|
|
|
assert.isTrue(transpileModuleResultWithSourceMap.sourceMapText !== undefined);
|
|
|
|
|
2015-09-03 18:25:43 +02:00
|
|
|
let expectedSourceMapFileName = removeFileExtension(getBaseFileName(normalizeSlashes(transpileOptions.fileName))) + ".js.map";
|
|
|
|
let expectedSourceMappingUrlLine = `//# sourceMappingURL=${expectedSourceMapFileName}`;
|
2015-07-22 20:58:27 +02:00
|
|
|
|
|
|
|
if (testSettings.expectedOutput !== undefined) {
|
2015-10-07 19:37:28 +02:00
|
|
|
assert.equal(transpileModuleResultWithSourceMap.outputText, testSettings.expectedOutput + expectedSourceMappingUrlLine);
|
2015-07-22 20:58:27 +02:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
// expected output is not set, just verify that output text has sourceMappingURL as a last line
|
|
|
|
let output = transpileModuleResultWithSourceMap.outputText;
|
|
|
|
assert.isTrue(output.length >= expectedSourceMappingUrlLine.length);
|
|
|
|
if (output.length === expectedSourceMappingUrlLine.length) {
|
|
|
|
assert.equal(output, expectedSourceMappingUrlLine);
|
|
|
|
}
|
|
|
|
else {
|
2015-10-07 19:37:28 +02:00
|
|
|
let suffix = getNewLineCharacter(transpileOptions.compilerOptions) + expectedSourceMappingUrlLine
|
2015-07-22 20:58:27 +02:00
|
|
|
assert.isTrue(output.indexOf(suffix, output.length - suffix.length) !== -1);
|
|
|
|
}
|
|
|
|
}
|
2015-05-27 05:18:13 +02:00
|
|
|
|
2015-07-22 20:58:27 +02:00
|
|
|
}
|
|
|
|
|
2015-05-27 05:18:13 +02:00
|
|
|
it("Generates correct compilerOptions diagnostics", () => {
|
|
|
|
// Expecting 5047: "Option 'isolatedModules' can only be used when either option'--module' is provided or option 'target' is 'ES6' or higher."
|
2015-07-22 20:58:27 +02:00
|
|
|
test(`var x = 0;`, { expectedDiagnosticCodes: [5047] });
|
2015-05-27 05:18:13 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
it("Generates no diagnostics with valid inputs", () => {
|
|
|
|
// No errors
|
2015-07-22 20:58:27 +02:00
|
|
|
test(`var x = 0;`, { options: { compilerOptions: { module: ModuleKind.CommonJS } } });
|
2015-05-27 05:18:13 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
it("Generates no diagnostics for missing file references", () => {
|
2015-07-22 20:58:27 +02:00
|
|
|
test(`/// <reference path="file2.ts" />
|
|
|
|
var x = 0;`,
|
|
|
|
{ options: { compilerOptions: { module: ModuleKind.CommonJS } } });
|
2015-05-27 05:18:13 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
it("Generates no diagnostics for missing module imports", () => {
|
2015-07-22 20:58:27 +02:00
|
|
|
test(`import {a} from "module2";`,
|
|
|
|
{ options: { compilerOptions: { module: ModuleKind.CommonJS } } });
|
2015-05-27 05:18:13 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
it("Generates expected syntactic diagnostics", () => {
|
2015-07-22 20:58:27 +02:00
|
|
|
test(`a b`,
|
|
|
|
{ options: { compilerOptions: { module: ModuleKind.CommonJS } }, expectedDiagnosticCodes: [1005] }); /// 1005: ';' Expected
|
2015-05-27 05:18:13 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
it("Does not generate semantic diagnostics", () => {
|
2015-07-22 20:58:27 +02:00
|
|
|
test(`var x: string = 0;`,
|
|
|
|
{ options: { compilerOptions: { module: ModuleKind.CommonJS } } });
|
2015-05-27 05:18:13 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
it("Generates module output", () => {
|
2015-07-22 20:58:27 +02:00
|
|
|
test(`var x = 0;`,
|
|
|
|
{
|
|
|
|
options: { compilerOptions: { module: ModuleKind.AMD } },
|
2015-11-24 00:16:10 +01:00
|
|
|
expectedOutput: `define(["require", "exports"], function (require, exports) {\r\n "use strict";\r\n var x = 0;\r\n});\r\n`
|
2015-07-22 20:58:27 +02:00
|
|
|
});
|
2015-05-27 05:18:13 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
it("Uses correct newLine character", () => {
|
2015-07-22 20:58:27 +02:00
|
|
|
test(`var x = 0;`,
|
|
|
|
{
|
|
|
|
options: { compilerOptions: { module: ModuleKind.CommonJS, newLine: NewLineKind.LineFeed } },
|
2015-11-24 00:16:10 +01:00
|
|
|
expectedOutput: `"use strict";\nvar x = 0;\n`
|
2015-07-22 20:58:27 +02:00
|
|
|
});
|
2015-06-05 07:22:25 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
it("Sets module name", () => {
|
|
|
|
let output =
|
2016-01-05 19:28:32 +01:00
|
|
|
`System.register("NamedModule", [], function(exports_1) {\n "use strict";\n var x;\n` +
|
2015-06-05 07:22:25 +02:00
|
|
|
` return {\n` +
|
|
|
|
` setters:[],\n` +
|
|
|
|
` execute: function() {\n` +
|
|
|
|
` var x = 1;\n` +
|
|
|
|
` }\n` +
|
|
|
|
` }\n` +
|
|
|
|
`});\n`;
|
2015-07-22 20:58:27 +02:00
|
|
|
test("var x = 1;",
|
|
|
|
{
|
|
|
|
options: { compilerOptions: { module: ModuleKind.System, newLine: NewLineKind.LineFeed }, moduleName: "NamedModule" },
|
|
|
|
expectedOutput: output
|
|
|
|
})
|
2015-05-27 05:18:13 +02:00
|
|
|
});
|
2015-06-19 00:06:03 +02:00
|
|
|
|
2015-06-11 23:30:58 +02:00
|
|
|
it("No extra errors for file without extension", () => {
|
2015-11-24 00:16:10 +01:00
|
|
|
test(`"use strict";\r\nvar x = 0;`, { options: { compilerOptions: { module: ModuleKind.CommonJS }, fileName: "file" } });
|
2015-06-11 23:30:58 +02:00
|
|
|
});
|
2015-08-14 22:00:41 +02:00
|
|
|
|
|
|
|
it("Rename dependencies - System", () => {
|
|
|
|
let input =
|
|
|
|
`import {foo} from "SomeName";\n` +
|
|
|
|
`declare function use(a: any);\n` +
|
|
|
|
`use(foo);`
|
|
|
|
let output =
|
2016-01-05 19:28:32 +01:00
|
|
|
`System.register(["SomeOtherName"], function(exports_1) {\n` +
|
2015-11-24 00:16:10 +01:00
|
|
|
` "use strict";\n` +
|
2015-08-14 22:00:41 +02:00
|
|
|
` var SomeName_1;\n` +
|
|
|
|
` return {\n` +
|
|
|
|
` setters:[\n` +
|
|
|
|
` function (SomeName_1_1) {\n` +
|
|
|
|
` SomeName_1 = SomeName_1_1;\n` +
|
|
|
|
` }],\n` +
|
|
|
|
` execute: function() {\n` +
|
|
|
|
` use(SomeName_1.foo);\n` +
|
|
|
|
` }\n` +
|
|
|
|
` }\n` +
|
|
|
|
`});\n`
|
|
|
|
|
|
|
|
test(input,
|
|
|
|
{
|
|
|
|
options: { compilerOptions: { module: ModuleKind.System, newLine: NewLineKind.LineFeed }, renamedDependencies: { "SomeName": "SomeOtherName" } },
|
|
|
|
expectedOutput: output
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it("Rename dependencies - AMD", () => {
|
|
|
|
let input =
|
|
|
|
`import {foo} from "SomeName";\n` +
|
|
|
|
`declare function use(a: any);\n` +
|
|
|
|
`use(foo);`
|
|
|
|
let output =
|
|
|
|
`define(["require", "exports", "SomeOtherName"], function (require, exports, SomeName_1) {\n` +
|
2015-11-24 00:16:10 +01:00
|
|
|
` "use strict";\n` +
|
2015-08-14 22:00:41 +02:00
|
|
|
` use(SomeName_1.foo);\n` +
|
|
|
|
`});\n`;
|
|
|
|
|
|
|
|
test(input,
|
|
|
|
{
|
|
|
|
options: { compilerOptions: { module: ModuleKind.AMD, newLine: NewLineKind.LineFeed }, renamedDependencies: { "SomeName": "SomeOtherName" } },
|
|
|
|
expectedOutput: output
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it("Rename dependencies - UMD", () => {
|
|
|
|
let input =
|
|
|
|
`import {foo} from "SomeName";\n` +
|
|
|
|
`declare function use(a: any);\n` +
|
|
|
|
`use(foo);`
|
|
|
|
let output =
|
2015-09-26 00:22:01 +02:00
|
|
|
`(function (factory) {\n` +
|
2015-08-14 22:00:41 +02:00
|
|
|
` if (typeof module === 'object' && typeof module.exports === 'object') {\n` +
|
|
|
|
` var v = factory(require, exports); if (v !== undefined) module.exports = v;\n` +
|
|
|
|
` }\n` +
|
|
|
|
` else if (typeof define === 'function' && define.amd) {\n` +
|
2015-09-26 00:22:01 +02:00
|
|
|
` define(["require", "exports", "SomeOtherName"], factory);\n` +
|
2015-08-14 22:00:41 +02:00
|
|
|
` }\n` +
|
2015-09-26 00:22:01 +02:00
|
|
|
`})(function (require, exports) {\n` +
|
2015-11-24 00:16:10 +01:00
|
|
|
` "use strict";\n` +
|
2015-08-14 22:00:41 +02:00
|
|
|
` var SomeName_1 = require("SomeOtherName");\n` +
|
|
|
|
` use(SomeName_1.foo);\n` +
|
|
|
|
`});\n`;
|
|
|
|
|
|
|
|
test(input,
|
|
|
|
{
|
|
|
|
options: { compilerOptions: { module: ModuleKind.UMD, newLine: NewLineKind.LineFeed }, renamedDependencies: { "SomeName": "SomeOtherName" } },
|
|
|
|
expectedOutput: output
|
|
|
|
});
|
|
|
|
});
|
2015-08-24 21:47:39 +02:00
|
|
|
|
|
|
|
it("Transpile with emit decorators and emit metadata", () => {
|
|
|
|
let input =
|
|
|
|
`import {db} from './db';\n` +
|
|
|
|
`function someDecorator(target) {\n` +
|
|
|
|
` return target;\n` +
|
|
|
|
`} \n` +
|
|
|
|
`@someDecorator\n` +
|
|
|
|
`class MyClass {\n` +
|
|
|
|
` db: db;\n` +
|
|
|
|
` constructor(db: db) {\n` +
|
|
|
|
` this.db = db;\n` +
|
|
|
|
` this.db.doSomething(); \n` +
|
|
|
|
` }\n` +
|
|
|
|
`}\n` +
|
|
|
|
`export {MyClass}; \n`
|
|
|
|
let output =
|
2015-11-24 00:16:10 +01:00
|
|
|
`"use strict";\n` +
|
2015-08-24 21:47:39 +02:00
|
|
|
`var db_1 = require(\'./db\');\n` +
|
|
|
|
`function someDecorator(target) {\n` +
|
|
|
|
` return target;\n` +
|
|
|
|
`}\n` +
|
|
|
|
`var MyClass = (function () {\n` +
|
|
|
|
` function MyClass(db) {\n` +
|
|
|
|
` this.db = db;\n` +
|
|
|
|
` this.db.doSomething();\n` +
|
|
|
|
` }\n` +
|
|
|
|
` MyClass = __decorate([\n` +
|
|
|
|
` someDecorator, \n` +
|
|
|
|
` __metadata(\'design:paramtypes\', [(typeof (_a = typeof db_1.db !== \'undefined\' && db_1.db) === \'function\' && _a) || Object])\n` +
|
|
|
|
` ], MyClass);\n` +
|
|
|
|
` return MyClass;\n` +
|
|
|
|
` var _a;\n` +
|
2015-12-09 02:49:29 +01:00
|
|
|
`}());\n` +
|
2015-08-24 21:47:39 +02:00
|
|
|
`exports.MyClass = MyClass;\n`;
|
2015-08-14 22:00:41 +02:00
|
|
|
|
2015-08-24 21:47:39 +02:00
|
|
|
test(input,
|
|
|
|
{
|
|
|
|
options: {
|
|
|
|
compilerOptions: {
|
|
|
|
module: ModuleKind.CommonJS,
|
|
|
|
newLine: NewLineKind.LineFeed,
|
|
|
|
noEmitHelpers: true,
|
|
|
|
emitDecoratorMetadata: true,
|
|
|
|
experimentalDecorators: true,
|
|
|
|
target: ScriptTarget.ES5,
|
|
|
|
}
|
|
|
|
},
|
|
|
|
expectedOutput: output
|
|
|
|
});
|
|
|
|
});
|
2015-09-03 18:25:43 +02:00
|
|
|
|
|
|
|
it("Supports backslashes in file name", () => {
|
2015-11-24 00:16:10 +01:00
|
|
|
test("var x", { expectedOutput: `"use strict";\r\nvar x;\r\n`, options: { fileName: "a\\b.ts" }});
|
2015-09-03 18:25:43 +02:00
|
|
|
});
|
2015-10-07 19:37:28 +02:00
|
|
|
|
|
|
|
it("transpile file as 'tsx' if 'jsx' is specified", () => {
|
2015-10-08 00:48:53 +02:00
|
|
|
let input = `var x = <div/>`;
|
2015-11-24 00:16:10 +01:00
|
|
|
let output = `"use strict";\nvar x = React.createElement("div", null);\n`;
|
2015-10-07 19:37:28 +02:00
|
|
|
test(input, {
|
|
|
|
expectedOutput: output,
|
2015-10-08 00:48:53 +02:00
|
|
|
options: { compilerOptions: { jsx: JsxEmit.React, newLine: NewLineKind.LineFeed } }
|
2015-10-07 19:37:28 +02:00
|
|
|
})
|
|
|
|
});
|
2015-05-27 05:18:13 +02:00
|
|
|
});
|
|
|
|
}
|