前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >angular采用注释进行文档编写

angular采用注释进行文档编写

作者头像
用户1437675
修改2019-08-07 19:51:39
1.8K0
修改2019-08-07 19:51:39
举报
文章被收录于专栏:Angular&服务Angular&服务

环境

代码语言:javascript
复制
node  -v 8.11.3
npm   -v 5.6.0

创建项目

代码语言:javascript
复制
npx ng new ngx-doc

方法一

使用 compodoc

安装
代码语言:javascript
复制
npm install  --save-dev @compodoc/compodoc
配置文档生成命令

package.jsonscripts 中配置如下

代码语言:javascript
复制
"compodoc": "compodoc -p tsconfig.json -d ./compodoc --hideGenerator --theme postmark -w -s --port 8852 --language zh-CN --open",

参数解释

代码语言:javascript
复制
-h, --help                              输出使用信息
-V, --version                           输出版本号
-c, --config [config]                   配置文件:.compodocrc,.compodocrc.json,.compodocrc.yaml或package.json中的compodoc属性
-p, --tsconfig [config]                 一个tsconfig.json文件
-d, --output [folder]                   存储生成的文档的位置
-y, --extraTheme [file]                 外部造型主题
-n, --name [name]                       文件标题
-a, --assetsFolder [folder]             外部资产文件夹,用于复制生成的文档文件夹
-o, --open                              打开生成的文档
-t, --silent                            在静默模式下,日志消息不会记录在控制台中
-s, --serve                             提供生成的文档(默认http://localhost:8080/)
-r, --port [port]                       更改默认服务端口
-w, --watch                             在serve和force documentation rebuild之后观察源文件
-e, --exportFormat [format]             以指定格式导出(json,html(默认))
--language [language]                   用于生成文档的语言(en-US,fr-FR,zh-CN,pt-BR)(默认值:en-US)
--theme [theme]                         选择一个可用主题,默认为'gitbook'(laravel,original,material,postmark,readthedocs,stripe,vagrant)
--hideGenerator                         不要在页面底部打印Compodoc徽标
--toggleMenuItems                       关闭菜单中的默认项目(默认['all'])值:['all']或其中一个['modules','components','directives','classes','injectables','interfaces' , '管道', 'additionalPages'])
--navTabConfig                          按所需顺序列出导航选项卡对象,其中包含两个字符串属性(“id”和“label”)。双引号必须使用'\'进行转义。可用的选项卡ID是“info”,“readme”,“source”,“templateData”,“tree”和“example”。注意:仅在适用于给定依赖项时才会显示某些选项卡
--templates [folder]                    Handlebars模板目录的路径,用于覆盖内置模板
--includes [path]                       要包含的外部markdown文件的路径
--includesName [name]                   外部降价文件的项目菜单名称(默认“附加文档”)
--coverageTest                          使用阈值测试文档覆盖率命令(默认为70)
--coverageMinimumPerFile [minimum]      每个文件的文档覆盖率测试命令至少(默认为0)
--coverageTestThresholdFail [boolean]   文档覆盖率(全局或每个文件)的测试命令将失败并显示错误或仅警告用户(true:error,false:warn)(默认值:true)
--coverageTestShowOnlyFailed            仅显示覆盖测试的失败文件
--unitTestCoverage [json-summary]       要包含单元测试覆盖率,请指定istanbul JSON覆盖率摘要文件
--disableSourceCode                     不要添加源代码选项卡和源代码链接
--disableDomTree                        不要添加dom树选项卡
--disableTemplateTab                    不要添加模板选项卡
--disableStyleTab                       不要添加样式选项卡
--disableGraph                          禁用依赖关系图的呈现
--disableCoverage                       不要添加文档覆盖率报告
--disablePrivate                        不要在生成的文档中显示私有
--disableProtected                      不要在生成的文档中显示受保护
--disableInternal                       不要在生成的文档中显示@internal
--disableLifeCycleHooks                 不要在生成的文档中显示Angular生命周期钩子
--disableRoutesGraph                    不要添加路线图
--disableSearch                         不要添加搜索输入
--minimal                               只有文档的最小模式。没有搜索,没有图表,没有覆盖。
--customFavicon [path]                  使用自定义图标
--customLogo [path]                     使用自定义徽标
--gaID [id]                             Google Analytics跟踪ID
--gaSite [site]                         Google Analytics网站名称(默认自动(默认:自动))
生成doc文档
代码语言:javascript
复制
npm run compodoc

方法二

参考

安装依赖插件

代码语言:javascript
复制
npm i dgeni dgeni-packages lodash gulp --save-dev

插件介绍

  • Dgeni 文档生成器。
  • Dgeni Packages 源代码生成文档的dgeni软件包。
  • Lodash Javascript工具库。
  • Gulp 编译dgeni。dgeni需要gulp来启用。

创建文档目录结构

代码语言:javascript
复制
├── docs/
│   ├── config/
│   │  ├── processors/
│   │  ├── templates/
│   │  ├── index.js
│   ├── dist/

文件目录介绍

  • docs 文件夹用于存放dgeni所有相关的配置信息
  • config 放置配置文件的目录
  • processors 处理器
  • templates 模板文件夹
  • index.js 配置文件
  • dist 文档生成结果

