remove-markdown 0.6.2 → 0.6.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,8 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "mcp__acp__Bash",
5
+ "mcp__acp__Write"
6
+ ]
7
+ }
8
+ }
@@ -12,7 +12,7 @@ jobs:
12
12
 
13
13
  strategy:
14
14
  matrix:
15
- node-version: [14.x, 16.x, 18.x]
15
+ node-version: [18.x, 20.x, 22.x]
16
16
  # See supported Node.js release schedule at https://nodejs.org/en/about/releases/
17
17
 
18
18
  steps:
package/CHANGELOG.md ADDED
@@ -0,0 +1,32 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ ## [0.6.3] - 2026-01-14
6
+
7
+ ### Added
8
+
9
+ - New `separateLinksAndTexts` option to replace inline links with text and URL separated by a custom string ([#101](https://github.com/zuchka/remove-markdown/pull/101) by [@tafel](https://github.com/tafel))
10
+ - Example: `removeMd('[link](http://example.com)', { separateLinksAndTexts: ': ' })` returns `'link: http://example.com'`
11
+
12
+ ## [0.6.2] - 2025-05-02
13
+
14
+ ### Fixed
15
+
16
+ - Improved handling of links with square brackets inside them ([#93](https://github.com/zuchka/remove-markdown/pull/93))
17
+
18
+ ## [0.6.1] - 2025-05-02
19
+
20
+ ### Improved
21
+
22
+ - Better support for multiline code blocks ([#96](https://github.com/zuchka/remove-markdown/pull/96) by [@johnjiang](https://github.com/johnjiang))
23
+
24
+ ## [0.6.0] - 2024-12-16
25
+
26
+ ### Added
27
+
28
+ - `htmlTagsToSkip` option to preserve specific HTML tags while stripping others ([#88](https://github.com/zuchka/remove-markdown/pull/88))
29
+
30
+ ### Fixed
31
+
32
+ - Horizontal rules regex pattern ([#91](https://github.com/zuchka/remove-markdown/pull/91))
package/CLAUDE.md ADDED
@@ -0,0 +1,70 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+ ## Project Overview
6
+
7
+ **remove-markdown** is a Node.js module that strips Markdown formatting from text, leaving only plain text. It's designed for use cases like displaying excerpts without Markdown syntax.
8
+
9
+ The entire implementation is a single-file module (`index.js`) that exports one function which applies a series of regex replacements to remove various Markdown elements.
10
+
11
+ ## Development Commands
12
+
13
+ ### Running Tests
14
+ ```bash
15
+ npm test
16
+ ```
17
+ Runs the Mocha test suite with the spec reporter.
18
+
19
+ ### Running a Single Test
20
+ To run a specific test, use Mocha's grep flag:
21
+ ```bash
22
+ ./node_modules/.bin/mocha -R spec test/remove-markdown.js --grep "test description pattern"
23
+ ```
24
+
25
+ ## Code Architecture
26
+
27
+ ### Core Structure
28
+ - **index.js** (97 lines): Main module that exports a single function
29
+ - Takes markdown text and an options object as parameters
30
+ - Applies regex replacements in a specific order to strip Markdown syntax
31
+ - Returns plain text or original input if error occurs (unless `throwError` option is set)
32
+
33
+ ### Key Implementation Details
34
+
35
+ **Regex Application Order Matters**: The order of regex replacements is critical. For example, horizontal rules must be removed before list leaders to avoid conflicts (see index.js:15).
36
+
37
+ **Options System**: All options default to specific values if not provided. The module uses `options.hasOwnProperty()` checks rather than simple truthy checks to allow `false` values to be explicitly set.
38
+
39
+ **Error Handling**: The entire regex processing is wrapped in try-catch. By default, errors are logged and the original markdown is returned. Set `options.throwError: true` to propagate errors.
40
+
41
+ **HTML Tag Filtering**: The `htmlTagsToSkip` option dynamically builds a regex to preserve specific HTML tags while removing others (see index.js:41-49).
42
+
43
+ **Link Replacement**: Two mutually exclusive link handling modes:
44
+ - `replaceLinksWithURL: true` - replaces links with URLs (note: implementation at index.js:66 references `$2` which appears to be a bug as it should extract the URL)
45
+ - `separateLinksAndTexts` - replaces `[text](url)` with `text<separator>url` format (applied first at index.js:52)
46
+
47
+ ### Test Structure
48
+ - **test/remove-markdown.js** (258 lines): Comprehensive test suite using Mocha and Chai
49
+ - Tests cover all markdown elements: headers, emphasis, lists, links, images, code blocks, blockquotes, HTML tags
50
+ - Includes performance tests to prevent ReDoS vulnerabilities
51
+ - Tests edge cases like emphasis with spaces, nested brackets, indentation
52
+
53
+ ## Important Considerations
54
+
55
+ ### When Adding Features
56
+ - New regex patterns must be carefully positioned in the replacement chain (index.js:18-89)
57
+ - Test edge cases thoroughly, especially patterns that could conflict with existing ones
58
+ - Consider performance implications - some patterns are vulnerable to ReDoS if not carefully written
59
+
60
+ ### Known Quirks
61
+ - The `replaceLinksWithURL` option appears to have a bug where it references `$2` but the capturing group setup may not work as intended (index.js:66)
62
+ - Empty or invalid markdown input is handled gracefully by returning the original input
63
+ - The module preserves code block content (including newlines) while stripping the fencing
64
+
65
+ ### Testing Strategy
66
+ When modifying regex patterns:
67
+ 1. Run the full test suite first
68
+ 2. Add specific test cases for your changes
69
+ 3. Test performance with large inputs and repeated patterns
70
+ 4. Verify your changes don't break the order-dependent behavior
package/README.md CHANGED
@@ -26,10 +26,14 @@ You can also supply an options object to the function. Currently, the following
26
26
 
27
27
  ```js
28
28
  const plainText = removeMd(markdown, {
29
- stripListLeaders: true , // strip list leaders (default: true)
30
- listUnicodeChar: '', // char to insert instead of stripped list leaders (default: '')
31
- gfm: true // support GitHub-Flavored Markdown (default: true)
32
- useImgAltText: true // replace images with alt-text, if present (default: true)
29
+ stripListLeaders: true , // strip list leaders (default: true)
30
+ listUnicodeChar: '', // char to insert instead of stripped list leaders (default: '')
31
+ gfm: true, // support GitHub-Flavored Markdown (default: true)
32
+ useImgAltText: true, // replace images with alt-text, if present (default: true)
33
+ abbr: true, // remove abbreviations, if present (default: false)
34
+ replaceLinksWithURL: true, // remove inline links, if present (default: false)
35
+ separateLinksAndTexts: ': ', // replace inline links with text, separator and link, if present (default: null)
36
+ htmlTagsToSkip: ['a', 'b'] // HTML tags to skip, if present (default: [])
33
37
  });
34
38
  ```
35
39
 
package/index.d.ts CHANGED
@@ -1,11 +1,12 @@
1
- declare function removeMd(md: string, options?: {
2
- stripListLeaders?: boolean;
3
- listUnicodeChar?: string;
4
- gfm?: boolean;
5
- useImgAltText: boolean;
6
- abbr?: boolean;
7
- replaceLinksWithURL?: boolean;
8
- htmlTagsToSkip?: string[];
9
- }): string;
10
-
11
- export = removeMd;
1
+ declare function removeMd(md: string, options?: {
2
+ stripListLeaders?: boolean;
3
+ listUnicodeChar?: string;
4
+ gfm?: boolean;
5
+ useImgAltText: boolean;
6
+ abbr?: boolean;
7
+ replaceLinksWithURL?: boolean;
8
+ separateLinksAndTexts?: string;
9
+ htmlTagsToSkip?: string[];
10
+ }): string;
11
+
12
+ export = removeMd;
package/index.js CHANGED
@@ -6,6 +6,7 @@ module.exports = function(md, options) {
6
6
  options.useImgAltText = options.hasOwnProperty('useImgAltText') ? options.useImgAltText : true;
7
7
  options.abbr = options.hasOwnProperty('abbr') ? options.abbr : false;
8
8
  options.replaceLinksWithURL = options.hasOwnProperty('replaceLinksWithURL') ? options.replaceLinksWithURL : false;
9
+ options.separateLinksAndTexts = options.hasOwnProperty('separateLinksAndTexts') ? options.separateLinksAndTexts : null;
9
10
  options.htmlTagsToSkip = options.hasOwnProperty('htmlTagsToSkip') ? options.htmlTagsToSkip : [];
10
11
  options.throwError = options.hasOwnProperty('throwError') ? options.throwError : false;
11
12
 
@@ -36,7 +37,7 @@ module.exports = function(md, options) {
36
37
  // Remove abbreviations
37
38
  output = output.replace(/\*\[.*\]:.*\n/, '');
38
39
  }
39
-
40
+
40
41
  let htmlReplaceRegex = /<[^>]*>/g
41
42
  if (options.htmlTagsToSkip && options.htmlTagsToSkip.length > 0) {
42
43
  // Create a regex that matches tags not in htmlTagsToSkip
@@ -47,6 +48,10 @@ module.exports = function(md, options) {
47
48
  )
48
49
  }
49
50
 
51
+ if (options.separateLinksAndTexts) {
52
+ output = output.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '$1' + options.separateLinksAndTexts + '$2');
53
+ }
54
+
50
55
  output = output
51
56
  // Remove HTML tags
52
57
  .replace(htmlReplaceRegex, '')
@@ -68,7 +73,7 @@ module.exports = function(md, options) {
68
73
  .replace(/^(\n)?\s{0,}#{1,6}\s*( (.+))? +#+$|^(\n)?\s{0,}#{1,6}\s*( (.+))?$/gm, '$1$3$4$6')
69
74
  // Remove * emphasis
70
75
  .replace(/([\*]+)(\S)(.*?\S)??\1/g, '$2$3')
71
- // Remove _ emphasis. Unlike *, _ emphasis gets rendered only if
76
+ // Remove _ emphasis. Unlike *, _ emphasis gets rendered only if
72
77
  // 1. Either there is a whitespace character before opening _ and after closing _.
73
78
  // 2. Or _ is at the start/end of the string.
74
79
  .replace(/(^|\W)([_]+)(\S)(.*?\S)??\2($|\W)/g, '$1$3$4$5')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "remove-markdown",
3
- "version": "0.6.2",
3
+ "version": "0.6.3",
4
4
  "description": "Remove Markdown formatting from text",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -62,13 +62,13 @@ describe('remove Markdown', function () {
62
62
  const expected = 'code';
63
63
  expect(removeMd(string)).to.equal(expected);
64
64
  });
65
-
65
+
66
66
  it('should strip complex multiline code blocks with language specified', function () {
67
67
  const string = '```javascript\nconst x = 1;\nconst y = 2;\nconsole.log(x + y);\n```';
68
68
  const expected = 'const x = 1;\nconst y = 2;\nconsole.log(x + y);';
69
69
  expect(removeMd(string)).to.equal(expected);
70
70
  });
71
-
71
+
72
72
  it('should strip multiline code blocks with multiple paragraphs', function () {
73
73
  const string = 'Text before\n\n```\ncode line 1\n\ncode line 2\n```\n\nText after';
74
74
  const expected = 'Text before\n\ncode line 1\n\ncode line 2\n\nText after';
@@ -145,7 +145,7 @@ describe('remove Markdown', function () {
145
145
  expect(removeMd(test.string)).to.equal(test.expected);
146
146
  });
147
147
  });
148
-
148
+
149
149
  it('should remove blockquotes over multiple lines', function () {
150
150
  const string = '> I am a blockquote firstline \n>I am a blockquote secondline';
151
151
  const expected = 'I am a blockquote firstline \nI am a blockquote secondline';
@@ -248,5 +248,11 @@ describe('remove Markdown', function () {
248
248
  'HTML content <sub>Superscript</sub> <span>span text</span>',
249
249
  )
250
250
  })
251
+
252
+ it('should replace inline link with text and link, with separator', function () {
253
+ const string = 'some [inline link](http://www.disney.com/).';
254
+ const expected = 'some inline link: http://www.disney.com/.';
255
+ expect(removeMd(string, {separateLinksAndTexts: ': '})).to.equal(expected);
256
+ });
251
257
  });
252
258
  });