@@ -163,12 +163,49 @@ function stripExpressions(template: TemplateLiteral, input: string): string {
163
163
const source = new Sourcemap ( input ) ;
164
164
let index = template . start ;
165
165
for ( const q of template . quasis ) {
166
- if ( q . start > index ) source . delete ( index , q . start ) ;
166
+ if ( q . start > index ) {
167
+ // In a case such as <img src=${…} style=…>, we must replace the
168
+ // placeholder with a non-empty value or it will change the interpre-
169
+ // tation of the subsequent attribute to be part of the src attribute!
170
+ // But we also don’t want to use a non-empty src attribute because that
171
+ // would cause the browser to load an asset that does not exist (before
172
+ // it is replaced by the client-generated content).
173
+ if ( hasPrecedingEquals ( input , index ) ) {
174
+ source . replaceLeft ( index , q . start , '""' ) ;
175
+ } else {
176
+ source . delete ( index , q . start ) ;
177
+ }
178
+ }
167
179
index = q . end ;
168
180
}
169
181
return String ( source ) ;
170
182
}
171
183
184
+ /** Returns true if the specified character is preceded by an equals sign, ignoring whitespace. */
185
+ function hasPrecedingEquals ( input : string , index : number ) : boolean {
186
+ let i = index - 1 ;
187
+ while ( isSpaceCode ( input . charCodeAt ( i ) ) ) -- i ;
188
+ return input . charCodeAt ( i ) === CODE_EQ ;
189
+ }
190
+
191
+ const CODE_TAB = 9 ,
192
+ CODE_LF = 10 ,
193
+ CODE_FF = 12 ,
194
+ CODE_CR = 13 ,
195
+ CODE_SPACE = 32 ,
196
+ CODE_EQ = 61 ;
197
+
198
+ /** Returns true if the specified character code is considered whitespace by HTML. */
199
+ function isSpaceCode ( code : number ) : boolean {
200
+ return (
201
+ code === CODE_TAB ||
202
+ code === CODE_LF ||
203
+ code === CODE_FF ||
204
+ code === CODE_SPACE ||
205
+ code === CODE_CR
206
+ ) ;
207
+ }
208
+
172
209
/** Note: only suitable for use in a script element. */
173
210
function escapeScript ( script : string ) : string {
174
211
return script . replace ( / < \/ s c r i p t > / g, "<\\/script>" ) ; // TODO handle other contexts
0 commit comments