@@ -166,6 +166,46 @@ describe('marked unit', () => {
166166 assert . strictEqual ( html , '<p>Not Underlined <u>Underlined</u> Not Underlined</p>\n' ) ;
167167 } ) ;
168168
169+ it ( 'should ignore em termination characters when emStrongMask hook is in place' , ( ) => {
170+ const underline = {
171+ name : 'underline' ,
172+ level : 'inline' ,
173+ start ( src ) { return src . indexOf ( '=' ) ; } ,
174+ tokenizer ( src ) {
175+ const rule = / ^ = ( [ ^ = ] + ) = / ;
176+ const match = rule . exec ( src ) ;
177+ if ( match ) {
178+ return {
179+ type : 'underline' ,
180+ raw : match [ 0 ] , // This is the text that you want your token to consume from the source
181+ text : match [ 1 ] . trim ( ) , // You can add additional properties to your tokens to pass along to the renderer
182+ } ;
183+ }
184+ } ,
185+ renderer ( token ) {
186+ return `<u>${ token . text } </u>` ;
187+ } ,
188+ } ;
189+ marked . use ( {
190+ hooks : {
191+ // Underline takes priority over emphasis in this example, to mask emphasis markers inside underline tags
192+ emStrongMask : ( src ) => src . replace ( / = ( [ ^ = ] + ) = / g, ( match ) => `[${ 'a' . repeat ( match . length - 2 ) } ]` ) ,
193+ } ,
194+ extensions : [ underline ] ,
195+ } ) ;
196+ const html = marked . parse ( '*Not Underlined =Underlined* with *asterisk= Not Underlined*' ) ;
197+ assert . strictEqual ( html , '<p><em>Not Underlined <u>Underlined* with *asterisk</u> Not Underlined</em></p>\n' ) ;
198+ } ) ;
199+
200+ it ( 'should combine multiple emStrongMask hooks' , ( ) => {
201+ const maskEqualSign = ( src ) => src . replace ( / = ( [ ^ = ] + ) = / g, ( match ) => `[${ 'a' . repeat ( match . length - 2 ) } ]` ) ;
202+ const maskDollarSign = ( src ) => src . replace ( / \$ ( [ ^ $ ] + ) \$ / g, ( match ) => `[${ 'b' . repeat ( match . length - 2 ) } ]` ) ;
203+ marked . use ( { hooks : { emStrongMask : maskEqualSign } } ) ;
204+ marked . use ( { hooks : { emStrongMask : maskDollarSign } } ) ;
205+ const html = marked . parse ( '*Before $dollar * dollar$ =equal * equal= after*' ) ;
206+ assert . strictEqual ( html , '<p><em>Before $dollar * dollar$ =equal * equal= after</em></p>\n' ) ;
207+ } ) ;
208+
169209 it ( 'should handle interacting block and inline extensions' , ( ) => {
170210 const descriptionlist = {
171211 name : 'descriptionList' ,
@@ -650,6 +690,38 @@ used extension2 walked</p>
650690 assert . throws ( ( ) => marked . parse ( 'test' , { async : false } ) ) ;
651691 } ) ;
652692
693+ it ( 'should ignore em termination characters when emStrongMask hook is in place in an async context' , async ( ) => {
694+ const underline = {
695+ name : 'underline' ,
696+ level : 'inline' ,
697+ start ( src ) { return src . indexOf ( '=' ) ; } ,
698+ tokenizer ( src ) {
699+ const rule = / ^ = ( [ ^ = ] + ) = / ;
700+ const match = rule . exec ( src ) ;
701+ if ( match ) {
702+ return {
703+ type : 'underline' ,
704+ raw : match [ 0 ] , // This is the text that you want your token to consume from the source
705+ text : match [ 1 ] . trim ( ) , // You can add additional properties to your tokens to pass along to the renderer
706+ } ;
707+ }
708+ } ,
709+ renderer ( token ) {
710+ return `<u>${ token . text } </u>` ;
711+ } ,
712+ } ;
713+ marked . use ( {
714+ hooks : {
715+ // Underline takes priority over emphasis in this example, to mask emphasis markers inside underline tags
716+ emStrongMask : ( src ) => src . replace ( / = ( [ ^ = ] + ) = / g, ( match ) => `[${ 'a' . repeat ( match . length - 2 ) } ]` ) ,
717+ } ,
718+ extensions : [ underline ] ,
719+ async : true ,
720+ } ) ;
721+ const html = await marked . parse ( '*Not Underlined =Underlined* with *asterisk= Not Underlined*' ) ;
722+ assert . strictEqual ( html , '<p><em>Not Underlined <u>Underlined* with *asterisk</u> Not Underlined</em></p>\n' ) ;
723+ } ) ;
724+
653725 it ( 'should allow deleting/editing tokens' , ( ) => {
654726 const styleTags = {
655727 extensions : [ {
0 commit comments