Skip to content

Commit 5ca2c62

Browse files
authored
Merge pull request #4 from ksylvan/0617-fix-checklinks
Handle reference-style links in checkLinks
2 parents ff82b60 + 0ddf637 commit 5ca2c62

File tree

6 files changed

+120
-156
lines changed

6 files changed

+120
-156
lines changed

bin/md-tree.js

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -385,13 +385,23 @@ For more information, visit: https://github.com/ksylvan/markdown-tree-parser
385385
const content = await this.readFile(resolvedPath);
386386
const tree = await this.parser.parse(content);
387387
const links = this.parser.selectAll(tree, 'link');
388+
const definitions = this.parser.selectAll(tree, 'definition');
389+
390+
const allUrls = [];
391+
for (const link of links) {
392+
allUrls.push(link.url);
393+
}
394+
for (const definition of definitions) {
395+
allUrls.push(definition.url);
396+
}
397+
398+
const uniqueUrls = new Set(allUrls);
388399

389400
console.log(
390-
`\n🔗 Checking ${links.length} links in ${path.basename(resolvedPath)}:`
401+
`\n🔗 Checking ${uniqueUrls.size} unique URLs in ${path.basename(resolvedPath)}:`
391402
);
392403

393-
for (const link of links) {
394-
const url = link.url;
404+
for (const url of uniqueUrls) {
395405
if (!url || url.startsWith('#')) {
396406
continue;
397407
}

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@kayvan/markdown-tree-parser",
3-
"version": "1.5.0",
3+
"version": "1.5.1",
44
"description": "A powerful JavaScript library and CLI tool for parsing and manipulating markdown files as tree structures using the remark/unified ecosystem",
55
"type": "module",
66
"main": "index.js",

test/sample.md

Lines changed: 2 additions & 152 deletions
Original file line numberDiff line numberDiff line change
@@ -1,153 +1,3 @@
1-
# Sample Document
1+
# Sample File
22

3-
This is a sample markdown document for testing the markdown-tree-parser package.
4-
5-
## Overview
6-
7-
This document demonstrates various markdown features and structures that can be parsed and manipulated.
8-
9-
### Key Features
10-
11-
- **Bold text** and *italic text*
12-
- `Inline code` and code blocks
13-
- [Links](https://example.com) and ![images](image.png)
14-
- Lists and tables
15-
16-
### Architecture
17-
18-
The document follows a hierarchical structure with multiple heading levels.
19-
20-
## Installation
21-
22-
Follow these steps to get started:
23-
24-
### Prerequisites
25-
26-
Make sure you have the following installed:
27-
28-
1. Node.js (version 18 or higher)
29-
2. npm package manager
30-
3. A text editor
31-
32-
### Quick Install
33-
34-
```bash
35-
npm install markdown-tree-parser
36-
```
37-
38-
### Configuration
39-
40-
You can configure the parser with various options:
41-
42-
```javascript
43-
const parser = new MarkdownTreeParser({
44-
bullet: '-',
45-
emphasis: '_'
46-
});
47-
```
48-
49-
## Usage Examples
50-
51-
Here are some common usage patterns.
52-
53-
### Basic Usage
54-
55-
```javascript
56-
import { MarkdownTreeParser } from 'markdown-tree-parser';
57-
58-
const parser = new MarkdownTreeParser();
59-
const tree = await parser.parse(markdown);
60-
```
61-
62-
### Advanced Features
63-
64-
For more complex scenarios:
65-
66-
- Extract specific sections
67-
- Search with CSS selectors
68-
- Transform document structure
69-
- Generate statistics
70-
71-
### CLI Usage
72-
73-
The package includes a powerful CLI:
74-
75-
```bash
76-
md-tree list document.md
77-
md-tree extract document.md "Installation"
78-
```
79-
80-
## API Reference
81-
82-
### Core Methods
83-
84-
The main parser class provides these methods:
85-
86-
- `parse(markdown)` - Parse markdown to AST
87-
- `stringify(tree)` - Convert AST to markdown
88-
- `extractSection(tree, heading)` - Extract sections
89-
- `selectAll(tree, selector)` - CSS-like search
90-
91-
### Utility Functions
92-
93-
Additional helper functions:
94-
95-
- `getHeadingsList(tree)` - List all headings
96-
- `getStats(tree)` - Document statistics
97-
- `generateTableOfContents(tree)` - Create TOC
98-
99-
## Testing
100-
101-
The package includes comprehensive tests:
102-
103-
```bash
104-
npm test
105-
npm run test:cli
106-
```
107-
108-
### Test Coverage
109-
110-
- Unit tests for all core functions
111-
- Integration tests for CLI commands
112-
- End-to-end examples
113-
114-
## Contributing
115-
116-
We welcome contributions from the community!
117-
118-
### Getting Started
119-
120-
1. Fork the repository
121-
2. Create a feature branch
122-
3. Make your changes
123-
4. Run the tests
124-
5. Submit a pull request
125-
126-
### Code Standards
127-
128-
Please follow these guidelines:
129-
130-
- Use ESLint for code quality
131-
- Write meaningful commit messages
132-
- Include tests for new features
133-
- Update documentation as needed
134-
135-
## Support
136-
137-
Need help? Here are your options:
138-
139-
### Documentation
140-
141-
- Check the README for basic usage
142-
- Browse the examples directory
143-
- Read the API documentation
144-
145-
### Community
146-
147-
- Open an issue on GitHub
148-
- Join our discussions
149-
- Check Stack Overflow
150-
151-
## License
152-
153-
This project is licensed under the MIT License.
3+
This is a sample file for testing links.

test/test-email-links.md

Whitespace-only changes.

test/test-reference-links.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Test File for Reference-Style Links
2+
3+
This is a [link to Google][google].
4+
Here is another [link to a local file][local-doc].
5+
And an [undefined link][undefined].
6+
7+
[google]: https://www.google.com
8+
[local-doc]: ./test-dummy-sample.md

test/test.js

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
*/
66

77
import { MarkdownTreeParser, createParser, extractSection } from '../index.js';
8+
import { MarkdownCLI } from '../bin/md-tree.js'; // Added for checkLinks test
89
import fs from 'node:fs/promises';
910
import path from 'node:path';
1011
import { fileURLToPath } from 'node:url';
@@ -583,6 +584,101 @@ Plain text with [email protected] should not be a link.
583584
);
584585
});
585586

