Fix findUsages/undo/node-lookup bugs, split Viewport and Editor, share command and inspector helpers

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
rootandClaude Opus 5 committed 2026-09-08 09:22:49 +02:00
1 parent 1eb28314cf
commit f140c2fd77
58 files changed
+1969 -1171

No files matched your search

+60
View File
@@ -0,0 +1,60 @@
/**
* The undo contract every "write one key into a property bag" command shares: a key that was
* not in the bag before the edit must be *absent* again afterwards, not present as undefined.
* Serialization and the "is this an override?" checks in the inspector go by key presence.
*/
import { describe, expect, it } from 'vitest';
import { ResetAssetPropertyCommand, SetAssetPropertyCommand } from '../../src/core/commands/assetCommands';
import { SetNodeParamCommand } from '../../src/core/commands/graphCommands';
import { ClearOverrideCommand, SetOverrideCommand } from '../../src/core/commands/sceneObjectCommands';
import { findAsset } from '../../src/core/model/Project';
import { graphEditor, makeBehavior, makeSpriteScene, place } from '../helpers';
describe('bag value commands', () => {
it('undoing an override leaves no key behind', () => {
const fixture = makeSpriteScene();
const box = place(fixture, fixture.spriteId, { x: 0, y: 0 });
fixture.stack.execute(new SetOverrideCommand(fixture.sceneId, box, 'width', 33));
expect(fixture.object(box).overrides).toEqual({ width: 33 });
fixture.stack.undo();
expect('width' in fixture.object(box).overrides).toBe(false);
});
it('undoing a cleared override puts the old value back', () => {
const fixture = makeSpriteScene();
const box = place(fixture, fixture.spriteId, { x: 0, y: 0 });
fixture.stack.execute(new SetOverrideCommand(fixture.sceneId, box, 'width', 33));
fixture.stack.execute(new ClearOverrideCommand(fixture.sceneId, box, 'width'));
expect('width' in fixture.object(box).overrides).toBe(false);
fixture.stack.undo();
expect(fixture.object(box).overrides.width).toBe(33);
});
it('coerces on set and restores the untouched default on undo of a reset', () => {
const fixture = makeSpriteScene();
const sprite = () => findAsset(fixture.project, fixture.spriteId)!;
// 'width' is a number property, so a numeric string is coerced.
fixture.stack.execute(new SetAssetPropertyCommand(fixture.spriteId, 'width', '250'));
expect(sprite().props.width).toBe(250);
fixture.stack.execute(new ResetAssetPropertyCommand(fixture.spriteId, 'width'));
expect(sprite().props.width).toBe(100);
fixture.stack.undo();
expect(sprite().props.width).toBe(250);
});
it('restores a node param that had no value before', () => {
const fixture = makeSpriteScene();
const behavior = makeBehavior(fixture, 'B');
// `Owner` declares no params, so 'value' is an inline input value: stored as given.
const node = graphEditor(fixture, behavior).addNode('Owner');
fixture.stack.execute(new SetNodeParamCommand(behavior.id, node.id, 'value', 7));
expect(node.params.value).toBe(7);
fixture.stack.undo();
expect('value' in node.params).toBe(false);
});
});