Skip to content

Commit f35a20e

Browse files
Merge pull request #23944 from RyanCavanaugh/projRefs
Project References Core Support
2 parents 5d8f1d9 + 10f2eb5 commit f35a20e

File tree

64 files changed

+1293
-224
lines changed

Some content is hidden

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

64 files changed

+1293
-224
lines changed

src/compiler/checker.ts

+16-1
Original file line numberDiff line numberDiff line change
@@ -2220,7 +2220,22 @@ namespace ts {
22202220
}
22212221

22222222
if (moduleNotFoundError) {
2223-
// report errors only if it was requested
2223+
// For relative paths, see if this was possibly a projectReference redirect
2224+
if (pathIsRelative(moduleReference)) {
2225+
const sourceFile = getSourceFileOfNode(location);
2226+
const redirects = sourceFile.redirectedReferences;
2227+
if (redirects) {
2228+
const normalizedTargetPath = getNormalizedAbsolutePath(moduleReference, getDirectoryPath(sourceFile.fileName));
2229+
for (const ext of [Extension.Ts, Extension.Tsx]) {
2230+
const probePath = normalizedTargetPath + ext;
2231+
if (redirects.indexOf(probePath) >= 0) {
2232+
error(errorNode, Diagnostics.Output_file_0_has_not_been_built_from_source_file_1, moduleReference, probePath);
2233+
return undefined;
2234+
}
2235+
}
2236+
}
2237+
}
2238+
22242239
if (resolutionDiagnostic) {
22252240
error(errorNode, resolutionDiagnostic, moduleReference, resolvedModule.resolvedFileName);
22262241
}

src/compiler/commandLineParser.ts

+100-5
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,13 @@ namespace ts {
235235
category: Diagnostics.Basic_Options,
236236
description: Diagnostics.Specify_the_root_directory_of_input_files_Use_to_control_the_output_directory_structure_with_outDir,
237237
},
238+
{
239+
name: "composite",
240+
type: "boolean",
241+
isTSConfigOnly: true,
242+
category: Diagnostics.Basic_Options,
243+
description: Diagnostics.Enable_project_compilation,
244+
},
238245
{
239246
name: "removeComments",
240247
type: "boolean",
@@ -814,12 +821,14 @@ namespace ts {
814821
export function parseCommandLine(commandLine: ReadonlyArray<string>, readFile?: (path: string) => string | undefined): ParsedCommandLine {
815822
const options: CompilerOptions = {};
816823
const fileNames: string[] = [];
824+
const projectReferences: ProjectReference[] | undefined = undefined;
817825
const errors: Diagnostic[] = [];
818826

819827
parseStrings(commandLine);
820828
return {
821829
options,
822830
fileNames,
831+
projectReferences,
823832
errors
824833
};
825834

@@ -933,6 +942,49 @@ namespace ts {
933942
return optionNameMap.get(optionName);
934943
}
935944

945+
946+
export type DiagnosticReporter = (diagnostic: Diagnostic) => void;
947+
/**
948+
* Reports config file diagnostics
949+
*/
950+
export interface ConfigFileDiagnosticsReporter {
951+
/**
952+
* Reports unrecoverable error when parsing config file
953+
*/
954+
onUnRecoverableConfigFileDiagnostic: DiagnosticReporter;
955+
}
956+
957+
/**
958+
* Interface extending ParseConfigHost to support ParseConfigFile that reads config file and reports errors
959+
*/
960+
export interface ParseConfigFileHost extends ParseConfigHost, ConfigFileDiagnosticsReporter {
961+
getCurrentDirectory(): string;
962+
}
963+
964+
/**
965+
* Reads the config file, reports errors if any and exits if the config file cannot be found
966+
*/
967+
export function getParsedCommandLineOfConfigFile(configFileName: string, optionsToExtend: CompilerOptions, host: ParseConfigFileHost): ParsedCommandLine | undefined {
968+
let configFileText: string;
969+
try {
970+
configFileText = host.readFile(configFileName);
971+
}
972+
catch (e) {
973+
const error = createCompilerDiagnostic(Diagnostics.Cannot_read_file_0_Colon_1, configFileName, e.message);
974+
host.onUnRecoverableConfigFileDiagnostic(error);
975+
return undefined;
976+
}
977+
if (!configFileText) {
978+
const error = createCompilerDiagnostic(Diagnostics.File_0_not_found, configFileName);
979+
host.onUnRecoverableConfigFileDiagnostic(error);
980+
return undefined;
981+
}
982+
983+
const result = parseJsonText(configFileName, configFileText);
984+
const cwd = host.getCurrentDirectory();
985+
return parseJsonSourceFileConfigFileContent(result, host, getNormalizedAbsolutePath(getDirectoryPath(configFileName), cwd), optionsToExtend, getNormalizedAbsolutePath(configFileName, cwd));
986+
}
987+
936988
/**
937989
* Read tsconfig.json file
938990
* @param fileName The path to the config file
@@ -1008,6 +1060,14 @@ namespace ts {
10081060
name: "extends",
10091061
type: "string"
10101062
},
1063+
{
1064+
name: "references",
1065+
type: "list",
1066+
element: {
1067+
name: "references",
1068+
type: "object"
1069+
}
1070+
},
10111071
{
10121072
name: "files",
10131073
type: "list",
@@ -1415,7 +1475,7 @@ namespace ts {
14151475
for (let i = 0; i < nameColumn.length; i++) {
14161476
const optionName = nameColumn[i];
14171477
const description = descriptionColumn[i];
1418-
result.push(optionName && `${tab}${tab}${optionName}${ description && (makePadding(marginLength - optionName.length + 2) + description)}`);
1478+
result.push(optionName && `${tab}${tab}${optionName}${description && (makePadding(marginLength - optionName.length + 2) + description)}`);
14191479
}
14201480
if (fileNames.length) {
14211481
result.push(`${tab}},`);
@@ -1499,12 +1559,13 @@ namespace ts {
14991559
const parsedConfig = parseConfig(json, sourceFile, host, basePath, configFileName, resolutionStack, errors);
15001560
const { raw } = parsedConfig;
15011561
const options = extend(existingOptions, parsedConfig.options || {});
1502-
options.configFilePath = configFileName;
1562+
options.configFilePath = configFileName && normalizeSlashes(configFileName);
15031563
setConfigFileInOptions(options, sourceFile);
1504-
const { fileNames, wildcardDirectories, spec } = getFileNames();
1564+
const { fileNames, wildcardDirectories, spec, projectReferences } = getFileNames();
15051565
return {
15061566
options,
15071567
fileNames,
1568+
projectReferences,
15081569
typeAcquisition: parsedConfig.typeAcquisition || getDefaultTypeAcquisition(),
15091570
raw,
15101571
errors,
@@ -1558,10 +1619,33 @@ namespace ts {
15581619
}
15591620

15601621
const result = matchFileNames(filesSpecs, includeSpecs, excludeSpecs, configFileName ? directoryOfCombinedPath(configFileName, basePath) : basePath, options, host, errors, extraFileExtensions, sourceFile);
1561-
if (result.fileNames.length === 0 && !hasProperty(raw, "files") && resolutionStack.length === 0) {
1622+
if (result.fileNames.length === 0 && !hasProperty(raw, "files") && resolutionStack.length === 0 && !hasProperty(raw, "references")) {
15621623
errors.push(getErrorForNoInputFiles(result.spec, configFileName));
15631624
}
15641625

1626+
if (hasProperty(raw, "references") && !isNullOrUndefined(raw.references)) {
1627+
if (isArray(raw.references)) {
1628+
const references: ProjectReference[] = [];
1629+
for (const ref of raw.references) {
1630+
if (typeof ref.path !== "string") {
1631+
createCompilerDiagnosticOnlyIfJson(Diagnostics.Compiler_option_0_requires_a_value_of_type_1, "reference.path", "string");
1632+
}
1633+
else {
1634+
references.push({
1635+
path: getNormalizedAbsolutePath(ref.path, basePath),
1636+
originalPath: ref.path,
1637+
prepend: ref.prepend,
1638+
circular: ref.circular
1639+
});
1640+
}
1641+
}
1642+
result.projectReferences = references;
1643+
}
1644+
else {
1645+
createCompilerDiagnosticOnlyIfJson(Diagnostics.Compiler_option_0_requires_a_value_of_type_1, "references", "Array");
1646+
}
1647+
}
1648+
15651649
return result;
15661650
}
15671651

@@ -1850,6 +1934,9 @@ namespace ts {
18501934

18511935
const options = getDefaultCompilerOptions(configFileName);
18521936
convertOptionsFromJson(optionDeclarations, jsonOptions, basePath, options, Diagnostics.Unknown_compiler_option_0, errors);
1937+
if (configFileName) {
1938+
options.configFilePath = normalizeSlashes(configFileName);
1939+
}
18531940
return options;
18541941
}
18551942

@@ -2048,7 +2135,7 @@ namespace ts {
20482135
// new entries in these paths.
20492136
const wildcardDirectories = getWildcardDirectories(validatedIncludeSpecs, validatedExcludeSpecs, basePath, host.useCaseSensitiveFileNames);
20502137

2051-
const spec: ConfigFileSpecs = { filesSpecs, includeSpecs, excludeSpecs, validatedIncludeSpecs, validatedExcludeSpecs, wildcardDirectories };
2138+
const spec: ConfigFileSpecs = { filesSpecs, referencesSpecs: undefined, includeSpecs, excludeSpecs, validatedIncludeSpecs, validatedExcludeSpecs, wildcardDirectories };
20522139
return getFileNamesFromConfigSpecs(spec, basePath, options, host, extraFileExtensions);
20532140
}
20542141

@@ -2119,8 +2206,16 @@ namespace ts {
21192206

21202207
const literalFiles = arrayFrom(literalFileMap.values());
21212208
const wildcardFiles = arrayFrom(wildcardFileMap.values());
2209+
const projectReferences = spec.referencesSpecs && spec.referencesSpecs.map((r): ProjectReference => {
2210+
return {
2211+
...r,
2212+
path: getNormalizedAbsolutePath(r.path, basePath)
2213+
};
2214+
});
2215+
21222216
return {
21232217
fileNames: literalFiles.concat(wildcardFiles),
2218+
projectReferences,
21242219
wildcardDirectories,
21252220
spec
21262221
};

src/compiler/core.ts

+4
Original file line numberDiff line numberDiff line change
@@ -1963,6 +1963,10 @@ namespace ts {
19631963
: moduleKind === ModuleKind.System;
19641964
}
19651965

1966+
export function getEmitDeclarations(compilerOptions: CompilerOptions): boolean {
1967+
return !!(compilerOptions.declaration || compilerOptions.composite);
1968+
}
1969+
19661970
export type StrictOptionName = "noImplicitAny" | "noImplicitThis" | "strictNullChecks" | "strictFunctionTypes" | "strictPropertyInitialization" | "alwaysStrict";
19671971

19681972
export function getStrictOptionValue(compilerOptions: CompilerOptions, flag: StrictOptionName): boolean {

src/compiler/diagnosticMessages.json

+37
Original file line numberDiff line numberDiff line change
@@ -3552,6 +3552,43 @@
35523552
"code": 6197
35533553
},
35543554

3555+
"Projects to reference": {
3556+
"category": "Message",
3557+
"code": 6300
3558+
},
3559+
"Enable project compilation": {
3560+
"category": "Message",
3561+
"code": 6302
3562+
},
3563+
"Project references may not form a circular graph. Cycle detected: {0}": {
3564+
"category": "Error",
3565+
"code": 6202
3566+
},
3567+
"Composite projects may not disable declaration emit.": {
3568+
"category": "Error",
3569+
"code": 6304
3570+
},
3571+
"Output file '{0}' has not been built from source file '{1}'.": {
3572+
"category": "Error",
3573+
"code": 6305
3574+
},
3575+
"Referenced project '{0}' must have setting \"composite\": true.": {
3576+
"category": "Error",
3577+
"code": 6306
3578+
},
3579+
"File '{0}' is not in project file list. Projects must list all files or use an 'include' pattern.": {
3580+
"category": "Error",
3581+
"code": 6307
3582+
},
3583+
"Cannot prepend project '{0}' because it does not have 'outFile' set": {
3584+
"category": "Error",
3585+
"code": 6308
3586+
},
3587+
"Output file '{0}' from project '{1}' does not exist": {
3588+
"category": "Error",
3589+
"code": 6309
3590+
},
3591+
35553592
"Variable '{0}' implicitly has an '{1}' type.": {
35563593
"category": "Error",
35573594
"code": 7005

0 commit comments

Comments
 (0)