/// /// namespace ts { export interface SourceFile { fileWatcher?: FileWatcher; } interface Statistic { name: string; value: string; } const defaultFormatDiagnosticsHost: FormatDiagnosticsHost = { getCurrentDirectory: () => sys.getCurrentDirectory(), getNewLine: () => sys.newLine, getCanonicalFileName: createGetCanonicalFileName(sys.useCaseSensitiveFileNames) }; let reportDiagnosticWorker = reportDiagnosticSimply; function reportDiagnostic(diagnostic: Diagnostic, host: FormatDiagnosticsHost) { reportDiagnosticWorker(diagnostic, host || defaultFormatDiagnosticsHost); } function reportDiagnostics(diagnostics: Diagnostic[], host: FormatDiagnosticsHost): void { for (const diagnostic of diagnostics) { reportDiagnostic(diagnostic, host); } } function reportEmittedFiles(files: string[]): void { if (!files || files.length == 0) { return; } const currentDir = sys.getCurrentDirectory(); for (const file of files) { const filepath = getNormalizedAbsolutePath(file, currentDir); sys.write(`TSFILE: ${filepath}${sys.newLine}`); } } function countLines(program: Program): number { let count = 0; forEach(program.getSourceFiles(), file => { count += getLineStarts(file).length; }); return count; } function getDiagnosticText(_message: DiagnosticMessage, ..._args: any[]): string { const diagnostic = createCompilerDiagnostic.apply(undefined, arguments); return diagnostic.messageText; } function reportDiagnosticSimply(diagnostic: Diagnostic, host: FormatDiagnosticsHost): void { sys.write(ts.formatDiagnostics([diagnostic], host)); } const redForegroundEscapeSequence = "\u001b[91m"; const yellowForegroundEscapeSequence = "\u001b[93m"; const blueForegroundEscapeSequence = "\u001b[93m"; const gutterStyleSequence = "\u001b[100;30m"; const gutterSeparator = " "; const resetEscapeSequence = "\u001b[0m"; const ellipsis = "..."; function getCategoryFormat(category: DiagnosticCategory): string { switch (category) { case DiagnosticCategory.Warning: return yellowForegroundEscapeSequence; case DiagnosticCategory.Error: return redForegroundEscapeSequence; case DiagnosticCategory.Message: return blueForegroundEscapeSequence; } } function formatAndReset(text: string, formatStyle: string) { return formatStyle + text + resetEscapeSequence; } function reportDiagnosticWithColorAndContext(diagnostic: Diagnostic, host: FormatDiagnosticsHost): void { let output = ""; if (diagnostic.file) { const { start, length, file } = diagnostic; const { line: firstLine, character: firstLineChar } = getLineAndCharacterOfPosition(file, start); const { line: lastLine, character: lastLineChar } = getLineAndCharacterOfPosition(file, start + length); const lastLineInFile = getLineAndCharacterOfPosition(file, file.text.length).line; const relativeFileName = host ? convertToRelativePath(file.fileName, host.getCurrentDirectory(), fileName => host.getCanonicalFileName(fileName)) : file.fileName; const hasMoreThanFiveLines = (lastLine - firstLine) >= 4; let gutterWidth = (lastLine + 1 + "").length; if (hasMoreThanFiveLines) { gutterWidth = Math.max(ellipsis.length, gutterWidth); } output += sys.newLine; for (let i = firstLine; i <= lastLine; i++) { // If the error spans over 5 lines, we'll only show the first 2 and last 2 lines, // so we'll skip ahead to the second-to-last line. if (hasMoreThanFiveLines && firstLine + 1 < i && i < lastLine - 1) { output += formatAndReset(padLeft(ellipsis, gutterWidth), gutterStyleSequence) + gutterSeparator + sys.newLine; i = lastLine - 1; } const lineStart = getPositionOfLineAndCharacter(file, i, 0); const lineEnd = i < lastLineInFile ? getPositionOfLineAndCharacter(file, i + 1, 0) : file.text.length; let lineContent = file.text.slice(lineStart, lineEnd); lineContent = lineContent.replace(/\s+$/g, ""); // trim from end lineContent = lineContent.replace("\t", " "); // convert tabs to single spaces // Output the gutter and the actual contents of the line. output += formatAndReset(padLeft(i + 1 + "", gutterWidth), gutterStyleSequence) + gutterSeparator; output += lineContent + sys.newLine; // Output the gutter and the error span for the line using tildes. output += formatAndReset(padLeft("", gutterWidth), gutterStyleSequence) + gutterSeparator; output += redForegroundEscapeSequence; if (i === firstLine) { // If we're on the last line, then limit it to the last character of the last line. // Otherwise, we'll just squiggle the rest of the line, giving 'slice' no end position. const lastCharForLine = i === lastLine ? lastLineChar : undefined; output += lineContent.slice(0, firstLineChar).replace(/\S/g, " "); output += lineContent.slice(firstLineChar, lastCharForLine).replace(/./g, "~"); } else if (i === lastLine) { output += lineContent.slice(0, lastLineChar).replace(/./g, "~"); } else { // Squiggle the entire line. output += lineContent.replace(/./g, "~"); } output += resetEscapeSequence; output += sys.newLine; } output += sys.newLine; output += `${ relativeFileName }(${ firstLine + 1 },${ firstLineChar + 1 }): `; } const categoryColor = getCategoryFormat(diagnostic.category); const category = DiagnosticCategory[diagnostic.category].toLowerCase(); output += `${ formatAndReset(category, categoryColor) } TS${ diagnostic.code }: ${ flattenDiagnosticMessageText(diagnostic.messageText, sys.newLine) }`; output += sys.newLine + sys.newLine; sys.write(output); } function reportWatchDiagnostic(diagnostic: Diagnostic) { let output = new Date().toLocaleTimeString() + " - "; if (diagnostic.file) { const loc = getLineAndCharacterOfPosition(diagnostic.file, diagnostic.start); output += `${ diagnostic.file.fileName }(${ loc.line + 1 },${ loc.character + 1 }): `; } output += `${ flattenDiagnosticMessageText(diagnostic.messageText, sys.newLine) }${ sys.newLine + sys.newLine + sys.newLine }`; sys.write(output); } function padLeft(s: string, length: number) { while (s.length < length) { s = " " + s; } return s; } function padRight(s: string, length: number) { while (s.length < length) { s = s + " "; } return s; } function isJSONSupported() { return typeof JSON === "object" && typeof JSON.parse === "function"; } export function executeCommandLine(args: string[]): void { const commandLine = parseCommandLine(args); let configFileName: string; // Configuration file name (if any) let cachedConfigFileText: string; // Cached configuration file text, used for reparsing (if any) let configFileWatcher: FileWatcher; // Configuration file watcher let directoryWatcher: FileWatcher; // Directory watcher to monitor source file addition/removal let cachedProgram: Program; // Program cached from last compilation let rootFileNames: string[]; // Root fileNames for compilation let compilerOptions: CompilerOptions; // Compiler options for compilation let compilerHost: CompilerHost; // Compiler host let hostGetSourceFile: typeof compilerHost.getSourceFile; // getSourceFile method from default host let timerHandleForRecompilation: any; // Handle for 0.25s wait timer to trigger recompilation let timerHandleForDirectoryChanges: any; // Handle for 0.25s wait timer to trigger directory change handler // This map stores and reuses results of fileExists check that happen inside 'createProgram' // This allows to save time in module resolution heavy scenarios when existence of the same file might be checked multiple times. let cachedExistingFiles: Map; let hostFileExists: typeof compilerHost.fileExists; if (commandLine.options.locale) { if (!isJSONSupported()) { reportDiagnostic(createCompilerDiagnostic(Diagnostics.The_current_host_does_not_support_the_0_option, "--locale"), /* host */ undefined); return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped); } validateLocaleAndSetLanguage(commandLine.options.locale, sys, commandLine.errors); } // If there are any errors due to command line parsing and/or // setting up localization, report them and quit. if (commandLine.errors.length > 0) { reportDiagnostics(commandLine.errors, compilerHost); return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped); } if (commandLine.options.init) { writeConfigFile(commandLine.options, commandLine.fileNames); return sys.exit(ExitStatus.Success); } if (commandLine.options.version) { printVersion(); return sys.exit(ExitStatus.Success); } if (commandLine.options.help) { printVersion(); printHelp(); return sys.exit(ExitStatus.Success); } if (commandLine.options.project) { if (!isJSONSupported()) { reportDiagnostic(createCompilerDiagnostic(Diagnostics.The_current_host_does_not_support_the_0_option, "--project"), /* host */ undefined); return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped); } if (commandLine.fileNames.length !== 0) { reportDiagnostic(createCompilerDiagnostic(Diagnostics.Option_project_cannot_be_mixed_with_source_files_on_a_command_line), /* host */ undefined); return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped); } const fileOrDirectory = normalizePath(commandLine.options.project); if (!fileOrDirectory /* current directory "." */ || sys.directoryExists(fileOrDirectory)) { configFileName = combinePaths(fileOrDirectory, "tsconfig.json"); if (!sys.fileExists(configFileName)) { reportDiagnostic(createCompilerDiagnostic(Diagnostics.Cannot_find_a_tsconfig_json_file_at_the_specified_directory_Colon_0, commandLine.options.project), /* host */ undefined); return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped); } } else { configFileName = fileOrDirectory; if (!sys.fileExists(configFileName)) { reportDiagnostic(createCompilerDiagnostic(Diagnostics.The_specified_path_does_not_exist_Colon_0, commandLine.options.project), /* host */ undefined); return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped); } } } else if (commandLine.fileNames.length === 0 && isJSONSupported()) { const searchPath = normalizePath(sys.getCurrentDirectory()); configFileName = findConfigFile(searchPath, sys.fileExists); } if (commandLine.fileNames.length === 0 && !configFileName) { printVersion(); printHelp(); return sys.exit(ExitStatus.Success); } if (isWatchSet(commandLine.options)) { if (!sys.watchFile) { reportDiagnostic(createCompilerDiagnostic(Diagnostics.The_current_host_does_not_support_the_0_option, "--watch"), /* host */ undefined); return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped); } if (configFileName) { configFileWatcher = sys.watchFile(configFileName, configFileChanged); } if (sys.watchDirectory && configFileName) { const directory = ts.getDirectoryPath(configFileName); directoryWatcher = sys.watchDirectory( // When the configFileName is just "tsconfig.json", the watched directory should be // the current directory; if there is a given "project" parameter, then the configFileName // is an absolute file name. directory == "" ? "." : directory, watchedDirectoryChanged, /*recursive*/ true); } } performCompilation(); function parseConfigFile(): ParsedCommandLine { if (!cachedConfigFileText) { try { cachedConfigFileText = sys.readFile(configFileName); } catch (e) { const error = createCompilerDiagnostic(Diagnostics.Cannot_read_file_0_Colon_1, configFileName, e.message); reportWatchDiagnostic(error); sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped); return; } } if (!cachedConfigFileText) { const error = createCompilerDiagnostic(Diagnostics.File_0_not_found, configFileName); reportDiagnostics([error], /* compilerHost */ undefined); sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped); return; } const result = parseConfigFileTextToJson(configFileName, cachedConfigFileText); const configObject = result.config; if (!configObject) { reportDiagnostics([result.error], /* compilerHost */ undefined); sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped); return; } const cwd = sys.getCurrentDirectory(); const configParseResult = parseJsonConfigFileContent(configObject, sys, getNormalizedAbsolutePath(getDirectoryPath(configFileName), cwd), commandLine.options, getNormalizedAbsolutePath(configFileName, cwd)); if (configParseResult.errors.length > 0) { reportDiagnostics(configParseResult.errors, /* compilerHost */ undefined); sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped); return; } if (isWatchSet(configParseResult.options)) { if (!sys.watchFile) { reportDiagnostic(createCompilerDiagnostic(Diagnostics.The_current_host_does_not_support_the_0_option, "--watch"), /* host */ undefined); sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped); } if (!directoryWatcher && sys.watchDirectory && configFileName) { const directory = ts.getDirectoryPath(configFileName); directoryWatcher = sys.watchDirectory( // When the configFileName is just "tsconfig.json", the watched directory should be // the current directory; if there is a given "project" parameter, then the configFileName // is an absolute file name. directory == "" ? "." : directory, watchedDirectoryChanged, /*recursive*/ true); }; } return configParseResult; } // Invoked to perform initial compilation or re-compilation in watch mode function performCompilation() { if (!cachedProgram) { if (configFileName) { const configParseResult = parseConfigFile(); rootFileNames = configParseResult.fileNames; compilerOptions = configParseResult.options; } else { rootFileNames = commandLine.fileNames; compilerOptions = commandLine.options; } compilerHost = createCompilerHost(compilerOptions); hostGetSourceFile = compilerHost.getSourceFile; compilerHost.getSourceFile = getSourceFile; hostFileExists = compilerHost.fileExists; compilerHost.fileExists = cachedFileExists; } if (compilerOptions.pretty) { reportDiagnosticWorker = reportDiagnosticWithColorAndContext; } // reset the cache of existing files cachedExistingFiles = createMap(); const compileResult = compile(rootFileNames, compilerOptions, compilerHost); if (!isWatchSet(compilerOptions)) { return sys.exit(compileResult.exitStatus); } setCachedProgram(compileResult.program); reportWatchDiagnostic(createCompilerDiagnostic(Diagnostics.Compilation_complete_Watching_for_file_changes)); } function cachedFileExists(fileName: string): boolean { let fileExists = cachedExistingFiles.get(fileName); if (fileExists === undefined) { cachedExistingFiles.set(fileName, fileExists = hostFileExists(fileName)); } return fileExists; } function getSourceFile(fileName: string, languageVersion: ScriptTarget, onError?: (message: string) => void) { // Return existing SourceFile object if one is available if (cachedProgram) { const sourceFile = cachedProgram.getSourceFile(fileName); // A modified source file has no watcher and should not be reused if (sourceFile && sourceFile.fileWatcher) { return sourceFile; } } // Use default host function const sourceFile = hostGetSourceFile(fileName, languageVersion, onError); if (sourceFile && isWatchSet(compilerOptions) && sys.watchFile) { // Attach a file watcher sourceFile.fileWatcher = sys.watchFile(sourceFile.fileName, (_fileName: string, removed?: boolean) => sourceFileChanged(sourceFile, removed)); } return sourceFile; } // Change cached program to the given program function setCachedProgram(program: Program) { if (cachedProgram) { const newSourceFiles = program ? program.getSourceFiles() : undefined; forEach(cachedProgram.getSourceFiles(), sourceFile => { if (!(newSourceFiles && contains(newSourceFiles, sourceFile))) { if (sourceFile.fileWatcher) { sourceFile.fileWatcher.close(); sourceFile.fileWatcher = undefined; } } }); } cachedProgram = program; } // If a source file changes, mark it as unwatched and start the recompilation timer function sourceFileChanged(sourceFile: SourceFile, removed?: boolean) { sourceFile.fileWatcher.close(); sourceFile.fileWatcher = undefined; if (removed) { unorderedRemoveItem(rootFileNames, sourceFile.fileName); } startTimerForRecompilation(); } // If the configuration file changes, forget cached program and start the recompilation timer function configFileChanged() { setCachedProgram(undefined); cachedConfigFileText = undefined; startTimerForRecompilation(); } function watchedDirectoryChanged(fileName: string) { if (fileName && !ts.isSupportedSourceFileName(fileName, compilerOptions)) { return; } startTimerForHandlingDirectoryChanges(); } function startTimerForHandlingDirectoryChanges() { if (!sys.setTimeout || !sys.clearTimeout) { return; } if (timerHandleForDirectoryChanges) { sys.clearTimeout(timerHandleForDirectoryChanges); } timerHandleForDirectoryChanges = sys.setTimeout(directoryChangeHandler, 250); } function directoryChangeHandler() { const parsedCommandLine = parseConfigFile(); const newFileNames = ts.map(parsedCommandLine.fileNames, compilerHost.getCanonicalFileName); const canonicalRootFileNames = ts.map(rootFileNames, compilerHost.getCanonicalFileName); // We check if the project file list has changed. If so, we just throw away the old program and start fresh. if (!arrayIsEqualTo(newFileNames && newFileNames.sort(), canonicalRootFileNames && canonicalRootFileNames.sort())) { setCachedProgram(undefined); startTimerForRecompilation(); } } // Upon detecting a file change, wait for 250ms and then perform a recompilation. This gives batch // operations (such as saving all modified files in an editor) a chance to complete before we kick // off a new compilation. function startTimerForRecompilation() { if (!sys.setTimeout || !sys.clearTimeout) { return; } if (timerHandleForRecompilation) { sys.clearTimeout(timerHandleForRecompilation); } timerHandleForRecompilation = sys.setTimeout(recompile, 250); } function recompile() { timerHandleForRecompilation = undefined; reportWatchDiagnostic(createCompilerDiagnostic(Diagnostics.File_change_detected_Starting_incremental_compilation)); performCompilation(); } } function compile(fileNames: string[], compilerOptions: CompilerOptions, compilerHost: CompilerHost) { const hasDiagnostics = compilerOptions.diagnostics || compilerOptions.extendedDiagnostics; let statistics: Statistic[]; if (hasDiagnostics) { performance.enable(); statistics = []; } const program = createProgram(fileNames, compilerOptions, compilerHost); const exitStatus = compileProgram(); if (compilerOptions.listFiles) { forEach(program.getSourceFiles(), file => { sys.write(file.fileName + sys.newLine); }); } if (hasDiagnostics) { const memoryUsed = sys.getMemoryUsage ? sys.getMemoryUsage() : -1; reportCountStatistic("Files", program.getSourceFiles().length); reportCountStatistic("Lines", countLines(program)); reportCountStatistic("Nodes", program.getNodeCount()); reportCountStatistic("Identifiers", program.getIdentifierCount()); reportCountStatistic("Symbols", program.getSymbolCount()); reportCountStatistic("Types", program.getTypeCount()); if (memoryUsed >= 0) { reportStatisticalValue("Memory used", Math.round(memoryUsed / 1000) + "K"); } const programTime = performance.getDuration("Program"); const bindTime = performance.getDuration("Bind"); const checkTime = performance.getDuration("Check"); const emitTime = performance.getDuration("Emit"); if (compilerOptions.extendedDiagnostics) { performance.forEachMeasure((name, duration) => reportTimeStatistic(`${name} time`, duration)); } else { // Individual component times. // Note: To match the behavior of previous versions of the compiler, the reported parse time includes // I/O read time and processing time for triple-slash references and module imports, and the reported // emit time includes I/O write time. We preserve this behavior so we can accurately compare times. reportTimeStatistic("I/O read", performance.getDuration("I/O Read")); reportTimeStatistic("I/O write", performance.getDuration("I/O Write")); reportTimeStatistic("Parse time", programTime); reportTimeStatistic("Bind time", bindTime); reportTimeStatistic("Check time", checkTime); reportTimeStatistic("Emit time", emitTime); } reportTimeStatistic("Total time", programTime + bindTime + checkTime + emitTime); reportStatistics(); performance.disable(); } return { program, exitStatus }; function compileProgram(): ExitStatus { let diagnostics: Diagnostic[]; // First get and report any syntactic errors. diagnostics = program.getSyntacticDiagnostics(); // If we didn't have any syntactic errors, then also try getting the global and // semantic errors. if (diagnostics.length === 0) { diagnostics = program.getOptionsDiagnostics().concat(program.getGlobalDiagnostics()); if (diagnostics.length === 0) { diagnostics = program.getSemanticDiagnostics(); } } // Otherwise, emit and report any errors we ran into. const emitOutput = program.emit(); diagnostics = diagnostics.concat(emitOutput.diagnostics); reportDiagnostics(sortAndDeduplicateDiagnostics(diagnostics), compilerHost); reportEmittedFiles(emitOutput.emittedFiles); if (emitOutput.emitSkipped && diagnostics.length > 0) { // If the emitter didn't emit anything, then pass that value along. return ExitStatus.DiagnosticsPresent_OutputsSkipped; } else if (diagnostics.length > 0) { // The emitter emitted something, inform the caller if that happened in the presence // of diagnostics or not. return ExitStatus.DiagnosticsPresent_OutputsGenerated; } return ExitStatus.Success; } function reportStatistics() { let nameSize = 0; let valueSize = 0; for (const { name, value } of statistics) { if (name.length > nameSize) { nameSize = name.length; } if (value.length > valueSize) { valueSize = value.length; } } for (const { name, value } of statistics) { sys.write(padRight(name + ":", nameSize + 2) + padLeft(value.toString(), valueSize) + sys.newLine); } } function reportStatisticalValue(name: string, value: string) { statistics.push({ name, value }); } function reportCountStatistic(name: string, count: number) { reportStatisticalValue(name, "" + count); } function reportTimeStatistic(name: string, time: number) { reportStatisticalValue(name, (time / 1000).toFixed(2) + "s"); } } function printVersion() { sys.write(getDiagnosticText(Diagnostics.Version_0, ts.version) + sys.newLine); } function printHelp() { 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 = filter(optionDeclarations.slice(), v => !v.experimental); optsList.sort((a, b) => compareValues(a.name.toLowerCase(), b.name.toLowerCase())); // 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(); // Map between option.description and list of option.type if it is a kind for (let i = 0; i < optsList.length; i++) { const option = optsList[i]; // 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 = (option).element; const typeMap = >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")); if (sys.fileExists(file)) { reportDiagnostic(createCompilerDiagnostic(Diagnostics.A_tsconfig_json_file_is_already_defined_at_Colon_0, file), /* host */ undefined); } else { sys.writeFile(file, JSON.stringify(generateTSConfig(options, fileNames), undefined, 4)); reportDiagnostic(createCompilerDiagnostic(Diagnostics.Successfully_created_a_tsconfig_json_file), /* host */ undefined); } return; } } if (ts.sys.tryEnableSourceMapsForHost && /^development$/i.test(ts.sys.getEnvironmentVariable("NODE_ENV"))) { ts.sys.tryEnableSourceMapsForHost(); } ts.executeCommandLine(ts.sys.args);