From 589602529d3195f97bd18ce5162d1d3c7c70abde Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Fri, 15 Dec 2017 15:38:32 -0800 Subject: [PATCH] Project references WIP --- Jakefile.js | 1 + src/compiler/commandLineParser.ts | 30 ++- src/compiler/diagnosticMessages.json | 20 ++ src/compiler/program.ts | 145 +++++++++++- src/compiler/types.ts | 7 +- src/harness/unittests/projectReferences.ts | 208 ++++++++++++++++++ src/harness/virtualFileSystem.ts | 63 ++++++ src/server/protocol.ts | 1 + .../reference/api/tsserverlibrary.d.ts | 8 +- tests/baselines/reference/api/typescript.d.ts | 7 +- .../tsconfig.json | 1 + .../tsconfig.json | 1 + .../tsconfig.json | 1 + .../tsconfig.json | 1 + .../tsconfig.json | 1 + .../tsconfig.json | 1 + .../tsconfig.json | 1 + .../tsconfig.json | 1 + 18 files changed, 487 insertions(+), 11 deletions(-) create mode 100644 src/harness/unittests/projectReferences.ts diff --git a/Jakefile.js b/Jakefile.js index da7d96f0699..12610402885 100644 --- a/Jakefile.js +++ b/Jakefile.js @@ -131,6 +131,7 @@ var harnessSources = harnessCoreSources.concat([ "tsconfigParsing.ts", "builder.ts", "commandLineParsing.ts", + "projectReferences.ts", "configurationExtension.ts", "convertCompilerOptionsFromJson.ts", "convertTypeAcquisitionFromJson.ts", diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index f050c4a5d16..ca190b947d6 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -384,6 +384,17 @@ namespace ts { category: Diagnostics.Module_Resolution_Options, description: Diagnostics.Type_declaration_files_to_be_included_in_compilation }, + { + name: "references", + type: "list", + element: { + name: "references", + type: "object" + }, + showInSimplifiedHelpView: true, + category: Diagnostics.Module_Resolution_Options, + description: Diagnostics.Projects_to_reference + }, { name: "allowSyntheticDefaultImports", type: "boolean", @@ -902,8 +913,9 @@ namespace ts { */ export function parseConfigFileTextToJson(fileName: string, jsonText: string): { config?: any; error?: Diagnostic } { const jsonSourceFile = parseJsonText(fileName, jsonText); + const config = convertToObject(jsonSourceFile, jsonSourceFile.parseDiagnostics); return { - config: convertToObject(jsonSourceFile, jsonSourceFile.parseDiagnostics), + config, error: jsonSourceFile.parseDiagnostics.length ? jsonSourceFile.parseDiagnostics[0] : undefined }; } @@ -966,6 +978,22 @@ namespace ts { type: "string" } }, + { + name: "references", + type: "list", + element: { + name: "references", + type: "object" + } + }, + { + name: "projects", + type: "list", + element: { + name: "projects", + type: "string" + } + }, { name: "include", type: "list", diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 0f88d5e4ac5..6e6e53b4529 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -3326,6 +3326,26 @@ "category": "Message", "code": 6186 }, + "Project references may not form a circular graph. Cycle detected: {0}": { + "category": "Error", + "code": 6187 + }, + "Projects to reference": { + "category": "Message", + "code": 6188 + }, + "Referenced project '{0}' must have 'declaration': true": { + "category": "Error", + "code": 6201 + }, + "Referenced project '{0}' must have an explicit 'rootDir' setting": { + "category": "Error", + "code": 6202 + }, + "Output file '{0}' has not been built from source file '{1}'": { + "category": "Error", + "code": 6203 + }, "Variable '{0}' implicitly has an '{1}' type.": { "category": "Error", "code": 7005 diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 1d325983f5f..f97d3425f63 100755 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -333,12 +333,12 @@ namespace ts { } output += host.getNewLine(); - output += `${ relativeFileName }(${ firstLine + 1 },${ firstLineChar + 1 }): `; + output += `${relativeFileName}(${firstLine + 1},${firstLineChar + 1}): `; } const categoryColor = getCategoryFormat(diagnostic.category); const category = DiagnosticCategory[diagnostic.category].toLowerCase(); - output += `${ formatAndReset(category, categoryColor) } TS${ diagnostic.code }: ${ flattenDiagnosticMessageText(diagnostic.messageText, host.getNewLine()) }`; + output += `${formatAndReset(category, categoryColor)} TS${diagnostic.code}: ${flattenDiagnosticMessageText(diagnostic.messageText, host.getNewLine())}`; if (diagnostic.file) { output += host.getNewLine(); @@ -562,6 +562,10 @@ namespace ts { resolveTypeReferenceDirectiveNamesWorker = (typeReferenceDirectiveNames, containingFile) => loadWithLocalCache(checkAllDefined(typeReferenceDirectiveNames), containingFile, loader); } + const projectReferenceRedirects = createProjectReferenceRedirects(options); + checkProjectReferenceGraph(); + void getReferencesSyntax; + // Map from a stringified PackageId to the source file with that id. // Only one source file may have a given packageId. Others become redirects (see createRedirectSourceFile). // `packageIdToSourceFile` is only used while building the program, while `sourceFileToPackageName` and `isSourceFileTargetOfRedirect` are kept around. @@ -1098,7 +1102,7 @@ namespace ts { // If '--lib' is not specified, include default library file according to '--target' // otherwise, using options specified in '--lib' instead of '--target' default library file if (!options.lib) { - return compareStrings(file.fileName, getDefaultLibraryFileName(), /*ignoreCase*/ !host.useCaseSensitiveFileNames()) === Comparison.EqualTo; + return compareStrings(file.fileName, getDefaultLibraryFileName(), /*ignoreCase*/ !host.useCaseSensitiveFileNames()) === Comparison.EqualTo; } else { return forEach(options.lib, libFileName => compareStrings(file.fileName, combinePaths(defaultLibraryPath, libFileName), /*ignoreCase*/ !host.useCaseSensitiveFileNames()) === Comparison.EqualTo); @@ -1695,7 +1699,13 @@ namespace ts { const sourceFile = getSourceFile(fileName); if (fail) { if (!sourceFile) { - fail(Diagnostics.File_0_not_found, fileName); + const redirect = getProjectReferenceRedirect(fileName); + if (redirect) { + fail(Diagnostics.Output_file_0_has_not_been_built_from_source_file_1, redirect, fileName); + } + else { + fail(Diagnostics.File_0_not_found, fileName); + } } else if (refFile && host.getCanonicalFileName(fileName) === host.getCanonicalFileName(refFile.fileName)) { fail(Diagnostics.A_file_cannot_have_a_reference_to_itself); @@ -1791,6 +1801,9 @@ namespace ts { return file; } + const redirect = getProjectReferenceRedirect(fileName); + fileName = redirect || fileName; + // We haven't looked for this file, do so now and cache result const file = host.getSourceFile(fileName, options.target, hostErrorMessage => { if (refFile !== undefined && refPos !== undefined && refEnd !== undefined) { @@ -1860,6 +1873,23 @@ namespace ts { return file; } + function getProjectReferenceRedirect(fileName: string): string | undefined { + const path = toPath(fileName); + // If this file is produced by a referenced project, we need to rewrite it to + // look in the output folder of the referenced project rather than the input + const normalized = getNormalizedAbsolutePath(fileName, path); + let result: string | undefined = undefined; + projectReferenceRedirects.forEach((v, k) => { + if (result !== undefined) { + return undefined; + } + if (normalized.indexOf(k) === 0) { + result = changeExtension(fileName.replace(k, v), ".d.ts"); + } + }); + return result; + } + function processReferencedFiles(file: SourceFile, isDefaultLib: boolean) { forEach(file.referencedFiles, ref => { const referencedFileName = resolveTripleslashReference(ref.fileName, file.fileName); @@ -2032,6 +2062,59 @@ namespace ts { return allFilesBelongToPath; } + function createProjectReferenceRedirects(rootOptions: CompilerOptions): Map { + const result = createMap(); + walkProjectReferenceGraph(host, rootOptions, createMapping); + + function createMapping(_resolvedFile: string, referencedProject: CompilerOptions) { + // No rootDir in target set; this will be an error later on in the process + if (referencedProject.rootDir === undefined) return; + result.set(referencedProject.rootDir, referencedProject.outDir); + // If this project uses outFile, add the outFile to our compilation + if (referencedProject.outFile) { + const outFile = combinePaths(referencedProject.outDir, referencedProject.outFile); + processSourceFile(outFile, /*isDefaultLib*/ false, /*packageId*/ undefined); + } + } + return result; + } + + function checkProjectReferenceGraph() { + // Checks the following conditions: + // * Any referenced project has declaration: true + // * Any referenced project has an explicit rootDir + // * No circularities exist + // * TODO No project root is a subfolder of any other project root + + const illegalRefs = createMap(); + const cycleName: string[] = [options.configFilePath || host.getCurrentDirectory()]; + + walkProjectReferenceGraph(host, options, checkReference, createDiagnosticForOptionName); + + function checkReference(fileName: string, opts: CompilerOptions) { + const normalizedPath = ts.normalizePath(fileName); + if (illegalRefs.has(normalizedPath)) { + createDiagnosticForOptionName(Diagnostics.Project_references_may_not_form_a_circular_graph_Cycle_detected_Colon_0, cycleName.map(normalizePath).map(s => host.getNewLine() + " " + s).join(" -> ")); + return; + } + if (opts === undefined) { + Debug.fail("Options cannot be undefined"); + return; + } + if (!opts.declaration) { + createDiagnosticForOptionName(Diagnostics.Referenced_project_0_must_have_declaration_Colon_true, fileName); + } + if (!opts.rootDir) { + createDiagnosticForOptionName(Diagnostics.Referenced_project_0_must_have_an_explicit_rootDir_setting, fileName); + } + illegalRefs.set(normalizedPath, true); + cycleName.push(normalizedPath); + walkProjectReferenceGraph(host, opts, checkReference, createDiagnosticForOptionName); + cycleName.pop(); + illegalRefs.delete(normalizedPath); + } + } + function verifyCompilerOptions() { if (options.isolatedModules) { if (options.declaration) { @@ -2277,12 +2360,20 @@ namespace ts { } } - function getOptionPathsSyntax() { + function getOptionsSyntaxByName(name: string): object | undefined { const compilerOptionsObjectLiteralSyntax = getCompilerOptionsObjectLiteralSyntax(); if (compilerOptionsObjectLiteralSyntax) { - return getPropertyAssignment(compilerOptionsObjectLiteralSyntax, "paths"); + return getPropertyAssignment(compilerOptionsObjectLiteralSyntax, name); } - return emptyArray; + return undefined; + } + + function getReferencesSyntax(): ObjectLiteralExpression[] | undefined { + return getOptionsSyntaxByName("references") as ObjectLiteralExpression[] | undefined; + } + + function getOptionPathsSyntax(): PropertyAssignment[] { + return getOptionsSyntaxByName("paths") as PropertyAssignment[] || emptyArray; } function createDiagnosticForOptionName(message: DiagnosticMessage, option1: string, option2?: string) { @@ -2332,6 +2423,46 @@ namespace ts { } } + function parseConfigHostFromCompilerHost(host: CompilerHost): ParseConfigHost { + return { + fileExists: host.fileExists, + readDirectory: () => [], + readFile: host.readFile, + useCaseSensitiveFileNames: host.useCaseSensitiveFileNames() + }; + } + + export function walkProjectReferenceGraph(host: CompilerHost, rootOptions: CompilerOptions, + callback: (resolvedFile: string, referencedProject: CompilerOptions) => void, + error?: (message: DiagnosticMessage | DiagnosticMessageChain | string, option1?: string) => void) { + if (rootOptions.references === undefined) return; + + const configHost = parseConfigHostFromCompilerHost(host); + const rootPath = rootOptions.configFilePath ? getDirectoryPath(rootOptions.configFilePath) : host.getCurrentDirectory(); + for (const ref of rootOptions.references) { + let refPath = combinePaths(rootPath, ref.path); + if (!host.fileExists(refPath)) { + refPath = combinePaths(refPath, "tsconfig.json"); + } + if (!host.fileExists(refPath)) { + if (error) { + error(Diagnostics.File_0_not_found, refPath); + } + continue; + } + + const referenceJsonSource = parseJsonText(refPath, host.readFile(refPath)); + const cmdLine = parseJsonSourceFileConfigFileContent(referenceJsonSource, configHost, getDirectoryPath(refPath), /*existingOptions*/ undefined, refPath); + cmdLine.options.configFilePath = refPath; + if (cmdLine.errors && cmdLine.errors.length) { + // TODO: Pass along errors + } + if (cmdLine.options) { + callback(refPath, cmdLine.options); + } + } + } + /* @internal */ /** * Returns a DiagnosticMessage if we won't include a resolved module due to its extension. diff --git a/src/compiler/types.ts b/src/compiler/types.ts index ff2a33266ed..80bccb05ee0 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3675,7 +3675,11 @@ namespace ts { name: string; } - export type CompilerOptionsValue = string | number | boolean | (string | number)[] | string[] | MapLike | PluginImport[] | null | undefined; + export interface ProjectReference { + path: string; + } + + export type CompilerOptionsValue = string | number | boolean | (string | number)[] | string[] | MapLike | PluginImport[] | ProjectReference[] | null | undefined; export interface CompilerOptions { /*@internal*/ all?: boolean; @@ -3743,6 +3747,7 @@ namespace ts { /* @internal */ pretty?: DiagnosticStyle; reactNamespace?: string; jsxFactory?: string; + references?: ProjectReference[]; removeComments?: boolean; rootDir?: string; rootDirs?: string[]; diff --git a/src/harness/unittests/projectReferences.ts b/src/harness/unittests/projectReferences.ts new file mode 100644 index 00000000000..dc225a314c8 --- /dev/null +++ b/src/harness/unittests/projectReferences.ts @@ -0,0 +1,208 @@ +/// +/// + +namespace ts { + interface TestProjectSpecification { + configFileName?: string; + references: string[]; + files: { [fileName: string]: string }; + outputFiles?: { [fileName: string]: string }; + options?: Partial; + } + interface TestSpecification { + [path: string]: TestProjectSpecification; + } + + function assertHasError(message: string, errors: ReadonlyArray, diag: DiagnosticMessage) { + if (!errors.some(e => e.code === diag.code)) { + const errorString = errors.map(e => ` ${e.file ? e.file.fileName : "[global]"}: ${e.messageText}`).join("\r\n"); + assert(false, `${message}: Did not find any diagnostic for ${diag.message} in:\r\n${errorString}`); + } + } + + function assertNoErrors(message: string, errors: ReadonlyArray) { + if (errors && errors.length > 0) { + assert(false, `${message}: Expected no errors, but found:\r\n${errors.map(e => ` ${e.messageText}`).join("\r\n")}`); + } + } + + function combineAllPaths(...paths: string[]) { + let result = paths[0]; + for (let i = 1; i < paths.length; i++) { + result = combinePaths(result, paths[i]); + } + return result; + } + + const emptyModule = "export { };"; + + /** + * Produces the text of a source file which imports all of the + * specified module names + */ + function moduleImporting(...names: string[]) { + return names.map((n, i) => `import * as mod_${i} from ${n}`).join("\r\n"); + } + + function testProjectReferences(spec: TestSpecification, entryPointConfigFileName: string, checkResult: (prog: Program) => void) { + const files = createMap(); + for (const key in spec) { + const sp = spec[key]; + const configFileName = combineAllPaths("/", key, sp.configFileName || "tsconfig.json"); + const options = { + compilerOptions: { + references: sp.references.map(r => ({ path: r })), + declaration: true, + rootDir: ".", + outDir: "bin", + ...sp.options + } + }; + const configContent = JSON.stringify(options); + const outDir = options.compilerOptions.outDir; + files.set(configFileName, configContent); + for (const sourceFile of Object.keys(sp.files)) { + files.set(sourceFile, sp.files[sourceFile]); + } + if (sp.outputFiles) { + for (const outFile of Object.keys(sp.outputFiles)) { + files.set(combineAllPaths("/", key, outDir, outFile), sp.outputFiles[outFile]); + } + } + } + + const host = new Utils.MockProjectReferenceCompilerHost("/", /*useCaseSensitiveFileNames*/ true, files); + + const { config, error } = ts.readConfigFile(entryPointConfigFileName, name => host.readFile(name)); + + // We shouldn't have any errors about invalid tsconfig files in these tests + assert(config && !error, flattenDiagnosticMessageText(error && error.messageText, "\n")); + const file = ts.parseJsonConfigFileContent(config, host.configHost, getDirectoryPath(entryPointConfigFileName), {}, entryPointConfigFileName); + file.options.configFilePath = entryPointConfigFileName; + const prog = ts.createProgram(file.fileNames, file.options, host); + checkResult(prog); + } + + describe("project-references meta check", () => { + it("default setup was created correctly", () => { + const spec: TestSpecification = { + "/primary": { + files: { "/primary/a.ts": emptyModule }, + references: [] + }, + "/reference": { + files: { "/secondary/b.ts": moduleImporting("../primary/a") }, + references: ["../primary"] + } + }; + testProjectReferences(spec, "/primary/tsconfig.json", prog => { + assert.isTrue(!!prog, "Program should exist"); + assertNoErrors("Sanity check should not produce errors", prog.getOptionsDiagnostics()); + }); + }); + + it("can detect a circularity error", () => { + const spec: TestSpecification = { + "/primary": { + files: { "/primary/a.ts": emptyModule }, + references: ["../secondary"] + }, + "/secondary": { + files: { "/secondary/b.ts": moduleImporting("../primary/a") }, + references: ["../primary"] + } + }; + testProjectReferences(spec, "/primary/tsconfig.json", prog => { + assert.isTrue(!!prog, "Program should exist"); + assertHasError("Should detect a circular error", prog.getOptionsDiagnostics(), Diagnostics.Project_references_may_not_form_a_circular_graph_Cycle_detected_Colon_0); + }); + }); + }); + + /** + * Validate that we enforce the basic settings constraints for referenced projects + */ + describe("project-references constraint checking for settings", () => { + const spec: TestSpecification = { + "/primary": { + files: { "/primary/a.ts": emptyModule }, + references: ["../secondary"] + }, + "/secondary": { + files: { "/secondary/b.ts": moduleImporting("../primary/a") }, + references: [], + options: { + declaration: false + } + } + }; + it("errors when declaration = false", () => { + testProjectReferences(spec, "/primary/tsconfig.json", program => { + const errs = program.getOptionsDiagnostics(); + assertHasError("Reports an error about the wrong decl setting", errs, Diagnostics.Referenced_project_0_must_have_declaration_Colon_true); + }); + }); + + it("errors when rootDir is not set", () => { + spec["/secondary"].options.declaration = true; + spec["/secondary"].options.rootDir = undefined; + testProjectReferences(spec, "/primary/tsconfig.json", program => { + const errs = program.getOptionsDiagnostics(); + assertHasError("Reports an error about the wrong decl setting", errs, Diagnostics.Referenced_project_0_must_have_an_explicit_rootDir_setting); + }); + }); + // * TODO No project root is a subfolder of any other project root + }); + + /** + * Circularity checking + */ + describe("project-references circularity checking", () => { + // Bare cycle with relative paths tested in sanity check block + it("detects an indirected cycle", () => { + const spec: TestSpecification = { + "/alpha": { + files: { "/alpha/a.ts": emptyModule }, + references: ["../beta"] + }, + "/beta": { + files: { "/beta/b.ts": moduleImporting("../alpha/a") }, + references: ["../gamma"] + }, + "/gamma": { + files: { "/gamma/a.ts": emptyModule }, + references: ["../alpha"], + + } + }; + + testProjectReferences(spec, "/alpha/tsconfig.json", program => { + const errs = program.getOptionsDiagnostics(); + assertHasError("Reports an error about the circular diagnsotic", errs, Diagnostics.Project_references_may_not_form_a_circular_graph_Cycle_detected_Colon_0); + }); + }); + }); + + /** + * Path mapping behavior + */ + describe("project-references path mapping", () => { + it("redirects to the output .d.ts file", () => { + const spec: TestSpecification = { + "/alpha": { + files: { "/alpha/a.ts": "export const m: number;" }, + references: [], + outputFiles: { "a.d.ts": emptyModule } + }, + "/beta": { + files: { "/beta/b.ts": "import { m } from '../alpha/a'" }, + references: ["../alpha"] + } + }; + testProjectReferences(spec, "/beta/tsconfig.json", program => { + assertNoErrors("File setup should be correct", program.getOptionsDiagnostics()); + assertHasError("Found a type error", program.getSemanticDiagnostics(), Diagnostics.Module_0_has_no_exported_member_1); + }); + }); + }); +} diff --git a/src/harness/virtualFileSystem.ts b/src/harness/virtualFileSystem.ts index 8accd6f621e..b52a5730bf5 100644 --- a/src/harness/virtualFileSystem.ts +++ b/src/harness/virtualFileSystem.ts @@ -220,4 +220,67 @@ namespace Utils { return ts.matchFiles(path, extensions, excludes, includes, this.useCaseSensitiveFileNames, this.currentDirectory, depth, (path: string) => this.getAccessibleFileSystemEntries(path)); } } + + export class MockProjectReferenceCompilerHost implements ts.CompilerHost { + public configHost: ts.ParseConfigHost = new MockParseConfigHost(this.currentDirectory, this.ignoreCase, this.files); + private readonly getCanonicalFileNameImpl = ts.createGetCanonicalFileName(!this.ignoreCase); + constructor(private currentDirectory: string, private ignoreCase: boolean, private files: ts.Map | string[]) { + } + + getCanonicalFileName = (fileName: string): string => { + return this.getCanonicalFileNameImpl(fileName); + } + fileExists = (fileName: string): boolean => { + return this.configHost.fileExists(fileName); + } + + // TODO try deleting this + directoryExists = (dirName: string): boolean => { + const fullName = this.getCanonicalFileName(dirName); + let exists = false; + if (Array.isArray(this.files)) { + for (const k of this.files) { + if (this.getCanonicalFileName(k).indexOf(fullName) === 0) { + exists = true; + } + } + } + else { + this.files.forEach((_v, k) => { + if (this.getCanonicalFileName(k).indexOf(fullName) === 0) { + exists = true; + } + }); + } + return exists; + } + readFile = (fileName: string): string => { + if (fileName === "lib.d.ts") return "declare var window: any;"; + + return this.configHost.readFile(fileName); + } + getSourceFile = (fileName: string, languageVersion: ts.ScriptTarget): ts.SourceFile => { + const content = this.readFile(fileName); + if (content === undefined) { + return undefined; + } + return ts.createSourceFile(fileName, content, languageVersion); + } + getDefaultLibFileName(options: ts.CompilerOptions): string { + return ts.getDefaultLibFileName(options); + } + writeFile: ts.WriteFileCallback; + getCurrentDirectory = (): string => { + return this.currentDirectory; + } + getNewLine(): string { + return "\r\n"; + } + getDirectories(): string[] { + return []; + } + useCaseSensitiveFileNames = () => { + return this.ignoreCase; + } + } } \ No newline at end of file diff --git a/src/server/protocol.ts b/src/server/protocol.ts index 35e9f20d058..055a93866a4 100644 --- a/src/server/protocol.ts +++ b/src/server/protocol.ts @@ -2501,6 +2501,7 @@ namespace ts.server.protocol { project?: string; reactNamespace?: string; removeComments?: boolean; + references?: ProjectReference[]; rootDir?: string; rootDirs?: string[]; skipLibCheck?: boolean; diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 0f20bfc8687..618ad3ca617 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -2199,7 +2199,10 @@ declare namespace ts { interface PluginImport { name: string; } - type CompilerOptionsValue = string | number | boolean | (string | number)[] | string[] | MapLike | PluginImport[] | null | undefined; + interface ProjectReference { + path: string; + } + type CompilerOptionsValue = string | number | boolean | (string | number)[] | string[] | MapLike | PluginImport[] | ProjectReference[] | null | undefined; interface CompilerOptions { allowJs?: boolean; allowSyntheticDefaultImports?: boolean; @@ -2252,6 +2255,7 @@ declare namespace ts { project?: string; reactNamespace?: string; jsxFactory?: string; + references?: ProjectReference[]; removeComments?: boolean; rootDir?: string; rootDirs?: string[]; @@ -3766,6 +3770,7 @@ declare namespace ts { * @returns A 'Program' object. */ function createProgram(rootNames: ReadonlyArray, options: CompilerOptions, host?: CompilerHost, oldProgram?: Program): Program; + function walkProjectReferenceGraph(host: CompilerHost, rootOptions: CompilerOptions, callback: (resolvedFile: string, referencedProject: CompilerOptions) => void, error?: (message: DiagnosticMessage | DiagnosticMessageChain | string, option1?: string) => void): void; } declare namespace ts { interface Node { @@ -6788,6 +6793,7 @@ declare namespace ts.server.protocol { project?: string; reactNamespace?: string; removeComments?: boolean; + references?: ProjectReference[]; rootDir?: string; rootDirs?: string[]; skipLibCheck?: boolean; diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 67a30bcd371..72d74517d63 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -2199,7 +2199,10 @@ declare namespace ts { interface PluginImport { name: string; } - type CompilerOptionsValue = string | number | boolean | (string | number)[] | string[] | MapLike | PluginImport[] | null | undefined; + interface ProjectReference { + path: string; + } + type CompilerOptionsValue = string | number | boolean | (string | number)[] | string[] | MapLike | PluginImport[] | ProjectReference[] | null | undefined; interface CompilerOptions { allowJs?: boolean; allowSyntheticDefaultImports?: boolean; @@ -2252,6 +2255,7 @@ declare namespace ts { project?: string; reactNamespace?: string; jsxFactory?: string; + references?: ProjectReference[]; removeComments?: boolean; rootDir?: string; rootDirs?: string[]; @@ -3713,6 +3717,7 @@ declare namespace ts { * @returns A 'Program' object. */ function createProgram(rootNames: ReadonlyArray, options: CompilerOptions, host?: CompilerHost, oldProgram?: Program): Program; + function walkProjectReferenceGraph(host: CompilerHost, rootOptions: CompilerOptions, callback: (resolvedFile: string, referencedProject: CompilerOptions) => void, error?: (message: DiagnosticMessage | DiagnosticMessageChain | string, option1?: string) => void): void; } declare namespace ts { function parseCommandLine(commandLine: ReadonlyArray, readFile?: (path: string) => string | undefined): ParsedCommandLine; diff --git a/tests/baselines/reference/tsConfig/Default initialized TSConfig/tsconfig.json b/tests/baselines/reference/tsConfig/Default initialized TSConfig/tsconfig.json index 08887fc6c94..464f37556b0 100644 --- a/tests/baselines/reference/tsConfig/Default initialized TSConfig/tsconfig.json +++ b/tests/baselines/reference/tsConfig/Default initialized TSConfig/tsconfig.json @@ -39,6 +39,7 @@ // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ // "typeRoots": [], /* List of folders to include type definitions from. */ // "types": [], /* Type declaration files to be included in compilation. */ + // "references": [], /* Projects to reference */ // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ diff --git a/tests/baselines/reference/tsConfig/Initialized TSConfig with boolean value compiler options/tsconfig.json b/tests/baselines/reference/tsConfig/Initialized TSConfig with boolean value compiler options/tsconfig.json index ca2b4aa4087..ed87e1c2f97 100644 --- a/tests/baselines/reference/tsConfig/Initialized TSConfig with boolean value compiler options/tsconfig.json +++ b/tests/baselines/reference/tsConfig/Initialized TSConfig with boolean value compiler options/tsconfig.json @@ -39,6 +39,7 @@ // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ // "typeRoots": [], /* List of folders to include type definitions from. */ // "types": [], /* Type declaration files to be included in compilation. */ + // "references": [], /* Projects to reference */ // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ diff --git a/tests/baselines/reference/tsConfig/Initialized TSConfig with enum value compiler options/tsconfig.json b/tests/baselines/reference/tsConfig/Initialized TSConfig with enum value compiler options/tsconfig.json index 9437685c295..65bf8a27c76 100644 --- a/tests/baselines/reference/tsConfig/Initialized TSConfig with enum value compiler options/tsconfig.json +++ b/tests/baselines/reference/tsConfig/Initialized TSConfig with enum value compiler options/tsconfig.json @@ -39,6 +39,7 @@ // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ // "typeRoots": [], /* List of folders to include type definitions from. */ // "types": [], /* Type declaration files to be included in compilation. */ + // "references": [], /* Projects to reference */ // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ diff --git a/tests/baselines/reference/tsConfig/Initialized TSConfig with files options/tsconfig.json b/tests/baselines/reference/tsConfig/Initialized TSConfig with files options/tsconfig.json index d2e7e85ad55..006b37d62a1 100644 --- a/tests/baselines/reference/tsConfig/Initialized TSConfig with files options/tsconfig.json +++ b/tests/baselines/reference/tsConfig/Initialized TSConfig with files options/tsconfig.json @@ -39,6 +39,7 @@ // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ // "typeRoots": [], /* List of folders to include type definitions from. */ // "types": [], /* Type declaration files to be included in compilation. */ + // "references": [], /* Projects to reference */ // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ diff --git a/tests/baselines/reference/tsConfig/Initialized TSConfig with incorrect compiler option value/tsconfig.json b/tests/baselines/reference/tsConfig/Initialized TSConfig with incorrect compiler option value/tsconfig.json index 3f4100033d0..d71db287fac 100644 --- a/tests/baselines/reference/tsConfig/Initialized TSConfig with incorrect compiler option value/tsconfig.json +++ b/tests/baselines/reference/tsConfig/Initialized TSConfig with incorrect compiler option value/tsconfig.json @@ -39,6 +39,7 @@ // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ // "typeRoots": [], /* List of folders to include type definitions from. */ // "types": [], /* Type declaration files to be included in compilation. */ + // "references": [], /* Projects to reference */ // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ diff --git a/tests/baselines/reference/tsConfig/Initialized TSConfig with incorrect compiler option/tsconfig.json b/tests/baselines/reference/tsConfig/Initialized TSConfig with incorrect compiler option/tsconfig.json index 08887fc6c94..464f37556b0 100644 --- a/tests/baselines/reference/tsConfig/Initialized TSConfig with incorrect compiler option/tsconfig.json +++ b/tests/baselines/reference/tsConfig/Initialized TSConfig with incorrect compiler option/tsconfig.json @@ -39,6 +39,7 @@ // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ // "typeRoots": [], /* List of folders to include type definitions from. */ // "types": [], /* Type declaration files to be included in compilation. */ + // "references": [], /* Projects to reference */ // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ diff --git a/tests/baselines/reference/tsConfig/Initialized TSConfig with list compiler options with enum value/tsconfig.json b/tests/baselines/reference/tsConfig/Initialized TSConfig with list compiler options with enum value/tsconfig.json index 22cb0444209..61eb1c707ea 100644 --- a/tests/baselines/reference/tsConfig/Initialized TSConfig with list compiler options with enum value/tsconfig.json +++ b/tests/baselines/reference/tsConfig/Initialized TSConfig with list compiler options with enum value/tsconfig.json @@ -39,6 +39,7 @@ // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ // "typeRoots": [], /* List of folders to include type definitions from. */ // "types": [], /* Type declaration files to be included in compilation. */ + // "references": [], /* Projects to reference */ // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ diff --git a/tests/baselines/reference/tsConfig/Initialized TSConfig with list compiler options/tsconfig.json b/tests/baselines/reference/tsConfig/Initialized TSConfig with list compiler options/tsconfig.json index fc3321600fe..7e5b95ed6b5 100644 --- a/tests/baselines/reference/tsConfig/Initialized TSConfig with list compiler options/tsconfig.json +++ b/tests/baselines/reference/tsConfig/Initialized TSConfig with list compiler options/tsconfig.json @@ -39,6 +39,7 @@ // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ // "typeRoots": [], /* List of folders to include type definitions from. */ "types": ["jquery","mocha"] /* Type declaration files to be included in compilation. */ + // "references": [], /* Projects to reference */ // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */