diff --git a/packages/@ember/-internals/glimmer/index.ts b/packages/@ember/-internals/glimmer/index.ts index 68e3994fd26..5df74a25934 100644 --- a/packages/@ember/-internals/glimmer/index.ts +++ b/packages/@ember/-internals/glimmer/index.ts @@ -456,7 +456,7 @@ export { type FunctionBasedHelper, type FunctionBasedHelperInstance, } from './lib/helper'; -export { SafeString, escapeExpression, htmlSafe, isHTMLSafe } from './lib/utils/string'; +export { SafeString, htmlSafe, isHTMLSafe } from './lib/utils/string'; export { Renderer, _resetRenderers, renderSettled } from './lib/renderer'; export { getTemplate, diff --git a/packages/@ember/-internals/glimmer/lib/utils/string.ts b/packages/@ember/-internals/glimmer/lib/utils/string.ts index 63c35cffb28..ca2184c3940 100644 --- a/packages/@ember/-internals/glimmer/lib/utils/string.ts +++ b/packages/@ember/-internals/glimmer/lib/utils/string.ts @@ -38,7 +38,7 @@ import type { SafeString as GlimmerSafeString } from '@glimmer/runtime'; @public */ export class SafeString implements GlimmerSafeString { - private __string: string; + private readonly __string: string; constructor(string: string) { this.__string = string; @@ -67,57 +67,6 @@ export class SafeString implements GlimmerSafeString { } } -const escape = { - '&': '&', - '<': '<', - '>': '>', - '"': '"', - "'": ''', - '`': '`', - '=': '=', -}; - -const possible = /[&<>"'`=]/; -const badChars = /[&<>"'`=]/g; - -function escapeChar(chr: keyof typeof escape) { - return escape[chr]; -} - -export function escapeExpression(string: unknown): string { - let s: string; - if (typeof string !== 'string') { - // don't escape SafeStrings, since they're already safe - if (isHTMLSafe(string)) { - return string.toHTML(); - } else if (string === null || string === undefined) { - return ''; - } else if (!string) { - return String(string); - } - - // Force a string conversion as this will be done by the append regardless and - // the regex test will do this transparently behind the scenes, causing issues if - // an object's to string has escaped characters in it. - s = String(string); - } else { - s = string; - } - - if (!possible.test(s)) { - return s; - } - - // SAFETY: this is technically a lie, but it's a true lie as long as the - // invariant it depends on is upheld: `escapeChar` will always return a string - // as long as its input is one of the characters in `escape`, and it will only - // be called if it matches one of the characters in the `badChar` regex, which - // is hand-maintained to match the set escaped. (It would be nice if TS could - // "see" into the regex to see how this works, but that'd be quite a lot of - // extra fanciness.) - return s.replace(badChars, escapeChar as (s: string) => string); -} - /** Use this method to indicate that a string should be rendered as HTML when the string is used in a template. To say this another way, @@ -177,6 +126,10 @@ export function htmlSafe(str: string): SafeString { */ export function isHTMLSafe(str: unknown): str is SafeString { return ( - str !== null && typeof str === 'object' && 'toHTML' in str && typeof str.toHTML === 'function' + // SAFETY: cast `as SafeString` only present to make this check "legal"; we + // can further improve this by changing the behavior to do an `in` check + // instead, but that's worth landing as a separate change for bisecting if + // it happens to have an impact on e.g. perf. + str !== null && typeof str === 'object' && typeof (str as SafeString).toHTML === 'function' ); } diff --git a/packages/ember/index.ts b/packages/ember/index.ts index 89436fd3743..f9c8b6b8ebe 100644 --- a/packages/ember/index.ts +++ b/packages/ember/index.ts @@ -56,7 +56,6 @@ import { componentCapabilities, modifierCapabilities, setComponentManager, - escapeExpression, getTemplates, setTemplates, template, @@ -597,9 +596,6 @@ namespace Ember { interface EmberHandlebars { template: typeof template; - Utils: { - escapeExpression: typeof escapeExpression; - }; compile?: typeof compile; precompile?: typeof precompile; } @@ -665,9 +661,6 @@ applicationRunLoadHooks('Ember.Application', EmberApplication); let EmberHandlebars: EmberHandlebars = { template, - Utils: { - escapeExpression, - }, }; let EmberHTMLBars: EmberHTMLBars = { diff --git a/packages/ember/tests/reexports_test.js b/packages/ember/tests/reexports_test.js index 3b3ee7c5da0..68f9b202919 100644 --- a/packages/ember/tests/reexports_test.js +++ b/packages/ember/tests/reexports_test.js @@ -318,7 +318,6 @@ let allExports = [ }, test56, ], - ['Handlebars.Utils.escapeExpression', '@ember/-internals/glimmer', 'escapeExpression', test56], ['_Input', '@ember/-internals/glimmer', 'Input', test56], ['_RegistryProxyMixin', '@ember/-internals/runtime', 'RegistryProxyMixin', test57], ['_ContainerProxyMixin', '@ember/-internals/runtime', 'ContainerProxyMixin', test57],