Skip to content

Commit

Permalink
Implement component definition resolver by element name
Browse files Browse the repository at this point in the history
  • Loading branch information
dzonatan committed Apr 3, 2017
1 parent 7b50c0a commit aeb2845
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 5 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
31 changes: 28 additions & 3 deletions src/providers/angular-html-definition-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,

Expand All @@ -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: <my-element ...>...</my-element>
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;

Expand Down
4 changes: 4 additions & 0 deletions test/_test_files/bar.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
@Component({
selector: 'xx-bar'
})
export class BarComponent { }
4 changes: 3 additions & 1 deletion test/_test_files/foo.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
<input type="text" [class.error]="myGetter" [(ngModel)]="myLongProperty" (click)="myMethod($event)">

<div *ngIf="good"></div>

{{ myProperty | myPipe }}
{{ myService.myProp }}
{{ myObj?.foo }}

<xx-bar></xx-bar>
</div>
8 changes: 8 additions & 0 deletions test/providers/angular-html-definition-provider.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
});
});

0 comments on commit aeb2845

Please sign in to comment.