配置文件

index.js 配置Dgeni。
代码语言:javascript
复制
const Dgeni = require('dgeni');
const DgeniPackage = Dgeni.Package;

let apiDocsPackage = new DgeniPackage('ngx-dgeni-start-docs', [
    require('dgeni-packages/jsdoc'), // jsdoc处理器
    require('dgeni-packages/nunjucks'), // HTML模板引擎
    require('dgeni-packages/typescript') // typescript包
])

先加载 Dgeni 所需要的包依赖。下一步,需要通过配置来告知dgeni如何生成我们的文档。

设置源文件和输出路径

代码语言:javascript
复制
.config(function(log, readFilesProcessor, writeFilesProcessor) {
    // 设置日志等级
    log.level = 'info';

    // 设置项目根目录为基准路径
    readFilesProcessor.basePath = sourceDir;
    readFilesProcessor.$enabled = false;

    // 指定输出路径
    writeFilesProcessor.outputFolder = outputDir;
})

设置Typescript解析器

代码语言:javascript
复制
.config(function(readTypeScriptModules) {
    // ts文件基准文件夹
    readTypeScriptModules.basePath = sourceDir;
    // 隐藏private变量
    readTypeScriptModules.hidePrivateMembers = true;
    // typescript 入口
    readTypeScriptModules.sourceFiles = [
        'app/**/*.{component,directive,service}.ts'
    ];
})

设置模板引擎

代码语言:javascript
复制
.config(function(templateFinder, templateEngine) {
    // 指定模板文件路径
    templateFinder.templateFolders = [path.resolve(__dirname, './templates')];
    // 设置文件类型与模板之间的匹配关系
    templateFinder.templatePatterns = [
        '${ doc.template }',
        '${ doc.id }.${ doc.docType }.template.html',
        '${ doc.id }.template.html',
        '${ doc.docType }.template.html',
        '${ doc.id }.${ doc.docType }.template.js',
        '${ doc.id }.template.js',
        '${ doc.docType }.template.js',
        '${ doc.id }.${ doc.docType }.template.json',
        '${ doc.id }.template.json',
        '${ doc.docType }.template.json',
        'common.template.html'
    ];
    // Nunjucks模板引擎,默认的标识会与Angular冲突
    templateEngine.config.tags = {
        variableStart: '{$',
        variableEnd: '$}'
    };
})

以上是Dgeni配置信息,而接下来重点是如何对文档进行解析。

处理器 Dgeni 通过一种类似 Gulp 的流管道一样,我们可以根据需要创建相应的处理器来对文档对象进行修饰,从而达到模板引擎最终所需要的数据结构。

虽说 dgeni-packages 已经提供很多种便利使用的处理器,可文档的展示总归还是因人而异,所以如何自定义处理器非常重要。

处理器的结构非常简单:

代码语言:javascript
复制
module.exports = function linkInheritedDocs() {
    return {
        // 指定运行之前处理器
        $runBefore: ['categorizer'],
        // 指定运行之后处理器
        $runAfter: ['readTypeScriptModules'],
        // 处理器函数
        $process: docs => docs.filter(doc => isPublicDoc(doc))
    };
};

最后,将处理器挂钩至 dgeni 上。

代码语言:javascript
复制
new DgeniPackage('ngx-dgeni-start-docs', []).processor(require('./processors/link-inherited-docs'))

过滤处理器

Dgeni 在调用Typescript解析 ts 文件后所得到的文档对象,包含着所有类型(不管私有、还是NgOninit之类的生命周期事件)。因此,适当过滤一些不必要显示的文档类型非常重要。

代码语言:javascript
复制
const INTERNAL_METHODS = [
    'ngOnInit',
    'ngOnChanges'
]

module.exports = function docsPrivateFilter() {
    return {
        $runBefore: ['componentGrouper'],
        $process: docs => docs.filter(doc => isPublicDoc(doc))
    };
};

function isPublicDoc(doc) {
    if (hasDocsPrivateTag(doc)) {
        return false;
    } else if (doc.docType === 'member') {
        return !isInternalMember(doc);
    } else if (doc.docType === 'class') {
        doc.members = doc.members.filter(memberDoc => isPublicDoc(memberDoc));
    }

    return true;
}

// 过滤内部成员
function isInternalMember(memberDoc) {
    return INTERNAL_METHODS.includes(memberDoc.name)
}

// 过滤 docs-private 标记
function hasDocsPrivateTag(doc) {
    let tags = doc.tags && doc.tags.tags;
    return tags ? tags.find(d => d.tagName == 'docs-private') : false;
}

分类处理器

虽然 Angular 是 Typescript 文件,但相对于 ts 而言本身对装饰器的依赖非常重,而默认 typescript 对这类的归纳其实是很难满足我们模板引擎所需要的数据结构的,比如一个 @Input() 变量,默认的情况下 ts 解析器统一用一个 tags 变量来表示,这对模板引擎来说太难于驾驭。

所以,对文档的分类是很必须的。

