Skip to content

Commit c17bdf4

Browse files
committed
[feat] API filtering
This PR adds filtering of members for classes and components that allows users to filter out private, protected, inherited, and deprecated members. In the case of components, users can also filter out `internal` properties - everything besides Yields and Arguments. Filters only appear if there is something to filter, and by default they are enabled (unchecked), so users should see the minimal public API of the class. The complexity of the filters is definitely not ideal, but at the moment I'm unsure if pushing that complexity into the object model (e.g. by adding `publicFields`, `privateFields`, `staticPublicFields`, `staticPrivateFields`, etc directly to models) as part of the build step will help much.
1 parent cbcc4b7 commit c17bdf4

File tree

14 files changed

+389
-32
lines changed

14 files changed

+389
-32
lines changed
Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,35 @@
11
import Component from '@ember/component';
22
import { computed } from '@ember/object';
3+
import { capitalize } from '@ember/string';
4+
import { memberFilter } from '../../../utils/computed';
35

46
import layout from './template';
57

68
export default Component.extend({
79
layout,
810

11+
showInherited: false,
12+
showProtected: false,
13+
showPrivate: false,
14+
showDeprecated: false,
15+
16+
accessors: memberFilter('class', 'accessors'),
17+
methods: memberFilter('class', 'methods'),
18+
fields: memberFilter('class', 'fields'),
19+
920
hasContents: computed('class', {
1021
get() {
1122
let klass = this.get('class');
1223

13-
return klass.get('constructors.length') > 0
14-
|| klass.get('fields.length') > 0
15-
|| klass.get('accessors.length') > 0
16-
|| klass.get('methods.length') > 0;
24+
return klass.get('allFields.length') > 0
25+
|| klass.get('allAccessors.length') > 0
26+
|| klass.get('allMethods.length') > 0;
27+
}
28+
}),
29+
30+
actions: {
31+
updateFilter(filter, { target: { checked } }) {
32+
this.set(`show${capitalize(filter)}`, checked);
1733
}
18-
})
34+
}
1935
});

addon/components/api/x-class/template.hbs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,20 @@
66
{{#if hasContents}}
77
<div class="class-contents">
88
{{api/x-index
9+
options=(hash
10+
inherited=inherited
11+
protected=protected
12+
private=private
13+
deprecated=deprecated
14+
)
15+
16+
onOptionToggle=(action 'updateFilter')
17+
918
sections=(hash
10-
constructors=class.constructors
11-
fields=class.fields
12-
accessors=class.accessors
13-
methods=class.methods
19+
constructors=constructors
20+
fields=fields
21+
accessors=accessors
22+
methods=methods
1423
)
1524
}}
1625

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,42 @@
11
import Component from '@ember/component';
22
import { computed } from '@ember/object';
3+
import { alias } from '@ember/object/computed';
4+
import { capitalize } from '@ember/string';
5+
import { memberFilter } from '../../../utils/computed';
36

47
import layout from './template';
58

69
export default Component.extend({
710
layout,
811

12+
showInherited: false,
13+
showInternal: false,
14+
showProtected: false,
15+
showPrivate: false,
16+
showDeprecated: false,
17+
18+
yields: alias('component.overloadedYields'),
19+
20+
arguments: memberFilter('component', 'arguments'),
21+
accessors: memberFilter('component', 'accessors'),
22+
methods: memberFilter('component', 'methods'),
23+
fields: memberFilter('component', 'fields'),
24+
925
hasContents: computed('component', {
1026
get() {
1127
let component = this.get('component');
1228

13-
return component.get('constructors.length') > 0
14-
|| component.get('yields.length') > 0
29+
return component.get('overloadedYields.length') > 0
1530
|| component.get('arguments.length') > 0
1631
|| component.get('fields.length') > 0
1732
|| component.get('accessors.length') > 0
1833
|| component.get('methods.length') > 0;
1934
}
20-
})
35+
}),
36+
37+
actions: {
38+
updateFilter(filter, { target: { checked } }) {
39+
this.set(`show${capitalize(filter)}`, checked);
40+
}
41+
}
2142
});

