diff --git a/README.md b/README.md index 43576e0..378a2c3 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Lightweight language support for angular definitions. ## Prerequisites - Angular with **Typescript** -- [Official style guide](https://angular.io/docs/ts/latest/guide/style-guide.html#!#naming) file naming (component `.ts` and `.html` names should match). +- [Official style guide](https://angular.io/docs/ts/latest/guide/style-guide.html#!#naming) file & selector naming ## Features diff --git a/src/providers/angular-html-definition-provider.ts b/src/providers/angular-html-definition-provider.ts index 1b43f37..f28b926 100644 --- a/src/providers/angular-html-definition-provider.ts +++ b/src/providers/angular-html-definition-provider.ts @@ -12,7 +12,7 @@ export class AngularHtmlDefinitionProvider implements DefinitionProvider { async provideDefinition(document: TextDocument, position: Position, token: CancellationToken) { const lineText = document.lineAt(position).text; - const regexps = [ + const propertyRegexps = [ // Interpolation. ex: {{ myProp }} /({{)([^}]+)}}/g, @@ -25,9 +25,34 @@ export class AngularHtmlDefinitionProvider implements DefinitionProvider { // Structural attributes. ex: *ngIf="myProp" /(\*\w+=")([^"]+)"/g ]; - const expressionMatch: string = utils.parseByLocationRegexps(lineText, position.character, regexps); - if (!expressionMatch) return null; + const propertyMatch = utils.parseByLocationRegexps(lineText, position.character, propertyRegexps); + if (!!propertyMatch) { + return await this.propertyDefinition(document, position); + } + // Element. ex: ... + const elementRegexp = /(<\/?)([a-zA-Z0-9-]+)/g; + const elementMatch = utils.parseByLocationRegexp(lineText, position.character, elementRegexp); + if (!!elementMatch) { + return await this.elementDefinition(elementMatch); + } + + return null; + } + + private async elementDefinition(selector: string) { + const expectedFileName = `src/**/${selector.replace(/(\w+-)/, (f) => '')}.component.ts`; + const foundFiles = await workspace.findFiles(expectedFileName, '**∕node_modules∕**', 2); + + // To be sure of defition origin return only when there is one match. + if (foundFiles.length === 1) { + return new Location(Uri.file(foundFiles[0].path), new Position(0, 0)); + } + + return null; + } + + private async propertyDefinition(document: TextDocument, position: Position) { const range = document.getWordRangeAtPosition(position, /[$\w]+/); if (!range) return null; diff --git a/test/_test_files/bar.component.ts b/test/_test_files/bar.component.ts new file mode 100644 index 0000000..9dd3353 --- /dev/null +++ b/test/_test_files/bar.component.ts @@ -0,0 +1,4 @@ +@Component({ + selector: 'xx-bar' +}) +export class BarComponent { } diff --git a/test/_test_files/foo.component.html b/test/_test_files/foo.component.html index 67d40c9..54aa782 100644 --- a/test/_test_files/foo.component.html +++ b/test/_test_files/foo.component.html @@ -3,8 +3,10 @@
- + {{ myProperty | myPipe }} {{ myService.myProp }} {{ myObj?.foo }} + + \ No newline at end of file diff --git a/test/providers/angular-html-definition-provider.test.ts b/test/providers/angular-html-definition-provider.test.ts index b08499b..f8ead0f 100644 --- a/test/providers/angular-html-definition-provider.test.ts +++ b/test/providers/angular-html-definition-provider.test.ts @@ -75,4 +75,12 @@ suite('AngularHtmlDefinitionProvider', () => { await assertGoToDefinition(templateFilePath, inputPosition, expectedFile, expectedPosition); }); + + test('should resolve component', async () => { + const inputPosition = new vscode.Position(10, 7); + const expectedFile = workspaceFilePath('bar.component.ts'); + const expectedPosition = new vscode.Position(0, 0); + + await assertGoToDefinition(templateFilePath, inputPosition, expectedFile, expectedPosition); + }); });