Merge pull request #3982 from Microsoft/sourceMapsInTranspile
add transpileModule function that can return emitted source map
This commit is contained in:
commit
e1fa3c5515
|
@ -509,7 +509,6 @@ namespace ts {
|
|||
Option_noEmit_cannot_be_specified_with_option_out_or_outDir: { code: 5040, category: DiagnosticCategory.Error, key: "Option 'noEmit' cannot be specified with option 'out' or 'outDir'." },
|
||||
Option_noEmit_cannot_be_specified_with_option_declaration: { code: 5041, category: DiagnosticCategory.Error, key: "Option 'noEmit' cannot be specified with option 'declaration'." },
|
||||
Option_project_cannot_be_mixed_with_source_files_on_a_command_line: { code: 5042, category: DiagnosticCategory.Error, key: "Option 'project' cannot be mixed with source files on a command line." },
|
||||
Option_sourceMap_cannot_be_specified_with_option_isolatedModules: { code: 5043, category: DiagnosticCategory.Error, key: "Option 'sourceMap' cannot be specified with option 'isolatedModules'." },
|
||||
Option_declaration_cannot_be_specified_with_option_isolatedModules: { code: 5044, category: DiagnosticCategory.Error, key: "Option 'declaration' cannot be specified with option 'isolatedModules'." },
|
||||
Option_noEmitOnError_cannot_be_specified_with_option_isolatedModules: { code: 5045, category: DiagnosticCategory.Error, key: "Option 'noEmitOnError' cannot be specified with option 'isolatedModules'." },
|
||||
Option_out_cannot_be_specified_with_option_isolatedModules: { code: 5046, category: DiagnosticCategory.Error, key: "Option 'out' cannot be specified with option 'isolatedModules'." },
|
||||
|
|
|
@ -2025,10 +2025,6 @@
|
|||
"category": "Error",
|
||||
"code": 5042
|
||||
},
|
||||
"Option 'sourceMap' cannot be specified with option 'isolatedModules'.": {
|
||||
"category": "Error",
|
||||
"code": 5043
|
||||
},
|
||||
"Option 'declaration' cannot be specified with option 'isolatedModules'.": {
|
||||
"category": "Error",
|
||||
"code": 5044
|
||||
|
|
|
@ -602,10 +602,6 @@ namespace ts {
|
|||
|
||||
function verifyCompilerOptions() {
|
||||
if (options.isolatedModules) {
|
||||
if (options.sourceMap) {
|
||||
diagnostics.add(createCompilerDiagnostic(Diagnostics.Option_sourceMap_cannot_be_specified_with_option_isolatedModules));
|
||||
}
|
||||
|
||||
if (options.declaration) {
|
||||
diagnostics.add(createCompilerDiagnostic(Diagnostics.Option_declaration_cannot_be_specified_with_option_isolatedModules));
|
||||
}
|
||||
|
|
|
@ -1760,18 +1760,31 @@ namespace ts {
|
|||
sourceFile.version = version;
|
||||
sourceFile.scriptSnapshot = scriptSnapshot;
|
||||
}
|
||||
|
||||
|
||||
export interface TranspileOptions {
|
||||
compilerOptions?: CompilerOptions;
|
||||
fileName?: string;
|
||||
reportDiagnostics?: boolean;
|
||||
moduleName?: string;
|
||||
}
|
||||
|
||||
export interface TranspileOutput {
|
||||
outputText: string;
|
||||
diagnostics?: Diagnostic[];
|
||||
sourceMapText?: string;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function will compile source text from 'input' argument using specified compiler options.
|
||||
* If not options are provided - it will use a set of default compiler options.
|
||||
* Extra compiler options that will unconditionally be used bu this function are:
|
||||
* Extra compiler options that will unconditionally be used by this function are:
|
||||
* - isolatedModules = true
|
||||
* - allowNonTsExtensions = true
|
||||
* - noLib = true
|
||||
* - noResolve = true
|
||||
*/
|
||||
export function transpile(input: string, compilerOptions?: CompilerOptions, fileName?: string, diagnostics?: Diagnostic[], moduleName?: string): string {
|
||||
let options = compilerOptions ? clone(compilerOptions) : getDefaultCompilerOptions();
|
||||
*/
|
||||
export function transpileModule(input: string, transpileOptions?: TranspileOptions): TranspileOutput {
|
||||
let options = transpileOptions.compilerOptions ? clone(transpileOptions.compilerOptions) : getDefaultCompilerOptions();
|
||||
|
||||
options.isolatedModules = true;
|
||||
|
||||
|
@ -1787,23 +1800,30 @@ namespace ts {
|
|||
options.noResolve = true;
|
||||
|
||||
// Parse
|
||||
let inputFileName = fileName || "module.ts";
|
||||
let inputFileName = transpileOptions.fileName || "module.ts";
|
||||
let sourceFile = createSourceFile(inputFileName, input, options.target);
|
||||
if (moduleName) {
|
||||
sourceFile.moduleName = moduleName;
|
||||
if (transpileOptions.moduleName) {
|
||||
sourceFile.moduleName = transpileOptions.moduleName;
|
||||
}
|
||||
|
||||
let newLine = getNewLineCharacter(options);
|
||||
|
||||
// Output
|
||||
let outputText: string;
|
||||
let sourceMapText: string;
|
||||
|
||||
// Create a compilerHost object to allow the compiler to read and write files
|
||||
let compilerHost: CompilerHost = {
|
||||
getSourceFile: (fileName, target) => fileName === inputFileName ? sourceFile : undefined,
|
||||
writeFile: (name, text, writeByteOrderMark) => {
|
||||
Debug.assert(outputText === undefined, "Unexpected multiple outputs for the file: " + name);
|
||||
outputText = text;
|
||||
if (fileExtensionIs(name, ".map")) {
|
||||
Debug.assert(sourceMapText === undefined, `Unexpected multiple source map outputs for the file '${name}'`);
|
||||
sourceMapText = text;
|
||||
}
|
||||
else {
|
||||
Debug.assert(outputText === undefined, "Unexpected multiple outputs for the file: " + name);
|
||||
outputText = text;
|
||||
}
|
||||
},
|
||||
getDefaultLibFileName: () => "lib.d.ts",
|
||||
useCaseSensitiveFileNames: () => false,
|
||||
|
@ -1813,16 +1833,29 @@ namespace ts {
|
|||
};
|
||||
|
||||
let program = createProgram([inputFileName], options, compilerHost);
|
||||
|
||||
addRange(/*to*/ diagnostics, /*from*/ program.getSyntacticDiagnostics(sourceFile));
|
||||
addRange(/*to*/ diagnostics, /*from*/ program.getOptionsDiagnostics());
|
||||
|
||||
|
||||
let diagnostics: Diagnostic[];
|
||||
if (transpileOptions.reportDiagnostics) {
|
||||
diagnostics = [];
|
||||
addRange(/*to*/ diagnostics, /*from*/ program.getSyntacticDiagnostics(sourceFile));
|
||||
addRange(/*to*/ diagnostics, /*from*/ program.getOptionsDiagnostics());
|
||||
}
|
||||
// Emit
|
||||
program.emit();
|
||||
|
||||
Debug.assert(outputText !== undefined, "Output generation failed");
|
||||
|
||||
return outputText;
|
||||
return { outputText, diagnostics, sourceMapText };
|
||||
}
|
||||
|
||||
/*
|
||||
* This is a shortcut function for transpileModule - it accepts transpileOptions as parameters and returns only outputText part of the result.
|
||||
*/
|
||||
export function transpile(input: string, compilerOptions?: CompilerOptions, fileName?: string, diagnostics?: Diagnostic[], moduleName?: string): string {
|
||||
let output = transpileModule(input, { compilerOptions, fileName, reportDiagnostics: !!diagnostics, moduleName });
|
||||
// addRange correctly handles cases when wither 'from' or 'to' argument is missing
|
||||
addRange(diagnostics, output.diagnostics);
|
||||
return output.outputText;
|
||||
}
|
||||
|
||||
export function createLanguageServiceSourceFile(fileName: string, scriptSnapshot: IScriptSnapshot, scriptTarget: ScriptTarget, version: string, setNodeParents: boolean): SourceFile {
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
error TS5043: Option 'sourceMap' cannot be specified with option 'isolatedModules'.
|
||||
|
||||
|
||||
!!! error TS5043: Option 'sourceMap' cannot be specified with option 'isolatedModules'.
|
||||
==== tests/cases/compiler/isolatedModulesSourceMap.ts (0 errors) ====
|
||||
|
||||
export var x;
|
|
@ -1,7 +1,7 @@
|
|||
//// [isolatedModulesSourceMap.ts]
|
||||
|
||||
export var x;
|
||||
export var x = 1;
|
||||
|
||||
//// [isolatedModulesSourceMap.js]
|
||||
export var x;
|
||||
export var x = 1;
|
||||
//# sourceMappingURL=isolatedModulesSourceMap.js.map
|
|
@ -1,2 +1,2 @@
|
|||
//// [isolatedModulesSourceMap.js.map]
|
||||
{"version":3,"file":"isolatedModulesSourceMap.js","sourceRoot":"","sources":["isolatedModulesSourceMap.ts"],"names":[],"mappings":"AACA,WAAW,CAAC,CAAC"}
|
||||
{"version":3,"file":"isolatedModulesSourceMap.js","sourceRoot":"","sources":["isolatedModulesSourceMap.ts"],"names":[],"mappings":"AACA,WAAW,CAAC,GAAG,CAAC,CAAC"}
|
|
@ -8,20 +8,26 @@ sources: isolatedModulesSourceMap.ts
|
|||
emittedFile:tests/cases/compiler/isolatedModulesSourceMap.js
|
||||
sourceFile:isolatedModulesSourceMap.ts
|
||||
-------------------------------------------------------------------
|
||||
>>>export var x;
|
||||
>>>export var x = 1;
|
||||
1 >
|
||||
2 >^^^^^^^^^^^
|
||||
3 > ^
|
||||
4 > ^
|
||||
5 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^->
|
||||
4 > ^^^
|
||||
5 > ^
|
||||
6 > ^
|
||||
7 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^->
|
||||
1 >
|
||||
>
|
||||
2 >export var
|
||||
3 > x
|
||||
4 > ;
|
||||
4 > =
|
||||
5 > 1
|
||||
6 > ;
|
||||
1 >Emitted(1, 1) Source(2, 1) + SourceIndex(0)
|
||||
2 >Emitted(1, 12) Source(2, 12) + SourceIndex(0)
|
||||
3 >Emitted(1, 13) Source(2, 13) + SourceIndex(0)
|
||||
4 >Emitted(1, 14) Source(2, 14) + SourceIndex(0)
|
||||
4 >Emitted(1, 16) Source(2, 16) + SourceIndex(0)
|
||||
5 >Emitted(1, 17) Source(2, 17) + SourceIndex(0)
|
||||
6 >Emitted(1, 18) Source(2, 18) + SourceIndex(0)
|
||||
---
|
||||
>>>//# sourceMappingURL=isolatedModulesSourceMap.js.map
|
|
@ -0,0 +1,5 @@
|
|||
=== tests/cases/compiler/isolatedModulesSourceMap.ts ===
|
||||
|
||||
export var x = 1;
|
||||
>x : Symbol(x, Decl(isolatedModulesSourceMap.ts, 1, 10))
|
||||
|
6
tests/baselines/reference/isolatedModulesSourceMap.types
Normal file
6
tests/baselines/reference/isolatedModulesSourceMap.types
Normal file
|
@ -0,0 +1,6 @@
|
|||
=== tests/cases/compiler/isolatedModulesSourceMap.ts ===
|
||||
|
||||
export var x = 1;
|
||||
>x : number
|
||||
>1 : number
|
||||
|
|
@ -3,4 +3,4 @@
|
|||
// @target: es6
|
||||
|
||||
// @filename: file1.ts
|
||||
export var x;
|
||||
export var x = 1;
|
|
@ -2,58 +2,120 @@
|
|||
|
||||
module ts {
|
||||
describe("Transpile", () => {
|
||||
|
||||
function runTest(input: string, compilerOptions: ts.CompilerOptions = {}, fileName?: string, moduleName?: string, expectedOutput?: string, expectedDiagnosticCodes: number[] = []): void {
|
||||
let diagnostics: Diagnostic[] = [];
|
||||
let result = transpile(input, compilerOptions, fileName || "file.ts", diagnostics, moduleName);
|
||||
|
||||
|
||||
interface TranspileTestSettings {
|
||||
options?: TranspileOptions;
|
||||
expectedOutput?: string;
|
||||
expectedDiagnosticCodes?: number[];
|
||||
}
|
||||
|
||||
function checkDiagnostics(diagnostics: Diagnostic[], expectedDiagnosticCodes?: number[]) {
|
||||
if(!expectedDiagnosticCodes) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (let i = 0; i < expectedDiagnosticCodes.length; i++) {
|
||||
assert.equal(expectedDiagnosticCodes[i], diagnostics[i] && diagnostics[i].code, `Could not find expeced diagnostic.`);
|
||||
}
|
||||
assert.equal(diagnostics.length, expectedDiagnosticCodes.length, "Resuting diagnostics count does not match expected");
|
||||
|
||||
if (expectedOutput !== undefined) {
|
||||
assert.equal(result, expectedOutput);
|
||||
}
|
||||
assert.equal(diagnostics.length, expectedDiagnosticCodes.length, "Resuting diagnostics count does not match expected");
|
||||
}
|
||||
|
||||
function test(input: string, testSettings: TranspileTestSettings): void {
|
||||
let diagnostics: Diagnostic[] = [];
|
||||
|
||||
let transpileOptions: TranspileOptions = testSettings.options || {};
|
||||
let transpileResult = transpile(input, transpileOptions.compilerOptions, transpileOptions.fileName, diagnostics, transpileOptions.moduleName);
|
||||
|
||||
transpileOptions.reportDiagnostics = true;
|
||||
let transpileModuleResult = transpileModule(input, transpileOptions);
|
||||
|
||||
checkDiagnostics(diagnostics, testSettings.expectedDiagnosticCodes);
|
||||
checkDiagnostics(transpileModuleResult.diagnostics, testSettings.expectedDiagnosticCodes);
|
||||
|
||||
if (testSettings.expectedOutput !== undefined) {
|
||||
assert.equal(transpileResult, testSettings.expectedOutput);
|
||||
assert.equal(transpileModuleResult.outputText, testSettings.expectedOutput);
|
||||
}
|
||||
|
||||
// check source maps
|
||||
if (!transpileOptions.compilerOptions) {
|
||||
transpileOptions.compilerOptions = {};
|
||||
}
|
||||
|
||||
if (!transpileOptions.fileName) {
|
||||
transpileOptions.fileName = "file.ts";
|
||||
}
|
||||
|
||||
transpileOptions.compilerOptions.sourceMap = true;
|
||||
let transpileModuleResultWithSourceMap = transpileModule(input, transpileOptions);
|
||||
assert.isTrue(transpileModuleResultWithSourceMap.sourceMapText !== undefined);
|
||||
|
||||
let expectedSourceMapFileName = removeFileExtension(transpileOptions.fileName) + ".js.map";
|
||||
let expectedSourceMappingUrlLine = `//# sourceMappingURL=${expectedSourceMapFileName}`;
|
||||
|
||||
if (testSettings.expectedOutput !== undefined) {
|
||||
assert.equal(transpileModuleResultWithSourceMap.outputText, testSettings.expectedOutput + expectedSourceMappingUrlLine);
|
||||
}
|
||||
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 {
|
||||
let suffix = getNewLineCharacter(transpileOptions.compilerOptions) + expectedSourceMappingUrlLine
|
||||
assert.isTrue(output.indexOf(suffix, output.length - suffix.length) !== -1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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."
|
||||
runTest(`var x = 0;`, {}, /*fileName*/ undefined, /*moduleName*/undefined, /*expectedOutput*/ undefined, /*expectedDiagnosticCodes*/ [5047]);
|
||||
test(`var x = 0;`, { expectedDiagnosticCodes: [5047] });
|
||||
});
|
||||
|
||||
it("Generates no diagnostics with valid inputs", () => {
|
||||
// No errors
|
||||
runTest(`var x = 0;`, { module: ModuleKind.CommonJS }, /*fileName*/ undefined, /*moduleName*/undefined, /*expectedOutput*/ undefined, /*expectedDiagnosticCodes*/ []);
|
||||
test(`var x = 0;`, { options: { compilerOptions: { module: ModuleKind.CommonJS } } });
|
||||
});
|
||||
|
||||
it("Generates no diagnostics for missing file references", () => {
|
||||
runTest(`/// <reference path="file2.ts" />
|
||||
var x = 0;`,
|
||||
{ module: ModuleKind.CommonJS }, /*fileName*/ undefined, /*moduleName*/undefined, /*expectedOutput*/ undefined, /*expectedDiagnosticCodes*/ []);
|
||||
test(`/// <reference path="file2.ts" />
|
||||
var x = 0;`,
|
||||
{ options: { compilerOptions: { module: ModuleKind.CommonJS } } });
|
||||
});
|
||||
|
||||
it("Generates no diagnostics for missing module imports", () => {
|
||||
runTest(`import {a} from "module2";`,
|
||||
{ module: ModuleKind.CommonJS }, /*fileName*/ undefined,/*moduleName*/undefined, /*expectedOutput*/ undefined, /*expectedDiagnosticCodes*/ []);
|
||||
test(`import {a} from "module2";`,
|
||||
{ options: { compilerOptions: { module: ModuleKind.CommonJS } } });
|
||||
});
|
||||
|
||||
it("Generates expected syntactic diagnostics", () => {
|
||||
runTest(`a b`,
|
||||
{ module: ModuleKind.CommonJS }, /*fileName*/ undefined, /*moduleName*/undefined, /*expectedOutput*/ undefined, /*expectedDiagnosticCodes*/ [1005]); /// 1005: ';' Expected
|
||||
test(`a b`,
|
||||
{ options: { compilerOptions: { module: ModuleKind.CommonJS } }, expectedDiagnosticCodes: [1005] }); /// 1005: ';' Expected
|
||||
});
|
||||
|
||||
it("Does not generate semantic diagnostics", () => {
|
||||
runTest(`var x: string = 0;`,
|
||||
{ module: ModuleKind.CommonJS }, /*fileName*/ undefined, /*moduleName*/undefined, /*expectedOutput*/ undefined, /*expectedDiagnosticCodes*/ []);
|
||||
test(`var x: string = 0;`,
|
||||
{ options: { compilerOptions: { module: ModuleKind.CommonJS } } });
|
||||
});
|
||||
|
||||
it("Generates module output", () => {
|
||||
runTest(`var x = 0;`, { module: ModuleKind.AMD }, /*fileName*/ undefined, /*moduleName*/undefined, `define(["require", "exports"], function (require, exports) {\r\n var x = 0;\r\n});\r\n`);
|
||||
test(`var x = 0;`,
|
||||
{
|
||||
options: { compilerOptions: { module: ModuleKind.AMD } },
|
||||
expectedOutput: `define(["require", "exports"], function (require, exports) {\r\n var x = 0;\r\n});\r\n`
|
||||
});
|
||||
});
|
||||
|
||||
it("Uses correct newLine character", () => {
|
||||
runTest(`var x = 0;`, { module: ModuleKind.CommonJS, newLine: NewLineKind.LineFeed }, /*fileName*/ undefined, /*moduleName*/undefined, `var x = 0;\n`, /*expectedDiagnosticCodes*/ []);
|
||||
test(`var x = 0;`,
|
||||
{
|
||||
options: { compilerOptions: { module: ModuleKind.CommonJS, newLine: NewLineKind.LineFeed } },
|
||||
expectedOutput: `var x = 0;\n`
|
||||
});
|
||||
});
|
||||
|
||||
it("Sets module name", () => {
|
||||
|
@ -66,12 +128,15 @@ var x = 0;`,
|
|||
` }\n` +
|
||||
` }\n` +
|
||||
`});\n`;
|
||||
runTest("var x = 1;", { module: ModuleKind.System, newLine: NewLineKind.LineFeed }, /*fileName*/ undefined, "NamedModule", output)
|
||||
test("var x = 1;",
|
||||
{
|
||||
options: { compilerOptions: { module: ModuleKind.System, newLine: NewLineKind.LineFeed }, moduleName: "NamedModule" },
|
||||
expectedOutput: output
|
||||
})
|
||||
});
|
||||
|
||||
it("No extra errors for file without extension", () => {
|
||||
runTest(`var x = 0;`, { module: ModuleKind.CommonJS }, "file", /*moduleName*/undefined, /*expectedOutput*/ undefined, /*expectedDiagnosticCodes*/[]);
|
||||
test(`var x = 0;`, { options: { compilerOptions: { module: ModuleKind.CommonJS }, fileName: "file" } });
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue