Skip to content

Commit f4fcb19

Browse files
Merge pull request #24465 from RyanCavanaugh/tsbuild
"tsc -b" with minimal watch capabilities
2 parents 04187bd + 0f626fd commit f4fcb19

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+2390
-185
lines changed

src/compiler/commandLineParser.ts

+127
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,14 @@ namespace ts {
109109
paramType: Diagnostics.FILE_OR_DIRECTORY,
110110
description: Diagnostics.Compile_the_project_given_the_path_to_its_configuration_file_or_to_a_folder_with_a_tsconfig_json,
111111
},
112+
{
113+
name: "build",
114+
type: "boolean",
115+
shortName: "b",
116+
showInSimplifiedHelpView: true,
117+
category: Diagnostics.Command_line_Options,
118+
description: Diagnostics.Build_one_or_more_projects_and_their_dependencies_if_out_of_date
119+
},
112120
{
113121
name: "pretty",
114122
type: "boolean",
@@ -968,6 +976,125 @@ namespace ts {
968976
}
969977

970978

979+
function getDiagnosticText(_message: DiagnosticMessage, ..._args: any[]): string {
980+
const diagnostic = createCompilerDiagnostic.apply(undefined, arguments);
981+
return <string>diagnostic.messageText;
982+
}
983+
984+
/* @internal */
985+
export function printVersion() {
986+
sys.write(getDiagnosticText(Diagnostics.Version_0, version) + sys.newLine);
987+
}
988+
989+
/* @internal */
990+
export function printHelp(optionsList: CommandLineOption[], syntaxPrefix = "") {
991+
const output: string[] = [];
992+
993+
// We want to align our "syntax" and "examples" commands to a certain margin.
994+
const syntaxLength = getDiagnosticText(Diagnostics.Syntax_Colon_0, "").length;
995+
const examplesLength = getDiagnosticText(Diagnostics.Examples_Colon_0, "").length;
996+
let marginLength = Math.max(syntaxLength, examplesLength);
997+
998+
// Build up the syntactic skeleton.
999+
let syntax = makePadding(marginLength - syntaxLength);
1000+
syntax += `tsc ${syntaxPrefix}[${getDiagnosticText(Diagnostics.options)}] [${getDiagnosticText(Diagnostics.file)}...]`;
1001+
1002+
output.push(getDiagnosticText(Diagnostics.Syntax_Colon_0, syntax));
1003+
output.push(sys.newLine + sys.newLine);
1004+
1005+
// Build up the list of examples.
1006+
const padding = makePadding(marginLength);
1007+
output.push(getDiagnosticText(Diagnostics.Examples_Colon_0, makePadding(marginLength - examplesLength) + "tsc hello.ts") + sys.newLine);
1008+
output.push(padding + "tsc --outFile file.js file.ts" + sys.newLine);
1009+
output.push(padding + "tsc @args.txt" + sys.newLine);
1010+
output.push(padding + "tsc --build tsconfig.json" + sys.newLine);
1011+
output.push(sys.newLine);
1012+
1013+
output.push(getDiagnosticText(Diagnostics.Options_Colon) + sys.newLine);
1014+
1015+
// We want our descriptions to align at the same column in our output,
1016+
// so we keep track of the longest option usage string.
1017+
marginLength = 0;
1018+
const usageColumn: string[] = []; // Things like "-d, --declaration" go in here.
1019+
const descriptionColumn: string[] = [];
1020+
1021+
const optionsDescriptionMap = createMap<string[]>(); // Map between option.description and list of option.type if it is a kind
1022+
1023+
for (const option of optionsList) {
1024+
// If an option lacks a description,
1025+
// it is not officially supported.
1026+
if (!option.description) {
1027+
continue;
1028+
}
1029+
1030+
let usageText = " ";
1031+
if (option.shortName) {
1032+
usageText += "-" + option.shortName;
1033+
usageText += getParamType(option);
1034+
usageText += ", ";
1035+
}
1036+
1037+
usageText += "--" + option.name;
1038+
usageText += getParamType(option);
1039+
1040+
usageColumn.push(usageText);
1041+
let description: string;
1042+
1043+
if (option.name === "lib") {
1044+
description = getDiagnosticText(option.description);
1045+
const element = (<CommandLineOptionOfListType>option).element;
1046+
const typeMap = <Map<number | string>>element.type;
1047+
optionsDescriptionMap.set(description, arrayFrom(typeMap.keys()).map(key => `'${key}'`));
1048+
}
1049+
else {
1050+
description = getDiagnosticText(option.description);
1051+
}
1052+
1053+
descriptionColumn.push(description);
1054+
1055+
// Set the new margin for the description column if necessary.
1056+
marginLength = Math.max(usageText.length, marginLength);
1057+
}
1058+
1059+
// Special case that can't fit in the loop.
1060+
const usageText = " @<" + getDiagnosticText(Diagnostics.file) + ">";
1061+
usageColumn.push(usageText);
1062+
descriptionColumn.push(getDiagnosticText(Diagnostics.Insert_command_line_options_and_files_from_a_file));
1063+
marginLength = Math.max(usageText.length, marginLength);
1064+
1065+
// Print out each row, aligning all the descriptions on the same column.
1066+
for (let i = 0; i < usageColumn.length; i++) {
1067+
const usage = usageColumn[i];
1068+
const description = descriptionColumn[i];
1069+
const kindsList = optionsDescriptionMap.get(description);
1070+
output.push(usage + makePadding(marginLength - usage.length + 2) + description + sys.newLine);
1071+
1072+
if (kindsList) {
1073+
output.push(makePadding(marginLength + 4));
1074+
for (const kind of kindsList) {
1075+
output.push(kind + " ");
1076+
}
1077+
output.push(sys.newLine);
1078+
}
1079+
}
1080+
1081+
for (const line of output) {
1082+
sys.write(line);
1083+
}
1084+
return;
1085+
1086+
function getParamType(option: CommandLineOption) {
1087+
if (option.paramType !== undefined) {
1088+
return " " + getDiagnosticText(option.paramType);
1089+
}
1090+
return "";
1091+
}
1092+
1093+
function makePadding(paddingLength: number): string {
1094+
return Array(paddingLength + 1).join(" ");
1095+
}
1096+
}
1097+
9711098
export type DiagnosticReporter = (diagnostic: Diagnostic) => void;
9721099
/**
9731100
* Reports config file diagnostics

src/compiler/diagnosticMessages.json

+89
Original file line numberDiff line numberDiff line change
@@ -3620,6 +3620,95 @@
36203620
"category": "Error",
36213621
"code": 6309
36223622
},
3623+
"Project '{0}' is out of date because oldest output '{1}' is older than newest input '{2}'": {
3624+
"category": "Message",
3625+
"code": 6350
3626+
},
3627+
"Project '{0}' is up to date because newest input '{1}' is older than oldest output '{2}'": {
3628+
"category": "Message",
3629+
"code": 6351
3630+
},
3631+
"Project '{0}' is out of date because output file '{1}' does not exist": {
3632+
"category": "Message",
3633+
"code": 6352
3634+
},
3635+
"Project '{0}' is out of date because its dependency '{1}' is out of date": {
3636+
"category": "Message",
3637+
"code": 6353
3638+
},
3639+
3640+
"Project '{0}' is up to date with .d.ts files from its dependencies": {
3641+
"category": "Message",
3642+
"code": 6354
3643+
},
3644+
"Projects in this build: {0}": {
3645+
"category": "Message",
3646+
"code": 6355
3647+
},
3648+
"A non-dry build would delete the following files: {0}": {
3649+
"category": "Message",
3650+
"code": 6356
3651+
},
3652+
"A non-dry build would build project '{0}'": {
3653+
"category": "Message",
3654+
"code": 6357
3655+
},
3656+
"Building project '{0}'...": {
3657+
"category": "Message",
3658+
"code": 6358
3659+
},
3660+
"Updating output timestamps of project '{0}'...": {
3661+
"category": "Message",
3662+
"code": 6359
3663+
},
3664+
"delete this - Project '{0}' is up to date because it was previously built": {
3665+
"category": "Message",
3666+
"code": 6360
3667+
},
3668+
"Project '{0}' is up to date": {
3669+
"category": "Message",
3670+
"code": 6361
3671+
},
3672+
"Skipping build of project '{0}' because its dependency '{1}' has errors": {
3673+
"category": "Message",
3674+
"code": 6362
3675+
},
3676+
"Project '{0}' can't be built because its dependency '{1}' has errors": {
3677+
"category": "Message",
3678+
"code": 6363
3679+
},
3680+
"Build one or more projects and their dependencies, if out of date": {
3681+
"category": "Message",
3682+
"code": 6364
3683+
},
3684+
"Delete the outputs of all projects": {
3685+
"category": "Message",
3686+
"code": 6365
3687+
},
3688+
"Enable verbose logging": {
3689+
"category": "Message",
3690+
"code": 6366
3691+
},
3692+
"Show what would be built (or deleted, if specified with '--clean')": {
3693+
"category": "Message",
3694+
"code": 6367
3695+
},
3696+
"Build all projects, including those that appear to be up to date": {
3697+
"category": "Message",
3698+
"code": 6368
3699+
},
3700+
"Option '--build' must be the first command line argument.": {
3701+
"category": "Error",
3702+
"code": 6369
3703+
},
3704+
"Options '{0}' and '{1}' cannot be combined.": {
3705+
"category": "Error",
3706+
"code": 6370
3707+
},
3708+
"Skipping clean because not all projects could be located": {
3709+
"category": "Error",
3710+
"code": 6371
3711+
},
36233712

36243713
"Variable '{0}' implicitly has an '{1}' type.": {
36253714
"category": "Error",

src/compiler/emitter.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1026,7 +1026,7 @@ namespace ts {
10261026

10271027
// SyntaxKind.UnparsedSource
10281028
function emitUnparsedSource(unparsed: UnparsedSource) {
1029-
write(unparsed.text);
1029+
writer.rawWrite(unparsed.text);
10301030
}
10311031

10321032
//

src/compiler/factory.ts

+5-2
Original file line numberDiff line numberDiff line change
@@ -2587,16 +2587,19 @@ namespace ts {
25872587
return node;
25882588
}
25892589

2590-
export function createUnparsedSourceFile(text: string): UnparsedSource {
2590+
export function createUnparsedSourceFile(text: string, map?: string): UnparsedSource {
25912591
const node = <UnparsedSource>createNode(SyntaxKind.UnparsedSource);
25922592
node.text = text;
2593+
node.sourceMapText = map;
25932594
return node;
25942595
}
25952596

2596-
export function createInputFiles(javascript: string, declaration: string): InputFiles {
2597+
export function createInputFiles(javascript: string, declaration: string, javascriptMapText?: string, declarationMapText?: string): InputFiles {
25972598
const node = <InputFiles>createNode(SyntaxKind.InputFiles);
25982599
node.javascriptText = javascript;
2600+
node.javascriptMapText = javascriptMapText;
25992601
node.declarationText = declaration;
2602+
node.declarationMapText = declarationMapText;
26002603
return node;
26012604
}
26022605

src/compiler/program.ts

+25-17
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,10 @@ namespace ts {
189189
getEnvironmentVariable: name => sys.getEnvironmentVariable ? sys.getEnvironmentVariable(name) : "",
190190
getDirectories: (path: string) => sys.getDirectories(path),
191191
realpath,
192-
readDirectory: (path, extensions, include, exclude, depth) => sys.readDirectory(path, extensions, include, exclude, depth)
192+
readDirectory: (path, extensions, include, exclude, depth) => sys.readDirectory(path, extensions, include, exclude, depth),
193+
getModifiedTime: sys.getModifiedTime && (path => sys.getModifiedTime!(path)),
194+
setModifiedTime: sys.setModifiedTime && ((path, date) => sys.setModifiedTime!(path, date)),
195+
deleteFile: sys.deleteFile && (path => sys.deleteFile!(path))
193196
};
194197
}
195198

@@ -615,25 +618,27 @@ namespace ts {
615618
// A parallel array to projectReferences storing the results of reading in the referenced tsconfig files
616619
const resolvedProjectReferences: (ResolvedProjectReference | undefined)[] | undefined = projectReferences ? [] : undefined;
617620
const projectReferenceRedirects: Map<string> = createMap();
618-
if (projectReferences) {
619-
for (const ref of projectReferences) {
620-
const parsedRef = parseProjectReferenceConfigFile(ref);
621-
resolvedProjectReferences!.push(parsedRef);
622-
if (parsedRef) {
623-
if (parsedRef.commandLine.options.outFile) {
624-
const dtsOutfile = changeExtension(parsedRef.commandLine.options.outFile, ".d.ts");
625-
processSourceFile(dtsOutfile, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, /*packageId*/ undefined);
626-
}
627-
addProjectReferenceRedirects(parsedRef.commandLine, projectReferenceRedirects);
628-
}
629-
}
630-
}
631621

