@@ -176,14 +176,13 @@ function analyzeFileUpdates(
176
176
}
177
177
178
178
// Compare component meta decorator object literals
179
- if (
180
- hasUnsupportedMetaUpdates (
181
- staleDecoratorExpression ,
182
- stale ,
183
- updatedDecoratorExpression ,
184
- updated ,
185
- )
186
- ) {
179
+ const analysis = analyzeMetaUpdates (
180
+ staleDecoratorExpression ,
181
+ stale ,
182
+ updatedDecoratorExpression ,
183
+ updated ,
184
+ ) ;
185
+ if ( analysis === MetaUpdateAnalysis . Unsupported ) {
187
186
return null ;
188
187
}
189
188
@@ -194,7 +193,9 @@ function analyzeFileUpdates(
194
193
}
195
194
196
195
// If all previous class checks passed, this class is supported for HMR updates
197
- candidates . push ( updatedNode ) ;
196
+ if ( analysis === MetaUpdateAnalysis . Supported ) {
197
+ candidates . push ( updatedNode ) ;
198
+ }
198
199
continue ;
199
200
}
200
201
}
@@ -213,7 +214,19 @@ function analyzeFileUpdates(
213
214
/**
214
215
* The set of Angular component metadata fields that are supported by HMR updates.
215
216
*/
216
- const SUPPORTED_FIELDS = new Set ( [ 'template' , 'templateUrl' , 'styles' , 'styleUrl' , 'stylesUrl' ] ) ;
217
+ const SUPPORTED_FIELD_NAMES = new Set ( [
218
+ 'template' ,
219
+ 'templateUrl' ,
220
+ 'styles' ,
221
+ 'styleUrl' ,
222
+ 'stylesUrl' ,
223
+ ] ) ;
224
+
225
+ enum MetaUpdateAnalysis {
226
+ Supported ,
227
+ Unsupported ,
228
+ None ,
229
+ }
217
230
218
231
/**
219
232
* Analyzes the metadata fields of a decorator call expression for unsupported HMR updates.
@@ -222,31 +235,34 @@ const SUPPORTED_FIELDS = new Set(['template', 'templateUrl', 'styles', 'styleUrl
222
235
* @param staleSource The source file instance containing the stale call instance.
223
236
* @param updatedCall A call expression instance.
224
237
* @param updatedSource The source file instance containing the updated call instance.
225
- * @returns true, if unsupported metadata updates are present; false, otherwise .
238
+ * @returns A MetaUpdateAnalysis enum value .
226
239
*/
227
- function hasUnsupportedMetaUpdates (
240
+ function analyzeMetaUpdates (
228
241
staleCall : ts . CallExpression ,
229
242
staleSource : ts . SourceFile ,
230
243
updatedCall : ts . CallExpression ,
231
244
updatedSource : ts . SourceFile ,
232
- ) : boolean {
245
+ ) : MetaUpdateAnalysis {
233
246
const staleObject = staleCall . arguments [ 0 ] ;
234
247
const updatedObject = updatedCall . arguments [ 0 ] ;
248
+ let hasSupportedUpdate = false ;
235
249
236
250
if ( ! ts . isObjectLiteralExpression ( staleObject ) || ! ts . isObjectLiteralExpression ( updatedObject ) ) {
237
- return true ;
251
+ return MetaUpdateAnalysis . Unsupported ;
238
252
}
239
253
254
+ const supportedFields = new Map < string , ts . Node > ( ) ;
240
255
const unsupportedFields : ts . Node [ ] = [ ] ;
241
256
242
257
for ( const property of staleObject . properties ) {
243
258
if ( ! ts . isPropertyAssignment ( property ) || ts . isComputedPropertyName ( property . name ) ) {
244
259
// Unsupported object literal property
245
- return true ;
260
+ return MetaUpdateAnalysis . Unsupported ;
246
261
}
247
262
248
263
const name = property . name . text ;
249
- if ( SUPPORTED_FIELDS . has ( name ) ) {
264
+ if ( SUPPORTED_FIELD_NAMES . has ( name ) ) {
265
+ supportedFields . set ( name , property . initializer ) ;
250
266
continue ;
251
267
}
252
268
@@ -257,21 +273,38 @@ function hasUnsupportedMetaUpdates(
257
273
for ( const property of updatedObject . properties ) {
258
274
if ( ! ts . isPropertyAssignment ( property ) || ts . isComputedPropertyName ( property . name ) ) {
259
275
// Unsupported object literal property
260
- return true ;
276
+ return MetaUpdateAnalysis . Unsupported ;
261
277
}
262
278
263
279
const name = property . name . text ;
264
- if ( SUPPORTED_FIELDS . has ( name ) ) {
280
+ if ( SUPPORTED_FIELD_NAMES . has ( name ) ) {
281
+ const staleInitializer = supportedFields . get ( name ) ;
282
+ // If the supported field was added or has its content changed, there has been a supported update
283
+ if (
284
+ ! staleInitializer ||
285
+ ! equalRangeText ( property . initializer , updatedSource , staleInitializer , staleSource )
286
+ ) {
287
+ hasSupportedUpdate = true ;
288
+ }
289
+ // Remove the field entry to allow tracking removed fields
290
+ supportedFields . delete ( name ) ;
265
291
continue ;
266
292
}
267
293
268
294
// Compare in order
269
295
if ( ! equalRangeText ( property . initializer , updatedSource , unsupportedFields [ i ++ ] , staleSource ) ) {
270
- return true ;
296
+ return MetaUpdateAnalysis . Unsupported ;
271
297
}
272
298
}
273
299
274
- return i !== unsupportedFields . length ;
300
+ if ( i !== unsupportedFields . length ) {
301
+ return MetaUpdateAnalysis . Unsupported ;
302
+ }
303
+
304
+ // Any remaining supported field indicates a field removal. This is also considered a supported update.
305
+ hasSupportedUpdate ||= supportedFields . size > 0 ;
306
+
307
+ return hasSupportedUpdate ? MetaUpdateAnalysis . Supported : MetaUpdateAnalysis . None ;
275
308
}
276
309
277
310
/**
0 commit comments