Skip to content
Closed
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
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -138,3 +138,7 @@ dist
# tmp directory
.tmp/
tmp/

# ignore CLAUDE.md file that is used by Claude Code AI to store
# its analysis of the codebase
CLAUDE.md
10 changes: 2 additions & 8 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,8 @@
{
"markdownlint.config": {
"MD033": {
"allowed_elements": [
"br",
"div",
"img"
]
"allowed_elements": ["br", "div", "img"]
}
},
"markdownlint.lintWorkspaceGlobs": [
"**/*.md"
]
"markdownlint.lintWorkspaceGlobs": ["**/*.md"]
}
37 changes: 21 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,13 +151,17 @@ console.log(sectionMarkdown);
### Advanced Usage

```javascript
import { MarkdownTreeParser, createParser, extractSection } from 'markdown-tree-parser';
import {
MarkdownTreeParser,
createParser,
extractSection,
} from 'markdown-tree-parser';

// Create parser with custom options
const parser = createParser({
bullet: '-', // Use '-' for lists
emphasis: '_', // Use '_' for emphasis
strong: '__' // Use '__' for strong
bullet: '-', // Use '-' for lists
emphasis: '_', // Use '_' for emphasis
strong: '__', // Use '__' for strong
});

// Extract all sections at level 2
Expand Down Expand Up @@ -185,8 +189,7 @@ const codeBlocks = parser.selectAll(tree, 'code');

// Custom search
const customNode = parser.findNode(tree, (node) => {
return node.type === 'heading' &&
parser.getHeadingText(node).includes('API');
return node.type === 'heading' && parser.getHeadingText(node).includes('API');
});

// Transform content
Expand All @@ -198,7 +201,9 @@ parser.transform(tree, (node) => {

// Get document statistics
const stats = parser.getStats(tree);
console.log(`Document has ${stats.wordCount} words and ${stats.headings.total} headings`);
console.log(
`Document has ${stats.wordCount} words and ${stats.headings.total} headings`
);

// Generate table of contents
const toc = parser.generateTableOfContents(tree, 3);
Expand Down Expand Up @@ -241,7 +246,7 @@ for (let i = 0; i < sections.length; i++) {
#### Constructor

```javascript
new MarkdownTreeParser(options = {})
new MarkdownTreeParser((options = {}));
```

#### Methods
Expand Down Expand Up @@ -272,18 +277,18 @@ The library supports powerful CSS-like selectors for searching:

```javascript
// Element selectors
parser.selectAll(tree, 'heading') // All headings
parser.selectAll(tree, 'paragraph') // All paragraphs
parser.selectAll(tree, 'link') // All links
parser.selectAll(tree, 'heading'); // All headings
parser.selectAll(tree, 'paragraph'); // All paragraphs
parser.selectAll(tree, 'link'); // All links

// Attribute selectors
parser.selectAll(tree, 'heading[depth=1]') // H1 headings
parser.selectAll(tree, 'heading[depth=2]') // H2 headings
parser.selectAll(tree, 'link[url*="github"]') // Links containing "github"
parser.selectAll(tree, 'heading[depth=1]'); // H1 headings
parser.selectAll(tree, 'heading[depth=2]'); // H2 headings
parser.selectAll(tree, 'link[url*="github"]'); // Links containing "github"

// Pseudo selectors
parser.selectAll(tree, ':first-child') // First child elements
parser.selectAll(tree, ':last-child') // Last child elements
parser.selectAll(tree, ':first-child'); // First child elements
parser.selectAll(tree, ':last-child'); // Last child elements
```

## 🧪 Testing
Expand Down
51 changes: 31 additions & 20 deletions bin/md-tree.js
Original file line number Diff line number Diff line change
Expand Up @@ -646,33 +646,44 @@ For more information, visit: https://github.com/ksylvan/markdown-tree-parser
const sections = [];
let currentSection = null;

// Track whether we're inside a code block to avoid treating # comments as headers
let inCodeBlock = false;

for (let i = 0; i < lines.length; i++) {
const line = lines[i];

// Check for main title (level 1)
if (line.match(/^# /)) {
if (currentSection) {
currentSection.endLine = i - 1;
sections.push(currentSection);
}
currentSection = null;
continue;
// Track code block boundaries (``` at start of line)
if (line.trim().startsWith('```')) {
inCodeBlock = !inCodeBlock;
}

// Check for level 2 heading (section start)
if (line.match(/^## /)) {
if (currentSection) {
currentSection.endLine = i - 1;
sections.push(currentSection);
// Skip header detection when inside code blocks (fixes GitHub issue #7)
if (!inCodeBlock) {
// Check for main title (level 1)
if (line.match(/^# /)) {
if (currentSection) {
currentSection.endLine = i - 1;
sections.push(currentSection);
}
currentSection = null;
continue;
}

currentSection = {
headingText: line.replace(/^## /, ''),
startLine: i,
endLine: null,
lines: [],
};
continue;
// Check for level 2 heading (section start)
if (line.match(/^## /)) {
if (currentSection) {
currentSection.endLine = i - 1;
sections.push(currentSection);
}

currentSection = {
headingText: line.replace(/^## /, ''),
startLine: i,
endLine: null,
lines: [],
};
continue;
}
}

// Add line to current section if we're in one
Expand Down
6 changes: 2 additions & 4 deletions cspell.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
{
"words": [
"mdast"
],
"ignorePaths": ["node_modules", ".gitignore"]
"words": ["mdast"],
"ignorePaths": ["node_modules", ".gitignore"]
}
2 changes: 1 addition & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,4 +74,4 @@ export async function generateTOC(markdown, maxLevel = 3, options = {}) {
const parser = new MarkdownTreeParser(options);
const tree = await parser.parse(markdown);
return parser.generateTableOfContents(tree, maxLevel);
}
}
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading