Skip to content

Commit 9b4d914

Browse files
committed
fix: address review feedback on finalKey merge block
- Guard finalKey block with config.target.length === 1 so it only runs for length-1 array targets, not nested paths handled by recursion - Explicitly write filtered rightValue in all code paths to prevent unfiltered VAR_SYMBOL objects from leaking into RN props - Add defensive comment about leaf-key storage limitation in getStyledProps
1 parent 5d8680e commit 9b4d914

File tree

1 file changed

+17
-3
lines changed

1 file changed

+17
-3
lines changed

src/native/styles/index.ts

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,12 @@ export function getStyledProps(
196196
// deepMergeConfig produces a full props object via Object.assign({}, left, right).
197197
// Later iterations overwrite earlier ones' correctly-merged target props.
198198
// We save each iteration's target value and restore them after the loop.
199+
//
200+
// Note: This uses the leaf key of config.target for storage/restoration.
201+
// For nested array targets (length > 1), the leaf key is stored at the
202+
// top level, which is correct because deepMergeConfig already builds the
203+
// nested structure. If two configs ever share the same leaf key, the last
204+
// one wins — but no built-in component mapping produces this scenario.
199205
const computedTargets: Record<string, any> = {};
200206
const consumedSources: string[] = [];
201207

@@ -456,15 +462,18 @@ function deepMergeConfig(
456462
// above runs 0 iterations. Merge the target prop so inline styles don't
457463
// silently overwrite className-computed styles (same as string target path).
458464
const finalKey = config.target[config.target.length - 1];
459-
if (finalKey && rightIsInline) {
465+
if (config.target.length === 1 && finalKey && rightIsInline) {
460466
let rightValue = right?.[finalKey];
461467
if (rightValue !== undefined) {
462468
rightValue = filterCssVariables(rightValue);
463469
}
464470
if (rightValue === undefined || rightValue === null) {
465-
// Inline is empty — preserve className-computed value
471+
// Inline is empty or fully filtered — preserve className-computed value
466472
if (left && finalKey in left) {
467473
result[finalKey] = left[finalKey];
474+
} else {
475+
// No left value either — remove unfiltered inline value from result
476+
delete result[finalKey];
468477
}
469478
} else if (left && finalKey in left) {
470479
const leftValue = left[finalKey];
@@ -479,11 +488,16 @@ function deepMergeConfig(
479488
if (leftIsObj && rightIsObj) {
480489
if (hasNonOverlappingProperties(leftValue, rightValue)) {
481490
result[finalKey] = [leftValue, rightValue];
491+
} else {
492+
// All left keys are in right — use filtered right value
493+
result[finalKey] = rightValue;
482494
}
483-
// else: all left keys are in right, right overrides — already set by mergeDefinedProps
484495
} else {
485496
result[finalKey] = [leftValue, rightValue];
486497
}
498+
} else {
499+
// No left value — use filtered right value (not the unfiltered one from mergeDefinedProps)
500+
result[finalKey] = rightValue;
487501
}
488502
}
489503

0 commit comments

Comments
 (0)