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..f3702c47b 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", "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/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/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..8340478c3 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( @@ -463,8 +463,16 @@ export class RenameProviderImpl implements RenameProvider { const mappedLocations = await Promise.all( renameLocations.map(async (loc) => { const snapshot = await snapshots.retrieve(loc.fileName); + const text = snapshot.getFullText(); + const end = loc.textSpan.start + loc.textSpan.length; - if (!isTextSpanInGeneratedCode(snapshot.getFullText(), loc.textSpan)) { + if ( + !(snapshot instanceof SvelteDocumentSnapshot) || + (!isTextSpanInGeneratedCode(text, loc.textSpan) && + // prevent generated code for bindings from being renamed + // (it's not inside a generate comment because diagnostics should show up) + text.slice(end + 3, end + 27) !== '__sveltets_binding_value') + ) { return { ...loc, range: this.mapRangeToOriginal(snapshot, loc.textSpan), @@ -536,7 +544,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/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..8f5720bb0 100644 --- a/packages/language-server/src/plugins/typescript/service.ts +++ b/packages/language-server/src/plugins/typescript/service.ts @@ -1,19 +1,25 @@ -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 { + 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 +33,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(): void; updateTsOrJsFile(fileName: string, changes?: TextDocumentContentChangeEvent[]): void; /** * Checks if a file is present in the project. @@ -50,7 +54,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 +69,12 @@ declare module 'typescript' { */ hasInvalidatedResolutions?: (sourceFile: string) => boolean; + /** + * @internal + */ getModuleResolutionCache?(): ts.ModuleResolutionCache; + /** @internal */ + setCompilerHost?(host: ts.CompilerHost): void; } interface ResolvedModuleWithFailedLookupLocations { @@ -82,17 +93,26 @@ declare module 'typescript' { } } +export interface TsConfigInfo { + parsedCommandLine: ts.ParsedCommandLine; + snapshotManager: SnapshotManager; + pendingProjectFileUpdate: boolean; + configFilePath: string; + extendedConfigPaths?: Set; +} + 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 +121,7 @@ const pendingForAllServices = new Set>(); */ export function __resetCache() { services.clear(); + parsedTsConfigInfo.clear(); serviceSizeMap.clear(); configFileForOpenFiles.clear(); } @@ -112,7 +133,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 +151,35 @@ 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; + } + + const defaultService = await findDefaultServiceForFile(service, triedTsConfig); + if (defaultService) { + configFileForOpenFiles.set(path, defaultService.tsconfigPath); + return defaultService; + } + + tsconfigPath = ''; } // Find closer boundary: workspace uri or node_modules @@ -156,6 +200,55 @@ 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(); + if (service.snapshotManager.isProjectFile(path)) { + return service; + } + if (triedTsConfig.has(service.tsconfigPath)) { + return; + } + + // 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 +275,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 +286,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 +313,31 @@ 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 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 +354,12 @@ 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; const host: ts.LanguageServiceHost = { log: (message) => Logger.debug(`[ts] ${message}`), @@ -297,7 +374,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 +385,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 +412,7 @@ async function createLanguageService( docContext.globalSnapshotsManager.onChange(scheduleUpdate); reduceLanguageServiceCapabilityIfFileSizeTooBig(); - updateExtendedConfigDependents(); - watchConfigFile(); + watchConfigFiles(projectConfig.extendedConfigPaths, projectConfig); return { tsconfigPath, @@ -338,6 +423,7 @@ async function createLanguageService( deleteSnapshot, scheduleProjectFileUpdate, updateTsOrJsFile, + ensureProjectFileUpdates, hasFile, fileBelongsToProject, snapshotManager, @@ -345,10 +431,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 +486,8 @@ async function createLanguageService( } function getService(skipSynchronize?: boolean) { - if (pendingProjectFileUpdate) { - updateProjectFiles(); - pendingProjectFileUpdate = false; - } + ensureProjectFileUpdates(); + if (!skipSynchronize) { updateIfDirty(); } @@ -411,7 +519,13 @@ 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; } @@ -481,17 +595,38 @@ 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(): void { + const info = parsedTsConfigInfo.get(tsconfigPath); + if (!info || !info.pendingProjectFileUpdate) { + return; + } const projectFileCountBefore = snapshotManager.getProjectFileNames().length; - snapshotManager.updateProjectFiles(); + ensureFilesForConfigUpdates(info); const projectFileCountAfter = snapshotManager.getProjectFileNames().length; if (projectFileCountAfter > projectFileCountBefore) { @@ -535,72 +670,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 +698,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 +713,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 @@ -640,6 +736,20 @@ async function createLanguageService( } } + const svelteConfigDiagnostics = checkSvelteInput(parsedConfig); + if (svelteConfigDiagnostics.length > 0) { + 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: ts.DiagnosticCategory.Error, + source: 'svelte' + })) + }); + parsedConfig.errors.push(...svelteConfigDiagnostics); + } + return { ...parsedConfig, fileNames: parsedConfig.fileNames.map(normalizePath), @@ -648,15 +758,43 @@ 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(config: ts.ParsedCommandLine) { + if (!tsconfigPath || config.raw.references || config.raw.files) { + return []; + } + + const svelteFiles = config.fileNames.filter(isSvelteFilePath); + if (svelteFiles.length > 0) { + return []; + } + const { include, exclude } = config.raw; + const inputText = JSON.stringify(include); + const excludeText = JSON.stringify(exclude); + const svelteConfigDiagnostics: ts.Diagnostic[] = [ + { + category: ts.DiagnosticCategory.Error, + code: 0, + 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 +802,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 +839,7 @@ async function createLanguageService( } function dispose() { + compilerHost = undefined; languageService.dispose(); snapshotManager.dispose(); configWatchers.get(tsconfigPath)?.close(); @@ -702,19 +848,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 +878,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 +913,8 @@ async function createLanguageService( configFileForOpenFiles.clear(); } - docContext.onProjectReloaded?.(); + docContext.onProjectReloaded?.([fileName]); + docContext.reportConfigError?.({ uri: pathToUrl(fileName), diagnostics: [] }); } function updateIfDirty() { @@ -780,6 +931,7 @@ async function createLanguageService( } dirty = false; + compilerHost = undefined; // 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 +943,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 +955,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 +1034,141 @@ 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; + } + 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 +1228,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 +1244,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 +1263,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..652f2d7a7 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,10 +189,36 @@ 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.length > 0) { + 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)) + })); } const lang = lsContainer.getService(); @@ -211,6 +238,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 +246,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), 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/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-two-way-check/Legacy.svelte b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/bindings-two-way-check/Legacy.svelte new file mode 100644 index 000000000..18db75ea2 --- /dev/null +++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/bindings-two-way-check/Legacy.svelte @@ -0,0 +1,7 @@ + + +{legacy1} +{legacy2} \ No newline at end of file diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/bindings-two-way-check/Runes.svelte b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/bindings-two-way-check/Runes.svelte new file mode 100644 index 000000000..299be4d66 --- /dev/null +++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/bindings-two-way-check/Runes.svelte @@ -0,0 +1,6 @@ + + +{runes1} +{runes2} \ No newline at end of file diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/bindings-two-way-check/RunesGeneric.svelte b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/bindings-two-way-check/RunesGeneric.svelte new file mode 100644 index 000000000..6accfc4b3 --- /dev/null +++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/bindings-two-way-check/RunesGeneric.svelte @@ -0,0 +1,6 @@ + + +{foo} +{bar} \ No newline at end of file diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/bindings-two-way-check/expected_svelte_5.json b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/bindings-two-way-check/expected_svelte_5.json new file mode 100644 index 000000000..6b1d57c83 --- /dev/null +++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/bindings-two-way-check/expected_svelte_5.json @@ -0,0 +1,36 @@ +[ + { + "code": 2322, + "message": "Type 'string | number' is not assignable to type 'string'.\n Type 'number' is not assignable to type 'string'.", + "range": { + "end": { + "character": 28, + "line": 17 + }, + "start": { + "character": 28, + "line": 17 + } + }, + "severity": 1, + "source": "ts", + "tags": [] + }, + { + "code": 2322, + "message": "Type 'string | number' is not assignable to type 'string'.\n Type 'number' is not assignable to type 'string'.", + "range": { + "end": { + "character": 45, + "line": 18 + }, + "start": { + "character": 45, + "line": 18 + } + }, + "severity": 1, + "source": "ts", + "tags": [] + } +] diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/bindings-two-way-check/expectedv2.json b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/bindings-two-way-check/expectedv2.json new file mode 100644 index 000000000..f8c8cb449 --- /dev/null +++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/bindings-two-way-check/expectedv2.json @@ -0,0 +1,18 @@ +[ + { + "code": -1, + "message": "Unexpected token", + "range": { + "end": { + "character": 47, + "line": 12 + }, + "start": { + "character": 47, + "line": 12 + } + }, + "severity": 1, + "source": "ts" + } +] diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/bindings-two-way-check/input.svelte b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/bindings-two-way-check/input.svelte new file mode 100644 index 000000000..49020f784 --- /dev/null +++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/bindings-two-way-check/input.svelte @@ -0,0 +1,19 @@ + + + + + + + + + + + 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/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..50c793c6f 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,117 @@ 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('do 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 +206,11 @@ describe('service', () => { }) ); + virtualSystem.writeFile( + path.join(dirPath, 'random.svelte'), + '' + ); + const ls = await getService( path.join(dirPath, 'random.svelte'), rootUris, @@ -125,21 +243,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 +282,11 @@ describe('service', () => { }) ); + virtualSystem.writeFile( + path.join(dirPath, 'random.svelte'), + '' + ); + const { reloadPromise, docContextWithReload } = createReloadTester( { ...lsDocumentContext, watchTsConfig: true }, testAfterReload @@ -189,6 +315,8 @@ describe('service', () => { true, 'expected to reload compilerOptions' ); + + return true; } }); @@ -197,7 +325,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 +334,11 @@ describe('service', () => { }) ); + virtualSystem.writeFile( + path.join(dirPath, 'random.svelte'), + '' + ); + const { reloadPromise, docContextWithReload } = createReloadTester( { ...lsDocumentContext, watchTsConfig: true }, testAfterReload @@ -234,23 +367,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 +454,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 +564,11 @@ describe('service', () => { sinon.assert.calledWith(watchDirectory.firstCall, []); }); + + function getSemanticDiagnosticsMessages(ls: LanguageServiceContainer, filePath: string) { + return ls + .getService() + .getSemanticDiagnostics(filePath) + .map((d) => d.messageText); + } }); 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/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..634a029f6 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", + "@jridgewell/trace-mapping": "^0.3.25", "chokidar": "^3.4.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..866d23bf3 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,47 @@ async function openAllDocuments( filePathsToIgnore: string[], svelteCheck: SvelteCheck ) { - const files = await glob('**/*.svelte', { - cwd: workspaceUri.fsPath, - ignore: ['node_modules/**'].concat(filePathsToIgnore.map((ignore) => `${ignore}/**`)) + 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: Array<(path: string) => boolean> = 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); }); - const absFilePaths = files.map((f) => path.resolve(workspaceUri.fsPath, f)); + 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'); 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/repl/index.svelte b/packages/svelte2tsx/repl/index.svelte index 49517cc72..bf8061fb0 100644 --- a/packages/svelte2tsx/repl/index.svelte +++ b/packages/svelte2tsx/repl/index.svelte @@ -1,7 +1,7 @@ - - -{#if value} - -{/if} + + \ No newline at end of file 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/nodes/Binding.ts b/packages/svelte2tsx/src/htmlxtojsx_v2/nodes/Binding.ts index 5bb17cca7..555269b61 100644 --- a/packages/svelte2tsx/src/htmlxtojsx_v2/nodes/Binding.ts +++ b/packages/svelte2tsx/src/htmlxtojsx_v2/nodes/Binding.ts @@ -131,6 +131,12 @@ export function handleBinding( if (isSvelte5Plus && element instanceof InlineComponent) { // To check if property is actually bindable element.appendToStartEnd([`${element.name}.$$bindings = '${attr.name}';`]); + // To check if the binding is also assigned to the variable (only works when there's no assertion, we can't transform that) + if (!isTypescriptNode(attr.expression)) { + element.appendToStartEnd([ + `${expressionStr} = __sveltets_binding_value(${element.originalName}, '${attr.name}');` + ]); + } } if (element instanceof Element) { diff --git a/packages/svelte2tsx/src/htmlxtojsx_v2/nodes/InlineComponent.ts b/packages/svelte2tsx/src/htmlxtojsx_v2/nodes/InlineComponent.ts index b1bab058d..7459f227e 100644 --- a/packages/svelte2tsx/src/htmlxtojsx_v2/nodes/InlineComponent.ts +++ b/packages/svelte2tsx/src/htmlxtojsx_v2/nodes/InlineComponent.ts @@ -39,6 +39,7 @@ export class InlineComponent { private startTagEnd: number; private isSelfclosing: boolean; public child?: any; + public originalName = this.node.name; // Add const $$xxx = ... only if the variable name is actually used // in order to prevent "$$xxx is defined but never used" TS hints 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/svelte-shims-v4.d.ts b/packages/svelte2tsx/svelte-shims-v4.d.ts index e8e276255..5227cb041 100644 --- a/packages/svelte2tsx/svelte-shims-v4.d.ts +++ b/packages/svelte2tsx/svelte-shims-v4.d.ts @@ -223,9 +223,9 @@ declare type ATypedSvelteComponent = { declare type ConstructorOfATypedSvelteComponent = new (args: {target: any, props?: any}) => ATypedSvelteComponent 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 + T extends ConstructorOfATypedSvelteComponent | (typeof import('svelte') extends { mount: any } ? import('svelte').Component : never) | null | undefined // @ts-ignore svelte.Component doesn't exist in Svelte 4 ->(type: T): NonNullable ? typeof import('svelte').SvelteComponent : T>; +>(type: T): NonNullable ? typeof import('svelte').SvelteComponent : T : T>; declare function __sveltets_2_ensureArray | Iterable>(array: T): T extends ArrayLike ? U[] : T extends Iterable ? Iterable : any[]; type __sveltets_2_PropsWithChildren = Props & @@ -254,3 +254,16 @@ declare function __sveltets_2_isomorphic_component< declare function __sveltets_2_isomorphic_component_slots< Props extends Record, Events extends Record, Slots extends Record, Exports extends Record, Bindings extends string >(klass: {props: Props, events: Events, slots: Slots, exports?: Exports, bindings?: Bindings }): __sveltets_2_IsomorphicComponent<__sveltets_2_PropsWithChildren, Events, Slots, Exports, Bindings>; + +type __sveltets_NonUndefined = T extends undefined ? never : T; + +declare function __sveltets_binding_value< + // @ts-ignore this is only used for Svelte 5, which knows about the Component type + Comp extends typeof import('svelte').Component, + Key extends string +>(comp: Comp, key: Key): Key extends keyof import('svelte').ComponentProps ? + // bail on unknown because it hints at a generic type which we can't properly resolve here + // remove undefined because optional properties have it, and would result in false positives + unknown extends import('svelte').ComponentProps[Key] ? any : __sveltets_NonUndefined[Key]> : any; +// Overload to ensure typings that only use old SvelteComponent class or something invalid are gracefully handled +declare function __sveltets_binding_value(comp: any, key: string): any diff --git a/packages/svelte2tsx/test/htmlx2jsx/samples/binding-bare/expected-svelte5.js b/packages/svelte2tsx/test/htmlx2jsx/samples/binding-bare/expected-svelte5.js index bb934f658..43291dbae 100644 --- a/packages/svelte2tsx/test/htmlx2jsx/samples/binding-bare/expected-svelte5.js +++ b/packages/svelte2tsx/test/htmlx2jsx/samples/binding-bare/expected-svelte5.js @@ -1,5 +1,5 @@ { svelteHTML.createElement("input", { "type":`text`,"bind:value":value,});/*Ωignore_startΩ*/() => value = __sveltets_2_any(null);/*Ωignore_endΩ*/} { svelteHTML.createElement("input", { "type":`checkbox`,"bind:checked":checked,});/*Ωignore_startΩ*/() => checked = __sveltets_2_any(null);/*Ωignore_endΩ*/} - { const $$_tupnI0C = __sveltets_2_ensureComponent(Input); const $$_tupnI0 = new $$_tupnI0C({ target: __sveltets_2_any(), props: { "type":`text`,value,}});/*Ωignore_startΩ*/() => value = __sveltets_2_any(null);/*Ωignore_endΩ*/$$_tupnI0.$$bindings = 'value';} - { const $$_tupnI0C = __sveltets_2_ensureComponent(Input); const $$_tupnI0 = new $$_tupnI0C({ target: __sveltets_2_any(), props: { "type":`checkbox`,checked,}});/*Ωignore_startΩ*/() => checked = __sveltets_2_any(null);/*Ωignore_endΩ*/$$_tupnI0.$$bindings = 'checked';} \ No newline at end of file + { const $$_tupnI0C = __sveltets_2_ensureComponent(Input); const $$_tupnI0 = new $$_tupnI0C({ target: __sveltets_2_any(), props: { "type":`text`,value,}});/*Ωignore_startΩ*/() => value = __sveltets_2_any(null);/*Ωignore_endΩ*/$$_tupnI0.$$bindings = 'value';value = __sveltets_binding_value(Input, 'value');} + { const $$_tupnI0C = __sveltets_2_ensureComponent(Input); const $$_tupnI0 = new $$_tupnI0C({ target: __sveltets_2_any(), props: { "type":`checkbox`,checked,}});/*Ωignore_startΩ*/() => checked = __sveltets_2_any(null);/*Ωignore_endΩ*/$$_tupnI0.$$bindings = 'checked';checked = __sveltets_binding_value(Input, 'checked');} \ No newline at end of file diff --git a/packages/svelte2tsx/test/htmlx2jsx/samples/binding/expected-svelte5.js b/packages/svelte2tsx/test/htmlx2jsx/samples/binding/expected-svelte5.js index 6c881fec9..355227003 100644 --- a/packages/svelte2tsx/test/htmlx2jsx/samples/binding/expected-svelte5.js +++ b/packages/svelte2tsx/test/htmlx2jsx/samples/binding/expected-svelte5.js @@ -2,7 +2,7 @@ { svelteHTML.createElement("input", { "type":`text`,"bind:value":test,});/*Ωignore_startΩ*/() => test = __sveltets_2_any(null);/*Ωignore_endΩ*/} { svelteHTML.createElement("input", { "type":`text`,"bind:value":test,});/*Ωignore_startΩ*/() => test = __sveltets_2_any(null);/*Ωignore_endΩ*/} - { const $$_tupnI0C = __sveltets_2_ensureComponent(Input); const $$_tupnI0 = new $$_tupnI0C({ target: __sveltets_2_any(), props: { "type":`text`,value:test,}});/*Ωignore_startΩ*/() => test = __sveltets_2_any(null);/*Ωignore_endΩ*/$$_tupnI0.$$bindings = 'value';} - { const $$_tupnI0C = __sveltets_2_ensureComponent(Input); const $$_tupnI0 = new $$_tupnI0C({ target: __sveltets_2_any(), props: { "type":`text`,value:test,}});/*Ωignore_startΩ*/() => test = __sveltets_2_any(null);/*Ωignore_endΩ*/$$_tupnI0.$$bindings = 'value';} - { const $$_tupnI0C = __sveltets_2_ensureComponent(Input); const $$_tupnI0 = new $$_tupnI0C({ target: __sveltets_2_any(), props: { "type":`text`,value:test,}});/*Ωignore_startΩ*/() => test = __sveltets_2_any(null);/*Ωignore_endΩ*/$$_tupnI0.$$bindings = 'value';} - { const $$_tupnI0C = __sveltets_2_ensureComponent(Input); const $$_tupnI0 = new $$_tupnI0C({ target: __sveltets_2_any(), props: { "type":`text`,value:test,}});/*Ωignore_startΩ*/() => test = __sveltets_2_any(null);/*Ωignore_endΩ*/$$_tupnI0.$$bindings = 'value'; Input} \ No newline at end of file + { const $$_tupnI0C = __sveltets_2_ensureComponent(Input); const $$_tupnI0 = new $$_tupnI0C({ target: __sveltets_2_any(), props: { "type":`text`,value:test,}});/*Ωignore_startΩ*/() => test = __sveltets_2_any(null);/*Ωignore_endΩ*/$$_tupnI0.$$bindings = 'value';test = __sveltets_binding_value(Input, 'value');} + { const $$_tupnI0C = __sveltets_2_ensureComponent(Input); const $$_tupnI0 = new $$_tupnI0C({ target: __sveltets_2_any(), props: { "type":`text`,value:test,}});/*Ωignore_startΩ*/() => test = __sveltets_2_any(null);/*Ωignore_endΩ*/$$_tupnI0.$$bindings = 'value';test = __sveltets_binding_value(Input, 'value');} + { const $$_tupnI0C = __sveltets_2_ensureComponent(Input); const $$_tupnI0 = new $$_tupnI0C({ target: __sveltets_2_any(), props: { "type":`text`,value:test,}});/*Ωignore_startΩ*/() => test = __sveltets_2_any(null);/*Ωignore_endΩ*/$$_tupnI0.$$bindings = 'value';test = __sveltets_binding_value(Input, 'value');} + { const $$_tupnI0C = __sveltets_2_ensureComponent(Input); const $$_tupnI0 = new $$_tupnI0C({ target: __sveltets_2_any(), props: { "type":`text`,value:test,}});/*Ωignore_startΩ*/() => test = __sveltets_2_any(null);/*Ωignore_endΩ*/$$_tupnI0.$$bindings = 'value';test = __sveltets_binding_value(Input, 'value'); Input} \ No newline at end of file diff --git a/packages/svelte2tsx/test/htmlx2jsx/samples/editing-binding/expected-svelte5.js b/packages/svelte2tsx/test/htmlx2jsx/samples/editing-binding/expected-svelte5.js index 7bb207fea..31e8b2747 100644 --- a/packages/svelte2tsx/test/htmlx2jsx/samples/editing-binding/expected-svelte5.js +++ b/packages/svelte2tsx/test/htmlx2jsx/samples/editing-binding/expected-svelte5.js @@ -1,3 +1,3 @@ { svelteHTML.createElement("input", { });obj = __sveltets_2_any(null);} { svelteHTML.createElement("input", { "bind:value":obj.,});/*Ωignore_startΩ*/() => obj = __sveltets_2_any(null);/*Ωignore_endΩ*/} - { const $$_tupnI0C = __sveltets_2_ensureComponent(Input); const $$_tupnI0 = new $$_tupnI0C({ target: __sveltets_2_any(), props: { value:obj.,}});/*Ωignore_startΩ*/() => obj = __sveltets_2_any(null);/*Ωignore_endΩ*/$$_tupnI0.$$bindings = 'value';} \ No newline at end of file + { const $$_tupnI0C = __sveltets_2_ensureComponent(Input); const $$_tupnI0 = new $$_tupnI0C({ target: __sveltets_2_any(), props: { value:obj.,}});/*Ωignore_startΩ*/() => obj = __sveltets_2_any(null);/*Ωignore_endΩ*/$$_tupnI0.$$bindings = 'value';obj = __sveltets_binding_value(Input, 'value');} \ No newline at end of file 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/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/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..f1bc6d8f0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -16,17 +16,17 @@ 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 @@ -36,21 +36,21 @@ importers: 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 + 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==} @@ -622,6 +627,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 +667,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 +695,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 +721,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 +744,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 +754,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 +907,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 +941,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 +972,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 +989,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 +1000,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 +1077,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 +1087,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 @@ -1100,10 +1120,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 +1156,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 +1183,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 +1209,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 +1229,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 +1264,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 +1295,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 +1315,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 +1322,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 +1389,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 +1408,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 +1479,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 +1538,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 +1553,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 +1573,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 +1586,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 +1594,8 @@ snapshots: acorn-walk@8.2.0: {} + acorn@8.12.1: {} + acorn@8.8.2: {} aggregate-error@3.1.0: @@ -1655,8 +1628,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 +1655,6 @@ snapshots: browser-stdout@1.3.1: {} - buffer-crc32@0.2.13: {} - buffer-from@1.1.2: {} builtin-modules@3.3.0: {} @@ -1715,6 +1692,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 +1732,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 +1760,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 +1779,6 @@ snapshots: emoji-regex@8.0.0: {} - es6-promise@3.3.1: {} - escalade@3.1.1: {} escape-string-regexp@1.0.5: {} @@ -1803,6 +1791,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 +1807,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 +1952,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 +1985,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 +2014,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 +2031,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 +2043,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 +2135,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: {} @@ -2172,10 +2172,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 +2212,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 +2239,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 +2262,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 +2278,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 +2304,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 +2330,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 +2363,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: {} pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy