@@ -46,9 +46,6 @@ const LIT_TEMPLATE_TYPE_MARKER = '_$litType$';
4646/** Lit's `nothing` sentinel — used to conditionally remove attributes */
4747const NOTHING_SYMBOL = Symbol . for ( 'lit-nothing' ) ;
4848
49- /** Lit's unsafeHTML directive marker — bypasses escaping */
50- const UNSAFE_HTML_DIRECTIVE = 'lit-html:unsafe-html' ;
51-
5249/**
5350 * Check if a value is a Lit TemplateResult.
5451 * Works with any Lit version that uses the _$litType$ marker.
@@ -194,27 +191,36 @@ function stringifyContentValue(value: unknown): string {
194191 return unwrapDsdForNestedCe ( result ) ;
195192 }
196193
197- // v0.6: Check if this value has a directive marker that indicates
198- // it should bypass escaping (e.g., unsafeHTML directive).
199- // Lit's unsafeHTML directive returns a special object with properties
200- // that signal "trust this HTML content".
194+ // v0.6.3: Detect Lit 3.x unsafeHTML directive to bypass escaping.
195+ // unsafeHTML() returns { _$litDirective$: UnsafeHTML, values: [htmlString] }
196+ // - _$litDirective$ is the directive class (not a string)
197+ // - The class has static `directiveName: 'unsafeHTML'` and `resultType: 1`
198+ // - The HTML string is in `values[0]`
201199 if ( typeof value === 'object' && value !== null ) {
202200 const obj = value as Record < string , unknown > ;
203- // Check for Lit's unsafeHTML directive marker
204- if ( obj . _$litDirective$ === UNSAFE_HTML_DIRECTIVE && typeof obj . _$resolve === 'function' ) {
205- try {
206- const resolved = obj . _$resolve ( ) ;
207- if ( resolved != null ) {
208- const str = String ( resolved ) ;
209- // FIX: Also unwrap DSD from unsafeHTML results containing custom elements
210- return unwrapDsdForNestedCe ( str ) ;
201+ const directiveCtor = obj . _$litDirective$ ;
202+
203+ if ( typeof directiveCtor === 'function' ) {
204+ const ctor = directiveCtor as unknown as Record < string , unknown > ;
205+ const isUnsafeHtml = ctor . directiveName === 'unsafeHTML' ||
206+ ctor . resultType === 1 ; // resultType 1 = unsafe HTML in Lit 3.x
207+
208+ if ( isUnsafeHtml && obj . values != null ) {
209+ try {
210+ const vals = Array . isArray ( obj . values )
211+ ? obj . values
212+ : Array . from ( obj . values as ArrayLike < unknown > ) ;
213+ const resolved = vals [ 0 ] ;
214+ if ( resolved != null ) {
215+ const str = String ( resolved ) ;
216+ return unwrapDsdForNestedCe ( str ) ;
217+ }
218+ return '' ;
219+ } catch ( e ) {
220+ log . debug (
221+ `unsafeHTML value extraction failed: ${ e instanceof Error ? e . message : String ( e ) } ` ,
222+ ) ;
211223 }
212- return '' ;
213- } catch ( e ) {
214- // If resolution fails, fall through to escaped string
215- log . debug (
216- `Directive resolution failed: ${ e instanceof Error ? e . message : String ( e ) } ` ,
217- ) ;
218224 }
219225 }
220226 // _$litDirective$ also appears in other Lit directives — fall through
0 commit comments