Fix issue with wildcard with supported extensions when plugins add external files and override getScriptKind to add script kinds for the additional extensions (#55716)

This commit is contained in:
Sheetal Nandi
2023-09-12 11:52:49 -07:00
committed by GitHub
parent a0c51b5336
commit 3bc41784f0
5 changed files with 286 additions and 3 deletions

View File

@@ -20,9 +20,11 @@ import {
FileWatcherCallback,
FileWatcherEventKind,
find,
getAllowJSCompilerOption,
getBaseFileName,
getDirectoryPath,
getNormalizedAbsolutePath,
getResolveJsonModule,
hasExtension,
identity,
insertSorted,
@@ -44,6 +46,7 @@ import {
removeIgnoredPath,
returnNoopFileWatcher,
returnTrue,
ScriptKind,
setSysLog,
SortedArray,
SortedReadonlyArray,
@@ -563,6 +566,7 @@ export interface IsIgnoredFileFromWildCardWatchingInput {
useCaseSensitiveFileNames: boolean;
writeLog: (s: string) => void;
toPath: (fileName: string) => Path;
getScriptKind?: (fileName: string) => ScriptKind;
}
/** @internal */
export function isIgnoredFileFromWildCardWatching({
@@ -577,6 +581,7 @@ export function isIgnoredFileFromWildCardWatching({
useCaseSensitiveFileNames,
writeLog,
toPath,
getScriptKind,
}: IsIgnoredFileFromWildCardWatchingInput): boolean {
const newPath = removeIgnoredPath(fileOrDirectoryPath);
if (!newPath) {
@@ -588,8 +593,12 @@ export function isIgnoredFileFromWildCardWatching({
if (fileOrDirectoryPath === watchedDirPath) return false;
// If the the added or created file or directory is not supported file name, ignore the file
// But when watched directory is added/removed, we need to reload the file list
if (hasExtension(fileOrDirectoryPath) && !isSupportedSourceFileName(fileOrDirectory, options, extraFileExtensions)) {
if (
hasExtension(fileOrDirectoryPath) && !(
isSupportedSourceFileName(fileOrDirectory, options, extraFileExtensions) ||
isSupportedScriptKind()
)
) {
writeLog(`Project: ${configFileName} Detected file add/remove of non supported extension: ${fileOrDirectory}`);
return true;
}
@@ -634,6 +643,25 @@ export function isIgnoredFileFromWildCardWatching({
builderProgram.getState().fileInfos.has(file) :
!!find(program as readonly string[], rootFile => toPath(rootFile) === file);
}
function isSupportedScriptKind() {
if (!getScriptKind) return false;
const scriptKind = getScriptKind(fileOrDirectory);
switch (scriptKind) {
case ScriptKind.TS:
case ScriptKind.TSX:
case ScriptKind.Deferred:
case ScriptKind.External:
return true;
case ScriptKind.JS:
case ScriptKind.JSX:
return getAllowJSCompilerOption(options);
case ScriptKind.JSON:
return getResolveJsonModule(options);
case ScriptKind.Unknown:
return false;
}
}
}
function isBuilderProgram<T extends BuilderProgram>(program: Program | T): program is T {

View File

@@ -1526,6 +1526,7 @@ export class ProjectService {
useCaseSensitiveFileNames: this.host.useCaseSensitiveFileNames,
writeLog: s => this.logger.info(s),
toPath: s => this.toPath(s),
getScriptKind: configuredProjectForConfig ? (fileName => configuredProjectForConfig.getScriptKind(fileName)) : undefined,
})
) return;

View File

@@ -663,7 +663,7 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo
}
getScriptKind(fileName: string) {
const info = this.getOrCreateScriptInfoAndAttachToProject(fileName);
const info = this.projectService.getScriptInfoForPath(this.toPath(fileName));
return (info && info.scriptKind)!; // TODO: GH#18217
}

View File

@@ -218,3 +218,72 @@ describe("unittests:: tsserver:: plugins:: overriding getSupportedCodeFixes", ()
baselineTsserverLogs("plugins", "getSupportedCodeFixes can be proxied", session);
});
});
describe("unittests:: tsserver:: plugins:: supportedExtensions::", () => {
it("new files with non ts extensions and wildcard matching", () => {
const aTs: File = {
path: "/user/username/projects/myproject/a.ts",
content: `export const a = 10;`,
};
const bVue: File = {
path: "/user/username/projects/myproject/b.vue",
content: "bVue file",
};
const config: File = {
path: "/user/username/projects/myproject/tsconfig.json",
content: JSON.stringify(
{
compilerOptions: { composite: true },
include: ["*.ts", "*.vue"],
},
undefined,
" ",
),
};
const host = createServerHost([aTs, bVue, config, libFile]);
host.require = () => {
return {
module: () => ({
create(info: ts.server.PluginCreateInfo) {
const proxy = Harness.LanguageService.makeDefaultProxy(info);
const originalScriptKind = info.languageServiceHost.getScriptKind!.bind(info.languageServiceHost);
info.languageServiceHost.getScriptKind = fileName =>
ts.fileExtensionIs(fileName, ".vue") ?
ts.ScriptKind.TS :
originalScriptKind(fileName);
const originalGetScriptSnapshot = info.languageServiceHost.getScriptSnapshot.bind(info.languageServiceHost);
info.languageServiceHost.getScriptSnapshot = fileName =>
ts.fileExtensionIs(fileName, ".vue") ?
ts.ScriptSnapshot.fromString(`export const y = "${info.languageServiceHost.readFile(fileName)}";`) :
originalGetScriptSnapshot(fileName);
return proxy;
},
getExternalFiles: (project: ts.server.Project) => {
if (project.projectKind !== ts.server.ProjectKind.Configured) return [];
const configFile = project.getProjectName();
const config = ts.readJsonConfigFile(configFile, project.readFile.bind(project));
const parseHost: ts.ParseConfigHost = {
useCaseSensitiveFileNames: project.useCaseSensitiveFileNames(),
fileExists: project.fileExists.bind(project),
readFile: project.readFile.bind(project),
readDirectory: (...args) => {
args[1] = [".vue"];
return project.readDirectory(...args);
},
};
const parsed = ts.parseJsonSourceFileConfigFileContent(config, parseHost, project.getCurrentDirectory());
return parsed.fileNames;
},
}),
error: undefined,
};
};
const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host), globalPlugins: ["myplugin"] });
openFilesForSession([aTs], session);
host.writeFile("/user/username/projects/myproject/c.vue", "cVue file");
host.runQueuedTimeoutCallbacks();
baselineTsserverLogs("plugins", "new files with non ts extensions with wildcard matching", session);
});
});