Skip to content

Commit 75b8293

Browse files
author
Andy
committed
Merge pull request #8988 from Microsoft/transpile_options
Support using string values in enums for CompilerOptions in transpile
2 parents 9e12290 + 9ef9b74 commit 75b8293

File tree

3 files changed

+79
-17
lines changed

3 files changed

+79
-17
lines changed

src/compiler/commandLineParser.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
namespace ts {
88
/* @internal */
9-
export let optionDeclarations: CommandLineOption[] = [
9+
export const optionDeclarations: CommandLineOption[] = [
1010
{
1111
name: "charset",
1212
type: "string",

src/services/services.ts

+37-3
Original file line numberDiff line numberDiff line change
@@ -1939,6 +1939,40 @@ namespace ts {
19391939
sourceMapText?: string;
19401940
}
19411941

1942+
1943+
1944+
let commandLineOptions_stringToEnum: CommandLineOptionOfCustomType[];
1945+
1946+
/** JS users may pass in string values for enum compiler options (such as ModuleKind), so convert. */
1947+
function fixupCompilerOptions(options: CompilerOptions, diagnostics: Diagnostic[]): CompilerOptions {
1948+
// Lazily create this value to fix module loading errors.
1949+
commandLineOptions_stringToEnum = commandLineOptions_stringToEnum || <CommandLineOptionOfCustomType[]>filter(optionDeclarations, o =>
1950+
typeof o.type === "object" && !forEachValue(<Map<any>> o.type, v => typeof v !== "number"));
1951+
1952+
options = clone(options);
1953+
1954+
for (const opt of commandLineOptions_stringToEnum) {
1955+
if (!hasProperty(options, opt.name)) {
1956+
continue;
1957+
}
1958+
1959+
const value = options[opt.name];
1960+
// Value should be a key of opt.type
1961+
if (typeof value === "string") {
1962+
// If value is not a string, this will fail
1963+
options[opt.name] = parseCustomTypeOption(opt, value, diagnostics);
1964+
}
1965+
else {
1966+
if (!forEachValue(opt.type, v => v === value)) {
1967+
// Supplied value isn't a valid enum value.
1968+
diagnostics.push(createCompilerDiagnosticForInvalidCustomType(opt));
1969+
}
1970+
}
1971+
}
1972+
1973+
return options;
1974+
}
1975+
19421976
/*
19431977
* This function will compile source text from 'input' argument using specified compiler options.
19441978
* If not options are provided - it will use a set of default compiler options.
@@ -1949,7 +1983,9 @@ namespace ts {
19491983
* - noResolve = true
19501984
*/
19511985
export function transpileModule(input: string, transpileOptions: TranspileOptions): TranspileOutput {
1952-
const options = transpileOptions.compilerOptions ? clone(transpileOptions.compilerOptions) : getDefaultCompilerOptions();
1986+
const diagnostics: Diagnostic[] = [];
1987+
1988+
const options: CompilerOptions = transpileOptions.compilerOptions ? fixupCompilerOptions(transpileOptions.compilerOptions, diagnostics) : getDefaultCompilerOptions();
19531989

19541990
options.isolatedModules = true;
19551991

@@ -2007,9 +2043,7 @@ namespace ts {
20072043

20082044
const program = createProgram([inputFileName], options, compilerHost);
20092045

2010-
let diagnostics: Diagnostic[];
20112046
if (transpileOptions.reportDiagnostics) {
2012-
diagnostics = [];
20132047
addRange(/*to*/ diagnostics, /*from*/ program.getSyntacticDiagnostics(sourceFile));
20142048
addRange(/*to*/ diagnostics, /*from*/ program.getOptionsDiagnostics());
20152049
}

tests/cases/unittests/transpile.ts

+41-13
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,21 @@ namespace ts {
77
options?: TranspileOptions;
88
expectedOutput?: string;
99
expectedDiagnosticCodes?: number[];
10+
expectedDiagnosticTexts?: string[];
1011
}
1112

12-
function checkDiagnostics(diagnostics: Diagnostic[], expectedDiagnosticCodes?: number[]) {
13-
if (!expectedDiagnosticCodes) {
14-
return;
13+
function checkDiagnostics(diagnostics: Diagnostic[], expectedDiagnosticCodes: number[] = [], expectedDiagnosticTexts?: string[]) {
14+
const n = expectedDiagnosticCodes.length;
15+
if (expectedDiagnosticTexts) {
16+
assert.equal(n, expectedDiagnosticTexts.length);
1517
}
16-
17-
for (let i = 0; i < expectedDiagnosticCodes.length; i++) {
18-
assert.equal(expectedDiagnosticCodes[i], diagnostics[i] && diagnostics[i].code, `Could not find expeced diagnostic.`);
19-
}
20-
assert.equal(diagnostics.length, expectedDiagnosticCodes.length, "Resuting diagnostics count does not match expected");
18+
for (let i = 0; i < n; i++) {
19+
assert.equal(expectedDiagnosticCodes[i], diagnostics[i] && diagnostics[i].code, `Could not find expected diagnostic.`);
20+
if (expectedDiagnosticTexts) {
21+
assert.equal(expectedDiagnosticTexts[i], diagnostics[i] && diagnostics[i].messageText);
22+
}
23+
};
24+
assert.equal(diagnostics.length, n, "Resuting diagnostics count does not match expected");
2125
}
2226

2327
function test(input: string, testSettings: TranspileTestSettings): void {
@@ -26,7 +30,7 @@ namespace ts {
2630
if (!transpileOptions.compilerOptions) {
2731
transpileOptions.compilerOptions = {};
2832
}
29-
if (transpileOptions.compilerOptions.newLine === undefined) { //
33+
if (transpileOptions.compilerOptions.newLine === undefined) {
3034
// use \r\n as default new line
3135
transpileOptions.compilerOptions.newLine = ts.NewLineKind.CarriageReturnLineFeed;
3236
}
@@ -36,7 +40,7 @@ namespace ts {
3640
transpileOptions.reportDiagnostics = true;
3741
const transpileModuleResult = transpileModule(input, transpileOptions);
3842

39-
checkDiagnostics(transpileModuleResult.diagnostics, testSettings.expectedDiagnosticCodes);
43+
checkDiagnostics(transpileModuleResult.diagnostics, testSettings.expectedDiagnosticCodes, testSettings.expectedDiagnosticTexts);
4044

4145
if (testSettings.expectedOutput !== undefined) {
4246
assert.equal(transpileModuleResult.outputText, testSettings.expectedOutput);
@@ -45,7 +49,7 @@ namespace ts {
4549
if (canUseOldTranspile) {
4650
const diagnostics: Diagnostic[] = [];
4751
const transpileResult = transpile(input, transpileOptions.compilerOptions, transpileOptions.fileName, diagnostics, transpileOptions.moduleName);
48-
checkDiagnostics(diagnostics, testSettings.expectedDiagnosticCodes);
52+
checkDiagnostics(diagnostics, testSettings.expectedDiagnosticCodes, testSettings.expectedDiagnosticTexts);
4953
if (testSettings.expectedOutput) {
5054
assert.equal(transpileResult, testSettings.expectedOutput);
5155
}
@@ -292,13 +296,37 @@ var x = 0;`,
292296
const output = `"use strict";\nvar a = 10;\n`;
293297
test(input, {
294298
expectedOutput: output,
295-
options: { compilerOptions: { newLine: NewLineKind.LineFeed, module: ModuleKind.CommonJS }, fileName: "input.js", reportDiagnostics: true },
296-
expectedDiagnosticCodes: []
299+
options: { compilerOptions: { newLine: NewLineKind.LineFeed, module: ModuleKind.CommonJS }, fileName: "input.js", reportDiagnostics: true }
297300
});
298301
});
299302

300303
it("Supports urls in file name", () => {
301304
test("var x", { expectedOutput: `"use strict";\r\nvar x;\r\n`, options: { fileName: "http://somewhere/directory//directory2/file.ts" } });
302305
});
306+
307+
describe("String values for enums", () => {
308+
it("Accepts strings instead of enum values", () => {
309+
test(`export const x = 0`, {
310+
options: {
311+
compilerOptions: {
312+
module: <ModuleKind><any>"es6",
313+
// Capitalization and spaces ignored
314+
target: <ScriptTarget><any>" Es6 "
315+
}
316+
},
317+
expectedOutput: "export const x = 0;\r\n"
318+
});
319+
});
320+
321+
it("Fails on bad value", () => {
322+
for (const value in [123, {}, ""]) {
323+
test(``, {
324+
options: { compilerOptions: { module: <ModuleKind><any>value } },
325+
expectedDiagnosticCodes: [6046],
326+
expectedDiagnosticTexts: ["Argument for '--module' option must be: 'none', 'commonjs', 'amd', 'system', 'umd', 'es6', 'es2015'"]
327+
});
328+
}
329+
});
330+
});
303331
});
304332
}

0 commit comments

Comments
 (0)