Skip to content

Commit 9bda568

Browse files
committed
Merge pull request #453 from arv/class-property
Infer class properties
2 parents 305a3aa + e13e5d7 commit 9bda568

File tree

8 files changed

+309
-294
lines changed

8 files changed

+309
-294
lines changed

lib/infer/kind.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ module.exports = function () {
4848
} else if (t.isExpressionStatement(path)) {
4949
// module.exports = function() {}
5050
findKind(path.node.expression.right);
51+
} else if (t.isClassProperty(path)) {
52+
comment.kind = 'member';
5153
} else if (t.isProperty(path)) {
5254
// { foo: function() {} }
5355
findKind(path.node.value);

lib/infer/membership.js

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ module.exports = function () {
170170
/*
171171
* Same as above but for `b: c` vs `b: function () {}`.
172172
*/
173-
if (n.isProperty(path.node) &&
173+
if (n.isObjectProperty(path.node) &&
174174
n.isIdentifier(path.node.key)) {
175175
path = path.get('key');
176176
}
@@ -221,23 +221,18 @@ module.exports = function () {
221221
}
222222

223223
// class Foo { bar() { } }
224-
if (n.isClassMethod(path) &&
225-
n.isClassBody(path.parentPath) &&
226-
n.isClassDeclaration(path.parentPath.parentPath)) {
227-
identifiers = [path.parentPath.parentPath.node.id.name];
228-
var scope = 'instance';
229-
if (path.node.static == true) {
230-
scope = 'static';
231-
}
232-
inferMembershipFromIdentifiers(comment, identifiers, scope);
233-
}
234-
235224
// var Foo = class { bar() { } }
236-
if (n.isClassMethod(path) &&
225+
// class Foo { prop: T }
226+
// var Foo = class { prop: T }
227+
if ((n.isClassMethod(path) || n.isClassProperty(path)) &&
237228
n.isClassBody(path.parentPath) &&
238-
n.isClassExpression(path.parentPath.parentPath)) {
239-
identifiers = extractIdentifiers(path.parentPath.parentPath.parentPath.get('left'));
240-
scope = 'instance';
229+
n.isClass(path.parentPath.parentPath)) {
230+
if (n.isExpression(path.parentPath.parentPath)) {
231+
identifiers = extractIdentifiers(path.parentPath.parentPath.parentPath.get('left'));
232+
} else {
233+
identifiers = [path.parentPath.parentPath.node.id.name];
234+
}
235+
var scope = 'instance';
241236
if (path.node.static == true) {
242237
scope = 'static';
243238
}

test/fixture/es6-import.output.json

Lines changed: 99 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -839,6 +839,105 @@
839839
"kind": "class",
840840
"members": {
841841
"instance": [
842+
{
843+
"description": {
844+
"type": "root",
845+
"children": [
846+
{
847+
"type": "paragraph",
848+
"children": [
849+
{
850+
"type": "text",
851+
"value": "This is a property of the sink.",
852+
"position": {
853+
"start": {
854+
"line": 1,
855+
"column": 1,
856+
"offset": 0
857+
},
858+
"end": {
859+
"line": 1,
860+
"column": 32,
861+
"offset": 31
862+
},
863+
"indent": []
864+
}
865+
}
866+
],
867+
"position": {
868+
"start": {
869+
"line": 1,
870+
"column": 1,
871+
"offset": 0
872+
},
873+
"end": {
874+
"line": 1,
875+
"column": 32,
876+
"offset": 31
877+
},
878+
"indent": []
879+
}
880+
}
881+
],
882+
"position": {
883+
"start": {
884+
"line": 1,
885+
"column": 1,
886+
"offset": 0
887+
},
888+
"end": {
889+
"line": 1,
890+
"column": 32,
891+
"offset": 31
892+
}
893+
}
894+
},
895+
"tags": [],
896+
"loc": {
897+
"start": {
898+
"line": 24,
899+
"column": 2
900+
},
901+
"end": {
902+
"line": 26,
903+
"column": 5
904+
}
905+
},
906+
"context": {
907+
"loc": {
908+
"start": {
909+
"line": 27,
910+
"column": 2
911+
},
912+
"end": {
913+
"line": 27,
914+
"column": 18
915+
}
916+
},
917+
"code": "/**\n * This function destructures with defaults.\n */\nfunction destructure({phoneNumbers = [], emailAddresses = [], ...params} = {}) {\n}\n\n/**\n * Similar, but with an array\n */\nfunction destructure([a, b, c]) {\n}\n\n/**\n * This function returns the number one.\n * @param {Array<Number>} a an array of numbers\n * @returns {Number} numberone\n */\nvar multiply = (a, b) => a * b;\n\n/**\n * This is a sink\n */\nclass Sink {\n /**\n * This is a property of the sink.\n */\n staticProp = 42;\n\n /**\n * Is it empty\n */\n empty() {\n return 1;\n }\n\n /**\n * This method says hello\n */\n static hello() {\n return 'hello';\n }\n\n /**\n * This is a getter method: it should be documented\n * as a property.\n */\n get aGetter() {\n return 42;\n }\n\n /**\n * @param {number} height the height of the thing\n * @param {number} width the width of the thing\n */\n constructor(height, width) {\n this.height = height;\n this.width = width;\n }\n}\n\n/**\n * This function takes rest params\n */\nfunction functionWithRest(...someParams) {\n}\n\n/**\n * So does this one, with types\n */\nfunction functionWithRestAndType(...someParams: number) {\n}\n\n// FUNCTION TYPES\n\n/**\n * This is an async method\n */\nasync function foo() { }\n\nexport default multiply;\n\n/**\n * @public\n */\nexport default (thisIsTheArgument) => {};\n\n/**\n * This function returns the number one.\n * @returns {Number} numberone\n */\nmodule.exports = () => (<p>hello</p>);\n\n/**\n * This tests our support of optional parameters in ES6\n */\nfunction veryImportantTransform(foo = 'bar') {\n return \"42\";\n}\n\n// ACCESS LEVELS\n\n/**\n * A private function\n * @private\n */\nfunction iAmPrivate() { }\n\n/**\n * A protected function\n * @protected\n */\nfunction iAmProtected() { }\n\n/**\n * A public function\n * @public\n */\nfunction iAmPublic() { }\n\n/**\n * A private function using the access tag\n * @access private\n */\nfunction iAmAccessPrivate() { }\n\n/**\n * This is re-exported\n */\nexport { execute } from 'external-module';\n"
918+
},
919+
"errors": [],
920+
"name": "staticProp",
921+
"kind": "member",
922+
"memberof": "Sink",
923+
"scope": "instance",
924+
"members": {
925+
"instance": [],
926+
"static": []
927+
},
928+
"path": [
929+
{
930+
"name": "Sink",
931+
"kind": "class"
932+
},
933+
{
934+
"name": "staticProp",
935+
"kind": "member",
936+
"scope": "instance"
937+
}
938+
],
939+
"namespace": "Sink#staticProp"
940+
},
842941
{
843942
"description": {
844943
"type": "root",
@@ -1344,96 +1443,6 @@
13441443
],
13451444
"namespace": "Sink"
13461445
},
1347-
{
1348-
"description": {
1349-
"type": "root",
1350-
"children": [
1351-
{
1352-
"type": "paragraph",
1353-
"children": [
1354-
{
1355-
"type": "text",
1356-
"value": "This is a property of the sink.",
1357-
"position": {
1358-
"start": {
1359-
"line": 1,
1360-
"column": 1,
1361-
"offset": 0
1362-
},
1363-
"end": {
1364-
"line": 1,
1365-
"column": 32,
1366-
"offset": 31
1367-
},
1368-
"indent": []
1369-
}
1370-
}
1371-
],
1372-
"position": {
1373-
"start": {
1374-
"line": 1,
1375-
"column": 1,
1376-
"offset": 0
1377-
},
1378-
"end": {
1379-
"line": 1,
1380-
"column": 32,
1381-
"offset": 31
1382-
},
1383-
"indent": []
1384-
}
1385-
}
1386-
],
1387-
"position": {
1388-
"start": {
1389-
"line": 1,
1390-
"column": 1,
1391-
"offset": 0
1392-
},
1393-
"end": {
1394-
"line": 1,
1395-
"column": 32,
1396-
"offset": 31
1397-
}
1398-
}
1399-
},
1400-
"tags": [],
1401-
"loc": {
1402-
"start": {
1403-
"line": 24,
1404-
"column": 2
1405-
},
1406-
"end": {
1407-
"line": 26,
1408-
"column": 5
1409-
}
1410-
},
1411-
"context": {
1412-
"loc": {
1413-
"start": {
1414-
"line": 27,
1415-
"column": 2
1416-
},
1417-
"end": {
1418-
"line": 27,
1419-
"column": 18
1420-
}
1421-
},
1422-
"code": "/**\n * This function destructures with defaults.\n */\nfunction destructure({phoneNumbers = [], emailAddresses = [], ...params} = {}) {\n}\n\n/**\n * Similar, but with an array\n */\nfunction destructure([a, b, c]) {\n}\n\n/**\n * This function returns the number one.\n * @param {Array<Number>} a an array of numbers\n * @returns {Number} numberone\n */\nvar multiply = (a, b) => a * b;\n\n/**\n * This is a sink\n */\nclass Sink {\n /**\n * This is a property of the sink.\n */\n staticProp = 42;\n\n /**\n * Is it empty\n */\n empty() {\n return 1;\n }\n\n /**\n * This method says hello\n */\n static hello() {\n return 'hello';\n }\n\n /**\n * This is a getter method: it should be documented\n * as a property.\n */\n get aGetter() {\n return 42;\n }\n\n /**\n * @param {number} height the height of the thing\n * @param {number} width the width of the thing\n */\n constructor(height, width) {\n this.height = height;\n this.width = width;\n }\n}\n\n/**\n * This function takes rest params\n */\nfunction functionWithRest(...someParams) {\n}\n\n/**\n * So does this one, with types\n */\nfunction functionWithRestAndType(...someParams: number) {\n}\n\n// FUNCTION TYPES\n\n/**\n * This is an async method\n */\nasync function foo() { }\n\nexport default multiply;\n\n/**\n * @public\n */\nexport default (thisIsTheArgument) => {};\n\n/**\n * This function returns the number one.\n * @returns {Number} numberone\n */\nmodule.exports = () => (<p>hello</p>);\n\n/**\n * This tests our support of optional parameters in ES6\n */\nfunction veryImportantTransform(foo = 'bar') {\n return \"42\";\n}\n\n// ACCESS LEVELS\n\n/**\n * A private function\n * @private\n */\nfunction iAmPrivate() { }\n\n/**\n * A protected function\n * @protected\n */\nfunction iAmProtected() { }\n\n/**\n * A public function\n * @public\n */\nfunction iAmPublic() { }\n\n/**\n * A private function using the access tag\n * @access private\n */\nfunction iAmAccessPrivate() { }\n\n/**\n * This is re-exported\n */\nexport { execute } from 'external-module';\n"
1423-
},
1424-
"errors": [],
1425-
"name": "staticProp",
1426-
"members": {
1427-
"instance": [],
1428-
"static": []
1429-
},
1430-
"path": [
1431-
{
1432-
"name": "staticProp"
1433-
}
1434-
],
1435-
"namespace": "staticProp"
1436-
},
14371446
{
14381447
"description": {
14391448
"type": "root",

test/fixture/es6-import.output.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ Returns **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refer
4949

5050
This is a sink
5151

52+
## staticProp
53+
54+
This is a property of the sink.
55+
5256
## empty
5357

5458
Is it empty
@@ -69,10 +73,6 @@ as a property.
6973

7074
This method says hello
7175

72-
# staticProp
73-
74-
This is a property of the sink.
75-
7676
# functionWithRest
7777

7878
This function takes rest params

test/fixture/es6-import.output.md.json

Lines changed: 45 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -875,6 +875,51 @@
875875
"indent": []
876876
}
877877
},
878+
{
879+
"depth": 2,
880+
"type": "heading",
881+
"children": [
882+
{
883+
"type": "text",
884+
"value": "staticProp"
885+
}
886+
]
887+
},
888+
{
889+
"type": "paragraph",
890+
"children": [
891+
{
892+
"type": "text",
893+
"value": "This is a property of the sink.",
894+
"position": {
895+
"start": {
896+
"line": 1,
897+
"column": 1,
898+
"offset": 0
899+
},
900+
"end": {
901+
"line": 1,
902+
"column": 32,
903+
"offset": 31
904+
},
905+
"indent": []
906+
}
907+
}
908+
],
909+
"position": {
910+
"start": {
911+
"line": 1,
912+
"column": 1,
913+
"offset": 0
914+
},
915+
"end": {
916+
"line": 1,
917+
"column": 32,
918+
"offset": 31
919+
},
920+
"indent": []
921+
}
922+
},
878923
{
879924
"depth": 2,
880925
"type": "heading",
@@ -1185,51 +1230,6 @@
11851230
"indent": []
11861231
}
11871232
},
1188-
{
1189-
"depth": 1,
1190-
"type": "heading",
1191-
"children": [
1192-
{
1193-
"type": "text",
1194-
"value": "staticProp"
1195-
}
1196-
]
1197-
},
1198-
{
1199-
"type": "paragraph",
1200-
"children": [
1201-
{
1202-
"type": "text",
1203-
"value": "This is a property of the sink.",
1204-
"position": {
1205-
"start": {
1206-
"line": 1,
1207-
"column": 1,
1208-
"offset": 0
1209-
},
1210-
"end": {
1211-
"line": 1,
1212-
"column": 32,
1213-
"offset": 31
1214-
},
1215-
"indent": []
1216-
}
1217-
}
1218-
],
1219-
"position": {
1220-
"start": {
1221-
"line": 1,
1222-
"column": 1,
1223-
"offset": 0
1224-
},
1225-
"end": {
1226-
"line": 1,
1227-
"column": 32,
1228-
"offset": 31
1229-
},
1230-
"indent": []
1231-
}
1232-
},
12331233
{
12341234
"depth": 1,
12351235
"type": "heading",

0 commit comments

Comments
 (0)