mirror of
https://github.com/jsdoc/jsdoc.git
synced 2025-12-08 19:46:11 +00:00
support class properties, including private properties
This commit is contained in:
parent
fb37938b77
commit
47005e9646
@ -8,6 +8,8 @@ var parserOptions = exports.parserOptions = {
|
||||
ranges: true,
|
||||
sourceType: 'module',
|
||||
plugins: [
|
||||
'classPrivateProperties',
|
||||
'classProperties',
|
||||
'decorators2',
|
||||
'doExpressions',
|
||||
'estree',
|
||||
|
||||
@ -46,6 +46,7 @@ var isFunction = exports.isFunction = function(node) {
|
||||
var isScope = exports.isScope = function(node) {
|
||||
// TODO: handle blocks with "let" declarations
|
||||
return !!node && typeof node === 'object' && ( node.type === Syntax.CatchClause ||
|
||||
node.type === Syntax.ClassDeclaration || node.type === Syntax.ClassExpression ||
|
||||
isFunction(node) );
|
||||
};
|
||||
|
||||
@ -138,6 +139,20 @@ var nodeToValue = exports.nodeToValue = function(node) {
|
||||
str = nodeToValue(node.id);
|
||||
break;
|
||||
|
||||
case Syntax.ClassPrivateProperty:
|
||||
// TODO: Strictly speaking, the name should be '#' plus node.key, but because we
|
||||
// already use '#' as scope punctuation, that causes JSDoc to get extremely confused.
|
||||
// The solution probably involves quoting part or all of the name, but JSDoc doesn't
|
||||
// deal with quoted names very nicely right now, and most people probably won't want to
|
||||
// document class private properties anyhow. So for now, we'll just cheat and omit the
|
||||
// leading '#'.
|
||||
str = nodeToValue(node.key);
|
||||
break;
|
||||
|
||||
case Syntax.ClassProperty:
|
||||
str = nodeToValue(node.key);
|
||||
break;
|
||||
|
||||
case Syntax.ExportAllDeclaration:
|
||||
// falls through
|
||||
|
||||
@ -382,6 +397,20 @@ var getInfo = exports.getInfo = function(node) {
|
||||
|
||||
break;
|
||||
|
||||
// like "#b = 1;" in: "class A { #b = 1; }"
|
||||
case Syntax.ClassPrivateProperty:
|
||||
info.node = node;
|
||||
info.name = nodeToValue(info.node);
|
||||
info.type = info.node.type;
|
||||
break;
|
||||
|
||||
// like "b = 1;" in: "class A { b = 1; }"
|
||||
case Syntax.ClassProperty:
|
||||
info.node = node;
|
||||
info.name = nodeToValue(info.node);
|
||||
info.type = info.node.type;
|
||||
break;
|
||||
|
||||
// like: "export * from 'foo'"
|
||||
case Syntax.ExportAllDeclaration:
|
||||
info.node = node;
|
||||
|
||||
@ -354,6 +354,11 @@ Parser.prototype.astnodeToMemberof = function(node) {
|
||||
result.memberof = doclet.longname + jsdoc.name.SCOPE.PUNC.INNER;
|
||||
}
|
||||
}
|
||||
else if (type === Syntax.ClassPrivateProperty || type === Syntax.ClassProperty) {
|
||||
doclet = this._getDocletById(node.enclosingScope.nodeId);
|
||||
|
||||
result.memberof = doclet.longname + jsdoc.name.SCOPE.PUNC.INSTANCE;
|
||||
}
|
||||
else {
|
||||
// check local references for aliases
|
||||
scope = node;
|
||||
|
||||
@ -16,6 +16,8 @@ exports.Syntax = {
|
||||
ClassBody: 'ClassBody',
|
||||
ClassDeclaration: 'ClassDeclaration',
|
||||
ClassExpression: 'ClassExpression',
|
||||
ClassPrivateProperty: 'ClassPrivateProperty',
|
||||
ClassProperty: 'ClassProperty',
|
||||
ComprehensionBlock: 'ComprehensionBlock',
|
||||
ComprehensionExpression: 'ComprehensionExpression',
|
||||
ConditionalExpression: 'ConditionalExpression',
|
||||
@ -65,6 +67,7 @@ exports.Syntax = {
|
||||
NewExpression: 'NewExpression',
|
||||
ObjectExpression: 'ObjectExpression',
|
||||
ObjectPattern: 'ObjectPattern',
|
||||
PrivateName: 'PrivateName',
|
||||
Program: 'Program',
|
||||
Property: 'Property',
|
||||
RestElement: 'RestElement',
|
||||
|
||||
@ -346,6 +346,19 @@ function makeAsyncFunctionFinisher(parser) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a function that will mark a doclet as private.
|
||||
*
|
||||
* @private
|
||||
* @param {module:jsdoc/src/parser.Parser} parser - The JSDoc parser.
|
||||
* @return {function} A function that marks a doclet as private.
|
||||
*/
|
||||
function makePrivatePropertyFinisher(parser) {
|
||||
return function(e) {
|
||||
e.doclet.access = 'private';
|
||||
};
|
||||
}
|
||||
|
||||
// TODO: docs
|
||||
function SymbolFound(node, filename, extras) {
|
||||
var self = this;
|
||||
@ -433,7 +446,6 @@ Visitor.prototype.visit = function(node, filename) {
|
||||
return true;
|
||||
};
|
||||
|
||||
// TODO: docs
|
||||
/**
|
||||
* Verify that a block comment exists and that its leading delimiter does not contain three or more
|
||||
* asterisks.
|
||||
@ -613,6 +625,25 @@ Visitor.prototype.makeSymbolFoundEvent = function(node, parser, filename) {
|
||||
|
||||
break;
|
||||
|
||||
// like `#b = 1` in: class A { #b = 1; }
|
||||
case Syntax.ClassPrivateProperty:
|
||||
extras.finishers = [
|
||||
parser.resolveEnum,
|
||||
makePrivatePropertyFinisher(parser)
|
||||
];
|
||||
|
||||
e = new SymbolFound(node, filename, extras);
|
||||
|
||||
break;
|
||||
|
||||
// like `b = 1` in: class A { b = 1; }
|
||||
case Syntax.ClassProperty:
|
||||
extras.finishers = [parser.resolveEnum];
|
||||
|
||||
e = new SymbolFound(node, filename, extras);
|
||||
|
||||
break;
|
||||
|
||||
// like: export * from 'foo'
|
||||
case Syntax.ExportAllDeclaration:
|
||||
e = new SymbolFound(node, filename, extras);
|
||||
|
||||
@ -12,20 +12,6 @@ var doclet = require('jsdoc/doclet');
|
||||
var logger = require('jsdoc/util/logger');
|
||||
var Syntax = require('jsdoc/src/syntax').Syntax;
|
||||
|
||||
/**
|
||||
* Check whether an AST node creates a new scope.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} node - The AST node to check.
|
||||
* @return {Boolean} Set to `true` if the node creates a new scope, or `false` in all other cases.
|
||||
*/
|
||||
function isScopeNode(node) {
|
||||
// TODO: handle blocks with "let" declarations
|
||||
return node && typeof node === 'object' && (node.type === Syntax.CatchClause ||
|
||||
node.type === Syntax.FunctionDeclaration || node.type === Syntax.FunctionExpression ||
|
||||
node.type === Syntax.ArrowFunctionExpression);
|
||||
}
|
||||
|
||||
// TODO: docs
|
||||
function getCurrentScope(scopes) {
|
||||
return scopes[scopes.length - 1] || null;
|
||||
@ -159,6 +145,10 @@ walkers[Syntax.ClassDeclaration] = function(node, parent, state, cb) {
|
||||
|
||||
walkers[Syntax.ClassExpression] = walkers[Syntax.ClassDeclaration];
|
||||
|
||||
// walkers[Syntax.ClassPrivateProperty] is defined later
|
||||
|
||||
// walkers[Syntax.ClassProperty] is defined later
|
||||
|
||||
// TODO: verify correctness
|
||||
walkers[Syntax.ComprehensionBlock] = walkers[Syntax.AssignmentExpression];
|
||||
|
||||
@ -448,6 +438,10 @@ walkers[Syntax.ObjectExpression] = function(node, parent, state, cb) {
|
||||
|
||||
walkers[Syntax.ObjectPattern] = walkers[Syntax.ObjectExpression];
|
||||
|
||||
walkers[Syntax.PrivateName] = function(node, parent, state, cb) {
|
||||
cb(node.name, node, state);
|
||||
};
|
||||
|
||||
walkers[Syntax.Program] = function(node, parent, state, cb) {
|
||||
// if the first item in the body has multiple leading comments, move all but the last one to
|
||||
// this node. this happens, for example, when a file has a /** @module */ standalone comment
|
||||
@ -479,6 +473,10 @@ walkers[Syntax.Property] = function(node, parent, state, cb) {
|
||||
}
|
||||
};
|
||||
|
||||
walkers[Syntax.ClassPrivateProperty] = walkers[Syntax.Property];
|
||||
|
||||
walkers[Syntax.ClassProperty] = walkers[Syntax.Property];
|
||||
|
||||
walkers[Syntax.RestElement] = function(node, parent, state, cb) {
|
||||
if (node.argument) {
|
||||
cb(node.argument, node, state);
|
||||
|
||||
8
test/fixtures/classproperties.js
vendored
Normal file
8
test/fixtures/classproperties.js
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
/** Sample class. */
|
||||
class A {
|
||||
/** Public property. */
|
||||
b = 1;
|
||||
|
||||
/** Private property. */
|
||||
#c = 2;
|
||||
}
|
||||
21
test/specs/documentation/classproperties.js
Normal file
21
test/specs/documentation/classproperties.js
Normal file
@ -0,0 +1,21 @@
|
||||
'use strict';
|
||||
|
||||
describe('class properties', function() {
|
||||
var docSet = jasmine.getDocSetFromFile('test/fixtures/classproperties.js');
|
||||
var b = docSet.getByLongname('A#b')[0];
|
||||
var c = docSet.getByLongname('A#c')[0];
|
||||
|
||||
it('should assign the correct name, memberof, and scope to class properties', function() {
|
||||
expect(b.name).toBe('b');
|
||||
expect(b.memberof).toBe('A');
|
||||
expect(b.scope).toBe('instance');
|
||||
});
|
||||
|
||||
it('should assign the correct name, memberof, scope, and access type to class private ' +
|
||||
'properties', function() {
|
||||
expect(c.name).toBe('c');
|
||||
expect(c.memberof).toBe('A');
|
||||
expect(c.scope).toBe('instance');
|
||||
expect(c.access).toBe('private');
|
||||
});
|
||||
});
|
||||
Loading…
x
Reference in New Issue
Block a user