diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 1b689cbf26f..7cab43a6931 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -29651,7 +29651,7 @@ namespace ts { function checkCollisionWithArgumentsInGeneratedCode(node: SignatureDeclaration) { // no rest parameters \ declaration context \ overload - no codegen impact - if (languageVersion >= ScriptTarget.ES2015 || compilerOptions.noEmit || !hasRestParameter(node) || node.flags & NodeFlags.Ambient || nodeIsMissing((node).body)) { + if (languageVersion >= ScriptTarget.ES2015 || shouldSuppressEmit(compilerOptions) || !hasRestParameter(node) || node.flags & NodeFlags.Ambient || nodeIsMissing((node).body)) { return; } @@ -29726,7 +29726,7 @@ namespace ts { function checkCollisionWithRequireExportsInGeneratedCode(node: Node, name: Identifier) { // No need to check for require or exports for ES6 modules and later - if (moduleKind >= ModuleKind.ES2015 || compilerOptions.noEmit) { + if (moduleKind >= ModuleKind.ES2015 || shouldSuppressEmit(compilerOptions)) { return; } @@ -29749,7 +29749,7 @@ namespace ts { } function checkCollisionWithGlobalPromiseInGeneratedCode(node: Node, name: Identifier): void { - if (languageVersion >= ScriptTarget.ES2017 || compilerOptions.noEmit || !needCollisionCheckForIdentifier(node, name, "Promise")) { + if (languageVersion >= ScriptTarget.ES2017 || shouldSuppressEmit(compilerOptions) || !needCollisionCheckForIdentifier(node, name, "Promise")) { return; } @@ -35639,7 +35639,7 @@ namespace ts { return grammarErrorOnNode(node.exclamationToken, Diagnostics.Definite_assignment_assertions_can_only_be_used_along_with_a_type_annotation); } - if (compilerOptions.module !== ModuleKind.ES2015 && compilerOptions.module !== ModuleKind.ESNext && compilerOptions.module !== ModuleKind.System && !compilerOptions.noEmit && + if (compilerOptions.module !== ModuleKind.ES2015 && compilerOptions.module !== ModuleKind.ESNext && compilerOptions.module !== ModuleKind.System && !shouldSuppressEmit(compilerOptions) && !(node.parent.parent.flags & NodeFlags.Ambient) && hasModifier(node.parent.parent, ModifierFlags.Export)) { checkESModuleMarker(node.name); } diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index 18280ecefdb..57278bd7be4 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -216,6 +216,13 @@ namespace ts { isCommandLineOnly: true, description: Diagnostics.Print_the_final_configuration_instead_of_building }, + { + name: "listFilesOnly", + type: "boolean", + category: Diagnostics.Command_line_Options, + isCommandLineOnly: true, + description: Diagnostics.Print_names_of_files_that_are_part_of_the_compilation_and_then_stop_processing + }, // Basic { diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 100d1a55a0b..5cb18c1f333 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -4311,6 +4311,10 @@ "category": "Message", "code": 6502 }, + "Print names of files that are part of the compilation and then stop processing.": { + "category": "Message", + "code": 6503 + }, "Variable '{0}' implicitly has an '{1}' type.": { "category": "Error", diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index cbff1fb2512..636d7c333f7 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -332,7 +332,7 @@ namespace ts { // Write build information if applicable if (!buildInfoPath || targetSourceFile || emitSkipped) return; const program = host.getProgramBuildInfo(); - if (host.isEmitBlocked(buildInfoPath) || compilerOptions.noEmit) { + if (host.isEmitBlocked(buildInfoPath) || shouldSuppressEmit(compilerOptions)) { emitSkipped = true; return; } @@ -349,7 +349,7 @@ namespace ts { } // Make sure not to write js file and source map file if any of them cannot be written - if ((jsFilePath && host.isEmitBlocked(jsFilePath)) || compilerOptions.noEmit) { + if ((jsFilePath && host.isEmitBlocked(jsFilePath)) || shouldSuppressEmit(compilerOptions)) { emitSkipped = true; return; } @@ -436,7 +436,7 @@ namespace ts { onEmitNode: declarationTransform.emitNodeWithNotification, substituteNode: declarationTransform.substituteNode, }); - const declBlocked = (!!declarationTransform.diagnostics && !!declarationTransform.diagnostics.length) || !!host.isEmitBlocked(declarationFilePath) || !!compilerOptions.noEmit; + const declBlocked = (!!declarationTransform.diagnostics && !!declarationTransform.diagnostics.length) || !!host.isEmitBlocked(declarationFilePath) || !!shouldSuppressEmit(compilerOptions); emitSkipped = emitSkipped || declBlocked; if (!declBlocked || forceDtsEmit) { Debug.assert(declarationTransform.transformed.length === 1, "Should only see one output from the decl transform"); diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 0c8444daa2f..df652da3f6a 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -1560,6 +1560,7 @@ namespace ts { } function getDiagnosticsProducingTypeChecker() { + Debug.assert(!options.listFilesOnly || !!options.extendedDiagnostics); return diagnosticsProducingTypeChecker || (diagnosticsProducingTypeChecker = createTypeChecker(program, /*produceDiagnostics:*/ true)); } @@ -1582,11 +1583,11 @@ namespace ts { function emitWorker(program: Program, sourceFile: SourceFile | undefined, writeFileCallback: WriteFileCallback | undefined, cancellationToken: CancellationToken | undefined, emitOnlyDtsFiles?: boolean, customTransformers?: CustomTransformers, forceDtsEmit?: boolean): EmitResult { let declarationDiagnostics: readonly Diagnostic[] = []; - if (!forceDtsEmit) { - if (options.noEmit) { - return { diagnostics: declarationDiagnostics, sourceMaps: undefined, emittedFiles: undefined, emitSkipped: true }; - } + if (options.listFilesOnly || (!forceDtsEmit && shouldSuppressEmit(options))) { + return { diagnostics: declarationDiagnostics, sourceMaps: undefined, emittedFiles: undefined, emitSkipped: true }; + } + if (!forceDtsEmit) { // If the noEmitOnError flag is set, then check if we have any errors so far. If so, // immediately bail out. Note that we pass 'undefined' for 'sourceFile' so that we // get any preEmit diagnostics, not just the ones @@ -2036,7 +2037,9 @@ namespace ts { } function getGlobalDiagnostics(): SortedReadonlyArray { - return rootNames.length ? sortAndDeduplicateDiagnostics(getDiagnosticsProducingTypeChecker().getGlobalDiagnostics().slice()) : emptyArray as any as SortedReadonlyArray; + return !options.listFilesOnly && rootNames.length + ? sortAndDeduplicateDiagnostics(getDiagnosticsProducingTypeChecker().getGlobalDiagnostics().slice()) + : emptyArray as any as SortedReadonlyArray; } function getConfigFileParsingDiagnostics(): readonly Diagnostic[] { @@ -3089,7 +3092,7 @@ namespace ts { createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1_or_option_2, "emitDeclarationOnly", "declaration", "composite"); } - if (options.noEmit) { + if (shouldSuppressEmit(options)) { createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "emitDeclarationOnly", "noEmit"); } } @@ -3112,7 +3115,7 @@ namespace ts { } // If the emit is enabled make sure that every output file is unique and not overwriting any of the input files - if (!options.noEmit && !options.suppressOutputPathCheck) { + if (!shouldSuppressEmit(options) && !options.suppressOutputPathCheck) { const emitHost = getEmitHost(); const emitFilesSeen = createMap(); forEachEmittedFile(emitHost, (emitFileNames) => { @@ -3181,7 +3184,7 @@ namespace ts { } function verifyProjectReferences() { - const buildInfoPath = !options.noEmit && !options.suppressOutputPathCheck ? getTsBuildInfoEmitOutputFilePath(options) : undefined; + const buildInfoPath = !shouldSuppressEmit(options) && !options.suppressOutputPathCheck ? getTsBuildInfoEmitOutputFilePath(options) : undefined; forEachProjectReference(projectReferences, resolvedProjectReferences, (resolvedRef, index, parent) => { const ref = (parent ? parent.commandLine.projectReferences : projectReferences)![index]; const parentFile = parent && parent.sourceFile as JsonSourceFile; @@ -3322,7 +3325,7 @@ namespace ts { } function isEmittedFile(file: string): boolean { - if (options.noEmit) { + if (shouldSuppressEmit(options)) { return false; } diff --git a/src/compiler/tsbuild.ts b/src/compiler/tsbuild.ts index 1924be4df89..dd590e357a4 100644 --- a/src/compiler/tsbuild.ts +++ b/src/compiler/tsbuild.ts @@ -167,6 +167,7 @@ namespace ts { /*@internal*/ preserveWatchOutput?: boolean; /*@internal*/ listEmittedFiles?: boolean; /*@internal*/ listFiles?: boolean; + /*@internal*/ listFilesOnly?: boolean; /*@internal*/ pretty?: boolean; incremental?: boolean; @@ -1923,7 +1924,7 @@ namespace ts { } function isOutputFile(state: SolutionBuilderState, fileName: string, configFile: ParsedCommandLine) { - if (configFile.options.noEmit) return false; + if (shouldSuppressEmit(configFile.options)) return false; // ts or tsx files are not output if (!fileExtensionIs(fileName, Extension.Dts) && diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 03b849b36c7..f8f03dff446 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -4951,6 +4951,7 @@ namespace ts { lib?: string[]; /*@internal*/listEmittedFiles?: boolean; /*@internal*/listFiles?: boolean; + /*@internal*/listFilesOnly?: boolean; locale?: string; mapRoot?: string; maxNodeModuleJsDepth?: number; diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index a841007d9d5..4d14b6b7e0c 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -7619,6 +7619,14 @@ namespace ts { return option.strictFlag ? getStrictOptionValue(options, option.name as StrictOptionName) : options[option.name]; } + export function shouldSuppressEmit(options: CompilerOptions): boolean { + return !!options.noEmit || !!options.listFilesOnly; + } + + export function shouldListFiles(options: CompilerOptions): boolean { + return !!options.listFiles || !!options.listFilesOnly; + } + export function hasZeroOrOneAsteriskCharacter(str: string): boolean { let seenAsterisk = false; for (let i = 0; i < str.length; i++) { @@ -8339,7 +8347,8 @@ namespace ts { // If skipLibCheck is enabled, skip reporting errors if file is a declaration file. // If skipDefaultLibCheck is enabled, skip reporting errors if file contains a // '/// ' directive. - return (options.skipLibCheck && sourceFile.isDeclarationFile || + return options.listFilesOnly || + (options.skipLibCheck && sourceFile.isDeclarationFile || options.skipDefaultLibCheck && sourceFile.hasNoDefaultLib) || host.isSourceOfProjectReferenceRedirect(sourceFile.fileName); } diff --git a/src/compiler/watch.ts b/src/compiler/watch.ts index cac3f3009b1..acbf4ff162a 100644 --- a/src/compiler/watch.ts +++ b/src/compiler/watch.ts @@ -129,7 +129,7 @@ namespace ts { } export function listFiles(program: ProgramToEmitFilesAndReportErrors, writeFileName: (s: string) => void) { - if (program.getCompilerOptions().listFiles) { + if (shouldListFiles(program.getCompilerOptions())) { forEach(program.getSourceFiles(), file => { writeFileName(file.fileName); }); diff --git a/src/testRunner/unittests/config/commandLineParsing.ts b/src/testRunner/unittests/config/commandLineParsing.ts index 5c4998a750a..5792ee1a39c 100644 --- a/src/testRunner/unittests/config/commandLineParsing.ts +++ b/src/testRunner/unittests/config/commandLineParsing.ts @@ -446,6 +446,23 @@ namespace ts { }); }); + it("parse build with listFilesOnly ", () => { + // --lib es6 0.ts + assertParseResult(["--listFilesOnly"], + { + errors: [{ + messageText:"Unknown build option '--listFilesOnly'.", + category: Diagnostics.Unknown_build_option_0.category, + code: Diagnostics.Unknown_build_option_0.code, + file: undefined, + start: undefined, + length: undefined, + }], + projects: ["."], + buildOptions: {} + }); + }); + it("Parse multiple flags with input projects at the end", () => { // --lib es5,es2015.symbol.wellknown --target es5 0.ts assertParseResult(["--force", "--verbose", "src", "tests"], diff --git a/src/tsc/executeCommandLine.ts b/src/tsc/executeCommandLine.ts index cf813fa2f60..d730de4a981 100644 --- a/src/tsc/executeCommandLine.ts +++ b/src/tsc/executeCommandLine.ts @@ -207,6 +207,11 @@ namespace ts { return sys.exit(ExitStatus.Success); } + if (commandLine.options.watch && commandLine.options.listFilesOnly) { + reportDiagnostic(createCompilerDiagnostic(Diagnostics.Options_0_and_1_cannot_be_combined, "watch", "listFilesOnly")); + return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped); + } + if (commandLine.options.project) { if (commandLine.fileNames.length !== 0) { reportDiagnostic(createCompilerDiagnostic(Diagnostics.Option_project_cannot_be_mixed_with_source_files_on_a_command_line)); diff --git a/tests/baselines/reference/showConfig/Shows tsconfig for single option/listFilesOnly/tsconfig.json b/tests/baselines/reference/showConfig/Shows tsconfig for single option/listFilesOnly/tsconfig.json new file mode 100644 index 00000000000..9134bd8c6fa --- /dev/null +++ b/tests/baselines/reference/showConfig/Shows tsconfig for single option/listFilesOnly/tsconfig.json @@ -0,0 +1,5 @@ +{ + "compilerOptions": { + "listFilesOnly": true + } +} diff --git a/tests/cases/fourslash/listFilesOnly.ts b/tests/cases/fourslash/listFilesOnly.ts new file mode 100644 index 00000000000..63e2ba19407 --- /dev/null +++ b/tests/cases/fourslash/listFilesOnly.ts @@ -0,0 +1,10 @@ +/// + +// @listFilesOnly: true + +// @Filename: a.js +////const x = 1; + +// Just want to see that no baseline is emitted + +verify.noErrors(); \ No newline at end of file