Permalink
Browse files

feat(experimental): class properties

  • Loading branch information...
h13i32maru committed Sep 25, 2016
1 parent e2689dd commit c7b4d9b415812cf18c451b1a452c9725593d3891
@@ -0,0 +1,45 @@
+import AbstractDoc from './AbstractDoc.js';
+import MethodDoc from './MethodDoc.js';
+import ParamParser from '../Parser/ParamParser.js';
+
+/**
+ * Doc Class from ClassProperty AST node.
+ */
+export default class ClassPropertyDoc extends AbstractDoc {
+ /**
+ * apply own tag.
+ * @private
+ */
+ _apply() {
+ super._apply();
+
+ Reflect.deleteProperty(this._value, 'export');
+ Reflect.deleteProperty(this._value, 'importPath');
+ Reflect.deleteProperty(this._value, 'importStyle');
+ }
+
+ /** specify ``member`` to kind. */
+ _$kind() {
+ super._$kind();
+ this._value.kind = 'member';
+ }
+
+ /** take out self name from self node */
+ _$name() {
+ super._$name();
+ this._value.name = this._node.key.name;
+ }
+
+ /** borrow {@link MethodDoc#@_memberof} */
+ _$memberof() {
+ Reflect.apply(MethodDoc.prototype._$memberof, this, []);
+ }
+
+ /** if @type is not exists, guess type by using self node */
+ _$type() {
+ super._$type();
+ if (this._value.type) return;
+
+ this._value.type = ParamParser.guessType(this._node.value);
+ }
+}
View
@@ -3,6 +3,7 @@ import CommentParser from '../Parser/CommentParser.js';
import FileDoc from '../Doc/FileDoc.js';
import ClassDoc from '../Doc/ClassDoc.js';
import MethodDoc from '../Doc/MethodDoc.js';
+import ClassProperty from '../Doc/ClassPropertyDoc';
import MemberDoc from '../Doc/MemberDoc.js';
import FunctionDoc from '../Doc/FunctionDoc.js';
import VariableDoc from '../Doc/VariableDoc.js';
@@ -374,6 +375,7 @@ export default class DocFactory {
switch (type) {
case 'Class': Clazz = ClassDoc; break;
case 'Method': Clazz = MethodDoc; break;
+ case 'ClassProperty': Clazz = ClassProperty; break;
case 'Member': Clazz = MemberDoc; break;
case 'Function': Clazz = FunctionDoc; break;
case 'Variable': Clazz = VariableDoc; break;
@@ -416,8 +418,10 @@ export default class DocFactory {
switch (node.type) {
case 'ClassDeclaration':
return this._decideClassDeclarationType(node);
- case 'ClassMethod': // for babylon
+ case 'ClassMethod':
return this._decideMethodDefinitionType(node);
+ case 'ClassProperty':
+ return this._decideClassPropertyType(node);
case 'ExpressionStatement':
return this._decideExpressionStatementType(node);
case 'FunctionDeclaration':
@@ -461,6 +465,22 @@ export default class DocFactory {
}
}
+ /**
+ * decide Doc type from class property node.
+ * @param {ASTNode} node - target node that is classs property node.
+ * @returns {{type: ?string, node: ?ASTNode}} decided type.
+ * @private
+ */
+ _decideClassPropertyType(node) {
+ const classNode = this._findUp(node, ['ClassDeclaration', 'ClassExpression']);
+ if (this._processedClassNodes.includes(classNode)) {
+ return {type: 'ClassProperty', node: node};
+ } else {
+ logger.w('this class property is not in class', node);
+ return {type: null, node: null};
+ }
+ }
+
/**
* decide Doc type from function declaration node.
* @param {ASTNode} node - target node that is function declaration node.
View
@@ -16,18 +16,21 @@ export default class ESParser {
* @returns {AST} AST of source code.
*/
static parse(config, filePath) {
- return this.parseWithBabylon(config, filePath);
+ return this._parseWithBabylon(config, filePath);
}
- static parseWithBabylon(config, filePath) {
+ /**
+ * parse ECMAScript source code with babylon.
+ * @param {ESDocConfig} config - config of esdoc.
+ * @param {string} filePath - source code file path.
+ * @returns {AST} AST of source code.
+ */
+ static _parseWithBabylon(config, filePath) {
let code = fs.readFileSync(filePath, {encode: 'utf8'}).toString();
code = Plugin.onHandleCode(code, filePath);
if (code.charAt(0) === '#') code = code.replace(/^#!/, '//');
- const option = {
- sourceType: 'module',
- plugins: ['jsx']
- };
+ const option = this._buildParserOptionForBabylon(config);
let parser = (code) => {
return babylon.parse(code, option);
@@ -41,4 +44,25 @@ export default class ESParser {
return ast;
}
+
+ /**
+ * build babylon option.
+ * @param {ESDocConfig} config - config of esdoc
+ * @returns {{sourceType: string, plugins: string[]}} option of babylon.
+ * @private
+ */
+ static _buildParserOptionForBabylon(config) {
+ const option = {
+ sourceType: 'module',
+ plugins: ['jsx']
+ };
+
+ const experimental = config.experimentalProposal;
+
+ if (experimental) {
+ if (experimental.classProperties) option.plugins.push('classProperties');
+ }
+
+ return option;
+ }
}
View
@@ -28,6 +28,8 @@
* @property {string[]} manual.example
* @property {string[]} manual.faq
* @property {string[]} manual.changelog
+ * @property {Object} [experimentalProposal]
+ * @property {boolean} experimentalProposal.classProperties
* @see https://esdoc.org/config.html
*/
@@ -20,5 +20,8 @@
"example": ["./test/fixture/package/manual/example.md"],
"faq": ["./test/fixture/package/manual/faq.md"],
"changelog": ["./test/fixture/package/CHANGELOG.md"]
+ },
+ "experimentalProposal": {
+ "classProperties": true
}
}
@@ -0,0 +1,17 @@
+/**
+ * this is TestClassPropertyDefinition.
+ * @todo test `Access`, `Deprecated`, `Desc`, `Duplication`, `Example`, `Experimental`, `Guess`, `Ignore`, `Link`, `See`, `Since`, `Todo` and `Version`.
+ */
+export default class TestClassPropertyDefinition {
+ /**
+ * this is static p1.
+ * @type {number}
+ */
+ static p1 = 123;
+
+ /**
+ * this is p1.
+ * @type {number}
+ */
+ p1 = 123;
+}
@@ -9,8 +9,8 @@ describe('test coverage', ()=> {
it('has coverage summary', ()=> {
assert(badge.includes('79%'));
assert.includes(doc, '[data-ice="coverageBadge"]', './badge.svg', 'src');
- assert.includes(doc, '[data-ice="totalCoverageCount"]', '263/330');
- assert.equal(doc.find('[data-ice="file"] [data-ice="coverage"]').length, 116);
+ assert.includes(doc, '[data-ice="totalCoverageCount"]', '266/333');
+ assert.equal(doc.find('[data-ice="file"] [data-ice="coverage"]').length, 117);
});
/* eslint-disable max-statements */
@@ -33,6 +33,7 @@ describe('test coverage', ()=> {
test('file/src/Async/Function.js.html', '100 %1/1');
test('file/src/Async/Method.js.html', '100 %2/2');
test('file/src/Class/Definition.js.html', '100 %8/8');
+ test('file/src/ClassProperty/Definition.js.html', '100 %3/3');
test('file/src/Computed/Method.js.html', '100 %11/11');
test('file/src/Computed/Property.js.html', '100 %12/12');
test('file/src/Deprecated/Class.js.html#errorLines=6', '75 %3/4');
@@ -140,6 +141,6 @@ describe('test coverage', ()=> {
test('file/src/Version/Function.js.html', '100 %1/1');
test('file/src/Version/Variable.js.html', '100 %1/1');
- assert.equal(count, 116);
+ assert.equal(count, 117);
});
});
@@ -0,0 +1,48 @@
+import {readDoc, assert, find} from './../../../util.js';
+
+/** @test {ClassDocBuilder} */
+describe('TestClassPropertyDefinition:', ()=> {
+ const doc = readDoc('class/src/ClassProperty/Definition.js~TestClassPropertyDefinition.html');
+
+ /** @test {ClassDocBuilder#_buildClassDoc} */
+ describe('in summary', ()=>{
+ it('has static member', ()=>{
+ find(doc, '[data-ice="staticMemberSummary"]', (doc)=>{
+ find(doc, 'table[data-ice="summary"]:nth-of-type(1)', (doc)=>{
+ assert.includes(doc, '[data-ice="target"]:nth-of-type(1)', 'public static p1: number this is static p1.');
+ assert.includes(doc, '[data-ice="target"]:nth-of-type(1) [data-ice="name"] a', 'class/src/ClassProperty/Definition.js~TestClassPropertyDefinition.html#static-member-p1', 'href');
+ });
+ });
+ });
+
+ it('has member.', ()=>{
+ find(doc, '[data-ice="memberSummary"]', (doc)=>{
+ find(doc, 'table[data-ice="summary"]:nth-of-type(1)', (doc)=> {
+ assert.includes(doc, '[data-ice="target"]:nth-of-type(1)', 'public p1: number this is p1.');
+ assert.includes(doc, '[data-ice="target"]:nth-of-type(1) [data-ice="name"] a', 'class/src/ClassProperty/Definition.js~TestClassPropertyDefinition.html#instance-member-p1', 'href');
+ });
+ });
+ });
+ });
+
+ /** @test {ClassDocBuilder#_buildClassDoc} */
+ describe('in detail', ()=>{
+ it('has static member.', ()=>{
+ find(doc, '[data-ice="staticMemberDetails"]', (doc)=>{
+ find(doc, '[data-ice="detail"]:nth-of-type(1)', (doc)=>{
+ assert.includes(doc, '#static-member-p1', 'public static p1: number');
+ assert.includes(doc, '[data-ice="description"]', 'this is static p1.');
+ });
+ });
+ });
+
+ it('has member.', ()=>{
+ find(doc, '[data-ice="memberDetails"]', (doc)=>{
+ find(doc, '[data-ice="detail"]:nth-of-type(1)', (doc)=>{
+ assert.includes(doc, '#instance-member-p1', 'public p1: number');
+ assert.includes(doc, '#instance-member-p1 + [data-ice="description"]', 'this is p1.');
+ });
+ });
+ });
+ });
+});

0 comments on commit c7b4d9b

Please sign in to comment.