mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Add sourceOf project reference redirect to filesByName list for redirect path so that module symbol is correctly resolved
This commit is contained in:
+10
-1
@@ -1411,6 +1411,13 @@ namespace ts {
|
||||
for (const newSourceFile of newSourceFiles) {
|
||||
const filePath = newSourceFile.path;
|
||||
addFileToFilesByName(newSourceFile, filePath, newSourceFile.resolvedPath);
|
||||
if (useSourceOfReference) {
|
||||
const redirectProject = getProjectReferenceRedirectProject(newSourceFile.fileName);
|
||||
if (redirectProject && !(redirectProject.commandLine.options.outFile || redirectProject.commandLine.options.out)) {
|
||||
const redirect = getProjectReferenceOutputName(redirectProject, newSourceFile.fileName);
|
||||
addFileToFilesByName(newSourceFile, toPath(redirect), /*redirectedPath*/ undefined);
|
||||
}
|
||||
}
|
||||
// Set the file as found during node modules search if it was found that way in old progra,
|
||||
if (oldProgram.isSourceFileFromExternalLibrary(oldProgram.getSourceFileByPath(filePath)!)) {
|
||||
sourceFilesFoundSearchingNodeModules.set(filePath, true);
|
||||
@@ -2240,9 +2247,11 @@ namespace ts {
|
||||
if (useSourceOfReference) {
|
||||
const source = getSourceOfProjectReferenceRedirect(fileName);
|
||||
if (source) {
|
||||
return isString(source) ?
|
||||
const file = isString(source) ?
|
||||
findSourceFile(source, toPath(source), isDefaultLib, ignoreNoDefaultLib, refFile, refPos, refEnd, packageId) :
|
||||
undefined;
|
||||
if (file) addFileToFilesByName(file, path, /*redirectedPath*/ undefined);
|
||||
return file;
|
||||
}
|
||||
}
|
||||
const originalFileName = fileName;
|
||||
|
||||
@@ -1148,10 +1148,11 @@ namespace ts {
|
||||
useCaseSensitiveFileNames: () => useCaseSensitiveFileNames,
|
||||
getCurrentDirectory: () => currentDirectory,
|
||||
getProgram,
|
||||
fileExists: host.fileExists && (f => host.fileExists!(f)),
|
||||
readFile: host.readFile && ((f, encoding) => host.readFile!(f, encoding)),
|
||||
getDocumentPositionMapper: host.getDocumentPositionMapper && ((generatedFileName, sourceFileName) => host.getDocumentPositionMapper!(generatedFileName, sourceFileName)),
|
||||
getSourceFileLike: host.getSourceFileLike && (f => host.getSourceFileLike!(f)),
|
||||
fileExists: maybeBind(host, host.fileExists),
|
||||
readFile: maybeBind(host, host.readFile),
|
||||
getDocumentPositionMapper: maybeBind(host, host.getDocumentPositionMapper),
|
||||
useSourceInsteadOfReferenceRedirect: maybeBind(host, host.useSourceInsteadOfReferenceRedirect),
|
||||
getSourceFileLike: maybeBind(host, host.getSourceFileLike),
|
||||
log
|
||||
});
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ namespace ts {
|
||||
readFile?(path: string, encoding?: string): string | undefined;
|
||||
getSourceFileLike?(fileName: string): SourceFileLike | undefined;
|
||||
getDocumentPositionMapper?(generatedFileName: string, sourceFileName?: string): DocumentPositionMapper | undefined;
|
||||
/* @internal */ useSourceInsteadOfReferenceRedirect?(): boolean;
|
||||
log(s: string): void;
|
||||
}
|
||||
|
||||
@@ -70,6 +71,11 @@ namespace ts {
|
||||
if (!sourceFile) return undefined;
|
||||
|
||||
const program = host.getProgram()!;
|
||||
// If this is source file of project reference source (instead of redirect) there is no generated position
|
||||
if (host.useSourceInsteadOfReferenceRedirect &&
|
||||
host.useSourceInsteadOfReferenceRedirect() &&
|
||||
program.getResolvedProjectReferenceToRedirect(sourceFile.fileName)) return undefined;
|
||||
|
||||
const options = program.getCompilerOptions();
|
||||
const outPath = options.outFile || options.out;
|
||||
|
||||
|
||||
@@ -373,7 +373,7 @@ fn5();
|
||||
verifyInfosWithRandom(session, host, openInfos, closedInfos, otherWatchedFiles);
|
||||
}
|
||||
|
||||
function verifyInfosWhenNoMapFile(session: TestSession, host: TestServerHost, dependencyTsOK?: true) {
|
||||
function verifyInfosWhenNoMapFile(session: TestSession, host: TestServerHost, dependencyTsOK?: boolean) {
|
||||
const dtsMapClosedInfo = firstDefined(closedInfos, f => f.toLowerCase() === dtsMapPath ? f : undefined);
|
||||
verifyInfosWithRandom(
|
||||
session,
|
||||
@@ -384,46 +384,48 @@ fn5();
|
||||
);
|
||||
}
|
||||
|
||||
function verifyInfosWhenNoDtsFile(session: TestSession, host: TestServerHost, watchDts: boolean, dependencyTsAndMapOk?: true) {
|
||||
function verifyInfosWhenNoDtsFile(session: TestSession, host: TestServerHost, watchDts: boolean, dependencyTsOk?: boolean, depedencyMapOk?: boolean) {
|
||||
const dtsMapClosedInfo = firstDefined(closedInfos, f => f.toLowerCase() === dtsMapPath ? f : undefined);
|
||||
const dtsClosedInfo = firstDefined(closedInfos, f => f.toLowerCase() === dtsPath ? f : undefined);
|
||||
verifyInfosWithRandom(
|
||||
session,
|
||||
host,
|
||||
openInfos,
|
||||
closedInfos.filter(f => (dependencyTsAndMapOk || f !== dtsMapClosedInfo) && f !== dtsClosedInfo && (dependencyTsAndMapOk || f !== dependencyTs.path)),
|
||||
closedInfos.filter(f => (depedencyMapOk || f !== dtsMapClosedInfo) && f !== dtsClosedInfo && (dependencyTsOk || f !== dependencyTs.path)),
|
||||
dtsClosedInfo && watchDts ?
|
||||
otherWatchedFiles.concat(dtsClosedInfo) :
|
||||
otherWatchedFiles
|
||||
);
|
||||
}
|
||||
|
||||
function verifyDocumentPositionMapper(session: TestSession, dependencyMap: server.ScriptInfo, documentPositionMapper: server.ScriptInfo["documentPositionMapper"], notEqual?: true) {
|
||||
function verifyDocumentPositionMapper(session: TestSession, dependencyMap: server.ScriptInfo | undefined, documentPositionMapper: server.ScriptInfo["documentPositionMapper"], notEqual?: true) {
|
||||
assert.strictEqual(session.getProjectService().filenameToScriptInfo.get(dtsMapPath), dependencyMap);
|
||||
if (notEqual) {
|
||||
assert.notStrictEqual(dependencyMap.documentPositionMapper, documentPositionMapper);
|
||||
}
|
||||
else {
|
||||
assert.strictEqual(dependencyMap.documentPositionMapper, documentPositionMapper);
|
||||
if (dependencyMap) {
|
||||
if (notEqual) {
|
||||
assert.notStrictEqual(dependencyMap.documentPositionMapper, documentPositionMapper);
|
||||
}
|
||||
else {
|
||||
assert.strictEqual(dependencyMap.documentPositionMapper, documentPositionMapper);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function action(verifier: DocumentPositionMapperVerifier, fn: number, session: TestSession) {
|
||||
const { reqName, request, expectedResponse, expectedResponseNoMap, expectedResponseNoDts } = verifier.actionGetter(fn);
|
||||
const { response } = session.executeCommandSeq(request);
|
||||
return { reqName, response, expectedResponse, expectedResponseNoMap, expectedResponseNoDts, verifier };
|
||||
function action(verifier: DocumentPositionMapperVerifier, fn: number, session: TestSession, useDependencyChange?: boolean) {
|
||||
const { reqName, request, expectedResponse, expectedResponseNoMap, expectedResponseNoDts, requestDependencyChange, expectedResponseDependencyChange } = verifier.actionGetter(fn);
|
||||
const { response } = session.executeCommandSeq(useDependencyChange ? requestDependencyChange || request : request);
|
||||
return { reqName, response, expectedResponse, expectedResponseNoMap, expectedResponseNoDts, expectedResponseDependencyChange, verifier };
|
||||
}
|
||||
|
||||
function firstAction(session: TestSession) {
|
||||
verifier.forEach(v => action(v, 1, session));
|
||||
}
|
||||
|
||||
function verifyAllFnActionWorker(session: TestSession, verifyAction: (result: ReturnType<typeof action>, dtsInfo: server.ScriptInfo | undefined, isFirst: boolean) => void, dtsAbsent?: true) {
|
||||
function verifyAllFnActionWorker(session: TestSession, verifyAction: (result: ReturnType<typeof action>, dtsInfo: server.ScriptInfo | undefined, isFirst: boolean) => void, dtsAbsent?: boolean, useDependencyChange?: boolean) {
|
||||
// action
|
||||
let isFirst = true;
|
||||
for (const v of verifier) {
|
||||
for (let fn = 1; fn <= 5; fn++) {
|
||||
const result = action(v, fn, session);
|
||||
const result = action(v, fn, session, useDependencyChange);
|
||||
const dtsInfo = session.getProjectService().filenameToScriptInfo.get(dtsPath);
|
||||
if (dtsAbsent) {
|
||||
assert.isUndefined(dtsInfo);
|
||||
@@ -437,33 +439,38 @@ fn5();
|
||||
}
|
||||
}
|
||||
|
||||
function dtsAbsent() {
|
||||
return withRefs && !contains(closedInfos, dtsPath, (a, b) => a.toLowerCase() === b.toLowerCase());
|
||||
}
|
||||
|
||||
function verifyAllFnAction(
|
||||
session: TestSession,
|
||||
host: TestServerHost,
|
||||
firstDocumentPositionMapperNotEquals?: true,
|
||||
dependencyMap?: server.ScriptInfo,
|
||||
documentPositionMapper?: server.ScriptInfo["documentPositionMapper"]
|
||||
documentPositionMapper?: server.ScriptInfo["documentPositionMapper"],
|
||||
useDependencyChange?: boolean
|
||||
) {
|
||||
// action
|
||||
verifyAllFnActionWorker(session, ({ reqName, response, expectedResponse }, dtsInfo, isFirst) => {
|
||||
assert.deepEqual(response, expectedResponse, `Failed on ${reqName}`);
|
||||
verifyAllFnActionWorker(session, ({ reqName, response, expectedResponse, expectedResponseDependencyChange }, dtsInfo, isFirst) => {
|
||||
assert.deepEqual(response, useDependencyChange ? expectedResponseDependencyChange || expectedResponse : expectedResponse, `Failed on ${reqName}`);
|
||||
verifyInfos(session, host);
|
||||
assert.equal(dtsInfo!.sourceMapFilePath, dtsMapPath);
|
||||
if (dtsInfo) assert.equal(dtsInfo.sourceMapFilePath, dtsMapPath);
|
||||
if (isFirst) {
|
||||
if (dependencyMap) {
|
||||
verifyDocumentPositionMapper(session, dependencyMap, documentPositionMapper, firstDocumentPositionMapperNotEquals);
|
||||
documentPositionMapper = dependencyMap.documentPositionMapper;
|
||||
}
|
||||
else {
|
||||
dependencyMap = session.getProjectService().filenameToScriptInfo.get(dtsMapPath)!;
|
||||
documentPositionMapper = dependencyMap.documentPositionMapper;
|
||||
dependencyMap = session.getProjectService().filenameToScriptInfo.get(dtsMapPath);
|
||||
documentPositionMapper = dependencyMap && dependencyMap.documentPositionMapper;
|
||||
}
|
||||
}
|
||||
else {
|
||||
verifyDocumentPositionMapper(session, dependencyMap!, documentPositionMapper);
|
||||
verifyDocumentPositionMapper(session, dependencyMap, documentPositionMapper);
|
||||
}
|
||||
});
|
||||
return { dependencyMap: dependencyMap!, documentPositionMapper };
|
||||
}, dtsAbsent(), useDependencyChange);
|
||||
return { dependencyMap, documentPositionMapper };
|
||||
}
|
||||
|
||||
function verifyAllFnActionWithNoMap(
|
||||
@@ -474,19 +481,21 @@ fn5();
|
||||
let sourceMapFilePath: server.ScriptInfo["sourceMapFilePath"];
|
||||
// action
|
||||
verifyAllFnActionWorker(session, ({ reqName, response, expectedResponse, expectedResponseNoMap }, dtsInfo, isFirst) => {
|
||||
assert.deepEqual(response, expectedResponseNoMap || expectedResponse, `Failed on ${reqName}`);
|
||||
assert.deepEqual(response, withRefs ? expectedResponse : expectedResponseNoMap || expectedResponse, `Failed on ${reqName}`);
|
||||
verifyInfosWhenNoMapFile(session, host, dependencyTsOK);
|
||||
assert.isUndefined(session.getProjectService().filenameToScriptInfo.get(dtsMapPath));
|
||||
if (isFirst) {
|
||||
assert.isNotString(dtsInfo!.sourceMapFilePath);
|
||||
assert.isNotFalse(dtsInfo!.sourceMapFilePath);
|
||||
assert.isDefined(dtsInfo!.sourceMapFilePath);
|
||||
sourceMapFilePath = dtsInfo!.sourceMapFilePath;
|
||||
if (!withRefs) {
|
||||
if (isFirst) {
|
||||
assert.isNotString(dtsInfo!.sourceMapFilePath);
|
||||
assert.isNotFalse(dtsInfo!.sourceMapFilePath);
|
||||
assert.isDefined(dtsInfo!.sourceMapFilePath);
|
||||
sourceMapFilePath = dtsInfo!.sourceMapFilePath;
|
||||
}
|
||||
else {
|
||||
assert.equal(dtsInfo!.sourceMapFilePath, sourceMapFilePath);
|
||||
}
|
||||
}
|
||||
else {
|
||||
assert.equal(dtsInfo!.sourceMapFilePath, sourceMapFilePath);
|
||||
}
|
||||
});
|
||||
}, dtsAbsent());
|
||||
return sourceMapFilePath;
|
||||
}
|
||||
|
||||
@@ -497,7 +506,7 @@ fn5();
|
||||
) {
|
||||
// action
|
||||
verifyAllFnActionWorker(session, ({ reqName, response, expectedResponse, expectedResponseNoDts, verifier }) => {
|
||||
assert.deepEqual(response, expectedResponseNoDts || expectedResponse, `Failed on ${reqName}`);
|
||||
assert.deepEqual(response, withRefs ? expectedResponse : expectedResponseNoDts || expectedResponse, `Failed on ${reqName}`);
|
||||
verifyInfosWhenNoDtsFile(
|
||||
session,
|
||||
host,
|
||||
@@ -505,7 +514,8 @@ fn5();
|
||||
// instead of succeeding to source file and then mapping using project reference (When using usage location)
|
||||
// But watched if sourcemapper is in source project since we need to keep track of dts to update the source mapper for any potential usages
|
||||
verifier.expectedProjectActualFiles.every(f => f.toLowerCase() !== dtsPath),
|
||||
dependencyTsAndMapOk,
|
||||
/*dependencyTsOk*/ withRefs || dependencyTsAndMapOk,
|
||||
/*dependencyMapOk*/ dependencyTsAndMapOk
|
||||
);
|
||||
}, /*dtsAbsent*/ true);
|
||||
}
|
||||
@@ -513,14 +523,15 @@ fn5();
|
||||
function verifyScenarioWithChangesWorker(
|
||||
change: (host: TestServerHost, session: TestSession) => void,
|
||||
afterActionDocumentPositionMapperNotEquals: true | undefined,
|
||||
timeoutBeforeAction: boolean
|
||||
timeoutBeforeAction: boolean,
|
||||
useDependencyChange?: boolean
|
||||
) {
|
||||
const { host, session } = openTsFile();
|
||||
|
||||
// Create DocumentPositionMapper
|
||||
firstAction(session);
|
||||
const dependencyMap = session.getProjectService().filenameToScriptInfo.get(dtsMapPath)!;
|
||||
const documentPositionMapper = dependencyMap.documentPositionMapper;
|
||||
const dependencyMap = session.getProjectService().filenameToScriptInfo.get(dtsMapPath);
|
||||
const documentPositionMapper = dependencyMap && dependencyMap.documentPositionMapper;
|
||||
|
||||
// change
|
||||
change(host, session);
|
||||
@@ -531,21 +542,22 @@ fn5();
|
||||
}
|
||||
|
||||
// action
|
||||
verifyAllFnAction(session, host, afterActionDocumentPositionMapperNotEquals, dependencyMap, documentPositionMapper);
|
||||
verifyAllFnAction(session, host, afterActionDocumentPositionMapperNotEquals, dependencyMap, documentPositionMapper, useDependencyChange);
|
||||
}
|
||||
|
||||
function verifyScenarioWithChanges(
|
||||
scenarioName: string,
|
||||
change: (host: TestServerHost, session: TestSession) => void,
|
||||
afterActionDocumentPositionMapperNotEquals?: true
|
||||
afterActionDocumentPositionMapperNotEquals?: true,
|
||||
useDependencyChange?: boolean
|
||||
) {
|
||||
describe(scenarioName, () => {
|
||||
it("when timeout occurs before request", () => {
|
||||
verifyScenarioWithChangesWorker(change, afterActionDocumentPositionMapperNotEquals, /*timeoutBeforeAction*/ true);
|
||||
verifyScenarioWithChangesWorker(change, afterActionDocumentPositionMapperNotEquals, /*timeoutBeforeAction*/ true, useDependencyChange);
|
||||
});
|
||||
|
||||
it("when timeout does not occur before request", () => {
|
||||
verifyScenarioWithChangesWorker(change, afterActionDocumentPositionMapperNotEquals, /*timeoutBeforeAction*/ false);
|
||||
verifyScenarioWithChangesWorker(change, afterActionDocumentPositionMapperNotEquals, /*timeoutBeforeAction*/ false, useDependencyChange);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -570,12 +582,12 @@ fn5();
|
||||
|
||||
function verifyMainScenarioAndScriptInfoCollectionWithNoMap(session: TestSession, host: TestServerHost, dependencyTsOKInScenario?: true) {
|
||||
// Main scenario action
|
||||
verifyAllFnActionWithNoMap(session, host, dependencyTsOKInScenario);
|
||||
verifyAllFnActionWithNoMap(session, host, withRefs || dependencyTsOKInScenario);
|
||||
|
||||
// Collecting at this point retains dependency.d.ts and map watcher
|
||||
closeFilesForSession([randomFile], session);
|
||||
openFilesForSession([randomFile], session);
|
||||
verifyInfosWhenNoMapFile(session, host);
|
||||
verifyInfosWhenNoMapFile(session, host, withRefs);
|
||||
|
||||
// Closing open file, removes dependencies too
|
||||
closeFilesForSession([...openFiles, randomFile], session);
|
||||
@@ -593,7 +605,8 @@ fn5();
|
||||
verifyInfosWhenNoDtsFile(
|
||||
session,
|
||||
host,
|
||||
!!forEach(verifier, v => v.expectedProjectActualFiles.every(f => f.toLowerCase() !== dtsPath))
|
||||
!!forEach(verifier, v => v.expectedProjectActualFiles.every(f => f.toLowerCase() !== dtsPath)),
|
||||
/*dependencyTsOk*/ withRefs
|
||||
);
|
||||
|
||||
// Closing open file, removes dependencies too
|
||||
@@ -694,35 +707,26 @@ fn5();
|
||||
);
|
||||
|
||||
if (withRefs) {
|
||||
it("when defining project source changes", () => {
|
||||
const { host, session } = openTsFile();
|
||||
|
||||
// First action
|
||||
firstAction(session);
|
||||
|
||||
// Make change, without rebuild of solution
|
||||
if (contains(openInfos, dependencyTs.path)) {
|
||||
session.executeCommandSeq<protocol.ChangeRequest>({
|
||||
command: protocol.CommandTypes.Change,
|
||||
arguments: {
|
||||
file: dependencyTs.path, line: 1, offset: 1, endLine: 1, endOffset: 1, insertString: `function fooBar() { }
|
||||
verifyScenarioWithChanges(
|
||||
"when defining project source changes",
|
||||
(host, session) => {
|
||||
// Make change, without rebuild of solution
|
||||
if (contains(openInfos, dependencyTs.path)) {
|
||||
session.executeCommandSeq<protocol.ChangeRequest>({
|
||||
command: protocol.CommandTypes.Change,
|
||||
arguments: {
|
||||
file: dependencyTs.path, line: 1, offset: 1, endLine: 1, endOffset: 1, insertString: `function fooBar() { }
|
||||
`}
|
||||
});
|
||||
}
|
||||
else {
|
||||
host.writeFile(dependencyTs.path, `function fooBar() { }
|
||||
${dependencyTs.content}`);
|
||||
}
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
|
||||
for (const v of verifier) {
|
||||
for (let fn = 1; fn <= 5; fn++) {
|
||||
const { reqName, request, requestDependencyChange, expectedResponseDependencyChange } = v.actionGetter(fn);
|
||||
const { response } = session.executeCommandSeq(requestDependencyChange || request);
|
||||
assert.deepEqual(response, expectedResponseDependencyChange, `Failed on ${reqName}`);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
else {
|
||||
host.writeFile(dependencyTs.path, `function fooBar() { }
|
||||
${dependencyTs.content}`);
|
||||
}
|
||||
},
|
||||
/*afterActionDocumentPositionMapperNotEquals*/ undefined,
|
||||
/*useDepedencyChange*/ true
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -730,13 +734,15 @@ ${dependencyTs.content}`);
|
||||
describe(withRefs ? "when main tsconfig has project reference" : "when main tsconfig doesnt have project reference", () => {
|
||||
const usageVerifier: DocumentPositionMapperVerifier = {
|
||||
openFile: mainTs,
|
||||
expectedProjectActualFiles: [mainTs.path, libFile.path, mainConfig.path, dtsPath],
|
||||
expectedProjectActualFiles: withRefs ?
|
||||
[mainTs.path, libFile.path, mainConfig.path, dependencyTs.path] :
|
||||
[mainTs.path, libFile.path, mainConfig.path, dtsPath],
|
||||
actionGetter: gotoDefintinionFromMainTs,
|
||||
openFileLastLine: 14
|
||||
};
|
||||
describe("from project that uses dependency", () => {
|
||||
const closedInfos = withRefs ?
|
||||
[dependencyTs.path, dependencyConfig.path, libFile.path, dtsPath, dtsMapLocation] :
|
||||
[dependencyTs.path, dependencyConfig.path, libFile.path] :
|
||||
[dependencyTs.path, libFile.path, dtsPath, dtsMapLocation];
|
||||
verifyDocumentPositionMapperUpdates(
|
||||
"can go to definition correctly",
|
||||
@@ -764,7 +770,7 @@ ${dependencyTs.content}`);
|
||||
|
||||
describe("when opening depedency and usage project", () => {
|
||||
const closedInfos = withRefs ?
|
||||
[libFile.path, dtsPath, dtsMapLocation, dependencyConfig.path] :
|
||||
[libFile.path, dependencyConfig.path] :
|
||||
[libFile.path, dtsPath, dtsMapLocation];
|
||||
verifyDocumentPositionMapperUpdates(
|
||||
"goto Definition in usage and rename locations from defining project",
|
||||
|
||||
Reference in New Issue
Block a user