Skip to content

Commit

Permalink
Merge pull request #7522 from Microsoft/parseCompilerFlagsWithListOpt…
Browse files Browse the repository at this point in the history
…ions

Parsing compiler flags which takes options in form of list
  • Loading branch information
yuit committed Mar 17, 2016
2 parents 1156141 + 9e2df04 commit b5f418f
Show file tree
Hide file tree
Showing 8 changed files with 891 additions and 149 deletions.
5 changes: 4 additions & 1 deletion Jakefile.js
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,10 @@ var harnessSources = harnessCoreSources.concat([
"reuseProgramStructure.ts",
"cachingInServerLSHost.ts",
"moduleResolution.ts",
"tsconfigParsing.ts"
"tsconfigParsing.ts",
"commandLineParsing.ts",
"convertCompilerOptionsFromJson.ts",
"convertTypingOptionsFromJson.ts"
].map(function (f) {
return path.join(unittestsDirectory, f);
})).concat([
Expand Down
259 changes: 141 additions & 118 deletions src/compiler/commandLineParser.ts

Large diffs are not rendered by default.

33 changes: 8 additions & 25 deletions src/compiler/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -2240,11 +2240,11 @@
"category": "Message",
"code": 6002
},
"Specifies the location where debugger should locate map files instead of generated locations.": {
"Specify the location where debugger should locate map files instead of generated locations.": {
"category": "Message",
"code": 6003
},
"Specifies the location where debugger should locate TypeScript files instead of source locations.": {
"Specify the location where debugger should locate TypeScript files instead of source locations.": {
"category": "Message",
"code": 6004
},
Expand Down Expand Up @@ -2276,7 +2276,7 @@
"category": "Message",
"code": 6011
},
"Specify ECMAScript target version: 'ES3' (default), 'ES5', or 'ES2015' (experimental)": {
"Specify ECMAScript target version: 'ES3' (default), 'ES5', or 'ES2015'": {
"category": "Message",
"code": 6015
},
Expand Down Expand Up @@ -2364,14 +2364,10 @@
"category": "Error",
"code": 6045
},
"Argument for '--module' option must be 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'none'.": {
"Argument for '{0}' option must be: {1}": {
"category": "Error",
"code": 6046
},
"Argument for '--target' option must be 'ES3', 'ES5', or 'ES2015'.": {
"category": "Error",
"code": 6047
},
"Locale must be of the form <language> or <language>-<territory>. For example '{0}' or '{1}'.": {
"category": "Error",
"code": 6048
Expand Down Expand Up @@ -2408,30 +2404,22 @@
"category": "Message",
"code": 6056
},
"Specifies the root directory of input files. Use to control the output directory structure with --outDir.": {
"Specify the root directory of input files. Use to control the output directory structure with --outDir.": {
"category": "Message",
"code": 6058
},
"File '{0}' is not under 'rootDir' '{1}'. 'rootDir' is expected to contain all source files.": {
"category": "Error",
"code": 6059
},
"Specifies the end of line sequence to be used when emitting files: 'CRLF' (dos) or 'LF' (unix).": {
"Specify the end of line sequence to be used when emitting files: 'CRLF' (dos) or 'LF' (unix).": {
"category": "Message",
"code": 6060
},
"NEWLINE": {
"category": "Message",
"code": 6061
},
"Argument for '--newLine' option must be 'CRLF' or 'LF'.": {
"category": "Error",
"code": 6062
},
"Argument for '--moduleResolution' option must be 'node' or 'classic'.": {
"category": "Error",
"code": 6063
},
"Option '{0}' can only be specified in 'tsconfig.json' file.": {
"category": "Error",
"code": 6064
Expand All @@ -2448,7 +2436,7 @@
"category": "Message",
"code": 6068
},
"Specifies module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6).": {
"Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6).": {
"category": "Message",
"code": 6069
},
Expand Down Expand Up @@ -2492,10 +2480,6 @@
"category": "Message",
"code": 6080
},
"Argument for '--jsx' must be 'preserve' or 'react'.": {
"category": "Message",
"code": 6081
},
"Only 'amd' and 'system' modules are supported alongside --{0}.": {
"category": "Error",
"code": 6082
Expand All @@ -2504,7 +2488,7 @@
"category": "Message",
"code": 6083
},
"Specifies the object invoked for createElement and __spread when targeting 'react' JSX emit": {
"Specify the object invoked for createElement and __spread when targeting 'react' JSX emit": {
"category": "Message",
"code": 6084
},
Expand Down Expand Up @@ -2620,7 +2604,6 @@
"category": "Message",
"code": 6112
},

"Variable '{0}' implicitly has an '{1}' type.": {
"category": "Error",
"code": 7005
Expand Down
20 changes: 15 additions & 5 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2381,6 +2381,8 @@ namespace ts {
export type PathSubstitutions = Map<string[]>;
export type TsConfigOnlyOptions = RootPaths | PathSubstitutions;

export type CompilerOptionsValue = string | number | boolean | (string | number)[] | TsConfigOnlyOptions;

export interface CompilerOptions {
allowNonTsExtensions?: boolean;
charset?: string;
Expand Down Expand Up @@ -2437,14 +2439,17 @@ namespace ts {
allowSyntheticDefaultImports?: boolean;
allowJs?: boolean;
noImplicitUseStrict?: boolean;
lib?: string[];
/* @internal */ stripInternal?: boolean;

// Skip checking lib.d.ts to help speed up tests.
/* @internal */ skipDefaultLibCheck?: boolean;
// Do not perform validation of output file name in transpile scenarios
/* @internal */ suppressOutputPathCheck?: boolean;

[option: string]: string | number | boolean | TsConfigOnlyOptions;
list?: string[];

[option: string]: CompilerOptionsValue;
}

export interface TypingOptions {
Expand Down Expand Up @@ -2529,7 +2534,7 @@ namespace ts {
/* @internal */
export interface CommandLineOptionBase {
name: string;
type: "string" | "number" | "boolean" | "object" | Map<number>; // a value of a primitive type, or an object literal mapping named values to actual values
type: "string" | "number" | "boolean" | "object" | "list" | Map<number | string>; // a value of a primitive type, or an object literal mapping named values to actual values
isFilePath?: boolean; // True if option value is a path or fileName
shortName?: string; // A short mnemonic for convenience - for instance, 'h' can be used in place of 'help'
description?: DiagnosticMessage; // The message describing what the command line switch does
Expand All @@ -2545,8 +2550,7 @@ namespace ts {

/* @internal */
export interface CommandLineOptionOfCustomType extends CommandLineOptionBase {
type: Map<number>; // an object literal mapping named values to actual values
error: DiagnosticMessage; // The error given when the argument does not fit a customized 'type'
type: Map<number | string>; // an object literal mapping named values to actual values
}

/* @internal */
Expand All @@ -2555,7 +2559,13 @@ namespace ts {
}

/* @internal */
export type CommandLineOption = CommandLineOptionOfCustomType | CommandLineOptionOfPrimitiveType | TsConfigOnlyOption;
export interface CommandLineOptionOfListType extends CommandLineOptionBase {
type: "list";
element: CommandLineOptionOfCustomType | CommandLineOptionOfPrimitiveType;
}

/* @internal */
export type CommandLineOption = CommandLineOptionOfCustomType | CommandLineOptionOfPrimitiveType | TsConfigOnlyOption | CommandLineOptionOfListType;

/* @internal */
export const enum CharacterCodes {
Expand Down
191 changes: 191 additions & 0 deletions tests/cases/unittests/commandLineParsing.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
/// <reference path="..\..\..\src\harness\harness.ts" />
/// <reference path="..\..\..\src\compiler\commandLineParser.ts" />

namespace ts {
describe('parseCommandLine', () => {

function assertParseResult(commandLine: string[], expectedParsedCommandLine: ts.ParsedCommandLine) {
const parsed = ts.parseCommandLine(commandLine);
const parsedCompilerOptions = JSON.stringify(parsed.options);
const expectedCompilerOptions = JSON.stringify(expectedParsedCommandLine.options);
assert.equal(parsedCompilerOptions, expectedCompilerOptions);

const parsedErrors = parsed.errors;
const expectedErrors = expectedParsedCommandLine.errors;
assert.isTrue(parsedErrors.length === expectedErrors.length, `Expected error: ${JSON.stringify(expectedErrors)}. Actual error: ${JSON.stringify(parsedErrors)}.`);
for (let i = 0; i < parsedErrors.length; ++i) {
const parsedError = parsedErrors[i];
const expectedError = expectedErrors[i];
assert.equal(parsedError.code, expectedError.code);
assert.equal(parsedError.category, expectedError.category);
assert.equal(parsedError.messageText, expectedError.messageText);
}

const parsedFileNames = parsed.fileNames;
const expectedFileNames = expectedParsedCommandLine.fileNames;
assert.isTrue(parsedFileNames.length === expectedFileNames.length, `Expected fileNames: [${JSON.stringify(expectedFileNames)}]. Actual fileNames: [${JSON.stringify(parsedFileNames)}].`);
for (let i = 0; i < parsedFileNames.length; ++i) {
const parsedFileName = parsedFileNames[i];
const expectedFileName = expectedFileNames[i];
assert.equal(parsedFileName, expectedFileName);
}
}

it("Parse empty options of --jsx ", () => {
// 0.ts --jsx
assertParseResult(["0.ts", "--jsx"],
{
errors: [{
messageText: "Compiler option 'jsx' expects an argument.",
category: ts.Diagnostics.Compiler_option_0_expects_an_argument.category,
code: ts.Diagnostics.Compiler_option_0_expects_an_argument.code,

file: undefined,
start: undefined,
length: undefined,
}, {
messageText: "Argument for '--jsx' option must be: 'preserve', 'react'",
category: ts.Diagnostics.Argument_for_0_option_must_be_Colon_1.category,
code: ts.Diagnostics.Argument_for_0_option_must_be_Colon_1.code,

file: undefined,
start: undefined,
length: undefined,
}],
fileNames: ["0.ts"],
options: {}
});
});

it("Parse empty options of --module ", () => {
// 0.ts --
assertParseResult(["0.ts", "--module"],
{
errors: [{
messageText: "Compiler option 'module' expects an argument.",
category: ts.Diagnostics.Compiler_option_0_expects_an_argument.category,
code: ts.Diagnostics.Compiler_option_0_expects_an_argument.code,

file: undefined,
start: undefined,
length: undefined,
}, {
messageText: "Argument for '--module' option must be: 'none', 'commonjs', 'amd', 'system', 'umd', 'es6', 'es2015'",
category: ts.Diagnostics.Argument_for_0_option_must_be_Colon_1.category,
code: ts.Diagnostics.Argument_for_0_option_must_be_Colon_1.code,

file: undefined,
start: undefined,
length: undefined,
}],
fileNames: ["0.ts"],
options: {}
});
});

it("Parse empty options of --newLine ", () => {
// 0.ts --newLine
assertParseResult(["0.ts", "--newLine"],
{
errors: [{
messageText: "Compiler option 'newLine' expects an argument.",
category: ts.Diagnostics.Compiler_option_0_expects_an_argument.category,
code: ts.Diagnostics.Compiler_option_0_expects_an_argument.code,

file: undefined,
start: undefined,
length: undefined,
}, {
messageText: "Argument for '--newLine' option must be: 'crlf', 'lf'",
category: ts.Diagnostics.Argument_for_0_option_must_be_Colon_1.category,
code: ts.Diagnostics.Argument_for_0_option_must_be_Colon_1.code,

file: undefined,
start: undefined,
length: undefined,
}],
fileNames: ["0.ts"],
options: {}
});
});

it("Parse empty options of --target ", () => {
// 0.ts --target
assertParseResult(["0.ts", "--target"],
{
errors: [{
messageText: "Compiler option 'target' expects an argument.",
category: ts.Diagnostics.Compiler_option_0_expects_an_argument.category,
code: ts.Diagnostics.Compiler_option_0_expects_an_argument.code,

file: undefined,
start: undefined,
length: undefined,
}, {
messageText: "Argument for '--target' option must be: 'es3', 'es5', 'es6', 'es2015'",
category: ts.Diagnostics.Argument_for_0_option_must_be_Colon_1.category,
code: ts.Diagnostics.Argument_for_0_option_must_be_Colon_1.code,

file: undefined,
start: undefined,
length: undefined,
}],
fileNames: ["0.ts"],
options: {}
});
});

it("Parse empty options of --moduleResolution ", () => {
// 0.ts --moduleResolution
assertParseResult(["0.ts", "--moduleResolution"],
{
errors: [{
messageText: "Compiler option 'moduleResolution' expects an argument.",
category: ts.Diagnostics.Compiler_option_0_expects_an_argument.category,
code: ts.Diagnostics.Compiler_option_0_expects_an_argument.code,

file: undefined,
start: undefined,
length: undefined,
}, {
messageText: "Argument for '--moduleResolution' option must be: 'node', 'classic'",
category: ts.Diagnostics.Argument_for_0_option_must_be_Colon_1.category,
code: ts.Diagnostics.Argument_for_0_option_must_be_Colon_1.code,

file: undefined,
start: undefined,
length: undefined,
}],
fileNames: ["0.ts"],
options: {}
});
});

it("Parse multiple compiler flags with input files at the end", () => {
// --module commonjs --target es5 0.ts
assertParseResult(["--module", "commonjs", "--target", "es5", "0.ts"],
{
errors: [],
fileNames: ["0.ts"],
options: {
module: ts.ModuleKind.CommonJS,
target: ts.ScriptTarget.ES5,
}
});
});

it("Parse multiple compiler flags with input files in the middle", () => {
// --module commonjs --target es5 0.ts --noImplicitAny
assertParseResult(["--module", "commonjs", "--target", "es5", "0.ts", "--noImplicitAny"],
{
errors: [],
fileNames: ["0.ts"],
options: {
module: ts.ModuleKind.CommonJS,
target: ts.ScriptTarget.ES5,
noImplicitAny: true,
}
});
});
});
}
Loading

0 comments on commit b5f418f

Please sign in to comment.