Skip to content
Merged
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
16 changes: 13 additions & 3 deletions bin/md-tree.js
Original file line number Diff line number Diff line change
Expand Up @@ -385,13 +385,23 @@ For more information, visit: https://github.com/ksylvan/markdown-tree-parser
const content = await this.readFile(resolvedPath);
const tree = await this.parser.parse(content);
const links = this.parser.selectAll(tree, 'link');
const definitions = this.parser.selectAll(tree, 'definition');

const allUrls = [];
for (const link of links) {
allUrls.push(link.url);
}
for (const definition of definitions) {
allUrls.push(definition.url);
}

const uniqueUrls = new Set(allUrls);

console.log(
`\n🔗 Checking ${links.length} links in ${path.basename(resolvedPath)}:`
`\n🔗 Checking ${uniqueUrls.size} unique URLs in ${path.basename(resolvedPath)}:`
);

for (const link of links) {
const url = link.url;
for (const url of uniqueUrls) {
if (!url || url.startsWith('#')) {
continue;
}
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@kayvan/markdown-tree-parser",
"version": "1.5.0",
"version": "1.5.1",
"description": "A powerful JavaScript library and CLI tool for parsing and manipulating markdown files as tree structures using the remark/unified ecosystem",
"type": "module",
"main": "index.js",
Expand Down
154 changes: 2 additions & 152 deletions test/sample.md
Original file line number Diff line number Diff line change
@@ -1,153 +1,3 @@
# Sample Document
# Sample File

This is a sample markdown document for testing the markdown-tree-parser package.

## Overview

This document demonstrates various markdown features and structures that can be parsed and manipulated.

### Key Features

- **Bold text** and *italic text*
- `Inline code` and code blocks
- [Links](https://example.com) and ![images](image.png)
- Lists and tables

### Architecture

The document follows a hierarchical structure with multiple heading levels.

## Installation

Follow these steps to get started:

### Prerequisites

Make sure you have the following installed:

1. Node.js (version 18 or higher)
2. npm package manager
3. A text editor

### Quick Install

```bash
npm install markdown-tree-parser
```

### Configuration

You can configure the parser with various options:

```javascript
const parser = new MarkdownTreeParser({
bullet: '-',
emphasis: '_'
});
```

## Usage Examples

Here are some common usage patterns.

### Basic Usage

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

const parser = new MarkdownTreeParser();
const tree = await parser.parse(markdown);
```

### Advanced Features

For more complex scenarios:

- Extract specific sections
- Search with CSS selectors
- Transform document structure
- Generate statistics

### CLI Usage

The package includes a powerful CLI:

```bash
md-tree list document.md
md-tree extract document.md "Installation"
```

## API Reference

### Core Methods

The main parser class provides these methods:

- `parse(markdown)` - Parse markdown to AST
- `stringify(tree)` - Convert AST to markdown
- `extractSection(tree, heading)` - Extract sections
- `selectAll(tree, selector)` - CSS-like search

### Utility Functions

Additional helper functions:

- `getHeadingsList(tree)` - List all headings
- `getStats(tree)` - Document statistics
- `generateTableOfContents(tree)` - Create TOC

## Testing

The package includes comprehensive tests:

```bash
npm test
npm run test:cli
```

### Test Coverage

- Unit tests for all core functions
- Integration tests for CLI commands
- End-to-end examples

## Contributing

We welcome contributions from the community!

### Getting Started

1. Fork the repository
2. Create a feature branch
3. Make your changes
4. Run the tests
5. Submit a pull request

### Code Standards

Please follow these guidelines:

- Use ESLint for code quality
- Write meaningful commit messages
- Include tests for new features
- Update documentation as needed

## Support

Need help? Here are your options:

### Documentation

- Check the README for basic usage
- Browse the examples directory
- Read the API documentation

### Community

- Open an issue on GitHub
- Join our discussions
- Check Stack Overflow

## License

This project is licensed under the MIT License.
This is a sample file for testing links.
Empty file removed test/test-email-links.md
Empty file.
8 changes: 8 additions & 0 deletions test/test-reference-links.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Test File for Reference-Style Links

This is a [link to Google][google].
Here is another [link to a local file][local-doc].
And an [undefined link][undefined].

[google]: https://www.google.com
[local-doc]: ./test-dummy-sample.md
96 changes: 96 additions & 0 deletions test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
*/

import { MarkdownTreeParser, createParser, extractSection } from '../index.js';
import { MarkdownCLI } from '../bin/md-tree.js'; // Added for checkLinks test
import fs from 'node:fs/promises';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
Expand Down Expand Up @@ -583,6 +584,101 @@ Plain text with email@domain.com should not be a link.
);
});

// Test suite for checkLinks
await test('Check Links Functionality', async () => {
const cli = new MarkdownCLI();
const testReferenceLinksFile = path.join(
__dirname,
'test-reference-links.md'
);
const testDummySampleFilePath = path.join(
__dirname,
'test-dummy-sample.md'
);

// Create a unique dummy file for local link checking to pass
await fs.writeFile(
testDummySampleFilePath,
'# Test Dummy Sample File\n\nThis is a test dummy file for testing links.'
);

await test('Check reference-style links', async () => {
const markdownContent = await fs.readFile(
testReferenceLinksFile,
'utf-8'
);
const tree = await cli.parser.parse(markdownContent);
const links = cli.parser.selectAll(tree, 'link');
const definitions = cli.parser.selectAll(tree, 'definition');

const collectedUrls = new Set();
for (const link of links) {
if (link.url) collectedUrls.add(link.url);
}
for (const def of definitions) {
if (def.url) collectedUrls.add(def.url);
}

assert(
collectedUrls.has('https://www.google.com'),
'Should find Google link from definition'
);
assert(
collectedUrls.has('./test-dummy-sample.md'),
'Should find local-doc link from definition'
);
assert(
!collectedUrls.has('[undefined]'),
'Should not treat undefined reference as a URL'
);
// The following assertions were removed because selectAll(tree, 'link') for reference-style links
// correctly returns linkReference nodes which do not have the 'url' property populated directly.
// The url is resolved by checkLinks by looking at 'definition' nodes,
// which is already tested by the collectedUrls assertions and the checkLinks output assertions.
// assert(links.some(link => link.reference === 'google' && link.url === 'https://www.google.com'), 'Link object for google should have url');
// assert(links.some(link => link.reference === 'local-doc' && link.url === './sample.md'), 'Link object for local-doc should have url');

// Test the checkLinks output
const originalConsoleLog = console.log;
const logs = [];
console.log = (...args) => {
logs.push(args.join(' '));
};

try {
await cli.checkLinks(testReferenceLinksFile);
} finally {
console.log = originalConsoleLog;
// Clean up test dummy file
try {
await fs.unlink(testDummySampleFilePath);
} catch (error) {
// Ignore cleanup errors - file might not exist
console.warn(
`Warning: Could not clean up ${testDummySampleFilePath}:`,
error.message
);
}
}

const output = logs.join('\n');
assert(
output.includes('🔗 Checking 2 unique URLs'),
'Should check 2 unique URLs'
);
assert(
output.includes('✅ https://www.google.com'),
'Should successfully check Google link'
);
// Note: The actual local file path in output might be resolved.
// We check for the original URL './test-dummy-sample.md' and the "✅" status.
assert(
output.includes('✅ ./test-dummy-sample.md'),
'Should successfully check local test dummy sample file link'
);
});
});

// Summary
console.log(`\n📊 Test Results: ${passedTests}/${testCount} passed`);

Expand Down