Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -176,14 +176,13 @@ function analyzeFileUpdates(
}

// Compare component meta decorator object literals
if (
hasUnsupportedMetaUpdates(
staleDecoratorExpression,
stale,
updatedDecoratorExpression,
updated,
)
) {
const analysis = analyzeMetaUpdates(
staleDecoratorExpression,
stale,
updatedDecoratorExpression,
updated,
);
if (analysis === MetaUpdateAnalysis.Unsupported) {
return null;
}

Expand All @@ -194,7 +193,9 @@ function analyzeFileUpdates(
}

// If all previous class checks passed, this class is supported for HMR updates
candidates.push(updatedNode);
if (analysis === MetaUpdateAnalysis.Supported) {
candidates.push(updatedNode);
}
continue;
}
}
Expand All @@ -213,7 +214,19 @@ function analyzeFileUpdates(
/**
* The set of Angular component metadata fields that are supported by HMR updates.
*/
const SUPPORTED_FIELDS = new Set(['template', 'templateUrl', 'styles', 'styleUrl', 'stylesUrl']);
const SUPPORTED_FIELD_NAMES = new Set([
'template',
'templateUrl',
'styles',
'styleUrl',
'stylesUrl',
]);

enum MetaUpdateAnalysis {
Supported,
Unsupported,
None,
}

/**
* Analyzes the metadata fields of a decorator call expression for unsupported HMR updates.
Expand All @@ -222,31 +235,34 @@ const SUPPORTED_FIELDS = new Set(['template', 'templateUrl', 'styles', 'styleUrl
* @param staleSource The source file instance containing the stale call instance.
* @param updatedCall A call expression instance.
* @param updatedSource The source file instance containing the updated call instance.
* @returns true, if unsupported metadata updates are present; false, otherwise.
* @returns A MetaUpdateAnalysis enum value.
*/
function hasUnsupportedMetaUpdates(
function analyzeMetaUpdates(
staleCall: ts.CallExpression,
staleSource: ts.SourceFile,
updatedCall: ts.CallExpression,
updatedSource: ts.SourceFile,
): boolean {
): MetaUpdateAnalysis {
const staleObject = staleCall.arguments[0];
const updatedObject = updatedCall.arguments[0];
let hasSupportedUpdate = false;

if (!ts.isObjectLiteralExpression(staleObject) || !ts.isObjectLiteralExpression(updatedObject)) {
return true;
return MetaUpdateAnalysis.Unsupported;
}

const supportedFields = new Map<string, ts.Node>();
const unsupportedFields: ts.Node[] = [];

for (const property of staleObject.properties) {
if (!ts.isPropertyAssignment(property) || ts.isComputedPropertyName(property.name)) {
// Unsupported object literal property
return true;
return MetaUpdateAnalysis.Unsupported;
}

const name = property.name.text;
if (SUPPORTED_FIELDS.has(name)) {
if (SUPPORTED_FIELD_NAMES.has(name)) {
supportedFields.set(name, property.initializer);
continue;
}

Expand All @@ -257,21 +273,38 @@ function hasUnsupportedMetaUpdates(
for (const property of updatedObject.properties) {
if (!ts.isPropertyAssignment(property) || ts.isComputedPropertyName(property.name)) {
// Unsupported object literal property
return true;
return MetaUpdateAnalysis.Unsupported;
}

const name = property.name.text;
if (SUPPORTED_FIELDS.has(name)) {
if (SUPPORTED_FIELD_NAMES.has(name)) {
const staleInitializer = supportedFields.get(name);
// If the supported field was added or has its content changed, there has been a supported update
if (
!staleInitializer ||
!equalRangeText(property.initializer, updatedSource, staleInitializer, staleSource)
) {
hasSupportedUpdate = true;
}
// Remove the field entry to allow tracking removed fields
supportedFields.delete(name);
continue;
}

// Compare in order
if (!equalRangeText(property.initializer, updatedSource, unsupportedFields[i++], staleSource)) {
return true;
return MetaUpdateAnalysis.Unsupported;
}
}

return i !== unsupportedFields.length;
if (i !== unsupportedFields.length) {
return MetaUpdateAnalysis.Unsupported;
}

// Any remaining supported field indicates a field removal. This is also considered a supported update.
hasSupportedUpdate ||= supportedFields.size > 0;

return hasSupportedUpdate ? MetaUpdateAnalysis.Supported : MetaUpdateAnalysis.None;
}

/**
Expand Down