Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(feat) watch tsconfig and extended tsconfig #1535

Merged
merged 7 commits into from Jun 26, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -13,23 +13,28 @@ import {
} from './service';
import { GlobalSnapshotsManager, SnapshotManager } from './SnapshotManager';

export class LSAndTSDocResolver {
interface LSAndTSDocResolverOptions {
notifyExceedSizeLimit?: () => void;
/**
* True, if used in the context of svelte-check
*/
isSvelteCheck?: boolean;

/**
*
* @param docManager
* @param workspaceUris
* @param configManager
* @param notifyExceedSizeLimit
* @param isSvelteCheck True, if used in the context of svelte-check
* @param tsconfigPath This should only be set via svelte-check. Makes sure all documents are resolved to that tsconfig. Has to be absolute.
* This should only be set via svelte-check. Makes sure all documents are resolved to that tsconfig. Has to be absolute.
*/
tsconfigPath?: string;

onProjectReloaded?: () => void;
watchTsConfig?: boolean;
}

export class LSAndTSDocResolver {
constructor(
private readonly docManager: DocumentManager,
private readonly workspaceUris: string[],
private readonly configManager: LSConfigManager,
private readonly notifyExceedSizeLimit?: () => void,
private readonly isSvelteCheck = false,
private readonly tsconfigPath?: string
private readonly options?: LSAndTSDocResolverOptions
) {
const handleDocumentChange = (document: Document) => {
// This refreshes the document in the ts language service
Expand Down Expand Up @@ -65,15 +70,20 @@ export class LSAndTSDocResolver {
};

private globalSnapshotsManager = new GlobalSnapshotsManager();
private extendedConfigCache = new Map<string, ts.ExtendedConfigCacheEntry>();

private get lsDocumentContext(): LanguageServiceDocumentContext {
return {
ambientTypesSource: this.isSvelteCheck ? 'svelte-check' : 'svelte2tsx',
ambientTypesSource: this.options?.isSvelteCheck ? 'svelte-check' : 'svelte2tsx',
createDocument: this.createDocument,
useNewTransformation: this.configManager.getConfig().svelte.useNewTransformation,
transformOnTemplateError: !this.isSvelteCheck,
transformOnTemplateError: !this.options?.isSvelteCheck,
globalSnapshotsManager: this.globalSnapshotsManager,
notifyExceedSizeLimit: this.notifyExceedSizeLimit
notifyExceedSizeLimit: this.options?.notifyExceedSizeLimit,
extendedConfigCache: this.extendedConfigCache,
onProjectReloaded: this.options?.onProjectReloaded,
watchTsConfig: !!this.options?.watchTsConfig,
tsSystem: ts.sys
};
}

Expand Down Expand Up @@ -157,8 +167,8 @@ export class LSAndTSDocResolver {
}

async getTSService(filePath?: string): Promise<LanguageServiceContainer> {
if (this.tsconfigPath) {
return getServiceForTsconfig(this.tsconfigPath, this.lsDocumentContext);
if (this.options?.tsconfigPath) {
return getServiceForTsconfig(this.options?.tsconfigPath, this.lsDocumentContext);
}
if (!filePath) {
throw new Error('Cannot call getTSService without filePath and without tsconfigPath');
Expand Down
39 changes: 26 additions & 13 deletions packages/language-server/src/plugins/typescript/SnapshotManager.ts
Expand Up @@ -5,6 +5,8 @@ import { TextDocumentContentChangeEvent } from 'vscode-languageserver';
import { normalizePath } from '../../utils';
import { EventEmitter } from 'events';

type SnapshotChangeHandler = (fileName: string, newDocument: DocumentSnapshot | undefined) => void;

/**
* Every snapshot corresponds to a unique file on disk.
* A snapshot can be part of multiple projects, but for a given file path
Expand Down Expand Up @@ -60,9 +62,13 @@ export class GlobalSnapshotsManager {
}
}

onChange(listener: (fileName: string, newDocument: DocumentSnapshot | undefined) => void) {
onChange(listener: SnapshotChangeHandler) {
this.emitter.on('change', listener);
}

removeChangeListener(listener: SnapshotChangeHandler) {
this.emitter.off('change', listener);
}
}

export interface TsFilesSpec {
Expand Down Expand Up @@ -92,18 +98,21 @@ export class SnapshotManager {
private fileSpec: TsFilesSpec,
private workspaceRoot: string
) {
this.globalSnapshotsManager.onChange((fileName, document) => {
// Only delete/update snapshots, don't add new ones,
// as they could be from another TS service and this
// snapshot manager can't reach this file.
// For these, instead wait on a `get` method invocation
// and set them "manually" in the set/update methods.
if (!document) {
this.documents.delete(fileName);
} else if (this.documents.has(fileName)) {
this.documents.set(fileName, document);
}
});
this.onSnapshotChange = this.onSnapshotChange.bind(this);
this.globalSnapshotsManager.onChange(this.onSnapshotChange);
}

private onSnapshotChange(fileName: string, document: DocumentSnapshot | undefined) {
// Only delete/update snapshots, don't add new ones,
// as they could be from another TS service and this
// snapshot manager can't reach this file.
// For these, instead wait on a `get` method invocation
// and set them "manually" in the set/update methods.
if (!document) {
this.documents.delete(fileName);
} else if (this.documents.has(fileName)) {
this.documents.set(fileName, document);
}
}

updateProjectFiles(): void {
Expand Down Expand Up @@ -191,6 +200,10 @@ export class SnapshotManager {
);
}
}

dispose() {
this.globalSnapshotsManager.removeChangeListener(this.onSnapshotChange);
}
}

export const ignoredBuildDirectories = ['__sapper__', '.svelte-kit'];