@@ -470,6 +470,11 @@ export function parseCalendarListItem(attrs: string, body: string): CalendarEven
470470// HTML extraction helpers
471471// ---------------------------------------------------------------------------
472472
473+ /** Escape a string for safe use in a `new RegExp(...)` constructor. */
474+ function escapeRegex ( s : string ) : string {
475+ return s . replace ( / [ . * + ? ^ $ { } ( ) | [ \] \\ ] / g, '\\$&' ) ;
476+ }
477+
473478/** Extract the `datetime` attribute from a `<time>` element. */
474479function extractDatetime ( html : string ) : string | null {
475480 const m = html . match ( / < t i m e \b [ ^ > ] * \b d a t e t i m e = ( [ " ' ] ) ( .* ?) \1/ i) ;
@@ -478,7 +483,7 @@ function extractDatetime(html: string): string | null {
478483
479484/** Extract a `data-{attr}` attribute value from a tag's attribute string. */
480485function extractDataAttr ( attrs : string , name : string ) : string | null {
481- const re = new RegExp ( `\\bdata-${ name } \\s*=\\s*(["'])(.*?)\\1` , 'i' ) ;
486+ const re = new RegExp ( `\\bdata-${ escapeRegex ( name ) } \\s*=\\s*(["'])(.*?)\\1` , 'i' ) ;
482487 const m = attrs . match ( re ) ;
483488 return m && m [ 2 ] ?. trim ( ) ? m [ 2 ] . trim ( ) : null ;
484489}
@@ -494,8 +499,9 @@ function hasCalendarItemClass(attrs: string): boolean {
494499 * Uses a simple, non-greedy regex that covers the common markup pattern.
495500 */
496501function extractSpanText ( html : string , name : string ) : string | null {
502+ const safe = escapeRegex ( name ) ;
497503 const re = new RegExp (
498- `<span\\b[^>]*\\bclass\\s*=\\s*(["'])[^"']*${ name } [^"']*\\1[^>]*>([\\s\\S]*?)<\\/span>` ,
504+ `<span\\b[^>]*\\bclass\\s*=\\s*(["'])[^"']*${ safe } [^"']*\\1[^>]*>([\\s\\S]*?)<\\/span>` ,
499505 'i' ,
500506 ) ;
501507 const m = html . match ( re ) ;
0 commit comments