使用NodeJS 生成Vue中文版 docSet 离线文档

栏目: Node.js · 发布时间: 5年前

内容简介:Dash所需的文档都是生成文档的方法有很多种,如Python、可以选择
  • 取自官方cn.vuejs.org (Version: 2.5 )
  • 持续更新

用法

  • Mac下用户下载 Dash 使用文档 (下载 .docset 后缀文件,双击导入即可)
  • Windows 和 Linux 用户可下载 Zeal 使用本文档 (应该类似吧,我没用过,自行搜一下吧,溜了溜了)
使用NodeJS 生成Vue中文版 docSet 离线文档

制作 docSet 文档

Dash所需的文档都是 .docSet 后缀的文件,其实docSet文件就是一个文件夹而已,里头包含最终的html文档,以及根据html建立的索引(索引放在 sqlite 数据库中)。

生成文档的方法有很多种,如 PythonRubyObjective-CNode.jsPHP

可以选择 镜像时处理 ,也可以 镜像后处理 。只需要结果中包含html,以及sqlite 就OJBK。

这里我选择 镜像后用NodeJS处理

需要用到的库为:

fs
path
sync-exec
sqlite-sync
cheerio

主要步骤:

根据官网提供的官方文档,整个转换主要有以下5个步骤:

1. 创建Docset目录结构(Create the Docset Folder);
2. 复制HTML文件(Copy the HTML Documentation);
3. 创建Info.plist文件(Create the Info.plist File);
4. 创建SQLite数据库文件(Create the SQLite Index);
5. 写入SQLite数据索引(Populate the SQLite Index);
复制代码

1. 镜像站点

镜像 工具 有很多,这里只推荐我尝试过的几款,并且用着还不错:

名称 平台 地址
HTTrack OS X / Windows/Linux/Unix/BSD www.httrack.com
SiteSucker OS X sitesucker.us/home.html
Cyotek WebCopy Windows www.cyotek.com/cyotek-webc…

实际上这几种都不是很完美,或多或少会漏一些外部站点的资源文件,目前还没找到解决办法,

如果你们有解决办法,麻烦**@**我一下。

我这里以 SiteSucker 为例,镜像 https://cn.vuejs.org ,一级目录结构如下:

// cn.vuejs.org
├── _00.txt
├── _downloads.html
├── coc
├── css
├── fonts
├── guide
├── images
├── index.html
├── js
├── manifest.json
├── support-vuejs
└── v2
复制代码

重点关注对象为以下,提取其中的内容,生成索引

cn.vuejs.org/v2/api/index.html
cn.vuejs.org/v2/guide/*
cn.vuejs.org/v2/style-guide/index.html

参考Dash的Vue文档,一层层拨开后,发现官方用的 HTTrack 做的镜像,并且资源文件比我自己用 HTTrack 镜像下来的资源齐全,一番折腾下来,也没成功。

对比后选择用官方的外部资源,文档内容则用自己镜像的

使用NodeJS 生成Vue中文版 docSet 离线文档 使用NodeJS 生成Vue中文版 docSet 离线文档 使用NodeJS 生成Vue中文版 docSet 离线文档

左侧为dash官方文档中的资源 、中间为合并后的资源(后面要用到)、 右侧为自己镜像的资源
复制代码

2. 创建Docset目录结构(Create the Docset Folder)

本例中我们创建的文档叫 VueJS,所以按下列结构创建目录:

mkdir -p VueJS.docset/Contents/Resources/Documents/
复制代码

3.复制HTML文件(Copy the HTML Documentation)

​ 把所有的html文档拷贝到Documents文件夹中,dash默认 Documents 为文档根目录

​ 为了省事,我把需要的资源文件放在了当前项目下。

cp -r  ./Documents  VueJS.docset/Contents/Resources/
复制代码

4.创建Info.plist文件(Create the Info.plist File)

在 VueJS.docset/Contents/ 中创建Info.plist文件,注意文件名的大小写,文件内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
        <key>CFBundleIdentifier</key>
        <string>VueJS</string>
        <key>CFBundleName</key>
        <string>VueJS-CN</string>
        <key>DocSetPlatformFamily</key>
        <string>VueJS</string>
        <key>isDashDocset</key>
        <true/>
        <key>DashDocSetFamily</key>
        <string>dashtoc3</string>
        <key>dashIndexFilePath</key>
        <string>cn.vuejs.org/index.html</string>
    </dict>
    </plist>
复制代码

一个xml文件,里面都是成对的key-string配置项

dashIndexFilePath
CFBundleName
DashDocSetFamily

5.创建SQLite数据库文件(Create the SQLite Index)

  1. 创建sqlite索引。

    索引文件的位置是:VueJS.docset/Contents/Resources/docSet.dsidx ,(Mac电脑已经预装了sqlite)

    所以直接从命令行进入Resources文件夹,在命令行中敲:

    sqlite3 docSet.dsidx 
    复制代码
  2. 这样就进入了sqlite数据库,接下来,创建数据表

    CREATE TABLE searchIndex(id INTEGER PRIMARY KEY, name TEXT, type TEXT, path TEXT)
    复制代码

6.写入SQLite数据索引(Populate the SQLite Index);

再往后就是,从html文件中提取内容,插入索引。这是最重要的一点,这里没弄好,整个都没啥用。

INSERT OR IGNORE INTO searchIndex(name, type, path) VALUES ('name', 'type', 'path');
复制代码

其中

name
type
path

官方原文为:

  • name is the name of the entry. For example, if you are adding a class, it would be the name of the class. This is the column that Dash searches.
  • type is the type of the entry. For example, if you are adding a class, it would be "Class". For a list of types that Dash recognises, see below.
  • path is the relative path towards the documentation file you want Dash to display for this entry. It can contain an anchor (#). Alternatively, Dash also supports http:// URL entries.

以下为我的部分代码,完整的代码在 build-vue.js

// build-vue.js

/**
 * 根据各个标题处理相应的锚点 添加索引
 *
 * @param $ dom 对象
 * @param relativePath 相对路径
 * @param dir 文件夹名称
 */
