Skip to content

Commit

Permalink
feat(toc_obj): Support unnumbered headings
Browse files Browse the repository at this point in the history
  • Loading branch information
Cerallin committed Jan 11, 2022
1 parent ab5ad9d commit fd8a49e
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 3 deletions.
25 changes: 22 additions & 3 deletions lib/toc_obj.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
'use strict';
const { Node } = require('domhandler');
const { DomHandler, DomUtils, Parser } = require('htmlparser2');
const escapeHTML = require('./escape_html');
const nonWord = /^\s*[^a-zA-Z0-9]\s*$/;
Expand All @@ -13,11 +14,26 @@ const getId = ({ attribs = {}, parent }) => {
return attribs.id || (!parent ? '' : getId(parent));
};

/**
* Identify a heading that to be unnumbered or not.
*
* @param {Node} {attribs.class} string contains all classes of the heading.
* @param {Set<string>} searchClassSet classes to search.
* @returns bool
*/
const isUnnumbered = ({ attribs = { class: "" } }, searchClassSet) => {
let classList = attribs.class;
return classList &&
classList.split(" ").filter(item => searchClassSet.has(item)).length > 0;
};

function tocObj(str, options = {}) {
const { min_depth, max_depth } = Object.assign({
const { min_depth, max_depth, unnumbered_class_list } = Object.assign({
min_depth: 1,
max_depth: 6
max_depth: 6,
unnumbered_class_list: []
}, options);
const unnumbered_class_set = new Set(unnumbered_class_list);

const headingsSelector = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'].slice(min_depth - 1, max_depth);
const headings = DomUtils.find(({ tagName }) => headingsSelector.includes(tagName), parseHtml(str), true);
Expand All @@ -31,6 +47,7 @@ function tocObj(str, options = {}) {
const el = headings[i];
const level = +el.name[1];
const id = getId(el);
const unnumbered = isUnnumbered(el, unnumbered_class_set);
let text = '';
for (const element of el.children) {
const elText = DomUtils.getText(element);
Expand All @@ -43,7 +60,9 @@ function tocObj(str, options = {}) {
}
if (!text) text = escapeHTML(DomUtils.getText(el));

result.push({ text, id, level });
const res = { text, id, level };
if (unnumbered) res.unnumbered = true;
result.push(res);
}

return result;
Expand Down
18 changes: 18 additions & 0 deletions test/toc_obj.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -165,5 +165,23 @@ describe('tocObj', () => {

result.forEach(str => str[0].text.should.eql('foobarbaz'));
});

it('unnumbered headings', () => {
const input = [
'<h1 id="title_1" class=" unnumbered_1 foo">Title 1</h1>',
'<h2 class="bar unnumbered_2" id="title_2">Title 2</h2>'
].join('');

const expected = [
{ text: 'Title 1', id: 'title_1', level: 1, unnumbered: true },
{ text: 'Title 2', id: 'title_2', level: 2, unnumbered: true }
];

tocObj(input, {
unnumbered_class_list: [
'unnumbered_1', 'unnumbered_2'
]
}).should.eql(expected);
});
});
});

0 comments on commit fd8a49e

Please sign in to comment.