Skip to content

Commit 1ab4311

Browse files
committed
feat(app): @HostBinding & @HostListener support
fix #277
1 parent b7d3406 commit 1ab4311

File tree

12 files changed

+418
-121
lines changed

12 files changed

+418
-121
lines changed

dist/index-cli.js

Lines changed: 96 additions & 37 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/index.js

Lines changed: 96 additions & 37 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/app/application.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -960,6 +960,8 @@ export class Application {
960960
_.forEach(list, (element) => {
961961
if (!element.propertiesClass ||
962962
!element.methodsClass ||
963+
!element.hostBindings ||
964+
!element.hostListeners ||
963965
!element.inputsClass ||
964966
!element.outputsClass) {
965967
return;
@@ -971,7 +973,7 @@ export class Application {
971973
name: element.name
972974
},
973975
totalStatementDocumented = 0,
974-
totalStatements = element.propertiesClass.length + element.methodsClass.length + element.inputsClass.length + element.outputsClass.length + 1; // +1 for element decorator comment
976+
totalStatements = element.propertiesClass.length + element.methodsClass.length + element.inputsClass.length + element.hostBindings.length + element.hostListeners.length + element.outputsClass.length + 1; // +1 for element decorator comment
975977

976978
if (element.constructorObj) {
977979
totalStatements += 1;
@@ -999,6 +1001,22 @@ export class Application {
9991001
totalStatementDocumented += 1;
10001002
}
10011003
});
1004+
_.forEach(element.hostBindings, (property) => {
1005+
if (property.modifierKind === 111) { // Doesn't handle private for coverage
1006+
totalStatements -= 1;
1007+
}
1008+
if(property.description && property.description !== '' && property.modifierKind !== 111) {
1009+
totalStatementDocumented += 1;
1010+
}
1011+
});
1012+
_.forEach(element.hostListeners, (method) => {
1013+
if (method.modifierKind === 111) { // Doesn't handle private for coverage
1014+
totalStatements -= 1;
1015+
}
1016+
if(method.description && method.description !== '' && method.modifierKind !== 111) {
1017+
totalStatementDocumented += 1;
1018+
}
1019+
});
10021020
_.forEach(element.inputsClass, (input) => {
10031021
if (input.modifierKind === 111) { // Doesn't handle private for coverage
10041022
totalStatements -= 1;

src/app/compiler/dependencies.ts

Lines changed: 86 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,9 @@ interface Deps {
8080
propertiesClass?: Object[];
8181
methodsClass?: Object[];
8282

83+
hostBindings?: Object[];
84+
hostListeners?: Object[];
85+
8386
//common
8487
providers?: Deps[];
8588

@@ -349,6 +352,10 @@ export class Dependencies {
349352
outputsClass: IO.outputs,
350353
propertiesClass: IO.properties,
351354
methodsClass: IO.methods,
355+
356+
hostBindings: IO.hostBindings,
357+
hostListeners: IO.hostListeners,
358+
352359
description: IO.description,
353360
type: 'component',
354361
sourceCode: srcFile.getText(),
@@ -420,6 +427,9 @@ export class Dependencies {
420427
inputsClass: IO.inputs,
421428
outputsClass: IO.outputs,
422429

430+
hostBindings: IO.hostBindings,
431+
hostListeners: IO.hostListeners,
432+
423433
propertiesClass: IO.properties,
424434
methodsClass: IO.methods,
425435
exampleUrls: _this.getComponentExampleUrls(srcFile.getText())
@@ -908,7 +918,65 @@ export class Dependencies {
908918
return null;
909919
}
910920

911-
private visitInput(property, inDecorator, sourceFile?) {
921+
private visitOutput(property, outDecorator, sourceFile?) {
922+
var inArgs = outDecorator.expression.arguments,
923+
_return = {};
924+
_return.name = (inArgs.length > 0) ? inArgs[0].text : property.name.text;
925+
_return.defaultValue = property.initializer ? this.stringifyDefaultValue(property.initializer) : undefined;
926+
if (property.symbol) {
927+
_return.description = marked(ts.displayPartsToString(property.symbol.getDocumentationComment()))
928+
}
929+
if (!_return.description) {
930+
if (property.jsDoc) {
931+
if (property.jsDoc.length > 0) {
932+
if (typeof property.jsDoc[0].comment !== 'undefined') {
933+
_return.description = marked(property.jsDoc[0].comment);
934+
}
935+
}
936+
}
937+
}
938+
_return.line = this.getPosition(property, sourceFile).line + 1;
939+
940+
if (property.type) {
941+
_return.type = this.visitType(property);
942+
} else {
943+
// handle NewExpression
944+
if (property.initializer) {
945+
if (property.initializer.kind === ts.SyntaxKind.NewExpression) {
946+
if (property.initializer.expression) {
947+
_return.type = property.initializer.expression.text;
948+
}
949+
}
950+
}
951+
}
952+
return _return;
953+
}
954+
955+
private visitHostListener(property, hostListenerDecorator, sourceFile?) {
956+
var inArgs = hostListenerDecorator.expression.arguments,
957+
_return = {};
958+
_return.name = (inArgs.length > 0) ? inArgs[0].text : property.name.text;
959+
_return.args = property.parameters ? property.parameters.map((prop) => this.visitArgument(prop)) : [];
960+
_return.argsDecorator = (inArgs.length > 1) ? inArgs[1].elements.map((prop) => {
961+
return prop.text;
962+
}) : [];
963+
if (property.symbol) {
964+
_return.description = marked(ts.displayPartsToString(property.symbol.getDocumentationComment()));
965+
}
966+
if (!_return.description) {
967+
if (property.jsDoc) {
968+
if (property.jsDoc.length > 0) {
969+
if (typeof property.jsDoc[0].comment !== 'undefined') {
970+
_return.description = marked(property.jsDoc[0].comment);
971+
}
972+
}
973+
}
974+
}
975+
_return.line = this.getPosition(property, sourceFile).line + 1;
976+
return _return;
977+
}
978+
979+
private visitInputAndHostBinding(property, inDecorator, sourceFile?) {
912980
var inArgs = inDecorator.expression.arguments,
913981
_return = {};
914982
_return.name = (inArgs.length > 0) ? inArgs[0].text : property.name.text;
@@ -1013,40 +1081,6 @@ export class Dependencies {
10131081
return _return;
10141082
}
10151083

1016-
private visitOutput(property, outDecorator, sourceFile?) {
1017-
var inArgs = outDecorator.expression.arguments,
1018-
_return = {};
1019-
_return.name = (inArgs.length > 0) ? inArgs[0].text : property.name.text;
1020-
_return.defaultValue = property.initializer ? this.stringifyDefaultValue(property.initializer) : undefined;
1021-
if (property.symbol) {
1022-
_return.description = marked(ts.displayPartsToString(property.symbol.getDocumentationComment()))
1023-
}
1024-
if (!_return.description) {
1025-
if (property.jsDoc) {
1026-
if (property.jsDoc.length > 0) {
1027-
if (typeof property.jsDoc[0].comment !== 'undefined') {
1028-
_return.description = marked(property.jsDoc[0].comment);
1029-
}
1030-
}
1031-
}
1032-
}
1033-
_return.line = this.getPosition(property, sourceFile).line + 1;
1034-
1035-
if (property.type) {
1036-
_return.type = this.visitType(property);
1037-
} else {
1038-
// handle NewExpression
1039-
if (property.initializer) {
1040-
if (property.initializer.kind === ts.SyntaxKind.NewExpression) {
1041-
if (property.initializer.expression) {
1042-
_return.type = property.initializer.expression.text;
1043-
}
1044-
}
1045-
}
1046-
}
1047-
return _return;
1048-
}
1049-
10501084
private isPublic(member): boolean {
10511085
if (member.modifiers) {
10521086
const isPublic: boolean = member.modifiers.some(function(modifier) {
@@ -1353,24 +1387,34 @@ export class Dependencies {
13531387
*/
13541388
var inputs = [],
13551389
outputs = [],
1390+
hostBindings = [],
1391+
hostListeners = [],
13561392
methods = [],
13571393
properties = [],
13581394
indexSignatures = [],
13591395
kind,
13601396
inputDecorator,
1397+
hostBinding,
1398+
hostListener,
13611399
constructor,
13621400
outDecorator;
13631401

13641402
for (var i = 0; i < members.length; i++) {
13651403
inputDecorator = this.getDecoratorOfType(members[i], 'Input');
13661404
outDecorator = this.getDecoratorOfType(members[i], 'Output');
1405+
hostBinding = this.getDecoratorOfType(members[i], 'HostBinding');
1406+
hostListener = this.getDecoratorOfType(members[i], 'HostListener');
13671407

13681408
kind = members[i].kind;
13691409

13701410
if (inputDecorator) {
1371-
inputs.push(this.visitInput(members[i], inputDecorator, sourceFile));
1411+
inputs.push(this.visitInputAndHostBinding(members[i], inputDecorator, sourceFile));
13721412
} else if (outDecorator) {
13731413
outputs.push(this.visitOutput(members[i], outDecorator, sourceFile));
1414+
} else if (hostBinding) {
1415+
hostBindings.push(this.visitInputAndHostBinding(members[i], hostBinding, sourceFile));
1416+
} else if (hostListener) {
1417+
hostListeners.push(this.visitHostListener(members[i], hostListener, sourceFile));
13741418
} else if (!this.isHiddenMember(members[i])) {
13751419

13761420
if ( (this.isPrivate(members[i]) || this.isInternal(members[i])) && this.configuration.mainData.disablePrivateOrInternalSupport) {} else {
@@ -1400,13 +1444,17 @@ export class Dependencies {
14001444

14011445
inputs.sort(getNamesCompareFn());
14021446
outputs.sort(getNamesCompareFn());
1447+
hostBindings.sort(getNamesCompareFn());
1448+
hostListeners.sort(getNamesCompareFn());
14031449
properties.sort(getNamesCompareFn());
14041450
methods.sort(getNamesCompareFn());
14051451
indexSignatures.sort(getNamesCompareFn());
14061452

14071453
return {
14081454
inputs,
14091455
outputs,
1456+
hostBindings,
1457+
hostListeners,
14101458
methods,
14111459
properties,
14121460
indexSignatures,
@@ -1518,6 +1566,8 @@ export class Dependencies {
15181566
description,
15191567
inputs: members.inputs,
15201568
outputs: members.outputs,
1569+
hostBindings: members.hostBindings,
1570+
hostListeners: members.hostListeners,
15211571
properties: members.properties,
15221572
methods: members.methods,
15231573
indexSignatures: members.indexSignatures,

src/templates/partials/block-method.hbs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
<section>
2-
{{#compare title "===" 'false' }}{{else}}
2+
{{#if title}}
3+
<h3>
4+
{{title}}
5+
</h3>
6+
{{else}}
37
<h3 id="methods">
48
Methods
59
</h3>
6-
{{/compare}}
10+
{{/if}}
711
{{#each methods}}
812
<table class="table table-sm table-bordered">
913
<tbody>
@@ -20,6 +24,13 @@
2024
</td>
2125
</tr>
2226
{{/if}}
27+
{{#if argsDecorator}}
28+
<tr>
29+
<td class="col-md-4">
30+
<i>Arguments : </i><code>{{#each argsDecorator}}'{{this}}' {{/each}}</code>
31+
</td>
32+
</tr>
33+
{{/if}}
2334
<tr>
2435
<td class="col-md-4">
2536
{{#if modifierKind}}

src/templates/partials/block-property.hbs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
<section>
2-
{{#compare title "===" 'false' }}{{else}}
2+
{{#if title}}
3+
<h3>
4+
{{title}}
5+
</h3>
6+
{{else}}
37
<h3 id="inputs">
48
Properties
59
</h3>
6-
{{/compare}}
10+
{{/if}}
711
{{#each properties}}
812
<table class="table table-sm table-bordered">
913
<tbody>

src/templates/partials/component-detail.hbs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -195,8 +195,8 @@
195195
</table>
196196
</section>
197197

198-
{{#orLength component.propertiesClass component.methodsClass component.inputsClass component.outputClass}}
199-
{{> index-directive methods=component.methodsClass properties=component.propertiesClass inputs=component.inputsClass outputs=component.outputsClass }}
198+
{{#orLength component.propertiesClass component.methodsClass component.inputsClass component.outputClass component.hostBindings component.hostListeners}}
199+
{{> index-directive methods=component.methodsClass properties=component.propertiesClass inputs=component.inputsClass outputs=component.outputsClass hostBindings=component.hostBindings hostListeners=component.hostListeners }}
200200
{{/orLength}}
201201

202202
{{#if component.constructorObj}}
@@ -280,6 +280,14 @@
280280
</section>
281281
{{/if}}
282282

283+
{{#if component.hostBindings}}
284+
{{> block-property properties=component.hostBindings file=component.file title="HostBindings" }}
285+
{{/if}}
286+
287+
{{#if component.hostListeners}}
288+
{{> block-method methods=component.hostListeners file=component.file title="HostListeners" }}
289+
{{/if}}
290+
283291
{{#if component.methodsClass}}
284292
{{> block-method methods=component.methodsClass file=component.file }}
285293
{{/if}}

src/templates/partials/directive.hbs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,8 @@
9999
</table>
100100
</section>
101101

102-
{{#orLength directive.propertiesClass directive.methodsClass directive.inputsClass directive.outputClass}}
103-
{{> index-directive methods=directive.methodsClass properties=directive.propertiesClass inputs=directive.inputsClass directive=component.outputsClass }}
102+
{{#orLength directive.propertiesClass directive.methodsClass directive.inputsClass directive.outputClass directive.hostBindings directive.hostListeners}}
103+
{{> index-directive methods=directive.methodsClass properties=directive.propertiesClass inputs=directive.inputsClass outputs=directive.outputsClass hostBindings=directive.hostBindings hostListeners=directive.hostListeners }}
104104
{{/orLength}}
105105

106106
{{#if directive.constructorObj}}
@@ -184,6 +184,14 @@
184184
</section>
185185
{{/if}}
186186

187+
{{#if directive.hostBindings}}
188+
{{> block-property properties=directive.hostBindings file=directive.file title="HostBindings" }}
189+
{{/if}}
190+
191+
{{#if directive.hostListeners}}
192+
{{> block-method methods=directive.hostListeners file=directive.file title="HostListeners" }}
193+
{{/if}}
194+
187195
{{#if directive.methodsClass}}
188196
{{> block-method methods=directive.methodsClass file=directive.file }}
189197
{{/if}}

src/templates/partials/index-directive.hbs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,42 @@
7474
</td>
7575
</tr>
7676
{{/compare}}
77+
{{#compare hostBindings.length ">" 0}}
78+
<tr>
79+
<td class="col-md-4">
80+
<h6><b>HostBindings</b></h6>
81+
</td>
82+
</tr>
83+
<tr>
84+
<td class="col-md-4">
85+
<ul class="index-list">
86+
{{#each hostBindings}}
87+
<li>
88+
<a href="#{{name}}">{{name}}</a>
89+
</li>
90+
{{/each}}
91+
</ul>
92+
</td>
93+
</tr>
94+
{{/compare}}
95+
{{#compare hostListeners.length ">" 0}}
96+
<tr>
97+
<td class="col-md-4">
98+
<h6><b>HostListeners</b></h6>
99+
</td>
100+
</tr>
101+
<tr>
102+
<td class="col-md-4">
103+
<ul class="index-list">
104+
{{#each hostListeners}}
105+
<li>
106+
<a href="#{{name}}">{{name}}</a>
107+
</li>
108+
{{/each}}
109+
</ul>
110+
</td>
111+
</tr>
112+
{{/compare}}
77113
</tbody>
78114
</table>
79115
</section>

test/src/cli/cli-generation-big-app.spec.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,4 +229,15 @@ describe('CLI simple generation - big app', () => {
229229
expect(file).to.contain('<code>literal type | null');
230230
});
231231

232+
it('should support @HostBindings', () => {
233+
let file = read('documentation/directives/DoNothingDirective.html');
234+
expect(file).to.contain('<code>style.color');
235+
});
236+
237+
it('should support @HostListener', () => {
238+
let file = read('documentation/components/AboutComponent.html');
239+
expect(file).to.contain('<code>mouseup(mouseX');
240+
expect(file).to.contain('i>Arguments : </i><code>\'$event.clientX');
241+
});
242+
232243
});

0 commit comments

Comments
 (0)