Add option disableSourceOfProjectReferenceRedirect to disable using sources of project reference redirect from editor

This commit is contained in:
Sheetal Nandi 2019-07-10 15:21:24 -07:00
parent 824c22c460
commit b631850978
13 changed files with 110 additions and 51 deletions

View File

@ -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",

View File

@ -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",

View File

@ -814,7 +814,7 @@ namespace ts {
let projectReferenceRedirects: Map<ResolvedProjectReference | false> | undefined;
let mapFromFileToProjectReferenceRedirects: Map<Path> | undefined;
let mapFromToProjectReferenceRedirectSource: Map<SourceOfProjectReferenceRedirect> | 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<T>(

View File

@ -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;

View File

@ -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

View File

@ -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();

View File

@ -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);

View File

@ -239,7 +239,7 @@ namespace ts {
/* @internal */
setResolvedProjectReferenceCallbacks?(callbacks: ResolvedProjectReferenceCallbacks): void;
/* @internal */
useSourceInsteadOfReferenceRedirect?(): boolean;
useSourceOfProjectReferenceRedirect?(): boolean;
}
/* @internal */

View File

@ -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<protocol.ReferencesRequest>({
command: protocol.CommandTypes.References,
arguments: {
file: bTs.path,
...protocolLocationFromSubstring(bTs.content, "A()")
}
});
session.executeCommandSeq<protocol.ReferencesRequest>({
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 ", () => {

View File

@ -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<protocol.ChangeRequest>({
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", () => {

View File

@ -2513,6 +2513,7 @@ declare namespace ts {
emitDeclarationOnly?: boolean;
declarationDir?: string;
disableSizeLimit?: boolean;
disableSourceOfProjectReferenceRedirect?: boolean;
downlevelIteration?: boolean;
emitBOM?: boolean;
emitDecoratorMetadata?: boolean;

View File

@ -2513,6 +2513,7 @@ declare namespace ts {
emitDeclarationOnly?: boolean;
declarationDir?: string;
disableSizeLimit?: boolean;
disableSourceOfProjectReferenceRedirect?: boolean;
downlevelIteration?: boolean;
emitBOM?: boolean;
emitDecoratorMetadata?: boolean;

View File

@ -0,0 +1,5 @@
{
"compilerOptions": {
"disableSourceOfProjectReferenceRedirect": true
}
}