function handleTitles($,relativePath,dir) {
    // 教程模块 以h2 为索引,需要添加一个h1 的索引
    let h1Title = '';
    if(dir === 'guide'){
        $('h1').each(function (i,h) {
            h1Title = Array.from(h.childNodes).map((node) => node.data ).join('');
            db.run(`INSERT INTO searchIndex (name, type, path) VALUES ('${h1Title}', '${type['guide']}', '${relativePath}')`,function(res){
                if(res.error) throw res.error;
                console.log(res);
            });
        });
    }
    $('h2').each(function (i,h) {
        if(!h.attribs.id) return;
        let h2s = extractText(h); // 提取标题中的ID、文本内容
        let h3s = [];
        if(dir === 'api'){
            h3s = collectH3s(h);
            if(h3s.length<1) return
        }
        let entryType = type[h2s.id] || type['h2'];  // 默认 Section
        console.log(h2s);
        let h2Num = dir === 'api' ? 1 : 0;
        let h2Type = type['h2'];  // h2 归类为 Section
        addDashAnchor(h,h2s.id,h2Type,h2Num);
        let inTitle = `${h2s.text} ${dir === 'guide' ? ' - '+ h1Title : ''}`;
        let iniType =  dir ==='api' ? type['guide'] : h2Type;
        db.run(`INSERT INTO searchIndex (name, type, path) VALUES ('${inTitle}', '${iniType}', '${relativePath}#${encodeURIComponent(h2s.id)}')`,function(res){
            if(res.error) throw res.error;
            console.log(res);
        });
        // api下 需要处理 h3 标题,生成相应的索引
        if(dir === 'api'){
            h3s.forEach(function (titleNode,index) {
                let id =  titleNode.attribs.id;
                let text = [].slice.call(titleNode.childNodes).map( (node) => node.data).join('');
                // 需要处理括号
                if(text.match(/^([^(]+)\(/)) text= text.match(/^([^(]+)\(/)[1];
                console.log(id,text,entryType);
                addDashAnchor(titleNode,id,entryType,0);
                db.run(`INSERT INTO searchIndex (name, type, path) VALUES ('${text}', '${entryType}', '${relativePath}#${encodeURIComponent(id)}')`,function(res){
                    if(res.error) throw res.error;
                    console.log(res);
                });
            });
        }
    });

    /**
     *  提取标题中的ID、文本内容
     * @param h node
     * @returns {{id: *, text: *}}   id 用来生成锚点、text当做标题
     */
    function extractText (h) {
        let title =  [].slice.call(h.childNodes).map( (node) => node.tagName === 'a' ?  node.attribs.title : '').join('');
        let id = h.attribs.id;
        return {
            id: id,
            text:  title ? htmlEscape(title) : id // 如果没有就用ID 代替
        }
    }

    // 字符转义
    function htmlEscape (text) {
        return text
            .replace(/&/g, '&')
            .replace(/"/g, '"')
            .replace(/ /g, `'`)
            .replace(/</g, '<')
            .replace(/>/g, '>')
    }
    // 提取h2 附近的h3 标题列表
    function collectH3s (h) {
        let h3s = [];
        let next = h.nextSibling;
        while (next && next.tagName !== 'h2') {
            if (next.tagName === 'h3') {
                next.childNodes = removeTagA(next);
                h3s.push(next)
            }
            next = next.nextSibling
        }
        return h3s
    }
    // 移除A标签
    function removeTagA(h) {
       return [].slice.call(h.childNodes).filter(function (node) {
            return node.tagName !== 'a'
        })
    }
    // 添加dash规定格式的 锚点
    function addDashAnchor(h,name,types,num) {
        let nameStr = (`//dash_ref_${name}/${types}/${encodeURIComponent(name)}/${num}`); // 需要对URL 进行URL编码(百分比转义)
        let dashAnchor = `<a class="dashAnchor" name="${nameStr}"/>`;
        h.childNodes = removeTagA(h); // 取完title之后移除原有的锚点,添加 dash规定格式的锚点
        $(h).before(dashAnchor).html();
    }
}

复制代码

7. 导入文档

把所有的索引数据都插入到 searchIndex 以后,docSet文档就制作好了,直接双击 VueJS.docSet 就可以导入Dash了。


以上所述就是小编给大家介绍的《使用NodeJS 生成Vue中文版 docSet 离线文档》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Intel汇编语言程序设计

Intel汇编语言程序设计

Kip Irvine / 电子工业出版社 / 2007-9-1 / 61.00元

《国外计算机科学教材系列•Intel汇编语言程序设计(第5版)》全面细致地讲述了汇编语言程序设计的各个方面。从微处理器体系结构、工作机制到指令集;从最基本的编译器链器的使用到高级过程、结构和宏的使用;从用纯汇编编写程序到用C/C++等最新编译器与汇编的混合接口编程;从16位实模式下BIOS、DOS实模式文本及图形程序设计到32位保护模式的Windows程序设计;从磁盘基础知识到Intel指令编码、......一起来看看 《Intel汇编语言程序设计》 这本书的介绍吧!

随机密码生成器
随机密码生成器

多种字符组合密码

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具