@@ -52,9 +52,20 @@ const plugin: Plugin = function plugin(
52
52
const options = normalizeOptions ( optionsInput ) ;
53
53
54
54
const keywords = Object . values ( options . keywords ) . map ( escapeRegExp ) . join ( '|' ) ;
55
+ const nestingChar = escapeRegExp ( options . tag . slice ( 0 , 1 ) ) ;
55
56
const tag = escapeRegExp ( options . tag ) ;
56
- const regex = new RegExp ( `${ tag } (${ keywords } )(?: *(.*))?\n` ) ;
57
- const escapeTag = new RegExp ( escapeRegExp ( `\\${ options . tag } ` ) , 'g' ) ;
57
+
58
+ // resolve th nesting level of an opening tag
59
+ // ::: -> 0, :::: -> 1, ::::: -> 2 ...
60
+ const nestingLevelRegex = new RegExp (
61
+ `^${ tag } (?<nestingLevel>${ nestingChar } *)` ,
62
+ ) ;
63
+
64
+ const regex = new RegExp ( `${ tag } ${ nestingChar } *(${ keywords } )(?: *(.*))?\n` ) ;
65
+ const escapeTag = new RegExp (
66
+ escapeRegExp ( `\\${ options . tag } ${ options . tag . slice ( 0 , 1 ) } *` ) ,
67
+ 'g' ,
68
+ ) ;
58
69
59
70
// The tokenizer is called on blocks to determine if there is an admonition
60
71
// present and create tags for it
@@ -77,6 +88,11 @@ const plugin: Plugin = function plugin(
77
88
] ;
78
89
const food = [ ] ;
79
90
const content = [ ] ;
91
+ // get the nesting level of the opening tag
92
+ const openingLevel =
93
+ nestingLevelRegex . exec ( opening ) ! . groups ! . nestingLevel ! . length ;
94
+ // used as a stack to keep track of nested admonitions
95
+ const nestingLevels : number [ ] = [ openingLevel ] ;
80
96
81
97
let newValue = value ;
82
98
// consume lines until a closing tag
@@ -88,12 +104,32 @@ const plugin: Plugin = function plugin(
88
104
next !== - 1 ? newValue . slice ( idx + 1 , next ) : newValue . slice ( idx + 1 ) ;
89
105
food . push ( line ) ;
90
106
newValue = newValue . slice ( idx + 1 ) ;
91
- // the closing tag is NOT part of the content
92
- if ( line . startsWith ( options . tag ) ) {
93
- break ;
107
+ const nesting = nestingLevelRegex . exec ( line ) ;
108
+ idx = newValue . indexOf ( NEWLINE ) ;
109
+ if ( ! nesting ) {
110
+ content . push ( line ) ;
111
+ continue ;
112
+ }
113
+ const tagLevel = nesting . groups ! . nestingLevel ! . length ;
114
+ // first level
115
+ if ( nestingLevels . length === 0 ) {
116
+ nestingLevels . push ( tagLevel ) ;
117
+ content . push ( line ) ;
118
+ continue ;
119
+ }
120
+ const currentLevel = nestingLevels [ nestingLevels . length - 1 ] ! ;
121
+ if ( tagLevel < currentLevel ) {
122
+ // entering a nested admonition block
123
+ nestingLevels . push ( tagLevel ) ;
124
+ } else if ( tagLevel === currentLevel ) {
125
+ // closing a nested admonition block
126
+ nestingLevels . pop ( ) ;
127
+ // the closing tag is NOT part of the content
128
+ if ( nestingLevels . length === 0 ) {
129
+ break ;
130
+ }
94
131
}
95
132
content . push ( line ) ;
96
- idx = newValue . indexOf ( NEWLINE ) ;
97
133
}
98
134
99
135
// consume the processed tag and replace escape sequences
0 commit comments