@@ -149,13 +149,24 @@ export class AnkiTemplateRenderer {
149149 }
150150
151151 /**
152+ * Marks a string as safe and not necessary to escape by handlebars.
153+ *
154+ * https://handlebarsjs.com/api-reference/utilities.html#handlebars-safestring-string
152155 * @param {string } text
153156 * @returns {string }
154157 */
155158 _safeString ( text ) {
156159 return new Handlebars . SafeString ( text ) ;
157160 }
158161
162+ /**
163+ * @param {string } text
164+ * @returns {string }
165+ */
166+ _escapeExpression ( text ) {
167+ return text . replaceAll ( '<' , '<' ) . replaceAll ( '>' , '>' ) ;
168+ }
169+
159170 // Template helpers
160171
161172 /** @type {import('template-renderer').HelperFunction<string> } */
@@ -721,12 +732,12 @@ export class AnkiTemplateRenderer {
721732 _formatGlossary ( args , _context , options ) {
722733 const [ dictionary , content ] = /** @type {[dictionary: string, content: import('dictionary-data').TermGlossaryContent] } */ ( args ) ;
723734 const data = this . _getNoteDataFromOptions ( options ) ;
724- if ( typeof content === 'string' ) { return this . _safeString ( this . _stringToMultiLineHtml ( content ) ) ; }
735+ if ( typeof content === 'string' ) { return this . _safeString ( this . _stringToMultiLineHtml ( this . _escapeExpression ( content ) ) ) ; }
725736 if ( ! ( typeof content === 'object' && content !== null ) ) { return '' ; }
726737 switch ( content . type ) {
727738 case 'image' : return this . _formatGlossaryImage ( content , dictionary , data ) ;
728739 case 'structured-content' : return this . _formatStructuredContent ( content , dictionary , data ) ;
729- case 'text' : return this . _safeString ( this . _stringToMultiLineHtml ( content . text ) ) ;
740+ case 'text' : return this . _safeString ( this . _stringToMultiLineHtml ( this . _escapeExpression ( content . text ) ) ) ;
730741 }
731742 return '' ;
732743 }
@@ -761,7 +772,7 @@ export class AnkiTemplateRenderer {
761772 _formatGlossaryPlain ( args , _context , options ) {
762773 const [ dictionary , content ] = /** @type {[dictionary: string, content: import('dictionary-data').TermGlossaryContent] } */ ( args ) ;
763774 const data = this . _getNoteDataFromOptions ( options ) ;
764- if ( typeof content === 'string' ) { return this . _safeString ( content ) ; }
775+ if ( typeof content === 'string' ) { return this . _safeString ( this . _escapeExpression ( content ) ) ; }
765776 if ( ! ( typeof content === 'object' && content !== null ) ) { return '' ; }
766777 const structuredContentGenerator = this . _createStructuredContentGenerator ( data ) ;
767778 switch ( content . type ) {
@@ -775,7 +786,7 @@ export class AnkiTemplateRenderer {
775786 return node !== null ? this . _getStructuredContentText ( node ) : '' ;
776787 }
777788 }
778- case 'text' : return this . _safeString ( content . text ) ;
789+ case 'text' : return this . _safeString ( this . _escapeExpression ( content . text ) ) ;
779790 }
780791 return '' ;
781792 }
0 commit comments