markdown-it-admon-collapsible 1.9.4 → 1.9.5

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.
Files changed (4) hide show
  1. package/CHANGELOG.md +14 -7
  2. package/README.md +24 -13
  3. package/index.js +115 -105
  4. package/package.json +5 -2
package/CHANGELOG.md CHANGED
@@ -1,10 +1,18 @@
1
1
  # Changelog
2
2
 
3
- ## 1.9.2
3
+ ## 1.9.5
4
4
 
5
- 2025-12-26
5
+ 2026-01-01
6
6
 
7
- - forked from markdown-it-admon
7
+ - Made validation customizable
8
+ - General cleanup and added markdownlint
9
+
10
+ ## 1.9.4
11
+
12
+ 2025-12-27
13
+
14
+ - Reverted since the previous change was a misunderstanding
15
+ - Using details/summary for collapsible admonitions
8
16
 
9
17
  ## 1.9.3
10
18
 
@@ -12,9 +20,8 @@
12
20
 
13
21
  - Changed the generated HTML to be more like markdown-it-container
14
22
 
15
- ## 1.9.4
23
+ ## 1.9.2
16
24
 
17
- 2025-12-27
25
+ 2025-12-26
18
26
 
19
- - Reverted since the previous change was a misunderstanding
20
- - Using details/summary for collapsible admonitions
27
+ - forked from markdown-it-admon
package/README.md CHANGED
@@ -1,7 +1,6 @@
1
1
  # markdown-it-admon-collapsible
2
2
 
