From b63185097889376b4c02094b863af9cf752f34cc Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Wed, 10 Jul 2019 15:21:24 -0700 Subject: [PATCH] Add option disableSourceOfProjectReferenceRedirect to disable using sources of project reference redirect from editor --- src/compiler/commandLineParser.ts | 6 ++ src/compiler/diagnosticMessages.json | 4 + src/compiler/program.ts | 12 +-- src/compiler/types.ts | 3 +- src/server/editorServices.ts | 2 +- src/server/project.ts | 7 +- src/services/services.ts | 4 +- src/services/types.ts | 2 +- .../tsserver/events/projectLoading.ts | 84 ++++++++++++------- .../unittests/tsserver/projectReferences.ts | 30 +++++-- .../reference/api/tsserverlibrary.d.ts | 1 + tests/baselines/reference/api/typescript.d.ts | 1 + .../tsconfig.json | 5 ++ 13 files changed, 110 insertions(+), 51 deletions(-) create mode 100644 tests/baselines/reference/showConfig/Shows tsconfig for single option/disableSourceOfProjectReferenceRedirect/tsconfig.json diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index 4747b89f08c..7f67b9c5097 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -751,6 +751,12 @@ namespace ts { category: Diagnostics.Advanced_Options, description: Diagnostics.Disable_size_limitations_on_JavaScript_projects }, + { + name: "disableSourceOfProjectReferenceRedirect", + type: "boolean", + category: Diagnostics.Advanced_Options, + description: Diagnostics.Disable_using_source_of_project_reference_redirect_files + }, { name: "noImplicitUseStrict", type: "boolean", diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 7d178f1d478..edc3903b38e 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -3967,6 +3967,10 @@ "category": "Message", "code": 6220 }, + "Disable using source of project reference redirect files.": { + "category": "Message", + "code": 6221 + }, "Projects to reference": { "category": "Message", diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 2149e175ca2..63f58066174 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -814,7 +814,7 @@ namespace ts { let projectReferenceRedirects: Map | undefined; let mapFromFileToProjectReferenceRedirects: Map | undefined; let mapFromToProjectReferenceRedirectSource: Map | undefined; - const useSourceOfReference = !!host.useSourceInsteadOfReferenceRedirect && host.useSourceInsteadOfReferenceRedirect(); + const useSourceOfProjectReferenceRedirect = !!host.useSourceOfProjectReferenceRedirect && host.useSourceOfProjectReferenceRedirect(); const shouldCreateNewSourceFile = shouldProgramCreateNewSourceFiles(oldProgram, options); const structuralIsReused = tryReuseStructureFromOldProgram(); @@ -836,7 +836,7 @@ namespace ts { for (const parsedRef of resolvedProjectReferences) { if (!parsedRef) continue; const out = parsedRef.commandLine.options.outFile || parsedRef.commandLine.options.out; - if (useSourceOfReference) { + if (useSourceOfProjectReferenceRedirect) { if (out || getEmitModuleKind(parsedRef.commandLine.options) === ModuleKind.None) { for (const fileName of parsedRef.commandLine.fileNames) { processSourceFile(fileName, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, /*packageId*/ undefined); @@ -1418,7 +1418,7 @@ namespace ts { for (const newSourceFile of newSourceFiles) { const filePath = newSourceFile.path; addFileToFilesByName(newSourceFile, filePath, newSourceFile.resolvedPath); - if (useSourceOfReference) { + if (useSourceOfProjectReferenceRedirect) { const redirectProject = getProjectReferenceRedirectProject(newSourceFile.fileName); if (redirectProject && !(redirectProject.commandLine.options.outFile || redirectProject.commandLine.options.out)) { const redirect = getProjectReferenceOutputName(redirectProject, newSourceFile.fileName); @@ -2252,7 +2252,7 @@ namespace ts { // Get source file from normalized fileName function findSourceFile(fileName: string, path: Path, isDefaultLib: boolean, ignoreNoDefaultLib: boolean, refFile: SourceFile, refPos: number, refEnd: number, packageId: PackageId | undefined): SourceFile | undefined { - if (useSourceOfReference) { + if (useSourceOfProjectReferenceRedirect) { const source = getSourceOfProjectReferenceRedirect(fileName); if (source) { const file = isString(source) ? @@ -2309,7 +2309,7 @@ namespace ts { } let redirectedPath: Path | undefined; - if (refFile && !useSourceOfReference) { + if (refFile && !useSourceOfProjectReferenceRedirect) { const redirectProject = getProjectReferenceRedirectProject(fileName); if (redirectProject) { if (redirectProject.commandLine.options.outFile || redirectProject.commandLine.options.out) { @@ -2498,7 +2498,7 @@ namespace ts { } function isSourceOfProjectReferenceRedirect(fileName: string) { - return useSourceOfReference && !!getResolvedProjectReferenceToRedirect(fileName); + return useSourceOfProjectReferenceRedirect && !!getResolvedProjectReferenceToRedirect(fileName); } function forEachProjectReference( diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 16ea47beecc..69ac55e6e1b 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -4645,6 +4645,7 @@ namespace ts { /* @internal */ diagnostics?: boolean; /* @internal */ extendedDiagnostics?: boolean; disableSizeLimit?: boolean; + disableSourceOfProjectReferenceRedirect?: boolean; downlevelIteration?: boolean; emitBOM?: boolean; emitDecoratorMetadata?: boolean; @@ -5169,7 +5170,7 @@ namespace ts { createHash?(data: string): string; getParsedCommandLine?(fileName: string): ParsedCommandLine | undefined; /* @internal */ setResolvedProjectReferenceCallbacks?(callbacks: ResolvedProjectReferenceCallbacks): void; - /* @internal */ useSourceInsteadOfReferenceRedirect?(): boolean; + /* @internal */ useSourceOfProjectReferenceRedirect?(): boolean; // TODO: later handle this in better way in builder host instead once the api for tsbuild finalizes and doesn't use compilerHost as base /*@internal*/createDirectory?(directory: string): void; diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index 6fea0bc4171..ab325d5ed33 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -2583,7 +2583,7 @@ namespace ts.server { if (!configFileName) return undefined; const configuredProject = this.findConfiguredProjectByProjectName(configFileName) || - this.createAndLoadConfiguredProject(configFileName, `Creating project for original file: ${originalFileInfo.fileName}${location !== originalLocation ? " for location " + location.fileName : ""}`); + this.createAndLoadConfiguredProject(configFileName, `Creating project for original file: ${originalFileInfo.fileName}${location !== originalLocation ? " for location: " + location.fileName : ""}`); if (configuredProject === project) return originalLocation; updateProjectIfDirty(configuredProject); // Keep this configured project as referenced from project diff --git a/src/server/project.ts b/src/server/project.ts index 2811b04c413..87ced54de8e 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -1540,11 +1540,12 @@ namespace ts.server { } /* @internal */ - useSourceInsteadOfReferenceRedirect = () => !!this.languageServiceEnabled; + useSourceOfProjectReferenceRedirect = () => !!this.languageServiceEnabled && + !this.getCompilerOptions().disableSourceOfProjectReferenceRedirect; fileExists(file: string): boolean { // Project references go to source file instead of .d.ts file - if (this.useSourceInsteadOfReferenceRedirect() && this.projectReferenceCallbacks) { + if (this.useSourceOfProjectReferenceRedirect() && this.projectReferenceCallbacks) { const source = this.projectReferenceCallbacks.getSourceOfProjectReferenceRedirect(file); if (source) return isString(source) ? super.fileExists(source) : true; } @@ -1553,7 +1554,7 @@ namespace ts.server { directoryExists(path: string): boolean { if (super.directoryExists(path)) return true; - if (!this.useSourceInsteadOfReferenceRedirect() || !this.projectReferenceCallbacks) return false; + if (!this.useSourceOfProjectReferenceRedirect() || !this.projectReferenceCallbacks) return false; if (!this.mapOfDeclarationDirectories) { this.mapOfDeclarationDirectories = createMap(); diff --git a/src/services/services.ts b/src/services/services.ts index 2f9ba6eec94..c4af3c94702 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1248,8 +1248,8 @@ namespace ts { if (host.setResolvedProjectReferenceCallbacks) { compilerHost.setResolvedProjectReferenceCallbacks = callbacks => host.setResolvedProjectReferenceCallbacks!(callbacks); } - if (host.useSourceInsteadOfReferenceRedirect) { - compilerHost.useSourceInsteadOfReferenceRedirect = () => host.useSourceInsteadOfReferenceRedirect!(); + if (host.useSourceOfProjectReferenceRedirect) { + compilerHost.useSourceOfProjectReferenceRedirect = () => host.useSourceOfProjectReferenceRedirect!(); } const documentRegistryBucketKey = documentRegistry.getKeyForCompilationSettings(newSettings); diff --git a/src/services/types.ts b/src/services/types.ts index b4fc25e587f..ec71813e1dc 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -239,7 +239,7 @@ namespace ts { /* @internal */ setResolvedProjectReferenceCallbacks?(callbacks: ResolvedProjectReferenceCallbacks): void; /* @internal */ - useSourceInsteadOfReferenceRedirect?(): boolean; + useSourceOfProjectReferenceRedirect?(): boolean; } /* @internal */ diff --git a/src/testRunner/unittests/tsserver/events/projectLoading.ts b/src/testRunner/unittests/tsserver/events/projectLoading.ts index 53fe28240f8..3cc25232bc2 100644 --- a/src/testRunner/unittests/tsserver/events/projectLoading.ts +++ b/src/testRunner/unittests/tsserver/events/projectLoading.ts @@ -73,44 +73,64 @@ namespace ts.projectSystem { verifyEvent(project, `Change in config file detected`); }); - it("when opening original location project", () => { - const aDTs: File = { - path: `${projectRoot}/a/a.d.ts`, - content: `export declare class A { + describe("when opening original location project", () => { + it("with project references", () => { + verify(); + }); + + it("when disableSourceOfProjectReferenceRedirect is true", () => { + verify(/*disableSourceOfProjectReferenceRedirect*/ true); + }); + + function verify(disableSourceOfProjectReferenceRedirect?: true) { + const aDTs: File = { + path: `${projectRoot}/a/a.d.ts`, + content: `export declare class A { } //# sourceMappingURL=a.d.ts.map ` - }; - const aDTsMap: File = { - path: `${projectRoot}/a/a.d.ts.map`, - content: `{"version":3,"file":"a.d.ts","sourceRoot":"","sources":["./a.ts"],"names":[],"mappings":"AAAA,qBAAa,CAAC;CAAI"}` - }; - const bTs: File = { - path: bTsPath, - content: `import {A} from "../a/a"; new A();` - }; - const configB: File = { - path: configBPath, - content: JSON.stringify({ - references: [{ path: "../a" }] - }) - }; + }; + const aDTsMap: File = { + path: `${projectRoot}/a/a.d.ts.map`, + content: `{"version":3,"file":"a.d.ts","sourceRoot":"","sources":["./a.ts"],"names":[],"mappings":"AAAA,qBAAa,CAAC;CAAI"}` + }; + const bTs: File = { + path: bTsPath, + content: `import {A} from "../a/a"; new A();` + }; + const configB: File = { + path: configBPath, + content: JSON.stringify({ + ...(disableSourceOfProjectReferenceRedirect && { + compilerOptions: { + disableSourceOfProjectReferenceRedirect + } + }), + references: [{ path: "../a" }] + }) + }; - const { service, session, verifyEventWithOpenTs, verifyEvent } = createSessionToVerifyEvent(files.concat(aDTs, aDTsMap, bTs, configB)); - verifyEventWithOpenTs(bTs, configB.path, 1); + const { service, session, verifyEventWithOpenTs, verifyEvent } = createSessionToVerifyEvent(files.concat(aDTs, aDTsMap, bTs, configB)); + verifyEventWithOpenTs(bTs, configB.path, 1); - session.executeCommandSeq({ - command: protocol.CommandTypes.References, - arguments: { - file: bTs.path, - ...protocolLocationFromSubstring(bTs.content, "A()") - } - }); + session.executeCommandSeq({ + command: protocol.CommandTypes.References, + arguments: { + file: bTs.path, + ...protocolLocationFromSubstring(bTs.content, "A()") + } + }); - checkNumberOfProjects(service, { configuredProjects: 2 }); - const project = service.configuredProjects.get(configA.path)!; - assert.isDefined(project); - verifyEvent(project, `Creating project for original file: ${aTs.path}`); + checkNumberOfProjects(service, { configuredProjects: 2 }); + const project = service.configuredProjects.get(configA.path)!; + assert.isDefined(project); + verifyEvent( + project, + disableSourceOfProjectReferenceRedirect ? + `Creating project for original file: ${aTs.path} for location: ${aDTs.path}` : + `Creating project for original file: ${aTs.path}` + ); + } }); describe("with external projects and config files ", () => { diff --git a/src/testRunner/unittests/tsserver/projectReferences.ts b/src/testRunner/unittests/tsserver/projectReferences.ts index f9445dc6d19..fe1ff10aac1 100644 --- a/src/testRunner/unittests/tsserver/projectReferences.ts +++ b/src/testRunner/unittests/tsserver/projectReferences.ts @@ -417,6 +417,7 @@ fn5(); interface VerifierAndWithRefs { withRefs: boolean; + disableSourceOfProjectReferenceRedirect?: true; verifier: (withRefs: boolean) => readonly DocumentPositionMapperVerifier[]; } @@ -426,7 +427,7 @@ fn5(); interface OpenTsFile extends VerifierAndWithRefs { onHostCreate?: (host: TestServerHost) => void; } - function openTsFile({ withRefs, verifier, onHostCreate }: OpenTsFile) { + function openTsFile({ withRefs, disableSourceOfProjectReferenceRedirect, verifier, onHostCreate }: OpenTsFile) { const host = createHost(files, [mainConfig.path]); if (!withRefs) { // Erase project reference @@ -434,11 +435,22 @@ fn5(); compilerOptions: { composite: true, declarationMap: true } })); } + else if (disableSourceOfProjectReferenceRedirect) { + // Erase project reference + host.writeFile(mainConfig.path, JSON.stringify({ + compilerOptions: { + composite: true, + declarationMap: true, + disableSourceOfProjectReferenceRedirect: !!disableSourceOfProjectReferenceRedirect + }, + references: [{ path: "../dependency" }] + })); + } if (onHostCreate) { onHostCreate(host); } const session = createSession(host); - const verifiers = verifier(withRefs); + const verifiers = verifier(withRefs && !disableSourceOfProjectReferenceRedirect); openFilesForSession([...openFiles(verifiers), randomFile], session); return { host, session, verifiers }; } @@ -786,9 +798,9 @@ fn5(); }); } - function verifyScenarioWorker({ mainScenario, verifier }: VerifyScenario, withRefs: boolean) { + function verifyScenarioWorker({ mainScenario, verifier }: VerifyScenario, withRefs: boolean, disableSourceOfProjectReferenceRedirect?: true) { it(mainScenario, () => { - const { host, session, verifiers } = openTsFile({ withRefs, verifier }); + const { host, session, verifiers } = openTsFile({ withRefs, disableSourceOfProjectReferenceRedirect, verifier }); checkProject(session, verifiers); verifyScenarioAndScriptInfoCollection(session, host, verifiers, "main"); }); @@ -798,6 +810,7 @@ fn5(); scenarioName: "when usage file changes, document position mapper doesnt change", verifier, withRefs, + disableSourceOfProjectReferenceRedirect, change: (_host, session, verifiers) => verifiers.forEach( verifier => session.executeCommandSeq({ command: protocol.CommandTypes.Change, @@ -819,6 +832,7 @@ fn5(); scenarioName: "when dependency .d.ts changes, document position mapper doesnt change", verifier, withRefs, + disableSourceOfProjectReferenceRedirect, change: host => host.writeFile( dtsLocation, host.readFile(dtsLocation)!.replace( @@ -835,6 +849,7 @@ fn5(); scenarioName: "when dependency file's map changes", verifier, withRefs, + disableSourceOfProjectReferenceRedirect, change: host => host.writeFile( dtsMapLocation, `{"version":3,"file":"FnS.d.ts","sourceRoot":"","sources":["../dependency/FnS.ts"],"names":[],"mappings":"AAAA,wBAAgB,GAAG,SAAM;AACzB,wBAAgB,GAAG,SAAM;AACzB,wBAAgB,GAAG,SAAM;AACzB,wBAAgB,GAAG,SAAM;AACzB,wBAAgB,GAAG,SAAM;AACzB,eAAO,MAAM,CAAC,KAAK,CAAC"}` @@ -846,6 +861,7 @@ fn5(); scenarioName: "with depedency files map file", verifier, withRefs, + disableSourceOfProjectReferenceRedirect, fileLocation: dtsMapLocation, fileNotPresentKey: "noMap", fileCreatedKey: "mapFileCreated", @@ -856,6 +872,7 @@ fn5(); scenarioName: "with depedency .d.ts file", verifier, withRefs, + disableSourceOfProjectReferenceRedirect, fileLocation: dtsLocation, fileNotPresentKey: "noDts", fileCreatedKey: "dtsFileCreated", @@ -863,7 +880,7 @@ fn5(); noDts: true }); - if (withRefs) { + if (withRefs && !disableSourceOfProjectReferenceRedirect) { verifyScenarioWithChanges({ scenarioName: "when defining project source changes", verifier, @@ -907,6 +924,9 @@ ${dependencyTs.content}`); describe("when main tsconfig has project reference", () => { verifyScenarioWorker(scenario, /*withRefs*/ true); }); + describe("when main tsconfig has but has disableSourceOfProjectReferenceRedirect", () => { + verifyScenarioWorker(scenario, /*withRefs*/ true); + }); } describe("from project that uses dependency", () => { diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 0b728ac95d8..09931908eda 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -2513,6 +2513,7 @@ declare namespace ts { emitDeclarationOnly?: boolean; declarationDir?: string; disableSizeLimit?: boolean; + disableSourceOfProjectReferenceRedirect?: boolean; downlevelIteration?: boolean; emitBOM?: boolean; emitDecoratorMetadata?: boolean; diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index be8eea8062b..34f6fd36dad 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -2513,6 +2513,7 @@ declare namespace ts { emitDeclarationOnly?: boolean; declarationDir?: string; disableSizeLimit?: boolean; + disableSourceOfProjectReferenceRedirect?: boolean; downlevelIteration?: boolean; emitBOM?: boolean; emitDecoratorMetadata?: boolean; diff --git a/tests/baselines/reference/showConfig/Shows tsconfig for single option/disableSourceOfProjectReferenceRedirect/tsconfig.json b/tests/baselines/reference/showConfig/Shows tsconfig for single option/disableSourceOfProjectReferenceRedirect/tsconfig.json new file mode 100644 index 00000000000..c8b95e0909d --- /dev/null +++ b/tests/baselines/reference/showConfig/Shows tsconfig for single option/disableSourceOfProjectReferenceRedirect/tsconfig.json @@ -0,0 +1,5 @@ +{ + "compilerOptions": { + "disableSourceOfProjectReferenceRedirect": true + } +}