diff --git a/package.json b/package.json index 793a32730..6e450086d 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ }, "devDependencies": { "cross-env": "^7.0.2", - "prettier": "~3.2.5", + "prettier": "~3.3.3", "ts-node": "^10.0.0" }, "packageManager": "pnpm@9.3.0" diff --git a/packages/language-server/.gitignore b/packages/language-server/.gitignore index 5dbbc7fbb..02c400bc6 100644 --- a/packages/language-server/.gitignore +++ b/packages/language-server/.gitignore @@ -1,3 +1,4 @@ dist/ .vscode/ node_modules/ +!test/plugins/typescript/features/diagnostics/fixtures/exports-map-svelte/node_modules/ \ No newline at end of file diff --git a/packages/language-server/package.json b/packages/language-server/package.json index 680e21419..2963ffe11 100644 --- a/packages/language-server/package.json +++ b/packages/language-server/package.json @@ -1,11 +1,16 @@ { "name": "svelte-language-server", - "version": "0.16.0", + "version": "0.17.0", "description": "A language server for Svelte", "main": "dist/src/index.js", "typings": "dist/src/index", + "exports": { + "./package.json": "./package.json", + ".": "./dist/src/index.js", + "./bin/server.js": "./bin/server.js" + }, "scripts": { - "test": "cross-env TS_NODE_TRANSPILE_ONLY=true mocha --require ts-node/register \"test/**/*.ts\" --exclude \"test/**/*.d.ts\"", + "test": "cross-env TS_NODE_TRANSPILE_ONLY=true mocha --require ts-node/register \"test/**/*.test.ts\"", "build": "tsc", "prepublishOnly": "npm run build", "watch": "tsc -w" @@ -31,14 +36,13 @@ }, "homepage": "https://github.com/sveltejs/language-tools#readme", "engines": { - "node": ">= 12.0.0" + "node": ">= 18.0.0" }, "devDependencies": { "@types/estree": "^0.0.42", "@types/lodash": "^4.14.116", "@types/mocha": "^9.1.0", - "@types/node": "^16.0.0", - "@types/prettier": "^2.2.3", + "@types/node": "^18.0.0", "@types/sinon": "^7.5.2", "cross-env": "^7.0.2", "mocha": "^9.2.0", @@ -46,23 +50,23 @@ "ts-node": "^10.0.0" }, "dependencies": { - "@jridgewell/trace-mapping": "^0.3.17", + "@jridgewell/trace-mapping": "^0.3.25", "@vscode/emmet-helper": "2.8.4", - "chokidar": "^3.4.1", + "chokidar": "^4.0.1", "estree-walker": "^2.0.1", - "fast-glob": "^3.2.7", + "fdir": "^6.2.0", "lodash": "^4.17.21", - "prettier": "~3.2.5", - "prettier-plugin-svelte": "^3.2.2", - "svelte": "^3.57.0", + "prettier": "~3.3.3", + "prettier-plugin-svelte": "^3.2.6", + "svelte": "^4.2.19", "svelte2tsx": "workspace:~", "typescript": "^5.5.2", "typescript-auto-import-cache": "^0.3.3", "vscode-css-languageservice": "~6.3.0", "vscode-html-languageservice": "~5.3.0", - "vscode-languageserver": "8.0.2", - "vscode-languageserver-protocol": "3.17.2", - "vscode-languageserver-types": "3.17.2", + "vscode-languageserver": "9.0.1", + "vscode-languageserver-protocol": "3.17.5", + "vscode-languageserver-types": "3.17.5", "vscode-uri": "~3.0.0" } } diff --git a/packages/language-server/src/importPackage.ts b/packages/language-server/src/importPackage.ts index 41e040762..7386a6c95 100644 --- a/packages/language-server/src/importPackage.ts +++ b/packages/language-server/src/importPackage.ts @@ -63,14 +63,6 @@ export function importSvelte(fromPath: string): typeof svelte { Logger.debug('Using Svelte v' + pkg.version.full, 'from', main); if (pkg.version.major === 4) { return dynamicRequire(main + '.cjs'); - } else if (pkg.version.major === 5) { - // TODO remove once Svelte 5 is released - // (we switched from compiler.cjs to compiler/index.js at some point) - try { - return dynamicRequire(main); - } catch (e) { - return dynamicRequire(main + '.cjs'); - } } else { return dynamicRequire(main); } diff --git a/packages/language-server/src/lib/FallbackWatcher.ts b/packages/language-server/src/lib/FallbackWatcher.ts index 81ec47349..4af7e71ff 100644 --- a/packages/language-server/src/lib/FallbackWatcher.ts +++ b/packages/language-server/src/lib/FallbackWatcher.ts @@ -25,12 +25,7 @@ export class FallbackWatcher { this.watcher = watch( workspacePaths.map((workspacePath) => join(workspacePath, recursivePatterns)), { - ignored: (path: string) => - gitOrNodeModules.test(path) && - // Handle Sapper's alias mapping - !path.includes('src/node_modules') && - !path.includes('src\\node_modules'), - + ignored: gitOrNodeModules, // typescript would scan the project files on init. // We only need to know what got updated. ignoreInitial: true, diff --git a/packages/language-server/src/lib/documents/configLoader.ts b/packages/language-server/src/lib/documents/configLoader.ts index 4d7e583c6..49413a6f8 100644 --- a/packages/language-server/src/lib/documents/configLoader.ts +++ b/packages/language-server/src/lib/documents/configLoader.ts @@ -4,7 +4,7 @@ import { CompileOptions } from 'svelte/types/compiler/interfaces'; // @ts-ignore import { PreprocessorGroup } from 'svelte/types/compiler/preprocess'; import { importSveltePreprocess } from '../../importPackage'; -import _glob from 'fast-glob'; +import { fdir } from 'fdir'; import _path from 'path'; import _fs from 'fs'; import { pathToFileURL, URL } from 'url'; @@ -47,6 +47,8 @@ const _dynamicImport = new Function('modulePath', 'return import(modulePath)') a modulePath: URL ) => Promise; +const configRegex = /\/svelte\.config\.(js|cjs|mjs)$/; + /** * Loads svelte.config.{js,cjs,mjs} files. Provides both a synchronous and asynchronous * interface to get a config file because snapshots need access to it synchronously. @@ -61,7 +63,7 @@ export class ConfigLoader { private disabled = false; constructor( - private globSync: typeof _glob.sync, + private globSync: typeof fdir, private fs: Pick, private path: Pick, private dynamicImport: typeof _dynamicImport @@ -84,12 +86,19 @@ export class ConfigLoader { Logger.log('Trying to load configs for', directory); try { - const pathResults = this.globSync('**/svelte.config.{js,cjs,mjs}', { - cwd: directory, - // the second pattern is necessary because else fast-glob treats .tmp/../node_modules/.. as a valid match for some reason - ignore: ['**/node_modules/**', '**/.*/**'], - onlyFiles: true - }); + const pathResults = new this.globSync({}) + .withPathSeparator('/') + .exclude((_, path) => { + // no / at the start, path could start with node_modules + return path.includes('node_modules/') || path.includes('/.') || path[0] === '.'; + }) + .filter((path, isDir) => { + return !isDir && configRegex.test(path); + }) + .withRelativePaths() + .crawl(directory) + .sync(); + const someConfigIsImmediateFileInDirectory = pathResults.length > 0 && pathResults.some((res) => !this.path.dirname(res)); if (!someConfigIsImmediateFileInDirectory) { @@ -296,4 +305,4 @@ export class ConfigLoader { } } -export const configLoader = new ConfigLoader(_glob.sync, _fs, _path, _dynamicImport); +export const configLoader = new ConfigLoader(fdir, _fs, _path, _dynamicImport); diff --git a/packages/language-server/src/lib/documents/utils.ts b/packages/language-server/src/lib/documents/utils.ts index 5ab0fcac4..ff8b4c016 100644 --- a/packages/language-server/src/lib/documents/utils.ts +++ b/packages/language-server/src/lib/documents/utils.ts @@ -143,8 +143,12 @@ export function extractScriptTags( return null; } - const script = scripts.find((s) => s.attributes['context'] !== 'module'); - const moduleScript = scripts.find((s) => s.attributes['context'] === 'module'); + const script = scripts.find( + (s) => s.attributes['context'] !== 'module' && !('module' in s.attributes) + ); + const moduleScript = scripts.find( + (s) => s.attributes['context'] === 'module' || 'module' in s.attributes + ); return { script, moduleScript }; } diff --git a/packages/language-server/src/ls-config.ts b/packages/language-server/src/ls-config.ts index 39e098ab3..63389e7bb 100644 --- a/packages/language-server/src/ls-config.ts +++ b/packages/language-server/src/ls-config.ts @@ -478,16 +478,25 @@ export class LSConfigManager { }; } - getTsUserPreferences(lang: TsUserConfigLang, workspacePath: string | null): ts.UserPreferences { + getTsUserPreferences( + lang: TsUserConfigLang, + normalizedWorkspacePath: string | null + ): ts.UserPreferences { const userPreferences = this.tsUserPreferences[lang]; - if (!workspacePath || !userPreferences.autoImportFileExcludePatterns) { + if (!normalizedWorkspacePath || !userPreferences.autoImportFileExcludePatterns) { return userPreferences; } - let autoImportFileExcludePatterns = this.resolvedAutoImportExcludeCache.get(workspacePath); + let autoImportFileExcludePatterns = + this.resolvedAutoImportExcludeCache.get(normalizedWorkspacePath); if (!autoImportFileExcludePatterns) { + const version = ts.version.split('.'); + const major = parseInt(version[0]); + const minor = parseInt(version[1]); + + const gte5_4 = major > 5 || (major === 5 && minor >= 4); autoImportFileExcludePatterns = userPreferences.autoImportFileExcludePatterns.map( (p) => { // Normalization rules: https://github.com/microsoft/TypeScript/pull/49578 @@ -497,17 +506,20 @@ export class LSConfigManager { return p; } - return path.join( - workspacePath, - p.startsWith('*') - ? '/' + slashNormalized - : isRelative - ? p - : '/**/' + slashNormalized - ); + // https://github.com/microsoft/vscode/pull/202762 + // ts 5.4+ supports leading wildcards + const wildcardPrefix = gte5_4 ? '' : path.parse(normalizedWorkspacePath).root; + return p.startsWith('*') + ? wildcardPrefix + slashNormalized + : isRelative + ? path.join(normalizedWorkspacePath, p) + : wildcardPrefix + '**/' + slashNormalized; } ); - this.resolvedAutoImportExcludeCache.set(workspacePath, autoImportFileExcludePatterns); + this.resolvedAutoImportExcludeCache.set( + normalizedWorkspacePath, + autoImportFileExcludePatterns + ); } return { diff --git a/packages/language-server/src/plugins/typescript/DocumentSnapshot.ts b/packages/language-server/src/plugins/typescript/DocumentSnapshot.ts index 00c902554..aaf2a11e6 100644 --- a/packages/language-server/src/plugins/typescript/DocumentSnapshot.ts +++ b/packages/language-server/src/plugins/typescript/DocumentSnapshot.ts @@ -109,7 +109,7 @@ export namespace DocumentSnapshot { tsSystem: ts.System ) { if (isSvelteFilePath(filePath)) { - return DocumentSnapshot.fromSvelteFilePath(filePath, createDocument, options); + return DocumentSnapshot.fromSvelteFilePath(filePath, createDocument, options, tsSystem); } else { return DocumentSnapshot.fromNonSvelteFilePath(filePath, tsSystem); } @@ -173,9 +173,10 @@ export namespace DocumentSnapshot { export function fromSvelteFilePath( filePath: string, createDocument: (filePath: string, text: string) => Document, - options: SvelteSnapshotOptions + options: SvelteSnapshotOptions, + tsSystem: ts.System ) { - const originalText = ts.sys.readFile(filePath) ?? ''; + const originalText = tsSystem.readFile(filePath) ?? ''; return fromDocument(createDocument(filePath, originalText), options); } } diff --git a/packages/language-server/src/plugins/typescript/LSAndTSDocResolver.ts b/packages/language-server/src/plugins/typescript/LSAndTSDocResolver.ts index 3843e8a89..3b0a76c06 100644 --- a/packages/language-server/src/plugins/typescript/LSAndTSDocResolver.ts +++ b/packages/language-server/src/plugins/typescript/LSAndTSDocResolver.ts @@ -1,6 +1,10 @@ import { dirname, join } from 'path'; import ts from 'typescript'; -import { RelativePattern, TextDocumentContentChangeEvent } from 'vscode-languageserver'; +import { + PublishDiagnosticsParams, + RelativePattern, + TextDocumentContentChangeEvent +} from 'vscode-languageserver'; import { Document, DocumentManager } from '../../lib/documents'; import { LSConfigManager } from '../../ls-config'; import { @@ -37,6 +41,7 @@ interface LSAndTSDocResolverOptions { tsconfigPath?: string; onProjectReloaded?: () => void; + reportConfigError?: (diagnostic: PublishDiagnosticsParams) => void; watch?: boolean; tsSystem?: ts.System; watchDirectory?: (patterns: RelativePattern[]) => void; @@ -50,14 +55,10 @@ export class LSAndTSDocResolver { private readonly configManager: LSConfigManager, private readonly options?: LSAndTSDocResolverOptions ) { - const handleDocumentChange = (document: Document) => { - // This refreshes the document in the ts language service - this.getSnapshot(document); - }; docManager.on( 'documentChange', debounceSameArg( - handleDocumentChange, + this.updateSnapshot.bind(this), (newDoc, prevDoc) => newDoc.uri === prevDoc?.uri, 1000 ) @@ -68,7 +69,11 @@ export class LSAndTSDocResolver { // where multiple files and their dependencies // being loaded in a short period of times docManager.on('documentOpen', (document) => { - handleDocumentChange(document); + if (document.openedByClient) { + this.getOrCreateSnapshot(document); + } else { + this.updateSnapshot(document); + } docManager.lockDocument(document.uri); }); @@ -121,7 +126,8 @@ export class LSAndTSDocResolver { watchDirectory: this.options?.watchDirectory ? this.watchDirectory.bind(this) : undefined, - nonRecursiveWatchPattern: this.options?.nonRecursiveWatchPattern + nonRecursiveWatchPattern: this.options?.nonRecursiveWatchPattern, + reportConfigError: this.options?.reportConfigError }; } @@ -151,18 +157,20 @@ export class LSAndTSDocResolver { private lsDocumentContext: LanguageServiceDocumentContext; private readonly watchedDirectories: FileSet; - async getLSForPath(path: string) { - return (await this.getTSService(path)).getService(); - } - async getLSAndTSDoc(document: Document): Promise<{ tsDoc: SvelteDocumentSnapshot; lang: ts.LanguageService; userPreferences: ts.UserPreferences; + lsContainer: LanguageServiceContainer; }> { const { tsDoc, lsContainer, userPreferences } = await this.getLSAndTSDocWorker(document); - return { tsDoc, lang: lsContainer.getService(), userPreferences }; + return { + tsDoc, + lang: lsContainer.getService(), + userPreferences, + lsContainer + }; } /** @@ -181,7 +189,7 @@ export class LSAndTSDocResolver { private async getLSAndTSDocWorker(document: Document) { const lsContainer = await this.getTSService(document.getFilePath() || ''); - const tsDoc = await this.getSnapshot(document); + const tsDoc = await this.getOrCreateSnapshot(document); const userPreferences = this.getUserPreferences(tsDoc); return { tsDoc, lsContainer, userPreferences }; @@ -192,13 +200,21 @@ export class LSAndTSDocResolver { * the ts service it primarily belongs into. * The update is mirrored in all other services, too. */ - async getSnapshot(document: Document): Promise; - async getSnapshot(pathOrDoc: string | Document): Promise; - async getSnapshot(pathOrDoc: string | Document) { + async getOrCreateSnapshot(document: Document): Promise; + async getOrCreateSnapshot(pathOrDoc: string | Document): Promise; + async getOrCreateSnapshot(pathOrDoc: string | Document) { const filePath = typeof pathOrDoc === 'string' ? pathOrDoc : pathOrDoc.getFilePath() || ''; const tsService = await this.getTSService(filePath); return tsService.updateSnapshot(pathOrDoc); } + private async updateSnapshot(document: Document) { + const filePath = document.getFilePath(); + if (!filePath) { + return; + } + // ensure no new service is created + await this.updateExistingFile(filePath, (service) => service.updateSnapshot(document)); + } /** * Updates snapshot path in all existing ts services and retrieves snapshot @@ -217,7 +233,7 @@ export class LSAndTSDocResolver { }); } else { // This may not be a file but a directory, still try - await this.getSnapshot(newPath); + await this.getOrCreateSnapshot(newPath); } } @@ -280,19 +296,11 @@ export class LSAndTSDocResolver { }); } - /** - * @internal Public for tests only - */ - async getSnapshotManager(filePath: string): Promise { - return (await this.getTSService(filePath)).snapshotManager; - } - async getTSService(filePath?: string): Promise { if (this.options?.tsconfigPath) { - return getServiceForTsconfig( - this.options?.tsconfigPath, - dirname(this.options.tsconfigPath), - this.lsDocumentContext + return this.getTSServiceByConfigPath( + this.options.tsconfigPath, + dirname(this.options.tsconfigPath) ); } if (!filePath) { @@ -301,6 +309,13 @@ export class LSAndTSDocResolver { return getService(filePath, this.workspaceUris, this.lsDocumentContext); } + async getTSServiceByConfigPath( + tsconfigPath: string, + workspacePath: string + ): Promise { + return getServiceForTsconfig(tsconfigPath, workspacePath, this.lsDocumentContext); + } + private getUserPreferences(tsDoc: DocumentSnapshot): ts.UserPreferences { const configLang = tsDoc.scriptKind === ts.ScriptKind.TS || tsDoc.scriptKind === ts.ScriptKind.TSX diff --git a/packages/language-server/src/plugins/typescript/SnapshotManager.ts b/packages/language-server/src/plugins/typescript/SnapshotManager.ts index 6bf64f0b6..85b152e49 100644 --- a/packages/language-server/src/plugins/typescript/SnapshotManager.ts +++ b/packages/language-server/src/plugins/typescript/SnapshotManager.ts @@ -262,6 +262,11 @@ export class SnapshotManager { return Array.from(this.projectFileToOriginalCasing.values()); } + isProjectFile(fileName: string): boolean { + fileName = normalizePath(fileName); + return this.projectFileToOriginalCasing.has(this.getCanonicalFileName(fileName)); + } + private logStatistics() { const date = new Date(); // Don't use setInterval because that will keep tests running forever diff --git a/packages/language-server/src/plugins/typescript/TypeScriptPlugin.ts b/packages/language-server/src/plugins/typescript/TypeScriptPlugin.ts index bc97f6175..264fe6665 100644 --- a/packages/language-server/src/plugins/typescript/TypeScriptPlugin.ts +++ b/packages/language-server/src/plugins/typescript/TypeScriptPlugin.ts @@ -168,7 +168,10 @@ export class TypeScriptPlugin this.completionProvider, configManager ); - this.updateImportsProvider = new UpdateImportsProviderImpl(this.lsAndTsDocResolver); + this.updateImportsProvider = new UpdateImportsProviderImpl( + this.lsAndTsDocResolver, + ts.sys.useCaseSensitiveFileNames + ); this.diagnosticsProvider = new DiagnosticsProviderImpl( this.lsAndTsDocResolver, configManager @@ -383,7 +386,7 @@ export class TypeScriptPlugin } async getDefinitions(document: Document, position: Position): Promise { - const { lang, tsDoc } = await this.lsAndTsDocResolver.getLSAndTSDoc(document); + const { lang, tsDoc, lsContainer } = await this.lsAndTsDocResolver.getLSAndTSDoc(document); const defs = lang.getDefinitionAndBoundSpan( tsDoc.filePath, @@ -394,7 +397,7 @@ export class TypeScriptPlugin return []; } - const snapshots = new SnapshotMap(this.lsAndTsDocResolver); + const snapshots = new SnapshotMap(this.lsAndTsDocResolver, lsContainer); snapshots.set(tsDoc.filePath, tsDoc); const result = await Promise.all( diff --git a/packages/language-server/src/plugins/typescript/features/CallHierarchyProvider.ts b/packages/language-server/src/plugins/typescript/features/CallHierarchyProvider.ts index b58e797a2..2151038b9 100644 --- a/packages/language-server/src/plugins/typescript/features/CallHierarchyProvider.ts +++ b/packages/language-server/src/plugins/typescript/features/CallHierarchyProvider.ts @@ -41,7 +41,7 @@ export class CallHierarchyProviderImpl implements CallHierarchyProvider { position: Position, cancellationToken?: CancellationToken ): Promise { - const { lang, tsDoc } = await this.lsAndTsDocResolver.getLSAndTSDoc(document); + const { lang, tsDoc, lsContainer } = await this.lsAndTsDocResolver.getLSAndTSDoc(document); if (cancellationToken?.isCancellationRequested) { return null; @@ -52,7 +52,7 @@ export class CallHierarchyProviderImpl implements CallHierarchyProvider { const itemsArray = Array.isArray(items) ? items : items ? [items] : []; - const snapshots = new SnapshotMap(this.lsAndTsDocResolver); + const snapshots = new SnapshotMap(this.lsAndTsDocResolver, lsContainer); snapshots.set(tsDoc.filePath, tsDoc); const program = lang.getProgram(); @@ -213,7 +213,7 @@ export class CallHierarchyProviderImpl implements CallHierarchyProvider { .provideCallHierarchyOutgoingCalls(filePath, offset) .concat( isComponentModulePosition - ? this.getOutgoingCallsForComponent(program, filePath) ?? [] + ? (this.getOutgoingCallsForComponent(program, filePath) ?? []) : [] ); @@ -251,8 +251,9 @@ export class CallHierarchyProviderImpl implements CallHierarchyProvider { return null; } - const lang = await this.lsAndTsDocResolver.getLSForPath(filePath); - const tsDoc = await this.lsAndTsDocResolver.getSnapshot(filePath); + const lsContainer = await this.lsAndTsDocResolver.getTSService(filePath); + const lang = lsContainer.getService(); + const tsDoc = await this.lsAndTsDocResolver.getOrCreateSnapshot(filePath); if (cancellationToken?.isCancellationRequested) { return null; @@ -260,7 +261,7 @@ export class CallHierarchyProviderImpl implements CallHierarchyProvider { const program = lang.getProgram(); - const snapshots = new SnapshotMap(this.lsAndTsDocResolver); + const snapshots = new SnapshotMap(this.lsAndTsDocResolver, lsContainer); snapshots.set(tsDoc.filePath, tsDoc); const isComponentModulePosition = diff --git a/packages/language-server/src/plugins/typescript/features/CodeActionsProvider.ts b/packages/language-server/src/plugins/typescript/features/CodeActionsProvider.ts index 287f21664..c114fc4b6 100644 --- a/packages/language-server/src/plugins/typescript/features/CodeActionsProvider.ts +++ b/packages/language-server/src/plugins/typescript/features/CodeActionsProvider.ts @@ -46,7 +46,6 @@ import { import { CompletionsProviderImpl } from './CompletionProvider'; import { findClosestContainingNode, - findContainingNode, FormatCodeBasis, getFormatCodeBasis, getNewScriptStartTag, @@ -56,6 +55,7 @@ import { } from './utils'; import { DiagnosticCode } from './DiagnosticsProvider'; import { createGetCanonicalFileName } from '../../../utils'; +import { LanguageServiceContainer } from '../service'; /** * TODO change this to protocol constant if it's part of the protocol @@ -156,7 +156,7 @@ export class CodeActionsProviderImpl implements CodeActionsProvider { return codeAction; } - const { lang, tsDoc, userPreferences } = + const { lang, tsDoc, userPreferences, lsContainer } = await this.lsAndTsDocResolver.getLSAndTSDoc(document); if (cancellationToken?.isCancellationRequested) { return codeAction; @@ -180,10 +180,11 @@ export class CodeActionsProviderImpl implements CodeActionsProvider { const isImportFix = codeAction.data.fixName === FIX_IMPORT_FIX_NAME; const virtualDocInfo = isImportFix - ? await this.createVirtualDocumentForCombinedImportCodeFix( + ? this.createVirtualDocumentForCombinedImportCodeFix( document, getDiagnostics(), tsDoc, + lsContainer, lang ) : undefined; @@ -218,7 +219,7 @@ export class CodeActionsProviderImpl implements CodeActionsProvider { await this.lsAndTsDocResolver.deleteSnapshot(virtualDocPath); } - const snapshots = new SnapshotMap(this.lsAndTsDocResolver); + const snapshots = new SnapshotMap(this.lsAndTsDocResolver, lsContainer); const fixActions: ts.CodeFixAction[] = [ { fixName: codeAction.data.fixName, @@ -259,10 +260,11 @@ export class CodeActionsProviderImpl implements CodeActionsProvider { * Do not use this in regular code action * This'll cause TypeScript to rebuild and invalidate caches every time. It'll be slow */ - private async createVirtualDocumentForCombinedImportCodeFix( + private createVirtualDocumentForCombinedImportCodeFix( document: Document, diagnostics: Diagnostic[], tsDoc: DocumentSnapshot, + lsContainer: LanguageServiceContainer, lang: ts.LanguageService ) { const virtualUri = document.uri + '.__virtual__.svelte'; @@ -314,10 +316,8 @@ export class CodeActionsProviderImpl implements CodeActionsProvider { const virtualDoc = new Document(virtualUri, newText); virtualDoc.openedByClient = true; // let typescript know about the virtual document - // getLSAndTSDoc instead of getSnapshot so that project dirty state is correctly tracked by us - // otherwise, sometime the applied code fix might not be picked up by the language service - // because we think the project is still dirty and doesn't update the project version - await this.lsAndTsDocResolver.getLSAndTSDoc(virtualDoc); + lsContainer.openVirtualDocument(virtualDoc); + lsContainer.getService(); return { virtualDoc, @@ -553,7 +553,7 @@ export class CodeActionsProviderImpl implements CodeActionsProvider { context: CodeActionContext, cancellationToken: CancellationToken | undefined ) { - const { lang, tsDoc, userPreferences } = await this.getLSAndTSDoc(document); + const { lang, tsDoc, userPreferences, lsContainer } = await this.getLSAndTSDoc(document); if (cancellationToken?.isCancellationRequested) { return []; @@ -613,7 +613,7 @@ export class CodeActionsProviderImpl implements CodeActionsProvider { ); } - const snapshots = new SnapshotMap(this.lsAndTsDocResolver); + const snapshots = new SnapshotMap(this.lsAndTsDocResolver, lsContainer); snapshots.set(tsDoc.filePath, tsDoc); const codeActionsPromises = codeFixes.map(async (fix) => { @@ -1471,7 +1471,7 @@ export class CodeActionsProviderImpl implements CodeActionsProvider { const position = inModuleScript ? originalRange.start - : this.fixPropsCodeActionRange(originalRange.start, document) ?? originalRange.start; + : (this.fixPropsCodeActionRange(originalRange.start, document) ?? originalRange.start); // fix the length of trailing indent const linesOfNewText = edit.newText.split('\n'); diff --git a/packages/language-server/src/plugins/typescript/features/CompletionProvider.ts b/packages/language-server/src/plugins/typescript/features/CompletionProvider.ts index ffb044938..e7b5bec75 100644 --- a/packages/language-server/src/plugins/typescript/features/CompletionProvider.ts +++ b/packages/language-server/src/plugins/typescript/features/CompletionProvider.ts @@ -49,6 +49,7 @@ import { isPartOfImportStatement } from './utils'; import { isInTag as svelteIsInTag } from '../svelte-ast-utils'; +import { LanguageServiceContainer } from '../service'; export interface CompletionResolveInfo extends Pick, @@ -170,7 +171,7 @@ export class CompletionsProviderImpl implements CompletionsProvider 0 ? [] - : await this.getCustomElementCompletions(lang, document, tsDoc, position); + : this.getCustomElementCompletions(lang, lsContainer, document, tsDoc, position); const formatSettings = await this.configManager.getFormatCodeSettingsForFile( document, @@ -474,12 +475,13 @@ export class CompletionsProviderImpl implements CompletionsProvider { + ): CompletionItem[] | undefined { const offset = document.offsetAt(position); const tag = getNodeIfIsInHTMLStartTag(document.html, offset); @@ -499,9 +501,7 @@ export class CompletionsProviderImpl implements CompletionsProvider ref.definition.kind === ts.ScriptElementKind.alias)) { @@ -124,7 +124,7 @@ export class FindReferencesProviderImpl implements FindReferencesProvider { let storeReferences: ts.ReferencedSymbolEntry[] = []; const storeReference = references.find( (ref) => - ref.fileName === tsDoc.filePath && + normalizePath(ref.fileName) === tsDoc.filePath && isTextSpanInGeneratedCode(tsDoc.getFullText(), ref.textSpan) && is$storeVariableIn$storeDeclaration(tsDoc.getFullText(), ref.textSpan.start) ); diff --git a/packages/language-server/src/plugins/typescript/features/ImplementationProvider.ts b/packages/language-server/src/plugins/typescript/features/ImplementationProvider.ts index e4a91c1bb..693afaa49 100644 --- a/packages/language-server/src/plugins/typescript/features/ImplementationProvider.ts +++ b/packages/language-server/src/plugins/typescript/features/ImplementationProvider.ts @@ -18,7 +18,7 @@ export class ImplementationProviderImpl implements ImplementationProvider { position: Position, cancellationToken?: CancellationToken ): Promise { - const { tsDoc, lang } = await this.lsAndTsDocResolver.getLSAndTSDoc(document); + const { tsDoc, lang, lsContainer } = await this.lsAndTsDocResolver.getLSAndTSDoc(document); if (cancellationToken?.isCancellationRequested) { return null; @@ -27,7 +27,7 @@ export class ImplementationProviderImpl implements ImplementationProvider { const offset = tsDoc.offsetAt(tsDoc.getGeneratedPosition(position)); const implementations = lang.getImplementationAtPosition(tsDoc.filePath, offset); - const snapshots = new SnapshotMap(this.lsAndTsDocResolver); + const snapshots = new SnapshotMap(this.lsAndTsDocResolver, lsContainer); snapshots.set(tsDoc.filePath, tsDoc); if (!implementations) { diff --git a/packages/language-server/src/plugins/typescript/features/InlayHintProvider.ts b/packages/language-server/src/plugins/typescript/features/InlayHintProvider.ts index 9ca919900..7db6f9f82 100644 --- a/packages/language-server/src/plugins/typescript/features/InlayHintProvider.ts +++ b/packages/language-server/src/plugins/typescript/features/InlayHintProvider.ts @@ -1,4 +1,4 @@ -import ts from 'typescript'; +import ts, { ArrowFunction } from 'typescript'; import { CancellationToken } from 'vscode-languageserver'; import { Position, @@ -41,7 +41,7 @@ export class InlayHintProviderImpl implements InlayHintProvider { return null; } - const { tsDoc, lang } = await this.lsAndTsDocResolver.getLSAndTSDoc(document); + const { tsDoc, lang, lsContainer } = await this.lsAndTsDocResolver.getLSAndTSDoc(document); const inlayHints = lang.provideInlayHints( tsDoc.filePath, @@ -59,7 +59,7 @@ export class InlayHintProviderImpl implements InlayHintProvider { const renderFunctionReturnTypeLocation = renderFunction && this.getTypeAnnotationPosition(renderFunction); - const snapshotMap = new SnapshotMap(this.lsAndTsDocResolver); + const snapshotMap = new SnapshotMap(this.lsAndTsDocResolver, lsContainer); snapshotMap.set(tsDoc.filePath, tsDoc); const convertPromises = inlayHints @@ -69,6 +69,7 @@ export class InlayHintProviderImpl implements InlayHintProvider { inlayHint.position !== renderFunctionReturnTypeLocation && !this.isSvelte2tsxFunctionHints(sourceFile, inlayHint) && !this.isGeneratedVariableTypeHint(sourceFile, inlayHint) && + !this.isGeneratedAsyncFunctionReturnType(sourceFile, inlayHint) && !this.isGeneratedFunctionReturnType(sourceFile, inlayHint) ) .map(async (inlayHint) => ({ @@ -254,6 +255,29 @@ export class InlayHintProviderImpl implements InlayHintProvider { ); } + /** `true` if is one of the `async () => {...}` functions svelte2tsx generates */ + private isGeneratedAsyncFunctionReturnType(sourceFile: ts.SourceFile, inlayHint: ts.InlayHint) { + if (inlayHint.kind !== ts.InlayHintKind.Type) { + return false; + } + + const expression = findContainingNode( + sourceFile, + { start: inlayHint.position, length: 0 }, + (node): node is ArrowFunction => ts.isArrowFunction(node) + ); + + if ( + !expression?.modifiers?.some((m) => m.kind === ts.SyntaxKind.AsyncKeyword) || + !expression.parent?.parent || + !ts.isBlock(expression.parent.parent) + ) { + return false; + } + + return this.getTypeAnnotationPosition(expression) === inlayHint.position; + } + private isGeneratedFunctionReturnType(sourceFile: ts.SourceFile, inlayHint: ts.InlayHint) { if (inlayHint.kind !== ts.InlayHintKind.Type) { return false; diff --git a/packages/language-server/src/plugins/typescript/features/RenameProvider.ts b/packages/language-server/src/plugins/typescript/features/RenameProvider.ts index 281ae659f..3b9caf86e 100644 --- a/packages/language-server/src/plugins/typescript/features/RenameProvider.ts +++ b/packages/language-server/src/plugins/typescript/features/RenameProvider.ts @@ -65,7 +65,7 @@ export class RenameProviderImpl implements RenameProvider { position: Position, newName: string ): Promise { - const { lang, tsDoc } = await this.getLSAndTSDoc(document); + const { lang, tsDoc, lsContainer } = await this.getLSAndTSDoc(document); const offset = tsDoc.offsetAt(tsDoc.getGeneratedPosition(position)); @@ -85,7 +85,7 @@ export class RenameProviderImpl implements RenameProvider { return null; } - const docs = new SnapshotMap(this.lsAndTsDocResolver); + const docs = new SnapshotMap(this.lsAndTsDocResolver, lsContainer); docs.set(tsDoc.filePath, tsDoc); let convertedRenameLocations: TsRenameLocation[] = await this.mapAndFilterRenameLocations( @@ -536,7 +536,7 @@ export class RenameProviderImpl implements RenameProvider { } private getSnapshot(filePath: string) { - return this.lsAndTsDocResolver.getSnapshot(filePath); + return this.lsAndTsDocResolver.getOrCreateSnapshot(filePath); } private checkShortHandBindingOrSlotLetLocation( diff --git a/packages/language-server/src/plugins/typescript/features/SemanticTokensProvider.ts b/packages/language-server/src/plugins/typescript/features/SemanticTokensProvider.ts index 9af4f4239..2103371f2 100644 --- a/packages/language-server/src/plugins/typescript/features/SemanticTokensProvider.ts +++ b/packages/language-server/src/plugins/typescript/features/SemanticTokensProvider.ts @@ -66,29 +66,23 @@ export class SemanticTokensProviderImpl implements SemanticTokensProvider { continue; } - const originalPosition = this.mapToOrigin( + const original = this.map( textDocument, tsDoc, generatedOffset, generatedLength, - encodedClassification + encodedClassification, + classificationType ); - if (!originalPosition) { - continue; - } - - const [line, character, length] = originalPosition; // remove identifiers whose start and end mapped to the same location, // like the svelte2tsx inserted render function, // or reversed like Component.$on - if (length <= 0) { + if (!original || original[2] <= 0) { continue; } - const modifier = this.getTokenModifierFromClassification(encodedClassification); - - data.push([line, character, length, classificationType, modifier]); + data.push(original); } const sorted = data.sort((a, b) => { @@ -103,17 +97,20 @@ export class SemanticTokensProviderImpl implements SemanticTokensProvider { return builder.build(); } - private mapToOrigin( + private map( document: Document, snapshot: SvelteDocumentSnapshot, generatedOffset: number, generatedLength: number, - token: number - ): [line: number, character: number, length: number, start: number] | undefined { + encodedClassification: number, + classificationType: number + ): + | [line: number, character: number, length: number, token: number, modifier: number] + | undefined { const text = snapshot.getFullText(); if ( isInGeneratedCode(text, generatedOffset, generatedOffset + generatedLength) || - (token === 2817 /* top level function */ && + (encodedClassification === 2817 /* top level function */ && text.substring(generatedOffset, generatedOffset + generatedLength) === 'render') ) { return; @@ -132,7 +129,26 @@ export class SemanticTokensProviderImpl implements SemanticTokensProvider { const startOffset = document.offsetAt(startPosition); const endOffset = document.offsetAt(endPosition); - return [startPosition.line, startPosition.character, endOffset - startOffset, startOffset]; + // Ensure components in the template get no semantic highlighting + if ( + (classificationType === 0 || + classificationType === 5 || + classificationType === 7 || + classificationType === 10) && + snapshot.svelteNodeAt(startOffset)?.type === 'InlineComponent' && + (document.getText().charCodeAt(startOffset - 1) === /* < */ 60 || + document.getText().charCodeAt(startOffset - 1) === /* / */ 47) + ) { + return; + } + + return [ + startPosition.line, + startPosition.character, + endOffset - startOffset, + classificationType, + this.getTokenModifierFromClassification(encodedClassification) + ]; } /** diff --git a/packages/language-server/src/plugins/typescript/features/TypeDefinitionProvider.ts b/packages/language-server/src/plugins/typescript/features/TypeDefinitionProvider.ts index 93674fd9e..3c2ecf625 100644 --- a/packages/language-server/src/plugins/typescript/features/TypeDefinitionProvider.ts +++ b/packages/language-server/src/plugins/typescript/features/TypeDefinitionProvider.ts @@ -10,11 +10,11 @@ export class TypeDefinitionProviderImpl implements TypeDefinitionProvider { constructor(private readonly lsAndTsDocResolver: LSAndTSDocResolver) {} async getTypeDefinition(document: Document, position: Position): Promise { - const { tsDoc, lang } = await this.lsAndTsDocResolver.getLSAndTSDoc(document); + const { tsDoc, lang, lsContainer } = await this.lsAndTsDocResolver.getLSAndTSDoc(document); const offset = tsDoc.offsetAt(tsDoc.getGeneratedPosition(position)); const typeDefs = lang.getTypeDefinitionAtPosition(tsDoc.filePath, offset); - const snapshots = new SnapshotMap(this.lsAndTsDocResolver); + const snapshots = new SnapshotMap(this.lsAndTsDocResolver, lsContainer); snapshots.set(tsDoc.filePath, tsDoc); if (!typeDefs) { diff --git a/packages/language-server/src/plugins/typescript/features/UpdateImportsProvider.ts b/packages/language-server/src/plugins/typescript/features/UpdateImportsProvider.ts index aa46594ff..54aa9a060 100644 --- a/packages/language-server/src/plugins/typescript/features/UpdateImportsProvider.ts +++ b/packages/language-server/src/plugins/typescript/features/UpdateImportsProvider.ts @@ -6,14 +6,27 @@ import { WorkspaceEdit } from 'vscode-languageserver'; import { mapRangeToOriginal } from '../../../lib/documents'; -import { urlToPath } from '../../../utils'; +import { + createGetCanonicalFileName, + GetCanonicalFileName, + normalizePath, + urlToPath +} from '../../../utils'; import { FileRename, UpdateImportsProvider } from '../../interfaces'; import { LSAndTSDocResolver } from '../LSAndTSDocResolver'; +import { forAllServices, LanguageServiceContainer } from '../service'; import { convertRange } from '../utils'; import { isKitTypePath, SnapshotMap } from './utils'; export class UpdateImportsProviderImpl implements UpdateImportsProvider { - constructor(private readonly lsAndTsDocResolver: LSAndTSDocResolver) {} + constructor( + private readonly lsAndTsDocResolver: LSAndTSDocResolver, + useCaseSensitiveFileNames: boolean + ) { + this.getCanonicalFileName = createGetCanonicalFileName(useCaseSensitiveFileNames); + } + + private getCanonicalFileName: GetCanonicalFileName; async updateImports(fileRename: FileRename): Promise { // TODO does this handle folder moves/renames correctly? old/new path isn't a file then @@ -23,7 +36,47 @@ export class UpdateImportsProviderImpl implements UpdateImportsProvider { return null; } - const ls = await this.getLSForPath(newPath); + const services: LanguageServiceContainer[] = []; + await forAllServices((ls) => { + services.push(ls); + }); + + const documentChanges = new Map(); + for (const service of services) { + await this.updateImportForSingleService(oldPath, newPath, service, documentChanges); + } + + return { + documentChanges: Array.from(documentChanges.values()) + }; + } + + async updateImportForSingleService( + oldPath: string, + newPath: string, + lsContainer: LanguageServiceContainer, + documentChanges: Map + ) { + const ls = lsContainer.getService(); + const program = ls.getProgram(); + if (!program) { + return; + } + + const canonicalOldPath = this.getCanonicalFileName(normalizePath(oldPath)); + const canonicalNewPath = this.getCanonicalFileName(normalizePath(newPath)); + const hasFile = program.getSourceFiles().some((sf) => { + const normalizedFileName = this.getCanonicalFileName(normalizePath(sf.fileName)); + return ( + normalizedFileName.startsWith(canonicalOldPath) || + normalizedFileName.startsWith(canonicalNewPath) + ); + }); + + if (!hasFile) { + return; + } + const oldPathTsProgramCasing = ls.getProgram()?.getSourceFile(oldPath)?.fileName ?? oldPath; // `getEditsForFileRename` might take a while const fileChanges = ls @@ -75,12 +128,15 @@ export class UpdateImportsProviderImpl implements UpdateImportsProvider { return change; }); - const docs = new SnapshotMap(this.lsAndTsDocResolver); - const documentChanges = await Promise.all( + const docs = new SnapshotMap(this.lsAndTsDocResolver, lsContainer); + await Promise.all( updateImportsChanges.map(async (change) => { + if (documentChanges.has(change.fileName)) { + return; + } const snapshot = await docs.retrieve(change.fileName); - return TextDocumentEdit.create( + const edit = TextDocumentEdit.create( OptionalVersionedTextDocumentIdentifier.create(snapshot.getURL(), null), change.textChanges.map((edit) => { const range = mapRangeToOriginal( @@ -90,13 +146,9 @@ export class UpdateImportsProviderImpl implements UpdateImportsProvider { return TextEdit.replace(range, edit.newText); }) ); + + documentChanges.set(change.fileName, edit); }) ); - - return { documentChanges }; - } - - private async getLSForPath(path: string) { - return this.lsAndTsDocResolver.getLSForPath(path); } } diff --git a/packages/language-server/src/plugins/typescript/features/utils.ts b/packages/language-server/src/plugins/typescript/features/utils.ts index f8ee48a21..dba13177a 100644 --- a/packages/language-server/src/plugins/typescript/features/utils.ts +++ b/packages/language-server/src/plugins/typescript/features/utils.ts @@ -12,6 +12,7 @@ import { LSAndTSDocResolver } from '../LSAndTSDocResolver'; import { or } from '../../../utils'; import { FileMap } from '../../../lib/documents/fileCollection'; import { LSConfig } from '../../../ls-config'; +import { LanguageServiceContainer } from '../service'; type NodePredicate = (node: ts.Node) => boolean; @@ -144,7 +145,10 @@ export function getStoreOffsetOf$storeDeclaration(text: string, $storeVarStart: export class SnapshotMap { private map = new FileMap(); - constructor(private resolver: LSAndTSDocResolver) {} + constructor( + private resolver: LSAndTSDocResolver, + private sourceLs: LanguageServiceContainer + ) {} set(fileName: string, snapshot: DocumentSnapshot) { this.map.set(fileName, snapshot); @@ -156,12 +160,18 @@ export class SnapshotMap { async retrieve(fileName: string) { let snapshot = this.get(fileName); - if (!snapshot) { - const snap = await this.resolver.getSnapshot(fileName); - this.set(fileName, snap); - snapshot = snap; + if (snapshot) { + return snapshot; } - return snapshot; + + const snap = + this.sourceLs.snapshotManager.get(fileName) ?? + // should not happen in most cases, + // the file should be in the project otherwise why would we know about it + (await this.resolver.getOrCreateSnapshot(fileName)); + + this.set(fileName, snap); + return snap; } } diff --git a/packages/language-server/src/plugins/typescript/module-loader.ts b/packages/language-server/src/plugins/typescript/module-loader.ts index 91e59827b..4cbde00b8 100644 --- a/packages/language-server/src/plugins/typescript/module-loader.ts +++ b/packages/language-server/src/plugins/typescript/module-loader.ts @@ -104,7 +104,7 @@ class ImpliedNodeFormatResolver { return undefined; } - let mode = undefined; + let mode: ReturnType = undefined; if (sourceFile) { this.cacheImpliedNodeFormat(sourceFile, compilerOptions); mode = ts.getModeForResolutionAtIndex(sourceFile, importIdxInFile, compilerOptions); @@ -166,7 +166,8 @@ export function createSvelteModuleLoader( getSnapshot: (fileName: string) => DocumentSnapshot, compilerOptions: ts.CompilerOptions, tsSystem: ts.System, - tsModule: typeof ts + tsModule: typeof ts, + getModuleResolutionHost: () => ts.ModuleResolutionHost | undefined ) { const getCanonicalFileName = createGetCanonicalFileName(tsSystem.useCaseSensitiveFileNames); const svelteSys = createSvelteSys(tsSystem); @@ -206,9 +207,16 @@ export function createSvelteModuleLoader( const previousTriedButFailed = failedPathToContainingFile.get(path); - for (const containingFile of previousTriedButFailed ?? []) { + if (!previousTriedButFailed) { + return; + } + + for (const containingFile of previousTriedButFailed) { failedLocationInvalidated.add(containingFile); } + + tsModuleCache.clear(); + typeReferenceCache.clear(); }, resolveModuleNames, resolveTypeReferenceDirectiveReferences, @@ -221,8 +229,8 @@ export function createSvelteModuleLoader( moduleNames: string[], containingFile: string, _reusedNames: string[] | undefined, - _redirectedReference: ts.ResolvedProjectReference | undefined, - _options: ts.CompilerOptions, + redirectedReference: ts.ResolvedProjectReference | undefined, + options: ts.CompilerOptions, containingSourceFile?: ts.SourceFile | undefined ): Array { return moduleNames.map((moduleName, index) => { @@ -234,7 +242,9 @@ export function createSvelteModuleLoader( moduleName, containingFile, containingSourceFile, - index + index, + redirectedReference, + options ); resolvedModule?.failedLookupLocations?.forEach((failedLocation) => { @@ -252,60 +262,44 @@ export function createSvelteModuleLoader( name: string, containingFile: string, containingSourceFile: ts.SourceFile | undefined, - index: number + index: number, + redirectedReference: ts.ResolvedProjectReference | undefined, + option: ts.CompilerOptions ): ts.ResolvedModuleWithFailedLookupLocations { - const mode = impliedNodeFormatResolver.resolve( - name, - index, - containingSourceFile, - compilerOptions - ); - // Delegate to the TS resolver first. - // If that does not bring up anything, try the Svelte Module loader - // which is able to deal with .svelte files. - const tsResolvedModuleWithFailedLookup = tsModule.resolveModuleName( + const mode = impliedNodeFormatResolver.resolve(name, index, containingSourceFile, option); + const resolvedModuleWithFailedLookup = tsModule.resolveModuleName( name, containingFile, compilerOptions, - tsSystem, + getModuleResolutionHost() ?? svelteSys, tsModuleCache, - undefined, + redirectedReference, mode ); - const tsResolvedModule = tsResolvedModuleWithFailedLookup.resolvedModule; - if (tsResolvedModule) { - return tsResolvedModuleWithFailedLookup; + const resolvedModule = resolvedModuleWithFailedLookup.resolvedModule; + + if (!resolvedModule || !isVirtualSvelteFilePath(resolvedModule.resolvedFileName)) { + return resolvedModuleWithFailedLookup; } - const svelteResolvedModuleWithFailedLookup = tsModule.resolveModuleName( - name, - containingFile, - compilerOptions, - svelteSys, - undefined, - undefined, - mode + const resolvedFileName = svelteSys.getRealSveltePathIfExists( + resolvedModule.resolvedFileName ); - const svelteResolvedModule = svelteResolvedModuleWithFailedLookup.resolvedModule; - if ( - !svelteResolvedModule || - !isVirtualSvelteFilePath(svelteResolvedModule.resolvedFileName) - ) { - return svelteResolvedModuleWithFailedLookup; + if (!isSvelteFilePath(resolvedFileName)) { + return resolvedModuleWithFailedLookup; } - const resolvedFileName = ensureRealSvelteFilePath(svelteResolvedModule.resolvedFileName); const snapshot = getSnapshot(resolvedFileName); const resolvedSvelteModule: ts.ResolvedModuleFull = { extension: getExtensionFromScriptKind(snapshot && snapshot.scriptKind), resolvedFileName, - isExternalLibraryImport: svelteResolvedModule.isExternalLibraryImport + isExternalLibraryImport: resolvedModule.isExternalLibraryImport }; return { - ...svelteResolvedModuleWithFailedLookup, + ...resolvedModuleWithFailedLookup, resolvedModule: resolvedSvelteModule }; } diff --git a/packages/language-server/src/plugins/typescript/service.ts b/packages/language-server/src/plugins/typescript/service.ts index fa2fe0c2b..caf8f0350 100644 --- a/packages/language-server/src/plugins/typescript/service.ts +++ b/packages/language-server/src/plugins/typescript/service.ts @@ -1,19 +1,26 @@ -import { basename, dirname, join, resolve } from 'path'; +import { dirname, join, resolve, basename } from 'path'; import ts from 'typescript'; -import { RelativePattern, TextDocumentContentChangeEvent } from 'vscode-languageserver-protocol'; +import { + DiagnosticSeverity, + PublishDiagnosticsParams, + RelativePattern, + TextDocumentContentChangeEvent +} from 'vscode-languageserver-protocol'; import { getPackageInfo, importSvelte } from '../../importPackage'; import { Document } from '../../lib/documents'; import { configLoader } from '../../lib/documents/configLoader'; import { FileMap, FileSet } from '../../lib/documents/fileCollection'; import { Logger } from '../../logger'; -import { createGetCanonicalFileName, normalizePath, pathToUrl, urlToPath } from '../../utils'; +import { + createGetCanonicalFileName, + isNotNullOrUndefined, + normalizePath, + pathToUrl, + urlToPath +} from '../../utils'; import { DocumentSnapshot, SvelteSnapshotOptions } from './DocumentSnapshot'; import { createSvelteModuleLoader } from './module-loader'; -import { - GlobalSnapshotsManager, - ignoredBuildDirectories, - SnapshotManager -} from './SnapshotManager'; +import { GlobalSnapshotsManager, SnapshotManager } from './SnapshotManager'; import { ensureRealSvelteFilePath, findTsConfigPath, @@ -27,15 +34,13 @@ export interface LanguageServiceContainer { readonly tsconfigPath: string; readonly compilerOptions: ts.CompilerOptions; readonly configErrors: ts.Diagnostic[]; - /** - * @internal Public for tests only - */ readonly snapshotManager: SnapshotManager; getService(skipSynchronize?: boolean): ts.LanguageService; updateSnapshot(documentOrFilePath: Document | string): DocumentSnapshot; deleteSnapshot(filePath: string): void; invalidateModuleCache(filePath: string[]): void; scheduleProjectFileUpdate(watcherNewFiles: string[]): void; + ensureProjectFileUpdates(newFile?: string): void; updateTsOrJsFile(fileName: string, changes?: TextDocumentContentChangeEvent[]): void; /** * Checks if a file is present in the project. @@ -50,7 +55,9 @@ export interface LanguageServiceContainer { onAutoImportProviderSettingsChanged(): void; onPackageJsonChange(packageJsonPath: string): void; getTsConfigSvelteOptions(): { namespace: string }; - + getResolvedProjectReferences(): TsConfigInfo[]; + openVirtualDocument(document: Document): void; + isShimFiles(filePath: string): boolean; dispose(): void; } @@ -63,7 +70,12 @@ declare module 'typescript' { */ hasInvalidatedResolutions?: (sourceFile: string) => boolean; + /** + * @internal + */ getModuleResolutionCache?(): ts.ModuleResolutionCache; + /** @internal */ + setCompilerHost?(host: ts.CompilerHost): void; } interface ResolvedModuleWithFailedLookupLocations { @@ -82,17 +94,30 @@ declare module 'typescript' { } } +export interface TsConfigInfo { + parsedCommandLine: ts.ParsedCommandLine; + snapshotManager: SnapshotManager; + pendingProjectFileUpdate: boolean; + configFilePath: string; + extendedConfigPaths?: Set; +} + +enum TsconfigSvelteDiagnostics { + NO_SVELTE_INPUT = 100_001 +} + const maxProgramSizeForNonTsFiles = 20 * 1024 * 1024; // 20 MB const services = new FileMap>(); const serviceSizeMap = new FileMap(); const configWatchers = new FileMap(); -const extendedConfigWatchers = new FileMap(); -const extendedConfigToTsConfigPath = new FileMap(); +const dependedConfigWatchers = new FileMap(); +const configPathToDependedProject = new FileMap(); const configFileModifiedTime = new FileMap(); const configFileForOpenFiles = new FileMap(); const pendingReloads = new FileSet(); const documentRegistries = new Map(); const pendingForAllServices = new Set>(); +const parsedTsConfigInfo = new FileMap(); /** * For testing only: Reset the cache for services. @@ -101,6 +126,7 @@ const pendingForAllServices = new Set>(); */ export function __resetCache() { services.clear(); + parsedTsConfigInfo.clear(); serviceSizeMap.clear(); configFileForOpenFiles.clear(); } @@ -112,7 +138,8 @@ export interface LanguageServiceDocumentContext { globalSnapshotsManager: GlobalSnapshotsManager; notifyExceedSizeLimit: (() => void) | undefined; extendedConfigCache: Map; - onProjectReloaded: (() => void) | undefined; + onProjectReloaded: ((configFileNames: string[]) => void) | undefined; + reportConfigError: ((diagnostics: PublishDiagnosticsParams) => void) | undefined; watchTsConfig: boolean; tsSystem: ts.System; projectService: ProjectService | undefined; @@ -129,13 +156,46 @@ export async function getService( docContext.tsSystem.useCaseSensitiveFileNames ); - const tsconfigPath = + const fileExistsWithCache = (fileName: string) => { + return ( + (parsedTsConfigInfo.has(fileName) && !pendingReloads.has(fileName)) || + docContext.tsSystem.fileExists(fileName) + ); + }; + + let tsconfigPath = configFileForOpenFiles.get(path) ?? - findTsConfigPath(path, workspaceUris, docContext.tsSystem.fileExists, getCanonicalFileName); + findTsConfigPath(path, workspaceUris, fileExistsWithCache, getCanonicalFileName); if (tsconfigPath) { - configFileForOpenFiles.set(path, tsconfigPath); - return getServiceForTsconfig(tsconfigPath, dirname(tsconfigPath), docContext); + /** + * Prevent infinite loop when the project reference is circular + */ + const triedTsConfig = new Set(); + const needAssign = !configFileForOpenFiles.has(path); + let service = await getConfiguredService(tsconfigPath); + if (!needAssign) { + return service; + } + + // First try to find a service whose includes config matches our file + const defaultService = await findDefaultServiceForFile(service, triedTsConfig); + if (defaultService) { + configFileForOpenFiles.set(path, defaultService.tsconfigPath); + return defaultService; + } + + // If no such service found, see if the file is part of any existing service indirectly. + // This can happen if the includes doesn't match the file but it was imported from one of the included files. + for (const configPath of triedTsConfig) { + const service = await getConfiguredService(configPath); + const ls = service.getService(); + if (ls.getProgram()?.getSourceFile(path)) { + return service; + } + } + + tsconfigPath = ''; } // Find closer boundary: workspace uri or node_modules @@ -156,6 +216,57 @@ export async function getService( docContext.tsSystem.getCurrentDirectory(), docContext ); + + function getConfiguredService(tsconfigPath: string) { + return getServiceForTsconfig(tsconfigPath, dirname(tsconfigPath), docContext); + } + + async function findDefaultServiceForFile( + service: LanguageServiceContainer, + triedTsConfig: Set + ): Promise { + service.ensureProjectFileUpdates(path); + if (service.snapshotManager.isProjectFile(path)) { + return service; + } + if (triedTsConfig.has(service.tsconfigPath)) { + return; + } + + triedTsConfig.add(service.tsconfigPath); + + // TODO: maybe add support for ts 5.6's ancestor searching + return findDefaultFromProjectReferences(service, triedTsConfig); + } + + async function findDefaultFromProjectReferences( + service: LanguageServiceContainer, + triedTsConfig: Set + ) { + const projectReferences = service.getResolvedProjectReferences(); + if (projectReferences.length === 0) { + return undefined; + } + + let possibleSubPaths: string[] = []; + for (const ref of projectReferences) { + if (ref.snapshotManager.isProjectFile(path)) { + return getConfiguredService(ref.configFilePath); + } + + if (ref.parsedCommandLine.projectReferences?.length) { + possibleSubPaths.push(ref.configFilePath); + } + } + + for (const ref of possibleSubPaths) { + const subService = await getConfiguredService(ref); + const defaultService = await findDefaultServiceForFile(subService, triedTsConfig); + if (defaultService) { + return defaultService; + } + } + } } export async function forAllServices( @@ -182,6 +293,9 @@ export async function getServiceForTsconfig( workspacePath: string, docContext: LanguageServiceDocumentContext ): Promise { + if (tsconfigPath) { + tsconfigPath = normalizePath(tsconfigPath); + } const tsconfigPathOrWorkspacePath = tsconfigPath || workspacePath; const reloading = pendingReloads.has(tsconfigPath); @@ -190,6 +304,7 @@ export async function getServiceForTsconfig( if (reloading || !services.has(tsconfigPathOrWorkspacePath)) { if (reloading) { Logger.log('Reloading ts service at ', tsconfigPath, ' due to config updated'); + parsedTsConfigInfo.delete(tsconfigPath); } else { Logger.log('Initialize new ts service at ', tsconfigPath); } @@ -216,36 +331,33 @@ async function createLanguageService( ): Promise { const { tsSystem } = docContext; - const { - options: compilerOptions, - errors: configErrors, - fileNames: files, - raw, - extendedConfigPaths, - wildcardDirectories - } = getParsedConfig(); + const projectConfig = getParsedConfig(); + const { options: compilerOptions, raw, errors: configErrors } = projectConfig; + const allowJs = compilerOptions.allowJs ?? !!compilerOptions.checkJs; + const virtualDocuments = new FileMap(tsSystem.useCaseSensitiveFileNames); const getCanonicalFileName = createGetCanonicalFileName(tsSystem.useCaseSensitiveFileNames); - watchWildCardDirectories(); - - // raw is the tsconfig merged with extending config - // see: https://github.com/microsoft/TypeScript/blob/08e4f369fbb2a5f0c30dee973618d65e6f7f09f8/src/compiler/commandLineParser.ts#L2537 - const snapshotManager = new SnapshotManager( - docContext.globalSnapshotsManager, - raw, - workspacePath, - tsSystem, - files, - wildcardDirectories - ); + watchWildCardDirectories(projectConfig); + + const snapshotManager = createSnapshotManager(projectConfig, tsconfigPath); // Load all configs within the tsconfig scope and the one above so that they are all loaded // by the time they need to be accessed synchronously by DocumentSnapshots. await configLoader.loadConfigs(workspacePath); - const svelteModuleLoader = createSvelteModuleLoader(getSnapshot, compilerOptions, tsSystem, ts); + const svelteModuleLoader = createSvelteModuleLoader( + getSnapshot, + compilerOptions, + tsSystem, + ts, + () => host?.getCompilerHost?.() + ); let svelteTsPath: string; + /** + * set and clear during program creation, shouldn't not be cached elsewhere + */ + let compilerHost: ts.CompilerHost | undefined; try { // For when svelte2tsx/svelte-check is part of node_modules, for example VS Code extension svelteTsPath = dirname(require.resolve(docContext.ambientTypesSource)); @@ -262,27 +374,13 @@ async function createLanguageService( ? importSvelte(tsconfigPath || workspacePath) : undefined; - const isSvelte3 = sveltePackageInfo.version.major === 3; - const svelteHtmlDeclaration = isSvelte3 - ? undefined - : join(sveltePackageInfo.path, 'svelte-html.d.ts'); - const svelteHtmlFallbackIfNotExist = - svelteHtmlDeclaration && tsSystem.fileExists(svelteHtmlDeclaration) - ? svelteHtmlDeclaration - : './svelte-jsx-v4.d.ts'; - const changedFilesForExportCache = new Set(); - - const svelteTsxFiles = ( - isSvelte3 - ? ['./svelte-shims.d.ts', './svelte-jsx.d.ts', './svelte-native-jsx.d.ts'] - : ['./svelte-shims-v4.d.ts', svelteHtmlFallbackIfNotExist, './svelte-native-jsx.d.ts'] - ).map((f) => tsSystem.resolvePath(resolve(svelteTsPath, f))); + const svelteTsxFiles = getSvelteShimFiles(); let languageServiceReducedMode = false; let projectVersion = 0; - let dirty = false; - let pendingProjectFileUpdate = false; + let dirty = projectConfig.fileNames.length > 0; + let skipSvelteInputCheck = !tsconfigPath; const host: ts.LanguageServiceHost = { log: (message) => Logger.debug(`[ts] ${message}`), @@ -297,7 +395,10 @@ async function createLanguageService( readFile: svelteModuleLoader.readFile, resolveModuleNames: svelteModuleLoader.resolveModuleNames, readDirectory: svelteModuleLoader.readDirectory, + realpath: tsSystem.realpath, getDirectories: tsSystem.getDirectories, + getProjectReferences: () => projectConfig.projectReferences, + getParsedCommandLine, useCaseSensitiveFileNames: () => tsSystem.useCaseSensitiveFileNames, getScriptKind: (fileName: string) => getSnapshot(fileName).scriptKind, getProjectVersion: () => projectVersion.toString(), @@ -305,11 +406,17 @@ async function createLanguageService( resolveTypeReferenceDirectiveReferences: svelteModuleLoader.resolveTypeReferenceDirectiveReferences, hasInvalidatedResolutions: svelteModuleLoader.mightHaveInvalidatedResolutions, - getModuleResolutionCache: svelteModuleLoader.getModuleResolutionCache + getModuleResolutionCache: svelteModuleLoader.getModuleResolutionCache, + useSourceOfProjectReferenceRedirect() { + return !languageServiceReducedMode; + }, + setCompilerHost: (host) => (compilerHost = host), + getCompilerHost: () => compilerHost }; const documentRegistry = getOrCreateDocumentRegistry( - host.getCurrentDirectory(), + // this should mostly be a singleton while host.getCurrentDirectory() might be the directory where the tsconfig is + tsSystem.getCurrentDirectory(), tsSystem.useCaseSensitiveFileNames ); @@ -326,8 +433,7 @@ async function createLanguageService( docContext.globalSnapshotsManager.onChange(scheduleUpdate); reduceLanguageServiceCapabilityIfFileSizeTooBig(); - updateExtendedConfigDependents(); - watchConfigFile(); + watchConfigFiles(projectConfig.extendedConfigPaths, projectConfig); return { tsconfigPath, @@ -338,6 +444,7 @@ async function createLanguageService( deleteSnapshot, scheduleProjectFileUpdate, updateTsOrJsFile, + ensureProjectFileUpdates, hasFile, fileBelongsToProject, snapshotManager, @@ -345,10 +452,34 @@ async function createLanguageService( onAutoImportProviderSettingsChanged, onPackageJsonChange, getTsConfigSvelteOptions, + getResolvedProjectReferences, + openVirtualDocument, + isShimFiles, dispose }; - function watchWildCardDirectories() { + function createSnapshotManager( + parsedCommandLine: ts.ParsedCommandLine, + configFileName: string + ) { + const cached = configFileName ? parsedTsConfigInfo.get(configFileName) : undefined; + if (cached?.snapshotManager) { + return cached.snapshotManager; + } + // raw is the tsconfig merged with extending config + // see: https://github.com/microsoft/TypeScript/blob/08e4f369fbb2a5f0c30dee973618d65e6f7f09f8/src/compiler/commandLineParser.ts#L2537 + return new SnapshotManager( + docContext.globalSnapshotsManager, + parsedCommandLine.raw, + configFileName ? dirname(configFileName) : workspacePath, + tsSystem, + parsedCommandLine.fileNames.map(normalizePath), + parsedCommandLine.wildcardDirectories + ); + } + + function watchWildCardDirectories(parseCommandLine: ts.ParsedCommandLine) { + const { wildcardDirectories } = parseCommandLine; if (!wildcardDirectories || !docContext.watchDirectory) { return; } @@ -376,10 +507,8 @@ async function createLanguageService( } function getService(skipSynchronize?: boolean) { - if (pendingProjectFileUpdate) { - updateProjectFiles(); - pendingProjectFileUpdate = false; - } + ensureProjectFileUpdates(); + if (!skipSynchronize) { updateIfDirty(); } @@ -411,16 +540,29 @@ async function createLanguageService( function updateSnapshotFromDocument(document: Document): DocumentSnapshot { const filePath = document.getFilePath() || ''; const prevSnapshot = snapshotManager.get(filePath); - if (prevSnapshot?.version === document.version) { + + if ( + prevSnapshot?.version === document.version && + // In the test, there might be a new document instance with a different openedByClient + // In that case, Create a new snapshot otherwise the getClientFileNames won't include the new client file + prevSnapshot.isOpenedInClient() === document.openedByClient + ) { return prevSnapshot; } + const newSnapshot = DocumentSnapshot.fromDocument(document, transformationConfig); + if (!prevSnapshot) { svelteModuleLoader.deleteUnresolvedResolutionsFromCache(filePath); + if (configFileForOpenFiles.get(filePath) === '' && services.size > 1) { + configFileForOpenFiles.delete(filePath); + } + } else if (prevSnapshot.scriptKind !== newSnapshot.scriptKind && !allowJs) { + // if allowJs is false, we need to invalid the cache so that js svelte files can be loaded through module resolution + svelteModuleLoader.deleteFromModuleCache(filePath); + configFileForOpenFiles.delete(filePath); } - const newSnapshot = DocumentSnapshot.fromDocument(document, transformationConfig); - snapshotManager.set(filePath, newSnapshot); return newSnapshot; @@ -481,17 +623,52 @@ async function createLanguageService( } function scheduleProjectFileUpdate(watcherNewFiles: string[]): void { - if (snapshotManager.areIgnoredFromNewFileWatch(watcherNewFiles)) { - return; + if (!snapshotManager.areIgnoredFromNewFileWatch(watcherNewFiles)) { + scheduleUpdate(); + const info = parsedTsConfigInfo.get(tsconfigPath); + if (info) { + info.pendingProjectFileUpdate = true; + } } - scheduleUpdate(); - pendingProjectFileUpdate = true; + if (!projectConfig.projectReferences) { + return; + } + for (const ref of projectConfig.projectReferences) { + const config = parsedTsConfigInfo.get(ref.path); + if ( + config && + // handled by the respective service + !services.has(config.configFilePath) && + !config.snapshotManager.areIgnoredFromNewFileWatch(watcherNewFiles) + ) { + config.pendingProjectFileUpdate = true; + scheduleUpdate(); + } + } } - function updateProjectFiles(): void { + function ensureProjectFileUpdates(newFile?: string): void { + const info = parsedTsConfigInfo.get(tsconfigPath); + if (!info) { + return; + } + + if ( + newFile && + !info.pendingProjectFileUpdate && + // no global snapshots yet when initial load pending + !snapshotManager.isProjectFile(newFile) && + !docContext.globalSnapshotsManager.get(newFile) + ) { + scheduleProjectFileUpdate([newFile]); + } + + if (!info.pendingProjectFileUpdate) { + return; + } const projectFileCountBefore = snapshotManager.getProjectFileNames().length; - snapshotManager.updateProjectFiles(); + ensureFilesForConfigUpdates(info); const projectFileCountAfter = snapshotManager.getProjectFileNames().length; if (projectFileCountAfter > projectFileCountBefore) { @@ -505,14 +682,22 @@ async function createLanguageService( : snapshotManager.getProjectFileNames(); const canonicalProjectFileNames = new Set(projectFiles.map(getCanonicalFileName)); + // We only assign project files (i.e. those found through includes config) and virtual files to getScriptFileNames. + // We don't to include other client files otherwise they stay in the program and are never removed + const clientFiles = tsconfigPath + ? Array.from(virtualDocuments.values()) + .map((v) => v.getFilePath()) + .filter(isNotNullOrUndefined) + : snapshotManager.getClientFileNames(); + return Array.from( new Set([ ...projectFiles, // project file is read from the file system so it's more likely to have // the correct casing - ...snapshotManager - .getClientFileNames() - .filter((file) => !canonicalProjectFileNames.has(getCanonicalFileName(file))), + ...clientFiles.filter( + (file) => !canonicalProjectFileNames.has(getCanonicalFileName(file)) + ), ...svelteTsxFiles ]) ); @@ -535,72 +720,26 @@ async function createLanguageService( } function getParsedConfig() { - const forcedCompilerOptions: ts.CompilerOptions = { - allowNonTsExtensions: true, - target: ts.ScriptTarget.Latest, - allowJs: true, - noEmit: true, - declaration: false, - skipLibCheck: true - }; - - // always let ts parse config to get default compilerOption - let configJson = - (tsconfigPath && ts.readConfigFile(tsconfigPath, tsSystem.readFile).config) || - getDefaultJsConfig(); - - // Only default exclude when no extends for now - if (!configJson.extends) { - configJson = Object.assign( - { - exclude: getDefaultExclude() - }, - configJson - ); - } - - const extendedConfigPaths = new Set(); - const { extendedConfigCache } = docContext; - const cacheMonitorProxy = { - ...docContext.extendedConfigCache, - get(key: string) { - extendedConfigPaths.add(key); - return extendedConfigCache.get(key); - }, - has(key: string) { - extendedConfigPaths.add(key); - return extendedConfigCache.has(key); - }, - set(key: string, value: ts.ExtendedConfigCacheEntry) { - extendedConfigPaths.add(key); - return extendedConfigCache.set(key, value); + let compilerOptions: ts.CompilerOptions; + let parsedConfig: ts.ParsedCommandLine; + let extendedConfigPaths: Set | undefined; + + if (tsconfigPath) { + const info = ensureTsConfigInfoUpToDate(tsconfigPath); + // tsconfig is either found from file-system or passed from svelte-check + // so this is already be validated to exist + if (!info) { + throw new Error('Failed to get tsconfig: ' + tsconfigPath); } - }; - - const parsedConfig = ts.parseJsonConfigFileContent( - configJson, - tsSystem, - workspacePath, - forcedCompilerOptions, - tsconfigPath, - undefined, - [ - { - extension: 'svelte', - isMixedContent: true, - // Deferred was added in a later TS version, fall back to tsx - // If Deferred exists, this means that all Svelte files are included - // in parsedConfig.fileNames - scriptKind: ts.ScriptKind.Deferred ?? ts.ScriptKind.TS - } - ], - cacheMonitorProxy - ); + compilerOptions = info.parsedCommandLine.options; + parsedConfig = info.parsedCommandLine; + extendedConfigPaths = info.extendedConfigPaths; + } else { + const config = parseDefaultCompilerOptions(); + compilerOptions = config.compilerOptions; + parsedConfig = config.parsedConfig; + } - const compilerOptions: ts.CompilerOptions = { - ...parsedConfig.options, - ...forcedCompilerOptions - }; if ( !compilerOptions.moduleResolution || compilerOptions.moduleResolution === ts.ModuleResolutionKind.Classic @@ -609,6 +748,7 @@ async function createLanguageService( // NodeJS: up to 4.9, Node10: since 5.0 (ts.ModuleResolutionKind as any).NodeJs ?? ts.ModuleResolutionKind.Node10; } + if ( !compilerOptions.module || [ @@ -623,6 +763,12 @@ async function createLanguageService( compilerOptions.module = ts.ModuleKind.ESNext; } + if (!compilerOptions.target) { + compilerOptions.target = ts.ScriptTarget.Latest; + } else if (ts.ScriptTarget.ES2015 > compilerOptions.target) { + compilerOptions.target = ts.ScriptTarget.ES2015; + } + // detect which JSX namespace to use (svelte | svelteNative) if not specified or not compatible if (!compilerOptions.jsxFactory || !compilerOptions.jsxFactory.startsWith('svelte')) { //override if we detect svelte-native @@ -648,15 +794,53 @@ async function createLanguageService( }; } - /** - * This should only be used when there's no jsconfig/tsconfig at all - */ - function getDefaultJsConfig(): { - compilerOptions: ts.CompilerOptions; - include: string[]; - } { - return { + function checkSvelteInput(program: ts.Program | undefined, config: ts.ParsedCommandLine) { + if (!tsconfigPath || config.raw.references || config.raw.files) { + return []; + } + + const configFileName = basename(tsconfigPath); + // Only report to possible nearest config file since referenced project might not be a svelte project + if (configFileName !== 'tsconfig.json' && configFileName !== 'jsconfig.json') { + return []; + } + + const hasSvelteFiles = + config.fileNames.some(isSvelteFilePath) || + program?.getSourceFiles().some((file) => isSvelteFilePath(file.fileName)); + + if (hasSvelteFiles) { + return []; + } + + const { include, exclude } = config.raw; + const inputText = JSON.stringify(include); + const excludeText = JSON.stringify(exclude); + const svelteConfigDiagnostics: ts.Diagnostic[] = [ + { + category: ts.DiagnosticCategory.Warning, + code: TsconfigSvelteDiagnostics.NO_SVELTE_INPUT, + file: undefined, + start: undefined, + length: undefined, + messageText: + `No svelte input files were found in config file '${tsconfigPath}'. ` + + `Did you forget to add svelte files to the 'include' in your ${basename(tsconfigPath)}? ` + + `Specified 'include' paths were '${inputText}' and 'exclude' paths were '${excludeText}'`, + source: 'svelte' + } + ]; + + return svelteConfigDiagnostics; + } + + function parseDefaultCompilerOptions() { + let configJson = { compilerOptions: { + allowJs: true, + noEmit: true, + declaration: false, + skipLibCheck: true, maxNodeModuleJsDepth: 2, allowSyntheticDefaultImports: true }, @@ -664,10 +848,17 @@ async function createLanguageService( // with potentially completely unrelated .ts/.js files: include: [] }; - } - function getDefaultExclude() { - return ['node_modules', ...ignoredBuildDirectories]; + const parsedConfig = ts.parseJsonConfigFileContent(configJson, tsSystem, workspacePath); + + const compilerOptions: ts.CompilerOptions = { + ...parsedConfig.options, + target: ts.ScriptTarget.Latest, + allowNonTsExtensions: true, + moduleResolution: ts.ModuleResolutionKind.Node10 + }; + + return { compilerOptions, parsedConfig }; } /** @@ -694,6 +885,7 @@ async function createLanguageService( } function dispose() { + compilerHost = undefined; languageService.dispose(); snapshotManager.dispose(); configWatchers.get(tsconfigPath)?.close(); @@ -702,19 +894,23 @@ async function createLanguageService( docContext.globalSnapshotsManager.removeChangeListener(scheduleUpdate); } - function updateExtendedConfigDependents() { - extendedConfigPaths.forEach((extendedConfig) => { - let dependedTsConfig = extendedConfigToTsConfigPath.get(extendedConfig); + function watchConfigFiles( + extendedConfigPaths: Set | undefined, + parsedCommandLine: ts.ParsedCommandLine + ) { + const tsconfigDependencies = Array.from(extendedConfigPaths ?? []).concat( + parsedCommandLine.projectReferences?.map((r) => r.path) ?? [] + ); + tsconfigDependencies.forEach((configPath) => { + let dependedTsConfig = configPathToDependedProject.get(configPath); if (!dependedTsConfig) { dependedTsConfig = new FileSet(tsSystem.useCaseSensitiveFileNames); - extendedConfigToTsConfigPath.set(extendedConfig, dependedTsConfig); + configPathToDependedProject.set(configPath, dependedTsConfig); } dependedTsConfig.add(tsconfigPath); }); - } - function watchConfigFile() { if (!tsSystem.watchFile || !docContext.watchTsConfig) { return; } @@ -728,16 +924,16 @@ async function createLanguageService( ); } - for (const config of extendedConfigPaths) { - if (extendedConfigWatchers.has(config)) { + for (const config of tsconfigDependencies) { + if (dependedConfigWatchers.has(config)) { continue; } configFileModifiedTime.set(config, tsSystem.getModifiedTime?.(config)); - extendedConfigWatchers.set( + dependedConfigWatchers.set( config, // for some reason setting the polling interval is necessary, else some error in TS is thrown - tsSystem.watchFile(config, createWatchExtendedConfigCallback(docContext), 1000) + tsSystem.watchFile(config, createWatchDependedConfigCallback(docContext), 1000) ); } } @@ -763,7 +959,8 @@ async function createLanguageService( configFileForOpenFiles.clear(); } - docContext.onProjectReloaded?.(); + docContext.onProjectReloaded?.([fileName]); + docContext.reportConfigError?.({ uri: pathToUrl(fileName), diagnostics: [] }); } function updateIfDirty() { @@ -780,6 +977,30 @@ async function createLanguageService( } dirty = false; + compilerHost = undefined; + + if (!skipSvelteInputCheck) { + const svelteConfigDiagnostics = checkSvelteInput(program, projectConfig); + const codes = svelteConfigDiagnostics.map((d) => d.code); + if (!svelteConfigDiagnostics.length) { + // stop checking once it passed once + skipSvelteInputCheck = true; + } + // report even if empty to clear previous diagnostics + docContext.reportConfigError?.({ + uri: pathToUrl(tsconfigPath), + diagnostics: svelteConfigDiagnostics.map((d) => ({ + message: d.messageText as string, + range: { start: { line: 0, character: 0 }, end: { line: 0, character: 0 } }, + severity: DiagnosticSeverity.Warning, + source: 'svelte' + })) + }); + const new_errors = projectConfig.errors + .filter((e) => !codes.includes(e.code)) + .concat(svelteConfigDiagnostics); + projectConfig.errors.splice(0, projectConfig.errors.length, ...new_errors); + } // https://github.com/microsoft/TypeScript/blob/23faef92703556567ddbcb9afb893f4ba638fc20/src/server/project.ts#L1624 // host.getCachedExportInfoMap will create the cache if it doesn't exist @@ -791,6 +1012,9 @@ async function createLanguageService( } exportMapCache.releaseSymbols(); + // https://github.com/microsoft/TypeScript/blob/941d1543c201e40d87e63c9db04818493afdd9e7/src/server/project.ts#L1731 + // if one file change results in clearing the cache + // don't continue to check other files, this will mark the cache as usable while it's empty for (const fileName of changedFilesForExportCache) { const oldFile = oldProgram.getSourceFile(fileName); const newFile = program?.getSourceFile(fileName); @@ -800,11 +1024,15 @@ async function createLanguageService( continue; } - if (oldFile && newFile) { - exportMapCache.onFileChanged?.(oldFile, newFile, false); - } else { + if (!oldFile || !newFile) { // new file or deleted file exportMapCache.clear(); + break; + } + + const cleared = exportMapCache.onFileChanged?.(oldFile, newFile, false); + if (cleared) { + break; } } changedFilesForExportCache.clear(); @@ -875,6 +1103,142 @@ async function createLanguageService( namespace: transformationConfig.typingsNamespace }; } + + function ensureTsConfigInfoUpToDate(configFilePath: string) { + const cached = parsedTsConfigInfo.get(configFilePath); + if (cached !== undefined) { + ensureFilesForConfigUpdates(cached); + return cached; + } + + const content = tsSystem.fileExists(configFilePath) && tsSystem.readFile(configFilePath); + if (!content) { + parsedTsConfigInfo.set(configFilePath, null); + return null; + } + + const json = ts.parseJsonText(configFilePath, content); + + const extendedConfigPaths = new Set(); + const { extendedConfigCache } = docContext; + const cacheMonitorProxy = { + ...docContext.extendedConfigCache, + get(key: string) { + extendedConfigPaths.add(key); + return extendedConfigCache.get(key); + }, + has(key: string) { + extendedConfigPaths.add(key); + return extendedConfigCache.has(key); + }, + set(key: string, value: ts.ExtendedConfigCacheEntry) { + extendedConfigPaths.add(key); + return extendedConfigCache.set(key, value); + } + }; + + // TypeScript will throw if the parsedCommandLine doesn't include the sourceFile for the config file + // i.e. it must be directly parse from the json text instead of a javascript object like we do in getParsedConfig + const parsedCommandLine = ts.parseJsonSourceFileConfigFileContent( + json, + tsSystem, + dirname(configFilePath), + /*existingOptions*/ undefined, + configFilePath, + /*resolutionStack*/ undefined, + [ + { + extension: 'svelte', + isMixedContent: true, + // Deferred was added in a later TS version, fall back to tsx + // If Deferred exists, this means that all Svelte files are included + // in parsedConfig.fileNames + scriptKind: ts.ScriptKind.Deferred ?? ts.ScriptKind.TS + } + ], + cacheMonitorProxy + ); + + parsedCommandLine.options.allowNonTsExtensions = true; + + const snapshotManager = createSnapshotManager(parsedCommandLine, configFilePath); + + const tsconfigInfo: TsConfigInfo = { + parsedCommandLine, + snapshotManager, + pendingProjectFileUpdate: false, + configFilePath, + extendedConfigPaths + }; + parsedTsConfigInfo.set(configFilePath, tsconfigInfo); + + watchConfigFiles(extendedConfigPaths, parsedCommandLine); + + return tsconfigInfo; + } + + function getParsedCommandLine(configFilePath: string) { + return ensureTsConfigInfoUpToDate(configFilePath)?.parsedCommandLine; + } + + function ensureFilesForConfigUpdates(info: TsConfigInfo | null) { + if (info?.pendingProjectFileUpdate) { + info.pendingProjectFileUpdate = false; + info.snapshotManager.updateProjectFiles(); + info.parsedCommandLine.fileNames = info.snapshotManager.getProjectFileNames(); + } + } + + function getResolvedProjectReferences(): TsConfigInfo[] { + if (!tsconfigPath || !projectConfig.projectReferences) { + return []; + } + + return projectConfig.projectReferences + .map((ref) => ensureTsConfigInfoUpToDate(normalizePath(ref.path))) + .filter(isNotNullOrUndefined); + } + + function openVirtualDocument(document: Document) { + const filePath = document.getFilePath(); + if (!filePath) { + return; + } + virtualDocuments.set(filePath, document); + configFileForOpenFiles.set(filePath, tsconfigPath || workspacePath); + updateSnapshot(document); + scheduleUpdate(filePath); + } + + function getSvelteShimFiles() { + const isSvelte3 = sveltePackageInfo.version.major === 3; + const svelteHtmlDeclaration = isSvelte3 + ? undefined + : join(sveltePackageInfo.path, 'svelte-html.d.ts'); + const svelteHtmlFallbackIfNotExist = + svelteHtmlDeclaration && tsSystem.fileExists(svelteHtmlDeclaration) + ? svelteHtmlDeclaration + : './svelte-jsx-v4.d.ts'; + + const svelteTsxFiles = ( + isSvelte3 + ? ['./svelte-shims.d.ts', './svelte-jsx.d.ts', './svelte-native-jsx.d.ts'] + : [ + './svelte-shims-v4.d.ts', + svelteHtmlFallbackIfNotExist, + './svelte-native-jsx.d.ts' + ] + ).map((f) => tsSystem.resolvePath(resolve(svelteTsPath, f))); + + const result = new FileSet(tsSystem.useCaseSensitiveFileNames); + + svelteTsxFiles.forEach((f) => result.add(normalizePath(f))); + return result; + } + + function isShimFiles(filePath: string) { + return svelteTsxFiles.has(normalizePath(filePath)); + } } /** @@ -934,7 +1298,7 @@ function exceedsTotalSizeLimitForNonTsFiles( * because it would reference the closure * So that GC won't drop it and cause memory leaks */ -function createWatchExtendedConfigCallback(docContext: LanguageServiceDocumentContext) { +function createWatchDependedConfigCallback(docContext: LanguageServiceDocumentContext) { return async ( fileName: string, kind: ts.FileWatcherEventKind, @@ -950,10 +1314,18 @@ function createWatchExtendedConfigCallback(docContext: LanguageServiceDocumentCo return; } + const getCanonicalFileName = createGetCanonicalFileName( + docContext.tsSystem.useCaseSensitiveFileNames + ); + + docContext.extendedConfigCache.delete(getCanonicalFileName(fileName)); + // rely on TypeScript internal behavior so delete both just in case docContext.extendedConfigCache.delete(fileName); - const promises = Array.from(extendedConfigToTsConfigPath.get(fileName) ?? []).map( + const reloadingConfigs: string[] = []; + const promises = Array.from(configPathToDependedProject.get(fileName) ?? []).map( async (config) => { + reloadingConfigs.push(config); const oldService = services.get(config); scheduleReload(config); (await oldService)?.dispose(); @@ -961,7 +1333,7 @@ function createWatchExtendedConfigCallback(docContext: LanguageServiceDocumentCo ); await Promise.all(promises); - docContext.onProjectReloaded?.(); + docContext.onProjectReloaded?.(reloadingConfigs); }; } diff --git a/packages/language-server/src/plugins/typescript/serviceCache.ts b/packages/language-server/src/plugins/typescript/serviceCache.ts index 379a0306f..d91b05b32 100644 --- a/packages/language-server/src/plugins/typescript/serviceCache.ts +++ b/packages/language-server/src/plugins/typescript/serviceCache.ts @@ -81,8 +81,10 @@ export function createProject( 'getSymlinkCache', 'getPackageJsonsVisibleToFile', 'getPackageJsonAutoImportProvider', - 'includePackageJsonAutoImports', - 'useSourceOfProjectReferenceRedirect' + 'includePackageJsonAutoImports' + // Volar doesn't have the "languageServiceReducedMode" support but we do + // so don't proxy this method and implement this directly in the ts.LanguageServiceHost + // 'useSourceOfProjectReferenceRedirect' ]; proxyMethods.forEach((key) => ((host as any)[key] = project[key].bind(project))); diff --git a/packages/language-server/src/plugins/typescript/svelte-sys.ts b/packages/language-server/src/plugins/typescript/svelte-sys.ts index 4fb3c205c..553bd17a3 100644 --- a/packages/language-server/src/plugins/typescript/svelte-sys.ts +++ b/packages/language-server/src/plugins/typescript/svelte-sys.ts @@ -11,6 +11,17 @@ export function createSvelteSys(tsSystem: ts.System) { function svelteFileExists(path: string) { if (isVirtualSvelteFilePath(path)) { const sveltePath = toRealSvelteFilePath(path); + + // First check if there's a `.svelte.d.ts` or `.d.svelte.ts` file, which should take precedence + const dtsPath = sveltePath.slice(0, -7) + '.svelte.d.ts'; + const dtsPathExists = fileExistsCache.get(dtsPath) ?? tsSystem.fileExists(dtsPath); + fileExistsCache.set(dtsPath, dtsPathExists); + if (dtsPathExists) return false; + + const svelteDtsPathExists = fileExistsCache.get(path) ?? tsSystem.fileExists(path); + fileExistsCache.set(path, svelteDtsPathExists); + if (svelteDtsPathExists) return false; + const sveltePathExists = fileExistsCache.get(sveltePath) ?? tsSystem.fileExists(sveltePath); fileExistsCache.set(sveltePath, sveltePathExists); @@ -20,23 +31,30 @@ export function createSvelteSys(tsSystem: ts.System) { } } + function getRealSveltePathIfExists(path: string) { + return svelteFileExists(path) ? toRealSvelteFilePath(path) : path; + } + const svelteSys: ts.System & { deleteFromCache: (path: string) => void; svelteFileExists: (path: string) => boolean; + getRealSveltePathIfExists: (path: string) => string; } = { ...tsSystem, svelteFileExists, + getRealSveltePathIfExists, fileExists(path: string) { - // We need to check both .svelte and .svelte.ts/js because that's how Svelte 5 will likely mark files with runes in them + // We need to check if this is a virtual svelte file const sveltePathExists = svelteFileExists(path); - const exists = - sveltePathExists || (fileExistsCache.get(path) ?? tsSystem.fileExists(path)); + if (sveltePathExists) return true; + + const exists = fileExistsCache.get(path) ?? tsSystem.fileExists(path); fileExistsCache.set(path, exists); return exists; }, readFile(path: string) { // No getSnapshot here, because TS will very rarely call this and only for files that are not in the project - return tsSystem.readFile(svelteFileExists(path) ? toRealSvelteFilePath(path) : path); + return tsSystem.readFile(getRealSveltePathIfExists(path)); }, readDirectory(path, extensions, exclude, include, depth) { const extensionsWithSvelte = extensions ? [...extensions, '.svelte'] : undefined; @@ -60,7 +78,7 @@ export function createSvelteSys(tsSystem: ts.System) { const realpath = tsSystem.realpath; svelteSys.realpath = function (path) { if (svelteFileExists(path)) { - return realpath(toRealSvelteFilePath(path)) + '.ts'; + return realpath(toRealSvelteFilePath(path)); } return realpath(path); }; diff --git a/packages/language-server/src/plugins/typescript/utils.ts b/packages/language-server/src/plugins/typescript/utils.ts index 62fa6359d..a8a6ce1f6 100644 --- a/packages/language-server/src/plugins/typescript/utils.ts +++ b/packages/language-server/src/plugins/typescript/utils.ts @@ -70,15 +70,17 @@ export function isSvelteFilePath(filePath: string) { } export function isVirtualSvelteFilePath(filePath: string) { - return filePath.endsWith('.svelte.ts'); + return filePath.endsWith('.d.svelte.ts'); } export function toRealSvelteFilePath(filePath: string) { - return filePath.slice(0, -'.ts'.length); + return filePath.slice(0, -11 /* 'd.svelte.ts'.length */) + 'svelte'; } -export function toVirtualSvelteFilePath(filePath: string) { - return filePath.endsWith('.ts') ? filePath : filePath + '.ts'; +export function toVirtualSvelteFilePath(svelteFilePath: string) { + return isVirtualSvelteFilePath(svelteFilePath) + ? svelteFilePath + : svelteFilePath.slice(0, -6 /* 'svelte'.length */) + 'd.svelte.ts'; } export function ensureRealSvelteFilePath(filePath: string) { diff --git a/packages/language-server/src/server.ts b/packages/language-server/src/server.ts index 3fffda855..d19e56dcc 100644 --- a/packages/language-server/src/server.ts +++ b/packages/language-server/src/server.ts @@ -199,7 +199,10 @@ export function startServer(options?: LSOptions) { onProjectReloaded: refreshCrossFilesSemanticFeatures, watch: true, nonRecursiveWatchPattern, - watchDirectory: (patterns) => watchDirectory(patterns) + watchDirectory: (patterns) => watchDirectory(patterns), + reportConfigError(diagnostic) { + connection?.sendDiagnostics(diagnostic); + } }), normalizedWorkspaceUris, docManager diff --git a/packages/language-server/src/svelte-check.ts b/packages/language-server/src/svelte-check.ts index b6100e60c..75a62b173 100644 --- a/packages/language-server/src/svelte-check.ts +++ b/packages/language-server/src/svelte-check.ts @@ -18,6 +18,7 @@ import { JSOrTSDocumentSnapshot } from './plugins/typescript/DocumentSnapshot'; import { isInGeneratedCode } from './plugins/typescript/features/utils'; import { convertRange, getDiagnosticTag, mapSeverity } from './plugins/typescript/utils'; import { pathToUrl, urlToPath } from './utils'; +import { groupBy } from 'lodash'; export type SvelteCheckDiagnosticSource = 'js' | 'css' | 'svelte'; @@ -188,17 +189,42 @@ export class SvelteCheck { private async getDiagnosticsForTsconfig(tsconfigPath: string) { const lsContainer = await this.getLSContainer(tsconfigPath); + const map = (diagnostic: ts.Diagnostic, range?: Range): Diagnostic => { + const file = diagnostic.file; + range ??= file + ? convertRange( + { positionAt: file.getLineAndCharacterOfPosition.bind(file) }, + diagnostic + ) + : { start: { line: 0, character: 0 }, end: { line: 0, character: 0 } }; - const noInputsFoundError = lsContainer.configErrors?.find((e) => e.code === 18003); - if (noInputsFoundError) { - throw new Error(noInputsFoundError.messageText.toString()); + return { + range: range, + severity: mapSeverity(diagnostic.category), + source: diagnostic.source, + message: ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n'), + code: diagnostic.code, + tags: getDiagnosticTag(diagnostic) + }; + }; + + if ( + lsContainer.configErrors.some((error) => error.category === ts.DiagnosticCategory.Error) + ) { + return reportConfigError(); } const lang = lsContainer.getService(); + if ( + lsContainer.configErrors.some((error) => error.category === ts.DiagnosticCategory.Error) + ) { + return reportConfigError(); + } + const files = lang.getProgram()?.getSourceFiles() || []; const options = lang.getProgram()?.getCompilerOptions() || {}; - return await Promise.all( + const diagnostics = await Promise.all( files.map((file) => { const uri = pathToUrl(file.fileName); const doc = this.docManager.get(uri); @@ -211,6 +237,7 @@ export class SvelteCheck { const skipDiagnosticsForFile = (options.skipLibCheck && file.isDeclarationFile) || (options.skipDefaultLibCheck && file.hasNoDefaultLib) || + lsContainer.isShimFiles(file.fileName) || // ignore JS files in node_modules /\/node_modules\/.+\.(c|m)?js$/.test(file.fileName); const snapshot = lsContainer.snapshotManager.get(file.fileName) as @@ -218,20 +245,6 @@ export class SvelteCheck { | undefined; const isKitFile = snapshot?.kitFile ?? false; const diagnostics: Diagnostic[] = []; - const map = (diagnostic: ts.Diagnostic, range?: Range) => ({ - range: - range ?? - convertRange( - { positionAt: file.getLineAndCharacterOfPosition.bind(file) }, - diagnostic - ), - severity: mapSeverity(diagnostic.category), - source: diagnostic.source, - message: ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n'), - code: diagnostic.code, - tags: getDiagnosticTag(diagnostic) - }); - if (!skipDiagnosticsForFile) { const originalDiagnostics = [ ...lang.getSyntacticDiagnostics(file.fileName), @@ -304,6 +317,25 @@ export class SvelteCheck { } }) ); + + if (lsContainer.configErrors.length) { + diagnostics.push(...reportConfigError()); + } + + return diagnostics; + + function reportConfigError() { + const grouped = groupBy( + lsContainer.configErrors, + (error) => error.file?.fileName ?? tsconfigPath + ); + + return Object.entries(grouped).map(([filePath, errors]) => ({ + filePath, + text: '', + diagnostics: errors.map((diagnostic) => map(diagnostic)) + })); + } } private async getDiagnosticsForFile(uri: string) { diff --git a/packages/language-server/test/lib/documents/configLoader.test.ts b/packages/language-server/test/lib/documents/configLoader.test.ts index 1825a2ec9..dbdfb677a 100644 --- a/packages/language-server/test/lib/documents/configLoader.test.ts +++ b/packages/language-server/test/lib/documents/configLoader.test.ts @@ -19,6 +19,29 @@ describe('ConfigLoader', () => { return path.join(...filePath.split('/')); } + function mockFdir(results: string[] | (() => string[])): any { + return class { + withPathSeparator() { + return this; + } + exclude() { + return this; + } + filter() { + return this; + } + withRelativePaths() { + return this; + } + crawl() { + return this; + } + sync() { + return typeof results === 'function' ? results() : results; + } + }; + } + async function assertFindsConfig( configLoader: ConfigLoader, filePath: string, @@ -32,7 +55,7 @@ describe('ConfigLoader', () => { it('should load all config files below and the one inside/above given directory', async () => { const configLoader = new ConfigLoader( - (() => ['svelte.config.js', 'below/svelte.config.js']) as any, + mockFdir(['svelte.config.js', 'below/svelte.config.js']), { existsSync: () => true }, path, (module: URL) => Promise.resolve({ default: { preprocess: module.toString() } }) @@ -63,7 +86,7 @@ describe('ConfigLoader', () => { it('finds first above if none found inside/below directory', async () => { const configLoader = new ConfigLoader( - () => [], + mockFdir([]), { existsSync: (p) => typeof p === 'string' && p.endsWith(path.join('some', 'svelte.config.js')) @@ -78,7 +101,7 @@ describe('ConfigLoader', () => { it('adds fallback if no config found', async () => { const configLoader = new ConfigLoader( - () => [], + mockFdir([]), { existsSync: () => false }, path, (module: URL) => Promise.resolve({ default: { preprocess: module.toString() } }) @@ -98,14 +121,14 @@ describe('ConfigLoader', () => { let firstGlobCall = true; let nrImportCalls = 0; const configLoader = new ConfigLoader( - (() => { + mockFdir(() => { if (firstGlobCall) { firstGlobCall = false; return ['svelte.config.js']; } else { return []; } - }) as any, + }), { existsSync: (p) => typeof p === 'string' && @@ -139,11 +162,8 @@ describe('ConfigLoader', () => { }); it('can deal with missing config', () => { - const configLoader = new ConfigLoader( - () => [], - { existsSync: () => false }, - path, - () => Promise.resolve('unimportant') + const configLoader = new ConfigLoader(mockFdir([]), { existsSync: () => false }, path, () => + Promise.resolve('unimportant') ); assert.deepStrictEqual( configLoader.getConfig(normalizePath('/some/file.svelte')), @@ -153,7 +173,7 @@ describe('ConfigLoader', () => { it('should await config', async () => { const configLoader = new ConfigLoader( - () => [], + mockFdir([]), { existsSync: () => true }, path, (module: URL) => Promise.resolve({ default: { preprocess: module.toString() } }) @@ -167,7 +187,7 @@ describe('ConfigLoader', () => { it('should not load config when disabled', async () => { const moduleLoader = spy(); const configLoader = new ConfigLoader( - () => [], + mockFdir([]), { existsSync: () => true }, path, moduleLoader diff --git a/packages/language-server/test/plugins/typescript/features/DiagnosticsProvider.test.ts b/packages/language-server/test/plugins/typescript/features/DiagnosticsProvider.test.ts index 92601459f..dbccee6e5 100644 --- a/packages/language-server/test/plugins/typescript/features/DiagnosticsProvider.test.ts +++ b/packages/language-server/test/plugins/typescript/features/DiagnosticsProvider.test.ts @@ -98,7 +98,7 @@ describe('DiagnosticsProvider', function () { ); const newFilePath = normalizePath(path.join(testDir, 'empty-export.ts')) || ''; - await lsAndTsDocResolver.getSnapshot(newFilePath); + await lsAndTsDocResolver.getOrCreateSnapshot(newFilePath); const diagnostics1 = await plugin.getDiagnostics(document); assert.deepStrictEqual( diff --git a/packages/language-server/test/plugins/typescript/features/FindReferencesProvider.test.ts b/packages/language-server/test/plugins/typescript/features/FindReferencesProvider.test.ts index ecd5d4f5b..12509c1c6 100644 --- a/packages/language-server/test/plugins/typescript/features/FindReferencesProvider.test.ts +++ b/packages/language-server/test/plugins/typescript/features/FindReferencesProvider.test.ts @@ -31,7 +31,11 @@ describe('FindReferencesProvider', function () { (textDocument) => new Document(textDocument.uri, textDocument.text) ); const lsConfigManager = new LSConfigManager(); - const lsAndTsDocResolver = new LSAndTSDocResolver(docManager, [testDir], lsConfigManager); + const lsAndTsDocResolver = new LSAndTSDocResolver( + docManager, + [pathToUrl(testDir)], + lsConfigManager + ); const provider = new FindReferencesProviderImpl( lsAndTsDocResolver, new FindComponentReferencesProviderImpl(lsAndTsDocResolver) diff --git a/packages/language-server/test/plugins/typescript/features/HoverProvider.test.ts b/packages/language-server/test/plugins/typescript/features/HoverProvider.test.ts index 17b6d8c35..49e146108 100644 --- a/packages/language-server/test/plugins/typescript/features/HoverProvider.test.ts +++ b/packages/language-server/test/plugins/typescript/features/HoverProvider.test.ts @@ -25,7 +25,11 @@ describe('HoverProvider', function () { (textDocument) => new Document(textDocument.uri, textDocument.text) ); const lsConfigManager = new LSConfigManager(); - const lsAndTsDocResolver = new LSAndTSDocResolver(docManager, [testDir], lsConfigManager); + const lsAndTsDocResolver = new LSAndTSDocResolver( + docManager, + [pathToUrl(testDir)], + lsConfigManager + ); const provider = new HoverProviderImpl(lsAndTsDocResolver); const document = openDoc(filename); return { provider, document }; diff --git a/packages/language-server/test/plugins/typescript/features/ImplemenationProvider.test.ts b/packages/language-server/test/plugins/typescript/features/ImplemenationProvider.test.ts index 57ad86192..152542342 100644 --- a/packages/language-server/test/plugins/typescript/features/ImplemenationProvider.test.ts +++ b/packages/language-server/test/plugins/typescript/features/ImplemenationProvider.test.ts @@ -29,7 +29,7 @@ describe('ImplementationProvider', function () { ); const lsAndTsDocResolver = new LSAndTSDocResolver( docManager, - [testDir], + [pathToUrl(testDir)], new LSConfigManager() ); const provider = new ImplementationProviderImpl(lsAndTsDocResolver); diff --git a/packages/language-server/test/plugins/typescript/features/SemanticTokensProvider.test.ts b/packages/language-server/test/plugins/typescript/features/SemanticTokensProvider.test.ts index 7acb27099..a942f32f8 100644 --- a/packages/language-server/test/plugins/typescript/features/SemanticTokensProvider.test.ts +++ b/packages/language-server/test/plugins/typescript/features/SemanticTokensProvider.test.ts @@ -191,13 +191,6 @@ describe('SemanticTokensProvider', function () { type: TokenType.variable, modifiers: [TokenModifier.declaration, TokenModifier.local, TokenModifier.readonly] }, - { - line: 12, - character: 5, - length: 'Imported'.length, - type: isSvelte5Plus ? TokenType.type : TokenType.class, - modifiers: isSvelte5Plus ? [TokenModifier.readonly] : [] - }, { line: 12, character: 23, diff --git a/packages/language-server/test/plugins/typescript/features/TypeDefinitionProvider.test.ts b/packages/language-server/test/plugins/typescript/features/TypeDefinitionProvider.test.ts index f4e0baa44..e709bbd3c 100644 --- a/packages/language-server/test/plugins/typescript/features/TypeDefinitionProvider.test.ts +++ b/packages/language-server/test/plugins/typescript/features/TypeDefinitionProvider.test.ts @@ -29,7 +29,7 @@ describe('TypeDefinitionProvider', function () { ); const lsAndTsDocResolver = new LSAndTSDocResolver( docManager, - [testDir], + [pathToUrl(testDir)], new LSConfigManager() ); const provider = new TypeDefinitionProviderImpl(lsAndTsDocResolver); diff --git a/packages/language-server/test/plugins/typescript/features/UpdateImportsProvider.test.ts b/packages/language-server/test/plugins/typescript/features/UpdateImportsProvider.test.ts index 998896aa3..cdba08f4b 100644 --- a/packages/language-server/test/plugins/typescript/features/UpdateImportsProvider.test.ts +++ b/packages/language-server/test/plugins/typescript/features/UpdateImportsProvider.test.ts @@ -33,7 +33,10 @@ describe('UpdateImportsProviderImpl', function () { new LSConfigManager(), { tsSystem: { ...ts.sys, useCaseSensitiveFileNames } } ); - const updateImportsProvider = new UpdateImportsProviderImpl(lsAndTsDocResolver); + const updateImportsProvider = new UpdateImportsProviderImpl( + lsAndTsDocResolver, + useCaseSensitiveFileNames + ); const filePath = join(updateImportTestDir, filename); const fileUri = pathToUrl(filePath); const document = docManager.openClientDocument({ diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/bindings/RunesGeneric.svelte b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/bindings/RunesGeneric.svelte new file mode 100644 index 000000000..0b9ff0c17 --- /dev/null +++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/bindings/RunesGeneric.svelte @@ -0,0 +1,7 @@ + diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/bindings/expected_svelte_5.json b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/bindings/expected_svelte_5.json index 72c8185db..8aca1d067 100644 --- a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/bindings/expected_svelte_5.json +++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/bindings/expected_svelte_5.json @@ -5,11 +5,11 @@ "range": { "end": { "character": 20, - "line": 25 + "line": 26 }, "start": { "character": 7, - "line": 25 + "line": 26 } }, "severity": 1, @@ -22,11 +22,11 @@ "range": { "end": { "character": 21, - "line": 26 + "line": 27 }, "start": { "character": 12, - "line": 26 + "line": 27 } }, "severity": 1, @@ -39,11 +39,11 @@ "range": { "end": { "character": 21, - "line": 26 + "line": 27 }, "start": { "character": 7, - "line": 26 + "line": 27 } }, "severity": 1, @@ -56,11 +56,79 @@ "range": { "end": { "character": 17, - "line": 27 + "line": 28 }, "start": { "character": 8, - "line": 27 + "line": 28 + } + }, + "severity": 1, + "source": "ts", + "tags": [] + }, + { + "code": 2322, + "message": "Cannot use 'bind:' with this property. It is declared as non-bindable inside the component.\nTo mark a property as bindable: 'let { readonly = $bindable() } = $props()'", + "range": { + "end": { + "character": 27, + "line": 30 + }, + "start": { + "character": 14, + "line": 30 + } + }, + "severity": 1, + "source": "ts", + "tags": [] + }, + { + "code": 2353, + "message": "Object literal may only specify known properties, and 'only_bind' does not exist in type '$$ComponentProps'.", + "range": { + "end": { + "character": 28, + "line": 31 + }, + "start": { + "character": 19, + "line": 31 + } + }, + "severity": 1, + "source": "ts", + "tags": [] + }, + { + "code": 2322, + "message": "Cannot use 'bind:' with this property. It is declared as non-bindable inside the component.\nTo mark a property as bindable: 'let { only_bind = $bindable() } = $props()'", + "range": { + "end": { + "character": 28, + "line": 31 + }, + "start": { + "character": 14, + "line": 31 + } + }, + "severity": 1, + "source": "ts", + "tags": [] + }, + { + "code": 2353, + "message": "Object literal may only specify known properties, and 'only_bind' does not exist in type '$$ComponentProps'.", + "range": { + "end": { + "character": 24, + "line": 32 + }, + "start": { + "character": 15, + "line": 32 } }, "severity": 1, diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/bindings/expectedv2.json b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/bindings/expectedv2.json index e441ca7e2..da73688bf 100644 --- a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/bindings/expectedv2.json +++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/bindings/expectedv2.json @@ -1,15 +1,32 @@ [ + { + "code": 2344, + "message": "Type 'typeof Runes__SvelteComponent_' does not satisfy the constraint '(...args: any) => any'.\n Type 'typeof Runes__SvelteComponent_' provides no match for the signature '(...args: any): any'.", + "range": { + "end": { + "character": 41, + "line": 12 + }, + "start": { + "character": 29, + "line": 12 + } + }, + "severity": 1, + "source": "ts", + "tags": [] + }, { "code": 2353, "message": "Object literal may only specify known properties, and 'can_bind' does not exist in type '{ only_bind?: (() => boolean) | undefined; }'.", "range": { "end": { "character": 20, - "line": 20 + "line": 21 }, "start": { "character": 12, - "line": 20 + "line": 21 } }, "severity": 1, @@ -22,11 +39,11 @@ "range": { "end": { "character": 16, - "line": 21 + "line": 22 }, "start": { "character": 8, - "line": 21 + "line": 22 } }, "severity": 1, @@ -39,11 +56,11 @@ "range": { "end": { "character": 16, - "line": 22 + "line": 23 }, "start": { "character": 8, - "line": 22 + "line": 23 } }, "severity": 1, @@ -56,11 +73,28 @@ "range": { "end": { "character": 20, - "line": 25 + "line": 26 }, "start": { "character": 12, - "line": 25 + "line": 26 + } + }, + "severity": 1, + "source": "ts", + "tags": [] + }, + { + "code": 2353, + "message": "Object literal may only specify known properties, and 'readonly' does not exist in type '{ only_bind?: (() => boolean) | undefined; }'.", + "range": { + "end": { + "character": 27, + "line": 30 + }, + "start": { + "character": 19, + "line": 30 } }, "severity": 1, diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/bindings/input.svelte b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/bindings/input.svelte index 55de44f2d..dd51d79f5 100644 --- a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/bindings/input.svelte +++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/bindings/input.svelte @@ -1,6 +1,7 @@ @@ -26,3 +27,7 @@ + + + + diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/exports-map-svelte/expectedv2.json b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/exports-map-svelte/expectedv2.json new file mode 100644 index 000000000..58680d099 --- /dev/null +++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/exports-map-svelte/expectedv2.json @@ -0,0 +1,36 @@ +[ + { + "code": 2307, + "message": "Cannot find module 'package' or its corresponding type declarations.", + "range": { + "end": { + "character": 45, + "line": 1 + }, + "start": { + "character": 36, + "line": 1 + } + }, + "severity": 1, + "source": "ts", + "tags": [] + }, + { + "code": 2307, + "message": "Cannot find module 'package/y' or its corresponding type declarations.", + "range": { + "start": { + "character": 38, + "line": 3 + }, + "end": { + "character": 49, + "line": 3 + } + }, + "severity": 1, + "source": "ts", + "tags": [] + } +] diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/exports-map-svelte/input.svelte b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/exports-map-svelte/input.svelte new file mode 100644 index 000000000..2775a7582 --- /dev/null +++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/exports-map-svelte/input.svelte @@ -0,0 +1,9 @@ + + + + + diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/exports-map-svelte/node_modules/package/foo.svelte b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/exports-map-svelte/node_modules/package/foo.svelte new file mode 100644 index 000000000..e29d29c54 --- /dev/null +++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/exports-map-svelte/node_modules/package/foo.svelte @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/exports-map-svelte/node_modules/package/package.json b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/exports-map-svelte/node_modules/package/package.json new file mode 100644 index 000000000..422ee721e --- /dev/null +++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/exports-map-svelte/node_modules/package/package.json @@ -0,0 +1,16 @@ +{ + "name": "package", + "version": "1.0.0", + "exports": { + ".": { + "svelte": "./foo.svelte" + }, + "./x": { + "types": "./x-types.d.ts", + "svelte": "./x.svelte" + }, + "./y": { + "svelte": "./y.svelte" + } + } +} \ No newline at end of file diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/exports-map-svelte/node_modules/package/x-types.d.ts b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/exports-map-svelte/node_modules/package/x-types.d.ts new file mode 100644 index 000000000..4d27ef5b0 --- /dev/null +++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/exports-map-svelte/node_modules/package/x-types.d.ts @@ -0,0 +1,2 @@ +declare const X: any; +export default X; \ No newline at end of file diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/exports-map-svelte/node_modules/package/x.svelte b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/exports-map-svelte/node_modules/package/x.svelte new file mode 100644 index 000000000..fb5dbfefa --- /dev/null +++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/exports-map-svelte/node_modules/package/x.svelte @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/exports-map-svelte/node_modules/package/y.svelte b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/exports-map-svelte/node_modules/package/y.svelte new file mode 100644 index 000000000..78f01008c --- /dev/null +++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/exports-map-svelte/node_modules/package/y.svelte @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/exports-map-svelte/tsconfig.json b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/exports-map-svelte/tsconfig.json new file mode 100644 index 000000000..d5e498207 --- /dev/null +++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/exports-map-svelte/tsconfig.json @@ -0,0 +1,7 @@ +{ + "compilerOptions": { + "module": "esnext", + "target": "esnext", + "moduleResolution": "Bundler" + } +} diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/generics-runes.v5/ValueComponent.svelte b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/generics-runes.v5/ValueComponent.svelte new file mode 100644 index 000000000..7d2dd5ebc --- /dev/null +++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/generics-runes.v5/ValueComponent.svelte @@ -0,0 +1,6 @@ + + +{value} +{defaultValue} \ No newline at end of file diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/generics-runes.v5/expectedv2.json b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/generics-runes.v5/expectedv2.json new file mode 100644 index 000000000..90f0fd771 --- /dev/null +++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/generics-runes.v5/expectedv2.json @@ -0,0 +1,19 @@ +[ + { + "code": 2322, + "message": "Type 'number' is not assignable to type 'string'.", + "range": { + "end": { + "character": 36, + "line": 10 + }, + "start": { + "character": 24, + "line": 10 + } + }, + "severity": 1, + "source": "ts", + "tags": [] + } +] diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/generics-runes.v5/input.svelte b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/generics-runes.v5/input.svelte new file mode 100644 index 000000000..d2442ff89 --- /dev/null +++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/generics-runes.v5/input.svelte @@ -0,0 +1,11 @@ + + + + + + + \ No newline at end of file diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/import-precedence/a.svelte b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/import-precedence/a.svelte new file mode 100644 index 000000000..1f6a1cbe4 --- /dev/null +++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/import-precedence/a.svelte @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/import-precedence/a.svelte.d.ts b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/import-precedence/a.svelte.d.ts new file mode 100644 index 000000000..227cc1bb1 --- /dev/null +++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/import-precedence/a.svelte.d.ts @@ -0,0 +1 @@ +export declare const a: boolean; diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/import-precedence/b.svelte b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/import-precedence/b.svelte new file mode 100644 index 000000000..1f6a1cbe4 --- /dev/null +++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/import-precedence/b.svelte @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/import-precedence/b.svelte.ts b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/import-precedence/b.svelte.ts new file mode 100644 index 000000000..1d9db10ef --- /dev/null +++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/import-precedence/b.svelte.ts @@ -0,0 +1 @@ +export const b = true; diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/import-precedence/c.d.svelte.ts b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/import-precedence/c.d.svelte.ts new file mode 100644 index 000000000..a12f971dd --- /dev/null +++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/import-precedence/c.d.svelte.ts @@ -0,0 +1 @@ +export declare const c: boolean; diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/import-precedence/c.svelte b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/import-precedence/c.svelte new file mode 100644 index 000000000..1f6a1cbe4 --- /dev/null +++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/import-precedence/c.svelte @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/import-precedence/d.svelte b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/import-precedence/d.svelte new file mode 100644 index 000000000..1f6a1cbe4 --- /dev/null +++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/import-precedence/d.svelte @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/import-precedence/d.svelte.js b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/import-precedence/d.svelte.js new file mode 100644 index 000000000..ecee2a83c --- /dev/null +++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/import-precedence/d.svelte.js @@ -0,0 +1 @@ +export const d = true; diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/import-precedence/expectedv2.json b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/import-precedence/expectedv2.json new file mode 100644 index 000000000..fe51488c7 --- /dev/null +++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/import-precedence/expectedv2.json @@ -0,0 +1 @@ +[] diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/import-precedence/input.svelte b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/import-precedence/input.svelte new file mode 100644 index 000000000..9966c707e --- /dev/null +++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/import-precedence/input.svelte @@ -0,0 +1,15 @@ + + + + diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/import-precedence/tsconfig.json b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/import-precedence/tsconfig.json new file mode 100644 index 000000000..eef515315 --- /dev/null +++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/import-precedence/tsconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "strict": true, + "allowJs": true, + "target": "ESNext", + /** + This is actually not needed, but makes the tests faster + because TS does not look up other types. + */ + "types": ["svelte"], + "allowArbitraryExtensions": true // else .d.svelte.ts will be an error + } +} diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/project-reference/nested/expectedv2.json b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/project-reference/nested/expectedv2.json new file mode 100644 index 000000000..ddef317a6 --- /dev/null +++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/project-reference/nested/expectedv2.json @@ -0,0 +1,10 @@ +[ + { + "range": { "start": { "line": 6, "character": 8 }, "end": { "line": 6, "character": 9 } }, + "severity": 1, + "source": "ts", + "message": "Type 'string' is not assignable to type 'number'.", + "code": 2322, + "tags": [] + } +] diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/project-reference/nested/imported.ts b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/project-reference/nested/imported.ts new file mode 100644 index 000000000..bc8481bbb --- /dev/null +++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/project-reference/nested/imported.ts @@ -0,0 +1,5 @@ +/** + * + * @param cb callback because if the module resolution failed there will be a noImplicitAny error + */ +export function hi(cb: (num: number) => string) {} diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/project-reference/nested/input.svelte b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/project-reference/nested/input.svelte new file mode 100644 index 000000000..3b505cd2c --- /dev/null +++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/project-reference/nested/input.svelte @@ -0,0 +1,8 @@ + diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/project-reference/nested/tsconfig_sub2.json b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/project-reference/nested/tsconfig_sub2.json new file mode 100644 index 000000000..310ef4967 --- /dev/null +++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/project-reference/nested/tsconfig_sub2.json @@ -0,0 +1,7 @@ +{ + "include": [], + "compilerOptions": { + "composite": true + }, + "references": [{ "path": "./tsconfig_sub3.json" }] +} diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/project-reference/nested/tsconfig_sub3.json b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/project-reference/nested/tsconfig_sub3.json new file mode 100644 index 000000000..f96815577 --- /dev/null +++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/project-reference/nested/tsconfig_sub3.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "composite": true, + "strict": true, + "paths": { + "hi2": ["./imported.ts"] + }, + "types": [] + } +} diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/project-reference/paths/expectedv2.json b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/project-reference/paths/expectedv2.json new file mode 100644 index 000000000..3d707cc47 --- /dev/null +++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/project-reference/paths/expectedv2.json @@ -0,0 +1,10 @@ +[ + { + "range": { "start": { "line": 6, "character": 4 }, "end": { "line": 6, "character": 5 } }, + "severity": 1, + "source": "ts", + "message": "Type 'string' is not assignable to type 'number'.", + "code": 2322, + "tags": [] + } +] diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/project-reference/paths/imported.ts b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/project-reference/paths/imported.ts new file mode 100644 index 000000000..bc8481bbb --- /dev/null +++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/project-reference/paths/imported.ts @@ -0,0 +1,5 @@ +/** + * + * @param cb callback because if the module resolution failed there will be a noImplicitAny error + */ +export function hi(cb: (num: number) => string) {} diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/project-reference/paths/input.svelte b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/project-reference/paths/input.svelte new file mode 100644 index 000000000..5e19507ef --- /dev/null +++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/project-reference/paths/input.svelte @@ -0,0 +1,8 @@ + diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/project-reference/paths/tsconfig_sub.json b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/project-reference/paths/tsconfig_sub.json new file mode 100644 index 000000000..384062fc0 --- /dev/null +++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/project-reference/paths/tsconfig_sub.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "baseUrl": ".", + "composite": true, + "strict": true, + "paths": { + "hi": ["./imported.ts"] + }, + "types": [] + } +} diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/project-reference/tsconfig.json b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/project-reference/tsconfig.json new file mode 100644 index 000000000..59b56bf8f --- /dev/null +++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/project-reference/tsconfig.json @@ -0,0 +1,11 @@ +{ + "include": [], + "references": [ + { + "path": "./paths/tsconfig_sub.json" + }, + { + "path": "./nested/tsconfig_sub2.json" + } + ] +} diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/tsconfig.json b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/tsconfig.json index f8add4155..da66f1d47 100644 --- a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/tsconfig.json +++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/tsconfig.json @@ -1,11 +1,13 @@ { "compilerOptions": { "strict": true, + "allowJs": true, + "target": "ESNext", /** This is actually not needed, but makes the tests faster because TS does not look up other types. */ "types": ["svelte"] }, - "exclude": ["./svelte-native/**/*", "./node16/**/*"] + "exclude": ["./svelte-native/**/*", "./node16/**/*", "project-reference/**/*"] } diff --git a/packages/language-server/test/plugins/typescript/features/inlayHints/fixtures/tsconfig.json b/packages/language-server/test/plugins/typescript/features/inlayHints/fixtures/tsconfig.json new file mode 100644 index 000000000..f493a66ae --- /dev/null +++ b/packages/language-server/test/plugins/typescript/features/inlayHints/fixtures/tsconfig.json @@ -0,0 +1,12 @@ +{ + "compilerOptions": { + "allowJs": true, + "target": "ESNext", + "strict": true, + /** + This is actually not needed, but makes the tests faster + because TS does not look up other types. + */ + "types": ["svelte"] + } +} diff --git a/packages/language-server/test/plugins/typescript/features/preferences.test.ts b/packages/language-server/test/plugins/typescript/features/preferences.test.ts index c794dc55b..b4c35f187 100644 --- a/packages/language-server/test/plugins/typescript/features/preferences.test.ts +++ b/packages/language-server/test/plugins/typescript/features/preferences.test.ts @@ -64,7 +64,14 @@ describe('ts user preferences', function () { typescript: { ...getPreferences(), ...preferences }, javascript: { ...getPreferences(), ...preferences } }); - return new LSAndTSDocResolver(docManager, [pathToUrl(testFilesDir)], configManager); + return { + lsAndTsDocResolver: new LSAndTSDocResolver( + docManager, + [pathToUrl(testFilesDir)], + configManager + ), + configManager + }; } function getDefaultPreferences(): TsUserPreferencesConfig { @@ -79,11 +86,8 @@ describe('ts user preferences', function () { it('provides auto import completion according to preferences', async () => { const { docManager, document } = setup('code-action.svelte'); - const lsAndTsDocResolver = createLSAndTSDocResolver(docManager); - const completionProvider = new CompletionsProviderImpl( - lsAndTsDocResolver, - new LSConfigManager() - ); + const { lsAndTsDocResolver, configManager } = createLSAndTSDocResolver(docManager); + const completionProvider = new CompletionsProviderImpl(lsAndTsDocResolver, configManager); const completions = await completionProvider.getCompletions( document, @@ -102,15 +106,13 @@ describe('ts user preferences', function () { context: CodeActionContext ) { const { docManager, document } = setup(filename); - const lsAndTsDocResolver = createLSAndTSDocResolver(docManager); - const completionProvider = new CompletionsProviderImpl( - lsAndTsDocResolver, - new LSConfigManager() - ); + const { lsAndTsDocResolver, configManager } = createLSAndTSDocResolver(docManager); + const completionProvider = new CompletionsProviderImpl(lsAndTsDocResolver, configManager); + const codeActionProvider = new CodeActionsProviderImpl( lsAndTsDocResolver, completionProvider, - new LSConfigManager() + configManager ); const codeAction = await codeActionProvider.getCodeActions(document, range, context); @@ -137,7 +139,7 @@ describe('ts user preferences', function () { it('provides auto import suggestions according to preferences', async () => { const { docManager, document } = setup('code-action.svelte'); - const lsAndTsDocResolver = createLSAndTSDocResolver(docManager, { + const { lsAndTsDocResolver, configManager } = createLSAndTSDocResolver(docManager, { suggest: { autoImports: false, includeAutomaticOptionalChainCompletions: undefined, @@ -147,10 +149,7 @@ describe('ts user preferences', function () { includeCompletionsWithSnippetText: undefined } }); - const completionProvider = new CompletionsProviderImpl( - lsAndTsDocResolver, - new LSConfigManager() - ); + const completionProvider = new CompletionsProviderImpl(lsAndTsDocResolver, configManager); const completions = await completionProvider.getCompletions( document, @@ -165,14 +164,14 @@ describe('ts user preferences', function () { function setupImportModuleSpecifierEndingJs() { const { docManager, document } = setup('module-specifier-js.svelte'); - const lsAndTsDocResolver = createLSAndTSDocResolver(docManager, { + const { lsAndTsDocResolver, configManager } = createLSAndTSDocResolver(docManager, { preferences: { ...getDefaultPreferences(), importModuleSpecifierEnding: 'js' } }); - return { document, lsAndTsDocResolver }; + return { document, lsAndTsDocResolver, configManager }; } it('provides auto import for svelte component when importModuleSpecifierEnding is js', async () => { @@ -248,16 +247,13 @@ describe('ts user preferences', function () { async function testExcludeDefinitionDir(pattern: string) { const { docManager, document } = setup('code-action.svelte'); - const lsAndTsDocResolver = createLSAndTSDocResolver(docManager, { + const { lsAndTsDocResolver, configManager } = createLSAndTSDocResolver(docManager, { preferences: { ...getDefaultPreferences(), autoImportFileExcludePatterns: [pattern] } }); - const completionProvider = new CompletionsProviderImpl( - lsAndTsDocResolver, - new LSConfigManager() - ); + const completionProvider = new CompletionsProviderImpl(lsAndTsDocResolver, configManager); const completions = await completionProvider.getCompletions( document, @@ -280,4 +276,24 @@ describe('ts user preferences', function () { it('exclude auto import (**/ pattern)', async () => { await testExcludeDefinitionDir('**/definition'); }); + + it('exclude auto import outside of the root', async () => { + const { docManager, document } = setup('code-action-outside-root.svelte'); + const { lsAndTsDocResolver, configManager } = createLSAndTSDocResolver(docManager, { + preferences: { + ...getDefaultPreferences(), + autoImportFileExcludePatterns: ['definitions.ts'] + } + }); + const completionProvider = new CompletionsProviderImpl(lsAndTsDocResolver, configManager); + + const completions = await completionProvider.getCompletions( + document, + Position.create(4, 7) + ); + + const item = completions?.items.find((item) => item.label === 'blubb'); + + assert.equal(item, undefined); + }); }); diff --git a/packages/language-server/test/plugins/typescript/module-loader.test.ts b/packages/language-server/test/plugins/typescript/module-loader.test.ts index d08e42682..1c3561cc2 100644 --- a/packages/language-server/test/plugins/typescript/module-loader.test.ts +++ b/packages/language-server/test/plugins/typescript/module-loader.test.ts @@ -21,8 +21,11 @@ describe('createSvelteModuleLoader', () => { const moduleCacheMock = { getPackageJsonInfoCache: () => ({}) }; + const moduleResolutionHost = { ...ts.sys }; - const svelteSys = 'svelteSys'; + const svelteSys = { + ...svS.createSvelteSys(ts.sys) + }; sinon.stub(svS, 'createSvelteSys').returns(svelteSys); const compilerOptions: ts.CompilerOptions = { strict: true, paths: { '/@/*': [] } }; @@ -34,7 +37,8 @@ describe('createSvelteModuleLoader', () => { ...ts, createModuleResolutionCache: () => moduleCacheMock, resolveModuleName: resolveStub - } + }, + () => moduleResolutionHost ); return { @@ -43,7 +47,8 @@ describe('createSvelteModuleLoader', () => { resolveStub, compilerOptions, moduleResolver, - svelteSys + svelteSys, + moduleResolutionHost }; } @@ -51,67 +56,16 @@ describe('createSvelteModuleLoader', () => { return stub.getCall(stub.getCalls().length - 1); } - it('uses tsSys for normal files', async () => { + it('uses svelte script kind if resolved module is svelte file', async () => { const resolvedModule: ts.ResolvedModuleFull = { extension: ts.Extension.Ts, - resolvedFileName: 'filename.ts' + resolvedFileName: 'filename.d.svelte.ts' }; - const { resolveStub, moduleResolver, compilerOptions, moduleCacheMock } = - setup(resolvedModule); - const result = moduleResolver.resolveModuleNames( - ['./normal.ts'], - 'C:/somerepo/somefile.svelte', - undefined, - undefined, - undefined as any - ); + const { getSvelteSnapshotStub, moduleResolver, svelteSys } = setup(resolvedModule); - assert.deepStrictEqual(result, [resolvedModule]); - assert.deepStrictEqual(lastCall(resolveStub).args, [ - './normal.ts', - 'C:/somerepo/somefile.svelte', - compilerOptions, - ts.sys, - moduleCacheMock, - undefined, - undefined - ]); - }); + svelteSys.getRealSveltePathIfExists = (filename: string) => + filename === 'filename.d.svelte.ts' ? 'filename.svelte' : filename; - it('uses tsSys for normal files part of TS aliases', async () => { - const resolvedModule: ts.ResolvedModuleFull = { - extension: ts.Extension.Ts, - resolvedFileName: 'filename.ts' - }; - const { resolveStub, moduleResolver, compilerOptions, moduleCacheMock } = - setup(resolvedModule); - const result = moduleResolver.resolveModuleNames( - ['/@/normal'], - 'C:/somerepo/somefile.svelte', - undefined, - undefined, - undefined as any - ); - - assert.deepStrictEqual(result, [resolvedModule]); - assert.deepStrictEqual(lastCall(resolveStub).args, [ - '/@/normal', - 'C:/somerepo/somefile.svelte', - compilerOptions, - ts.sys, - moduleCacheMock, - undefined, - undefined - ]); - }); - - it('uses tsSys for svelte.d.ts files', async () => { - const resolvedModule: ts.ResolvedModuleFull = { - extension: ts.Extension.Dts, - resolvedFileName: 'filename.d.ts' - }; - const { resolveStub, moduleResolver, compilerOptions, moduleCacheMock } = - setup(resolvedModule); const result = moduleResolver.resolveModuleNames( ['./normal.ts'], 'C:/somerepo/somefile.svelte', @@ -120,69 +74,6 @@ describe('createSvelteModuleLoader', () => { undefined as any ); - assert.deepStrictEqual(result, [resolvedModule]); - assert.deepStrictEqual(lastCall(resolveStub).args, [ - './normal.ts', - 'C:/somerepo/somefile.svelte', - compilerOptions, - ts.sys, - moduleCacheMock, - undefined, - undefined - ]); - }); - - it('uses svelte module loader for virtual svelte files', async () => { - const resolvedModule: ts.ResolvedModuleFull = { - extension: ts.Extension.Ts, - resolvedFileName: 'filename.svelte.ts' - }; - const { resolveStub, svelteSys, moduleResolver, compilerOptions, getSvelteSnapshotStub } = - setup(resolvedModule); - resolveStub.onFirstCall().returns({ resolvedModule: undefined }); - const result = moduleResolver.resolveModuleNames( - ['./svelte.svelte'], - 'C:/somerepo/somefile.svelte', - undefined, - undefined, - undefined as any - ); - - assert.deepStrictEqual(result, [ - { - extension: ts.Extension.Jsx, - resolvedFileName: 'filename.svelte', - isExternalLibraryImport: undefined - } - ]); - assert.deepStrictEqual(lastCall(resolveStub).args, [ - './svelte.svelte', - 'C:/somerepo/somefile.svelte', - compilerOptions, - svelteSys, - undefined, - undefined, - undefined - ]); - assert.deepStrictEqual(lastCall(getSvelteSnapshotStub).args, ['filename.svelte']); - }); - - it('uses svelte module loader for virtual svelte files with TS path aliases', async () => { - const resolvedModule: ts.ResolvedModuleFull = { - extension: ts.Extension.Ts, - resolvedFileName: 'filename.svelte.ts' - }; - const { resolveStub, svelteSys, moduleResolver, compilerOptions, getSvelteSnapshotStub } = - setup(resolvedModule); - resolveStub.onFirstCall().returns({ resolvedModule: undefined }); - const result = moduleResolver.resolveModuleNames( - ['/@/svelte.svelte'], - 'C:/somerepo/somefile.svelte', - undefined, - undefined, - undefined as any - ); - assert.deepStrictEqual(result, [ { extension: ts.Extension.Jsx, @@ -190,15 +81,6 @@ describe('createSvelteModuleLoader', () => { isExternalLibraryImport: undefined } ]); - assert.deepStrictEqual(lastCall(resolveStub).args, [ - '/@/svelte.svelte', - 'C:/somerepo/somefile.svelte', - compilerOptions, - svelteSys, - undefined, - undefined, - undefined - ]); assert.deepStrictEqual(lastCall(getSvelteSnapshotStub).args, ['filename.svelte']); }); diff --git a/packages/language-server/test/plugins/typescript/service.test.ts b/packages/language-server/test/plugins/typescript/service.test.ts index 02cac2d21..e0aa9ffd4 100644 --- a/packages/language-server/test/plugins/typescript/service.test.ts +++ b/packages/language-server/test/plugins/typescript/service.test.ts @@ -1,16 +1,17 @@ import assert from 'assert'; import path from 'path'; +import sinon from 'sinon'; import ts from 'typescript'; +import { RelativePattern } from 'vscode-languageserver-protocol'; import { Document } from '../../../src/lib/documents'; import { GlobalSnapshotsManager } from '../../../src/plugins/typescript/SnapshotManager'; import { + LanguageServiceContainer, LanguageServiceDocumentContext, getService } from '../../../src/plugins/typescript/service'; -import { pathToUrl } from '../../../src/utils'; +import { normalizePath, pathToUrl } from '../../../src/utils'; import { createVirtualTsSystem, getRandomVirtualDirPath } from './test-utils'; -import sinon from 'sinon'; -import { RelativePattern } from 'vscode-languageserver-protocol'; describe('service', () => { const testDir = path.join(__dirname, 'testfiles'); @@ -33,7 +34,8 @@ describe('service', () => { onProjectReloaded: undefined, projectService: undefined, nonRecursiveWatchPattern: undefined, - watchDirectory: undefined + watchDirectory: undefined, + reportConfigError: undefined }; return { virtualSystem, lsDocumentContext, rootUris }; @@ -53,6 +55,11 @@ describe('service', () => { }) ); + virtualSystem.writeFile( + path.join(dirPath, 'random.svelte'), + '' + ); + const ls = await getService( path.join(dirPath, 'random.svelte'), rootUris, @@ -63,11 +70,156 @@ describe('service', () => { delete ls.compilerOptions.configFilePath; assert.deepStrictEqual(ls.compilerOptions, { - allowJs: true, allowNonTsExtensions: true, checkJs: true, strict: true, + module: ts.ModuleKind.ESNext, + moduleResolution: ts.ModuleResolutionKind.Node10, + target: ts.ScriptTarget.ESNext + }); + }); + + it('errors if tsconfig matches no svelte files', async () => { + const dirPath = getRandomVirtualDirPath(testDir); + const { virtualSystem, lsDocumentContext, rootUris } = setup(); + + virtualSystem.readDirectory = () => [path.join(dirPath, 'random.ts')]; + + virtualSystem.writeFile( + path.join(dirPath, 'tsconfig.json'), + JSON.stringify({ + include: ['**/*.ts'] + }) + ); + + virtualSystem.writeFile( + path.join(dirPath, 'random.svelte'), + '' + ); + + let called = false; + await getService(path.join(dirPath, 'random.svelte'), rootUris, { + ...lsDocumentContext, + reportConfigError: (message) => { + called = true; + assert.equal(message.uri, pathToUrl(path.join(dirPath, 'tsconfig.json'))); + } + }); + assert.ok(called); + }); + + it('does not report no svelte files when loaded through import', async () => { + const dirPath = getRandomVirtualDirPath(testDir); + const { virtualSystem, lsDocumentContext, rootUris } = setup(); + + virtualSystem.readDirectory = () => [path.join(dirPath, 'random.ts')]; + + virtualSystem.writeFile( + path.join(dirPath, 'tsconfig.json'), + JSON.stringify({ + include: ['**/*.ts'] + }) + ); + + virtualSystem.writeFile( + path.join(dirPath, 'random.svelte'), + '' + ); + + virtualSystem.writeFile( + path.join(dirPath, 'random.ts'), + 'import {} from "./random.svelte"' + ); + + let called = false; + const service = await getService(path.join(dirPath, 'random.svelte'), rootUris, { + ...lsDocumentContext, + reportConfigError: (message) => { + called = true; + assert.deepStrictEqual([], message.diagnostics); + } + }); + + assert.equal( + normalizePath(path.join(dirPath, 'tsconfig.json')), + normalizePath(service.tsconfigPath) + ); + assert.ok(called); + }); + + it('does not errors if referenced tsconfig matches no svelte files', async () => { + const dirPath = getRandomVirtualDirPath(testDir); + const { virtualSystem, lsDocumentContext, rootUris } = setup(); + + const tsPattern = '**/*.ts'; + const sveltePattern = '**/*.svelte'; + virtualSystem.readDirectory = (_path, _extensions, _excludes, include) => { + return include?.[0] === tsPattern + ? [path.join(dirPath, 'random.ts')] + : include?.[0] === sveltePattern + ? [path.join(dirPath, 'random.svelte')] + : []; + }; + + virtualSystem.writeFile( + path.join(dirPath, 'tsconfig.json'), + JSON.stringify({ + include: [], + references: [{ path: './tsconfig_node.json' }, { path: './tsconfig_web.json' }] + }) + ); + + virtualSystem.writeFile( + path.join(dirPath, 'tsconfig_node.json'), + JSON.stringify({ + include: [tsPattern] + }) + ); + + virtualSystem.writeFile( + path.join(dirPath, 'tsconfig_web.json'), + JSON.stringify({ + include: [sveltePattern] + }) + ); + + virtualSystem.writeFile( + path.join(dirPath, 'random.svelte'), + '' + ); + + let called = false; + const lsContainer = await getService(path.join(dirPath, 'random.svelte'), rootUris, { + ...lsDocumentContext, + reportConfigError: () => { + called = true; + } + }); + + assert.equal( + normalizePath(path.join(dirPath, 'tsconfig_web.json')), + lsContainer.tsconfigPath + ); + assert.equal(called, false, 'expected not to call reportConfigError'); + }); + + it('can loads default tsconfig', async () => { + const dirPath = getRandomVirtualDirPath(testDir); + const { lsDocumentContext, rootUris } = setup(); + + const ls = await getService( + path.join(dirPath, 'random.svelte'), + rootUris, + lsDocumentContext + ); + + assert.deepStrictEqual(ls.compilerOptions, { + allowJs: true, + allowSyntheticDefaultImports: true, + allowNonTsExtensions: true, + configFilePath: undefined, declaration: false, + maxNodeModuleJsDepth: 2, module: ts.ModuleKind.ESNext, moduleResolution: ts.ModuleResolutionKind.Node10, noEmit: true, @@ -93,6 +245,11 @@ describe('service', () => { }) ); + virtualSystem.writeFile( + path.join(dirPath, 'random.svelte'), + '' + ); + const ls = await getService( path.join(dirPath, 'random.svelte'), rootUris, @@ -125,21 +282,24 @@ describe('service', () => { function createReloadTester( docContext: LanguageServiceDocumentContext, - testAfterReload: () => Promise + testAfterReload: (reloadingConfigs: string[]) => Promise ) { let _resolve: () => void; - const reloadPromise = new Promise((resolve) => { + let _reject: (e: unknown) => void; + const reloadPromise = new Promise((resolve, reject) => { _resolve = resolve; + _reject = reject; }); return { docContextWithReload: { ...docContext, - async onProjectReloaded() { + async onProjectReloaded(reloadingConfigs: string[]) { try { - await testAfterReload(); - } finally { + await testAfterReload(reloadingConfigs); _resolve(); + } catch (e) { + _reject(e); } } }, @@ -161,6 +321,11 @@ describe('service', () => { }) ); + virtualSystem.writeFile( + path.join(dirPath, 'random.svelte'), + '' + ); + const { reloadPromise, docContextWithReload } = createReloadTester( { ...lsDocumentContext, watchTsConfig: true }, testAfterReload @@ -189,6 +354,8 @@ describe('service', () => { true, 'expected to reload compilerOptions' ); + + return true; } }); @@ -197,7 +364,7 @@ describe('service', () => { const { virtualSystem, lsDocumentContext, rootUris } = setup(); const tsconfigPath = path.join(dirPath, 'tsconfig.json'); const extend = './.svelte-kit/tsconfig.json'; - const extendedConfigPathFull = path.resolve(tsconfigPath, extend); + const extendedConfigPathFull = path.resolve(path.dirname(tsconfigPath), extend); virtualSystem.writeFile( tsconfigPath, @@ -206,6 +373,11 @@ describe('service', () => { }) ); + virtualSystem.writeFile( + path.join(dirPath, 'random.svelte'), + '' + ); + const { reloadPromise, docContextWithReload } = createReloadTester( { ...lsDocumentContext, watchTsConfig: true }, testAfterReload @@ -234,23 +406,78 @@ describe('service', () => { true, 'expected to reload compilerOptions' ); + return true; } }); - it('can open client file that do not exist in fs', async () => { + it('can watch project reference tsconfig', async () => { const dirPath = getRandomVirtualDirPath(testDir); const { virtualSystem, lsDocumentContext, rootUris } = setup(); + const tsconfigPath = path.join(dirPath, 'tsconfig.json'); + const referenced = './tsconfig_node.json'; + const referencedConfigPathFull = path.resolve(path.dirname(tsconfigPath), referenced); virtualSystem.writeFile( - path.join(dirPath, 'tsconfig.json'), + tsconfigPath, + JSON.stringify({ + references: [{ path: referenced }], + include: [] + }) + ); + + virtualSystem.writeFile( + referencedConfigPathFull, JSON.stringify({ compilerOptions: { - checkJs: true, strict: true + }, + files: ['random.ts'] + }) + ); + + const { reloadPromise, docContextWithReload } = createReloadTester( + { ...lsDocumentContext, watchTsConfig: true }, + testAfterReload + ); + + const tsFilePath = path.join(dirPath, 'random.ts'); + virtualSystem.writeFile(tsFilePath, 'const a: number = null;'); + + const ls = await getService(tsFilePath, rootUris, docContextWithReload); + assert.deepStrictEqual(getSemanticDiagnosticsMessages(ls, tsFilePath), [ + "Type 'null' is not assignable to type 'number'." + ]); + + virtualSystem.writeFile( + referencedConfigPathFull, + JSON.stringify({ + compilerOptions: { + strict: false } }) ); + await reloadPromise; + + async function testAfterReload(reloadingConfigs: string[]) { + if (!reloadingConfigs.includes(referencedConfigPathFull)) { + return false; + } + const newLs = await getService(tsFilePath, rootUris, { + ...lsDocumentContext, + watchTsConfig: true + }); + + assert.deepStrictEqual(getSemanticDiagnosticsMessages(newLs, tsFilePath), []); + return true; + } + }); + + it('can open client file that do not exist in fs', async () => { + const dirPath = getRandomVirtualDirPath(testDir); + const { lsDocumentContext, rootUris } = setup(); + + // don't need tsconfig because files doesn't exist in fs goes to a service with default config const ls = await getService( path.join(dirPath, 'random.svelte'), rootUris, @@ -266,6 +493,60 @@ describe('service', () => { }); }); + it('resolve module with source project reference redirect', async () => { + const dirPath = getRandomVirtualDirPath(testDir); + const { virtualSystem, lsDocumentContext, rootUris } = setup(); + + const package1 = path.join(dirPath, 'package1'); + + virtualSystem.writeFile( + path.join(package1, 'tsconfig.json'), + JSON.stringify({ + references: [{ path: '../package2' }], + files: ['index.ts'] + }) + ); + + const package2 = path.join(dirPath, 'package2'); + virtualSystem.writeFile( + path.join(package2, 'tsconfig.json'), + JSON.stringify({ + compilerOptions: { + composite: true, + strict: true + }, + files: ['index.ts'] + }) + ); + + const importing = path.join(package1, 'index.ts'); + virtualSystem.writeFile(importing, 'import { hi } from "package2"; hi((a) => `${a}`);'); + + const imported = path.join(package2, 'index.ts'); + virtualSystem.writeFile(imported, 'export function hi(cb: (num: number) => string) {}'); + + const package2Link = normalizePath(path.join(package1, 'node_modules', 'package2')); + virtualSystem.realpath = (p) => { + if (normalizePath(p).startsWith(package2Link)) { + const sub = p.substring(package2Link.length); + return path.join(package2) + sub; + } + + return p; + }; + + const fileExists = virtualSystem.fileExists; + virtualSystem.fileExists = (p) => { + const realPath = virtualSystem.realpath!(p); + + return fileExists(realPath); + }; + + const ls = await getService(importing, rootUris, lsDocumentContext); + + assert.deepStrictEqual(getSemanticDiagnosticsMessages(ls, importing), []); + }); + it('skip directory watching if directory is root', async () => { const dirPath = getRandomVirtualDirPath(path.join(testDir, 'Test')); const { virtualSystem, lsDocumentContext } = setup(); @@ -322,4 +603,91 @@ describe('service', () => { sinon.assert.calledWith(watchDirectory.firstCall, []); }); + + it('assigns files to service with the file in the program', async () => { + const dirPath = getRandomVirtualDirPath(testDir); + const { virtualSystem, lsDocumentContext, rootUris } = setup(); + + const tsconfigPath = path.join(dirPath, 'tsconfig.json'); + virtualSystem.writeFile( + tsconfigPath, + JSON.stringify({ + compilerOptions: { + noImplicitOverride: true + }, + include: ['src/*.ts'] + }) + ); + + const referencedFile = path.join(dirPath, 'anotherPackage', 'index.svelte'); + const tsFilePath = path.join(dirPath, 'src', 'random.ts'); + + virtualSystem.readDirectory = () => [tsFilePath]; + virtualSystem.writeFile( + referencedFile, + '' + ); + virtualSystem.writeFile(tsFilePath, 'import "../anotherPackage/index.svelte";'); + + const document = new Document( + pathToUrl(referencedFile), + virtualSystem.readFile(referencedFile)! + ); + document.openedByClient = true; + const ls = await getService(referencedFile, rootUris, lsDocumentContext); + ls.updateSnapshot(document); + + assert.equal(normalizePath(ls.tsconfigPath), normalizePath(tsconfigPath)); + + const noImplicitOverrideErrorCode = 4114; + const findError = (ls: LanguageServiceContainer) => + ls + .getService() + .getSemanticDiagnostics(referencedFile) + .find((f) => f.code === noImplicitOverrideErrorCode); + + assert.ok(findError(ls)); + + virtualSystem.writeFile(tsFilePath, ''); + ls.updateTsOrJsFile(tsFilePath); + + const ls2 = await getService(referencedFile, rootUris, lsDocumentContext); + ls2.updateSnapshot(document); + + assert.deepStrictEqual(findError(ls2), undefined); + }); + + it('assigns newly created files to the right service before the watcher trigger', async () => { + const dirPath = getRandomVirtualDirPath(testDir); + const { virtualSystem, lsDocumentContext, rootUris } = setup(); + + const tsconfigPath = path.join(dirPath, 'tsconfig.json'); + virtualSystem.writeFile( + tsconfigPath, + JSON.stringify({ + compilerOptions: {} + }) + ); + + const svelteFilePath = path.join(dirPath, 'random.svelte'); + + virtualSystem.writeFile(svelteFilePath, ''); + + const ls = await getService(svelteFilePath, rootUris, lsDocumentContext); + + assert.equal(normalizePath(ls.tsconfigPath), normalizePath(tsconfigPath)); + + const svelteFilePath2 = path.join(dirPath, 'random2.svelte'); + virtualSystem.writeFile(svelteFilePath2, ''); + + const ls2 = await getService(svelteFilePath2, rootUris, lsDocumentContext); + assert.equal(normalizePath(ls2.tsconfigPath), normalizePath(tsconfigPath)); + }); + + function getSemanticDiagnosticsMessages(ls: LanguageServiceContainer, filePath: string) { + return ls + .getService() + .getSemanticDiagnostics(filePath) + .map((d) => ts.flattenDiagnosticMessageText(d.messageText, '\n')); + } }); diff --git a/packages/language-server/test/plugins/typescript/svelte-sys.test.ts b/packages/language-server/test/plugins/typescript/svelte-sys.test.ts index 2da35db20..ba9a21d5a 100644 --- a/packages/language-server/test/plugins/typescript/svelte-sys.test.ts +++ b/packages/language-server/test/plugins/typescript/svelte-sys.test.ts @@ -29,18 +29,24 @@ describe('Svelte Sys', () => { } describe('#fileExists', () => { - it('should leave files with no .svelte.ts-ending as is', async () => { + it('should leave files with no .d.svelte.ts-ending as is', async () => { const { loader, fileExistsStub } = setupLoader(); loader.fileExists('../file.ts'); assert.strictEqual(fileExistsStub.getCall(0).args[0], '../file.ts'); }); - it('should convert .svelte.ts-endings', async () => { + it('should convert .d.svelte.ts-endings', async () => { const { loader, fileExistsStub } = setupLoader(); - loader.fileExists('../file.svelte.ts'); + fileExistsStub.onCall(0).returns(false); + fileExistsStub.onCall(1).returns(false); + fileExistsStub.onCall(2).returns(true); - assert.strictEqual(fileExistsStub.getCall(0).args[0], '../file.svelte'); + loader.fileExists('../file.d.svelte.ts'); + + assert.strictEqual(fileExistsStub.getCall(0).args[0], '../file.svelte.d.ts'); + assert.strictEqual(fileExistsStub.getCall(1).args[0], '../file.d.svelte.ts'); + assert.strictEqual(fileExistsStub.getCall(2).args[0], '../file.svelte'); }); }); }); diff --git a/packages/language-server/test/plugins/typescript/test-utils.ts b/packages/language-server/test/plugins/typescript/test-utils.ts index c77970256..f615f847f 100644 --- a/packages/language-server/test/plugins/typescript/test-utils.ts +++ b/packages/language-server/test/plugins/typescript/test-utils.ts @@ -6,8 +6,14 @@ import { DocumentManager, Document } from '../../../src/lib/documents'; import { FileMap } from '../../../src/lib/documents/fileCollection'; import { LSConfigManager } from '../../../src/ls-config'; import { LSAndTSDocResolver } from '../../../src/plugins'; -import { createGetCanonicalFileName, normalizePath, pathToUrl } from '../../../src/utils'; +import { + createGetCanonicalFileName, + normalizePath, + pathToUrl, + urlToPath +} from '../../../src/utils'; import { VERSION } from 'svelte/compiler'; +import { findTsConfigPath } from '../../../src/plugins/typescript/utils'; const isSvelte5Plus = Number(VERSION.split('.')[0]) >= 5; @@ -100,7 +106,7 @@ export function createVirtualTsSystem(currentDirectory: string): ts.System { ); } - const normalizedPath = normalizePath(toAbsolute(path)); + const normalizedPath = getCanonicalFileName(normalizePath(toAbsolute(path))); return Array.from(virtualFs.keys()).filter((fileName) => fileName.startsWith(normalizedPath) ); @@ -110,6 +116,11 @@ export function createVirtualTsSystem(currentDirectory: string): ts.System { return virtualSystem; function triggerWatch(normalizedPath: string, kind: ts.FileWatcherEventKind) { + // if watcher is not set yet. don't trigger it + if (!watchers.has(normalizedPath)) { + return; + } + let timeoutsOfPath = watchTimeout.get(normalizedPath); if (!timeoutsOfPath) { @@ -273,37 +284,56 @@ export async function createJsonSnapshotFormatter(dir: string) { }); } -export function serviceWarmup(suite: Mocha.Suite, testDir: string, rootUri = pathToUrl(testDir)) { +export function serviceWarmup( + suite: Mocha.Suite, + testDir: string, + rootUri = pathToUrl(testDir), + tsconfigPath: string | undefined = undefined +) { const defaultTimeout = suite.timeout(); // allow to set a higher timeout for slow machines from cli flag const warmupTimeout = Math.max(defaultTimeout, 5_000); suite.timeout(warmupTimeout); - before(async () => { + before(() => warmup(tsconfigPath)); + + suite.timeout(defaultTimeout); + + async function warmup(configFilePath: string | undefined = undefined) { const start = Date.now(); console.log('Warming up language service...'); const docManager = new DocumentManager( (textDocument) => new Document(textDocument.uri, textDocument.text) ); + const lsAndTsDocResolver = new LSAndTSDocResolver( docManager, [rootUri], new LSConfigManager() ); - const filePath = join(testDir, 'DoesNotMater.svelte'); - const document = docManager.openClientDocument({ - uri: pathToUrl(filePath), - text: ts.sys.readFile(filePath) || '' - }); + configFilePath ??= findTsConfigPath( + join(testDir, 'DoesNotMater.svelte'), + [rootUri], + ts.sys.fileExists, + createGetCanonicalFileName(ts.sys.useCaseSensitiveFileNames) + ); - await lsAndTsDocResolver.getLSAndTSDoc(document); + const ls = await lsAndTsDocResolver.getTSServiceByConfigPath( + configFilePath, + configFilePath ? dirname(configFilePath) : urlToPath(rootUri)! + ); + ls.getService(); - console.log(`Service warming up done in ${Date.now() - start}ms`); - }); + const projectReferences = ls.getResolvedProjectReferences(); - suite.timeout(defaultTimeout); + if (projectReferences.length) { + await Promise.all(projectReferences.map((ref) => warmup(ref.configFilePath))); + } + + console.log(`Service warming up done in ${Date.now() - start}ms`); + } } export function recursiveServiceWarmup( diff --git a/packages/language-server/test/plugins/typescript/testfiles/diagnostics/different-ts-service/tsconfig.json b/packages/language-server/test/plugins/typescript/testfiles/diagnostics/different-ts-service/tsconfig.json index 6d3385d79..04d6ed3d5 100644 --- a/packages/language-server/test/plugins/typescript/testfiles/diagnostics/different-ts-service/tsconfig.json +++ b/packages/language-server/test/plugins/typescript/testfiles/diagnostics/different-ts-service/tsconfig.json @@ -1,5 +1,6 @@ { "compilerOptions": { + "allowJs": true, /** This is actually not needed, but makes the tests faster because TS does not look up other types. diff --git a/packages/language-server/test/plugins/typescript/testfiles/diagnostics/tsconfig.json b/packages/language-server/test/plugins/typescript/testfiles/diagnostics/tsconfig.json index 89dd24236..8cd68407b 100644 --- a/packages/language-server/test/plugins/typescript/testfiles/diagnostics/tsconfig.json +++ b/packages/language-server/test/plugins/typescript/testfiles/diagnostics/tsconfig.json @@ -1,5 +1,7 @@ { "compilerOptions": { + "allowJs": true, + "target": "ESNext", "strict": true, /** This is actually not needed, but makes the tests faster diff --git a/packages/language-server/test/plugins/typescript/testfiles/preferences/code-action-outside-root.svelte b/packages/language-server/test/plugins/typescript/testfiles/preferences/code-action-outside-root.svelte new file mode 100644 index 000000000..cb38cfe93 --- /dev/null +++ b/packages/language-server/test/plugins/typescript/testfiles/preferences/code-action-outside-root.svelte @@ -0,0 +1,4 @@ + \ No newline at end of file diff --git a/packages/language-server/test/plugins/typescript/testfiles/tsconfig.json b/packages/language-server/test/plugins/typescript/testfiles/tsconfig.json index 63ec98505..03afba4d9 100644 --- a/packages/language-server/test/plugins/typescript/testfiles/tsconfig.json +++ b/packages/language-server/test/plugins/typescript/testfiles/tsconfig.json @@ -1,5 +1,7 @@ { "compilerOptions": { + "allowJs": true, + "target": "ESNext", "strict": true, /** This is actually not needed, but makes the tests faster diff --git a/packages/svelte-check/package.json b/packages/svelte-check/package.json index 9d8309c46..b49d294a2 100644 --- a/packages/svelte-check/package.json +++ b/packages/svelte-check/package.json @@ -1,7 +1,7 @@ { "name": "svelte-check", "description": "Svelte Code Checker Terminal Interface", - "version": "3.0.0", + "version": "4.0.0", "main": "./dist/src/index.js", "bin": "./bin/svelte-check", "author": "The Svelte Community", @@ -22,16 +22,19 @@ "url": "https://github.com/sveltejs/language-tools/issues" }, "homepage": "https://github.com/sveltejs/language-tools#readme", + "engines": { + "node": ">= 18.0.0" + }, "dependencies": { - "@jridgewell/trace-mapping": "^0.3.17", - "chokidar": "^3.4.1", + "@jridgewell/trace-mapping": "^0.3.25", + "chokidar": "^4.0.1", + "fdir": "^6.2.0", "picocolors": "^1.0.0", - "sade": "^1.7.4", - "svelte-preprocess": "^5.1.3", - "typescript": "^5.0.3" + "sade": "^1.7.4" }, "peerDependencies": { - "svelte": "^3.55.0 || ^4.0.0-next.0 || ^4.0.0 || ^5.0.0-next.0" + "svelte": "^4.0.0 || ^5.0.0-next.0", + "typescript": ">=5.0.0" }, "scripts": { "build": "rollup -c && node ./dist/src/index.js --workspace ./test --tsconfig ./tsconfig.json", @@ -46,11 +49,12 @@ "@rollup/plugin-typescript": "^10.0.0", "@types/sade": "^1.7.2", "builtin-modules": "^3.3.0", - "fast-glob": "^3.2.7", "rollup": "3.7.5", "rollup-plugin-cleanup": "^3.2.0", "rollup-plugin-copy": "^3.4.0", + "svelte": "^4.2.19", "svelte-language-server": "workspace:*", + "typescript": "^5.5.2", "vscode-languageserver": "8.0.2", "vscode-languageserver-protocol": "3.17.2", "vscode-languageserver-types": "3.17.2", diff --git a/packages/svelte-check/rollup.config.mjs b/packages/svelte-check/rollup.config.mjs index 2488f2bae..e5346edee 100644 --- a/packages/svelte-check/rollup.config.mjs +++ b/packages/svelte-check/rollup.config.mjs @@ -65,7 +65,6 @@ export default [ 'sade', 'svelte', 'svelte/compiler', - 'svelte-preprocess', '@jridgewell/trace-mapping' // import-fresh removed some time ago, no dependency uses it anymore. // if it creeps back in check if the dependency uses a version that diff --git a/packages/svelte-check/src/index.ts b/packages/svelte-check/src/index.ts index 6e64414ed..f2aeb79fb 100644 --- a/packages/svelte-check/src/index.ts +++ b/packages/svelte-check/src/index.ts @@ -4,7 +4,7 @@ import { watch } from 'chokidar'; import * as fs from 'fs'; -import glob from 'fast-glob'; +import { fdir } from 'fdir'; import * as path from 'path'; import { SvelteCheck, SvelteCheckOptions } from 'svelte-language-server'; import { Diagnostic, DiagnosticSeverity } from 'vscode-languageserver-protocol'; @@ -30,11 +30,27 @@ async function openAllDocuments( filePathsToIgnore: string[], svelteCheck: SvelteCheck ) { - const files = await glob('**/*.svelte', { - cwd: workspaceUri.fsPath, - ignore: ['node_modules/**'].concat(filePathsToIgnore.map((ignore) => `${ignore}/**`)) - }); - const absFilePaths = files.map((f) => path.resolve(workspaceUri.fsPath, f)); + const offset = workspaceUri.fsPath.length + 1; + // We support a very limited subset of glob patterns: You can only have ** at the end or the start + const ignored = createIgnored(filePathsToIgnore); + const isIgnored = (path: string) => { + path = path.slice(offset); + for (const i of ignored) { + if (i(path)) { + return true; + } + } + return false; + }; + const absFilePaths = await new fdir() + .filter((path) => path.endsWith('.svelte') && !isIgnored(path)) + .exclude((_, path) => { + return path.includes('/node_modules/') || path.includes('/.'); + }) + .withPathSeparator('/') + .withFullPaths() + .crawl(workspaceUri.fsPath) + .withPromise(); for (const absFilePath of absFilePaths) { const text = fs.readFileSync(absFilePath, 'utf-8'); @@ -48,6 +64,30 @@ async function openAllDocuments( } } +function createIgnored(filePathsToIgnore: string[]): Array<(path: string) => boolean> { + return filePathsToIgnore.map((i) => { + if (i.endsWith('**')) i = i.slice(0, -2); + + if (i.startsWith('**')) { + i = i.slice(2); + + if (i.includes('*')) + throw new Error( + 'Invalid svelte-check --ignore pattern: Only ** at the start or end is supported' + ); + + return (path) => path.includes(i); + } + + if (i.includes('*')) + throw new Error( + 'Invalid svelte-check --ignore pattern: Only ** at the start or end is supported' + ); + + return (path) => path.startsWith(i); + }); +} + async function getDiagnostics( workspaceUri: URI, writer: Writer, @@ -113,10 +153,32 @@ class DiagnosticsWatcher { filePathsToIgnore: string[], ignoreInitialAdd: boolean ) { - watch(`${workspaceUri.fsPath}/**/*.{svelte,d.ts,ts,js,jsx,tsx,mjs,cjs,mts,cts}`, { - ignored: ['node_modules', 'vite.config.{js,ts}.timestamp-*'] - .concat(filePathsToIgnore) - .map((ignore) => path.join(workspaceUri.fsPath, ignore)), + const fileEnding = /\.(svelte|d\.ts|ts|js|jsx|tsx|mjs|cjs|mts|cts)$/; + const viteConfigRegex = /vite\.config\.(js|ts)\.timestamp-/; + const userIgnored = createIgnored(filePathsToIgnore); + const offset = workspaceUri.fsPath.length + 1; + + watch(workspaceUri.fsPath, { + ignored: (path, stats) => { + if ( + path.includes('node_modules') || + path.includes('.git') || + (stats?.isFile() && (!fileEnding.test(path) || viteConfigRegex.test(path))) + ) { + return true; + } + + if (userIgnored.length !== 0) { + path = path.slice(offset); + for (const i of userIgnored) { + if (i(path)) { + return true; + } + } + } + + return false; + }, ignoreInitial: ignoreInitialAdd }) .on('add', (path) => this.updateDocument(path, true)) diff --git a/packages/svelte-check/src/options.ts b/packages/svelte-check/src/options.ts index bf270e3c4..b43dd7695 100644 --- a/packages/svelte-check/src/options.ts +++ b/packages/svelte-check/src/options.ts @@ -67,13 +67,19 @@ export function parseOptions(cb: (opts: SvelteCheckCliOptions) => any) { ) .action((opts) => { const workspaceUri = getWorkspaceUri(opts); + const tsconfig = getTsconfig(opts, workspaceUri.fsPath); + + if (opts.ignore && tsconfig) { + throwError('`--ignore` only has an effect when using `--no-tsconfig`'); + } + cb({ workspaceUri, outputFormat: getOutputFormat(opts), watch: !!opts.watch, preserveWatchOutput: !!opts.preserveWatchOutput, - tsconfig: getTsconfig(opts, workspaceUri.fsPath), - filePathsToIgnore: getFilepathsToIgnore(opts), + tsconfig, + filePathsToIgnore: opts.ignore?.split(',') || [], failOnWarnings: !!opts['fail-on-warnings'], compilerWarnings: getCompilerWarnings(opts), diagnosticSources: getDiagnosticSources(opts), @@ -141,11 +147,15 @@ function getTsconfig(myArgs: Record, workspacePath: string) { tsconfig = path.join(workspacePath, tsconfig); } if (tsconfig && !fs.existsSync(tsconfig)) { - throw new Error('Could not find tsconfig/jsconfig file at ' + myArgs.tsconfig); + throwError('Could not find tsconfig/jsconfig file at ' + myArgs.tsconfig); } return tsconfig; } +function throwError(msg: string) { + throw new Error('Invalid svelte-check CLI args: ' + msg); +} + function getCompilerWarnings(opts: Record) { return stringToObj(opts['compiler-warnings']); @@ -180,10 +190,6 @@ function getDiagnosticSources(opts: Record): DiagnosticSource[] { : diagnosticSources; } -function getFilepathsToIgnore(opts: Record): string[] { - return opts.ignore?.split(',') || []; -} - const thresholds = ['warning', 'error'] as const; type Threshold = (typeof thresholds)[number]; diff --git a/packages/svelte-check/src/writers.ts b/packages/svelte-check/src/writers.ts index 37c6823b8..af1fd89d8 100644 --- a/packages/svelte-check/src/writers.ts +++ b/packages/svelte-check/src/writers.ts @@ -57,14 +57,9 @@ export class HumanFriendlyWriter implements Writer { `${workspaceDir}${sep}${pc.green(filename)}:${line + 1}:${character + 1}\n` ); - // Show some context around diagnostic range - const codePrevLine = this.getLine(diagnostic.range.start.line - 1, text); - const codeLine = this.getCodeLine(diagnostic, text); - const codeNextLine = this.getLine(diagnostic.range.end.line + 1, text); - const code = codePrevLine + codeLine + codeNextLine; - let msg; if (this.isVerbose) { + const code = this.formatRelatedCode(diagnostic, text); msg = `${diagnostic.message} ${source}\n${pc.cyan(code)}`; } else { msg = `${diagnostic.message} ${source}`; @@ -80,6 +75,20 @@ export class HumanFriendlyWriter implements Writer { }); } + private formatRelatedCode(diagnostic: Diagnostic, text: string) { + if (!text) { + return ''; + } + + // Show some context around diagnostic range + const codePrevLine = this.getLine(diagnostic.range.start.line - 1, text); + const codeLine = this.getCodeLine(diagnostic, text); + const codeNextLine = this.getLine(diagnostic.range.end.line + 1, text); + const code = codePrevLine + codeLine + codeNextLine; + + return code; + } + private getCodeLine(diagnostic: Diagnostic, text: string) { const startOffset = offsetAt(diagnostic.range.start, text); const endOffset = offsetAt(diagnostic.range.end, text); diff --git a/packages/svelte-check/test/tsconfig.json b/packages/svelte-check/test/tsconfig.json index 15458e89c..86649d013 100644 --- a/packages/svelte-check/test/tsconfig.json +++ b/packages/svelte-check/test/tsconfig.json @@ -1,6 +1,6 @@ { - "extends": "@tsconfig/node12/tsconfig.json", "compilerOptions": { + "target": "ESNext", "moduleResolution": "node", "strict": true, "allowJs": true, diff --git a/packages/svelte-vscode/package.json b/packages/svelte-vscode/package.json index 27ed07e9e..a39165e17 100644 --- a/packages/svelte-vscode/package.json +++ b/packages/svelte-vscode/package.json @@ -37,7 +37,7 @@ "Formatters" ], "engines": { - "vscode": "^1.67.0" + "vscode": "^1.82.0" }, "activationEvents": [ "onLanguage:svelte", @@ -718,7 +718,7 @@ }, "devDependencies": { "@types/lodash": "^4.14.116", - "@types/node": "^16.0.0", + "@types/node": "^18.0.0", "@types/vscode": "^1.67", "js-yaml": "^3.14.0", "tslib": "^2.4.0", @@ -729,7 +729,7 @@ "lodash": "^4.17.21", "svelte-language-server": "workspace:*", "typescript-svelte-plugin": "workspace:*", - "vscode-languageclient": "^8.0.0", - "vscode-languageserver-protocol": "3.17.2" + "vscode-languageclient": "^9.0.1", + "vscode-languageserver-protocol": "3.17.5" } } diff --git a/packages/svelte-vscode/src/html/autoClose.ts b/packages/svelte-vscode/src/html/autoClose.ts index 1dc71b2b3..281bb600f 100644 --- a/packages/svelte-vscode/src/html/autoClose.ts +++ b/packages/svelte-vscode/src/html/autoClose.ts @@ -26,7 +26,7 @@ export function activateTagClosing( updateEnabledState(); window.onDidChangeActiveTextEditor(updateEnabledState, null, disposables); - let timeout: NodeJS.Timer | undefined = void 0; + let timeout: NodeJS.Timeout | undefined = void 0; function updateEnabledState() { isEnabled = false; diff --git a/packages/svelte2tsx/package.json b/packages/svelte2tsx/package.json index 34d5ef7be..258f5397e 100644 --- a/packages/svelte2tsx/package.json +++ b/packages/svelte2tsx/package.json @@ -18,26 +18,26 @@ "module": "index.mjs", "types": "index.d.ts", "devDependencies": { - "@jridgewell/sourcemap-codec": "^1.4.14", - "@jridgewell/trace-mapping": "^0.3.17", + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.25", "@rollup/plugin-commonjs": "^24.0.0", "@rollup/plugin-json": "^6.0.0", "@rollup/plugin-node-resolve": "^15.0.0", "@rollup/plugin-typescript": "^10.0.0", "@types/estree": "^0.0.42", "@types/mocha": "^9.1.0", - "@types/node": "^16.0.0", + "@types/node": "^18.0.0", "@types/unist": "^2.0.3", "@types/vfile": "^3.0.2", "builtin-modules": "^3.3.0", "estree-walker": "^2.0.1", - "magic-string": "^0.27.0", + "magic-string": "^0.30.11", "mocha": "^9.2.0", "periscopic": "^2.0.2", "rollup": "3.7.5", "rollup-plugin-delete": "^2.0.0", "source-map-support": "^0.5.16", - "svelte": "~3.57.0", + "svelte": "~4.2.19", "tiny-glob": "^0.2.6", "tslib": "^2.4.0", "typescript": "^5.5.2" diff --git a/packages/svelte2tsx/src/emitDts.ts b/packages/svelte2tsx/src/emitDts.ts index 91b254f39..3740a66c3 100644 --- a/packages/svelte2tsx/src/emitDts.ts +++ b/packages/svelte2tsx/src/emitDts.ts @@ -18,7 +18,13 @@ export async function emitDts(config: EmitDtsConfig) { const likely_failed_files = result.diagnostics.filter((diagnostic) => { // List of errors which hint at a failed d.ts generation // https://github.com/microsoft/TypeScript/blob/main/src/compiler/diagnosticMessages.json - return diagnostic.code === 2527 || (diagnostic.code >= 4000 && diagnostic.code <= 4108); + return ( + diagnostic.code === 2527 || + diagnostic.code === 5088 || + diagnostic.code === 2742 || + (diagnostic.code >= 9005 && diagnostic.code <= 9039) || + (diagnostic.code >= 4000 && diagnostic.code <= 4108) + ); }); if (likely_failed_files.length > 0) { diff --git a/packages/svelte2tsx/src/htmlxtojsx_v2/utils/node-utils.ts b/packages/svelte2tsx/src/htmlxtojsx_v2/utils/node-utils.ts index c523a53f2..d3c95164a 100644 --- a/packages/svelte2tsx/src/htmlxtojsx_v2/utils/node-utils.ts +++ b/packages/svelte2tsx/src/htmlxtojsx_v2/utils/node-utils.ts @@ -233,7 +233,7 @@ export function rangeWithTrailingPropertyAccess( * Get the end of the node, excluding the type annotation */ export function getEnd(node: any) { - return isTypescriptNode(node) ? node.expression.end : node.typeAnnotation?.start ?? node.end; + return isTypescriptNode(node) ? node.expression.end : (node.typeAnnotation?.start ?? node.end); } export function isTypescriptNode(node: any) { diff --git a/packages/svelte2tsx/src/svelte2tsx/addComponentExport.ts b/packages/svelte2tsx/src/svelte2tsx/addComponentExport.ts index 4cbf2b980..fc9550b77 100644 --- a/packages/svelte2tsx/src/svelte2tsx/addComponentExport.ts +++ b/packages/svelte2tsx/src/svelte2tsx/addComponentExport.ts @@ -5,15 +5,16 @@ import { ExportedNames } from './nodes/ExportedNames'; import { ComponentDocumentation } from './nodes/ComponentDocumentation'; import { Generics } from './nodes/Generics'; import { surroundWithIgnoreComments } from '../utils/ignore'; +import { ComponentEvents } from './nodes/ComponentEvents'; export interface AddComponentExportPara { str: MagicString; canHaveAnyProp: boolean; /** - * If true, not fallback to `any` + * If strictEvents true, not fallback to `any` * -> all unknown events will throw a type error * */ - strictEvents: boolean; + events: ComponentEvents; isTsFile: boolean; usesAccessors: boolean; exportedNames: ExportedNames; @@ -41,7 +42,7 @@ export function addComponentExport(params: AddComponentExportPara) { } function addGenericsComponentExport({ - strictEvents, + events, canHaveAnyProp, exportedNames, componentDocumentation, @@ -70,7 +71,7 @@ class __sveltets_Render${genericsDef} { return ${props(true, canHaveAnyProp, exportedNames, `render${genericsRef}()`)}.props; } events() { - return ${events(strictEvents, `render${genericsRef}()`)}.events; + return ${_events(events.hasStrictEvents() || exportedNames.usesRunes(), `render${genericsRef}()`)}.events; } slots() { return render${genericsRef}().slots; @@ -94,15 +95,29 @@ ${ if (isSvelte5) { // Don't add props/events/slots type exports in dts mode for now, maybe someone asks for it to be back, // but it's safer to not do it for now to have more flexibility in the future. + let eventsSlotsType = []; + if (events.hasEvents() || !exportedNames.usesRunes()) { + eventsSlotsType.push(`$$events?: ${returnType('events')}`); + } + if (usesSlots) { + eventsSlotsType.push(`$$slots?: ${returnType('slots')}`); + eventsSlotsType.push(`children?: any`); + } const propsType = !canHaveAnyProp && exportedNames.hasNoProps() - ? `{$$events?: ${returnType('events')}${usesSlots ? `, $$slots?: ${returnType('slots')}, children?: any` : ''}}` - : `${returnType('props')} & {$$events?: ${returnType('events')}${usesSlots ? `, $$slots?: ${returnType('slots')}, children?: any` : ''}}`; + ? `{${eventsSlotsType.join(', ')}}` + : `${returnType('props')} & {${eventsSlotsType.join(', ')}}`; + const bindingsType = `ReturnType<__sveltets_Render${generics.toReferencesAnyString()}['bindings']>`; + + // Sadly, due to a combination of requirements and TypeScript limitations, we need to always create both a legacy class component and function component type. + // - Constraints: Need to support Svelte 4 class component types, therefore we need to use __sveltets_2_ensureComponent to transform function components to classes + // - Limitations: TypeScript is not able to preserve generics during said transformation (i.e. there's no way to express keeping the generic etc) + // TODO Svelte 6/7: Switch this around and not use new Component in svelte2tsx anymore, which means we can remove the legacy class component. We need something like _ensureFnComponent then. statement += `\ninterface $$IsomorphicComponent {\n` + ` new ${genericsDef}(options: import('svelte').ComponentConstructorOptions<${returnType('props') + (usesSlots ? '& {children?: any}' : '')}>): import('svelte').SvelteComponent<${returnType('props')}, ${returnType('events')}, ${returnType('slots')}> & { $$bindings?: ${returnType('bindings')} } & ${returnType('exports')};\n` + ` ${genericsDef}(internal: unknown, props: ${propsType}): ${returnType('exports')};\n` + - ` z_$$bindings?: ReturnType<__sveltets_Render${generics.toReferencesAnyString()}['bindings']>;\n` + + ` z_$$bindings?: ${bindingsType};\n` + `}\n` + `${doc}const ${className || '$$Component'}: $$IsomorphicComponent = null as any;\n` + surroundWithIgnoreComments( @@ -137,7 +152,7 @@ ${ } function addSimpleComponentExport({ - strictEvents, + events, isTsFile, canHaveAnyProp, exportedNames, @@ -154,7 +169,7 @@ function addSimpleComponentExport({ isTsFile, canHaveAnyProp, exportedNames, - events(strictEvents, 'render()') + _events(events.hasStrictEvents(), 'render()') ); const doc = componentDocumentation.getFormatted(); @@ -162,7 +177,11 @@ function addSimpleComponentExport({ let statement: string; if (mode === 'dts') { - if (isSvelte5) { + if (isSvelte5 && exportedNames.usesRunes() && !usesSlots && !events.hasEvents()) { + statement = + `\n${doc}const ${className || '$$Component'} = __sveltets_2_fn_component(render());\n` + + `export default ${className || '$$Component'};`; + } else if (isSvelte5) { // Inline definitions from Svelte shims; else dts files will reference the globals which will be unresolved statement = `\ninterface $$__sveltets_2_IsomorphicComponent = any, Events extends Record = any, Slots extends Record = any, Exports = {}, Bindings = string> { @@ -223,12 +242,18 @@ declare function $$__sveltets_2_isomorphic_component< } } else { if (isSvelte5) { - statement = - `\n${doc}const ${className || '$$Component'} = __sveltets_2_isomorphic_component${usesSlots ? '_slots' : ''}(${propDef});\n` + - surroundWithIgnoreComments( - `type ${className || '$$Component'} = InstanceType;\n` - ) + - `export default ${className || '$$Component'};`; + if (exportedNames.usesRunes() && !usesSlots && !events.hasEvents()) { + statement = + `\n${doc}const ${className || '$$Component'} = __sveltets_2_fn_component(render());\n` + + `export default ${className || '$$Component'};`; + } else { + statement = + `\n${doc}const ${className || '$$Component'} = __sveltets_2_isomorphic_component${usesSlots ? '_slots' : ''}(${propDef});\n` + + surroundWithIgnoreComments( + `type ${className || '$$Component'} = InstanceType;\n` + ) + + `export default ${className || '$$Component'};`; + } } else { statement = `\n\n${doc}export default class${ @@ -281,7 +306,7 @@ function addTypeExport( } } -function events(strictEvents: boolean, renderStr: string) { +function _events(strictEvents: boolean, renderStr: string) { return strictEvents ? renderStr : `__sveltets_2_with_any_event(${renderStr})`; } diff --git a/packages/svelte2tsx/src/svelte2tsx/index.ts b/packages/svelte2tsx/src/svelte2tsx/index.ts index e6410d661..91e0d6b5a 100644 --- a/packages/svelte2tsx/src/svelte2tsx/index.ts +++ b/packages/svelte2tsx/src/svelte2tsx/index.ts @@ -435,7 +435,7 @@ export function svelte2tsx( addComponentExport({ str, canHaveAnyProp: !exportedNames.uses$$Props && (uses$$props || uses$$restProps), - strictEvents: events.hasStrictEvents(), // TODO in Svelte 6 we should also apply strictEvents in runes mode + events, isTsFile: options?.isTsFile, exportedNames, usesAccessors, diff --git a/packages/svelte2tsx/src/svelte2tsx/nodes/ComponentEvents.ts b/packages/svelte2tsx/src/svelte2tsx/nodes/ComponentEvents.ts index b2bb18e8e..a83dc9df0 100644 --- a/packages/svelte2tsx/src/svelte2tsx/nodes/ComponentEvents.ts +++ b/packages/svelte2tsx/src/svelte2tsx/nodes/ComponentEvents.ts @@ -77,6 +77,10 @@ export class ComponentEvents { this.componentEventsInterface.setComponentEventsInterface(node, this.str, astOffset); } + hasEvents(): boolean { + return this.eventsClass.events.size > 0; + } + hasStrictEvents(): boolean { return this.componentEventsInterface.isPresent() || this.strictEvents; } diff --git a/packages/svelte2tsx/src/svelte2tsx/nodes/ExportedNames.ts b/packages/svelte2tsx/src/svelte2tsx/nodes/ExportedNames.ts index d461ecd66..3f5ec412a 100644 --- a/packages/svelte2tsx/src/svelte2tsx/nodes/ExportedNames.ts +++ b/packages/svelte2tsx/src/svelte2tsx/nodes/ExportedNames.ts @@ -793,7 +793,7 @@ export class ExportedNames { } hasPropsRune() { - return this.isSvelte5Plus && (this.$props.type || this.$props.comment); + return this.isSvelte5Plus && !!(this.$props.type || this.$props.comment); } checkGlobalsForRunes(globals: string[]) { diff --git a/packages/svelte2tsx/svelte-jsx.d.ts b/packages/svelte2tsx/svelte-jsx.d.ts index 68307ae47..5c576f715 100644 --- a/packages/svelte2tsx/svelte-jsx.d.ts +++ b/packages/svelte2tsx/svelte-jsx.d.ts @@ -1,4 +1,6 @@ /// +// @ts-nocheck +// nocheck because we don't want to adjust this anymore (only used for Svelte 3) declare namespace svelteHTML { diff --git a/packages/svelte2tsx/svelte-shims-v4.d.ts b/packages/svelte2tsx/svelte-shims-v4.d.ts index e8e276255..2d36a539d 100644 --- a/packages/svelte2tsx/svelte-shims-v4.d.ts +++ b/packages/svelte2tsx/svelte-shims-v4.d.ts @@ -59,7 +59,6 @@ type KeysMatching = {[K in keyof Obj]-?: Obj[K] extends V ? K : never}[k /** @internal PRIVATE API, DO NOT USE */ declare type __sveltets_2_CustomEvents = {[K in KeysMatching]: T[K] extends CustomEvent ? T[K]['detail']: T[K]} -declare var process: NodeJS.Process & { browser: boolean } declare function __sveltets_2_ensureRightProps(props: Props): {}; declare function __sveltets_2_instanceOf(type: AConstructorTypeOf): T; declare function __sveltets_2_allPropsType(): SvelteAllProps @@ -208,7 +207,7 @@ declare type ATypedSvelteComponent = { */ $$slot_def: any; - $on(event: string, handler: ((e: any) => any) | null | undefined): () => void; + $on(event: string, handler: any): () => void; } /** * Ambient type only used for intellisense, DO NOT USE IN YOUR PROJECT. @@ -221,11 +220,36 @@ declare type ATypedSvelteComponent = { * ``` */ declare type ConstructorOfATypedSvelteComponent = new (args: {target: any, props?: any}) => ATypedSvelteComponent +// Usage note: Cannot properly transform generic function components to class components due to TypeScript limitations declare function __sveltets_2_ensureComponent< - // @ts-ignore svelte.Component doesn't exist in Svelte 4 - T extends ConstructorOfATypedSvelteComponent | (0 extends (1 & import('svelte').Component) ? never : import('svelte').Component) | null | undefined - // @ts-ignore svelte.Component doesn't exist in Svelte 4 ->(type: T): NonNullable ? typeof import('svelte').SvelteComponent : T>; + T extends + | ConstructorOfATypedSvelteComponent + | (typeof import('svelte') extends { mount: any } + ? // @ts-ignore svelte.Component doesn't exist in Svelte 4 + import('svelte').Component + : never) + | null + | undefined +>( + type: T +): NonNullable< + T extends ConstructorOfATypedSvelteComponent + ? T + : typeof import('svelte') extends { mount: any } + ? // @ts-ignore svelte.Component doesn't exist in Svelte 4 + T extends import('svelte').Component< + infer Props extends Record, + infer Exports extends Record, + infer Bindings extends string + > + ? new ( + options: import('svelte').ComponentConstructorOptions + ) => import('svelte').SvelteComponent & + Exports & { $$bindings: Bindings } + : never + : never +>; + declare function __sveltets_2_ensureArray | Iterable>(array: T): T extends ArrayLike ? U[] : T extends Iterable ? Iterable : any[]; type __sveltets_2_PropsWithChildren = Props & @@ -241,6 +265,11 @@ declare function __sveltets_2_runes_constructor(render: {props declare function __sveltets_$$bindings(...bindings: Bindings): Bindings[number]; +declare function __sveltets_2_fn_component< + Props extends Record, Exports extends Record, Bindings extends string + // @ts-ignore Svelte 5 only +>(klass: {props: Props, exports?: Exports, bindings?: Bindings }): import('svelte').Component; + interface __sveltets_2_IsomorphicComponent = any, Events extends Record = any, Slots extends Record = any, Exports = {}, Bindings = string> { new (options: import('svelte').ComponentConstructorOptions): import('svelte').SvelteComponent & { $$bindings?: Bindings } & Exports; (internal: unknown, props: Props extends Record ? {$$events?: Events, $$slots?: Slots} : Props & {$$events?: Events, $$slots?: Slots}): Exports & { $set?: any, $on?: any }; diff --git a/packages/svelte2tsx/svelte-shims.d.ts b/packages/svelte2tsx/svelte-shims.d.ts index a8066b0a7..b7be2cbcc 100644 --- a/packages/svelte2tsx/svelte-shims.d.ts +++ b/packages/svelte2tsx/svelte-shims.d.ts @@ -1,3 +1,5 @@ +// @ts-nocheck +// nocheck because we don't want to adjust this anymore (only used for Svelte 3) // Whenever a ambient declaration changes, its number should be increased // This way, we avoid the situation where multiple ambient versions of svelte2tsx // are loaded and their declarations conflict each other @@ -138,7 +140,6 @@ type KeysMatching = {[K in keyof Obj]-?: Obj[K] extends V ? K : never}[k /** @internal PRIVATE API, DO NOT USE */ declare type __sveltets_2_CustomEvents = {[K in KeysMatching]: T[K] extends CustomEvent ? T[K]['detail']: T[K]} -declare var process: NodeJS.Process & { browser: boolean } declare function __sveltets_2_ensureRightProps(props: Props): {}; declare function __sveltets_2_instanceOf(type: AConstructorTypeOf): T; declare function __sveltets_2_allPropsType(): SvelteAllProps diff --git a/packages/svelte2tsx/test/emitDts/samples/javascript-runes.v5/expected/TestRunes.svelte.d.ts b/packages/svelte2tsx/test/emitDts/samples/javascript-runes.v5/expected/TestRunes.svelte.d.ts index 6c3b7250e..04808233f 100644 --- a/packages/svelte2tsx/test/emitDts/samples/javascript-runes.v5/expected/TestRunes.svelte.d.ts +++ b/packages/svelte2tsx/test/emitDts/samples/javascript-runes.v5/expected/TestRunes.svelte.d.ts @@ -1,23 +1,7 @@ -interface $$__sveltets_2_IsomorphicComponent = any, Events extends Record = any, Slots extends Record = any, Exports = {}, Bindings = string> { - new (options: import('svelte').ComponentConstructorOptions): import('svelte').SvelteComponent & { - $$bindings?: Bindings; - } & Exports; - (internal: unknown, props: Props & { - $$events?: Events; - $$slots?: Slots; - }): Exports & { - $set?: any; - $on?: any; - }; - z_$$bindings?: Bindings; -} -declare const TestRunes: $$__sveltets_2_IsomorphicComponent<{ +declare const TestRunes: import("svelte").Component<{ foo: string; bar?: number; }, { - [evt: string]: CustomEvent; -}, {}, { baz: () => void; }, "bar">; -type TestRunes = InstanceType; export default TestRunes; diff --git a/packages/svelte2tsx/test/emitDts/samples/typescript-runes-generics.v5/expected/TestRunes.svelte.d.ts b/packages/svelte2tsx/test/emitDts/samples/typescript-runes-generics.v5/expected/TestRunes.svelte.d.ts index 6f01eae42..296b24ab4 100644 --- a/packages/svelte2tsx/test/emitDts/samples/typescript-runes-generics.v5/expected/TestRunes.svelte.d.ts +++ b/packages/svelte2tsx/test/emitDts/samples/typescript-runes-generics.v5/expected/TestRunes.svelte.d.ts @@ -3,9 +3,7 @@ declare class __sveltets_Render, K extends keyof T foo: T; bar?: K; }; - events(): {} & { - [evt: string]: CustomEvent; - }; + events(): {}; slots(): {}; bindings(): "bar"; exports(): { @@ -16,9 +14,7 @@ interface $$IsomorphicComponent { new , K extends keyof T>(options: import('svelte').ComponentConstructorOptions['props']>>): import('svelte').SvelteComponent['props']>, ReturnType<__sveltets_Render['events']>, ReturnType<__sveltets_Render['slots']>> & { $$bindings?: ReturnType<__sveltets_Render['bindings']>; } & ReturnType<__sveltets_Render['exports']>; - , K extends keyof T>(internal: unknown, props: ReturnType<__sveltets_Render['props']> & { - $$events?: ReturnType<__sveltets_Render['events']>; - }): ReturnType<__sveltets_Render['exports']>; + , K extends keyof T>(internal: unknown, props: ReturnType<__sveltets_Render['props']> & {}): ReturnType<__sveltets_Render['exports']>; z_$$bindings?: ReturnType<__sveltets_Render['bindings']>; } declare const TestRunes: $$IsomorphicComponent; diff --git a/packages/svelte2tsx/test/emitDts/samples/typescript-runes.v5/expected/TestRunes.svelte.d.ts b/packages/svelte2tsx/test/emitDts/samples/typescript-runes.v5/expected/TestRunes.svelte.d.ts index 6c3b7250e..04808233f 100644 --- a/packages/svelte2tsx/test/emitDts/samples/typescript-runes.v5/expected/TestRunes.svelte.d.ts +++ b/packages/svelte2tsx/test/emitDts/samples/typescript-runes.v5/expected/TestRunes.svelte.d.ts @@ -1,23 +1,7 @@ -interface $$__sveltets_2_IsomorphicComponent = any, Events extends Record = any, Slots extends Record = any, Exports = {}, Bindings = string> { - new (options: import('svelte').ComponentConstructorOptions): import('svelte').SvelteComponent & { - $$bindings?: Bindings; - } & Exports; - (internal: unknown, props: Props & { - $$events?: Events; - $$slots?: Slots; - }): Exports & { - $set?: any; - $on?: any; - }; - z_$$bindings?: Bindings; -} -declare const TestRunes: $$__sveltets_2_IsomorphicComponent<{ +declare const TestRunes: import("svelte").Component<{ foo: string; bar?: number; }, { - [evt: string]: CustomEvent; -}, {}, { baz: () => void; }, "bar">; -type TestRunes = InstanceType; export default TestRunes; diff --git a/packages/svelte2tsx/test/helpers.ts b/packages/svelte2tsx/test/helpers.ts index ceec3b03d..7fa3f5acf 100644 --- a/packages/svelte2tsx/test/helpers.ts +++ b/packages/svelte2tsx/test/helpers.ts @@ -230,7 +230,10 @@ export function test_samples(dir: string, transform: TransformSampleFn, js: 'js' if (sample.name.endsWith('.v5') && !isSvelte5Plus) continue; const svelteFile = sample.find_file('*.svelte'); - const expectedFile = isSvelte5Plus ? `expected-svelte5.${js}` : `expectedv2.${js}`; + const expectedFile = + isSvelte5Plus && !sample.name.endsWith('.v5') + ? `expected-svelte5.${js}` + : `expectedv2.${js}`; const config = { filename: svelteFile, sampleName: sample.name, diff --git a/packages/svelte2tsx/test/sourcemaps/samples/action-directive/mappings.jsx b/packages/svelte2tsx/test/sourcemaps/samples/action-directive/mappings.jsx index abaf91f05..9864b0bcc 100644 --- a/packages/svelte2tsx/test/sourcemaps/samples/action-directive/mappings.jsx +++ b/packages/svelte2tsx/test/sourcemaps/samples/action-directive/mappings.jsx @@ -7,10 +7,12 @@ async•()•=>•{•{const•$$action_0•=•__sveltets_2_ensureAction(action < action/ element su ↲ #================================================================== # Order-breaking mappings ↲ [original] line 1 +↲ [original] line 1 (rest generated at line 4) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} {/** - +↲ [generated] line 4 + ↲ +↲ [original] line 1 (rest generated at line 3) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} {const $$action_0 = __sveltets_2_ensureAction(action(svelteHTML.mapElementTag('element')));{ svelteHTML.createElement("element", __sveltets_2_union($$action_0), { });}}{/** •{const•$$action_0•=•__sveltets_2_ensureAction(action(svelteHTML.mapElementTag('element')));{•svelteHTML.createElement("element",•__sveltets_2_union($$action_0),•{••});}}↲ [generated] line 5 @@ -30,27 +32,31 @@ async•()•=>•{•{const•$$action_0•=•__sveltets_2_ensureAction(action • ↲ [generated] subset / ↲ / ↲ -/>↲ [original] line 5 +/>↲ [original] line 5 (rest generated at line 6) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} {/** - +↲ [generated] line 6 + ↲ +/>↲ [original] line 5 (rest generated at line 5) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} {const $$action_0 = __sveltets_2_ensureAction(action.nested.method(svelteHTML.mapElementTag('element'),(foo)));{ svelteHTML.createElement("element", __sveltets_2_union($$action_0), { });}}{/** ••{const•$$action_0•=•__sveltets_2_ensureAction(action.nested.method(svelteHTML.mapElementTag('element'),(foo)));{•svelteHTML.createElement("element",•__sveltets_2_union($$action_0),•{••});}}↲ [generated] line 7 <> action.nested.method= foo} element s{u ↲ #============================================== #=============================== # Order-breaking mappings ↲ -↲ [original] line 7 +↲ [original] line 7 (rest generated at line 8) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} {/** - +↲ [generated] line 8 + ↲ +↲ [original] line 7 (rest generated at line 7) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} {const $$action_0 = __sveltets_2_ensureAction(action(svelteHTML.mapElementTag('element'),($foo)));{ svelteHTML.createElement("element", __sveltets_2_union($$action_0), { });}}{/** •{const•$$action_0•=•__sveltets_2_ensureAction(action(svelteHTML.mapElementTag('element'),($foo)));{•svelteHTML.createElement("element",•__sveltets_2_union($$action_0),•{•••});}}↲ [generated] line 9 • ↲ [generated] subset / ↲ / ↲ -/>↲ [original] line 11 +/>↲ [original] line 11 (rest generated at line 10) •{const•$$action_0•=•__sveltets_2_ensureAction(action(svelteHTML.mapElementTag('element'),($foo)));{•svelteHTML.createElement("element",•__sveltets_2_union($$action_0),•{•••});}}↲ [generated] line 9 •{const•$$action_0•=•__sveltets_2_ensureAction( element",•__sveltets_2_union($$action_0),•{ });}} [generated] subset @@ -66,7 +72,9 @@ async•()•=>•{•{const•$$action_0•=•__sveltets_2_ensureAction(action ╚use:action={$foo}↲ [original] line 10 ------------------------------------------------------------------------------------------------------------------------------------------------------ */} {/** - +↲ [generated] line 10 + ↲ +/>↲ [original] line 11 (rest generated at line 9) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} {const $$action_0 = __sveltets_2_ensureAction(action(svelteHTML.mapElementTag('element'),({ foo })));{ svelteHTML.createElement("element", __sveltets_2_union($$action_0), { });}}{/** •{const•$$action_0•=•__sveltets_2_ensureAction(action(svelteHTML.mapElementTag('element'),({•foo•})));{•svelteHTML.createElement("element",•__sveltets_2_union($$action_0),•{•••});}}↲ [generated] line 11 @@ -86,10 +94,12 @@ async•()•=>•{•{const•$$action_0•=•__sveltets_2_ensureAction(action • ↲ [generated] subset / ↲ / ↲ -/>↲ [original] line 15 +/>↲ [original] line 15 (rest generated at line 12) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} {/** - +↲ [generated] line 12 + ↲ +/>↲ [original] line 15 (rest generated at line 11) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} {const $$action_0 = __sveltets_2_ensureAction(action(svelteHTML.mapElementTag('element'),({ {/** •{const•$$action_0•=•__sveltets_2_ensureAction(action(svelteHTML.mapElementTag('element'),({•↲ [generated] line 13 diff --git a/packages/svelte2tsx/test/sourcemaps/samples/await-block/mappings.jsx b/packages/svelte2tsx/test/sourcemaps/samples/await-block/mappings.jsx index 35fff79b7..8e81cad42 100644 --- a/packages/svelte2tsx/test/sourcemaps/samples/await-block/mappings.jsx +++ b/packages/svelte2tsx/test/sourcemaps/samples/await-block/mappings.jsx @@ -8,17 +8,23 @@ async•()•=>•{•••{•const•$$_value•=•await•(promise);{•con {t promise• value} ↲ #=========================== Order-breaking mappings { promise•t value}↲ -{#await•promise•then•value}↲ [original] line 1 +{#await•promise•then•value}↲ [original] line 1 (rest generated at line 4) async•()•=>•{•••{•const•$$_value•=•await•(promise);{•const•value•=•$$_value;•↲ [generated] line 3 •{•const•$$_value•=•await•( [generated] subset a a -{/await}↲ [original] line 3 (rest generated at line 5) +{/await}↲ [original] line 3 (rest generated at lines 5, 6) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} { svelteHTML.createElement("element", { "foo":value.bar,});} {/** -===# Originless mappings ••••••{•svelteHTML.createElement("element",•{•"foo":value.bar,});}↲ [generated] line 4 +•••• [generated] subset +↲ + ↲ +{#await•promise•then•value}↲ [original] line 1 (rest generated at line 3) + +••••••{•svelteHTML.createElement("element",•{•"foo":value.bar,});}↲ [generated] line 4 + ••{•svelteHTML.createElement("element",•{•"foo":value.bar,});}↲ [generated] subset <> element {f oo= value.bar} ↲ #============================ # Order-breaking mappings ↲ @@ -28,31 +34,39 @@ async•()•=>•{•••{•const•$$_value•=•await•(promise);{•con }}↲ [generated] line 5 { ↲ { ↲ -{/await}↲ [original] line 3 (rest generated at line 3) +{/await}↲ [original] line 3 (rest generated at lines 3, 6) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} {/** - +↲ [generated] line 6 + ↲ +{/await}↲ [original] line 3 (rest generated at lines 3, 5) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} { {/** •••{•↲ [generated] line 7 • ↲ [generated] subset { ↲ { ↲ -{#await•promise}↲ [original] line 5 (rest generated at line 9) +{#await•promise}↲ [original] line 5 (rest generated at lines 8, 9) •••{•↲ [generated] line 7 • [generated] subset : -{:then}↲ [original] line 7 (rest generated at line 9) +{:then}↲ [original] line 7 (rest generated at lines 9, 10) •••{•↲ [generated] line 7 •{• [generated] subset a -{/await}↲ [original] line 9 (rest generated at line 11) +{/await}↲ [original] line 9 (rest generated at lines 11, 12) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} { svelteHTML.createElement("element", {});} {/** - # Originless mappings ╚•{•svelteHTML.createElement("element",•{});}↲ [generated] line 8 + ╚ [generated] subset + ↲ + ↲ + {#await•promise}↲ [original] line 5 (rest generated at lines 7, 9) + + ╚•{•svelteHTML.createElement("element",•{});}↲ [generated] line 8 + •{•svelteHTML.createElement("element",•{});}↲ [generated] subset < element / ↲ ↲ [original] line 6 @@ -62,17 +76,23 @@ await•(promise);↲ [generated] line 9 promise); [generated] subset promise} promise} -{#await•promise}↲ [original] line 5 (rest generated at line 7) +{#await•promise}↲ [original] line 5 (rest generated at lines 7, 8) await•(promise);↲ [generated] line 9 await•( ↲ [generated] subset { ↲ { ↲ -{:then}↲ [original] line 7 (rest generated at line 7) +{:then}↲ [original] line 7 (rest generated at lines 7, 10) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} { svelteHTML.createElement("element", {});} {/** - # Originless mappings ╚•{•svelteHTML.createElement("element",•{});}↲ [generated] line 10 + ╚ [generated] subset + ↲ + ↲ + {:then}↲ [original] line 7 (rest generated at lines 7, 9) + + ╚•{•svelteHTML.createElement("element",•{});}↲ [generated] line 10 + •{•svelteHTML.createElement("element",•{});}↲ [generated] subset < element / ↲ ↲ [original] line 8 @@ -81,17 +101,19 @@ await•( ↲ [generated] subset }↲ [generated] line 11 {↲ { ↲ -{/await}↲ [original] line 9 (rest generated at line 7) +{/await}↲ [original] line 9 (rest generated at lines 7, 12) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} {/** - +↲ [generated] line 12 + ↲ +{/await}↲ [original] line 9 (rest generated at lines 7, 11) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} { {/** ••{•↲ [generated] line 13 • ↲ [generated] subset { ↲ { ↲ -{#await•$promise}↲ [original] line 11 (rest generated at line 15) +{#await•$promise}↲ [original] line 11 (rest generated at lines 14, 15) ••{•↲ [generated] line 13 •{• [generated] subset @@ -100,8 +122,14 @@ await•( ↲ [generated] subset {/await} [original] line 13 (rest generated at line 15) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} { svelteHTML.createElement("element", {});} {/** - # Originless mappings ╚•{•svelteHTML.createElement("element",•{});}↲ [generated] line 14 + ╚ [generated] subset + ↲ + ↲ + {#await•$promise}↲ [original] line 11 (rest generated at lines 13, 15) + + ╚•{•svelteHTML.createElement("element",•{});}↲ [generated] line 14 + •{•svelteHTML.createElement("element",•{});}↲ [generated] subset < element / ↲ ↲ [original] line 12 @@ -111,7 +139,7 @@ await•($promise);}};↲ [generated] line 15 $promise);}};↲ [generated] subset $promise} $promise} -{#await•$promise}↲ [original] line 11 (rest generated at line 13) +{#await•$promise}↲ [original] line 11 (rest generated at lines 13, 14) await•($promise);}};↲ [generated] line 15 await•( [generated] subset diff --git a/packages/svelte2tsx/test/sourcemaps/samples/component-props/mappings.jsx b/packages/svelte2tsx/test/sourcemaps/samples/component-props/mappings.jsx index 86889cddc..e19b69c73 100644 --- a/packages/svelte2tsx/test/sourcemaps/samples/component-props/mappings.jsx +++ b/packages/svelte2tsx/test/sourcemaps/samples/component-props/mappings.jsx @@ -7,30 +7,37 @@ async•()•=>•{••{•const•$$_tnenopmoC0C•=•__sveltets_2_ensureCom <> Component f oo• ↲ #====================================================== Order-breaking mappings ↲ -↲ [original] line 1 +↲ [original] line 1 (rest generated at line 4) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} {/** - +↲ [generated] line 4 + ↲ +↲ [original] line 1 (rest generated at line 3) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} { const $$_tnenopmoC0C = __sveltets_2_ensureComponent(Component); new $$_tnenopmoC0C({ target: __sveltets_2_any(), props: { "foo":`leet`,"bar":true,}});}{/** •{•const•$$_tnenopmoC0C•=•__sveltets_2_ensureComponent(Component);•new•$$_tnenopmoC0C({•target:•__sveltets_2_any(),•props:•{•"foo":`leet`,"bar":true,}});}↲ [generated] line 5 < Component "f oo= leet" b ar/ ↲ # Order-breaking mappings ↲ [original] line 3 +↲ [original] line 3 (rest generated at line 6) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} {/** - + ╚↲ [generated] line 6 + ↲ + ↲ + ↲ [original] line 3 (rest generated at line 5) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} { const $$_tnenopmoC0C = __sveltets_2_ensureComponent(Component); new $$_tnenopmoC0C({ target: __sveltets_2_any(), props: { ...bar,}});} {/** •{•const•$$_tnenopmoC0C•=•__sveltets_2_ensureComponent(Component);•new•$$_tnenopmoC0C({•target:•__sveltets_2_any(),•props:•{•...bar,}});}↲ [generated] line 7 < Component /...bar} ↲ # Order-breaking mappings ↲ [original] line 5 +↲ [original] line 5 (rest generated at line 8) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} {/** - +↲ [generated] line 8 + ↲ +↲ [original] line 5 (rest generated at line 7) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} { const $$_tnenopmoC0C = __sveltets_2_ensureComponent(Component); new $$_tnenopmoC0C({ target: __sveltets_2_any(), props: { ...bar,}});} {/** •{•const•$$_tnenopmoC0C•=•__sveltets_2_ensureComponent(Component);•new•$$_tnenopmoC0C({•target:•__sveltets_2_any(),•props:•{••...bar,}});}↲ [generated] line 9 @@ -49,10 +56,12 @@ async•()•=>•{••{•const•$$_tnenopmoC0C•=•__sveltets_2_ensureCom • ↲ [generated] subset / ↲ / ↲ -/>↲ [original] line 9 +/>↲ [original] line 9 (rest generated at line 10) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} {/** - +↲ [generated] line 10 + ↲ +/>↲ [original] line 9 (rest generated at line 9) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} { const $$_tnenopmoC0C = __sveltets_2_ensureComponent(Component); new $$_tnenopmoC0C({ target: __sveltets_2_any(), props: { foo:bar,}});/*Ωignore_startΩ*/() => bar = __sveltets_2_any(null);/*Ωignore_endΩ*/}{/** •{•const•$$_tnenopmoC0C•=•__sveltets_2_ensureComponent(Component);•new•$$_tnenopmoC0C({•target:•__sveltets_2_any(),•props:•{•••foo:bar,}});/*Ωignore_startΩ*/()•=>•bar•=•__sveltets_2_any(null);/*Ωignore_endΩ*/}↲ [generated] line 11 @@ -72,10 +81,12 @@ async•()•=>•{••{•const•$$_tnenopmoC0C•=•__sveltets_2_ensureCom • ↲ [generated] subset / ↲ / ↲ -/>↲ [original] line 13 +/>↲ [original] line 13 (rest generated at line 12) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} {/** - +↲ [generated] line 12 + ↲ +/>↲ [original] line 13 (rest generated at line 11) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} { const $$_tnenopmoC0C = __sveltets_2_ensureComponent(Component); const $$_tnenopmoC0 = new $$_tnenopmoC0C({ target: __sveltets_2_any(), props: { }});bar = $$_tnenopmoC0;}};{/** •{•const•$$_tnenopmoC0C•=•__sveltets_2_ensureComponent(Component);•const•$$_tnenopmoC0•=•new•$$_tnenopmoC0C({•target:•__sveltets_2_any(),•props:•{••}});bar•=•$$_tnenopmoC0;}};↲ [generated] line 13 diff --git a/packages/svelte2tsx/test/sourcemaps/samples/each-block/mappings.jsx b/packages/svelte2tsx/test/sourcemaps/samples/each-block/mappings.jsx index 4ae205f2d..7e934b571 100644 --- a/packages/svelte2tsx/test/sourcemaps/samples/each-block/mappings.jsx +++ b/packages/svelte2tsx/test/sourcemaps/samples/each-block/mappings.jsx @@ -19,10 +19,12 @@ async•()•=>•{••for(let•item•of•__sveltets_2_ensureArray(items)){ }↲ [generated] line 5 {↲ { ↲ -{/each}↲ [original] line 3 +{/each}↲ [original] line 3 (rest generated at line 6) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} {/** - +↲ [generated] line 6 + ↲ +{/each}↲ [original] line 3 (rest generated at line 5) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} for(let item of __sveltets_2_ensureArray(items)){let i = 1; {/** •••for(let•item•of•__sveltets_2_ensureArray(items)){let•i•=•1;↲ [generated] line 7 @@ -41,10 +43,12 @@ async•()•=>•{••for(let•item•of•__sveltets_2_ensureArray(items)){ }↲ [generated] line 9 {↲ { ↲ -{/each}↲ [original] line 7 +{/each}↲ [original] line 7 (rest generated at line 10) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} {/** - +↲ [generated] line 10 + ↲ +{/each}↲ [original] line 7 (rest generated at line 9) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} for(let { id, name, qty } of __sveltets_2_ensureArray(items)){let i = 1;id; {/** ••••for(let•{•id,•name,•qty•}•of•__sveltets_2_ensureArray(items)){let•i•=•1;id;↲ [generated] line 11 @@ -63,10 +67,12 @@ async•()•=>•{••for(let•item•of•__sveltets_2_ensureArray(items)){ }↲ [generated] line 13 {↲ { ↲ -{/each}↲ [original] line 11 +{/each}↲ [original] line 11 (rest generated at line 14) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} {/** - +↲ [generated] line 14 + ↲ +{/each}↲ [original] line 11 (rest generated at line 13) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} for(let { id, ...rest } of __sveltets_2_ensureArray(objects)){ {/** ••for(let•{•id,•...rest•}•of•__sveltets_2_ensureArray(objects)){↲ [generated] line 15 @@ -86,10 +92,12 @@ async•()•=>•{••for(let•item•of•__sveltets_2_ensureArray(items)){ }↲ [generated] line 17 {↲ { ↲ -{/each}↲ [original] line 15 +{/each}↲ [original] line 15 (rest generated at line 18) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} {/** - +↲ [generated] line 18 + ↲ +{/each}↲ [original] line 15 (rest generated at line 17) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} for(let [id, ...rest] of __sveltets_2_ensureArray(items)){ {/** ••for(let•[id,•...rest]•of•__sveltets_2_ensureArray(items)){↲ [generated] line 19 @@ -109,10 +117,12 @@ async•()•=>•{••for(let•item•of•__sveltets_2_ensureArray(items)){ }↲ [generated] line 21 {↲ { ↲ -{/each}↲ [original] line 19 +{/each}↲ [original] line 19 (rest generated at line 22) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} {/** - +↲ [generated] line 22 + ↲ +{/each}↲ [original] line 19 (rest generated at line 21) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} for(let todo of __sveltets_2_ensureArray(todos)){ {/** ••for(let•todo•of•__sveltets_2_ensureArray(todos)){↲ [generated] line 23 diff --git a/packages/svelte2tsx/test/sourcemaps/samples/element-attributes/mappings.jsx b/packages/svelte2tsx/test/sourcemaps/samples/element-attributes/mappings.jsx index 7ef16bb3f..b5a478a40 100644 --- a/packages/svelte2tsx/test/sourcemaps/samples/element-attributes/mappings.jsx +++ b/packages/svelte2tsx/test/sourcemaps/samples/element-attributes/mappings.jsx @@ -6,10 +6,12 @@ async () => { { svelteHTML.createElement("element", {"foo":true,});} async•()•=>•{•{•svelteHTML.createElement("element",•{"foo":true,});}↲ [generated] line 3 < element f oo/ ↲ ↲ [original] line 1 +↲ [original] line 1 (rest generated at line 4) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} {/** - +↲ [generated] line 4 + ↲ +↲ [original] line 1 (rest generated at line 3) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} { svelteHTML.createElement("element", { "foo":true,});} {/** ••{•svelteHTML.createElement("element",•{•"foo":true,});}↲ [generated] line 5 @@ -28,10 +30,12 @@ async•()•=>•{•{•svelteHTML.createElement("element",•{"foo":true,});} •{•svelteHTML.createElement(" ↲ [generated] subset > ↲ >↲ -/>↲ [original] line 5 +/>↲ [original] line 5 (rest generated at line 6) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} {/** - +↲ [generated] line 6 + ↲ +/>↲ [original] line 5 (rest generated at line 5) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} { svelteHTML.createElement("element", { "foo":`leet`,});} {/** •{•svelteHTML.createElement("element",•{•••"foo":`leet`,});}↲ [generated] line 7 @@ -50,10 +54,12 @@ async•()•=>•{•{•svelteHTML.createElement("element",•{"foo":true,});} •{•svelteHTML.createElement("element",•{•••"foo":`leet`,});}↲ [generated] line 7 ↲ [generated] subset ↲ -/>↲ [original] line 9 +/>↲ [original] line 9 (rest generated at line 8) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} {/** - +↲ [generated] line 8 + ↲ +/>↲ [original] line 9 (rest generated at line 7) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} { svelteHTML.createElement("element", { foo,"bar":true,});} {/** ••{•svelteHTML.createElement("element",•{•foo,"bar":true,});}↲ [generated] line 9 @@ -72,10 +78,12 @@ async•()•=>•{•{•svelteHTML.createElement("element",•{"foo":true,});} •{•svelteHTML.createElement(" ↲ [generated] subset > ↲ >↲ -/>↲ [original] line 13 +/>↲ [original] line 13 (rest generated at line 10) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} {/** - +↲ [generated] line 10 + ↲ +/>↲ [original] line 13 (rest generated at line 9) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} { svelteHTML.createElement("element", { foo,});} {/** •{•svelteHTML.createElement("element",•{••foo,});}↲ [generated] line 11 @@ -94,10 +102,12 @@ async•()•=>•{•{•svelteHTML.createElement("element",•{"foo":true,});} •{•svelteHTML.createElement("element",•{••foo,});}↲ [generated] line 11 ↲ [generated] subset ↲ -/>↲ [original] line 17 +/>↲ [original] line 17 (rest generated at line 12) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} {/** - +↲ [generated] line 12 + ↲ +/>↲ [original] line 17 (rest generated at line 11) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} { svelteHTML.createElement("element", { "bind:foo":foo,});/*Ωignore_startΩ*/() => foo = __sveltets_2_any(null);/*Ωignore_endΩ*/} {/** •{•svelteHTML.createElement("element",•{••"bind:foo":foo,});/*Ωignore_startΩ*/()•=>•foo•=•__sveltets_2_any(null);/*Ωignore_endΩ*/}↲ [generated] line 13 @@ -116,10 +126,12 @@ async•()•=>•{•{•svelteHTML.createElement("element",•{"foo":true,});} • ↲ [generated] subset / ↲ / ↲ -/>↲ [original] line 21 +/>↲ [original] line 21 (rest generated at line 14) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} {/** - +↲ [generated] line 14 + ↲ +/>↲ [original] line 21 (rest generated at line 13) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} { svelteHTML.createElement("element", { "bind:foo":bar,});/*Ωignore_startΩ*/() => bar = __sveltets_2_any(null);/*Ωignore_endΩ*/}}; {/** •{•svelteHTML.createElement("element",•{••"bind:foo":bar,});/*Ωignore_startΩ*/()•=>•bar•=•__sveltets_2_any(null);/*Ωignore_endΩ*/}};↲ [generated] line 15 diff --git a/packages/svelte2tsx/test/sourcemaps/samples/if-block/mappings.jsx b/packages/svelte2tsx/test/sourcemaps/samples/if-block/mappings.jsx index 080912ca8..f76cef7ba 100644 --- a/packages/svelte2tsx/test/sourcemaps/samples/if-block/mappings.jsx +++ b/packages/svelte2tsx/test/sourcemaps/samples/if-block/mappings.jsx @@ -18,19 +18,23 @@ async•()•=>•{if(foo){↲ [generated] line 3 }↲ [generated] line 5 {↲ { ↲ -{/if}↲ [original] line 3 +{/if}↲ [original] line 3 (rest generated at line 6) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} {/** - +↲ [generated] line 6 + ↲ +{/if}↲ [original] line 3 (rest generated at line 5) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} if($foo){ { svelteHTML.createElement("element", {});}} {/** if($foo){•{•svelteHTML.createElement("element",•{});}}↲ [generated] line 7 { $foo} < element / {↲ { $foo}{/if}↲ [original] line 5 +{#if•$foo}{/if}↲ [original] line 5 (rest generated at line 8) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} {/** - +↲ [generated] line 8 + ↲ +{#if•$foo}{/if}↲ [original] line 5 (rest generated at line 7) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} if(foo){ {/** if(foo){↲ [generated] line 9 diff --git a/packages/svelte2tsx/test/sourcemaps/samples/import-equal/mappings.jsx b/packages/svelte2tsx/test/sourcemaps/samples/import-equal/mappings.jsx index e122d928f..e1548fcb1 100644 --- a/packages/svelte2tsx/test/sourcemaps/samples/import-equal/mappings.jsx +++ b/packages/svelte2tsx/test/sourcemaps/samples/import-equal/mappings.jsx @@ -19,9 +19,13 @@ ; {/** ;↲ [generated] line 6 < - [original] line 4 + [original] line 4 (rest generated at line 7) +------------------------------------------------------------------------------------------------------------------------------------------------------ */} +async () => {}; {/** +async•()•=>•{};↲ [generated] line 7 +< + [original] line 4 (rest generated at line 6) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} -async () => {}; return { props: /** @type {Record} */ ({}), slots: {}, events: {} }} export default class Input__SvelteComponent_ extends __sveltets_2_createSvelte2TsxComponent(__sveltets_2_partial(__sveltets_2_with_any_event(render()))) { diff --git a/packages/svelte2tsx/test/sourcemaps/samples/large-sample-1/mappings.jsx b/packages/svelte2tsx/test/sourcemaps/samples/large-sample-1/mappings.jsx index dd6cc6ee5..44c3de9a8 100644 --- a/packages/svelte2tsx/test/sourcemaps/samples/large-sample-1/mappings.jsx +++ b/packages/svelte2tsx/test/sourcemaps/samples/large-sample-1/mappings.jsx @@ -23,7 +23,7 @@ ;;↲ [generated] line 15 ; [generated] subset < -↲ [original] line 14 (rest generated at line 119) +↲ [original] line 14 (rest generated at lines 119, 120) ;;↲ [generated] line 15 ;↲ [generated] subset @@ -251,69 +251,105 @@ s ; {/** ;↲ [generated] line 118 < -↲ [original] line 109 (rest generated at line 121) +↲ [original] line 109 (rest generated at lines 119, 121, 122) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} async () => { {/** -============# Originless mappings async•()•=>•{↲ [generated] line 119 - ↲ +async•()•=>•{ [generated] subset +< +↲ [original] line 109 (rest generated at lines 118, 121, 122) + +async•()•=>•{↲ [generated] line 119 + ↲ [generated] subset ↲ -↲ [original] line 14 (rest generated at line 15) +↲ [original] line 14 (rest generated at lines 15, 120) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} {/** - +↲ [generated] line 120 + ↲ +↲ [original] line 14 (rest generated at lines 15, 119) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} {/** ↲ [generated] line 121 ↲ -↲ [original] line 109 (rest generated at line 118) +↲ [original] line 109 (rest generated at lines 118, 119, 122) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} {/** - +↲ [generated] line 122 + ↲ +↲ [original] line 109 (rest generated at lines 118, 119, 121) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} {/** ↲ [generated] line 123 ↲ -↲ [original] line 259 +↲ [original] line 259 (rest generated at line 124) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} {/** - +↲ [generated] line 124 + ↲ +↲ [original] line 259 (rest generated at line 123) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} { svelteHTML.createElement("svelte:head", {}); {/** •{•svelteHTML.createElement("svelte:head",•{});↲ [generated] line 125 s ↲ s ↲ -↲ [original] line 261 +↲ [original] line 261 (rest generated at line 126) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} { svelteHTML.createElement("title", {});selected.section.title; selected.chapter.title; } {/** - # Originless mappings ╚•{•svelteHTML.createElement("title",•{});selected.section.title;••selected.chapter.title;••••}↲ [generated] line 126 + ╚ [generated] subset + ↲ + ↲ + ↲ [original] line 261 (rest generated at line 125) + + ╚•{•svelteHTML.createElement("title",•{});selected.section.title;••selected.chapter.title;••••}↲ [generated] line 126 + •{•svelteHTML.createElement("title",•{});selected.section.title;••selected.chapter.title;••••}↲ [generated] subset < title selected.section.title}• selected.chapter.title}• / ↲ {selected.section.title}•/•{selected.chapter.title}•••Svelte•Tutorial↲ [original] line 262 + ╚{selected.section.title}•/•{selected.chapter.title}•••Svelte•Tutorial↲ [original] line 262 (rest generated at lines 127, 128) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} {/** - +↲ [generated] line 127 + ↲ +╚{selected.section.title}•/•{selected.chapter.title}•••Svelte•Tutorial↲ [original] line 262 (rest generated at lines 126, 128) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} { svelteHTML.createElement("meta", { "name":`twitter:title`,"content":`Svelte tutorial`,});} {/** - # Originless mappings ╚•{•svelteHTML.createElement("meta",•{•••"name":`twitter:title`,"content":`Svelte•tutorial`,});}↲ [generated] line 128 + ╚ [generated] subset + ↲ + ↲ + ╚{selected.section.title}•/•{selected.chapter.title}•••Svelte•Tutorial↲ [original] line 262 (rest generated at lines 126, 127) + + ╚•{•svelteHTML.createElement("meta",•{•••"name":`twitter:title`,"content":`Svelte•tutorial`,});}↲ [generated] line 128 + •{•svelteHTML.createElement("meta",•{•••"name":`twitter:title`,"content":`Svelte•tutorial`,});}↲ [generated] subset < meta "•"n ame= twitter:title" c ontent= Svelte•tutorial" ↲ # Order-breaking mappings ↲ [original] line 264 + ╚↲ [original] line 264 (rest generated at line 129) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} { svelteHTML.createElement("meta", { "name":`twitter:description`,"content":`${selected.section.title} / ${selected.chapter.title}`,});} {/** - # Originless mappings ╚•{•svelteHTML.createElement("meta",•{•••"name":`twitter:description`,"content":`${selected.section.title}•/•${selected.chapter.title}`,});}↲ [generated] line 129 + ╚ [generated] subset + ↲ + ↲ + ╚↲ [original] line 264 (rest generated at line 128) + + ╚•{•svelteHTML.createElement("meta",•{•••"name":`twitter:description`,"content":`${selected.section.title}•/•${selected.chapter.title}`,});}↲ [generated] line 129 + •{•svelteHTML.createElement("meta",•{•••"name":`twitter:description`,"content":`${selected.section.title}•/•${selected.chapter.title}`,});}↲ [generated] subset < meta "•"n ame= twitter:description" c ontent= {selected.section.title}•/• {selected.chapter.title}" ↲ # Order-breaking mappings ↲ [original] line 265 + ╚↲ [original] line 265 (rest generated at line 130) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} { svelteHTML.createElement("meta", { "name":`Description`,"content":`${selected.section.title} / ${selected.chapter.title}`,});} {/** - # Originless mappings ╚•{•svelteHTML.createElement("meta",•{•••"name":`Description`,"content":`${selected.section.title}•/•${selected.chapter.title}`,});}↲ [generated] line 130 + ╚ [generated] subset + ↲ + ↲ + ╚↲ [original] line 265 (rest generated at line 129) + + ╚•{•svelteHTML.createElement("meta",•{•••"name":`Description`,"content":`${selected.section.title}•/•${selected.chapter.title}`,});}↲ [generated] line 130 + •{•svelteHTML.createElement("meta",•{•••"name":`Description`,"content":`${selected.section.title}•/•${selected.chapter.title}`,});}↲ [generated] subset < meta "•"n ame= Description" c ontent= {selected.section.title}•/• {selected.chapter.title}" ↲ # Order-breaking mappings ↲ [original] line 267 +↲ [original] line 267 (rest generated at line 132) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} {/** - +↲ [generated] line 132 + ↲ +↲ [original] line 267 (rest generated at line 131) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} { svelteHTML.createElement("svelte:window", { "bind:innerWidth":width,});/*Ωignore_startΩ*/() => width = __sveltets_2_any(null);/*Ωignore_endΩ*/} {/** ••{•svelteHTML.createElement("svelte:window",•{•"bind:innerWidth":width,});/*Ωignore_startΩ*/()•=>•width•=•__sveltets_2_any(null);/*Ωignore_endΩ*/}↲ [generated] line 133 <> ib width} ↲ #=============================================# Order-breaking mappings < bi width} >↲ -↲ [original] line 269 +↲ [original] line 269 (rest generated at line 134) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} {/** - +↲ [generated] line 134 + ↲ +↲ [original] line 269 (rest generated at line 133) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} { svelteHTML.createElement("div", { "class":`tutorial-outer`,}); {/** •{•svelteHTML.createElement("div",•{•"class":`tutorial-outer`,});↲ [generated] line 135 < div "c lass= tutorial-outer" ↲ # Order-breaking mappings
↲ [original] line 271 +↲ [original] line 271 (rest generated at line 136) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} { svelteHTML.createElement("div", { "class":`viewport offset-${offset}`,}); {/** - # Originless mappings ╚•{•svelteHTML.createElement("div",•{•"class":`viewport•offset-${offset}`,});↲ [generated] line 136 + ╚ [generated] subset + ↲ + ↲ + ↲ [original] line 271 (rest generated at line 135) + + ╚•{•svelteHTML.createElement("div",•{•"class":`viewport•offset-${offset}`,});↲ [generated] line 136 + •{•svelteHTML.createElement("div",•{•"class":`viewport•offset-${offset}`,});↲ [generated] subset < div "c lass= viewport•offset- {offset}" ↲ # Order-breaking mappings
↲ [original] line 272 + ╚↲ [original] line 272 (rest generated at line 137) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} { svelteHTML.createElement("div", { "class":`tutorial-text`,}); {/** - =# Originless mappings ╚╚•{•svelteHTML.createElement("div",•{•"class":`tutorial-text`,});↲ [generated] line 137 + ╚╚ [generated] subset + ↲ + ↲ + ╚↲ [original] line 272 (rest generated at line 136) + + ╚╚•{•svelteHTML.createElement("div",•{•"class":`tutorial-text`,});↲ [generated] line 137 + •{•svelteHTML.createElement("div",•{•"class":`tutorial-text`,});↲ [generated] subset < div "c lass= tutorial-text" ↲ # Order-breaking mappings
↲ [original] line 273 + ╚╚↲ [original] line 273 (rest generated at line 138) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} { svelteHTML.createElement("div", { "class":`table-of-contents`,}); {/** - ==# Originless mappings ╚╚╚•{•svelteHTML.createElement("div",•{•"class":`table-of-contents`,});↲ [generated] line 138 + ╚╚╚ [generated] subset + ↲ + ↲ + ╚╚↲ [original] line 273 (rest generated at line 137) + + ╚╚╚•{•svelteHTML.createElement("div",•{•"class":`table-of-contents`,});↲ [generated] line 138 + •{•svelteHTML.createElement("div",•{•"class":`table-of-contents`,});↲ [generated] subset < div "c lass= table-of-contents" ↲ # Order-breaking mappings
↲ [original] line 274 + ╚╚╚↲ [original] line 274 (rest generated at line 139) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} { const $$_stnetnoCfOelbaT4C = __sveltets_2_ensureComponent(TableOfContents); new $$_stnetnoCfOelbaT4C({ target: __sveltets_2_any(), props: { sections,slug,selected,}});}{/** - ===# Originless mappings ╚╚╚╚••{•const•$$_stnetnoCfOelbaT4C•=•__sveltets_2_ensureComponent(TableOfContents);•new•$$_stnetnoCfOelbaT4C({•target:•__sveltets_2_any(),•props:•{••sections,slug,selected,}});}↲ [generated] line 139 + ╚╚╚╚ [generated] subset + ↲ + ↲ + ╚╚╚↲ [original] line 274 (rest generated at line 138) + + ╚╚╚╚••{•const•$$_stnetnoCfOelbaT4C•=•__sveltets_2_ensureComponent(TableOfContents);•new•$$_stnetnoCfOelbaT4C({•target:•__sveltets_2_any(),•props:•{••sections,slug,selected,}});}↲ [generated] line 139 + ••{•const•$$_stnetnoCfOelbaT4C•=•__sveltets_2_ensureComponent(TableOfContents);•new•$$_stnetnoCfOelbaT4C({•target:•__sveltets_2_any(),•props:•{••sections,slug,selected,}});}↲ [generated] subset <> TableOfContents ••sections}slug}selected} ↲ #============================================================ # Order-breaking mappings ↲ - ╚╚╚╚↲ [original] line 275 + ╚╚╚╚↲ [original] line 275 (rest generated at line 140) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} } {/** - ==# Originless mappings - ╚╚╚•}↲ [generated] line 140 + ╚╚╚•}↲ [generated] line 140 + ╚╚╚ [generated] subset + ↲ + ↲ + ╚╚╚╚↲ [original] line 275 (rest generated at line 139) + + ╚╚╚•}↲ [generated] line 140 + •}↲ [generated] subset / ↲ / ↲ - ╚╚╚
↲ [original] line 276 + ╚╚╚
↲ [original] line 276 (rest generated at lines 141, 142) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} {/** - +↲ [generated] line 141 + ↲ +╚╚╚
↲ [original] line 276 (rest generated at lines 140, 142) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} { const $$_div3 = svelteHTML.createElement("div", { "class":`chapter-markup`,});scrollable = $$_div3; {/** - ==# Originless mappings ╚╚╚•{•const•$$_div3•=•svelteHTML.createElement("div",•{••"class":`chapter-markup`,});scrollable•=•$$_div3;↲ [generated] line 142 + ╚╚╚ [generated] subset + ↲ + ↲ + ╚╚╚
↲ [original] line 276 (rest generated at lines 140, 141) + + ╚╚╚•{•const•$$_div3•=•svelteHTML.createElement("div",•{••"class":`chapter-markup`,});scrollable•=•$$_div3;↲ [generated] line 142 + •{•const•$$_div3•=•svelteHTML.createElement("div",•{••"class":`chapter-markup`,});scrollable•=•$$_div3;↲ [generated] subset < div "•c lass= chapter-markup" scrollable} ↲ # Order-breaking mappings
↲ [original] line 278 + ╚╚╚↲ [original] line 278 (rest generated at line 143) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} chapter.html; {/** - ===# Originless mappings - ╚╚╚╚•chapter.html;↲ [generated] line 143 + ╚╚╚╚•chapter.html;↲ [generated] line 143 + ╚╚╚╚ [generated] subset + ↲ + ↲ + ╚╚╚↲ [original] line 278 (rest generated at line 142) + + ╚╚╚╚•chapter.html;↲ [generated] line 143 + •chapter.html;↲ [generated] subset {chapter.html}↲ { chapter.html}↲ - ╚╚╚╚{@html•chapter.html}↲ [original] line 279 + ╚╚╚╚{@html•chapter.html}↲ [original] line 279 (rest generated at lines 144, 145) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} {/** - +↲ [generated] line 144 + ↲ +╚╚╚╚{@html•chapter.html}↲ [original] line 279 (rest generated at lines 143, 145) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} { svelteHTML.createElement("div", { "class":`controls`,}); {/** - ===# Originless mappings ╚╚╚╚•{•svelteHTML.createElement("div",•{•"class":`controls`,});↲ [generated] line 145 + ╚╚╚╚ [generated] subset + ↲ + ↲ + ╚╚╚╚{@html•chapter.html}↲ [original] line 279 (rest generated at lines 143, 144) + + ╚╚╚╚•{•svelteHTML.createElement("div",•{•"class":`controls`,});↲ [generated] line 145 + •{•svelteHTML.createElement("div",•{•"class":`controls`,});↲ [generated] subset < div "c lass= controls" ↲ # Order-breaking mappings
↲ [original] line 281 + ╚╚╚╚↲ [original] line 281 (rest generated at line 146) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} if(chapter.app_b){ {/** - ====# Originless mappings - ╚╚╚╚╚if(chapter.app_b){↲ [generated] line 146 + ╚╚╚╚╚if(chapter.app_b){↲ [generated] line 146 + ╚╚╚╚╚ [generated] subset + ↲ + ↲ + ╚╚╚╚↲ [original] line 281 (rest generated at line 145) + + ╚╚╚╚╚if(chapter.app_b){↲ [generated] line 146 + if(chapter.app_b){↲ [generated] subset { chapter.app_b} ↲ { chapter.app_b}↲ - ╚╚╚╚╚{#if•chapter.app_b}↲ [original] line 282 + ╚╚╚╚╚{#if•chapter.app_b}↲ [original] line 282 ------------------------------------------------------------------------------------------------------------------------------------------------------ */} {/** ╚╚╚╚╚╚↲ [generated] line 147 @@ -429,42 +527,68 @@ s ↲ ╚╚╚╚╚╚↲ [generated] line 147 ↲ [generated] subset ↲ - ╚╚╚╚╚╚╚matches•the•expected•end•result•-->↲ [original] line 284 + ╚╚╚╚╚╚╚matches•the•expected•end•result•-->↲ [original] line 284 (rest generated at line 148) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} { svelteHTML.createElement("button", { "class":`show`,"on:click":() => completed ? reset() : complete(),}); {/** - =====# Originless mappings ╚╚╚╚╚╚••{•svelteHTML.createElement("button",•{•••"class":`show`,"on:click":()•=>•completed•?•reset()•:•complete(),});↲ [generated] line 148 + ╚╚╚╚╚╚ [generated] subset + ↲ + ↲ + ╚╚╚╚╚╚╚matches•the•expected•end•result•-->↲ [original] line 284 (rest generated at line 147) + + ╚╚╚╚╚╚••{•svelteHTML.createElement("button",•{•••"class":`show`,"on:click":()•=>•completed•?•reset()•:•complete(),});↲ [generated] line 148 + ••{•svelteHTML.createElement("button",•{•••"class":`show`,"on:click":()•=>•completed•?•reset()•:•complete(),});↲ [generated] subset <> button "•"c lass= show" c lick =()•=>•completed•?•reset()•:•complete()} ↲ #============================ # Order-breaking mappings ↲ [original] line 287 + ╚╚╚╚╚╚↲ [original] line 287 ------------------------------------------------------------------------------------------------------------------------------------------------------ */} } {/** ╚╚╚╚╚}↲ [generated] line 151 ╚╚╚╚╚{↲ ╚╚╚╚╚{ ↲ - ╚╚╚╚╚{/if}↲ [original] line 288 + ╚╚╚╚╚{/if}↲ [original] line 288 (rest generated at lines 152, 153) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} {/** - +↲ [generated] line 152 + ↲ +╚╚╚╚╚{/if}↲ [original] line 288 (rest generated at lines 151, 153) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} if(selected.next){ {/** - ====# Originless mappings ╚╚╚╚╚if(selected.next){↲ [generated] line 153 + ╚╚╚╚╚ [generated] subset + ↲ + ↲ + ╚╚╚╚╚{/if}↲ [original] line 288 (rest generated at lines 151, 152) + + ╚╚╚╚╚if(selected.next){↲ [generated] line 153 + if(selected.next){↲ [generated] subset { selected.next} ↲ { selected.next}↲ ╚╚╚╚╚{#if•selected.next}↲ [original] line 290 @@ -480,68 +604,119 @@ s ↲ ╚╚╚╚╚}↲ [generated] line 155 ╚╚╚╚╚{↲ ╚╚╚╚╚{ ↲ - ╚╚╚╚╚{/if}↲ [original] line 292 + ╚╚╚╚╚{/if}↲ [original] line 292 (rest generated at line 156) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} } {/** - ===# Originless mappings ╚╚╚╚•}↲ [generated] line 156 + ╚╚╚╚ [generated] subset + ↲ + ↲ + ╚╚╚╚╚{/if}↲ [original] line 292 (rest generated at line 155) + + ╚╚╚╚•}↲ [generated] line 156 + •}↲ [generated] subset / ↲ / ↲ - ╚╚╚╚
↲ [original] line 293 + ╚╚╚╚
↲ [original] line 293 (rest generated at lines 157, 158) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} {/** - +↲ [generated] line 157 + ↲ +╚╚╚╚↲ [original] line 293 (rest generated at lines 156, 158) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} { svelteHTML.createElement("div", { "class":`improve-chapter`,}); {/** - ===# Originless mappings ╚╚╚╚•{•svelteHTML.createElement("div",•{•"class":`improve-chapter`,});↲ [generated] line 158 + ╚╚╚╚ [generated] subset + ↲ + ↲ + ╚╚╚╚↲ [original] line 293 (rest generated at lines 156, 157) + + ╚╚╚╚•{•svelteHTML.createElement("div",•{•"class":`improve-chapter`,});↲ [generated] line 158 + •{•svelteHTML.createElement("div",•{•"class":`improve-chapter`,});↲ [generated] subset < div "c lass= improve-chapter" ↲ # Order-breaking mappings
↲ [original] line 295 + ╚╚╚╚↲ [original] line 295 (rest generated at line 159) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} { svelteHTML.createElement("a", { "class":`no-underline`,"href":improve_link,}); } {/** - ====# Originless mappings ╚╚╚╚╚•{•svelteHTML.createElement("a",•{•••"class":`no-underline`,"href":improve_link,});•••}↲ [generated] line 159 + ╚╚╚╚╚ [generated] subset + ↲ + ↲ + ╚╚╚╚↲ [original] line 295 (rest generated at line 158) + + ╚╚╚╚╚•{•svelteHTML.createElement("a",•{•••"class":`no-underline`,"href":improve_link,});•••}↲ [generated] line 159 + •{•svelteHTML.createElement("a",•{•••"class":`no-underline`,"href":improve_link,});•••}↲ [generated] subset < a "•{c lass= no-underline" h ref= improve_link} E / ↲ # Order-breaking mappings Edit•this•chapter↲ [original] line 296 + ╚╚╚╚╚Edit•this•chapter↲ [original] line 296 (rest generated at line 160) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} } {/** - ===# Originless mappings - ╚╚╚╚•}↲ [generated] line 160 + ╚╚╚╚•}↲ [generated] line 160 + ╚╚╚╚ [generated] subset + ↲ + ↲ + ╚╚╚╚╚Edit•this•chapter↲ [original] line 296 (rest generated at line 159) + + ╚╚╚╚•}↲ [generated] line 160 + •}↲ [generated] subset / ↲ / ↲ - ╚╚╚╚
↲ [original] line 297 + ╚╚╚╚↲ [original] line 297 (rest generated at line 161) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} } {/** - ==# Originless mappings - ╚╚╚•}↲ [generated] line 161 + ╚╚╚•}↲ [generated] line 161 + ╚╚╚ [generated] subset + ↲ + ↲ + ╚╚╚╚↲ [original] line 297 (rest generated at line 160) + + ╚╚╚•}↲ [generated] line 161 + •}↲ [generated] subset / ↲ / ↲ - ╚╚╚↲ [original] line 298 + ╚╚╚↲ [original] line 298 (rest generated at line 162) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} } {/** - =# Originless mappings - ╚╚•}↲ [generated] line 162 + ╚╚•}↲ [generated] line 162 + ╚╚ [generated] subset + ↲ + ↲ + ╚╚╚↲ [original] line 298 (rest generated at line 161) + + ╚╚•}↲ [generated] line 162 + •}↲ [generated] subset / ↲ / ↲ - ╚╚↲ [original] line 299 + ╚╚↲ [original] line 299 (rest generated at lines 163, 164) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} {/** - +↲ [generated] line 163 + ↲ +╚╚↲ [original] line 299 (rest generated at lines 162, 164) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} { svelteHTML.createElement("div", { "class":`tutorial-repl`,}); {/** - =# Originless mappings ╚╚•{•svelteHTML.createElement("div",•{•"class":`tutorial-repl`,});↲ [generated] line 164 + ╚╚ [generated] subset + ↲ + ↲ + ╚╚↲ [original] line 299 (rest generated at lines 162, 163) + + ╚╚•{•svelteHTML.createElement("div",•{•"class":`tutorial-repl`,});↲ [generated] line 164 + •{•svelteHTML.createElement("div",•{•"class":`tutorial-repl`,});↲ [generated] subset < div "c lass= tutorial-repl" ↲ # Order-breaking mappings
↲ [original] line 301 + ╚╚↲ [original] line 301 (rest generated at line 165) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} { const $$_lpeR3C = __sveltets_2_ensureComponent(Repl); const $$_lpeR3 = new $$_lpeR3C({ target: __sveltets_2_any(), props: { "workersUrl":`workers`,svelteUrl,rollupUrl,"orientation":mobile ? 'columns' : 'rows',"fixed":mobile,"injectedJS":mapbox_setup,"relaxed":true,}});repl = $$_lpeR3;$$_lpeR3.$on("change", handle_change);}{/** - ==# Originless mappings + ╚╚╚•{•const•$$_lpeR3C•=•__sveltets_2_ensureComponent(Repl);•const•$$_lpeR3•=•new•$$_lpeR3C({•target:•__sveltets_2_any(),•props:•{•••••••••••••••"workersUrl":`workers`,svelteUrl,rollupUrl,"orientation":mobile•?•'columns'•:•'rows',"fixed":mobile,"injectedJS":mapbox_setup,"relaxed":true,}});repl•=•$$_lpeR3;$$_lpeR3.$on("change",•handle_change);}↲ [generated] line 165 + ╚╚╚ [generated] subset + ↲ + ↲ + ╚╚↲ [original] line 301 (rest generated at line 164) + ╚╚╚•{•const•$$_lpeR3C•=•__sveltets_2_ensureComponent(Repl);•const•$$_lpeR3•=•new•$$_lpeR3C({•target:•__sveltets_2_any(),•props:•{•••••••••••••••"workersUrl":`workers`,svelteUrl,rollupUrl,"orientation":mobile•?•'columns'•:•'rows',"fixed":mobile,"injectedJS":mapbox_setup,"relaxed":true,}});repl•=•$$_lpeR3;$$_lpeR3.$on("change",•handle_change);}↲ [generated] line 165 •{•const•$$_lpeR3C•=•__sveltets_2_ensureComponent(Repl);•const•$$_lpeR3•=•new•$$_lpeR3C({•target:•__sveltets_2_any(),•props:•{ [generated] subset < Repl @@ -614,28 +789,48 @@ s ↲ • ↲ [generated] subset ╚ ↲ ╚ ↲ - ╚╚╚/>↲ [original] line 312 + ╚╚╚/>↲ [original] line 312 (rest generated at line 166) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} } {/** - =# Originless mappings ╚╚•}↲ [generated] line 166 + ╚╚ [generated] subset + ↲ + ↲ + ╚╚╚/>↲ [original] line 312 (rest generated at line 165) + + ╚╚•}↲ [generated] line 166 + •}↲ [generated] subset / ↲ / ↲ - ╚╚
↲ [original] line 313 + ╚╚↲ [original] line 313 (rest generated at line 167) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} } {/** - # Originless mappings - ╚•}↲ [generated] line 167 + ╚•}↲ [generated] line 167 + ╚ [generated] subset + ↲ + ↲ + ╚╚↲ [original] line 313 (rest generated at line 166) + + ╚•}↲ [generated] line 167 + •}↲ [generated] subset / ↲ / ↲ - ╚↲ [original] line 314 + ╚↲ [original] line 314 (rest generated at lines 168, 169) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} {/** - +↲ [generated] line 168 + ↲ +╚↲ [original] line 314 (rest generated at lines 167, 169) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} if(mobile){ {/** - # Originless mappings ╚if(mobile){↲ [generated] line 169 + ╚ [generated] subset + ↲ + ↲ + ╚↲ [original] line 314 (rest generated at lines 167, 168) + + ╚if(mobile){↲ [generated] line 169 + if(mobile){↲ [generated] subset { mobile} ↲ { mobile}↲ ╚{#if•mobile}↲ [original] line 316 diff --git a/packages/svelte2tsx/test/sourcemaps/samples/let/mappings.jsx b/packages/svelte2tsx/test/sourcemaps/samples/let/mappings.jsx index 265203757..36af25336 100644 --- a/packages/svelte2tsx/test/sourcemaps/samples/let/mappings.jsx +++ b/packages/svelte2tsx/test/sourcemaps/samples/let/mappings.jsx @@ -19,9 +19,13 @@ ; {/** ;↲ [generated] line 5 < - [original] line 3 + [original] line 3 (rest generated at line 6) +------------------------------------------------------------------------------------------------------------------------------------------------------ */} +async () => {}; {/** +async•()•=>•{};↲ [generated] line 6 +< + [original] line 3 (rest generated at line 5) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} -async () => {}; return { props: /** @type {Record} */ ({}), slots: {}, events: {} }} export default class Input__SvelteComponent_ extends __sveltets_2_createSvelte2TsxComponent(__sveltets_2_partial(__sveltets_2_with_any_event(render()))) { diff --git a/packages/svelte2tsx/test/sourcemaps/samples/reactive-statements/mappings.jsx b/packages/svelte2tsx/test/sourcemaps/samples/reactive-statements/mappings.jsx index 8ef14e465..348d67a39 100644 --- a/packages/svelte2tsx/test/sourcemaps/samples/reactive-statements/mappings.jsx +++ b/packages/svelte2tsx/test/sourcemaps/samples/reactive-statements/mappings.jsx @@ -41,9 +41,13 @@ ; {/** ;↲ [generated] line 9 < - [original] line 7 + [original] line 7 (rest generated at line 10) +------------------------------------------------------------------------------------------------------------------------------------------------------ */} +async () => {}; {/** +async•()•=>•{};↲ [generated] line 10 +< + [original] line 7 (rest generated at line 9) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} -async () => {}; return { props: {prop: prop}, slots: {}, events: {} }} export default class Input__SvelteComponent_ extends __sveltets_2_createSvelte2TsxComponent(__sveltets_2_partial(__sveltets_2_with_any_event(render()))) { diff --git a/packages/svelte2tsx/test/sourcemaps/samples/reserved-variables/mappings.jsx b/packages/svelte2tsx/test/sourcemaps/samples/reserved-variables/mappings.jsx index 9ac4a75c6..9ff7d1c21 100644 --- a/packages/svelte2tsx/test/sourcemaps/samples/reserved-variables/mappings.jsx +++ b/packages/svelte2tsx/test/sourcemaps/samples/reserved-variables/mappings.jsx @@ -23,17 +23,18 @@ ; {/** ;↲ [generated] line 8 < -↲ [original] line 6 (rest generated at line 9) +↲ [original] line 6 (rest generated at lines 9, 10) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} async () => { {/** -============# Originless mappings async•()•=>•{↲ [generated] line 9 - ↲ - ↲ -↲ [original] line 6 (rest generated at line 8) +< ↲ +< ↲ +↲ [original] line 6 (rest generated at lines 8, 10) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} {/** - +↲ [generated] line 10 + ↲ +↲ [original] line 6 (rest generated at lines 8, 9) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} if($$slots.foo){ {/** if($$slots.foo){↲ [generated] line 11 @@ -45,10 +46,9 @@ if($$slots.foo){↲ [generated] line 11 ╚$$restProps.bar;↲ [generated] line 12 ╚$$restProps.bar}↲ ╚ $$restProps.bar}↲ - ╚{$$restProps.bar}↲ [original] line 9 + ╚{$$restProps.bar}↲ [original] line 9 (rest generated at line 13) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} { const $$_tnenopmoC0C = __sveltets_2_ensureComponent(Component); new $$_tnenopmoC0C({ target: __sveltets_2_any(), props: { ...$$props,}});} {/** - # Originless mappings ╚•{•const•$$_tnenopmoC0C•=•__sveltets_2_ensureComponent(Component);•new•$$_tnenopmoC0C({•target:•__sveltets_2_any(),•props:•{••...$$props,}});}↲ [generated] line 13 • ...$$props,}});} [generated] subset ╚ ...$$props} @@ -61,6 +61,12 @@ if($$slots.foo){↲ [generated] line 11 ╚ ↲ ╚/>↲ [original] line 12 + ╚•{•const•$$_tnenopmoC0C•=•__sveltets_2_ensureComponent(Component);•new•$$_tnenopmoC0C({•target:•__sveltets_2_any(),•props:•{••...$$props,}});}↲ [generated] line 13 + ╚ [generated] subset + ↲ + ↲ + ╚{$$restProps.bar}↲ [original] line 9 (rest generated at line 12) + ╚•{•const•$$_tnenopmoC0C•=•__sveltets_2_ensureComponent(Component);•new•$$_tnenopmoC0C({•target:•__sveltets_2_any(),•props:•{••...$$props,}});}↲ [generated] line 13 •{•const•$$_tnenopmoC0C•=•__sveltets_2_ensureComponent(Component);•new•$$_tnenopmoC0C({•target:•__sveltets_2_any(),•props:•{ [generated] subset < Component diff --git a/packages/svelte2tsx/test/sourcemaps/samples/slot-let/mappings.jsx b/packages/svelte2tsx/test/sourcemaps/samples/slot-let/mappings.jsx index 2612247aa..a07171311 100644 --- a/packages/svelte2tsx/test/sourcemaps/samples/slot-let/mappings.jsx +++ b/packages/svelte2tsx/test/sourcemaps/samples/slot-let/mappings.jsx @@ -7,14 +7,20 @@ async•()•=>•{•{•const•$$_tnenopmoC0C•=•__sveltets_2_ensureCompon < Component el{•l hi•hi2=hi_2}hi3 ↲ # Order-breaking mappings ↲ [original] line 1 +↲ [original] line 1 (rest generated at line 4) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} hi;hi_2;hi3; {/** -===# Originless mappings -••••hi;hi_2;hi3;↲ [generated] line 4 +••••hi;hi_2;hi3;↲ [generated] line 4 +•••• [generated] subset +↲ + ↲ +↲ [original] line 1 (rest generated at line 3) + +••••hi;hi_2;hi3;↲ [generated] line 4 + hi;hi_2;hi3;↲ [generated] subset hi}hi_2}hi3}↲ hi} hi_2} hi3}↲ -••••{hi}{hi_2}{hi3}↲ [original] line 2 +••••{hi}{hi_2}{hi3}↲ [original] line 2 ------------------------------------------------------------------------------------------------------------------------------------------------------ */} }Component}}; {/** •}Component}};↲ [generated] line 5 diff --git a/packages/svelte2tsx/test/sourcemaps/samples/slots/mappings.jsx b/packages/svelte2tsx/test/sourcemaps/samples/slots/mappings.jsx index 86e0654ab..8353a45dd 100644 --- a/packages/svelte2tsx/test/sourcemaps/samples/slots/mappings.jsx +++ b/packages/svelte2tsx/test/sourcemaps/samples/slots/mappings.jsx @@ -7,30 +7,36 @@ async () => { { __sveltets_createSlot("default", {});} async•()•=>•{•{•__sveltets_createSlot("default",•{});}↲ [generated] line 4 < / ↲ < / ↲ -↲ [original] line 1 +↲ [original] line 1 (rest generated at line 5) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} {/** - +↲ [generated] line 5 + ↲ +↲ [original] line 1 (rest generated at line 4) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} { __sveltets_createSlot("foo", { }); } {/** •{•__sveltets_createSlot("foo",•{•});••}↲ [generated] line 6 < f oo " an f/ ↲ #==# Order-breaking mappings < na foo" f / ↲ -fallback↲ [original] line 3 +fallback↲ [original] line 3 (rest generated at line 7) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} {/** - +↲ [generated] line 7 + ↲ +fallback↲ [original] line 3 (rest generated at line 6) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} { __sveltets_createSlot("bar", { "foo":foo,baz,"leet":true,}); } {/** •{•__sveltets_createSlot("bar",•{••••"foo":foo,baz,"leet":true,});••}↲ [generated] line 8 < b ar " {•••f oo= foo}baz}l eet f/ ↲ #== # Order-breaking mappings < foo={foo}• bar"• baz}•leet f / ↲ -fallback↲ [original] line 5 +fallback↲ [original] line 5 (rest generated at line 9) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} {/** - +↲ [generated] line 9 + ↲ +fallback↲ [original] line 5 (rest generated at line 8) ------------------------------------------------------------------------------------------------------------------------------------------------------ */} { __sveltets_createSlot("bar", { "foo":foo,baz,"leet":true,}); {/** •{•__sveltets_createSlot("bar",•{•••••"foo":foo,baz,"leet":true,});↲ [generated] line 10 diff --git a/packages/svelte2tsx/test/svelte2tsx/samples/module-script-and-script3.v5/expectedv2.ts b/packages/svelte2tsx/test/svelte2tsx/samples/module-script-and-script3.v5/expectedv2.ts index 6406a56c2..5c395efb6 100644 --- a/packages/svelte2tsx/test/svelte2tsx/samples/module-script-and-script3.v5/expectedv2.ts +++ b/packages/svelte2tsx/test/svelte2tsx/samples/module-script-and-script3.v5/expectedv2.ts @@ -9,7 +9,7 @@ async () => { { svelteHTML.createElement("h1", {}); world; }}; -return { props: {world: world}, slots: {}, events: {} }} - -export default class Input__SvelteComponent_ extends __sveltets_2_createSvelte2TsxComponent(__sveltets_2_partial(['world'], __sveltets_2_with_any_event(render()))) { -} \ No newline at end of file +return { props: {world: world}, exports: {}, bindings: "", slots: {}, events: {} }} +const Input__SvelteComponent_ = __sveltets_2_isomorphic_component(__sveltets_2_partial(['world'], __sveltets_2_with_any_event(render()))); +/*Ωignore_startΩ*/type Input__SvelteComponent_ = InstanceType; +/*Ωignore_endΩ*/export default Input__SvelteComponent_; \ No newline at end of file diff --git a/packages/svelte2tsx/test/svelte2tsx/samples/runes-best-effort-types.v5/expectedv2.ts b/packages/svelte2tsx/test/svelte2tsx/samples/runes-best-effort-types.v5/expectedv2.ts index 4b9dd9437..b5c446abe 100644 --- a/packages/svelte2tsx/test/svelte2tsx/samples/runes-best-effort-types.v5/expectedv2.ts +++ b/packages/svelte2tsx/test/svelte2tsx/samples/runes-best-effort-types.v5/expectedv2.ts @@ -5,6 +5,5 @@ ; async () => {}; return { props: /** @type {$$ComponentProps} */({}), exports: {}, bindings: __sveltets_$$bindings(''), slots: {}, events: {} }} -const Input__SvelteComponent_ = __sveltets_2_isomorphic_component(__sveltets_2_with_any_event(render())); -/*Ωignore_startΩ*/type Input__SvelteComponent_ = InstanceType; -/*Ωignore_endΩ*/export default Input__SvelteComponent_; \ No newline at end of file +const Input__SvelteComponent_ = __sveltets_2_fn_component(render()); +export default Input__SvelteComponent_; \ No newline at end of file diff --git a/packages/svelte2tsx/test/svelte2tsx/samples/runes-bindable.v5/expectedv2.ts b/packages/svelte2tsx/test/svelte2tsx/samples/runes-bindable.v5/expectedv2.ts index c4de2d23e..5c4ac5f23 100644 --- a/packages/svelte2tsx/test/svelte2tsx/samples/runes-bindable.v5/expectedv2.ts +++ b/packages/svelte2tsx/test/svelte2tsx/samples/runes-bindable.v5/expectedv2.ts @@ -5,6 +5,5 @@ ; async () => {}; return { props: /** @type {$$ComponentProps} */({}), exports: {}, bindings: __sveltets_$$bindings('b'), slots: {}, events: {} }} -const Input__SvelteComponent_ = __sveltets_2_isomorphic_component(__sveltets_2_with_any_event(render())); -/*Ωignore_startΩ*/type Input__SvelteComponent_ = InstanceType; -/*Ωignore_endΩ*/export default Input__SvelteComponent_; \ No newline at end of file +const Input__SvelteComponent_ = __sveltets_2_fn_component(render()); +export default Input__SvelteComponent_; \ No newline at end of file diff --git a/packages/svelte2tsx/test/svelte2tsx/samples/runes-looking-like-stores.v5/expectedv2.ts b/packages/svelte2tsx/test/svelte2tsx/samples/runes-looking-like-stores.v5/expectedv2.ts index 05b04da66..8263d1173 100644 --- a/packages/svelte2tsx/test/svelte2tsx/samples/runes-looking-like-stores.v5/expectedv2.ts +++ b/packages/svelte2tsx/test/svelte2tsx/samples/runes-looking-like-stores.v5/expectedv2.ts @@ -9,6 +9,5 @@ async () => { state; derived;}; return { props: /** @type {$$ComponentProps} */({}), exports: {}, bindings: __sveltets_$$bindings(''), slots: {}, events: {} }} -const Input__SvelteComponent_ = __sveltets_2_isomorphic_component(__sveltets_2_with_any_event(render())); -/*Ωignore_startΩ*/type Input__SvelteComponent_ = InstanceType; -/*Ωignore_endΩ*/export default Input__SvelteComponent_; \ No newline at end of file +const Input__SvelteComponent_ = __sveltets_2_fn_component(render()); +export default Input__SvelteComponent_; \ No newline at end of file diff --git a/packages/svelte2tsx/test/svelte2tsx/samples/runes-only-export.v5/expectedv2.ts b/packages/svelte2tsx/test/svelte2tsx/samples/runes-only-export.v5/expectedv2.ts index cd5d6aca0..0a77ec5d6 100644 --- a/packages/svelte2tsx/test/svelte2tsx/samples/runes-only-export.v5/expectedv2.ts +++ b/packages/svelte2tsx/test/svelte2tsx/samples/runes-only-export.v5/expectedv2.ts @@ -8,6 +8,5 @@ async () => { x;}; return { props: /** @type {Record} */ ({}), exports: /** @type {{foo: typeof foo}} */ ({}), bindings: __sveltets_$$bindings(''), slots: {}, events: {} }} -const Input__SvelteComponent_ = __sveltets_2_isomorphic_component(__sveltets_2_with_any_event(render())); -/*Ωignore_startΩ*/type Input__SvelteComponent_ = InstanceType; -/*Ωignore_endΩ*/export default Input__SvelteComponent_; \ No newline at end of file +const Input__SvelteComponent_ = __sveltets_2_fn_component(render()); +export default Input__SvelteComponent_; \ No newline at end of file diff --git a/packages/svelte2tsx/test/svelte2tsx/samples/runes.v5/expectedv2.ts b/packages/svelte2tsx/test/svelte2tsx/samples/runes.v5/expectedv2.ts index 06e1497b4..328328888 100644 --- a/packages/svelte2tsx/test/svelte2tsx/samples/runes.v5/expectedv2.ts +++ b/packages/svelte2tsx/test/svelte2tsx/samples/runes.v5/expectedv2.ts @@ -8,6 +8,5 @@ ; async () => {}; return { props: /** @type {$$ComponentProps} */({}), exports: {}, bindings: __sveltets_$$bindings(''), slots: {}, events: {} }} -const Input__SvelteComponent_ = __sveltets_2_isomorphic_component(__sveltets_2_with_any_event(render())); -/*Ωignore_startΩ*/type Input__SvelteComponent_ = InstanceType; -/*Ωignore_endΩ*/export default Input__SvelteComponent_; \ No newline at end of file +const Input__SvelteComponent_ = __sveltets_2_fn_component(render()); +export default Input__SvelteComponent_; \ No newline at end of file diff --git a/packages/svelte2tsx/test/svelte2tsx/samples/sveltekit-autotypes-$props-rune-no-changes.v5/expectedv2.ts b/packages/svelte2tsx/test/svelte2tsx/samples/sveltekit-autotypes-$props-rune-no-changes.v5/expectedv2.ts index fe4d98e31..6eceb26ee 100644 --- a/packages/svelte2tsx/test/svelte2tsx/samples/sveltekit-autotypes-$props-rune-no-changes.v5/expectedv2.ts +++ b/packages/svelte2tsx/test/svelte2tsx/samples/sveltekit-autotypes-$props-rune-no-changes.v5/expectedv2.ts @@ -8,6 +8,5 @@ ; async () => {}; return { props: /** @type {$$ComponentProps} */({}), exports: /** @type {{snapshot: typeof snapshot}} */ ({}), bindings: __sveltets_$$bindings(''), slots: {}, events: {} }} -const Page__SvelteComponent_ = __sveltets_2_isomorphic_component(__sveltets_2_with_any_event(render())); -/*Ωignore_startΩ*/type Page__SvelteComponent_ = InstanceType; -/*Ωignore_endΩ*/export default Page__SvelteComponent_; \ No newline at end of file +const Page__SvelteComponent_ = __sveltets_2_fn_component(render()); +export default Page__SvelteComponent_; \ No newline at end of file diff --git a/packages/svelte2tsx/test/svelte2tsx/samples/sveltekit-autotypes-$props-rune.v5/expectedv2.ts b/packages/svelte2tsx/test/svelte2tsx/samples/sveltekit-autotypes-$props-rune.v5/expectedv2.ts index b5014a5d2..eeb3e8864 100644 --- a/packages/svelte2tsx/test/svelte2tsx/samples/sveltekit-autotypes-$props-rune.v5/expectedv2.ts +++ b/packages/svelte2tsx/test/svelte2tsx/samples/sveltekit-autotypes-$props-rune.v5/expectedv2.ts @@ -6,6 +6,5 @@ ; async () => {}; return { props: /** @type {$$ComponentProps} */({}), exports: /** @type {{snapshot: typeof snapshot}} */ ({}), bindings: __sveltets_$$bindings(''), slots: {}, events: {} }} -const Page__SvelteComponent_ = __sveltets_2_isomorphic_component(__sveltets_2_with_any_event(render())); -/*Ωignore_startΩ*/type Page__SvelteComponent_ = InstanceType; -/*Ωignore_endΩ*/export default Page__SvelteComponent_; \ No newline at end of file +const Page__SvelteComponent_ = __sveltets_2_fn_component(render()); +export default Page__SvelteComponent_; \ No newline at end of file diff --git a/packages/svelte2tsx/test/svelte2tsx/samples/ts-runes-best-effort-types.v5/expectedv2.ts b/packages/svelte2tsx/test/svelte2tsx/samples/ts-runes-best-effort-types.v5/expectedv2.ts index eab76fea5..faa1d533b 100644 --- a/packages/svelte2tsx/test/svelte2tsx/samples/ts-runes-best-effort-types.v5/expectedv2.ts +++ b/packages/svelte2tsx/test/svelte2tsx/samples/ts-runes-best-effort-types.v5/expectedv2.ts @@ -5,6 +5,5 @@ ; async () => {}; return { props: {} as any as $$ComponentProps, exports: {}, bindings: __sveltets_$$bindings(''), slots: {}, events: {} }} -const Input__SvelteComponent_ = __sveltets_2_isomorphic_component(__sveltets_2_with_any_event(render())); -/*Ωignore_startΩ*/type Input__SvelteComponent_ = InstanceType; -/*Ωignore_endΩ*/export default Input__SvelteComponent_; \ No newline at end of file +const Input__SvelteComponent_ = __sveltets_2_fn_component(render()); +export default Input__SvelteComponent_; \ No newline at end of file diff --git a/packages/svelte2tsx/test/svelte2tsx/samples/ts-runes-bindable.v5/expectedv2.ts b/packages/svelte2tsx/test/svelte2tsx/samples/ts-runes-bindable.v5/expectedv2.ts index 90775addb..ce3a575fe 100644 --- a/packages/svelte2tsx/test/svelte2tsx/samples/ts-runes-bindable.v5/expectedv2.ts +++ b/packages/svelte2tsx/test/svelte2tsx/samples/ts-runes-bindable.v5/expectedv2.ts @@ -5,6 +5,5 @@ ; async () => {}; return { props: {} as any as $$ComponentProps, exports: {}, bindings: __sveltets_$$bindings('b', 'c'), slots: {}, events: {} }} -const Input__SvelteComponent_ = __sveltets_2_isomorphic_component(__sveltets_2_with_any_event(render())); -/*Ωignore_startΩ*/type Input__SvelteComponent_ = InstanceType; -/*Ωignore_endΩ*/export default Input__SvelteComponent_; \ No newline at end of file +const Input__SvelteComponent_ = __sveltets_2_fn_component(render()); +export default Input__SvelteComponent_; \ No newline at end of file diff --git a/packages/svelte2tsx/test/svelte2tsx/samples/ts-runes-generics.v5/expectedv2.ts b/packages/svelte2tsx/test/svelte2tsx/samples/ts-runes-generics.v5/expectedv2.ts index b7e2a8765..d87b3a3ee 100644 --- a/packages/svelte2tsx/test/svelte2tsx/samples/ts-runes-generics.v5/expectedv2.ts +++ b/packages/svelte2tsx/test/svelte2tsx/samples/ts-runes-generics.v5/expectedv2.ts @@ -12,7 +12,7 @@ class __sveltets_Render { return render().props; } events() { - return __sveltets_2_with_any_event(render()).events; + return render().events; } slots() { return render().slots; @@ -23,7 +23,7 @@ class __sveltets_Render { interface $$IsomorphicComponent { new (options: import('svelte').ComponentConstructorOptions['props']>>): import('svelte').SvelteComponent['props']>, ReturnType<__sveltets_Render['events']>, ReturnType<__sveltets_Render['slots']>> & { $$bindings?: ReturnType<__sveltets_Render['bindings']> } & ReturnType<__sveltets_Render['exports']>; - (internal: unknown, props: ReturnType<__sveltets_Render['props']> & {$$events?: ReturnType<__sveltets_Render['events']>}): ReturnType<__sveltets_Render['exports']>; + (internal: unknown, props: ReturnType<__sveltets_Render['props']> & {}): ReturnType<__sveltets_Render['exports']>; z_$$bindings?: ReturnType<__sveltets_Render['bindings']>; } const Input__SvelteComponent_: $$IsomorphicComponent = null as any; diff --git a/packages/svelte2tsx/test/svelte2tsx/samples/ts-runes-with-slot.v5/expectedv2.ts b/packages/svelte2tsx/test/svelte2tsx/samples/ts-runes-with-slot.v5/expectedv2.ts index 68212de3d..d34195b64 100644 --- a/packages/svelte2tsx/test/svelte2tsx/samples/ts-runes-with-slot.v5/expectedv2.ts +++ b/packages/svelte2tsx/test/svelte2tsx/samples/ts-runes-with-slot.v5/expectedv2.ts @@ -16,7 +16,7 @@ class __sveltets_Render { return render().props; } events() { - return __sveltets_2_with_any_event(render()).events; + return render().events; } slots() { return render().slots; @@ -27,7 +27,7 @@ class __sveltets_Render { interface $$IsomorphicComponent { new (options: import('svelte').ComponentConstructorOptions['props']>& {children?: any}>): import('svelte').SvelteComponent['props']>, ReturnType<__sveltets_Render['events']>, ReturnType<__sveltets_Render['slots']>> & { $$bindings?: ReturnType<__sveltets_Render['bindings']> } & ReturnType<__sveltets_Render['exports']>; - (internal: unknown, props: ReturnType<__sveltets_Render['props']> & {$$events?: ReturnType<__sveltets_Render['events']>, $$slots?: ReturnType<__sveltets_Render['slots']>, children?: any}): ReturnType<__sveltets_Render['exports']>; + (internal: unknown, props: ReturnType<__sveltets_Render['props']> & {$$slots?: ReturnType<__sveltets_Render['slots']>, children?: any}): ReturnType<__sveltets_Render['exports']>; z_$$bindings?: ReturnType<__sveltets_Render['bindings']>; } const Input__SvelteComponent_: $$IsomorphicComponent = null as any; diff --git a/packages/svelte2tsx/test/svelte2tsx/samples/ts-runes.v5/expectedv2.ts b/packages/svelte2tsx/test/svelte2tsx/samples/ts-runes.v5/expectedv2.ts index 12e191193..8e4065235 100644 --- a/packages/svelte2tsx/test/svelte2tsx/samples/ts-runes.v5/expectedv2.ts +++ b/packages/svelte2tsx/test/svelte2tsx/samples/ts-runes.v5/expectedv2.ts @@ -7,6 +7,5 @@ ; async () => {}; return { props: {} as any as $$ComponentProps, exports: {}, bindings: __sveltets_$$bindings(''), slots: {}, events: {} }} -const Input__SvelteComponent_ = __sveltets_2_isomorphic_component(__sveltets_2_with_any_event(render())); -/*Ωignore_startΩ*/type Input__SvelteComponent_ = InstanceType; -/*Ωignore_endΩ*/export default Input__SvelteComponent_; \ No newline at end of file +const Input__SvelteComponent_ = __sveltets_2_fn_component(render()); +export default Input__SvelteComponent_; \ No newline at end of file diff --git a/packages/svelte2tsx/test/svelte2tsx/samples/ts-sveltekit-autotypes-$props-rune-unchanged.v5/expectedv2.ts b/packages/svelte2tsx/test/svelte2tsx/samples/ts-sveltekit-autotypes-$props-rune-unchanged.v5/expectedv2.ts index 522d58fd2..df7501a9a 100644 --- a/packages/svelte2tsx/test/svelte2tsx/samples/ts-sveltekit-autotypes-$props-rune-unchanged.v5/expectedv2.ts +++ b/packages/svelte2tsx/test/svelte2tsx/samples/ts-sveltekit-autotypes-$props-rune-unchanged.v5/expectedv2.ts @@ -6,6 +6,5 @@ ; async () => {}; return { props: {} as any as $$ComponentProps, exports: {} as any as { snapshot: any }, bindings: __sveltets_$$bindings(''), slots: {}, events: {} }} -const Page__SvelteComponent_ = __sveltets_2_isomorphic_component(__sveltets_2_with_any_event(render())); -/*Ωignore_startΩ*/type Page__SvelteComponent_ = InstanceType; -/*Ωignore_endΩ*/export default Page__SvelteComponent_; \ No newline at end of file +const Page__SvelteComponent_ = __sveltets_2_fn_component(render()); +export default Page__SvelteComponent_; \ No newline at end of file diff --git a/packages/svelte2tsx/test/svelte2tsx/samples/ts-sveltekit-autotypes-$props-rune.v5/expectedv2.ts b/packages/svelte2tsx/test/svelte2tsx/samples/ts-sveltekit-autotypes-$props-rune.v5/expectedv2.ts index 04db7b55e..ae77eca3f 100644 --- a/packages/svelte2tsx/test/svelte2tsx/samples/ts-sveltekit-autotypes-$props-rune.v5/expectedv2.ts +++ b/packages/svelte2tsx/test/svelte2tsx/samples/ts-sveltekit-autotypes-$props-rune.v5/expectedv2.ts @@ -6,6 +6,5 @@ ; async () => {}; return { props: {} as any as $$ComponentProps, exports: {} as any as { snapshot: typeof snapshot }, bindings: __sveltets_$$bindings(''), slots: {}, events: {} }} -const Page__SvelteComponent_ = __sveltets_2_isomorphic_component(__sveltets_2_with_any_event(render())); -/*Ωignore_startΩ*/type Page__SvelteComponent_ = InstanceType; -/*Ωignore_endΩ*/export default Page__SvelteComponent_; \ No newline at end of file +const Page__SvelteComponent_ = __sveltets_2_fn_component(render()); +export default Page__SvelteComponent_; \ No newline at end of file diff --git a/packages/typescript-plugin/package.json b/packages/typescript-plugin/package.json index 9b17e9196..ebf00ea10 100644 --- a/packages/typescript-plugin/package.json +++ b/packages/typescript-plugin/package.json @@ -1,6 +1,6 @@ { "name": "typescript-svelte-plugin", - "version": "0.2.0", + "version": "0.3.0", "description": "A TypeScript Plugin providing Svelte intellisense", "main": "dist/src/index.js", "scripts": { @@ -16,14 +16,19 @@ "plugin" ], "author": "The Svelte Community", + "homepage": "https://github.com/sveltejs/language-tools/tree/master/packages/typescript-plugin", + "repository": { + "type": "git", + "url": "https://github.com/sveltejs/language-tools/tree/master/packages/typescript-plugin" + }, "license": "MIT", "devDependencies": { - "@types/node": "^16.0.0", + "@types/node": "^18.0.0", "typescript": "^5.5.2", - "svelte": "^3.57.0" + "svelte": "^4.2.19" }, "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.14", + "@jridgewell/sourcemap-codec": "^1.5.0", "svelte2tsx": "workspace:~" } } diff --git a/packages/typescript-plugin/src/language-service/call-hierarchy.ts b/packages/typescript-plugin/src/language-service/call-hierarchy.ts index bfd7248eb..b16aafb0a 100644 --- a/packages/typescript-plugin/src/language-service/call-hierarchy.ts +++ b/packages/typescript-plugin/src/language-service/call-hierarchy.ts @@ -89,7 +89,7 @@ export function decorateCallHierarchy( return provideCallHierarchyOutgoingCalls(fileName, offset) .concat( program && sourceFile && isComponentModulePosition(fileName, position) - ? getOutgoingCallsForComponent(program, sourceFile) ?? [] + ? (getOutgoingCallsForComponent(program, sourceFile) ?? []) : [] ) .map((item): ts.CallHierarchyOutgoingCall | null => { diff --git a/packages/typescript-plugin/src/language-service/sveltekit.ts b/packages/typescript-plugin/src/language-service/sveltekit.ts index 5fec0bebe..9b5ee4fca 100644 --- a/packages/typescript-plugin/src/language-service/sveltekit.ts +++ b/packages/typescript-plugin/src/language-service/sveltekit.ts @@ -10,6 +10,22 @@ interface KitSnapshot { addedCode: InternalHelpers.AddedCode[]; } +declare module 'typescript/lib/tsserverlibrary' { + interface LanguageServiceHost { + /** @internal */ getCachedExportInfoMap?(): unknown; + /** @internal */ getModuleSpecifierCache?(): unknown; + /** @internal */ getGlobalTypingsCacheLocation?(): string | undefined; + /** @internal */ getSymlinkCache?(files: readonly ts.SourceFile[]): unknown; + /** @internal */ getPackageJsonsVisibleToFile?( + fileName: string, + rootDir?: string + ): readonly unknown[]; + /** @internal */ getPackageJsonAutoImportProvider?(): ts.Program | undefined; + + /** @internal*/ getModuleResolutionCache?(): ts.ModuleResolutionCache; + } +} + const cache = new WeakMap< ts.server.PluginCreateInfo, { @@ -232,13 +248,13 @@ export const kitExports: Record< kind: 'punctuation' }, { - text: "'auto' | 'always' | 'never'", + text: "'never' | 'always' | 'ignore'", kind: 'stringLiteral' } ], documentation: [ { - text: 'Control how SvelteKit should handle (missing) trailing slashes in the URL. More info: https://kit.svelte.dev/docs/page-options#trailingslash', + text: 'Control how SvelteKit should handle trailing slashes in the URL. More info: https://kit.svelte.dev/docs/page-options#trailingslash', kind: 'text' } ] @@ -719,6 +735,51 @@ function getProxiedLanguageService(info: ts.server.PluginCreateInfo, ts: _ts, lo ? (...args: Parameters>) => originalLanguageServiceHost.realpath!(...args) : undefined; + + getProjectReferences = originalLanguageServiceHost.getProjectReferences + ? () => originalLanguageServiceHost.getProjectReferences!() + : undefined; + + getParsedCommandLine = originalLanguageServiceHost.getParsedCommandLine + ? (fileName: string) => originalLanguageServiceHost.getParsedCommandLine!(fileName) + : undefined; + + getCachedExportInfoMap = originalLanguageServiceHost.getCachedExportInfoMap + ? () => originalLanguageServiceHost.getCachedExportInfoMap!() + : undefined; + + getModuleSpecifierCache = originalLanguageServiceHost.getModuleSpecifierCache + ? () => originalLanguageServiceHost.getModuleSpecifierCache!() + : undefined; + + getGlobalTypingsCacheLocation = originalLanguageServiceHost.getGlobalTypingsCacheLocation + ? () => originalLanguageServiceHost.getGlobalTypingsCacheLocation!() + : undefined; + + getSymlinkCache = originalLanguageServiceHost.getSymlinkCache + ? (...args: any[]) => + originalLanguageServiceHost.getSymlinkCache!( + // @ts-ignore + ...args + ) + : undefined; + + getPackageJsonsVisibleToFile = originalLanguageServiceHost.getPackageJsonsVisibleToFile + ? (...args: any[]) => + originalLanguageServiceHost.getPackageJsonsVisibleToFile!( + // @ts-ignore + ...args + ) + : undefined; + + getPackageJsonAutoImportProvider = + originalLanguageServiceHost.getPackageJsonAutoImportProvider + ? () => originalLanguageServiceHost.getPackageJsonAutoImportProvider!() + : undefined; + + getModuleResolutionCache = originalLanguageServiceHost.getModuleResolutionCache + ? () => originalLanguageServiceHost.getModuleResolutionCache!() + : undefined; } // Ideally we'd create a full Proxy of the language service, but that seems to have cache issues diff --git a/packages/typescript-plugin/src/module-loader.ts b/packages/typescript-plugin/src/module-loader.ts index cc2003cba..569f073b3 100644 --- a/packages/typescript-plugin/src/module-loader.ts +++ b/packages/typescript-plugin/src/module-loader.ts @@ -3,30 +3,7 @@ import { ConfigManager } from './config-manager'; import { Logger } from './logger'; import { SvelteSnapshotManager } from './svelte-snapshots'; import { createSvelteSys } from './svelte-sys'; -import { ensureRealSvelteFilePath, isVirtualSvelteFilePath } from './utils'; - -// TODO remove when we update to typescript 5.0 -declare module 'typescript/lib/tsserverlibrary' { - interface LanguageServiceHost { - /** @deprecated supply resolveModuleNameLiterals instead for resolution that can handle newer resolution modes like nodenext */ - resolveModuleNames?( - moduleNames: string[], - containingFile: string, - reusedNames: string[] | undefined, - redirectedReference: ts.ResolvedProjectReference | undefined, - options: ts.CompilerOptions, - containingSourceFile?: ts.SourceFile - ): (ts.ResolvedModule | undefined)[]; - resolveModuleNameLiterals?( - moduleLiterals: readonly ts.StringLiteralLike[], - containingFile: string, - redirectedReference: ts.ResolvedProjectReference | undefined, - options: ts.CompilerOptions, - containingSourceFile: ts.SourceFile, - reusedNames: readonly ts.StringLiteralLike[] | undefined - ): readonly ts.ResolvedModuleWithFailedLookupLocations[]; - } -} +import { ensureRealSvelteFilePath, isSvelteFilePath, isVirtualSvelteFilePath } from './utils'; /** * Caches resolved modules. @@ -110,6 +87,8 @@ export function patchModuleLoader( if (lsHost.resolveModuleNameLiterals) { lsHost.resolveModuleNameLiterals = resolveModuleNameLiterals; } else { + // TODO do we need to keep this around? We're requiring 5.0 now, so TS doesn't need it, + // but would this break when other TS plugins are used and we no longer provide it? lsHost.resolveModuleNames = resolveModuleNames; } @@ -161,12 +140,22 @@ export function patchModuleLoader( return resolved.map((tsResolvedModule, idx) => { const moduleName = moduleNames[idx]; - if (tsResolvedModule || !ensureRealSvelteFilePath(moduleName).endsWith('.svelte')) { + if ( + !isSvelteFilePath(moduleName) || + // corresponding .d.ts files take precedence over .svelte files + tsResolvedModule?.resolvedFileName.endsWith('.d.ts') || + tsResolvedModule?.resolvedFileName.endsWith('.d.svelte.ts') + ) { return tsResolvedModule; } - return resolveSvelteModuleNameFromCache(moduleName, containingFile, compilerOptions) - .resolvedModule; + const result = resolveSvelteModuleNameFromCache( + moduleName, + containingFile, + compilerOptions + ).resolvedModule; + // .svelte takes precedence over .svelte.ts etc + return result ?? tsResolvedModule; }); } @@ -238,14 +227,20 @@ export function patchModuleLoader( return resolved.map((tsResolvedModule, idx) => { const moduleName = moduleLiterals[idx].text; + const resolvedModule = tsResolvedModule.resolvedModule; + if ( - tsResolvedModule.resolvedModule || - !ensureRealSvelteFilePath(moduleName).endsWith('.svelte') + !isSvelteFilePath(moduleName) || + // corresponding .d.ts files take precedence over .svelte files + resolvedModule?.resolvedFileName.endsWith('.d.ts') || + resolvedModule?.resolvedFileName.endsWith('.d.svelte.ts') ) { return tsResolvedModule; } - return resolveSvelteModuleNameFromCache(moduleName, containingFile, options); + const result = resolveSvelteModuleNameFromCache(moduleName, containingFile, options); + // .svelte takes precedence over .svelte.ts etc + return result.resolvedModule ? result : tsResolvedModule; }); } @@ -262,6 +257,7 @@ export function patchModuleLoader( } const resolvedModule = resolveSvelteModuleName(moduleName, containingFile, options); + moduleCache.set(moduleName, containingFile, resolvedModule); return { resolvedModule: resolvedModule diff --git a/packages/typescript-plugin/src/svelte-sys.ts b/packages/typescript-plugin/src/svelte-sys.ts index d530e0b47..75b0a6f80 100644 --- a/packages/typescript-plugin/src/svelte-sys.ts +++ b/packages/typescript-plugin/src/svelte-sys.ts @@ -30,7 +30,7 @@ export function createSvelteSys(ts: _ts, logger: Logger) { const realpath = ts.sys.realpath; svelteSys.realpath = function (path) { if (isVirtualSvelteFilePath(path)) { - return realpath(toRealSvelteFilePath(path)) + '.ts'; + return realpath(toRealSvelteFilePath(path)); } return realpath(path); }; diff --git a/packages/typescript-plugin/src/utils.ts b/packages/typescript-plugin/src/utils.ts index d189f7ad1..1b14a6dbe 100644 --- a/packages/typescript-plugin/src/utils.ts +++ b/packages/typescript-plugin/src/utils.ts @@ -8,11 +8,17 @@ export function isSvelteFilePath(filePath: string) { } export function isVirtualSvelteFilePath(filePath: string) { - return filePath.endsWith('.svelte.ts'); + return filePath.endsWith('.d.svelte.ts'); } export function toRealSvelteFilePath(filePath: string) { - return filePath.slice(0, -'.ts'.length); + return filePath.slice(0, -11 /* 'd.svelte.ts'.length */) + 'svelte'; +} + +export function toVirtualSvelteFilePath(svelteFilePath: string) { + return isVirtualSvelteFilePath(svelteFilePath) + ? svelteFilePath + : svelteFilePath.slice(0, -6 /* 'svelte'.length */) + 'd.svelte.ts'; } export function ensureRealSvelteFilePath(filePath: string) { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a1e587871..f7d19793f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -16,41 +16,41 @@ importers: specifier: ^7.0.2 version: 7.0.3 prettier: - specifier: ~3.2.5 - version: 3.2.5 + specifier: ~3.3.3 + version: 3.3.3 ts-node: specifier: ^10.0.0 - version: 10.9.1(@types/node@16.18.32)(typescript@5.5.2) + version: 10.9.1(@types/node@18.19.46)(typescript@5.5.2) packages/language-server: dependencies: '@jridgewell/trace-mapping': - specifier: ^0.3.17 - version: 0.3.18 + specifier: ^0.3.25 + version: 0.3.25 '@vscode/emmet-helper': specifier: 2.8.4 version: 2.8.4 chokidar: - specifier: ^3.4.1 - version: 3.5.3 + specifier: ^4.0.1 + version: 4.0.1 estree-walker: specifier: ^2.0.1 version: 2.0.2 - fast-glob: - specifier: ^3.2.7 - version: 3.2.12 + fdir: + specifier: ^6.2.0 + version: 6.2.0 lodash: specifier: ^4.17.21 version: 4.17.21 prettier: - specifier: ~3.2.5 - version: 3.2.5 + specifier: ~3.3.3 + version: 3.3.3 prettier-plugin-svelte: - specifier: ^3.2.2 - version: 3.2.2(prettier@3.2.5)(svelte@3.57.0) + specifier: ^3.2.6 + version: 3.2.6(prettier@3.3.3)(svelte@4.2.19) svelte: - specifier: ^3.57.0 - version: 3.57.0 + specifier: ^4.2.19 + version: 4.2.19 svelte2tsx: specifier: workspace:~ version: link:../svelte2tsx @@ -67,14 +67,14 @@ importers: specifier: ~5.3.0 version: 5.3.0 vscode-languageserver: - specifier: 8.0.2 - version: 8.0.2 + specifier: 9.0.1 + version: 9.0.1 vscode-languageserver-protocol: - specifier: 3.17.2 - version: 3.17.2 + specifier: 3.17.5 + version: 3.17.5 vscode-languageserver-types: - specifier: 3.17.2 - version: 3.17.2 + specifier: 3.17.5 + version: 3.17.5 vscode-uri: specifier: ~3.0.0 version: 3.0.8 @@ -89,11 +89,8 @@ importers: specifier: ^9.1.0 version: 9.1.1 '@types/node': - specifier: ^16.0.0 - version: 16.18.32 - '@types/prettier': - specifier: ^2.2.3 - version: 2.7.2 + specifier: ^18.0.0 + version: 18.19.46 '@types/sinon': specifier: ^7.5.2 version: 7.5.2 @@ -108,31 +105,25 @@ importers: version: 11.1.2 ts-node: specifier: ^10.0.0 - version: 10.9.1(@types/node@16.18.32)(typescript@5.5.2) + version: 10.9.1(@types/node@18.19.46)(typescript@5.5.2) packages/svelte-check: dependencies: '@jridgewell/trace-mapping': - specifier: ^0.3.17 - version: 0.3.18 + specifier: ^0.3.25 + version: 0.3.25 chokidar: - specifier: ^3.4.1 - version: 3.5.3 + specifier: ^4.0.1 + version: 4.0.1 + fdir: + specifier: ^6.2.0 + version: 6.2.0 picocolors: specifier: ^1.0.0 version: 1.0.0 sade: specifier: ^1.7.4 version: 1.8.1 - svelte: - specifier: ^3.55.0 || ^4.0.0-next.0 || ^4.0.0 || ^5.0.0-next.0 - version: 3.57.0 - svelte-preprocess: - specifier: ^5.1.3 - version: 5.1.3(svelte@3.57.0)(typescript@5.4.5) - typescript: - specifier: ^5.0.3 - version: 5.4.5 devDependencies: '@rollup/plugin-commonjs': specifier: ^24.0.0 @@ -148,16 +139,13 @@ importers: version: 5.0.2(rollup@3.7.5) '@rollup/plugin-typescript': specifier: ^10.0.0 - version: 10.0.1(rollup@3.7.5)(tslib@2.5.2)(typescript@5.4.5) + version: 10.0.1(rollup@3.7.5)(tslib@2.5.2)(typescript@5.5.2) '@types/sade': specifier: ^1.7.2 version: 1.7.4 builtin-modules: specifier: ^3.3.0 version: 3.3.0 - fast-glob: - specifier: ^3.2.7 - version: 3.2.12 rollup: specifier: 3.7.5 version: 3.7.5 @@ -167,9 +155,15 @@ importers: rollup-plugin-copy: specifier: ^3.4.0 version: 3.4.0 + svelte: + specifier: ^4.2.19 + version: 4.2.19 svelte-language-server: specifier: workspace:* version: link:../language-server + typescript: + specifier: ^5.5.2 + version: 5.5.2 vscode-languageserver: specifier: 8.0.2 version: 8.0.2 @@ -195,18 +189,18 @@ importers: specifier: workspace:* version: link:../typescript-plugin vscode-languageclient: - specifier: ^8.0.0 - version: 8.1.0 + specifier: ^9.0.1 + version: 9.0.1 vscode-languageserver-protocol: - specifier: 3.17.2 - version: 3.17.2 + specifier: 3.17.5 + version: 3.17.5 devDependencies: '@types/lodash': specifier: ^4.14.116 version: 4.14.194 '@types/node': - specifier: ^16.0.0 - version: 16.18.32 + specifier: ^18.0.0 + version: 18.19.46 '@types/vscode': specifier: ^1.67 version: 1.78.0 @@ -233,11 +227,11 @@ importers: version: 3.1.2 devDependencies: '@jridgewell/sourcemap-codec': - specifier: ^1.4.14 - version: 1.4.15 + specifier: ^1.5.0 + version: 1.5.0 '@jridgewell/trace-mapping': - specifier: ^0.3.17 - version: 0.3.18 + specifier: ^0.3.25 + version: 0.3.25 '@rollup/plugin-commonjs': specifier: ^24.0.0 version: 24.1.0(rollup@3.7.5) @@ -257,8 +251,8 @@ importers: specifier: ^9.1.0 version: 9.1.1 '@types/node': - specifier: ^16.0.0 - version: 16.18.32 + specifier: ^18.0.0 + version: 18.19.46 '@types/unist': specifier: ^2.0.3 version: 2.0.6 @@ -272,8 +266,8 @@ importers: specifier: ^2.0.1 version: 2.0.2 magic-string: - specifier: ^0.27.0 - version: 0.27.0 + specifier: ^0.30.11 + version: 0.30.11 mocha: specifier: ^9.2.0 version: 9.2.2 @@ -290,8 +284,8 @@ importers: specifier: ^0.5.16 version: 0.5.21 svelte: - specifier: ~3.57.0 - version: 3.57.0 + specifier: ~4.2.19 + version: 4.2.19 tiny-glob: specifier: ^0.2.6 version: 0.2.9 @@ -305,24 +299,28 @@ importers: packages/typescript-plugin: dependencies: '@jridgewell/sourcemap-codec': - specifier: ^1.4.14 - version: 1.4.15 + specifier: ^1.5.0 + version: 1.5.0 svelte2tsx: specifier: workspace:~ version: link:../svelte2tsx devDependencies: '@types/node': - specifier: ^16.0.0 - version: 16.18.32 + specifier: ^18.0.0 + version: 18.19.46 svelte: - specifier: ^3.57.0 - version: 3.57.0 + specifier: ^4.2.19 + version: 4.2.19 typescript: specifier: ^5.5.2 version: 5.5.2 packages: + '@ampproject/remapping@2.3.0': + resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} + engines: {node: '>=6.0.0'} + '@cspotcode/source-map-support@0.8.1': resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} engines: {node: '>=12'} @@ -336,22 +334,26 @@ packages: '@emmetio/scanner@1.0.4': resolution: {integrity: sha512-IqRuJtQff7YHHBk4G8YZ45uB9BaAGcwQeVzgj/zj8/UdOhtQpEIupUhSk8dys6spFIWVZVeK20CzGEnqR5SbqA==} - '@jridgewell/resolve-uri@3.1.0': - resolution: {integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==} + '@jridgewell/gen-mapping@0.3.5': + resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} engines: {node: '>=6.0.0'} '@jridgewell/resolve-uri@3.1.1': resolution: {integrity: sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==} engines: {node: '>=6.0.0'} - '@jridgewell/sourcemap-codec@1.4.14': - resolution: {integrity: sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==} + '@jridgewell/set-array@1.2.1': + resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} + engines: {node: '>=6.0.0'} '@jridgewell/sourcemap-codec@1.4.15': resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} - '@jridgewell/trace-mapping@0.3.18': - resolution: {integrity: sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==} + '@jridgewell/sourcemap-codec@1.5.0': + resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} + + '@jridgewell/trace-mapping@0.3.25': + resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} '@jridgewell/trace-mapping@0.3.9': resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} @@ -483,14 +485,8 @@ packages: '@types/mri@1.1.1': resolution: {integrity: sha512-nJOuiTlsvmClSr3+a/trTSx4DTuY/VURsWGKSf/eeavh0LRMqdsK60ti0TlwM5iHiGOK3/Ibkxsbr7i9rzGreA==} - '@types/node@16.18.32': - resolution: {integrity: sha512-zpnXe4dEz6PrWz9u7dqyRoq9VxwCvoXRPy/ewhmMa1CgEyVmtL1NJPQ2MX+4pf97vetquVKkpiMx0MwI8pjNOw==} - - '@types/prettier@2.7.2': - resolution: {integrity: sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg==} - - '@types/pug@2.0.6': - resolution: {integrity: sha512-SnHmG9wN1UVmagJOnyo/qkk0Z7gejYxOYYmaAwr5u2yFYfsupN3sg10kyzN8Hep/2zbHxCnsumxOoRIRMBwKCg==} + '@types/node@18.19.46': + resolution: {integrity: sha512-vnRgMS7W6cKa1/0G3/DTtQYpVrZ8c0Xm6UkLaVFrb9jtcVC3okokW09Ki1Qdrj9ISokszD69nY4WDLRlvHlhAA==} '@types/resolve@1.20.2': resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==} @@ -527,6 +523,11 @@ packages: resolution: {integrity: sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==} engines: {node: '>=0.4.0'} + acorn@8.12.1: + resolution: {integrity: sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==} + engines: {node: '>=0.4.0'} + hasBin: true + acorn@8.8.2: resolution: {integrity: sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==} engines: {node: '>=0.4.0'} @@ -565,10 +566,17 @@ packages: argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + aria-query@5.3.0: + resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==} + array-union@2.1.0: resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} engines: {node: '>=8'} + axobject-query@4.1.0: + resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} + engines: {node: '>= 0.4'} + balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} @@ -589,9 +597,6 @@ packages: browser-stdout@1.3.1: resolution: {integrity: sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==} - buffer-crc32@0.2.13: - resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} - buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} @@ -615,6 +620,10 @@ packages: resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} engines: {node: '>= 8.10.0'} + chokidar@4.0.1: + resolution: {integrity: sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==} + engines: {node: '>= 14.16.0'} + clean-stack@2.2.0: resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} engines: {node: '>=6'} @@ -622,6 +631,9 @@ packages: cliui@7.0.4: resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} + code-red@1.0.4: + resolution: {integrity: sha512-7qJWqItLA8/VPVlKJlFXU+NBlo/qyfs39aJcuMT/2ere32ZqvF5OSxgdM5xOfJJ7O429gg2HM47y8v9P+9wrNw==} + color-convert@1.9.3: resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} @@ -659,6 +671,10 @@ packages: resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} engines: {node: '>= 8'} + css-tree@2.3.1: + resolution: {integrity: sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} + debug@4.3.3: resolution: {integrity: sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==} engines: {node: '>=6.0'} @@ -683,9 +699,9 @@ packages: resolution: {integrity: sha512-wH9xOVHnczo9jN2IW68BabcecVPxacIA3g/7z6vhSU/4stOKQzeCRK0yD0A24WiAAUJmmVpWqrERcTxnLo3AnA==} engines: {node: '>=8'} - detect-indent@6.1.0: - resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} - engines: {node: '>=8'} + dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} diff@4.0.2: resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} @@ -709,9 +725,6 @@ packages: emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - es6-promise@3.3.1: - resolution: {integrity: sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==} - escalade@3.1.1: resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} engines: {node: '>=6'} @@ -735,6 +748,9 @@ packages: estree-walker@2.0.2: resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + fast-glob@3.2.12: resolution: {integrity: sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==} engines: {node: '>=8.6.0'} @@ -742,6 +758,14 @@ packages: fastq@1.15.0: resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==} + fdir@6.2.0: + resolution: {integrity: sha512-9XaWcDl0riOX5j2kYfy0kKdg7skw3IY6kA4LFT8Tk2yF9UdrADUy8D6AJuBLtf7ISm/MksumwAHE3WVbMRyCLw==} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + fill-range@7.0.1: resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} engines: {node: '>=8'} @@ -887,6 +911,9 @@ packages: is-reference@1.2.1: resolution: {integrity: sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==} + is-reference@3.0.2: + resolution: {integrity: sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==} + is-unicode-supported@0.1.0: resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} engines: {node: '>=10'} @@ -918,6 +945,9 @@ packages: just-extend@4.2.1: resolution: {integrity: sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg==} + locate-character@3.0.0: + resolution: {integrity: sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==} + locate-path@6.0.0: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} @@ -946,13 +976,15 @@ packages: resolution: {integrity: sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==} engines: {node: '>=12'} - magic-string@0.30.7: - resolution: {integrity: sha512-8vBuFF/I/+OSLRmdf2wwFCJCz+nSn0m6DPvGH1fS/KiQoSaR+sETbov0eIk9KhEKy8CYqIkIAnbohxT/4H0kuA==} - engines: {node: '>=12'} + magic-string@0.30.11: + resolution: {integrity: sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==} make-error@1.3.6: resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} + mdn-data@2.0.30: + resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==} + merge2@1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} @@ -961,10 +993,6 @@ packages: resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} engines: {node: '>=8.6'} - min-indent@1.0.1: - resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} - engines: {node: '>=4'} - minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} @@ -976,13 +1004,6 @@ packages: resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} engines: {node: '>=10'} - minimist@1.2.8: - resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - - mkdirp@0.5.6: - resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} - hasBin: true - mocha@9.2.2: resolution: {integrity: sha512-L6XC3EdwT6YrIk0yXpavvLkn8h+EU+Y5UcCHKECyMbdUIxyMuZj4bX4U9e1nvnvUUvQVsV2VHQr5zLdcUkhW/g==} engines: {node: '>= 12.0.0'} @@ -1060,6 +1081,9 @@ packages: periscopic@2.0.3: resolution: {integrity: sha512-FuCZe61mWxQOJAQFEfmt9FjzebRlcpFz8sFPbyaCKtdusPkMEbA9ey0eARnRav5zAhmXznhaQkKGFAPn7X9NUw==} + periscopic@3.1.0: + resolution: {integrity: sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==} + picocolors@1.0.0: resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} @@ -1067,14 +1091,14 @@ packages: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} - prettier-plugin-svelte@3.2.2: - resolution: {integrity: sha512-ZzzE/wMuf48/1+Lf2Ffko0uDa6pyCfgHV6+uAhtg2U0AAXGrhCSW88vEJNAkAxW5qyrFY1y1zZ4J8TgHrjW++Q==} + prettier-plugin-svelte@3.2.6: + resolution: {integrity: sha512-Y1XWLw7vXUQQZmgv1JAEiLcErqUniAF2wO7QJsw8BVMvpLET2dI5WpEIEJx1r11iHVdSMzQxivyfrH9On9t2IQ==} peerDependencies: prettier: ^3.0.0 svelte: ^3.2.0 || ^4.0.0-next.0 || ^5.0.0-next.0 - prettier@3.2.5: - resolution: {integrity: sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==} + prettier@3.3.3: + resolution: {integrity: sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==} engines: {node: '>=14'} hasBin: true @@ -1088,6 +1112,10 @@ packages: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} + readdirp@4.0.1: + resolution: {integrity: sha512-GkMg9uOTpIWWKbSsgwb5fA4EavTR+SG/PMPoAY8hkhHfEEY0/vqljY+XHqtDf2cr2IJtoNRDbrrEpZUiZCkYRw==} + engines: {node: '>= 14.16.0'} + require-directory@2.1.1: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} @@ -1100,10 +1128,6 @@ packages: resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - rimraf@2.7.1: - resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==} - hasBin: true - rimraf@3.0.2: resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} hasBin: true @@ -1140,9 +1164,6 @@ packages: safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - sander@0.5.1: - resolution: {integrity: sha512-3lVqBir7WuKDHGrKRDn/1Ye3kwpXaDOMsiRP1wd6wpZW56gJhsbp5RqQpA6JG/P+pkXizygnr1dKR8vzWaVsfA==} - semver@7.5.1: resolution: {integrity: sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==} engines: {node: '>=10'} @@ -1170,9 +1191,9 @@ packages: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} - sorcery@0.11.0: - resolution: {integrity: sha512-J69LQ22xrQB1cIFJhPfgtLuI6BpWRiWu1Y3vSsIwK/eAScqJxd/+CJlUuHQRdX2C9NGFamq+KqNywGgaThwfHw==} - hasBin: true + source-map-js@1.2.0: + resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==} + engines: {node: '>=0.10.0'} source-map-support@0.5.21: resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} @@ -1196,10 +1217,6 @@ packages: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} - strip-indent@3.0.0: - resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} - engines: {node: '>=8'} - strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} @@ -1220,46 +1237,9 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} - svelte-preprocess@5.1.3: - resolution: {integrity: sha512-xxAkmxGHT+J/GourS5mVJeOXZzne1FR5ljeOUAMXUkfEhkLEllRreXpbl3dIYJlcJRfL1LO1uIAPpBpBfiqGPw==} - engines: {node: '>= 16.0.0', pnpm: ^8.0.0} - peerDependencies: - '@babel/core': ^7.10.2 - coffeescript: ^2.5.1 - less: ^3.11.3 || ^4.0.0 - postcss: ^7 || ^8 - postcss-load-config: ^2.1.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 - pug: ^3.0.0 - sass: ^1.26.8 - stylus: ^0.55.0 - sugarss: ^2.0.0 || ^3.0.0 || ^4.0.0 - svelte: ^3.23.0 || ^4.0.0-next.0 || ^4.0.0 || ^5.0.0-next.0 - typescript: '>=3.9.5 || ^4.0.0 || ^5.0.0' - peerDependenciesMeta: - '@babel/core': - optional: true - coffeescript: - optional: true - less: - optional: true - postcss: - optional: true - postcss-load-config: - optional: true - pug: - optional: true - sass: - optional: true - stylus: - optional: true - sugarss: - optional: true - typescript: - optional: true - - svelte@3.57.0: - resolution: {integrity: sha512-WMXEvF+RtAaclw0t3bPDTUe19pplMlfyKDsixbHQYgCWi9+O9VN0kXU1OppzrB9gPAvz4NALuoca2LfW2bOjTQ==} - engines: {node: '>= 8'} + svelte@4.2.19: + resolution: {integrity: sha512-IY1rnGr6izd10B0A8LqsBfmlT5OILVuZ7XsI0vdGPEvuonFV7NYEUK4dAkm9Zg2q0Um92kYjTpS1CAP3Nh/KWw==} + engines: {node: '>=16'} tiny-glob@0.2.9: resolution: {integrity: sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==} @@ -1292,16 +1272,14 @@ packages: typescript-auto-import-cache@0.3.3: resolution: {integrity: sha512-ojEC7+Ci1ij9eE6hp8Jl9VUNnsEKzztktP5gtYNRMrTmfXVwA1PITYYAkpxCvvupdSYa/Re51B6KMcv1CTZEUA==} - typescript@5.4.5: - resolution: {integrity: sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==} - engines: {node: '>=14.17'} - hasBin: true - typescript@5.5.2: resolution: {integrity: sha512-NcRtPEOsPFFWjobJEtfihkLCZCXZt/os3zf8nTxjVH3RvTSxjrCamJpbExGvYOF+tFHc3pA65qpdwPbzjohhew==} engines: {node: '>=14.17'} hasBin: true + undici-types@5.26.5: + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + unist-util-stringify-position@3.0.3: resolution: {integrity: sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg==} @@ -1325,19 +1303,19 @@ packages: resolution: {integrity: sha512-RY7HwI/ydoC1Wwg4gJ3y6LpU9FJRZAUnTYMXthqhFXXu77ErDd/xkREpGuk4MyYkk4a+XDWAMqe0S3KkelYQEQ==} engines: {node: '>=14.0.0'} - vscode-jsonrpc@8.1.0: - resolution: {integrity: sha512-6TDy/abTQk+zDGYazgbIPc+4JoXdwC8NHU9Pbn4UJP1fehUyZmM4RHp5IthX7A6L5KS30PRui+j+tbbMMMafdw==} + vscode-jsonrpc@8.2.0: + resolution: {integrity: sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==} engines: {node: '>=14.0.0'} - vscode-languageclient@8.1.0: - resolution: {integrity: sha512-GL4QdbYUF/XxQlAsvYWZRV3V34kOkpRlvV60/72ghHfsYFnS/v2MANZ9P6sHmxFcZKOse8O+L9G7Czg0NUWing==} - engines: {vscode: ^1.67.0} + vscode-languageclient@9.0.1: + resolution: {integrity: sha512-JZiimVdvimEuHh5olxhxkht09m3JzUGwggb5eRUkzzJhZ2KjCN0nh55VfiED9oez9DyF8/fz1g1iBV3h+0Z2EA==} + engines: {vscode: ^1.82.0} vscode-languageserver-protocol@3.17.2: resolution: {integrity: sha512-8kYisQ3z/SQ2kyjlNeQxbkkTNmVFoQCqkmGrzLH6A9ecPlgTbp3wDTnUNqaUxYr4vlAcloxx8zwy7G5WdguYNg==} - vscode-languageserver-protocol@3.17.3: - resolution: {integrity: sha512-924/h0AqsMtA5yK22GgMtCYiMdCOtWTSGgUOkgEDX+wk2b0x4sAfLiO4NxBxqbiVtz7K7/1/RgVrVI0NClZwqA==} + vscode-languageserver-protocol@3.17.5: + resolution: {integrity: sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==} vscode-languageserver-textdocument@1.0.11: resolution: {integrity: sha512-X+8T3GoiwTVlJbicx/sIAF+yuJAqz8VvwJyoMVhwEMoEKE/fkDmrqUgDMyBECcM2A2frVZIUj5HI/ErRXCfOeA==} @@ -1345,9 +1323,6 @@ packages: vscode-languageserver-types@3.17.2: resolution: {integrity: sha512-zHhCWatviizPIq9B7Vh9uvrH6x3sK8itC84HkamnBWoDFJtzBf7SWlpLCZUit72b3os45h6RWQNC9xHRDF8dRA==} - vscode-languageserver-types@3.17.3: - resolution: {integrity: sha512-SYU4z1dL0PyIMd4Vj8YOqFvHu7Hz/enbWtpfnVbJHU4Nd1YNYx8u0ennumc6h48GQNeOLxmwySmnADouT/AuZA==} - vscode-languageserver-types@3.17.5: resolution: {integrity: sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==} @@ -1355,6 +1330,10 @@ packages: resolution: {integrity: sha512-bpEt2ggPxKzsAOZlXmCJ50bV7VrxwCS5BI4+egUmure/oI/t4OlFzi/YNtVvY24A2UDOZAgwFGgnZPwqSJubkA==} hasBin: true + vscode-languageserver@9.0.1: + resolution: {integrity: sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==} + hasBin: true + vscode-nls@5.2.0: resolution: {integrity: sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng==} @@ -1418,6 +1397,11 @@ packages: snapshots: + '@ampproject/remapping@2.3.0': + dependencies: + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 + '@cspotcode/source-map-support@0.8.1': dependencies: '@jridgewell/trace-mapping': 0.3.9 @@ -1432,23 +1416,29 @@ snapshots: '@emmetio/scanner@1.0.4': {} - '@jridgewell/resolve-uri@3.1.0': {} + '@jridgewell/gen-mapping@0.3.5': + dependencies: + '@jridgewell/set-array': 1.2.1 + '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/trace-mapping': 0.3.25 '@jridgewell/resolve-uri@3.1.1': {} - '@jridgewell/sourcemap-codec@1.4.14': {} + '@jridgewell/set-array@1.2.1': {} '@jridgewell/sourcemap-codec@1.4.15': {} - '@jridgewell/trace-mapping@0.3.18': + '@jridgewell/sourcemap-codec@1.5.0': {} + + '@jridgewell/trace-mapping@0.3.25': dependencies: - '@jridgewell/resolve-uri': 3.1.0 - '@jridgewell/sourcemap-codec': 1.4.14 + '@jridgewell/resolve-uri': 3.1.1 + '@jridgewell/sourcemap-codec': 1.5.0 '@jridgewell/trace-mapping@0.3.9': dependencies: '@jridgewell/resolve-uri': 3.1.1 - '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/sourcemap-codec': 1.5.0 '@nodelib/fs.scandir@2.1.5': dependencies: @@ -1497,15 +1487,6 @@ snapshots: optionalDependencies: rollup: 3.7.5 - '@rollup/plugin-typescript@10.0.1(rollup@3.7.5)(tslib@2.5.2)(typescript@5.4.5)': - dependencies: - '@rollup/pluginutils': 5.0.2(rollup@3.7.5) - resolve: 1.22.2 - typescript: 5.4.5 - optionalDependencies: - rollup: 3.7.5 - tslib: 2.5.2 - '@rollup/plugin-typescript@10.0.1(rollup@3.7.5)(tslib@2.5.2)(typescript@5.5.2)': dependencies: '@rollup/pluginutils': 5.0.2(rollup@3.7.5) @@ -1565,12 +1546,12 @@ snapshots: '@types/fs-extra@8.1.2': dependencies: - '@types/node': 16.18.32 + '@types/node': 18.19.46 '@types/glob@7.2.0': dependencies: '@types/minimatch': 5.1.2 - '@types/node': 16.18.32 + '@types/node': 18.19.46 '@types/lodash@4.14.194': {} @@ -1580,11 +1561,9 @@ snapshots: '@types/mri@1.1.1': {} - '@types/node@16.18.32': {} - - '@types/prettier@2.7.2': {} - - '@types/pug@2.0.6': {} + '@types/node@18.19.46': + dependencies: + undici-types: 5.26.5 '@types/resolve@1.20.2': {} @@ -1602,7 +1581,7 @@ snapshots: '@types/vfile@3.0.2': dependencies: - '@types/node': 16.18.32 + '@types/node': 18.19.46 '@types/unist': 2.0.6 '@types/vfile-message': 2.0.0 @@ -1615,7 +1594,7 @@ snapshots: emmet: 2.4.4 jsonc-parser: 2.3.1 vscode-languageserver-textdocument: 1.0.11 - vscode-languageserver-types: 3.17.2 + vscode-languageserver-types: 3.17.5 vscode-nls: 5.2.0 vscode-uri: 2.1.2 @@ -1623,6 +1602,8 @@ snapshots: acorn-walk@8.2.0: {} + acorn@8.12.1: {} + acorn@8.8.2: {} aggregate-error@3.1.0: @@ -1655,8 +1636,14 @@ snapshots: argparse@2.0.1: {} + aria-query@5.3.0: + dependencies: + dequal: 2.0.3 + array-union@2.1.0: {} + axobject-query@4.1.0: {} + balanced-match@1.0.2: {} binary-extensions@2.2.0: {} @@ -1676,8 +1663,6 @@ snapshots: browser-stdout@1.3.1: {} - buffer-crc32@0.2.13: {} - buffer-from@1.1.2: {} builtin-modules@3.3.0: {} @@ -1707,6 +1692,10 @@ snapshots: optionalDependencies: fsevents: 2.3.3 + chokidar@4.0.1: + dependencies: + readdirp: 4.0.1 + clean-stack@2.2.0: {} cliui@7.0.4: @@ -1715,6 +1704,14 @@ snapshots: strip-ansi: 6.0.1 wrap-ansi: 7.0.0 + code-red@1.0.4: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.0 + '@types/estree': 1.0.1 + acorn: 8.12.1 + estree-walker: 3.0.3 + periscopic: 3.1.0 + color-convert@1.9.3: dependencies: color-name: 1.1.3 @@ -1747,6 +1744,11 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 + css-tree@2.3.1: + dependencies: + mdn-data: 2.0.30 + source-map-js: 1.2.0 + debug@4.3.3(supports-color@8.1.1): dependencies: ms: 2.1.2 @@ -1770,7 +1772,7 @@ snapshots: rimraf: 3.0.2 slash: 3.0.0 - detect-indent@6.1.0: {} + dequal@2.0.3: {} diff@4.0.2: {} @@ -1789,8 +1791,6 @@ snapshots: emoji-regex@8.0.0: {} - es6-promise@3.3.1: {} - escalade@3.1.1: {} escape-string-regexp@1.0.5: {} @@ -1803,6 +1803,10 @@ snapshots: estree-walker@2.0.2: {} + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.1 + fast-glob@3.2.12: dependencies: '@nodelib/fs.stat': 2.0.5 @@ -1815,6 +1819,8 @@ snapshots: dependencies: reusify: 1.0.4 + fdir@6.2.0: {} + fill-range@7.0.1: dependencies: to-regex-range: 5.0.1 @@ -1958,6 +1964,10 @@ snapshots: dependencies: '@types/estree': 0.0.42 + is-reference@3.0.2: + dependencies: + '@types/estree': 0.0.42 + is-unicode-supported@0.1.0: {} isarray@0.0.1: {} @@ -1987,6 +1997,8 @@ snapshots: just-extend@4.2.1: {} + locate-character@3.0.0: {} + locate-path@6.0.0: dependencies: p-locate: 5.0.0 @@ -2014,14 +2026,16 @@ snapshots: magic-string@0.27.0: dependencies: - '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/sourcemap-codec': 1.5.0 - magic-string@0.30.7: + magic-string@0.30.11: dependencies: - '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/sourcemap-codec': 1.5.0 make-error@1.3.6: {} + mdn-data@2.0.30: {} + merge2@1.4.1: {} micromatch@4.0.5: @@ -2029,8 +2043,6 @@ snapshots: braces: 3.0.2 picomatch: 2.3.1 - min-indent@1.0.1: {} - minimatch@3.1.2: dependencies: brace-expansion: 1.1.11 @@ -2043,12 +2055,6 @@ snapshots: dependencies: brace-expansion: 2.0.1 - minimist@1.2.8: {} - - mkdirp@0.5.6: - dependencies: - minimist: 1.2.8 - mocha@9.2.2: dependencies: '@ungap/promise-all-settled': 1.1.2 @@ -2141,16 +2147,22 @@ snapshots: estree-walker: 2.0.2 is-reference: 1.2.1 + periscopic@3.1.0: + dependencies: + '@types/estree': 1.0.1 + estree-walker: 3.0.3 + is-reference: 3.0.2 + picocolors@1.0.0: {} picomatch@2.3.1: {} - prettier-plugin-svelte@3.2.2(prettier@3.2.5)(svelte@3.57.0): + prettier-plugin-svelte@3.2.6(prettier@3.3.3)(svelte@4.2.19): dependencies: - prettier: 3.2.5 - svelte: 3.57.0 + prettier: 3.3.3 + svelte: 4.2.19 - prettier@3.2.5: {} + prettier@3.3.3: {} queue-microtask@1.2.3: {} @@ -2162,6 +2174,8 @@ snapshots: dependencies: picomatch: 2.3.1 + readdirp@4.0.1: {} + require-directory@2.1.1: {} resolve@1.22.2: @@ -2172,10 +2186,6 @@ snapshots: reusify@1.0.4: {} - rimraf@2.7.1: - dependencies: - glob: 7.2.3 - rimraf@3.0.2: dependencies: glob: 7.2.3 @@ -2216,13 +2226,6 @@ snapshots: safe-buffer@5.2.1: {} - sander@0.5.1: - dependencies: - es6-promise: 3.3.1 - graceful-fs: 4.2.11 - mkdirp: 0.5.6 - rimraf: 2.7.1 - semver@7.5.1: dependencies: lru-cache: 6.0.0 @@ -2250,12 +2253,7 @@ snapshots: slash@3.0.0: {} - sorcery@0.11.0: - dependencies: - '@jridgewell/sourcemap-codec': 1.4.15 - buffer-crc32: 0.2.13 - minimist: 1.2.8 - sander: 0.5.1 + source-map-js@1.2.0: {} source-map-support@0.5.21: dependencies: @@ -2278,10 +2276,6 @@ snapshots: dependencies: ansi-regex: 5.0.1 - strip-indent@3.0.0: - dependencies: - min-indent: 1.0.1 - strip-json-comments@3.1.1: {} supports-color@5.5.0: @@ -2298,29 +2292,22 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} - svelte-preprocess@5.1.3(svelte@3.57.0)(typescript@5.4.5): + svelte@4.2.19: dependencies: - '@types/pug': 2.0.6 - detect-indent: 6.1.0 - magic-string: 0.30.7 - sorcery: 0.11.0 - strip-indent: 3.0.0 - svelte: 3.57.0 - optionalDependencies: - typescript: 5.4.5 - - svelte-preprocess@5.1.3(svelte@3.57.0)(typescript@5.5.2): - dependencies: - '@types/pug': 2.0.6 - detect-indent: 6.1.0 - magic-string: 0.30.7 - sorcery: 0.11.0 - strip-indent: 3.0.0 - svelte: 3.57.0 - optionalDependencies: - typescript: 5.5.2 - - svelte@3.57.0: {} + '@ampproject/remapping': 2.3.0 + '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/trace-mapping': 0.3.25 + '@types/estree': 1.0.1 + acorn: 8.12.1 + aria-query: 5.3.0 + axobject-query: 4.1.0 + code-red: 1.0.4 + css-tree: 2.3.1 + estree-walker: 3.0.3 + is-reference: 3.0.2 + locate-character: 3.0.0 + magic-string: 0.30.11 + periscopic: 3.1.0 tiny-glob@0.2.9: dependencies: @@ -2331,14 +2318,14 @@ snapshots: dependencies: is-number: 7.0.0 - ts-node@10.9.1(@types/node@16.18.32)(typescript@5.5.2): + ts-node@10.9.1(@types/node@18.19.46)(typescript@5.5.2): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.9 '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 - '@types/node': 16.18.32 + '@types/node': 18.19.46 acorn: 8.8.2 acorn-walk: 8.2.0 arg: 4.1.3 @@ -2357,10 +2344,10 @@ snapshots: dependencies: semver: 7.5.1 - typescript@5.4.5: {} - typescript@5.5.2: {} + undici-types@5.26.5: {} + unist-util-stringify-position@3.0.3: dependencies: '@types/unist': 2.0.6 @@ -2390,36 +2377,38 @@ snapshots: vscode-jsonrpc@8.0.2: {} - vscode-jsonrpc@8.1.0: {} + vscode-jsonrpc@8.2.0: {} - vscode-languageclient@8.1.0: + vscode-languageclient@9.0.1: dependencies: minimatch: 5.1.6 semver: 7.5.1 - vscode-languageserver-protocol: 3.17.3 + vscode-languageserver-protocol: 3.17.5 vscode-languageserver-protocol@3.17.2: dependencies: vscode-jsonrpc: 8.0.2 vscode-languageserver-types: 3.17.2 - vscode-languageserver-protocol@3.17.3: + vscode-languageserver-protocol@3.17.5: dependencies: - vscode-jsonrpc: 8.1.0 - vscode-languageserver-types: 3.17.3 + vscode-jsonrpc: 8.2.0 + vscode-languageserver-types: 3.17.5 vscode-languageserver-textdocument@1.0.11: {} vscode-languageserver-types@3.17.2: {} - vscode-languageserver-types@3.17.3: {} - vscode-languageserver-types@3.17.5: {} vscode-languageserver@8.0.2: dependencies: vscode-languageserver-protocol: 3.17.2 + vscode-languageserver@9.0.1: + dependencies: + vscode-languageserver-protocol: 3.17.5 + vscode-nls@5.2.0: {} vscode-oniguruma@1.7.0: {}