代码语言:javascript
复制
/**
 * 对文档对象增加一些 `isMethod`、`isDirective` 等属性
 *
 * isMethod     | 是否类方法
 * isDirective  | 是否@Directive类
 * isComponent  | 是否@Component类
 * isService    | 是否@Injectable类
 * isNgModule   | 是否NgModule类
 */
module.exports = function categorizer() {
    return {
        $runBefore: ['docs-processed'],
        $process: function(docs) {
            docs.filter(doc => ~['class'].indexOf(doc.docType)).forEach(doc => decorateClassDoc(doc));
        }
    };
    
    /** 识别Component、Directive等 */
    function decorateClassDoc(classDoc) {
        // 将所有方法与属性写入doc中(包括继承)
        classDoc.methods = resolveMethods(classDoc);
        classDoc.properties = resolveProperties(classDoc);

        // 根据装饰器重新修改方法与属性
        classDoc.methods.forEach(doc => decorateMethodDoc(doc));
        classDoc.properties.forEach(doc => decoratePropertyDoc(doc));
        
        const component = isComponent(classDoc);
        const directive = isDirective(classDoc);
        if (component || directive) {
            classDoc.exportAs = getMetadataProperty(classDoc, 'exportAs');
            classDoc.selectors = getDirectiveSelectors(classDoc);
        }
        classDoc.isComponent = component;
        classDoc.isDirective = directive;
        
        if (isService(classDoc)) {
            classDoc.isService = true;
        } else if (isNgModule(classDoc)) {
            classDoc.isNgModule = true;
        }
    }
}

分组处理器

ts 解析后在程序中的表现是一个数组类似,每一个文档都被当成一个数组元素。所以需要将这些文档进行分组。

我这里采用跟源文件相同目录结构分法。

代码语言:javascript
复制
/** 数据结构*/
class ComponentGroup {
    constructor(name) {
        this.name = name;
        this.id = `component-group-${name}`;
        this.aliases = [];
        this.docType = 'componentGroup';
        this.components = [];
        this.directives = [];
        this.services = [];
        this.additionalClasses = [];
        this.typeClasses = [];
        this.interfaceClasses = [];
        this.ngModule = null;
    }
}

module.exports = function componentGrouper() {
    return {
        $runBefore: ['docs-processed'],
        $process: function(docs) {
            let groups = new Map();

            docs.forEach(doc => {
                let basePath = doc.fileInfo.basePath;
                let filePath = doc.fileInfo.filePath;

                // 保持 `/src/app` 的目录结构
                let fileSep = path.relative(basePath, filePath).split(path.sep);
                let groupName = fileSep.slice(0, fileSep.length - 1).join('/');

                // 不存在时创建它
                let group;
                if (groups.has(groupName)) {
                    group = groups.get(groupName);
                } else {
                    group = new ComponentGroup(groupName);
                    groups.set(groupName, group);
                }

                if (doc.isComponent) {
                    group.components.push(doc);
                } else if (doc.isDirective) {
                    group.directives.push(doc);
                } else if (doc.isService) {
                    group.services.push(doc);
                } else if (doc.isNgModule) {
                    group.ngModule = doc;
                } else if (doc.docType === 'class') {
                    group.additionalClasses.push(doc);
                } else if (doc.docType === 'interface') {
                    group.interfaceClasses.push(doc);
                } else if (doc.docType === 'type') {
                    group.typeClasses.push(doc);
                }
            });

            return Array.from(groups.values());
        }
    };
};

但,这样还是无法让 Dgeni 知道如何去区分?因此,我们还需要按路径输出处理器配置:

代码语言:javascript
复制
.config(function(computePathsProcessor) {
    computePathsProcessor.pathTemplates = [{
        docTypes: ['componentGroup'],
        pathTemplate: '${name}',
        outputPathTemplate: '${name}.html',
    }];
})

模板引擎

dgeni-packages 提供 Nunjucks 模板引擎来渲染文档。之前,我们就学过如何配置模板引擎所需要的模板文件目录及标签格式。

接下来,只需要创建这些模板文件即可,数据源就是文档对象,之前花很多功夫去了解处理器;最核心的目的就是要将文档对象转换成更便利于模板引擎使用。而如何编写 Nunjucks 模板不再赘述。

在编写分组处理器时,强制文件类型 this.docType = 'componentGroup';;而在配置按路径输出处理器也指明这一层关系。

因此,需要创建一个文件名叫 componentGroup.template.html 模板文件做为开始,为什么必须是这样的名称,你可以回头看模板引擎配置那一节。

而模板文件中所需要的数据结构名叫 doc,因此,在模板引擎中使用 {$ doc.name $} 来表示分组处理器数据结构中的 ComponentGroup.name

最后,文章中所有源代码见 Github

方法二主要采用 cipchk的博客 注: 侵权删

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019.02.21 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 环境
  • 创建项目
  • 使用 compodoc
    • 安装
      • 配置文档生成命令
        • 生成doc文档
        • 安装依赖插件
        • 创建文档目录结构
        • 配置文件
        • 设置源文件和输出路径
        • 设置Typescript解析器
        • 设置模板引擎
        • 过滤处理器
        • 分类处理器
        • 分组处理器
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档