Skip to content

refactor(toc): support skipping heading level #5653

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open

Conversation

stevenjoezhang
Copy link
Member

What does it do?

Issue resolved: #2137

Screenshots

Pull request tasks

  • Add test cases for the changes.
  • Passed the CI test.

Copy link

How to test

git clone -b toc https://github.com/hexojs/hexo.git
cd hexo
npm install
npm test

@coveralls
Copy link

coveralls commented Apr 19, 2025

Pull Request Test Coverage Report for Build 16493028975

Details

  • 87 of 87 (100.0%) changed or added relevant lines in 1 file are covered.
  • No unchanged relevant lines lost coverage.
  • Overall first build on toc at 99.526%

Totals Coverage Status
Change from base Build 15609358336: 99.5%
Covered Lines: 9870
Relevant Lines: 9917

💛 - Coveralls

@stevenjoezhang stevenjoezhang force-pushed the toc branch 2 times, most recently from dfdecdb to ce6512d Compare April 22, 2025 14:27
@stevenjoezhang stevenjoezhang requested review from Copilot and a team July 24, 2025 09:23
Copy link

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR refactors the Table of Contents (TOC) helper to support skipping heading levels by replacing the previous linear processing approach with a tree-based structure. The refactor addresses issue #2137 by properly handling cases where heading levels are not sequential (e.g., h1 followed directly by h3).

Key changes:

  • Replaced linear TOC generation with tree-based approach using buildTree() function
  • Separated numbering logic into dedicated assignNumbers() function
  • Added comprehensive test case for skipped heading levels scenario

Reviewed Changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.

File Description
lib/plugins/helper/toc.ts Complete refactor from linear to tree-based TOC generation with new helper functions
test/scripts/helpers/toc.ts Added test case verifying correct handling of skipped heading levels

* @param {string} str Raw markdown/html string
* @param {Options} options Configuration options
*/
function tocHelper(str, options: Options = {}) {
Copy link
Preview

Copilot AI Jul 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The str parameter should have explicit type annotation string to maintain consistency with TypeScript best practices and the original function signature.

Suggested change
function tocHelper(str, options: Options = {}) {
function tocHelper(str: string, options: Options = {}) {

Copilot uses AI. Check for mistakes.

/**
* Extract flat TOC data and enforce max_items
*/
function getAndTruncateTocObj(str, { min_depth, max_depth }, max_items) {
Copy link
Preview

Copilot AI Jul 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function parameters lack type annotations. Should be str: string, { min_depth, max_depth }: {min_depth: number, max_depth: number}, and max_items: number to maintain TypeScript type safety.

Suggested change
function getAndTruncateTocObj(str, { min_depth, max_depth }, max_items) {
function getAndTruncateTocObj(str: string, { min_depth, max_depth }: { min_depth: number, max_depth: number }, max_items: number) {

Copilot uses AI. Check for mistakes.

/**
* Build nested tree from flat heading list
*/
function buildTree(headings) {
Copy link
Preview

Copilot AI Jul 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The headings parameter should have explicit type annotation to maintain TypeScript consistency. Consider adding appropriate interface or type definition.

Suggested change
function buildTree(headings) {
function buildTree(headings: Heading[]) {

Copilot uses AI. Check for mistakes.

Comment on lines +128 to +130
function assignNumbers(nodes) {
const counters = [];
function dfs(list, depth) {
Copy link
Preview

Copilot AI Jul 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The nodes parameter should have explicit type annotation to maintain TypeScript consistency. Consider adding appropriate interface or type definition.

Suggested change
function assignNumbers(nodes) {
const counters = [];
function dfs(list, depth) {
function assignNumbers(nodes: Node[]) {
const counters: number[] = [];
function dfs(list: Node[], depth: number) {

Copilot uses AI. Check for mistakes.

'<h1>Title 1</h1>'
].join('');

toc(input).should.eql('<ol class="toc"><li class="toc-item toc-level-1"><a class="toc-link"><span class="toc-number">1.</span> <span class="toc-text">Title 1</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link"><span class="toc-number">1.1.</span> <span class="toc-text">Title 3</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link"><span class="toc-number">1.1.1.</span> <span class="toc-text">Title 4</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link"><span class="toc-number">1.2.</span> <span class="toc-text">Title 2</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link"><span class="toc-number">1.2.1.</span> <span class="toc-text">Title 5</span></a></li></ol></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link"><span class="toc-number">2.</span> <span class="toc-text">Title 1</span></a></li></ol>');
Copy link
Preview

Copilot AI Jul 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This extremely long assertion string (over 500 characters) is difficult to read and maintain. Consider breaking it into a multi-line template literal or extracting it to a variable for better readability.

Suggested change
toc(input).should.eql('<ol class="toc"><li class="toc-item toc-level-1"><a class="toc-link"><span class="toc-number">1.</span> <span class="toc-text">Title 1</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link"><span class="toc-number">1.1.</span> <span class="toc-text">Title 3</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link"><span class="toc-number">1.1.1.</span> <span class="toc-text">Title 4</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link"><span class="toc-number">1.2.</span> <span class="toc-text">Title 2</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link"><span class="toc-number">1.2.1.</span> <span class="toc-text">Title 5</span></a></li></ol></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link"><span class="toc-number">2.</span> <span class="toc-text">Title 1</span></a></li></ol>');
toc(input).should.eql(`
<ol class="toc">
<li class="toc-item toc-level-1">
<a class="toc-link">
<span class="toc-number">1.</span> <span class="toc-text">Title 1</span>
</a>
<ol class="toc-child">
<li class="toc-item toc-level-3">
<a class="toc-link">
<span class="toc-number">1.1.</span> <span class="toc-text">Title 3</span>
</a>
<ol class="toc-child">
<li class="toc-item toc-level-4">
<a class="toc-link">
<span class="toc-number">1.1.1.</span> <span class="toc-text">Title 4</span>
</a>
</li>
</ol>
</li>
<li class="toc-item toc-level-2">
<a class="toc-link">
<span class="toc-number">1.2.</span> <span class="toc-text">Title 2</span>
</a>
<ol class="toc-child">
<li class="toc-item toc-level-5">
<a class="toc-link">
<span class="toc-number">1.2.1.</span> <span class="toc-text">Title 5</span>
</a>
</li>
</ol>
</li>
</ol>
</li>
<li class="toc-item toc-level-1">
<a class="toc-link">
<span class="toc-number">2.</span> <span class="toc-text">Title 1</span>
</a>
</li>
</ol>
`);

Copilot uses AI. Check for mistakes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

TOC seems not suitable when skipping heading levels
2 participants