近期一直在做Js文档生成软件。
目前占据这个领域的主要就是 jsdoc 开源项目。先介绍下 jsdoc 本身,它是用Java开发的(其实主要是Javascript开发) 基于字符串直接处理的文档工具。 因为Javscript非常灵活,Javascript的文档生成自然也比不上Java之类的准确、有效。jsdoc本身要求在注释中大量使用一些标签来告诉文档生成器这是一个类、属性、方法或其它的类型,jsdoc在解析中是通过上下文来决定变量的归属,比如上文使用 @class 标识类, 下文的 @method 就自动处理为上个 @class 所指的类,而完全忽视了代码自身的逻辑。
且不说jsdoc的方法是否方便、有效。总之,我要做的是基于语法分析而生成文档的工具。
我目标是生成完全面向对象阻止的文档,即最后的文档最高级是名字空间(包) , 下级是类, 再下级是成员。
1. 成员的归类。一个变量在定义后,它到底属于哪个父成员,这是文档分析必须要分析出的。
/**
* 将当前值转为数字。
*/
Boolean.prototype.toNumber = function(){
return +this;
};
从这段代码可知: 有一个 toNumber 成员, 其父成员为 Boolean.prototype , 这个情况可以轻松检测所在成员,但假如换一个写法,比如 Ext 中的写法是:
/**
* 将当前值转为数字。
*/
Ext.extend(Boolean.prototype,{toNumber: function(){
return +this;
}} );
这就很麻烦了,因为文档分析程序不肯能去执行这个代码,它当然不知道 toNumber 的父成员。 jsdoc采用最近使用的 @class 最为其父成员。但这样很容易导致 @class 多很多错误的成员。
最终我采用作用域的分析方式。即 函数调用 或 函数定义 被作为一个作用域。它们之前的 @class 将被理解为这个作用域内成员的父成员。即代码应该这样注释:
/**
* 将当前值转为数字。* @class Boolean
*/
Ext.extend(Boolean.prototype,{toNumber: function(){
return +this;
}} );
@class Boolean 只对此函数有效,即 @class 只解释相邻的作用域。 同理有:
/**
* 将当前值转为数字。* @class Boolean
*/
(function(){function toNumber(){
return +this;
}})();
由于这是函数定义,所以函数内部的成员的父成员也是 @class Boolean 。
当然,这些都是无理的推算,肯能导致错误结果,可以通过指定 @memberOf 来覆盖自动判断的父变量。
以上对于 @class C , 成员解释为 C.prototype.p
对于 @namespace C , 或成员已记 @static, 解释为 C.p
2. 具备识别继承、原型的功能。
比如 A.prototype = new B 是很典型的继承代码。
通过模拟运行可以实现 原型操作。
3. 根据平时写Javascript的经验,再参考jsdoc, 最终我决定将使用以下几个系统标签,它们将为文档生成做出伟大贡献。
全局标签
全局标签主要用于全项目或文件的描述。一般全局标签只能在文件顶部使用。
- @projectDescription Summary 当前项目功能描述
- @author Summary 代码的作者
- @lisense Summary 代码的协议
- @version Summary 代码的版本
- @fileOverview Summary 当前文件描述
- @file Summary 表示当前文件名,默认为真实文件名
公开标签
以下标签可以在任何位置使用,就像 HTML 中任何标签都有 tagName 的属性。
- @summary Summary 注释的简介 - 一般不需要直接使用这个标签, 因为注释的最开始处到第一个可解析的标签前的文字就是 @summary 标签。即: /** 内容 */ 等价于 /** @summary 内容 */
- @remark Summary 备注 - 一般不需要直接使用这个标签, 因为注释中已经使用了标签之后的文字就是 @remark 。即:
/**
* @return {Number}
* 说明
*/
等价于
/**
* @return {Number}
* @remark 说明
*/ - @ignore 忽略有这个标记注释。
- @define {Type} {Type} 定义同意义的类型。 比如 @define {int} {Number} 这样就可以用 int 代替 Number
- @define Name Name 定义同意义的注释, 使用 define 可以定义标签的 别名。比如 @define description summary 之后就可用 @description 替代 @summary
- @since [Summary] 指示自指定的版本提供。
- @deprecated [Summary] 指示一个成员已经废弃。
- @see Link 指向一个文件的链接。
- @example Summary 示例。
- @syntax Summary 手动指定语法。
- @name Name 名字。
- @memberOf Name 指示父成员。
- @type Type 指示类型。
类型说明
- @class [Name] 指示这是一个类。
- @enum [Name] 指示这是枚举。
- @interface [Name] 指示这是一个接口。
- @member [Name] 指示这是一个成员。
- @property [{Type}] [Name] 指示这是一个属性。
- @field [{Type}] [Name] 指示这是一个字段。
- @method [Name] 指示这是一个方法。
- @event [{Type}] [Name] 指示当前类的事件。
- @getter [{Type}] [Name] 指示这是一个只读属性。
- @setter [{Type}] [Name] 指示这是一个只写属性。
- @constructor [Name] 指示这是构造函数。
- @config {Type} [Name] 指示这是类的配置成员。
属性说明
- @public 指示公开
- @private 指示一个类或函数是私有的。
- @protected 指示保护。
- @internal 指示内部。
- @final 指示一个函数是不能覆盖的。
- @static 指示一个类是静态的。
- @abstract 指示一个类是抽象的。
- @virtual 指示一个类是抽象的。
- @const 指示一个值是常量值。
其它
- @extends Name 指示一个类派生了另一个类。
- @implements Name 指示一个类派生了另一个类。
- @param {Type} Name Summary 表示参数。如果是可选参数加上 [Name] ,如果是 随机参数 名字为 ... 如果有默认值, 使用 Name=Value 多类型使用任意符号分开。
- @return [{Type}] [Summary] 返回 。
- {@link Link} 链接。
- {@code [{Type}] <<< Summary >>>} 代码。
- @{ 表示字符 {
- @@ 表示字符 @
- @} 表示字符 }
- @* 表示字符 *