Skip to content

Commit

Permalink
refactor(compiler): normalize style prop binding names (angular#50805)
Browse files Browse the repository at this point in the history
Normalizes style property names in bindings by converting them to
kebab-case and stripping off `!important`

PR Close angular#50805
  • Loading branch information
mmalerba authored and thePunderWoman committed Jul 17, 2023
1 parent c27d6b6 commit 03e6dc3
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,7 @@
}
]
}
],
"skipForTemplatePipeline": true
]
},
{
"description": "should support class interpolation",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,7 @@
"failureMessage": "Incorrect handling of interpolated style properties",
"files": ["style_binding_important.js"]
}
],
"skipForTemplatePipeline": true
]
}
]
}
8 changes: 5 additions & 3 deletions packages/compiler/src/template/pipeline/src/emit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,32 +17,34 @@ import {phaseAttributeExtraction} from './phases/attribute_extraction';
import {phaseChaining} from './phases/chaining';
import {phaseConstCollection} from './phases/const_collection';
import {phaseEmptyElements} from './phases/empty_elements';
import {phaseExpandSafeReads} from './phases/expand_safe_reads';
import {phaseGenerateAdvance} from './phases/generate_advance';
import {phaseNullishCoalescing} from './phases/nullish_coalescing';
import {phaseGenerateVariables} from './phases/generate_variables';
import {phaseLocalRefs} from './phases/local_refs';
import {phaseNaming} from './phases/naming';
import {phaseMergeNextContext} from './phases/next_context_merging';
import {phaseNgContainer} from './phases/ng_container';
import {phaseNullishCoalescing} from './phases/nullish_coalescing';
import {phasePipeCreation} from './phases/pipe_creation';
import {phasePipeVariadic} from './phases/pipe_variadic';
import {phasePropertyNameNormalization} from './phases/property_name_normalization';
import {phasePureFunctionExtraction} from './phases/pure_function_extraction';
import {phasePureLiteralStructures} from './phases/pure_literal_structures';
import {phaseReify} from './phases/reify';
import {phaseResolveContexts} from './phases/resolve_contexts';
import {phaseResolveNames} from './phases/resolve_names';
import {phaseSaveRestoreView} from './phases/save_restore_view';
import {phaseSlotAllocation} from './phases/slot_allocation';
import {phaseTemporaryVariables} from './phases/temporary_variables';
import {phaseVarCounting} from './phases/var_counting';
import {phaseVariableOptimization} from './phases/variable_optimization';
import {phaseExpandSafeReads} from './phases/expand_safe_reads';
import {phaseTemporaryVariables} from './phases/temporary_variables';

/**
* Run all transformation phases in the correct order against a `ComponentCompilation`. After this
* processing, the compilation should be in a state where it can be emitted via `emitTemplateFn`.s
*/
export function transformTemplate(cpl: ComponentCompilation): void {
phasePropertyNameNormalization(cpl);
phaseAttributeExtraction(cpl, true);
phasePipeCreation(cpl);
phasePipeVariadic(cpl);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/

import {hyphenate} from '../../../../render3/view/style_parser';
import {OpKind} from '../../ir';
import {ComponentCompilation} from '../compilation';

/**
* Normalizes the property name for style properties. The following normalizations are performed:
* - Convert style property names (other than CSS vars) to hyphenated (e.g. `backgroundColor` to
* `background-color`)
* - Strip `!important` from the end of class and style properties
*/
export function phasePropertyNameNormalization(cpl: ComponentCompilation) {
for (const [, view] of cpl.views) {
for (const op of view.update) {
if (op.kind === OpKind.StyleProp || op.kind === OpKind.InterpolateStyleProp) {
op.name = normalizeStylePropName(op.name);
} else if (op.kind === OpKind.ClassProp) {
op.name = stripImportant(op.name);
}
}
}
}

/**
* Normalizes a style prop name by hyphenating it and stripping `!important`.
*/
function normalizeStylePropName(name: string) {
if (!name.startsWith('--')) {
name = hyphenate(name);
}
return stripImportant(name);
}

/**
* Strips `!important` out of the op name.
*/
function stripImportant(name: string) {
// TODO: should we be doing this? The information seems to just be discarded.
// It also strips !important from cases like [style.!important] and
// [style.color!important-other-stuff], which is kind of strange.
const importantIndex = name.indexOf('!important');
if (importantIndex > -1) {
return name.substring(0, importantIndex);
}
return name;
}

0 comments on commit 03e6dc3

Please sign in to comment.