Skip to content

Commit 25db0b0

Browse files
committed
Merge baselining and tsc logic into one
1 parent e3cc4f4 commit 25db0b0

File tree

7 files changed

+765
-735
lines changed

7 files changed

+765
-735
lines changed

src/compiler/commandLineParser.ts

Lines changed: 16 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -1227,7 +1227,7 @@ namespace ts {
12271227
}
12281228

12291229
/*@internal*/
1230-
export function parseBuildCommand(args: string[]): ParsedBuildCommand {
1230+
export function parseBuildCommand(args: readonly string[]): ParsedBuildCommand {
12311231
let buildOptionNameMap: OptionNameMap | undefined;
12321232
const returnBuildOptionNameMap = () => (buildOptionNameMap || (buildOptionNameMap = createOptionNameMap(buildOpts)));
12331233
const { options, fileNames: projects, errors } = parseCommandLineWorker(returnBuildOptionNameMap, [
@@ -1258,125 +1258,12 @@ namespace ts {
12581258
return { buildOptions, projects, errors };
12591259
}
12601260

1261-
function getDiagnosticText(_message: DiagnosticMessage, ..._args: any[]): string {
1261+
/* @internal */
1262+
export function getDiagnosticText(_message: DiagnosticMessage, ..._args: any[]): string {
12621263
const diagnostic = createCompilerDiagnostic.apply(undefined, arguments);
12631264
return <string>diagnostic.messageText;
12641265
}
12651266

1266-
/* @internal */
1267-
export function printVersion() {
1268-
sys.write(getDiagnosticText(Diagnostics.Version_0, version) + sys.newLine);
1269-
}
1270-
1271-
/* @internal */
1272-
export function printHelp(optionsList: readonly CommandLineOption[], syntaxPrefix = "") {
1273-
const output: string[] = [];
1274-
1275-
// We want to align our "syntax" and "examples" commands to a certain margin.
1276-
const syntaxLength = getDiagnosticText(Diagnostics.Syntax_Colon_0, "").length;
1277-
const examplesLength = getDiagnosticText(Diagnostics.Examples_Colon_0, "").length;
1278-
let marginLength = Math.max(syntaxLength, examplesLength);
1279-
1280-
// Build up the syntactic skeleton.
1281-
let syntax = makePadding(marginLength - syntaxLength);
1282-
syntax += `tsc ${syntaxPrefix}[${getDiagnosticText(Diagnostics.options)}] [${getDiagnosticText(Diagnostics.file)}...]`;
1283-
1284-
output.push(getDiagnosticText(Diagnostics.Syntax_Colon_0, syntax));
1285-
output.push(sys.newLine + sys.newLine);
1286-
1287-
// Build up the list of examples.
1288-
const padding = makePadding(marginLength);
1289-
output.push(getDiagnosticText(Diagnostics.Examples_Colon_0, makePadding(marginLength - examplesLength) + "tsc hello.ts") + sys.newLine);
1290-
output.push(padding + "tsc --outFile file.js file.ts" + sys.newLine);
1291-
output.push(padding + "tsc @args.txt" + sys.newLine);
1292-
output.push(padding + "tsc --build tsconfig.json" + sys.newLine);
1293-
output.push(sys.newLine);
1294-
1295-
output.push(getDiagnosticText(Diagnostics.Options_Colon) + sys.newLine);
1296-
1297-
// We want our descriptions to align at the same column in our output,
1298-
// so we keep track of the longest option usage string.
1299-
marginLength = 0;
1300-
const usageColumn: string[] = []; // Things like "-d, --declaration" go in here.
1301-
const descriptionColumn: string[] = [];
1302-
1303-
const optionsDescriptionMap = createMap<string[]>(); // Map between option.description and list of option.type if it is a kind
1304-
1305-
for (const option of optionsList) {
1306-
// If an option lacks a description,
1307-
// it is not officially supported.
1308-
if (!option.description) {
1309-
continue;
1310-
}
1311-
1312-
let usageText = " ";
1313-
if (option.shortName) {
1314-
usageText += "-" + option.shortName;
1315-
usageText += getParamType(option);
1316-
usageText += ", ";
1317-
}
1318-
1319-
usageText += "--" + option.name;
1320-
usageText += getParamType(option);
1321-
1322-
usageColumn.push(usageText);
1323-
let description: string;
1324-
1325-
if (option.name === "lib") {
1326-
description = getDiagnosticText(option.description);
1327-
const element = (<CommandLineOptionOfListType>option).element;
1328-
const typeMap = <Map<number | string>>element.type;
1329-
optionsDescriptionMap.set(description, arrayFrom(typeMap.keys()).map(key => `'${key}'`));
1330-
}
1331-
else {
1332-
description = getDiagnosticText(option.description);
1333-
}
1334-
1335-
descriptionColumn.push(description);
1336-
1337-
// Set the new margin for the description column if necessary.
1338-
marginLength = Math.max(usageText.length, marginLength);
1339-
}
1340-
1341-
// Special case that can't fit in the loop.
1342-
const usageText = " @<" + getDiagnosticText(Diagnostics.file) + ">";
1343-
usageColumn.push(usageText);
1344-
descriptionColumn.push(getDiagnosticText(Diagnostics.Insert_command_line_options_and_files_from_a_file));
1345-
marginLength = Math.max(usageText.length, marginLength);
1346-
1347-
// Print out each row, aligning all the descriptions on the same column.
1348-
for (let i = 0; i < usageColumn.length; i++) {
1349-
const usage = usageColumn[i];
1350-
const description = descriptionColumn[i];
1351-
const kindsList = optionsDescriptionMap.get(description);
1352-
output.push(usage + makePadding(marginLength - usage.length + 2) + description + sys.newLine);
1353-
1354-
if (kindsList) {
1355-
output.push(makePadding(marginLength + 4));
1356-
for (const kind of kindsList) {
1357-
output.push(kind + " ");
1358-
}
1359-
output.push(sys.newLine);
1360-
}
1361-
}
1362-
1363-
for (const line of output) {
1364-
sys.write(line);
1365-
}
1366-
return;
1367-
1368-
function getParamType(option: CommandLineOption) {
1369-
if (option.paramType !== undefined) {
1370-
return " " + getDiagnosticText(option.paramType);
1371-
}
1372-
return "";
1373-
}
1374-
1375-
function makePadding(paddingLength: number): string {
1376-
return Array(paddingLength + 1).join(" ");
1377-
}
1378-
}
1379-
13801267
export type DiagnosticReporter = (diagnostic: Diagnostic) => void;
13811268
/**
13821269
* Reports config file diagnostics
@@ -1801,22 +1688,29 @@ namespace ts {
18011688
references: readonly ProjectReference[] | undefined;
18021689
}
18031690

1691+
/** @internal */
1692+
export interface ConvertToTSConfigHost {
1693+
getCurrentDirectory(): string;
1694+
useCaseSensitiveFileNames: boolean;
1695+
}
1696+
18041697
/**
18051698
* Generate an uncommented, complete tsconfig for use with "--showConfig"
18061699
* @param configParseResult options to be generated into tsconfig.json
18071700
* @param configFileName name of the parsed config file - output paths will be generated relative to this
18081701
* @param host provides current directory and case sensitivity services
18091702
*/
18101703
/** @internal */
1811-
export function convertToTSConfig(configParseResult: ParsedCommandLine, configFileName: string, host: { getCurrentDirectory(): string, useCaseSensitiveFileNames: boolean }): TSConfig {
1704+
export function convertToTSConfig(configParseResult: ParsedCommandLine, configFileName: string, host: ConvertToTSConfigHost): TSConfig {
18121705
const getCanonicalFileName = createGetCanonicalFileName(host.useCaseSensitiveFileNames);
18131706
const files = map(
18141707
filter(
18151708
configParseResult.fileNames,
18161709
(!configParseResult.configFileSpecs || !configParseResult.configFileSpecs.validatedIncludeSpecs) ? _ => true : matchesSpecs(
18171710
configFileName,
18181711
configParseResult.configFileSpecs.validatedIncludeSpecs,
1819-
configParseResult.configFileSpecs.validatedExcludeSpecs
1712+
configParseResult.configFileSpecs.validatedExcludeSpecs,
1713+
host,
18201714
)
18211715
),
18221716
f => getRelativePathFromFile(getNormalizedAbsolutePath(configFileName, host.getCurrentDirectory()), getNormalizedAbsolutePath(f, host.getCurrentDirectory()), getCanonicalFileName)
@@ -1854,11 +1748,11 @@ namespace ts {
18541748
return specs;
18551749
}
18561750

1857-
function matchesSpecs(path: string, includeSpecs: readonly string[] | undefined, excludeSpecs: readonly string[] | undefined): (path: string) => boolean {
1751+
function matchesSpecs(path: string, includeSpecs: readonly string[] | undefined, excludeSpecs: readonly string[] | undefined, host: ConvertToTSConfigHost): (path: string) => boolean {
18581752
if (!includeSpecs) return _ => true;
1859-
const patterns = getFileMatcherPatterns(path, excludeSpecs, includeSpecs, sys.useCaseSensitiveFileNames, sys.getCurrentDirectory());
1860-
const excludeRe = patterns.excludePattern && getRegexFromPattern(patterns.excludePattern, sys.useCaseSensitiveFileNames);
1861-
const includeRe = patterns.includeFilePattern && getRegexFromPattern(patterns.includeFilePattern, sys.useCaseSensitiveFileNames);
1753+
const patterns = getFileMatcherPatterns(path, excludeSpecs, includeSpecs, host.useCaseSensitiveFileNames, host.getCurrentDirectory());
1754+
const excludeRe = patterns.excludePattern && getRegexFromPattern(patterns.excludePattern, host.useCaseSensitiveFileNames);
1755+
const includeRe = patterns.includeFilePattern && getRegexFromPattern(patterns.includeFilePattern, host.useCaseSensitiveFileNames);
18621756
if (includeRe) {
18631757
if (excludeRe) {
18641758
return path => !(includeRe.test(path) && !excludeRe.test(path));

src/compiler/watch.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ namespace ts {
9191
/** Parses config file using System interface */
9292
export function parseConfigFileWithSystem(configFileName: string, optionsToExtend: CompilerOptions, system: System, reportDiagnostic: DiagnosticReporter) {
9393
const host: ParseConfigFileHost = <any>system;
94-
host.onUnRecoverableConfigFileDiagnostic = diagnostic => reportUnrecoverableDiagnostic(sys, reportDiagnostic, diagnostic);
94+
host.onUnRecoverableConfigFileDiagnostic = diagnostic => reportUnrecoverableDiagnostic(system, reportDiagnostic, diagnostic);
9595
const result = getParsedCommandLineOfConfigFile(configFileName, optionsToExtend, host);
9696
host.onUnRecoverableConfigFileDiagnostic = undefined!; // TODO: GH#18217
9797
return result;

src/testRunner/tsconfig.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939

4040
"unittests/services/extract/helpers.ts",
4141
"unittests/tsbuild/helpers.ts",
42+
"../tsc/executeCommandLine.ts",
4243
"unittests/tsc/helpers.ts",
4344
"unittests/tscWatch/helpers.ts",
4445
"unittests/tsserver/helpers.ts",

src/testRunner/unittests/tsc/helpers.ts

Lines changed: 10 additions & 162 deletions
Original file line numberDiff line numberDiff line change
@@ -3,167 +3,6 @@ namespace ts {
33
writtenFiles: Map<true>;
44
baseLine(): void;
55
};
6-
function executeCommandLine(sys: TscCompileSystem, commandLineArgs: readonly string[]) {
7-
if (isBuild(commandLineArgs)) {
8-
return performBuild(sys, commandLineArgs.slice(1));
9-
}
10-
11-
const reportDiagnostic = createDiagnosticReporter(sys);
12-
const commandLine = parseCommandLine(commandLineArgs, path => sys.readFile(path));
13-
if (commandLine.options.build) {
14-
reportDiagnostic(createCompilerDiagnostic(Diagnostics.Option_build_must_be_the_first_command_line_argument));
15-
return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped);
16-
}
17-
18-
if (commandLine.errors.length > 0) {
19-
commandLine.errors.forEach(reportDiagnostic);
20-
return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped);
21-
}
22-
23-
let configFileName: string | undefined;
24-
if (commandLine.options.project) {
25-
if (commandLine.fileNames.length !== 0) {
26-
reportDiagnostic(createCompilerDiagnostic(Diagnostics.Option_project_cannot_be_mixed_with_source_files_on_a_command_line));
27-
return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped);
28-
}
29-
30-
const fileOrDirectory = normalizePath(commandLine.options.project);
31-
if (!fileOrDirectory /* current directory "." */ || sys.directoryExists(fileOrDirectory)) {
32-
configFileName = combinePaths(fileOrDirectory, "tsconfig.json");
33-
if (!sys.fileExists(configFileName)) {
34-
reportDiagnostic(createCompilerDiagnostic(Diagnostics.Cannot_find_a_tsconfig_json_file_at_the_specified_directory_Colon_0, commandLine.options.project));
35-
return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped);
36-
}
37-
}
38-
else {
39-
configFileName = fileOrDirectory;
40-
if (!sys.fileExists(configFileName)) {
41-
reportDiagnostic(createCompilerDiagnostic(Diagnostics.The_specified_path_does_not_exist_Colon_0, commandLine.options.project));
42-
return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped);
43-
}
44-
}
45-
}
46-
else if (commandLine.fileNames.length === 0) {
47-
const searchPath = normalizePath(sys.getCurrentDirectory());
48-
configFileName = findConfigFile(searchPath, sys.fileExists);
49-
}
50-
51-
Debug.assert(commandLine.fileNames.length !== 0 || !!configFileName);
52-
53-
const currentDirectory = sys.getCurrentDirectory();
54-
const getCanonicalFileName = createGetCanonicalFileName(sys.useCaseSensitiveFileNames);
55-
const commandLineOptions = convertToOptionsWithAbsolutePaths(
56-
commandLine.options,
57-
fileName => toPath(fileName, currentDirectory, getCanonicalFileName)
58-
);
59-
60-
if (configFileName) {
61-
const configParseResult = Debug.assertDefined(parseConfigFileWithSystem(configFileName, commandLineOptions, sys, reportDiagnostic));
62-
if (isIncrementalCompilation(configParseResult.options)) {
63-
performIncrementalCompilation(sys, configParseResult);
64-
}
65-
else {
66-
performCompilation(sys, configParseResult);
67-
}
68-
}
69-
else {
70-
if (isIncrementalCompilation(commandLine.options)) {
71-
performIncrementalCompilation(sys, {
72-
...commandLine,
73-
options: commandLineOptions
74-
});
75-
}
76-
else {
77-
performCompilation(sys, {
78-
...commandLine,
79-
options: commandLineOptions
80-
});
81-
}
82-
}
83-
}
84-
85-
function createReportErrorSummary(sys: TscCompileSystem, options: CompilerOptions): ReportEmitErrorSummary | undefined {
86-
return options.pretty ?
87-
errorCount => sys.write(getErrorSummaryText(errorCount, sys.newLine)) :
88-
undefined;
89-
}
90-
91-
function performCompilation(sys: TscCompileSystem, config: ParsedCommandLine) {
92-
const { fileNames, options, projectReferences } = config;
93-
const reportDiagnostic = createDiagnosticReporter(sys, options.pretty);
94-
const host = createCompilerHostWorker(options, /*setParentPos*/ undefined, sys);
95-
fakes.patchHostForBuildInfoReadWrite(host);
96-
const currentDirectory = host.getCurrentDirectory();
97-
const getCanonicalFileName = createGetCanonicalFileName(host.useCaseSensitiveFileNames());
98-
changeCompilerHostLikeToUseCache(host, fileName => toPath(fileName, currentDirectory, getCanonicalFileName));
99-
const program = createProgram({
100-
rootNames: fileNames,
101-
options,
102-
projectReferences,
103-
host,
104-
configFileParsingDiagnostics: getConfigFileParsingDiagnostics(config)
105-
});
106-
const exitStatus = emitFilesAndReportErrorsAndGetExitStatus(
107-
program,
108-
reportDiagnostic,
109-
s => sys.write(s + sys.newLine),
110-
createReportErrorSummary(sys, options)
111-
);
112-
baselineBuildInfo([config], sys.vfs, sys.writtenFiles);
113-
return sys.exit(exitStatus);
114-
}
115-
116-
function performIncrementalCompilation(sys: TscCompileSystem, config: ParsedCommandLine) {
117-
const reportDiagnostic = createDiagnosticReporter(sys, config.options.pretty);
118-
const { options, fileNames, projectReferences } = config;
119-
const host = createIncrementalCompilerHost(options, sys);
120-
fakes.patchHostForBuildInfoReadWrite(host);
121-
const exitCode = ts.performIncrementalCompilation({
122-
host,
123-
system: sys,
124-
rootNames: fileNames,
125-
options,
126-
configFileParsingDiagnostics: getConfigFileParsingDiagnostics(config),
127-
projectReferences,
128-
reportDiagnostic,
129-
reportErrorSummary: createReportErrorSummary(sys, options),
130-
});
131-
baselineBuildInfo([config], sys.vfs, sys.writtenFiles);
132-
return sys.exit(exitCode);
133-
}
134-
135-
function performBuild(sys: TscCompileSystem, args: string[]) {
136-
const { buildOptions, projects, errors } = parseBuildCommand(args);
137-
const reportDiagnostic = createDiagnosticReporter(sys, buildOptions.pretty);
138-
139-
if (errors.length > 0) {
140-
errors.forEach(reportDiagnostic);
141-
return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped);
142-
}
143-
144-
Debug.assert(projects.length !== 0);
145-
146-
const buildHost = createSolutionBuilderHost(
147-
sys,
148-
/*createProgram*/ undefined,
149-
reportDiagnostic,
150-
createBuilderStatusReporter(sys, buildOptions.pretty),
151-
createReportErrorSummary(sys, buildOptions)
152-
);
153-
fakes.patchSolutionBuilderHost(buildHost, sys);
154-
const builder = createSolutionBuilder(buildHost, projects, buildOptions);
155-
const exitCode = buildOptions.clean ? builder.clean() : builder.build();
156-
baselineBuildInfo(builder.getAllParsedConfigs(), sys.vfs, sys.writtenFiles);
157-
return sys.exit(exitCode);
158-
}
159-
160-
function isBuild(commandLineArgs: readonly string[]) {
161-
if (commandLineArgs.length > 0 && commandLineArgs[0].charCodeAt(0) === CharacterCodes.minus) {
162-
const firstOption = commandLineArgs[0].slice(commandLineArgs[0].charCodeAt(1) === CharacterCodes.minus ? 2 : 1).toLowerCase();
163-
return firstOption === "build" || firstOption === "b";
164-
}
165-
return false;
166-
}
1676

1687
export enum BuildKind {
1698
Initial = "initial-build",
@@ -221,7 +60,16 @@ namespace ts {
22160

22261
sys.write(`${sys.getExecutingFilePath()} ${commandLineArgs.join(" ")}\n`);
22362
sys.exit = exitCode => sys.exitCode = exitCode;
224-
executeCommandLine(sys, commandLineArgs);
63+
ts.executeCommandLine(
64+
sys,
65+
{
66+
onCompilerHostCreate: host => fakes.patchHostForBuildInfoReadWrite(host),
67+
onCompilationComplete: config => baselineBuildInfo([config], sys.vfs, sys.writtenFiles),
68+
onSolutionBuilderHostCreate: host => fakes.patchSolutionBuilderHost(host, sys),
69+
onSolutionBuildComplete: configs => baselineBuildInfo(configs, sys.vfs, sys.writtenFiles),
70+
},
71+
commandLineArgs,
72+
);
22573
sys.write(`exitCode:: ExitStatus.${ExitStatus[sys.exitCode as ExitStatus]}\n`);
22674
if (baselineReadFileCalls) {
22775
sys.write(`readFiles:: ${JSON.stringify(actualReadFileMap, /*replacer*/ undefined, " ")} `);

0 commit comments

Comments
 (0)