cfb6e62331
Список сцен активной линии в порядке бокового списка редактора; переход с записью в историю. Co-authored-by: Cursor <cursoragent@cursor.com>
126 lines
4.0 KiB
TypeScript
126 lines
4.0 KiB
TypeScript
import assert from 'node:assert/strict';
|
|
import test from 'node:test';
|
|
|
|
import type { Project, SceneGraphEdge, SceneGraphNode } from '../types';
|
|
import { asGraphNodeId, asSceneId } from '../types/ids';
|
|
|
|
import { getActiveStorylineGraphNodeIds, listActiveStorylineScenes } from './activeStorylineScenes';
|
|
|
|
function node(id: string, sceneId: string, extra: Partial<SceneGraphNode> = {}): SceneGraphNode {
|
|
return {
|
|
id: asGraphNodeId(id),
|
|
sceneId: asSceneId(sceneId),
|
|
x: 0,
|
|
y: 0,
|
|
isStartScene: false,
|
|
isSideStoryStart: false,
|
|
sideStoryLineTitle: '',
|
|
...extra,
|
|
};
|
|
}
|
|
|
|
function edge(source: string, target: string): SceneGraphEdge {
|
|
return { sourceGraphNodeId: asGraphNodeId(source), targetGraphNodeId: asGraphNodeId(target) };
|
|
}
|
|
|
|
function minimalProject(partial: Partial<Project> & Pick<Project, 'sceneGraphNodes' | 'sceneGraphEdges'>): Project {
|
|
return {
|
|
id: partial.id ?? ('p1' as Project['id']),
|
|
title: partial.title ?? 'Test',
|
|
scenes: partial.scenes ?? {},
|
|
sceneListOrder: partial.sceneListOrder ?? [],
|
|
sceneGraphNodes: partial.sceneGraphNodes,
|
|
sceneGraphEdges: partial.sceneGraphEdges,
|
|
currentGraphNodeId: partial.currentGraphNodeId ?? null,
|
|
currentSceneId: partial.currentSceneId ?? null,
|
|
materials: partial.materials ?? [],
|
|
campaignAudio: partial.campaignAudio ?? [],
|
|
npcs: partial.npcs ?? [],
|
|
npcGroups: partial.npcGroups ?? [],
|
|
npcRelations: partial.npcRelations ?? [],
|
|
};
|
|
}
|
|
|
|
void test('listActiveStorylineScenes: main line ordered by sceneListOrder, deduped', () => {
|
|
const s1 = asSceneId('s1');
|
|
const s2 = asSceneId('s2');
|
|
const s3 = asSceneId('s3');
|
|
const nodes = [
|
|
node('main', 's1', { isStartScene: true }),
|
|
node('a', 's2'),
|
|
node('b', 's3'),
|
|
node('dup', 's2'),
|
|
];
|
|
const edges = [edge('main', 'a'), edge('a', 'b'), edge('a', 'dup')];
|
|
const project = minimalProject({
|
|
scenes: {
|
|
[s1]: { id: s1, title: 'Start' },
|
|
[s2]: { id: s2, title: 'Mid' },
|
|
[s3]: { id: s3, title: 'End' },
|
|
},
|
|
sceneListOrder: [s3, s1, s2],
|
|
sceneGraphNodes: nodes,
|
|
sceneGraphEdges: edges,
|
|
currentGraphNodeId: asGraphNodeId('a'),
|
|
});
|
|
|
|
const list = listActiveStorylineScenes(project);
|
|
assert.deepEqual(
|
|
list.map((e) => e.sceneId),
|
|
[s3, s1, s2],
|
|
);
|
|
assert.equal(list[2]?.graphNodeId, asGraphNodeId('a'));
|
|
});
|
|
|
|
void test('listActiveStorylineScenes: side line only', () => {
|
|
const s1 = asSceneId('s1');
|
|
const s2 = asSceneId('s2');
|
|
const sSide = asSceneId('sSide');
|
|
const nodes = [
|
|
node('main', 's1', { isStartScene: true }),
|
|
node('side', 'sSide', { isSideStoryStart: true }),
|
|
node('x', 's2'),
|
|
];
|
|
const edges = [edge('side', 'x')];
|
|
const project = minimalProject({
|
|
scenes: {
|
|
[s1]: { id: s1, title: 'Main' },
|
|
[s2]: { id: s2, title: 'Side step' },
|
|
[sSide]: { id: sSide, title: 'Side start' },
|
|
},
|
|
sceneListOrder: [s1, s2, sSide],
|
|
sceneGraphNodes: nodes,
|
|
sceneGraphEdges: edges,
|
|
currentGraphNodeId: asGraphNodeId('x'),
|
|
});
|
|
|
|
const ids = getActiveStorylineGraphNodeIds(nodes, edges, asGraphNodeId('x'));
|
|
assert.deepEqual([...ids].sort(), [asGraphNodeId('side'), asGraphNodeId('x')].sort());
|
|
|
|
const list = listActiveStorylineScenes(project);
|
|
assert.deepEqual(
|
|
list.map((e) => e.sceneId),
|
|
[s2, sSide],
|
|
);
|
|
});
|
|
|
|
void test('listActiveStorylineScenes: current node preferred for duplicate sceneId', () => {
|
|
const s2 = asSceneId('s2');
|
|
const nodes = [
|
|
node('main', 's1', { isStartScene: true }),
|
|
node('a', 's2'),
|
|
node('dup', 's2'),
|
|
];
|
|
const edges = [edge('main', 'a'), edge('main', 'dup')];
|
|
const project = minimalProject({
|
|
scenes: { [asSceneId('s1')]: { id: asSceneId('s1'), title: 'S1' }, [s2]: { id: s2, title: 'S2' } },
|
|
sceneListOrder: [asSceneId('s1'), s2],
|
|
sceneGraphNodes: nodes,
|
|
sceneGraphEdges: edges,
|
|
currentGraphNodeId: asGraphNodeId('dup'),
|
|
});
|
|
|
|
const list = listActiveStorylineScenes(project);
|
|
assert.equal(list.find((e) => e.sceneId === s2)?.graphNodeId, asGraphNodeId('dup'));
|
|
});
|