3
3
  > **Note:** This package is a fork of [markdown-it-admon](https://github.com/commenthol/markdown-it-admon) with added support for collapsible blocks (???), inspired by Material for MkDocs.
4
-
5
4
  > Plugin for creating admonitions for [markdown-it](https://github.com/markdown-it/markdown-it) markdown parser.
6
5
 
7
6
  With this plugin you can have collapsible admonitions:
@@ -31,7 +30,7 @@ Markdown syntax is inspired by [Material for MkDocs](https://squidfunk.github.io
31
30
 
32
31
  A styles file does support the following admonition types: Credits go to [vscode-markdown-extended][].
33
32
 
34
- ```
33
+ ```text
35
34
  'note',
36
35
  'summary', 'abstract', 'tldr',
37
36
  'info', 'todo',
@@ -45,17 +44,16 @@ A styles file does support the following admonition types: Credits go to [vscode
45
44
  'quote', 'cite'
46
45
  ```
47
46
 
48
- ![](./docs/admonition-types.png)
47
+ ![Admonition types](./docs/admonition-types.png)
49
48
 
50
49
  ## Installation
51
50
 
52
51
  node.js:
53
52
 
54
53
  ```bash
55
- $ npm install markdown-it-admon-collapsible --save
54
+ npm install markdown-it-admon-collapsible --save
56
55
  ```
57
56
 
58
-
59
57
  ## API
60
58
 
61
59
  ```js
@@ -63,11 +61,24 @@ const md = require('markdown-it')()
63
61
  .use(require('markdown-it-admon-collapsible') [, options]);
64
62
  ```
65
63
 
66
- Params:
64
+ Plugin Options
65
+
66
+ - `render`: (optional) Custom render function.
67
+ - `validate`: (optional) Custom validation function. If provided, this function will be used to validate the parameters for admonitions.
67
68
 
68
- - __name__ - container name (mandatory)
69
- - __options?:__
70
- - __render__ - optional, renderer function for opening/closing tokens.
69
+ ### Example usage
70
+
71
+ ```js
72
+ const md = require('markdown-it')();
73
+ const admonitionPlugin = require('markdown-it-admon-collapsible');
74
+
75
+ md.use(admonitionPlugin, {
76
+ validate: function(params) {
77
+ // Custom validation logic
78
+ return params.startsWith('note');
79
+ }
80
+ });
81
+ ```
71
82
 
72
83
  ## License
73
84
 
@@ -75,7 +86,7 @@ Params:
75
86
 
76
87
  ## References
77
88
 
78
- * [Material for MkDocs](https://squidfunk.github.io/mkdocs-material/reference/admonitions/)
79
- * [vscode-markdown-extended][vscode-markdown-extended]
80
- * [rST]: https://docutils.sourceforge.io/docs/ref/rst/directives.html#specific-admonitions
81
- * [vscode-markdown-extended]: https://github.com/qjebbs/vscode-markdown-extended
89
+ - [Material for MkDocs](https://squidfunk.github.io/mkdocs-material/reference/admonitions/)
90
+ - [vscode-markdown-extended][vscode-markdown-extended]
91
+ - [rST]: https://docutils.sourceforge.io/docs/ref/rst/directives.html#specific-admonitions
92
+ - [vscode-markdown-extended]: https://github.com/qjebbs/vscode-markdown-extended
package/index.js CHANGED
@@ -25,18 +25,18 @@ function getTag (params) {
25
25
  return {}
26
26
  }
27
27
 
28
- const joined = _title.join(' ');
29
- let title;
28
+ const joined = _title.join(' ')
29
+ let title
30
30
  if (!joined) {
31
- title = capitalize(tag);
31
+ title = capitalize(tag)
32
32
  } else if (joined === '""') {
33
- title = '';
33
+ title = ''
34
34
  } else if ((joined.startsWith('"') && joined.endsWith('"')) || (joined.startsWith("'") && joined.endsWith("'"))) {
35
- title = joined.slice(1, -1);
35
+ title = joined.slice(1, -1)
36
36
  } else {
37
- title = joined;
37
+ title = joined
38
38
  }
39
- return { tag: tag.toLowerCase(), title };
39
+ return { tag: tag.toLowerCase(), title }
40
40
  }
41
41
 
42
42
  function validate (params) {
@@ -44,171 +44,181 @@ function validate (params) {
44
44
  return !!tag
45
45
  }
46
46
 
47
- function renderDefault(tokens, idx, _options, env, slf) {
48
- return slf.renderToken(tokens, idx, _options, env, slf);
47
+ function renderDefault (tokens, idx, _options, env, slf) {
48
+ return slf.renderToken(tokens, idx, _options, env, slf)
49
49
  }
50
50
 
51
- function renderCollapsibleContentOpen(tokens, idx) {
52
- return '';
51
+ function renderCollapsibleContentOpen (tokens, idx) {
52
+ return ''
53
53
  }
54
54
 
55
- function renderCollapsibleContentClose() {
56
- return '';
55
+ function renderCollapsibleContentClose () {
56
+ return ''
57
57
  }
58
58
 
59
- const minMarkers = 3;
59
+ const minMarkers = 3
60
60
  const markerTypes = [
61
61
  { str: '!', type: 'admonition' },
62
62
  { str: '?', type: 'collapsible' }
63
- ];
63
+ ]
64
64
 
65
- function admonition(state, startLine, endLine, silent) {
66
- let pos, nextLine, token;
67
- const start = state.bMarks[startLine] + state.tShift[startLine];
68
- let max = state.eMarks[startLine];
65
+ function admonition (state, startLine, endLine, silent) {
66
+ let pos, nextLine, token
67
+ const start = state.bMarks[startLine] + state.tShift[startLine]
68
+ let max = state.eMarks[startLine]
69
69
 
70
70
  // Determine marker type
71
- let markerType = null;
71
+ let markerType = null
72
72
  for (const type of markerTypes) {
73
73
  if (state.src.substr(start, type.str.length) === type.str.repeat(type.str.length)) {
74
- markerType = type;
75
- break;
74
+ markerType = type
75
+ break
76
76
  }
77
77
  }
78
- if (!markerType) return false;
78
+ if (!markerType) return false
79
79
 
80
- const markerStr = markerType.str;
81
- const markerLen = markerStr.length;
80
+ const markerStr = markerType.str
81
+ const markerLen = markerStr.length
82
82
 
83
83
  // Check out the rest of the marker string
84
84
  for (pos = start + 1; pos <= max; pos++) {
85
85
  if (markerStr[(pos - start) % markerLen] !== state.src[pos]) {
86
- break;
86
+ break
87
87
  }
88
88
  }
89
89
 
90
- const markerCount = Math.floor((pos - start) / markerLen);
91
- if (markerCount < minMarkers) return false;
92
- const markerPos = pos - ((pos - start) % markerLen);
93
- let params = state.src.slice(markerPos, max);
94
- let markup = state.src.slice(start, markerPos);
90
+ const markerCount = Math.floor((pos - start) / markerLen)
91
+ if (markerCount < minMarkers) return false
92
+ const markerPos = pos - ((pos - start) % markerLen)
93
+ let params = state.src.slice(markerPos, max)
94
+ let markup = state.src.slice(start, markerPos)
95
95
 
96
96
  // Collapsible: check for plus sign
97
- let isCollapsible = markerType.type === 'collapsible';
98
- let expanded = false;
97
+ const isCollapsible = markerType.type === 'collapsible'
98
+ let expanded = false
99
99
  if (isCollapsible && params.trim().startsWith('+')) {
100
- expanded = true;
101
- params = params.trim().slice(1).trim();
102
- markup += '+';
100
+ expanded = true
101
+ params = params.trim().slice(1).trim()
102
+ markup += '+'
103
103
  }
104
104
 
105
- if (!validate(params)) return false;
106
- if (silent) return true;
105
+ const validateFn = state.md.options && state.md.options.admonitionValidate
106
+ ? state.md.options.admonitionValidate
107
+ : validate
108
+ if (!validateFn(params)) return false
109
+ if (silent) return true
107
110
 
108
- const oldParent = state.parentType;
109
- const oldLineMax = state.lineMax;
110
- const oldIndent = state.blkIndent;
111
+ const oldParent = state.parentType
112
+ const oldLineMax = state.lineMax
113
+ const oldIndent = state.blkIndent
111
114
 
112
- let blkStart = pos;
115
+ let blkStart = pos
113
116
  for (; blkStart < max; blkStart += 1) {
114
- if (state.src[blkStart] !== ' ') break;
117
+ if (state.src[blkStart] !== ' ') break
115
118
  }
116
- state.parentType = 'admonition';
117
- state.blkIndent += blkStart - start;
119
+ state.parentType = 'admonition'
120
+ state.blkIndent += blkStart - start
118
121
 
119
- let wasEmpty = false;
120
- nextLine = startLine;
122
+ let wasEmpty = false
123
+ nextLine = startLine
121
124
  for (;;) {
122
- nextLine++;
123
- if (nextLine >= endLine) break;
124
- pos = state.bMarks[nextLine] + state.tShift[nextLine];
125
- max = state.eMarks[nextLine];
126
- const isEmpty = state.sCount[nextLine] < state.blkIndent;
127
- if (isEmpty && wasEmpty) break;
128
- wasEmpty = isEmpty;
129
- if (pos < max && state.sCount[nextLine] < state.blkIndent) break;
125
+ nextLine++
126
+ if (nextLine >= endLine) break
127
+ pos = state.bMarks[nextLine] + state.tShift[nextLine]
128
+ max = state.eMarks[nextLine]
129
+ const isEmpty = state.sCount[nextLine] < state.blkIndent
130
+ if (isEmpty && wasEmpty) break
131
+ wasEmpty = isEmpty
132
+ if (pos < max && state.sCount[nextLine] < state.blkIndent) break
130
133
  }
131
- state.lineMax = nextLine;
134
+ state.lineMax = nextLine
132
135
 
133
- const { tag, title } = getTag(params);
136
+ const { tag, title } = getTag(params)
134
137
 
135
138
  // Use different token for collapsible
136
- const openType = isCollapsible ? 'collapsible_open' : 'admonition_open';
137
- const closeType = isCollapsible ? 'collapsible_close' : 'admonition_close';
139
+ const openType = isCollapsible ? 'collapsible_open' : 'admonition_open'
140
+ const closeType = isCollapsible ? 'collapsible_close' : 'admonition_close'
138
141
 
139
142
  token = isCollapsible ? state.push(openType, 'details', 1) : state.push(openType, 'div', 1)
140
- token.markup = markup;
141
- token.block = true;
142
- token.attrs = [['class', `admonition ${tag}`]];
143
+ token.markup = markup
144
+ token.block = true
145
+ token.attrs = [['class', `admonition ${tag}`]]
143
146
  if (expanded) {
144
- token.attrs.push(['open', '']);
147
+ token.attrs.push(['open', ''])
145
148
  }
146
- token.meta = { tag, expanded };
147
- token.content = title;
148
- token.info = params;
149
- token.map = [startLine, nextLine];
149
+ token.meta = { tag, expanded }
150
+ token.content = title
151
+ token.info = params
152
+ token.map = [startLine, nextLine]
150
153
 
151
154
  if (title) {
152
- const titleMarkup = markup + ' ' + tag;
155
+ const titleMarkup = markup + ' ' + tag
153
156
  token = isCollapsible ? state.push('collapsible_title_open', 'summary', 1) : state.push('admonition_title_open', 'p', 1)
154
- token.markup = titleMarkup;
155
- token.attrs = [['class', 'admonition-title']];
156
- token.map = [startLine, startLine + 1];
157
+ token.markup = titleMarkup
158
+ token.attrs = [['class', 'admonition-title']]
159
+ token.map = [startLine, startLine + 1]
157
160
 
158
- token = state.push('inline', '', 0);
159
- token.content = title;
160
- token.map = [startLine, startLine + 1];
161
- token.children = [];
161
+ token = state.push('inline', '', 0)
162
+ token.content = title
163
+ token.map = [startLine, startLine + 1]
164
+ token.children = []
162
165
 
163
- token = isCollapsible ? state.push('collapsible_title_close', 'summary', -1) : state.push('admonition_title_close', 'p', -1);
164
- token.markup = titleMarkup;
166
+ token = isCollapsible ? state.push('collapsible_title_close', 'summary', -1) : state.push('admonition_title_close', 'p', -1)
167
+ token.markup = titleMarkup
165
168
  }
166
169
 
167
- state.md.block.tokenize(state, startLine + 1, nextLine);
170
+ state.md.block.tokenize(state, startLine + 1, nextLine)
168
171
 
169
- token = state.push(closeType, 'div', -1);
170
- token.markup = state.src.slice(start, pos);
171
- token.block = true;
172
+ token = state.push(closeType, 'div', -1)
173
+ token.markup = state.src.slice(start, pos)
174
+ token.block = true
172
175
 
173
- state.parentType = oldParent;
174
- state.lineMax = oldLineMax;
175
- state.blkIndent = oldIndent;
176
- state.line = nextLine;
176
+ state.parentType = oldParent
177
+ state.lineMax = oldLineMax
178
+ state.blkIndent = oldIndent
179
+ state.line = nextLine
177
180
 
178
- return true;
181
+ return true
179
182
  }
180
183
 
181
- module.exports = function admonitionPlugin(md, options = {}) {
182
- const render = options.render || renderDefault;
184
+ function admonitionPlugin (md, options = {}) {
185
+ const render = options.render || renderDefault
186
+
187
+ if (options.validate) {
188
+ md.options.admonitionValidate = options.validate
189
+ }
183
190
 
184
- md.renderer.rules.admonition_open = render;
185
- md.renderer.rules.admonition_close = render;
186
- md.renderer.rules.admonition_title_open = render;
187
- md.renderer.rules.admonition_title_close = render;
191
+ md.renderer.rules.admonition_open = render
192
+ md.renderer.rules.admonition_close = render
193
+ md.renderer.rules.admonition_title_open = render
194
+ md.renderer.rules.admonition_title_close = render
188
195
 
189
196
  // Collapsible rendering
190
197
  // Use default renderer for collapsible_open/close
191
- md.renderer.rules.collapsible_close = (tokens, idx) => '</details>\n';
198
+ md.renderer.rules.collapsible_close = (tokens, idx) => '</details>\n'
192
199
  // Use default renderer for collapsible_title_open/close
193
200
 
194
201
  // Wrap content in collapsible-content div
195
- const origBlockTokenize = md.block.tokenize;
196
- md.block.tokenize = function(state, startLine, endLine) {
202
+ const origBlockTokenize = md.block.tokenize
203
+ md.block.tokenize = function (state, startLine, endLine) {
197
204
  if (state.parentType === 'admonition' && state.tokens.length > 0) {
198
- const lastToken = state.tokens[state.tokens.length - 1];
205
+ const lastToken = state.tokens[state.tokens.length - 1]
199
206
  if (lastToken.type === 'collapsible_title_close') {
200
- state.tokens.push({ type: 'collapsible_content_open' });
201
- origBlockTokenize.call(this, state, startLine, endLine);
202
- state.tokens.push({ type: 'collapsible_content_close' });
203
- return;
207
+ state.tokens.push({ type: 'collapsible_content_open' })
208
+ origBlockTokenize.call(this, state, startLine, endLine)
209
+ state.tokens.push({ type: 'collapsible_content_close' })
210
+ return
204
211
  }
205
212
  }
206
- origBlockTokenize.call(this, state, startLine, endLine);
207
- };
208
- md.renderer.rules.collapsible_content_open = renderCollapsibleContentOpen;
209
- md.renderer.rules.collapsible_content_close = renderCollapsibleContentClose;
213
+ origBlockTokenize.call(this, state, startLine, endLine)
214
+ }
215
+ md.renderer.rules.collapsible_content_open = renderCollapsibleContentOpen
216
+ md.renderer.rules.collapsible_content_close = renderCollapsibleContentClose
210
217
 
211
218
  md.block.ruler.before('fence', 'admonition', admonition, {
212
219
  alt: ['paragraph', 'reference', 'blockquote', 'list']
213
- });
220
+ })
214
221
  }
222
+
223
+ admonitionPlugin.admonition = admonition
224
+ module.exports = admonitionPlugin
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "markdown-it-admon-collapsible",
3
- "version": "1.9.4",
3
+ "version": "1.9.5",
4
4
  "description": "Plugin to create admonitions for markdown-it markdown parser",
5
5
  "keywords": [
6
6
  "admonition",
@@ -37,7 +37,7 @@
37
37
  "scripts": {
38
38
  "clean": "git clean -fXd -e \\!node_modules -e \\!node_modules/**/*",
39
39
  "coverage": "npm run test && c8 report --reporter html",
40
- "lint": "eslint --fix .",
40
+ "lint": "eslint --fix . && markdownlint-cli2 **/*.md",
41
41
  "test": "c8 mocha",
42
42
  "build": "mkdir -p dist && node_modules/.bin/browserify ./ -s markdownitAdmonCollapsible > dist/markdown-it-admon-collapsible.js && terser dist/markdown-it-admon-collapsible.js -c -m > dist/markdown-it-admon-collapsible.min.js"
43
43
  },
@@ -51,6 +51,9 @@
51
51
  "eslint-plugin-promise": "^6.1.1",
52
52
  "markdown-it": "^14.0.0",
53
53
  "markdown-it-testgen": "~0.1.6",
54
+ "markdownlint": "^0.40.0",
55
+ "markdownlint-cli2": "^0.20.0",
56
+ "markdownlint-rule-numbered-headings-unique": "^1.0.7",
54
57
  "mocha": "^11.7.5",
55
58
  "rimraf": "^6.1.2",
56
59
  "terser": "^5.26.0"