@diplodoc/cli
Advanced tools
@@ -49,2 +49,9 @@ import type { Run } from '../../..'; | ||
| * Also removes the trailing empty line after the heading if present. | ||
| * | ||
| * If the result is empty (e.g. `#hash` + `notitle` on a section that is | ||
| * only a heading line, like a single `#### {#id}` block) we deliberately | ||
| * return empty content: the author wrote `notitle`, asking for the title | ||
| * to be removed. Returning the original heading as a fallback would | ||
| * silently contradict the directive and produce different output from | ||
| * the md→html path (which also yields empty content in that case). | ||
| */ | ||
@@ -54,4 +61,13 @@ export declare function stripFirstHeading(content: string): string; | ||
| * Adds indentation to all lines of content except the first line (which | ||
| * is already preceded by indent in the parent) and empty lines. | ||
| * is already preceded by indent in the parent). | ||
| * | ||
| * Empty lines are normally NOT indented to avoid trailing whitespace, | ||
| * EXCEPT when they fall inside a CommonMark HTML block of types 1–5 | ||
| * (e.g. multi-line `<!-- ... -->` comments). Such blocks are not | ||
| * interrupted by blank lines per spec, but markdown-it’s list-item | ||
| * parser treats an unindented blank line as the boundary of the HTML | ||
| * block and breaks the surrounding list / cut / blockquote. Indenting | ||
| * the blank line keeps the HTML block continuous and the parent | ||
| * structure intact. | ||
| * | ||
| * Preserves original line endings (\r\n, \r, \n) for cross-platform support. | ||
@@ -58,0 +74,0 @@ */ |
@@ -607,5 +607,79 @@ "use strict"; | ||
| // src/core/markdown/loader/resolve-deps.ts | ||
| function findFencedCodeBlockRanges(content, excludeRanges = []) { | ||
| const ranges = []; | ||
| const lines = content.split("\n"); | ||
| const lineStarts = new Array(lines.length); | ||
| let pos = 0; | ||
| for (let i = 0; i < lines.length; i++) { | ||
| lineStarts[i] = pos; | ||
| pos += lines[i].length + 1; | ||
| } | ||
| const lineIsExcluded = (line) => { | ||
| const lineStart = lineStarts[line]; | ||
| const lineEnd = lineStart + lines[line].length; | ||
| return excludeRanges.some(([start, end]) => lineStart >= start && lineEnd <= end); | ||
| }; | ||
| let openLine = -1; | ||
| let openChar = ""; | ||
| let openLen = 0; | ||
| const stripContainerPrefix = (s) => { | ||
| const list = /^(?:[-*+]|\d{1,9}[.)])\s+/.exec(s); | ||
| if (list) { | ||
| return s.slice(list[0].length); | ||
| } | ||
| const deflist2 = /^:\s+/.exec(s); | ||
| if (deflist2) { | ||
| return s.slice(deflist2[0].length); | ||
| } | ||
| return s; | ||
| }; | ||
| const END_CLOSE_RE = /(`{3,}|~{3,})\s*(?:\|\||\|#|\|)\s*$/; | ||
| for (let i = 0; i < lines.length; i++) { | ||
| if (lineIsExcluded(i)) { | ||
| continue; | ||
| } | ||
| const trimmed = lines[i].trimStart(); | ||
| if (openLine < 0) { | ||
| const search = stripContainerPrefix(trimmed); | ||
| const fenceMatch = /^(`{3,}|~{3,})/.exec(search); | ||
| if (!fenceMatch) { | ||
| continue; | ||
| } | ||
| const fence = fenceMatch[1]; | ||
| const info = search.slice(fence.length); | ||
| if (fence[0] === "`" && info.includes("`")) { | ||
| continue; | ||
| } | ||
| openLine = i; | ||
| openChar = fence[0]; | ||
| openLen = fence.length; | ||
| continue; | ||
| } | ||
| const startMatch = /^(`{3,}|~{3,})/.exec(trimmed); | ||
| if (startMatch && startMatch[1][0] === openChar && startMatch[1].length >= openLen) { | ||
| const after = trimmed.slice(startMatch[1].length).trim(); | ||
| if (after === "" || /^(?:\|\||\|#|\|)$/.test(after)) { | ||
| ranges.push([lineStarts[openLine], lineStarts[i] + lines[i].length]); | ||
| openLine = -1; | ||
| continue; | ||
| } | ||
| } | ||
| const endMatch = END_CLOSE_RE.exec(lines[i]); | ||
| if (endMatch && endMatch[1][0] === openChar && endMatch[1].length >= openLen) { | ||
| ranges.push([lineStarts[openLine], lineStarts[i] + lines[i].length]); | ||
| openLine = -1; | ||
| } | ||
| } | ||
| return ranges; | ||
| } | ||
| function resolveDependencies(content) { | ||
| const includes = []; | ||
| const exclude = [...this.api.comments.get(), ...findIncludedBlockRanges(content)]; | ||
| const commentRanges = this.api.comments.get(); | ||
| const exclude = [ | ||
| ...commentRanges, | ||
| ...findIncludedBlockRanges(content), | ||
| // Pass the comment ranges so a fence run that lies inside an HTML | ||
| // comment is not treated as a code block boundary (see Bug 26). | ||
| ...findFencedCodeBlockRanges(content, commentRanges) | ||
| ]; | ||
| const includeRegex = new RegExp(INCLUDE_REGEX.source, INCLUDE_REGEX.flags); | ||
@@ -612,0 +686,0 @@ let match; |
@@ -572,5 +572,79 @@ var __create = Object.create; | ||
| // src/core/markdown/loader/resolve-deps.ts | ||
| function findFencedCodeBlockRanges(content, excludeRanges = []) { | ||
| const ranges = []; | ||
| const lines = content.split("\n"); | ||
| const lineStarts = new Array(lines.length); | ||
| let pos = 0; | ||
| for (let i = 0; i < lines.length; i++) { | ||
| lineStarts[i] = pos; | ||
| pos += lines[i].length + 1; | ||
| } | ||
| const lineIsExcluded = (line) => { | ||
| const lineStart = lineStarts[line]; | ||
| const lineEnd = lineStart + lines[line].length; | ||
| return excludeRanges.some(([start, end]) => lineStart >= start && lineEnd <= end); | ||
| }; | ||
| let openLine = -1; | ||
| let openChar = ""; | ||
| let openLen = 0; | ||
| const stripContainerPrefix = (s) => { | ||
| const list = /^(?:[-*+]|\d{1,9}[.)])\s+/.exec(s); | ||
| if (list) { | ||
| return s.slice(list[0].length); | ||
| } | ||
| const deflist2 = /^:\s+/.exec(s); | ||
| if (deflist2) { | ||
| return s.slice(deflist2[0].length); | ||
| } | ||
| return s; | ||
| }; | ||
| const END_CLOSE_RE = /(`{3,}|~{3,})\s*(?:\|\||\|#|\|)\s*$/; | ||
| for (let i = 0; i < lines.length; i++) { | ||
| if (lineIsExcluded(i)) { | ||
| continue; | ||
| } | ||
| const trimmed = lines[i].trimStart(); | ||
| if (openLine < 0) { | ||
| const search = stripContainerPrefix(trimmed); | ||
| const fenceMatch = /^(`{3,}|~{3,})/.exec(search); | ||
| if (!fenceMatch) { | ||
| continue; | ||
| } | ||
| const fence = fenceMatch[1]; | ||
| const info = search.slice(fence.length); | ||
| if (fence[0] === "`" && info.includes("`")) { | ||
| continue; | ||
| } | ||
| openLine = i; | ||
| openChar = fence[0]; | ||
| openLen = fence.length; | ||
| continue; | ||
| } | ||
| const startMatch = /^(`{3,}|~{3,})/.exec(trimmed); | ||
| if (startMatch && startMatch[1][0] === openChar && startMatch[1].length >= openLen) { | ||
| const after = trimmed.slice(startMatch[1].length).trim(); | ||
| if (after === "" || /^(?:\|\||\|#|\|)$/.test(after)) { | ||
| ranges.push([lineStarts[openLine], lineStarts[i] + lines[i].length]); | ||
| openLine = -1; | ||
| continue; | ||
| } | ||
| } | ||
| const endMatch = END_CLOSE_RE.exec(lines[i]); | ||
| if (endMatch && endMatch[1][0] === openChar && endMatch[1].length >= openLen) { | ||
| ranges.push([lineStarts[openLine], lineStarts[i] + lines[i].length]); | ||
| openLine = -1; | ||
| } | ||
| } | ||
| return ranges; | ||
| } | ||
| function resolveDependencies(content) { | ||
| const includes = []; | ||
| const exclude = [...this.api.comments.get(), ...findIncludedBlockRanges(content)]; | ||
| const commentRanges = this.api.comments.get(); | ||
| const exclude = [ | ||
| ...commentRanges, | ||
| ...findIncludedBlockRanges(content), | ||
| // Pass the comment ranges so a fence run that lies inside an HTML | ||
| // comment is not treated as a code block boundary (see Bug 26). | ||
| ...findFencedCodeBlockRanges(content, commentRanges) | ||
| ]; | ||
| const includeRegex = new RegExp(INCLUDE_REGEX.source, INCLUDE_REGEX.flags); | ||
@@ -577,0 +651,0 @@ let match; |
+2
-1
| { | ||
| "name": "@diplodoc/cli", | ||
| "version": "5.39.7", | ||
| "version": "5.39.8", | ||
| "description": "Make documentation using yfm-docs in Markdown and HTML formats", | ||
@@ -127,2 +127,3 @@ "keywords": [ | ||
| "@types/markdown-it": "^13.0.9", | ||
| "@types/markdown-it-attrs": "^4.1.0", | ||
| "@types/mime-types": "2.1.4", | ||
@@ -129,0 +130,0 @@ "@types/node": "^22.19.0", |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
115395809
0.07%187503
0.09%46
2.22%