1+ /**
2+ * Escapes # characters that are not valid Markdown headers to prevent
3+ * unintended Obsidian tags (e.g., #1337-YesSr becomes \#1337-YesSr)
4+ * while preserving valid Markdown headers (# followed by space)
5+ * @param text The text to process
6+ * @returns The text with escaped # characters
7+ */
8+ function escapeHashTags ( text : string ) : string {
9+ const lines = text . split ( '\n' ) ;
10+
11+ return lines . map ( line => {
12+ const trimmed = line . trim ( ) ;
13+
14+ // Check if this is a valid Markdown header (one or more # followed by a space)
15+ // Valid: "# Header", "## Header", "### Header", etc.
16+ // Invalid: "#1337", "#tag", "###NoSpace"
17+ if ( / ^ # { 1 , 6 } \s / . test ( trimmed ) ) {
18+ // This is a valid Markdown header, don't escape
19+ return line ;
20+ }
21+
22+ // Escape all # characters in this line
23+ return line . replace ( / # / g, '\\#' ) ;
24+ } ) . join ( '\n' ) ;
25+ }
26+
127/**
228 * Utility function for escaping content in different modes
329 * @param unsafe The string to escape
430 * @param mode The escaping mode: "disabled", "normal", "strict", or "veryStrict"
31+ * @param shouldEscapeHashTags Whether to apply context-sensitive # escaping
532 * @returns The escaped string
633 * @throws Error if input is null or undefined
734 *
1441export function escapeBody (
1542 unsafe : string ,
1643 mode : "disabled" | "normal" | "strict" | "veryStrict" = "normal" ,
44+ shouldEscapeHashTags : boolean = false ,
1745) : string {
46+ // Validate input
1847 if ( unsafe === null || unsafe === undefined ) {
1948 throw new Error ( "Input cannot be null or undefined" ) ;
2049 }
2150
51+ // No escaping in disabled mode
2252 if ( mode === "disabled" ) {
2353 return unsafe ;
2454 }
2555
26- if ( mode === "strict" ) {
27- // Allow Unicode characters, whitespace, common punctuation, and URL/Markdown specific characters
28- // Remove potentially dangerous characters while preserving Chinese and other Unicode characters
29- return unsafe
30- . replace ( / [ < > { } $ ` \\ ] / g, "" ) // Remove potentially dangerous HTML/JS/template characters
31- . replace ( / - - - / g, "- - -" ) ; // Escape YAML frontmatter separators
32- }
56+ // Apply mode-specific escaping
57+ let escaped : string ;
58+
59+ switch ( mode ) {
60+ case "strict" :
61+ // Allow Unicode characters, whitespace, common punctuation, and URL/Markdown specific characters
62+ // Remove potentially dangerous characters while preserving Chinese and other Unicode characters
63+ escaped = unsafe
64+ . replace ( / [ < > { } $ ` \\ ] / g, "" ) // Remove potentially dangerous HTML/JS/template characters
65+ . replace ( / - - - / g, "- - -" ) ; // Escape YAML frontmatter separators
66+ break ;
67+
68+ case "veryStrict" :
69+ // Allow Unicode characters, whitespace, basic punctuation, and essential URL/Markdown characters
70+ // More restrictive than strict mode but still preserves Chinese and other Unicode characters
71+ escaped = unsafe
72+ . replace ( / [ < > { } $ ` \\ " ' | & * ~ ^ ] / g, "" ) // Remove more potentially dangerous characters
73+ . replace ( / - - - / g, "- - -" ) ; // Escape YAML frontmatter separators
74+ break ;
3375
34- if ( mode === "veryStrict" ) {
35- // Allow Unicode characters, whitespace, basic punctuation, and essential URL/Markdown characters
36- // More restrictive than strict mode but still preserves Chinese and other Unicode characters
37- return unsafe
38- . replace ( / [ < > { } $ ` \\ " ' | & * ~ ^ ] / g, "" ) // Remove more potentially dangerous characters
39- . replace ( / - - - / g, "- - -" ) ; // Escape YAML frontmatter separators
76+ case "normal" :
77+ default :
78+ // Basic escaping for Templater and Dataview compatibility
79+ escaped = unsafe
80+ . replace ( / < % / g, "'<<'" ) // Templater tags
81+ . replace ( / % > / g, "'>>'" ) // Templater tags
82+ . replace ( / ` / g, '"' ) // Backticks (can interfere with Dataview)
83+ . replace ( / - - - / g, "- - -" ) // YAML frontmatter separators
84+ . replace ( / { { / g, "((" ) // Templater/Dataview variables
85+ . replace ( / } } / g, "))" ) ; // Templater/Dataview variables
86+ break ;
4087 }
4188
42- // normal mode
43- return unsafe
44- . replace ( / < % / g, "'<<'" )
45- . replace ( / % > / g, "'>>'" )
46- . replace ( / ` / g, '"' )
47- . replace ( / - - - / g, "- - -" )
48- . replace ( / { { / g, "((" )
49- . replace ( / } } / g, "))" ) ;
89+ // Apply context-sensitive # escaping if enabled
90+ return shouldEscapeHashTags ? escapeHashTags ( escaped ) : escaped ;
5091}
5192
5293/**
@@ -56,5 +97,7 @@ export function escapeBody(
5697 */
5798export function escapeYamlString ( str : string ) : string {
5899 // In YAML double-quoted strings, we need to escape backslashes and double quotes
59- return str . replace ( / \\ / g, '\\\\' ) . replace ( / " / g, '\\"' ) ;
100+ return str
101+ . replace ( / \\ / g, '\\\\' ) // Escape backslashes first
102+ . replace ( / " / g, '\\"' ) ; // Then escape double quotes
60103}
0 commit comments