jsdoc 主题模板参考

文件目录

使用npm安装jsdoc后,其文件目录结构如下:

image.png

其中templates放置了默认的主题模板。其中default主题的文件结构如下:
image.png

其中,publish.js是最重要的文件,它导出一个publish函数,在cli.js中被调用

// cli.js
publishPromise = template.publish(
    // 保存所有数据的Taffy对象,见下面
    taffy(props.docs), 
    // env是一个保存运行环境信息的对象
    // 参考:lib/jsdoc/env.js
    env.opts,
    // 暂时未
    resolver.root
);

// publish.js
// 这里的publish就是上面的template.publish
exports.publish = function (taffyData, opts, tutorials) {
  // ...
}

参考:taffydb
而static文件夹放置静态文件,它会被原封不动地复制到生成的文件夹中,tmpl是模板文件

publish.js解析

publish函数参数

function (taffyData, opts, tutorials)

taffyData是包含所有doclet的taffyData,doclet是@link,@name...
比如使用了@name,就可以使用docs[0].name获取第一个@name值

模板

和模板相关的模块是:

const template = require('jsdoc/template'); // 模板定义
const helper = require('jsdoc/util/templateHelper'); // 模板的辅助函数库

生成template的语句是

// templatePath是配置文件中的opts.template或者使用cli时的template选项的值
// 它应该是模板文件夹`tmpl`的所在文件夹的路径`(主题文件夹的根目录)`
view = new template.Template( path.join(templatePath, 'tmpl') );

再看template.js导出类的构造函数

constructor(filepath) {
    // 模板文件所在路径
    this.path = filepath;
    // layout的文件名
    this.layout = null;
    // 表明使用的模板语法
    this.settings = {
        evaluate: /<\?js([\s\S]+?)\?>/g,
        interpolate: /<\?js=([\s\S]+?)\?>/g,
        escape: /<\?js~([\s\S]+?)\?>/g
    };
}

layout的初始化语句:

// env.conf是配置文件导出的对象
conf = env.conf.templates || {};
conf.default = conf.default || {};

// ....

// 设置layout的路径
view.layout = conf.default.layoutFile ?
        path.getResourcePath(path.dirname(conf.default.layoutFile),
            path.basename(conf.default.layoutFile) ) :
        'layout.tmpl';

所以,如果要自定义模板(假设为selfTheme,以下都以其为例)的配置项,只需要使用env.conf.templates获取即可。例如:

// conf.json
{
  templates: {
    selfProp: 'selfValue'
  }
}

// publish.js
conf = env.conf.templates || {};
conf.selfProp = conf.selfProp; // get selfProp

template.js导出类的方法如下:

  • load(file: string) // 解析模板
  • partial(file: string, data: any) // 引用另一模板文件,data是载入模板的数据
  • render(file: string, data: any) // 渲染模板
    重点看render代码:
render(file, data) {
    // 渲染当前模板文件
    let content = this.partial(file, data);

    if (this.layout) {
        // 将当前内容赋值给data.content,传递给layout模板
        data.content = content;
        content = this.partial(this.layout, data);
    }

    return content;
}

因此,在layout.tmpl文件中,有content变量表示当前页内容

<?js= content ?>

当然,同时具有data包含的其它属性变量
在publish.js中,直接使用render函数的有两处。

// function generate(title, docs, filename, resolveLinks)
docData = {
    env: env,
    title: title, // 标题
    docs: docs // 见下面docs
};
html = view.render('container.tmpl', docData);

// function generateTutorial(title, tutorial, filename)
const tutorialData = {
    title: title,
    header: tutorial.title,
    content: tutorial.parse(),
    children: tutorial.children
};
const tutorialPath = path.join(outdir, filename);
let html = view.render('tutorial.tmpl', tutorialData);

所以,要修改各页面的标题,只需要将调用这两个函数的title函数换掉,比如:

generate('Global', [{kind: 'globalobj'}], globalUrl)
// 改成
generate('MyGlobal', [{kind: 'globalobj'}], globalUrl)

不过重点还是添加模板变量和方法

// 添加变量,只需要改变render调用时的data,比如以下改变container.tmpl的变量
docData = {
    env: env,
    title: title, // 标题
    docs: docs,
    myVar: 'myVar'
};
html = view.render('container.tmpl', docData);

