@@ -38,7 +38,7 @@ import type { SafeString as GlimmerSafeString } from '@glimmer/runtime';
3838 @public
3939 */
4040export class SafeString implements GlimmerSafeString {
41- private __string : string ;
41+ private readonly __string : string ;
4242
4343 constructor ( string : string ) {
4444 this . __string = string ;
@@ -67,57 +67,6 @@ export class SafeString implements GlimmerSafeString {
6767 }
6868}
6969
70- const escape = {
71- '&' : '&' ,
72- '<' : '<' ,
73- '>' : '>' ,
74- '"' : '"' ,
75- "'" : ''' ,
76- '`' : '`' ,
77- '=' : '=' ,
78- } ;
79-
80- const possible = / [ & < > " ' ` = ] / ;
81- const badChars = / [ & < > " ' ` = ] / g;
82-
83- function escapeChar ( chr : keyof typeof escape ) {
84- return escape [ chr ] ;
85- }
86-
87- export function escapeExpression ( string : unknown ) : string {
88- let s : string ;
89- if ( typeof string !== 'string' ) {
90- // don't escape SafeStrings, since they're already safe
91- if ( isHTMLSafe ( string ) ) {
92- return string . toHTML ( ) ;
93- } else if ( string === null || string === undefined ) {
94- return '' ;
95- } else if ( ! string ) {
96- return String ( string ) ;
97- }
98-
99- // Force a string conversion as this will be done by the append regardless and
100- // the regex test will do this transparently behind the scenes, causing issues if
101- // an object's to string has escaped characters in it.
102- s = String ( string ) ;
103- } else {
104- s = string ;
105- }
106-
107- if ( ! possible . test ( s ) ) {
108- return s ;
109- }
110-
111- // SAFETY: this is technically a lie, but it's a true lie as long as the
112- // invariant it depends on is upheld: `escapeChar` will always return a string
113- // as long as its input is one of the characters in `escape`, and it will only
114- // be called if it matches one of the characters in the `badChar` regex, which
115- // is hand-maintained to match the set escaped. (It would be nice if TS could
116- // "see" into the regex to see how this works, but that'd be quite a lot of
117- // extra fanciness.)
118- return s . replace ( badChars , escapeChar as ( s : string ) => string ) ;
119- }
120-
12170/**
12271 Use this method to indicate that a string should be rendered as HTML
12372 when the string is used in a template. To say this another way,
@@ -177,6 +126,10 @@ export function htmlSafe(str: string): SafeString {
177126*/
178127export function isHTMLSafe ( str : unknown ) : str is SafeString {
179128 return (
180- str !== null && typeof str === 'object' && 'toHTML' in str && typeof str . toHTML === 'function'
129+ // SAFETY: cast `as SafeString` only present to make this check "legal"; we
130+ // can further improve this by changing the behavior to do an `in` check
131+ // instead, but that's worth landing as a separate change for bisecting if
132+ // it happens to have an impact on e.g. perf.
133+ str !== null && typeof str === 'object' && typeof ( str as SafeString ) . toHTML === 'function'
181134 ) ;
182135}
0 commit comments