diff --git a/packages/language-server/src/plugins/typescript/TypeScriptPlugin.ts b/packages/language-server/src/plugins/typescript/TypeScriptPlugin.ts index 05be1bccb..fa7709bea 100644 --- a/packages/language-server/src/plugins/typescript/TypeScriptPlugin.ts +++ b/packages/language-server/src/plugins/typescript/TypeScriptPlugin.ts @@ -159,13 +159,16 @@ export class TypeScriptPlugin ); this.renameProvider = new RenameProviderImpl(this.lsAndTsDocResolver, configManager); this.hoverProvider = new HoverProviderImpl(this.lsAndTsDocResolver); - this.findReferencesProvider = new FindReferencesProviderImpl(this.lsAndTsDocResolver); this.findFileReferencesProvider = new FindFileReferencesProviderImpl( this.lsAndTsDocResolver ); this.findComponentReferencesProvider = new FindComponentReferencesProviderImpl( this.lsAndTsDocResolver ); + this.findReferencesProvider = new FindReferencesProviderImpl( + this.lsAndTsDocResolver, + this.findComponentReferencesProvider + ); this.selectionRangeProvider = new SelectionRangeProviderImpl(this.lsAndTsDocResolver); this.signatureHelpProvider = new SignatureHelpProviderImpl(this.lsAndTsDocResolver); this.semanticTokensProvider = new SemanticTokensProviderImpl(this.lsAndTsDocResolver); diff --git a/packages/language-server/src/plugins/typescript/features/FindReferencesProvider.ts b/packages/language-server/src/plugins/typescript/features/FindReferencesProvider.ts index 2e8934ae8..c530398ea 100644 --- a/packages/language-server/src/plugins/typescript/features/FindReferencesProvider.ts +++ b/packages/language-server/src/plugins/typescript/features/FindReferencesProvider.ts @@ -1,11 +1,15 @@ -import type ts from 'typescript'; +import ts from 'typescript'; import { Location, Position, ReferenceContext } from 'vscode-languageserver'; import { Document } from '../../../lib/documents'; -import { flatten, isNotNullOrUndefined } from '../../../utils'; -import { FindReferencesProvider } from '../../interfaces'; +import { flatten, isNotNullOrUndefined, pathToUrl } from '../../../utils'; +import { FindComponentReferencesProvider, FindReferencesProvider } from '../../interfaces'; import { SvelteDocumentSnapshot } from '../DocumentSnapshot'; import { LSAndTSDocResolver } from '../LSAndTSDocResolver'; -import { convertToLocationForReferenceOrDefinition, hasNonZeroRange } from '../utils'; +import { + convertToLocationForReferenceOrDefinition, + hasNonZeroRange, + isGeneratedSvelteComponentName +} from '../utils'; import { get$storeOffsetOf$storeDeclaration, getStoreOffsetOf$storeDeclaration, @@ -16,14 +20,22 @@ import { } from './utils'; export class FindReferencesProviderImpl implements FindReferencesProvider { - constructor(private readonly lsAndTsDocResolver: LSAndTSDocResolver) {} + constructor( + private readonly lsAndTsDocResolver: LSAndTSDocResolver, + private readonly componentReferencesProvider: FindComponentReferencesProvider + ) {} async findReferences( document: Document, position: Position, context: ReferenceContext ): Promise { + if (this.isScriptStartOrEndTag(position, document)) { + return this.componentReferencesProvider.findComponentReferences(document.uri); + } + const { lang, tsDoc } = await this.getLSAndTSDoc(document); + const offset = tsDoc.offsetAt(tsDoc.getGeneratedPosition(position)); const rawReferences = lang.findReferences( tsDoc.filePath, @@ -36,7 +48,19 @@ export class FindReferencesProviderImpl implements FindReferencesProvider { const snapshots = new SnapshotMap(this.lsAndTsDocResolver); snapshots.set(tsDoc.filePath, tsDoc); + if (rawReferences.some((ref) => ref.definition.kind === ts.ScriptElementKind.alias)) { + const componentReferences = await this.checkIfHasAliasedComponentReference( + offset, + tsDoc, + lang + ); + + if (componentReferences?.length) { + return componentReferences; + } + } const references = flatten(rawReferences.map((ref) => ref.references)); + references.push(...(await this.getStoreReferences(references, tsDoc, snapshots, lang))); const locations = await Promise.all( @@ -51,6 +75,19 @@ export class FindReferencesProviderImpl implements FindReferencesProvider { ); } + private isScriptStartOrEndTag(position: Position, document: Document) { + if (!document.scriptInfo) { + return false; + } + const { start, end } = document.scriptInfo.container; + + const offset = document.offsetAt(position); + return ( + (offset >= start && offset <= start + '= end - ''.length && offset <= end) + ); + } + /** * If references of a $store are searched, also find references for the corresponding store * and vice versa. @@ -110,6 +147,30 @@ export class FindReferencesProviderImpl implements FindReferencesProvider { return [...storeReferences, ...$storeReferences]; } + private async checkIfHasAliasedComponentReference( + offset: number, + tsDoc: SvelteDocumentSnapshot, + lang: ts.LanguageService + ) { + const definitions = lang.getDefinitionAtPosition(tsDoc.filePath, offset); + if (!definitions?.length) { + return null; + } + + const nonAliasDefinitions = definitions.filter((definition) => + isGeneratedSvelteComponentName(definition.name) + ); + const references = await Promise.all( + nonAliasDefinitions.map((definition) => + this.componentReferencesProvider.findComponentReferences( + pathToUrl(definition.fileName) + ) + ) + ); + + return flatten(references.filter(isNotNullOrUndefined)); + } + private async mapReference( ref: ts.ReferencedSymbolEntry, context: ReferenceContext, diff --git a/packages/language-server/test/plugins/typescript/features/FindComponentReferencesProvider.test.ts b/packages/language-server/test/plugins/typescript/features/FindComponentReferencesProvider.test.ts index 482af1ffd..25b38235e 100644 --- a/packages/language-server/test/plugins/typescript/features/FindComponentReferencesProvider.test.ts +++ b/packages/language-server/test/plugins/typescript/features/FindComponentReferencesProvider.test.ts @@ -50,6 +50,7 @@ describe('FindComponentReferencesProvider', function () { const { provider, document, openDoc } = setup('find-component-references-child.svelte'); //Make known all the associated files openDoc('find-component-references-parent.svelte'); + openDoc('find-component-references-parent2.svelte'); const results = await provider.findComponentReferences(document.uri.toString()); @@ -105,6 +106,19 @@ describe('FindComponentReferencesProvider', function () { } }, uri: getUri('find-component-references-parent.svelte') + }, + { + range: { + start: { + line: 1, + character: 9 + }, + end: { + line: 1, + character: 19 + } + }, + uri: getUri('find-component-references-parent2.svelte') } ]); }); 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 1719ca933..aa160034a 100644 --- a/packages/language-server/test/plugins/typescript/features/FindReferencesProvider.test.ts +++ b/packages/language-server/test/plugins/typescript/features/FindReferencesProvider.test.ts @@ -9,6 +9,7 @@ import { LSAndTSDocResolver } from '../../../../src/plugins/typescript/LSAndTSDo import { __resetCache } from '../../../../src/plugins/typescript/service'; import { pathToUrl } from '../../../../src/utils'; import { serviceWarmup } from '../test-utils'; +import { FindComponentReferencesProviderImpl } from '../../../../src/plugins/typescript/features/FindComponentReferencesProvider'; const testDir = path.join(__dirname, '..'); @@ -29,7 +30,10 @@ describe('FindReferencesProvider', function () { ); const lsConfigManager = new LSConfigManager(); const lsAndTsDocResolver = new LSAndTSDocResolver(docManager, [testDir], lsConfigManager); - const provider = new FindReferencesProviderImpl(lsAndTsDocResolver); + const provider = new FindReferencesProviderImpl( + lsAndTsDocResolver, + new FindComponentReferencesProviderImpl(lsAndTsDocResolver) + ); const document = openDoc(filename); return { provider, document, openDoc }; @@ -76,7 +80,7 @@ describe('FindReferencesProvider', function () { await test(Position.create(1, 11), true); }); - it('finds references, exluding definition', async () => { + it('finds references, excluding definition', async () => { await test(Position.create(1, 11), false); }); @@ -330,6 +334,99 @@ describe('FindReferencesProvider', function () { ]); }); + const componentReferences = [ + { + range: { + start: { + line: 8, + character: 15 + }, + end: { + line: 8, + character: 22 + } + }, + uri: getUri('find-component-references-parent.svelte') + }, + { + range: { + start: { + line: 1, + character: 9 + }, + end: { + line: 1, + character: 19 + } + }, + uri: getUri('find-component-references-parent.svelte') + }, + { + range: { + start: { + line: 18, + character: 1 + }, + end: { + line: 18, + character: 11 + } + }, + uri: getUri('find-component-references-parent.svelte') + }, + { + range: { + start: { + line: 20, + character: 1 + }, + end: { + line: 20, + character: 11 + } + }, + uri: getUri('find-component-references-parent.svelte') + }, + { + range: { + start: { + line: 1, + character: 9 + }, + end: { + line: 1, + character: 19 + } + }, + uri: getUri('find-component-references-parent2.svelte') + } + ]; + + it('can find component references from script tag', async () => { + const { provider, document, openDoc } = setup('find-component-references-child.svelte'); + + openDoc('find-component-references-parent.svelte'); + openDoc('find-component-references-parent2.svelte'); + + const results = await provider.findReferences(document, Position.create(0, 1), { + includeDeclaration: true + }); + + assert.deepStrictEqual(results, componentReferences); + }); + + it('can find all component references', async () => { + const { provider, document, openDoc } = setup('find-component-references-parent.svelte'); + + openDoc('find-component-references-parent2.svelte'); + + const results = await provider.findReferences(document, Position.create(18, 1), { + includeDeclaration: true + }); + + assert.deepStrictEqual(results, componentReferences); + }); + // Hacky, but it works. Needed due to testing both new and old transformation after(() => { __resetCache(); diff --git a/packages/language-server/test/plugins/typescript/testfiles/find-component-references-parent2.svelte b/packages/language-server/test/plugins/typescript/testfiles/find-component-references-parent2.svelte new file mode 100644 index 000000000..bb50774d7 --- /dev/null +++ b/packages/language-server/test/plugins/typescript/testfiles/find-component-references-parent2.svelte @@ -0,0 +1,3 @@ +