632622
const shouldCreateNewSourceFile = shouldProgramCreateNewSourceFiles(oldProgram, options);
633623
const structuralIsReused = tryReuseStructureFromOldProgram();
634624
if (structuralIsReused !== StructureIsReused.Completely) {
635625
processingDefaultLibFiles = [];
636626
processingOtherFiles = [];
627+
628+
if (projectReferences) {
629+
for (const ref of projectReferences) {
630+
const parsedRef = parseProjectReferenceConfigFile(ref);
631+
resolvedProjectReferences!.push(parsedRef);
632+
if (parsedRef) {
633+
if (parsedRef.commandLine.options.outFile) {
634+
const dtsOutfile = changeExtension(parsedRef.commandLine.options.outFile, ".d.ts");
635+
processSourceFile(dtsOutfile, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, /*packageId*/ undefined);
636+
}
637+
addProjectReferenceRedirects(parsedRef.commandLine, projectReferenceRedirects);
638+
}
639+
}
640+
}
641+
637642
forEach(rootNames, name => processRootFile(name, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false));
638643

639644
// load type declarations specified via 'types' argument or implicitly from types/ and node_modules/@types folders
@@ -1021,7 +1026,7 @@ namespace ts {
10211026

10221027
for (const oldSourceFile of oldSourceFiles) {
10231028
let newSourceFile = host.getSourceFileByPath
1024-
? host.getSourceFileByPath(oldSourceFile.fileName, oldSourceFile.path, options.target!, /*onError*/ undefined, shouldCreateNewSourceFile)
1029+
? host.getSourceFileByPath(oldSourceFile.fileName, oldSourceFile.resolvedPath || oldSourceFile.path, options.target!, /*onError*/ undefined, shouldCreateNewSourceFile)
10251030
: host.getSourceFile(oldSourceFile.fileName, options.target!, /*onError*/ undefined, shouldCreateNewSourceFile); // TODO: GH#18217
10261031

10271032
if (!newSourceFile) {
@@ -1234,8 +1239,10 @@ namespace ts {
12341239

12351240
const dtsFilename = changeExtension(resolvedRefOpts.options.outFile, ".d.ts");
12361241
const js = host.readFile(resolvedRefOpts.options.outFile) || `/* Input file ${resolvedRefOpts.options.outFile} was missing */\r\n`;
1242+
const jsMap = host.readFile(resolvedRefOpts.options.outFile + ".map"); // TODO: try to read sourceMappingUrl comment from the js file
12371243
const dts = host.readFile(dtsFilename) || `/* Input file ${dtsFilename} was missing */\r\n`;
1238-
const node = createInputFiles(js, dts);
1244+
const dtsMap = host.readFile(dtsFilename + ".map");
1245+
const node = createInputFiles(js, dts, jsMap, dtsMap);
12391246
nodes.push(node);
12401247
}
12411248
}
@@ -2047,6 +2054,7 @@ namespace ts {
20472054
if (file) {
20482055
sourceFilesFoundSearchingNodeModules.set(path, currentNodeModulesDepth > 0);
20492056
file.path = path;
2057+
file.resolvedPath = toPath(fileName);
20502058

20512059
if (host.useCaseSensitiveFileNames()) {
20522060
const pathLowerCase = path.toLowerCase();
@@ -2781,7 +2789,7 @@ namespace ts {
27812789
/**
27822790
* Returns the target config filename of a project reference
27832791
*/
2784-
function resolveProjectReferencePath(host: CompilerHost, ref: ProjectReference): string | undefined {
2792+
export function resolveProjectReferencePath(host: CompilerHost, ref: ProjectReference): string | undefined {
27852793
if (!host.fileExists(ref.path)) {
27862794
return combinePaths(ref.path, "tsconfig.json");
27872795
}

0 commit comments

Comments
 (0)