fix(builder): update_props no longer wipes style on style: null
style: null fell through the shallow-merge branch's `value && typeof value === 'object'` guard and hit the `p[key] = value` fallback, setting p.style = null and losing every existing style key. Treat style: null (or any other non-object style value) as "ignore this key" instead. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -188,6 +188,36 @@ describe('applyPatch', () => {
|
|||||||
expect(propsById['craft-1'].style).toEqual({ color: 'blue', fontSize: '16px' });
|
expect(propsById['craft-1'].style).toEqual({ color: 'blue', fontSize: '16px' });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('update_props: style: null does NOT wipe existing style (existing keys preserved)', () => {
|
||||||
|
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
||||||
|
const { query, actions, propsById } = makeSingleNodeHarness('craft-1', 'ai-node-1', {
|
||||||
|
text: 'Old',
|
||||||
|
style: { color: 'red', fontSize: '16px' },
|
||||||
|
});
|
||||||
|
const ops = [
|
||||||
|
{
|
||||||
|
op: 'update_props',
|
||||||
|
node_id: 'ai-node-1',
|
||||||
|
props: { style: null },
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const result = __test.applyPatch(actions, query, ops);
|
||||||
|
expect(result.ok).toBe(true);
|
||||||
|
expect(propsById['craft-1'].style).toEqual({ color: 'red', fontSize: '16px' });
|
||||||
|
warnSpy.mockRestore();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('update_props: a valid style object still merges shallowly alongside a style:null-safe path', () => {
|
||||||
|
const { query, actions, propsById } = makeSingleNodeHarness('craft-1', 'ai-node-1', {
|
||||||
|
style: { color: 'red', fontSize: '16px' },
|
||||||
|
});
|
||||||
|
const ops = [
|
||||||
|
{ op: 'update_props', node_id: 'ai-node-1', props: { style: { color: 'blue' } } },
|
||||||
|
];
|
||||||
|
__test.applyPatch(actions, query, ops);
|
||||||
|
expect(propsById['craft-1'].style).toEqual({ color: 'blue', fontSize: '16px' });
|
||||||
|
});
|
||||||
|
|
||||||
test('an op with an unknown resolvedName tree is skipped without throwing; other ops in the batch still apply', () => {
|
test('an op with an unknown resolvedName tree is skipped without throwing; other ops in the batch still apply', () => {
|
||||||
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
||||||
const { query, actions, propsById } = makeSingleNodeHarness('craft-1', 'ai-node-1', {});
|
const { query, actions, propsById } = makeSingleNodeHarness('craft-1', 'ai-node-1', {});
|
||||||
|
|||||||
@@ -181,9 +181,16 @@ function applyPatch(
|
|||||||
// AI usually only means to change one or two style keys, and a
|
// AI usually only means to change one or two style keys, and a
|
||||||
// blind Object.assign would clobber every other style the user
|
// blind Object.assign would clobber every other style the user
|
||||||
// (or a previous AI turn) had already set.
|
// (or a previous AI turn) had already set.
|
||||||
if (key === 'style' && value && typeof value === 'object' && !Array.isArray(value)) {
|
if (key === 'style') {
|
||||||
|
if (value && typeof value === 'object' && !Array.isArray(value)) {
|
||||||
const existingStyle = p.style && typeof p.style === 'object' ? p.style : {};
|
const existingStyle = p.style && typeof p.style === 'object' ? p.style : {};
|
||||||
p.style = { ...existingStyle, ...(value as Record<string, unknown>) };
|
p.style = { ...existingStyle, ...(value as Record<string, unknown>) };
|
||||||
|
} else {
|
||||||
|
// `style: null` (or any other non-object) is not a valid
|
||||||
|
// style patch — ignore it rather than clobbering the whole
|
||||||
|
// style object with null/undefined/a stray primitive.
|
||||||
|
console.warn('sitesmith patch: update_props ignoring non-object "style" value', value);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
p[key] = value;
|
p[key] = value;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user