587+
// Test suite for checkLinks
588+
await test('Check Links Functionality', async () => {
589+
const cli = new MarkdownCLI();
590+
const testReferenceLinksFile = path.join(
591+
__dirname,
592+
'test-reference-links.md'
593+
);
594+
const testDummySampleFilePath = path.join(
595+
__dirname,
596+
'test-dummy-sample.md'
597+
);
598+
599+
// Create a unique dummy file for local link checking to pass
600+
await fs.writeFile(
601+
testDummySampleFilePath,
602+
'# Test Dummy Sample File\n\nThis is a test dummy file for testing links.'
603+
);
604+
605+
await test('Check reference-style links', async () => {
606+
const markdownContent = await fs.readFile(
607+
testReferenceLinksFile,
608+
'utf-8'
609+
);
610+
const tree = await cli.parser.parse(markdownContent);
611+
const links = cli.parser.selectAll(tree, 'link');
612+
const definitions = cli.parser.selectAll(tree, 'definition');
613+
614+
const collectedUrls = new Set();
615+
for (const link of links) {
616+
if (link.url) collectedUrls.add(link.url);
617+
}
618+
for (const def of definitions) {
619+
if (def.url) collectedUrls.add(def.url);
620+
}
621+
622+
assert(
623+
collectedUrls.has('https://www.google.com'),
624+
'Should find Google link from definition'
625+
);
626+
assert(
627+
collectedUrls.has('./test-dummy-sample.md'),
628+
'Should find local-doc link from definition'
629+
);
630+
assert(
631+
!collectedUrls.has('[undefined]'),
632+
'Should not treat undefined reference as a URL'
633+
);
634+
// The following assertions were removed because selectAll(tree, 'link') for reference-style links
635+
// correctly returns linkReference nodes which do not have the 'url' property populated directly.
636+
// The url is resolved by checkLinks by looking at 'definition' nodes,
637+
// which is already tested by the collectedUrls assertions and the checkLinks output assertions.
638+
// assert(links.some(link => link.reference === 'google' && link.url === 'https://www.google.com'), 'Link object for google should have url');
639+
// assert(links.some(link => link.reference === 'local-doc' && link.url === './sample.md'), 'Link object for local-doc should have url');
640+
641+
// Test the checkLinks output
642+
const originalConsoleLog = console.log;
643+
const logs = [];
644+
console.log = (...args) => {
645+
logs.push(args.join(' '));
646+
};
647+
648+
try {
649+
await cli.checkLinks(testReferenceLinksFile);
650+
} finally {
651+
console.log = originalConsoleLog;
652+
// Clean up test dummy file
653+
try {
654+
await fs.unlink(testDummySampleFilePath);
655+
} catch (error) {
656+
// Ignore cleanup errors - file might not exist
657+
console.warn(
658+
`Warning: Could not clean up ${testDummySampleFilePath}:`,
659+
error.message
660+
);
661+
}
662+
}
663+
664+
const output = logs.join('\n');
665+
assert(
666+
output.includes('🔗 Checking 2 unique URLs'),
667+
'Should check 2 unique URLs'
668+
);
669+
assert(
670+
output.includes('✅ https://www.google.com'),
671+
'Should successfully check Google link'
672+
);
673+
// Note: The actual local file path in output might be resolved.
674+
// We check for the original URL './test-dummy-sample.md' and the "✅" status.
675+
assert(
676+
output.includes('✅ ./test-dummy-sample.md'),
677+
'Should successfully check local test dummy sample file link'
678+
);
679+
});
680+
});
681+
586682
// Summary
587683
console.log(`\n📊 Test Results: ${passedTests}/${testCount} passed`);
588684

0 commit comments

Comments
 (0)