mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Merge pull request #27078 from Microsoft/commonCompilerOptionsWithBuild
Parse selected command line options with build and use them as base for solution building
This commit is contained in:
@@ -62,7 +62,8 @@ namespace ts {
|
||||
/* @internal */
|
||||
export const libMap = createMapFromEntries(libEntries);
|
||||
|
||||
const commonOptionsWithBuild: CommandLineOption[] = [
|
||||
/* @internal */
|
||||
export const commonOptionsWithBuild: CommandLineOption[] = [
|
||||
{
|
||||
name: "help",
|
||||
shortName: "h",
|
||||
@@ -83,6 +84,18 @@ namespace ts {
|
||||
category: Diagnostics.Command_line_Options,
|
||||
description: Diagnostics.Whether_to_keep_outdated_console_output_in_watch_mode_instead_of_clearing_the_screen,
|
||||
},
|
||||
{
|
||||
name: "listFiles",
|
||||
type: "boolean",
|
||||
category: Diagnostics.Advanced_Options,
|
||||
description: Diagnostics.Print_names_of_files_part_of_the_compilation
|
||||
},
|
||||
{
|
||||
name: "listEmittedFiles",
|
||||
type: "boolean",
|
||||
category: Diagnostics.Advanced_Options,
|
||||
description: Diagnostics.Print_names_of_generated_files_part_of_the_compilation
|
||||
},
|
||||
{
|
||||
name: "watch",
|
||||
shortName: "w",
|
||||
@@ -561,18 +574,6 @@ namespace ts {
|
||||
category: Diagnostics.Advanced_Options,
|
||||
description: Diagnostics.Include_modules_imported_with_json_extension
|
||||
},
|
||||
{
|
||||
name: "listFiles",
|
||||
type: "boolean",
|
||||
category: Diagnostics.Advanced_Options,
|
||||
description: Diagnostics.Print_names_of_files_part_of_the_compilation
|
||||
},
|
||||
{
|
||||
name: "listEmittedFiles",
|
||||
type: "boolean",
|
||||
category: Diagnostics.Advanced_Options,
|
||||
description: Diagnostics.Print_names_of_generated_files_part_of_the_compilation
|
||||
},
|
||||
|
||||
{
|
||||
name: "out",
|
||||
@@ -903,17 +904,27 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
export function parseCommandLine(commandLine: ReadonlyArray<string>, readFile?: (path: string) => string | undefined): ParsedCommandLine {
|
||||
const options: CompilerOptions = {};
|
||||
/* @internal */
|
||||
export interface OptionsBase {
|
||||
[option: string]: CompilerOptionsValue | undefined;
|
||||
}
|
||||
|
||||
/** Tuple with error messages for 'unknown compiler option', 'option requires type' */
|
||||
type ParseCommandLineWorkerDiagnostics = [DiagnosticMessage, DiagnosticMessage];
|
||||
|
||||
function parseCommandLineWorker(
|
||||
getOptionNameMap: () => OptionNameMap,
|
||||
[unknownOptionDiagnostic, optionTypeMismatchDiagnostic]: ParseCommandLineWorkerDiagnostics,
|
||||
commandLine: ReadonlyArray<string>,
|
||||
readFile?: (path: string) => string | undefined) {
|
||||
const options = {} as OptionsBase;
|
||||
const fileNames: string[] = [];
|
||||
const projectReferences: ProjectReference[] | undefined = undefined;
|
||||
const errors: Diagnostic[] = [];
|
||||
|
||||
parseStrings(commandLine);
|
||||
return {
|
||||
options,
|
||||
fileNames,
|
||||
projectReferences,
|
||||
errors
|
||||
};
|
||||
|
||||
@@ -926,7 +937,7 @@ namespace ts {
|
||||
parseResponseFile(s.slice(1));
|
||||
}
|
||||
else if (s.charCodeAt(0) === CharacterCodes.minus) {
|
||||
const opt = getOptionFromName(s.slice(s.charCodeAt(1) === CharacterCodes.minus ? 2 : 1), /*allowShort*/ true);
|
||||
const opt = getOptionDeclarationFromName(getOptionNameMap, s.slice(s.charCodeAt(1) === CharacterCodes.minus ? 2 : 1), /*allowShort*/ true);
|
||||
if (opt) {
|
||||
if (opt.isTSConfigOnly) {
|
||||
errors.push(createCompilerDiagnostic(Diagnostics.Option_0_can_only_be_specified_in_tsconfig_json_file, opt.name));
|
||||
@@ -934,7 +945,7 @@ namespace ts {
|
||||
else {
|
||||
// Check to see if no argument was provided (e.g. "--locale" is the last command-line argument).
|
||||
if (!args[i] && opt.type !== "boolean") {
|
||||
errors.push(createCompilerDiagnostic(Diagnostics.Compiler_option_0_expects_an_argument, opt.name));
|
||||
errors.push(createCompilerDiagnostic(optionTypeMismatchDiagnostic, opt.name));
|
||||
}
|
||||
|
||||
switch (opt.type) {
|
||||
@@ -971,7 +982,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
else {
|
||||
errors.push(createCompilerDiagnostic(Diagnostics.Unknown_compiler_option_0, s));
|
||||
errors.push(createCompilerDiagnostic(unknownOptionDiagnostic, s));
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -1014,13 +1025,19 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
export function parseCommandLine(commandLine: ReadonlyArray<string>, readFile?: (path: string) => string | undefined): ParsedCommandLine {
|
||||
return parseCommandLineWorker(getOptionNameMap, [
|
||||
Diagnostics.Unknown_compiler_option_0,
|
||||
Diagnostics.Compiler_option_0_expects_an_argument
|
||||
], commandLine, readFile);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function getOptionFromName(optionName: string, allowShort?: boolean): CommandLineOption | undefined {
|
||||
return getOptionDeclarationFromName(getOptionNameMap, optionName, allowShort);
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
export function getOptionDeclarationFromName(getOptionNameMap: () => OptionNameMap, optionName: string, allowShort = false): CommandLineOption | undefined {
|
||||
function getOptionDeclarationFromName(getOptionNameMap: () => OptionNameMap, optionName: string, allowShort = false): CommandLineOption | undefined {
|
||||
optionName = optionName.toLowerCase();
|
||||
const { optionNameMap, shortOptionNames } = getOptionNameMap();
|
||||
// Try to translate short option names to their full equivalents.
|
||||
@@ -1044,25 +1061,11 @@ namespace ts {
|
||||
export function parseBuildCommand(args: string[]): ParsedBuildCommand {
|
||||
let buildOptionNameMap: OptionNameMap | undefined;
|
||||
const returnBuildOptionNameMap = () => (buildOptionNameMap || (buildOptionNameMap = createOptionNameMap(buildOpts)));
|
||||
|
||||
const buildOptions: BuildOptions = {};
|
||||
const projects: string[] = [];
|
||||
let errors: Diagnostic[] | undefined;
|
||||
for (const arg of args) {
|
||||
if (arg.charCodeAt(0) === CharacterCodes.minus) {
|
||||
const opt = getOptionDeclarationFromName(returnBuildOptionNameMap, arg.slice(arg.charCodeAt(1) === CharacterCodes.minus ? 2 : 1), /*allowShort*/ true);
|
||||
if (opt) {
|
||||
buildOptions[opt.name as keyof BuildOptions] = true;
|
||||
}
|
||||
else {
|
||||
(errors || (errors = [])).push(createCompilerDiagnostic(Diagnostics.Unknown_build_option_0, arg));
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Not a flag, parse as filename
|
||||
projects.push(arg);
|
||||
}
|
||||
}
|
||||
const { options, fileNames: projects, errors } = parseCommandLineWorker(returnBuildOptionNameMap, [
|
||||
Diagnostics.Unknown_build_option_0,
|
||||
Diagnostics.Build_option_0_requires_a_value_of_type_1
|
||||
], args);
|
||||
const buildOptions = options as BuildOptions;
|
||||
|
||||
if (projects.length === 0) {
|
||||
// tsc -b invoked with no extra arguments; act as if invoked with "tsc -b ."
|
||||
@@ -1071,19 +1074,19 @@ namespace ts {
|
||||
|
||||
// Nonsensical combinations
|
||||
if (buildOptions.clean && buildOptions.force) {
|
||||
(errors || (errors = [])).push(createCompilerDiagnostic(Diagnostics.Options_0_and_1_cannot_be_combined, "clean", "force"));
|
||||
errors.push(createCompilerDiagnostic(Diagnostics.Options_0_and_1_cannot_be_combined, "clean", "force"));
|
||||
}
|
||||
if (buildOptions.clean && buildOptions.verbose) {
|
||||
(errors || (errors = [])).push(createCompilerDiagnostic(Diagnostics.Options_0_and_1_cannot_be_combined, "clean", "verbose"));
|
||||
errors.push(createCompilerDiagnostic(Diagnostics.Options_0_and_1_cannot_be_combined, "clean", "verbose"));
|
||||
}
|
||||
if (buildOptions.clean && buildOptions.watch) {
|
||||
(errors || (errors = [])).push(createCompilerDiagnostic(Diagnostics.Options_0_and_1_cannot_be_combined, "clean", "watch"));
|
||||
errors.push(createCompilerDiagnostic(Diagnostics.Options_0_and_1_cannot_be_combined, "clean", "watch"));
|
||||
}
|
||||
if (buildOptions.watch && buildOptions.dry) {
|
||||
(errors || (errors = [])).push(createCompilerDiagnostic(Diagnostics.Options_0_and_1_cannot_be_combined, "watch", "dry"));
|
||||
errors.push(createCompilerDiagnostic(Diagnostics.Options_0_and_1_cannot_be_combined, "watch", "dry"));
|
||||
}
|
||||
|
||||
return { buildOptions, projects, errors: errors || emptyArray };
|
||||
return { buildOptions, projects, errors };
|
||||
}
|
||||
|
||||
function getDiagnosticText(_message: DiagnosticMessage, ..._args: any[]): string {
|
||||
|
||||
@@ -2948,7 +2948,10 @@
|
||||
"category": "Error",
|
||||
"code": 5072
|
||||
},
|
||||
|
||||
"Build option '{0}' requires a value of type {1}.": {
|
||||
"category": "Error",
|
||||
"code": 5073
|
||||
},
|
||||
|
||||
"Generates a sourcemap for each corresponding '.d.ts' file.": {
|
||||
"category": "Message",
|
||||
@@ -4640,7 +4643,7 @@
|
||||
"category": "Message",
|
||||
"code": 95062
|
||||
},
|
||||
|
||||
|
||||
"Add missing enum member '{0}'": {
|
||||
"category": "Message",
|
||||
"code": 95063
|
||||
@@ -4649,12 +4652,12 @@
|
||||
"category": "Message",
|
||||
"code": 95064
|
||||
},
|
||||
"Convert to async function":{
|
||||
"Convert to async function": {
|
||||
"category": "Message",
|
||||
"code": 95065
|
||||
"code": 95065
|
||||
},
|
||||
"Convert all to async functions": {
|
||||
"category": "Message",
|
||||
"code": 95066
|
||||
"category": "Message",
|
||||
"code": 95066
|
||||
}
|
||||
}
|
||||
|
||||
+37
-17
@@ -17,14 +17,18 @@ namespace ts {
|
||||
referencingProjectsMap: ConfigFileMap<ConfigFileMap<boolean>>;
|
||||
}
|
||||
|
||||
export interface BuildOptions {
|
||||
export interface BuildOptions extends OptionsBase {
|
||||
dry?: boolean;
|
||||
force?: boolean;
|
||||
verbose?: boolean;
|
||||
|
||||
/*@internal*/ clean?: boolean;
|
||||
/*@internal*/ watch?: boolean;
|
||||
/*@internal*/ help?: boolean;
|
||||
|
||||
preserveWatchOutput?: boolean;
|
||||
listEmittedFiles?: boolean;
|
||||
listFiles?: boolean;
|
||||
}
|
||||
|
||||
enum BuildResultFlags {
|
||||
@@ -44,8 +48,9 @@ namespace ts {
|
||||
SyntaxErrors = 1 << 3,
|
||||
TypeErrors = 1 << 4,
|
||||
DeclarationEmitErrors = 1 << 5,
|
||||
EmitErrors = 1 << 6,
|
||||
|
||||
AnyErrors = ConfigFileErrors | SyntaxErrors | TypeErrors | DeclarationEmitErrors
|
||||
AnyErrors = ConfigFileErrors | SyntaxErrors | TypeErrors | DeclarationEmitErrors | EmitErrors
|
||||
}
|
||||
|
||||
export enum UpToDateStatusType {
|
||||
@@ -370,6 +375,14 @@ namespace ts {
|
||||
return host;
|
||||
}
|
||||
|
||||
function getCompilerOptionsOfBuildOptions(buildOptions: BuildOptions): CompilerOptions {
|
||||
const result = {} as CompilerOptions;
|
||||
commonOptionsWithBuild.forEach(option => {
|
||||
result[option.name] = buildOptions[option.name];
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* A SolutionBuilder has an immutable set of rootNames that are the "entry point" projects, but
|
||||
* can dynamically add/remove other projects based on changes on the rootNames' references
|
||||
@@ -384,6 +397,7 @@ namespace ts {
|
||||
|
||||
// State of the solution
|
||||
let options = defaultOptions;
|
||||
let baseCompilerOptions = getCompilerOptionsOfBuildOptions(options);
|
||||
type ConfigFileCacheEntry = ParsedCommandLine | Diagnostic;
|
||||
const configFileCache = createFileMap<ConfigFileCacheEntry>(toPath);
|
||||
/** Map from output file name to its pre-build timestamp */
|
||||
@@ -392,6 +406,7 @@ namespace ts {
|
||||
const projectStatus = createFileMap<UpToDateStatus>(toPath);
|
||||
const missingRoots = createMap<true>();
|
||||
let globalDependencyGraph: DependencyGraph | undefined;
|
||||
const writeFileName = (s: string) => host.trace && host.trace(s);
|
||||
|
||||
// Watch state
|
||||
const diagnostics = createFileMap<ReadonlyArray<Diagnostic>>(toPath);
|
||||
@@ -430,6 +445,7 @@ namespace ts {
|
||||
|
||||
function resetBuildContext(opts = defaultOptions) {
|
||||
options = opts;
|
||||
baseCompilerOptions = getCompilerOptionsOfBuildOptions(options);
|
||||
configFileCache.clear();
|
||||
unchangedOutputs.clear();
|
||||
projectStatus.clear();
|
||||
@@ -463,7 +479,7 @@ namespace ts {
|
||||
|
||||
let diagnostic: Diagnostic | undefined;
|
||||
parseConfigFileHost.onUnRecoverableConfigFileDiagnostic = d => diagnostic = d;
|
||||
const parsed = getParsedCommandLineOfConfigFile(configFilePath, {}, parseConfigFileHost);
|
||||
const parsed = getParsedCommandLineOfConfigFile(configFilePath, baseCompilerOptions, parseConfigFileHost);
|
||||
parseConfigFileHost.onUnRecoverableConfigFileDiagnostic = noop;
|
||||
configFileCache.setValue(configFilePath, parsed || diagnostic!);
|
||||
return parsed;
|
||||
@@ -475,7 +491,7 @@ namespace ts {
|
||||
|
||||
function reportWatchStatus(message: DiagnosticMessage, ...args: (string | number | undefined)[]) {
|
||||
if (hostWithWatch.onWatchStatusChange) {
|
||||
hostWithWatch.onWatchStatusChange(createCompilerDiagnostic(message, ...args), host.getNewLine(), { preserveWatchOutput: options.preserveWatchOutput });
|
||||
hostWithWatch.onWatchStatusChange(createCompilerDiagnostic(message, ...args), host.getNewLine(), baseCompilerOptions);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1004,35 +1020,28 @@ namespace ts {
|
||||
...program.getConfigFileParsingDiagnostics(),
|
||||
...program.getSyntacticDiagnostics()];
|
||||
if (syntaxDiagnostics.length) {
|
||||
resultFlags |= BuildResultFlags.SyntaxErrors;
|
||||
reportAndStoreErrors(proj, syntaxDiagnostics);
|
||||
projectStatus.setValue(proj, { type: UpToDateStatusType.Unbuildable, reason: "Syntactic errors" });
|
||||
return resultFlags;
|
||||
return buildErrors(syntaxDiagnostics, BuildResultFlags.SyntaxErrors, "Syntactic");
|
||||
}
|
||||
|
||||
// Don't emit .d.ts if there are decl file errors
|
||||
if (getEmitDeclarations(program.getCompilerOptions())) {
|
||||
const declDiagnostics = program.getDeclarationDiagnostics();
|
||||
if (declDiagnostics.length) {
|
||||
resultFlags |= BuildResultFlags.DeclarationEmitErrors;
|
||||
reportAndStoreErrors(proj, declDiagnostics);
|
||||
projectStatus.setValue(proj, { type: UpToDateStatusType.Unbuildable, reason: "Declaration file errors" });
|
||||
return resultFlags;
|
||||
return buildErrors(declDiagnostics, BuildResultFlags.DeclarationEmitErrors, "Declaration file");
|
||||
}
|
||||
}
|
||||
|
||||
// Same as above but now for semantic diagnostics
|
||||
const semanticDiagnostics = program.getSemanticDiagnostics();
|
||||
if (semanticDiagnostics.length) {
|
||||
resultFlags |= BuildResultFlags.TypeErrors;
|
||||
reportAndStoreErrors(proj, semanticDiagnostics);
|
||||
projectStatus.setValue(proj, { type: UpToDateStatusType.Unbuildable, reason: "Semantic errors" });
|
||||
return resultFlags;
|
||||
return buildErrors(semanticDiagnostics, BuildResultFlags.TypeErrors, "Semantic");
|
||||
}
|
||||
|
||||
let newestDeclarationFileContentChangedTime = minimumDate;
|
||||
let anyDtsChanged = false;
|
||||
program.emit(/*targetSourceFile*/ undefined, (fileName, content, writeBom, onError) => {
|
||||
let emitDiagnostics: Diagnostic[] | undefined;
|
||||
const reportEmitDiagnostic = (d: Diagnostic) => (emitDiagnostics || (emitDiagnostics = [])).push(d);
|
||||
emitFilesAndReportErrors(program, reportEmitDiagnostic, writeFileName, /*reportSummary*/ undefined, (fileName, content, writeBom, onError) => {
|
||||
let priorChangeTime: Date | undefined;
|
||||
if (!anyDtsChanged && isDeclarationFile(fileName)) {
|
||||
// Check for unchanged .d.ts files
|
||||
@@ -1052,12 +1061,23 @@ namespace ts {
|
||||
}
|
||||
});
|
||||
|
||||
if (emitDiagnostics) {
|
||||
return buildErrors(emitDiagnostics, BuildResultFlags.EmitErrors, "Emit");
|
||||
}
|
||||
|
||||
const status: UpToDateStatus = {
|
||||
type: UpToDateStatusType.UpToDate,
|
||||
newestDeclarationFileContentChangedTime: anyDtsChanged ? maximumDate : newestDeclarationFileContentChangedTime
|
||||
};
|
||||
projectStatus.setValue(proj, status);
|
||||
return resultFlags;
|
||||
|
||||
function buildErrors(diagnostics: ReadonlyArray<Diagnostic>, errorFlags: BuildResultFlags, errorType: string) {
|
||||
resultFlags |= errorFlags;
|
||||
reportAndStoreErrors(proj, diagnostics);
|
||||
projectStatus.setValue(proj, { type: UpToDateStatusType.Unbuildable, reason: `${errorType} errors` });
|
||||
return resultFlags;
|
||||
}
|
||||
}
|
||||
|
||||
function updateOutputTimestamps(proj: ParsedCommandLine) {
|
||||
|
||||
@@ -101,7 +101,7 @@ namespace ts {
|
||||
getGlobalDiagnostics(): ReadonlyArray<Diagnostic>;
|
||||
getSemanticDiagnostics(): ReadonlyArray<Diagnostic>;
|
||||
getConfigFileParsingDiagnostics(): ReadonlyArray<Diagnostic>;
|
||||
emit(): EmitResult;
|
||||
emit(targetSourceFile?: SourceFile, writeFile?: WriteFileCallback): EmitResult;
|
||||
}
|
||||
|
||||
export type ReportEmitErrorSummary = (errorCount: number) => void;
|
||||
@@ -109,7 +109,7 @@ namespace ts {
|
||||
/**
|
||||
* Helper that emit files, report diagnostics and lists emitted and/or source files depending on compiler options
|
||||
*/
|
||||
export function emitFilesAndReportErrors(program: ProgramToEmitFilesAndReportErrors, reportDiagnostic: DiagnosticReporter, writeFileName?: (s: string) => void, reportSummary?: ReportEmitErrorSummary) {
|
||||
export function emitFilesAndReportErrors(program: ProgramToEmitFilesAndReportErrors, reportDiagnostic: DiagnosticReporter, writeFileName?: (s: string) => void, reportSummary?: ReportEmitErrorSummary, writeFile?: WriteFileCallback) {
|
||||
// First get and report any syntactic errors.
|
||||
const diagnostics = program.getConfigFileParsingDiagnostics().slice();
|
||||
const configFileParsingDiagnosticsLength = diagnostics.length;
|
||||
@@ -128,7 +128,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
// Emit and report any errors we ran into.
|
||||
const { emittedFiles, emitSkipped, diagnostics: emitDiagnostics } = program.emit();
|
||||
const { emittedFiles, emitSkipped, diagnostics: emitDiagnostics } = program.emit(/*targetSourceFile*/ undefined, writeFile);
|
||||
addRange(diagnostics, emitDiagnostics);
|
||||
|
||||
if (reportSemanticDiagnostics) {
|
||||
|
||||
@@ -264,6 +264,63 @@ export class cNew {}`);
|
||||
verifyProjectWithResolveJsonModule("/src/tests/tsconfig_withIncludeAndFiles.json");
|
||||
});
|
||||
});
|
||||
|
||||
describe("tsbuild - lists files", () => {
|
||||
it("listFiles", () => {
|
||||
const fs = projFs.shadow();
|
||||
const host = new fakes.SolutionBuilderHost(fs);
|
||||
const builder = createSolutionBuilder(host, ["/src/tests"], { listFiles: true });
|
||||
builder.buildAllProjects();
|
||||
assert.deepEqual(host.traces, [
|
||||
...getLibs(),
|
||||
"/src/core/anotherModule.ts",
|
||||
"/src/core/index.ts",
|
||||
"/src/core/some_decl.d.ts",
|
||||
...getLibs(),
|
||||
...getCoreOutputs(),
|
||||
"/src/logic/index.ts",
|
||||
...getLibs(),
|
||||
...getCoreOutputs(),
|
||||
"/src/logic/index.d.ts",
|
||||
"/src/tests/index.ts"
|
||||
]);
|
||||
|
||||
function getLibs() {
|
||||
return [
|
||||
"/lib/lib.d.ts",
|
||||
"/lib/lib.es5.d.ts",
|
||||
"/lib/lib.dom.d.ts",
|
||||
"/lib/lib.webworker.importscripts.d.ts",
|
||||
"/lib/lib.scripthost.d.ts"
|
||||
];
|
||||
}
|
||||
|
||||
function getCoreOutputs() {
|
||||
return [
|
||||
"/src/core/index.d.ts",
|
||||
"/src/core/anotherModule.d.ts"
|
||||
];
|
||||
}
|
||||
});
|
||||
|
||||
it("listEmittedFiles", () => {
|
||||
const fs = projFs.shadow();
|
||||
const host = new fakes.SolutionBuilderHost(fs);
|
||||
const builder = createSolutionBuilder(host, ["/src/tests"], { listEmittedFiles: true });
|
||||
builder.buildAllProjects();
|
||||
assert.deepEqual(host.traces, [
|
||||
"TSFILE: /src/core/anotherModule.js",
|
||||
"TSFILE: /src/core/anotherModule.d.ts",
|
||||
"TSFILE: /src/core/index.js",
|
||||
"TSFILE: /src/core/index.d.ts",
|
||||
"TSFILE: /src/logic/index.js",
|
||||
"TSFILE: /src/logic/index.js.map",
|
||||
"TSFILE: /src/logic/index.d.ts",
|
||||
"TSFILE: /src/tests/index.js",
|
||||
"TSFILE: /src/tests/index.d.ts",
|
||||
]);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export namespace OutFile {
|
||||
|
||||
@@ -2,7 +2,7 @@ namespace ts.tscWatch {
|
||||
export import libFile = TestFSWithWatch.libFile;
|
||||
function createSolutionBuilder(system: WatchedSystem, rootNames: ReadonlyArray<string>, defaultOptions?: BuildOptions) {
|
||||
const host = createSolutionBuilderWithWatchHost(system);
|
||||
return ts.createSolutionBuilder(host, rootNames, defaultOptions || { dry: false, force: false, verbose: false, watch: true });
|
||||
return ts.createSolutionBuilder(host, rootNames, defaultOptions || { watch: true });
|
||||
}
|
||||
|
||||
function createSolutionBuilderWithWatch(host: WatchedSystem, rootNames: ReadonlyArray<string>, defaultOptions?: BuildOptions) {
|
||||
@@ -95,11 +95,11 @@ namespace ts.tscWatch {
|
||||
const allFiles: ReadonlyArray<File> = [libFile, ...core, ...logic, ...tests, ...ui];
|
||||
const testProjectExpectedWatchedFiles = [core[0], core[1], core[2], ...logic, ...tests].map(f => f.path);
|
||||
|
||||
function createSolutionInWatchMode(allFiles: ReadonlyArray<File>) {
|
||||
function createSolutionInWatchMode(allFiles: ReadonlyArray<File>, defaultOptions?: BuildOptions, disableConsoleClears?: boolean) {
|
||||
const host = createWatchedSystem(allFiles, { currentDirectory: projectsLocation });
|
||||
createSolutionBuilderWithWatch(host, [`${project}/${SubProject.tests}`]);
|
||||
createSolutionBuilderWithWatch(host, [`${project}/${SubProject.tests}`], defaultOptions);
|
||||
verifyWatches(host);
|
||||
checkOutputErrorsInitial(host, emptyArray);
|
||||
checkOutputErrorsInitial(host, emptyArray, disableConsoleClears);
|
||||
const outputFileStamps = getOutputFileStamps(host);
|
||||
for (const stamp of outputFileStamps) {
|
||||
assert.isDefined(stamp[1], `${stamp[0]} expected to be present`);
|
||||
@@ -351,32 +351,42 @@ function myFunc() { return 100; }`);
|
||||
}
|
||||
});
|
||||
|
||||
it("reports errors in all projects on incremental compile", () => {
|
||||
const host = createSolutionInWatchMode(allFiles);
|
||||
const outputFileStamps = getOutputFileStamps(host);
|
||||
describe("reports errors in all projects on incremental compile", () => {
|
||||
function verifyIncrementalErrors(defaultBuildOptions?: BuildOptions, disabledConsoleClear?: boolean) {
|
||||
const host = createSolutionInWatchMode(allFiles, defaultBuildOptions, disabledConsoleClear);
|
||||
const outputFileStamps = getOutputFileStamps(host);
|
||||
|
||||
host.writeFile(logic[1].path, `${logic[1].content}
|
||||
host.writeFile(logic[1].path, `${logic[1].content}
|
||||
let y: string = 10;`);
|
||||
|
||||
host.checkTimeoutQueueLengthAndRun(1); // Builds logic
|
||||
const changedLogic = getOutputFileStamps(host);
|
||||
verifyChangedFiles(changedLogic, outputFileStamps, emptyArray);
|
||||
host.checkTimeoutQueueLength(0);
|
||||
checkOutputErrorsIncremental(host, [
|
||||
`sample1/logic/index.ts(8,5): error TS2322: Type '10' is not assignable to type 'string'.\n`
|
||||
]);
|
||||
host.checkTimeoutQueueLengthAndRun(1); // Builds logic
|
||||
const changedLogic = getOutputFileStamps(host);
|
||||
verifyChangedFiles(changedLogic, outputFileStamps, emptyArray);
|
||||
host.checkTimeoutQueueLength(0);
|
||||
checkOutputErrorsIncremental(host, [
|
||||
`sample1/logic/index.ts(8,5): error TS2322: Type '10' is not assignable to type 'string'.\n`
|
||||
], disabledConsoleClear);
|
||||
|
||||
host.writeFile(core[1].path, `${core[1].content}
|
||||
host.writeFile(core[1].path, `${core[1].content}
|
||||
let x: string = 10;`);
|
||||
|
||||
host.checkTimeoutQueueLengthAndRun(1); // Builds core
|
||||
const changedCore = getOutputFileStamps(host);
|
||||
verifyChangedFiles(changedCore, changedLogic, emptyArray);
|
||||
host.checkTimeoutQueueLength(0);
|
||||
checkOutputErrorsIncremental(host, [
|
||||
`sample1/core/index.ts(5,5): error TS2322: Type '10' is not assignable to type 'string'.\n`,
|
||||
`sample1/logic/index.ts(8,5): error TS2322: Type '10' is not assignable to type 'string'.\n`
|
||||
]);
|
||||
host.checkTimeoutQueueLengthAndRun(1); // Builds core
|
||||
const changedCore = getOutputFileStamps(host);
|
||||
verifyChangedFiles(changedCore, changedLogic, emptyArray);
|
||||
host.checkTimeoutQueueLength(0);
|
||||
checkOutputErrorsIncremental(host, [
|
||||
`sample1/core/index.ts(5,5): error TS2322: Type '10' is not assignable to type 'string'.\n`,
|
||||
`sample1/logic/index.ts(8,5): error TS2322: Type '10' is not assignable to type 'string'.\n`
|
||||
], disabledConsoleClear);
|
||||
}
|
||||
|
||||
it("when preserveWatchOutput is not used", () => {
|
||||
verifyIncrementalErrors();
|
||||
});
|
||||
|
||||
it("when preserveWatchOutput is passed on command line", () => {
|
||||
verifyIncrementalErrors({ preserveWatchOutput: true, watch: true }, /*disabledConsoleClear*/ true);
|
||||
});
|
||||
});
|
||||
// TODO: write tests reporting errors but that will have more involved work since file
|
||||
});
|
||||
|
||||
+12
-17
@@ -53,14 +53,10 @@ namespace ts {
|
||||
}
|
||||
|
||||
export function executeCommandLine(args: string[]): void {
|
||||
if (args.length > 0 && ((args[0].toLowerCase() === "--build") || (args[0].toLowerCase() === "-b"))) {
|
||||
const result = performBuild(args.slice(1));
|
||||
// undefined = in watch mode, do not exit
|
||||
if (result !== undefined) {
|
||||
return sys.exit(result);
|
||||
}
|
||||
else {
|
||||
return;
|
||||
if (args.length > 0 && args[0].charCodeAt(0) === CharacterCodes.minus) {
|
||||
const firstOption = args[0].slice(args[0].charCodeAt(1) === CharacterCodes.minus ? 2 : 1).toLowerCase();
|
||||
if (firstOption === "build" || firstOption === "b") {
|
||||
return performBuild(args.slice(1));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,17 +160,17 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function performBuild(args: string[]): number | undefined {
|
||||
function performBuild(args: string[]) {
|
||||
const { buildOptions, projects, errors } = parseBuildCommand(args);
|
||||
if (errors.length > 0) {
|
||||
errors.forEach(reportDiagnostic);
|
||||
return ExitStatus.DiagnosticsPresent_OutputsSkipped;
|
||||
return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped);
|
||||
}
|
||||
|
||||
if (buildOptions.help) {
|
||||
printVersion();
|
||||
printHelp(buildOpts, "--build ");
|
||||
return ExitStatus.Success;
|
||||
return sys.exit(ExitStatus.Success);
|
||||
}
|
||||
|
||||
// Update to pretty if host supports it
|
||||
@@ -182,12 +178,12 @@ namespace ts {
|
||||
if (projects.length === 0) {
|
||||
printVersion();
|
||||
printHelp(buildOpts, "--build ");
|
||||
return ExitStatus.Success;
|
||||
return sys.exit(ExitStatus.Success);
|
||||
}
|
||||
|
||||
if (!sys.getModifiedTime || !sys.setModifiedTime || (buildOptions.clean && !sys.deleteFile)) {
|
||||
reportDiagnostic(createCompilerDiagnostic(Diagnostics.The_current_host_does_not_support_the_0_option, "--build"));
|
||||
return ExitStatus.DiagnosticsPresent_OutputsSkipped;
|
||||
return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped);
|
||||
}
|
||||
if (buildOptions.watch) {
|
||||
reportWatchModeWithoutSysSupport();
|
||||
@@ -196,16 +192,15 @@ namespace ts {
|
||||
// TODO: change this to host if watch => watchHost otherwiue without wathc
|
||||
const builder = createSolutionBuilder(createSolutionBuilderWithWatchHost(sys, reportDiagnostic, createBuilderStatusReporter(sys, shouldBePretty()), createWatchStatusReporter()), projects, buildOptions);
|
||||
if (buildOptions.clean) {
|
||||
return builder.cleanAllProjects();
|
||||
return sys.exit(builder.cleanAllProjects());
|
||||
}
|
||||
|
||||
if (buildOptions.watch) {
|
||||
builder.buildAllProjects();
|
||||
builder.startWatching();
|
||||
return undefined;
|
||||
return builder.startWatching();
|
||||
}
|
||||
|
||||
return builder.buildAllProjects();
|
||||
return sys.exit(builder.buildAllProjects());
|
||||
}
|
||||
|
||||
function performCompilation(rootNames: string[], projectReferences: ReadonlyArray<ProjectReference> | undefined, options: CompilerOptions, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>) {
|
||||
|
||||
Reference in New Issue
Block a user