Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -241,8 +241,6 @@ It is recommended to also include this argument when performing an update on an

Use the `--toc-title-padding-before` option to add padding line/s above the TOC which ensures formatters such as prettier will pass; e.g., `doctoc --toc-title-padding-before 1 .`

NOTE: Currently it is only supported to add one line before the title.
Comment thread
thompson-tomo marked this conversation as resolved.

By default,
Comment thread
thompson-tomo marked this conversation as resolved.

- no padding is added above the table of contents title
Expand Down
1 change: 0 additions & 1 deletion doctoc.js
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,6 @@ var dryRun = argv.d || argv.dryrun || false;

var padBeforeTitle = argv['toc-title-padding-before'];
if (padBeforeTitle && isNaN(padBeforeTitle) || padBeforeTitle < 0) { console.error('Padding before title specified is not a positive number: ' + padBeforeTitle), printUsageAndExit(true); }
else if (padBeforeTitle && padBeforeTitle > 1) { console.error('Padding before title: ' + padBeforeTitle + ' is not currently supported as greater than 1'), printUsageAndExit(true); }

var maxHeaderLevel = argv.m || argv.maxlevel;
if (maxHeaderLevel && isNaN(maxHeaderLevel)) { log.error('Max. heading level specified is not a number: ' + maxHeaderLevel), printUsageAndExit(true); }
Expand Down
36 changes: 35 additions & 1 deletion lib/content-generation.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,44 @@ function escapedStartTag(syntax) {
return commentTypes[syntax].escapedStart;
}

function tocFooter(footerOptions) {
return tocPart(footerOptions?.padding, footerOptions?.content);
}

function tocHeader(headerOptions) {
return tocPart(headerOptions?.padding, headerOptions?.content);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

header.padding and footer.padding are read here but nothing ever sets them — no flag in doctoc.js, no mention in the README, no test. Same for title.padding.after. Only title.padding.before has a way in.

Either wire up the flags and docs in this PR (which is what the title suggests), or leave padding off header/footer until there's a way to reach it. As-is it reads like a feature but is dead for every CLI user.

}

function tocTitle(titleOptions, existingTitle) {
if (titleOptions?.remove || (existingTitle === "" && !titleOptions?.content)) return [];

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This creates a with determineTitle that nothing spells out: undefined means "nothing known, use the default", "" means "the existing TOC deliberately had no title, keep it that way", and a non-empty string means "preserve this one". Maybe worth a simple object, like:

const titleSetting: {
  default: undefined,
  existingTocNoTitle: "",
  preserveTocTitle: "...",
}

Or at least some comments.

var content;
if (titleOptions?.content){
content = titleOptions.content;
}
else if(existingTitle){
content = existingTitle;
}
else{
content = '**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)*';
}
return tocPart(titleOptions?.padding, content);
}

function tocPart(padding, content){
if (content === undefined) return [];
var lines = Array(Number(padding?.before ?? 0)).fill('');

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The CLI needs validation on non-negative integers, e.g.:

$ doctoc --toc-title-padding-before 0.5 README.md
RangeError: Invalid array length
    at tocPart (lib/content-generation.js:83:15)

Similar for 1.5.

Let's add some CLI arg validation?

lines.push(content);
lines.push(...Array(Number(padding?.after ?? 0)).fill(''));
return lines;
}

module.exports = {
commentedBlock,
escapedStartTag,
pragmaMarkers,
skipTag,
excludeTag
excludeTag,
tocFooter,
tocHeader,
tocTitle

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

General thought: add direct unit tests for tocTitle's fallback chain (explicit content → existing title → default → removed).

};
27 changes: 9 additions & 18 deletions lib/transform.js
Original file line number Diff line number Diff line change
Expand Up @@ -153,14 +153,8 @@ function processHeaders(headers, mode) {
return headers;
}

// When updating an existing TOC, try to preserve the title that was there before.
// Falls back to CLI args (--title, --notitle) or the default title for new TOCs.
function determineTitle(nodes, tocPosition, title, notitle, header) {
var defaultTitle = '**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)*';

if (notitle) return "";
if (title) return title;
if (!tocPosition?.existing) return defaultTitle;
function determineTitle(nodes, tocPosition, titleOptions, header) {
if (titleOptions.remove || titleOptions.content || !tocPosition?.existing) return undefined;

// Find the TOC's list node so we know where the title region ends
var listStartIdx = nodes.children.filter(function (x) {
Expand Down Expand Up @@ -231,6 +225,7 @@ exports = module.exports = function transform(content, mode, maxHeaderLevel, min
options.toc.items ??= {};
options.toc.items.indentation ??= {};
options.toc.list ??= {};
options.toc.title ??= {};

syntax = syntax || "md";
options.toc.items.indentation.style ??= 'space';
Expand All @@ -241,6 +236,8 @@ exports = module.exports = function transform(content, mode, maxHeaderLevel, min
var ordered = options.toc.list.format === 'ordered';
options.toc.items.symbols ??= ordered ? undefined : String(entryPrefix || '-').split(',');
options.toc.list.style ??= ordered ? 'number' : undefined
options.toc.title.content ??= title;
options.toc.title.remove ??= notitle;

var eol = '\n';
eol = detectLineEnding(content, eol);
Expand All @@ -255,11 +252,6 @@ exports = module.exports = function transform(content, mode, maxHeaderLevel, min
minTocItems = 1;
}

var padTitle = options?.toc?.title?.padding?.before > 0;
if (options?.toc?.title?.padding?.before === undefined){
padTitle = notitle || false;
}

// only limit *HTML* headings by default
var maxHeaderLevelHtml = maxHeaderLevel || 4;

Expand Down Expand Up @@ -338,16 +330,15 @@ exports = module.exports = function transform(content, mode, maxHeaderLevel, min

if (headers.length >= minTocItems && docNodes.children[docNodes.children.length - 1].loc.end.line >= minLines) {
var tocLines = [];
var inferredTitle = determineTitle(docNodes, tocPosition, title, notitle, options?.toc?.header?.content);
var inferredTitle = determineTitle(docNodes, tocPosition, options.toc.title, options.toc.header?.content);

var allHeaders = processHeaders(headers, mode);
var lowestRank = allHeaders.reduce((min, h) => Math.min(min, h.rank), Infinity);

var indentation = options.toc.items.indentation.style === 'tab' ? '\t' : ' ';

if (options?.toc?.header?.content) { tocLines.push(options.toc.header.content); }
if (padTitle && inferredTitle) { tocLines.push(''); }
if (inferredTitle) { tocLines.push(inferredTitle); }
tocLines.push(...contentGenerator.tocHeader(options.toc.header));
tocLines.push(...contentGenerator.tocTitle(options.toc.title, inferredTitle));
tocLines.push('');

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

padding.after stacks on top of this hardcoded blank rather than replacing it, so the new knob is effectively off by one — { toc: { title: { padding: { after: 1 } } } } produces two blank lines:

**Table of Contents**  *generated with [DocToc](...)*
                              ← padding.after
                              ← this line
- [A](#a)

Similar to footer.

Can we add tests to cover this?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

That is expected. The hard coded padding is for the items. It is no different to enabling padding after header & before title.

var symbolQty = options.toc.items.symbols?.length || 1;

Expand Down Expand Up @@ -383,7 +374,7 @@ exports = module.exports = function transform(content, mode, maxHeaderLevel, min
}));

tocLines.push('');
if (options?.toc?.footer?.content) { tocLines.push(options.toc.footer.content); }
tocLines.push(...contentGenerator.tocFooter(options.toc.footer));

toc = tocLines.join(eol);
}
Expand Down