addon/components/api/x-component/template.hbs

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,34 @@
66
{{#if hasContents}}
77
<div class="class-contents">
88
{{api/x-index
9+
options=(hash
10+
inherited=(hash shouldShow=component.hasInherited value=showInherited)
11+
internal=(hash shouldShow=component.hasInternal value=showInternal)
12+
protected=(hash shouldShow=component.hasProtected value=showProtected)
13+
private=(hash shouldShow=component.hasPrivate value=showPrivate)
14+
deprecated=(hash shouldShow=component.hasDeprecated value=showDeprecated)
15+
)
16+
17+
onOptionToggle=(action 'updateFilter')
18+
919
sections=(hash
10-
constructors=component.constructors
11-
yields=component.yields
12-
arguments=component.arguments
13-
fields=component.fields
14-
accessors=component.accessors
15-
methods=component.methods
20+
constructors=constructors
21+
yields=yields
22+
arguments=arguments
23+
fields=fields
24+
accessors=accessors
25+
methods=methods
1626
)
1727
}}
1828

1929
{{api/x-sections
2030
sections=(hash
21-
constructors=component.constructors
22-
yields=component.yields
23-
arguments=component.arguments
24-
fields=component.fields
25-
accessors=component.accessors
26-
methods=component.methods
31+
constructors=constructors
32+
yields=yields
33+
arguments=arguments
34+
fields=fields
35+
accessors=accessors
36+
methods=methods
2737
)
2838
}}
2939
</div>

addon/components/api/x-index/style.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
.class-index {
2-
width: 200px;
2+
flex: 0 0 200px;
33
padding: 0 20px;
44

55
font-size: 0.85em;

addon/components/api/x-index/template.hbs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,20 @@
11
<div class="class-index__sticky">
22
<h2>Index</h2>
33

4+
<ul>
5+
{{#each-in options as |key option|}}
6+
{{#if option.shouldShow}}
7+
<li>
8+
<label>
9+
<input type="checkbox" checked={{option.value}} onclick={{action onOptionToggle key}}>
10+
11+
{{capitalize key}}
12+
</label>
13+
</li>
14+
{{/if}}
15+
{{/each-in}}
16+
</ul>
17+
418
{{#each-in sections as |section items|}}
519
{{#if items}}
620
<h3>{{capitalize section}}</h3>

addon/helpers/type-signature.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,14 @@ export function typeSignature([typed]) {
4242
signature = functionSignature(typed);
4343
}
4444

45+
if (typed.isStatic) {
46+
signature = `static ${signature}`;
47+
}
48+
49+
if (typed.access === 'private' || typed.access === 'protected') {
50+
signature = `${typed.access} ${signature}`;
51+
}
52+
4553
return htmlSafe(signature);
4654
}
4755

addon/models/class.js

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
11
import DS from 'ember-data';
2+
import {
3+
filterBy,
4+
or,
5+
union
6+
} from '@ember/object/computed';
7+
import { memberUnion, hasMemberType } from '../utils/computed';
28

39
const { attr, belongsTo } = DS;
410

@@ -17,5 +23,61 @@ export default DS.Model.extend({
1723
accessors: attr(),
1824
methods: attr(),
1925
fields: attr(),
20-
tags: attr()
26+
tags: attr(),
27+
28+
publicAccessors: filterBy('accessors', 'access', 'public'),
29+
publicMethods: filterBy('methods', 'access', 'public'),
30+
publicFields: filterBy('fields', 'access', 'public'),
31+
32+
privateAccessors: filterBy('accessors', 'access', 'private'),
33+
privateMethods: filterBy('methods', 'access', 'private'),
34+
privateFields: filterBy('fields', 'access', 'private'),
35+
36+
protectedAccessors: filterBy('accessors', 'access', 'protected'),
37+
protectedMethods: filterBy('methods', 'access', 'protected'),
38+
protectedFields: filterBy('fields', 'access', 'protected'),
39+
40+
allPublicAccessors: memberUnion('parentClass.allPublicAccessors', 'publicAccessors'),
41+
allPublicMethods: memberUnion('parentClass.allPublicMethods', 'publicMethods'),
42+
allPublicFields: memberUnion('parentClass.allPublicFields', 'publicFields'),
43+
44+
allPrivateAccessors: memberUnion('parentClass.allPrivateAccessors', 'privateAccessors'),
45+
allPrivateMethods: memberUnion('parentClass.allPrivateMethods', 'privateMethods'),
46+
allPrivateFields: memberUnion('parentClass.allPrivateFields', 'privateFields'),
47+
48+
allProtectedAccessors: memberUnion('parentClass.allProtectedAccessors', 'protectedAccessors'),
49+
allProtectedMethods: memberUnion('parentClass.allProtectedMethods', 'protectedMethods'),
50+
allProtectedFields: memberUnion('parentClass.allProtectedFields', 'protectedFields'),
51+
52+
allAccessors: union('allPublicAccessors', 'allPrivateAccessors', 'allProtectedAccessors'),
53+
allMethods: union('allPublicMethods', 'allPrivateMethods', 'allProtectedMethods'),
54+
allFields: union('allPublicFields', 'allPrivateFields', 'allProtectedFields'),
55+
56+
hasInherited: or(
57+
'parentClass.allAccessors.length',
58+
'parentClass.allMethods.length',
59+
'parentClass.allFields.length'
60+
),
61+
62+
hasPrivate: or(
63+
'allPrivateAccessors.length',
64+
'allPrivateMethods.length',
65+
'allPrivateFields.length'
66+
),
67+
68+
hasProtected: or(
69+
'allProtectedAccessors.length',
70+
'allProtectedMethods.length',
71+
'allProtectedFields.length'
72+
),
73+
74+
hasDeprecated: hasMemberType(
75+
'allFields',
76+
'allAccessors',
77+
'allMethods',
78+
79+
function(member) {
80+
return member.tags && member.tags.find(t => t.name === 'deprecated');
81+
}
82+
)
2183
});

addon/models/component.js

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,65 @@
11
import DS from 'ember-data';
2+
import { filterBy, or } from '@ember/object/computed';
3+
24
import Class from './class';
5+
import { memberUnion, hasMemberType } from '../utils/computed';
36

47
const { attr } = DS;
58

69
export default Class.extend({
710
isComponent: true,
811

912
yields: attr(),
10-
arguments: attr()
13+
arguments: attr(),
14+
15+
overloadedYields: or('yields', 'inheritedYields'),
16+
17+
publicArguments: filterBy('arguments', 'access', 'public'),
18+
privateArguments: filterBy('arguments', 'access', 'private'),
19+
protectedArguments: filterBy('arguments', 'access', 'protected'),
20+
21+
allPublicArguments: memberUnion('parentClass.allPublicArguments', 'publicArguments'),
22+
allPrivateArguments: memberUnion('parentClass.allPrivateArguments', 'privateArguments'),
23+
allProtectedArguments: memberUnion('parentClass.allProtectedArguments', 'protectedArguments'),
24+
25+
allArguments: memberUnion('parentClass.allArguments', 'arguments'),
26+
27+
hasInherited: or(
28+
'parentClass.overloadedYields.length',
29+
'parentClass.allArguments.length',
30+
'parentClass.allAccessors.length',
31+
'parentClass.allMethods.length',
32+
'parentClass.allFields.length'
33+
),
34+
35+
hasInternal: or(
36+
'allAccessors.length',
37+
'allMethods.length',
38+
'allFields.length'
39+
),
40+
41+
hasPrivate: or(
42+
'allPrivateAccessors.length',
43+
'allPrivateArguments.length',
44+
'allPrivateMethods.length',
45+
'allPrivateFields.length'
46+
),
47+
48+
hasProtected: or(
49+
'allProtectedAccessors.length',
50+
'allProtectedArguments.length',
51+
'allProtectedMethods.length',
52+
'allProtectedFields.length'
53+
),
54+
55+
hasDeprecated: hasMemberType(
56+
'allAccessors',
57+
'allArguments',
58+
'allMethods',
59+
'allFields',
60+
61+
function(member) {
62+
return member.tags && member.tags.find(t => t.name === 'deprecated');
63+
}
64+
)
1165
});

0 commit comments

Comments
 (0)