// 添加方法
view.find = find;
view.linkto = linkto;
view.resolveAuthorLinks = resolveAuthorLinks;
view.tutoriallink = tutoriallink;
view.htmlsafe = htmlsafe;
view.outputSourceFiles = outputSourceFiles;
view.nav = buildNav(members);

// 在模板中可以使用`this.method`来调用,因为模板的this指向view
// 比如
// <?js this.find()  ?>

添加到view中的方法/属性:

  • find(spec)
    通过find({kind: 'class'})来获取所有class,也可以添加其它doclet:find({kind, 'class', memberOf: 'Class1' })
  • linkTo(longname, linkText)
    渲染一个跳转到longname即namepath所指代的url的链接(a标签),文本是linkText
    resolveAuthorLinks
    渲染形如Jane Doe <jdoe@example.org> 的文本为<a href="mailto:jdoe@example.org">Jane Doe</a>
  • htmlsafe(str) 转义html文本
  • outputSourceFiles 是否导出源文件的标志
  • nav 导航栏标签

docs

docs是一个包含数据的Taffy对象,它的来源是:

data = taffyData
// 获取各部分的数据taffy对象
members = helper.getMembers(data)
classes = taffy(members.classes);
modules = taffy(members.modules);
namespaces = taffy(members.namespaces);
mixins = taffy(members.mixins);
externals = taffy(members.externals);
interfaces = taffy(members.interfaces);

// 获取对应longname的docs
const myClasses = helper.find(classes, {longname: longname});
const myExternals = helper.find(externals, {longname: longname});
const myInterfaces = helper.find(interfaces, {longname: longname});
const myMixins = helper.find(mixins, {longname: longname});
const myModules = helper.find(modules, {longname: longname});
const myNamespaces = helper.find(namespaces, {longname: longname});

// myClasses等就是传入模板文件的docs变量

if (myModules.length) {
    generate(`Module: ${myModules[0].name}`, myModules, helper.longnameToUrl[longname]);
}

if (myClasses.length) {
    generate(`Class: ${myClasses[0].name}`, myClasses, helper.longnameToUrl[longname]);
}

if (myNamespaces.length) {
    generate(`Namespace: ${myNamespaces[0].name}`, myNamespaces, helper.longnameToUrl[longname]);
}

if (myMixins.length) {
    generate(`Mixin: ${myMixins[0].name}`, myMixins, helper.longnameToUrl[longname]);
}

if (myExternals.length) {
    generate(`External: ${myExternals[0].name}`, myExternals, helper.longnameToUrl[longname]);
}

if (myInterfaces.length) {
    generate(`Interface: ${myInterfaces[0].name}`, myInterfaces, helper.longnameToUrl[longname]);
}

在模板中则用this.find({kind: 'class'})代替(view.find)
docs的元素内容是:

// 参考doclet.js
{
  comment: ''
  name: '',,
  kind: '',
  // ...
}

特别的:

// source
{
  kind: 'source',
  code: ''
}

// main page
{
  kind: 'mainpage',
  readme: opts.readme,
  longname: (opts.mainpagetitle) ? opts.mainpagetitle : 'Main Page'
}

// global
{
  kind: 'globalobj'
}

tutorials相关待续

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,108评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,699评论 1 296
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,812评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,236评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,583评论 3 288
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,739评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,957评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,704评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,447评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,643评论 2 249
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,133评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,486评论 3 256
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,151评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,108评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,889评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,782评论 2 277
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,681评论 2 272

推荐阅读更多精彩内容

  • mean to add the formatted="false" attribute?.[ 46% 47325/...
    ProZoom阅读 2,621评论 0 3
  • 模板引擎其实就是将一个带有自定义标签的字符串,通过相应的规则解析,返回php可以解析的字符串,这其中正则的运用是必...
    hopevow阅读 1,325评论 0 10
  • 概要 64学时 3.5学分 章节安排 电子商务网站概况 HTML5+CSS3 JavaScript Node 电子...
    阿啊阿吖丁阅读 8,630评论 0 3
  • 模板标签除了几个常用的,还真心没有仔细了解一下,看到2.0发布后,翻译学习一下。 本文尽量忠实原著,毕竟大神的东西...
    海明_fd17阅读 1,920评论 0 5
  • 传于吾辈门人,诸生需当敬听 自古人生于世,须有一技之能 吾辈既务斯业,便当专心用功 以后明扬四海,根据即在年轻
    Harry小哥哥阅读 435评论 0 0