mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-04 21:53:42 -06:00
Add more errors; commandline help for --build; invalid flag combo detection
This commit is contained in:
parent
129f747ccc
commit
f8c4301f14
@ -49,6 +49,14 @@ namespace ts {
|
||||
paramType: Diagnostics.FILE_OR_DIRECTORY,
|
||||
description: Diagnostics.Compile_the_project_given_the_path_to_its_configuration_file_or_to_a_folder_with_a_tsconfig_json,
|
||||
},
|
||||
{
|
||||
name: "build",
|
||||
type: "boolean",
|
||||
shortName: "b",
|
||||
showInSimplifiedHelpView: true,
|
||||
category: Diagnostics.Command_line_Options,
|
||||
description: Diagnostics.Build_one_or_more_projects_and_their_dependencies_if_out_of_date
|
||||
},
|
||||
{
|
||||
name: "pretty",
|
||||
type: "boolean",
|
||||
@ -943,6 +951,125 @@ namespace ts {
|
||||
}
|
||||
|
||||
|
||||
function getDiagnosticText(_message: DiagnosticMessage, ..._args: any[]): string {
|
||||
const diagnostic = createCompilerDiagnostic.apply(undefined, arguments);
|
||||
return <string>diagnostic.messageText;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function printVersion() {
|
||||
sys.write(getDiagnosticText(Diagnostics.Version_0, version) + sys.newLine);
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function printHelp(optionsList: CommandLineOption[], syntaxPrefix = "") {
|
||||
const output: string[] = [];
|
||||
|
||||
// We want to align our "syntax" and "examples" commands to a certain margin.
|
||||
const syntaxLength = getDiagnosticText(Diagnostics.Syntax_Colon_0, "").length;
|
||||
const examplesLength = getDiagnosticText(Diagnostics.Examples_Colon_0, "").length;
|
||||
let marginLength = Math.max(syntaxLength, examplesLength);
|
||||
|
||||
// Build up the syntactic skeleton.
|
||||
let syntax = makePadding(marginLength - syntaxLength);
|
||||
syntax += `tsc ${syntaxPrefix}[${getDiagnosticText(Diagnostics.options)}] [${getDiagnosticText(Diagnostics.file)}...]`;
|
||||
|
||||
output.push(getDiagnosticText(Diagnostics.Syntax_Colon_0, syntax));
|
||||
output.push(sys.newLine + sys.newLine);
|
||||
|
||||
// Build up the list of examples.
|
||||
const padding = makePadding(marginLength);
|
||||
output.push(getDiagnosticText(Diagnostics.Examples_Colon_0, makePadding(marginLength - examplesLength) + "tsc hello.ts") + sys.newLine);
|
||||
output.push(padding + "tsc --outFile file.js file.ts" + sys.newLine);
|
||||
output.push(padding + "tsc @args.txt" + sys.newLine);
|
||||
output.push(padding + "tsc --build tsconfig.json" + sys.newLine);
|
||||
output.push(sys.newLine);
|
||||
|
||||
output.push(getDiagnosticText(Diagnostics.Options_Colon) + sys.newLine);
|
||||
|
||||
// We want our descriptions to align at the same column in our output,
|
||||
// so we keep track of the longest option usage string.
|
||||
marginLength = 0;
|
||||
const usageColumn: string[] = []; // Things like "-d, --declaration" go in here.
|
||||
const descriptionColumn: string[] = [];
|
||||
|
||||
const optionsDescriptionMap = createMap<string[]>(); // Map between option.description and list of option.type if it is a kind
|
||||
|
||||
for (const option of optionsList) {
|
||||
// If an option lacks a description,
|
||||
// it is not officially supported.
|
||||
if (!option.description) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let usageText = " ";
|
||||
if (option.shortName) {
|
||||
usageText += "-" + option.shortName;
|
||||
usageText += getParamType(option);
|
||||
usageText += ", ";
|
||||
}
|
||||
|
||||
usageText += "--" + option.name;
|
||||
usageText += getParamType(option);
|
||||
|
||||
usageColumn.push(usageText);
|
||||
let description: string;
|
||||
|
||||
if (option.name === "lib") {
|
||||
description = getDiagnosticText(option.description);
|
||||
const element = (<CommandLineOptionOfListType>option).element;
|
||||
const typeMap = <Map<number | string>>element.type;
|
||||
optionsDescriptionMap.set(description, arrayFrom(typeMap.keys()).map(key => `'${key}'`));
|
||||
}
|
||||
else {
|
||||
description = getDiagnosticText(option.description);
|
||||
}
|
||||
|
||||
descriptionColumn.push(description);
|
||||
|
||||
// Set the new margin for the description column if necessary.
|
||||
marginLength = Math.max(usageText.length, marginLength);
|
||||
}
|
||||
|
||||
// Special case that can't fit in the loop.
|
||||
const usageText = " @<" + getDiagnosticText(Diagnostics.file) + ">";
|
||||
usageColumn.push(usageText);
|
||||
descriptionColumn.push(getDiagnosticText(Diagnostics.Insert_command_line_options_and_files_from_a_file));
|
||||
marginLength = Math.max(usageText.length, marginLength);
|
||||
|
||||
// Print out each row, aligning all the descriptions on the same column.
|
||||
for (let i = 0; i < usageColumn.length; i++) {
|
||||
const usage = usageColumn[i];
|
||||
const description = descriptionColumn[i];
|
||||
const kindsList = optionsDescriptionMap.get(description);
|
||||
output.push(usage + makePadding(marginLength - usage.length + 2) + description + sys.newLine);
|
||||
|
||||
if (kindsList) {
|
||||
output.push(makePadding(marginLength + 4));
|
||||
for (const kind of kindsList) {
|
||||
output.push(kind + " ");
|
||||
}
|
||||
output.push(sys.newLine);
|
||||
}
|
||||
}
|
||||
|
||||
for (const line of output) {
|
||||
sys.write(line);
|
||||
}
|
||||
return;
|
||||
|
||||
function getParamType(option: CommandLineOption) {
|
||||
if (option.paramType !== undefined) {
|
||||
return " " + getDiagnosticText(option.paramType);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
function makePadding(paddingLength: number): string {
|
||||
return Array(paddingLength + 1).join(" ");
|
||||
}
|
||||
}
|
||||
|
||||
export type DiagnosticReporter = (diagnostic: Diagnostic) => void;
|
||||
/**
|
||||
* Reports config file diagnostics
|
||||
|
||||
@ -3657,6 +3657,34 @@
|
||||
"category": "Message",
|
||||
"code": 6362
|
||||
},
|
||||
"Build one or more projects and their dependencies, if out-of-date": {
|
||||
"category": "Message",
|
||||
"code": 6363
|
||||
},
|
||||
"Delete the outputs of all projects": {
|
||||
"category": "Message",
|
||||
"code": 6364
|
||||
},
|
||||
"Enable verbose logging": {
|
||||
"category": "Message",
|
||||
"code": 6365
|
||||
},
|
||||
"Show what would be built (or deleted, if specified with --clean)": {
|
||||
"category": "Message",
|
||||
"code": 6366
|
||||
},
|
||||
"Build all projects, including those that appear to be up-to-date": {
|
||||
"category": "Message",
|
||||
"code": 6367
|
||||
},
|
||||
"Option '--build' must be the first command line argument.": {
|
||||
"category": "Error",
|
||||
"code": 6368
|
||||
},
|
||||
"Options '{0}' and '{1}' cannot be combined.": {
|
||||
"category": "Error",
|
||||
"code": 6369
|
||||
},
|
||||
|
||||
"Variable '{0}' implicitly has an '{1}' type.": {
|
||||
"category": "Error",
|
||||
|
||||
@ -338,11 +338,48 @@ namespace ts {
|
||||
};
|
||||
}
|
||||
|
||||
const buildOpts: CommandLineOption[] = [
|
||||
{
|
||||
name: "verbose",
|
||||
shortName: "v",
|
||||
category: Diagnostics.Command_line_Options,
|
||||
description: Diagnostics.Enable_verbose_logging,
|
||||
type: "boolean"
|
||||
},
|
||||
{
|
||||
name: "dry",
|
||||
shortName: "d",
|
||||
category: Diagnostics.Command_line_Options,
|
||||
description: Diagnostics.Show_what_would_be_built_or_deleted_if_specified_with_clean,
|
||||
type: "boolean"
|
||||
},
|
||||
{
|
||||
name: "force",
|
||||
shortName: "f",
|
||||
category: Diagnostics.Command_line_Options,
|
||||
description: Diagnostics.Build_all_projects_including_those_that_appear_to_be_up_to_date,
|
||||
type: "boolean"
|
||||
},
|
||||
{
|
||||
name: "clean",
|
||||
category: Diagnostics.Command_line_Options,
|
||||
description: Diagnostics.Delete_the_outputs_of_all_projects,
|
||||
type: "boolean"
|
||||
},
|
||||
{
|
||||
name: "watch",
|
||||
category: Diagnostics.Command_line_Options,
|
||||
description: Diagnostics.Watch_input_files,
|
||||
type: "boolean"
|
||||
}
|
||||
];
|
||||
|
||||
export function performBuild(host: CompilerHost, reportDiagnostic: DiagnosticReporter, args: string[]) {
|
||||
let verbose = false;
|
||||
let dry = false;
|
||||
let force = false;
|
||||
let clean = false;
|
||||
let watch = false;
|
||||
|
||||
const projects: string[] = [];
|
||||
for (const arg of args) {
|
||||
@ -362,11 +399,38 @@ namespace ts {
|
||||
case "--clean":
|
||||
clean = true;
|
||||
continue;
|
||||
case "--watch":
|
||||
case "-w":
|
||||
watch = true;
|
||||
continue;
|
||||
|
||||
case "--?":
|
||||
case "-?":
|
||||
case "--help":
|
||||
return printHelp(buildOpts, "--build ");
|
||||
}
|
||||
// Not a flag, parse as filename
|
||||
addProject(arg);
|
||||
}
|
||||
|
||||
// Nonsensical combinations
|
||||
if (clean && force) {
|
||||
reportDiagnostic(createCompilerDiagnostic(Diagnostics.Options_0_and_1_cannot_be_combined, "clean", "force"));
|
||||
return;
|
||||
}
|
||||
if (clean && verbose) {
|
||||
reportDiagnostic(createCompilerDiagnostic(Diagnostics.Options_0_and_1_cannot_be_combined, "clean", "verbose"));
|
||||
return;
|
||||
}
|
||||
if (clean && watch) {
|
||||
reportDiagnostic(createCompilerDiagnostic(Diagnostics.Options_0_and_1_cannot_be_combined, "clean", "watch"));
|
||||
return;
|
||||
}
|
||||
if (watch && dry) {
|
||||
reportDiagnostic(createCompilerDiagnostic(Diagnostics.Options_0_and_1_cannot_be_combined, "watch", "dry"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (projects.length === 0) {
|
||||
// tsc -b invoked with no extra arguments; act as if invoked with "tsc -b ."
|
||||
addProject(".");
|
||||
|
||||
@ -12,11 +12,6 @@ namespace ts {
|
||||
return count;
|
||||
}
|
||||
|
||||
function getDiagnosticText(_message: DiagnosticMessage, ..._args: any[]): string {
|
||||
const diagnostic = createCompilerDiagnostic.apply(undefined, arguments);
|
||||
return <string>diagnostic.messageText;
|
||||
}
|
||||
|
||||
let reportDiagnostic = createDiagnosticReporter(sys);
|
||||
function updateReportDiagnostic(options: CompilerOptions) {
|
||||
if (shouldBePretty(options)) {
|
||||
@ -46,6 +41,13 @@ namespace ts {
|
||||
return s;
|
||||
}
|
||||
|
||||
function getOptionsForHelp(commandLine: ParsedCommandLine) {
|
||||
// Sort our options by their names, (e.g. "--noImplicitAny" comes before "--watch")
|
||||
return !!commandLine.options.all ?
|
||||
sort(optionDeclarations, (a, b) => compareStringsCaseInsensitive(a.name, b.name)) :
|
||||
filter(optionDeclarations.slice(), v => !!v.showInSimplifiedHelpView);
|
||||
}
|
||||
|
||||
export function executeCommandLine(args: string[]): void {
|
||||
if ((args[0].toLowerCase() === "--build") || (args[0].toLowerCase() === "-b")) {
|
||||
return performBuild(createCompilerHost({}), createDiagnosticReporter(sys), args.slice(1));
|
||||
@ -53,6 +55,11 @@ namespace ts {
|
||||
|
||||
const commandLine = parseCommandLine(args);
|
||||
|
||||
if (commandLine.options.build) {
|
||||
reportDiagnostic(createCompilerDiagnostic(Diagnostics.Option_build_must_be_the_first_command_line_argument));
|
||||
return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped);
|
||||
}
|
||||
|
||||
// Configuration file name (if any)
|
||||
let configFileName: string | undefined;
|
||||
if (commandLine.options.locale) {
|
||||
@ -78,7 +85,7 @@ namespace ts {
|
||||
|
||||
if (commandLine.options.help || commandLine.options.all) {
|
||||
printVersion();
|
||||
printHelp(!!commandLine.options.all);
|
||||
printHelp(getOptionsForHelp(commandLine));
|
||||
return sys.exit(ExitStatus.Success);
|
||||
}
|
||||
|
||||
@ -111,7 +118,7 @@ namespace ts {
|
||||
|
||||
if (commandLine.fileNames.length === 0 && !configFileName) {
|
||||
printVersion();
|
||||
printHelp(!!commandLine.options.all);
|
||||
printHelp(getOptionsForHelp(commandLine));
|
||||
return sys.exit(ExitStatus.Success);
|
||||
}
|
||||
|
||||
@ -275,122 +282,6 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function printVersion() {
|
||||
sys.write(getDiagnosticText(Diagnostics.Version_0, version) + sys.newLine);
|
||||
}
|
||||
|
||||
function printHelp(showAllOptions: boolean) {
|
||||
const output: string[] = [];
|
||||
|
||||
// We want to align our "syntax" and "examples" commands to a certain margin.
|
||||
const syntaxLength = getDiagnosticText(Diagnostics.Syntax_Colon_0, "").length;
|
||||
const examplesLength = getDiagnosticText(Diagnostics.Examples_Colon_0, "").length;
|
||||
let marginLength = Math.max(syntaxLength, examplesLength);
|
||||
|
||||
// Build up the syntactic skeleton.
|
||||
let syntax = makePadding(marginLength - syntaxLength);
|
||||
syntax += "tsc [" + getDiagnosticText(Diagnostics.options) + "] [" + getDiagnosticText(Diagnostics.file) + " ...]";
|
||||
|
||||
output.push(getDiagnosticText(Diagnostics.Syntax_Colon_0, syntax));
|
||||
output.push(sys.newLine + sys.newLine);
|
||||
|
||||
// Build up the list of examples.
|
||||
const padding = makePadding(marginLength);
|
||||
output.push(getDiagnosticText(Diagnostics.Examples_Colon_0, makePadding(marginLength - examplesLength) + "tsc hello.ts") + sys.newLine);
|
||||
output.push(padding + "tsc --outFile file.js file.ts" + sys.newLine);
|
||||
output.push(padding + "tsc @args.txt" + sys.newLine);
|
||||
output.push(sys.newLine);
|
||||
|
||||
output.push(getDiagnosticText(Diagnostics.Options_Colon) + sys.newLine);
|
||||
|
||||
// Sort our options by their names, (e.g. "--noImplicitAny" comes before "--watch")
|
||||
const optsList = showAllOptions ?
|
||||
sort(optionDeclarations, (a, b) => compareStringsCaseInsensitive(a.name, b.name)) :
|
||||
filter(optionDeclarations.slice(), v => !!v.showInSimplifiedHelpView);
|
||||
|
||||
// We want our descriptions to align at the same column in our output,
|
||||
// so we keep track of the longest option usage string.
|
||||
marginLength = 0;
|
||||
const usageColumn: string[] = []; // Things like "-d, --declaration" go in here.
|
||||
const descriptionColumn: string[] = [];
|
||||
|
||||
const optionsDescriptionMap = createMap<string[]>(); // Map between option.description and list of option.type if it is a kind
|
||||
|
||||
for (const option of optsList) {
|
||||
// If an option lacks a description,
|
||||
// it is not officially supported.
|
||||
if (!option.description) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let usageText = " ";
|
||||
if (option.shortName) {
|
||||
usageText += "-" + option.shortName;
|
||||
usageText += getParamType(option);
|
||||
usageText += ", ";
|
||||
}
|
||||
|
||||
usageText += "--" + option.name;
|
||||
usageText += getParamType(option);
|
||||
|
||||
usageColumn.push(usageText);
|
||||
let description: string;
|
||||
|
||||
if (option.name === "lib") {
|
||||
description = getDiagnosticText(option.description);
|
||||
const element = (<CommandLineOptionOfListType>option).element;
|
||||
const typeMap = <Map<number | string>>element.type;
|
||||
optionsDescriptionMap.set(description, arrayFrom(typeMap.keys()).map(key => `'${key}'`));
|
||||
}
|
||||
else {
|
||||
description = getDiagnosticText(option.description);
|
||||
}
|
||||
|
||||
descriptionColumn.push(description);
|
||||
|
||||
// Set the new margin for the description column if necessary.
|
||||
marginLength = Math.max(usageText.length, marginLength);
|
||||
}
|
||||
|
||||
// Special case that can't fit in the loop.
|
||||
const usageText = " @<" + getDiagnosticText(Diagnostics.file) + ">";
|
||||
usageColumn.push(usageText);
|
||||
descriptionColumn.push(getDiagnosticText(Diagnostics.Insert_command_line_options_and_files_from_a_file));
|
||||
marginLength = Math.max(usageText.length, marginLength);
|
||||
|
||||
// Print out each row, aligning all the descriptions on the same column.
|
||||
for (let i = 0; i < usageColumn.length; i++) {
|
||||
const usage = usageColumn[i];
|
||||
const description = descriptionColumn[i];
|
||||
const kindsList = optionsDescriptionMap.get(description);
|
||||
output.push(usage + makePadding(marginLength - usage.length + 2) + description + sys.newLine);
|
||||
|
||||
if (kindsList) {
|
||||
output.push(makePadding(marginLength + 4));
|
||||
for (const kind of kindsList) {
|
||||
output.push(kind + " ");
|
||||
}
|
||||
output.push(sys.newLine);
|
||||
}
|
||||
}
|
||||
|
||||
for (const line of output) {
|
||||
sys.write(line);
|
||||
}
|
||||
return;
|
||||
|
||||
function getParamType(option: CommandLineOption) {
|
||||
if (option.paramType !== undefined) {
|
||||
return " " + getDiagnosticText(option.paramType);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
function makePadding(paddingLength: number): string {
|
||||
return Array(paddingLength + 1).join(" ");
|
||||
}
|
||||
}
|
||||
|
||||
function writeConfigFile(options: CompilerOptions, fileNames: string[]) {
|
||||
const currentDirectory = sys.getCurrentDirectory();
|
||||
const file = normalizePath(combinePaths(currentDirectory, "tsconfig.json"));
|
||||
|
||||
@ -4281,6 +4281,9 @@ namespace ts {
|
||||
allowUnusedLabels?: boolean;
|
||||
alwaysStrict?: boolean; // Always combine with strict property
|
||||
baseUrl?: string;
|
||||
/** An error if set - this should only go through the -b pipeline and not actually be observed */
|
||||
/*@internal*/
|
||||
build?: boolean;
|
||||
charset?: string;
|
||||
checkJs?: boolean;
|
||||
/* @internal */ configFilePath?: string;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user