Monkeypatch ScriptInfo instead of subclassing-and-replacing.
This means we can ditch the whole approach of trying to remove stale ScriptInfo instances at plugin startup, instead just endowing existing ones with new behaviour. This repairs an error where renaming an identifer would perform spurious edits.
This commit is contained in:
parent
2eb7045b5c
commit
a0f87bf687
|
@ -229,25 +229,13 @@ const boot: tslib.server.PluginModuleFactory = ({ typescript: ts }) => {
|
|||
ts.createSourceFile = createSourceFile;
|
||||
}
|
||||
|
||||
class SyndicateScriptInfo extends ts.server.ScriptInfo {
|
||||
constructor(
|
||||
host: ts.server.ServerHost,
|
||||
fileName: ts.server.NormalizedPath,
|
||||
scriptKind: ts.ScriptKind,
|
||||
hasMixedContent: boolean,
|
||||
path: ts.Path,
|
||||
initialVersion?: ts.server.ScriptInfoVersion,
|
||||
) {
|
||||
if (shouldExpand(fileName)) {
|
||||
console.log('SyndicateScriptInfo constructor', fileName);
|
||||
}
|
||||
super(host, fileName, scriptKind, hasMixedContent, path, initialVersion);
|
||||
}
|
||||
|
||||
editContent(start: number, end: number, newText: string): void {
|
||||
{
|
||||
const oldEditContent = ts.server.ScriptInfo.prototype.editContent;
|
||||
ts.server.ScriptInfo.prototype.editContent =
|
||||
function (start: number, end: number, newText: string): void {
|
||||
// console.log('SyndicateScriptInfo.editContent', this.fileName, start, end, newText);
|
||||
withFileName(this.fileName,
|
||||
() => super.editContent(start, end, newText),
|
||||
() => oldEditContent(start, end, newText),
|
||||
(fx) => {
|
||||
const info = fx.info;
|
||||
const revised = info.originalSource.substring(0, start) +
|
||||
|
@ -256,10 +244,40 @@ const boot: tslib.server.PluginModuleFactory = ({ typescript: ts }) => {
|
|||
info.originalSource = revised;
|
||||
this.open(revised);
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
ts.server.ScriptInfo = SyndicateScriptInfo;
|
||||
// class SyndicateScriptInfo extends ts.server.ScriptInfo {
|
||||
// constructor(
|
||||
// host: ts.server.ServerHost,
|
||||
// fileName: ts.server.NormalizedPath,
|
||||
// scriptKind: ts.ScriptKind,
|
||||
// hasMixedContent: boolean,
|
||||
// path: ts.Path,
|
||||
// initialVersion?: ts.server.ScriptInfoVersion,
|
||||
// ) {
|
||||
// if (shouldExpand(fileName)) {
|
||||
// console.log('SyndicateScriptInfo constructor', fileName);
|
||||
// }
|
||||
// super(host, fileName, scriptKind, hasMixedContent, path, initialVersion);
|
||||
// }
|
||||
//
|
||||
// editContent(start: number, end: number, newText: string): void {
|
||||
// // console.log('SyndicateScriptInfo.editContent', this.fileName, start, end, newText);
|
||||
// withFileName(this.fileName,
|
||||
// () => super.editContent(start, end, newText),
|
||||
// (fx) => {
|
||||
// const info = fx.info;
|
||||
// const revised = info.originalSource.substring(0, start) +
|
||||
// newText +
|
||||
// info.originalSource.substring(end);
|
||||
// info.originalSource = revised;
|
||||
// this.open(revised);
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// ts.server.ScriptInfo = SyndicateScriptInfo;
|
||||
|
||||
class SyndicateLanguageService implements ts.LanguageService {
|
||||
readonly inner: ts.LanguageService;
|
||||
|
@ -761,7 +779,9 @@ const boot: tslib.server.PluginModuleFactory = ({ typescript: ts }) => {
|
|||
|
||||
class SyndicatePlugin implements ts.server.PluginModule {
|
||||
create(createInfo: ts.server.PluginCreateInfo): ts.LanguageService {
|
||||
const options = createInfo.project.getCompilerOptions();
|
||||
const project = createInfo.project;
|
||||
|
||||
const options = project.getCompilerOptions();
|
||||
if (options.rootDir !== void 0) {
|
||||
syndicateRootDirs.add(finalSlash(options.rootDir));
|
||||
}
|
||||
|
@ -771,31 +791,59 @@ const boot: tslib.server.PluginModuleFactory = ({ typescript: ts }) => {
|
|||
if (options.rootDir === void 0 && options.rootDirs === void 0) {
|
||||
syndicateRootDirs.add(finalSlash(path.resolve('.')));
|
||||
}
|
||||
// This next little block is required to flush out previously-created ScriptInfo
|
||||
// instances for our project, since they were created before our plugin was even
|
||||
// loaded and our plugin monkey-patches ScriptInfo to SyndicateScriptInfo.
|
||||
{
|
||||
const infos: Map<string, ts.server.ScriptInfo> =
|
||||
(createInfo.project.projectService as any).filenameToScriptInfo;
|
||||
const oldInfos = Array.from(infos.values());
|
||||
infos.clear();
|
||||
for (const info of oldInfos) {
|
||||
// console.log('---', info.fileName);
|
||||
// console.log(JSON.stringify({
|
||||
// oldText: (info as any).textStorage.text,
|
||||
|
||||
// // This next block is required to flush out previously-created ScriptInfo instances
|
||||
// // for our project, since they were created before our plugin was even loaded and
|
||||
// // our plugin monkey-patches ScriptInfo to SyndicateScriptInfo.
|
||||
// {
|
||||
// const infos: Map<string, ts.server.ScriptInfo> =
|
||||
// (project.projectService as any).filenameToScriptInfo;
|
||||
// const oldInfos = Array.from(infos.values());
|
||||
|
||||
// infos.clear();
|
||||
// for (const info of oldInfos) {
|
||||
|
||||
// if (!shouldExpand(info.fileName)) {
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// const existingText = (info as any).textStorage.text;
|
||||
|
||||
// console.log('---', JSON.stringify({
|
||||
// fileName: info.fileName,
|
||||
// existingText,
|
||||
// containingProjects: info.containingProjects.map(p => p.getProjectName()),
|
||||
// }, void 0, 2));
|
||||
const newInfo = new SyndicateScriptInfo(
|
||||
(info as any).host,
|
||||
info.fileName,
|
||||
info.scriptKind,
|
||||
info.hasMixedContent,
|
||||
info.path,
|
||||
(info as any).textStorage.version);
|
||||
(newInfo as any).textStorage = (info as any).textStorage;
|
||||
infos.set(info.fileName, newInfo);
|
||||
createInfo.project.getSourceFile(info.fileName as any);
|
||||
}
|
||||
}
|
||||
|
||||
// const newInfo = new SyndicateScriptInfo(
|
||||
// (info as any).host,
|
||||
// info.fileName,
|
||||
// info.scriptKind,
|
||||
// info.hasMixedContent,
|
||||
// info.path,
|
||||
// (info as any).textStorage.version);
|
||||
// (newInfo as any).textStorage = (info as any).textStorage;
|
||||
// infos.set(info.fileName, newInfo);
|
||||
// // ^ transfers necessary live information from old ScriptInfo instances to
|
||||
// // new SyndicateScriptInfo instances, so open files with syntax errors keep
|
||||
// // their syntax error info.
|
||||
|
||||
// info.close();
|
||||
// // ^ detaches old ScriptInfo from projects, so we don't end up with bizarre
|
||||
// // duplicates in e.g. automated renamings.
|
||||
|
||||
// info.detachAllProjects();
|
||||
// // info.detachFromProject(project);
|
||||
// newInfo.attachToProject(project);
|
||||
|
||||
// newInfo.open(existingText);
|
||||
// // ^ flag the info as open again, so that a (re)compilation happens and any
|
||||
// // existing syntax errors actually show up
|
||||
|
||||
// // project.getSourceFile(info.fileName as any);
|
||||
// }
|
||||
// }
|
||||
|
||||
return new SyndicateLanguageService(createInfo.languageService);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue